Initial commit: unionflow-mobile-apps

Application Flutter complète (sans build artifacts).

Signed-off-by: lions dev Team
This commit is contained in:
dahoud
2026-03-15 16:30:08 +00:00
commit d094d6db9c
1790 changed files with 507435 additions and 0 deletions

View File

@@ -0,0 +1,561 @@
/// Système de navigation adaptatif basé sur les rôles
/// Navigation qui s'adapte selon les permissions et rôles utilisateurs
library adaptive_navigation;
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 '../../features/authentication/data/models/permission_matrix.dart';
import '../../shared/widgets/adaptive_widget.dart';
/// Élément de navigation adaptatif
class AdaptiveNavigationItem {
/// Icône de l'élément
final IconData icon;
/// Icône sélectionnée (optionnelle)
final IconData? selectedIcon;
/// Libellé de l'élément
final String label;
/// Route de destination
final String route;
/// Permissions requises pour afficher cet élément
final List<String> requiredPermissions;
/// Rôles minimum requis
final UserRole? minimumRole;
/// Badge de notification (optionnel)
final String? badge;
/// Couleur personnalisée (optionnelle)
final Color? color;
const AdaptiveNavigationItem({
required this.icon,
this.selectedIcon,
required this.label,
required this.route,
this.requiredPermissions = const [],
this.minimumRole,
this.badge,
this.color,
});
}
/// Drawer de navigation adaptatif
class AdaptiveNavigationDrawer extends StatelessWidget {
/// Callback de navigation
final Function(String route) onNavigate;
/// Callback de déconnexion
final VoidCallback onLogout;
/// Éléments de navigation personnalisés
final List<AdaptiveNavigationItem>? customItems;
const AdaptiveNavigationDrawer({
super.key,
required this.onNavigate,
required this.onLogout,
this.customItems,
});
@override
Widget build(BuildContext context) {
return AdaptiveWidget(
roleWidgets: {
UserRole.superAdmin: () => _buildSuperAdminDrawer(context),
UserRole.orgAdmin: () => _buildOrgAdminDrawer(context),
UserRole.moderator: () => _buildModeratorDrawer(context),
UserRole.activeMember: () => _buildActiveMemberDrawer(context),
UserRole.simpleMember: () => _buildSimpleMemberDrawer(context),
UserRole.visitor: () => _buildVisitorDrawer(context),
},
fallbackWidget: _buildBasicDrawer(context),
loadingWidget: _buildLoadingDrawer(context),
);
}
/// Drawer pour Super Admin
Widget _buildSuperAdminDrawer(BuildContext context) {
final items = [
const AdaptiveNavigationItem(
icon: Icons.dashboard,
label: 'Command Center',
route: '/dashboard',
requiredPermissions: [PermissionMatrix.SYSTEM_ADMIN],
),
const AdaptiveNavigationItem(
icon: Icons.business,
label: 'Organisations',
route: '/organizations',
requiredPermissions: [PermissionMatrix.ORG_CREATE],
),
const AdaptiveNavigationItem(
icon: Icons.people,
label: 'Utilisateurs Globaux',
route: '/global-users',
requiredPermissions: [PermissionMatrix.MEMBERS_VIEW_ALL],
),
const AdaptiveNavigationItem(
icon: Icons.settings,
label: 'Administration',
route: '/system-admin',
requiredPermissions: [PermissionMatrix.SYSTEM_CONFIG],
),
const AdaptiveNavigationItem(
icon: Icons.analytics,
label: 'Analytics',
route: '/analytics',
requiredPermissions: [PermissionMatrix.DASHBOARD_ANALYTICS],
),
const AdaptiveNavigationItem(
icon: Icons.security,
label: 'Sécurité',
route: '/security',
requiredPermissions: [PermissionMatrix.SYSTEM_SECURITY],
),
];
return _buildDrawer(
context,
'Super Administrateur',
const Color(0xFF6C5CE7),
Icons.admin_panel_settings,
items,
);
}
/// Drawer pour Org Admin
Widget _buildOrgAdminDrawer(BuildContext context) {
final items = [
const AdaptiveNavigationItem(
icon: Icons.dashboard,
label: 'Control Panel',
route: '/dashboard',
requiredPermissions: [PermissionMatrix.DASHBOARD_VIEW],
),
const AdaptiveNavigationItem(
icon: Icons.people,
label: 'Membres',
route: '/members',
requiredPermissions: [PermissionMatrix.MEMBERS_VIEW_ALL],
),
const AdaptiveNavigationItem(
icon: Icons.account_balance_wallet,
label: 'Finances',
route: '/finances',
requiredPermissions: [PermissionMatrix.FINANCES_VIEW_ALL],
),
const AdaptiveNavigationItem(
icon: Icons.event,
label: 'Événements',
route: '/events',
requiredPermissions: [PermissionMatrix.EVENTS_VIEW_ALL],
),
const AdaptiveNavigationItem(
icon: Icons.volunteer_activism,
label: 'Solidarité',
route: '/solidarity',
requiredPermissions: [PermissionMatrix.SOLIDARITY_VIEW_ALL],
),
const AdaptiveNavigationItem(
icon: Icons.assessment,
label: 'Rapports',
route: '/reports',
requiredPermissions: [PermissionMatrix.REPORTS_GENERATE],
),
const AdaptiveNavigationItem(
icon: Icons.settings,
label: 'Configuration',
route: '/org-settings',
requiredPermissions: [PermissionMatrix.ORG_CONFIG],
),
];
return _buildDrawer(
context,
'Administrateur',
const Color(0xFF0984E3),
Icons.business_center,
items,
);
}
/// Drawer pour Modérateur
Widget _buildModeratorDrawer(BuildContext context) {
final items = [
const AdaptiveNavigationItem(
icon: Icons.dashboard,
label: 'Management Hub',
route: '/dashboard',
requiredPermissions: [PermissionMatrix.DASHBOARD_VIEW],
),
const AdaptiveNavigationItem(
icon: Icons.gavel,
label: 'Modération',
route: '/moderation',
requiredPermissions: [PermissionMatrix.MODERATION_CONTENT],
),
const AdaptiveNavigationItem(
icon: Icons.people,
label: 'Membres',
route: '/members',
requiredPermissions: [PermissionMatrix.MEMBERS_VIEW_ALL],
),
const AdaptiveNavigationItem(
icon: Icons.event,
label: 'Événements',
route: '/events',
requiredPermissions: [PermissionMatrix.EVENTS_VIEW_ALL],
),
const AdaptiveNavigationItem(
icon: Icons.message,
label: 'Communication',
route: '/communication',
requiredPermissions: [PermissionMatrix.COMM_MODERATE],
),
];
return _buildDrawer(
context,
'Modérateur',
const Color(0xFFE17055),
Icons.manage_accounts,
items,
);
}
/// Drawer pour Membre Actif
Widget _buildActiveMemberDrawer(BuildContext context) {
final items = [
const AdaptiveNavigationItem(
icon: Icons.dashboard,
label: 'Activity Center',
route: '/dashboard',
requiredPermissions: [PermissionMatrix.DASHBOARD_VIEW],
),
const AdaptiveNavigationItem(
icon: Icons.person,
label: 'Mon Profil',
route: '/profile',
requiredPermissions: [PermissionMatrix.MEMBERS_VIEW_OWN],
),
const AdaptiveNavigationItem(
icon: Icons.event,
label: 'Événements',
route: '/events',
requiredPermissions: [PermissionMatrix.EVENTS_VIEW_ALL],
),
const AdaptiveNavigationItem(
icon: Icons.volunteer_activism,
label: 'Solidarité',
route: '/solidarity',
requiredPermissions: [PermissionMatrix.SOLIDARITY_VIEW_ALL],
),
const AdaptiveNavigationItem(
icon: Icons.payment,
label: 'Mes Cotisations',
route: '/my-finances',
requiredPermissions: [PermissionMatrix.FINANCES_VIEW_OWN],
),
const AdaptiveNavigationItem(
icon: Icons.message,
label: 'Messages',
route: '/messages',
requiredPermissions: [PermissionMatrix.DASHBOARD_VIEW],
),
];
return _buildDrawer(
context,
'Membre Actif',
const Color(0xFF00B894),
Icons.groups,
items,
);
}
/// Drawer pour Membre Simple
Widget _buildSimpleMemberDrawer(BuildContext context) {
final items = [
const AdaptiveNavigationItem(
icon: Icons.dashboard,
label: 'Mon Espace',
route: '/dashboard',
requiredPermissions: [PermissionMatrix.DASHBOARD_VIEW],
),
const AdaptiveNavigationItem(
icon: Icons.person,
label: 'Mon Profil',
route: '/profile',
requiredPermissions: [PermissionMatrix.MEMBERS_VIEW_OWN],
),
const AdaptiveNavigationItem(
icon: Icons.event,
label: 'Événements',
route: '/events',
requiredPermissions: [PermissionMatrix.EVENTS_VIEW_PUBLIC],
),
const AdaptiveNavigationItem(
icon: Icons.payment,
label: 'Mes Cotisations',
route: '/my-finances',
requiredPermissions: [PermissionMatrix.FINANCES_VIEW_OWN],
),
const AdaptiveNavigationItem(
icon: Icons.help,
label: 'Aide',
route: '/help',
requiredPermissions: [],
),
];
return _buildDrawer(
context,
'Membre',
const Color(0xFF00CEC9),
Icons.person,
items,
);
}
/// Drawer pour Visiteur
Widget _buildVisitorDrawer(BuildContext context) {
final items = [
const AdaptiveNavigationItem(
icon: Icons.home,
label: 'Accueil',
route: '/dashboard',
requiredPermissions: [],
),
const AdaptiveNavigationItem(
icon: Icons.info,
label: 'À Propos',
route: '/about',
requiredPermissions: [],
),
const AdaptiveNavigationItem(
icon: Icons.event,
label: 'Événements Publics',
route: '/public-events',
requiredPermissions: [PermissionMatrix.EVENTS_VIEW_PUBLIC],
),
const AdaptiveNavigationItem(
icon: Icons.contact_mail,
label: 'Contact',
route: '/contact',
requiredPermissions: [],
),
const AdaptiveNavigationItem(
icon: Icons.login,
label: 'Se Connecter',
route: '/login',
requiredPermissions: [],
),
];
return _buildDrawer(
context,
'Visiteur',
const Color(0xFF6C5CE7),
Icons.waving_hand,
items,
);
}
/// Drawer basique de fallback
Widget _buildBasicDrawer(BuildContext context) {
return _buildDrawer(
context,
'UnionFlow',
Colors.grey,
Icons.dashboard,
[
const AdaptiveNavigationItem(
icon: Icons.home,
label: 'Accueil',
route: '/dashboard',
),
],
);
}
/// Drawer de chargement
Widget _buildLoadingDrawer(BuildContext context) {
return Drawer(
child: Container(
decoration: const BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [Color(0xFF6C5CE7), Color(0xFF5A4FCF)],
),
),
child: const Center(
child: CircularProgressIndicator(
valueColor: AlwaysStoppedAnimation<Color>(Colors.white),
),
),
),
);
}
/// Construit un drawer avec les éléments spécifiés
Widget _buildDrawer(
BuildContext context,
String title,
Color color,
IconData icon,
List<AdaptiveNavigationItem> items,
) {
return Drawer(
child: Column(
children: [
// En-tête du drawer
_buildDrawerHeader(context, title, color, icon),
// Éléments de navigation
Expanded(
child: ListView(
padding: EdgeInsets.zero,
children: [
...items.map((item) => _buildNavigationItem(context, item)),
const Divider(),
_buildLogoutItem(context),
],
),
),
],
),
);
}
/// Construit l'en-tête du drawer
Widget _buildDrawerHeader(
BuildContext context,
String title,
Color color,
IconData icon,
) {
return DrawerHeader(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: [color, color.withOpacity(0.8)],
),
),
child: BlocBuilder<AuthBloc, AuthState>(
builder: (context, state) {
if (state is AuthAuthenticated) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Icon(icon, color: Colors.white, size: 32),
const SizedBox(width: 12),
Text(
title,
style: const TextStyle(
color: Colors.white,
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
],
),
const SizedBox(height: 16),
Text(
state.user.fullName,
style: const TextStyle(
color: Colors.white,
fontSize: 16,
),
),
Text(
state.user.email,
style: TextStyle(
color: Colors.white.withOpacity(0.8),
fontSize: 14,
),
),
],
);
}
return Row(
children: [
Icon(icon, color: Colors.white, size: 32),
const SizedBox(width: 12),
Text(
title,
style: const TextStyle(
color: Colors.white,
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
],
);
},
),
);
}
/// Construit un élément de navigation
Widget _buildNavigationItem(
BuildContext context,
AdaptiveNavigationItem item,
) {
return SecureWidget(
requiredPermissions: item.requiredPermissions,
child: ListTile(
leading: Icon(item.icon, color: item.color),
title: Text(item.label),
trailing: item.badge != null
? Container(
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
decoration: BoxDecoration(
color: Colors.red,
borderRadius: BorderRadius.circular(12),
),
child: Text(
item.badge!,
style: const TextStyle(
color: Colors.white,
fontSize: 12,
fontWeight: FontWeight.bold,
),
),
)
: null,
onTap: () {
Navigator.of(context).pop();
onNavigate(item.route);
},
),
);
}
/// Construit l'élément de déconnexion
Widget _buildLogoutItem(BuildContext context) {
return ListTile(
leading: const Icon(Icons.logout, color: Colors.red),
title: const Text(
'Déconnexion',
style: TextStyle(color: Colors.red),
),
onTap: () {
Navigator.of(context).pop();
onLogout();
},
);
}
}

