petitspas/frontend/lib/utils/date_display_utils.dart
Julien Martin 003fe6b762 feat(#131): fiches parent/AM éditable, placement AM↔enfant, statuts garde/sans_garde
Squash merge develop → master.

- Fiche parent éditable (co-parent, PATCH fiche, GET /parents)
- Fiche AM 3 onglets (PATCH fiche, rattacher/détacher enfants)
- Table enfants_assistantes_maternelles + enum garde/sans_garde
- Migration SQL + BDD.sql canonique
- Correctifs recette : @Get() parents, DTO fiche AM, fix NIR

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-11 22:49:57 +02:00

99 lines
2.8 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import 'package:intl/intl.dart';
import 'package:p_tits_pas/utils/enfant_status_utils.dart';
/// Affiche une date ISO / parseable en `dd/MM/yyyy`, avec repli sur la chaîne ou [ifEmpty].
String formatIsoDateFr(String? s, {String ifEmpty = ''}) {
if (s == null || s.trim().isEmpty) return ifEmpty;
try {
return DateFormat('dd/MM/yyyy').format(DateTime.parse(s.trim()));
} catch (_) {
return s.trim();
}
}
/// Convertit `dd/MM/yyyy` (ou ISO) en `yyyy-MM-dd` pour l'API.
String? parseFrDateToIso(String text) {
final t = text.trim();
if (t.isEmpty) return null;
try {
return DateFormat('dd/MM/yyyy')
.parseStrict(t)
.toIso8601String()
.split('T')
.first;
} catch (_) {
try {
return DateTime.parse(t).toIso8601String().split('T').first;
} catch (_) {
return null;
}
}
}
({int years, int months, int days}) computeChildAgeParts(
DateTime birth,
DateTime reference,
) {
final birthDay = DateTime(birth.year, birth.month, birth.day);
final refDay = DateTime(reference.year, reference.month, reference.day);
var years = refDay.year - birthDay.year;
var months = refDay.month - birthDay.month;
var days = refDay.day - birthDay.day;
if (days < 0) {
months--;
final prevMonth = DateTime(refDay.year, refDay.month, 0);
days += prevMonth.day;
}
if (months < 0) {
years--;
months += 12;
}
return (years: years, months: months, days: days);
}
String _yearLabel(int years) => years == 1 ? '1 an' : '$years ans';
String _monthLabel(int months) => months == 1 ? '1 mois' : '$months mois';
/// Libellé d'âge pour un enfant (liste admin, fiche parent, etc.).
String formatChildAgeLabel({
String? birthDate,
String? dueDate,
String? status,
}) {
if (status == 'a_naitre' || normalizeEnfantStatus(status) == 'a_naitre') {
final due = formatIsoDateFr(dueDate, ifEmpty: '');
if (due.isNotEmpty) return 'Naissance prévue : $due';
return 'À naître';
}
if (birthDate == null || birthDate.trim().isEmpty) return '';
try {
final birth = DateTime.parse(birthDate.trim().split('T').first);
final now = DateTime.now();
final parts = computeChildAgeParts(birth, now);
if (parts.years >= 1) {
if (parts.months > 0) {
return 'Âge : ${_yearLabel(parts.years)} ${parts.months} mois';
}
return 'Âge : ${_yearLabel(parts.years)}';
}
if (parts.months >= 1) {
return 'Âge : ${_monthLabel(parts.months)}';
}
final totalDays = DateTime(now.year, now.month, now.day)
.difference(DateTime(birth.year, birth.month, birth.day))
.inDays;
if (totalDays <= 0) return 'Âge : né récemment';
return 'Âge : $totalDays jour${totalDays > 1 ? 's' : ''}';
} catch (_) {
return 'Né le ${formatIsoDateFr(birthDate)}';
}
}