Files
2025-11-17 16:02:04 +00:00

489 lines
15 KiB
Dart

/// BLoC pour la gestion des organisations
library organizations_bloc;
import 'package:flutter_bloc/flutter_bloc.dart';
import '../data/models/organization_model.dart';
import '../data/services/organization_service.dart';
import 'organizations_event.dart';
import 'organizations_state.dart';
/// BLoC principal pour la gestion des organisations
class OrganizationsBloc extends Bloc<OrganizationsEvent, OrganizationsState> {
final OrganizationService _organizationService;
OrganizationsBloc(this._organizationService) : super(const OrganizationsInitial()) {
// Enregistrement des handlers d'événements
on<LoadOrganizations>(_onLoadOrganizations);
on<LoadMoreOrganizations>(_onLoadMoreOrganizations);
on<SearchOrganizations>(_onSearchOrganizations);
on<AdvancedSearchOrganizations>(_onAdvancedSearchOrganizations);
on<LoadOrganizationById>(_onLoadOrganizationById);
on<CreateOrganization>(_onCreateOrganization);
on<UpdateOrganization>(_onUpdateOrganization);
on<DeleteOrganization>(_onDeleteOrganization);
on<ActivateOrganization>(_onActivateOrganization);
on<FilterOrganizationsByStatus>(_onFilterOrganizationsByStatus);
on<FilterOrganizationsByType>(_onFilterOrganizationsByType);
on<SortOrganizations>(_onSortOrganizations);
on<LoadOrganizationsStats>(_onLoadOrganizationsStats);
on<ClearOrganizationsFilters>(_onClearOrganizationsFilters);
on<RefreshOrganizations>(_onRefreshOrganizations);
on<ResetOrganizationsState>(_onResetOrganizationsState);
}
/// Charge la liste des organisations
Future<void> _onLoadOrganizations(
LoadOrganizations event,
Emitter<OrganizationsState> emit,
) async {
try {
if (event.refresh || state is! OrganizationsLoaded) {
emit(const OrganizationsLoading());
}
final organizations = await _organizationService.getOrganizations(
page: event.page,
size: event.size,
recherche: event.recherche,
);
emit(OrganizationsLoaded(
organizations: organizations,
filteredOrganizations: organizations,
hasReachedMax: organizations.length < event.size,
currentPage: event.page,
currentSearch: event.recherche,
));
} catch (e) {
emit(OrganizationsError(
'Erreur lors du chargement des organisations',
details: e.toString(),
));
}
}
/// Charge plus d'organisations (pagination)
Future<void> _onLoadMoreOrganizations(
LoadMoreOrganizations event,
Emitter<OrganizationsState> emit,
) async {
final currentState = state;
if (currentState is! OrganizationsLoaded || currentState.hasReachedMax) {
return;
}
emit(OrganizationsLoadingMore(currentState.organizations));
try {
final nextPage = currentState.currentPage + 1;
final newOrganizations = await _organizationService.getOrganizations(
page: nextPage,
size: 20,
recherche: currentState.currentSearch,
);
final allOrganizations = [...currentState.organizations, ...newOrganizations];
final filteredOrganizations = _applyCurrentFilters(allOrganizations, currentState);
emit(currentState.copyWith(
organizations: allOrganizations,
filteredOrganizations: filteredOrganizations,
hasReachedMax: newOrganizations.length < 20,
currentPage: nextPage,
));
} catch (e) {
emit(OrganizationsError(
'Erreur lors du chargement de plus d\'organisations',
details: e.toString(),
previousOrganizations: currentState.organizations,
));
}
}
/// Recherche des organisations
Future<void> _onSearchOrganizations(
SearchOrganizations event,
Emitter<OrganizationsState> emit,
) async {
final currentState = state;
if (currentState is! OrganizationsLoaded) {
// Si pas encore chargé, charger avec recherche
add(LoadOrganizations(recherche: event.query, refresh: true));
return;
}
try {
if (event.query.isEmpty) {
// Recherche vide, afficher toutes les organisations
final filteredOrganizations = _applyCurrentFilters(
currentState.organizations,
currentState.copyWith(clearSearch: true),
);
emit(currentState.copyWith(
filteredOrganizations: filteredOrganizations,
clearSearch: true,
));
} else {
// Recherche locale d'abord
final localResults = _organizationService.searchLocal(
currentState.organizations,
event.query,
);
emit(currentState.copyWith(
filteredOrganizations: localResults,
currentSearch: event.query,
));
// Puis recherche serveur pour plus de résultats
final serverResults = await _organizationService.getOrganizations(
page: 0,
size: 50,
recherche: event.query,
);
final filteredResults = _applyCurrentFilters(serverResults, currentState);
emit(currentState.copyWith(
organizations: serverResults,
filteredOrganizations: filteredResults,
currentSearch: event.query,
currentPage: 0,
hasReachedMax: true,
));
}
} catch (e) {
emit(OrganizationsError(
'Erreur lors de la recherche',
details: e.toString(),
previousOrganizations: currentState.organizations,
));
}
}
/// Recherche avancée
Future<void> _onAdvancedSearchOrganizations(
AdvancedSearchOrganizations event,
Emitter<OrganizationsState> emit,
) async {
emit(const OrganizationsLoading());
try {
final organizations = await _organizationService.searchOrganizations(
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(OrganizationsLoaded(
organizations: organizations,
filteredOrganizations: organizations,
hasReachedMax: organizations.length < event.size,
currentPage: event.page,
typeFilter: event.type,
statusFilter: event.statut,
));
} catch (e) {
emit(OrganizationsError(
'Erreur lors de la recherche avancée',
details: e.toString(),
));
}
}
/// Charge une organisation par ID
Future<void> _onLoadOrganizationById(
LoadOrganizationById event,
Emitter<OrganizationsState> emit,
) async {
emit(OrganizationLoading(event.id));
try {
final organization = await _organizationService.getOrganizationById(event.id);
if (organization != null) {
emit(OrganizationLoaded(organization));
} else {
emit(OrganizationError('Organisation non trouvée', organizationId: event.id));
}
} catch (e) {
emit(OrganizationError(
'Erreur lors du chargement de l\'organisation',
organizationId: event.id,
));
}
}
/// Crée une nouvelle organisation
Future<void> _onCreateOrganization(
CreateOrganization event,
Emitter<OrganizationsState> emit,
) async {
emit(const OrganizationCreating());
try {
final createdOrganization = await _organizationService.createOrganization(event.organization);
emit(OrganizationCreated(createdOrganization));
// Recharger la liste si elle était déjà chargée
if (state is OrganizationsLoaded) {
add(const RefreshOrganizations());
}
} catch (e) {
emit(OrganizationsError(
'Erreur lors de la création de l\'organisation',
details: e.toString(),
));
}
}
/// Met à jour une organisation
Future<void> _onUpdateOrganization(
UpdateOrganization event,
Emitter<OrganizationsState> emit,
) async {
emit(OrganizationUpdating(event.id));
try {
final updatedOrganization = await _organizationService.updateOrganization(
event.id,
event.organization,
);
emit(OrganizationUpdated(updatedOrganization));
// Mettre à jour la liste si elle était déjà chargée
final currentState = state;
if (currentState is OrganizationsLoaded) {
final updatedList = currentState.organizations.map((org) {
return org.id == event.id ? updatedOrganization : org;
}).toList();
final filteredList = _applyCurrentFilters(updatedList, currentState);
emit(currentState.copyWith(
organizations: updatedList,
filteredOrganizations: filteredList,
));
}
} catch (e) {
emit(OrganizationsError(
'Erreur lors de la mise à jour de l\'organisation',
details: e.toString(),
));
}
}
/// Supprime une organisation
Future<void> _onDeleteOrganization(
DeleteOrganization event,
Emitter<OrganizationsState> emit,
) async {
emit(OrganizationDeleting(event.id));
try {
await _organizationService.deleteOrganization(event.id);
emit(OrganizationDeleted(event.id));
// Retirer de la liste si elle était déjà chargée
final currentState = state;
if (currentState is OrganizationsLoaded) {
final updatedList = currentState.organizations.where((org) => org.id != event.id).toList();
final filteredList = _applyCurrentFilters(updatedList, currentState);
emit(currentState.copyWith(
organizations: updatedList,
filteredOrganizations: filteredList,
));
}
} catch (e) {
emit(OrganizationsError(
'Erreur lors de la suppression de l\'organisation',
details: e.toString(),
));
}
}
/// Active une organisation
Future<void> _onActivateOrganization(
ActivateOrganization event,
Emitter<OrganizationsState> emit,
) async {
emit(OrganizationActivating(event.id));
try {
final activatedOrganization = await _organizationService.activateOrganization(event.id);
emit(OrganizationActivated(activatedOrganization));
// Mettre à jour la liste si elle était déjà chargée
final currentState = state;
if (currentState is OrganizationsLoaded) {
final updatedList = currentState.organizations.map((org) {
return org.id == event.id ? activatedOrganization : org;
}).toList();
final filteredList = _applyCurrentFilters(updatedList, currentState);
emit(currentState.copyWith(
organizations: updatedList,
filteredOrganizations: filteredList,
));
}
} catch (e) {
emit(OrganizationsError(
'Erreur lors de l\'activation de l\'organisation',
details: e.toString(),
));
}
}
/// Filtre par statut
void _onFilterOrganizationsByStatus(
FilterOrganizationsByStatus event,
Emitter<OrganizationsState> emit,
) {
final currentState = state;
if (currentState is! OrganizationsLoaded) return;
final filteredOrganizations = _applyCurrentFilters(
currentState.organizations,
currentState.copyWith(statusFilter: event.statut),
);
emit(currentState.copyWith(
filteredOrganizations: filteredOrganizations,
statusFilter: event.statut,
));
}
/// Filtre par type
void _onFilterOrganizationsByType(
FilterOrganizationsByType event,
Emitter<OrganizationsState> emit,
) {
final currentState = state;
if (currentState is! OrganizationsLoaded) return;
final filteredOrganizations = _applyCurrentFilters(
currentState.organizations,
currentState.copyWith(typeFilter: event.type),
);
emit(currentState.copyWith(
filteredOrganizations: filteredOrganizations,
typeFilter: event.type,
));
}
/// Trie les organisations
void _onSortOrganizations(
SortOrganizations event,
Emitter<OrganizationsState> emit,
) {
final currentState = state;
if (currentState is! OrganizationsLoaded) return;
List<OrganizationModel> sortedOrganizations;
switch (event.sortType) {
case OrganizationSortType.name:
sortedOrganizations = _organizationService.sortByName(
currentState.filteredOrganizations,
ascending: event.ascending,
);
break;
case OrganizationSortType.creationDate:
sortedOrganizations = _organizationService.sortByCreationDate(
currentState.filteredOrganizations,
ascending: event.ascending,
);
break;
case OrganizationSortType.memberCount:
sortedOrganizations = _organizationService.sortByMemberCount(
currentState.filteredOrganizations,
ascending: event.ascending,
);
break;
default:
sortedOrganizations = currentState.filteredOrganizations;
}
emit(currentState.copyWith(
filteredOrganizations: sortedOrganizations,
sortType: event.sortType,
sortAscending: event.ascending,
));
}
/// Charge les statistiques
Future<void> _onLoadOrganizationsStats(
LoadOrganizationsStats event,
Emitter<OrganizationsState> emit,
) async {
emit(const OrganizationsStatsLoading());
try {
final stats = await _organizationService.getOrganizationsStats();
emit(OrganizationsStatsLoaded(stats));
} catch (e) {
emit(const OrganizationsStatsError('Erreur lors du chargement des statistiques'));
}
}
/// Efface les filtres
void _onClearOrganizationsFilters(
ClearOrganizationsFilters event,
Emitter<OrganizationsState> emit,
) {
final currentState = state;
if (currentState is! OrganizationsLoaded) return;
emit(currentState.copyWith(
filteredOrganizations: currentState.organizations,
clearSearch: true,
clearStatusFilter: true,
clearTypeFilter: true,
clearSort: true,
));
}
/// Rafraîchit les données
void _onRefreshOrganizations(
RefreshOrganizations event,
Emitter<OrganizationsState> emit,
) {
add(const LoadOrganizations(refresh: true));
}
/// Remet à zéro l'état
void _onResetOrganizationsState(
ResetOrganizationsState event,
Emitter<OrganizationsState> emit,
) {
emit(const OrganizationsInitial());
}
/// Applique les filtres actuels à une liste d'organisations
List<OrganizationModel> _applyCurrentFilters(
List<OrganizationModel> organizations,
OrganizationsLoaded state,
) {
var filtered = organizations;
// Filtre par recherche
if (state.currentSearch?.isNotEmpty == true) {
filtered = _organizationService.searchLocal(filtered, state.currentSearch!);
}
// Filtre par statut
if (state.statusFilter != null) {
filtered = _organizationService.filterByStatus(filtered, state.statusFilter!);
}
// Filtre par type
if (state.typeFilter != null) {
filtered = _organizationService.filterByType(filtered, state.typeFilter!);
}
return filtered;
}
}