# GEOSECTOR v2.0 🚒 **Application de gestion des distributions de calendriers par secteurs géographiques pour les amicales de pompiers** --- ## 🎯 Vue d'ensemble GEOSECTOR est une solution complète développée en Flutter qui révolutionne la gestion des campagnes de distribution de calendriers pour les amicales de pompiers. L'application combine géolocalisation, gestion multi-rôles et synchronisation en temps réel pour optimiser les tournées et maximiser l'efficacité des équipes. ### 🏆 Points forts de la v2.0 - **Architecture moderne** sans Provider, basée sur l'injection de dépendances - **Réactivité native** avec ValueListenableBuilder et Hive - **Interface adaptative** selon les rôles utilisateur - **Performance optimisée** avec un ApiService singleton - **Gestion avancée des permissions** multi-niveaux - **Gestion d'erreurs centralisée** avec ApiException - **Interface utilisateur unifiée** avec UserFormDialog réutilisable --- ## 📋 Table des matières 1. [Fonctionnalités](#-fonctionnalités) 2. [Architecture technique](#️-architecture-technique) 3. [Installation](#-installation-et-configuration) 4. [Modèles de données](#️-modèles-de-données) 5. [Architecture des composants](#-architecture-des-composants) 6. [Gestion des rôles](#-gestion-des-rôles) 7. [Interface utilisateur](#-interface-utilisateur) 8. [API et synchronisation](#-api-et-synchronisation) 9. [Gestion des erreurs](#-gestion-des-erreurs) 10. [Cartes et géolocalisation](#️-cartes-et-géolocalisation) --- ## 🚀 Fonctionnalités ### 🎯 Fonctionnalités métier #### Pour les **Membres** (Rôle 1) - ✅ Visualisation des secteurs assignés sur carte interactive - ✅ Suivi GPS en temps réel des tournées - ✅ Enregistrement des passages avec géolocalisation - ✅ Gestion des stocks de calendriers - ✅ Historique des distributions - ✅ Chat intégré avec l'équipe #### Pour les **Admins Amicale** (Rôle 2) - ✅ Gestion de leur amicale (informations, coordonnées) - ✅ Gestion des membres de l'amicale (création, modification, suppression) - ✅ Attribution des rôles aux membres (Membre/Administrateur) - ✅ Gestion du statut actif des comptes membres - ✅ Consultation des statistiques de l'amicale - ✅ Attribution des secteurs aux membres - ✅ Suivi des performances équipe #### Pour les **Super Admins** (Rôle 3+) - ✅ Gestion globale multi-amicales - ✅ Administration des utilisateurs et permissions - ✅ Configuration des paramètres système - ✅ Analytics avancées et reporting - ✅ Gestion des secteurs géographiques ### 🔧 Fonctionnalités techniques - **🗺️ Cartographie avancée** : Flutter Map avec tuiles Mapbox - **📍 Géolocalisation précise** : Suivi GPS des équipes - **💾 Stockage hybride** : Cache local Hive + synchronisation cloud avec optimisation des performances - **💬 Communication** : Chat MQTT en temps réel - **🔐 Sécurité** : Authentification JWT + gestion fine des permissions - **📱 Multi-plateforme** : iOS, Android, Web - **🌐 Mode hors-ligne** : Fonctionnement dégradé sans connexion - **⚡ Gestion d'erreurs robuste** : Extraction automatique des messages API - **🎨 Interface responsive** : Adaptation automatique selon la taille d'écran --- ## 🏗️ Architecture technique ### Stack technologique | Composant | Technologie | Version | Usage | | ------------------- | ---------------------- | ------- | ------------------------------ | | **Framework** | Flutter | 3.32+ | Interface multi-plateforme | | **Langage** | Dart | 3.0+ | Logique applicative | | **Navigation** | GoRouter | 12.1.3 | Routing déclaratif | | **Stockage local** | Hive | 2.2.3 | Base de données NoSQL locale | | **Réactivité** | ValueListenableBuilder | Native | Écoute des changements Hive | | **HTTP** | Dio | 5.4.0 | Client HTTP avec intercepteurs | | **Cartes** | Flutter Map | 6.1.0 | Rendu cartographique | | **Géolocalisation** | Geolocator | 10.1.0 | Services de localisation | | **Chat** | MQTT5 Client | 4.2.0 | Messagerie temps réel | | **UI** | Material Design 3 | Native | Composants d'interface | ### 🏛️ Architecture en couches ```mermaid graph TD A[UI Layer - Widgets] --> B[Repository Layer - Business Logic] B --> C[Data Layer - Hive + API] A1[ValueListenableBuilder] --> A A2[Custom Widgets] --> A A3[UserFormDialog] --> A B1[UserRepository] --> B B2[AmicaleRepository] --> B B3[MembreRepository] --> B C1[Hive Boxes] --> C C2[API Service Singleton] --> C C3[ApiException Handler] --> C ``` ### 📁 Structure du projet ``` app/ ├── lib/ │ ├── core/ # Couche centrale │ │ ├── constants/ # Constantes globales │ │ │ ├── app_keys.dart # Clés des Box Hive │ │ │ └── api_endpoints.dart # Endpoints API │ │ ├── data/ │ │ │ └── models/ # Modèles Hive │ │ │ ├── user_model.dart # @HiveType(typeId: 3) │ │ │ ├── amicale_model.dart # @HiveType(typeId: 4) │ │ │ └── membre_model.dart # @HiveType(typeId: 5) │ │ ├── repositories/ # Logique métier │ │ │ ├── user_repository.dart │ │ │ ├── amicale_repository.dart │ │ │ └── membre_repository.dart │ │ ├── services/ # Services externes │ │ │ ├── api_service.dart # HTTP Singleton │ │ │ ├── chat_service.dart # MQTT │ │ │ └── location_service.dart # GPS │ │ └── utils/ # Utilitaires │ │ ├── validators.dart │ │ └── formatters.dart │ ├── presentation/ # Interface utilisateur │ │ ├── admin/ # Pages administrateur │ │ │ ├── admin_dashboard_page.dart │ │ │ ├── admin_amicale_page.dart │ │ │ └── admin_statistics_page.dart │ │ ├── user/ # Pages utilisateur │ │ │ ├── user_dashboard_page.dart │ │ │ ├── map_page.dart │ │ │ └── distribution_page.dart │ │ ├── widgets/ # Composants réutilisables │ │ │ ├── tables/ │ │ │ │ ├── amicale_table_widget.dart │ │ │ │ ├── amicale_row_widget.dart │ │ │ │ ├── membre_table_widget.dart │ │ │ │ └── membre_row_widget.dart │ │ │ ├── forms/ │ │ │ │ ├── amicale_form.dart │ │ │ │ └── custom_text_field.dart │ │ │ └── common/ │ │ │ ├── dashboard_layout.dart │ │ │ └── loading_widget.dart │ │ └── theme/ │ │ └── app_theme.dart │ ├── app.dart # Configuration app │ └── main.dart # Point d'entrée ├── assets/ # Ressources statiques │ ├── images/ │ ├── icons/ │ └── fonts/ ├── test/ # Tests unitaires ├── integration_test/ # Tests d'intégration └── docs/ # Documentation ``` --- --- ## 🚀 Installation et configuration ### Prérequis système - **Flutter SDK** : 3.32 ou supérieur - **Dart SDK** : 3.0 ou supérieur - **IDE** : Android Studio, VS Code, ou IntelliJ - **Environnement** : - Android : SDK 21+ (Android 5.0+) - iOS : iOS 12.0+ - Web : Navigateurs modernes ## 🔐 Configuration des clés API ### Mapbox (Cartographie) 1. Créer un compte sur [Mapbox](https://www.mapbox.com/) 2. Générer un token d'accès 3. Ajouter le token dans `.env` ### Configuration MQTT (Chat) 1. Configurer votre broker MQTT 2. Créer les credentials 3. Tester la connexion --- ## 🗄️ Modèles de données ### Registres Hive des adaptateurs ```dart // Modèles principaux UserModelAdapter() // typeId: 0 OperationModelAdapter() // typeId: 1 SectorModelAdapter() // typeId: 3 PassageModelAdapter() // typeId: 4 MembreModelAdapter() // typeId: 5 UserSectorModelAdapter() // typeId: 6 RegionModelAdapter() // typeId: 7 ClientModelAdapter() // typeId: 10 AmicaleModelAdapter() // typeId: 11 // Modèles de chat ConversationModelAdapter() // typeId: 20 MessageModelAdapter() // typeId: 21 ParticipantModelAdapter() // typeId: 22 AnonymousUserModelAdapter() // typeId: 23 AudienceTargetModelAdapter() // typeId: 24 NotificationSettingsAdapter() // typeId: 25 ``` ### Clarification importante : UserModel vs MembreModel vs UserSectorModel ⚠️ **ATTENTION** : Il existe une distinction cruciale entre ces trois modèles : #### **UserModel** (Box: `users`) - Représente **uniquement l'utilisateur courant connecté** (current user) - Stocké dans la box Hive `users` qui ne contient qu'un seul enregistrement - Utilisé pour l'authentification et la session de l'utilisateur actuel - **Ne pas confondre avec les membres de l'amicale** #### **MembreModel** (Box: `membres`) - Représente **tous les membres d'une amicale** - Stocké dans la box Hive `membres` qui contient plusieurs enregistrements - Utilisé pour la gestion des équipes et l'attribution aux secteurs - Chaque membre a son propre ID unique #### **UserSectorModel** (Box: `user_sector`) - Représente **l'association entre un membre et un secteur** - ⚠️ **IMPORTANT** : Le champ `id` dans `UserSectorModel` correspond à l'ID du **membre** (MembreModel.id), **PAS** à l'ID de l'utilisateur (UserModel.id) - Permet de savoir quels membres sont affectés à quels secteurs - Nom trompeur : devrait s'appeler "MemberSectorModel" pour éviter la confusion ### Compatibilité entre modèles - **UserModel ↔ MembreModel** : Conversion bidirectionnelle via `toUserModel()` et `fromUserModel()` - **Synchronisation** : Maintien de la cohérence entre les deux représentations - **Champs spécialisés** : Préservation des données spécifiques à chaque modèle 🎨 Interface utilisateur Architecture des composants UserFormDialog - Modale unifiée Réutilisabilité : Même widget pour "Mon Compte" et "Gestion des Membres" Personnalisation contextuelle : Sélecteur de rôle (Membre/Administrateur) Checkbox statut actif/inactif Édition du nom d'utilisateur selon le contexte Gestion du nom de tournée (sectName) Interface responsive : Adaptation automatique selon la largeur d'écran UserForm - Formulaire intelligent Layout adaptatif : > 900px : Champs groupés en lignes (username+email, prénom+nom, téléphones, dates) > ≤ 900px : Champs empilés verticalement > Validation conditionnelle : Au moins nom OU nom de tournée requis > Champs dynamiques : Affichage selon les permissions et le contexte > Indicateurs visuels : Points rouges sur les champs obligatoires > Tableaux interactifs > AmicaleTableWidget : Gestion des amicales avec édition inline > MembreTableWidget : Gestion des membres avec actions contextuelles > Alternance de couleurs : Amélioration de la lisibilité > Clic sur ligne : Ouverture directe du formulaire d'édition ## 🔗 API et synchronisation Principe "API First" ### Flow de mise à jour Validation API : Tentative de mise à jour sur le serveur Succès → Sauvegarde locale avec isSynced: true Erreur → Aucune modification locale + affichage de l'erreur ### Avantages Cohérence des données : Local toujours synchronisé avec le serveur Gestion d'erreurs propre : Pas de conflits entre données locales et distantes UX claire : Feedback immédiat sur les erreurs de validation ### ApiService Singleton - Thread-safe : Initialisation sécurisée avec verrous - Auto-configuration : Détection automatique de l'environnement (DEV/REC/PROD) - Gestion de session : Headers d'authentification automatiques - Retry logic : Nouvelles tentatives pour les erreurs réseau ## ⚠️ Gestion des erreurs ### 🎯 Système ApiException intelligent GEOSECTOR v2.0 utilise un **système centralisé de gestion des messages** qui s'adapte automatiquement au contexte d'affichage pour garantir une visibilité optimale des notifications utilisateur. #### **🧠 Détection automatique de contexte** L'`ApiException` détecte intelligemment si elle est appelée depuis une Dialog et adapte l'affichage : - **📱 Contexte normal** : SnackBar standard en bas d'écran - **💬 Contexte Dialog** : Overlay SnackBar positionné au-dessus de la Dialog estompée - **🌐 Mobile/Web** : Adaptation automatique selon la plateforme - **🎨 Cohérence visuelle** : Couleurs, icônes et comportements unifiés ```dart // Même API partout - détection intelligente du contexte void _handleValidation() { if (formInvalid) { // Dans une Dialog : overlay au-dessus, Dialog reste ouverte ApiException.showError(context, Exception("Champs requis manquants")); return; } // Succès : fermer Dialog puis afficher confirmation Navigator.pop(context); ApiException.showSuccess(context, "Données sauvegardées"); } ``` #### **✨ Avantages de l'approche unifiée** | Aspect | Avant | Avec ApiException | |--------|-------|-------------------| | **Visibilité** | SnackBar masqué par Dialog | Overlay visible au-dessus | | **Consistance** | Messages dispersés | API unifiée dans toute l'app | | **Maintenance** | Code répétitif | Système centralisé | | **UX** | Frustrant (messages cachés) | Fluide et prévisible | ### Architecture centralisée ```mermaid sequenceDiagram participant UI as dashboard_app_bar.dart participant UR as user_repository.dart participant AS as api_service.dart participant API as API Server participant AE as ApiException participant EU as ErrorUtils Note over UI: Utilisateur clique "Enregistrer" UI->>UR: updateUser(updatedUser) Note over UR: Tente la mise à jour UR->>AS: updateUser(user) Note over AS: Appel HTTP PUT AS->>API: PUT /users/123 {email: "test@test.com"} alt Succès API API-->>AS: 200 OK {user data} AS-->>UR: UserModel (mis à jour) UR-->>UI: UserModel (succès) UI->>EU: showSuccessSnackBar() Note over UI: ✅ "Profil mis à jour" else Erreur API (ex: email déjà utilisé) API-->>AS: 409 Conflict {"message": "Cet email est déjà utilisé"} Note over AS: Conversion en ApiException AS->>AE: ApiException.fromDioException(dioError) AE-->>AS: ApiException("Cet email est déjà utilisé") AS-->>UR: throw ApiException UR-->>UI: throw ApiException Note over UI: Gestion de l'erreur UI->>EU: showErrorSnackBar(context, exception) EU->>AE: extractErrorMessage(exception) AE-->>EU: "Cet email est déjà utilisé" Note over UI: ❌ "Erreur: Cet email est déjà utilisé" Note over UI: Dialog reste ouvert else Erreur réseau API-->>AS: Network Error / Timeout AS->>AE: ApiException.fromDioException(networkError) AE-->>AS: ApiException("Problème de connexion réseau") AS-->>UR: throw ApiException UR-->>UI: throw ApiException UI->>EU: showErrorSnackBar(context, exception) Note over UI: ❌ "Problème de connexion réseau" end ``` ## Composants de gestion d'erreurs ### ApiException Extraction intelligente : Messages spécifiques depuis la réponse API Codes HTTP standardisés : Mapping automatique des erreurs communes Types d'erreurs : Classification (validation, authentification, réseau, conflit) Méthodes d'affichage : showError() et showSuccess() intégrées ### Responsabilités par couche ApiService : Conversion des erreurs Dio en ApiException Repository : Propagation transparente des erreurs Interface : Affichage utilisateur via ApiException.showError() ### Messages d'erreurs contextuels 409 Conflict : "Cet email est déjà utilisé par un autre utilisateur" 400 Bad Request : "Données invalides" 401 Unauthorized : "Non autorisé : veuillez vous reconnecter" 500 Server Error : "Erreur serveur interne" Network Errors : "Problème de connexion réseau" Timeout : "Délai d'attente dépassé" ## 🎯 Gestion des rôles ### Hiérarchie des permissions Membre (Rôle 1) : Consultation et distribution dans ses secteurs Admin Amicale (Rôle 2) : Gestion complète de son amicale et ses membres Super Admin (Rôle 3+) : Administration globale multi-amicales ### Fonctionnalités par rôle Admin Amicale - Gestion des membres Création : Nouveaux membres avec attribution de rôle Modification : Informations personnelles, rôle, statut actif Suppression : Avec confirmation obligatoire Validation : Contrôle d'unicité email/username par l'API ### Interface adaptative Sélecteur de rôle : Visible uniquement pour les admins Checkbox statut actif : Contrôle d'accès aux comptes Édition contextuelle : Champs modifiables selon les permissions Actions conditionnelles : Boutons disponibles selon le niveau d'autorisation ## 👥 Gestion des membres (Admin Amicale) ### 🎯 Vue d'ensemble La gestion des membres est une fonctionnalité clé pour les **Admins Amicale** (Rôle 2) qui permet une administration complète des équipes au sein de leur amicale. Cette interface centralise toutes les opérations liées aux membres avec une approche sécurisée et intuitive. ### 📱 Interface AdminAmicalePage L'interface principale `admin_amicale_page.dart` offre une vue d'ensemble complète : - **Informations de l'amicale** : Affichage des détails de l'amicale courante - **Liste des membres** : Tableau interactif avec actions contextuelles - **Ajout de membres** : Bouton d'action pour créer de nouveaux comptes - **Opération courante** : Indication de l'opération active en cours ### ✨ Fonctionnalités principales #### 🆕 Création de nouveaux membres ```dart // Workflow de création 1. Clic sur "Ajouter un membre" 2. Ouverture du UserFormDialog 3. Formulaire vierge avec valeurs par défaut 4. Sélection du rôle (Membre/Administrateur) 5. Configuration du statut actif 6. Validation et création via API 7. Attribution automatique à l'amicale courante ``` **Champs obligatoires :** - Email (unique dans le système) - Au moins un nom (nom de famille OU nom de tournée) - Rôle dans l'amicale **Champs optionnels :** - Nom d'utilisateur (éditable pour les admins) - Prénom, téléphones, dates - Nom de tournée (pour identification terrain) #### ✏️ Modification des membres existants ```dart // Actions disponibles - Clic sur une ligne → Ouverture du formulaire d'édition - Modification de tous les champs personnels - Changement de rôle (Membre ↔ Administrateur) - Activation/Désactivation du compte - Gestion du nom de tournée ``` **Workflow de modification :** 1. Sélection du membre dans le tableau 2. Ouverture automatique du `UserFormDialog` 3. Formulaire pré-rempli avec données existantes 4. Modification des champs souhaités 5. Validation et mise à jour via API 6. Synchronisation automatique avec Hive #### 🗑️ Suppression intelligente des membres La suppression des membres intègre une **logique métier avancée** pour préserver l'intégrité des données : ##### 🔍 Vérification des passages ```dart // Algorithme de vérification 1. Récupération de opération courante 2. Analyse des passages du membre pour cette opération 3. Classification : passages réalisés vs passages à finaliser 4. Comptage total des passages actifs ``` ##### 📊 Scénarios de suppression **Cas 1 : Aucun passage (suppression simple)** ```http DELETE /users/{id} ``` - Confirmation simple - Suppression directe - Aucun transfert nécessaire **Cas 2 : Passages existants (suppression avec transfert)** ```http DELETE /users/{id}?transfer_to={destinataire}&operation_id={operation} ``` - Dialog d'avertissement avec détails - Sélection obligatoire d'un membre destinataire - Transfert automatique de tous les passages - Préservation de l'historique **Cas 3 : Alternative recommandée (désactivation)** ```dart // Mise à jour du statut membre.copyWith(isActive: false) ``` - Préservation complète des données - Blocage de la connexion - Maintien de l'historique - Réactivation possible ultérieurement ### 🔐 Sécurité et permissions #### Contrôles d'accès - **Isolation par amicale** : Admins limités à leur amicale - **Vérification des rôles** : Validation côté client et serveur - **Opération courante** : Filtrage par contexte d'opération - **Validation API** : Contrôles d'unicité et cohérence #### Gestion des erreurs ```mermaid graph TD A[Action utilisateur] --> B[Validation locale] B --> C[Appel API] C --> D{Succès ?} D -->|Oui| E[Mise à jour Hive] D -->|Non| F[Affichage erreur] E --> G[Notification succès] F --> H[Dialog reste ouvert] ``` ### 🎨 Interface utilisateur #### Tableaux interactifs **MembreTableWidget** - Composant principal : - Colonnes : ID, Prénom, Nom, Email, Rôle, Statut - Actions : Modification, Suppression - Alternance de couleurs pour lisibilité - Tri et navigation intuitifs **MembreRowWidget** - Ligne individuelle : - Clic pour édition rapide - Boutons d'action contextuels - Indicateurs visuels de statut - Tooltip informatifs #### Formulaires adaptatifs **UserFormDialog** - Modale réutilisable : - Layout responsive (>900px vs mobile) - Validation en temps réel - Gestion des erreurs inline - Sauvegarde avec feedback ### 📡 Synchronisation et réactivité #### Architecture ValueListenableBuilder ```dart // Écoute automatique des changements ValueListenableBuilder>( valueListenable: membreRepository.getMembresBox().listenable(), builder: (context, membresBox, child) { // Interface mise à jour automatiquement final membres = membresBox.values .where((m) => m.fkEntite == currentUser.fkEntite) .toList(); return MembreTableWidget(membres: membres); }, ) ``` #### Principe "API First" 1. **Validation API** : Tentative sur serveur en priorité 2. **Succès** → Sauvegarde locale + mise à jour interface 3. **Erreur** → Affichage message + maintien état local 4. **Cohérence** : Données locales toujours synchronisées ### 🔄 Workflow complet ```mermaid sequenceDiagram participant A as Admin participant UI as Interface participant R as Repository participant API as Serveur participant H as Hive A->>UI: Action membre UI->>R: Appel repository R->>API: Requête HTTP API-->>R: Réponse alt Succès R->>H: Sauvegarde locale H-->>UI: Notification changement UI-->>A: Interface mise à jour else Erreur R-->>UI: Exception UI-->>A: Message d'erreur end ``` ### 🎯 Bonnes pratiques #### Pour les administrateurs 1. **Vérification avant suppression** : Toujours examiner les passages 2. **Préférer la désactivation** : Éviter la perte de données 3. **Noms de tournée** : Utiliser des identifiants terrain clairs 4. **Rôles appropriés** : Limiter les administrateurs aux besoins #### Gestion des erreurs courantes | Erreur | Cause | Solution | | ----------------------- | ------------- | ------------------------ | | Email déjà utilisé | Duplication | Choisir un autre email | | Membre avec passages | Données liées | Transférer ou désactiver | | Aucune opération active | Configuration | Vérifier les opérations | | Accès refusé | Permissions | Vérifier le rôle admin | Cette architecture garantit une gestion des membres robuste, sécurisée et intuitive, optimisant l'efficacité administrative tout en préservant l'intégrité des données opérationnelles. 👥✨ ## 🗺️ Cartes et géolocalisation Flutter Map : Rendu cartographique haute performance Tuiles Mapbox : Cartographie détaillée et personnalisable Géolocalisation temps réel : Suivi GPS des équipes Secteurs géographiques : Visualisation et attribution dynamique Passages géolocalisés : Enregistrement précis des distributions ## 🔄 Synchronisation et réactivité ### Hive + ValueListenableBuilder Réactivité native : Mise à jour automatique de l'interface Performance optimisée : Pas de Provider, injection directe Écoute sélective : Réactivité fine par Box Hive Cohérence des données : Synchronisation bidirectionnelle User/Membre ### Services Singleton CurrentUserService : Gestion de l'utilisateur connecté CurrentAmicaleService : Amicale de l'utilisateur actuel ApiService : Communication centralisée avec l'API DataLoadingService : Orchestration du chargement des données ## 🚀 Optimisation des performances Hive ### 📈 Gestion des Box Hive avec cache GEOSECTOR v2.0 implémente une **stratégie de cache avancée** pour les Box Hive afin d'éliminer les goulots d'étranglement de performance lors d'opérations haute fréquence. #### **🎯 Problème résolu** Avant l'optimisation, l'application effectuait jusqu'à **848 vérifications** `Hive.isBoxOpen()` par chargement de page, causant des ralentissements significatifs lors du rendu des listes et du filtrage des données. #### **💡 Solution : Cache lazy des Box** ```dart // Pattern implémenté dans tous les repositories class OptimizedRepository { Box? _cachedBox; Box get _modelBox { if (_cachedBox == null) { if (!Hive.isBoxOpen(AppKeys.boxName)) { throw Exception('Box non ouverte'); } _cachedBox = Hive.box(AppKeys.boxName); debugPrint('Repository: Box mise en cache'); } return _cachedBox!; } void _resetCache() { _cachedBox = null; } } ``` #### **🔄 Gestion du cache et réactivité** **Point critique** : Le cache doit être réinitialisé après **toute modification** pour garantir le bon fonctionnement de `ValueListenableBuilder` : ```dart // ✅ OBLIGATOIRE après modification Future saveData(ModelType data) async { await _modelBox.put(data.id, data); _resetCache(); // ← Crucial pour la réactivité UI notifyListeners(); } // ✅ OBLIGATOIRE après suppression Future deleteData(int id) async { await _modelBox.delete(id); _resetCache(); // ← Crucial pour la réactivité UI notifyListeners(); } // ✅ OBLIGATOIRE après vidage ou traitement API Future processApiData(List data) async { await _modelBox.clear(); // ... traitement des données _resetCache(); // ← Crucial pour la réactivité UI notifyListeners(); } ``` #### **📊 Impact performance** | Métrique | Avant optimisation | Après optimisation | |----------|-------------------|-------------------| | **Vérifications box** | 848 par page | 1 par session | | **Temps de rendu** | 200-500ms | <50ms | | **Filtrage liste** | Lent (check répétés) | Instantané | | **Mémoire** | Overhead minimal | Impact négligeable | #### **🏗️ Repositories optimisés** L'optimisation est implémentée dans tous les repositories critiques : - ✅ **SectorRepository** : Gestion des secteurs géographiques - ✅ **PassageRepository** : Suivi des distributions - ✅ **MembreRepository** : Gestion des équipes - ✅ **OperationRepository** : Campagnes et opérations - ✅ **AmicaleRepository** : Organisations #### **🎯 Règles d'implémentation** 1. **Cache systématique** : Tous les repositories fréquemment utilisés 2. **Reset obligatoire** : Après toute opération de modification 3. **Getter lazy** : Accès différé à la box uniquement si nécessaire 4. **Debug logging** : Traçabilité du cache en développement 5. **Cohérence** : Pattern appliqué uniformément Cette architecture garantit une application performante, maintenable et évolutive avec une excellente expérience utilisateur. 🚀 ## 🎨 Architecture des Dialogs Auto-Gérées ### 🎯 Principe de conception GEOSECTOR v2.0 implémente une **architecture simplifiée des dialogs** qui élimine la complexité des callbacks asynchrones et garantit une gestion robuste des formulaires modaux. ### 🏗️ Pattern "Dialog Auto-Gérée" ```mermaid graph TD A[Page Parente] -->|Injection Repository| B[Dialog Auto-Gérée] B -->|Appel Direct| C[Repository] C -->|API Call| D[Serveur] D -->|Réponse| C C -->|Sauvegarde| E[Hive Local] B -->|Auto-Fermeture| A B -->|Callback Simple| A E -->|ValueListenableBuilder| A ``` ### ✨ Composants de l'architecture #### **1. Page Parente (ex: AdminOperationsPage)** ```dart // Ouverture simplifiée de dialog void _showEditOperationDialog(OperationModel op) { showDialog( context: context, builder: (dialogContext) => OperationFormDialog( operation: op, operationRepository: widget.operationRepository, // ← Injection directe onSuccess: () { if (mounted) setState(() {}); // ← Simple rafraîchissement }, ), ); } ``` #### **2. Dialog Auto-Gérée (ex: OperationFormDialog)** ```dart // Gestion complète dans la dialog void _handleSubmit() async { try { // Appel direct du repository final success = await widget.operationRepository.saveOperationFromModel(operationData); if (success && mounted) { // Délai pour synchronisation Hive Future.delayed(const Duration(milliseconds: 200), () { Navigator.of(context).pop(); // ← Auto-fermeture widget.onSuccess?.call(); // ← Notification simple ApiException.showSuccess(context, "Opération sauvegardée"); }); } } catch (e) { ApiException.showError(context, e); // ← Erreur sans fermeture } } ``` ### 🎯 Avantages de cette approche | Aspect | Avant (Complexe) | Après (Simplifié) | | --------------------- | --------------------- | ------------------------------------ | | **Callbacks** | Asynchrones complexes | Simple `onSuccess: () => setState()` | | **Fermeture** | Gérée par le parent | Auto-fermeture dans la dialog | | **Gestion d'erreurs** | Dispersée | Centralisée dans la dialog | | **Synchronisation** | Problématique | Délai de 200ms pour Hive | | **Maintenance** | Code dispersé | Logique unifiée | ### 🔧 Responsabilités claires #### **Page Parente** - ✅ Ouverture des dialogs avec injection de dépendances - ✅ Rafraîchissement de l'interface via `setState()` - ✅ Gestion des tableaux et listes intégrés #### **Dialog Auto-Gérée** - ✅ Validation et soumission du formulaire - ✅ Appel direct des repositories - ✅ Auto-fermeture en cas de succès - ✅ Gestion des erreurs sans fermeture #### **Repository** - ✅ Logique métier (création vs modification) - ✅ Appels API appropriés - ✅ Sauvegarde locale dans Hive - ✅ Propagation des exceptions ### 🚀 Exemple d'implémentation ```dart // 1. Page parente - Code minimal void _showCreateDialog() { showDialog( context: context, builder: (context) => OperationFormDialog( title: 'Créer une opération', operationRepository: widget.operationRepository, onSuccess: () => setState(() {}), ), ); } // 2. Dialog - Auto-gestion complète class OperationFormDialog extends StatefulWidget { final OperationRepository operationRepository; final VoidCallback? onSuccess; // Gestion interne : validation, API, fermeture, erreurs } // 3. Repository - Logique métier pure Future saveOperationFromModel(OperationModel operation) async { if (operation.id == 0) { return await createOperation(...); // POST } else { return await updateOperation(...); // PUT } } ``` ### ✅ Résultats obtenus - **🎯 Simplicité** : Code plus lisible et maintenable - **🔒 Robustesse** : Gestion d'erreurs centralisée - **⚡ Performance** : Synchronisation optimisée avec Hive - **🎨 UX** : Fermeture automatique et messages appropriés - **🔧 Maintenance** : Architecture cohérente et prévisible Cette approche **"Dialog Auto-Gérée"** constitue un pattern architectural clé de GEOSECTOR v2.0, garantissant une expérience utilisateur fluide et un code maintenable. 🎉 ## Fonction de création d'une opération ## Fonction de création d'une opération ### 🔄 Traitement des données complexes Lors de la création d'une opération via `OperationRepository.createOperation()`, l'API retourne en réponse **201 Created** ou **200 OK** un payload complexe contenant 4 groupes de données essentiels : ```json { "operations": [...], // 3 dernières opérations dont la nouvelle active "secteurs": [...], // Secteurs de la nouvelle opération active "passages": [...], // Passages de la nouvelle opération active "users_sectors": [...] // Associations user-secteurs de la nouvelle opération } ``` ### 📦 Groupes de données attendus #### 🎯 Groupe **operations** Contient les **3 dernières opérations** de l'amicale, incluant celle qui vient d'être créée et qui devient automatiquement active. #### 🗺️ Groupe **secteurs** Contient tous les **secteurs géographiques** associés à la dernière opération créée et active. #### 📍 Groupe **passages** Contient l'ensemble des **passages** générés pour cette dernière opération créée et active. #### 👥 Groupe **users_sectors** Contient les **associations utilisateur-secteurs** définissant les attributions pour cette dernière opération créée et active. ### ⚙️ Traitement automatique des données Ces 4 groupes sont traités de manière identique au processus de connexion utilisateur, en utilisant le **DataLoadingService** avec la logique suivante : ```dart // Dans OperationRepository._processCreationResponse() await _processOperationCreationData(responseData); Future _processOperationCreationData(Map data) async { // 1. Vidage des Box Hive concernées (comme au login) await _clearRelatedBoxes(); // 2. Traitement des 4 groupes via DataLoadingService if (data.containsKey('operations')) { await DataLoadingService.instance.processOperationsFromApi(data['operations']); } if (data.containsKey('secteurs')) { await DataLoadingService.instance.processSectorsFromApi(data['secteurs']); } if (data.containsKey('passages')) { await DataLoadingService.instance.processPassagesFromApi(data['passages']); } if (data.containsKey('users_sectors')) { await DataLoadingService.instance.processUserSectorsFromApi(data['users_sectors']); } } Future _clearRelatedBoxes() async { // Vidage des Box respectives avant rechargement final operationsBox = HiveService.instance.getTypedBox(AppKeys.operationsBoxName); final sectorsBox = HiveService.instance.getTypedBox(AppKeys.sectorsBoxName); final passagesBox = HiveService.instance.getTypedBox(AppKeys.passagesBoxName); final userSectorsBox = HiveService.instance.getTypedBox(AppKeys.userSectorBoxName); await operationsBox.clear(); await sectorsBox.clear(); await passagesBox.clear(); await userSectorsBox.clear(); } ``` ### 🔄 Flux de synchronisation ```mermaid sequenceDiagram participant UI as Interface participant OR as OperationRepository participant API as Serveur API participant HS as HiveService participant DLS as DataLoadingService participant VLB as ValueListenableBuilder UI->>OR: createOperation(newOperation) OR->>API: POST /operations API-->>OR: 201 Created + 4 groupes Note over OR: Traitement des données complexes OR->>HS: clear() sur 4 Box concernées OR->>DLS: processOperationsFromApi() OR->>DLS: processSectorsFromApi() OR->>DLS: processPassagesFromApi() OR->>DLS: processUserSectorsFromApi() Note over DLS: Sauvegarde dans Hive DLS->>HS: put() dans Box typées HS-->>VLB: Notifications de changement VLB-->>UI: Mise à jour automatique ``` ### ✅ Avantages de cette approche - **Cohérence totale** : Données locales parfaitement synchronisées avec le serveur - **Performance optimisée** : Un seul appel API pour toutes les données nécessaires - **Réactivité immédiate** : Interface mise à jour automatiquement via ValueListenableBuilder - **Logique centralisée** : Réutilisation du DataLoadingService existant - **Gestion d'erreurs** : Rollback automatique en cas d'échec du traitement Cette architecture garantit une synchronisation robuste et performante lors de la création d'opérations, en maintenant la cohérence des données tout en optimisant l'expérience utilisateur. 🚀