Refactoring

This commit is contained in:
DahoudG
2025-09-17 17:54:06 +00:00
parent 12d514d866
commit 63fe107f98
165 changed files with 54220 additions and 276 deletions

View File

@@ -0,0 +1,382 @@
import 'package:equatable/equatable.dart';
import '../../../domain/entities/proposition_aide.dart';
/// Événements pour la gestion des propositions d'aide
///
/// Ces événements représentent toutes les actions possibles
/// que l'utilisateur peut effectuer sur les propositions d'aide.
abstract class PropositionsAideEvent extends Equatable {
const PropositionsAideEvent();
@override
List<Object?> get props => [];
}
/// Événement pour charger les propositions d'aide
class ChargerPropositionsAideEvent extends PropositionsAideEvent {
final String? organisationId;
final TypeAide? typeAide;
final StatutProposition? statut;
final String? proposantId;
final bool? disponible;
final bool forceRefresh;
const ChargerPropositionsAideEvent({
this.organisationId,
this.typeAide,
this.statut,
this.proposantId,
this.disponible,
this.forceRefresh = false,
});
@override
List<Object?> get props => [
organisationId,
typeAide,
statut,
proposantId,
disponible,
forceRefresh,
];
}
/// Événement pour charger plus de propositions (pagination)
class ChargerPlusPropositionsAideEvent extends PropositionsAideEvent {
const ChargerPlusPropositionsAideEvent();
}
/// Événement pour créer une nouvelle proposition d'aide
class CreerPropositionAideEvent extends PropositionsAideEvent {
final PropositionAide proposition;
const CreerPropositionAideEvent({required this.proposition});
@override
List<Object> get props => [proposition];
}
/// Événement pour mettre à jour une proposition d'aide
class MettreAJourPropositionAideEvent extends PropositionsAideEvent {
final PropositionAide proposition;
const MettreAJourPropositionAideEvent({required this.proposition});
@override
List<Object> get props => [proposition];
}
/// Événement pour obtenir une proposition d'aide spécifique
class ObtenirPropositionAideEvent extends PropositionsAideEvent {
final String propositionId;
const ObtenirPropositionAideEvent({required this.propositionId});
@override
List<Object> get props => [propositionId];
}
/// Événement pour activer/désactiver une proposition
class ToggleDisponibilitePropositionEvent extends PropositionsAideEvent {
final String propositionId;
final bool disponible;
const ToggleDisponibilitePropositionEvent({
required this.propositionId,
required this.disponible,
});
@override
List<Object> get props => [propositionId, disponible];
}
/// Événement pour rechercher des propositions d'aide
class RechercherPropositionsAideEvent extends PropositionsAideEvent {
final String? organisationId;
final TypeAide? typeAide;
final StatutProposition? statut;
final String? proposantId;
final bool? disponible;
final String? motCle;
final int page;
final int taille;
const RechercherPropositionsAideEvent({
this.organisationId,
this.typeAide,
this.statut,
this.proposantId,
this.disponible,
this.motCle,
this.page = 0,
this.taille = 20,
});
@override
List<Object?> get props => [
organisationId,
typeAide,
statut,
proposantId,
disponible,
motCle,
page,
taille,
];
}
/// Événement pour charger mes propositions
class ChargerMesPropositionsEvent extends PropositionsAideEvent {
final String utilisateurId;
const ChargerMesPropositionsEvent({required this.utilisateurId});
@override
List<Object> get props => [utilisateurId];
}
/// Événement pour charger les propositions disponibles
class ChargerPropositionsDisponiblesEvent extends PropositionsAideEvent {
final String organisationId;
final TypeAide? typeAide;
const ChargerPropositionsDisponiblesEvent({
required this.organisationId,
this.typeAide,
});
@override
List<Object?> get props => [organisationId, typeAide];
}
/// Événement pour filtrer les propositions localement
class FiltrerPropositionsAideEvent extends PropositionsAideEvent {
final TypeAide? typeAide;
final StatutProposition? statut;
final bool? disponible;
final String? motCle;
final double? capaciteMin;
final double? capaciteMax;
const FiltrerPropositionsAideEvent({
this.typeAide,
this.statut,
this.disponible,
this.motCle,
this.capaciteMin,
this.capaciteMax,
});
@override
List<Object?> get props => [
typeAide,
statut,
disponible,
motCle,
capaciteMin,
capaciteMax,
];
}
/// Événement pour trier les propositions
class TrierPropositionsAideEvent extends PropositionsAideEvent {
final TriPropositions critere;
final bool croissant;
const TrierPropositionsAideEvent({
required this.critere,
this.croissant = true,
});
@override
List<Object> get props => [critere, croissant];
}
/// Événement pour rafraîchir les propositions
class RafraichirPropositionsAideEvent extends PropositionsAideEvent {
const RafraichirPropositionsAideEvent();
}
/// Événement pour réinitialiser l'état
class ReinitialiserPropositionsAideEvent extends PropositionsAideEvent {
const ReinitialiserPropositionsAideEvent();
}
/// Événement pour sélectionner/désélectionner une proposition
class SelectionnerPropositionAideEvent extends PropositionsAideEvent {
final String propositionId;
final bool selectionne;
const SelectionnerPropositionAideEvent({
required this.propositionId,
required this.selectionne,
});
@override
List<Object> get props => [propositionId, selectionne];
}
/// Événement pour sélectionner/désélectionner toutes les propositions
class SelectionnerToutesPropositionsAideEvent extends PropositionsAideEvent {
final bool selectionne;
const SelectionnerToutesPropositionsAideEvent({required this.selectionne});
@override
List<Object> get props => [selectionne];
}
/// Événement pour supprimer des propositions sélectionnées
class SupprimerPropositionsSelectionnees extends PropositionsAideEvent {
final List<String> propositionIds;
const SupprimerPropositionsSelectionnees({required this.propositionIds});
@override
List<Object> get props => [propositionIds];
}
/// Événement pour exporter des propositions
class ExporterPropositionsAideEvent extends PropositionsAideEvent {
final List<String> propositionIds;
final FormatExport format;
const ExporterPropositionsAideEvent({
required this.propositionIds,
required this.format,
});
@override
List<Object> get props => [propositionIds, format];
}
/// Événement pour calculer la compatibilité avec une demande
class CalculerCompatibiliteEvent extends PropositionsAideEvent {
final String propositionId;
final String demandeId;
const CalculerCompatibiliteEvent({
required this.propositionId,
required this.demandeId,
});
@override
List<Object> get props => [propositionId, demandeId];
}
/// Événement pour obtenir les statistiques d'une proposition
class ObtenirStatistiquesPropositionEvent extends PropositionsAideEvent {
final String propositionId;
const ObtenirStatistiquesPropositionEvent({required this.propositionId});
@override
List<Object> get props => [propositionId];
}
/// Énumération pour les critères de tri
enum TriPropositions {
dateCreation,
dateModification,
titre,
statut,
capacite,
proposant,
scoreCompatibilite,
nombreMatches,
}
/// Énumération pour les formats d'export
enum FormatExport {
pdf,
excel,
csv,
json,
}
/// Extension pour obtenir le libellé des critères de tri
extension TriPropositionsExtension on TriPropositions {
String get libelle {
switch (this) {
case TriPropositions.dateCreation:
return 'Date de création';
case TriPropositions.dateModification:
return 'Date de modification';
case TriPropositions.titre:
return 'Titre';
case TriPropositions.statut:
return 'Statut';
case TriPropositions.capacite:
return 'Capacité';
case TriPropositions.proposant:
return 'Proposant';
case TriPropositions.scoreCompatibilite:
return 'Score de compatibilité';
case TriPropositions.nombreMatches:
return 'Nombre de matches';
}
}
String get icone {
switch (this) {
case TriPropositions.dateCreation:
return 'calendar_today';
case TriPropositions.dateModification:
return 'update';
case TriPropositions.titre:
return 'title';
case TriPropositions.statut:
return 'flag';
case TriPropositions.capacite:
return 'trending_up';
case TriPropositions.proposant:
return 'person';
case TriPropositions.scoreCompatibilite:
return 'star';
case TriPropositions.nombreMatches:
return 'link';
}
}
}
/// Extension pour obtenir le libellé des formats d'export
extension FormatExportExtension on FormatExport {
String get libelle {
switch (this) {
case FormatExport.pdf:
return 'PDF';
case FormatExport.excel:
return 'Excel';
case FormatExport.csv:
return 'CSV';
case FormatExport.json:
return 'JSON';
}
}
String get extension {
switch (this) {
case FormatExport.pdf:
return '.pdf';
case FormatExport.excel:
return '.xlsx';
case FormatExport.csv:
return '.csv';
case FormatExport.json:
return '.json';
}
}
String get mimeType {
switch (this) {
case FormatExport.pdf:
return 'application/pdf';
case FormatExport.excel:
return 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';
case FormatExport.csv:
return 'text/csv';
case FormatExport.json:
return 'application/json';
}
}
}

