import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import '../../blocs/expense/expense_bloc.dart'; import '../../blocs/expense/expense_event.dart'; import '../../blocs/expense/expense_state.dart'; import '../../blocs/balance/balance_bloc.dart'; import '../../blocs/balance/balance_event.dart'; import '../../blocs/balance/balance_state.dart'; import '../../blocs/user/user_bloc.dart'; import '../../blocs/user/user_state.dart' as user_state; import '../../models/account.dart'; import '../../models/group.dart'; import 'add_expense_dialog.dart'; import 'balances_tab.dart'; import 'expenses_tab.dart'; import 'settlements_tab.dart'; class GroupExpensesPage extends StatefulWidget { final Account account; final Group group; const GroupExpensesPage({ super.key, required this.account, required this.group, }); @override State createState() => _GroupExpensesPageState(); } class _GroupExpensesPageState extends State with SingleTickerProviderStateMixin { late TabController _tabController; @override void initState() { super.initState(); _tabController = TabController(length: 3, vsync: this); _loadData(); } @override void dispose() { _tabController.dispose(); super.dispose(); } void _loadData() { // Charger les dépenses du groupe context.read().add(LoadExpensesByGroup(widget.group.id)); // Charger les balances du groupe context.read().add(LoadGroupBalances(widget.group.id)); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(widget.account.name), backgroundColor: Theme.of(context).primaryColor, foregroundColor: Colors.white, elevation: 0, bottom: TabBar( controller: _tabController, indicatorColor: Colors.white, labelColor: Colors.white, unselectedLabelColor: Colors.white70, tabs: const [ Tab( icon: Icon(Icons.balance), text: 'Balances', ), Tab( icon: Icon(Icons.receipt_long), text: 'Dépenses', ), Tab( icon: Icon(Icons.payment), text: 'Règlements', ), ], ), ), body: MultiBlocListener( listeners: [ BlocListener( listener: (context, state) { if (state is ExpenseOperationSuccess) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text(state.message), backgroundColor: Colors.green, ), ); _loadData(); // Recharger les données après une opération } else if (state is ExpenseError) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text(state.message), backgroundColor: Colors.red, ), ); } }, ), ], child: TabBarView( controller: _tabController, children: [ // Onglet Balances BlocBuilder( builder: (context, state) { if (state is BalanceLoading) { return const Center(child: CircularProgressIndicator()); } else if (state is GroupBalancesLoaded) { return BalancesTab(balances: state.balances); } else if (state is BalanceError) { return _buildErrorState('Erreur lors du chargement des balances: ${state.message}'); } return _buildEmptyState('Aucune balance disponible'); }, ), // Onglet Dépenses BlocBuilder( builder: (context, state) { if (state is ExpenseLoading) { return const Center(child: CircularProgressIndicator()); } else if (state is ExpensesLoaded) { return ExpensesTab( expenses: state.expenses, group: widget.group, ); } else if (state is ExpenseError) { return _buildErrorState('Erreur lors du chargement des dépenses: ${state.message}'); } return _buildEmptyState('Aucune dépense trouvée'); }, ), // Onglet Règlements BlocBuilder( builder: (context, state) { if (state is BalanceLoading) { return const Center(child: CircularProgressIndicator()); } else if (state is GroupBalancesLoaded) { return SettlementsTab(settlements: state.settlements); } else if (state is BalanceError) { return _buildErrorState('Erreur lors du chargement des règlements: ${state.message}'); } return _buildEmptyState('Aucun règlement nécessaire'); }, ), ], ), ), floatingActionButton: FloatingActionButton( onPressed: _showAddExpenseDialog, heroTag: "add_expense_fab", tooltip: 'Ajouter une dépense', child: const Icon(Icons.add), ), ); } Widget _buildErrorState(String message) { return Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon( Icons.error_outline, size: 80, color: Colors.red[300], ), const SizedBox(height: 16), Text( 'Erreur', style: TextStyle( fontSize: 20, fontWeight: FontWeight.bold, color: Colors.red[600], ), ), const SizedBox(height: 8), Padding( padding: const EdgeInsets.symmetric(horizontal: 32), child: Text( message, style: TextStyle( fontSize: 16, color: Colors.grey[600], ), textAlign: TextAlign.center, ), ), const SizedBox(height: 32), ElevatedButton.icon( onPressed: _loadData, icon: const Icon(Icons.refresh), label: const Text('Réessayer'), ), ], ), ); } Widget _buildEmptyState(String message) { return Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon( Icons.info_outline, size: 80, color: Colors.grey[400], ), const SizedBox(height: 16), Text( 'Aucune donnée', style: TextStyle( fontSize: 20, fontWeight: FontWeight.bold, color: Colors.grey[600], ), ), const SizedBox(height: 8), Text( message, style: TextStyle( fontSize: 16, color: Colors.grey[500], ), textAlign: TextAlign.center, ), ], ), ); } void _showAddExpenseDialog() { final userState = context.read().state; if (userState is user_state.UserLoaded) { showDialog( context: context, builder: (context) => AddExpenseDialog( group: widget.group, currentUser: userState.user, ), ); } else { ScaffoldMessenger.of(context).showSnackBar( const SnackBar( content: Text('Erreur: utilisateur non connecté'), backgroundColor: Colors.red, ), ); } } }