Version propre - Dashboard enhanced
This commit is contained in:
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user