View File

@@ -0,0 +1,445 @@
import 'package:equatable/equatable.dart';
import '../../../domain/entities/proposition_aide.dart';
import 'propositions_aide_event.dart';
/// États pour la gestion des propositions d'aide
///
/// Ces états représentent tous les états possibles
/// de l'interface utilisateur pour les propositions d'aide.
abstract class PropositionsAideState extends Equatable {
const PropositionsAideState();
@override
List<Object?> get props => [];
}
/// État initial
class PropositionsAideInitial extends PropositionsAideState {
const PropositionsAideInitial();
}
/// État de chargement
class PropositionsAideLoading extends PropositionsAideState {
final bool isRefreshing;
final bool isLoadingMore;
const PropositionsAideLoading({
this.isRefreshing = false,
this.isLoadingMore = false,
});
@override
List<Object> get props => [isRefreshing, isLoadingMore];
}
/// État de succès avec données chargées
class PropositionsAideLoaded extends PropositionsAideState {
final List<PropositionAide> propositions;
final List<PropositionAide> propositionsFiltrees;
final bool hasReachedMax;
final int currentPage;
final int totalElements;
final Map<String, bool> propositionsSelectionnees;
final TriPropositions? criterieTri;
final bool triCroissant;
final FiltresPropositionsAide filtres;
final bool isRefreshing;
final bool isLoadingMore;
final DateTime lastUpdated;
const PropositionsAideLoaded({
required this.propositions,
required this.propositionsFiltrees,
this.hasReachedMax = false,
this.currentPage = 0,
this.totalElements = 0,
this.propositionsSelectionnees = const {},
this.criterieTri,
this.triCroissant = true,
this.filtres = const FiltresPropositionsAide(),
this.isRefreshing = false,
this.isLoadingMore = false,
required this.lastUpdated,
});
@override
List<Object?> get props => [
propositions,
propositionsFiltrees,
hasReachedMax,
currentPage,
totalElements,
propositionsSelectionnees,
criterieTri,
triCroissant,
filtres,
isRefreshing,
isLoadingMore,
lastUpdated,
];
/// Copie l'état avec de nouvelles valeurs
PropositionsAideLoaded copyWith({
List<PropositionAide>? propositions,
List<PropositionAide>? propositionsFiltrees,
bool? hasReachedMax,
int? currentPage,
int? totalElements,
Map<String, bool>? propositionsSelectionnees,
TriPropositions? criterieTri,
bool? triCroissant,
FiltresPropositionsAide? filtres,
bool? isRefreshing,
bool? isLoadingMore,
DateTime? lastUpdated,
}) {
return PropositionsAideLoaded(
propositions: propositions ?? this.propositions,
propositionsFiltrees: propositionsFiltrees ?? this.propositionsFiltrees,
hasReachedMax: hasReachedMax ?? this.hasReachedMax,
currentPage: currentPage ?? this.currentPage,
totalElements: totalElements ?? this.totalElements,
propositionsSelectionnees: propositionsSelectionnees ?? this.propositionsSelectionnees,
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 de propositions sélectionnées
int get nombrePropositionsSelectionnees {
return propositionsSelectionnees.values.where((selected) => selected).length;
}
/// Vérifie si toutes les propositions sont sélectionnées
bool get toutesPropositionsSelectionnees {
if (propositionsFiltrees.isEmpty) return false;
return propositionsFiltrees.every((proposition) =>
propositionsSelectionnees[proposition.id] == true
);
}
/// Obtient les IDs des propositions sélectionnées
List<String> get propositionsSelectionneesIds {
return propositionsSelectionnees.entries
.where((entry) => entry.value)
.map((entry) => entry.key)
.toList();
}
/// Obtient les propositions sélectionnées
List<PropositionAide> get propositionsSelectionneesEntities {
return propositions.where((proposition) =>
propositionsSelectionnees[proposition.id] == true
).toList();
}
/// Vérifie si des données sont disponibles
bool get hasData => propositions.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 (propositionsFiltrees.isEmpty && hasData) return 'Aucun résultat pour les filtres appliqués';
if (propositionsFiltrees.isEmpty) return 'Aucune proposition d\'aide';
return '${propositionsFiltrees.length} proposition${propositionsFiltrees.length > 1 ? 's' : ''}';
}
/// Obtient le nombre de propositions disponibles
int get nombrePropositionsDisponibles {
return propositionsFiltrees.where((p) => p.estDisponible).length;
}
/// Obtient la capacité totale disponible
double get capaciteTotaleDisponible {
return propositionsFiltrees
.where((p) => p.estDisponible)
.fold(0.0, (sum, p) => sum + (p.capaciteMaximale ?? 0.0));
}
}
/// État d'erreur
class PropositionsAideError extends PropositionsAideState {
final String message;
final String? code;
final bool isNetworkError;
final bool canRetry;
final List<PropositionAide>? cachedData;
const PropositionsAideError({
required this.message,
this.code,
this.isNetworkError = false,
this.canRetry = true,
this.cachedData,
});
@override
List<Object?> 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 PropositionsAideOperationSuccess extends PropositionsAideState {
final String message;
final PropositionAide? proposition;
final TypeOperationProposition operation;
const PropositionsAideOperationSuccess({
required this.message,
this.proposition,
required this.operation,
});
@override
List<Object?> get props => [message, proposition, operation];
}
/// État de compatibilité calculée
class PropositionsAideCompatibilite extends PropositionsAideState {
final String propositionId;
final String demandeId;
final double scoreCompatibilite;
final Map<String, dynamic> detailsCompatibilite;
const PropositionsAideCompatibilite({
required this.propositionId,
required this.demandeId,
required this.scoreCompatibilite,
required this.detailsCompatibilite,
});
@override
List<Object> get props => [propositionId, demandeId, scoreCompatibilite, detailsCompatibilite];
}
/// État des statistiques d'une proposition
class PropositionsAideStatistiques extends PropositionsAideState {
final String propositionId;
final Map<String, dynamic> statistiques;
const PropositionsAideStatistiques({
required this.propositionId,
required this.statistiques,
});
@override
List<Object> get props => [propositionId, statistiques];
}
/// État d'export
class PropositionsAideExporting extends PropositionsAideState {
final double progress;
final String? currentStep;
const PropositionsAideExporting({
required this.progress,
this.currentStep,
});
@override
List<Object?> get props => [progress, currentStep];
}
/// État d'export terminé
class PropositionsAideExported extends PropositionsAideState {
final String filePath;
final FormatExport format;
final int nombrePropositions;
const PropositionsAideExported({
required this.filePath,
required this.format,
required this.nombrePropositions,
});
@override
List<Object> get props => [filePath, format, nombrePropositions];
}
/// Classe pour les filtres des propositions d'aide
class FiltresPropositionsAide extends Equatable {
final TypeAide? typeAide;
final StatutProposition? statut;
final bool? disponible;
final String? motCle;
final String? organisationId;
final String? proposantId;
final DateTime? dateDebutCreation;
final DateTime? dateFinCreation;
final double? capaciteMin;
final double? capaciteMax;
const FiltresPropositionsAide({
this.typeAide,
this.statut,
this.disponible,
this.motCle,
this.organisationId,
this.proposantId,
this.dateDebutCreation,
this.dateFinCreation,
this.capaciteMin,
this.capaciteMax,
});
@override
List<Object?> get props => [
typeAide,
statut,
disponible,
motCle,
organisationId,
proposantId,
dateDebutCreation,
dateFinCreation,
capaciteMin,
capaciteMax,
];
/// Copie les filtres avec de nouvelles valeurs
FiltresPropositionsAide copyWith({
TypeAide? typeAide,
StatutProposition? statut,
bool? disponible,
String? motCle,
String? organisationId,
String? proposantId,
DateTime? dateDebutCreation,
DateTime? dateFinCreation,
double? capaciteMin,
double? capaciteMax,
}) {
return FiltresPropositionsAide(
typeAide: typeAide ?? this.typeAide,
statut: statut ?? this.statut,
disponible: disponible ?? this.disponible,
motCle: motCle ?? this.motCle,
organisationId: organisationId ?? this.organisationId,
proposantId: proposantId ?? this.proposantId,
dateDebutCreation: dateDebutCreation ?? this.dateDebutCreation,
dateFinCreation: dateFinCreation ?? this.dateFinCreation,
capaciteMin: capaciteMin ?? this.capaciteMin,
capaciteMax: capaciteMax ?? this.capaciteMax,
);
}
/// Réinitialise tous les filtres
FiltresPropositionsAide clear() {
return const FiltresPropositionsAide();
}
/// Vérifie si les filtres sont vides
bool get isEmpty {
return typeAide == null &&
statut == null &&
disponible == null &&
(motCle == null || motCle!.isEmpty) &&
organisationId == null &&
proposantId == null &&
dateDebutCreation == null &&
dateFinCreation == null &&
capaciteMin == null &&
capaciteMax == null;
}
/// Obtient le nombre de filtres actifs
int get nombreFiltresActifs {
int count = 0;
if (typeAide != null) count++;
if (statut != null) count++;
if (disponible != null) count++;
if (motCle != null && motCle!.isNotEmpty) count++;
if (organisationId != null) count++;
if (proposantId != null) count++;
if (dateDebutCreation != null) count++;
if (dateFinCreation != null) count++;
if (capaciteMin != null) count++;
if (capaciteMax != null) count++;
return count;
}
/// Obtient une description textuelle des filtres
String get description {
final parts = <String>[];
if (typeAide != null) parts.add('Type: ${typeAide!.libelle}');
if (statut != null) parts.add('Statut: ${statut!.libelle}');
if (disponible == true) parts.add('Disponible uniquement');
if (disponible == false) parts.add('Non disponible uniquement');
if (motCle != null && motCle!.isNotEmpty) parts.add('Recherche: "$motCle"');
if (capaciteMin != null || capaciteMax != null) {
if (capaciteMin != null && capaciteMax != null) {
parts.add('Capacité: ${capaciteMin!.toInt()} - ${capaciteMax!.toInt()}');
} else if (capaciteMin != null) {
parts.add('Capacité min: ${capaciteMin!.toInt()}');
} else {
parts.add('Capacité max: ${capaciteMax!.toInt()}');
}
}
return parts.join(', ');
}
}
/// Énumération pour les types d'opération
enum TypeOperationProposition {
creation,
modification,
activation,
desactivation,
suppression,
export,
}
/// Extension pour obtenir le libellé des opérations
extension TypeOperationPropositionExtension on TypeOperationProposition {
String get libelle {
switch (this) {
case TypeOperationProposition.creation:
return 'Création';
case TypeOperationProposition.modification:
return 'Modification';
case TypeOperationProposition.activation:
return 'Activation';
case TypeOperationProposition.desactivation:
return 'Désactivation';
case TypeOperationProposition.suppression:
return 'Suppression';
case TypeOperationProposition.export:
return 'Export';
}
}
String get messageSucces {
switch (this) {
case TypeOperationProposition.creation:
return 'Proposition d\'aide créée avec succès';
case TypeOperationProposition.modification:
return 'Proposition d\'aide modifiée avec succès';
case TypeOperationProposition.activation:
return 'Proposition d\'aide activée avec succès';
case TypeOperationProposition.desactivation:
return 'Proposition d\'aide désactivée avec succès';
case TypeOperationProposition.suppression:
return 'Proposition d\'aide supprimée avec succès';
case TypeOperationProposition.export:
return 'Export réalisé avec succès';
}
}
}