/// BLoC pour la gestion des budgets library budget_bloc; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:injectable/injectable.dart'; import '../../domain/usecases/get_budgets.dart'; import '../../domain/usecases/get_budget_by_id.dart'; import '../../domain/usecases/create_budget.dart'; import '../../domain/usecases/get_budget_tracking.dart'; import 'budget_event.dart'; import 'budget_state.dart'; @injectable class BudgetBloc extends Bloc { final GetBudgets getBudgets; final GetBudgetById getBudgetById; final CreateBudget createBudget; final GetBudgetTracking getBudgetTracking; BudgetBloc({ required this.getBudgets, required this.getBudgetById, required this.createBudget, required this.getBudgetTracking, }) : super(const BudgetInitial()) { on(_onLoadBudgets); on(_onLoadBudgetById); on(_onCreateBudget); on(_onLoadBudgetTracking); on(_onRefreshBudgets); on(_onFilterBudgets); } Future _onLoadBudgets( LoadBudgets event, Emitter emit, ) async { emit(const BudgetsLoading()); final result = await getBudgets( organizationId: event.organizationId, status: event.status, year: event.year, ); result.fold( (failure) => emit(BudgetError(failure.message)), (budgets) { if (budgets.isEmpty) { emit(const BudgetsEmpty()); } else { emit(BudgetsLoaded( budgets: budgets, filterStatus: event.status, filterYear: event.year, )); } }, ); } Future _onLoadBudgetById( LoadBudgetById event, Emitter emit, ) async { emit(const BudgetsLoading()); final result = await getBudgetById(event.budgetId); result.fold( (failure) => emit(BudgetError(failure.message)), (budget) => emit(BudgetDetailLoaded(budget)), ); } Future _onCreateBudget( CreateBudgetEvent event, Emitter emit, ) async { emit(const BudgetActionInProgress('create')); final result = await createBudget( name: event.name, description: event.description, organizationId: event.organizationId, period: event.period, year: event.year, month: event.month, lines: event.lines, ); result.fold( (failure) => emit(BudgetError(failure.message)), (budget) => emit(BudgetCreated(budget: budget)), ); } Future _onLoadBudgetTracking( LoadBudgetTracking event, Emitter emit, ) async { emit(const BudgetsLoading()); // Load budget first final budgetResult = await getBudgetById(event.budgetId); await budgetResult.fold( (failure) async => emit(BudgetError(failure.message)), (budget) async { // Then load tracking final trackingResult = await getBudgetTracking(budgetId: event.budgetId); trackingResult.fold( (failure) => emit(BudgetError(failure.message)), (tracking) => emit(BudgetTrackingLoaded( budget: budget, tracking: tracking, )), ); }, ); } Future _onRefreshBudgets( RefreshBudgets event, Emitter emit, ) async { final result = await getBudgets( organizationId: event.organizationId, status: event.status, year: event.year, ); result.fold( (failure) => emit(BudgetError(failure.message)), (budgets) { if (budgets.isEmpty) { emit(const BudgetsEmpty()); } else { emit(BudgetsLoaded( budgets: budgets, filterStatus: event.status, filterYear: event.year, )); } }, ); } Future _onFilterBudgets( FilterBudgets event, Emitter emit, ) async { // Keep current organization if in loaded state String? organizationId; if (state is BudgetsLoaded) { final currentState = state as BudgetsLoaded; // Extract org ID from first budget if available if (currentState.budgets.isNotEmpty) { organizationId = currentState.budgets.first.organizationId; } } emit(const BudgetsLoading()); final result = await getBudgets( organizationId: organizationId, status: event.status, year: event.year, ); result.fold( (failure) => emit(BudgetError(failure.message)), (budgets) { if (budgets.isEmpty) { emit(const BudgetsEmpty()); } else { emit(BudgetsLoaded( budgets: budgets, filterStatus: event.status, filterYear: event.year, )); } }, ); } }