- auth_bloc: quand onboardingState==VALIDATED, refresh token et vérifier
si statutCompte==ACTIF → dashboard direct (pas d'écran d'attente)
- Edge case: si activation backend échouée, fallback vers AwaitingValidationPage
avec polling 15s
- onboarding_bloc: séparer VALIDATED de AWAITING_VALIDATION dans le switch
Le SuperAdmin dashboard avait déjà RefreshIndicator+Completer.
Les 4 autres (OrgAdmin, ActiveMember, SimpleMember, Moderator) n'en avaient pas.
Ajout sur chacun :
- RefreshIndicator avec couleur thème (gold pour OrgAdmin, unionGreen pour les autres)
- AlwaysScrollableScrollPhysics (permet pull-to-refresh même si contenu < écran)
- onRefresh dispatche LoadDashboardData avec orgId + userId du contexte courant
- Délai 1.2s pour laisser le BLoC recharger avant de masquer l'indicateur
1. confirmerMockPaiement() placé HORS de la classe → déplacé à l'intérieur
(contribution_repository.dart + transaction_epargne_repository.dart)
2. result.clientReference?.isNotEmpty → null-safe avec ?.
3. IContributionRepository n'a pas confirmerMockPaiement → cast vers
ContributionRepository (implémentation) avec check is
4. Import data/repositories ajouté dans payment_dialog.dart
Le mock simulait seulement l'UI mais n'appelait pas le backend pour
confirmer le paiement → le solde restait à 0 après dépôt simulé.
Fix : en mode mock, après la simulation UI, appeler
GET /api/wave-redirect/mock-complete?ref={id} qui :
- Marque l'intention de paiement comme complétée
- Crédite le compte épargne (pour les dépôts)
- Enregistre le paiement de cotisation (pour les cotisations)
Changements :
- depot_epargne_dialog : appelle confirmerMockPaiement(versementId)
- payment_dialog : appelle confirmerMockPaiement(clientReference)
- transaction_epargne_repository : nouvelle méthode confirmerMockPaiement()
+ versementId ajouté à DepotWaveResult
- contribution_repository : nouvelle méthode confirmerMockPaiement()
+ intentionPaiementId ajouté à WavePaiementInitResult
En mode dev (URL contient 'mock' ou 'localhost', ou !AppConfig.isProd),
le paiement Wave est simulé directement sans ouvrir le navigateur :
- Dépôt épargne (depot_epargne_dialog.dart) : simulation 800ms + SnackBar succès
- Paiement cotisation (payment_dialog.dart) : même pattern
En mode prod : comportement inchangé (ouvre l'app Wave via launchUrl).
Pattern identique à wave_payment_page.dart (onboarding souscription)
appliqué à tous les flux Wave de l'application.
L'endpoint de dépôt épargne est dans VersementResource, pas PaiementResource :
- Mobile appelait : POST /api/paiements/initier-depot-epargne-en-ligne → 405
- Backend expose : POST /api/versements/initier-depot-epargne
Corrigé le path + retiré le suffixe '-en-ligne' (absent du backend).
Améliorations UX Annuaire Membres (parité avec Gestion Organisations) :
1. Panneau recherche/filtres toujours visible (plus de toggle collapsible)
→ UX plus directe, pas de clic supplémentaire pour chercher
2. Filtre par rôle (nouveau) : chips Admin, Modérateur, Membre Actif, Membre Simple
avec icône badge devant la rangée, couleur accent différente du statut
3. Bouton Refresh ajouté dans l'AppBar (cohérence avec la page Organisations)
4. Lien 'Réinitialiser les filtres' visible quand au moins un filtre est actif
5. _filteredMembers intègre le filtre rôle via _roleFilterMapping
Supprimé :
- _isSearchExpanded (plus utile — panneau toujours visible)
- Bouton toggle search dans l'AppBar (remplacé par affichage permanent)
3 fonctionnalités ajoutées pour aligner avec l'UX de l'Annuaire Membres :
1. Filtres par statut (chips) : Tous, Active, En création, Inactive, Suspendue, Dissoute
Chips horizontaux scrollables sous la barre de recherche, filtre local
(combiné avec le filtre par type de la TabBar + recherche texte)
2. Vue grille toggle : bouton grid/list dans l'AppBar
Grid 2 colonnes avec cartes compactes (icône, nom, statut, type, localisation, membres)
3. Swipe actions : swipe DROIT → modifier, swipe GAUCHE → supprimer
Uniquement pour SuperAdmin/OrgAdmin (canManage=true)
Background coloré avec icônes + labels
confirmDismiss retourne false → la carte ne disparaît pas
Le code technique est désormais auto-généré par le backend depuis le libellé.
Création : le champ code est supprimé du formulaire. Le backend génère
automatiquement un code UPPER_SNAKE_CASE depuis le libellé saisi.
Édition : le code existant est affiché en lecture seule (container gris monospace)
pour information — non modifiable (les types système sont protégés).
Le paramètre code: '' est envoyé en création (le backend détecte le vide et
auto-génère).
Aligné avec le backend MessagingResource :
- Nouveau module communication (conversations, messages, participants)
- Respect des ContactPolicy (qui peut parler à qui par rôle)
- Gestion MemberBlock (blocages individuels)
- UI : conversations list, conversation detail, broadcast, tiles
- BLoC : MessagingBloc avec events (envoyer, démarrer conversation rôle, etc.)
Plan selection :
- Grille 2×2 compacte pour les plages (au lieu de liste verticale)
- Badge ⭐ POPULAIRE sur STANDARD
- Remise annuelle affichée (−X%/an)
- AnimatedSwitcher + auto-scroll vers formules quand plage sélectionnée
- Dark mode adaptatif complet
Récapitulatif :
- Dark mode complet (AppColors pairs)
- Bloc Total gradient gold adaptatif
- NoteBox avec backgrounds accent.withOpacity()
- Utilise OnboardingBottomBar (consistence)
Payment method :
- Dark mode + couleurs de marque Wave/Orange hardcodées (intentionnel)
- Logo container reste blanc (brand)
- Mapping typeOrganisation détaillé → enum backend ASSOCIATION/MUTUELLE/
COOPERATIVE/FEDERATION (fix HTTP 400 'Valeur invalide pour typeOrganisation')
Wave payment :
- Dark mode adaptatif
- Message dev clair (simulation automatique)
- Gestion OnboardingPaiementEchoue : SnackBar rouge + reset flags + reste sur page
(plus de faux succès quand confirmerPaiement() return false ou lève exception)
Bloc : nouvel état OnboardingPaiementEchoue, _onRetourDepuisWave vérifie le return
de confirmerPaiement() (plus de catch silencieux qui émettait OnboardingPaiementConfirme)
Shared widgets : OnboardingSectionTitle + OnboardingBottomBar dark mode + hint optionnel
Swipe actions différenciées par rôle :
- SuperAdmin : → Reset MDP, ← Affecter Org
- OrgAdmin : → Reset MDP, ← lifecycle selon statut (Suspendre/Activer/Réactiver)
(masqué si cible = ORGADMIN/SUPERADMIN — cohérent avec guard backend)
- Autres rôles : → Reset MDP seulement
Suppression compte (SuperAdmin uniquement) :
- Nouveau callback onDeleteAccount dans MembersPage + MemberDetailPage
- Bouton rouge 'Supprimer ce compte' dans action sheet (zone destructive)
- Dialog de confirmation adaptatif dark/light avec badge admin si cible ORGADMIN
- Bouton caché si compte déjà désactivé (actif=false)
- Bannière 'Compte désactivé' visible sur page détail d'un compte soft-deleted
- BlocListener MembreDeleted : SnackBar + maybePop() + reload liste
- Bloc gère 409 Conflict (mono-admin) → MembresActionForbidden avec message backend
Nouvelles signatures :
- onLifecycleAction : (memberId, organisationId, action, motif) — inclut orgId
pour permettre au SuperAdmin d'agir via l'org du membre lui-même
- 'actif' et 'roleCode' exposés dans la map via _convertMembreToMap
Ajoute KeycloakAuthService.getValidAccessToken() qui vérifie l'expiration
du JWT et rafraîchit automatiquement avant de retourner le token.
FinanceWorkflowRemoteDatasource et MessagingRemoteDatasource injectent
désormais KeycloakAuthService au lieu de FlutterSecureStorage directement,
ce qui évite d'envoyer un Bearer expiré et d'obtenir un 401 silencieux.
- Epargne: badge LCB-FT (bouclier ambre) sur comptes avec fonds bloques + note recap
- EpargneDetail: historique pagine (page/size), affichage soldeAvant/soldeApres/motif dans chaque transaction, bouton "Charger plus"
- TransactionEpargneRepository: getByCompte accepte page et size, gere reponse paginee Spring (content[])
- MessagingDatasource: markMessageAsRead silencieuse (pas d'endpoint unitaire), getUnreadCount somme unreadCount des conversations
- OrganizationDetail: _memberCount charge le vrai nombre depuis GET /membres/count, affiche la valeur reelle au lieu de nombreMembres (toujours 0)
- AuthStatusResult: nouveau champ reAuthRequired (ancien compte nécessitant UPDATE_PASSWORD)
- AuthBloc._onLoginRequested: si reAuthRequired → logout silencieux + re-déclenchement AppAuth
automatique (Keycloak affiche l'écran de changement de mot de passe dans Chrome Custom Tab)
- AuthBloc._onStatusChecked: si reAuthRequired → logout + AuthUnauthenticated (redirection login)
- Remplacement du flux premierLoginComplet (boolean) par enum côté backend
- Suppression de AuthPasswordChangeRequired, AuthPasswordChanging, change_password_page.dart
- Import KycStatusWidget dans ProfilePage
- Ajout BlocBuilder dans _buildSecurityTab()
- Affichage KYC en premier dans onglet Sécurité
- Données depuis ProfileLoaded state (niveauVigilanceKyc, statutKyc, dateVerificationIdentite)
Spec 001-mutuelles-anti-blanchiment - Phase 4 Mobile
Task T027 complétée : Widget KYC intégré dans UI profil
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- NotImplementedFailure: ajout userFriendlyMessage et icon construction (blue)
- ErrorDisplayWidget: support spécial pour NotImplementedFailure (bientôt disponible)
- SnackbarHelper: classe centralisée pour messages cohérents (success, error, warning, info, notImplemented)
- budgets_list_page: remplace generic snackbar par SnackbarHelper.showNotImplemented
- conversations_page: remplace 2 TODOs par SnackbarHelper.showNotImplemented
- export_members: met à jour TODO obsolète (endpoint PDF maintenant disponible)
- cache_service: fix AppLogger.error calls (error: named param)
- cached_datasource_decorator: fix AppLogger.error call
Task #64 - Fix Snackbar Placeholders + NotImplementedFailure UX