Version propre - Dashboard enhanced

This commit is contained in:
DahoudG
2025-09-13 19:05:06 +00:00
parent 3df010add7
commit 73459b3092
70 changed files with 15317 additions and 1498 deletions

View File

@@ -0,0 +1,509 @@
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:injectable/injectable.dart';
import '../../../../core/models/cotisation_model.dart';
import '../../domain/repositories/cotisation_repository.dart';
import 'cotisations_event.dart';
import 'cotisations_state.dart';
/// BLoC pour la gestion des cotisations
/// Gère l'état et les événements liés aux cotisations
@injectable
class CotisationsBloc extends Bloc<CotisationsEvent, CotisationsState> {
final CotisationRepository _cotisationRepository;
CotisationsBloc(this._cotisationRepository) : super(const CotisationsInitial()) {
// Enregistrement des handlers d'événements
on<LoadCotisations>(_onLoadCotisations);
on<LoadCotisationById>(_onLoadCotisationById);
on<LoadCotisationByReference>(_onLoadCotisationByReference);
on<CreateCotisation>(_onCreateCotisation);
on<UpdateCotisation>(_onUpdateCotisation);
on<DeleteCotisation>(_onDeleteCotisation);
on<LoadCotisationsByMembre>(_onLoadCotisationsByMembre);
on<LoadCotisationsByStatut>(_onLoadCotisationsByStatut);
on<LoadCotisationsEnRetard>(_onLoadCotisationsEnRetard);
on<SearchCotisations>(_onSearchCotisations);
on<LoadCotisationsStats>(_onLoadCotisationsStats);
on<RefreshCotisations>(_onRefreshCotisations);
on<ResetCotisationsState>(_onResetCotisationsState);
on<FilterCotisations>(_onFilterCotisations);
on<SortCotisations>(_onSortCotisations);
}
/// Handler pour charger la liste des cotisations
Future<void> _onLoadCotisations(
LoadCotisations event,
Emitter<CotisationsState> emit,
) async {
try {
if (event.refresh || state is CotisationsInitial) {
emit(CotisationsLoading(isRefreshing: event.refresh));
}
final cotisations = await _cotisationRepository.getCotisations(
page: event.page,
size: event.size,
);
List<CotisationModel> allCotisations = [];
// Si c'est un refresh ou la première page, remplacer la liste
if (event.refresh || event.page == 0) {
allCotisations = cotisations;
} else {
// Sinon, ajouter à la liste existante (pagination)
if (state is CotisationsLoaded) {
final currentState = state as CotisationsLoaded;
allCotisations = [...currentState.cotisations, ...cotisations];
} else {
allCotisations = cotisations;
}
}
emit(CotisationsLoaded(
cotisations: allCotisations,
filteredCotisations: allCotisations,
hasReachedMax: cotisations.length < event.size,
currentPage: event.page,
));
} catch (error) {
emit(CotisationsError(
'Erreur lors du chargement des cotisations: ${error.toString()}',
originalError: error,
));
}
}
/// Handler pour charger une cotisation par ID
Future<void> _onLoadCotisationById(
LoadCotisationById event,
Emitter<CotisationsState> emit,
) async {
try {
emit(const CotisationsLoading());
final cotisation = await _cotisationRepository.getCotisationById(event.id);
emit(CotisationDetailLoaded(cotisation));
} catch (error) {
emit(CotisationsError(
'Erreur lors du chargement de la cotisation: ${error.toString()}',
originalError: error,
));
}
}
/// Handler pour charger une cotisation par référence
Future<void> _onLoadCotisationByReference(
LoadCotisationByReference event,
Emitter<CotisationsState> emit,
) async {
try {
emit(const CotisationsLoading());
final cotisation = await _cotisationRepository.getCotisationByReference(event.numeroReference);
emit(CotisationDetailLoaded(cotisation));
} catch (error) {
emit(CotisationsError(
'Erreur lors du chargement de la cotisation: ${error.toString()}',
originalError: error,
));
}
}
/// Handler pour créer une nouvelle cotisation
Future<void> _onCreateCotisation(
CreateCotisation event,
Emitter<CotisationsState> emit,
) async {
try {
emit(const CotisationOperationLoading('create'));
final nouvelleCotisation = await _cotisationRepository.createCotisation(event.cotisation);
emit(CotisationCreated(nouvelleCotisation));
// Recharger la liste des cotisations
add(const LoadCotisations(refresh: true));
} catch (error) {
emit(CotisationsError(
'Erreur lors de la création de la cotisation: ${error.toString()}',
originalError: error,
));
}
}
/// Handler pour mettre à jour une cotisation
Future<void> _onUpdateCotisation(
UpdateCotisation event,
Emitter<CotisationsState> emit,
) async {
try {
emit(CotisationOperationLoading('update', cotisationId: event.id));
final cotisationMiseAJour = await _cotisationRepository.updateCotisation(
event.id,
event.cotisation,
);
emit(CotisationUpdated(cotisationMiseAJour));
// Mettre à jour la liste si elle est chargée
if (state is CotisationsLoaded) {
final currentState = state as CotisationsLoaded;
final updatedList = currentState.cotisations.map((c) {
return c.id == event.id ? cotisationMiseAJour : c;
}).toList();
emit(currentState.copyWith(
cotisations: updatedList,
filteredCotisations: updatedList,
));
}
} catch (error) {
emit(CotisationsError(
'Erreur lors de la mise à jour de la cotisation: ${error.toString()}',
originalError: error,
));
}
}
/// Handler pour supprimer une cotisation
Future<void> _onDeleteCotisation(
DeleteCotisation event,
Emitter<CotisationsState> emit,
) async {
try {
emit(CotisationOperationLoading('delete', cotisationId: event.id));
await _cotisationRepository.deleteCotisation(event.id);
emit(CotisationDeleted(event.id));
// Retirer de la liste si elle est chargée
if (state is CotisationsLoaded) {
final currentState = state as CotisationsLoaded;
final updatedList = currentState.cotisations
.where((c) => c.id != event.id)
.toList();
emit(currentState.copyWith(
cotisations: updatedList,
filteredCotisations: updatedList,
));
}
} catch (error) {
emit(CotisationsError(
'Erreur lors de la suppression de la cotisation: ${error.toString()}',
originalError: error,
));
}
}
/// Handler pour charger les cotisations d'un membre
Future<void> _onLoadCotisationsByMembre(
LoadCotisationsByMembre event,
Emitter<CotisationsState> emit,
) async {
try {
if (event.refresh || event.page == 0) {
emit(CotisationsLoading(isRefreshing: event.refresh));
}
final cotisations = await _cotisationRepository.getCotisationsByMembre(
event.membreId,
page: event.page,
size: event.size,
);
List<CotisationModel> allCotisations = [];
if (event.refresh || event.page == 0) {
allCotisations = cotisations;
} else {
if (state is CotisationsByMembreLoaded) {
final currentState = state as CotisationsByMembreLoaded;
allCotisations = [...currentState.cotisations, ...cotisations];
} else {
allCotisations = cotisations;
}
}
emit(CotisationsByMembreLoaded(
membreId: event.membreId,
cotisations: allCotisations,
hasReachedMax: cotisations.length < event.size,
currentPage: event.page,
));
} catch (error) {
emit(CotisationsError(
'Erreur lors du chargement des cotisations du membre: ${error.toString()}',
originalError: error,
));
}
}
/// Handler pour charger les cotisations par statut
Future<void> _onLoadCotisationsByStatut(
LoadCotisationsByStatut event,
Emitter<CotisationsState> emit,
) async {
try {
if (event.refresh || event.page == 0) {
emit(CotisationsLoading(isRefreshing: event.refresh));
}
final cotisations = await _cotisationRepository.getCotisationsByStatut(
event.statut,
page: event.page,
size: event.size,
);
List<CotisationModel> allCotisations = [];
if (event.refresh || event.page == 0) {
allCotisations = cotisations;
} else {
if (state is CotisationsLoaded) {
final currentState = state as CotisationsLoaded;
allCotisations = [...currentState.cotisations, ...cotisations];
} else {
allCotisations = cotisations;
}
}
emit(CotisationsLoaded(
cotisations: allCotisations,
filteredCotisations: allCotisations,
hasReachedMax: cotisations.length < event.size,
currentPage: event.page,
currentFilter: event.statut,
));
} catch (error) {
emit(CotisationsError(
'Erreur lors du chargement des cotisations par statut: ${error.toString()}',
originalError: error,
));
}
}
/// Handler pour charger les cotisations en retard
Future<void> _onLoadCotisationsEnRetard(
LoadCotisationsEnRetard event,
Emitter<CotisationsState> emit,
) async {
try {
if (event.refresh || event.page == 0) {
emit(CotisationsLoading(isRefreshing: event.refresh));
}
final cotisations = await _cotisationRepository.getCotisationsEnRetard(
page: event.page,
size: event.size,
);
List<CotisationModel> allCotisations = [];
if (event.refresh || event.page == 0) {
allCotisations = cotisations;
} else {
if (state is CotisationsEnRetardLoaded) {
final currentState = state as CotisationsEnRetardLoaded;
allCotisations = [...currentState.cotisations, ...cotisations];
} else {
allCotisations = cotisations;
}
}
emit(CotisationsEnRetardLoaded(
cotisations: allCotisations,
hasReachedMax: cotisations.length < event.size,
currentPage: event.page,
));
} catch (error) {
emit(CotisationsError(
'Erreur lors du chargement des cotisations en retard: ${error.toString()}',
originalError: error,
));
}
}
/// Handler pour la recherche de cotisations
Future<void> _onSearchCotisations(
SearchCotisations event,
Emitter<CotisationsState> emit,
) async {
try {
if (event.refresh || event.page == 0) {
emit(CotisationsLoading(isRefreshing: event.refresh));
}
final cotisations = await _cotisationRepository.rechercherCotisations(
membreId: event.membreId,
statut: event.statut,
typeCotisation: event.typeCotisation,
annee: event.annee,
mois: event.mois,
page: event.page,
size: event.size,
);
final searchCriteria = <String, dynamic>{
if (event.membreId != null) 'membreId': event.membreId,
if (event.statut != null) 'statut': event.statut,
if (event.typeCotisation != null) 'typeCotisation': event.typeCotisation,
if (event.annee != null) 'annee': event.annee,
if (event.mois != null) 'mois': event.mois,
};
List<CotisationModel> allCotisations = [];
if (event.refresh || event.page == 0) {
allCotisations = cotisations;
} else {
if (state is CotisationsSearchResults) {
final currentState = state as CotisationsSearchResults;
allCotisations = [...currentState.cotisations, ...cotisations];
} else {
allCotisations = cotisations;
}
}
emit(CotisationsSearchResults(
cotisations: allCotisations,
searchCriteria: searchCriteria,
hasReachedMax: cotisations.length < event.size,
currentPage: event.page,
));
} catch (error) {
emit(CotisationsError(
'Erreur lors de la recherche de cotisations: ${error.toString()}',
originalError: error,
));
}
}
/// Handler pour charger les statistiques
Future<void> _onLoadCotisationsStats(
LoadCotisationsStats event,
Emitter<CotisationsState> emit,
) async {
try {
emit(const CotisationsLoading());
final statistics = await _cotisationRepository.getCotisationsStats();
emit(CotisationsStatsLoaded(statistics));
} catch (error) {
emit(CotisationsError(
'Erreur lors du chargement des statistiques: ${error.toString()}',
originalError: error,
));
}
}
/// Handler pour rafraîchir les données
Future<void> _onRefreshCotisations(
RefreshCotisations event,
Emitter<CotisationsState> emit,
) async {
add(const LoadCotisations(refresh: true));
}
/// Handler pour réinitialiser l'état
Future<void> _onResetCotisationsState(
ResetCotisationsState event,
Emitter<CotisationsState> emit,
) async {
emit(const CotisationsInitial());
}
/// Handler pour filtrer les cotisations localement
Future<void> _onFilterCotisations(
FilterCotisations event,
Emitter<CotisationsState> emit,
) async {
if (state is CotisationsLoaded) {
final currentState = state as CotisationsLoaded;
List<CotisationModel> filteredList = currentState.cotisations;
// Filtrage par recherche textuelle
if (event.searchQuery != null && event.searchQuery!.isNotEmpty) {
final query = event.searchQuery!.toLowerCase();
filteredList = filteredList.where((cotisation) {
return cotisation.numeroReference.toLowerCase().contains(query) ||
(cotisation.nomMembre?.toLowerCase().contains(query) ?? false) ||
cotisation.typeCotisation.toLowerCase().contains(query) ||
(cotisation.description?.toLowerCase().contains(query) ?? false);
}).toList();
}
// Filtrage par statut
if (event.statutFilter != null && event.statutFilter!.isNotEmpty) {
filteredList = filteredList.where((cotisation) {
return cotisation.statut == event.statutFilter;
}).toList();
}
// Filtrage par type
if (event.typeFilter != null && event.typeFilter!.isNotEmpty) {
filteredList = filteredList.where((cotisation) {
return cotisation.typeCotisation == event.typeFilter;
}).toList();
}
emit(currentState.copyWith(
filteredCotisations: filteredList,
searchQuery: event.searchQuery,
currentFilter: event.statutFilter ?? event.typeFilter,
));
}
}
/// Handler pour trier les cotisations
Future<void> _onSortCotisations(
SortCotisations event,
Emitter<CotisationsState> emit,
) async {
if (state is CotisationsLoaded) {
final currentState = state as CotisationsLoaded;
List<CotisationModel> sortedList = [...currentState.filteredCotisations];
switch (event.sortBy) {
case 'dateEcheance':
sortedList.sort((a, b) => event.ascending
? a.dateEcheance.compareTo(b.dateEcheance)
: b.dateEcheance.compareTo(a.dateEcheance));
break;
case 'montantDu':
sortedList.sort((a, b) => event.ascending
? a.montantDu.compareTo(b.montantDu)
: b.montantDu.compareTo(a.montantDu));
break;
case 'statut':
sortedList.sort((a, b) => event.ascending
? a.statut.compareTo(b.statut)
: b.statut.compareTo(a.statut));
break;
case 'nomMembre':
sortedList.sort((a, b) => event.ascending
? (a.nomMembre ?? '').compareTo(b.nomMembre ?? '')
: (b.nomMembre ?? '').compareTo(a.nomMembre ?? ''));
break;
case 'typeCotisation':
sortedList.sort((a, b) => event.ascending
? a.typeCotisation.compareTo(b.typeCotisation)
: b.typeCotisation.compareTo(a.typeCotisation));
break;
default:
// Tri par défaut par date d'échéance
sortedList.sort((a, b) => b.dateEcheance.compareTo(a.dateEcheance));
}
emit(currentState.copyWith(filteredCotisations: sortedList));
}
}
}

