From fc483d05730c733f9b648645155a74aa6e1e46b6 Mon Sep 17 00:00:00 2001 From: Julien Froidefond Date: Fri, 28 Nov 2025 13:56:58 +0100 Subject: [PATCH] feat: enhance category breakdown and pie chart components with icon support and improved tooltip formatting --- app/statistics/page.tsx | 1 + components/dashboard/category-breakdown.tsx | 81 ++++--------------- components/statistics/balance-line-chart.tsx | 4 +- components/statistics/category-pie-chart.tsx | 85 ++++++++++++++++---- components/statistics/monthly-chart.tsx | 4 +- 5 files changed, 92 insertions(+), 83 deletions(-) diff --git a/app/statistics/page.tsx b/app/statistics/page.tsx index d9d0c8b..4017a2c 100644 --- a/app/statistics/page.tsx +++ b/app/statistics/page.tsx @@ -97,6 +97,7 @@ export default function StatisticsPage() { name: category?.name || "Non catégorisé", value: Math.round(total), color: category?.color || "#94a3b8", + icon: category?.icon || "HelpCircle", }; }) .sort((a, b) => b.value - a.value) diff --git a/components/dashboard/category-breakdown.tsx b/components/dashboard/category-breakdown.tsx index de41275..d637123 100644 --- a/components/dashboard/category-breakdown.tsx +++ b/components/dashboard/category-breakdown.tsx @@ -1,15 +1,10 @@ "use client"; -import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; -import type { BankingData } from "@/lib/types"; import { - PieChart, - Pie, - Cell, - ResponsiveContainer, - Legend, - Tooltip, -} from "recharts"; + CategoryPieChart, + type CategoryChartData, +} from "@/components/statistics/category-pie-chart"; +import type { BankingData } from "@/lib/types"; interface CategoryBreakdownProps { data: BankingData; @@ -22,7 +17,7 @@ export function CategoryBreakdown({ data }: CategoryBreakdownProps) { const thisMonthStr = thisMonth.toISOString().slice(0, 7); const monthExpenses = data.transactions.filter( - (t) => t.date.startsWith(thisMonthStr) && t.amount < 0, + (t) => t.date.startsWith(thisMonthStr) && t.amount < 0 ); const categoryTotals = new Map(); @@ -33,13 +28,14 @@ export function CategoryBreakdown({ data }: CategoryBreakdownProps) { categoryTotals.set(catId, current + Math.abs(t.amount)); }); - const chartData = Array.from(categoryTotals.entries()) + const chartData: CategoryChartData[] = Array.from(categoryTotals.entries()) .map(([categoryId, total]) => { const category = data.categories.find((c) => c.id === categoryId); return { name: category?.name || "Non catégorisé", value: total, color: category?.color || "#94a3b8", + icon: category?.icon || "HelpCircle", }; }) .sort((a, b) => b.value - a.value) @@ -52,60 +48,15 @@ export function CategoryBreakdown({ data }: CategoryBreakdownProps) { }).format(value); }; - if (chartData.length === 0) { - return ( - - - Dépenses par catégorie - - -
-

Pas de données ce mois-ci

-
-
-
- ); - } - return ( - - - Dépenses par catégorie - - -
- - - - {chartData.map((entry, index) => ( - - ))} - - formatCurrency(value)} - contentStyle={{ - backgroundColor: "hsl(var(--card))", - border: "1px solid hsl(var(--border))", - borderRadius: "8px", - }} - /> - ( - {value} - )} - /> - - -
-
-
+ ); } diff --git a/components/statistics/balance-line-chart.tsx b/components/statistics/balance-line-chart.tsx index b3bfe7f..ef30e4e 100644 --- a/components/statistics/balance-line-chart.tsx +++ b/components/statistics/balance-line-chart.tsx @@ -45,8 +45,8 @@ export function BalanceLineChart({ formatCurrency(value)} contentStyle={{ - backgroundColor: "hsl(var(--card))", - border: "1px solid hsl(var(--border))", + backgroundColor: "var(--card)", + border: "1px solid var(--border)", borderRadius: "8px", }} /> diff --git a/components/statistics/category-pie-chart.tsx b/components/statistics/category-pie-chart.tsx index e472e7f..421655d 100644 --- a/components/statistics/category-pie-chart.tsx +++ b/components/statistics/category-pie-chart.tsx @@ -1,6 +1,7 @@ "use client"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; +import { CategoryIcon } from "@/components/ui/category-icon"; import { PieChart, Pie, @@ -10,37 +11,49 @@ import { Legend, } from "recharts"; -interface CategoryChartData { +export interface CategoryChartData { name: string; value: number; color: string; + icon: string; + [key: string]: string | number; } interface CategoryPieChartProps { data: CategoryChartData[]; formatCurrency: (amount: number) => string; + title?: string; + height?: number; + innerRadius?: number; + outerRadius?: number; + emptyMessage?: string; } export function CategoryPieChart({ data, formatCurrency, + title = "Répartition par catégorie", + height = 300, + innerRadius = 60, + outerRadius = 100, + emptyMessage = "Pas de données pour cette période", }: CategoryPieChartProps) { return ( - Répartition par catégorie + {title} {data.length > 0 ? ( -
+
@@ -49,24 +62,68 @@ export function CategoryPieChart({ ))} formatCurrency(value)} - contentStyle={{ - backgroundColor: "hsl(var(--card))", - border: "1px solid hsl(var(--border))", - borderRadius: "8px", + content={({ active, payload }) => { + if (!active || !payload?.length) return null; + const item = payload[0].payload as CategoryChartData; + return ( +
+
+ + + {item.name} + +
+
+ {formatCurrency(item.value)} +
+
+ ); }} /> ( - {value} + content={({ payload }) => ( +
+ {payload?.map((entry, index) => { + const item = data.find((d) => d.name === entry.value); + return ( +
+ + {entry.value} +
+ ); + })} +
)} />
) : ( -
- Pas de données pour cette période +
+ {emptyMessage}
)} diff --git a/components/statistics/monthly-chart.tsx b/components/statistics/monthly-chart.tsx index 9020e64..f5132d5 100644 --- a/components/statistics/monthly-chart.tsx +++ b/components/statistics/monthly-chart.tsx @@ -41,8 +41,8 @@ export function MonthlyChart({ data, formatCurrency }: MonthlyChartProps) { formatCurrency(value)} contentStyle={{ - backgroundColor: "hsl(var(--card))", - border: "1px solid hsl(var(--border))", + backgroundColor: "var(--card)", + border: "1px solid var(--border)", borderRadius: "8px", }} />