import 'package:equatable/equatable.dart'; /// Entité pour les statistiques du dashboard class DashboardStatsEntity extends Equatable { final int totalMembers; final int activeMembers; final int totalEvents; final int upcomingEvents; final int totalContributions; final double totalContributionAmount; final int pendingRequests; final int completedProjects; final double monthlyGrowth; final double engagementRate; final DateTime lastUpdated; const DashboardStatsEntity({ required this.totalMembers, required this.activeMembers, required this.totalEvents, required this.upcomingEvents, required this.totalContributions, required this.totalContributionAmount, required this.pendingRequests, required this.completedProjects, required this.monthlyGrowth, required this.engagementRate, required this.lastUpdated, }); // Méthodes utilitaires double get memberActivityRate => totalMembers > 0 ? activeMembers / totalMembers : 0.0; bool get hasGrowth => monthlyGrowth > 0; bool get isHighEngagement => engagementRate > 0.7; String get formattedContributionAmount { if (totalContributionAmount >= 1000000) { return '${(totalContributionAmount / 1000000).toStringAsFixed(1)}M'; } else if (totalContributionAmount >= 1000) { return '${(totalContributionAmount / 1000).toStringAsFixed(1)}K'; } return totalContributionAmount.toStringAsFixed(0); } @override List get props => [ totalMembers, activeMembers, totalEvents, upcomingEvents, totalContributions, totalContributionAmount, pendingRequests, completedProjects, monthlyGrowth, engagementRate, lastUpdated, ]; } /// Entité pour les activités récentes class RecentActivityEntity extends Equatable { final String id; final String type; final String title; final String description; final String? userAvatar; final String userName; final DateTime timestamp; final String? actionUrl; final Map? metadata; const RecentActivityEntity({ required this.id, required this.type, required this.title, required this.description, this.userAvatar, required this.userName, required this.timestamp, this.actionUrl, this.metadata, }); // Méthodes utilitaires String get timeAgo { final now = DateTime.now(); final difference = now.difference(timestamp); if (difference.inDays > 0) { return '${difference.inDays}j'; } else if (difference.inHours > 0) { return '${difference.inHours}h'; } else if (difference.inMinutes > 0) { return '${difference.inMinutes}min'; } else { return 'maintenant'; } } bool get isRecent => DateTime.now().difference(timestamp).inHours < 24; bool get hasAction => actionUrl != null && actionUrl!.isNotEmpty; @override List get props => [ id, type, title, description, userAvatar, userName, timestamp, actionUrl, metadata, ]; } /// Entité pour les événements à venir class UpcomingEventEntity extends Equatable { final String id; final String title; final String description; final DateTime startDate; final DateTime? endDate; final String location; final int maxParticipants; final int currentParticipants; final String status; final String? imageUrl; final List tags; const UpcomingEventEntity({ required this.id, required this.title, required this.description, required this.startDate, this.endDate, required this.location, required this.maxParticipants, required this.currentParticipants, required this.status, this.imageUrl, required this.tags, }); // Méthodes utilitaires bool get isAlmostFull => currentParticipants >= (maxParticipants * 0.8); bool get isFull => currentParticipants >= maxParticipants; double get fillPercentage => maxParticipants > 0 ? currentParticipants / maxParticipants : 0.0; String get daysUntilEvent { final now = DateTime.now(); final difference = startDate.difference(now); if (difference.inDays > 0) { return '${difference.inDays} jour${difference.inDays > 1 ? 's' : ''}'; } else if (difference.inHours > 0) { return '${difference.inHours}h'; } else if (difference.inMinutes > 0) { return '${difference.inMinutes}min'; } else { return 'En cours'; } } bool get isToday { final now = DateTime.now(); return startDate.year == now.year && startDate.month == now.month && startDate.day == now.day; } bool get isTomorrow { final tomorrow = DateTime.now().add(const Duration(days: 1)); return startDate.year == tomorrow.year && startDate.month == tomorrow.month && startDate.day == tomorrow.day; } @override List get props => [ id, title, description, startDate, endDate, location, maxParticipants, currentParticipants, status, imageUrl, tags, ]; } /// Entité principale du dashboard class DashboardEntity extends Equatable { final DashboardStatsEntity stats; final List recentActivities; final List upcomingEvents; final Map userPreferences; final String organizationId; final String userId; const DashboardEntity({ required this.stats, required this.recentActivities, required this.upcomingEvents, required this.userPreferences, required this.organizationId, required this.userId, }); // Méthodes utilitaires bool get hasRecentActivity => recentActivities.isNotEmpty; bool get hasUpcomingEvents => upcomingEvents.isNotEmpty; int get todayEventsCount => upcomingEvents.where((e) => e.isToday).length; int get tomorrowEventsCount => upcomingEvents.where((e) => e.isTomorrow).length; int get recentActivitiesCount => recentActivities.length; @override List get props => [ stats, recentActivities, upcomingEvents, userPreferences, organizationId, userId, ]; }