petitspas/frontend/lib/utils/date_display_utils.dart
Julien Martin 966f4a9c9c feat(#140): liste enfants unifiée — cartes, âge précis et cadre scrollable
Partage AdminEnfantUserCard entre fiche parent et onglet Enfants, enrichit ParentChildSummary (photo, dates) et compacte la modale parent.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-24 23:06:38 +02:00

80 lines
2.3 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';
/// 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();
}
}
/// Parties d'âge calendaire entre [birth] et [reference] (date-only).
({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') {
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)}';
}
}