/// Page de détails d'un événement library event_detail_page; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import '../../bloc/evenements_bloc.dart'; import '../../bloc/evenements_state.dart'; import '../../data/models/evenement_model.dart'; import '../widgets/inscription_event_dialog.dart'; import '../widgets/edit_event_dialog.dart'; class EventDetailPage extends StatelessWidget { final EvenementModel evenement; const EventDetailPage({ super.key, required this.evenement, }); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Détails de l\'événement'), backgroundColor: const Color(0xFF3B82F6), foregroundColor: Colors.white, actions: [ IconButton( icon: const Icon(Icons.edit), onPressed: () => _showEditDialog(context), ), ], ), body: BlocBuilder( builder: (context, state) { return SingleChildScrollView( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ _buildHeader(), _buildInfoSection(), _buildDescriptionSection(), if (evenement.lieu != null) _buildLocationSection(), _buildParticipantsSection(), const SizedBox(height: 80), // Espace pour le bouton flottant ], ), ); }, ), floatingActionButton: _buildInscriptionButton(context), ); } Widget _buildHeader() { return Container( width: double.infinity, padding: const EdgeInsets.all(24), decoration: BoxDecoration( gradient: LinearGradient( colors: [ const Color(0xFF3B82F6), const Color(0xFF3B82F6).withOpacity(0.8), ], begin: Alignment.topLeft, end: Alignment.bottomRight, ), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Container( padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6), decoration: BoxDecoration( color: Colors.white.withOpacity(0.2), borderRadius: BorderRadius.circular(20), ), child: Text( _getTypeLabel(evenement.type), style: const TextStyle( color: Colors.white, fontSize: 12, fontWeight: FontWeight.bold, ), ), ), const SizedBox(height: 12), Text( evenement.titre, style: const TextStyle( color: Colors.white, fontSize: 24, fontWeight: FontWeight.bold, ), ), const SizedBox(height: 8), Row( children: [ Container( padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), decoration: BoxDecoration( color: _getStatutColor(evenement.statut), borderRadius: BorderRadius.circular(4), ), child: Text( _getStatutLabel(evenement.statut), style: const TextStyle( color: Colors.white, fontSize: 12, fontWeight: FontWeight.bold, ), ), ), ], ), ], ), ); } Widget _buildInfoSection() { return Container( padding: const EdgeInsets.all(16), child: Column( children: [ _buildInfoRow( Icons.calendar_today, 'Date de début', _formatDate(evenement.dateDebut), ), const Divider(), _buildInfoRow( Icons.event, 'Date de fin', _formatDate(evenement.dateFin), ), if (evenement.maxParticipants != null) ...[ const Divider(), _buildInfoRow( Icons.people, 'Places', '${evenement.participantsActuels} / ${evenement.maxParticipants}', ), ], if (evenement.organisateurNom != null) ...[ const Divider(), _buildInfoRow( Icons.person, 'Organisateur', evenement.organisateurNom!, ), ], ], ), ); } Widget _buildInfoRow(IconData icon, String label, String value) { return Padding( padding: const EdgeInsets.symmetric(vertical: 8), child: Row( children: [ Icon(icon, color: const Color(0xFF3B82F6), size: 20), const SizedBox(width: 12), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( label, style: TextStyle( fontSize: 12, color: Colors.grey[600], ), ), const SizedBox(height: 2), Text( value, style: const TextStyle( fontSize: 16, fontWeight: FontWeight.w500, ), ), ], ), ), ], ), ); } Widget _buildDescriptionSection() { if (evenement.description == null) return const SizedBox.shrink(); return Container( padding: const EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text( 'Description', style: TextStyle( fontSize: 18, fontWeight: FontWeight.bold, ), ), const SizedBox(height: 8), Text( evenement.description!, style: const TextStyle(fontSize: 14, height: 1.5), ), ], ), ); } Widget _buildLocationSection() { return Container( padding: const EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text( 'Lieu', style: TextStyle( fontSize: 18, fontWeight: FontWeight.bold, ), ), const SizedBox(height: 8), Row( children: [ const Icon(Icons.location_on, color: Color(0xFF3B82F6)), const SizedBox(width: 8), Expanded( child: Text( evenement.lieu!, style: const TextStyle(fontSize: 14), ), ), ], ), ], ), ); } Widget _buildParticipantsSection() { return Container( padding: const EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ const Text( 'Participants', style: TextStyle( fontSize: 18, fontWeight: FontWeight.bold, ), ), Text( '${evenement.participantsActuels} inscrits', style: TextStyle( fontSize: 14, color: Colors.grey[600], ), ), ], ), const SizedBox(height: 12), Container( padding: const EdgeInsets.all(12), decoration: BoxDecoration( color: Colors.grey[100], borderRadius: BorderRadius.circular(8), ), child: const Row( children: [ Icon(Icons.info_outline, size: 20), SizedBox(width: 8), Expanded( child: Text( 'La liste des participants est visible uniquement pour les organisateurs', style: TextStyle(fontSize: 12), ), ), ], ), ), ], ), ); } Widget _buildInscriptionButton(BuildContext context) { const isInscrit = false; // TODO: Vérifier si l'utilisateur est inscrit final placesRestantes = (evenement.maxParticipants ?? 0) - evenement.participantsActuels; final isComplet = placesRestantes <= 0 && evenement.maxParticipants != null; if (!isComplet) { return FloatingActionButton.extended( onPressed: () => _showInscriptionDialog(context, isInscrit), backgroundColor: const Color(0xFF3B82F6), icon: const Icon(Icons.check), label: const Text('S\'inscrire'), ); } else { return const FloatingActionButton.extended( onPressed: null, backgroundColor: Colors.grey, icon: Icon(Icons.block), label: Text('Complet'), ); } } void _showInscriptionDialog(BuildContext context, bool isInscrit) { showDialog( context: context, builder: (context) => BlocProvider.value( value: context.read(), child: InscriptionEventDialog( evenement: evenement, isInscrit: isInscrit, ), ), ); } void _showEditDialog(BuildContext context) { showDialog( context: context, builder: (context) => BlocProvider.value( value: context.read(), child: EditEventDialog(evenement: evenement), ), ); } String _formatDate(DateTime date) { final months = [ 'janvier', 'février', 'mars', 'avril', 'mai', 'juin', 'juillet', 'août', 'septembre', 'octobre', 'novembre', 'décembre' ]; return '${date.day} ${months[date.month - 1]} ${date.year} à ${date.hour}:${date.minute.toString().padLeft(2, '0')}'; } String _getTypeLabel(TypeEvenement type) { switch (type) { case TypeEvenement.assembleeGenerale: return 'Assemblée Générale'; case TypeEvenement.reunion: return 'Réunion'; case TypeEvenement.formation: return 'Formation'; case TypeEvenement.conference: return 'Conférence'; case TypeEvenement.atelier: return 'Atelier'; case TypeEvenement.seminaire: return 'Séminaire'; case TypeEvenement.evenementSocial: return 'Événement Social'; case TypeEvenement.manifestation: return 'Manifestation'; case TypeEvenement.celebration: return 'Célébration'; case TypeEvenement.autre: return 'Autre'; } } String _getStatutLabel(StatutEvenement statut) { switch (statut) { case StatutEvenement.planifie: return 'Planifié'; case StatutEvenement.confirme: return 'Confirmé'; case StatutEvenement.enCours: return 'En cours'; case StatutEvenement.termine: return 'Terminé'; case StatutEvenement.annule: return 'Annulé'; case StatutEvenement.reporte: return 'Reporté'; } } Color _getStatutColor(StatutEvenement statut) { switch (statut) { case StatutEvenement.planifie: return Colors.blue; case StatutEvenement.confirme: return Colors.green; case StatutEvenement.enCours: return Colors.orange; case StatutEvenement.termine: return Colors.grey; case StatutEvenement.annule: return Colors.red; case StatutEvenement.reporte: return Colors.purple; } } }