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
@@ -1,6 +1,7 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:p_tits_pas/models/relais_model.dart';
import 'package:p_tits_pas/utils/phone_utils.dart';
import 'package:p_tits_pas/services/relais_service.dart';
class RelaisManagementPanel extends StatefulWidget {
@@ -723,7 +724,7 @@ class _RelaisFormDialogState extends State<_RelaisFormDialog> {
inputFormatters: [
FilteringTextInputFormatter.digitsOnly,
LengthLimitingTextInputFormatter(10),
_FrenchPhoneNumberFormatter(),
FrenchPhoneNumberFormatter(),
],
decoration: const InputDecoration(
labelText: 'Ligne fixe',
@@ -991,30 +992,6 @@ class _RelaisFormDialogState extends State<_RelaisFormDialog> {
}
}
class _FrenchPhoneNumberFormatter extends TextInputFormatter {
@override
TextEditingValue formatEditUpdate(
TextEditingValue oldValue,
TextEditingValue newValue,
) {
final digits = newValue.text.replaceAll(RegExp(r'\D'), '');
final buffer = StringBuffer();
for (var i = 0; i < digits.length; i++) {
if (i > 0 && i.isEven) {
buffer.write(' ');
}
buffer.write(digits[i]);
}
final formatted = buffer.toString();
return TextEditingValue(
text: formatted,
selection: TextSelection.collapsed(offset: formatted.length),
);
}
}
class _RelaisAddressFields extends StatelessWidget {
final TextEditingController streetController;
final TextEditingController postalCodeController;