import 'package:equatable/equatable.dart'; import '../../../domain/entities/evaluation_aide.dart'; import 'evaluations_event.dart'; /// États pour la gestion des évaluations d'aide /// /// Ces états représentent tous les états possibles /// de l'interface utilisateur pour les évaluations d'aide. abstract class EvaluationsState extends Equatable { const EvaluationsState(); @override List get props => []; } /// État initial class EvaluationsInitial extends EvaluationsState { const EvaluationsInitial(); } /// État de chargement class EvaluationsLoading extends EvaluationsState { final bool isRefreshing; final bool isLoadingMore; const EvaluationsLoading({ this.isRefreshing = false, this.isLoadingMore = false, }); @override List get props => [isRefreshing, isLoadingMore]; } /// État de succès avec données chargées class EvaluationsLoaded extends EvaluationsState { final List evaluations; final List evaluationsFiltrees; final bool hasReachedMax; final int currentPage; final int totalElements; final Map evaluationsSelectionnees; final TriEvaluations? criterieTri; final bool triCroissant; final FiltresEvaluations filtres; final bool isRefreshing; final bool isLoadingMore; final DateTime lastUpdated; const EvaluationsLoaded({ required this.evaluations, required this.evaluationsFiltrees, this.hasReachedMax = false, this.currentPage = 0, this.totalElements = 0, this.evaluationsSelectionnees = const {}, this.criterieTri, this.triCroissant = true, this.filtres = const FiltresEvaluations(), this.isRefreshing = false, this.isLoadingMore = false, required this.lastUpdated, }); @override List get props => [ evaluations, evaluationsFiltrees, hasReachedMax, currentPage, totalElements, evaluationsSelectionnees, criterieTri, triCroissant, filtres, isRefreshing, isLoadingMore, lastUpdated, ]; /// Copie l'état avec de nouvelles valeurs EvaluationsLoaded copyWith({ List? evaluations, List? evaluationsFiltrees, bool? hasReachedMax, int? currentPage, int? totalElements, Map? evaluationsSelectionnees, TriEvaluations? criterieTri, bool? triCroissant, FiltresEvaluations? filtres, bool? isRefreshing, bool? isLoadingMore, DateTime? lastUpdated, }) { return EvaluationsLoaded( evaluations: evaluations ?? this.evaluations, evaluationsFiltrees: evaluationsFiltrees ?? this.evaluationsFiltrees, hasReachedMax: hasReachedMax ?? this.hasReachedMax, currentPage: currentPage ?? this.currentPage, totalElements: totalElements ?? this.totalElements, evaluationsSelectionnees: evaluationsSelectionnees ?? this.evaluationsSelectionnees, criterieTri: criterieTri ?? this.criterieTri, triCroissant: triCroissant ?? this.triCroissant, filtres: filtres ?? this.filtres, isRefreshing: isRefreshing ?? this.isRefreshing, isLoadingMore: isLoadingMore ?? this.isLoadingMore, lastUpdated: lastUpdated ?? this.lastUpdated, ); } /// Obtient le nombre d'évaluations sélectionnées int get nombreEvaluationsSelectionnees { return evaluationsSelectionnees.values.where((selected) => selected).length; } /// Vérifie si toutes les évaluations sont sélectionnées bool get toutesEvaluationsSelectionnees { if (evaluationsFiltrees.isEmpty) return false; return evaluationsFiltrees.every((evaluation) => evaluationsSelectionnees[evaluation.id] == true ); } /// Obtient les IDs des évaluations sélectionnées List get evaluationsSelectionneesIds { return evaluationsSelectionnees.entries .where((entry) => entry.value) .map((entry) => entry.key) .toList(); } /// Obtient les évaluations sélectionnées List get evaluationsSelectionneesEntities { return evaluations.where((evaluation) => evaluationsSelectionnees[evaluation.id] == true ).toList(); } /// Vérifie si des données sont disponibles bool get hasData => evaluations.isNotEmpty; /// Vérifie si des filtres sont appliqués bool get hasFiltres => !filtres.isEmpty; /// Obtient le texte de statut String get statusText { if (isRefreshing) return 'Actualisation...'; if (isLoadingMore) return 'Chargement...'; if (evaluationsFiltrees.isEmpty && hasData) return 'Aucun résultat pour les filtres appliqués'; if (evaluationsFiltrees.isEmpty) return 'Aucune évaluation'; return '${evaluationsFiltrees.length} évaluation${evaluationsFiltrees.length > 1 ? 's' : ''}'; } /// Obtient la note moyenne double get noteMoyenne { if (evaluationsFiltrees.isEmpty) return 0.0; final notesValides = evaluationsFiltrees .where((e) => e.noteGlobale != null) .map((e) => e.noteGlobale!) .toList(); if (notesValides.isEmpty) return 0.0; return notesValides.reduce((a, b) => a + b) / notesValides.length; } /// Obtient le nombre d'évaluations par décision Map get repartitionDecisions { final repartition = {}; for (final evaluation in evaluationsFiltrees) { repartition[evaluation.decision] = (repartition[evaluation.decision] ?? 0) + 1; } return repartition; } } /// État d'erreur class EvaluationsError extends EvaluationsState { final String message; final String? code; final bool isNetworkError; final bool canRetry; final List? cachedData; const EvaluationsError({ required this.message, this.code, this.isNetworkError = false, this.canRetry = true, this.cachedData, }); @override List get props => [ message, code, isNetworkError, canRetry, cachedData, ]; /// Vérifie si des données en cache sont disponibles bool get hasCachedData => cachedData != null && cachedData!.isNotEmpty; } /// État de succès pour une opération spécifique class EvaluationsOperationSuccess extends EvaluationsState { final String message; final EvaluationAide? evaluation; final TypeOperationEvaluation operation; const EvaluationsOperationSuccess({ required this.message, this.evaluation, required this.operation, }); @override List get props => [message, evaluation, operation]; } /// État de validation class EvaluationsValidation extends EvaluationsState { final Map erreurs; final bool isValid; final EvaluationAide? evaluation; const EvaluationsValidation({ required this.erreurs, required this.isValid, this.evaluation, }); @override List get props => [erreurs, isValid, evaluation]; /// Obtient la première erreur String? get premiereErreur { return erreurs.values.isNotEmpty ? erreurs.values.first : null; } /// Obtient les erreurs pour un champ spécifique String? getErreurPourChamp(String champ) { return erreurs[champ]; } } /// État de calcul de note globale class EvaluationsNoteCalculee extends EvaluationsState { final double noteGlobale; final Map criteres; const EvaluationsNoteCalculee({ required this.noteGlobale, required this.criteres, }); @override List get props => [noteGlobale, criteres]; } /// État des statistiques d'évaluation class EvaluationsStatistiques extends EvaluationsState { final Map statistiques; final DateTime? dateDebut; final DateTime? dateFin; const EvaluationsStatistiques({ required this.statistiques, this.dateDebut, this.dateFin, }); @override List get props => [statistiques, dateDebut, dateFin]; } /// État d'export class EvaluationsExporting extends EvaluationsState { final double progress; final String? currentStep; const EvaluationsExporting({ required this.progress, this.currentStep, }); @override List get props => [progress, currentStep]; } /// État d'export terminé class EvaluationsExported extends EvaluationsState { final String filePath; final FormatExport format; final int nombreEvaluations; const EvaluationsExported({ required this.filePath, required this.format, required this.nombreEvaluations, }); @override List get props => [filePath, format, nombreEvaluations]; } /// Classe pour les filtres des évaluations class FiltresEvaluations extends Equatable { final TypeEvaluateur? typeEvaluateur; final StatutAide? decision; final double? noteMin; final double? noteMax; final String? motCle; final String? evaluateurId; final String? demandeId; final DateTime? dateDebutEvaluation; final DateTime? dateFinEvaluation; const FiltresEvaluations({ this.typeEvaluateur, this.decision, this.noteMin, this.noteMax, this.motCle, this.evaluateurId, this.demandeId, this.dateDebutEvaluation, this.dateFinEvaluation, }); @override List get props => [ typeEvaluateur, decision, noteMin, noteMax, motCle, evaluateurId, demandeId, dateDebutEvaluation, dateFinEvaluation, ]; /// Copie les filtres avec de nouvelles valeurs FiltresEvaluations copyWith({ TypeEvaluateur? typeEvaluateur, StatutAide? decision, double? noteMin, double? noteMax, String? motCle, String? evaluateurId, String? demandeId, DateTime? dateDebutEvaluation, DateTime? dateFinEvaluation, }) { return FiltresEvaluations( typeEvaluateur: typeEvaluateur ?? this.typeEvaluateur, decision: decision ?? this.decision, noteMin: noteMin ?? this.noteMin, noteMax: noteMax ?? this.noteMax, motCle: motCle ?? this.motCle, evaluateurId: evaluateurId ?? this.evaluateurId, demandeId: demandeId ?? this.demandeId, dateDebutEvaluation: dateDebutEvaluation ?? this.dateDebutEvaluation, dateFinEvaluation: dateFinEvaluation ?? this.dateFinEvaluation, ); } /// Réinitialise tous les filtres FiltresEvaluations clear() { return const FiltresEvaluations(); } /// Vérifie si les filtres sont vides bool get isEmpty { return typeEvaluateur == null && decision == null && noteMin == null && noteMax == null && (motCle == null || motCle!.isEmpty) && evaluateurId == null && demandeId == null && dateDebutEvaluation == null && dateFinEvaluation == null; } /// Obtient le nombre de filtres actifs int get nombreFiltresActifs { int count = 0; if (typeEvaluateur != null) count++; if (decision != null) count++; if (noteMin != null) count++; if (noteMax != null) count++; if (motCle != null && motCle!.isNotEmpty) count++; if (evaluateurId != null) count++; if (demandeId != null) count++; if (dateDebutEvaluation != null) count++; if (dateFinEvaluation != null) count++; return count; } /// Obtient une description textuelle des filtres String get description { final parts = []; if (typeEvaluateur != null) parts.add('Type: ${typeEvaluateur!.libelle}'); if (decision != null) parts.add('Décision: ${decision!.libelle}'); if (motCle != null && motCle!.isNotEmpty) parts.add('Recherche: "$motCle"'); if (noteMin != null || noteMax != null) { if (noteMin != null && noteMax != null) { parts.add('Note: ${noteMin!.toStringAsFixed(1)} - ${noteMax!.toStringAsFixed(1)}'); } else if (noteMin != null) { parts.add('Note min: ${noteMin!.toStringAsFixed(1)}'); } else { parts.add('Note max: ${noteMax!.toStringAsFixed(1)}'); } } return parts.join(', '); } } /// Énumération pour les types d'opération enum TypeOperationEvaluation { creation, modification, soumission, approbation, rejet, suppression, export, signalement, } /// Extension pour obtenir le libellé des opérations extension TypeOperationEvaluationExtension on TypeOperationEvaluation { String get libelle { switch (this) { case TypeOperationEvaluation.creation: return 'Création'; case TypeOperationEvaluation.modification: return 'Modification'; case TypeOperationEvaluation.soumission: return 'Soumission'; case TypeOperationEvaluation.approbation: return 'Approbation'; case TypeOperationEvaluation.rejet: return 'Rejet'; case TypeOperationEvaluation.suppression: return 'Suppression'; case TypeOperationEvaluation.export: return 'Export'; case TypeOperationEvaluation.signalement: return 'Signalement'; } } String get messageSucces { switch (this) { case TypeOperationEvaluation.creation: return 'Évaluation créée avec succès'; case TypeOperationEvaluation.modification: return 'Évaluation modifiée avec succès'; case TypeOperationEvaluation.soumission: return 'Évaluation soumise avec succès'; case TypeOperationEvaluation.approbation: return 'Évaluation approuvée avec succès'; case TypeOperationEvaluation.rejet: return 'Évaluation rejetée avec succès'; case TypeOperationEvaluation.suppression: return 'Évaluation supprimée avec succès'; case TypeOperationEvaluation.export: return 'Export réalisé avec succès'; case TypeOperationEvaluation.signalement: return 'Évaluation signalée avec succès'; } } }