import { ChartViewToggle, MoMChart, MoMPercentChart, } from '@/components/charts'; import { PercentageTrendIndicator } from '@/components/dashboard/percentage-trend-indicator'; import { EncryptedText } from '@/components/encrypted-text'; import { AmountDisplay } from '@/components/ui/amount-display'; import { Card, CardContent, CardDescription, CardHeader, CardTitle, } from '@/components/ui/card'; import { ChartConfig, ChartContainer, ChartTooltip, ChartTooltipContent, } from '@/components/ui/chart'; import { convertSingleAccountData, useChartViews, } from '@/hooks/use-chart-views'; import { Account } from '@/types/account'; import { format, subMonths } from 'date-fns'; import { useEffect, useMemo, useState } from 'react'; import { Bar, BarChart, XAxis } from 'recharts'; interface BalanceDataPoint { month: string; timestamp: number; value: number; } interface AccountBalanceData { data: BalanceDataPoint[]; account: { id: string; name: string; name_iv: string; type: string; currency_code: string; }; } interface AccountBalanceChartProps { account: Account; loading?: boolean; refreshKey?: number; onBalanceClick?: () => void; } function formatXAxisLabel(value: string): string { const [year, month] = value.split('-'); const date = new Date(parseInt(year), parseInt(month) - 1); const monthName = date.toLocaleString('en-US', { month: 'short' }); const currentYear = new Date().getFullYear(); if (parseInt(year) === currentYear) { return monthName; } return `${monthName} ${year.slice(-2)}`; } function formatCurrency(value: number, currencyCode: string): string { return new Intl.NumberFormat('en-US', { style: 'currency', currency: currencyCode, minimumFractionDigits: 0, maximumFractionDigits: 0, }).format(value / 100); } function calculateTrend( data: BalanceDataPoint[], monthsBack: number, ): { percentage: number; previousValue: number; currentValue: number } | null { if (data.length < 2) return null; const currentIndex = data.length - 1; const previousIndex = Math.max(0, data.length - 1 - monthsBack); if (currentIndex === previousIndex) return null; const currentValue = data[currentIndex].value; const previousValue = data[previousIndex].value; if (previousValue === 0) return null; return { percentage: ((currentValue - previousValue) / Math.abs(previousValue)) * 100, previousValue, currentValue, }; } export function AccountBalanceChart({ account, loading: initialLoading, refreshKey, onBalanceClick, }: AccountBalanceChartProps) { const [balanceData, setBalanceData] = useState( null, ); const [isLoading, setIsLoading] = useState(true); useEffect(() => { async function fetchBalanceData() { setIsLoading(true); try { const now = new Date(); const to = format(now, 'yyyy-MM-dd'); const from = format(subMonths(now, 12), 'yyyy-MM-dd'); const params = new URLSearchParams({ from, to }); const response = await fetch( `/api/dashboard/account/${account.id}/balance-evolution?${params.toString()}`, ); const data = await response.json(); setBalanceData(data); } catch (error) { console.error('Failed to fetch balance data:', error); } finally { setIsLoading(false); } } fetchBalanceData(); }, [account.id, refreshKey]); const { chartData, currentBalance, monthlyTrend, yearlyTrend } = useMemo(() => { if (!balanceData?.data?.length) { return { chartData: [], currentBalance: 0, monthlyTrend: null, yearlyTrend: null, }; } const data = balanceData.data; const current = data[data.length - 1]?.value ?? 0; return { chartData: data, currentBalance: current, monthlyTrend: calculateTrend(data, 1), yearlyTrend: calculateTrend(data, data.length - 1), }; }, [balanceData]); // Convert data for useChartViews hook const { data: hookData, accounts: hookAccounts } = useMemo(() => { return convertSingleAccountData( chartData, account.id, account.type, account.currency_code, ); }, [chartData, account.id, account.type, account.currency_code]); const chartViews = useChartViews({ data: hookData, accounts: hookAccounts, initialView: 'stacked', hasStackedView: true, }); const chartConfig: ChartConfig = { value: { label: ( ), color: 'var(--color-chart-2)', }, }; const valueFormatter = (value: number): string => { return formatCurrency(value, account.currency_code); }; if (initialLoading || isLoading) { return ( Balance evolution
); } if (chartData.length === 0) { return ( Balance evolution
No balance data available
); } return (
Balance evolution
{chartViews.currentView === 'stacked' && ( } /> )} {chartViews.currentView === 'mom' && ( )} {chartViews.currentView === 'mom_percent' && ( )}
); }