role et excel mis a jours

This commit is contained in:
b.razafimandimbihery 2025-05-30 12:28:26 +03:00
parent e1de473768
commit 34569c2843
3 changed files with 402 additions and 291 deletions

View File

@ -21,6 +21,9 @@ class CustomDrawer extends StatelessWidget {
final prefs = await SharedPreferences.getInstance(); final prefs = await SharedPreferences.getInstance();
await prefs.remove('username'); await prefs.remove('username');
await prefs.remove('role'); await prefs.remove('role');
await prefs.remove('user_id');
userController.clearUserData();
} }
CustomDrawer({super.key}); CustomDrawer({super.key});
@ -29,10 +32,26 @@ class CustomDrawer extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Drawer( return Drawer(
backgroundColor: Colors.white, backgroundColor: Colors.white,
child: ListView( child: FutureBuilder(
future: _buildDrawerItems(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
return ListView(
padding: EdgeInsets.zero, padding: EdgeInsets.zero,
children: [ children: snapshot.data as List<Widget>,
// Header avec informations utilisateur );
} else {
return const Center(child: CircularProgressIndicator());
}
},
),
);
}
Future<List<Widget>> _buildDrawerItems() async {
List<Widget> drawerItems = [];
drawerItems.add(
GetBuilder<UserController>( GetBuilder<UserController>(
builder: (controller) => Container( builder: (controller) => Container(
padding: const EdgeInsets.only(top: 50, left: 20, bottom: 20), padding: const EdgeInsets.only(top: 50, left: 20, bottom: 20),
@ -54,7 +73,7 @@ class CustomDrawer extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text( Text(
controller.name, controller.name.isNotEmpty ? controller.name : 'Utilisateur',
style: const TextStyle( style: const TextStyle(
color: Colors.white, color: Colors.white,
fontSize: 18, fontSize: 18,
@ -62,14 +81,7 @@ class CustomDrawer extends StatelessWidget {
), ),
), ),
Text( Text(
controller.email, controller.role.isNotEmpty ? controller.role : 'Aucun rôle',
style: const TextStyle(
color: Colors.white70,
fontSize: 14,
),
),
Text(
controller.role,
style: const TextStyle( style: const TextStyle(
color: Colors.white70, color: Colors.white70,
fontSize: 12, fontSize: 12,
@ -81,9 +93,10 @@ class CustomDrawer extends StatelessWidget {
), ),
), ),
), ),
);
// Section Accueil drawerItems.add(
_buildDrawerItem( await _buildDrawerItem(
icon: Icons.home, icon: Icons.home,
title: "Accueil", title: "Accueil",
color: Colors.blue, color: Colors.blue,
@ -91,8 +104,29 @@ class CustomDrawer extends StatelessWidget {
permissionRoute: '/accueil', permissionRoute: '/accueil',
onTap: () => Get.to(const AccueilPage()), onTap: () => Get.to(const AccueilPage()),
), ),
);
// Section Utilisateurs List<Widget> 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( const Padding(
padding: EdgeInsets.only(left: 20, top: 15, bottom: 5), padding: EdgeInsets.only(left: 20, top: 15, bottom: 5),
child: Text( child: Text(
@ -104,24 +138,31 @@ class CustomDrawer extends StatelessWidget {
), ),
), ),
), ),
_buildDrawerItem( );
icon: Icons.person_add, drawerItems.addAll(gestionUtilisateursItems);
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 List<Widget> 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( const Padding(
padding: EdgeInsets.only(left: 20, top: 15, bottom: 5), padding: EdgeInsets.only(left: 20, top: 15, bottom: 5),
child: Text( child: Text(
@ -133,24 +174,31 @@ class CustomDrawer extends StatelessWidget {
), ),
), ),
), ),
_buildDrawerItem( );
icon: Icons.inventory, drawerItems.addAll(gestionProduitsItems);
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 List<Widget> 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( const Padding(
padding: EdgeInsets.only(left: 20, top: 15, bottom: 5), padding: EdgeInsets.only(left: 20, top: 15, bottom: 5),
child: Text( child: Text(
@ -162,24 +210,31 @@ class CustomDrawer extends StatelessWidget {
), ),
), ),
), ),
_buildDrawerItem( );
icon: Icons.add_shopping_cart, drawerItems.addAll(gestionCommandesItems);
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 List<Widget> 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( const Padding(
padding: EdgeInsets.only(left: 20, top: 15, bottom: 5), padding: EdgeInsets.only(left: 20, top: 15, bottom: 5),
child: Text( child: Text(
@ -191,24 +246,23 @@ class CustomDrawer extends StatelessWidget {
), ),
), ),
), ),
_buildDrawerItem( );
icon: Icons.bar_chart, drawerItems.addAll(rapportsItems);
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 List<Widget> 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( const Padding(
padding: EdgeInsets.only(left: 20, top: 15, bottom: 5), padding: EdgeInsets.only(left: 20, top: 15, bottom: 5),
child: Text( child: Text(
@ -220,21 +274,16 @@ class CustomDrawer extends StatelessWidget {
), ),
), ),
), ),
_buildDrawerItem( );
icon: Icons.admin_panel_settings, drawerItems.addAll(administrationItems);
title: "Gérer les rôles", }
color: Colors.redAccent,
permissionAction: 'admin',
permissionRoute: '/gerer-roles',
onTap: () => Get.to(const RoleListPage()),
),
// Déconnexion drawerItems.add(const Divider());
const Divider(),
_buildDrawerItem( drawerItems.add(
icon: Icons.logout, ListTile(
title: "Déconnexion", leading: const Icon(Icons.logout, color: Colors.red),
color: Colors.red, title: const Text("Déconnexion"),
onTap: () { onTap: () {
Get.defaultDialog( Get.defaultDialog(
title: "Déconnexion", title: "Déconnexion",
@ -249,8 +298,8 @@ class CustomDrawer extends StatelessWidget {
backgroundColor: Colors.red, backgroundColor: Colors.red,
), ),
child: const Text("Oui"), child: const Text("Oui"),
onPressed: () { onPressed: () async {
clearUserData(); await clearUserData();
Get.offAll(const LoginPage()); Get.offAll(const LoginPage());
}, },
), ),
@ -258,45 +307,33 @@ class CustomDrawer extends StatelessWidget {
); );
}, },
), ),
],
),
); );
return drawerItems;
} }
Widget _buildDrawerItem({ Future<Widget> _buildDrawerItem({
required IconData icon, required IconData icon,
required String title, required String title,
required Color color, required Color color,
String? permissionAction, String? permissionAction,
String? permissionRoute, String? permissionRoute,
required VoidCallback onTap, required VoidCallback onTap,
}) { }) async {
if (permissionAction != null && permissionRoute != null) {
bool hasPermission = await userController.hasPermission(permissionAction, permissionRoute);
if (!hasPermission) {
return const SizedBox.shrink();
}
}
return ListTile( return ListTile(
leading: Icon(icon, color: color), leading: Icon(icon, color: color),
title: Text(title), title: Text(title),
trailing: permissionAction != null trailing: permissionAction != null
? const Icon(Icons.chevron_right, color: Colors.grey) ? const Icon(Icons.chevron_right, color: Colors.grey)
: null, : null,
onTap: () async { onTap: onTap,
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();
}
},
); );
} }
} }

