420 lines
12 KiB
Dart
420 lines
12 KiB
Dart
/// BLoC pour la gestion des membres
|
|
library membres_bloc;
|
|
|
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
|
import 'package:dio/dio.dart';
|
|
import 'membres_event.dart';
|
|
import 'membres_state.dart';
|
|
import '../data/repositories/membre_repository_impl.dart';
|
|
|
|
/// BLoC pour la gestion des membres
|
|
class MembresBloc extends Bloc<MembresEvent, MembresState> {
|
|
final MembreRepository _repository;
|
|
|
|
MembresBloc(this._repository) : super(const MembresInitial()) {
|
|
on<LoadMembres>(_onLoadMembres);
|
|
on<LoadMembreById>(_onLoadMembreById);
|
|
on<CreateMembre>(_onCreateMembre);
|
|
on<UpdateMembre>(_onUpdateMembre);
|
|
on<DeleteMembre>(_onDeleteMembre);
|
|
on<ActivateMembre>(_onActivateMembre);
|
|
on<DeactivateMembre>(_onDeactivateMembre);
|
|
on<SearchMembres>(_onSearchMembres);
|
|
on<LoadActiveMembres>(_onLoadActiveMembres);
|
|
on<LoadBureauMembres>(_onLoadBureauMembres);
|
|
on<LoadMembresStats>(_onLoadMembresStats);
|
|
}
|
|
|
|
/// Charge la liste des membres
|
|
Future<void> _onLoadMembres(
|
|
LoadMembres event,
|
|
Emitter<MembresState> emit,
|
|
) async {
|
|
try {
|
|
// Si refresh et qu'on a déjà des données, on garde l'état actuel
|
|
if (event.refresh && state is MembresLoaded) {
|
|
final currentState = state as MembresLoaded;
|
|
emit(MembresRefreshing(currentState.membres));
|
|
} else {
|
|
emit(const MembresLoading());
|
|
}
|
|
|
|
final result = await _repository.getMembres(
|
|
page: event.page,
|
|
size: event.size,
|
|
recherche: event.recherche,
|
|
);
|
|
|
|
emit(MembresLoaded(
|
|
membres: result.membres,
|
|
totalElements: result.totalElements,
|
|
currentPage: result.currentPage,
|
|
pageSize: result.pageSize,
|
|
totalPages: result.totalPages,
|
|
));
|
|
} on DioException catch (e) {
|
|
emit(MembresNetworkError(
|
|
message: _getNetworkErrorMessage(e),
|
|
code: e.response?.statusCode.toString(),
|
|
error: e,
|
|
));
|
|
} catch (e) {
|
|
emit(MembresError(
|
|
message: 'Erreur inattendue lors du chargement des membres: $e',
|
|
error: e,
|
|
));
|
|
}
|
|
}
|
|
|
|
/// Charge un membre par ID
|
|
Future<void> _onLoadMembreById(
|
|
LoadMembreById event,
|
|
Emitter<MembresState> emit,
|
|
) async {
|
|
try {
|
|
emit(const MembresLoading());
|
|
|
|
final membre = await _repository.getMembreById(event.id);
|
|
|
|
if (membre != null) {
|
|
emit(MembreDetailLoaded(membre));
|
|
} else {
|
|
emit(const MembresError(
|
|
message: 'Membre non trouvé',
|
|
code: '404',
|
|
));
|
|
}
|
|
} on DioException catch (e) {
|
|
emit(MembresNetworkError(
|
|
message: _getNetworkErrorMessage(e),
|
|
code: e.response?.statusCode.toString(),
|
|
error: e,
|
|
));
|
|
} catch (e) {
|
|
emit(MembresError(
|
|
message: 'Erreur lors du chargement du membre: $e',
|
|
error: e,
|
|
));
|
|
}
|
|
}
|
|
|
|
/// Crée un nouveau membre
|
|
Future<void> _onCreateMembre(
|
|
CreateMembre event,
|
|
Emitter<MembresState> emit,
|
|
) async {
|
|
try {
|
|
emit(const MembresLoading());
|
|
|
|
final membre = await _repository.createMembre(event.membre);
|
|
|
|
emit(MembreCreated(membre));
|
|
} on DioException catch (e) {
|
|
if (e.response?.statusCode == 400) {
|
|
// Erreur de validation
|
|
final errors = _extractValidationErrors(e.response?.data);
|
|
emit(MembresValidationError(
|
|
message: 'Erreur de validation',
|
|
validationErrors: errors,
|
|
code: '400',
|
|
));
|
|
} else {
|
|
emit(MembresNetworkError(
|
|
message: _getNetworkErrorMessage(e),
|
|
code: e.response?.statusCode.toString(),
|
|
error: e,
|
|
));
|
|
}
|
|
} catch (e) {
|
|
emit(MembresError(
|
|
message: 'Erreur lors de la création du membre: $e',
|
|
error: e,
|
|
));
|
|
}
|
|
}
|
|
|
|
/// Met à jour un membre
|
|
Future<void> _onUpdateMembre(
|
|
UpdateMembre event,
|
|
Emitter<MembresState> emit,
|
|
) async {
|
|
try {
|
|
emit(const MembresLoading());
|
|
|
|
final membre = await _repository.updateMembre(event.id, event.membre);
|
|
|
|
emit(MembreUpdated(membre));
|
|
} on DioException catch (e) {
|
|
if (e.response?.statusCode == 400) {
|
|
final errors = _extractValidationErrors(e.response?.data);
|
|
emit(MembresValidationError(
|
|
message: 'Erreur de validation',
|
|
validationErrors: errors,
|
|
code: '400',
|
|
));
|
|
} else {
|
|
emit(MembresNetworkError(
|
|
message: _getNetworkErrorMessage(e),
|
|
code: e.response?.statusCode.toString(),
|
|
error: e,
|
|
));
|
|
}
|
|
} catch (e) {
|
|
emit(MembresError(
|
|
message: 'Erreur lors de la mise à jour du membre: $e',
|
|
error: e,
|
|
));
|
|
}
|
|
}
|
|
|
|
/// Supprime un membre
|
|
Future<void> _onDeleteMembre(
|
|
DeleteMembre event,
|
|
Emitter<MembresState> emit,
|
|
) async {
|
|
try {
|
|
emit(const MembresLoading());
|
|
|
|
await _repository.deleteMembre(event.id);
|
|
|
|
emit(MembreDeleted(event.id));
|
|
} on DioException catch (e) {
|
|
emit(MembresNetworkError(
|
|
message: _getNetworkErrorMessage(e),
|
|
code: e.response?.statusCode.toString(),
|
|
error: e,
|
|
));
|
|
} catch (e) {
|
|
emit(MembresError(
|
|
message: 'Erreur lors de la suppression du membre: $e',
|
|
error: e,
|
|
));
|
|
}
|
|
}
|
|
|
|
/// Active un membre
|
|
Future<void> _onActivateMembre(
|
|
ActivateMembre event,
|
|
Emitter<MembresState> emit,
|
|
) async {
|
|
try {
|
|
emit(const MembresLoading());
|
|
|
|
final membre = await _repository.activateMembre(event.id);
|
|
|
|
emit(MembreActivated(membre));
|
|
} on DioException catch (e) {
|
|
emit(MembresNetworkError(
|
|
message: _getNetworkErrorMessage(e),
|
|
code: e.response?.statusCode.toString(),
|
|
error: e,
|
|
));
|
|
} catch (e) {
|
|
emit(MembresError(
|
|
message: 'Erreur lors de l\'activation du membre: $e',
|
|
error: e,
|
|
));
|
|
}
|
|
}
|
|
|
|
/// Désactive un membre
|
|
Future<void> _onDeactivateMembre(
|
|
DeactivateMembre event,
|
|
Emitter<MembresState> emit,
|
|
) async {
|
|
try {
|
|
emit(const MembresLoading());
|
|
|
|
final membre = await _repository.deactivateMembre(event.id);
|
|
|
|
emit(MembreDeactivated(membre));
|
|
} on DioException catch (e) {
|
|
emit(MembresNetworkError(
|
|
message: _getNetworkErrorMessage(e),
|
|
code: e.response?.statusCode.toString(),
|
|
error: e,
|
|
));
|
|
} catch (e) {
|
|
emit(MembresError(
|
|
message: 'Erreur lors de la désactivation du membre: $e',
|
|
error: e,
|
|
));
|
|
}
|
|
}
|
|
|
|
/// Recherche avancée de membres
|
|
Future<void> _onSearchMembres(
|
|
SearchMembres event,
|
|
Emitter<MembresState> emit,
|
|
) async {
|
|
try {
|
|
emit(const MembresLoading());
|
|
|
|
final result = await _repository.searchMembres(
|
|
criteria: event.criteria,
|
|
page: event.page,
|
|
size: event.size,
|
|
);
|
|
|
|
emit(MembresLoaded(
|
|
membres: result.membres,
|
|
totalElements: result.totalElements,
|
|
currentPage: result.currentPage,
|
|
pageSize: result.pageSize,
|
|
totalPages: result.totalPages,
|
|
));
|
|
} on DioException catch (e) {
|
|
emit(MembresNetworkError(
|
|
message: _getNetworkErrorMessage(e),
|
|
code: e.response?.statusCode.toString(),
|
|
error: e,
|
|
));
|
|
} catch (e) {
|
|
emit(MembresError(
|
|
message: 'Erreur lors de la recherche de membres: $e',
|
|
error: e,
|
|
));
|
|
}
|
|
}
|
|
|
|
/// Charge les membres actifs
|
|
Future<void> _onLoadActiveMembres(
|
|
LoadActiveMembres event,
|
|
Emitter<MembresState> emit,
|
|
) async {
|
|
try {
|
|
emit(const MembresLoading());
|
|
|
|
final result = await _repository.getActiveMembers(
|
|
page: event.page,
|
|
size: event.size,
|
|
);
|
|
|
|
emit(MembresLoaded(
|
|
membres: result.membres,
|
|
totalElements: result.totalElements,
|
|
currentPage: result.currentPage,
|
|
pageSize: result.pageSize,
|
|
totalPages: result.totalPages,
|
|
));
|
|
} on DioException catch (e) {
|
|
emit(MembresNetworkError(
|
|
message: _getNetworkErrorMessage(e),
|
|
code: e.response?.statusCode.toString(),
|
|
error: e,
|
|
));
|
|
} catch (e) {
|
|
emit(MembresError(
|
|
message: 'Erreur lors du chargement des membres actifs: $e',
|
|
error: e,
|
|
));
|
|
}
|
|
}
|
|
|
|
/// Charge les membres du bureau
|
|
Future<void> _onLoadBureauMembres(
|
|
LoadBureauMembres event,
|
|
Emitter<MembresState> emit,
|
|
) async {
|
|
try {
|
|
emit(const MembresLoading());
|
|
|
|
final result = await _repository.getBureauMembers(
|
|
page: event.page,
|
|
size: event.size,
|
|
);
|
|
|
|
emit(MembresLoaded(
|
|
membres: result.membres,
|
|
totalElements: result.totalElements,
|
|
currentPage: result.currentPage,
|
|
pageSize: result.pageSize,
|
|
totalPages: result.totalPages,
|
|
));
|
|
} on DioException catch (e) {
|
|
emit(MembresNetworkError(
|
|
message: _getNetworkErrorMessage(e),
|
|
code: e.response?.statusCode.toString(),
|
|
error: e,
|
|
));
|
|
} catch (e) {
|
|
emit(MembresError(
|
|
message: 'Erreur lors du chargement des membres du bureau: $e',
|
|
error: e,
|
|
));
|
|
}
|
|
}
|
|
|
|
/// Charge les statistiques
|
|
Future<void> _onLoadMembresStats(
|
|
LoadMembresStats event,
|
|
Emitter<MembresState> emit,
|
|
) async {
|
|
try {
|
|
emit(const MembresLoading());
|
|
|
|
final stats = await _repository.getMembresStats();
|
|
|
|
emit(MembresStatsLoaded(stats));
|
|
} on DioException catch (e) {
|
|
emit(MembresNetworkError(
|
|
message: _getNetworkErrorMessage(e),
|
|
code: e.response?.statusCode.toString(),
|
|
error: e,
|
|
));
|
|
} catch (e) {
|
|
emit(MembresError(
|
|
message: 'Erreur lors du chargement des statistiques: $e',
|
|
error: e,
|
|
));
|
|
}
|
|
}
|
|
|
|
/// Extrait les erreurs de validation de la réponse
|
|
Map<String, String> _extractValidationErrors(dynamic data) {
|
|
final errors = <String, String>{};
|
|
if (data is Map<String, dynamic> && data.containsKey('errors')) {
|
|
final errorsData = data['errors'];
|
|
if (errorsData is Map<String, dynamic>) {
|
|
errorsData.forEach((key, value) {
|
|
errors[key] = value.toString();
|
|
});
|
|
}
|
|
}
|
|
return errors;
|
|
}
|
|
|
|
/// Génère un message d'erreur réseau approprié
|
|
String _getNetworkErrorMessage(DioException e) {
|
|
switch (e.type) {
|
|
case DioExceptionType.connectionTimeout:
|
|
return 'Délai de connexion dépassé. Vérifiez votre connexion internet.';
|
|
case DioExceptionType.sendTimeout:
|
|
return 'Délai d\'envoi dépassé. Vérifiez votre connexion internet.';
|
|
case DioExceptionType.receiveTimeout:
|
|
return 'Délai de réception dépassé. Vérifiez votre connexion internet.';
|
|
case DioExceptionType.badResponse:
|
|
final statusCode = e.response?.statusCode;
|
|
if (statusCode == 401) {
|
|
return 'Non autorisé. Veuillez vous reconnecter.';
|
|
} else if (statusCode == 403) {
|
|
return 'Accès refusé. Vous n\'avez pas les permissions nécessaires.';
|
|
} else if (statusCode == 404) {
|
|
return 'Ressource non trouvée.';
|
|
} else if (statusCode == 409) {
|
|
return 'Conflit. Cette ressource existe déjà.';
|
|
} else if (statusCode != null && statusCode >= 500) {
|
|
return 'Erreur serveur. Veuillez réessayer plus tard.';
|
|
}
|
|
return 'Erreur lors de la communication avec le serveur.';
|
|
case DioExceptionType.cancel:
|
|
return 'Requête annulée.';
|
|
case DioExceptionType.unknown:
|
|
return 'Erreur de connexion. Vérifiez votre connexion internet.';
|
|
default:
|
|
return 'Erreur réseau inattendue.';
|
|
}
|
|
}
|
|
}
|
|
|