feat(admin): onglet À valider, dossier unifié et modales de validation

- Onglet « À valider » (AM + familles), pending-families et détail dossier par numéro.
- Wizards validation AM et famille, modale commune, chargement via GET /dossiers/:num.
- UI : cartes enfants, photo AM (cadre uniforme, ratio), NIR affiché formaté (espaces autour du tiret).
- Backend : DTO / routes parents pending ; scripts de test et mise à jour issue Gitea.

Tickets #107, #119.

Made-with: Cursor
This commit is contained in:
2026-03-26 00:15:18 +01:00
parent d832559027
commit 2e02f60601
36 changed files with 3303 additions and 173 deletions
+34 -22
View File
@@ -15,6 +15,7 @@ class AppUser {
final String? codePostal;
final String? relaisId;
final String? relaisNom;
final String? numeroDossier;
AppUser({
required this.id,
@@ -33,40 +34,50 @@ class AppUser {
this.codePostal,
this.relaisId,
this.relaisNom,
this.numeroDossier,
});
static String _str(dynamic v) {
if (v == null) return '';
if (v is String) return v;
return v.toString();
}
static DateTime _date(dynamic v) {
if (v == null) return DateTime.now();
if (v is DateTime) return v;
try {
return DateTime.parse(v.toString());
} catch (_) {
return DateTime.now();
}
}
factory AppUser.fromJson(Map<String, dynamic> json) {
final relaisJson = json['relais'];
final relaisMap =
relaisJson is Map<String, dynamic> ? relaisJson : <String, dynamic>{};
return AppUser(
id: (json['id'] as String?) ?? '',
email: (json['email'] as String?) ?? '',
role: (json['role'] as String?) ?? '',
createdAt: json['cree_le'] != null
? DateTime.parse(json['cree_le'] as String)
: (json['createdAt'] != null
? DateTime.parse(json['createdAt'] as String)
: DateTime.now()),
updatedAt: json['modifie_le'] != null
? DateTime.parse(json['modifie_le'] as String)
: (json['updatedAt'] != null
? DateTime.parse(json['updatedAt'] as String)
: DateTime.now()),
id: _str(json['id']),
email: _str(json['email']),
role: _str(json['role']),
createdAt: _date(json['cree_le'] ?? json['createdAt']),
updatedAt: _date(json['modifie_le'] ?? json['updatedAt']),
changementMdpObligatoire:
json['changement_mdp_obligatoire'] as bool? ?? false,
nom: json['nom'] as String?,
prenom: json['prenom'] as String?,
statut: json['statut'] as String?,
telephone: json['telephone'] as String?,
photoUrl: json['photo_url'] as String?,
adresse: json['adresse'] as String?,
ville: json['ville'] as String?,
codePostal: json['code_postal'] as String?,
json['changement_mdp_obligatoire'] == true,
nom: json['nom'] is String ? json['nom'] as String : null,
prenom: json['prenom'] is String ? json['prenom'] as String : null,
statut: json['statut'] is String ? json['statut'] as String : null,
telephone: json['telephone'] is String ? json['telephone'] as String : null,
photoUrl: json['photo_url'] is String ? json['photo_url'] as String : null,
adresse: json['adresse'] is String ? json['adresse'] as String : null,
ville: json['ville'] is String ? json['ville'] as String : null,
codePostal: json['code_postal'] is String ? json['code_postal'] as String : null,
relaisId: (json['relaisId'] ?? json['relais_id'] ?? relaisMap['id'])
?.toString(),
relaisNom: relaisMap['nom']?.toString(),
numeroDossier: json['numero_dossier'] is String ? json['numero_dossier'] as String : null,
);
}
@@ -88,6 +99,7 @@ class AppUser {
'code_postal': codePostal,
'relais_id': relaisId,
'relais_nom': relaisNom,
'numero_dossier': numeroDossier,
};
}