refactoring and checkpoint

This commit is contained in:
DahoudG
2024-09-24 00:32:20 +00:00
parent dc73ba7dcc
commit 6b12cfeb41
159 changed files with 8119 additions and 1535 deletions

View File

@@ -1,429 +1,172 @@
import 'package:flutter/material.dart';
import 'package:afterwork/data/datasources/event_remote_data_source.dart';
import '../../../core/utils/date_formatter.dart';
import 'package:afterwork/data/models/event_model.dart';
import 'package:afterwork/core/utils/date_formatter.dart'; // Importer DateFormatter
/// Widget pour afficher une carte d'événement.
/// Cette classe est utilisée pour afficher les détails d'un événement,
/// incluant son titre, sa description, son image, et des actions possibles
/// telles que réagir, commenter, partager, participer, et fermer ou rouvrir l'événement.
class EventCard extends StatelessWidget {
// Identifiant unique de l'événement
final String eventId;
// Source de données distante pour les opérations sur l'événement
final EventRemoteDataSource eventRemoteDataSource;
// Identifiant de l'utilisateur
final EventModel event;
final String userId;
// Nom de l'utilisateur
final String userName;
// Prénom de l'utilisateur
final String userLastName;
// URL de l'image de profil de l'utilisateur
final String profileImage;
// Nom complet de l'utilisateur (nom + prénom)
final String name;
// Date de publication de l'événement
final String datePosted;
// Titre de l'événement
final String eventTitle;
// Description de l'événement
final String eventDescription;
// URL de l'image de l'événement
final String eventImageUrl;
// Statut de l'événement (e.g., "OPEN", "CLOSED")
final String eventStatus;
// Catégorie de l'événement
final String eventCategory;
// Nombre de réactions à l'événement
final int reactionsCount;
// Nombre de commentaires sur l'événement
final int commentsCount;
// Nombre de partages de l'événement
final int sharesCount;
// Callback pour l'action "Réagir"
final VoidCallback onReact;
// Callback pour l'action "Commenter"
final VoidCallback onComment;
// Callback pour l'action "Partager"
final VoidCallback onShare;
// Callback pour l'action "Participer"
final VoidCallback onParticipate;
// Callback pour afficher plus d'options
final VoidCallback onMoreOptions;
// Callback pour fermer l'événement
final VoidCallback onCloseEvent;
// Callback pour rouvrir l'événement
final VoidCallback onReopenEvent;
const EventCard({
Key? key,
required this.eventId,
required this.eventRemoteDataSource,
required this.event,
required this.userId,
required this.userName,
required this.userLastName,
required this.profileImage,
required this.name,
required this.datePosted,
required this.eventTitle,
required this.eventDescription,
required this.eventImageUrl,
required this.eventStatus,
required this.eventCategory,
required this.reactionsCount,
required this.commentsCount,
required this.sharesCount,
required this.onReact,
required this.onComment,
required this.onShare,
required this.onParticipate,
required this.onMoreOptions,
required this.onCloseEvent,
required this.onReopenEvent,
}) : super(key: key);
@override
Widget build(BuildContext context) {
// Log du rendu de la carte d'événement
print('Rendu de l\'EventCard pour l\'événement $eventId avec statut $eventStatus');
return AnimatedOpacity(
opacity: 1.0,
duration: const Duration(milliseconds: 300),
child: Dismissible(
key: ValueKey(eventId),
direction: eventStatus == 'CLOSED'
? DismissDirection.endToStart // Permet de rouvrir avec un swipe à gauche
: DismissDirection.startToEnd, // Permet de fermer avec un swipe à droite
onDismissed: (direction) {
if (direction == DismissDirection.startToEnd) {
// Log du déclenchement de la fermeture de l'événement
print('Tentative de fermeture de l\'événement $eventId');
onCloseEvent();
} else if (direction == DismissDirection.endToStart && eventStatus == 'CLOSED') {
// Log du déclenchement de la réouverture de l'événement
print('Tentative de réouverture de l\'événement $eventId');
onReopenEvent();
}
},
background: Container(
color: Colors.red,
alignment: Alignment.centerLeft,
padding: const EdgeInsets.only(left: 20.0),
child: const Icon(Icons.delete, color: Colors.white),
),
secondaryBackground: Container(
color: Colors.green,
alignment: Alignment.centerRight,
padding: const EdgeInsets.only(right: 20.0),
child: const Icon(Icons.replay, color: Colors.white),
),
child: Stack(
return Card(
color: const Color(0xFF2C2C3E),
margin: const EdgeInsets.symmetric(vertical: 10.0),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(15.0)),
child: Padding(
padding: const EdgeInsets.all(12.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Card(
color: const Color(0xFF2C2C3E),
margin: const EdgeInsets.symmetric(vertical: 10.0),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15.0),
),
child: Padding(
padding: const EdgeInsets.all(12.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildHeader(context),
const SizedBox(height: 10),
_buildEventCategory(),
const SizedBox(height: 5),
_buildEventDetails(),
const SizedBox(height: 10),
_buildEventImage(),
const SizedBox(height: 10),
Divider(color: Colors.white.withOpacity(0.2)),
_buildInteractionRow(),
const SizedBox(height: 5),
_buildParticipateButton(),
],
),
),
_buildHeader(),
const SizedBox(height: 10),
Text(
event.title,
style: const TextStyle(color: Colors.white, fontSize: 18, fontWeight: FontWeight.bold),
),
const SizedBox(height: 5),
Text(
event.description,
style: const TextStyle(color: Colors.white70, fontSize: 14),
maxLines: 3,
overflow: TextOverflow.ellipsis,
),
const SizedBox(height: 10),
_buildEventImage(),
const Divider(color: Colors.white24),
_buildInteractionRow(),
const SizedBox(height: 10),
_buildStatusAndActions(),
],
),
),
);
}
/// Construire l'en-tête de la carte avec les informations de l'utilisateur.
/// Cette méthode affiche l'image de profil, le nom de l'utilisateur, la date
/// de publication de l'événement, et le statut de l'événement.
Widget _buildHeader(BuildContext context) {
// Log du rendu de l'en-tête de la carte
print('Rendu de l\'en-tête pour l\'événement $eventId');
// Convertir la date `datePosted` en DateTime si ce n'est pas déjà fait
DateTime dateTimePosted = DateTime.parse(datePosted);
Widget _buildHeader() {
// Convertir la date de l'événement (de String à DateTime)
DateTime? eventDate;
try {
eventDate = DateTime.parse(event.startDate);
} catch (e) {
eventDate = null; // Gérer le cas où la date ne serait pas valide
}
// Utiliser le DateFormatter pour formater la date
String formattedDate = DateFormatter.formatDate(dateTimePosted);
// Utiliser DateFormatter pour afficher une date lisible si elle est valide
String formattedDate = eventDate != null ? DateFormatter.formatDate(eventDate) : 'Date inconnue';
return Row(
children: [
CircleAvatar(
backgroundImage: AssetImage(profileImage),
radius: 25,
),
CircleAvatar(backgroundImage: NetworkImage(event.imageUrl ?? 'lib/assets/images/placeholder.png')),
const SizedBox(width: 10),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
name,
style: const TextStyle(
color: Colors.white,
fontSize: 16,
fontWeight: FontWeight.bold,
),
),
Row(
children: [
Text(
formattedDate,
style: const TextStyle(color: Colors.white70, fontSize: 14),
),
const SizedBox(width: 10),
_buildStatusBadge(), // Badge de statut aligné sur la même ligne que la date du post
],
),
],
),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'$userName $userLastName',
style: const TextStyle(color: Colors.white, fontSize: 16, fontWeight: FontWeight.bold),
),
const SizedBox(height: 5),
Text(
formattedDate, // Utiliser la date formatée ici
style: const TextStyle(color: Colors.white70, fontSize: 14),
),
],
),
const Spacer(),
IconButton(
icon: const Icon(Icons.more_vert, color: Colors.white),
onPressed: () {
// Log du déclenchement du bouton "Plus d'options"
print('Plus d\'options déclenché pour l\'événement $eventId');
onMoreOptions();
// Logique d'affichage d'options supplémentaires pour l'événement.
// Vous pouvez utiliser un menu déroulant ou une boîte de dialogue ici.
},
),
if (eventStatus != 'CLOSED') // Masquer le bouton de fermeture si l'événement est fermé
IconButton(
icon: const Icon(Icons.close, color: Colors.white),
onPressed: () {
// Log du déclenchement du bouton de fermeture de l'événement
print('Tentative de fermeture de l\'événement $eventId');
onCloseEvent();
},
),
],
);
}
/// Afficher la catégorie de l'événement au-dessus du titre.
/// Cette méthode affiche la catégorie en italique pour distinguer le type d'événement.
Widget _buildEventCategory() {
// Log du rendu de la catégorie de l'événement
print('Affichage de la catégorie pour l\'événement $eventId: $eventCategory');
return Text(
eventCategory,
style: const TextStyle(
color: Colors.blueAccent,
fontSize: 14,
fontStyle: FontStyle.italic, // Style en italique
fontWeight: FontWeight.w400, // Titre fin
),
);
}
/// Afficher les détails de l'événement.
/// Cette méthode affiche le titre et la description de l'événement.
Widget _buildEventDetails() {
// Log du rendu des détails de l'événement
print('Affichage des détails pour l\'événement $eventId');
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
eventTitle,
style: const TextStyle(
color: Colors.white,
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 5),
Text(
eventDescription,
style: const TextStyle(color: Colors.white70, fontSize: 14),
),
],
);
}
/// Afficher l'image de l'événement.
/// Cette méthode affiche l'image associée à l'événement.
Widget _buildEventImage() {
// Log du rendu de l'image de l'événement
print('Affichage de l\'image pour l\'événement $eventId');
return ClipRRect(
borderRadius: BorderRadius.circular(10.0),
child: Image.network(
eventImageUrl,
height: 180,
width: double.infinity,
fit: BoxFit.cover,
errorBuilder: (context, error, stackTrace) {
// Log de l'erreur lors du chargement de l'image
print('Erreur de chargement de l\'image pour l\'événement $eventId: $error');
return Image.asset(
'lib/assets/images/placeholder.png',
height: 180,
width: double.infinity,
fit: BoxFit.cover,
);
},
event.imageUrl ?? 'lib/assets/images/placeholder.png',
height: 180,
width: double.infinity,
fit: BoxFit.cover,
errorBuilder: (context, error, stackTrace) {
return Image.asset('lib/assets/images/placeholder.png'); // Image par défaut si erreur de chargement
}
),
);
}
/// Afficher les icônes d'interaction (réagir, commenter, partager).
/// Cette méthode affiche les boutons pour réagir, commenter, et partager l'événement.
Widget _buildInteractionRow() {
// Log du rendu de la ligne d'interaction de l'événement
print('Affichage des interactions pour l\'événement $eventId');
return Padding(
padding: const EdgeInsets.symmetric(vertical: 4.0), // Réduire le padding vertical
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround, // Utiliser spaceAround pour réduire l'espace
children: [
Expanded(
child: _buildIconButton(
icon: Icons.thumb_up_alt_outlined,
label: 'Réagir',
count: reactionsCount,
onPressed: () {
// Log de l'action "Réagir"
print('Réaction à l\'événement $eventId');
onReact();
},
),
),
Expanded(
child: _buildIconButton(
icon: Icons.comment_outlined,
label: 'Commenter',
count: commentsCount,
onPressed: () {
// Log de l'action "Commenter"
print('Commentaire sur l\'événement $eventId');
onComment();
},
),
),
Expanded(
child: _buildIconButton(
icon: Icons.share_outlined,
label: 'Partager',
count: sharesCount,
onPressed: () {
// Log de l'action "Partager"
print('Partage de l\'événement $eventId');
onShare();
},
),
),
],
),
return Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
_buildIconButton(Icons.thumb_up_alt_outlined, 'Réagir', event.reactionsCount, onReact),
_buildIconButton(Icons.comment_outlined, 'Commenter', event.commentsCount, onComment),
_buildIconButton(Icons.share_outlined, 'Partager', event.sharesCount, onShare),
],
);
}
/// Bouton d'interaction personnalisé.
/// Cette méthode construit un bouton avec une icône et un label pour l'interaction.
Widget _buildIconButton({
required IconData icon,
required String label,
required int count,
required VoidCallback onPressed,
}) {
// Log de la construction du bouton d'interaction
print('Construction du bouton $label pour l\'événement $eventId');
Widget _buildIconButton(IconData icon, String label, int count, VoidCallback onPressed) {
return TextButton.icon(
onPressed: onPressed,
icon: Icon(icon, color: const Color(0xFF1DBF73), size: 20),
label: Text(
'$label ($count)',
style: const TextStyle(color: Colors.white70, fontSize: 12),
overflow: TextOverflow.ellipsis,
),
);
}
/// Bouton pour participer à l'événement.
/// Cette méthode construit un bouton qui permet de participer à l'événement.
/// Si l'événement est fermé, le bouton est caché.
Widget _buildParticipateButton() {
// Log de la construction du bouton "Participer"
print('Construction du bouton "Participer" pour l\'événement $eventId avec statut $eventStatus');
// Si l'événement est fermé, ne rien retourner (pas de bouton)
if (eventStatus == 'CLOSED') {
print('L\'événement $eventId est fermé, le bouton "Participer" est caché.');
return SizedBox.shrink(); // Retourne un widget vide pour ne pas occuper d'espace
}
// Sinon, retourner le bouton "Participer"
return ElevatedButton(
onPressed: onParticipate,
style: ElevatedButton.styleFrom(
backgroundColor: const Color(0xFF1DBF73),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8.0),
// Widget pour afficher le statut de l'événement et les actions associées (fermer, réouvrir)
Widget _buildStatusAndActions() {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
event.status == 'closed' ? 'Événement fermé' : 'Événement ouvert',
style: TextStyle(
color: event.status == 'closed' ? Colors.red : Colors.green,
fontSize: 14,
fontWeight: FontWeight.bold,
),
),
padding: const EdgeInsets.symmetric(vertical: 12.0),
minimumSize: const Size(double.infinity, 40),
),
child: const Text(
'Participer',
style: TextStyle(color: Colors.white),
),
);
}
/// Construire un badge pour afficher le statut de l'événement.
/// Cette méthode affiche un badge avec le statut de l'événement ("OPEN" ou "CLOSED").
Widget _buildStatusBadge() {
// Log de la construction du badge de statut
print('Construction du badge de statut pour l\'événement $eventId: $eventStatus');
Color badgeColor;
switch (eventStatus) {
case 'CLOSED':
badgeColor = Colors.redAccent;
break;
case 'OPEN':
default:
badgeColor = Colors.greenAccent;
break;
}
return Container(
padding: const EdgeInsets.symmetric(horizontal: 8.0, vertical: 4.0),
decoration: BoxDecoration(
color: badgeColor.withOpacity(0.7),
borderRadius: BorderRadius.circular(8.0),
),
child: Text(
eventStatus.toUpperCase(),
style: const TextStyle(
color: Colors.white,
fontSize: 10, // Réduction de la taille du texte
fontWeight: FontWeight.bold,
event.status == 'closed'
? ElevatedButton(
onPressed: onReopenEvent,
child: const Text('Rouvrir l\'événement'),
)
: ElevatedButton(
onPressed: onCloseEvent,
child: const Text('Fermer l\'événement'),
),
),
],
);
}
}

