Compare commits
No commits in common. "faa50f637c9bf503e46dec898dd906b733fcf90f" and "77d952a6f74a21b7fdf76116afdf6588a825e0c4" have entirely different histories.
faa50f637c
...
77d952a6f7
@ -37,34 +37,6 @@ class EnfantAdminModel {
|
|||||||
return '$fn $ln';
|
return '$fn $ln';
|
||||||
}
|
}
|
||||||
|
|
||||||
EnfantAdminModel copyWith({
|
|
||||||
String? id,
|
|
||||||
String? firstName,
|
|
||||||
String? lastName,
|
|
||||||
String? gender,
|
|
||||||
String? birthDate,
|
|
||||||
String? dueDate,
|
|
||||||
String? status,
|
|
||||||
String? photoUrl,
|
|
||||||
bool? consentPhoto,
|
|
||||||
bool? isMultiple,
|
|
||||||
List<EnfantParentLink>? parentLinks,
|
|
||||||
}) {
|
|
||||||
return EnfantAdminModel(
|
|
||||||
id: id ?? this.id,
|
|
||||||
firstName: firstName ?? this.firstName,
|
|
||||||
lastName: lastName ?? this.lastName,
|
|
||||||
gender: gender ?? this.gender,
|
|
||||||
birthDate: birthDate ?? this.birthDate,
|
|
||||||
dueDate: dueDate ?? this.dueDate,
|
|
||||||
status: status ?? this.status,
|
|
||||||
photoUrl: photoUrl ?? this.photoUrl,
|
|
||||||
consentPhoto: consentPhoto ?? this.consentPhoto,
|
|
||||||
isMultiple: isMultiple ?? this.isMultiple,
|
|
||||||
parentLinks: parentLinks ?? this.parentLinks,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
factory EnfantAdminModel.fromJson(Map<String, dynamic> json) {
|
factory EnfantAdminModel.fromJson(Map<String, dynamic> json) {
|
||||||
final linksRaw = json['parentLinks'] as List?;
|
final linksRaw = json['parentLinks'] as List?;
|
||||||
final links = <EnfantParentLink>[];
|
final links = <EnfantParentLink>[];
|
||||||
@ -76,25 +48,17 @@ class EnfantAdminModel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final photoUrl = json['photo_url'] as String? ?? json['photoUrl'] as String?;
|
|
||||||
final consentPhoto = _parseBool(json['consent_photo']) ||
|
|
||||||
_parseBool(json['consentement_photo']) ||
|
|
||||||
_parseBool(json['consentPhoto']);
|
|
||||||
|
|
||||||
return EnfantAdminModel(
|
return EnfantAdminModel(
|
||||||
id: (json['id'] ?? '').toString(),
|
id: (json['id'] ?? '').toString(),
|
||||||
firstName: json['first_name'] as String? ?? json['prenom'] as String?,
|
firstName: json['first_name'] as String?,
|
||||||
lastName: json['last_name'] as String? ?? json['nom'] as String?,
|
lastName: json['last_name'] as String?,
|
||||||
gender: json['gender'] as String? ?? json['genre'] as String?,
|
gender: json['gender'] as String?,
|
||||||
birthDate: _dateString(json['birth_date'] ?? json['date_naissance']),
|
birthDate: _dateString(json['birth_date']),
|
||||||
dueDate: _dateString(json['due_date'] ?? json['date_prevue_naissance']),
|
dueDate: _dateString(json['due_date']),
|
||||||
status: normalizeEnfantStatus(
|
status: normalizeEnfantStatus(json['status']?.toString()),
|
||||||
(json['status'] ?? json['statut'])?.toString(),
|
photoUrl: json['photo_url'] as String?,
|
||||||
),
|
consentPhoto: json['consent_photo'] == true,
|
||||||
photoUrl: photoUrl,
|
isMultiple: json['is_multiple'] == true,
|
||||||
consentPhoto: consentPhoto,
|
|
||||||
isMultiple: _parseBool(json['is_multiple']) ||
|
|
||||||
_parseBool(json['est_multiple']),
|
|
||||||
parentLinks: links,
|
parentLinks: links,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -112,15 +76,6 @@ class EnfantAdminModel {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool _parseBool(dynamic value) {
|
|
||||||
if (value == true || value == 1) return true;
|
|
||||||
if (value is String) {
|
|
||||||
final s = value.trim().toLowerCase();
|
|
||||||
return s == 'true' || s == '1' || s == 't' || s == 'yes';
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static String? _dateString(dynamic v) {
|
static String? _dateString(dynamic v) {
|
||||||
if (v == null) return null;
|
if (v == null) return null;
|
||||||
if (v is String) return v.split('T').first;
|
if (v is String) return v.split('T').first;
|
||||||
@ -134,13 +89,6 @@ class EnfantParentLink {
|
|||||||
|
|
||||||
EnfantParentLink({required this.parentId, this.parentName});
|
EnfantParentLink({required this.parentId, this.parentName});
|
||||||
|
|
||||||
EnfantParentLink copyWith({String? parentId, String? parentName}) {
|
|
||||||
return EnfantParentLink(
|
|
||||||
parentId: parentId ?? this.parentId,
|
|
||||||
parentName: parentName ?? this.parentName,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
factory EnfantParentLink.fromJson(Map<String, dynamic> json) {
|
factory EnfantParentLink.fromJson(Map<String, dynamic> json) {
|
||||||
final parentId =
|
final parentId =
|
||||||
(json['parentId'] ?? json['id_parent'] ?? '').toString();
|
(json['parentId'] ?? json['id_parent'] ?? '').toString();
|
||||||
@ -151,12 +99,6 @@ class EnfantParentLink {
|
|||||||
if (user is Map<String, dynamic>) {
|
if (user is Map<String, dynamic>) {
|
||||||
final u = AppUser.fromJson(user);
|
final u = AppUser.fromJson(user);
|
||||||
name = u.fullName.isNotEmpty ? u.fullName : u.email;
|
name = u.fullName.isNotEmpty ? u.fullName : u.email;
|
||||||
} else {
|
|
||||||
// Parfois le parent est aplati (prenom/nom) sans nested user.
|
|
||||||
final prenom = (parent['prenom'] ?? parent['first_name'] ?? '').toString().trim();
|
|
||||||
final nom = (parent['nom'] ?? parent['last_name'] ?? '').toString().trim();
|
|
||||||
final flat = '$prenom $nom'.trim();
|
|
||||||
if (flat.isNotEmpty) name = flat;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return EnfantParentLink(
|
return EnfantParentLink(
|
||||||
|
|||||||
@ -460,40 +460,7 @@ class UserService {
|
|||||||
if (response.statusCode != 200) {
|
if (response.statusCode != 200) {
|
||||||
throw Exception(_extractErrorMessage(response.body, 'Erreur chargement enfant'));
|
throw Exception(_extractErrorMessage(response.body, 'Erreur chargement enfant'));
|
||||||
}
|
}
|
||||||
final enfant = EnfantAdminModel.fromJson(
|
return EnfantAdminModel.fromJson(jsonDecode(response.body) as Map<String, dynamic>);
|
||||||
jsonDecode(response.body) as Map<String, dynamic>,
|
|
||||||
);
|
|
||||||
// GET /enfants/:id ne joint pas toujours parent.user → noms manquants.
|
|
||||||
return enrichEnfantParentNames(enfant);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Complète [parentName] via GET parent quand l'API n'a pas fourni le nested user.
|
|
||||||
static Future<EnfantAdminModel> enrichEnfantParentNames(
|
|
||||||
EnfantAdminModel enfant,
|
|
||||||
) async {
|
|
||||||
final links = enfant.parentLinks;
|
|
||||||
if (links.isEmpty) return enfant;
|
|
||||||
if (links.every((l) => (l.parentName ?? '').trim().isNotEmpty)) {
|
|
||||||
return enfant;
|
|
||||||
}
|
|
||||||
|
|
||||||
final enriched = await Future.wait(
|
|
||||||
links.map((link) async {
|
|
||||||
if ((link.parentName ?? '').trim().isNotEmpty) return link;
|
|
||||||
final id = link.parentId.trim();
|
|
||||||
if (id.isEmpty) return link;
|
|
||||||
try {
|
|
||||||
final parent = await getParent(id);
|
|
||||||
final name = parent.user.fullName.trim();
|
|
||||||
if (name.isEmpty) return link;
|
|
||||||
return link.copyWith(parentName: name);
|
|
||||||
} catch (_) {
|
|
||||||
return link;
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
return enfant.copyWith(parentLinks: enriched);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static Future<EnfantAdminModel> updateEnfant({
|
static Future<EnfantAdminModel> updateEnfant({
|
||||||
@ -508,29 +475,7 @@ class UserService {
|
|||||||
if (response.statusCode != 200) {
|
if (response.statusCode != 200) {
|
||||||
throw Exception(_extractErrorMessage(response.body, 'Erreur mise à jour enfant'));
|
throw Exception(_extractErrorMessage(response.body, 'Erreur mise à jour enfant'));
|
||||||
}
|
}
|
||||||
final enfant = EnfantAdminModel.fromJson(
|
return EnfantAdminModel.fromJson(jsonDecode(response.body) as Map<String, dynamic>);
|
||||||
jsonDecode(response.body) as Map<String, dynamic>,
|
|
||||||
);
|
|
||||||
return enrichEnfantParentNames(enfant);
|
|
||||||
}
|
|
||||||
|
|
||||||
static Future<void> deleteEnfant(String enfantId) async {
|
|
||||||
final response = await http.delete(
|
|
||||||
Uri.parse('${ApiConfig.baseUrl}${ApiConfig.enfants}/$enfantId'),
|
|
||||||
headers: await _headers(),
|
|
||||||
);
|
|
||||||
if (response.statusCode != 200 && response.statusCode != 204) {
|
|
||||||
throw Exception(_extractErrorMessage(response.body, 'Erreur suppression enfant'));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// AM dont la liste d'enfants actifs contient [enfantId] (API actuelle).
|
|
||||||
static Future<AssistanteMaternelleModel?> findAmForEnfant(String enfantId) async {
|
|
||||||
final ams = await getAssistantesMaternelles();
|
|
||||||
for (final am in ams) {
|
|
||||||
if (am.children.any((c) => c.id == enfantId)) return am;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static ParentModel _parentModelFromBody(String body) {
|
static ParentModel _parentModelFromBody(String body) {
|
||||||
|
|||||||
@ -14,10 +14,10 @@ String normalizeEnfantStatus(String? raw) {
|
|||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
String _accordeAuGenre(String masculin, String feminin, String? gender) {
|
String _scolariseAccordeAuGenre(String? gender) {
|
||||||
final g = (gender ?? '').trim().toUpperCase();
|
final g = (gender ?? '').trim().toUpperCase();
|
||||||
if (g == 'F') return feminin;
|
if (g == 'F') return 'Scolarisée';
|
||||||
return masculin;
|
return 'Scolarisé';
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Libellé affiché pour un statut enfant.
|
/// Libellé affiché pour un statut enfant.
|
||||||
@ -28,9 +28,9 @@ String enfantStatusLabel(String? status, {String? gender}) {
|
|||||||
case 'sans_garde':
|
case 'sans_garde':
|
||||||
return 'Sans garde';
|
return 'Sans garde';
|
||||||
case 'garde':
|
case 'garde':
|
||||||
return _accordeAuGenre('Gardé', 'Gardée', gender);
|
return 'En garde';
|
||||||
case 'scolarise':
|
case 'scolarise':
|
||||||
return _accordeAuGenre('Scolarisé', 'Scolarisée', gender);
|
return _scolariseAccordeAuGenre(gender);
|
||||||
default:
|
default:
|
||||||
return status?.trim().isNotEmpty == true ? status!.trim() : '–';
|
return status?.trim().isNotEmpty == true ? status!.trim() : '–';
|
||||||
}
|
}
|
||||||
|
|||||||
@ -38,12 +38,15 @@ class RepriseMapper {
|
|||||||
? isoToDdMmYyyy(e.dueDate)
|
? isoToDdMmYyyy(e.dueDate)
|
||||||
: isoToDdMmYyyy(e.birthDate);
|
: isoToDdMmYyyy(e.birthDate);
|
||||||
final photo = e.photoUrl?.trim();
|
final photo = e.photoUrl?.trim();
|
||||||
|
final hasPhoto = photo != null && photo.isNotEmpty;
|
||||||
return ChildData(
|
return ChildData(
|
||||||
firstName: e.firstName ?? '',
|
firstName: e.firstName ?? '',
|
||||||
lastName: e.lastName ?? '',
|
lastName: e.lastName ?? '',
|
||||||
dob: dob,
|
dob: dob,
|
||||||
genre: e.gender ?? '',
|
genre: e.gender ?? '',
|
||||||
photoConsent: e.consentPhoto,
|
// Legacy : dossiers inscrits avant #144 avaient consent_photo=false malgré une photo.
|
||||||
|
// On pré-coche encore si photo en base pour ne pas bloquer la reprise.
|
||||||
|
photoConsent: e.consentPhoto || hasPhoto,
|
||||||
multipleBirth: e.estMultiple,
|
multipleBirth: e.estMultiple,
|
||||||
isUnbornChild: isUnborn,
|
isUnbornChild: isUnborn,
|
||||||
cardColor: _childCardColors[index % _childCardColors.length],
|
cardColor: _childCardColors[index % _childCardColors.length],
|
||||||
@ -197,7 +200,7 @@ class RepriseMapper {
|
|||||||
postalCode: dossier.codePostal ?? '',
|
postalCode: dossier.codePostal ?? '',
|
||||||
city: dossier.ville ?? '',
|
city: dossier.ville ?? '',
|
||||||
existingPhotoUrl: displayPhoto,
|
existingPhotoUrl: displayPhoto,
|
||||||
consentementPhoto: dossier.consentementPhoto,
|
consentementPhoto: dossier.consentementPhoto || hasPhoto,
|
||||||
dateOfBirth: parseIsoDate(dossier.dateNaissance),
|
dateOfBirth: parseIsoDate(dossier.dateNaissance),
|
||||||
birthCity: dossier.lieuNaissanceVille ?? '',
|
birthCity: dossier.lieuNaissanceVille ?? '',
|
||||||
birthCountry: dossier.lieuNaissancePays ?? '',
|
birthCountry: dossier.lieuNaissancePays ?? '',
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -64,7 +64,6 @@ class AdminChildrenAffiliationPanel extends StatelessWidget {
|
|||||||
final c = children[i];
|
final c = children[i];
|
||||||
return AdminEnfantUserCard.fromSummary(
|
return AdminEnfantUserCard.fromSummary(
|
||||||
c,
|
c,
|
||||||
onCardTap: () => onOpen(c),
|
|
||||||
actions: [
|
actions: [
|
||||||
IconButton(
|
IconButton(
|
||||||
icon: const Icon(Icons.visibility_outlined),
|
icon: const Icon(Icons.visibility_outlined),
|
||||||
|
|||||||
@ -14,7 +14,6 @@ class AdminUserCard extends StatefulWidget {
|
|||||||
final Color? infoColor;
|
final Color? infoColor;
|
||||||
final String? vigilanceTooltip;
|
final String? vigilanceTooltip;
|
||||||
final VoidCallback? onCardTap;
|
final VoidCallback? onCardTap;
|
||||||
final EdgeInsetsGeometry? margin;
|
|
||||||
|
|
||||||
const AdminUserCard({
|
const AdminUserCard({
|
||||||
super.key,
|
super.key,
|
||||||
@ -29,7 +28,6 @@ class AdminUserCard extends StatefulWidget {
|
|||||||
this.infoColor,
|
this.infoColor,
|
||||||
this.vigilanceTooltip,
|
this.vigilanceTooltip,
|
||||||
this.onCardTap,
|
this.onCardTap,
|
||||||
this.margin,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -61,7 +59,7 @@ class _AdminUserCardState extends State<AdminUserCard> {
|
|||||||
borderRadius: BorderRadius.circular(10),
|
borderRadius: BorderRadius.circular(10),
|
||||||
hoverColor: const Color(0x149CC5C0),
|
hoverColor: const Color(0x149CC5C0),
|
||||||
child: Card(
|
child: Card(
|
||||||
margin: widget.margin ?? const EdgeInsets.only(bottom: 12),
|
margin: const EdgeInsets.only(bottom: 12),
|
||||||
elevation: 0,
|
elevation: 0,
|
||||||
color: widget.backgroundColor,
|
color: widget.backgroundColor,
|
||||||
shape: RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(
|
||||||
|
|||||||
@ -215,7 +215,7 @@ class _UserManagementPanelState extends State<UserManagementPanel> {
|
|||||||
value: 'garde',
|
value: 'garde',
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: EdgeInsets.only(left: 10),
|
padding: EdgeInsets.only(left: 10),
|
||||||
child: Text('Gardé', style: TextStyle(fontSize: 12)),
|
child: Text('En garde', style: TextStyle(fontSize: 12)),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
DropdownMenuItem<String?>(
|
DropdownMenuItem<String?>(
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user