From f141c4ff73f43522e64a037b6a41dec72f4c2627 Mon Sep 17 00:00:00 2001 From: Jean-Luc Makiola Date: Thu, 12 Mar 2026 09:26:13 +0100 Subject: [PATCH] feat(04-02): add locale prop and custom currency tooltips to chart components - Add locale?: string prop to ExpenseBreakdown and AvailableBalance - Replace bare in ExpenseBreakdown with custom content renderer - Add Tooltip import and custom content renderer to AvailableBalance - Pass locale to formatCurrency in AvailableBalance center text - Tooltip styled with shadcn design tokens (bg-background, border-border/50, shadow-xl) --- frontend/src/components/AvailableBalance.tsx | 21 +++++++++++++++++--- frontend/src/components/ExpenseBreakdown.tsx | 19 ++++++++++++++++-- 2 files changed, 35 insertions(+), 5 deletions(-) diff --git a/frontend/src/components/AvailableBalance.tsx b/frontend/src/components/AvailableBalance.tsx index 963a462..c311a66 100644 --- a/frontend/src/components/AvailableBalance.tsx +++ b/frontend/src/components/AvailableBalance.tsx @@ -1,6 +1,6 @@ import { useTranslation } from 'react-i18next' import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card' -import { PieChart, Pie, Cell, ResponsiveContainer } from 'recharts' +import { PieChart, Pie, Cell, ResponsiveContainer, Tooltip } from 'recharts' import type { BudgetDetail } from '@/lib/api' import { formatCurrency } from '@/lib/format' import { palette, headerGradient, type CategoryType } from '@/lib/palette' @@ -8,9 +8,10 @@ import { cn } from '@/lib/utils' interface Props { budget: BudgetDetail + locale?: string } -export function AvailableBalance({ budget }: Props) { +export function AvailableBalance({ budget, locale = 'en' }: Props) { const { t } = useTranslation() const { totals } = budget @@ -48,11 +49,25 @@ export function AvailableBalance({ budget }: Props) { ))} + { + if (!active || !payload?.length) return null + const item = payload[0] + return ( +
+

{item.name}

+

+ {formatCurrency(Number(item.value), budget.currency, locale)} +

+
+ ) + }} + />
= 0 ? 'text-success' : 'text-destructive')}> - {formatCurrency(available, budget.currency)} + {formatCurrency(available, budget.currency, locale)} {t('dashboard.available', 'Available')}
diff --git a/frontend/src/components/ExpenseBreakdown.tsx b/frontend/src/components/ExpenseBreakdown.tsx index 7ee7fc0..698b7c1 100644 --- a/frontend/src/components/ExpenseBreakdown.tsx +++ b/frontend/src/components/ExpenseBreakdown.tsx @@ -2,13 +2,15 @@ import { useTranslation } from 'react-i18next' import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card' import { PieChart, Pie, Cell, ResponsiveContainer, Tooltip } from 'recharts' import type { BudgetDetail } from '@/lib/api' +import { formatCurrency } from '@/lib/format' import { palette, headerGradient, type CategoryType } from '@/lib/palette' interface Props { budget: BudgetDetail + locale?: string } -export function ExpenseBreakdown({ budget }: Props) { +export function ExpenseBreakdown({ budget, locale = 'en' }: Props) { const { t } = useTranslation() const expenses = budget.items .filter((i) => i.category_type === 'variable_expense' && i.actual_amount > 0) @@ -41,7 +43,20 @@ export function ExpenseBreakdown({ budget }: Props) { ))} - + { + if (!active || !payload?.length) return null + const item = payload[0] + return ( +
+

{item.name}

+

+ {formatCurrency(Number(item.value), budget.currency, locale)} +

+
+ ) + }} + />