import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import '../../bloc/dashboard_bloc.dart'; import '../../../domain/entities/dashboard_entity.dart'; import '../../../../../shared/design_system/unionflow_design_system.dart'; import '../../../../../shared/widgets/core_card.dart'; /// Widget des événements à venir connecté au backend class ConnectedUpcomingEvents extends StatelessWidget { final int maxItems; final VoidCallback? onSeeAll; const ConnectedUpcomingEvents({ super.key, this.maxItems = 3, this.onSeeAll, }); @override Widget build(BuildContext context) { return CoreCard( padding: const EdgeInsets.all(10), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ _buildHeader(), const SizedBox(height: 8), BlocBuilder( builder: (ctx, state) { if (state is DashboardLoading) { return _buildLoadingList(); } else if (state is DashboardLoaded || state is DashboardRefreshing) { final data = state is DashboardLoaded ? state.dashboardData : (state as DashboardRefreshing).dashboardData; return _buildEventsList(context, data.upcomingEvents); } else if (state is DashboardError) { return _buildErrorState(state.message); } return _buildEmptyState(); }, ), ], ), ); } Widget _buildHeader() { return Row( children: [ const Icon( Icons.event_outlined, color: AppColors.primaryGreen, size: 18, ), const SizedBox(width: 8), Expanded( child: Text( 'ÉVÉNEMENTS À VENIR', style: AppTypography.subtitleSmall.copyWith(fontWeight: FontWeight.bold, letterSpacing: 1.1), ), ), if (onSeeAll != null) GestureDetector( onTap: onSeeAll, child: Text( 'TOUT VOIR', style: AppTypography.badgeText.copyWith( color: AppColors.primaryGreen, fontWeight: FontWeight.bold, ), ), ), ], ); } Widget _buildEventsList(BuildContext context, List events) { if (events.isEmpty) { return _buildEmptyState(); } final displayEvents = events.take(maxItems).toList(); return Column( children: displayEvents.asMap().entries.map((entry) { final index = entry.key; final event = entry.value; final isLast = index == displayEvents.length - 1; return Column( children: [ _buildEventCard(context, event), if (!isLast) const SizedBox(height: 12), ], ); }).toList(), ); } Widget _buildEventCard(BuildContext context, UpcomingEventEntity event) { final statusColor = event.isToday ? AppColors.success : (event.isTomorrow ? AppColors.warning : AppColors.primaryGreen); return CoreCard( backgroundColor: Theme.of(context).cardColor, padding: const EdgeInsets.all(8), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Container( width: 32, height: 32, decoration: BoxDecoration( color: statusColor.withOpacity(0.1), borderRadius: BorderRadius.circular(6), ), child: event.imageUrl != null ? ClipRRect( borderRadius: BorderRadius.circular(6), child: Image.network( event.imageUrl!, fit: BoxFit.cover, errorBuilder: (context, error, stackTrace) => Icon(Icons.event_outlined, color: statusColor, size: 16), ), ) : Icon(Icons.event_outlined, color: statusColor, size: 16), ), const SizedBox(width: 12), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( event.title, style: AppTypography.actionText.copyWith(fontSize: 12), maxLines: 1, overflow: TextOverflow.ellipsis, ), Row( children: [ const Icon(Icons.location_on_outlined, size: 10, color: AppColors.textSecondaryLight), const SizedBox(width: 4), Expanded( child: Text( event.location, style: AppTypography.subtitleSmall.copyWith(fontSize: 9), maxLines: 1, overflow: TextOverflow.ellipsis, ), ), ], ), ], ), ), Container( padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2), decoration: BoxDecoration( color: statusColor.withOpacity(0.1), borderRadius: BorderRadius.circular(4), ), child: Text( event.daysUntilEvent.toUpperCase(), style: AppTypography.badgeText.copyWith(color: statusColor, fontSize: 8, fontWeight: FontWeight.bold), ), ), ], ), const SizedBox(height: 8), Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text('PARTICIPANTS', style: AppTypography.subtitleSmall.copyWith(fontSize: 8, fontWeight: FontWeight.bold)), Text( '${event.currentParticipants}/${event.maxParticipants}', style: AppTypography.subtitleSmall.copyWith(fontSize: 8, fontWeight: FontWeight.bold), ), ], ), const SizedBox(height: 4), ClipRRect( borderRadius: BorderRadius.circular(2), child: LinearProgressIndicator( value: event.fillPercentage, minHeight: 4, backgroundColor: AppColors.lightBorder, valueColor: AlwaysStoppedAnimation( event.isFull ? AppColors.error : (event.isAlmostFull ? AppColors.warning : AppColors.success), ), ), ), ], ), ], ), ); } Widget _buildLoadingList() { return Column( children: List.generate(2, (index) => Column( children: [ _buildLoadingCard(), if (index < 1) const SizedBox(height: 12), ], )), ); } Widget _buildLoadingCard() { return const CoreCard( child: Center(child: CircularProgressIndicator(strokeWidth: 2)), ); } Widget _buildErrorState(String message) { return Center( child: Column( children: [ const Icon(Icons.error_outline, color: AppColors.error, size: 32), const SizedBox(height: 8), Text(message, style: AppTypography.subtitleSmall.copyWith(color: AppColors.error)), ], ), ); } Widget _buildEmptyState() { return Center( child: Column( children: [ const Icon(Icons.event_outlined, color: AppColors.textSecondaryLight, size: 32), const SizedBox(height: 8), const Text('AUCUN ÉVÉNEMENT', style: AppTypography.subtitleSmall), Text('Les événements apparaîtront ici', style: AppTypography.subtitleSmall.copyWith(fontSize: 10)), ], ), ); } }