@marcos_feitoza/personal-finance-frontend-feature-investments 1.1.1 → 1.2.0

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,23 @@
1
+ # [1.2.0](https://github.com/MarcosOps/personal-finance-frontend-feature-investments/compare/v1.1.2...v1.2.0) (2025-12-06)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * add totals back ([0abb920](https://github.com/MarcosOps/personal-finance-frontend-feature-investments/commit/0abb920257d8988083f08a24f8db90ad9a24d463))
7
+
8
+
9
+ ### Features
10
+
11
+ * new dividend logic ([5aed0ed](https://github.com/MarcosOps/personal-finance-frontend-feature-investments/commit/5aed0edd789072894c927192fb2105dd7cf1623b))
12
+ * update dividend ([67c9dc3](https://github.com/MarcosOps/personal-finance-frontend-feature-investments/commit/67c9dc327a15e114c7a4acc590f797e1f89ac2ed))
13
+
14
+ ## [1.1.2](https://github.com/MarcosOps/personal-finance-frontend-feature-investments/compare/v1.1.1...v1.1.2) (2025-12-03)
15
+
16
+
17
+ ### Bug Fixes
18
+
19
+ * refatoração das telas InvestmentAccountScreen, CryptoAccountScreen e RrspSunLifeScreen para o padrão ViewModel com ChangeNotifier ([20419ac](https://github.com/MarcosOps/personal-finance-frontend-feature-investments/commit/20419ac0c38259469c69389496ec7e24c6d95e3b))
20
+
1
21
  ## [1.1.1](https://github.com/MarcosOps/personal-finance-frontend-feature-investments/compare/v1.1.0...v1.1.1) (2025-12-02)
2
22
 
3
23
 
@@ -1,240 +1,123 @@
1
1
  import 'package:flutter/material.dart';
2
2
  import 'package:intl/intl.dart';
3
- import 'package:personal_finance_frontend_core_services/services/crypto_service.dart';
4
- import 'package:personal_finance_frontend_core_services/services/transaction_service.dart';
5
- import 'package:personal_finance_frontend_core_ui/widgets/crypto_trade_form.dart';
6
- import 'package:personal_finance_frontend_core_ui/widgets/app_widgets.dart';
7
3
  import 'package:provider/provider.dart';
8
4
  import 'package:personal_finance_frontend_core_services/providers/auth_provider.dart';
9
5
  import 'package:personal_finance_frontend_core_ui/utils/app_dialogs.dart';
6
+ import 'package:personal_finance_frontend_core_ui/widgets/crypto_trade_form.dart';
7
+ import '../viewmodels/crypto_account_viewmodel.dart';
10
8
 
11
- class CryptoAccountScreen extends StatefulWidget {
9
+ class CryptoAccountScreen extends StatelessWidget {
12
10
  final String accountName;
13
11
 
14
- const CryptoAccountScreen({Key? key, required this.accountName}) : super(key: key);
15
-
16
- @override
17
- _CryptoAccountScreenState createState() => _CryptoAccountScreenState();
18
- }
19
-
20
- class _CryptoAccountScreenState extends State<CryptoAccountScreen> {
21
- final TransactionService _transactionService = TransactionService();
22
- final CryptoService _cryptoService = CryptoService();
23
-
24
- List<Map<String, dynamic>> _trades = [];
25
- List<Map<String, dynamic>> _assets = [];
26
- List<Map<String, dynamic>> _portfolioSummary = [];
27
- Map<String, double> _livePrices = {};
28
- double _cashBalance = 0.0;
29
- double _accountTotalValue = 0.0;
30
- double _totalPortfolioBookCost = 0.0;
31
- bool _isLoading = true;
32
- bool _isFetchingPrices = false;
33
- String? _selectedSymbolForFilter;
34
- String? _token;
35
-
36
- @override
37
- void initState() {
38
- super.initState();
39
- WidgetsBinding.instance.addPostFrameCallback((_) {
40
- final authProvider = Provider.of<AuthProvider>(context, listen: false);
41
- setState(() {
42
- _token = authProvider.token;
43
- });
44
- _fetchData();
45
- });
46
- }
47
-
48
- String currencySymbol = r'$';
49
-
50
- String _formatCurrency(double value) {
51
- return '$currencySymbol${value.toStringAsFixed(2)}';
52
- }
53
-
54
- Future<void> _fetchData() async {
55
- if (_token == null) return;
56
- setState(() => _isLoading = true);
57
- try {
58
- final futures = <Future>[
59
- _transactionService.getTrades(investmentAccount: widget.accountName, token: _token),
60
- _transactionService.getAccountBalance(widget.accountName, token: _token),
61
- _transactionService.getAssets(investmentAccount: widget.accountName, token: _token),
62
- _transactionService.getTotalPortfolioBookCost(token: _token), // Fetch total cost
63
- ];
64
- final results = await Future.wait(futures);
65
-
66
- final trades = results[0] as List<Map<String, dynamic>>;
67
- final balance = results[1] as double;
68
- final assets = results[2] as List<Map<String, dynamic>>;
69
- final totalPortfolioBookCost = results[3] as double;
70
-
71
- final summaryData = _calculatePortfolioSummary(trades, totalPortfolioBookCost);
72
-
73
- setState(() {
74
- _trades = trades;
75
- _cashBalance = balance;
76
- _assets = assets;
77
- _portfolioSummary = summaryData['summary'];
78
- _accountTotalValue = summaryData['total_value'] + _cashBalance;
79
- _totalPortfolioBookCost = totalPortfolioBookCost;
80
- });
81
-
82
- if (mounted) await _fetchLivePrices();
83
- } catch (e) {
84
- if (mounted) ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('Error fetching data: $e')));
85
- } finally {
86
- if (mounted) setState(() => _isLoading = false);
87
- }
88
- }
89
-
90
- Future<void> _fetchLivePrices() async {
91
- if (_portfolioSummary.isEmpty || !mounted) return;
92
- setState(() => _isFetchingPrices = true);
93
-
94
- final idsToFetch = _portfolioSummary.map((p) => p['id_crypto'] as String? ?? p['symbol'] as String).where((s) => s.isNotEmpty).toList();
95
-
96
- if (idsToFetch.isEmpty) {
97
- setState(() => _isFetchingPrices = false);
98
- return;
99
- }
100
-
101
- final livePrices = await _cryptoService.getLiveCryptoPrices(idsToFetch);
102
-
103
- if (!mounted) return;
104
-
105
- double newTotalValue = _cashBalance;
106
- for (final position in _portfolioSummary) {
107
- final shares = double.parse(position['shares'].toString());
108
- final idForLookup = (position['id_crypto'] as String? ?? position['symbol'] as String).toLowerCase();
109
- final livePrice = livePrices[idForLookup];
110
- if (livePrice != null) {
111
- newTotalValue += shares * livePrice;
112
- } else {
113
- newTotalValue += (position['total_cost'] as num?)?.toDouble() ?? 0.0;
114
- }
115
- }
116
-
117
- setState(() {
118
- _livePrices = livePrices;
119
- _accountTotalValue = newTotalValue;
120
- _isFetchingPrices = false;
121
- });
122
- }
123
-
124
- Map<String, dynamic> _calculatePortfolioSummary(List<Map<String, dynamic>> trades, double totalPortfolioBookCost) {
125
- Map<String, dynamic> summary = {};
126
- double accountPortfolioBookCost = 0;
127
-
128
- for (var trade in trades) {
129
- final asset = trade['asset'];
130
- if (asset == null || asset['symbol'] == null) continue;
131
- String symbol = asset['symbol'];
132
- String idCrypto = asset['id_crypto'] ?? symbol;
133
-
134
- double shares = double.parse(trade['shares'].toString());
135
- double price = double.parse(trade['price'].toString());
136
- String tradeType = trade['trade_type'];
137
-
138
- if (!summary.containsKey(symbol)) {
139
- summary[symbol] = {
140
- 'symbol': symbol,
141
- 'id_crypto': idCrypto,
142
- 'name': asset['name'] ?? symbol,
143
- 'shares': 0.0,
144
- 'total_cost': 0.0,
145
- };
146
- }
147
-
148
- if (tradeType == 'buy') {
149
- summary[symbol]['shares'] += shares;
150
- summary[symbol]['total_cost'] += shares * price;
151
- } else if (tradeType == 'sell') {
152
- double originalShares = summary[symbol]['shares'];
153
- if (originalShares > 0) {
154
- double avgPrice = summary[symbol]['total_cost'] / originalShares;
155
- summary[symbol]['total_cost'] -= shares * avgPrice;
156
- }
157
- summary[symbol]['shares'] -= shares;
158
- }
159
- }
160
-
161
- summary.removeWhere((key, value) => value['shares'] < 0.01);
162
- accountPortfolioBookCost = summary.values.fold(0.0, (sum, item) => sum + item['total_cost']);
163
-
164
- List<Map<String, dynamic>> result = [];
165
- summary.forEach((symbol, data) {
166
- double shares = data['shares'];
167
- double totalCost = data['total_cost'];
168
- data['avg_price'] = (shares > 0) ? totalCost / shares : 0.0;
169
- data['account_allocation'] = (accountPortfolioBookCost > 0) ? (totalCost / accountPortfolioBookCost) * 100 : 0.0;
170
- data['stocks_allocation'] = (totalPortfolioBookCost > 0) ? (totalCost / totalPortfolioBookCost) * 100 : 0.0;
171
- result.add(data);
172
- });
173
-
174
- return {'summary': result, 'total_value': accountPortfolioBookCost};
175
- }
176
-
12
+ const CryptoAccountScreen({Key? key, required this.accountName})
13
+ : super(key: key);
177
14
 
178
15
  @override
179
16
  Widget build(BuildContext context) {
180
- return Scaffold(
181
- appBar: AppBar(
182
- title: Text('${widget.accountName} Portfolio'),
183
- actions: [
184
- Center(
185
- child: Padding(
186
- padding: const EdgeInsets.only(right: 16.0),
187
- child: Column(
188
- mainAxisAlignment: MainAxisAlignment.center,
189
- crossAxisAlignment: CrossAxisAlignment.end,
190
- children: [
191
- Text('Total Portfolio: ${_formatCurrency(_accountTotalValue)}', style: const TextStyle(fontSize: 16, fontWeight: FontWeight.bold)),
192
- Text('Account Balance: ${_formatCurrency(_cashBalance)}', style: const TextStyle(fontSize: 12)),
193
- ],
194
- ),
195
- ),
196
- ),
197
- IconButton(icon: const Icon(Icons.refresh), onPressed: _fetchData, tooltip: 'Refresh Data'),
198
- ],
17
+ final authProvider = Provider.of<AuthProvider>(context, listen: false);
18
+
19
+ return ChangeNotifierProvider(
20
+ create: (_) => CryptoAccountViewModel(
21
+ accountName: accountName,
22
+ token: authProvider.token,
199
23
  ),
200
- body: _isLoading
201
- ? const Center(child: CircularProgressIndicator())
202
- : RefreshIndicator(
203
- onRefresh: _fetchData,
204
- child: SingleChildScrollView(
205
- physics: const AlwaysScrollableScrollPhysics(),
206
- padding: const EdgeInsets.all(16.0),
207
- child: Column(
208
- crossAxisAlignment: CrossAxisAlignment.stretch,
209
- children: [
210
- Row(
211
- mainAxisAlignment: MainAxisAlignment.spaceBetween,
24
+ child: Consumer<CryptoAccountViewModel>(
25
+ builder: (context, viewModel, child) {
26
+ return Scaffold(
27
+ appBar: AppBar(
28
+ title: Text('$accountName Portfolio'),
29
+ actions: [
30
+ Center(
31
+ child: Padding(
32
+ padding: const EdgeInsets.only(right: 16.0),
33
+ child: Column(
34
+ mainAxisAlignment: MainAxisAlignment.center,
35
+ crossAxisAlignment: CrossAxisAlignment.end,
212
36
  children: [
213
- Text('Portfolio Summary', style: Theme.of(context).textTheme.titleLarge),
214
- if (_isFetchingPrices) const SizedBox(height: 20, width: 20, child: CircularProgressIndicator(strokeWidth: 2.0)),
37
+ Text(
38
+ 'Total Portfolio: ${_formatCurrency(viewModel.accountTotalValue)}',
39
+ style: const TextStyle(
40
+ fontSize: 16, fontWeight: FontWeight.bold),
41
+ ),
42
+ Text(
43
+ 'Account Balance: ${_formatCurrency(viewModel.cashBalance)}',
44
+ style: const TextStyle(fontSize: 12),
45
+ ),
215
46
  ],
216
47
  ),
217
- _buildSinteticoTable(),
218
- const SizedBox(height: 24),
219
- CryptoTradeForm(
220
- accountName: widget.accountName,
221
- portfolioSummary: _portfolioSummary,
222
- onTradeCreated: (_) => _fetchData(),
223
- token: _token),
224
- const SizedBox(height: 24),
225
- Text('Trade History', style: Theme.of(context).textTheme.titleLarge),
226
- const SizedBox(height: 8),
227
- _buildAnaliticoTable(),
228
- ],
48
+ ),
229
49
  ),
230
- ),
50
+ IconButton(
51
+ icon: const Icon(Icons.refresh),
52
+ onPressed: viewModel.fetchData,
53
+ tooltip: 'Refresh Data',
54
+ ),
55
+ ],
231
56
  ),
57
+ body: viewModel.isLoading
58
+ ? const Center(child: CircularProgressIndicator())
59
+ : RefreshIndicator(
60
+ onRefresh: viewModel.fetchData,
61
+ child: SingleChildScrollView(
62
+ physics: const AlwaysScrollableScrollPhysics(),
63
+ padding: const EdgeInsets.all(16.0),
64
+ child: Column(
65
+ crossAxisAlignment: CrossAxisAlignment.stretch,
66
+ children: [
67
+ Row(
68
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
69
+ children: [
70
+ Text('Portfolio Summary',
71
+ style:
72
+ Theme.of(context).textTheme.titleLarge),
73
+ if (viewModel.isFetchingPrices)
74
+ const SizedBox(
75
+ height: 20,
76
+ width: 20,
77
+ child: CircularProgressIndicator(
78
+ strokeWidth: 2.0),
79
+ ),
80
+ ],
81
+ ),
82
+ _buildSinteticoTable(context, viewModel),
83
+ const SizedBox(height: 24),
84
+ CryptoTradeForm(
85
+ accountName: accountName,
86
+ portfolioSummary: viewModel.portfolioSummary,
87
+ onTradeCreated: (_) => viewModel.fetchData(),
88
+ token: viewModel.token,
89
+ ),
90
+ const SizedBox(height: 24),
91
+ Text('Trade History',
92
+ style: Theme.of(context).textTheme.titleLarge),
93
+ const SizedBox(height: 8),
94
+ _buildAnaliticoTable(context, viewModel),
95
+ ],
96
+ ),
97
+ ),
98
+ ),
99
+ );
100
+ },
101
+ ),
232
102
  );
233
103
  }
234
104
 
235
- Widget _buildSinteticoTable() {
236
- if (_portfolioSummary.isEmpty) return const Center(child: Padding(padding: EdgeInsets.all(16.0), child: Text('No positions held.')));
237
-
105
+ String _formatCurrency(double value) {
106
+ String currencySymbol = r'$';
107
+ return '$currencySymbol${value.toStringAsFixed(2)}';
108
+ }
109
+
110
+ Widget _buildSinteticoTable(
111
+ BuildContext context, CryptoAccountViewModel viewModel) {
112
+ if (viewModel.portfolioSummary.isEmpty) {
113
+ return const Center(
114
+ child: Padding(
115
+ padding: EdgeInsets.all(16.0),
116
+ child: Text('No positions held.'),
117
+ ),
118
+ );
119
+ }
120
+
238
121
  return SingleChildScrollView(
239
122
  scrollDirection: Axis.horizontal,
240
123
  child: DataTable(
@@ -251,51 +134,75 @@ class _CryptoAccountScreenState extends State<CryptoAccountScreen> {
251
134
  DataColumn(label: Text('Return')),
252
135
  DataColumn(label: Text('% Return')),
253
136
  ],
254
- rows: _portfolioSummary.map((position) {
137
+ rows: viewModel.portfolioSummary.map((position) {
255
138
  final symbol = position['symbol'] as String;
256
- final idForLookup = (position['id_crypto'] as String? ?? symbol).toLowerCase();
257
- final livePrice = _livePrices[idForLookup];
258
- final shares = double.parse(position['shares'].toString());
259
- final avgPrice = double.parse(position['avg_price'].toString());
260
- final totalPurchased = double.parse(position['total_cost'].toString());
261
- final accountAllocation = (position['account_allocation'] as num?)?.toDouble() ?? 0.0;
262
- final stocksAllocation = (position['stocks_allocation'] as num?)?.toDouble() ?? 0.0;
263
-
264
- double? totalReturnValue, percentageReturn;
139
+ final idForLookup =
140
+ (position['id_crypto'] as String? ?? symbol).toLowerCase();
141
+ final livePrice = viewModel.livePrices[idForLookup];
142
+ final shares = double.tryParse(position['shares']?.toString() ?? '0.0') ?? 0.0;
143
+ final avgPrice = double.tryParse(position['avg_price']?.toString() ?? '0.0') ?? 0.0;
144
+ final totalPurchased = double.tryParse(position['total_cost']?.toString() ?? '0.0') ?? 0.0;
145
+ final accountAllocation = double.tryParse(position['account_allocation']?.toString() ?? '0.0') ?? 0.0;
146
+ final stocksAllocation = double.tryParse(position['stocks_allocation']?.toString() ?? '0.0') ?? 0.0;
265
147
 
266
- if (livePrice != null && shares > 0) {
267
- final currentMarketValue = livePrice * shares;
268
- totalReturnValue = currentMarketValue - totalPurchased;
269
- if (totalPurchased > 0) percentageReturn = (totalReturnValue / totalPurchased) * 100;
270
- }
148
+ final totalReturnValue = double.tryParse(position['total_return_value']?.toString() ?? '0.0') ?? 0.0;
149
+ final percentageReturn = double.tryParse(position['percentage_return']?.toString() ?? '0.0') ?? 0.0;
271
150
 
272
- final returnColor = (totalReturnValue ?? 0) >= 0 ? Colors.green : Colors.red;
151
+ final returnColor =
152
+ totalReturnValue >= 0 ? Colors.green : Colors.red;
273
153
 
274
154
  return DataRow(cells: [
275
- DataCell(SizedBox(width: 150, child: Text(position['name'] as String, overflow: TextOverflow.ellipsis))),
155
+ DataCell(SizedBox(
156
+ width: 150,
157
+ child: Text(position['name'] as String,
158
+ overflow: TextOverflow.ellipsis))),
276
159
  DataCell(Text(symbol)),
277
160
  DataCell(Text(shares.toStringAsFixed(6))),
278
161
  DataCell(Text(_formatCurrency(avgPrice))),
279
- DataCell(livePrice != null ? Text(_formatCurrency(livePrice)) : const Text('N/A')),
162
+ DataCell(livePrice != null
163
+ ? Text(_formatCurrency(livePrice))
164
+ : const Text('N/A')),
280
165
  DataCell(Text(_formatCurrency(totalPurchased))),
281
166
  DataCell(Text('${accountAllocation.toStringAsFixed(2)}%')),
282
167
  DataCell(Text('${stocksAllocation.toStringAsFixed(2)}%')),
283
- DataCell(totalReturnValue != null ? Text(_formatCurrency(totalReturnValue), style: TextStyle(color: returnColor)) : const Text('N/A')),
284
- DataCell(percentageReturn != null ? Text('${percentageReturn.toStringAsFixed(2)}%', style: TextStyle(color: returnColor)) : const Text('N/A')),
168
+ DataCell(
169
+ totalReturnValue != null
170
+ ? Text(_formatCurrency(totalReturnValue),
171
+ style: TextStyle(color: returnColor))
172
+ : const Text('N/A'),
173
+ ),
174
+ DataCell(
175
+ percentageReturn != null
176
+ ? Text('${percentageReturn.toStringAsFixed(2)}%',
177
+ style: TextStyle(color: returnColor))
178
+ : const Text('N/A'),
179
+ ),
285
180
  ]);
286
181
  }).toList(),
287
182
  ),
288
183
  );
289
184
  }
290
185
 
291
- Widget _buildAnaliticoTable() {
292
- if (_trades.isEmpty) return const Center(child: Padding(padding: EdgeInsets.all(16.0), child: Text('No trades found.')));
186
+ Widget _buildAnaliticoTable(
187
+ BuildContext context, CryptoAccountViewModel viewModel) {
188
+ if (viewModel.trades.isEmpty) {
189
+ return const Center(
190
+ child: Padding(
191
+ padding: EdgeInsets.all(16.0),
192
+ child: Text('No trades found.'),
193
+ ),
194
+ );
195
+ }
293
196
 
294
- final sortedTrades = List<Map<String, dynamic>>.from(_trades)..sort((a, b) {
295
- try {
296
- return DateTime.parse(b['date'] as String).compareTo(DateTime.parse(a['date'] as String));
297
- } catch (e) { return 0; }
298
- });
197
+ final sortedTrades = List<Map<String, dynamic>>.from(viewModel.trades)
198
+ ..sort((a, b) {
199
+ try {
200
+ return DateTime.parse(b['date'] as String)
201
+ .compareTo(DateTime.parse(a['date'] as String));
202
+ } catch (e) {
203
+ return 0;
204
+ }
205
+ });
299
206
 
300
207
  return DataTable(
301
208
  columns: const [
@@ -305,14 +212,14 @@ class _CryptoAccountScreenState extends State<CryptoAccountScreen> {
305
212
  DataColumn(label: Text('Quantity')),
306
213
  DataColumn(label: Text('Price')),
307
214
  DataColumn(label: Text('Total')),
308
- DataColumn(label: Text('Actions')), // New column
215
+ DataColumn(label: Text('Actions')),
309
216
  ],
310
217
  rows: sortedTrades.map((trade) {
311
- final double shares = double.parse(trade['shares'].toString());
312
- final double price = double.parse(trade['price'].toString());
218
+ final double shares = double.tryParse(trade['shares']?.toString() ?? '0.0') ?? 0.0;
219
+ final double price = double.tryParse(trade['price']?.toString() ?? '0.0') ?? 0.0;
313
220
  final double total = shares * price;
314
221
  final tradeDate = DateTime.parse(trade['date'] as String);
315
- final int tradeId = trade['id'] as int; // Get trade ID
222
+ final int tradeId = trade['id'] as int;
316
223
 
317
224
  return DataRow(cells: [
318
225
  DataCell(Text(DateFormat('yyyy-MM-dd').format(tradeDate))),
@@ -321,10 +228,11 @@ class _CryptoAccountScreenState extends State<CryptoAccountScreen> {
321
228
  DataCell(Text(shares.toStringAsFixed(6))),
322
229
  DataCell(Text(_formatCurrency(price))),
323
230
  DataCell(Text(_formatCurrency(total))),
324
- DataCell( // New cell for the delete button
231
+ DataCell(
325
232
  IconButton(
326
233
  icon: const Icon(Icons.delete, color: Colors.red),
327
- onPressed: () => _confirmAndDeleteTrade(tradeId),
234
+ onPressed: () =>
235
+ _confirmAndDeleteTrade(context, viewModel, tradeId),
328
236
  tooltip: 'Delete Trade',
329
237
  ),
330
238
  ),
@@ -333,31 +241,20 @@ class _CryptoAccountScreenState extends State<CryptoAccountScreen> {
333
241
  );
334
242
  }
335
243
 
336
- Future<void> _confirmAndDeleteTrade(int tradeId) async {
337
- final bool? confirm = await AppDialogs.showDeleteConfirmationDialog(context, 'this trade');
244
+ Future<void> _confirmAndDeleteTrade(BuildContext context,
245
+ CryptoAccountViewModel viewModel, int tradeId) async {
246
+ final bool? confirm =
247
+ await AppDialogs.showDeleteConfirmationDialog(context, 'this trade');
338
248
 
339
249
  if (confirm == true) {
340
- if (_token == null) {
250
+ final success = await viewModel.deleteTrade(tradeId);
251
+ if (ScaffoldMessenger.of(context).mounted) {
341
252
  ScaffoldMessenger.of(context).showSnackBar(
342
- const SnackBar(content: Text('Authentication token not available.')),
343
- );
344
- return;
345
- }
346
- try {
347
- final success = await _transactionService.deleteTrade(tradeId, token: _token);
348
- if (success) {
349
- ScaffoldMessenger.of(context).showSnackBar(
350
- const SnackBar(content: Text('Trade deleted successfully.')),
351
- );
352
- _fetchData(); // Refresh data after deletion
353
- } else {
354
- ScaffoldMessenger.of(context).showSnackBar(
355
- const SnackBar(content: Text('Failed to delete trade.')),
356
- );
357
- }
358
- } catch (e) {
359
- ScaffoldMessenger.of(context).showSnackBar(
360
- SnackBar(content: Text('Error deleting trade: $e')),
253
+ SnackBar(
254
+ content: Text(success
255
+ ? 'Trade deleted successfully.'
256
+ : 'Failed to delete trade.'),
257
+ ),
361
258
  );
362
259
  }
363
260
  }