510 lines
16 KiB
Dart
510 lines
16 KiB
Dart
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));
|
|
}
|
|
}
|
|
}
|