import { ArrowDown, ArrowRight, ArrowUp, TrendingUp } from "lucide-react"; import { useMemo } from "react"; import { useInflation, useMonthlyLast } from "@/lib/queries"; type MonthKey = string; type CurrencyValues = { variation: number | null; prev: number | null; current: number | null; }; type MonthRow = { month: MonthKey; label: string; BELO: CurrencyValues; BLUE: CurrencyValues; BNA: CurrencyValues; inflation: number | null; }; const MONTH_NAMES = [ "Enero", "Febrero", "Marzo", "Abril", "Mayo", "Junio", "Julio", "Agosto", "Septiembre", "Octubre", "Noviembre", "Diciembre", ]; function formatMonth(monthKey: string): string { const [y, m] = monthKey.split("-"); return `${MONTH_NAMES[Number(m) - 1]} ${y}`; } function formatPct(value: number): string { const sign = value >= 0 ? "+" : ""; return `${sign}${value.toFixed(1)}%`; } const priceFormatter = new Intl.NumberFormat("es-AR", { minimumFractionDigits: 0, maximumFractionDigits: 0, }); function formatPrice(value: number): string { return `$${priceFormatter.format(value)}`; } function VariationIndicator({ variation, inflation, prev, current, }: { variation: number | null; inflation: number | null; prev: number | null; current: number | null; }) { if (variation === null) { return ( -- ); } const indicator = ( 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)} ); if (prev !== null && current !== null) { return ( {indicator} {formatPrice(prev)} → {formatPrice(current)} ); } return indicator; } export function MonthlyVariationTable() { const { data: monthlyData, isLoading: monthlyLoading } = useMonthlyLast(); const { data: inflationData, isLoading: inflationLoading } = useInflation(); const rows = useMemo(() => { if (!monthlyData || monthlyData.length === 0) return []; const monthsMap = new Map< MonthKey, { BELO: number | null; BLUE: number | null; BNA: number | null } >(); for (const entry of monthlyData) { const existing = monthsMap.get(entry.month) ?? { BELO: null, BLUE: null, BNA: null, }; if (entry.type === "BELO") existing.BELO = entry.buy; if (entry.type === "BLUE") existing.BLUE = entry.buy; if (entry.type === "BNA") existing.BNA = entry.buy; monthsMap.set(entry.month, existing); } const inflationMap = new Map(); if (inflationData) { for (const inf of inflationData) { const monthKey = inf.fecha.slice(0, 7); inflationMap.set(monthKey, inf.valor); } } const sortedMonths = [...monthsMap.keys()].sort(); const calcVariation = ( currentVal: number | null, prevVal: number | null, ): number | null => { if (currentVal === null || prevVal === null || prevVal === 0) return null; return ((currentVal - prevVal) / prevVal) * 100; }; return sortedMonths .map((month, i) => { const prev = i > 0 ? sortedMonths[i - 1] : null; const current = monthsMap.get(month); const prevData = prev ? monthsMap.get(prev) : null; const beloVar = calcVariation( current?.BELO ?? null, prevData?.BELO ?? null, ); const blueVar = calcVariation( current?.BLUE ?? null, prevData?.BLUE ?? null, ); const bnaVar = calcVariation( current?.BNA ?? null, prevData?.BNA ?? null, ); let inflation: number | null = null; inflation = inflationMap.get(month) ?? null; return { month, label: formatMonth(month), BELO: { variation: beloVar, prev: prevData?.BELO ?? null, current: current?.BELO ?? null, }, BLUE: { variation: blueVar, prev: prevData?.BLUE ?? null, current: current?.BLUE ?? null, }, BNA: { variation: bnaVar, prev: prevData?.BNA ?? null, current: current?.BNA ?? null, }, inflation, }; }) .reverse(); }, [monthlyData, inflationData]); const isLoading = monthlyLoading || inflationLoading; if (isLoading) { return (
Cargando datos mensuales...
); } if (rows.length === 0) { return (
Sin datos mensuales disponibles
); } return ( <>
{rows.map((row) => (
{row.label} {row.inflation !== null ? ( {formatPct(row.inflation)} inflación ) : ( Sin inflación )}

BELO

Blue

Oficial

))}
{rows.map((row) => ( ))}
Mes BELO Blue Oficial Inflación
{row.label} {row.inflation !== null ? ( {formatPct(row.inflation)} ) : ( -- )}
); }