489 lines
15 KiB
Dart
489 lines
15 KiB
Dart
/// BLoC pour la gestion des organisations
|
|
library organisations_bloc;
|
|
|
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
|
import '../data/models/organisation_model.dart';
|
|
import '../data/services/organisation_service.dart';
|
|
import 'organisations_event.dart';
|
|
import 'organisations_state.dart';
|
|
|
|
/// BLoC principal pour la gestion des organisations
|
|
class OrganisationsBloc extends Bloc<OrganisationsEvent, OrganisationsState> {
|
|
final OrganisationService _organisationService;
|
|
|
|
OrganisationsBloc(this._organisationService) : super(const OrganisationsInitial()) {
|
|
// Enregistrement des handlers d'événements
|
|
on<LoadOrganisations>(_onLoadOrganisations);
|
|
on<LoadMoreOrganisations>(_onLoadMoreOrganisations);
|
|
on<SearchOrganisations>(_onSearchOrganisations);
|
|
on<AdvancedSearchOrganisations>(_onAdvancedSearchOrganisations);
|
|
on<LoadOrganisationById>(_onLoadOrganisationById);
|
|
on<CreateOrganisation>(_onCreateOrganisation);
|
|
on<UpdateOrganisation>(_onUpdateOrganisation);
|
|
on<DeleteOrganisation>(_onDeleteOrganisation);
|
|
on<ActivateOrganisation>(_onActivateOrganisation);
|
|
on<FilterOrganisationsByStatus>(_onFilterOrganisationsByStatus);
|
|
on<FilterOrganisationsByType>(_onFilterOrganisationsByType);
|
|
on<SortOrganisations>(_onSortOrganisations);
|
|
on<LoadOrganisationsStats>(_onLoadOrganisationsStats);
|
|
on<ClearOrganisationsFilters>(_onClearOrganisationsFilters);
|
|
on<RefreshOrganisations>(_onRefreshOrganisations);
|
|
on<ResetOrganisationsState>(_onResetOrganisationsState);
|
|
}
|
|
|
|
/// Charge la liste des organisations
|
|
Future<void> _onLoadOrganisations(
|
|
LoadOrganisations event,
|
|
Emitter<OrganisationsState> emit,
|
|
) async {
|
|
try {
|
|
if (event.refresh || state is! OrganisationsLoaded) {
|
|
emit(const OrganisationsLoading());
|
|
}
|
|
|
|
final organisations = await _organisationService.getOrganisations(
|
|
page: event.page,
|
|
size: event.size,
|
|
recherche: event.recherche,
|
|
);
|
|
|
|
emit(OrganisationsLoaded(
|
|
organisations: organisations,
|
|
filteredOrganisations: organisations,
|
|
hasReachedMax: organisations.length < event.size,
|
|
currentPage: event.page,
|
|
currentSearch: event.recherche,
|
|
));
|
|
} catch (e) {
|
|
emit(OrganisationsError(
|
|
'Erreur lors du chargement des organisations',
|
|
details: e.toString(),
|
|
));
|
|
}
|
|
}
|
|
|
|
/// Charge plus d'organisations (pagination)
|
|
Future<void> _onLoadMoreOrganisations(
|
|
LoadMoreOrganisations event,
|
|
Emitter<OrganisationsState> emit,
|
|
) async {
|
|
final currentState = state;
|
|
if (currentState is! OrganisationsLoaded || currentState.hasReachedMax) {
|
|
return;
|
|
}
|
|
|
|
emit(OrganisationsLoadingMore(currentState.organisations));
|
|
|
|
try {
|
|
final nextPage = currentState.currentPage + 1;
|
|
final newOrganisations = await _organisationService.getOrganisations(
|
|
page: nextPage,
|
|
size: 20,
|
|
recherche: currentState.currentSearch,
|
|
);
|
|
|
|
final allOrganisations = [...currentState.organisations, ...newOrganisations];
|
|
final filteredOrganisations = _applyCurrentFilters(allOrganisations, currentState);
|
|
|
|
emit(currentState.copyWith(
|
|
organisations: allOrganisations,
|
|
filteredOrganisations: filteredOrganisations,
|
|
hasReachedMax: newOrganisations.length < 20,
|
|
currentPage: nextPage,
|
|
));
|
|
} catch (e) {
|
|
emit(OrganisationsError(
|
|
'Erreur lors du chargement de plus d\'organisations',
|
|
details: e.toString(),
|
|
previousOrganisations: currentState.organisations,
|
|
));
|
|
}
|
|
}
|
|
|
|
/// Recherche des organisations
|
|
Future<void> _onSearchOrganisations(
|
|
SearchOrganisations event,
|
|
Emitter<OrganisationsState> emit,
|
|
) async {
|
|
final currentState = state;
|
|
if (currentState is! OrganisationsLoaded) {
|
|
// Si pas encore chargé, charger avec recherche
|
|
add(LoadOrganisations(recherche: event.query, refresh: true));
|
|
return;
|
|
}
|
|
|
|
try {
|
|
if (event.query.isEmpty) {
|
|
// Recherche vide, afficher toutes les organisations
|
|
final filteredOrganisations = _applyCurrentFilters(
|
|
currentState.organisations,
|
|
currentState.copyWith(clearSearch: true),
|
|
);
|
|
emit(currentState.copyWith(
|
|
filteredOrganisations: filteredOrganisations,
|
|
clearSearch: true,
|
|
));
|
|
} else {
|
|
// Recherche locale d'abord
|
|
final localResults = _organisationService.searchLocal(
|
|
currentState.organisations,
|
|
event.query,
|
|
);
|
|
|
|
emit(currentState.copyWith(
|
|
filteredOrganisations: localResults,
|
|
currentSearch: event.query,
|
|
));
|
|
|
|
// Puis recherche serveur pour plus de résultats
|
|
final serverResults = await _organisationService.getOrganisations(
|
|
page: 0,
|
|
size: 50,
|
|
recherche: event.query,
|
|
);
|
|
|
|
final filteredResults = _applyCurrentFilters(serverResults, currentState);
|
|
emit(currentState.copyWith(
|
|
organisations: serverResults,
|
|
filteredOrganisations: filteredResults,
|
|
currentSearch: event.query,
|
|
currentPage: 0,
|
|
hasReachedMax: true,
|
|
));
|
|
}
|
|
} catch (e) {
|
|
emit(OrganisationsError(
|
|
'Erreur lors de la recherche',
|
|
details: e.toString(),
|
|
previousOrganisations: currentState.organisations,
|
|
));
|
|
}
|
|
}
|
|
|
|
/// Recherche avancée
|
|
Future<void> _onAdvancedSearchOrganisations(
|
|
AdvancedSearchOrganisations event,
|
|
Emitter<OrganisationsState> emit,
|
|
) async {
|
|
emit(const OrganisationsLoading());
|
|
|
|
try {
|
|
final organisations = await _organisationService.searchOrganisations(
|
|
nom: event.nom,
|
|
type: event.type,
|
|
statut: event.statut,
|
|
ville: event.ville,
|
|
region: event.region,
|
|
pays: event.pays,
|
|
page: event.page,
|
|
size: event.size,
|
|
);
|
|
|
|
emit(OrganisationsLoaded(
|
|
organisations: organisations,
|
|
filteredOrganisations: organisations,
|
|
hasReachedMax: organisations.length < event.size,
|
|
currentPage: event.page,
|
|
typeFilter: event.type,
|
|
statusFilter: event.statut,
|
|
));
|
|
} catch (e) {
|
|
emit(OrganisationsError(
|
|
'Erreur lors de la recherche avancée',
|
|
details: e.toString(),
|
|
));
|
|
}
|
|
}
|
|
|
|
/// Charge une organisation par ID
|
|
Future<void> _onLoadOrganisationById(
|
|
LoadOrganisationById event,
|
|
Emitter<OrganisationsState> emit,
|
|
) async {
|
|
emit(OrganisationLoading(event.id));
|
|
|
|
try {
|
|
final organisation = await _organisationService.getOrganisationById(event.id);
|
|
if (organisation != null) {
|
|
emit(OrganisationLoaded(organisation));
|
|
} else {
|
|
emit(OrganisationError('Organisation non trouvée', organisationId: event.id));
|
|
}
|
|
} catch (e) {
|
|
emit(OrganisationError(
|
|
'Erreur lors du chargement de l\'organisation',
|
|
organisationId: event.id,
|
|
));
|
|
}
|
|
}
|
|
|
|
/// Crée une nouvelle organisation
|
|
Future<void> _onCreateOrganisation(
|
|
CreateOrganisation event,
|
|
Emitter<OrganisationsState> emit,
|
|
) async {
|
|
emit(const OrganisationCreating());
|
|
|
|
try {
|
|
final createdOrganisation = await _organisationService.createOrganisation(event.organisation);
|
|
emit(OrganisationCreated(createdOrganisation));
|
|
|
|
// Recharger la liste si elle était déjà chargée
|
|
if (state is OrganisationsLoaded) {
|
|
add(const RefreshOrganisations());
|
|
}
|
|
} catch (e) {
|
|
emit(OrganisationsError(
|
|
'Erreur lors de la création de l\'organisation',
|
|
details: e.toString(),
|
|
));
|
|
}
|
|
}
|
|
|
|
/// Met à jour une organisation
|
|
Future<void> _onUpdateOrganisation(
|
|
UpdateOrganisation event,
|
|
Emitter<OrganisationsState> emit,
|
|
) async {
|
|
emit(OrganisationUpdating(event.id));
|
|
|
|
try {
|
|
final updatedOrganisation = await _organisationService.updateOrganisation(
|
|
event.id,
|
|
event.organisation,
|
|
);
|
|
emit(OrganisationUpdated(updatedOrganisation));
|
|
|
|
// Mettre à jour la liste si elle était déjà chargée
|
|
final currentState = state;
|
|
if (currentState is OrganisationsLoaded) {
|
|
final updatedList = currentState.organisations.map((org) {
|
|
return org.id == event.id ? updatedOrganisation : org;
|
|
}).toList();
|
|
|
|
final filteredList = _applyCurrentFilters(updatedList, currentState);
|
|
emit(currentState.copyWith(
|
|
organisations: updatedList,
|
|
filteredOrganisations: filteredList,
|
|
));
|
|
}
|
|
} catch (e) {
|
|
emit(OrganisationsError(
|
|
'Erreur lors de la mise à jour de l\'organisation',
|
|
details: e.toString(),
|
|
));
|
|
}
|
|
}
|
|
|
|
/// Supprime une organisation
|
|
Future<void> _onDeleteOrganisation(
|
|
DeleteOrganisation event,
|
|
Emitter<OrganisationsState> emit,
|
|
) async {
|
|
emit(OrganisationDeleting(event.id));
|
|
|
|
try {
|
|
await _organisationService.deleteOrganisation(event.id);
|
|
emit(OrganisationDeleted(event.id));
|
|
|
|
// Retirer de la liste si elle était déjà chargée
|
|
final currentState = state;
|
|
if (currentState is OrganisationsLoaded) {
|
|
final updatedList = currentState.organisations.where((org) => org.id != event.id).toList();
|
|
final filteredList = _applyCurrentFilters(updatedList, currentState);
|
|
emit(currentState.copyWith(
|
|
organisations: updatedList,
|
|
filteredOrganisations: filteredList,
|
|
));
|
|
}
|
|
} catch (e) {
|
|
emit(OrganisationsError(
|
|
'Erreur lors de la suppression de l\'organisation',
|
|
details: e.toString(),
|
|
));
|
|
}
|
|
}
|
|
|
|
/// Active une organisation
|
|
Future<void> _onActivateOrganisation(
|
|
ActivateOrganisation event,
|
|
Emitter<OrganisationsState> emit,
|
|
) async {
|
|
emit(OrganisationActivating(event.id));
|
|
|
|
try {
|
|
final activatedOrganisation = await _organisationService.activateOrganisation(event.id);
|
|
emit(OrganisationActivated(activatedOrganisation));
|
|
|
|
// Mettre à jour la liste si elle était déjà chargée
|
|
final currentState = state;
|
|
if (currentState is OrganisationsLoaded) {
|
|
final updatedList = currentState.organisations.map((org) {
|
|
return org.id == event.id ? activatedOrganisation : org;
|
|
}).toList();
|
|
|
|
final filteredList = _applyCurrentFilters(updatedList, currentState);
|
|
emit(currentState.copyWith(
|
|
organisations: updatedList,
|
|
filteredOrganisations: filteredList,
|
|
));
|
|
}
|
|
} catch (e) {
|
|
emit(OrganisationsError(
|
|
'Erreur lors de l\'activation de l\'organisation',
|
|
details: e.toString(),
|
|
));
|
|
}
|
|
}
|
|
|
|
/// Filtre par statut
|
|
void _onFilterOrganisationsByStatus(
|
|
FilterOrganisationsByStatus event,
|
|
Emitter<OrganisationsState> emit,
|
|
) {
|
|
final currentState = state;
|
|
if (currentState is! OrganisationsLoaded) return;
|
|
|
|
final filteredOrganisations = _applyCurrentFilters(
|
|
currentState.organisations,
|
|
currentState.copyWith(statusFilter: event.statut),
|
|
);
|
|
|
|
emit(currentState.copyWith(
|
|
filteredOrganisations: filteredOrganisations,
|
|
statusFilter: event.statut,
|
|
));
|
|
}
|
|
|
|
/// Filtre par type
|
|
void _onFilterOrganisationsByType(
|
|
FilterOrganisationsByType event,
|
|
Emitter<OrganisationsState> emit,
|
|
) {
|
|
final currentState = state;
|
|
if (currentState is! OrganisationsLoaded) return;
|
|
|
|
final filteredOrganisations = _applyCurrentFilters(
|
|
currentState.organisations,
|
|
currentState.copyWith(typeFilter: event.type),
|
|
);
|
|
|
|
emit(currentState.copyWith(
|
|
filteredOrganisations: filteredOrganisations,
|
|
typeFilter: event.type,
|
|
));
|
|
}
|
|
|
|
/// Trie les organisations
|
|
void _onSortOrganisations(
|
|
SortOrganisations event,
|
|
Emitter<OrganisationsState> emit,
|
|
) {
|
|
final currentState = state;
|
|
if (currentState is! OrganisationsLoaded) return;
|
|
|
|
List<OrganisationModel> sortedOrganisations;
|
|
switch (event.sortType) {
|
|
case OrganisationSortType.nom:
|
|
sortedOrganisations = _organisationService.sortByName(
|
|
currentState.filteredOrganisations,
|
|
ascending: event.ascending,
|
|
);
|
|
break;
|
|
case OrganisationSortType.dateCreation:
|
|
sortedOrganisations = _organisationService.sortByCreationDate(
|
|
currentState.filteredOrganisations,
|
|
ascending: event.ascending,
|
|
);
|
|
break;
|
|
case OrganisationSortType.nombreMembres:
|
|
sortedOrganisations = _organisationService.sortByMemberCount(
|
|
currentState.filteredOrganisations,
|
|
ascending: event.ascending,
|
|
);
|
|
break;
|
|
default:
|
|
sortedOrganisations = currentState.filteredOrganisations;
|
|
}
|
|
|
|
emit(currentState.copyWith(
|
|
filteredOrganisations: sortedOrganisations,
|
|
sortType: event.sortType,
|
|
sortAscending: event.ascending,
|
|
));
|
|
}
|
|
|
|
/// Charge les statistiques
|
|
Future<void> _onLoadOrganisationsStats(
|
|
LoadOrganisationsStats event,
|
|
Emitter<OrganisationsState> emit,
|
|
) async {
|
|
emit(const OrganisationsStatsLoading());
|
|
|
|
try {
|
|
final stats = await _organisationService.getOrganisationsStats();
|
|
emit(OrganisationsStatsLoaded(stats));
|
|
} catch (e) {
|
|
emit(const OrganisationsStatsError('Erreur lors du chargement des statistiques'));
|
|
}
|
|
}
|
|
|
|
/// Efface les filtres
|
|
void _onClearOrganisationsFilters(
|
|
ClearOrganisationsFilters event,
|
|
Emitter<OrganisationsState> emit,
|
|
) {
|
|
final currentState = state;
|
|
if (currentState is! OrganisationsLoaded) return;
|
|
|
|
emit(currentState.copyWith(
|
|
filteredOrganisations: currentState.organisations,
|
|
clearSearch: true,
|
|
clearStatusFilter: true,
|
|
clearTypeFilter: true,
|
|
clearSort: true,
|
|
));
|
|
}
|
|
|
|
/// Rafraîchit les données
|
|
void _onRefreshOrganisations(
|
|
RefreshOrganisations event,
|
|
Emitter<OrganisationsState> emit,
|
|
) {
|
|
add(const LoadOrganisations(refresh: true));
|
|
}
|
|
|
|
/// Remet à zéro l'état
|
|
void _onResetOrganisationsState(
|
|
ResetOrganisationsState event,
|
|
Emitter<OrganisationsState> emit,
|
|
) {
|
|
emit(const OrganisationsInitial());
|
|
}
|
|
|
|
/// Applique les filtres actuels à une liste d'organisations
|
|
List<OrganisationModel> _applyCurrentFilters(
|
|
List<OrganisationModel> organisations,
|
|
OrganisationsLoaded state,
|
|
) {
|
|
var filtered = organisations;
|
|
|
|
// Filtre par recherche
|
|
if (state.currentSearch?.isNotEmpty == true) {
|
|
filtered = _organisationService.searchLocal(filtered, state.currentSearch!);
|
|
}
|
|
|
|
// Filtre par statut
|
|
if (state.statusFilter != null) {
|
|
filtered = _organisationService.filterByStatus(filtered, state.statusFilter!);
|
|
}
|
|
|
|
// Filtre par type
|
|
if (state.typeFilter != null) {
|
|
filtered = _organisationService.filterByType(filtered, state.typeFilter!);
|
|
}
|
|
|
|
return filtered;
|
|
}
|
|
}
|