View File

@@ -0,0 +1,206 @@
import 'package:equatable/equatable.dart';
import '../../../../core/models/cotisation_model.dart';
/// Événements du BLoC des cotisations
abstract class CotisationsEvent extends Equatable {
const CotisationsEvent();
@override
List<Object?> get props => [];
}
/// Événement pour charger la liste des cotisations
class LoadCotisations extends CotisationsEvent {
final int page;
final int size;
final bool refresh;
const LoadCotisations({
this.page = 0,
this.size = 20,
this.refresh = false,
});
@override
List<Object?> get props => [page, size, refresh];
}
/// Événement pour charger une cotisation par ID
class LoadCotisationById extends CotisationsEvent {
final String id;
const LoadCotisationById(this.id);
@override
List<Object?> get props => [id];
}
/// Événement pour charger une cotisation par référence
class LoadCotisationByReference extends CotisationsEvent {
final String numeroReference;
const LoadCotisationByReference(this.numeroReference);
@override
List<Object?> get props => [numeroReference];
}
/// Événement pour créer une nouvelle cotisation
class CreateCotisation extends CotisationsEvent {
final CotisationModel cotisation;
const CreateCotisation(this.cotisation);
@override
List<Object?> get props => [cotisation];
}
/// Événement pour mettre à jour une cotisation
class UpdateCotisation extends CotisationsEvent {
final String id;
final CotisationModel cotisation;
const UpdateCotisation(this.id, this.cotisation);
@override
List<Object?> get props => [id, cotisation];
}
/// Événement pour supprimer une cotisation
class DeleteCotisation extends CotisationsEvent {
final String id;
const DeleteCotisation(this.id);
@override
List<Object?> get props => [id];
}
/// Événement pour charger les cotisations d'un membre
class LoadCotisationsByMembre extends CotisationsEvent {
final String membreId;
final int page;
final int size;
final bool refresh;
const LoadCotisationsByMembre(
this.membreId, {
this.page = 0,
this.size = 20,
this.refresh = false,
});
@override
List<Object?> get props => [membreId, page, size, refresh];
}
/// Événement pour charger les cotisations par statut
class LoadCotisationsByStatut extends CotisationsEvent {
final String statut;
final int page;
final int size;
final bool refresh;
const LoadCotisationsByStatut(
this.statut, {
this.page = 0,
this.size = 20,
this.refresh = false,
});
@override
List<Object?> get props => [statut, page, size, refresh];
}
/// Événement pour charger les cotisations en retard
class LoadCotisationsEnRetard extends CotisationsEvent {
final int page;
final int size;
final bool refresh;
const LoadCotisationsEnRetard({
this.page = 0,
this.size = 20,
this.refresh = false,
});
@override
List<Object?> get props => [page, size, refresh];
}
/// Événement pour rechercher des cotisations
class SearchCotisations extends CotisationsEvent {
final String? membreId;
final String? statut;
final String? typeCotisation;
final int? annee;
final int? mois;
final int page;
final int size;
final bool refresh;
const SearchCotisations({
this.membreId,
this.statut,
this.typeCotisation,
this.annee,
this.mois,
this.page = 0,
this.size = 20,
this.refresh = false,
});
@override
List<Object?> get props => [
membreId,
statut,
typeCotisation,
annee,
mois,
page,
size,
refresh,
];
}
/// Événement pour charger les statistiques
class LoadCotisationsStats extends CotisationsEvent {
const LoadCotisationsStats();
}
/// Événement pour rafraîchir les données
class RefreshCotisations extends CotisationsEvent {
const RefreshCotisations();
}
/// Événement pour réinitialiser l'état
class ResetCotisationsState extends CotisationsEvent {
const ResetCotisationsState();
}
/// Événement pour filtrer les cotisations localement
class FilterCotisations extends CotisationsEvent {
final String? searchQuery;
final String? statutFilter;
final String? typeFilter;
const FilterCotisations({
this.searchQuery,
this.statutFilter,
this.typeFilter,
});
@override
List<Object?> get props => [searchQuery, statutFilter, typeFilter];
}
/// Événement pour trier les cotisations
class SortCotisations extends CotisationsEvent {
final String sortBy; // 'dateEcheance', 'montantDu', 'statut', etc.
final bool ascending;
const SortCotisations(this.sortBy, {this.ascending = true});
@override
List<Object?> get props => [sortBy, ascending];
}

