fix(#129): peaufiner le wizard famille (co-parent, hauteurs, à naître).
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -35,19 +35,23 @@ class ValidationFormMetrics {
|
|||||||
);
|
);
|
||||||
|
|
||||||
static double get sectionTitleBlockHeight =>
|
static double get sectionTitleBlockHeight =>
|
||||||
sectionTitleFontSize + sectionTitleGapBelow;
|
sectionTitleFontSize * 1.25 + sectionTitleGapBelow;
|
||||||
|
|
||||||
|
/// Libellé : marge au-dessus de [fieldLabelFontSize] (métriques police).
|
||||||
static double get labeledRowHeight =>
|
static double get labeledRowHeight =>
|
||||||
fieldLabelFontSize + fieldLabelGapBelow + fieldHeight + rowGapBelow;
|
fieldLabelFontSize * 1.25 +
|
||||||
|
fieldLabelGapBelow +
|
||||||
|
fieldHeight +
|
||||||
|
rowGapBelow;
|
||||||
|
|
||||||
/// Corps modale AM : padding wizard + titre + [rows] lignes + nav.
|
/// Corps modale AM / famille : padding wizard + titre + [rows] lignes + nav.
|
||||||
static double shellBodyHeightForRows(int rows) =>
|
static double shellBodyHeightForRows(int rows) =>
|
||||||
20 * 2 + // padding wizard
|
20 * 2 + // padding wizard
|
||||||
4 + // espace haut
|
4 + // espace haut
|
||||||
sectionTitleBlockHeight +
|
sectionTitleBlockHeight +
|
||||||
rows * labeledRowHeight +
|
rows * labeledRowHeight +
|
||||||
24 + // avant nav
|
24 + // avant nav
|
||||||
44; // boutons
|
48; // boutons (+ marge anti-overflow)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Bloc type formulaire (titre de section + champs read-only) pour les modales de validation.
|
/// Bloc type formulaire (titre de section + champs read-only) pour les modales de validation.
|
||||||
@@ -134,6 +138,7 @@ class ValidationFormGrid extends StatelessWidget {
|
|||||||
label: f.label,
|
label: f.label,
|
||||||
field: f.field,
|
field: f.field,
|
||||||
expand: expandVertically,
|
expand: expandVertically,
|
||||||
|
labelTrailing: f.labelTrailing,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.toList();
|
.toList();
|
||||||
@@ -262,28 +267,37 @@ class ValidationLabeledField extends StatelessWidget {
|
|||||||
final String label;
|
final String label;
|
||||||
final Widget field;
|
final Widget field;
|
||||||
final bool expand;
|
final bool expand;
|
||||||
|
/// Widget aligné à droite sur la ligne du libellé (ex. switch « Même adresse »).
|
||||||
|
final Widget? labelTrailing;
|
||||||
|
|
||||||
const ValidationLabeledField({
|
const ValidationLabeledField({
|
||||||
super.key,
|
super.key,
|
||||||
required this.label,
|
required this.label,
|
||||||
required this.field,
|
required this.field,
|
||||||
this.expand = false,
|
this.expand = false,
|
||||||
|
this.labelTrailing,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
final labelStyle = TextStyle(
|
||||||
|
fontSize: ValidationFormMetrics.fieldLabelFontSize,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
color: Colors.grey.shade700,
|
||||||
|
);
|
||||||
return Column(
|
return Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
mainAxisSize: expand ? MainAxisSize.max : MainAxisSize.min,
|
mainAxisSize: expand ? MainAxisSize.max : MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
if (labelTrailing == null)
|
||||||
label,
|
Text(label, style: labelStyle)
|
||||||
style: TextStyle(
|
else
|
||||||
fontSize: ValidationFormMetrics.fieldLabelFontSize,
|
Row(
|
||||||
fontWeight: FontWeight.w500,
|
children: [
|
||||||
color: Colors.grey.shade700,
|
Expanded(child: Text(label, style: labelStyle)),
|
||||||
|
labelTrailing!,
|
||||||
|
],
|
||||||
),
|
),
|
||||||
),
|
|
||||||
SizedBox(height: ValidationFormMetrics.fieldLabelGapBelow),
|
SizedBox(height: ValidationFormMetrics.fieldLabelGapBelow),
|
||||||
if (expand) Expanded(child: field) else field,
|
if (expand) Expanded(child: field) else field,
|
||||||
],
|
],
|
||||||
@@ -299,6 +313,7 @@ class ValidationEditableField extends StatelessWidget {
|
|||||||
final String? hintText;
|
final String? hintText;
|
||||||
final int maxLines;
|
final int maxLines;
|
||||||
final bool compact;
|
final bool compact;
|
||||||
|
final bool enabled;
|
||||||
|
|
||||||
const ValidationEditableField({
|
const ValidationEditableField({
|
||||||
super.key,
|
super.key,
|
||||||
@@ -308,6 +323,7 @@ class ValidationEditableField extends StatelessWidget {
|
|||||||
this.hintText,
|
this.hintText,
|
||||||
this.maxLines = 1,
|
this.maxLines = 1,
|
||||||
this.compact = false,
|
this.compact = false,
|
||||||
|
this.enabled = true,
|
||||||
});
|
});
|
||||||
|
|
||||||
static const double _compactFieldHeight = 34;
|
static const double _compactFieldHeight = 34;
|
||||||
@@ -339,6 +355,7 @@ class ValidationEditableField extends StatelessWidget {
|
|||||||
if (maxLines > 1) {
|
if (maxLines > 1) {
|
||||||
return TextField(
|
return TextField(
|
||||||
controller: controller,
|
controller: controller,
|
||||||
|
enabled: enabled,
|
||||||
keyboardType: keyboardType,
|
keyboardType: keyboardType,
|
||||||
inputFormatters: inputFormatters,
|
inputFormatters: inputFormatters,
|
||||||
maxLines: maxLines,
|
maxLines: maxLines,
|
||||||
@@ -350,6 +367,7 @@ class ValidationEditableField extends StatelessWidget {
|
|||||||
return _validationFieldFillHeight(
|
return _validationFieldFillHeight(
|
||||||
TextField(
|
TextField(
|
||||||
controller: controller,
|
controller: controller,
|
||||||
|
enabled: enabled,
|
||||||
keyboardType: keyboardType,
|
keyboardType: keyboardType,
|
||||||
inputFormatters: inputFormatters,
|
inputFormatters: inputFormatters,
|
||||||
maxLines: 1,
|
maxLines: 1,
|
||||||
@@ -365,6 +383,7 @@ class ValidationEditableField extends StatelessWidget {
|
|||||||
decoration: _compactDecoration(),
|
decoration: _compactDecoration(),
|
||||||
child: TextField(
|
child: TextField(
|
||||||
controller: controller,
|
controller: controller,
|
||||||
|
enabled: enabled,
|
||||||
keyboardType: keyboardType,
|
keyboardType: keyboardType,
|
||||||
inputFormatters: inputFormatters,
|
inputFormatters: inputFormatters,
|
||||||
maxLines: 1,
|
maxLines: 1,
|
||||||
@@ -381,13 +400,15 @@ class ValidationEditableField extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Étire le champ si le parent impose une hauteur (grille [expandVertically]).
|
/// Hauteur TF fixe ; en grille [expandVertically], étire jusqu’à la hauteur dispo.
|
||||||
Widget _validationFieldFillHeight(Widget field) {
|
Widget _validationFieldFillHeight(Widget field) {
|
||||||
return LayoutBuilder(
|
return LayoutBuilder(
|
||||||
builder: (context, c) {
|
builder: (context, c) {
|
||||||
if (!c.hasBoundedHeight || !c.maxHeight.isFinite) return field;
|
final h = (c.hasBoundedHeight && c.maxHeight.isFinite)
|
||||||
|
? c.maxHeight
|
||||||
|
: ValidationFormMetrics.fieldHeight;
|
||||||
return SizedBox(
|
return SizedBox(
|
||||||
height: c.maxHeight,
|
height: h,
|
||||||
width: double.infinity,
|
width: double.infinity,
|
||||||
child: field,
|
child: field,
|
||||||
);
|
);
|
||||||
@@ -481,12 +502,14 @@ class ValidationPostalCodeField extends StatefulWidget {
|
|||||||
final TextEditingController controller;
|
final TextEditingController controller;
|
||||||
final String? hintText;
|
final String? hintText;
|
||||||
final bool allowEmpty;
|
final bool allowEmpty;
|
||||||
|
final bool enabled;
|
||||||
|
|
||||||
const ValidationPostalCodeField({
|
const ValidationPostalCodeField({
|
||||||
super.key,
|
super.key,
|
||||||
required this.controller,
|
required this.controller,
|
||||||
this.hintText,
|
this.hintText,
|
||||||
this.allowEmpty = false,
|
this.allowEmpty = false,
|
||||||
|
this.enabled = true,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -536,6 +559,7 @@ class _ValidationPostalCodeFieldState extends State<ValidationPostalCodeField> {
|
|||||||
key: _fieldKey,
|
key: _fieldKey,
|
||||||
controller: widget.controller,
|
controller: widget.controller,
|
||||||
focusNode: _focusNode,
|
focusNode: _focusNode,
|
||||||
|
enabled: widget.enabled,
|
||||||
keyboardType: TextInputType.number,
|
keyboardType: TextInputType.number,
|
||||||
textInputAction: TextInputAction.next,
|
textInputAction: TextInputAction.next,
|
||||||
textAlignVertical: TextAlignVertical.center,
|
textAlignVertical: TextAlignVertical.center,
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ class _CreateChild {
|
|||||||
final TextEditingController nomCtrl = TextEditingController();
|
final TextEditingController nomCtrl = TextEditingController();
|
||||||
final TextEditingController dateCtrl = TextEditingController();
|
final TextEditingController dateCtrl = TextEditingController();
|
||||||
String? genre;
|
String? genre;
|
||||||
|
bool isUnborn = false;
|
||||||
Uint8List? photoBytes;
|
Uint8List? photoBytes;
|
||||||
String? photoFilename;
|
String? photoFilename;
|
||||||
|
|
||||||
@@ -92,9 +93,9 @@ class ParentDossierWizard extends StatefulWidget {
|
|||||||
|
|
||||||
bool get isCreate => mode == ParentDossierWizardMode.create;
|
bool get isCreate => mode == ParentDossierWizardMode.create;
|
||||||
|
|
||||||
/// Hauteur corps modale famille — dérivée de [ValidationFormMetrics] (4 lignes).
|
/// Hauteur corps modale famille — 4 lignes TF + marge pour le bandeau switch.
|
||||||
static double get shellBodyHeight =>
|
static double get shellBodyHeight =>
|
||||||
ValidationFormMetrics.shellBodyHeightForRows(4);
|
ValidationFormMetrics.shellBodyHeightForRows(4) + 20;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<ParentDossierWizard> createState() => _ParentDossierWizardState();
|
State<ParentDossierWizard> createState() => _ParentDossierWizardState();
|
||||||
@@ -319,60 +320,122 @@ class _ParentDossierWizardState extends State<ParentDossierWizard> {
|
|||||||
return Column(
|
return Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
children: [
|
children: [
|
||||||
SwitchListTile(
|
Row(
|
||||||
contentPadding: EdgeInsets.zero,
|
children: [
|
||||||
title: const Text('Ajouter un co-parent'),
|
const Text(
|
||||||
value: _hasCoParent,
|
'Deuxième parent',
|
||||||
onChanged: (v) => setState(() => _hasCoParent = v),
|
style: TextStyle(
|
||||||
),
|
fontSize: ValidationFormMetrics.sectionTitleFontSize,
|
||||||
if (!_hasCoParent)
|
fontWeight: FontWeight.w600,
|
||||||
const Padding(
|
color: Colors.black87,
|
||||||
padding: EdgeInsets.symmetric(vertical: 12),
|
|
||||||
child: Text(
|
|
||||||
'Un seul parent pour ce dossier.',
|
|
||||||
style: TextStyle(color: Colors.black87),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
else ...[
|
|
||||||
const SizedBox(height: 8),
|
|
||||||
Expanded(
|
|
||||||
child: SingleChildScrollView(
|
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
|
||||||
children: [
|
|
||||||
IdentityBlock.editable(
|
|
||||||
title: 'Deuxième parent',
|
|
||||||
nomController: _p2NomCtrl,
|
|
||||||
prenomController: _p2PrenomCtrl,
|
|
||||||
telephoneController: _p2TelCtrl,
|
|
||||||
emailController: _p2EmailCtrl,
|
|
||||||
adresseController: _p2AdresseCtrl,
|
|
||||||
codePostalController: _p2CpCtrl,
|
|
||||||
villeController: _p2VilleCtrl,
|
|
||||||
),
|
|
||||||
const SizedBox(height: 12),
|
|
||||||
SwitchListTile(
|
|
||||||
contentPadding: EdgeInsets.zero,
|
|
||||||
title: const Text('Même adresse que le parent principal'),
|
|
||||||
value: _sameAddress,
|
|
||||||
onChanged: (v) => setState(() {
|
|
||||||
_sameAddress = v;
|
|
||||||
if (v) {
|
|
||||||
_p2AdresseCtrl.text = _p1AdresseCtrl.text;
|
|
||||||
_p2CpCtrl.text = _p1CpCtrl.text;
|
|
||||||
_p2VilleCtrl.text = _p1VilleCtrl.text;
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
const Spacer(),
|
||||||
|
const Text(
|
||||||
|
'Ajouter un co-parent',
|
||||||
|
style: TextStyle(fontSize: 14, color: Colors.black87),
|
||||||
|
),
|
||||||
|
Transform.scale(
|
||||||
|
scale: 0.75,
|
||||||
|
child: Switch(
|
||||||
|
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
|
||||||
|
value: _hasCoParent,
|
||||||
|
onChanged: (v) => setState(() => _hasCoParent = v),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
const SizedBox(height: 8),
|
||||||
|
if (!_hasCoParent)
|
||||||
|
const Text(
|
||||||
|
'Un seul parent pour ce dossier.',
|
||||||
|
style: TextStyle(color: Colors.black87),
|
||||||
|
)
|
||||||
|
else
|
||||||
|
ValidationFormGrid(
|
||||||
|
compact: true,
|
||||||
|
rowLayout: IdentityBlock.rowLayout,
|
||||||
|
rowFlex: IdentityBlock.rowFlex,
|
||||||
|
fields: [
|
||||||
|
ValidationLabeledField(
|
||||||
|
label: 'Nom',
|
||||||
|
field: ValidationEditableField(
|
||||||
|
controller: _p2NomCtrl,
|
||||||
|
inputFormatters: const [PersonNameInputFormatter()],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
ValidationLabeledField(
|
||||||
|
label: 'Prénom',
|
||||||
|
field: ValidationEditableField(
|
||||||
|
controller: _p2PrenomCtrl,
|
||||||
|
inputFormatters: const [PersonNameInputFormatter()],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
ValidationLabeledField(
|
||||||
|
label: 'Téléphone',
|
||||||
|
field: ValidationPhoneField(controller: _p2TelCtrl),
|
||||||
|
),
|
||||||
|
ValidationLabeledField(
|
||||||
|
label: 'Email',
|
||||||
|
field: ValidationEmailField(controller: _p2EmailCtrl),
|
||||||
|
),
|
||||||
|
ValidationLabeledField(
|
||||||
|
label: 'Adresse (N° et Rue)',
|
||||||
|
labelTrailing: Row(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
const Text(
|
||||||
|
'Même adresse',
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: ValidationFormMetrics.fieldLabelFontSize,
|
||||||
|
color: Colors.black87,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Transform.scale(
|
||||||
|
scale: 0.75,
|
||||||
|
child: Switch(
|
||||||
|
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
|
||||||
|
value: _sameAddress,
|
||||||
|
onChanged: (v) => setState(() {
|
||||||
|
_sameAddress = v;
|
||||||
|
if (v) _copyP1AddressToP2();
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
field: ValidationEditableField(
|
||||||
|
controller: _p2AdresseCtrl,
|
||||||
|
enabled: !_sameAddress,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
ValidationLabeledField(
|
||||||
|
label: 'Code postal',
|
||||||
|
field: ValidationPostalCodeField(
|
||||||
|
controller: _p2CpCtrl,
|
||||||
|
enabled: !_sameAddress,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
ValidationLabeledField(
|
||||||
|
label: 'Ville',
|
||||||
|
field: ValidationEditableField(
|
||||||
|
controller: _p2VilleCtrl,
|
||||||
|
enabled: !_sameAddress,
|
||||||
|
inputFormatters: const [PersonNameInputFormatter()],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
],
|
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _copyP1AddressToP2() {
|
||||||
|
_p2AdresseCtrl.text = _p1AdresseCtrl.text;
|
||||||
|
_p2CpCtrl.text = _p1CpCtrl.text;
|
||||||
|
_p2VilleCtrl.text = _p1VilleCtrl.text;
|
||||||
|
}
|
||||||
|
|
||||||
Widget _buildParent2Step() {
|
Widget _buildParent2Step() {
|
||||||
if (_dossier.parents.length < 2) {
|
if (_dossier.parents.length < 2) {
|
||||||
return const Padding(
|
return const Padding(
|
||||||
@@ -643,11 +706,12 @@ class _ParentDossierWizardState extends State<ParentDossierWizard> {
|
|||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
children: [
|
children: [
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.fromLTRB(12, 12, 40, 8),
|
padding: const EdgeInsets.fromLTRB(12, 12, 14, 8),
|
||||||
child: ValidationLabeledField(
|
child: ValidationLabeledField(
|
||||||
label: 'Prénom',
|
label: 'Prénom',
|
||||||
field: ValidationEditableField(
|
field: ValidationEditableField(
|
||||||
controller: child.prenomCtrl,
|
controller: child.prenomCtrl,
|
||||||
|
hintText: child.isUnborn ? 'Facultatif' : null,
|
||||||
inputFormatters: const [PersonNameInputFormatter()],
|
inputFormatters: const [PersonNameInputFormatter()],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -715,7 +779,36 @@ class _ParentDossierWizardState extends State<ParentDossierWizard> {
|
|||||||
),
|
),
|
||||||
const SizedBox(height: 12),
|
const SizedBox(height: 12),
|
||||||
ValidationLabeledField(
|
ValidationLabeledField(
|
||||||
label: 'Date de naissance',
|
label: child.isUnborn
|
||||||
|
? 'Date prévisionnelle'
|
||||||
|
: 'Date de naissance',
|
||||||
|
labelTrailing: Row(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
const Text(
|
||||||
|
'À naître',
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: ValidationFormMetrics
|
||||||
|
.fieldLabelFontSize,
|
||||||
|
color: Colors.black87,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Transform.scale(
|
||||||
|
scale: 0.75,
|
||||||
|
child: Switch(
|
||||||
|
materialTapTargetSize:
|
||||||
|
MaterialTapTargetSize.shrinkWrap,
|
||||||
|
value: child.isUnborn,
|
||||||
|
onChanged: (v) => setState(() {
|
||||||
|
child.isUnborn = v;
|
||||||
|
if (!v && child.genre == 'Autre') {
|
||||||
|
child.genre = null;
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
field: ValidationEditableField(
|
field: ValidationEditableField(
|
||||||
controller: child.dateCtrl,
|
controller: child.dateCtrl,
|
||||||
hintText: 'jj / mm / aaaa',
|
hintText: 'jj / mm / aaaa',
|
||||||
@@ -766,20 +859,28 @@ class _ParentDossierWizardState extends State<ParentDossierWizard> {
|
|||||||
|
|
||||||
Widget _genreDropdown(int index) {
|
Widget _genreDropdown(int index) {
|
||||||
final child = _children[index];
|
final child = _children[index];
|
||||||
|
final items = <DropdownMenuItem<String>>[
|
||||||
|
const DropdownMenuItem(value: 'H', child: Text('Garçon')),
|
||||||
|
const DropdownMenuItem(value: 'F', child: Text('Fille')),
|
||||||
|
if (child.isUnborn)
|
||||||
|
const DropdownMenuItem(value: 'Autre', child: Text('Inconnu')),
|
||||||
|
];
|
||||||
|
final value = child.genre != null &&
|
||||||
|
items.any((e) => e.value == child.genre)
|
||||||
|
? child.genre
|
||||||
|
: null;
|
||||||
return SizedBox(
|
return SizedBox(
|
||||||
height: ValidationFormMetrics.fieldHeight,
|
height: ValidationFormMetrics.fieldHeight,
|
||||||
child: DropdownButtonFormField<String>(
|
child: DropdownButtonFormField<String>(
|
||||||
value: child.genre,
|
key: ValueKey('genre-$index-${child.isUnborn}'),
|
||||||
|
value: value,
|
||||||
isExpanded: true,
|
isExpanded: true,
|
||||||
hint: Text(
|
hint: Text(
|
||||||
'Sélectionner',
|
'Sélectionner',
|
||||||
style: TextStyle(color: Colors.grey.shade600, fontSize: 14),
|
style: TextStyle(color: Colors.grey.shade600, fontSize: 14),
|
||||||
),
|
),
|
||||||
decoration: ValidationFieldDecoration.input(),
|
decoration: ValidationFieldDecoration.input(),
|
||||||
items: const [
|
items: items,
|
||||||
DropdownMenuItem(value: 'H', child: Text('Garçon')),
|
|
||||||
DropdownMenuItem(value: 'F', child: Text('Fille')),
|
|
||||||
],
|
|
||||||
onChanged: (v) => setState(() => child.genre = v),
|
onChanged: (v) => setState(() => child.genre = v),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@@ -1118,6 +1219,10 @@ class _ParentDossierWizardState extends State<ParentDossierWizard> {
|
|||||||
normalizeEmailText(_p1EmailCtrl.text)) {
|
normalizeEmailText(_p1EmailCtrl.text)) {
|
||||||
return 'L’email du co-parent doit être différent de celui du parent principal.';
|
return 'L’email du co-parent doit être différent de celui du parent principal.';
|
||||||
}
|
}
|
||||||
|
if (_sameAddress) {
|
||||||
|
_copyP1AddressToP2();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
if (_p2AdresseCtrl.text.trim().isEmpty) {
|
if (_p2AdresseCtrl.text.trim().isEmpty) {
|
||||||
return 'L’adresse du co-parent est requise.';
|
return 'L’adresse du co-parent est requise.';
|
||||||
}
|
}
|
||||||
@@ -1134,14 +1239,27 @@ class _ParentDossierWizardState extends State<ParentDossierWizard> {
|
|||||||
for (var i = 0; i < _children.length; i++) {
|
for (var i = 0; i < _children.length; i++) {
|
||||||
final c = _children[i];
|
final c = _children[i];
|
||||||
final label = 'Enfant ${i + 1}';
|
final label = 'Enfant ${i + 1}';
|
||||||
if (c.prenomCtrl.text.trim().length < 2) {
|
final prenom = c.prenomCtrl.text.trim();
|
||||||
return '$label : le prénom doit contenir au moins 2 caractères.';
|
if (c.isUnborn) {
|
||||||
}
|
if (prenom.isNotEmpty && prenom.length < 2) {
|
||||||
if (parseFrDateToIso(c.dateCtrl.text) == null) {
|
return '$label : le prénom doit contenir au moins 2 caractères.';
|
||||||
return '$label : indiquez une date de naissance valide (jj/mm/aaaa).';
|
}
|
||||||
}
|
if (parseFrDateToIso(c.dateCtrl.text) == null) {
|
||||||
if (c.genre != 'H' && c.genre != 'F') {
|
return '$label : indiquez une date prévisionnelle valide (jj/mm/aaaa).';
|
||||||
return '$label : indiquez le genre (Garçon ou Fille).';
|
}
|
||||||
|
if (c.genre != 'H' && c.genre != 'F' && c.genre != 'Autre') {
|
||||||
|
return '$label : indiquez le genre (Garçon, Fille ou Inconnu).';
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (prenom.length < 2) {
|
||||||
|
return '$label : le prénom doit contenir au moins 2 caractères.';
|
||||||
|
}
|
||||||
|
if (parseFrDateToIso(c.dateCtrl.text) == null) {
|
||||||
|
return '$label : indiquez une date de naissance valide (jj/mm/aaaa).';
|
||||||
|
}
|
||||||
|
if (c.genre != 'H' && c.genre != 'F') {
|
||||||
|
return '$label : indiquez le genre (Garçon ou Fille).';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
@@ -1207,17 +1325,29 @@ class _ParentDossierWizardState extends State<ParentDossierWizard> {
|
|||||||
final nom = nomRaw.isNotEmpty
|
final nom = nomRaw.isNotEmpty
|
||||||
? formatPersonNameCase(nomRaw)
|
? formatPersonNameCase(nomRaw)
|
||||||
: formatPersonNameCase(_p1NomCtrl.text);
|
: formatPersonNameCase(_p1NomCtrl.text);
|
||||||
final birthIso = parseFrDateToIso(c.dateCtrl.text);
|
final dateIso = parseFrDateToIso(c.dateCtrl.text);
|
||||||
|
|
||||||
final map = <String, dynamic>{
|
final map = <String, dynamic>{
|
||||||
'prenom': prenom,
|
|
||||||
'nom': nom,
|
|
||||||
'date_naissance': birthIso,
|
|
||||||
'genre': c.genre,
|
'genre': c.genre,
|
||||||
'consent_photo': true,
|
'consent_photo': true,
|
||||||
'grossesse_multiple': false,
|
'grossesse_multiple': false,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (prenom.length >= 2) {
|
||||||
|
map['prenom'] = prenom;
|
||||||
|
}
|
||||||
|
if (nom.length >= 2) {
|
||||||
|
map['nom'] = nom;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c.isUnborn) {
|
||||||
|
if (dateIso != null) {
|
||||||
|
map['date_previsionnelle_naissance'] = dateIso;
|
||||||
|
}
|
||||||
|
} else if (dateIso != null) {
|
||||||
|
map['date_naissance'] = dateIso;
|
||||||
|
}
|
||||||
|
|
||||||
final bytes = c.photoBytes;
|
final bytes = c.photoBytes;
|
||||||
if (bytes != null && bytes.isNotEmpty) {
|
if (bytes != null && bytes.isNotEmpty) {
|
||||||
final mime = _imageMimeForBytes(bytes);
|
final mime = _imageMimeForBytes(bytes);
|
||||||
@@ -1243,16 +1373,13 @@ class _ParentDossierWizardState extends State<ParentDossierWizard> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (_hasCoParent) {
|
if (_hasCoParent) {
|
||||||
final sameAddr =
|
if (_sameAddress) _copyP1AddressToP2();
|
||||||
_p2AdresseCtrl.text.trim() == _p1AdresseCtrl.text.trim() &&
|
|
||||||
_p2CpCtrl.text.trim() == _p1CpCtrl.text.trim() &&
|
|
||||||
_p2VilleCtrl.text.trim() == _p1VilleCtrl.text.trim();
|
|
||||||
body['co_parent_email'] = normalizeEmailText(_p2EmailCtrl.text);
|
body['co_parent_email'] = normalizeEmailText(_p2EmailCtrl.text);
|
||||||
body['co_parent_prenom'] = formatPersonNameCase(_p2PrenomCtrl.text);
|
body['co_parent_prenom'] = formatPersonNameCase(_p2PrenomCtrl.text);
|
||||||
body['co_parent_nom'] = formatPersonNameCase(_p2NomCtrl.text);
|
body['co_parent_nom'] = formatPersonNameCase(_p2NomCtrl.text);
|
||||||
body['co_parent_telephone'] = normalizePhone(_p2TelCtrl.text);
|
body['co_parent_telephone'] = normalizePhone(_p2TelCtrl.text);
|
||||||
body['co_parent_meme_adresse'] = sameAddr;
|
body['co_parent_meme_adresse'] = _sameAddress;
|
||||||
if (!sameAddr) {
|
if (!_sameAddress) {
|
||||||
body['co_parent_adresse'] = _p2AdresseCtrl.text.trim();
|
body['co_parent_adresse'] = _p2AdresseCtrl.text.trim();
|
||||||
body['co_parent_code_postal'] = _p2CpCtrl.text.trim();
|
body['co_parent_code_postal'] = _p2CpCtrl.text.trim();
|
||||||
body['co_parent_ville'] = formatPersonNameCase(_p2VilleCtrl.text);
|
body['co_parent_ville'] = formatPersonNameCase(_p2VilleCtrl.text);
|
||||||
|
|||||||
Reference in New Issue
Block a user