@marcos_feitoza/personal-finance-frontend-feature-management 1.0.1 → 1.0.3
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.3](https://github.com/MarcosOps/personal-finance-frontend-feature-management/compare/v1.0.2...v1.0.3) (2026-01-30)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* Web responsivo (mobile/tablet/resize) ([f8b2be9](https://github.com/MarcosOps/personal-finance-frontend-feature-management/commit/f8b2be9a6b9b6fbe3b5a0bd8fed602204142461d))
|
|
7
|
+
|
|
8
|
+
## [1.0.2](https://github.com/MarcosOps/personal-finance-frontend-feature-management/compare/v1.0.1...v1.0.2) (2026-01-29)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Bug Fixes
|
|
12
|
+
|
|
13
|
+
* new SnackBar ([2249b0b](https://github.com/MarcosOps/personal-finance-frontend-feature-management/commit/2249b0b80d8983dc6636d9de3192a0e744696ae0))
|
|
14
|
+
|
|
1
15
|
## [1.0.1](https://github.com/MarcosOps/personal-finance-frontend-feature-management/compare/v1.0.0...v1.0.1) (2025-12-06)
|
|
2
16
|
|
|
3
17
|
|
|
@@ -4,6 +4,7 @@ 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/utils/app_responsive.dart';
|
|
7
8
|
import 'package:personal_finance_frontend_core_services/models/payment_method.dart';
|
|
8
9
|
import 'package:personal_finance_frontend_core_services/providers/auth_provider.dart';
|
|
9
10
|
|
|
@@ -71,68 +72,70 @@ class ManageTransactionsScreen extends StatelessWidget {
|
|
|
71
72
|
_buildFilters(context, viewModel),
|
|
72
73
|
Expanded(
|
|
73
74
|
child: SingleChildScrollView(
|
|
74
|
-
child:
|
|
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
|
-
|
|
75
|
+
child: ResponsiveHorizontalScroll(
|
|
76
|
+
child: DataTable(
|
|
77
|
+
columns: const [
|
|
78
|
+
DataColumn(label: Text('Select')),
|
|
79
|
+
DataColumn(label: Text('Date')),
|
|
80
|
+
DataColumn(label: Text('Category')),
|
|
81
|
+
DataColumn(label: Text('Subcategory')),
|
|
82
|
+
DataColumn(label: Text('Method')),
|
|
83
|
+
DataColumn(label: Text('Amount')),
|
|
84
|
+
DataColumn(label: Text('Description')),
|
|
85
|
+
DataColumn(label: Text('Paid')), // Added Paid column
|
|
86
|
+
DataColumn(label: Text('Actions')),
|
|
87
|
+
],
|
|
88
|
+
rows: viewModel.transactions.map((transaction) {
|
|
89
|
+
return DataRow(
|
|
90
|
+
selected: viewModel.selectedTransactionIds
|
|
91
|
+
.contains(transaction.id),
|
|
92
|
+
onSelectChanged: (isSelected) {
|
|
93
|
+
viewModel
|
|
94
|
+
.toggleTransactionSelection(transaction.id);
|
|
95
|
+
},
|
|
96
|
+
cells: [
|
|
97
|
+
DataCell(Checkbox(
|
|
98
|
+
value: viewModel.selectedTransactionIds
|
|
99
|
+
.contains(transaction.id),
|
|
100
|
+
onChanged: (isSelected) {
|
|
101
|
+
viewModel
|
|
102
|
+
.toggleTransactionSelection(transaction.id);
|
|
103
|
+
},
|
|
104
|
+
)),
|
|
105
|
+
DataCell(Text(DateFormat('yyyy-MM-dd')
|
|
106
|
+
.format(transaction.date))),
|
|
107
|
+
DataCell(Text(transaction.category)),
|
|
108
|
+
DataCell(Text(transaction.subcategory)),
|
|
109
|
+
DataCell(Text(transaction.paymentMethod)),
|
|
110
|
+
DataCell(Text(NumberFormat.currency(
|
|
111
|
+
locale: 'en_CA', symbol: '\$')
|
|
112
|
+
.format(transaction.amount))),
|
|
113
|
+
DataCell(Text(transaction.description)),
|
|
114
|
+
DataCell(Switch( // Added Switch for Paid status
|
|
115
|
+
value: transaction.isPaid,
|
|
116
|
+
onChanged: (bool newValue) {
|
|
117
|
+
print('Switch onChanged: transaction.id=${transaction.id}, newValue=$newValue'); // Added log
|
|
118
|
+
viewModel.updateTransactionPaidStatus(transaction.id, newValue);
|
|
119
|
+
},
|
|
120
|
+
)),
|
|
121
|
+
DataCell(IconButton(
|
|
122
|
+
icon: const Icon(Icons.edit),
|
|
123
|
+
onPressed: () {
|
|
124
|
+
showDialog(
|
|
125
|
+
context: context,
|
|
126
|
+
builder: (BuildContext context) {
|
|
127
|
+
return EditTransactionDialog(
|
|
128
|
+
transaction: transaction,
|
|
129
|
+
viewModel: viewModel,
|
|
130
|
+
);
|
|
131
|
+
},
|
|
132
|
+
);
|
|
133
|
+
},
|
|
134
|
+
)),
|
|
135
|
+
],
|
|
136
|
+
);
|
|
137
|
+
}).toList(),
|
|
138
|
+
),
|
|
136
139
|
),
|
|
137
140
|
),
|
|
138
141
|
),
|
|
@@ -3,6 +3,8 @@ 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';
|
|
7
|
+
import 'package:personal_finance_frontend_core_ui/utils/app_snackbars.dart';
|
|
6
8
|
import 'package:provider/provider.dart';
|
|
7
9
|
import 'package:personal_finance_frontend_core_services/providers/auth_provider.dart';
|
|
8
10
|
|
|
@@ -120,17 +122,12 @@ class _ReconciliationScreenState extends State<ReconciliationScreen> {
|
|
|
120
122
|
|
|
121
123
|
Future<void> _reconcile() async {
|
|
122
124
|
if (_selectedIds.isEmpty) {
|
|
123
|
-
|
|
124
|
-
const SnackBar(
|
|
125
|
-
content: Text('Please select transactions to reconcile.')),
|
|
126
|
-
);
|
|
125
|
+
showInfoSnackBar(context, 'Please select transactions to reconcile.');
|
|
127
126
|
return;
|
|
128
127
|
}
|
|
129
128
|
|
|
130
129
|
if (_selectedPaymentMethod == null) {
|
|
131
|
-
|
|
132
|
-
const SnackBar(content: Text('Please select a payment method.')),
|
|
133
|
-
);
|
|
130
|
+
showInfoSnackBar(context, 'Please select a payment method.');
|
|
134
131
|
return;
|
|
135
132
|
}
|
|
136
133
|
|
|
@@ -142,15 +139,10 @@ class _ReconciliationScreenState extends State<ReconciliationScreen> {
|
|
|
142
139
|
);
|
|
143
140
|
|
|
144
141
|
if (newBalance != null) {
|
|
145
|
-
|
|
146
|
-
const SnackBar(content: Text('Reconciliation successful!')),
|
|
147
|
-
);
|
|
142
|
+
showSuccessSnackBar(context, 'Reconciliation successful!');
|
|
148
143
|
Navigator.of(context).pop(true); // Pop with a success result
|
|
149
144
|
} else {
|
|
150
|
-
|
|
151
|
-
const SnackBar(
|
|
152
|
-
content: Text('Reconciliation failed. Please try again.')),
|
|
153
|
-
);
|
|
145
|
+
showErrorSnackBar(context, 'Reconciliation failed. Please try again.');
|
|
154
146
|
}
|
|
155
147
|
}
|
|
156
148
|
|
|
@@ -158,7 +150,7 @@ class _ReconciliationScreenState extends State<ReconciliationScreen> {
|
|
|
158
150
|
Widget build(BuildContext context) {
|
|
159
151
|
return Scaffold(
|
|
160
152
|
appBar: AppBar(
|
|
161
|
-
title: Text('Reconcile Transactions'),
|
|
153
|
+
title: const Text('Reconcile Transactions'),
|
|
162
154
|
actions: [
|
|
163
155
|
Center(
|
|
164
156
|
child: Padding(
|
|
@@ -186,49 +178,61 @@ class _ReconciliationScreenState extends State<ReconciliationScreen> {
|
|
|
186
178
|
? const Center(child: Text('No unpaid transactions found.'))
|
|
187
179
|
: SingleChildScrollView(
|
|
188
180
|
scrollDirection: Axis.vertical,
|
|
189
|
-
child:
|
|
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
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
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
|
+
),
|
|
227
231
|
),
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
)
|
|
231
|
-
|
|
232
|
+
],
|
|
233
|
+
);
|
|
234
|
+
}).toList(),
|
|
235
|
+
),
|
|
232
236
|
),
|
|
233
237
|
),
|
|
234
238
|
),
|