import 'package:flutter/material.dart'; import 'package:flutter/services.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/dashboard/presentation/bloc/dashboard_bloc.dart'; import '../di/injection.dart'; /// Layout principal β€” Navigation hybride /// Pill navigation (style Material 3) au bas de l'Γ©cran class MainNavigationLayout extends StatefulWidget { const MainNavigationLayout({super.key}); @override State createState() => _MainNavigationLayoutState(); } class _MainNavigationLayoutState extends State { int _selectedIndex = 0; List? _cachedPages; UserRole? _lastRole; String? _lastUserId; String? _lastOrgId; Widget _getDashboardForRole(UserRole role, String userId, String? orgId) { if (role == UserRole.orgAdmin && (orgId == null || orgId.isEmpty)) { return OrgAdminDashboardLoader(userId: userId); } // Pour SUPER_ADMIN sans org: forcer les stats globales (toutes organisations) final isGlobalAdmin = role == UserRole.superAdmin && (orgId == null || orgId.isEmpty); return BlocProvider( create: (context) => getIt() ..add(LoadDashboardData( organizationId: orgId ?? '', userId: userId, useGlobalDashboard: isGlobalAdmin, )), 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(); } } List _getPages(UserRole role, String userId, String? orgId) { if (_cachedPages != null && _lastRole == role && _lastUserId == userId && _lastOrgId == orgId) { return _cachedPages!; } debugPrint('πŸ”„ [MainNavigationLayout] Init pages (Role: $role, User: $userId)'); _lastRole = role; _lastUserId = userId; _lastOrgId = orgId; _cachedPages = [ _getDashboardForRole(role, userId, orgId), if (role.hasLevelOrAbove(UserRole.hrManager)) MembersPageWrapper( organisationId: role == UserRole.orgAdmin ? orgId : null, ), const EventsPageWrapper(), const MorePage(), ]; return _cachedPages!; } @override Widget build(BuildContext context) { return BlocBuilder( 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; // Construire la liste des items de navigation selon le rΓ΄le final navItems = _buildNavItems(state.effectiveRole); return AnnotatedRegion( value: const SystemUiOverlayStyle( statusBarColor: Colors.transparent, statusBarIconBrightness: Brightness.dark, ), child: Scaffold( backgroundColor: ColorTokens.background, body: SafeArea( top: true, bottom: false, child: IndexedStack( index: safeIndex, children: pages, ), ), bottomNavigationBar: SafeArea( top: false, child: _PillNavigationBar( items: navItems, selectedIndex: safeIndex, onItemTap: (i) => setState(() => _selectedIndex = i), ), ), ), ); }, ); } List<_NavItem> _buildNavItems(UserRole role) { return [ const _NavItem( icon: Icons.dashboard_outlined, activeIcon: Icons.dashboard_rounded, label: 'Dashboard', ), if (role.hasLevelOrAbove(UserRole.hrManager)) const _NavItem( icon: Icons.people_outline_rounded, activeIcon: Icons.people_rounded, label: 'Membres', ), const _NavItem( icon: Icons.event_outlined, activeIcon: Icons.event_rounded, label: 'Γ‰vΓ©nements', ), const _NavItem( icon: Icons.more_horiz_rounded, activeIcon: Icons.more_horiz_rounded, label: 'Plus', ), ]; } } // ───────────────────────────────────────────────────────────────────────────── // Pill Navigation Bar β€” Material 3 style // ───────────────────────────────────────────────────────────────────────────── class _NavItem { const _NavItem({ required this.icon, required this.activeIcon, required this.label, }); final IconData icon; final IconData activeIcon; final String label; } class _PillNavigationBar extends StatelessWidget { const _PillNavigationBar({ required this.items, required this.selectedIndex, required this.onItemTap, }); final List<_NavItem> items; final int selectedIndex; final ValueChanged onItemTap; @override Widget build(BuildContext context) { return Container( decoration: BoxDecoration( color: ColorTokens.surface, boxShadow: [ BoxShadow( color: ColorTokens.shadow, blurRadius: 12, offset: const Offset(0, -2), ), ], ), padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 10), child: Row( mainAxisAlignment: MainAxisAlignment.spaceAround, children: List.generate(items.length, (i) { return _PillNavItem( item: items[i], isSelected: i == selectedIndex, onTap: () => onItemTap(i), ); }), ), ); } } class _PillNavItem extends StatelessWidget { const _PillNavItem({ required this.item, required this.isSelected, required this.onTap, }); final _NavItem item; final bool isSelected; final VoidCallback onTap; @override Widget build(BuildContext context) { return GestureDetector( onTap: onTap, behavior: HitTestBehavior.opaque, child: AnimatedContainer( duration: const Duration(milliseconds: 250), curve: Curves.easeInOut, padding: EdgeInsets.symmetric( horizontal: isSelected ? 16 : 14, vertical: 8, ), decoration: BoxDecoration( color: isSelected ? ColorTokens.primary.withOpacity(0.12) : Colors.transparent, borderRadius: BorderRadius.circular(24), ), child: isSelected ? Row( mainAxisSize: MainAxisSize.min, children: [ Icon( item.activeIcon, size: 22, color: ColorTokens.primary, ), const SizedBox(width: 6), Text( item.label, style: const TextStyle( fontFamily: 'Inter', fontSize: 12, fontWeight: FontWeight.w700, color: ColorTokens.primary, letterSpacing: 0.2, ), ), ], ) : Icon( item.icon, size: 22, color: ColorTokens.navigationUnselected, ), ), ); } }