fix(#112): préremplissage AM complet en reprise + lien login repositionné
Parse dates/places/consentement de façon robuste, rafraîchit l'étape 2 AM et place « J'ai un numéro de dossier » sous « Créer un compte ». Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
9d54d9b19b
commit
c26ed00374
@ -1,4 +1,5 @@
|
|||||||
import 'package:p_tits_pas/models/dossier_unifie.dart';
|
import 'package:p_tits_pas/models/dossier_unifie.dart';
|
||||||
|
import 'package:p_tits_pas/utils/reprise_mapper.dart';
|
||||||
|
|
||||||
/// Réponse GET /auth/reprise-dossier. Tickets #111, #112.
|
/// Réponse GET /auth/reprise-dossier. Tickets #111, #112.
|
||||||
class RepriseDossier {
|
class RepriseDossier {
|
||||||
@ -20,7 +21,7 @@ class RepriseDossier {
|
|||||||
final List<EnfantDossier> enfants;
|
final List<EnfantDossier> enfants;
|
||||||
final String? texteMotivation;
|
final String? texteMotivation;
|
||||||
|
|
||||||
final bool? consentementPhoto;
|
final bool consentementPhoto;
|
||||||
final String? dateNaissance;
|
final String? dateNaissance;
|
||||||
final String? lieuNaissanceVille;
|
final String? lieuNaissanceVille;
|
||||||
final String? lieuNaissancePays;
|
final String? lieuNaissancePays;
|
||||||
@ -48,7 +49,7 @@ class RepriseDossier {
|
|||||||
this.parents = const [],
|
this.parents = const [],
|
||||||
this.enfants = const [],
|
this.enfants = const [],
|
||||||
this.texteMotivation,
|
this.texteMotivation,
|
||||||
this.consentementPhoto,
|
this.consentementPhoto = false,
|
||||||
this.dateNaissance,
|
this.dateNaissance,
|
||||||
this.lieuNaissanceVille,
|
this.lieuNaissanceVille,
|
||||||
this.lieuNaissancePays,
|
this.lieuNaissancePays,
|
||||||
@ -80,9 +81,6 @@ class RepriseDossier {
|
|||||||
.toList()
|
.toList()
|
||||||
: <EnfantDossier>[];
|
: <EnfantDossier>[];
|
||||||
|
|
||||||
final nbMax = json['nb_max_enfants'];
|
|
||||||
final places = json['place_disponible'];
|
|
||||||
|
|
||||||
return RepriseDossier(
|
return RepriseDossier(
|
||||||
id: json['id']?.toString() ?? '',
|
id: json['id']?.toString() ?? '',
|
||||||
email: json['email']?.toString() ?? '',
|
email: json['email']?.toString() ?? '',
|
||||||
@ -101,17 +99,22 @@ class RepriseDossier {
|
|||||||
enfants: enfantsList,
|
enfants: enfantsList,
|
||||||
texteMotivation: (json['texte_motivation'] ?? json['presentation_dossier'])
|
texteMotivation: (json['texte_motivation'] ?? json['presentation_dossier'])
|
||||||
?.toString(),
|
?.toString(),
|
||||||
consentementPhoto: json['consentement_photo'] == true,
|
consentementPhoto: RepriseMapper.optionalBool(json['consentement_photo']) ||
|
||||||
dateNaissance: json['date_naissance']?.toString(),
|
RepriseMapper.optionalBool(json['consent_photo']),
|
||||||
|
dateNaissance: RepriseMapper.optionalDateString(json['date_naissance']),
|
||||||
lieuNaissanceVille: json['lieu_naissance_ville']?.toString(),
|
lieuNaissanceVille: json['lieu_naissance_ville']?.toString(),
|
||||||
lieuNaissancePays: json['lieu_naissance_pays']?.toString(),
|
lieuNaissancePays: json['lieu_naissance_pays']?.toString(),
|
||||||
numeroAgrement: json['numero_agrement']?.toString(),
|
numeroAgrement: (json['numero_agrement'] ?? json['numero_agrement_am'])
|
||||||
|
?.toString(),
|
||||||
nir: json['nir']?.toString(),
|
nir: json['nir']?.toString(),
|
||||||
dateAgrement: json['date_agrement']?.toString(),
|
dateAgrement: RepriseMapper.optionalDateString(json['date_agrement']),
|
||||||
nbMaxEnfants: nbMax is int ? nbMax : (nbMax is num ? nbMax.toInt() : null),
|
nbMaxEnfants: RepriseMapper.optionalInt(
|
||||||
placeDisponible:
|
json['nb_max_enfants'] ?? json['capacite_accueil'],
|
||||||
places is int ? places : (places is num ? places.toInt() : null),
|
),
|
||||||
biographie: json['biographie']?.toString(),
|
placeDisponible: RepriseMapper.optionalInt(
|
||||||
|
json['place_disponible'] ?? json['places_disponibles'],
|
||||||
|
),
|
||||||
|
biographie: (json['biographie'] ?? json['presentation'])?.toString(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -29,6 +29,12 @@ class AmRegisterStep2Screen extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
|
|
||||||
return ProfessionalInfoFormScreen(
|
return ProfessionalInfoFormScreen(
|
||||||
|
key: ValueKey(
|
||||||
|
'am-pro-${registrationData.dateOfBirth?.millisecondsSinceEpoch}'
|
||||||
|
'-${registrationData.agreementDate?.millisecondsSinceEpoch}'
|
||||||
|
'-${registrationData.placesAvailable}'
|
||||||
|
'-${registrationData.nir}',
|
||||||
|
),
|
||||||
stepText: 'Étape 2/4',
|
stepText: 'Étape 2/4',
|
||||||
title: 'Vos informations professionnelles',
|
title: 'Vos informations professionnelles',
|
||||||
cardColor: CardColorHorizontal.green,
|
cardColor: CardColorHorizontal.green,
|
||||||
|
|||||||
@ -377,8 +377,6 @@ class _LoginPageState extends State<LoginScreen> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 10),
|
const SizedBox(height: 10),
|
||||||
Center(child: _buildRepriseDossierLink()),
|
|
||||||
const SizedBox(height: 10),
|
|
||||||
// Lien mot de passe oublié
|
// Lien mot de passe oublié
|
||||||
Center(
|
Center(
|
||||||
child: TextButton(
|
child: TextButton(
|
||||||
@ -412,6 +410,7 @@ class _LoginPageState extends State<LoginScreen> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
Center(child: _buildRepriseDossierLink()),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -645,7 +644,6 @@ class _LoginPageState extends State<LoginScreen> {
|
|||||||
onPressed: _handleLogin,
|
onPressed: _handleLogin,
|
||||||
),
|
),
|
||||||
const SizedBox(height: 12),
|
const SizedBox(height: 12),
|
||||||
_buildRepriseDossierLink(),
|
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () => context.go('/forgot-password'),
|
onPressed: () => context.go('/forgot-password'),
|
||||||
child: Text(
|
child: Text(
|
||||||
@ -669,6 +667,7 @@ class _LoginPageState extends State<LoginScreen> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
_buildRepriseDossierLink(),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@ -53,26 +53,6 @@ class RepriseSession {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void applyToAm(AmRegistrationData data, RepriseDossier dossier) {
|
static void applyToAm(AmRegistrationData data, RepriseDossier dossier) {
|
||||||
final displayPhoto = _photoUrl;
|
RepriseMapper.applyAmDossier(data, dossier);
|
||||||
data.resetForReprise(
|
|
||||||
firstName: dossier.prenom ?? '',
|
|
||||||
lastName: dossier.nom ?? '',
|
|
||||||
phone: dossier.telephone ?? '',
|
|
||||||
email: dossier.email,
|
|
||||||
streetAddress: dossier.adresse ?? '',
|
|
||||||
postalCode: dossier.codePostal ?? '',
|
|
||||||
city: dossier.ville ?? '',
|
|
||||||
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 ?? '',
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
import 'package:p_tits_pas/models/am_registration_data.dart';
|
||||||
import 'package:p_tits_pas/models/card_assets.dart';
|
import 'package:p_tits_pas/models/card_assets.dart';
|
||||||
import 'package:p_tits_pas/models/dossier_unifie.dart';
|
import 'package:p_tits_pas/models/dossier_unifie.dart';
|
||||||
import 'package:p_tits_pas/models/reprise_dossier.dart';
|
import 'package:p_tits_pas/models/reprise_dossier.dart';
|
||||||
@ -106,13 +107,79 @@ class RepriseMapper {
|
|||||||
|
|
||||||
static DateTime? parseIsoDate(String? raw) {
|
static DateTime? parseIsoDate(String? raw) {
|
||||||
if (raw == null || raw.trim().isEmpty) return null;
|
if (raw == null || raw.trim().isEmpty) return null;
|
||||||
|
final s = raw.trim();
|
||||||
try {
|
try {
|
||||||
return DateTime.parse(raw.trim());
|
return DateTime.parse(s);
|
||||||
} catch (_) {
|
} catch (_) {
|
||||||
|
final parts = s.split('/');
|
||||||
|
if (parts.length == 3) {
|
||||||
|
final day = int.tryParse(parts[0]);
|
||||||
|
final month = int.tryParse(parts[1]);
|
||||||
|
final year = int.tryParse(parts[2]);
|
||||||
|
if (day != null && month != null && year != null) {
|
||||||
|
return DateTime(year, month, day);
|
||||||
|
}
|
||||||
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static String? optionalDateString(dynamic value) {
|
||||||
|
if (value == null) return null;
|
||||||
|
if (value is String) {
|
||||||
|
final s = value.trim();
|
||||||
|
return s.isEmpty ? null : s;
|
||||||
|
}
|
||||||
|
if (value is DateTime) return value.toIso8601String();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int? optionalInt(dynamic value) {
|
||||||
|
if (value == null) return null;
|
||||||
|
if (value is int) return value;
|
||||||
|
if (value is num) return value.toInt();
|
||||||
|
if (value is String) {
|
||||||
|
final s = value.trim();
|
||||||
|
if (s.isEmpty) return null;
|
||||||
|
return int.tryParse(s);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool optionalBool(dynamic value) {
|
||||||
|
if (value == true) return true;
|
||||||
|
if (value is String && value.toLowerCase() == 'true') return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void applyAmDossier(AmRegistrationData data, RepriseDossier dossier) {
|
||||||
|
final rawPhoto = dossier.photoUrl?.trim();
|
||||||
|
final hasPhoto = rawPhoto != null && rawPhoto.isNotEmpty;
|
||||||
|
final displayPhoto =
|
||||||
|
hasPhoto ? ApiConfig.absoluteMediaUrl(rawPhoto) : null;
|
||||||
|
|
||||||
|
data.resetForReprise(
|
||||||
|
firstName: dossier.prenom ?? '',
|
||||||
|
lastName: dossier.nom ?? '',
|
||||||
|
phone: dossier.telephone ?? '',
|
||||||
|
email: dossier.email,
|
||||||
|
streetAddress: dossier.adresse ?? '',
|
||||||
|
postalCode: dossier.codePostal ?? '',
|
||||||
|
city: dossier.ville ?? '',
|
||||||
|
existingPhotoUrl: displayPhoto,
|
||||||
|
consentementPhoto: dossier.consentementPhoto || hasPhoto,
|
||||||
|
dateOfBirth: parseIsoDate(dossier.dateNaissance),
|
||||||
|
birthCity: dossier.lieuNaissanceVille ?? '',
|
||||||
|
birthCountry: dossier.lieuNaissancePays ?? '',
|
||||||
|
nir: dossier.nir ?? '',
|
||||||
|
agrementNumber: dossier.numeroAgrement ?? '',
|
||||||
|
agreementDate: parseIsoDate(dossier.dateAgrement),
|
||||||
|
capacity: dossier.nbMaxEnfants,
|
||||||
|
placesAvailable: dossier.placeDisponible,
|
||||||
|
presentationText: dossier.biographie ?? '',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
static String isoToDdMmYyyy(String? iso) {
|
static String isoToDdMmYyyy(String? iso) {
|
||||||
final dt = parseIsoDate(iso);
|
final dt = parseIsoDate(iso);
|
||||||
if (dt == null) return '';
|
if (dt == null) return '';
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user