diff --git a/lib/Components/appDrawer.dart b/lib/Components/appDrawer.dart index fcded5e..098144d 100644 --- a/lib/Components/appDrawer.dart +++ b/lib/Components/appDrawer.dart @@ -21,6 +21,9 @@ class CustomDrawer extends StatelessWidget { final prefs = await SharedPreferences.getInstance(); await prefs.remove('username'); await prefs.remove('role'); + await prefs.remove('user_id'); + + userController.clearUserData(); } CustomDrawer({super.key}); @@ -29,274 +32,308 @@ class CustomDrawer extends StatelessWidget { Widget build(BuildContext context) { return Drawer( backgroundColor: Colors.white, - child: ListView( - padding: EdgeInsets.zero, - children: [ - // Header avec informations utilisateur - GetBuilder( - builder: (controller) => Container( - padding: const EdgeInsets.only(top: 50, left: 20, bottom: 20), - decoration: const BoxDecoration( - gradient: LinearGradient( - colors: [Color.fromARGB(255, 4, 54, 95), Colors.blue], - begin: Alignment.topLeft, - end: Alignment.bottomRight, - ), + child: FutureBuilder( + future: _buildDrawerItems(), + builder: (context, snapshot) { + if (snapshot.connectionState == ConnectionState.done) { + return ListView( + padding: EdgeInsets.zero, + children: snapshot.data as List, + ); + } else { + return const Center(child: CircularProgressIndicator()); + } + }, + ), + ); + } + + Future> _buildDrawerItems() async { + List drawerItems = []; + + drawerItems.add( + GetBuilder( + builder: (controller) => Container( + padding: const EdgeInsets.only(top: 50, left: 20, bottom: 20), + decoration: const BoxDecoration( + gradient: LinearGradient( + colors: [Color.fromARGB(255, 4, 54, 95), Colors.blue], + begin: Alignment.topLeft, + end: Alignment.bottomRight, + ), + ), + child: Row( + children: [ + const CircleAvatar( + radius: 30, + backgroundImage: AssetImage("assets/youmaz2.png"), ), - child: Row( + const SizedBox(width: 15), + Column( + crossAxisAlignment: CrossAxisAlignment.start, children: [ - const CircleAvatar( - radius: 30, - backgroundImage: AssetImage("assets/youmaz2.png"), + Text( + controller.name.isNotEmpty ? controller.name : 'Utilisateur', + style: const TextStyle( + color: Colors.white, + fontSize: 18, + fontWeight: FontWeight.bold, + ), ), - const SizedBox(width: 15), - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - controller.name, - style: const TextStyle( - color: Colors.white, - fontSize: 18, - fontWeight: FontWeight.bold, - ), - ), - Text( - controller.email, - style: const TextStyle( - color: Colors.white70, - fontSize: 14, - ), - ), - Text( - controller.role, - style: const TextStyle( - color: Colors.white70, - fontSize: 12, - ), - ), - ], + Text( + controller.role.isNotEmpty ? controller.role : 'Aucun rôle', + style: const TextStyle( + color: Colors.white70, + fontSize: 12, + ), ), ], ), - ), - ), - - // Section Accueil - _buildDrawerItem( - icon: Icons.home, - title: "Accueil", - color: Colors.blue, - permissionAction: 'view', - permissionRoute: '/accueil', - onTap: () => Get.to(const AccueilPage()), + ], ), - - // Section Utilisateurs - const Padding( - padding: EdgeInsets.only(left: 20, top: 15, bottom: 5), - child: Text( - "GESTION UTILISATEURS", - style: TextStyle( - color: Colors.grey, - fontSize: 12, - fontWeight: FontWeight.bold, - ), + ), + ), + ); + + drawerItems.add( + await _buildDrawerItem( + icon: Icons.home, + title: "Accueil", + color: Colors.blue, + permissionAction: 'view', + permissionRoute: '/accueil', + onTap: () => Get.to(const AccueilPage()), + ), + ); + + List gestionUtilisateursItems = [ + await _buildDrawerItem( + icon: Icons.person_add, + title: "Ajouter un utilisateur", + color: Colors.green, + permissionAction: 'create', + permissionRoute: '/ajouter-utilisateur', + onTap: () => Get.to(const RegistrationPage()), + ), + await _buildDrawerItem( + icon: Icons.supervised_user_circle, + title: "Gérer les utilisateurs", + color: const Color.fromARGB(255, 4, 54, 95), + permissionAction: 'update', + permissionRoute: '/modifier-utilisateur', + onTap: () => Get.to(const ListUserPage()), + ), + ]; + + if (gestionUtilisateursItems.any((item) => item is ListTile)) { + drawerItems.add( + const Padding( + padding: EdgeInsets.only(left: 20, top: 15, bottom: 5), + child: Text( + "GESTION UTILISATEURS", + style: TextStyle( + color: Colors.grey, + fontSize: 12, + fontWeight: FontWeight.bold, ), ), - _buildDrawerItem( - icon: Icons.person_add, - title: "Ajouter un utilisateur", - color: Colors.green, - permissionAction: 'create', - permissionRoute: '/ajouter-utilisateur', - onTap: () => Get.to(const RegistrationPage()), - ), - _buildDrawerItem( - icon: Icons.supervised_user_circle, - title: "Gérer les utilisateurs", - color: Color.fromARGB(255, 4, 54, 95), - permissionAction: 'update', - permissionRoute: '/modifier-utilisateur', - onTap: () => Get.to(const ListUserPage()), - ), - - // Section Produits - const Padding( - padding: EdgeInsets.only(left: 20, top: 15, bottom: 5), - child: Text( - "GESTION PRODUITS", - style: TextStyle( - color: Colors.grey, - fontSize: 12, - fontWeight: FontWeight.bold, - ), + ), + ); + drawerItems.addAll(gestionUtilisateursItems); + } + + List gestionProduitsItems = [ + await _buildDrawerItem( + icon: Icons.inventory, + title: "Gestion des produits", + color: Colors.indigoAccent, + permissionAction: 'create', + permissionRoute: '/ajouter-produit', + onTap: () => Get.to(const ProductManagementPage()), + ), + await _buildDrawerItem( + icon: Icons.storage, + title: "Gestion de stock", + color: Colors.blueAccent, + permissionAction: 'update', + permissionRoute: '/gestion-stock', + onTap: () => Get.to(const GestionStockPage()), + ), + ]; + + if (gestionProduitsItems.any((item) => item is ListTile)) { + drawerItems.add( + const Padding( + padding: EdgeInsets.only(left: 20, top: 15, bottom: 5), + child: Text( + "GESTION PRODUITS", + style: TextStyle( + color: Colors.grey, + fontSize: 12, + fontWeight: FontWeight.bold, ), ), - _buildDrawerItem( - icon: Icons.inventory, - title: "Gestion des produits", - color: Colors.indigoAccent, - permissionAction: 'create', - permissionRoute: '/ajouter-produit', - onTap: () => Get.to(const ProductManagementPage()), - ), - _buildDrawerItem( - icon: Icons.storage, - title: "Gestion de stock", - color: Colors.blueAccent, - permissionAction: 'update', - permissionRoute: '/gestion-stock', - onTap: () => Get.to(const GestionStockPage()), - ), - - // Section Commandes - const Padding( - padding: EdgeInsets.only(left: 20, top: 15, bottom: 5), - child: Text( - "GESTION COMMANDES", - style: TextStyle( - color: Colors.grey, - fontSize: 12, - fontWeight: FontWeight.bold, - ), + ), + ); + drawerItems.addAll(gestionProduitsItems); + } + + List gestionCommandesItems = [ + await _buildDrawerItem( + icon: Icons.add_shopping_cart, + title: "Nouvelle commande", + color: Colors.orange, + permissionAction: 'create', + permissionRoute: '/nouvelle-commande', + onTap: () => Get.to(const NouvelleCommandePage()), + ), + await _buildDrawerItem( + icon: Icons.list_alt, + title: "Gérer les commandes", + color: Colors.deepPurple, + permissionAction: 'manage', + permissionRoute: '/gerer-commandes', + onTap: () => Get.to(const GestionCommandesPage()), + ), + ]; + + if (gestionCommandesItems.any((item) => item is ListTile)) { + drawerItems.add( + const Padding( + padding: EdgeInsets.only(left: 20, top: 15, bottom: 5), + child: Text( + "GESTION COMMANDES", + style: TextStyle( + color: Colors.grey, + fontSize: 12, + fontWeight: FontWeight.bold, ), ), - _buildDrawerItem( - icon: Icons.add_shopping_cart, - title: "Nouvelle commande", - color: Colors.orange, - permissionAction: 'create', - permissionRoute: '/nouvelle-commande', - onTap: () => Get.to(const NouvelleCommandePage()), - ), - _buildDrawerItem( - icon: Icons.list_alt, - title: "Gérer les commandes", - color: Colors.deepPurple, - permissionAction: 'manage', - permissionRoute: '/gerer-commandes', - onTap: () => Get.to(const GestionCommandesPage()), - ), - - // Section Rapports - const Padding( - padding: EdgeInsets.only(left: 20, top: 15, bottom: 5), - child: Text( - "RAPPORTS", - style: TextStyle( - color: Colors.grey, - fontSize: 12, - fontWeight: FontWeight.bold, - ), + ), + ); + drawerItems.addAll(gestionCommandesItems); + } + + List rapportsItems = [ + await _buildDrawerItem( + icon: Icons.bar_chart, + title: "Bilan mensuel", + color: Colors.teal, + permissionAction: 'read', + permissionRoute: '/bilan', + onTap: () => Get.to(const BilanMois()), + ), + await _buildDrawerItem( + icon: Icons.history, + title: "Historique", + color: Colors.blue, + permissionAction: 'read', + permissionRoute: '/historique', + onTap: () => Get.to(HistoryPage()), + ), + ]; + + if (rapportsItems.any((item) => item is ListTile)) { + drawerItems.add( + const Padding( + padding: EdgeInsets.only(left: 20, top: 15, bottom: 5), + child: Text( + "RAPPORTS", + style: TextStyle( + color: Colors.grey, + fontSize: 12, + fontWeight: FontWeight.bold, ), ), - _buildDrawerItem( - icon: Icons.bar_chart, - title: "Bilan mensuel", - color: Colors.teal, - permissionAction: 'read', - permissionRoute: '/bilan', - onTap: () => Get.to(const BilanMois()), - ), - _buildDrawerItem( - icon: Icons.history, - title: "Historique", - color: Colors.blue, - permissionAction: 'read', - permissionRoute: '/historique', - onTap: () => Get.to(HistoryPage()), - ), - - // Section Administration - const Padding( - padding: EdgeInsets.only(left: 20, top: 15, bottom: 5), - child: Text( - "ADMINISTRATION", - style: TextStyle( - color: Colors.grey, - fontSize: 12, - fontWeight: FontWeight.bold, - ), + ), + ); + drawerItems.addAll(rapportsItems); + } + + List administrationItems = [ + await _buildDrawerItem( + icon: Icons.admin_panel_settings, + title: "Gérer les rôles", + color: Colors.redAccent, + permissionAction: 'admin', + permissionRoute: '/gerer-roles', + onTap: () => Get.to(const RoleListPage()), + ), + ]; + + if (administrationItems.any((item) => item is ListTile)) { + drawerItems.add( + const Padding( + padding: EdgeInsets.only(left: 20, top: 15, bottom: 5), + child: Text( + "ADMINISTRATION", + style: TextStyle( + color: Colors.grey, + fontSize: 12, + fontWeight: FontWeight.bold, ), ), - _buildDrawerItem( - icon: Icons.admin_panel_settings, - title: "Gérer les rôles", - color: Colors.redAccent, - permissionAction: 'admin', - permissionRoute: '/gerer-roles', - onTap: () => Get.to(const RoleListPage()), - ), - - // Déconnexion - const Divider(), - _buildDrawerItem( - icon: Icons.logout, + ), + ); + drawerItems.addAll(administrationItems); + } + + drawerItems.add(const Divider()); + + drawerItems.add( + ListTile( + leading: const Icon(Icons.logout, color: Colors.red), + title: const Text("Déconnexion"), + onTap: () { + Get.defaultDialog( title: "Déconnexion", - color: Colors.red, - onTap: () { - Get.defaultDialog( - title: "Déconnexion", - content: const Text("Voulez-vous vraiment vous déconnecter ?"), - actions: [ - TextButton( - child: const Text("Non"), - onPressed: () => Get.back(), - ), - ElevatedButton( - style: ElevatedButton.styleFrom( - backgroundColor: Colors.red, - ), - child: const Text("Oui"), - onPressed: () { - clearUserData(); - Get.offAll(const LoginPage()); - }, - ), - ], - ); - }, - ), - ], + content: const Text("Voulez-vous vraiment vous déconnecter ?"), + actions: [ + TextButton( + child: const Text("Non"), + onPressed: () => Get.back(), + ), + ElevatedButton( + style: ElevatedButton.styleFrom( + backgroundColor: Colors.red, + ), + child: const Text("Oui"), + onPressed: () async { + await clearUserData(); + Get.offAll(const LoginPage()); + }, + ), + ], + ); + }, ), ); + + return drawerItems; } - Widget _buildDrawerItem({ + Future _buildDrawerItem({ required IconData icon, required String title, required Color color, String? permissionAction, String? permissionRoute, required VoidCallback onTap, - }) { + }) async { + if (permissionAction != null && permissionRoute != null) { + bool hasPermission = await userController.hasPermission(permissionAction, permissionRoute); + if (!hasPermission) { + return const SizedBox.shrink(); + } + } + return ListTile( leading: Icon(icon, color: color), title: Text(title), - trailing: permissionAction != null + trailing: permissionAction != null ? const Icon(Icons.chevron_right, color: Colors.grey) : null, - onTap: () async { - if (permissionAction != null && permissionRoute != null) { - bool hasPermission = await userController.hasPermission(permissionAction, permissionRoute); - if (hasPermission) { - onTap(); - } else { - Get.snackbar( - "Accès refusé", - "Vous n'avez pas les droits pour accéder à cette page", - backgroundColor: Colors.red, - colorText: Colors.white, - icon: const Icon(Icons.error), - duration: const Duration(seconds: 3), - snackPosition: SnackPosition.TOP, - ); - } - } else { - onTap(); - } - }, + onTap: onTap, ); } -} \ No newline at end of file +} diff --git a/lib/Views/loginPage.dart b/lib/Views/loginPage.dart index dff0539..3ab2505 100644 --- a/lib/Views/loginPage.dart +++ b/lib/Views/loginPage.dart @@ -63,13 +63,13 @@ class _LoginPageState extends State { super.dispose(); } - Future saveUser(String username, String role, int userId) async { + Future saveUserData(Users user, String role, int userId) async { try { - final prefs = await SharedPreferences.getInstance(); - await prefs.setString('username', username); - await prefs.setString('role', role); - await prefs.setInt('user_id', userId); - print('Utilisateur sauvegardé: $username, rôle: $role, id: $userId'); + // ✅ CORRECTION : Utiliser la nouvelle méthode du contrôleur + // Le contrôleur se charge maintenant de tout (observable + SharedPreferences) + userController.setUserWithCredentials(user, role, userId); + + print('Utilisateur sauvegardé: ${user.username}, rôle: $role, id: $userId'); } catch (error) { print('Erreur lors de la sauvegarde: $error'); throw Exception('Erreur lors de la sauvegarde des données utilisateur'); @@ -128,12 +128,9 @@ class _LoginPageState extends State { print('Rôle: ${userCredentials['role']}'); print('ID: ${userCredentials['id']}'); - // Sauvegarder dans le contrôleur - // userController.setUser(user); - - // Sauvegarder dans SharedPreferences - await saveUser( - userCredentials['username'] as String, + // ✅ CORRECTION : Sauvegarder ET mettre à jour le contrôleur + await saveUserData( + user, userCredentials['role'] as String, userCredentials['id'] as int, ); diff --git a/lib/controller/userController.dart b/lib/controller/userController.dart index d326843..8d24f06 100644 --- a/lib/controller/userController.dart +++ b/lib/controller/userController.dart @@ -10,6 +10,7 @@ class UserController extends GetxController { final _name = ''.obs; final _lastname = ''.obs; final _password = ''.obs; + final _userId = 0.obs; // ✅ Ajout de l'ID utilisateur String get username => _username.value; String get email => _email.value; @@ -17,6 +18,7 @@ class UserController extends GetxController { String get name => _name.value; String get lastname => _lastname.value; String get password => _password.value; + int get userId => _userId.value; @override void onInit() { @@ -24,43 +26,90 @@ class UserController extends GetxController { loadUserData(); // Charger les données au démarrage } - // Charger les données depuis SharedPreferences + // ✅ CORRECTION : Charger les données complètes depuis SharedPreferences ET la base de données Future loadUserData() async { try { final prefs = await SharedPreferences.getInstance(); - _username.value = prefs.getString('username') ?? ''; - _email.value = prefs.getString('email') ?? ''; - _role.value = prefs.getString('role') ?? ''; - _name.value = prefs.getString('name') ?? ''; - _lastname.value = prefs.getString('lastname') ?? ''; + final storedUsername = prefs.getString('username') ?? ''; + final storedRole = prefs.getString('role') ?? ''; + final storedUserId = prefs.getInt('user_id') ?? 0; - print("Données chargées - Username: ${_username.value}"); - print("Role: ${_role.value}"); + if (storedUsername.isNotEmpty) { + try { + // Récupérer les données complètes depuis la base de données + Users user = await AppDatabase.instance.getUser(storedUsername); + + // Mettre à jour TOUTES les données + _username.value = user.username; + _email.value = user.email; + _name.value = user.name; + _lastname.value = user.lastName; + _password.value = user.password; + _role.value = storedRole; // Récupéré depuis SharedPreferences + _userId.value = storedUserId; // Récupéré depuis SharedPreferences + + print("✅ Données chargées depuis la DB - Username: ${_username.value}"); + print("✅ Name: ${_name.value}, Email: ${_email.value}"); + print("✅ Role: ${_role.value}, UserID: ${_userId.value}"); + } catch (dbError) { + print('❌ Erreur DB, chargement depuis SharedPreferences uniquement: $dbError'); + // Fallback : charger depuis SharedPreferences uniquement + _username.value = storedUsername; + _email.value = prefs.getString('email') ?? ''; + _role.value = storedRole; + _name.value = prefs.getString('name') ?? ''; + _lastname.value = prefs.getString('lastname') ?? ''; + _userId.value = storedUserId; + } + } else { + print("❌ Aucun utilisateur stocké trouvé"); + } } catch (e) { - print('Erreur lors du chargement des données utilisateur: $e'); + print('❌ Erreur lors du chargement des données utilisateur: $e'); } } + // ✅ NOUVELLE MÉTHODE : Mise à jour complète avec Users + credentials + void setUserWithCredentials(Users user, String role, int userId) { + _username.value = user.username; + _email.value = user.email; + _role.value = role; // Rôle depuis les credentials + _name.value = user.name; + _lastname.value = user.lastName; + _password.value = user.password; + _userId.value = userId; // ID depuis les credentials + + print("✅ Utilisateur mis à jour avec credentials:"); + print(" Username: ${_username.value}"); + print(" Name: ${_name.value}"); + print(" Email: ${_email.value}"); + print(" Role: ${_role.value}"); + print(" UserID: ${_userId.value}"); + + // Sauvegarder dans SharedPreferences + saveUserData(); + } + + // ✅ MÉTHODE EXISTANTE AMÉLIORÉE void setUser(Users user) { _username.value = user.username; - print("username " + _username.value); _email.value = user.email; - print(_email.value); _role.value = user.role; - print(_role.value); _name.value = user.name; - print(_name.value); _lastname.value = user.lastName; - print(_lastname.value); _password.value = user.password; - print(_password.value); + // Note: _userId reste inchangé si pas fourni + + print("✅ Utilisateur mis à jour (méthode legacy):"); + print(" Username: ${_username.value}"); + print(" Role: ${_role.value}"); // Sauvegarder dans SharedPreferences saveUserData(); } - // Sauvegarder les données dans SharedPreferences + // ✅ CORRECTION : Sauvegarder TOUTES les données importantes Future saveUserData() async { try { final prefs = await SharedPreferences.getInstance(); @@ -70,23 +119,26 @@ class UserController extends GetxController { await prefs.setString('role', _role.value); await prefs.setString('name', _name.value); await prefs.setString('lastname', _lastname.value); + await prefs.setInt('user_id', _userId.value); // ✅ Sauvegarder l'ID - print("Données sauvegardées avec succès"); + print("✅ Données sauvegardées avec succès dans SharedPreferences"); } catch (e) { - print('Erreur lors de la sauvegarde des données utilisateur: $e'); + print('❌ Erreur lors de la sauvegarde des données utilisateur: $e'); } } - // Méthode pour vider les données utilisateur + // ✅ CORRECTION : Vider TOUTES les données (SharedPreferences + Observables) Future clearUserData() async { try { final prefs = await SharedPreferences.getInstance(); + // Vider SharedPreferences await prefs.remove('username'); await prefs.remove('email'); await prefs.remove('role'); await prefs.remove('name'); await prefs.remove('lastname'); + await prefs.remove('user_id'); // ✅ Supprimer l'ID aussi // Vider les variables observables _username.value = ''; @@ -95,23 +147,35 @@ class UserController extends GetxController { _name.value = ''; _lastname.value = ''; _password.value = ''; + _userId.value = 0; // ✅ Réinitialiser l'ID - print("Données utilisateur effacées"); + print("✅ Toutes les données utilisateur ont été effacées"); } catch (e) { - print('Erreur lors de l\'effacement des données utilisateur: $e'); + print('❌ Erreur lors de l\'effacement des données utilisateur: $e'); } } + // ✅ MÉTHODE UTILITAIRE : Vérifier si un utilisateur est connecté + bool get isLoggedIn => _username.value.isNotEmpty && _userId.value > 0; + + // ✅ MÉTHODE UTILITAIRE : Obtenir le nom complet + String get fullName => '${_name.value} ${_lastname.value}'.trim(); + Future hasPermission(String permission, String route) async { try { if (_username.value.isEmpty) { - print('Username vide, rechargement des données...'); + print('⚠️ Username vide, rechargement des données...'); await loadUserData(); } + if (_username.value.isEmpty) { + print('❌ Impossible de vérifier les permissions : utilisateur non connecté'); + return false; + } + return await AppDatabase.instance.hasPermission(username, permission, route); } catch (e) { - print('Erreur vérification permission: $e'); + print('❌ Erreur vérification permission: $e'); return false; // Sécurité : refuser l'accès en cas d'erreur } } @@ -124,4 +188,17 @@ class UserController extends GetxController { } return false; } + + // ✅ MÉTHODE DEBUG : Afficher l'état actuel + void debugPrintUserState() { + print("=== ÉTAT UTILISATEUR ==="); + print("Username: ${_username.value}"); + print("Name: ${_name.value}"); + print("Lastname: ${_lastname.value}"); + print("Email: ${_email.value}"); + print("Role: ${_role.value}"); + print("UserID: ${_userId.value}"); + print("IsLoggedIn: $isLoggedIn"); + print("========================"); + } } \ No newline at end of file