114 lines
3.0 KiB
Dart
114 lines
3.0 KiB
Dart
/// Modèles du couple de garde (enfant ↔ AM) — ticket #167.
|
|
/// Contrat backend #168 : GET /parents/me/couples-garde.
|
|
|
|
/// Identité minimale d'une personne du couple (enfant, AM ou parent).
|
|
class CoupleMembre {
|
|
final String id;
|
|
final String? prenom;
|
|
final String? nom;
|
|
final String? photoUrl;
|
|
|
|
const CoupleMembre({
|
|
required this.id,
|
|
this.prenom,
|
|
this.nom,
|
|
this.photoUrl,
|
|
});
|
|
|
|
/// Nom d'affichage : prénom seul si dispo, sinon « Prénom Nom », sinon repli.
|
|
String displayName({String fallback = ''}) {
|
|
final p = (prenom ?? '').trim();
|
|
final n = (nom ?? '').trim();
|
|
if (p.isNotEmpty && n.isNotEmpty) return '$p $n';
|
|
if (p.isNotEmpty) return p;
|
|
if (n.isNotEmpty) return n;
|
|
return fallback;
|
|
}
|
|
|
|
factory CoupleMembre.fromJson(Map<String, dynamic> json) {
|
|
return CoupleMembre(
|
|
id: (json['id'] ?? '').toString(),
|
|
prenom: json['prenom']?.toString(),
|
|
nom: json['nom']?.toString(),
|
|
photoUrl: json['photo_url']?.toString(),
|
|
);
|
|
}
|
|
}
|
|
|
|
/// Un couple de garde = placement actif enfant ↔ AM.
|
|
class CoupleGarde {
|
|
final String id;
|
|
final CoupleMembre enfant;
|
|
final CoupleMembre am;
|
|
final bool courant;
|
|
|
|
const CoupleGarde({
|
|
required this.id,
|
|
required this.enfant,
|
|
required this.am,
|
|
this.courant = false,
|
|
});
|
|
|
|
factory CoupleGarde.fromJson(Map<String, dynamic> json) {
|
|
return CoupleGarde(
|
|
id: (json['id'] ?? '').toString(),
|
|
enfant: CoupleMembre.fromJson(
|
|
Map<String, dynamic>.from(json['enfant'] ?? const {}),
|
|
),
|
|
am: CoupleMembre.fromJson(
|
|
Map<String, dynamic>.from(json['am'] ?? const {}),
|
|
),
|
|
courant: json['courant'] == true,
|
|
);
|
|
}
|
|
|
|
CoupleGarde copyWith({bool? courant}) {
|
|
return CoupleGarde(
|
|
id: id,
|
|
enfant: enfant,
|
|
am: am,
|
|
courant: courant ?? this.courant,
|
|
);
|
|
}
|
|
}
|
|
|
|
/// Réponse de l'API couples de garde (liste + id du couple courant).
|
|
class CouplesGardeResponse {
|
|
final List<CoupleGarde> couples;
|
|
final String? coupleCourantId;
|
|
|
|
const CouplesGardeResponse({
|
|
required this.couples,
|
|
this.coupleCourantId,
|
|
});
|
|
|
|
bool get isEmpty => couples.isEmpty;
|
|
bool get isUnique => couples.length == 1;
|
|
|
|
/// Couple courant : celui marqué `courant`, sinon celui de [coupleCourantId],
|
|
/// sinon le premier (repli implicite côté client, prévu par le back).
|
|
CoupleGarde? get coupleCourant {
|
|
if (couples.isEmpty) return null;
|
|
for (final c in couples) {
|
|
if (c.courant) return c;
|
|
}
|
|
if (coupleCourantId != null) {
|
|
for (final c in couples) {
|
|
if (c.id == coupleCourantId) return c;
|
|
}
|
|
}
|
|
return couples.first;
|
|
}
|
|
|
|
factory CouplesGardeResponse.fromJson(Map<String, dynamic> json) {
|
|
final list = (json['couples'] as List?) ?? const [];
|
|
return CouplesGardeResponse(
|
|
couples: list
|
|
.whereType<Map>()
|
|
.map((e) => CoupleGarde.fromJson(Map<String, dynamic>.from(e)))
|
|
.toList(),
|
|
coupleCourantId: json['couple_courant_id']?.toString(),
|
|
);
|
|
}
|
|
}
|