fix(#131): activer Sauvegarder sur statut, enfants et champs AM.
Compare l'état de la fiche à un snapshot initial (liste enfants, statut, places, formulaire) et corrige la gélule statut pour les valeurs hors liste. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
66c7f22280
commit
d03a8e6c8b
@ -1,3 +1,4 @@
|
|||||||
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:p_tits_pas/models/assistante_maternelle_model.dart';
|
import 'package:p_tits_pas/models/assistante_maternelle_model.dart';
|
||||||
@ -57,6 +58,25 @@ class _AdminAmEditModalState extends State<AdminAmEditModal>
|
|||||||
bool _saving = false;
|
bool _saving = false;
|
||||||
bool _dirty = false;
|
bool _dirty = false;
|
||||||
|
|
||||||
|
late String _baseStatut;
|
||||||
|
late bool _baseDisponible;
|
||||||
|
late int? _basePlacesAvailable;
|
||||||
|
late List<String> _baseChildIds;
|
||||||
|
late String _baseNom;
|
||||||
|
late String _basePrenom;
|
||||||
|
late String _baseEmail;
|
||||||
|
late String _baseTelephone;
|
||||||
|
late String _baseAdresse;
|
||||||
|
late String _baseVille;
|
||||||
|
late String _baseCodePostal;
|
||||||
|
late String _baseAgrement;
|
||||||
|
late String _baseNir;
|
||||||
|
late String? _baseDateNaissanceIso;
|
||||||
|
late String _baseLieuNaissanceVille;
|
||||||
|
late String _baseLieuNaissancePays;
|
||||||
|
late String? _baseAgreementDateIso;
|
||||||
|
late int? _baseCapacite;
|
||||||
|
|
||||||
static const double _modalWidth = 930;
|
static const double _modalWidth = 930;
|
||||||
static const double _photoProGap = 24;
|
static const double _photoProGap = 24;
|
||||||
static const double _proColumnMinWidth = 260;
|
static const double _proColumnMinWidth = 260;
|
||||||
@ -147,16 +167,77 @@ class _AdminAmEditModalState extends State<AdminAmEditModal>
|
|||||||
_nomCtrl.addListener(_onNameFieldChanged);
|
_nomCtrl.addListener(_onNameFieldChanged);
|
||||||
_prenomCtrl.addListener(_onNameFieldChanged);
|
_prenomCtrl.addListener(_onNameFieldChanged);
|
||||||
_tabCtrl.addListener(_onTabChanged);
|
_tabCtrl.addListener(_onTabChanged);
|
||||||
|
_captureBaseline();
|
||||||
_reloadChildren();
|
_reloadChildren();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _captureBaseline() {
|
||||||
|
_baseStatut = _statut;
|
||||||
|
_baseDisponible = _disponible;
|
||||||
|
_basePlacesAvailable = _placesAvailable;
|
||||||
|
_baseChildIds = _children.map((c) => c.id).toList()..sort();
|
||||||
|
_baseNom = _nomCtrl.text.trim();
|
||||||
|
_basePrenom = _prenomCtrl.text.trim();
|
||||||
|
_baseEmail = _emailCtrl.text.trim();
|
||||||
|
_baseTelephone = normalizePhone(_telCtrl.text);
|
||||||
|
_baseAdresse = _adresseCtrl.text.trim();
|
||||||
|
_baseVille = _villeCtrl.text.trim();
|
||||||
|
_baseCodePostal = _cpCtrl.text.trim();
|
||||||
|
_baseAgrement = _agrementCtrl.text.trim();
|
||||||
|
_baseNir = nirToRaw(_nirCtrl.text);
|
||||||
|
_baseDateNaissanceIso = _frDateToIso(_dateNaissanceCtrl.text);
|
||||||
|
_baseLieuNaissanceVille = _lieuNaissanceVilleCtrl.text.trim();
|
||||||
|
_baseLieuNaissancePays = _lieuNaissancePaysCtrl.text.trim();
|
||||||
|
_baseAgreementDateIso = _frDateToIso(_dateAgrementCtrl.text);
|
||||||
|
_baseCapacite = _capaciteMax();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool _hasUnsavedChanges() {
|
||||||
|
if (_statut != _baseStatut) return true;
|
||||||
|
if (_disponible != _baseDisponible) return true;
|
||||||
|
if (_placesAvailable != _basePlacesAvailable) return true;
|
||||||
|
final childIds = _children.map((c) => c.id).toList()..sort();
|
||||||
|
if (!listEquals(childIds, _baseChildIds)) return true;
|
||||||
|
if (_nomCtrl.text.trim() != _baseNom) return true;
|
||||||
|
if (_prenomCtrl.text.trim() != _basePrenom) return true;
|
||||||
|
if (_emailCtrl.text.trim() != _baseEmail) return true;
|
||||||
|
if (normalizePhone(_telCtrl.text) != _baseTelephone) return true;
|
||||||
|
if (_adresseCtrl.text.trim() != _baseAdresse) return true;
|
||||||
|
if (_villeCtrl.text.trim() != _baseVille) return true;
|
||||||
|
if (_cpCtrl.text.trim() != _baseCodePostal) return true;
|
||||||
|
if (_agrementCtrl.text.trim() != _baseAgrement) return true;
|
||||||
|
if (nirToRaw(_nirCtrl.text) != _baseNir) return true;
|
||||||
|
if (_frDateToIso(_dateNaissanceCtrl.text) != _baseDateNaissanceIso) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (_lieuNaissanceVilleCtrl.text.trim() != _baseLieuNaissanceVille) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (_lieuNaissancePaysCtrl.text.trim() != _baseLieuNaissancePays) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (_frDateToIso(_dateAgrementCtrl.text) != _baseAgreementDateIso) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (_capaciteMax() != _baseCapacite) return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _syncDirtyState() {
|
||||||
|
final next = _hasUnsavedChanges();
|
||||||
|
if (next != _dirty) setState(() => _dirty = next);
|
||||||
|
}
|
||||||
|
|
||||||
void _onTabChanged() {
|
void _onTabChanged() {
|
||||||
if (!_tabCtrl.indexIsChanging) setState(() {});
|
if (!_tabCtrl.indexIsChanging) setState(() {});
|
||||||
}
|
}
|
||||||
|
|
||||||
void _onNameFieldChanged() => setState(() {});
|
void _onNameFieldChanged() => setState(() {});
|
||||||
|
|
||||||
void _onCapacityChanged() => setState(() {});
|
void _onCapacityChanged() {
|
||||||
|
setState(() {});
|
||||||
|
_syncDirtyState();
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
@ -182,9 +263,7 @@ class _AdminAmEditModalState extends State<AdminAmEditModal>
|
|||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
void _markDirty() {
|
void _markDirty() => _syncDirtyState();
|
||||||
if (!_dirty) setState(() => _dirty = true);
|
|
||||||
}
|
|
||||||
|
|
||||||
String _headerTitle() {
|
String _headerTitle() {
|
||||||
final fn = _prenomCtrl.text.trim();
|
final fn = _prenomCtrl.text.trim();
|
||||||
@ -240,10 +319,8 @@ class _AdminAmEditModalState extends State<AdminAmEditModal>
|
|||||||
void _applyPlacesCorrection() {
|
void _applyPlacesCorrection() {
|
||||||
final expected = _computedPlacesAvailable();
|
final expected = _computedPlacesAvailable();
|
||||||
if (expected == null) return;
|
if (expected == null) return;
|
||||||
setState(() {
|
setState(() => _placesAvailable = expected);
|
||||||
_placesAvailable = expected;
|
_syncDirtyState();
|
||||||
_dirty = true;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
String? _placesInconsistencyMessage() {
|
String? _placesInconsistencyMessage() {
|
||||||
@ -318,6 +395,7 @@ class _AdminAmEditModalState extends State<AdminAmEditModal>
|
|||||||
_dirty = false;
|
_dirty = false;
|
||||||
_saving = false;
|
_saving = false;
|
||||||
});
|
});
|
||||||
|
_captureBaseline();
|
||||||
widget.onSaved?.call();
|
widget.onSaved?.call();
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
const SnackBar(content: Text('Fiche assistante maternelle enregistrée')),
|
const SnackBar(content: Text('Fiche assistante maternelle enregistrée')),
|
||||||
@ -346,6 +424,7 @@ class _AdminAmEditModalState extends State<AdminAmEditModal>
|
|||||||
|
|
||||||
if (!mounted) return;
|
if (!mounted) return;
|
||||||
setState(() => _children = kids);
|
setState(() => _children = kids);
|
||||||
|
_syncDirtyState();
|
||||||
} catch (_) {}
|
} catch (_) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -574,10 +653,10 @@ class _AdminAmEditModalState extends State<AdminAmEditModal>
|
|||||||
style: TextStyle(fontSize: 13),
|
style: TextStyle(fontSize: 13),
|
||||||
),
|
),
|
||||||
value: _disponible,
|
value: _disponible,
|
||||||
onChanged: (v) => setState(() {
|
onChanged: (v) {
|
||||||
_disponible = v;
|
setState(() => _disponible = v);
|
||||||
_dirty = true;
|
_syncDirtyState();
|
||||||
}),
|
},
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@ -756,10 +835,10 @@ class _AdminAmEditModalState extends State<AdminAmEditModal>
|
|||||||
width: 160,
|
width: 160,
|
||||||
child: AdminStatusCapsule(
|
child: AdminStatusCapsule(
|
||||||
statut: _statut,
|
statut: _statut,
|
||||||
onChanged: (v) => setState(() {
|
onChanged: (v) {
|
||||||
_statut = v;
|
setState(() => _statut = v);
|
||||||
_dirty = true;
|
_syncDirtyState();
|
||||||
}),
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
IconButton(
|
IconButton(
|
||||||
|
|||||||
@ -30,7 +30,10 @@ class AdminStatusCapsule extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final value = statuts.contains(statut) ? statut : statuts.first;
|
final value = statut;
|
||||||
|
final items = statuts.contains(statut)
|
||||||
|
? statuts
|
||||||
|
: <String>[statut, ...statuts];
|
||||||
return Container(
|
return Container(
|
||||||
height: 34,
|
height: 34,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
@ -46,7 +49,7 @@ class AdminStatusCapsule extends StatelessWidget {
|
|||||||
isDense: true,
|
isDense: true,
|
||||||
style: const TextStyle(fontSize: 13, color: Colors.black87),
|
style: const TextStyle(fontSize: 13, color: Colors.black87),
|
||||||
icon: const Icon(Icons.arrow_drop_down, size: 20),
|
icon: const Icon(Icons.arrow_drop_down, size: 20),
|
||||||
items: statuts
|
items: items
|
||||||
.map(
|
.map(
|
||||||
(s) => DropdownMenuItem(
|
(s) => DropdownMenuItem(
|
||||||
value: s,
|
value: s,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user