@marcos_feitoza/personal-finance-frontend-feature-investments 1.0.0 → 1.0.1

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,12 @@
1
+ ## [1.0.1](https://github.com/MarcosOps/personal-finance-frontend-feature-investments/compare/v1.0.0...v1.0.1) (2025-11-27)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * add crypto table update ([e2e0da7](https://github.com/MarcosOps/personal-finance-frontend-feature-investments/commit/e2e0da77e334dd4416d04770db50be9b91bb0c06))
7
+ * fix and update the tables of investments ([ff5a7b5](https://github.com/MarcosOps/personal-finance-frontend-feature-investments/commit/ff5a7b56d627ebf0ef128e03ff6ad6a57efda042))
8
+ * update rrsp sl table ([107b6dc](https://github.com/MarcosOps/personal-finance-frontend-feature-investments/commit/107b6dce59621e3563e589e00b21f2fbbb529921))
9
+
1
10
  # 1.0.0 (2025-11-22)
2
11
 
3
12
 
@@ -58,7 +58,7 @@ class _CryptoAccountScreenState extends State<CryptoAccountScreen> {
58
58
  _transactionService.getTrades(investmentAccount: widget.accountName, token: _token),
59
59
  _transactionService.getAccountBalance(widget.accountName, token: _token),
60
60
  _transactionService.getAssets(investmentAccount: widget.accountName, token: _token),
61
- _transactionService.getTotalPortfolioBookCost(token: _token), // Fetch total cost
61
+ _transactionService.getTotalPortfolioBookCost(token: _token),
62
62
  ];
63
63
  final results = await Future.wait(futures);
64
64
 
@@ -67,18 +67,21 @@ class _CryptoAccountScreenState extends State<CryptoAccountScreen> {
67
67
  final assets = results[2] as List<Map<String, dynamic>>;
68
68
  final totalPortfolioBookCost = results[3] as double;
69
69
 
70
- final summaryData = _calculatePortfolioSummary(trades, totalPortfolioBookCost);
70
+ // Initial calculation without live prices
71
+ final initialSummaryData = _calculatePortfolioSummary(trades, totalPortfolioBookCost);
71
72
 
72
73
  setState(() {
73
74
  _trades = trades;
74
75
  _cashBalance = balance;
75
76
  _assets = assets;
76
- _portfolioSummary = summaryData['summary'];
77
- _accountTotalValue = summaryData['total_value'] + _cashBalance;
77
+ _portfolioSummary = initialSummaryData['summary'];
78
+ _accountTotalValue = initialSummaryData['total_value'] + _cashBalance;
78
79
  _totalPortfolioBookCost = totalPortfolioBookCost;
79
80
  });
80
81
 
81
- if (mounted) await _fetchLivePrices();
82
+ // Fetch live prices and recalculate summary
83
+ if (mounted) await _fetchLivePricesAndRecalculate();
84
+
82
85
  } catch (e) {
83
86
  if (mounted) ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('Error fetching data: $e')));
84
87
  } finally {
@@ -86,7 +89,7 @@ class _CryptoAccountScreenState extends State<CryptoAccountScreen> {
86
89
  }
87
90
  }
88
91
 
89
- Future<void> _fetchLivePrices() async {
92
+ Future<void> _fetchLivePricesAndRecalculate() async {
90
93
  if (_portfolioSummary.isEmpty || !mounted) return;
91
94
  setState(() => _isFetchingPrices = true);
92
95
 
@@ -101,28 +104,22 @@ class _CryptoAccountScreenState extends State<CryptoAccountScreen> {
101
104
 
102
105
  if (!mounted) return;
103
106
 
104
- double newTotalValue = _cashBalance;
105
- for (final position in _portfolioSummary) {
106
- final shares = double.parse(position['shares'].toString());
107
- final idForLookup = (position['id_crypto'] as String? ?? position['symbol'] as String).toLowerCase();
108
- final livePrice = livePrices[idForLookup];
109
- if (livePrice != null) {
110
- newTotalValue += shares * livePrice;
111
- } else {
112
- newTotalValue += (position['total_cost'] as num?)?.toDouble() ?? 0.0;
113
- }
114
- }
107
+ // Recalculate summary with live prices
108
+ final summaryDataWithLivePrices = _calculatePortfolioSummary(_trades, _totalPortfolioBookCost, livePrices: livePrices);
109
+
110
+ double newTotalMarketValue = summaryDataWithLivePrices['total_value'];
115
111
 
116
112
  setState(() {
117
113
  _livePrices = livePrices;
118
- _accountTotalValue = newTotalValue;
114
+ _portfolioSummary = summaryDataWithLivePrices['summary'];
115
+ _accountTotalValue = newTotalMarketValue + _cashBalance;
119
116
  _isFetchingPrices = false;
120
117
  });
121
118
  }
122
119
 
123
- Map<String, dynamic> _calculatePortfolioSummary(List<Map<String, dynamic>> trades, double totalPortfolioBookCost) {
120
+ Map<String, dynamic> _calculatePortfolioSummary(List<Map<String, dynamic>> trades, double totalPortfolioBookCost, {Map<String, double>? livePrices}) {
124
121
  Map<String, dynamic> summary = {};
125
- double accountPortfolioBookCost = 0;
122
+ livePrices ??= _livePrices; // Use state's live prices if not provided
126
123
 
127
124
  for (var trade in trades) {
128
125
  final asset = trade['asset'];
@@ -140,39 +137,53 @@ class _CryptoAccountScreenState extends State<CryptoAccountScreen> {
140
137
  'id_crypto': idCrypto,
141
138
  'name': asset['name'] ?? symbol,
142
139
  'shares': 0.0,
143
- 'total_cost': 0.0,
140
+ 'book_cost': 0.0,
144
141
  };
145
142
  }
146
143
 
147
144
  if (tradeType == 'buy') {
148
145
  summary[symbol]['shares'] += shares;
149
- summary[symbol]['total_cost'] += shares * price;
146
+ summary[symbol]['book_cost'] += shares * price;
150
147
  } else if (tradeType == 'sell') {
151
148
  double originalShares = summary[symbol]['shares'];
152
149
  if (originalShares > 0) {
153
- double avgPrice = summary[symbol]['total_cost'] / originalShares;
154
- summary[symbol]['total_cost'] -= shares * avgPrice;
150
+ double avgPrice = summary[symbol]['book_cost'] / originalShares;
151
+ summary[symbol]['book_cost'] -= shares * avgPrice;
155
152
  }
156
153
  summary[symbol]['shares'] -= shares;
157
154
  }
158
155
  }
159
156
 
160
157
  summary.removeWhere((key, value) => value['shares'] < 0.01);
161
- accountPortfolioBookCost = summary.values.fold(0.0, (sum, item) => sum + item['total_cost']);
162
158
 
159
+ double accountTotalBookCost = summary.values.fold(0.0, (sum, item) => sum + item['book_cost']);
160
+
163
161
  List<Map<String, dynamic>> result = [];
164
162
  summary.forEach((symbol, data) {
165
163
  double shares = data['shares'];
166
- double totalCost = data['total_cost'];
167
- data['avg_price'] = (shares > 0) ? totalCost / shares : 0.0;
168
- data['account_allocation'] = (accountPortfolioBookCost > 0) ? (totalCost / accountPortfolioBookCost) * 100 : 0.0;
169
- data['stocks_allocation'] = (totalPortfolioBookCost > 0) ? (totalCost / totalPortfolioBookCost) * 100 : 0.0;
164
+ double bookCost = data['book_cost'];
165
+
166
+ data['avg_price'] = (shares > 0) ? bookCost / shares : 0.0;
167
+ data['account_allocation_percent'] = (accountTotalBookCost > 0) ? (bookCost / accountTotalBookCost) * 100 : 0.0;
168
+ data['portfolio_allocation_percent'] = (totalPortfolioBookCost > 0) ? (bookCost / totalPortfolioBookCost) * 100 : 0.0;
169
+
170
+ final idForLookup = (data['id_crypto'] as String? ?? data['symbol'] as String).toLowerCase();
171
+ final livePrice = livePrices![idForLookup];
172
+ double marketValue = livePrice != null ? shares * livePrice : bookCost;
173
+ double unrealizedPL = marketValue - bookCost;
174
+
175
+ data['market_value'] = marketValue;
176
+ data['unrealized_pl'] = unrealizedPL;
177
+ data['percent_pl'] = (bookCost > 0) ? (unrealizedPL / bookCost) * 100 : 0.0;
178
+
170
179
  result.add(data);
171
180
  });
172
181
 
173
- return {'summary': result, 'total_value': accountPortfolioBookCost};
182
+ double accountTotalMarketValue = result.fold(0.0, (sum, item) => sum + item['market_value']);
183
+ return {'summary': result, 'total_value': accountTotalMarketValue};
174
184
  }
175
185
 
186
+
176
187
  @override
177
188
  Widget build(BuildContext context) {
178
189
  return Scaffold(
@@ -238,48 +249,43 @@ class _CryptoAccountScreenState extends State<CryptoAccountScreen> {
238
249
  child: DataTable(
239
250
  columnSpacing: 24.0,
240
251
  columns: const [
241
- DataColumn(label: Text('Name')),
242
252
  DataColumn(label: Text('Symbol')),
243
- DataColumn(label: Text('Quantity')),
253
+ DataColumn(label: Text('Shares')),
244
254
  DataColumn(label: Text('Avg Price')),
245
- DataColumn(label: Text('Live')),
246
255
  DataColumn(label: Text('Book Cost')),
247
- DataColumn(label: Text('Allocation')),
248
- DataColumn(label: Text('Stocks Allocation')),
249
- DataColumn(label: Text('Return')),
250
- DataColumn(label: Text('% Return')),
256
+ DataColumn(label: Text('Live Price')),
257
+ DataColumn(label: Text('Market Value')),
258
+ DataColumn(label: Text('Unrealized P/L')),
259
+ DataColumn(label: Text('% P/L')),
260
+ DataColumn(label: Text('Account %')),
261
+ DataColumn(label: Text('Portfolio %')),
251
262
  ],
252
263
  rows: _portfolioSummary.map((position) {
253
- final symbol = position['symbol'] as String;
254
- final idForLookup = (position['id_crypto'] as String? ?? symbol).toLowerCase();
255
- final livePrice = _livePrices[idForLookup];
256
- final shares = double.parse(position['shares'].toString());
257
- final avgPrice = double.parse(position['avg_price'].toString());
258
- final totalPurchased = double.parse(position['total_cost'].toString());
259
- final accountAllocation = (position['account_allocation'] as num?)?.toDouble() ?? 0.0;
260
- final stocksAllocation = (position['stocks_allocation'] as num?)?.toDouble() ?? 0.0;
261
-
262
- double? totalReturnValue, percentageReturn;
263
-
264
- if (livePrice != null && shares > 0) {
265
- final currentMarketValue = livePrice * shares;
266
- totalReturnValue = currentMarketValue - totalPurchased;
267
- if (totalPurchased > 0) percentageReturn = (totalReturnValue / totalPurchased) * 100;
268
- }
269
-
270
- final returnColor = (totalReturnValue ?? 0) >= 0 ? Colors.green : Colors.red;
264
+ final String symbol = position['symbol'];
265
+ final double shares = position['shares'];
266
+ final double avgPrice = position['avg_price'];
267
+ final double bookCost = position['book_cost'];
268
+ final String idForLookup = (position['id_crypto'] as String? ?? symbol).toLowerCase();
269
+ final double? livePrice = _livePrices[idForLookup];
270
+ final double marketValue = position['market_value'];
271
+ final double unrealizedPL = position['unrealized_pl'];
272
+ final double percentPL = position['percent_pl'];
273
+ final double accountAllocation = position['account_allocation_percent'];
274
+ final double portfolioAllocation = position['portfolio_allocation_percent'];
275
+
276
+ final plColor = (unrealizedPL >= 0) ? Colors.green : Colors.red;
271
277
 
272
278
  return DataRow(cells: [
273
- DataCell(SizedBox(width: 150, child: Text(position['name'] as String, overflow: TextOverflow.ellipsis))),
274
279
  DataCell(Text(symbol)),
275
280
  DataCell(Text(shares.toStringAsFixed(6))),
276
281
  DataCell(Text(_formatCurrency(avgPrice))),
282
+ DataCell(Text(_formatCurrency(bookCost))),
277
283
  DataCell(livePrice != null ? Text(_formatCurrency(livePrice)) : const Text('N/A')),
278
- DataCell(Text(_formatCurrency(totalPurchased))),
284
+ DataCell(Text(_formatCurrency(marketValue))),
285
+ DataCell(Text(_formatCurrency(unrealizedPL), style: TextStyle(color: plColor))),
286
+ DataCell(Text('${percentPL.toStringAsFixed(2)}%', style: TextStyle(color: plColor))),
279
287
  DataCell(Text('${accountAllocation.toStringAsFixed(2)}%')),
280
- DataCell(Text('${stocksAllocation.toStringAsFixed(2)}%')),
281
- DataCell(totalReturnValue != null ? Text(_formatCurrency(totalReturnValue), style: TextStyle(color: returnColor)) : const Text('N/A')),
282
- DataCell(percentageReturn != null ? Text('${percentageReturn.toStringAsFixed(2)}%', style: TextStyle(color: returnColor)) : const Text('N/A')),
288
+ DataCell(Text('${portfolioAllocation.toStringAsFixed(2)}%')),
283
289
  ]);
284
290
  }).toList(),
285
291
  ),
@@ -141,7 +141,8 @@ class _InvestmentAccountScreenState extends State<InvestmentAccountScreen> {
141
141
  if (livePrice != null) {
142
142
  newTotalValue += shares * livePrice;
143
143
  } else {
144
- newTotalValue += (position['total_cost'] as num?)?.toDouble() ?? 0.0;
144
+ // If live price is not available, use book cost as a fallback for market value
145
+ newTotalValue += (position['book_cost'] as num?)?.toDouble() ?? 0.0;
145
146
  }
146
147
  }
147
148
 
@@ -155,7 +156,7 @@ class _InvestmentAccountScreenState extends State<InvestmentAccountScreen> {
155
156
  Map<String, dynamic> _calculatePortfolioSummary(
156
157
  List<Map<String, dynamic>> trades, List<Map<String, dynamic>> dividends) {
157
158
  Map<String, dynamic> summary = {};
158
- double accountPortfolioBookCost = 0;
159
+ double accountTotalBookCost = 0;
159
160
 
160
161
  Map<String, double> dividendSummary = {};
161
162
  if (widget.showDividends) {
@@ -186,7 +187,7 @@ class _InvestmentAccountScreenState extends State<InvestmentAccountScreen> {
186
187
  'name': asset['name'] ?? symbol,
187
188
  'industry': asset['industry'] ?? 'N/A',
188
189
  'shares': 0.0,
189
- 'total_cost': 0.0,
190
+ 'book_cost': 0.0, // Renamed from total_cost for clarity
190
191
  'total_dividends': dividendSummary[symbol] ?? 0.0,
191
192
  'first_trade_date': tradeDate,
192
193
  'last_activity_date': tradeDate,
@@ -202,12 +203,12 @@ class _InvestmentAccountScreenState extends State<InvestmentAccountScreen> {
202
203
 
203
204
  if (tradeType == 'buy') {
204
205
  summary[symbol]['shares'] += shares;
205
- summary[symbol]['total_cost'] += shares * price;
206
+ summary[symbol]['book_cost'] += shares * price;
206
207
  } else if (tradeType == 'sell') {
207
208
  double originalShares = summary[symbol]['shares'];
208
209
  if (originalShares > 0) {
209
- double avgPrice = summary[symbol]['total_cost'] / originalShares;
210
- summary[symbol]['total_cost'] -= shares * avgPrice;
210
+ double avgPrice = summary[symbol]['book_cost'] / originalShares;
211
+ summary[symbol]['book_cost'] -= shares * avgPrice;
211
212
  }
212
213
  summary[symbol]['shares'] -= shares;
213
214
  }
@@ -215,21 +216,40 @@ class _InvestmentAccountScreenState extends State<InvestmentAccountScreen> {
215
216
 
216
217
  summary.removeWhere((key, value) => value['shares'] < 0.01);
217
218
 
218
- accountPortfolioBookCost =
219
- summary.values.fold(0.0, (sum, item) => sum + item['total_cost']);
219
+ accountTotalBookCost =
220
+ summary.values.fold(0.0, (sum, item) => sum + item['book_cost']);
220
221
 
221
222
  List<Map<String, dynamic>> result = [];
222
223
  summary.forEach((symbol, data) {
223
224
  double shares = data['shares'];
224
- double totalCost = data['total_cost'];
225
- data['avg_price'] = (shares > 0) ? totalCost / shares : 0.0;
226
- data['account_allocation'] = (accountPortfolioBookCost > 0)
227
- ? (totalCost / accountPortfolioBookCost) * 100
225
+ double bookCost = data['book_cost'];
226
+ double totalDividends = data['total_dividends'];
227
+
228
+ data['avg_price'] = (shares > 0) ? bookCost / shares : 0.0;
229
+ data['account_allocation_percent'] = (accountTotalBookCost > 0)
230
+ ? (bookCost / accountTotalBookCost) * 100
231
+ : 0.0;
232
+ data['portfolio_allocation_percent'] = (_totalPortfolioBookCost > 0)
233
+ ? (bookCost / _totalPortfolioBookCost) * 100
228
234
  : 0.0;
235
+
236
+ // Calculate Market Value, Unrealized P/L, Total Return
237
+ final livePrice = _livePrices[symbol];
238
+ double marketValue = livePrice != null ? shares * livePrice : bookCost; // Fallback to bookCost if no live price
239
+ double unrealizedPL = marketValue - bookCost;
240
+ double totalReturn = unrealizedPL + totalDividends;
241
+
242
+ data['market_value'] = marketValue;
243
+ data['unrealized_pl'] = unrealizedPL;
244
+ data['total_return'] = totalReturn;
245
+
246
+ data['percent_unrealized_pl'] = (bookCost > 0) ? (unrealizedPL / bookCost) * 100 : 0.0;
247
+ data['percent_total_return'] = (bookCost > 0) ? (totalReturn / bookCost) * 100 : 0.0;
248
+
229
249
  result.add(data);
230
250
  });
231
251
 
232
- return {'summary': result, 'total_value': accountPortfolioBookCost};
252
+ return {'summary': result, 'total_value': accountTotalBookCost};
233
253
  }
234
254
 
235
255
  @override
@@ -357,111 +377,60 @@ class _InvestmentAccountScreenState extends State<InvestmentAccountScreen> {
357
377
  columnSpacing: 24.0,
358
378
  columns: [
359
379
  const DataColumn(label: Text('Symbol')),
360
- const DataColumn(label: Text('Age')),
361
- const DataColumn(label: Text('Purchased')),
362
380
  const DataColumn(label: Text('Shares')),
363
381
  const DataColumn(label: Text('Avg Price')),
364
- const DataColumn(label: Text('Live')),
365
- const DataColumn(label: Text('Purchased')),
366
- const DataColumn(label: Text('Allocation')),
367
- const DataColumn(label: Text('Stocks Allocation')),
368
- const DataColumn(label: Text('Return')),
369
- const DataColumn(label: Text('% Return')),
370
382
  const DataColumn(label: Text('Book Cost')),
383
+ const DataColumn(label: Text('Live Price')),
384
+ const DataColumn(label: Text('Market Value')),
385
+ const DataColumn(label: Text('Unrealized P/L')),
386
+ const DataColumn(label: Text('% P/L')),
371
387
  if (widget.showDividends) ...[
372
388
  const DataColumn(label: Text('Dividends')),
373
- const DataColumn(label: Text('Return + Div')),
374
- const DataColumn(label: Text('Book Cost + Div')),
375
- const DataColumn(label: Text('% Return Div')),
389
+ const DataColumn(label: Text('Total Return')),
390
+ const DataColumn(label: Text('% Total Return')),
376
391
  ],
392
+ const DataColumn(label: Text('Account %')),
393
+ const DataColumn(label: Text('Portfolio %')),
377
394
  ],
378
395
  rows: _portfolioSummary.map((position) {
379
396
  final symbol = position['symbol'] as String;
397
+ final shares = position['shares'] as double;
398
+ final avgPrice = position['avg_price'] as double;
399
+ final bookCost = position['book_cost'] as double;
380
400
  final livePrice = _livePrices[symbol];
381
- final shares = double.parse(position['shares'].toString());
382
- final avgPrice = double.parse(position['avg_price'].toString());
383
- final totalPurchased =
384
- double.parse(position['total_cost'].toString());
385
- final accountAllocation =
386
- (position['account_allocation'] as num?)?.toDouble() ?? 0.0;
387
- final stocksAllocation = (_totalPortfolioBookCost > 0)
388
- ? (totalPurchased / _totalPortfolioBookCost) * 100
389
- : 0.0;
390
- final totalDividends =
391
- (position['total_dividends'] as num?)?.toDouble() ?? 0.0;
392
- final firstActivity = position['first_trade_date'] as DateTime?;
393
- final positionAge = firstActivity != null
394
- ? DateTime.now().difference(firstActivity)
395
- : null;
396
-
397
- double? totalReturnValue,
398
- percentageReturn,
399
- bookCost,
400
- returnPlusDividend,
401
- bookCostPlusDividend,
402
- percentageReturnDividend;
403
-
404
- if (livePrice != null && shares > 0) {
405
- final currentMarketValue = livePrice * shares;
406
- totalReturnValue = currentMarketValue - totalPurchased;
407
- bookCost = currentMarketValue;
408
- if (totalPurchased > 0)
409
- percentageReturn = (totalReturnValue / totalPurchased) * 100;
410
- if (widget.showDividends) {
411
- returnPlusDividend = totalReturnValue + totalDividends;
412
- bookCostPlusDividend = bookCost + totalDividends;
413
- if (totalPurchased > 0)
414
- percentageReturnDividend =
415
- (returnPlusDividend / totalPurchased) * 100;
416
- }
417
- }
418
-
419
- final returnColor =
420
- (totalReturnValue ?? 0) >= 0 ? Colors.green : Colors.red;
421
- final returnWithDivColor =
422
- (returnPlusDividend ?? 0) >= 0 ? Colors.green : Colors.red;
401
+ final marketValue = position['market_value'] as double;
402
+ final unrealizedPL = position['unrealized_pl'] as double;
403
+ final percentUnrealizedPL = position['percent_unrealized_pl'] as double;
404
+ final totalDividends = position['total_dividends'] as double;
405
+ final totalReturn = position['total_return'] as double;
406
+ final percentTotalReturn = position['percent_total_return'] as double;
407
+ final accountAllocationPercent = position['account_allocation_percent'] as double;
408
+ final portfolioAllocationPercent = position['portfolio_allocation_percent'] as double;
409
+
410
+
411
+ final plColor =
412
+ (unrealizedPL ?? 0) >= 0 ? Colors.green : Colors.red;
413
+ final totalReturnColor =
414
+ (totalReturn ?? 0) >= 0 ? Colors.green : Colors.red;
423
415
 
424
416
  return DataRow(cells: [
425
417
  DataCell(Text(symbol)),
426
- DataCell(Text(
427
- positionAge != null ? _formatDuration(positionAge) : 'N/A')),
428
- DataCell(Text(position['last_activity_date'] != null
429
- ? DateFormat('yyyy-MM-dd')
430
- .format(position['last_activity_date'])
431
- : 'N/A')),
432
418
  DataCell(Text(shares.toStringAsFixed(4))),
433
419
  DataCell(Text(_formatCurrency(avgPrice))),
420
+ DataCell(Text(_formatCurrency(bookCost))),
434
421
  DataCell(livePrice != null
435
422
  ? Text(_formatCurrency(livePrice))
436
423
  : const Text('N/A')),
437
- DataCell(Text(_formatCurrency(totalPurchased))),
438
- DataCell(Text('${accountAllocation.toStringAsFixed(2)}%')),
439
- DataCell(Text('${stocksAllocation.toStringAsFixed(2)}%')),
440
- DataCell(totalReturnValue != null
441
- ? Text(_formatCurrency(totalReturnValue),
442
- style: TextStyle(color: returnColor))
443
- : const Text('N/A')),
444
- DataCell(percentageReturn != null
445
- ? Text('${percentageReturn.toStringAsFixed(2)}%',
446
- style: TextStyle(color: returnColor))
447
- : const Text('N/A')),
448
- DataCell(bookCost != null
449
- ? Text(_formatCurrency(bookCost))
450
- : const Text('N/A')),
424
+ DataCell(Text(_formatCurrency(marketValue))),
425
+ DataCell(Text(_formatCurrency(unrealizedPL), style: TextStyle(color: plColor))),
426
+ DataCell(Text('${percentUnrealizedPL.toStringAsFixed(2)}%', style: TextStyle(color: plColor))),
451
427
  if (widget.showDividends) ...[
452
428
  DataCell(Text(_formatCurrency(totalDividends))),
453
- DataCell(returnPlusDividend != null
454
- ? Text(_formatCurrency(returnPlusDividend),
455
- style: TextStyle(color: returnWithDivColor))
456
- : const Text('N/A')),
457
- DataCell(bookCostPlusDividend != null
458
- ? Text(_formatCurrency(bookCostPlusDividend))
459
- : const Text('N/A')),
460
- DataCell(percentageReturnDividend != null
461
- ? Text('${percentageReturnDividend.toStringAsFixed(2)}%',
462
- style: TextStyle(color: returnWithDivColor))
463
- : const Text('N/A')),
464
- ]
429
+ DataCell(Text(_formatCurrency(totalReturn), style: TextStyle(color: totalReturnColor))),
430
+ DataCell(Text('${percentTotalReturn.toStringAsFixed(2)}%', style: TextStyle(color: totalReturnColor))),
431
+ ],
432
+ DataCell(Text('${accountAllocationPercent.toStringAsFixed(2)}%')),
433
+ DataCell(Text('${portfolioAllocationPercent.toStringAsFixed(2)}%')),
465
434
  ]);
466
435
  }).toList(),
467
436
  ),
@@ -621,4 +590,4 @@ class _InvestmentAccountScreenState extends State<InvestmentAccountScreen> {
621
590
  }
622
591
  }
623
592
  }
624
- }
593
+ }
@@ -59,8 +59,6 @@ class _RrspSunLifeScreenState extends State<RrspSunLifeScreen> {
59
59
  final sinteticoSummaryData =
60
60
  _calculateSinteticoSummary(contributions, totalPortfolioBookCost);
61
61
 
62
- print('[DEBUG] Sintetico Summary Data: $sinteticoSummaryData');
63
-
64
62
  if (!mounted) return;
65
63
  setState(() {
66
64
  _contributions = contributions;
@@ -85,40 +83,35 @@ class _RrspSunLifeScreenState extends State<RrspSunLifeScreen> {
85
83
 
86
84
  Map<String, dynamic> _calculateSinteticoSummary(
87
85
  List<Map<String, dynamic>> contributions, double totalPortfolioBookCost) {
88
- double totalRrsp = 0;
89
-
90
- double totalDpsp = 0;
91
-
92
- double totalReturn = 0;
86
+ double totalUserContribution = 0;
87
+ double totalCompanyContribution = 0;
88
+ double totalUnrealizedPL = 0;
93
89
 
94
90
  for (var c in contributions) {
95
- totalRrsp += double.parse(c['rrsp_amount'].toString());
96
-
97
- totalDpsp += double.parse(c['dpsp_amount'].toString());
98
-
99
- totalReturn += double.parse(c['return_amount']?.toString() ?? '0.0');
91
+ totalUserContribution += double.parse(c['rrsp_amount'].toString());
92
+ totalCompanyContribution += double.parse(c['dpsp_amount'].toString());
93
+ totalUnrealizedPL += double.parse(c['return_amount']?.toString() ?? '0.0');
100
94
  }
101
95
 
102
- final totalPurchased = totalRrsp + totalDpsp;
103
-
104
- final bookCost = totalPurchased + totalReturn;
96
+ final totalContributed = totalUserContribution + totalCompanyContribution;
97
+ final marketValue = totalContributed + totalUnrealizedPL;
105
98
 
106
99
  final summaryData = {
107
- 'rrsp_amount': totalRrsp,
108
- 'dpsp_amount': totalDpsp,
109
- 'total_purchased': totalPurchased,
110
- 'return_amount': totalReturn,
100
+ 'user_contribution': totalUserContribution,
101
+ 'company_contribution': totalCompanyContribution,
102
+ 'total_contributed': totalContributed,
103
+ 'unrealized_pl': totalUnrealizedPL,
111
104
  'percent_return':
112
- (totalPurchased > 0) ? (totalReturn / totalPurchased) * 100 : 0.0,
113
- 'book_cost': bookCost,
114
- 'portfolio_allocation': (totalPortfolioBookCost > 0)
115
- ? (bookCost / totalPortfolioBookCost) * 100
105
+ (totalContributed > 0) ? (totalUnrealizedPL / totalContributed) * 100 : 0.0,
106
+ 'market_value': marketValue,
107
+ 'portfolio_allocation_percent': (totalPortfolioBookCost > 0)
108
+ ? (marketValue / totalPortfolioBookCost) * 100
116
109
  : 0.0,
117
110
  };
118
111
 
119
112
  return {
120
113
  'summary': [summaryData],
121
- 'total_value': bookCost
114
+ 'total_value': marketValue
122
115
  };
123
116
  }
124
117
 
@@ -191,27 +184,33 @@ class _RrspSunLifeScreenState extends State<RrspSunLifeScreen> {
191
184
  }
192
185
 
193
186
  final summary = _sinteticoSummary.first;
187
+ final double unrealizedPL = summary['unrealized_pl'];
188
+ final plColor = (unrealizedPL >= 0) ? Colors.green : Colors.red;
189
+
194
190
 
195
191
  return DataTable(
196
192
  columns: const [
197
- DataColumn(label: Text('RRSP')),
198
- DataColumn(label: Text('DPSP')),
199
- DataColumn(label: Text('Total Purchased')),
200
- DataColumn(label: Text('Return')),
193
+ DataColumn(label: Text('User Contr.')),
194
+ DataColumn(label: Text('Company Contr.')),
195
+ DataColumn(label: Text('Total Contributed')),
196
+ DataColumn(label: Text('Unrealized P/L')),
201
197
  DataColumn(label: Text('% Return')),
202
- DataColumn(label: Text('Book Cost')),
198
+ DataColumn(label: Text('Market Value')),
199
+ DataColumn(label: Text('Portfolio %')),
203
200
  ],
204
201
  rows: [
205
202
  DataRow(
206
203
  cells: [
207
- DataCell(Text(_formatCurrency(summary['rrsp_amount'] as double))),
208
- DataCell(Text(_formatCurrency(summary['dpsp_amount'] as double))),
204
+ DataCell(Text(_formatCurrency(summary['user_contribution'] as double))),
205
+ DataCell(Text(_formatCurrency(summary['company_contribution'] as double))),
209
206
  DataCell(
210
- Text(_formatCurrency(summary['total_purchased'] as double))),
211
- DataCell(Text(_formatCurrency(summary['return_amount'] as double))),
207
+ Text(_formatCurrency(summary['total_contributed'] as double))),
208
+ DataCell(Text(_formatCurrency(unrealizedPL), style: TextStyle(color: plColor))),
209
+ DataCell(Text(
210
+ '${(summary['percent_return'] as double).toStringAsFixed(2)}%', style: TextStyle(color: plColor))),
211
+ DataCell(Text(_formatCurrency(summary['market_value'] as double))),
212
212
  DataCell(Text(
213
- '${(summary['percent_return'] as double).toStringAsFixed(2)}%')),
214
- DataCell(Text(_formatCurrency(summary['book_cost'] as double))),
213
+ '${(summary['portfolio_allocation_percent'] as double).toStringAsFixed(2)}%')),
215
214
  ],
216
215
  ),
217
216
  ],
@@ -231,30 +230,30 @@ class _RrspSunLifeScreenState extends State<RrspSunLifeScreen> {
231
230
  return DataTable(
232
231
  columns: const [
233
232
  DataColumn(label: Text('Date')),
234
- DataColumn(label: Text('RRSP')),
235
- DataColumn(label: Text('DPSP')),
236
- DataColumn(label: Text('Total Purchased')),
233
+ DataColumn(label: Text('User Contr.')),
234
+ DataColumn(label: Text('Company Contr.')),
235
+ DataColumn(label: Text('Total Contributed')),
237
236
  DataColumn(label: Text('Return')),
238
237
  DataColumn(label: Text('% Return')),
239
- DataColumn(label: Text('Book Cost')),
240
- DataColumn(label: Text('Stock Allocation')),
241
- DataColumn(label: Text('Actions')), // New column
238
+ DataColumn(label: Text('Cumulative Value')),
239
+ DataColumn(label: Text('Portfolio %')),
240
+ DataColumn(label: Text('Actions')),
242
241
  ],
243
242
  rows: _contributions.map((c) {
244
243
  final contributionId = c['id'] as int;
245
244
  final rrspAmount = double.parse(c['rrsp_amount'].toString());
246
245
  final dpspAmount = double.parse(c['dpsp_amount'].toString());
247
- final totalPurchased = rrspAmount + dpspAmount;
246
+ final totalContributed = rrspAmount + dpspAmount;
248
247
 
249
248
  final returnAmount =
250
249
  double.parse(c['return_amount']?.toString() ?? '0.0');
251
250
  final percentReturn =
252
- totalPurchased > 0 ? (returnAmount / totalPurchased) * 100 : 0.0;
251
+ totalContributed > 0 ? (returnAmount / totalContributed) * 100 : 0.0;
253
252
 
254
- final bookCost = totalPurchased + returnAmount;
253
+ final cumulativeValue = totalContributed + returnAmount;
255
254
 
256
- final stockAllocation = _totalPortfolioBookCost > 0
257
- ? (bookCost / _totalPortfolioBookCost) * 100
255
+ final portfolioAllocation = _totalPortfolioBookCost > 0
256
+ ? (cumulativeValue / _totalPortfolioBookCost) * 100
258
257
  : 0.0;
259
258
 
260
259
  String dateStr;
@@ -272,12 +271,12 @@ class _RrspSunLifeScreenState extends State<RrspSunLifeScreen> {
272
271
  DataCell(Text(dateStr)),
273
272
  DataCell(Text(_formatCurrency(rrspAmount))),
274
273
  DataCell(Text(_formatCurrency(dpspAmount))),
275
- DataCell(Text(_formatCurrency(totalPurchased))),
274
+ DataCell(Text(_formatCurrency(totalContributed))),
276
275
  DataCell(Text(_formatCurrency(returnAmount))),
277
276
  DataCell(Text('${percentReturn.toStringAsFixed(2)}%')),
278
- DataCell(Text(_formatCurrency(bookCost))),
279
- DataCell(Text('${stockAllocation.toStringAsFixed(2)}%')),
280
- DataCell( // New cell for the delete button
277
+ DataCell(Text(_formatCurrency(cumulativeValue))),
278
+ DataCell(Text('${portfolioAllocation.toStringAsFixed(2)}%')),
279
+ DataCell(
281
280
  IconButton(
282
281
  icon: const Icon(Icons.delete, color: Colors.red),
283
282
  onPressed: () => _confirmAndDeleteContribution(contributionId),
@@ -337,4 +336,4 @@ class _RrspSunLifeScreenState extends State<RrspSunLifeScreen> {
337
336
  }
338
337
  }
339
338
  }
340
- }
339
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@marcos_feitoza/personal-finance-frontend-feature-investments",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },