From 5da2ab900597d222bb88210f551365956f3a3af1 Mon Sep 17 00:00:00 2001 From: Julien Martin Date: Fri, 20 Feb 2026 11:35:42 +0100 Subject: [PATCH] =?UTF-8?q?feat(#93):=20optimiser=20l=E2=80=99affichage=20?= =?UTF-8?q?Parents/AM=20avec=20modale=20de=20d=C3=A9tails?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Intègre un bandeau unique (onglets à gauche, recherche/filtre en pilule, bouton Ajouter à droite) et compacte les cartes Parents/AM avec ouverture d’une modale complète sur Modifier (croix, actions Modifier/Supprimer). Co-authored-by: Cursor --- .../admin/admin_management_widget.dart | 50 ++---- ...sistante_maternelle_management_widget.dart | 139 ++++++++-------- .../admin/common/admin_detail_modal.dart | 138 ++++++++++++++++ .../admin/common/admin_list_header.dart | 58 ------- .../widgets/admin/common/admin_user_card.dart | 78 +++++++-- .../lib/widgets/admin/dashboard_admin.dart | 78 +++++++-- .../admin/parent_managmant_widget.dart | 153 ++++++++---------- 7 files changed, 429 insertions(+), 265 deletions(-) create mode 100644 frontend/lib/widgets/admin/common/admin_detail_modal.dart delete mode 100644 frontend/lib/widgets/admin/common/admin_list_header.dart diff --git a/frontend/lib/widgets/admin/admin_management_widget.dart b/frontend/lib/widgets/admin/admin_management_widget.dart index 2b1efd4..14ef51c 100644 --- a/frontend/lib/widgets/admin/admin_management_widget.dart +++ b/frontend/lib/widgets/admin/admin_management_widget.dart @@ -1,12 +1,16 @@ import 'package:flutter/material.dart'; import 'package:p_tits_pas/models/user.dart'; import 'package:p_tits_pas/services/user_service.dart'; -import 'package:p_tits_pas/widgets/admin/common/admin_list_header.dart'; import 'package:p_tits_pas/widgets/admin/common/admin_list_state.dart'; import 'package:p_tits_pas/widgets/admin/common/admin_user_card.dart'; class AdminManagementWidget extends StatefulWidget { - const AdminManagementWidget({super.key}); + final String searchQuery; + + const AdminManagementWidget({ + super.key, + required this.searchQuery, + }); @override State createState() => _AdminManagementWidgetState(); @@ -16,21 +20,15 @@ class _AdminManagementWidgetState extends State { bool _isLoading = false; String? _error; List _admins = []; - List _filteredAdmins = []; - final TextEditingController _searchController = TextEditingController(); @override void initState() { super.initState(); _loadAdmins(); - _searchController.addListener(_onSearchChanged); } @override - void dispose() { - _searchController.dispose(); - super.dispose(); - } + void dispose() => super.dispose(); Future _loadAdmins() async { setState(() { @@ -42,7 +40,6 @@ class _AdminManagementWidgetState extends State { if (!mounted) return; setState(() { _admins = list; - _filteredAdmins = list; _isLoading = false; }); } catch (e) { @@ -54,42 +51,29 @@ class _AdminManagementWidgetState extends State { } } - void _onSearchChanged() { - final query = _searchController.text.toLowerCase(); - setState(() { - _filteredAdmins = _admins.where((u) { - final name = u.fullName.toLowerCase(); - final email = u.email.toLowerCase(); - return name.contains(query) || email.contains(query); - }).toList(); - }); - } - @override Widget build(BuildContext context) { + final query = widget.searchQuery.toLowerCase(); + final filteredAdmins = _admins.where((u) { + final name = u.fullName.toLowerCase(); + final email = u.email.toLowerCase(); + return name.contains(query) || email.contains(query); + }).toList(); + return Padding( padding: const EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ - AdminListHeader( - searchController: _searchController, - searchHint: 'Rechercher un administrateur...', - actionLabel: 'Créer un admin', - onActionPressed: () { - // TODO: Créer admin - }, - ), - const SizedBox(height: 16), AdminListState( isLoading: _isLoading, error: _error, - isEmpty: _filteredAdmins.isEmpty, + isEmpty: filteredAdmins.isEmpty, emptyMessage: 'Aucun administrateur trouvé.', list: ListView.builder( - itemCount: _filteredAdmins.length, + itemCount: filteredAdmins.length, itemBuilder: (context, index) { - final user = _filteredAdmins[index]; + final user = filteredAdmins[index]; return AdminUserCard( title: user.fullName, subtitleLines: [ diff --git a/frontend/lib/widgets/admin/assistante_maternelle_management_widget.dart b/frontend/lib/widgets/admin/assistante_maternelle_management_widget.dart index c9aa010..e91d570 100644 --- a/frontend/lib/widgets/admin/assistante_maternelle_management_widget.dart +++ b/frontend/lib/widgets/admin/assistante_maternelle_management_widget.dart @@ -1,12 +1,19 @@ 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/widgets/admin/common/admin_list_header.dart'; +import 'package:p_tits_pas/widgets/admin/common/admin_detail_modal.dart'; import 'package:p_tits_pas/widgets/admin/common/admin_list_state.dart'; import 'package:p_tits_pas/widgets/admin/common/admin_user_card.dart'; class AssistanteMaternelleManagementWidget extends StatefulWidget { - const AssistanteMaternelleManagementWidget({super.key}); + final String searchQuery; + final int? capacityMin; + + const AssistanteMaternelleManagementWidget({ + super.key, + required this.searchQuery, + this.capacityMin, + }); @override State createState() => @@ -18,25 +25,15 @@ class _AssistanteMaternelleManagementWidgetState bool _isLoading = false; String? _error; List _assistantes = []; - List _filteredAssistantes = []; - - final TextEditingController _zoneController = TextEditingController(); - final TextEditingController _capacityController = TextEditingController(); @override void initState() { super.initState(); _loadAssistantes(); - _zoneController.addListener(_filter); - _capacityController.addListener(_filter); } @override - void dispose() { - _zoneController.dispose(); - _capacityController.dispose(); - super.dispose(); - } + void dispose() => super.dispose(); Future _loadAssistantes() async { setState(() { @@ -48,7 +45,6 @@ class _AssistanteMaternelleManagementWidgetState if (!mounted) return; setState(() { _assistantes = list; - _filter(); _isLoading = false; }); } catch (e) { @@ -60,50 +56,38 @@ class _AssistanteMaternelleManagementWidgetState } } - void _filter() { - final zoneQuery = _zoneController.text.toLowerCase(); - final capacityQuery = int.tryParse(_capacityController.text); - - setState(() { - _filteredAssistantes = _assistantes.where((am) { - final matchesZone = zoneQuery.isEmpty || - (am.residenceCity?.toLowerCase().contains(zoneQuery) ?? false); - final matchesCapacity = capacityQuery == null || - (am.maxChildren != null && am.maxChildren! >= capacityQuery); - return matchesZone && matchesCapacity; - }).toList(); - }); - } - @override Widget build(BuildContext context) { + final query = widget.searchQuery.toLowerCase(); + final filteredAssistantes = _assistantes.where((am) { + final matchesName = am.user.fullName.toLowerCase().contains(query) || + am.user.email.toLowerCase().contains(query) || + (am.residenceCity?.toLowerCase().contains(query) ?? false); + final matchesCapacity = widget.capacityMin == null || + (am.maxChildren != null && am.maxChildren! >= widget.capacityMin!); + return matchesName && matchesCapacity; + }).toList(); + return Padding( padding: const EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - AdminListHeader( - searchController: _zoneController, - searchHint: 'Rechercher une zone géographique...', - filters: _buildFilters(), - ), - const SizedBox(height: 16), AdminListState( isLoading: _isLoading, error: _error, - isEmpty: _filteredAssistantes.isEmpty, + isEmpty: filteredAssistantes.isEmpty, emptyMessage: 'Aucune assistante maternelle trouvée.', list: ListView.builder( - itemCount: _filteredAssistantes.length, + itemCount: filteredAssistantes.length, itemBuilder: (context, index) { - final assistante = _filteredAssistantes[index]; + final assistante = filteredAssistantes[index]; return AdminUserCard( title: assistante.user.fullName, avatarUrl: assistante.user.photoUrl, fallbackIcon: Icons.face, subtitleLines: [ assistante.user.email, - 'N° Agrément : ${assistante.approvalNumber ?? 'N/A'}', 'Zone : ${assistante.residenceCity ?? 'N/A'} | Capacité : ${assistante.maxChildren ?? 0}', ], actions: [ @@ -111,14 +95,7 @@ class _AssistanteMaternelleManagementWidgetState icon: const Icon(Icons.edit), tooltip: 'Modifier', onPressed: () { - // TODO: Ajouter modification - }, - ), - IconButton( - icon: const Icon(Icons.delete), - tooltip: 'Supprimer', - onPressed: () { - // TODO: Ajouter suppression + _openAssistanteDetails(assistante); }, ), ], @@ -131,24 +108,58 @@ class _AssistanteMaternelleManagementWidgetState ); } - Widget _buildFilters() { - return Wrap( - spacing: 16, - runSpacing: 8, - children: [ - SizedBox( - width: 240, - child: TextField( - controller: _capacityController, - decoration: const InputDecoration( - labelText: 'Capacité minimum', - border: OutlineInputBorder(), - isDense: true, - ), - keyboardType: TextInputType.number, + void _openAssistanteDetails(AssistanteMaternelleModel assistante) { + showDialog( + context: context, + builder: (context) => AdminDetailModal( + title: assistante.user.fullName.isEmpty + ? 'Assistante maternelle' + : assistante.user.fullName, + subtitle: assistante.user.email, + fields: [ + AdminDetailField(label: 'ID', value: _v(assistante.user.id)), + AdminDetailField( + label: 'Numero agrement', + value: _v(assistante.approvalNumber), ), - ), - ], + AdminDetailField( + label: 'Ville residence', + value: _v(assistante.residenceCity), + ), + AdminDetailField( + label: 'Capacite max', + value: assistante.maxChildren?.toString() ?? '-', + ), + AdminDetailField( + label: 'Places disponibles', + value: assistante.placesAvailable?.toString() ?? '-', + ), + AdminDetailField( + label: 'Telephone', + value: _v(assistante.user.telephone), + ), + AdminDetailField(label: 'Adresse', value: _v(assistante.user.adresse)), + AdminDetailField(label: 'Ville', value: _v(assistante.user.ville)), + AdminDetailField( + label: 'Code postal', + value: _v(assistante.user.codePostal), + ), + ], + onEdit: () { + Navigator.of(context).pop(); + ScaffoldMessenger.of(this.context).showSnackBar( + const SnackBar(content: Text('Action Modifier a implementer')), + ); + }, + onDelete: () { + Navigator.of(context).pop(); + ScaffoldMessenger.of(this.context).showSnackBar( + const SnackBar(content: Text('Action Supprimer a implementer')), + ); + }, + ), ); } + + String _v(String? value) => (value == null || value.isEmpty) ? '-' : value; } diff --git a/frontend/lib/widgets/admin/common/admin_detail_modal.dart b/frontend/lib/widgets/admin/common/admin_detail_modal.dart new file mode 100644 index 0000000..affc0d8 --- /dev/null +++ b/frontend/lib/widgets/admin/common/admin_detail_modal.dart @@ -0,0 +1,138 @@ +import 'package:flutter/material.dart'; + +class AdminDetailField { + final String label; + final String value; + + const AdminDetailField({ + required this.label, + required this.value, + }); +} + +class AdminDetailModal extends StatelessWidget { + final String title; + final String? subtitle; + final List fields; + final VoidCallback onEdit; + final VoidCallback onDelete; + + const AdminDetailModal({ + super.key, + required this.title, + this.subtitle, + required this.fields, + required this.onEdit, + required this.onDelete, + }); + + @override + Widget build(BuildContext context) { + return Dialog( + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)), + child: ConstrainedBox( + constraints: const BoxConstraints(maxWidth: 620), + child: Padding( + padding: const EdgeInsets.all(18), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + title, + style: const TextStyle( + fontSize: 18, + fontWeight: FontWeight.w700, + ), + ), + if (subtitle != null && subtitle!.isNotEmpty) ...[ + const SizedBox(height: 4), + Text( + subtitle!, + style: const TextStyle(color: Colors.black54), + ), + ], + ], + ), + ), + IconButton( + tooltip: 'Fermer', + onPressed: () => Navigator.of(context).pop(), + icon: const Icon(Icons.close), + ), + ], + ), + const SizedBox(height: 8), + const Divider(height: 1), + const SizedBox(height: 12), + Flexible( + child: SingleChildScrollView( + child: Column( + children: fields + .map( + (field) => Padding( + padding: const EdgeInsets.symmetric(vertical: 6), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox( + width: 180, + child: Text( + field.label, + style: const TextStyle( + fontWeight: FontWeight.w600, + color: Colors.black87, + ), + ), + ), + Expanded( + child: Text( + field.value, + style: const TextStyle(color: Colors.black87), + ), + ), + ], + ), + ), + ) + .toList(), + ), + ), + ), + const SizedBox(height: 14), + Align( + alignment: Alignment.centerRight, + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + OutlinedButton.icon( + onPressed: onDelete, + icon: const Icon(Icons.delete_outline), + label: const Text('Supprimer'), + style: OutlinedButton.styleFrom( + foregroundColor: Colors.red.shade700, + side: BorderSide(color: Colors.red.shade300), + ), + ), + const SizedBox(width: 10), + ElevatedButton.icon( + onPressed: onEdit, + icon: const Icon(Icons.edit), + label: const Text('Modifier'), + ), + ], + ), + ), + ], + ), + ), + ), + ); + } +} diff --git a/frontend/lib/widgets/admin/common/admin_list_header.dart b/frontend/lib/widgets/admin/common/admin_list_header.dart deleted file mode 100644 index 185c9e2..0000000 --- a/frontend/lib/widgets/admin/common/admin_list_header.dart +++ /dev/null @@ -1,58 +0,0 @@ -import 'package:flutter/material.dart'; - -class AdminListHeader extends StatelessWidget { - final TextEditingController searchController; - final String searchHint; - final String? actionLabel; - final VoidCallback? onActionPressed; - final Widget? filters; - - const AdminListHeader({ - super.key, - required this.searchController, - required this.searchHint, - this.actionLabel, - this.onActionPressed, - this.filters, - }); - - @override - Widget build(BuildContext context) { - return Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - Row( - children: [ - Expanded( - child: TextField( - controller: searchController, - decoration: InputDecoration( - hintText: searchHint, - prefixIcon: const Icon(Icons.search), - border: const OutlineInputBorder(), - isDense: true, - contentPadding: const EdgeInsets.symmetric( - horizontal: 12, - vertical: 12, - ), - ), - ), - ), - if (actionLabel != null && onActionPressed != null) ...[ - const SizedBox(width: 16), - ElevatedButton.icon( - onPressed: onActionPressed, - icon: const Icon(Icons.add), - label: Text(actionLabel!), - ), - ], - ], - ), - if (filters != null) ...[ - const SizedBox(height: 12), - filters!, - ], - ], - ); - } -} diff --git a/frontend/lib/widgets/admin/common/admin_user_card.dart b/frontend/lib/widgets/admin/common/admin_user_card.dart index d9fe1bc..8745d4c 100644 --- a/frontend/lib/widgets/admin/common/admin_user_card.dart +++ b/frontend/lib/widgets/admin/common/admin_user_card.dart @@ -20,20 +20,72 @@ class AdminUserCard extends StatelessWidget { Widget build(BuildContext context) { return Card( margin: const EdgeInsets.only(bottom: 12), - child: ListTile( - leading: CircleAvatar( - backgroundImage: avatarUrl != null ? NetworkImage(avatarUrl!) : null, - child: avatarUrl == null ? Icon(fallbackIcon) : null, - ), - title: Text(title.isNotEmpty ? title : 'Sans nom'), - subtitle: Text(subtitleLines.join('\n')), - isThreeLine: subtitleLines.length > 1, - trailing: actions.isEmpty - ? null - : Row( - mainAxisSize: MainAxisSize.min, - children: actions, + elevation: 0, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + side: BorderSide(color: Colors.grey.shade300), + ), + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 10), + child: Row( + children: [ + CircleAvatar( + radius: 14, + backgroundColor: const Color(0xFFEDE5FA), + backgroundImage: + avatarUrl != null ? NetworkImage(avatarUrl!) : null, + child: avatarUrl == null + ? Icon( + fallbackIcon, + size: 16, + color: const Color(0xFF6B3FA0), + ) + : null, + ), + const SizedBox(width: 10), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + title.isNotEmpty ? title : 'Sans nom', + style: const TextStyle( + fontWeight: FontWeight.w600, + fontSize: 14, + ), + ), + const SizedBox(height: 2), + ...subtitleLines.map( + (line) => Text( + line, + style: const TextStyle( + color: Colors.black54, + fontSize: 12, + ), + ), + ), + ], ), + ), + if (actions.isNotEmpty) + IconTheme( + data: const IconThemeData(size: 18), + child: IconButtonTheme( + data: IconButtonThemeData( + style: IconButton.styleFrom( + visualDensity: VisualDensity.compact, + padding: const EdgeInsets.all(4), + minimumSize: const Size(28, 28), + ), + ), + child: Row( + mainAxisSize: MainAxisSize.min, + children: actions, + ), + ), + ), + ], + ), ), ); } diff --git a/frontend/lib/widgets/admin/dashboard_admin.dart b/frontend/lib/widgets/admin/dashboard_admin.dart index 18d16ea..ff1aa3b 100644 --- a/frontend/lib/widgets/admin/dashboard_admin.dart +++ b/frontend/lib/widgets/admin/dashboard_admin.dart @@ -136,39 +136,91 @@ class DashboardAppBarAdmin extends StatelessWidget class DashboardUserManagementSubBar extends StatelessWidget { final int selectedSubIndex; final ValueChanged onSubTabChange; + final TextEditingController searchController; + final String searchHint; + final Widget? filterControl; + final VoidCallback? onAddPressed; + final String addLabel; const DashboardUserManagementSubBar({ Key? key, required this.selectedSubIndex, required this.onSubTabChange, + required this.searchController, + required this.searchHint, + this.filterControl, + this.onAddPressed, + this.addLabel = '+ Ajouter', }) : super(key: key); @override Widget build(BuildContext context) { return Container( - height: 48, + height: 56, decoration: BoxDecoration( color: Colors.grey.shade100, border: Border(bottom: BorderSide(color: Colors.grey.shade300)), ), padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 6), - child: Center( - child: Row( - mainAxisSize: MainAxisSize.min, - children: [ - _buildSubNavItem(context, 'Gestionnaires', 0), - const SizedBox(width: 16), - _buildSubNavItem(context, 'Parents', 1), - const SizedBox(width: 16), - _buildSubNavItem(context, 'Assistantes maternelles', 2), - const SizedBox(width: 16), - _buildSubNavItem(context, 'Administrateurs', 3), + child: Row( + children: [ + _buildSubNavItem(context, 'Gestionnaires', 0), + const SizedBox(width: 12), + _buildSubNavItem(context, 'Parents', 1), + const SizedBox(width: 12), + _buildSubNavItem(context, 'Assistantes maternelles', 2), + const SizedBox(width: 12), + _buildSubNavItem(context, 'Administrateurs', 3), + const SizedBox(width: 36), + _pillField( + width: 320, + child: TextField( + controller: searchController, + decoration: InputDecoration( + hintText: searchHint, + prefixIcon: const Icon(Icons.search, size: 18), + border: InputBorder.none, + isDense: true, + contentPadding: const EdgeInsets.symmetric( + horizontal: 10, + vertical: 8, + ), + ), + ), + ), + if (filterControl != null) ...[ + const SizedBox(width: 12), + _pillField(width: 150, child: filterControl!), ], - ), + const Spacer(), + _buildAddButton(), + ], ), ); } + Widget _pillField({required double width, required Widget child}) { + return Container( + width: width, + height: 34, + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(18), + border: Border.all(color: Colors.black26), + ), + alignment: Alignment.centerLeft, + child: child, + ); + } + + Widget _buildAddButton() { + return ElevatedButton.icon( + onPressed: onAddPressed, + icon: const Icon(Icons.add), + label: Text(addLabel), + ); + } + Widget _buildSubNavItem(BuildContext context, String title, int index) { final bool isActive = index == selectedSubIndex; return InkWell( diff --git a/frontend/lib/widgets/admin/parent_managmant_widget.dart b/frontend/lib/widgets/admin/parent_managmant_widget.dart index cac73c8..c6d302f 100644 --- a/frontend/lib/widgets/admin/parent_managmant_widget.dart +++ b/frontend/lib/widgets/admin/parent_managmant_widget.dart @@ -1,12 +1,19 @@ import 'package:flutter/material.dart'; import 'package:p_tits_pas/models/parent_model.dart'; import 'package:p_tits_pas/services/user_service.dart'; -import 'package:p_tits_pas/widgets/admin/common/admin_list_header.dart'; +import 'package:p_tits_pas/widgets/admin/common/admin_detail_modal.dart'; import 'package:p_tits_pas/widgets/admin/common/admin_list_state.dart'; import 'package:p_tits_pas/widgets/admin/common/admin_user_card.dart'; class ParentManagementWidget extends StatefulWidget { - const ParentManagementWidget({super.key}); + final String searchQuery; + final String? statusFilter; + + const ParentManagementWidget({ + super.key, + required this.searchQuery, + this.statusFilter, + }); @override State createState() => _ParentManagementWidgetState(); @@ -16,23 +23,15 @@ class _ParentManagementWidgetState extends State { bool _isLoading = false; String? _error; List _parents = []; - List _filteredParents = []; - - final TextEditingController _searchController = TextEditingController(); - String? _selectedStatus; @override void initState() { super.initState(); _loadParents(); - _searchController.addListener(_filter); } @override - void dispose() { - _searchController.dispose(); - super.dispose(); - } + void dispose() => super.dispose(); Future _loadParents() async { setState(() { @@ -44,7 +43,6 @@ class _ParentManagementWidgetState extends State { if (!mounted) return; setState(() { _parents = list; - _filter(); // Apply initial filter (if any) _isLoading = false; }); } catch (e) { @@ -56,70 +54,44 @@ class _ParentManagementWidgetState extends State { } } - void _filter() { - final query = _searchController.text.toLowerCase(); - setState(() { - _filteredParents = _parents.where((p) { - final matchesName = p.user.fullName.toLowerCase().contains(query) || - p.user.email.toLowerCase().contains(query); - final matchesStatus = - _selectedStatus == null || p.user.statut == _selectedStatus; - - return matchesName && matchesStatus; - }).toList(); - }); - } - @override Widget build(BuildContext context) { + final query = widget.searchQuery.toLowerCase(); + final filteredParents = _parents.where((p) { + final matchesName = p.user.fullName.toLowerCase().contains(query) || + p.user.email.toLowerCase().contains(query); + final matchesStatus = + widget.statusFilter == null || p.user.statut == widget.statusFilter; + return matchesName && matchesStatus; + }).toList(); + return Padding( padding: const EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - AdminListHeader( - searchController: _searchController, - searchHint: 'Rechercher un parent...', - filters: _buildFilters(), - ), - const SizedBox(height: 16), AdminListState( isLoading: _isLoading, error: _error, - isEmpty: _filteredParents.isEmpty, + isEmpty: filteredParents.isEmpty, emptyMessage: 'Aucun parent trouvé.', list: ListView.builder( - itemCount: _filteredParents.length, + itemCount: filteredParents.length, itemBuilder: (context, index) { - final parent = _filteredParents[index]; + final parent = filteredParents[index]; return AdminUserCard( title: parent.user.fullName, avatarUrl: parent.user.photoUrl, subtitleLines: [ parent.user.email, - 'Statut : ${_displayStatus(parent.user.statut)}', - 'Enfants : ${parent.childrenCount}', + 'Statut : ${_displayStatus(parent.user.statut)} | Enfants : ${parent.childrenCount}', ], actions: [ - IconButton( - icon: const Icon(Icons.visibility), - tooltip: 'Voir dossier', - onPressed: () { - // TODO: Voir le statut du dossier - }, - ), IconButton( icon: const Icon(Icons.edit), tooltip: 'Modifier', onPressed: () { - // TODO: Modifier parent - }, - ), - IconButton( - icon: const Icon(Icons.delete), - tooltip: 'Supprimer', - onPressed: () { - // TODO: Supprimer compte + _openParentDetails(parent); }, ), ], @@ -132,38 +104,6 @@ class _ParentManagementWidgetState extends State { ); } - Widget _buildFilters() { - return SizedBox( - width: 240, - child: DropdownButtonFormField( - decoration: const InputDecoration( - labelText: 'Statut', - border: OutlineInputBorder(), - isDense: true, - ), - value: _selectedStatus, - items: const [ - DropdownMenuItem(value: null, child: Text('Tous')), - DropdownMenuItem(value: 'actif', child: Text('Actif')), - DropdownMenuItem( - value: 'en_attente', - child: Text('En attente'), - ), - DropdownMenuItem( - value: 'suspendu', - child: Text('Suspendu'), - ), - ], - onChanged: (value) { - setState(() { - _selectedStatus = value; - }); - _filter(); - }, - ), - ); - } - String _displayStatus(String? status) { switch (status) { case 'actif': @@ -176,4 +116,49 @@ class _ParentManagementWidgetState extends State { return 'Inconnu'; } } + + void _openParentDetails(ParentModel parent) { + showDialog( + context: context, + builder: (context) => AdminDetailModal( + title: parent.user.fullName.isEmpty ? 'Parent' : parent.user.fullName, + subtitle: parent.user.email, + fields: [ + AdminDetailField(label: 'ID', value: _v(parent.user.id)), + AdminDetailField( + label: 'Statut', + value: _displayStatus(parent.user.statut), + ), + AdminDetailField( + label: 'Telephone', + value: _v(parent.user.telephone), + ), + AdminDetailField(label: 'Adresse', value: _v(parent.user.adresse)), + AdminDetailField(label: 'Ville', value: _v(parent.user.ville)), + AdminDetailField( + label: 'Code postal', + value: _v(parent.user.codePostal), + ), + AdminDetailField( + label: 'Nombre d\'enfants', + value: parent.childrenCount.toString(), + ), + ], + onEdit: () { + Navigator.of(context).pop(); + ScaffoldMessenger.of(this.context).showSnackBar( + const SnackBar(content: Text('Action Modifier a implementer')), + ); + }, + onDelete: () { + Navigator.of(context).pop(); + ScaffoldMessenger.of(this.context).showSnackBar( + const SnackBar(content: Text('Action Supprimer a implementer')), + ); + }, + ), + ); + } + + String _v(String? value) => (value == null || value.isEmpty) ? '-' : value; }