import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import '../../../domain/entities/dashboard_entity.dart'; import '../../bloc/dashboard_bloc.dart'; import '../../../../../shared/design_system/unionflow_design_system.dart'; import '../../../../../shared/widgets/core_card.dart'; import '../../../../adhesions/presentation/pages/adhesions_page_wrapper.dart'; import '../../../../events/presentation/pages/events_page_wrapper.dart'; import '../../../../settings/presentation/pages/system_settings_page.dart'; /// Widget de notifications pour le dashboard class DashboardNotificationsWidget extends StatelessWidget { final int maxNotifications; const DashboardNotificationsWidget({ super.key, this.maxNotifications = 5, }); @override Widget build(BuildContext context) { return CoreCard( padding: EdgeInsets.zero, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ _buildHeader(context), BlocBuilder( builder: (context, state) { if (state is DashboardLoading) { return _buildLoadingNotifications(); } else if (state is DashboardLoaded || state is DashboardRefreshing) { final data = state is DashboardLoaded ? state.dashboardData : (state as DashboardRefreshing).dashboardData; return _buildNotifications(context, data); } else if (state is DashboardError) { return _buildErrorNotifications(); } return _buildEmptyNotifications(context); }, ), ], ), ); } Widget _buildHeader(BuildContext context) { return Container( padding: const EdgeInsets.all(12), decoration: BoxDecoration( color: AppColors.primary.withOpacity(0.05), borderRadius: const BorderRadius.only( topLeft: Radius.circular(12), topRight: Radius.circular(12), ), ), child: Row( children: [ Container( padding: const EdgeInsets.all(6), decoration: BoxDecoration( color: AppColors.primary, borderRadius: BorderRadius.circular(4), ), child: const Icon( Icons.notifications_outlined, color: Colors.white, size: 16, ), ), const SizedBox(width: 10), Expanded( child: Text( 'NOTIFICATIONS', style: AppTypography.subtitleSmall.copyWith( color: AppColors.primary, fontWeight: FontWeight.bold, letterSpacing: 1.1, ), ), ), BlocBuilder( builder: (context, state) { if (state is DashboardLoaded || state is DashboardRefreshing) { final data = state is DashboardLoaded ? state.dashboardData : (state as DashboardRefreshing).dashboardData; final urgentCount = _getUrgentNotificationsCount(context, data); if (urgentCount > 0) { return Container( padding: const EdgeInsets.symmetric( horizontal: 6, vertical: 2, ), decoration: BoxDecoration( color: AppColors.error, borderRadius: BorderRadius.circular(4), ), child: Text( urgentCount.toString(), style: AppTypography.badgeText.copyWith( color: Colors.white, fontWeight: FontWeight.bold, fontSize: 8, ), ), ); } } return const SizedBox.shrink(); }, ), ], ), ); } Widget _buildNotifications(BuildContext context, DashboardEntity data) { final notifications = _generateNotifications(context, data); if (notifications.isEmpty) { return _buildEmptyNotifications(context); } return Column( children: notifications.take(maxNotifications).map((notification) { return _buildNotificationItem(context, notification); }).toList(), ); } Widget _buildNotificationItem(BuildContext context, DashboardNotification notification) { final isDark = Theme.of(context).brightness == Brightness.dark; return Container( padding: const EdgeInsets.all(12), decoration: BoxDecoration( border: Border( bottom: BorderSide( color: isDark ? AppColors.borderDark : AppColors.border, width: 1, ), ), ), child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Container( padding: const EdgeInsets.all(6), decoration: BoxDecoration( color: notification.color.withOpacity(0.1), borderRadius: BorderRadius.circular(4), ), child: Icon( notification.icon, color: notification.color, size: 16, ), ), const SizedBox(width: 10), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Expanded( child: Text( notification.title, style: AppTypography.actionText.copyWith( fontSize: 12, fontWeight: FontWeight.w600, ), ), ), if (notification.isUrgent) ...[ Container( padding: const EdgeInsets.symmetric( horizontal: 4, vertical: 1, ), decoration: BoxDecoration( color: AppColors.error, borderRadius: BorderRadius.circular(2), ), child: Text( 'URGENT', style: AppTypography.badgeText.copyWith( color: Colors.white, fontWeight: FontWeight.bold, fontSize: 7, ), ), ), ], ], ), const SizedBox(height: 2), Text( notification.message, style: AppTypography.subtitleSmall.copyWith( color: isDark ? AppColors.textSecondaryDark : AppColors.textSecondary, fontSize: 10, ), ), const SizedBox(height: 8), Row( children: [ Text( notification.timeAgo, style: AppTypography.subtitleSmall.copyWith( color: isDark ? AppColors.textSecondaryDark : AppColors.textSecondary, fontSize: 9, ), ), const Spacer(), if (notification.actionLabel != null) ...[ GestureDetector( onTap: notification.onAction, child: Text( notification.actionLabel!, style: AppTypography.badgeText.copyWith( color: AppColors.primary, fontWeight: FontWeight.bold, fontSize: 9, ), ), ), ], ], ), ], ), ), ], ), ); } Widget _buildLoadingNotifications() { return const Padding( padding: EdgeInsets.all(20), child: Center(child: CircularProgressIndicator(strokeWidth: 2)), ); } Widget _buildErrorNotifications() { return Container( padding: const EdgeInsets.all(24), child: Center( child: Column( children: [ const Icon( Icons.error_outline, color: AppColors.error, size: 24, ), const SizedBox(height: 8), Text( 'Erreur', style: AppTypography.subtitleSmall.copyWith( color: AppColors.error, ), ), ], ), ), ); } Widget _buildEmptyNotifications(BuildContext context) { final isDark = Theme.of(context).brightness == Brightness.dark; return Container( padding: const EdgeInsets.all(24), child: Center( child: Column( children: [ Icon( Icons.notifications_none_outlined, color: isDark ? AppColors.textSecondaryDark : AppColors.textSecondary, size: 24, ), const SizedBox(height: 8), Text( 'AUCUNE NOTIFICATION', style: AppTypography.subtitleSmall.copyWith(fontWeight: FontWeight.bold), ), Text( 'Vous êtes à jour !', style: AppTypography.subtitleSmall.copyWith(fontSize: 10), ), ], ), ), ); } List _generateNotifications(BuildContext context, DashboardEntity data) { List notifications = []; // Notification pour les demandes en attente if (data.stats.pendingRequests > 0) { notifications.add(DashboardNotification( title: 'Demandes en attente', message: '${data.stats.pendingRequests} demandes à valider', icon: Icons.pending_actions_outlined, color: AppColors.warning, timeAgo: '2h', isUrgent: data.stats.pendingRequests > 20, actionLabel: 'Voir', onAction: () => Navigator.of(context).push(MaterialPageRoute(builder: (_) => const AdhesionsPageWrapper())), )); } // Notification pour les événements aujourd'hui if (data.todayEventsCount > 0) { notifications.add(DashboardNotification( title: 'Événements aujourd\'hui', message: '${data.todayEventsCount} événement(s) aujourd\'hui', icon: Icons.event_available_outlined, color: AppColors.info, timeAgo: '30min', isUrgent: false, actionLabel: 'Voir', onAction: () => Navigator.of(context).push(MaterialPageRoute(builder: (_) => const EventsPageWrapper())), )); } // Notification pour la croissance if (data.stats.hasGrowth) { notifications.add(DashboardNotification( title: 'Croissance positive', message: 'Progression de ${data.stats.monthlyGrowth.toStringAsFixed(1)}% ce mois', icon: Icons.trending_up_outlined, color: AppColors.success, timeAgo: '1j', isUrgent: false, actionLabel: null, onAction: null, )); } // Notification pour l'engagement faible if (!data.stats.isHighEngagement) { notifications.add(DashboardNotification( title: 'Engagement à surveiller', message: 'Taux: ${(data.stats.engagementRate * 100).toStringAsFixed(0)}%', icon: Icons.trending_down_outlined, color: AppColors.error, timeAgo: '3h', isUrgent: data.stats.engagementRate < 0.5, actionLabel: 'Améliorer', onAction: () => Navigator.of(context).push(MaterialPageRoute(builder: (_) => const SystemSettingsPage())), )); } // Notification pour les nouveaux membres if (data.recentActivitiesCount > 0) { notifications.add(DashboardNotification( title: 'Nouvelles activités', message: '${data.recentActivitiesCount} activités récentes', icon: Icons.fiber_new_outlined, color: AppColors.primaryDark, timeAgo: '15min', isUrgent: false, actionLabel: 'Voir', onAction: () => Navigator.of(context).push(MaterialPageRoute(builder: (_) => const EventsPageWrapper())), )); } return notifications; } int _getUrgentNotificationsCount(BuildContext context, DashboardEntity data) { final notifications = _generateNotifications(context, data); return notifications.where((n) => n.isUrgent).length; } } class DashboardNotification { final String title; final String message; final IconData icon; final Color color; final String timeAgo; final bool isUrgent; final String? actionLabel; final VoidCallback? onAction; const DashboardNotification({ required this.title, required this.message, required this.icon, required this.color, required this.timeAgo, required this.isUrgent, this.actionLabel, this.onAction, }); }