From d24f3ce872d86df8d9bb5e93114ae18ded387908 Mon Sep 17 00:00:00 2001 From: Jose Selesan Date: Thu, 27 Aug 2026 11:56:02 -0300 Subject: [PATCH] feat(analysis): add 12-month summary row with total variation and accumulated inflation --- .../components/MonthlyVariationTable.tsx | 139 ++++++++++++++++++ 1 file changed, 139 insertions(+) diff --git a/apps/frontend/src/features/analysis/components/MonthlyVariationTable.tsx b/apps/frontend/src/features/analysis/components/MonthlyVariationTable.tsx index b95fc3e..3b9a31b 100644 --- a/apps/frontend/src/features/analysis/components/MonthlyVariationTable.tsx +++ b/apps/frontend/src/features/analysis/components/MonthlyVariationTable.tsx @@ -54,6 +54,43 @@ function formatPrice(value: number): string { return `$${priceFormatter.format(value)}`; } +function TotalVariation({ + variation, + inflation, +}: { + variation: number | null; + inflation: number | null; +}) { + if (variation === null) { + return ( + + -- + + ); + } + + return ( + inflation + ? "bg-emerald-100 text-emerald-700 dark:bg-emerald-900/30 dark:text-emerald-400 px-1.5 py-0.5 rounded" + : "bg-red-100 text-red-700 dark:bg-red-900/30 dark:text-red-400 px-1.5 py-0.5 rounded" + : variation >= 0 + ? "text-emerald-500" + : "text-red-500" + }`} + > + {variation >= 0 ? ( + + ) : ( + + )} + {formatPct(variation)} + + ); +} + function VariationIndicator({ variation, inflation, @@ -205,6 +242,34 @@ export function MonthlyVariationTable() { .reverse(); }, [monthlyData, inflationData]); + const summary = useMemo(() => { + if (rows.length < 2) return null; + + const oldest = rows[rows.length - 1]; + const newest = rows[0]; + + const totalVariation = ( + first: number | null, + last: number | null, + ): number | null => { + if (first === null || last === null || first === 0) return null; + return ((last - first) / first) * 100; + }; + + const accumulatedInflation = rows.reduce((acc, row) => { + if (row.inflation === null) return acc; + return (acc ?? 0) + row.inflation; + }, null); + + return { + BELO: totalVariation(oldest.BELO.current, newest.BELO.current), + BLUE: totalVariation(oldest.BLUE.current, newest.BLUE.current), + BNA: totalVariation(oldest.BNA.current, newest.BNA.current), + inflation: accumulatedInflation, + period: `${oldest.label} – ${newest.label}`, + }; + }, [rows]); + const isLoading = monthlyLoading || inflationLoading; if (isLoading) { @@ -279,6 +344,48 @@ export function MonthlyVariationTable() { ))} + {summary && ( +
+
+ Total 12 meses + {summary.inflation !== null ? ( + + + {formatPct(summary.inflation)} inflación + + ) : ( + + Sin inflación + + )} +
+
+
+

BELO

+ +
+
+

Blue

+ +
+
+

+ Oficial +

+ +
+
+
+ )}
@@ -348,6 +455,38 @@ export function MonthlyVariationTable() { ))} + {summary && ( + + Total 12 meses + + + + + + + + + + + {summary.inflation !== null ? ( + + {formatPct(summary.inflation)} + + ) : ( + -- + )} + + + )}