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/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 '../../shared/design_system/tokens/app_colors.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( appBar: const UFAppBar( title: 'PLUS', automaticallyImplyLeading: false, moduleGradient: ModuleColors.systemeGradient, ), 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 scheme = Theme.of(context).colorScheme; 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: scheme.onSurface), ), Text( state.effectiveRole.displayName.toUpperCase(), style: AppTypography.badgeText.copyWith( color: ModuleColors.profil, fontWeight: FontWeight.bold, ), ), if (orgCtx.hasContext) ...[ const SizedBox(height: 4), _OrgBadge(orgCtx: orgCtx, onTap: () => _openOrgSelector(context)), ], ], ), ), Icon(Icons.chevron_right, color: scheme.onSurfaceVariant, size: 16), ], ), ); } void _openOrgSelector(BuildContext context) { try { showOrgSelector(context); } catch (_) { Navigator.of(context).push( MaterialPageRoute(builder: (_) => const ProfilePageWrapper()), ); } } List _buildRoleBasedOptions( BuildContext context, AuthAuthenticated state, OrgContextService orgCtx) { final options = []; // Note: les items SYSTÈME (Gestion utilisateurs, Paramètres Système, // Sauvegarde & Restauration, Logs & Monitoring) ont été déplacés dans // le burger drawer (section "Système" — super admin only) afin de // respecter la démarcation Métier (Plus) / Système (Drawer). if (state.effectiveRole == UserRole.orgAdmin || state.effectiveRole == UserRole.superAdmin) { final isSuperAdmin = state.effectiveRole == UserRole.superAdmin; final orgTitle = _orgTitle(context, isSuperAdmin); final orgSubtitle = _orgSubtitle(context, isSuperAdmin); options.addAll([ _buildSectionTitle(context, 'Administration'), _buildOptionTile(context, icon: Icons.business, title: orgTitle, subtitle: orgSubtitle, accentColor: ModuleColors.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', accentColor: ModuleColors.financeWorkflow, onTap: () => Navigator.pushNamed(context, '/approvals'), ), _buildOptionTile(context, icon: Icons.account_balance_wallet, title: 'Gestion des Budgets', subtitle: 'Créer et suivre les budgets', accentColor: ModuleColors.financeWorkflow, onTap: () => Navigator.pushNamed(context, '/budgets'), ), _buildSectionTitle(context, 'Communication'), _buildOptionTile(context, icon: Icons.message, title: 'Messages & Broadcast', subtitle: 'Communiquer avec les membres', accentColor: ModuleColors.communication, onTap: () => Navigator.pushNamed(context, '/messages'), ), _buildSectionTitle(context, 'Rapports & Analytics'), _buildOptionTile(context, icon: Icons.assessment, title: 'Rapports & Analytics', subtitle: 'Statistiques détaillées', accentColor: ModuleColors.rapports, 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', accentColor: ModuleColors.communication, 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; if (orgCtx.isModuleActif('TONTINE')) { options.add(_buildSectionTitle(context, 'Tontine')); options.add(_buildOptionTile(context, icon: Icons.autorenew, title: isAdmin ? 'Gestion Tontine' : 'Ma Tontine', subtitle: isAdmin ? 'Cycles, cotisations et remises' : 'Mes cycles et cotisations', accentColor: ModuleColors.cotisations, onTap: () => _comingSoon(context, 'Tontine'), )); } if (orgCtx.isModuleActif('EPARGNE')) { options.add(_buildSectionTitle(context, 'Épargne')); options.add(_buildOptionTile(context, icon: Icons.savings, title: isAdmin ? 'Gestion Épargne' : 'Mon Épargne', subtitle: isAdmin ? 'Épargne, dépôts, crédits et transactions' : 'Mon épargne et mes crédits', accentColor: ModuleColors.epargne, onTap: () => Navigator.of(context).push( MaterialPageRoute(builder: (_) => const EpargnePage())), )); } 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', accentColor: ModuleColors.financeWorkflow, onTap: () => _comingSoon(context, 'Crédit'), )); } 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', accentColor: ModuleColors.epargne, onTap: () => _comingSoon(context, 'Agriculture'), )); } 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', accentColor: ModuleColors.solidarite, onTap: () => _comingSoon(context, 'Collecte de Fonds'), )); } 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', accentColor: ModuleColors.rapports, onTap: () => _comingSoon(context, 'Projets ONG'), )); } 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', accentColor: ModuleColors.solidarite, onTap: () => _comingSoon(context, 'Culte & Dons'), )); } 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', accentColor: ModuleColors.financeWorkflow, onTap: () => _comingSoon(context, 'Votes & Élections'), )); } 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', accentColor: ModuleColors.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', accentColor: ModuleColors.adhesions, onTap: () => Navigator.of(context).push( MaterialPageRoute(builder: (_) => const AdhesionsPageWrapper())), ), _buildOptionTile(context, icon: Icons.volunteer_activism, title: 'Demandes d\'aide', subtitle: 'Solidarité – demandes d\'aide', accentColor: ModuleColors.solidarite, onTap: () => Navigator.of(context).push( MaterialPageRoute(builder: (_) => const DemandesAidePageWrapper())), ), if (!orgCtx.isModuleActif('EPARGNE')) _buildOptionTile(context, icon: Icons.savings_outlined, title: 'Épargne & Crédit', subtitle: 'Comptes épargne, dépôts et crédits (LCB-FT)', accentColor: ModuleColors.epargne, onTap: () => Navigator.of(context).push( MaterialPageRoute(builder: (_) => const EpargnePage())), ), ]; } // ─── Helpers titre organisation ───────────────────────────────────────── /// Titre de l'entrée "Organisation(s)" selon le rôle et le nombre d'orgs gérées. String _orgTitle(BuildContext context, bool isSuperAdmin) { if (isSuperAdmin) return 'Gestion des Organisations'; final switcherState = context.read().state; final count = switcherState is OrgSwitcherLoaded ? switcherState.organisations.length : 1; return count > 1 ? 'Mes Organisations' : 'Mon Organisation'; } String _orgSubtitle(BuildContext context, bool isSuperAdmin) { if (isSuperAdmin) return 'Créer et gérer les organisations'; final switcherState = context.read().state; final count = switcherState is OrgSwitcherLoaded ? switcherState.organisations.length : 1; return count > 1 ? 'Gérer mes organisations' : 'Gérer mon organisation'; } // ─── Modules non encore implémentés ───────────────────────────────────── void _comingSoon(BuildContext context, String feature) { final isDark = Theme.of(context).brightness == Brightness.dark; ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Row(children: [ const Icon(Icons.construction_outlined, color: Colors.white, size: 16), const SizedBox(width: 8), Expanded(child: Text('$feature — Disponible prochainement')), ]), backgroundColor: isDark ? AppColors.surfaceVariantDark : AppColors.textSecondary, behavior: SnackBarBehavior.floating, duration: const Duration(seconds: 3), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)), ), ); } Widget _buildSectionTitle(BuildContext context, String title) { final scheme = Theme.of(context).colorScheme; 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: scheme.onSurfaceVariant, ), ), ); } Widget _buildOptionTile( BuildContext context, { required IconData icon, required String title, required String subtitle, required VoidCallback onTap, Color? accentColor, }) { final scheme = Theme.of(context).colorScheme; final accent = accentColor ?? scheme.primary; return CoreCard( margin: const EdgeInsets.only(bottom: 8), onTap: onTap, child: Row( children: [ Container( padding: const EdgeInsets.all(7), decoration: BoxDecoration( color: accent.withOpacity(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: scheme.onSurface, ), ), Text( subtitle, style: AppTypography.subtitleSmall.copyWith(color: scheme.onSurfaceVariant), ), ], ), ), Icon(Icons.chevron_right, color: scheme.onSurfaceVariant, 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), ], ), ), ); } }