View File

@@ -0,0 +1,247 @@
import 'package:equatable/equatable.dart';
import '../../../../core/models/cotisation_model.dart';
/// États du BLoC des cotisations
abstract class CotisationsState extends Equatable {
const CotisationsState();
@override
List<Object?> get props => [];
}
/// État initial
class CotisationsInitial extends CotisationsState {
const CotisationsInitial();
}
/// État de chargement
class CotisationsLoading extends CotisationsState {
final bool isRefreshing;
const CotisationsLoading({this.isRefreshing = false});
@override
List<Object?> get props => [isRefreshing];
}
/// État de succès avec liste des cotisations
class CotisationsLoaded extends CotisationsState {
final List<CotisationModel> cotisations;
final List<CotisationModel> filteredCotisations;
final Map<String, dynamic>? statistics;
final bool hasReachedMax;
final int currentPage;
final String? currentFilter;
final String? searchQuery;
const CotisationsLoaded({
required this.cotisations,
required this.filteredCotisations,
this.statistics,
this.hasReachedMax = false,
this.currentPage = 0,
this.currentFilter,
this.searchQuery,
});
/// Copie avec modifications
CotisationsLoaded copyWith({
List<CotisationModel>? cotisations,
List<CotisationModel>? filteredCotisations,
Map<String, dynamic>? statistics,
bool? hasReachedMax,
int? currentPage,
String? currentFilter,
String? searchQuery,
}) {
return CotisationsLoaded(
cotisations: cotisations ?? this.cotisations,
filteredCotisations: filteredCotisations ?? this.filteredCotisations,
statistics: statistics ?? this.statistics,
hasReachedMax: hasReachedMax ?? this.hasReachedMax,
currentPage: currentPage ?? this.currentPage,
currentFilter: currentFilter ?? this.currentFilter,
searchQuery: searchQuery ?? this.searchQuery,
);
}
@override
List<Object?> get props => [
cotisations,
filteredCotisations,
statistics,
hasReachedMax,
currentPage,
currentFilter,
searchQuery,
];
}
/// État de succès pour une cotisation unique
class CotisationDetailLoaded extends CotisationsState {
final CotisationModel cotisation;
const CotisationDetailLoaded(this.cotisation);
@override
List<Object?> get props => [cotisation];
}
/// État de succès pour la création d'une cotisation
class CotisationCreated extends CotisationsState {
final CotisationModel cotisation;
const CotisationCreated(this.cotisation);
@override
List<Object?> get props => [cotisation];
}
/// État de succès pour la mise à jour d'une cotisation
class CotisationUpdated extends CotisationsState {
final CotisationModel cotisation;
const CotisationUpdated(this.cotisation);
@override
List<Object?> get props => [cotisation];
}
/// État de succès pour la suppression d'une cotisation
class CotisationDeleted extends CotisationsState {
final String cotisationId;
const CotisationDeleted(this.cotisationId);
@override
List<Object?> get props => [cotisationId];
}
/// État d'erreur
class CotisationsError extends CotisationsState {
final String message;
final String? errorCode;
final dynamic originalError;
const CotisationsError(
this.message, {
this.errorCode,
this.originalError,
});
@override
List<Object?> get props => [message, errorCode, originalError];
}
/// État de chargement pour une opération spécifique
class CotisationOperationLoading extends CotisationsState {
final String operation; // 'create', 'update', 'delete'
final String? cotisationId;
const CotisationOperationLoading(this.operation, {this.cotisationId});
@override
List<Object?> get props => [operation, cotisationId];
}
/// État de succès pour les statistiques
class CotisationsStatsLoaded extends CotisationsState {
final Map<String, dynamic> statistics;
const CotisationsStatsLoaded(this.statistics);
@override
List<Object?> get props => [statistics];
}
/// État pour les cotisations filtrées par membre
class CotisationsByMembreLoaded extends CotisationsState {
final String membreId;
final List<CotisationModel> cotisations;
final bool hasReachedMax;
final int currentPage;
const CotisationsByMembreLoaded({
required this.membreId,
required this.cotisations,
this.hasReachedMax = false,
this.currentPage = 0,
});
CotisationsByMembreLoaded copyWith({
String? membreId,
List<CotisationModel>? cotisations,
bool? hasReachedMax,
int? currentPage,
}) {
return CotisationsByMembreLoaded(
membreId: membreId ?? this.membreId,
cotisations: cotisations ?? this.cotisations,
hasReachedMax: hasReachedMax ?? this.hasReachedMax,
currentPage: currentPage ?? this.currentPage,
);
}
@override
List<Object?> get props => [membreId, cotisations, hasReachedMax, currentPage];
}
/// État pour les cotisations en retard
class CotisationsEnRetardLoaded extends CotisationsState {
final List<CotisationModel> cotisations;
final bool hasReachedMax;
final int currentPage;
const CotisationsEnRetardLoaded({
required this.cotisations,
this.hasReachedMax = false,
this.currentPage = 0,
});
CotisationsEnRetardLoaded copyWith({
List<CotisationModel>? cotisations,
bool? hasReachedMax,
int? currentPage,
}) {
return CotisationsEnRetardLoaded(
cotisations: cotisations ?? this.cotisations,
hasReachedMax: hasReachedMax ?? this.hasReachedMax,
currentPage: currentPage ?? this.currentPage,
);
}
@override
List<Object?> get props => [cotisations, hasReachedMax, currentPage];
}
/// État pour les résultats de recherche
class CotisationsSearchResults extends CotisationsState {
final List<CotisationModel> cotisations;
final Map<String, dynamic> searchCriteria;
final bool hasReachedMax;
final int currentPage;
const CotisationsSearchResults({
required this.cotisations,
required this.searchCriteria,
this.hasReachedMax = false,
this.currentPage = 0,
});
CotisationsSearchResults copyWith({
List<CotisationModel>? cotisations,
Map<String, dynamic>? searchCriteria,
bool? hasReachedMax,
int? currentPage,
}) {
return CotisationsSearchResults(
cotisations: cotisations ?? this.cotisations,
searchCriteria: searchCriteria ?? this.searchCriteria,
hasReachedMax: hasReachedMax ?? this.hasReachedMax,
currentPage: currentPage ?? this.currentPage,
);
}
@override
List<Object?> get props => [cotisations, searchCriteria, hasReachedMax, currentPage];
}