feat: alignement master sur develop (squash)

- Dossiers unifiés #119, pending-families enrichi, validation admin (wizards)
- Front: modèles dossier_unifie / pending_family, NIR, auth
- Migrations dossier_famille, scripts de test API
- Résolution conflits: parents.*, docs tickets, auth_service, nir_utils

Made-with: Cursor
This commit is contained in:
2026-03-26 00:20:47 +01:00
parent 060e610a75
commit cde676c4f9
49 changed files with 3934 additions and 222 deletions
@@ -1,5 +1,7 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:p_tits_pas/utils/phone_utils.dart';
import 'package:go_router/go_router.dart';
import 'dart:math' as math;
@@ -92,7 +94,7 @@ class _PersonalInfoFormScreenState extends State<PersonalInfoFormScreen> {
super.initState();
_lastNameController = TextEditingController(text: widget.initialData.lastName);
_firstNameController = TextEditingController(text: widget.initialData.firstName);
_phoneController = TextEditingController(text: widget.initialData.phone);
_phoneController = TextEditingController(text: formatPhoneForDisplay(widget.initialData.phone));
_emailController = TextEditingController(text: widget.initialData.email);
_addressController = TextEditingController(text: widget.initialData.address);
_postalCodeController = TextEditingController(text: widget.initialData.postalCode);
@@ -134,7 +136,7 @@ class _PersonalInfoFormScreenState extends State<PersonalInfoFormScreen> {
final data = PersonalInfoData(
firstName: _firstNameController.text,
lastName: _lastNameController.text,
phone: _phoneController.text,
phone: normalizePhone(_phoneController.text),
email: _emailController.text,
address: _addressController.text,
postalCode: _postalCodeController.text,
@@ -631,6 +633,7 @@ class _PersonalInfoFormScreenState extends State<PersonalInfoFormScreen> {
hint: 'Votre numéro de téléphone',
keyboardType: TextInputType.phone,
enabled: _fieldsEnabled,
inputFormatters: _phoneInputFormatters,
),
),
const SizedBox(width: 20),
@@ -732,7 +735,9 @@ class _PersonalInfoFormScreenState extends State<PersonalInfoFormScreen> {
child: _buildDisplayFieldValue(
context,
'Téléphone :',
_phoneController.text,
_phoneController.text.trim().isNotEmpty
? formatPhoneForDisplay(_phoneController.text)
: _phoneController.text,
labelFontSize: labelFontSize,
valueFontSize: valueFontSize,
),
@@ -868,6 +873,7 @@ class _PersonalInfoFormScreenState extends State<PersonalInfoFormScreen> {
hint: 'Votre numéro de téléphone',
keyboardType: TextInputType.phone,
enabled: _fieldsEnabled,
inputFormatters: _phoneInputFormatters,
),
const SizedBox(height: 12),
@@ -923,13 +929,17 @@ class _PersonalInfoFormScreenState extends State<PersonalInfoFormScreen> {
String? hint,
TextInputType? keyboardType,
bool enabled = true,
List<TextInputFormatter>? inputFormatters,
}) {
if (config.isReadonly) {
// Mode readonly : utiliser FormFieldWrapper
// Mode readonly : utiliser FormFieldWrapper (téléphone formaté pour affichage)
final displayValue = label == 'Téléphone' && controller.text.trim().isNotEmpty
? formatPhoneForDisplay(controller.text)
: controller.text;
return FormFieldWrapper(
config: config,
label: label,
value: controller.text,
value: displayValue,
);
} else {
// Mode éditable : style adapté mobile/desktop
@@ -944,10 +954,17 @@ class _PersonalInfoFormScreenState extends State<PersonalInfoFormScreen> {
inputFontSize: config.isMobile ? 14.0 : 20.0,
keyboardType: keyboardType ?? TextInputType.text,
enabled: enabled,
inputFormatters: inputFormatters,
);
}
}
static final _phoneInputFormatters = [
FilteringTextInputFormatter.digitsOnly,
LengthLimitingTextInputFormatter(10),
FrenchPhoneNumberFormatter(),
];
/// Retourne l'asset de carte vertical correspondant à la couleur
String _getVerticalCardAsset() {
switch (widget.cardColor) {