feat(#157): alerte enfants sans responsable + rattachement foyer.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -65,6 +65,9 @@ class _AdminChildDetailModalState extends State<AdminChildDetailModal> {
|
||||
/// Famille choisie en mode création (#132).
|
||||
AdminFamilleFoyer? _selectedFamily;
|
||||
|
||||
/// Liens parents locaux (édition) — mis à jour après rattachement foyer (#157).
|
||||
List<EnfantParentLink>? _localParentLinks;
|
||||
|
||||
/// Photo locale (création) — upload multipart `photo`.
|
||||
Uint8List? _photoBytes;
|
||||
String? _photoFilename;
|
||||
@@ -262,10 +265,14 @@ class _AdminChildDetailModalState extends State<AdminChildDetailModal> {
|
||||
}
|
||||
|
||||
List<EnfantParentLink> get _parentLinks =>
|
||||
(widget.enfant?.parentLinks ?? const <EnfantParentLink>[])
|
||||
(_localParentLinks ??
|
||||
widget.enfant?.parentLinks ??
|
||||
const <EnfantParentLink>[])
|
||||
.where((l) => l.parentId.trim().isNotEmpty)
|
||||
.toList();
|
||||
|
||||
bool get _isOrphan => !widget.isCreating && _parentLinks.isEmpty;
|
||||
|
||||
Future<void> _openParent(EnfantParentLink link) async {
|
||||
if (_busy) return;
|
||||
final id = link.parentId.trim();
|
||||
@@ -580,6 +587,7 @@ class _AdminChildDetailModalState extends State<AdminChildDetailModal> {
|
||||
if (!enfantStatusValues.contains(_status)) {
|
||||
_status = 'sans_garde';
|
||||
}
|
||||
_localParentLinks = enfant.parentLinks;
|
||||
_coerceGenderForStatus();
|
||||
});
|
||||
} catch (_) {
|
||||
@@ -960,7 +968,9 @@ class _AdminChildDetailModalState extends State<AdminChildDetailModal> {
|
||||
padding: const EdgeInsets.only(top: 16),
|
||||
child: Align(
|
||||
alignment: Alignment.bottomCenter,
|
||||
child: _placementBlock(),
|
||||
child: SingleChildScrollView(
|
||||
child: _placementBlock(),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -1219,6 +1229,24 @@ class _AdminChildDetailModalState extends State<AdminChildDetailModal> {
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
if (_isOrphan) ...[
|
||||
Text(
|
||||
'Sélection du dossier de la famille',
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Colors.red.shade800,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
'Aucun responsable rattaché — choisissez un foyer',
|
||||
style: TextStyle(fontSize: 12, color: Colors.red.shade700),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
_familyPlacementSection(),
|
||||
const SizedBox(height: 16),
|
||||
],
|
||||
Text(
|
||||
_placementTitle,
|
||||
style: TextStyle(
|
||||
@@ -1240,10 +1268,45 @@ class _AdminChildDetailModalState extends State<AdminChildDetailModal> {
|
||||
title: 'Choisir une famille',
|
||||
);
|
||||
if (selected == null || !mounted) return;
|
||||
setState(() {
|
||||
_selectedFamily = selected;
|
||||
_dirty = true;
|
||||
});
|
||||
|
||||
if (widget.isCreating) {
|
||||
setState(() {
|
||||
_selectedFamily = selected;
|
||||
_dirty = true;
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// Édition orphelin (#157) : rattache immédiatement au foyer.
|
||||
final enfantId = widget.enfant?.id;
|
||||
if (enfantId == null || enfantId.isEmpty) return;
|
||||
|
||||
setState(() => _saving = true);
|
||||
try {
|
||||
for (final parentId in selected.parentUserIds) {
|
||||
await UserService.attachEnfantToParent(
|
||||
parentUserId: parentId,
|
||||
enfantId: enfantId,
|
||||
);
|
||||
}
|
||||
final refreshed = await UserService.getEnfant(enfantId);
|
||||
if (!mounted) return;
|
||||
setState(() {
|
||||
_localParentLinks = refreshed.parentLinks;
|
||||
_selectedFamily = selected;
|
||||
_saving = false;
|
||||
});
|
||||
widget.onSaved?.call();
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(content: Text('Enfant rattaché au foyer')),
|
||||
);
|
||||
} catch (e) {
|
||||
if (!mounted) return;
|
||||
setState(() => _saving = false);
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(content: Text(e.toString().replaceFirst('Exception: ', ''))),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Widget _familyPlacementSection() {
|
||||
|
||||
Reference in New Issue
Block a user