View File

@@ -0,0 +1,188 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'more_page.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 '../../features/dashboard/presentation/pages/role_dashboards/role_dashboards.dart';
import '../../features/dashboard/presentation/pages/role_dashboards/org_admin_dashboard_loader.dart';
import '../../features/members/presentation/pages/members_page_wrapper.dart';
import '../../features/events/presentation/pages/events_page_wrapper.dart';
import '../../features/contributions/presentation/pages/contributions_page_wrapper.dart';
import '../../features/adhesions/presentation/pages/adhesions_page_wrapper.dart';
import '../../features/solidarity/presentation/pages/demandes_aide_page_wrapper.dart';
import '../../features/admin/presentation/pages/user_management_page.dart';
import '../../features/about/presentation/pages/about_page.dart';
import '../../features/help/presentation/pages/help_support_page.dart';
import '../../features/notifications/presentation/pages/notifications_page_wrapper.dart';
import '../../features/profile/presentation/pages/profile_page_wrapper.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/dashboard/presentation/bloc/dashboard_bloc.dart';
import '../di/injection.dart';
/// Layout principal avec navigation hybride
/// Bottom Navigation pour les sections principales + Drawer pour fonctions avancées
class MainNavigationLayout extends StatefulWidget {
const MainNavigationLayout({super.key});
@override
State<MainNavigationLayout> createState() => _MainNavigationLayoutState();
}
class _MainNavigationLayoutState extends State<MainNavigationLayout> {
int _selectedIndex = 0;
List<Widget>? _cachedPages;
UserRole? _lastRole;
String? _lastUserId;
/// Obtient le dashboard approprié selon le rôle de l'utilisateur
Widget _getDashboardForRole(UserRole role, String userId, String? orgId) {
// Admin d'organisation sans orgId (organizationContexts vide) : charger /mes puis dashboard
if (role == UserRole.orgAdmin && (orgId == null || orgId.isEmpty)) {
return OrgAdminDashboardLoader(userId: userId);
}
return BlocProvider<DashboardBloc>(
create: (context) => getIt<DashboardBloc>()
..add(LoadDashboardData(
organizationId: orgId ?? '',
userId: userId,
)),
child: _buildDashboardView(role),
);
}
Widget _buildDashboardView(UserRole role) {
switch (role) {
case UserRole.superAdmin:
return const SuperAdminDashboard();
case UserRole.orgAdmin:
return const OrgAdminDashboard();
case UserRole.moderator:
return const ModeratorDashboard();
case UserRole.consultant:
return const ConsultantDashboard();
case UserRole.hrManager:
return const HRManagerDashboard();
case UserRole.activeMember:
return const ActiveMemberDashboard();
case UserRole.simpleMember:
return const SimpleMemberDashboard();
case UserRole.visitor:
return const VisitorDashboard();
}
}
/// Obtient les pages et les met en cache pour éviter les rebuilds inutiles
List<Widget> _getPages(UserRole role, String userId, String? orgId) {
if (_cachedPages != null && _lastRole == role && _lastUserId == userId) {
return _cachedPages!;
}
debugPrint('🔄 [MainNavigationLayout] Initialisation des pages (Role: $role, User: $userId)');
_lastRole = role;
_lastUserId = userId;
final canManageMembers = role.hasLevelOrAbove(UserRole.hrManager);
_cachedPages = [
_getDashboardForRole(role, userId, orgId),
if (canManageMembers) const MembersPageWrapper(),
const EventsPageWrapper(),
const MorePage(),
];
return _cachedPages!;
}
@override
Widget build(BuildContext context) {
return BlocBuilder<AuthBloc, AuthState>(
builder: (context, state) {
if (state is! AuthAuthenticated) {
return const Scaffold(
body: Center(child: CircularProgressIndicator()),
);
}
final orgId = state.user.organizationContexts.isNotEmpty
? state.user.organizationContexts.first.organizationId
: null;
final pages = _getPages(state.effectiveRole, state.user.id, orgId);
final safeIndex = _selectedIndex >= pages.length ? 0 : _selectedIndex;
return Scaffold(
backgroundColor: ColorTokens.background,
body: SafeArea(
top: true, // Respecte le StatusBar
bottom: false, // Le BottomNavigationBar gère son propre SafeArea
child: IndexedStack(
index: safeIndex,
children: pages,
),
),
bottomNavigationBar: SafeArea(
top: false,
child: Container(
decoration: const BoxDecoration(
color: ColorTokens.surface,
boxShadow: [
BoxShadow(
color: ColorTokens.shadow,
blurRadius: 8,
offset: Offset(0, -2),
),
],
),
child: BottomNavigationBar(
type: BottomNavigationBarType.fixed,
currentIndex: safeIndex,
onTap: (index) {
setState(() {
_selectedIndex = index;
});
},
backgroundColor: ColorTokens.surface,
selectedItemColor: ColorTokens.primary,
unselectedItemColor: ColorTokens.onSurfaceVariant,
selectedLabelStyle: TypographyTokens.labelSmall.copyWith(
fontWeight: FontWeight.w600,
),
unselectedLabelStyle: TypographyTokens.labelSmall,
elevation: 0, // Géré par le Container
items: [
const BottomNavigationBarItem(
icon: Icon(Icons.dashboard_outlined),
activeIcon: Icon(Icons.dashboard),
label: 'Dashboard',
),
if (state.effectiveRole.hasLevelOrAbove(UserRole.hrManager))
const BottomNavigationBarItem(
icon: Icon(Icons.people_outline),
activeIcon: Icon(Icons.people),
label: 'Membres',
),
const BottomNavigationBarItem(
icon: Icon(Icons.event_outlined),
activeIcon: Icon(Icons.event),
label: 'Événements',
),
const BottomNavigationBarItem(
icon: Icon(Icons.more_horiz_outlined),
activeIcon: Icon(Icons.more_horiz),
label: 'Plus',
),
],
),
),
),
);
},
);
}
}

