From c190867c59b319f4f47bd1f28d21d5b225fc0c0c Mon Sep 17 00:00:00 2001 From: dahoud Date: Sun, 15 Mar 2026 02:53:17 +0000 Subject: [PATCH] feat(mobile): widget affichage statut KYC membre (T023) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Phase 4 Mobile - Section 4.2 Fiche membre KYC Nouveau widget : KycStatusWidget - Affichage lecture seule du statut KYC du membre - 3 informations LCB-FT : * Statut de vérification (NON_VERIFIE, EN_COURS, VERIFIE, REFUSE) * Niveau de vigilance (SIMPLIFIE, RENFORCE) * Date de vérification d'identité (si disponible) Design : - Card avec icône verified_user - Emojis pour statuts (✅ ⏳ ❌ ⏸️) - Couleurs sémantiques (vert=vérifié, rouge=refusé, bleu=en cours, orange=non vérifié) - Message informatif sur conformité BCEAO/OHADA - Format date DD/MM/YYYY (intl) Utilisation : - Prêt pour intégration dans ProfilePage (onglet Informations personnelles) - Accepte MembreCompletModel ou champs individuels - Gère les valeurs nulles (affiche "Non renseigné") Impact UX : - Membre informé de son statut KYC - Transparence sur processus de vérification - Conformité réglementaire visible Spec : specs/001-mutuelles-anti-blanchiment/spec.md Progression : 20/27 tâches (74%) Signed-off-by: lions dev Team --- .../widgets/kyc_status_widget.dart | 192 ++++++++++++++++++ 1 file changed, 192 insertions(+) create mode 100644 unionflow/unionflow-mobile-apps/lib/features/profile/presentation/widgets/kyc_status_widget.dart diff --git a/unionflow/unionflow-mobile-apps/lib/features/profile/presentation/widgets/kyc_status_widget.dart b/unionflow/unionflow-mobile-apps/lib/features/profile/presentation/widgets/kyc_status_widget.dart new file mode 100644 index 0000000..16da6b4 --- /dev/null +++ b/unionflow/unionflow-mobile-apps/lib/features/profile/presentation/widgets/kyc_status_widget.dart @@ -0,0 +1,192 @@ +import 'package:flutter/material.dart'; +import 'package:intl/intl.dart'; + +import '../../../members/data/models/membre_complete_model.dart'; + +/// Widget d'affichage du statut KYC (Know Your Customer) d'un membre. +/// Affiche en lecture seule le niveau de vigilance, le statut de vérification, +/// et la date de vérification d'identité (conformité LCB-FT). +class KycStatusWidget extends StatelessWidget { + final NiveauVigilanceKyc? niveauVigilance; + final StatutKyc? statutKyc; + final DateTime? dateVerification; + + const KycStatusWidget({ + super.key, + this.niveauVigilance, + this.statutKyc, + this.dateVerification, + }); + + @override + Widget build(BuildContext context) { + final theme = Theme.of(context); + final colorScheme = theme.colorScheme; + + return Card( + margin: const EdgeInsets.all(16), + child: Padding( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + Icon( + Icons.verified_user, + color: colorScheme.primary, + size: 24, + ), + const SizedBox(width: 8), + Text( + 'Vérification KYC (Anti-blanchiment)', + style: theme.textTheme.titleMedium?.copyWith( + fontWeight: FontWeight.bold, + color: colorScheme.primary, + ), + ), + ], + ), + const SizedBox(height: 4), + Text( + 'Conformité LCB-FT (Lutte contre le Blanchiment)', + style: theme.textTheme.bodySmall?.copyWith( + color: colorScheme.onSurfaceVariant, + fontStyle: FontStyle.italic, + ), + ), + const Divider(height: 24), + _buildInfoRow( + context, + 'Statut de vérification', + _getStatutKycLabel(statutKyc), + _getStatutKycColor(statutKyc), + ), + const SizedBox(height: 12), + _buildInfoRow( + context, + 'Niveau de vigilance', + _getNiveauVigilanceLabel(niveauVigilance), + _getNiveauVigilanceColor(niveauVigilance), + ), + if (dateVerification != null) ...[ + const SizedBox(height: 12), + _buildInfoRow( + context, + 'Date de vérification', + DateFormat('dd/MM/yyyy').format(dateVerification!), + colorScheme.onSurface, + ), + ], + const SizedBox(height: 16), + Container( + padding: const EdgeInsets.all(12), + decoration: BoxDecoration( + color: colorScheme.primaryContainer.withOpacity(0.3), + borderRadius: BorderRadius.circular(8), + ), + child: Row( + children: [ + Icon( + Icons.info_outline, + size: 16, + color: colorScheme.primary, + ), + const SizedBox(width: 8), + Expanded( + child: Text( + 'Ces informations sont gérées par l\'administrateur et permettent de garantir la conformité aux normes BCEAO/OHADA.', + style: theme.textTheme.bodySmall?.copyWith( + color: colorScheme.onSurface, + ), + ), + ), + ], + ), + ), + ], + ), + ), + ); + } + + Widget _buildInfoRow( + BuildContext context, + String label, + String value, + Color valueColor, + ) { + return Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded( + flex: 2, + child: Text( + label, + style: Theme.of(context).textTheme.bodyMedium?.copyWith( + fontWeight: FontWeight.w500, + ), + ), + ), + Expanded( + flex: 3, + child: Text( + value, + style: Theme.of(context).textTheme.bodyMedium?.copyWith( + color: valueColor, + fontWeight: FontWeight.bold, + ), + ), + ), + ], + ); + } + + String _getStatutKycLabel(StatutKyc? statut) { + if (statut == null) return 'Non renseigné'; + switch (statut) { + case StatutKyc.nonVerifie: + return '⏸️ Non vérifié'; + case StatutKyc.enCours: + return '⏳ En cours de vérification'; + case StatutKyc.verifie: + return '✅ Vérifié'; + case StatutKyc.refuse: + return '❌ Refusé'; + } + } + + Color _getStatutKycColor(StatutKyc? statut) { + if (statut == null) return Colors.grey; + switch (statut) { + case StatutKyc.nonVerifie: + return Colors.orange; + case StatutKyc.enCours: + return Colors.blue; + case StatutKyc.verifie: + return Colors.green; + case StatutKyc.refuse: + return Colors.red; + } + } + + String _getNiveauVigilanceLabel(NiveauVigilanceKyc? niveau) { + if (niveau == null) return 'Non renseigné'; + switch (niveau) { + case NiveauVigilanceKyc.simplifie: + return '🔵 Simplifiée'; + case NiveauVigilanceKyc.renforce: + return '🔴 Renforcée'; + } + } + + Color _getNiveauVigilanceColor(NiveauVigilanceKyc? niveau) { + if (niveau == null) return Colors.grey; + switch (niveau) { + case NiveauVigilanceKyc.simplifie: + return Colors.blue; + case NiveauVigilanceKyc.renforce: + return Colors.deepOrange; + } + } +}