import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import '../../features/authentication/presentation/bloc/auth_bloc.dart'; import '../../features/authentication/data/models/user_role.dart'; import '../../shared/design_system/unionflow_design_system.dart'; import '../../shared/widgets/core_card.dart'; import '../../shared/widgets/mini_avatar.dart'; import '../di/injection_container.dart'; import '../network/org_context_service.dart'; import '../../features/admin/presentation/pages/user_management_page.dart'; import '../../features/settings/presentation/pages/system_settings_page.dart'; import '../../features/backup/presentation/pages/backup_page.dart'; import '../../features/logs/presentation/pages/logs_page.dart'; import '../../features/reports/presentation/pages/reports_page_wrapper.dart'; import '../../features/epargne/presentation/pages/epargne_page.dart'; import '../../features/contributions/presentation/pages/contributions_page_wrapper.dart' show CotisationsPageWrapper; import '../../features/adhesions/presentation/pages/adhesions_page_wrapper.dart'; import '../../features/solidarity/presentation/pages/demandes_aide_page_wrapper.dart'; import '../../features/organizations/presentation/pages/organizations_page_wrapper.dart'; import '../../features/organizations/presentation/pages/org_selector_page.dart'; import '../../features/organizations/bloc/org_switcher_bloc.dart'; import '../../features/profile/presentation/pages/profile_page_wrapper.dart'; /// Page "Plus" avec les fonctions avancées selon le rôle et les modules actifs. class MorePage extends StatelessWidget { const MorePage({super.key}); @override Widget build(BuildContext context) { final orgCtx = sl(); return BlocBuilder( builder: (context, state) { if (state is! AuthAuthenticated) { return const Scaffold( body: Center(child: CircularProgressIndicator()), ); } return Scaffold( backgroundColor: AppColors.lightBackground, appBar: const UFAppBar( title: 'PLUS', automaticallyImplyLeading: false, ), body: SingleChildScrollView( padding: const EdgeInsets.all(12), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ _buildUserProfile(context, state, orgCtx), const SizedBox(height: SpacingTokens.md), ..._buildRoleBasedOptions(context, state, orgCtx), ..._buildModuleOptions(context, state, orgCtx), const SizedBox(height: SpacingTokens.md), ..._buildCommonOptions(context, orgCtx), ], ), ), ); }, ); } Widget _buildUserProfile( BuildContext context, AuthAuthenticated state, OrgContextService orgCtx) { final isDark = Theme.of(context).brightness == Brightness.dark; final textColor = isDark ? AppColors.textPrimaryDark : AppColors.textPrimaryLight; final roleColor = isDark ? AppColors.brandGreenLight : AppColors.primaryGreen; return CoreCard( onTap: () => Navigator.of(context).push( MaterialPageRoute(builder: (_) => const ProfilePageWrapper()), ), child: Row( children: [ MiniAvatar( fallbackText: state.user.firstName.isNotEmpty ? state.user.firstName[0].toUpperCase() : 'U', size: 40, imageUrl: state.user.avatar, ), const SizedBox(width: 16), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( '${state.user.firstName} ${state.user.lastName}', style: AppTypography.actionText.copyWith(color: textColor), ), Text( state.effectiveRole.displayName.toUpperCase(), style: AppTypography.badgeText.copyWith( color: roleColor, fontWeight: FontWeight.bold, ), ), if (orgCtx.hasContext) ...[ const SizedBox(height: 4), _OrgBadge(orgCtx: orgCtx, onTap: () => _openOrgSelector(context)), ], ], ), ), Icon(Icons.chevron_right, color: isDark ? AppColors.textSecondaryDark : AppColors.textSecondaryLight, size: 16), ], ), ); } void _openOrgSelector(BuildContext context) { // Vérifier que OrgSwitcherBloc est disponible (fourni par un ancêtre) try { showOrgSelector(context); } catch (_) { // OrgSwitcherBloc pas fourni dans ce contexte, navigation vers ProfilePage Navigator.of(context).push( MaterialPageRoute(builder: (_) => const ProfilePageWrapper()), ); } } List _buildRoleBasedOptions( BuildContext context, AuthAuthenticated state, OrgContextService orgCtx) { final options = []; if (state.effectiveRole == UserRole.superAdmin) { options.addAll([ _buildSectionTitle(context, 'Administration Système'), _buildOptionTile(context, icon: Icons.people, title: 'Gestion des utilisateurs', subtitle: 'Utilisateurs Keycloak et rôles', onTap: () => Navigator.of(context).push( MaterialPageRoute(builder: (_) => const UserManagementPage())), ), _buildOptionTile(context, icon: Icons.settings, title: 'Paramètres Système', subtitle: 'Configuration globale', onTap: () => Navigator.of(context).push( MaterialPageRoute(builder: (_) => const SystemSettingsPage())), ), _buildOptionTile(context, icon: Icons.backup, title: 'Sauvegarde & Restauration', subtitle: 'Gestion des sauvegardes', onTap: () => Navigator.of(context).push( MaterialPageRoute(builder: (_) => const BackupPage())), ), _buildOptionTile(context, icon: Icons.article, title: 'Logs & Monitoring', subtitle: 'Surveillance et journaux', onTap: () => Navigator.of(context).push( MaterialPageRoute(builder: (_) => const LogsPage())), ), ]); } if (state.effectiveRole == UserRole.orgAdmin || state.effectiveRole == UserRole.superAdmin) { options.addAll([ _buildSectionTitle(context, 'Administration'), _buildOptionTile(context, icon: Icons.business, title: 'Gestion des Organisations', subtitle: 'Créer et gérer les organisations', onTap: () => Navigator.of(context).push( MaterialPageRoute(builder: (_) => const OrganizationsPageWrapper())), ), _buildSectionTitle(context, 'Workflow Financier'), _buildOptionTile(context, icon: Icons.pending_actions, title: 'Approbations en attente', subtitle: 'Valider les transactions financières', onTap: () => Navigator.pushNamed(context, '/approvals'), ), _buildOptionTile(context, icon: Icons.account_balance_wallet, title: 'Gestion des Budgets', subtitle: 'Créer et suivre les budgets', onTap: () => Navigator.pushNamed(context, '/budgets'), ), _buildSectionTitle(context, 'Communication'), _buildOptionTile(context, icon: Icons.message, title: 'Messages & Broadcast', subtitle: 'Communiquer avec les membres', onTap: () => Navigator.pushNamed(context, '/messages'), ), _buildSectionTitle(context, 'Rapports & Analytics'), _buildOptionTile(context, icon: Icons.assessment, title: 'Rapports & Analytics', subtitle: 'Statistiques détaillées', onTap: () => Navigator.of(context).push( MaterialPageRoute(builder: (_) => const ReportsPageWrapper())), ), ]); } if (state.effectiveRole == UserRole.moderator) { options.addAll([ _buildSectionTitle(context, 'Communication'), _buildOptionTile(context, icon: Icons.message, title: 'Messages aux membres', subtitle: 'Communiquer avec les membres', onTap: () => Navigator.pushNamed(context, '/messages'), ), ]); } return options; } /// Sections de modules métier — visibles uniquement si le module est actif. List _buildModuleOptions( BuildContext context, AuthAuthenticated state, OrgContextService orgCtx) { final options = []; final isAdmin = state.effectiveRole == UserRole.orgAdmin || state.effectiveRole == UserRole.superAdmin; // Module TONTINE if (orgCtx.isModuleActif('TONTINE')) { options.add(_buildSectionTitle(context, 'Tontine')); if (isAdmin) { options.add(_buildOptionTile(context, icon: Icons.autorenew, title: 'Gestion Tontine', subtitle: 'Cycles, cotisations et remises', onTap: () => Navigator.pushNamed(context, '/tontine'), )); } else { options.add(_buildOptionTile(context, icon: Icons.autorenew, title: 'Ma Tontine', subtitle: 'Mes cycles et cotisations', onTap: () => Navigator.pushNamed(context, '/tontine'), )); } } // Module EPARGNE if (orgCtx.isModuleActif('EPARGNE')) { options.add(_buildSectionTitle(context, 'Épargne')); options.add(_buildOptionTile(context, icon: Icons.savings, title: isAdmin ? 'Gestion Épargne' : 'Mon Épargne', subtitle: isAdmin ? 'Comptes épargne et transactions' : 'Mon compte épargne', onTap: () => Navigator.of(context).push( MaterialPageRoute(builder: (_) => const EpargnePage())), )); } // Module CREDIT if (orgCtx.isModuleActif('CREDIT')) { options.add(_buildSectionTitle(context, 'Crédit')); options.add(_buildOptionTile(context, icon: Icons.account_balance, title: isAdmin ? 'Gestion Crédit' : 'Mon Crédit', subtitle: isAdmin ? 'Demandes et suivi des crédits' : 'Mes demandes de crédit', onTap: () => Navigator.pushNamed(context, '/credit'), )); } // Module AGRICULTURE if (orgCtx.isModuleActif('AGRICULTURE')) { options.add(_buildSectionTitle(context, 'Agriculture')); options.add(_buildOptionTile(context, icon: Icons.eco, title: 'Campagnes Agricoles', subtitle: 'Parcelles, récoltes et stocks', onTap: () => Navigator.pushNamed(context, '/agricole'), )); } // Module COLLECTE_FONDS if (orgCtx.isModuleActif('COLLECTE_FONDS')) { options.add(_buildSectionTitle(context, 'Collecte de Fonds')); options.add(_buildOptionTile(context, icon: Icons.volunteer_activism, title: 'Campagnes de Collecte', subtitle: 'Dons et levées de fonds', onTap: () => Navigator.pushNamed(context, '/collecte'), )); } // Module PROJETS_ONG if (orgCtx.isModuleActif('PROJETS_ONG')) { options.add(_buildSectionTitle(context, 'Projets ONG')); options.add(_buildOptionTile(context, icon: Icons.public, title: 'Projets', subtitle: 'Gérer et suivre les projets', onTap: () => Navigator.pushNamed(context, '/projets-ong'), )); } // Module CULTE_DONS if (orgCtx.isModuleActif('CULTE_DONS')) { options.add(_buildSectionTitle(context, 'Culte & Dons')); options.add(_buildOptionTile(context, icon: Icons.church, title: 'Dons et Offrandes', subtitle: 'Gestion des dons religieux', onTap: () => Navigator.pushNamed(context, '/culte'), )); } // Module VOTES if (orgCtx.isModuleActif('VOTES')) { options.add(_buildSectionTitle(context, 'Votes')); options.add(_buildOptionTile(context, icon: Icons.how_to_vote, title: 'Votes & Élections', subtitle: 'Campagnes et résultats', onTap: () => Navigator.pushNamed(context, '/votes'), )); } return options; } List _buildCommonOptions(BuildContext context, OrgContextService orgCtx) { return [ _buildSectionTitle(context, 'Général'), _buildOptionTile(context, icon: Icons.payment, title: 'Cotisations', subtitle: 'Gérer les cotisations', onTap: () => Navigator.of(context).push( MaterialPageRoute(builder: (_) => const CotisationsPageWrapper())), ), _buildOptionTile(context, icon: Icons.how_to_reg, title: 'Demandes d\'adhésion', subtitle: 'Demandes d\'adhésion à une organisation', onTap: () => Navigator.of(context).push( MaterialPageRoute(builder: (_) => const AdhesionsPageWrapper())), ), _buildOptionTile(context, icon: Icons.volunteer_activism, title: 'Demandes d\'aide', subtitle: 'Solidarité – demandes d\'aide', onTap: () => Navigator.of(context).push( MaterialPageRoute(builder: (_) => const DemandesAidePageWrapper())), ), // Épargne — affiché en commun uniquement si le module n'est PAS actif (évite doublon avec section module) if (!orgCtx.isModuleActif('EPARGNE')) _buildOptionTile(context, icon: Icons.savings_outlined, title: 'Comptes épargne', subtitle: 'Mutuelle épargne – dépôts (LCB-FT)', onTap: () => Navigator.of(context).push( MaterialPageRoute(builder: (_) => const EpargnePage())), ), ]; } Widget _buildSectionTitle(BuildContext context, String title) { final isDark = Theme.of(context).brightness == Brightness.dark; return Padding( padding: const EdgeInsets.only(top: 16, bottom: 6, left: 4), child: Text( title.toUpperCase(), style: AppTypography.subtitleSmall.copyWith( fontWeight: FontWeight.bold, letterSpacing: 1.1, color: isDark ? AppColors.textSecondaryDark : AppColors.textSecondaryLight, ), ), ); } Widget _buildOptionTile( BuildContext context, { required IconData icon, required String title, required String subtitle, required VoidCallback onTap, Color? accentColor, }) { final isDark = Theme.of(context).brightness == Brightness.dark; final accent = accentColor ?? AppColors.primaryGreen; final titleColor = accentColor != null ? accentColor : (isDark ? AppColors.textPrimaryDark : AppColors.textPrimaryLight); final subtitleColor = isDark ? AppColors.textSecondaryDark : AppColors.textSecondaryLight; final chevronColor = isDark ? AppColors.textSecondaryDark : AppColors.textSecondaryLight; return CoreCard( margin: const EdgeInsets.only(bottom: 8), onTap: onTap, child: Row( children: [ Container( padding: const EdgeInsets.all(7), decoration: BoxDecoration( color: accent.withOpacity(isDark ? 0.2 : 0.1), borderRadius: BorderRadius.circular(8), ), child: Icon(icon, color: accent, size: 18), ), const SizedBox(width: 16), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( title, style: AppTypography.actionText.copyWith(color: titleColor), ), Text( subtitle, style: AppTypography.subtitleSmall.copyWith(color: subtitleColor), ), ], ), ), Icon(Icons.chevron_right, color: chevronColor, size: 16), ], ), ); } } /// Badge compact affichant l'organisation active avec bouton de changement. class _OrgBadge extends StatelessWidget { final OrgContextService orgCtx; final VoidCallback onTap; const _OrgBadge({required this.orgCtx, required this.onTap}); @override Widget build(BuildContext context) { final colorScheme = Theme.of(context).colorScheme; return GestureDetector( onTap: onTap, child: Container( padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 3), decoration: BoxDecoration( color: colorScheme.primaryContainer.withValues(alpha: 0.4), borderRadius: BorderRadius.circular(12), ), child: Row( mainAxisSize: MainAxisSize.min, children: [ Icon(Icons.business, size: 12, color: colorScheme.primary), const SizedBox(width: 4), Flexible( child: Text( orgCtx.activeOrganisationNom ?? '—', style: TextStyle( fontSize: 11, color: colorScheme.primary, fontWeight: FontWeight.w600, ), overflow: TextOverflow.ellipsis, ), ), const SizedBox(width: 2), Icon(Icons.swap_horiz, size: 12, color: colorScheme.primary), ], ), ), ); } }