feat(#112): aligner reprise front sur dossier complet GET/PATCH

Préremplit parents, enfants, motivation et fiche AM depuis reprise-dossier
et envoie le body PATCH complet (co-parent, enfants par id, champs pro AM).

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-06-16 16:46:51 +02:00
co-authored by Cursor
parent 25c10c885a
commit f300505225
11 changed files with 439 additions and 92 deletions
+5 -28
View File
@@ -291,43 +291,20 @@ class AuthService {
}
/// Resoumission après refus. PATCH /auth/reprise-resoumettre. Ticket #112.
static Future<void> resoumettreReprise({
required String token,
String? prenom,
String? nom,
String? telephone,
String? adresse,
String? ville,
String? codePostal,
String? photoUrl,
}) async {
final cleaned = token.trim();
static Future<void> resoumettreReprise(Map<String, dynamic> body) async {
final cleaned = body['token']?.toString().trim() ?? '';
if (cleaned.isEmpty) {
throw Exception('Lien invalide ou expiré.');
}
final body = <String, dynamic>{'token': cleaned};
if (prenom != null && prenom.trim().isNotEmpty) body['prenom'] = prenom.trim();
if (nom != null && nom.trim().isNotEmpty) body['nom'] = nom.trim();
if (telephone != null && telephone.trim().isNotEmpty) {
body['telephone'] = telephone.trim();
}
if (adresse != null && adresse.trim().isNotEmpty) {
body['adresse'] = adresse.trim();
}
if (ville != null && ville.trim().isNotEmpty) body['ville'] = ville.trim();
if (codePostal != null && codePostal.trim().isNotEmpty) {
body['code_postal'] = codePostal.trim();
}
if (photoUrl != null && photoUrl.trim().isNotEmpty) {
body['photo_url'] = photoUrl.trim();
}
final payload = Map<String, dynamic>.from(body);
payload['token'] = cleaned;
late final http.Response response;
try {
response = await http.patch(
Uri.parse('${ApiConfig.baseUrl}${ApiConfig.repriseResoumettre}'),
headers: ApiConfig.headers,
body: jsonEncode(body),
body: jsonEncode(payload),
);
} on http.ClientException {
throw Exception(
+24 -13
View File
@@ -2,6 +2,7 @@ import 'package:p_tits_pas/models/am_registration_data.dart';
import 'package:p_tits_pas/models/reprise_dossier.dart';
import 'package:p_tits_pas/models/user_registration_data.dart';
import 'package:p_tits_pas/services/api/api_config.dart';
import 'package:p_tits_pas/utils/reprise_mapper.dart';
/// Contexte reprise après refus (token e-mail ou identify). Ticket #112.
class RepriseSession {
@@ -10,6 +11,7 @@ class RepriseSession {
static String? _token;
static String? _role;
static String? _photoUrl;
static String? _photoUrlForApi;
static bool get isActive =>
_token != null && _token!.trim().isNotEmpty;
@@ -20,16 +22,22 @@ class RepriseSession {
static bool get isAm => _role == 'assistante_maternelle';
/// URL absolue pour l'affichage.
static String? get photoUrl => _photoUrl;
/// Chemin relatif API (`/uploads/…`) pour PATCH sans re-upload.
static String? get photoUrlForApi => _photoUrlForApi;
static void start({
required String token,
required RepriseDossier dossier,
}) {
_token = token.trim();
_role = dossier.role;
_photoUrl = dossier.photoUrl?.trim().isNotEmpty == true
? ApiConfig.absoluteMediaUrl(dossier.photoUrl)
final raw = dossier.photoUrl?.trim();
_photoUrlForApi = raw != null && raw.isNotEmpty ? raw : null;
_photoUrl = _photoUrlForApi != null
? ApiConfig.absoluteMediaUrl(_photoUrlForApi)
: null;
}
@@ -37,22 +45,15 @@ class RepriseSession {
_token = null;
_role = null;
_photoUrl = null;
_photoUrlForApi = null;
}
static void applyToParent(UserRegistrationData data, RepriseDossier dossier) {
data.resetForReprise(
firstName: dossier.prenom ?? '',
lastName: dossier.nom ?? '',
phone: dossier.telephone ?? '',
email: dossier.email,
address: dossier.adresse ?? '',
postalCode: dossier.codePostal ?? '',
city: dossier.ville ?? '',
);
RepriseMapper.applyParentDossier(data, dossier);
}
static void applyToAm(AmRegistrationData data, RepriseDossier dossier) {
final photo = _photoUrl;
final displayPhoto = _photoUrl;
data.resetForReprise(
firstName: dossier.prenom ?? '',
lastName: dossier.nom ?? '',
@@ -61,7 +62,17 @@ class RepriseSession {
streetAddress: dossier.adresse ?? '',
postalCode: dossier.codePostal ?? '',
city: dossier.ville ?? '',
existingPhotoUrl: photo,
existingPhotoUrl: displayPhoto,
consentementPhoto: dossier.consentementPhoto ?? false,
dateOfBirth: RepriseMapper.parseIsoDate(dossier.dateNaissance),
birthCity: dossier.lieuNaissanceVille ?? '',
birthCountry: dossier.lieuNaissancePays ?? '',
nir: dossier.nir ?? '',
agrementNumber: dossier.numeroAgrement ?? '',
agreementDate: RepriseMapper.parseIsoDate(dossier.dateAgrement),
capacity: dossier.nbMaxEnfants,
placesAvailable: dossier.placeDisponible,
presentationText: dossier.biographie ?? '',
);
}
}