import 'package:em2rp/providers/local_user_provider.dart'; import 'package:em2rp/providers/event_provider.dart'; import 'package:flutter/material.dart'; import 'package:em2rp/views/widgets/custom_app_bar.dart'; import 'package:em2rp/views/widgets/nav/main_drawer.dart'; import 'package:provider/provider.dart'; import 'package:table_calendar/table_calendar.dart'; import 'package:em2rp/models/event_model.dart'; import 'package:em2rp/views/widgets/calendar_widgets/event_details.dart'; import 'package:intl/date_symbol_data_local.dart'; import 'package:em2rp/views/widgets/calendar_widgets/month_view.dart'; import 'package:em2rp/views/widgets/calendar_widgets/week_view.dart'; import 'package:em2rp/views/pages/event_add_page.dart'; import 'package:em2rp/views/widgets/calendar_widgets/mobile_calendar_view.dart'; import 'package:em2rp/utils/colors.dart'; class CalendarPage extends StatefulWidget { const CalendarPage({super.key}); @override State createState() => _CalendarPageState(); } class _CalendarPageState extends State { CalendarFormat _calendarFormat = CalendarFormat.month; DateTime _focusedDay = DateTime.now(); DateTime? _selectedDay; EventModel? _selectedEvent; bool _calendarCollapsed = false; int _selectedEventIndex = 0; @override void initState() { super.initState(); initializeDateFormatting('fr_FR', null); Future.microtask(() => _loadEvents()); // Sélection automatique de l'événement le plus proche de maintenant WidgetsBinding.instance.addPostFrameCallback((_) { final eventProvider = Provider.of(context, listen: false); final events = eventProvider.events; if (events.isNotEmpty) { final now = DateTime.now(); events.sort((a, b) => a.startDateTime.compareTo(b.startDateTime)); int closestIdx = 0; Duration minDiff = (events[0].startDateTime.difference(now)).abs(); for (int i = 1; i < events.length; i++) { final diff = (events[i].startDateTime.difference(now)).abs(); if (diff < minDiff) { minDiff = diff; closestIdx = i; } } final closestEvent = events[closestIdx]; setState(() { _selectedDay = DateTime(closestEvent.startDateTime.year, closestEvent.startDateTime.month, closestEvent.startDateTime.day); _focusedDay = _selectedDay!; _selectedEventIndex = 0; _selectedEvent = closestEvent; }); } }); } Future _loadEvents() async { final localAuthProvider = Provider.of(context, listen: false); final eventProvider = Provider.of(context, listen: false); final userId = localAuthProvider.uid; print('Permissions utilisateur: ${localAuthProvider.permissions}'); final canViewAllEvents = localAuthProvider.hasPermission('view_all_events'); print('canViewAllEvents: $canViewAllEvents'); if (userId != null) { await eventProvider.loadUserEvents(userId, canViewAllEvents: canViewAllEvents); } } void _changeWeek(int delta) { setState(() { _focusedDay = _focusedDay.add(Duration(days: 7 * delta)); }); } @override Widget build(BuildContext context) { final eventProvider = Provider.of(context); final localUserProvider = Provider.of(context); final isAdmin = localUserProvider.hasPermission('view_all_users'); final isMobile = MediaQuery.of(context).size.width < 600; if (eventProvider.isLoading) { return const Scaffold( body: Center( child: CircularProgressIndicator(), ), ); } return Scaffold( appBar: CustomAppBar( title: _getMonthName(_focusedDay.month), actions: [ IconButton( icon: Icon( _calendarCollapsed ? Icons.keyboard_arrow_down : Icons.keyboard_arrow_up, color: AppColors.blanc, ), onPressed: () { setState(() { _calendarCollapsed = !_calendarCollapsed; }); }, ), ], ), drawer: const MainDrawer(currentPage: '/calendar'), body: isMobile ? _buildMobileLayout() : _buildDesktopLayout(), floatingActionButton: isAdmin ? FloatingActionButton( backgroundColor: Colors.white, onPressed: () { Navigator.of(context).push( MaterialPageRoute( builder: (context) => const EventAddPage(), ), ); }, child: const Icon(Icons.add, color: Colors.red), tooltip: 'Ajouter un événement', ) : null, ); } Widget _buildDesktopLayout() { final eventProvider = Provider.of(context); return Row( children: [ // Calendrier (65% de la largeur) Expanded( flex: 65, child: _buildCalendar(), ), // Détails de l'événement (35% de la largeur) Expanded( flex: 35, child: _selectedEvent != null ? EventDetails( event: _selectedEvent!, selectedDate: _selectedDay, events: eventProvider.events, onSelectEvent: (event, date) { setState(() { _selectedEvent = event; _selectedDay = date; }); }, ) : Center( child: _selectedDay != null ? Text('Aucun événement ne démarre à cette date') : const Text( 'Sélectionnez un événement pour voir les détails'), ), ), ], ); } Widget _buildMobileLayout() { final eventProvider = Provider.of(context); final eventsForSelectedDay = _selectedDay == null ? [] : eventProvider.events .where((e) => e.startDateTime.year == _selectedDay!.year && e.startDateTime.month == _selectedDay!.month && e.startDateTime.day == _selectedDay!.day) .toList() ..sort((a, b) => a.startDateTime.compareTo(b.startDateTime)); final hasEvents = eventsForSelectedDay.isNotEmpty; final currentEvent = hasEvents && _selectedEventIndex < eventsForSelectedDay.length ? eventsForSelectedDay[_selectedEventIndex] : null; return Stack( children: [ // Calendrier + détails en dessous AnimatedPositioned( duration: const Duration(milliseconds: 400), curve: Curves.easeInOut, top: _calendarCollapsed ? -600 : 0, // cache le calendrier en haut left: 0, right: 0, height: _calendarCollapsed ? 0 : null, child: Container( height: MediaQuery.of(context).size.height, child: Column( children: [ _buildMonthHeader(context), if (!_calendarCollapsed) MobileCalendarView( focusedDay: _focusedDay, selectedDay: _selectedDay, events: eventProvider.events, onDaySelected: (day) { final eventsForDay = eventProvider.events .where((e) => e.startDateTime.year == day.year && e.startDateTime.month == day.month && e.startDateTime.day == day.day) .toList() ..sort((a, b) => a.startDateTime.compareTo(b.startDateTime)); setState(() { _selectedDay = day; _calendarCollapsed = false; _selectedEventIndex = 0; _selectedEvent = eventsForDay.isNotEmpty ? eventsForDay[0] : null; }); }, ), Expanded( child: hasEvents ? EventDetails( event: eventsForSelectedDay[_selectedEventIndex], selectedDate: _selectedDay, events: eventsForSelectedDay.cast(), onSelectEvent: (event, date) { final idx = eventsForSelectedDay .indexWhere((e) => e.id == event.id); setState(() { _selectedEventIndex = idx >= 0 ? idx : 0; _selectedEvent = event; }); }, ) : Center( child: Text('Aucun événement ne démarre à cette date')), ), ], ), ), ), // Vue détail (prend tout l'espace quand calendrier caché) if (_calendarCollapsed && _selectedDay != null) AnimatedPositioned( duration: const Duration(milliseconds: 400), curve: Curves.easeInOut, top: _calendarCollapsed ? 0 : 600, left: 0, right: 0, bottom: 0, child: Container( height: MediaQuery.of(context).size.height, child: Column( children: [ _buildMonthHeader(context), Expanded( child: Stack( children: [ if (currentEvent != null) EventDetails( event: currentEvent, selectedDate: _selectedDay, events: eventsForSelectedDay.cast(), onSelectEvent: (event, date) { final idx = eventsForSelectedDay .indexWhere((e) => e.id == event.id); setState(() { _selectedEventIndex = idx >= 0 ? idx : 0; _selectedEvent = event; }); }, ), if (!hasEvents) Center( child: Text('Aucun événement ne démarre à cette date'), ), ], ), ), ], ), ), ), ], ); } Widget _buildMonthHeader(BuildContext context) { return Padding( padding: const EdgeInsets.only(top: 8, bottom: 8), child: Row( children: [ IconButton( icon: const Icon(Icons.chevron_left, color: AppColors.rouge, size: 28), onPressed: () { setState(() { _focusedDay = DateTime(_focusedDay.year, _focusedDay.month - 1, 1); }); }, ), Expanded( child: GestureDetector( onTap: () { setState(() { _calendarCollapsed = !_calendarCollapsed; }); }, child: Row( mainAxisAlignment: MainAxisAlignment.center, mainAxisSize: MainAxisSize.min, children: [ Text( _getMonthName(_focusedDay.month), style: const TextStyle( color: AppColors.rouge, fontWeight: FontWeight.bold, fontSize: 20, ), ), const SizedBox(width: 6), Icon( _calendarCollapsed ? Icons.keyboard_arrow_down : Icons.keyboard_arrow_up, color: AppColors.rouge, size: 26, ), ], ), ), ), IconButton( icon: const Icon(Icons.chevron_right, color: AppColors.rouge, size: 28), onPressed: () { setState(() { _focusedDay = DateTime(_focusedDay.year, _focusedDay.month + 1, 1); }); }, ), ], ), ); } String _getMonthName(int month) { switch (month) { case 1: return 'Janvier'; case 2: return 'Février'; case 3: return 'Mars'; case 4: return 'Avril'; case 5: return 'Mai'; case 6: return 'Juin'; case 7: return 'Juillet'; case 8: return 'Août'; case 9: return 'Septembre'; case 10: return 'Octobre'; case 11: return 'Novembre'; case 12: return 'Décembre'; default: return ''; } } Widget _buildCalendar() { final eventProvider = Provider.of(context); if (_calendarFormat == CalendarFormat.week) { return WeekView( focusedDay: _focusedDay, events: eventProvider.events, onWeekChange: _changeWeek, onEventSelected: (event) { setState(() { _selectedEvent = event; _selectedDay = event.startDateTime; }); }, onSwitchToMonth: () { setState(() { _calendarFormat = CalendarFormat.month; }); }, onDaySelected: (selectedDay) { final eventsForDay = eventProvider.events .where((e) => e.startDateTime.year == selectedDay.year && e.startDateTime.month == selectedDay.month && e.startDateTime.day == selectedDay.day) .toList(); eventsForDay .sort((a, b) => a.startDateTime.compareTo(b.startDateTime)); setState(() { _selectedDay = selectedDay; if (eventsForDay.isNotEmpty) { _selectedEvent = eventsForDay.first; } else { _selectedEvent = null; } }); if (eventsForDay.isEmpty) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar( content: Text("Aucun événement ne démarre à cette date."), duration: Duration(seconds: 2), ), ); } }, selectedEvent: _selectedEvent, ); } else { return MonthView( focusedDay: _focusedDay, selectedDay: _selectedDay, calendarFormat: _calendarFormat, events: eventProvider.events, onDaySelected: (selectedDay, focusedDay) { final eventsForDay = eventProvider.events .where((event) => event.startDateTime.year == selectedDay.year && event.startDateTime.month == selectedDay.month && event.startDateTime.day == selectedDay.day) .toList() ..sort((a, b) => a.startDateTime.compareTo(b.startDateTime)); setState(() { _selectedDay = selectedDay; _focusedDay = focusedDay; if (eventsForDay.isNotEmpty) { _selectedEvent = eventsForDay.first; } else { _selectedEvent = null; } }); }, onFormatChanged: (format) { setState(() { _calendarFormat = format; }); }, onPageChanged: (focusedDay) { setState(() { _focusedDay = focusedDay; }); }, onEventSelected: (event) { setState(() { _selectedEvent = event; }); }, ); } } }