feat: Add expense management features with tabs for expenses, balances, and settlements
- Implemented ExpensesTab to display a list of expenses with details. - Created GroupExpensesPage to manage group expenses with a tabbed interface. - Added SettlementsTab to show optimized settlements between users. - Developed data models for Expense and Balance, including necessary methods for serialization. - Introduced CountRepository for Firestore interactions related to expenses. - Added CountService to handle business logic for expenses and settlements. - Integrated image picker for receipt uploads. - Updated main.dart to include CountBloc and CountRepository. - Enhanced pubspec.yaml with new dependencies for image picking and Firebase storage. Not Tested yet
This commit is contained in:
116
lib/components/count/group_expenses_page.dart
Normal file
116
lib/components/count/group_expenses_page.dart
Normal file
@@ -0,0 +1,116 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import '../../blocs/count/count_bloc.dart';
|
||||
import '../../blocs/count/count_event.dart';
|
||||
import '../../blocs/count/count_state.dart';
|
||||
import '../../blocs/user/user_bloc.dart';
|
||||
import '../../blocs/user/user_state.dart' as user_state;
|
||||
import '../../data/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 Group group;
|
||||
|
||||
const GroupExpensesPage({
|
||||
super.key,
|
||||
required this.group,
|
||||
});
|
||||
|
||||
@override
|
||||
State<GroupExpensesPage> createState() => _GroupExpensesPageState();
|
||||
}
|
||||
|
||||
class _GroupExpensesPageState extends State<GroupExpensesPage>
|
||||
with SingleTickerProviderStateMixin {
|
||||
late TabController _tabController;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_tabController = TabController(length: 3, vsync: this);
|
||||
context.read<CountBloc>().add(LoadExpenses(widget.group.id));
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_tabController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text(widget.group.name),
|
||||
bottom: TabBar(
|
||||
controller: _tabController,
|
||||
tabs: const [
|
||||
Tab(text: 'Dépenses', icon: Icon(Icons.receipt_long)),
|
||||
Tab(text: 'Balances', icon: Icon(Icons.account_balance)),
|
||||
Tab(text: 'Remboursements', icon: Icon(Icons.payments)),
|
||||
],
|
||||
),
|
||||
),
|
||||
body: BlocConsumer<CountBloc, CountState>(
|
||||
listener: (context, state) {
|
||||
if (state is CountError) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text(state.message),
|
||||
backgroundColor: Colors.red,
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
builder: (context, state) {
|
||||
if (state is CountLoading) {
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
}
|
||||
|
||||
if (state is ExpensesLoaded) {
|
||||
return TabBarView(
|
||||
controller: _tabController,
|
||||
children: [
|
||||
ExpensesTab(
|
||||
expenses: state.expenses,
|
||||
group: widget.group,
|
||||
),
|
||||
BalancesTab(balances: state.balances),
|
||||
SettlementsTab(settlements: state.settlements),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
return const Center(child: Text('Aucune donnée'));
|
||||
},
|
||||
),
|
||||
floatingActionButton: BlocBuilder<UserBloc, user_state.UserState>(
|
||||
builder: (context, userState) {
|
||||
if (userState is! user_state.UserLoaded) return const SizedBox();
|
||||
|
||||
return FloatingActionButton.extended(
|
||||
onPressed: () => _showAddExpenseDialog(context, userState.user),
|
||||
icon: const Icon(Icons.add),
|
||||
label: const Text('Dépense'),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _showAddExpenseDialog(BuildContext context, user_state.UserModel currentUser) {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (dialogContext) => BlocProvider.value(
|
||||
value: context.read<CountBloc>(),
|
||||
child: AddExpenseDialog(
|
||||
group: widget.group,
|
||||
currentUser: currentUser,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user