View File

@@ -1,19 +1,17 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:afterwork/data/models/event_model.dart';
import 'package:afterwork/data/datasources/event_remote_data_source.dart';
import 'event_card.dart';
import 'package:afterwork/presentation/screens/event/event_card.dart';
import '../../state_management/event_bloc.dart';
import '../dialogs/add_event_dialog.dart';
/// Écran principal pour afficher les événements.
class EventScreen extends StatefulWidget {
final EventRemoteDataSource eventRemoteDataSource;
final String userId;
final String userName; // Nom de l'utilisateur
final String userLastName; // Prénom de l'utilisateur
final String userName;
final String userLastName;
const EventScreen({
Key? key,
required this.eventRemoteDataSource,
required this.userId,
required this.userName,
required this.userLastName,
@@ -24,13 +22,11 @@ class EventScreen extends StatefulWidget {
}
class _EventScreenState extends State<EventScreen> {
late Future<List<EventModel>> _eventsFuture;
@override
void initState() {
super.initState();
// Récupérer la liste des événements à partir de la source de données distante
_eventsFuture = widget.eventRemoteDataSource.getAllEvents();
// Charger les événements lors de l'initialisation
context.read<EventBloc>().add(LoadEvents(widget.userId));
}
@override
@@ -60,161 +56,98 @@ class _EventScreenState extends State<EventScreen> {
);
if (eventData != null) {
try {
print('Tentative de création d\'un nouvel événement par l\'utilisateur ${widget.userId}');
await widget.eventRemoteDataSource.createEvent(eventData as EventModel);
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Événement ajouté avec succès !')),
);
// Réactualiser la liste des événements après création
setState(() {
_eventsFuture = widget.eventRemoteDataSource.getAllEvents();
});
} catch (e) {
print('Erreur lors de la création de l\'événement: $e');
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Erreur : $e')),
);
}
// Ajouter l'événement en appelant l'API via le bloc
context.read<EventBloc>().add(AddEvent(EventModel.fromJson(eventData)));
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Événement ajouté avec succès !')),
);
}
},
),
],
),
body: FutureBuilder<List<EventModel>>(
future: _eventsFuture,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
body: BlocBuilder<EventBloc, EventState>(
builder: (context, state) {
if (state is EventLoading) {
return const Center(child: CircularProgressIndicator());
} else if (snapshot.hasError) {
print('Erreur lors de la récupération des événements: ${snapshot.error}');
return Center(child: Text('Erreur: ${snapshot.error}'));
} else if (!snapshot.hasData || snapshot.data!.isEmpty) {
return const Center(child: Text('Aucun événement trouvé.'));
} else if (state is EventLoaded) {
final events = state.events;
if (events.isEmpty) {
return const Center(child: Text('Aucun événement disponible.'));
}
return ListView.builder(
padding: const EdgeInsets.all(16.0),
itemCount: events.length,
itemBuilder: (context, index) {
final event = events[index];
return EventCard(
key: ValueKey(event.id),
event: event,
userId: widget.userId,
userName: widget.userName,
userLastName: widget.userLastName,
onReact: () => _onReact(event.id),
onComment: () => _onComment(event.id),
onShare: () => _onShare(event.id),
onParticipate: () => _onParticipate(event.id),
onCloseEvent: () => _onCloseEvent(event.id),
onReopenEvent: () => _onReopenEvent(event.id),
);
},
);
} else if (state is EventError) {
return Center(child: Text('Erreur: ${state.message}'));
}
final events = snapshot.data!;
print('Nombre d\'événements récupérés: ${events.length}');
return ListView.builder(
padding: const EdgeInsets.all(16.0),
itemCount: events.length,
itemBuilder: (context, index) {
final event = events[index];
print('Affichage de l\'événement ${event.id}');
return EventCard(
key: ValueKey(event.id),
eventRemoteDataSource: widget.eventRemoteDataSource,
userId: widget.userId,
eventId: event.id,
userName: widget.userName,
userLastName: widget.userLastName,
profileImage: 'lib/assets/images/profile_picture.png',
name: '${widget.userName} ${widget.userLastName}',
eventCategory: event.category,
datePosted: event.date,
eventTitle: event.title,
eventDescription: event.description,
eventImageUrl: event.imageUrl ?? 'lib/assets/images/placeholder.png',
eventStatus: event.status,
reactionsCount: 120, // Exemple de valeur
commentsCount: 45, // Exemple de valeur
sharesCount: 30, // Exemple de valeur
onReact: () {
print('Réaction à l\'événement ${event.id}');
},
onComment: () {
print('Commentaire sur l\'événement ${event.id}');
},
onShare: () {
print('Partage de l\'événement ${event.id}');
},
onParticipate: () {
print('Participation à l\'événement ${event.id}');
},
onCloseEvent: () => _onCloseEvent(context, event.id, index),
onMoreOptions: () {
print('Affichage des options pour l\'événement ${event.id}');
},
onReopenEvent: () => _onReopenEvent(context, event.id, index),
);
},
);
return const Center(child: Text('Aucun événement disponible.'));
},
),
backgroundColor: const Color(0xFF1E1E2C),
floatingActionButton: FloatingActionButton(
onPressed: () {
// Recharger les événements
context.read<EventBloc>().add(LoadEvents(widget.userId));
},
backgroundColor: const Color(0xFF1DBF73),
child: const Icon(Icons.refresh),
),
);
}
/// Logique pour fermer un événement
void _onCloseEvent(BuildContext context, String eventId, int index) async {
try {
print('Tentative de fermeture de l\'événement $eventId');
// Appeler l'API pour fermer l'événement
await widget.eventRemoteDataSource.closeEvent(eventId);
print('Événement fermé avec succès');
// Montrer un message de succès AVANT de supprimer l'événement de la liste
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('L\'événement a été fermé avec succès.')),
);
// Supprimez l'événement de la liste après avoir affiché le SnackBar
setState(() {
_eventsFuture = _eventsFuture.then((events) {
events.removeAt(index);
return events;
});
});
} catch (e) {
print('Erreur lors de la fermeture de l\'événement: $e');
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Erreur lors de la fermeture de l\'événement : $e')),
);
}
void _onReact(String eventId) {
print('Réaction à l\'événement $eventId');
// Implémentez la logique pour réagir à un événement ici
}
/// Logique pour rouvrir un événement
void _onReopenEvent(BuildContext context, String eventId, int index) async {
try {
print('Tentative de réouverture de l\'événement $eventId');
await widget.eventRemoteDataSource.reopenEvent(eventId);
print('Événement rouvert avec succès');
void _onComment(String eventId) {
print('Commentaire sur l\'événement $eventId');
// Implémentez la logique pour commenter un événement ici
}
// Montrer un message de succès
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('L\'événement a été rouvert avec succès.')),
);
void _onShare(String eventId) {
print('Partage de l\'événement $eventId');
// Implémentez la logique pour partager un événement ici
}
// Mettre à jour le statut de l'événement dans la liste des événements
setState(() {
_eventsFuture = _eventsFuture.then((events) {
final updatedEvent = EventModel(
id: events[index].id,
title: events[index].title,
description: events[index].description,
date: events[index].date,
location: events[index].location,
category: events[index].category,
link: events[index].link,
imageUrl: events[index].imageUrl,
creator: events[index].creator,
participants: events[index].participants,
status: 'OPEN', // Mettre à jour le statut à 'OPEN'
);
void _onParticipate(String eventId) {
print('Participation à l\'événement $eventId');
// Implémentez la logique pour participer à un événement ici
}
// Remplacer l'événement dans la liste
events[index] = updatedEvent;
return events;
});
});
} catch (e) {
print('Erreur lors de la réouverture de l\'événement: $e');
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Erreur lors de la réouverture de l\'événement : $e')),
);
}
void _onCloseEvent(String eventId) {
print('Fermeture de l\'événement $eventId');
// Appeler le bloc pour fermer l'événement
context.read<EventBloc>().add(CloseEvent(eventId));
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('L\'événement a été fermé avec succès.')),
);
}
void _onReopenEvent(String eventId) {
print('Réouverture de l\'événement $eventId');
// Appeler le bloc pour rouvrir l'événement
context.read<EventBloc>().add(ReopenEvent(eventId));
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('L\'événement a été rouvert avec succès.')),
);
}
}