import { ChartViewToggle, MoMChart, MoMPercentChart, } from '@/components/charts'; 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 } from '@/components/ui/chart'; import { StackedBarChart } from '@/components/ui/stacked-bar-chart'; import { useChartViews } from '@/hooks/use-chart-views'; import { NetWorthEvolutionData } from '@/hooks/use-dashboard-data'; import { useLocale } from '@/hooks/use-locale'; import { AccountInfo } from '@/lib/chart-calculations'; import { __ } from '@/utils/i18n'; import { useMemo } from 'react'; import { PercentageTrendIndicator } from './percentage-trend-indicator'; interface NetWorthChartProps { data: NetWorthEvolutionData; loading?: boolean; showLegend?: boolean; } interface TrendData { percentage: number; previousAmount: number; currentAmount: number; } function formatXAxisLabel(value: string, locale: string = 'en'): string { const [year, month] = value.split('-'); const date = new Date(parseInt(year), parseInt(month) - 1); const monthName = date.toLocaleString(locale, { month: 'short' }); const currentYear = new Date().getFullYear(); if (parseInt(year) === currentYear) { return monthName; } return `${monthName} ${year.slice(-2)}`; } function calculateTrend( data: Array>, accountIds: string[], monthsBack: number, ): TrendData | 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 currentTotal = accountIds.reduce((sum, id) => { const value = data[currentIndex][id]; return sum + (typeof value === 'number' ? value : 0); }, 0); const previousTotal = accountIds.reduce((sum, id) => { const value = data[previousIndex][id]; return sum + (typeof value === 'number' ? value : 0); }, 0); if (previousTotal === 0) return null; return { percentage: ((currentTotal - previousTotal) / Math.abs(previousTotal)) * 100, previousAmount: previousTotal, currentAmount: currentTotal, }; } interface EncryptedLabelProps { account: { name: string; name_iv: string }; } function EncryptedLabel({ account }: EncryptedLabelProps) { return ( ); } interface CurrencyTotal { currency: string; total: number; } function TotalDisplay({ totals }: { totals: CurrencyTotal[] }) { if (totals.length === 0) return null; if (totals.length === 1) { return ( ); } return (
{totals.map((item, index) => ( {index > 0 && ( + )} ))}
); } export function NetWorthChart({ data, loading, showLegend = false, }: NetWorthChartProps) { const locale = useLocale(); const { chartData, dataKeys, chartConfig, monthlyTrend, yearlyTrend, currencyTotals, accountCurrencies, primaryCurrency, accountsForHook, } = useMemo(() => { const accounts = data.accounts || {}; const accountIds = Object.keys(accounts); const chartDataArray = data.data || []; const config: ChartConfig = {}; const currencies: Record = {}; const hookAccounts: Record = {}; accountIds.forEach((id) => { const account = accounts[id]; config[id] = { label: account ? : id, }; if (account?.currency_code) { currencies[id] = account.currency_code; } if (account) { hookAccounts[id] = { id: account.id, type: account.type, currency_code: account.currency_code, }; } }); const totals: Record = {}; if (chartDataArray.length > 0) { const lastDataPoint = chartDataArray[chartDataArray.length - 1]; accountIds.forEach((id) => { const value = lastDataPoint[id]; const currency = currencies[id] || 'USD'; if (typeof value === 'number') { totals[currency] = (totals[currency] || 0) + value; } }); } const currencyTotalsList: CurrencyTotal[] = Object.entries(totals) .map(([currency, total]) => ({ currency, total })) .sort((a, b) => b.total - a.total); const primary = currencyTotalsList.length > 0 ? currencyTotalsList[0].currency : 'USD'; return { chartData: chartDataArray, dataKeys: accountIds, chartConfig: config, monthlyTrend: calculateTrend(chartDataArray, accountIds, 1), yearlyTrend: calculateTrend( chartDataArray, accountIds, chartDataArray.length - 1, ), currencyTotals: currencyTotalsList, accountCurrencies: currencies, primaryCurrency: primary, accountsForHook: hookAccounts, }; }, [data]); const chartViews = useChartViews({ data: chartData, accounts: accountsForHook, initialView: 'stacked', hasStackedView: true, }); const valueFormatter = useMemo(() => { return (value: number, accountId?: string): React.ReactNode => { const currency = accountId && accountCurrencies[accountId] ? accountCurrencies[accountId] : 'USD'; return ( ); }; }, [accountCurrencies]); if (loading) { return ( {__('Net Worth Evolution')}
); } if (dataKeys.length === 0) { return ( {__('Net Worth Evolution')}
{__('No account data available')}
); } return (
{__('Net Worth Evolution')}
{chartViews.currentView === 'stacked' && ( formatXAxisLabel(value, locale) } valueFormatter={valueFormatter} accountCurrencies={accountCurrencies} className="h-[300px] w-full" showLegend={showLegend} /> )} {chartViews.currentView === 'mom' && ( formatXAxisLabel(value, locale) } className="h-[300px] w-full" /> )} {chartViews.currentView === 'mom_percent' && ( formatXAxisLabel(value, locale) } className="h-[300px] w-full" /> )}
); }