import 'package:p_tits_pas/config/env.dart'; class ApiConfig { /// Aligné sur [Env.apiBaseUrl] (`--dart-define=API_BASE_URL=...`) pour que les images `/uploads/...` visent le même hôte que l’API. static String get baseUrl { final root = Env.apiBaseUrl.replaceAll(RegExp(r'/+$'), ''); return '$root/api/v1'; } /// Origine (schéma + hôte + port) dérivée de [baseUrl], pour préfixer les chemins `/uploads/...`. static String get apiOrigin { final uri = Uri.parse(baseUrl); if (uri.hasScheme && uri.host.isNotEmpty) { return '${uri.scheme}://${uri.authority}'; } return baseUrl.replaceAll(RegExp(r'/api/v1/?.*'), ''); } /// URL absolue pour une image renvoyée par l’API (chemin type `/uploads/...`). /// On préfixe avec [baseUrl] (…/api/v1), pas seulement l’hôte : Traefik n’expose souvent que `/api`. static String absoluteMediaUrl(String? pathOrUrl) { if (pathOrUrl == null || pathOrUrl.trim().isEmpty) { return ''; } final u = pathOrUrl.trim(); if (u.startsWith('http://') || u.startsWith('https://')) { return u; } final base = baseUrl.replaceAll(RegExp(r'/+$'), ''); // Le back renvoie parfois des chemins déjà préfixés `/api/v1/...` (ex. documents // légaux). Ne pas les coller à [baseUrl] sous peine de doubler `/api/v1`. if (u.startsWith('/api/')) { final origin = apiOrigin.replaceAll(RegExp(r'/+$'), ''); return '$origin$u'; } return u.startsWith('/') ? '$base$u' : '$base/$u'; } // Auth endpoints static const String login = '/auth/login'; static const String register = '/auth/register'; static const String registerParent = '/auth/register/parent'; static const String registerAM = '/auth/register/am'; static const String refreshToken = '/auth/refresh'; static const String authMe = '/auth/me'; static const String changePasswordRequired = '/auth/change-password-required'; static const String verifyCreatePasswordToken = '/auth/verify-token'; static const String createPassword = '/auth/create-password'; /// Ticket #127 — mot de passe oublié (back à livrer en parallèle). static const String forgotPassword = '/auth/forgot-password'; static const String resetPassword = '/auth/reset-password'; /// Ticket #112 — reprise après refus (#111 back). static const String repriseDossier = '/auth/reprise-dossier'; static const String repriseResoumettre = '/auth/reprise-resoumettre'; static const String repriseIdentify = '/auth/reprise-identify'; // Users endpoints static const String users = '/users'; static const String userProfile = '/users/profile'; static const String userChildren = '/users/children'; static const String gestionnaires = '/gestionnaires'; static const String parents = '/parents'; static const String assistantesMaternelles = '/assistantes-maternelles'; static const String relais = '/relais'; static const String dossiers = '/dossiers'; // Configuration (admin) static const String configuration = '/configuration'; static const String configurationSetupStatus = '/configuration/setup/status'; static const String configurationSetupComplete = '/configuration/setup/complete'; static const String configurationTestSmtp = '/configuration/test-smtp'; static const String configurationBulk = '/configuration/bulk'; // Dashboard endpoints static const String dashboard = '/dashboard'; static const String events = '/events'; static const String contracts = '/contracts'; static const String conversations = '/conversations'; static const String notifications = '/notifications'; // Headers static Map get headers => { 'Content-Type': 'application/json', 'Accept': 'application/json', }; static Map authHeaders(String token) => { ...headers, 'Authorization': 'Bearer $token', }; }