import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:p_tits_pas/models/assistante_maternelle_model.dart'; import 'package:p_tits_pas/services/user_service.dart'; import 'package:p_tits_pas/utils/am_vigilance.dart'; import 'package:p_tits_pas/widgets/admin/common/admin_am_edit_modal.dart'; import 'package:p_tits_pas/widgets/admin/common/admin_select_list_modal.dart'; import 'package:p_tits_pas/widgets/admin/common/admin_user_card.dart'; import 'package:p_tits_pas/widgets/admin/validation_modal_theme.dart'; List _amSelectSubtitleLines(AssistanteMaternelleModel am) { final lines = []; final zone = (am.residenceCity ?? '').trim(); if (zone.isNotEmpty) lines.add('Zone : $zone'); final agrement = (am.approvalNumber ?? '').trim(); if (agrement.isNotEmpty) lines.add('Agrément : $agrement'); final max = am.maxChildren; final free = amExpectedPlacesAvailable( maxChildren: max, childrenCount: am.children.length, ) ?? am.placesAvailable; if (free != null || max != null) { lines.add('Places libres : ${free ?? '–'} / capa. ${max ?? '–'}'); } lines.add('${am.children.length} enfant(s)'); return lines; } /// Sélection d'une AM à rattacher (fiche enfant) — ticket #147. /// S'appuie sur [AdminSelectListModal] (shell partagé avec #146). class AdminSelectAmModal { AdminSelectAmModal._(); static Future show( BuildContext context, { Set excludeIds = const {}, String title = 'Choisir une assistante maternelle', }) { return AdminSelectListModal.show( context, title: title, searchHint: 'Rechercher par nom, prénom ou zone…', emptyMessage: 'Aucune assistante maternelle disponible', noResultsMessage: 'Aucune AM avec place libre pour cette recherche', toggleFilter: const AdminSelectToggleFilter( label: 'Libre', initialValue: true, whenEnabled: amHasFreePlace, ), loadItems: () async { final list = await UserService.getAssistantesMaternelles(); return list .where((am) => !excludeIds.contains(am.user.id)) .toList() ..sort( (a, b) => a.user.fullName .toLowerCase() .compareTo(b.user.fullName.toLowerCase()), ); }, matchesQuery: (am, q) { final u = am.user; final name = u.fullName.toLowerCase(); final fn = (u.prenom ?? '').toLowerCase(); final ln = (u.nom ?? '').toLowerCase(); final zone = (am.residenceCity ?? '').toLowerCase(); final agrement = (am.approvalNumber ?? '').toLowerCase(); return name.contains(q) || fn.contains(q) || ln.contains(q) || zone.contains(q) || agrement.contains(q); }, resolveSelect: (ctx, am, reload) => _resolveAmSelection(ctx, am, reload), itemBuilder: (context, am, onSelect) { final full = !amHasFreePlace(am); return AdminUserCard( title: am.user.fullName, avatarUrl: am.user.photoUrl, fallbackIcon: Icons.face, subtitleLines: _amSelectSubtitleLines(am), vigilanceTooltip: amPlacesVigilanceMessage(am), onCardTap: onSelect, margin: const EdgeInsets.only(bottom: 4), contentPadding: const EdgeInsets.symmetric( horizontal: 10, vertical: 5, ), backgroundColor: full ? const Color(0xFFFFEBEE) : null, borderColor: full ? Colors.red.shade200 : null, actions: [ IconButton( icon: const Icon(Icons.add_link), tooltip: 'Rattacher', onPressed: onSelect, ), ], ); }, ); } static Future _resolveAmSelection( BuildContext context, AssistanteMaternelleModel am, Future Function() reloadList, ) async { if (amHasFreePlace(am)) return am; final selected = await showDialog( context: context, builder: (ctx) => _AmNoPlaceWarningDialog(initialAm: am), ); await reloadList(); return selected; } } /// Avertissement AM saturée + lien vers la fiche pour ajuster les places. class _AmNoPlaceWarningDialog extends StatefulWidget { final AssistanteMaternelleModel initialAm; const _AmNoPlaceWarningDialog({required this.initialAm}); @override State<_AmNoPlaceWarningDialog> createState() => _AmNoPlaceWarningDialogState(); } class _AmNoPlaceWarningDialogState extends State<_AmNoPlaceWarningDialog> { late AssistanteMaternelleModel _am; TapGestureRecognizer? _linkRecognizer; @override void initState() { super.initState(); _am = widget.initialAm; _linkRecognizer = TapGestureRecognizer()..onTap = _openAmFiche; } @override void dispose() { _linkRecognizer?.dispose(); super.dispose(); } Future _openAmFiche() async { if (!mounted) return; await showDialog( context: context, builder: (ctx) => AdminAmEditModal( assistante: _am, onSaved: () async { try { final fresh = await UserService.getAssistanteMaternelle(_am.user.id); if (mounted) setState(() => _am = fresh); } catch (_) {} }, ), ); if (!mounted) return; try { final fresh = await UserService.getAssistanteMaternelle(_am.user.id); if (!mounted) return; setState(() => _am = fresh); if (amHasFreePlace(fresh)) { Navigator.of(context).pop(fresh); } } catch (_) {} } @override Widget build(BuildContext context) { final name = _am.user.fullName.trim().isNotEmpty ? _am.user.fullName.trim() : 'Cette assistante maternelle'; const linkColor = ValidationModalTheme.primaryActionBackground; return AlertDialog( title: const Text('Plus de place disponible'), content: Text.rich( TextSpan( style: const TextStyle(fontSize: 14, color: Colors.black87, height: 1.4), children: [ TextSpan( text: '$name n\'a plus de place libre pour accueillir ' 'un enfant supplémentaire.\n\n', ), const TextSpan(text: 'Vous pouvez '), TextSpan( text: 'ouvrir sa fiche', style: TextStyle( color: linkColor, decoration: TextDecoration.underline, fontWeight: FontWeight.w600, ), recognizer: _linkRecognizer, ), const TextSpan( text: ' pour modifier la capacité ou les places, ' 'puis la sélectionner si une place se libère.', ), ], ), ), actions: [ TextButton( onPressed: () => Navigator.of(context).pop(), child: const Text('Fermer'), ), ], ); } }