import 'package:em2rp/views/widgets/nav/main_drawer.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:em2rp/providers/users_provider.dart'; import 'package:em2rp/models/user_model.dart'; import 'package:em2rp/views/widgets/user_management/user_card.dart'; import 'package:em2rp/views/widgets/user_management/edit_user_dialog.dart'; import 'package:em2rp/utils/colors.dart'; import 'package:em2rp/utils/permission_gate.dart'; import 'package:em2rp/models/role_model.dart'; import 'package:em2rp/views/widgets/nav/custom_app_bar.dart'; import 'package:em2rp/services/data_service.dart'; import 'package:em2rp/services/api_service.dart'; class UserManagementPage extends StatefulWidget { const UserManagementPage({super.key}); @override State createState() => _UserManagementPageState(); } class _UserManagementPageState extends State { @override void initState() { super.initState(); WidgetsBinding.instance.addPostFrameCallback((_) { if (mounted) { Provider.of(context, listen: false).fetchUsers(); } }); } @override Widget build(BuildContext context) { return PermissionGate( requiredPermissions: const ['view_all_users'], fallback: const Scaffold( appBar: CustomAppBar( title: 'Accès refusé', ), body: Center( child: Text( 'Vous n\'avez pas les permissions nécessaires pour accéder à cette page.', textAlign: TextAlign.center, style: TextStyle(fontSize: 16), ), ), ), child: Scaffold( appBar: const CustomAppBar( title: 'Gestion des utilisateurs', ), drawer: const MainDrawer(currentPage: '/account_management'), body: Consumer( builder: (context, usersProvider, child) { if (usersProvider.isLoading) { return const Center(child: CircularProgressIndicator()); } final users = usersProvider.users; if (users.isEmpty) { return const Center(child: Text("Aucun utilisateur trouvé")); } final width = MediaQuery.of(context).size.width; int crossAxisCount; if (width > 1200) { crossAxisCount = 4; } else if (width > 800) { crossAxisCount = 3; } else if (width > 600) { crossAxisCount = 2; } else { crossAxisCount = 1; } return Padding( padding: const EdgeInsets.all(16), child: GridView.builder( itemCount: users.length, gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: crossAxisCount, crossAxisSpacing: 16, mainAxisSpacing: 16, mainAxisExtent: width < 600 ? 80 : 180, ), itemBuilder: (context, i) { final user = users[i]; return UserCard( user: user, onEdit: () => showDialog( context: context, builder: (_) => EditUserDialog(user: user)), onResetPassword: () => _resetPassword(context, user), onDelete: () => _confirmDeleteUser(context, usersProvider, user), ); }, ), ); }, ), floatingActionButton: FloatingActionButton( backgroundColor: AppColors.rouge, child: const Icon(Icons.add, color: AppColors.blanc), onPressed: () => _showCreateUserDialog(context), ), ), ); } void _showCreateUserDialog(BuildContext context) { final firstNameController = TextEditingController(); final lastNameController = TextEditingController(); final emailController = TextEditingController(); final phoneController = TextEditingController(); String? selectedRoleId; List availableRoles = []; bool isLoadingRoles = true; Future loadRoles() async { try { final dataService = DataService(FirebaseFunctionsApiService()); final rolesData = await dataService.getRoles(); availableRoles = rolesData .map((data) => RoleModel.fromMap(data, data['id'] as String)) .toList(); selectedRoleId = availableRoles.isNotEmpty ? availableRoles.first.id : null; isLoadingRoles = false; } catch (e) { isLoadingRoles = false; } } InputDecoration buildInputDecoration(String label, IconData icon) { return InputDecoration( labelText: label, prefixIcon: Icon(icon, color: AppColors.rouge), border: OutlineInputBorder( borderRadius: BorderRadius.circular(8), ), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(8), borderSide: const BorderSide(color: AppColors.rouge, width: 2), ), contentPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), ); } showDialog( context: context, builder: (context) => FutureBuilder( future: loadRoles(), builder: (context, snapshot) { return Dialog( shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(16), ), child: Container( width: 400, padding: const EdgeInsets.all(24), child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.stretch, children: [ Row( children: [ const Icon(Icons.person_add, color: AppColors.rouge), const SizedBox(width: 12), Text( 'Nouvel utilisateur', style: Theme.of(context).textTheme.titleLarge?.copyWith( color: AppColors.noir, fontWeight: FontWeight.bold, ), ), ], ), const SizedBox(height: 24), SingleChildScrollView( child: Column( mainAxisSize: MainAxisSize.min, children: [ TextField( controller: firstNameController, decoration: buildInputDecoration( 'Prénom', Icons.person_outline), ), const SizedBox(height: 16), TextField( controller: lastNameController, decoration: buildInputDecoration('Nom', Icons.person), ), const SizedBox(height: 16), TextField( controller: emailController, decoration: buildInputDecoration( 'Email', Icons.email_outlined), keyboardType: TextInputType.emailAddress, ), const SizedBox(height: 16), TextField( controller: phoneController, decoration: buildInputDecoration( 'Téléphone', Icons.phone_outlined), keyboardType: TextInputType.phone, ), const SizedBox(height: 16), isLoadingRoles ? const CircularProgressIndicator() : DropdownButtonFormField( initialValue: selectedRoleId, decoration: buildInputDecoration('Rôle', Icons.admin_panel_settings_outlined), items: availableRoles.map((role) { return DropdownMenuItem( value: role.id, child: Text(role.name), ); }).toList(), onChanged: (String? newValue) { if (newValue != null) { selectedRoleId = newValue; } }, ), ], ), ), const SizedBox(height: 24), Row( mainAxisAlignment: MainAxisAlignment.end, children: [ TextButton( onPressed: () => Navigator.pop(context), style: TextButton.styleFrom( padding: const EdgeInsets.symmetric( horizontal: 16, vertical: 12), ), child: const Text( 'Annuler', style: TextStyle(color: AppColors.gris), ), ), const SizedBox(width: 8), ElevatedButton( onPressed: () async { if (emailController.text.isEmpty || firstNameController.text.isEmpty || lastNameController.text.isEmpty || selectedRoleId == null) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar( content: Text( 'Veuillez remplir tous les champs obligatoires'), backgroundColor: Colors.red, ), ); return; } try { await Provider.of(context, listen: false) .createUserWithEmailInvite( email: emailController.text, firstName: firstNameController.text, lastName: lastNameController.text, phoneNumber: phoneController.text, roleId: selectedRoleId!, ); if (context.mounted) { Navigator.pop(context); ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text( 'Utilisateur créé avec succès. Email de réinitialisation envoyé à ${emailController.text}', ), backgroundColor: Colors.green, ), ); } } catch (e) { if (context.mounted) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text( 'Erreur lors de la création: ${e.toString()}'), backgroundColor: Colors.red, ), ); } } }, style: ElevatedButton.styleFrom( backgroundColor: AppColors.rouge, padding: const EdgeInsets.symmetric( horizontal: 24, vertical: 12), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8), ), ), child: const Text( 'Inviter', style: TextStyle(color: AppColors.blanc), ), ), ], ), ], ), ), ); }, ), ); } /// Réinitialise le mot de passe d'un utilisateur Future _resetPassword(BuildContext context, UserModel user) async { try { await Provider.of(context, listen: false) .resetPassword(user.email); if (context.mounted) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text( 'Email de réinitialisation envoyé à ${user.email}', ), backgroundColor: Colors.green, ), ); } } catch (e) { if (context.mounted) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text( 'Erreur lors de l\'envoi: ${e.toString()}', ), backgroundColor: Colors.red, ), ); } } } /// Affiche une confirmation avant de supprimer un utilisateur Future _confirmDeleteUser( BuildContext context, UsersProvider usersProvider, UserModel user, ) async { final confirmed = await showDialog( context: context, builder: (context) => AlertDialog( shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(16), ), title: Row( children: [ const Icon(Icons.warning, color: Colors.orange), const SizedBox(width: 12), Expanded( child: Text( 'Confirmer la suppression', style: Theme.of(context).textTheme.titleLarge?.copyWith( fontWeight: FontWeight.bold, ), ), ), ], ), content: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'Êtes-vous sûr de vouloir supprimer cet utilisateur ?', style: Theme.of(context).textTheme.bodyLarge, ), const SizedBox(height: 16), Container( padding: const EdgeInsets.all(12), decoration: BoxDecoration( color: Colors.grey[100], borderRadius: BorderRadius.circular(8), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ const Icon(Icons.person, size: 20, color: AppColors.noir), const SizedBox(width: 8), Expanded( child: Text( '${user.firstName} ${user.lastName}', style: const TextStyle(fontWeight: FontWeight.bold), ), ), ], ), const SizedBox(height: 4), Row( children: [ const Icon(Icons.email, size: 20, color: AppColors.gris), const SizedBox(width: 8), Expanded( child: Text( user.email, style: TextStyle(color: Colors.grey[700]), ), ), ], ), ], ), ), const SizedBox(height: 16), Text( 'Cette action est irréversible. L\'utilisateur sera supprimé et désattribué de tous les événements liés', style: Theme.of(context).textTheme.bodySmall?.copyWith( color: Colors.red[700], fontStyle: FontStyle.italic, ), ), ], ), actions: [ TextButton( onPressed: () => Navigator.of(context).pop(false), style: TextButton.styleFrom( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), ), child: const Text( 'Annuler', style: TextStyle(color: AppColors.gris), ), ), ElevatedButton( onPressed: () => Navigator.of(context).pop(true), style: ElevatedButton.styleFrom( backgroundColor: Colors.red, padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8), ), ), child: const Text( 'Supprimer', style: TextStyle(color: Colors.white), ), ), ], ), ); if (confirmed == true && context.mounted) { try { await usersProvider.deleteUser(user.uid); if (context.mounted) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text( 'Utilisateur ${user.firstName} ${user.lastName} supprimé avec succès', ), backgroundColor: Colors.green, ), ); } } catch (e) { if (context.mounted) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text( 'Erreur lors de la suppression: ${e.toString()}', ), backgroundColor: Colors.red, ), ); } } } } }