View File

@@ -0,0 +1,332 @@
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 '../../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';
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';
/// Page "Plus" avec les fonctions avancées selon le rôle (Menu Principal Extensif)
class MorePage extends StatelessWidget {
const MorePage({super.key});
@override
Widget build(BuildContext context) {
return BlocBuilder<AuthBloc, AuthState>(
builder: (context, state) {
if (state is! AuthAuthenticated) {
return const Scaffold(
body: Center(child: CircularProgressIndicator()),
);
}
return Scaffold(
backgroundColor: ColorTokens.background,
appBar: const UFAppBar(
title: 'PLUS',
automaticallyImplyLeading: false,
),
body: SingleChildScrollView(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Profil utilisateur
_buildUserProfile(state),
const SizedBox(height: SpacingTokens.md),
// Options selon le rôle
..._buildRoleBasedOptions(context, state),
const SizedBox(height: SpacingTokens.md),
// Options communes
..._buildCommonOptions(context),
],
),
),
);
},
);
}
Widget _buildUserProfile(AuthAuthenticated state) {
return CoreCard(
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,
),
Text(
state.effectiveRole.displayName.toUpperCase(),
style: AppTypography.badgeText.copyWith(
color: AppColors.primaryGreen,
fontWeight: FontWeight.bold,
),
),
],
),
),
],
),
);
}
List<Widget> _buildRoleBasedOptions(BuildContext context, AuthAuthenticated state) {
final options = <Widget>[];
// Options Super Admin uniquement
if (state.effectiveRole == UserRole.superAdmin) {
options.addAll([
_buildSectionTitle('Administration Système'),
_buildOptionTile(
icon: Icons.people,
title: 'Gestion des utilisateurs',
subtitle: 'Utilisateurs Keycloak et rôles',
onTap: () {
Navigator.of(context).push(
MaterialPageRoute(builder: (context) => const UserManagementPage()),
);
},
),
_buildOptionTile(
icon: Icons.settings,
title: 'Paramètres Système',
subtitle: 'Configuration globale',
onTap: () {
Navigator.of(context).push(
MaterialPageRoute(builder: (context) => const SystemSettingsPage()),
);
},
),
_buildOptionTile(
icon: Icons.backup,
title: 'Sauvegarde & Restauration',
subtitle: 'Gestion des sauvegardes',
onTap: () {
Navigator.of(context).push(
MaterialPageRoute(builder: (context) => const BackupPage()),
);
},
),
_buildOptionTile(
icon: Icons.article,
title: 'Logs & Monitoring',
subtitle: 'Surveillance et journaux',
onTap: () {
Navigator.of(context).push(
MaterialPageRoute(builder: (context) => const LogsPage()),
);
},
),
]);
}
// Options Admin+ (Admin Organisation et Super Admin)
if (state.effectiveRole == UserRole.orgAdmin || state.effectiveRole == UserRole.superAdmin) {
options.addAll([
_buildSectionTitle('Administration'),
_buildOptionTile(
icon: Icons.business,
title: 'Gestion des Organisations',
subtitle: 'Créer et gérer les organisations',
onTap: () {
Navigator.of(context).push(
MaterialPageRoute(builder: (context) => const OrganizationsPageWrapper()),
);
},
),
_buildSectionTitle('Workflow Financier'),
_buildOptionTile(
icon: Icons.pending_actions,
title: 'Approbations en attente',
subtitle: 'Valider les transactions financières',
onTap: () {
Navigator.pushNamed(context, '/approvals');
},
),
_buildOptionTile(
icon: Icons.account_balance_wallet,
title: 'Gestion des Budgets',
subtitle: 'Créer et suivre les budgets',
onTap: () {
Navigator.pushNamed(context, '/budgets');
},
),
_buildSectionTitle('Communication'),
_buildOptionTile(
icon: Icons.message,
title: 'Messages & Broadcast',
subtitle: 'Communiquer avec les membres',
onTap: () {
Navigator.pushNamed(context, '/messages');
},
),
_buildSectionTitle('Rapports & Analytics'),
_buildOptionTile(
icon: Icons.assessment,
title: 'Rapports & Analytics',
subtitle: 'Statistiques détaillées',
onTap: () {
Navigator.of(context).push(
MaterialPageRoute(builder: (context) => const ReportsPageWrapper()),
);
},
),
]);
}
// Options Modérateur (Communication limitée)
if (state.effectiveRole == UserRole.moderator) {
options.addAll([
_buildSectionTitle('Communication'),
_buildOptionTile(
icon: Icons.message,
title: 'Messages aux membres',
subtitle: 'Communiquer avec les membres',
onTap: () {
Navigator.pushNamed(context, '/messages');
},
),
]);
}
return options;
}
List<Widget> _buildCommonOptions(BuildContext context) {
return [
_buildSectionTitle('Général'),
_buildOptionTile(
icon: Icons.payment,
title: 'Cotisations',
subtitle: 'Gérer les cotisations',
onTap: () {
Navigator.of(context).push(
MaterialPageRoute(builder: (context) => const CotisationsPageWrapper()),
);
},
),
_buildOptionTile(
icon: Icons.how_to_reg,
title: 'Demandes d\'adhésion',
subtitle: 'Demandes d\'adhésion à une organisation',
onTap: () {
Navigator.of(context).push(
MaterialPageRoute(builder: (context) => const AdhesionsPageWrapper()),
);
},
),
_buildOptionTile(
icon: Icons.volunteer_activism,
title: 'Demandes d\'aide',
subtitle: 'Solidarité demandes d\'aide',
onTap: () {
Navigator.of(context).push(
MaterialPageRoute(builder: (context) => const DemandesAidePageWrapper()),
);
},
),
_buildOptionTile(
icon: Icons.savings_outlined,
title: 'Comptes épargne',
subtitle: 'Mutuelle épargne dépôts (LCB-FT)',
onTap: () {
Navigator.of(context).push(
MaterialPageRoute(builder: (context) => const EpargnePage()),
);
},
),
];
}
Widget _buildSectionTitle(String title) {
return Padding(
padding: const EdgeInsets.only(top: 24, bottom: 8, left: 4),
child: Text(
title.toUpperCase(),
style: AppTypography.subtitleSmall.copyWith(
fontWeight: FontWeight.bold,
letterSpacing: 1.1,
color: AppColors.textSecondaryLight,
),
),
);
}
Widget _buildOptionTile({
required IconData icon,
required String title,
required String subtitle,
required VoidCallback onTap,
Color? color,
}) {
final effectiveColor = color ?? AppColors.primaryGreen;
return CoreCard(
margin: const EdgeInsets.only(bottom: 8),
onTap: onTap,
child: Row(
children: [
Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
color: effectiveColor.withOpacity(0.1),
borderRadius: BorderRadius.circular(8),
),
child: Icon(
icon,
color: effectiveColor,
size: 20,
),
),
const SizedBox(width: 16),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
title,
style: AppTypography.actionText.copyWith(
color: color ?? AppColors.textPrimaryLight,
),
),
Text(
subtitle,
style: AppTypography.subtitleSmall,
),
],
),
),
const Icon(
Icons.chevron_right,
color: AppColors.textSecondaryLight,
size: 16,
),
],
),
);
}
}