View File

@ -63,13 +63,13 @@ class _LoginPageState extends State<LoginPage> {
super.dispose(); super.dispose();
} }
Future<void> saveUser(String username, String role, int userId) async { Future<void> saveUserData(Users user, String role, int userId) async {
try { try {
final prefs = await SharedPreferences.getInstance(); // CORRECTION : Utiliser la nouvelle méthode du contrôleur
await prefs.setString('username', username); // Le contrôleur se charge maintenant de tout (observable + SharedPreferences)
await prefs.setString('role', role); userController.setUserWithCredentials(user, role, userId);
await prefs.setInt('user_id', userId);
print('Utilisateur sauvegardé: $username, rôle: $role, id: $userId'); print('Utilisateur sauvegardé: ${user.username}, rôle: $role, id: $userId');
} catch (error) { } catch (error) {
print('Erreur lors de la sauvegarde: $error'); print('Erreur lors de la sauvegarde: $error');
throw Exception('Erreur lors de la sauvegarde des données utilisateur'); throw Exception('Erreur lors de la sauvegarde des données utilisateur');
@ -128,12 +128,9 @@ class _LoginPageState extends State<LoginPage> {
print('Rôle: ${userCredentials['role']}'); print('Rôle: ${userCredentials['role']}');
print('ID: ${userCredentials['id']}'); print('ID: ${userCredentials['id']}');
// Sauvegarder dans le contrôleur // CORRECTION : Sauvegarder ET mettre à jour le contrôleur
// userController.setUser(user); await saveUserData(
user,
// Sauvegarder dans SharedPreferences
await saveUser(
userCredentials['username'] as String,
userCredentials['role'] as String, userCredentials['role'] as String,
userCredentials['id'] as int, userCredentials['id'] as int,
); );

View File

@ -10,6 +10,7 @@ class UserController extends GetxController {
final _name = ''.obs; final _name = ''.obs;
final _lastname = ''.obs; final _lastname = ''.obs;
final _password = ''.obs; final _password = ''.obs;
final _userId = 0.obs; // Ajout de l'ID utilisateur
String get username => _username.value; String get username => _username.value;
String get email => _email.value; String get email => _email.value;
@ -17,6 +18,7 @@ class UserController extends GetxController {
String get name => _name.value; String get name => _name.value;
String get lastname => _lastname.value; String get lastname => _lastname.value;
String get password => _password.value; String get password => _password.value;
int get userId => _userId.value;
@override @override
void onInit() { void onInit() {
@ -24,43 +26,90 @@ class UserController extends GetxController {
loadUserData(); // Charger les données au démarrage 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<void> loadUserData() async { Future<void> loadUserData() async {
try { try {
final prefs = await SharedPreferences.getInstance(); final prefs = await SharedPreferences.getInstance();
_username.value = prefs.getString('username') ?? ''; final storedUsername = prefs.getString('username') ?? '';
final storedRole = prefs.getString('role') ?? '';
final storedUserId = prefs.getInt('user_id') ?? 0;
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') ?? ''; _email.value = prefs.getString('email') ?? '';
_role.value = prefs.getString('role') ?? ''; _role.value = storedRole;
_name.value = prefs.getString('name') ?? ''; _name.value = prefs.getString('name') ?? '';
_lastname.value = prefs.getString('lastname') ?? ''; _lastname.value = prefs.getString('lastname') ?? '';
_userId.value = storedUserId;
print("Données chargées - Username: ${_username.value}"); }
print("Role: ${_role.value}"); } else {
print("❌ Aucun utilisateur stocké trouvé");
}
} catch (e) { } catch (e) {
print('Erreur lors du chargement des données utilisateur: $e'); print('Erreur lors du chargement des données utilisateur: $e');
} }
} }
void setUser(Users user) { // NOUVELLE MÉTHODE : Mise à jour complète avec Users + credentials
void setUserWithCredentials(Users user, String role, int userId) {
_username.value = user.username; _username.value = user.username;
print("username " + _username.value);
_email.value = user.email; _email.value = user.email;
print(_email.value); _role.value = role; // Rôle depuis les credentials
_role.value = user.role;
print(_role.value);
_name.value = user.name; _name.value = user.name;
print(_name.value);
_lastname.value = user.lastName; _lastname.value = user.lastName;
print(_lastname.value);
_password.value = user.password; _password.value = user.password;
print(_password.value); _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 // Sauvegarder dans SharedPreferences
saveUserData(); saveUserData();
} }
// Sauvegarder les données dans SharedPreferences // MÉTHODE EXISTANTE AMÉLIORÉE
void setUser(Users user) {
_username.value = user.username;
_email.value = user.email;
_role.value = user.role;
_name.value = user.name;
_lastname.value = user.lastName;
_password.value = user.password;
// 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();
}
// CORRECTION : Sauvegarder TOUTES les données importantes
Future<void> saveUserData() async { Future<void> saveUserData() async {
try { try {
final prefs = await SharedPreferences.getInstance(); final prefs = await SharedPreferences.getInstance();
@ -70,23 +119,26 @@ class UserController extends GetxController {
await prefs.setString('role', _role.value); await prefs.setString('role', _role.value);
await prefs.setString('name', _name.value); await prefs.setString('name', _name.value);
await prefs.setString('lastname', _lastname.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) { } 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<void> clearUserData() async { Future<void> clearUserData() async {
try { try {
final prefs = await SharedPreferences.getInstance(); final prefs = await SharedPreferences.getInstance();
// Vider SharedPreferences
await prefs.remove('username'); await prefs.remove('username');
await prefs.remove('email'); await prefs.remove('email');
await prefs.remove('role'); await prefs.remove('role');
await prefs.remove('name'); await prefs.remove('name');
await prefs.remove('lastname'); await prefs.remove('lastname');
await prefs.remove('user_id'); // Supprimer l'ID aussi
// Vider les variables observables // Vider les variables observables
_username.value = ''; _username.value = '';
@ -95,23 +147,35 @@ class UserController extends GetxController {
_name.value = ''; _name.value = '';
_lastname.value = ''; _lastname.value = '';
_password.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) { } 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<bool> hasPermission(String permission, String route) async { Future<bool> hasPermission(String permission, String route) async {
try { try {
if (_username.value.isEmpty) { if (_username.value.isEmpty) {
print('Username vide, rechargement des données...'); print('⚠️ Username vide, rechargement des données...');
await loadUserData(); 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); return await AppDatabase.instance.hasPermission(username, permission, route);
} catch (e) { } 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 return false; // Sécurité : refuser l'accès en cas d'erreur
} }
} }
@ -124,4 +188,17 @@ class UserController extends GetxController {
} }
return false; 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("========================");
}
} }