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>
This commit is contained in:
@@ -13,6 +13,7 @@ class AuthNetworkImage extends StatefulWidget {
|
||||
this.width,
|
||||
this.height,
|
||||
this.fit = BoxFit.cover,
|
||||
this.alignment = Alignment.center,
|
||||
this.loadingBuilder,
|
||||
this.errorBuilder,
|
||||
});
|
||||
@@ -21,6 +22,7 @@ class AuthNetworkImage extends StatefulWidget {
|
||||
final double? width;
|
||||
final double? height;
|
||||
final BoxFit fit;
|
||||
final AlignmentGeometry alignment;
|
||||
final ImageLoadingBuilder? loadingBuilder;
|
||||
final ImageErrorWidgetBuilder? errorBuilder;
|
||||
|
||||
@@ -75,6 +77,7 @@ class _AuthNetworkImageState extends State<AuthNetworkImage> {
|
||||
width: widget.width,
|
||||
height: widget.height,
|
||||
fit: widget.fit,
|
||||
alignment: widget.alignment,
|
||||
loadingBuilder: widget.loadingBuilder,
|
||||
errorBuilder: err,
|
||||
);
|
||||
@@ -105,6 +108,7 @@ class _AuthNetworkImageState extends State<AuthNetworkImage> {
|
||||
width: widget.width,
|
||||
height: widget.height,
|
||||
fit: widget.fit,
|
||||
alignment: widget.alignment,
|
||||
headers: headers,
|
||||
loadingBuilder: widget.loadingBuilder,
|
||||
errorBuilder: err,
|
||||
|
||||
@@ -0,0 +1,278 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:p_tits_pas/models/dossier_unifie.dart';
|
||||
import 'package:p_tits_pas/models/user.dart';
|
||||
import 'package:p_tits_pas/utils/phone_utils.dart';
|
||||
import 'package:p_tits_pas/widgets/admin/common/validation_detail_section.dart';
|
||||
|
||||
/// Valeurs affichées dans un [IdentityBlock] en lecture seule.
|
||||
class IdentityValues {
|
||||
final String nom;
|
||||
final String prenom;
|
||||
final String telephone;
|
||||
final String email;
|
||||
final String adresse;
|
||||
final String codePostal;
|
||||
final String ville;
|
||||
|
||||
const IdentityValues({
|
||||
required this.nom,
|
||||
required this.prenom,
|
||||
required this.telephone,
|
||||
required this.email,
|
||||
required this.adresse,
|
||||
required this.codePostal,
|
||||
required this.ville,
|
||||
});
|
||||
|
||||
static String _fmt(String? s, String empty) {
|
||||
final t = (s ?? '').trim();
|
||||
return t.isEmpty ? empty : t;
|
||||
}
|
||||
|
||||
static String _fmtPhone(String? s, String empty) {
|
||||
final tel = _fmt(s, empty);
|
||||
return tel != empty ? formatPhoneForDisplay(tel) : tel;
|
||||
}
|
||||
|
||||
factory IdentityValues.fromUser(
|
||||
AppUser user, {
|
||||
String emptyLabel = 'Non défini',
|
||||
}) {
|
||||
return IdentityValues(
|
||||
nom: _fmt(user.nom, emptyLabel),
|
||||
prenom: _fmt(user.prenom, emptyLabel),
|
||||
telephone: _fmtPhone(user.telephone, emptyLabel),
|
||||
email: _fmt(user.email, emptyLabel),
|
||||
adresse: _fmt(user.adresse, emptyLabel),
|
||||
codePostal: _fmt(user.codePostal, emptyLabel),
|
||||
ville: _fmt(user.ville, emptyLabel),
|
||||
);
|
||||
}
|
||||
|
||||
factory IdentityValues.fromParentDossier(
|
||||
ParentDossier parent, {
|
||||
String emptyLabel = 'Non défini',
|
||||
}) {
|
||||
return IdentityValues(
|
||||
nom: _fmt(parent.nom, emptyLabel),
|
||||
prenom: _fmt(parent.prenom, emptyLabel),
|
||||
telephone: _fmtPhone(parent.telephone, emptyLabel),
|
||||
email: _fmt(parent.email, emptyLabel),
|
||||
adresse: _fmt(parent.adresse, emptyLabel),
|
||||
codePostal: _fmt(parent.codePostal, emptyLabel),
|
||||
ville: _fmt(parent.ville, emptyLabel),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Bloc identité : Nom/Prénom, Tél/Email, Adresse, CP/Ville.
|
||||
/// Grille partagée (création de compte, validation AM/famille, fiches admin, etc.).
|
||||
class IdentityBlock extends StatelessWidget { final String? title;
|
||||
|
||||
final String? _nom;
|
||||
final String? _prenom;
|
||||
final String? _telephone;
|
||||
final String? _email;
|
||||
final String? _adresse;
|
||||
final String? _codePostal;
|
||||
final String? _ville;
|
||||
|
||||
final TextEditingController? _nomCtrl;
|
||||
final TextEditingController? _prenomCtrl;
|
||||
final TextEditingController? _telCtrl;
|
||||
final TextEditingController? _emailCtrl;
|
||||
final TextEditingController? _adresseCtrl;
|
||||
final TextEditingController? _cpCtrl;
|
||||
final TextEditingController? _villeCtrl;
|
||||
|
||||
static const List<int> rowLayout = [2, 2, 1, 2];
|
||||
static const Map<int, List<int>> rowFlex = {3: [2, 5]};
|
||||
|
||||
const IdentityBlock.readOnly({
|
||||
super.key,
|
||||
this.title,
|
||||
required String nom,
|
||||
required String prenom,
|
||||
required String telephone,
|
||||
required String email,
|
||||
required String adresse,
|
||||
required String codePostal,
|
||||
required String ville,
|
||||
}) : _nom = nom,
|
||||
_prenom = prenom,
|
||||
_telephone = telephone,
|
||||
_email = email,
|
||||
_adresse = adresse,
|
||||
_codePostal = codePostal,
|
||||
_ville = ville,
|
||||
_nomCtrl = null,
|
||||
_prenomCtrl = null,
|
||||
_telCtrl = null,
|
||||
_emailCtrl = null,
|
||||
_adresseCtrl = null,
|
||||
_cpCtrl = null,
|
||||
_villeCtrl = null;
|
||||
|
||||
const IdentityBlock.editable({
|
||||
super.key,
|
||||
this.title,
|
||||
required TextEditingController nomController,
|
||||
required TextEditingController prenomController,
|
||||
required TextEditingController telephoneController,
|
||||
required TextEditingController emailController,
|
||||
required TextEditingController adresseController,
|
||||
required TextEditingController codePostalController,
|
||||
required TextEditingController villeController,
|
||||
}) : _nom = null,
|
||||
_prenom = null,
|
||||
_telephone = null,
|
||||
_email = null,
|
||||
_adresse = null,
|
||||
_codePostal = null,
|
||||
_ville = null,
|
||||
_nomCtrl = nomController,
|
||||
_prenomCtrl = prenomController,
|
||||
_telCtrl = telephoneController,
|
||||
_emailCtrl = emailController,
|
||||
_adresseCtrl = adresseController,
|
||||
_cpCtrl = codePostalController,
|
||||
_villeCtrl = villeController;
|
||||
|
||||
/// Lecture seule à partir de [IdentityValues].
|
||||
factory IdentityBlock.readOnlyValues({
|
||||
Key? key,
|
||||
String? title,
|
||||
required IdentityValues values,
|
||||
}) {
|
||||
return IdentityBlock.readOnly(
|
||||
key: key,
|
||||
title: title,
|
||||
nom: values.nom,
|
||||
prenom: values.prenom,
|
||||
telephone: values.telephone,
|
||||
email: values.email,
|
||||
adresse: values.adresse,
|
||||
codePostal: values.codePostal,
|
||||
ville: values.ville,
|
||||
);
|
||||
}
|
||||
|
||||
/// Lecture seule depuis un [AppUser] (validation AM, fiche AM, etc.).
|
||||
factory IdentityBlock.readOnlyFromUser(
|
||||
AppUser user, {
|
||||
Key? key,
|
||||
String? title,
|
||||
String emptyLabel = 'Non défini',
|
||||
}) {
|
||||
return IdentityBlock.readOnlyValues(
|
||||
key: key,
|
||||
title: title,
|
||||
values: IdentityValues.fromUser(user, emptyLabel: emptyLabel),
|
||||
);
|
||||
}
|
||||
|
||||
/// Lecture seule depuis un [ParentDossier] (validation famille).
|
||||
factory IdentityBlock.readOnlyFromParentDossier(
|
||||
ParentDossier parent, {
|
||||
Key? key,
|
||||
String? title,
|
||||
String emptyLabel = 'Non défini',
|
||||
}) {
|
||||
return IdentityBlock.readOnlyValues(
|
||||
key: key,
|
||||
title: title,
|
||||
values: IdentityValues.fromParentDossier(
|
||||
parent,
|
||||
emptyLabel: emptyLabel,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
bool get _isEditable => _nomCtrl != null;
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (_isEditable) {
|
||||
return ValidationFormGrid(
|
||||
title: title,
|
||||
rowLayout: rowLayout,
|
||||
rowFlex: rowFlex,
|
||||
fields: [
|
||||
ValidationLabeledField(
|
||||
label: 'Nom',
|
||||
field: ValidationEditableField(controller: _nomCtrl!),
|
||||
),
|
||||
ValidationLabeledField(
|
||||
label: 'Prénom',
|
||||
field: ValidationEditableField(controller: _prenomCtrl!),
|
||||
),
|
||||
ValidationLabeledField(
|
||||
label: 'Téléphone',
|
||||
field: ValidationEditableField(
|
||||
controller: _telCtrl!,
|
||||
keyboardType: TextInputType.phone,
|
||||
inputFormatters: frenchPhoneInputFormatters,
|
||||
),
|
||||
),
|
||||
ValidationLabeledField(
|
||||
label: 'Email',
|
||||
field: ValidationEditableField(
|
||||
controller: _emailCtrl!,
|
||||
keyboardType: TextInputType.emailAddress,
|
||||
),
|
||||
),
|
||||
ValidationLabeledField(
|
||||
label: 'Adresse (N° et Rue)',
|
||||
field: ValidationEditableField(controller: _adresseCtrl!),
|
||||
),
|
||||
ValidationLabeledField(
|
||||
label: 'Code postal',
|
||||
field: ValidationEditableField(
|
||||
controller: _cpCtrl!,
|
||||
keyboardType: TextInputType.number,
|
||||
),
|
||||
),
|
||||
ValidationLabeledField(
|
||||
label: 'Ville',
|
||||
field: ValidationEditableField(controller: _villeCtrl!),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
return ValidationFormGrid(
|
||||
title: title,
|
||||
rowLayout: rowLayout,
|
||||
rowFlex: rowFlex,
|
||||
fields: [
|
||||
ValidationLabeledField(
|
||||
label: 'Nom',
|
||||
field: ValidationReadOnlyField(value: _nom!),
|
||||
),
|
||||
ValidationLabeledField(
|
||||
label: 'Prénom',
|
||||
field: ValidationReadOnlyField(value: _prenom!),
|
||||
),
|
||||
ValidationLabeledField(
|
||||
label: 'Téléphone',
|
||||
field: ValidationReadOnlyField(value: _telephone!),
|
||||
),
|
||||
ValidationLabeledField(
|
||||
label: 'Email',
|
||||
field: ValidationReadOnlyField(value: _email!),
|
||||
),
|
||||
ValidationLabeledField(
|
||||
label: 'Adresse (N° et Rue)',
|
||||
field: ValidationReadOnlyField(value: _adresse!),
|
||||
),
|
||||
ValidationLabeledField(
|
||||
label: 'Code postal',
|
||||
field: ValidationReadOnlyField(value: _codePostal!),
|
||||
),
|
||||
ValidationLabeledField(
|
||||
label: 'Ville',
|
||||
field: ValidationReadOnlyField(value: _ville!),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user