Fix: Hive sync et update entité via API REST
- Correction mapping JSON membres (fk_role, chk_active) - Ajout traitement amicale au login - Fix callback onSubmit pour sync Hive après update API
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:geosector_app/core/services/api_service.dart';
|
||||
import 'dart:math' as math;
|
||||
import 'package:hive_flutter/hive_flutter.dart';
|
||||
import 'package:geosector_app/core/data/models/amicale_model.dart';
|
||||
@@ -64,6 +65,9 @@ class _AdminAmicalePageState extends State<AdminAmicalePage> {
|
||||
void _loadCurrentUser() {
|
||||
final currentUser = widget.userRepository.getCurrentUser();
|
||||
|
||||
debugPrint('🔍 _loadCurrentUser - Utilisateur: ${currentUser?.username} (ID: ${currentUser?.id})');
|
||||
debugPrint('🔍 _loadCurrentUser - fkEntite: ${currentUser?.fkEntite}');
|
||||
|
||||
if (currentUser == null) {
|
||||
setState(() {
|
||||
_errorMessage = 'Utilisateur non connecté';
|
||||
@@ -78,43 +82,16 @@ class _AdminAmicalePageState extends State<AdminAmicalePage> {
|
||||
return;
|
||||
}
|
||||
|
||||
// Vérifier immédiatement si l'amicale existe
|
||||
final amicale = widget.amicaleRepository.getUserAmicale(currentUser.fkEntite!);
|
||||
debugPrint('🔍 Amicale trouvée dans le repository: ${amicale?.name ?? 'null'}');
|
||||
|
||||
setState(() {
|
||||
_currentUser = currentUser;
|
||||
_errorMessage = null;
|
||||
});
|
||||
}
|
||||
|
||||
void _handleEditAmicale(AmicaleModel amicale) {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => AlertDialog(
|
||||
title: const Text('Modifier l\'amicale'),
|
||||
content: Text('Voulez-vous modifier l\'amicale ${amicale.name} ?'),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
child: const Text('Annuler'),
|
||||
),
|
||||
ElevatedButton(
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
// TODO: Naviguer vers la page de modification
|
||||
// Navigator.of(context).push(
|
||||
// MaterialPageRoute(
|
||||
// builder: (context) => EditAmicalePage(
|
||||
// amicale: amicale,
|
||||
// amicaleRepository: widget.amicaleRepository,
|
||||
// ),
|
||||
// ),
|
||||
// );
|
||||
},
|
||||
child: const Text('Modifier'),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _handleEditMembre(MembreModel membre) {
|
||||
showDialog(
|
||||
context: context,
|
||||
@@ -226,9 +203,19 @@ class _AdminAmicalePageState extends State<AdminAmicalePage> {
|
||||
child: ValueListenableBuilder<Box<AmicaleModel>>(
|
||||
valueListenable: widget.amicaleRepository.getAmicalesBox().listenable(),
|
||||
builder: (context, amicalesBox, child) {
|
||||
debugPrint('🔍 AmicalesBox - Nombre d\'amicales: ${amicalesBox.length}');
|
||||
debugPrint('🔍 AmicalesBox - Clés disponibles: ${amicalesBox.keys.toList()}');
|
||||
debugPrint('🔍 Recherche amicale avec fkEntite: ${_currentUser!.fkEntite}');
|
||||
|
||||
final amicale = amicalesBox.get(_currentUser!.fkEntite!);
|
||||
debugPrint('🔍 Amicale récupérée: ${amicale?.name ?? 'AUCUNE'}');
|
||||
|
||||
if (amicale == null) {
|
||||
// Ajouter plus d'informations de debug
|
||||
debugPrint('❌ PROBLÈME: Amicale non trouvée');
|
||||
debugPrint('❌ fkEntite recherché: ${_currentUser!.fkEntite}');
|
||||
debugPrint('❌ Contenu de la box: ${amicalesBox.values.map((a) => '${a.id}: ${a.name}').join(', ')}');
|
||||
|
||||
return Center(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
@@ -245,7 +232,7 @@ class _AdminAmicalePageState extends State<AdminAmicalePage> {
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
'L\'amicale associée à votre compte n\'existe plus.',
|
||||
'L\'amicale associée à votre compte n\'existe plus.\nfkEntite: ${_currentUser!.fkEntite}',
|
||||
textAlign: TextAlign.center,
|
||||
style: theme.textTheme.bodyLarge,
|
||||
),
|
||||
@@ -293,7 +280,7 @@ class _AdminAmicalePageState extends State<AdminAmicalePage> {
|
||||
onDelete: null,
|
||||
amicaleRepository: widget.amicaleRepository,
|
||||
userRepository: widget.userRepository,
|
||||
apiService: null, // Ou passez l'ApiService si vous l'avez disponible
|
||||
apiService: ApiService.instance,
|
||||
showActionsColumn: false,
|
||||
),
|
||||
),
|
||||
|
||||
@@ -68,10 +68,9 @@ class _SplashPageState extends State<SplashPage> with SingleTickerProviderStateM
|
||||
}
|
||||
} catch (e) {
|
||||
debugPrint('Erreur lors de la récupération de la version: $e');
|
||||
// Fallback sur la version du AppInfoService si elle existe
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
_appVersion = AppInfoService.fullVersion.split(' ').last; // Extraire juste le numéro
|
||||
_appVersion = AppInfoService.fullVersion.split(' ').last;
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -81,29 +80,24 @@ class _SplashPageState extends State<SplashPage> with SingleTickerProviderStateM
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
||||
// Animation controller sur 5 secondes (augmenté de 3 à 5 secondes)
|
||||
// Animation controller
|
||||
_animationController = AnimationController(
|
||||
vsync: this,
|
||||
duration: const Duration(seconds: 5),
|
||||
);
|
||||
|
||||
// Animation de 4x la taille à 1x la taille (augmenté de 3x à 4x)
|
||||
_scaleAnimation = Tween<double>(
|
||||
begin: 4.0, // Commencer à 4x la taille
|
||||
end: 1.0, // Terminer à la taille normale
|
||||
begin: 4.0,
|
||||
end: 1.0,
|
||||
).animate(
|
||||
CurvedAnimation(
|
||||
parent: _animationController,
|
||||
curve: Curves.easeOutBack, // Curve pour un effet de rebond
|
||||
curve: Curves.easeOutBack,
|
||||
),
|
||||
);
|
||||
|
||||
// Démarrer l'animation immédiatement
|
||||
_animationController.forward();
|
||||
|
||||
_getAppVersion();
|
||||
|
||||
// Simuler le processus d'initialisation
|
||||
_startInitialization();
|
||||
}
|
||||
|
||||
@@ -114,151 +108,337 @@ class _SplashPageState extends State<SplashPage> with SingleTickerProviderStateM
|
||||
}
|
||||
|
||||
void _startInitialization() async {
|
||||
// Étape 1: Initialisation des boîtes Hive (0% à 75%)
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
_statusMessage = "Initialisation des données...";
|
||||
_progress = 0.0;
|
||||
});
|
||||
}
|
||||
|
||||
// Initialiser toutes les boîtes Hive
|
||||
await _initializeAllHiveBoxes();
|
||||
await Future.delayed(const Duration(milliseconds: 500));
|
||||
|
||||
// Étape 2: Initialisation des services (75% à 100%)
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
_statusMessage = "Préparation de l'application...";
|
||||
_progress = 0.75;
|
||||
});
|
||||
}
|
||||
await Future.delayed(const Duration(milliseconds: 500));
|
||||
|
||||
// Table rase complète et recréation propre
|
||||
await _completeReset();
|
||||
|
||||
// Finalisation
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
_statusMessage = "Application prête !";
|
||||
_progress = 1.0;
|
||||
_isInitializing = false;
|
||||
_showButtons = true;
|
||||
_progress = 1.0; // S'assurer que la barre est à 100%
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Méthode pour initialiser toutes les boîtes Hive
|
||||
Future<void> _initializeAllHiveBoxes() async {
|
||||
/// RESET COMPLET : Destruction totale et recréation propre
|
||||
Future<void> _completeReset() async {
|
||||
try {
|
||||
debugPrint('Initialisation de toutes les boîtes Hive...');
|
||||
debugPrint('🧹 RESET COMPLET : Destruction totale des données Hive...');
|
||||
|
||||
// Structure pour les boîtes à ouvrir avec leurs noms d'affichage
|
||||
final boxesToOpen = [
|
||||
{'name': AppKeys.userBoxName, 'display': 'Préparation utilisateurs'},
|
||||
{'name': AppKeys.amicaleBoxName, 'display': 'Préparation amicale'},
|
||||
{'name': AppKeys.clientsBoxName, 'display': 'Préparation clients'},
|
||||
{'name': AppKeys.regionsBoxName, 'display': 'Préparation régions'},
|
||||
{'name': AppKeys.operationsBoxName, 'display': 'Préparation opérations'},
|
||||
{'name': AppKeys.sectorsBoxName, 'display': 'Préparation secteurs'},
|
||||
{'name': AppKeys.passagesBoxName, 'display': 'Préparation passages'},
|
||||
{'name': AppKeys.membresBoxName, 'display': 'Préparation membres'},
|
||||
{'name': AppKeys.userSectorBoxName, 'display': 'Préparation secteurs utilisateurs'},
|
||||
{'name': AppKeys.settingsBoxName, 'display': 'Préparation paramètres'},
|
||||
{'name': AppKeys.chatConversationsBoxName, 'display': 'Préparation conversations'},
|
||||
{'name': AppKeys.chatMessagesBoxName, 'display': 'Préparation messages'},
|
||||
];
|
||||
// Étape 1: Sauvegarder les utilisateurs existants (optionnel)
|
||||
Map<dynamic, UserModel>? existingUsers;
|
||||
|
||||
// Calculer l'incrément de progression pour chaque boîte (0.75 / nombre de boîtes)
|
||||
final progressIncrement = 0.75 / boxesToOpen.length;
|
||||
double currentProgress = 0.0;
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
_statusMessage = "Sauvegarde des utilisateurs...";
|
||||
_progress = 0.05;
|
||||
});
|
||||
}
|
||||
|
||||
// Ouvrir chaque boîte si elle n'est pas déjà ouverte
|
||||
for (int i = 0; i < boxesToOpen.length; i++) {
|
||||
final boxName = boxesToOpen[i]['name'] as String;
|
||||
final displayName = boxesToOpen[i]['display'] as String;
|
||||
try {
|
||||
if (Hive.isBoxOpen(AppKeys.userBoxName)) {
|
||||
final userBox = Hive.box<UserModel>(AppKeys.userBoxName);
|
||||
existingUsers = Map.from(userBox.toMap());
|
||||
debugPrint('📦 ${existingUsers.length} utilisateurs sauvegardés');
|
||||
}
|
||||
} catch (e) {
|
||||
debugPrint('⚠️ Erreur sauvegarde utilisateurs: $e');
|
||||
existingUsers = null;
|
||||
}
|
||||
|
||||
// Mettre à jour la barre de progression et le message
|
||||
currentProgress = progressIncrement * (i + 1);
|
||||
// Étape 2: DESTRUCTION RADICALE - Fermer tout ce qui peut être ouvert
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
_statusMessage = "Fermeture de toutes les bases de données...";
|
||||
_progress = 0.15;
|
||||
});
|
||||
}
|
||||
|
||||
await _closeAllKnownBoxes();
|
||||
|
||||
// Étape 3: DESTRUCTION RADICALE - Supprimer tout Hive du disque
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
_statusMessage = "Suppression complète des anciennes données...";
|
||||
_progress = 0.25;
|
||||
});
|
||||
}
|
||||
|
||||
await _nukeHiveCompletely();
|
||||
|
||||
// Étape 4: RECRÉATION PROPRE
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
_statusMessage = "Création des nouvelles bases de données...";
|
||||
_progress = 0.40;
|
||||
});
|
||||
}
|
||||
|
||||
await _createAllBoxesFresh();
|
||||
|
||||
// Étape 5: Restaurer les utilisateurs (optionnel)
|
||||
if (existingUsers != null && existingUsers.isNotEmpty) {
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
_statusMessage = displayName;
|
||||
_progress = currentProgress;
|
||||
_statusMessage = "Restauration des utilisateurs...";
|
||||
_progress = 0.80;
|
||||
});
|
||||
}
|
||||
|
||||
if (!Hive.isBoxOpen(boxName)) {
|
||||
debugPrint('Ouverture de la boîte $boxName ($displayName)...');
|
||||
|
||||
// Ouvrir la boîte avec le type approprié
|
||||
if (boxName == AppKeys.userBoxName) {
|
||||
await Hive.openBox<UserModel>(boxName);
|
||||
} else if (boxName == AppKeys.amicaleBoxName) {
|
||||
await Hive.openBox<AmicaleModel>(boxName);
|
||||
} else if (boxName == AppKeys.clientsBoxName) {
|
||||
await Hive.openBox<ClientModel>(boxName);
|
||||
} else if (boxName == AppKeys.regionsBoxName) {
|
||||
// Ouvrir la boîte des régions sans type spécifique pour l'instant
|
||||
// car RegionModelAdapter n'est pas encore enregistré
|
||||
await Hive.openBox(boxName);
|
||||
} else if (boxName == AppKeys.operationsBoxName) {
|
||||
await Hive.openBox<OperationModel>(boxName);
|
||||
} else if (boxName == AppKeys.sectorsBoxName) {
|
||||
await Hive.openBox<SectorModel>(boxName);
|
||||
} else if (boxName == AppKeys.passagesBoxName) {
|
||||
await Hive.openBox<PassageModel>(boxName);
|
||||
} else if (boxName == AppKeys.membresBoxName) {
|
||||
await Hive.openBox<MembreModel>(boxName);
|
||||
} else if (boxName == AppKeys.userSectorBoxName) {
|
||||
await Hive.openBox<UserSectorModel>(boxName);
|
||||
} else if (boxName == AppKeys.chatConversationsBoxName) {
|
||||
await Hive.openBox<ConversationModel>(boxName);
|
||||
} else if (boxName == AppKeys.chatMessagesBoxName) {
|
||||
await Hive.openBox<MessageModel>(boxName);
|
||||
} else {
|
||||
await Hive.openBox(boxName);
|
||||
}
|
||||
|
||||
debugPrint('Boîte $boxName ouverte avec succès');
|
||||
} else {
|
||||
debugPrint('Boîte $boxName déjà ouverte');
|
||||
}
|
||||
|
||||
// Ajouter une temporisation entre chaque ouverture
|
||||
await Future.delayed(const Duration(milliseconds: 500));
|
||||
await _restoreUsers(existingUsers);
|
||||
}
|
||||
|
||||
// Mettre à jour la barre de progression à 0.2 (20%) à la fin
|
||||
// Étape 6: Vérification finale
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
_statusMessage = 'Toutes les boîtes sont prêtes';
|
||||
_progress = 0.8;
|
||||
_statusMessage = "Vérification des bases de données...";
|
||||
_progress = 0.90;
|
||||
});
|
||||
await Future.delayed(const Duration(milliseconds: 500));
|
||||
}
|
||||
|
||||
debugPrint('✅ RESET COMPLET terminé avec succès');
|
||||
} catch (e) {
|
||||
debugPrint('❌ Erreur lors du reset complet: $e');
|
||||
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
_statusMessage = "Préparation de l'application...";
|
||||
_progress = 0.9;
|
||||
});
|
||||
await Future.delayed(const Duration(milliseconds: 500));
|
||||
}
|
||||
|
||||
// Finalisation
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
_statusMessage = "Erreur critique - Redémarrage recommandé";
|
||||
_progress = 1.0;
|
||||
_isInitializing = false;
|
||||
_showButtons = true;
|
||||
_progress = 1.0;
|
||||
});
|
||||
}
|
||||
debugPrint('Toutes les boîtes Hive sont maintenant ouvertes');
|
||||
} catch (e) {
|
||||
debugPrint('Erreur lors de l\'initialisation des boîtes Hive: $e');
|
||||
}
|
||||
}
|
||||
|
||||
// En cas d'erreur, mettre à jour le message
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
_statusMessage = 'Erreur lors de l\'initialisation des données';
|
||||
});
|
||||
/// Ferme toutes les boîtes connues
|
||||
Future<void> _closeAllKnownBoxes() async {
|
||||
try {
|
||||
final allKnownBoxes = [
|
||||
AppKeys.userBoxName,
|
||||
AppKeys.amicaleBoxName,
|
||||
AppKeys.clientsBoxName,
|
||||
AppKeys.regionsBoxName,
|
||||
AppKeys.operationsBoxName,
|
||||
AppKeys.sectorsBoxName,
|
||||
AppKeys.passagesBoxName,
|
||||
AppKeys.membresBoxName,
|
||||
AppKeys.userSectorBoxName,
|
||||
AppKeys.settingsBoxName,
|
||||
AppKeys.chatConversationsBoxName,
|
||||
AppKeys.chatMessagesBoxName,
|
||||
// Boîtes potentiellement problématiques
|
||||
'auth', 'locations', 'messages', 'temp'
|
||||
];
|
||||
|
||||
debugPrint('🔒 Fermeture de ${allKnownBoxes.length} boîtes connues...');
|
||||
|
||||
for (final boxName in allKnownBoxes) {
|
||||
try {
|
||||
if (Hive.isBoxOpen(boxName)) {
|
||||
await Hive.box(boxName).close();
|
||||
debugPrint('✅ Boîte $boxName fermée');
|
||||
}
|
||||
} catch (e) {
|
||||
debugPrint('⚠️ Erreur fermeture $boxName: $e');
|
||||
// Continuer même en cas d'erreur
|
||||
}
|
||||
}
|
||||
|
||||
await Future.delayed(const Duration(milliseconds: 1000));
|
||||
} catch (e) {
|
||||
debugPrint('❌ Erreur fermeture des boîtes: $e');
|
||||
}
|
||||
}
|
||||
|
||||
/// Suppression RADICALE de tout Hive
|
||||
Future<void> _nukeHiveCompletely() async {
|
||||
try {
|
||||
debugPrint('💥 DESTRUCTION NUCLÉAIRE de Hive...');
|
||||
|
||||
if (kIsWeb) {
|
||||
// En version web, supprimer toutes les boîtes possibles une par une
|
||||
final allPossibleBoxes = [
|
||||
AppKeys.userBoxName,
|
||||
AppKeys.amicaleBoxName,
|
||||
AppKeys.clientsBoxName,
|
||||
AppKeys.regionsBoxName,
|
||||
AppKeys.operationsBoxName,
|
||||
AppKeys.sectorsBoxName,
|
||||
AppKeys.passagesBoxName,
|
||||
AppKeys.membresBoxName,
|
||||
AppKeys.userSectorBoxName,
|
||||
AppKeys.settingsBoxName,
|
||||
AppKeys.chatConversationsBoxName,
|
||||
AppKeys.chatMessagesBoxName,
|
||||
// Toutes les boîtes potentiellement corrompues
|
||||
'auth', 'locations', 'messages', 'temp', 'cache', 'data'
|
||||
];
|
||||
|
||||
for (final boxName in allPossibleBoxes) {
|
||||
try {
|
||||
await Hive.deleteBoxFromDisk(boxName);
|
||||
debugPrint('✅ Boîte $boxName DÉTRUITE');
|
||||
} catch (e) {
|
||||
debugPrint('⚠️ Erreur destruction $boxName: $e');
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Sur mobile/desktop, destruction totale
|
||||
try {
|
||||
await Hive.deleteFromDisk();
|
||||
debugPrint('✅ Hive COMPLÈTEMENT DÉTRUIT');
|
||||
} catch (e) {
|
||||
debugPrint('⚠️ Erreur destruction totale: $e');
|
||||
// Fallback : supprimer boîte par boîte
|
||||
await _deleteBoxesOneByOne();
|
||||
}
|
||||
}
|
||||
|
||||
// Attendre pour s'assurer que tout est détruit
|
||||
await Future.delayed(const Duration(seconds: 2));
|
||||
} catch (e) {
|
||||
debugPrint('❌ Erreur destruction Hive: $e');
|
||||
}
|
||||
}
|
||||
|
||||
/// Fallback : supprimer les boîtes une par une
|
||||
Future<void> _deleteBoxesOneByOne() async {
|
||||
final allBoxes = [
|
||||
AppKeys.userBoxName,
|
||||
AppKeys.amicaleBoxName,
|
||||
AppKeys.clientsBoxName,
|
||||
AppKeys.regionsBoxName,
|
||||
AppKeys.operationsBoxName,
|
||||
AppKeys.sectorsBoxName,
|
||||
AppKeys.passagesBoxName,
|
||||
AppKeys.membresBoxName,
|
||||
AppKeys.userSectorBoxName,
|
||||
AppKeys.settingsBoxName,
|
||||
AppKeys.chatConversationsBoxName,
|
||||
AppKeys.chatMessagesBoxName,
|
||||
];
|
||||
|
||||
for (final boxName in allBoxes) {
|
||||
try {
|
||||
await Hive.deleteBoxFromDisk(boxName);
|
||||
debugPrint('✅ Boîte $boxName supprimée (fallback)');
|
||||
} catch (e) {
|
||||
debugPrint('⚠️ Erreur suppression fallback $boxName: $e');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Recrée toutes les boîtes VIDES et PROPRES
|
||||
Future<void> _createAllBoxesFresh() async {
|
||||
try {
|
||||
debugPrint('🆕 Création de toutes les boîtes vides...');
|
||||
|
||||
final boxesToCreate = [
|
||||
{'name': AppKeys.userBoxName, 'type': 'UserModel'},
|
||||
{'name': AppKeys.amicaleBoxName, 'type': 'AmicaleModel'},
|
||||
{'name': AppKeys.clientsBoxName, 'type': 'ClientModel'},
|
||||
{'name': AppKeys.regionsBoxName, 'type': 'dynamic'},
|
||||
{'name': AppKeys.operationsBoxName, 'type': 'OperationModel'},
|
||||
{'name': AppKeys.sectorsBoxName, 'type': 'SectorModel'},
|
||||
{'name': AppKeys.passagesBoxName, 'type': 'PassageModel'},
|
||||
{'name': AppKeys.membresBoxName, 'type': 'MembreModel'},
|
||||
{'name': AppKeys.userSectorBoxName, 'type': 'UserSectorModel'},
|
||||
{'name': AppKeys.settingsBoxName, 'type': 'dynamic'},
|
||||
{'name': AppKeys.chatConversationsBoxName, 'type': 'ConversationModel'},
|
||||
{'name': AppKeys.chatMessagesBoxName, 'type': 'MessageModel'},
|
||||
];
|
||||
|
||||
final progressIncrement = 0.35 / boxesToCreate.length; // De 0.40 à 0.75
|
||||
|
||||
for (int i = 0; i < boxesToCreate.length; i++) {
|
||||
final boxInfo = boxesToCreate[i];
|
||||
final boxName = boxInfo['name'] as String;
|
||||
final boxType = boxInfo['type'] as String;
|
||||
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
_statusMessage = "Création de $boxName...";
|
||||
_progress = 0.40 + (progressIncrement * i);
|
||||
});
|
||||
}
|
||||
|
||||
try {
|
||||
// Créer la boîte avec le bon type
|
||||
switch (boxType) {
|
||||
case 'UserModel':
|
||||
await Hive.openBox<UserModel>(boxName);
|
||||
break;
|
||||
case 'AmicaleModel':
|
||||
await Hive.openBox<AmicaleModel>(boxName);
|
||||
break;
|
||||
case 'ClientModel':
|
||||
await Hive.openBox<ClientModel>(boxName);
|
||||
break;
|
||||
case 'OperationModel':
|
||||
await Hive.openBox<OperationModel>(boxName);
|
||||
break;
|
||||
case 'SectorModel':
|
||||
await Hive.openBox<SectorModel>(boxName);
|
||||
break;
|
||||
case 'PassageModel':
|
||||
await Hive.openBox<PassageModel>(boxName);
|
||||
break;
|
||||
case 'MembreModel':
|
||||
await Hive.openBox<MembreModel>(boxName);
|
||||
break;
|
||||
case 'UserSectorModel':
|
||||
await Hive.openBox<UserSectorModel>(boxName);
|
||||
break;
|
||||
case 'ConversationModel':
|
||||
await Hive.openBox<ConversationModel>(boxName);
|
||||
break;
|
||||
case 'MessageModel':
|
||||
await Hive.openBox<MessageModel>(boxName);
|
||||
break;
|
||||
default:
|
||||
await Hive.openBox(boxName);
|
||||
}
|
||||
|
||||
debugPrint('✅ Boîte $boxName créée (type: $boxType)');
|
||||
} catch (e) {
|
||||
debugPrint('❌ Erreur création $boxName: $e');
|
||||
// En cas d'erreur, essayer sans type
|
||||
try {
|
||||
await Hive.openBox(boxName);
|
||||
debugPrint('⚠️ Boîte $boxName créée sans type');
|
||||
} catch (e2) {
|
||||
debugPrint('❌ Échec total création $boxName: $e2');
|
||||
}
|
||||
}
|
||||
|
||||
await Future.delayed(const Duration(milliseconds: 200));
|
||||
}
|
||||
} catch (e) {
|
||||
debugPrint('❌ Erreur création des boîtes: $e');
|
||||
}
|
||||
}
|
||||
|
||||
/// Restaure les utilisateurs sauvegardés
|
||||
Future<void> _restoreUsers(Map<dynamic, UserModel> users) async {
|
||||
try {
|
||||
if (Hive.isBoxOpen(AppKeys.userBoxName)) {
|
||||
final userBox = Hive.box<UserModel>(AppKeys.userBoxName);
|
||||
|
||||
for (final entry in users.entries) {
|
||||
try {
|
||||
await userBox.put(entry.key, entry.value);
|
||||
} catch (e) {
|
||||
debugPrint('⚠️ Erreur restauration utilisateur ${entry.key}: $e');
|
||||
}
|
||||
}
|
||||
|
||||
debugPrint('✅ ${users.length} utilisateurs restaurés');
|
||||
}
|
||||
} catch (e) {
|
||||
debugPrint('❌ Erreur restauration utilisateurs: $e');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -295,7 +475,7 @@ class _SplashPageState extends State<SplashPage> with SingleTickerProviderStateM
|
||||
children: [
|
||||
const Spacer(flex: 2),
|
||||
|
||||
// Logo avec animation de réduction
|
||||
// Logo avec animation
|
||||
AnimatedBuilder(
|
||||
animation: _scaleAnimation,
|
||||
builder: (context, child) {
|
||||
@@ -306,13 +486,13 @@ class _SplashPageState extends State<SplashPage> with SingleTickerProviderStateM
|
||||
},
|
||||
child: Image.asset(
|
||||
'assets/images/logo-geosector-1024.png',
|
||||
height: 180, // Augmenté de 140 à 180
|
||||
height: 180,
|
||||
),
|
||||
),
|
||||
|
||||
const SizedBox(height: 24),
|
||||
|
||||
// Titre avec animation fade-in
|
||||
// Titre
|
||||
AnimatedOpacity(
|
||||
opacity: _isInitializing ? 0.9 : 1.0,
|
||||
duration: const Duration(milliseconds: 500),
|
||||
@@ -328,7 +508,7 @@ class _SplashPageState extends State<SplashPage> with SingleTickerProviderStateM
|
||||
|
||||
const SizedBox(height: 16),
|
||||
|
||||
// Sous-titre avec nouveau slogan
|
||||
// Sous-titre
|
||||
AnimatedOpacity(
|
||||
opacity: _isInitializing ? 0.8 : 1.0,
|
||||
duration: const Duration(milliseconds: 500),
|
||||
@@ -356,7 +536,7 @@ class _SplashPageState extends State<SplashPage> with SingleTickerProviderStateM
|
||||
valueColor: AlwaysStoppedAnimation<Color>(
|
||||
theme.colorScheme.primary,
|
||||
),
|
||||
minHeight: 10, // Augmenté de 6 à 10
|
||||
minHeight: 10,
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -369,7 +549,7 @@ class _SplashPageState extends State<SplashPage> with SingleTickerProviderStateM
|
||||
),
|
||||
],
|
||||
|
||||
// Boutons après l'initialisation
|
||||
// Boutons (reste identique)
|
||||
if (_showButtons) ...[
|
||||
// Bouton Connexion Utilisateur
|
||||
AnimatedOpacity(
|
||||
@@ -377,7 +557,7 @@ class _SplashPageState extends State<SplashPage> with SingleTickerProviderStateM
|
||||
duration: const Duration(milliseconds: 500),
|
||||
child: ElevatedButton(
|
||||
onPressed: () {
|
||||
context.go('/login/user'); // Utiliser la route spécifique
|
||||
context.go('/login/user');
|
||||
},
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: Colors.green,
|
||||
@@ -402,13 +582,13 @@ class _SplashPageState extends State<SplashPage> with SingleTickerProviderStateM
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
|
||||
// Bouton Connexion Administrateur
|
||||
// Bouton Connexion Administrateur
|
||||
AnimatedOpacity(
|
||||
opacity: _showButtons ? 1.0 : 0.0,
|
||||
duration: const Duration(milliseconds: 500),
|
||||
child: ElevatedButton(
|
||||
onPressed: () {
|
||||
context.go('/login/admin'); // Utiliser la route spécifique
|
||||
context.go('/login/admin');
|
||||
},
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: Colors.red,
|
||||
@@ -432,7 +612,7 @@ class _SplashPageState extends State<SplashPage> with SingleTickerProviderStateM
|
||||
),
|
||||
),
|
||||
|
||||
const SizedBox(height: 32), // 2 espaces sous le bouton précédent
|
||||
const SizedBox(height: 32),
|
||||
|
||||
// Bouton d'inscription
|
||||
AnimatedOpacity(
|
||||
@@ -472,7 +652,6 @@ class _SplashPageState extends State<SplashPage> with SingleTickerProviderStateM
|
||||
duration: const Duration(milliseconds: 500),
|
||||
child: TextButton.icon(
|
||||
onPressed: () {
|
||||
// Déterminer l'URL du site web en fonction de l'environnement
|
||||
String webUrl = 'https://geosector.fr';
|
||||
|
||||
if (kIsWeb) {
|
||||
@@ -486,7 +665,6 @@ class _SplashPageState extends State<SplashPage> with SingleTickerProviderStateM
|
||||
}
|
||||
}
|
||||
|
||||
// Ouvrir l'URL dans une nouvelle fenêtre/onglet
|
||||
launchUrl(
|
||||
Uri.parse(webUrl),
|
||||
mode: LaunchMode.externalApplication,
|
||||
@@ -514,7 +692,8 @@ class _SplashPageState extends State<SplashPage> with SingleTickerProviderStateM
|
||||
),
|
||||
),
|
||||
),
|
||||
// Badge de version en bas à droite
|
||||
|
||||
// Badge de version
|
||||
if (_appVersion.isNotEmpty)
|
||||
Positioned(
|
||||
bottom: 16,
|
||||
|
||||
@@ -98,14 +98,23 @@ class _AmicaleFormState extends State<AmicaleForm> {
|
||||
|
||||
// Appeler l'API pour mettre à jour l'entité
|
||||
Future<void> _updateAmicale(AmicaleModel amicale) async {
|
||||
if (!mounted) return;
|
||||
|
||||
try {
|
||||
// Afficher un indicateur de chargement
|
||||
showDialog(
|
||||
context: context,
|
||||
barrierDismissible: false,
|
||||
builder: (BuildContext context) {
|
||||
return const Center(
|
||||
child: CircularProgressIndicator(),
|
||||
return const AlertDialog(
|
||||
content: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
CircularProgressIndicator(),
|
||||
SizedBox(height: 16),
|
||||
Text('Mise à jour en cours...'),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
@@ -121,9 +130,9 @@ class _AmicaleFormState extends State<AmicaleForm> {
|
||||
'phone': amicale.phone,
|
||||
'mobile': amicale.mobile,
|
||||
'email': amicale.email,
|
||||
'chk_copie_mail_recu': amicale.chkCopieMailRecu,
|
||||
'chk_accept_sms': amicale.chkAcceptSms,
|
||||
'chk_stripe': amicale.chkStripe,
|
||||
'chk_copie_mail_recu': amicale.chkCopieMailRecu ? 1 : 0,
|
||||
'chk_accept_sms': amicale.chkAcceptSms ? 1 : 0,
|
||||
'chk_stripe': amicale.chkStripe ? 1 : 0,
|
||||
};
|
||||
|
||||
// Ajouter les champs réservés aux administrateurs si l'utilisateur est admin
|
||||
@@ -132,63 +141,81 @@ class _AmicaleFormState extends State<AmicaleForm> {
|
||||
data['gps_lat'] = amicale.gpsLat;
|
||||
data['gps_lng'] = amicale.gpsLng;
|
||||
data['stripe_id'] = amicale.stripeId;
|
||||
data['chk_demo'] = amicale.chkDemo;
|
||||
data['chk_active'] = amicale.chkActive;
|
||||
data['chk_demo'] = amicale.chkDemo ? 1 : 0;
|
||||
data['chk_active'] = amicale.chkActive ? 1 : 0;
|
||||
}
|
||||
|
||||
// Fermer l'indicateur de chargement
|
||||
Navigator.of(context).pop();
|
||||
debugPrint('🔧 Données à envoyer à l\'API: $data');
|
||||
|
||||
bool apiSuccess = false;
|
||||
String? errorMessage;
|
||||
|
||||
// Appeler l'API si le service est disponible
|
||||
if (widget.apiService != null) {
|
||||
try {
|
||||
await widget.apiService!.post('/entite/update', data: data);
|
||||
debugPrint('📡 Appel API pour mise à jour amicale...');
|
||||
|
||||
// Afficher un message de succès
|
||||
if (mounted) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(
|
||||
content: Text('Amicale mise à jour avec succès'),
|
||||
backgroundColor: Colors.green,
|
||||
),
|
||||
);
|
||||
// Version RESTful correcte avec PUT
|
||||
final response = await widget.apiService!.put('/entites/${amicale.id}', data: data);
|
||||
|
||||
// Alternative avec PATCH si votre API le supporte
|
||||
// final response = await widget.apiService!.patch('/entites/${amicale.id}', data: data);
|
||||
|
||||
debugPrint('📡 Réponse API: ${response.statusCode}');
|
||||
|
||||
if (response.statusCode == 200 || response.statusCode == 201) {
|
||||
apiSuccess = true;
|
||||
} else {
|
||||
errorMessage = 'Erreur serveur: ${response.statusCode}';
|
||||
}
|
||||
} catch (error) {
|
||||
// Afficher un message d'erreur
|
||||
if (mounted) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text('Erreur lors de la mise à jour de l\'amicale: $error'),
|
||||
backgroundColor: Colors.red,
|
||||
),
|
||||
);
|
||||
}
|
||||
return; // Sortir de la fonction en cas d'erreur
|
||||
}
|
||||
} else {
|
||||
// Pas d'API service, afficher un message d'information
|
||||
if (mounted) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(
|
||||
content: Text('Modifications enregistrées localement'),
|
||||
backgroundColor: Colors.blue,
|
||||
),
|
||||
);
|
||||
debugPrint('❌ Erreur API: $error');
|
||||
errorMessage = 'Erreur lors de la communication avec le serveur: $error';
|
||||
}
|
||||
}
|
||||
|
||||
// Appeler la fonction onSubmit si elle existe
|
||||
if (widget.onSubmit != null) {
|
||||
widget.onSubmit!(amicale);
|
||||
}
|
||||
|
||||
// Fermer le formulaire
|
||||
if (mounted) {
|
||||
// Fermer l'indicateur de chargement
|
||||
if (mounted && Navigator.of(context).canPop()) {
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
|
||||
if (!mounted) return;
|
||||
|
||||
if (apiSuccess) {
|
||||
// Appeler la fonction onSubmit si elle existe
|
||||
if (widget.onSubmit != null) {
|
||||
widget.onSubmit!(amicale);
|
||||
}
|
||||
|
||||
// Afficher un message de succès
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text(widget.apiService != null ? 'Amicale mise à jour avec succès' : 'Modifications enregistrées localement'),
|
||||
backgroundColor: Colors.green,
|
||||
),
|
||||
);
|
||||
|
||||
// Fermer le formulaire après un délai pour que l'utilisateur voie le message
|
||||
await Future.delayed(const Duration(milliseconds: 500));
|
||||
|
||||
if (mounted && Navigator.of(context).canPop()) {
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
} else {
|
||||
// Afficher un message d'erreur
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text(errorMessage ?? 'Erreur lors de la mise à jour'),
|
||||
backgroundColor: Colors.red,
|
||||
duration: const Duration(seconds: 4),
|
||||
),
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
debugPrint('❌ Erreur générale dans _updateAmicale: $e');
|
||||
|
||||
// Fermer l'indicateur de chargement si encore ouvert
|
||||
if (Navigator.of(context).canPop()) {
|
||||
if (mounted && Navigator.of(context).canPop()) {
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
|
||||
@@ -196,8 +223,9 @@ class _AmicaleFormState extends State<AmicaleForm> {
|
||||
if (mounted) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text('Erreur: ${e.toString()}'),
|
||||
content: Text('Erreur inattendue: ${e.toString()}'),
|
||||
backgroundColor: Colors.red,
|
||||
duration: const Duration(seconds: 4),
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -205,9 +233,14 @@ class _AmicaleFormState extends State<AmicaleForm> {
|
||||
}
|
||||
|
||||
void _submitForm() {
|
||||
debugPrint('🔧 _submitForm appelée');
|
||||
|
||||
if (_formKey.currentState!.validate()) {
|
||||
debugPrint('🔧 Formulaire valide');
|
||||
|
||||
// Vérifier qu'au moins un numéro de téléphone est renseigné
|
||||
if (_phoneController.text.isEmpty && _mobileController.text.isEmpty) {
|
||||
debugPrint('⚠️ Aucun numéro de téléphone renseigné');
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(
|
||||
content: Text('Veuillez renseigner au moins un numéro de téléphone'),
|
||||
@@ -217,6 +250,8 @@ class _AmicaleFormState extends State<AmicaleForm> {
|
||||
return;
|
||||
}
|
||||
|
||||
debugPrint('🔧 Création de l\'objet AmicaleModel...');
|
||||
|
||||
final amicale = widget.amicale?.copyWith(
|
||||
name: _nameController.text,
|
||||
adresse1: _adresse1Controller.text,
|
||||
@@ -258,10 +293,13 @@ class _AmicaleFormState extends State<AmicaleForm> {
|
||||
chkActive: _chkActive,
|
||||
);
|
||||
|
||||
debugPrint('🔧 AmicaleModel créé: ${amicale.name}');
|
||||
debugPrint('🔧 Appel de _updateAmicale...');
|
||||
|
||||
// Appeler l'API pour mettre à jour l'amicale
|
||||
_updateAmicale(amicale);
|
||||
|
||||
// Ne pas appeler widget.onSubmit ici car c'est fait dans _updateAmicale
|
||||
} else {
|
||||
debugPrint('❌ Formulaire invalide');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ class AmicaleTableWidget extends StatelessWidget {
|
||||
final Function(AmicaleModel)? onDelete;
|
||||
final AmicaleRepository amicaleRepository;
|
||||
final UserRepository userRepository; // Nouveau paramètre
|
||||
final ApiService? apiService; // Nouveau paramètre optionnel
|
||||
final ApiService? apiService;
|
||||
final bool isLoading;
|
||||
final String? emptyMessage;
|
||||
final bool readOnly;
|
||||
@@ -35,7 +35,7 @@ class AmicaleTableWidget extends StatelessWidget {
|
||||
required this.userRepository, // Requis
|
||||
this.onEdit,
|
||||
this.onDelete,
|
||||
this.apiService, // Optionnel
|
||||
this.apiService,
|
||||
this.isLoading = false,
|
||||
this.emptyMessage,
|
||||
this.readOnly = false,
|
||||
@@ -83,9 +83,13 @@ class AmicaleTableWidget extends StatelessWidget {
|
||||
readOnly: false,
|
||||
userRepository: userRepository,
|
||||
apiService: apiService,
|
||||
onSubmit: (updatedAmicale) {
|
||||
onSubmit: (updatedAmicale) async {
|
||||
// Sauvegarder l'amicale mise à jour dans le repository
|
||||
debugPrint('🔄 Sauvegarde de l\'amicale mise à jour: ${updatedAmicale.name}');
|
||||
await amicaleRepository.saveAmicale(updatedAmicale);
|
||||
debugPrint('✅ Amicale sauvegardée dans le repository');
|
||||
|
||||
Navigator.of(dialogContext).pop();
|
||||
// La mise à jour sera gérée par les ValueListenableBuilder
|
||||
},
|
||||
),
|
||||
),
|
||||
@@ -227,7 +231,12 @@ class AmicaleTableWidget extends StatelessWidget {
|
||||
readOnly: true,
|
||||
userRepository: userRepository,
|
||||
apiService: apiService,
|
||||
onSubmit: (updatedAmicale) {
|
||||
onSubmit: (updatedAmicale) async {
|
||||
// Sauvegarder l'amicale mise à jour dans le repository
|
||||
debugPrint('🔄 Sauvegarde de l\'amicale mise à jour: ${updatedAmicale.name}');
|
||||
await amicaleRepository.saveAmicale(updatedAmicale);
|
||||
debugPrint('✅ Amicale sauvegardée dans le repository');
|
||||
|
||||
Navigator.of(dialogContext).pop();
|
||||
},
|
||||
),
|
||||
|
||||
@@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter_map/flutter_map.dart';
|
||||
import 'package:latlong2/latlong.dart';
|
||||
import 'package:geosector_app/core/constants/app_keys.dart';
|
||||
import 'package:geosector_app/app.dart'; // Pour accéder à l'instance globale de ApiService
|
||||
import 'package:geosector_app/core/services/api_service.dart'; // Import du service singleton
|
||||
|
||||
/// Widget de carte réutilisable utilisant Mapbox
|
||||
///
|
||||
@@ -105,11 +105,10 @@ class _MapboxMapState extends State<MapboxMap> {
|
||||
Widget build(BuildContext context) {
|
||||
// Déterminer l'URL du template de tuiles Mapbox
|
||||
// Utiliser l'environnement actuel pour obtenir la bonne clé API
|
||||
final String environment = apiService.getCurrentEnvironment();
|
||||
final String environment = ApiService.instance.getCurrentEnvironment();
|
||||
final String mapboxToken = AppKeys.getMapboxApiKey(environment);
|
||||
final String mapStyle = widget.mapStyle ?? 'mapbox/streets-v11';
|
||||
final String urlTemplate =
|
||||
'https://api.mapbox.com/styles/v1/$mapStyle/tiles/256/{z}/{x}/{y}@2x?access_token=$mapboxToken';
|
||||
final String urlTemplate = 'https://api.mapbox.com/styles/v1/$mapStyle/tiles/256/{z}/{x}/{y}@2x?access_token=$mapboxToken';
|
||||
|
||||
return Stack(
|
||||
children: [
|
||||
@@ -145,12 +144,10 @@ class _MapboxMapState extends State<MapboxMap> {
|
||||
),
|
||||
|
||||
// Polygones
|
||||
if (widget.polygons != null && widget.polygons!.isNotEmpty)
|
||||
PolygonLayer(polygons: widget.polygons!),
|
||||
if (widget.polygons != null && widget.polygons!.isNotEmpty) PolygonLayer(polygons: widget.polygons!),
|
||||
|
||||
// Marqueurs
|
||||
if (widget.markers != null && widget.markers!.isNotEmpty)
|
||||
MarkerLayer(markers: widget.markers!),
|
||||
if (widget.markers != null && widget.markers!.isNotEmpty) MarkerLayer(markers: widget.markers!),
|
||||
],
|
||||
),
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@ class MembreRowWidget extends StatelessWidget {
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Text(
|
||||
membre.firstName,
|
||||
membre.firstName ?? '',
|
||||
style: theme.textTheme.bodyMedium,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
@@ -54,7 +54,7 @@ class MembreRowWidget extends StatelessWidget {
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Text(
|
||||
membre.name,
|
||||
membre.name ?? '',
|
||||
style: theme.textTheme.bodyMedium,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
@@ -70,31 +70,31 @@ class MembreRowWidget extends StatelessWidget {
|
||||
),
|
||||
),
|
||||
|
||||
// Rôle (fkRole)
|
||||
// Rôle (role au lieu de fkRole)
|
||||
Expanded(
|
||||
flex: 1,
|
||||
child: Text(
|
||||
_getRoleName(membre.fkRole),
|
||||
_getRoleName(membre.role),
|
||||
style: theme.textTheme.bodyMedium,
|
||||
),
|
||||
),
|
||||
|
||||
// Statut (actif/inactif)
|
||||
// Statut (isActive au lieu de chkActive)
|
||||
Expanded(
|
||||
flex: 1,
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
|
||||
decoration: BoxDecoration(
|
||||
color: membre.chkActive == 1 ? Colors.green.withOpacity(0.1) : Colors.red.withOpacity(0.1),
|
||||
color: membre.isActive ? Colors.green.withOpacity(0.1) : Colors.red.withOpacity(0.1),
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
border: Border.all(
|
||||
color: membre.chkActive == 1 ? Colors.green.withOpacity(0.3) : Colors.red.withOpacity(0.3),
|
||||
color: membre.isActive ? Colors.green.withOpacity(0.3) : Colors.red.withOpacity(0.3),
|
||||
),
|
||||
),
|
||||
child: Text(
|
||||
membre.chkActive == 1 ? 'Actif' : 'Inactif',
|
||||
membre.isActive ? 'Actif' : 'Inactif',
|
||||
style: theme.textTheme.bodySmall?.copyWith(
|
||||
color: membre.chkActive == 1 ? Colors.green[700] : Colors.red[700],
|
||||
color: membre.isActive ? Colors.green[700] : Colors.red[700],
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
@@ -161,18 +161,20 @@ class MembreRowWidget extends StatelessWidget {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => AlertDialog(
|
||||
title: Text('${membre.firstName} ${membre.name}'),
|
||||
title: Text('${membre.firstName ?? ''} ${membre.name ?? ''}'),
|
||||
content: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
_buildDetailRow('ID', membre.id.toString()),
|
||||
_buildDetailRow('Email', membre.email),
|
||||
_buildDetailRow('Username', membre.username),
|
||||
_buildDetailRow('Rôle', _getRoleName(membre.fkRole)),
|
||||
_buildDetailRow('Titre', membre.fkTitre.toString()),
|
||||
_buildDetailRow('Username', membre.username ?? 'Non défini'),
|
||||
_buildDetailRow('Rôle', _getRoleName(membre.role)),
|
||||
_buildDetailRow('Titre', membre.fkTitre?.toString() ?? 'Non défini'),
|
||||
_buildDetailRow('Secteur', membre.sectName ?? 'Non défini'),
|
||||
_buildDetailRow('Statut', membre.chkActive == 1 ? 'Actif' : 'Inactif'),
|
||||
_buildDetailRow('Statut', membre.isActive ? 'Actif' : 'Inactif'),
|
||||
_buildDetailRow('Téléphone', membre.phone ?? 'Non défini'),
|
||||
_buildDetailRow('Mobile', membre.mobile ?? 'Non défini'),
|
||||
if (membre.dateNaissance != null)
|
||||
_buildDetailRow('Date de naissance', '${membre.dateNaissance!.day}/${membre.dateNaissance!.month}/${membre.dateNaissance!.year}'),
|
||||
if (membre.dateEmbauche != null)
|
||||
|
||||
Reference in New Issue
Block a user