import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:manager_app/Models/managerContext.dart'; import 'package:manager_app/app_context.dart'; import 'package:manager_app/constants.dart'; import 'package:provider/provider.dart'; class UsersScreen extends StatefulWidget { const UsersScreen({Key? key}) : super(key: key); @override _UsersScreenState createState() => _UsersScreenState(); } class _UsersScreenState extends State { List> _users = []; bool _loading = true; static String _roleName(int? v) { switch (v) { case 0: return 'SuperAdmin'; case 1: return 'InstanceAdmin'; case 2: return 'ContentEditor'; case 3: return 'Viewer'; default: return '—'; } } // Roles the caller is allowed to assign (can't assign higher than own role) List _allowedRoles(int callerRoleValue) => [0, 1, 2, 3].where((r) => r >= callerRoleValue).toList(); Future _loadUsers(ManagerAppContext ctx) async { try { final response = await ctx.clientAPI!.userApi!.userGetWithHttpInfo(); if (response.statusCode == 200) { final List json = jsonDecode(utf8.decode(response.bodyBytes)); setState(() { _users = json.cast>(); _loading = false; }); } } catch (e) { setState(() => _loading = false); } } Future _createUser(ManagerAppContext ctx, String email, String firstName, String lastName, String password, int roleValue) async { final body = { 'email': email, 'firstName': firstName, 'lastName': lastName, 'password': password, 'role': roleValue, }; await ctx.clientAPI!.apiApi!.invokeAPI( '/api/User', 'POST', [], body, {}, {}, 'application/json'); await _loadUsers(ctx); } Future _updateUser(ManagerAppContext ctx, String id, String firstName, String lastName, int roleValue) async { final body = { 'id': id, 'firstName': firstName, 'lastName': lastName, 'role': roleValue, }; await ctx.clientAPI!.apiApi!.invokeAPI( '/api/User', 'PUT', [], body, {}, {}, 'application/json'); await _loadUsers(ctx); } Future _deleteUser(ManagerAppContext ctx, String id) async { await ctx.clientAPI!.userApi!.userDeleteUser(id); await _loadUsers(ctx); } void _showCreateDialog(BuildContext context, ManagerAppContext ctx) { final callerRole = ctx.role?.value ?? 2; final emailCtrl = TextEditingController(); final firstCtrl = TextEditingController(); final lastCtrl = TextEditingController(); final passCtrl = TextEditingController(); int selectedRole = callerRole; // default: same as caller showDialog( context: context, builder: (_) => StatefulBuilder(builder: (ctx2, setLocal) { return AlertDialog( title: const Text('Créer un utilisateur'), content: SingleChildScrollView( child: Column(mainAxisSize: MainAxisSize.min, children: [ TextField(controller: emailCtrl, decoration: const InputDecoration(labelText: 'Email')), TextField(controller: firstCtrl, decoration: const InputDecoration(labelText: 'Prénom')), TextField(controller: lastCtrl, decoration: const InputDecoration(labelText: 'Nom')), TextField(controller: passCtrl, obscureText: true, decoration: const InputDecoration(labelText: 'Mot de passe')), const SizedBox(height: 8), Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text('Rôle', style: TextStyle(fontSize: 12, color: Colors.grey)), DropdownButton( value: selectedRole, isExpanded: true, items: _allowedRoles(callerRole) .map((r) => DropdownMenuItem(value: r, child: Text(_roleName(r)))) .toList(), onChanged: (v) => setLocal(() => selectedRole = v!), ), ], ), ]), ), actions: [ TextButton(onPressed: () => Navigator.pop(ctx2), child: const Text('Annuler')), ElevatedButton( onPressed: () async { Navigator.pop(ctx2); await _createUser(ctx, emailCtrl.text, firstCtrl.text, lastCtrl.text, passCtrl.text, selectedRole); }, child: const Text('Créer'), ), ], ); }), ); } void _showEditDialog(BuildContext context, ManagerAppContext ctx, Map user) { final callerRole = ctx.role?.value ?? 2; final firstCtrl = TextEditingController(text: user['firstName'] as String? ?? ''); final lastCtrl = TextEditingController(text: user['lastName'] as String? ?? ''); int selectedRole = (user['role'] as int?) ?? callerRole; showDialog( context: context, builder: (_) => StatefulBuilder(builder: (ctx2, setLocal) { return AlertDialog( title: const Text('Modifier l\'utilisateur'), content: SingleChildScrollView( child: Column(mainAxisSize: MainAxisSize.min, children: [ TextField(controller: firstCtrl, decoration: const InputDecoration(labelText: 'Prénom')), TextField(controller: lastCtrl, decoration: const InputDecoration(labelText: 'Nom')), const SizedBox(height: 8), Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text('Rôle', style: TextStyle(fontSize: 12, color: Colors.grey)), DropdownButton( value: selectedRole, isExpanded: true, items: _allowedRoles(callerRole) .map((r) => DropdownMenuItem(value: r, child: Text(_roleName(r)))) .toList(), onChanged: (v) => setLocal(() => selectedRole = v!), ), ], ), ]), ), actions: [ TextButton(onPressed: () => Navigator.pop(ctx2), child: const Text('Annuler')), ElevatedButton( onPressed: () async { Navigator.pop(ctx2); await _updateUser(ctx, user['id'] as String, firstCtrl.text, lastCtrl.text, selectedRole); }, child: const Text('Enregistrer'), ), ], ); }), ); } void _confirmDelete(BuildContext context, ManagerAppContext ctx, Map user) { showDialog( context: context, builder: (_) => AlertDialog( title: const Text('Supprimer l\'utilisateur'), content: Text('Supprimer ${user['email']} ?'), actions: [ TextButton(onPressed: () => Navigator.pop(context), child: const Text('Annuler')), ElevatedButton( style: ElevatedButton.styleFrom(backgroundColor: Colors.red), onPressed: () async { Navigator.pop(context); await _deleteUser(ctx, user['id'] as String); }, child: const Text('Supprimer', style: TextStyle(color: Colors.white)), ), ], ), ); } @override void initState() { super.initState(); WidgetsBinding.instance.addPostFrameCallback((_) { final ctx = Provider.of(context, listen: false).getContext() as ManagerAppContext; _loadUsers(ctx); }); } @override Widget build(BuildContext context) { final appContext = Provider.of(context); final managerCtx = appContext.getContext() as ManagerAppContext; return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text('Utilisateurs', style: TextStyle(fontSize: 24, fontWeight: FontWeight.w600, color: kPrimaryColor)), ElevatedButton.icon( onPressed: () => _showCreateDialog(context, managerCtx), icon: const Icon(Icons.add), label: const Text('Créer un utilisateur'), ), ], ), const SizedBox(height: 16), if (_loading) const Center(child: CircularProgressIndicator()) else if (_users.isEmpty) const Center(child: Text('Aucun utilisateur')) else Expanded( child: SingleChildScrollView( child: DataTable( columns: const [ DataColumn(label: Text('Email')), DataColumn(label: Text('Prénom')), DataColumn(label: Text('Nom')), DataColumn(label: Text('Rôle')), DataColumn(label: Text('Actions')), ], rows: _users.map((user) { return DataRow(cells: [ DataCell(Text(user['email'] as String? ?? '')), DataCell(Text(user['firstName'] as String? ?? '')), DataCell(Text(user['lastName'] as String? ?? '')), DataCell(Text(_roleName(user['role'] as int?))), DataCell(Row(children: [ IconButton( icon: Icon(Icons.edit, color: kPrimaryColor), onPressed: () => _showEditDialog(context, managerCtx, user), ), IconButton( icon: const Icon(Icons.delete, color: Colors.red), onPressed: () => _confirmDelete(context, managerCtx, user), ), ])), ]); }).toList(), ), ), ), ], ); } }