@marcos_feitoza/personal-finance-frontend-feature-management 1.0.2 → 1.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
## [1.0.4](https://github.com/MarcosOps/personal-finance-frontend-feature-management/compare/v1.0.3...v1.0.4) (2026-01-30)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* Padronizar mensagens de erro e estados de loading ([039757d](https://github.com/MarcosOps/personal-finance-frontend-feature-management/commit/039757d6c16a0f521aad7a653cd4b907eef94177))
|
|
7
|
+
|
|
8
|
+
## [1.0.3](https://github.com/MarcosOps/personal-finance-frontend-feature-management/compare/v1.0.2...v1.0.3) (2026-01-30)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Bug Fixes
|
|
12
|
+
|
|
13
|
+
* Web responsivo (mobile/tablet/resize) ([f8b2be9](https://github.com/MarcosOps/personal-finance-frontend-feature-management/commit/f8b2be9a6b9b6fbe3b5a0bd8fed602204142461d))
|
|
14
|
+
|
|
1
15
|
## [1.0.2](https://github.com/MarcosOps/personal-finance-frontend-feature-management/compare/v1.0.1...v1.0.2) (2026-01-29)
|
|
2
16
|
|
|
3
17
|
|
|
@@ -4,6 +4,8 @@ import 'package:provider/provider.dart';
|
|
|
4
4
|
import '../viewmodels/manage_transactions_viewmodel.dart';
|
|
5
5
|
import 'package:personal_finance_frontend_core_ui/widgets/edit_transaction_dialog.dart';
|
|
6
6
|
import 'package:personal_finance_frontend_core_ui/widgets/app_widgets.dart';
|
|
7
|
+
import 'package:personal_finance_frontend_core_ui/widgets/app_async_state_view.dart';
|
|
8
|
+
import 'package:personal_finance_frontend_core_ui/utils/app_responsive.dart';
|
|
7
9
|
import 'package:personal_finance_frontend_core_services/models/payment_method.dart';
|
|
8
10
|
import 'package:personal_finance_frontend_core_services/providers/auth_provider.dart';
|
|
9
11
|
|
|
@@ -60,83 +62,94 @@ class ManageTransactionsScreen extends StatelessWidget {
|
|
|
60
62
|
),
|
|
61
63
|
body: Consumer<ManageTransactionsViewModel>(
|
|
62
64
|
builder: (context, viewModel, child) {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
65
|
+
return AppAsyncStateView(
|
|
66
|
+
isLoading: viewModel.isLoading,
|
|
67
|
+
errorMessage:
|
|
68
|
+
viewModel.errorMessage.isEmpty ? null : viewModel.errorMessage,
|
|
69
|
+
onRetry: viewModel.fetchTransactions,
|
|
70
|
+
child: Column(
|
|
71
|
+
children: [
|
|
72
|
+
_buildFilters(context, viewModel),
|
|
73
|
+
Expanded(
|
|
74
|
+
child: viewModel.transactions.isEmpty
|
|
75
|
+
? const Center(
|
|
76
|
+
child: Padding(
|
|
77
|
+
padding: EdgeInsets.all(16.0),
|
|
78
|
+
child: Text(
|
|
79
|
+
'No transactions found for the selected filters.',
|
|
80
|
+
),
|
|
81
|
+
),
|
|
82
|
+
)
|
|
83
|
+
: SingleChildScrollView(
|
|
84
|
+
child: ResponsiveHorizontalScroll(
|
|
85
|
+
child: DataTable(
|
|
86
|
+
columns: const [
|
|
87
|
+
DataColumn(label: Text('Select')),
|
|
88
|
+
DataColumn(label: Text('Date')),
|
|
89
|
+
DataColumn(label: Text('Category')),
|
|
90
|
+
DataColumn(label: Text('Subcategory')),
|
|
91
|
+
DataColumn(label: Text('Method')),
|
|
92
|
+
DataColumn(label: Text('Amount')),
|
|
93
|
+
DataColumn(label: Text('Description')),
|
|
94
|
+
DataColumn(label: Text('Paid')),
|
|
95
|
+
DataColumn(label: Text('Actions')),
|
|
96
|
+
],
|
|
97
|
+
rows: viewModel.transactions.map((transaction) {
|
|
98
|
+
return DataRow(
|
|
99
|
+
selected: viewModel.selectedTransactionIds
|
|
100
|
+
.contains(transaction.id),
|
|
101
|
+
onSelectChanged: (isSelected) {
|
|
102
|
+
viewModel.toggleTransactionSelection(
|
|
103
|
+
transaction.id);
|
|
104
|
+
},
|
|
105
|
+
cells: [
|
|
106
|
+
DataCell(Checkbox(
|
|
107
|
+
value: viewModel.selectedTransactionIds
|
|
108
|
+
.contains(transaction.id),
|
|
109
|
+
onChanged: (isSelected) {
|
|
110
|
+
viewModel.toggleTransactionSelection(
|
|
111
|
+
transaction.id);
|
|
112
|
+
},
|
|
113
|
+
)),
|
|
114
|
+
DataCell(Text(DateFormat('yyyy-MM-dd')
|
|
115
|
+
.format(transaction.date))),
|
|
116
|
+
DataCell(Text(transaction.category)),
|
|
117
|
+
DataCell(Text(transaction.subcategory)),
|
|
118
|
+
DataCell(Text(transaction.paymentMethod)),
|
|
119
|
+
DataCell(Text(NumberFormat.currency(
|
|
120
|
+
locale: 'en_CA', symbol: '\$')
|
|
121
|
+
.format(transaction.amount))),
|
|
122
|
+
DataCell(Text(transaction.description)),
|
|
123
|
+
DataCell(Switch(
|
|
124
|
+
value: transaction.isPaid,
|
|
125
|
+
onChanged: (bool newValue) {
|
|
126
|
+
viewModel.updateTransactionPaidStatus(
|
|
127
|
+
transaction.id, newValue);
|
|
128
|
+
},
|
|
129
|
+
)),
|
|
130
|
+
DataCell(IconButton(
|
|
131
|
+
icon: const Icon(Icons.edit),
|
|
132
|
+
onPressed: () {
|
|
133
|
+
showDialog(
|
|
134
|
+
context: context,
|
|
135
|
+
builder: (BuildContext context) {
|
|
136
|
+
return EditTransactionDialog(
|
|
137
|
+
transaction: transaction,
|
|
138
|
+
viewModel: viewModel,
|
|
139
|
+
);
|
|
140
|
+
},
|
|
141
|
+
);
|
|
142
|
+
},
|
|
143
|
+
)),
|
|
144
|
+
],
|
|
145
|
+
);
|
|
146
|
+
}).toList(),
|
|
147
|
+
),
|
|
148
|
+
),
|
|
149
|
+
),
|
|
137
150
|
),
|
|
138
|
-
|
|
139
|
-
|
|
151
|
+
],
|
|
152
|
+
),
|
|
140
153
|
);
|
|
141
154
|
},
|
|
142
155
|
),
|
|
@@ -3,6 +3,7 @@ import 'package:personal_finance_frontend_core_services/services/transaction_ser
|
|
|
3
3
|
import 'package:intl/intl.dart';
|
|
4
4
|
import 'package:personal_finance_frontend_core_services/models/payment_method.dart';
|
|
5
5
|
import 'package:personal_finance_frontend_core_ui/widgets/app_widgets.dart';
|
|
6
|
+
import 'package:personal_finance_frontend_core_ui/utils/app_responsive.dart';
|
|
6
7
|
import 'package:personal_finance_frontend_core_ui/utils/app_snackbars.dart';
|
|
7
8
|
import 'package:provider/provider.dart';
|
|
8
9
|
import 'package:personal_finance_frontend_core_services/providers/auth_provider.dart';
|
|
@@ -149,7 +150,7 @@ class _ReconciliationScreenState extends State<ReconciliationScreen> {
|
|
|
149
150
|
Widget build(BuildContext context) {
|
|
150
151
|
return Scaffold(
|
|
151
152
|
appBar: AppBar(
|
|
152
|
-
title: Text('Reconcile Transactions'),
|
|
153
|
+
title: const Text('Reconcile Transactions'),
|
|
153
154
|
actions: [
|
|
154
155
|
Center(
|
|
155
156
|
child: Padding(
|
|
@@ -177,49 +178,61 @@ class _ReconciliationScreenState extends State<ReconciliationScreen> {
|
|
|
177
178
|
? const Center(child: Text('No unpaid transactions found.'))
|
|
178
179
|
: SingleChildScrollView(
|
|
179
180
|
scrollDirection: Axis.vertical,
|
|
180
|
-
child:
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
:
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
181
|
+
child: ResponsiveHorizontalScroll(
|
|
182
|
+
child: DataTable(
|
|
183
|
+
columns: const [
|
|
184
|
+
DataColumn(label: Text('Select')),
|
|
185
|
+
DataColumn(label: Text('Date')),
|
|
186
|
+
DataColumn(label: Text('Subcategory')),
|
|
187
|
+
DataColumn(label: Text('Method')),
|
|
188
|
+
DataColumn(label: Text('Amount')),
|
|
189
|
+
],
|
|
190
|
+
rows: _unpaidTransactions.map((transaction) {
|
|
191
|
+
final transactionId = transaction['id'] as int;
|
|
192
|
+
final double amount = double.tryParse(
|
|
193
|
+
transaction['amount']?.toString() ?? '0.0') ??
|
|
194
|
+
0.0;
|
|
195
|
+
|
|
196
|
+
return DataRow(
|
|
197
|
+
cells: [
|
|
198
|
+
DataCell(
|
|
199
|
+
Checkbox(
|
|
200
|
+
value: _selectedIds.contains(transactionId),
|
|
201
|
+
onChanged: _selectedPaymentMethod == null
|
|
202
|
+
? null
|
|
203
|
+
: (bool? selected) {
|
|
204
|
+
_onTransactionSelected(selected, transaction);
|
|
205
|
+
},
|
|
206
|
+
),
|
|
207
|
+
),
|
|
208
|
+
DataCell(
|
|
209
|
+
Text(
|
|
210
|
+
DateFormat('yyyy-MM-dd').format(
|
|
211
|
+
DateTime.parse(transaction['date']),
|
|
212
|
+
),
|
|
213
|
+
),
|
|
214
|
+
),
|
|
215
|
+
DataCell(
|
|
216
|
+
Text(transaction['subcategory'] ?? 'No subcategory'),
|
|
217
|
+
),
|
|
218
|
+
DataCell(
|
|
219
|
+
Text(transaction['payment_method'] ?? 'N/A'),
|
|
220
|
+
),
|
|
221
|
+
DataCell(
|
|
222
|
+
Text(
|
|
223
|
+
_formatCurrency(amount),
|
|
224
|
+
style: TextStyle(
|
|
225
|
+
color: transaction['type'] == 'debit'
|
|
226
|
+
? Colors.red
|
|
227
|
+
: Colors.green,
|
|
228
|
+
fontWeight: FontWeight.bold,
|
|
229
|
+
),
|
|
230
|
+
),
|
|
218
231
|
),
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
)
|
|
222
|
-
|
|
232
|
+
],
|
|
233
|
+
);
|
|
234
|
+
}).toList(),
|
|
235
|
+
),
|
|
223
236
|
),
|
|
224
237
|
),
|
|
225
238
|
),
|