"use client"; import { RiPieChartLine } from "@remixicon/react"; import * as React from "react"; import { Area, AreaChart, CartesianGrid, type TooltipProps, XAxis, } from "recharts"; import { EmptyState } from "@/components/shared/empty-state"; import { Card, CardContent, CardDescription, CardHeader, CardTitle, } from "@/components/ui/card"; import { type ChartConfig, ChartContainer, ChartLegend, ChartLegendContent, ChartTooltip, } from "@/components/ui/chart"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select"; import { currencyFormatter } from "@/lib/lancamentos/formatting-helpers"; import type { CategoryChartData } from "@/lib/relatorios/fetch-category-chart-data"; import { CATEGORY_COLORS } from "@/lib/utils/category-colors"; function AreaTooltip({ active, payload, label }: TooltipProps) { if (!active || !payload?.length) return null; const items = payload .filter((entry) => Number(entry.value) > 0) .sort((a, b) => Number(b.value) - Number(a.value)); if (items.length === 0) return null; return (

{label}

{items.map((entry) => (
{entry.name}
{currencyFormatter.format(Number(entry.value))}
))}
); } interface CategoryReportChartProps { data: CategoryChartData; } const LIMIT_OPTIONS = [ { value: "5", label: "Top 5" }, { value: "10", label: "Top 10" }, { value: "15", label: "Top 15" }, ] as const; const MAX_CATEGORIES = 15; export function CategoryReportChart({ data }: CategoryReportChartProps) { const { chartData, categories } = data; const [limit, setLimit] = React.useState("10"); const { topCategories, filteredChartData } = React.useMemo(() => { const limitNum = Math.min(Number(limit), MAX_CATEGORIES); const categoriesWithTotal = categories.map((category) => ({ ...category, total: chartData.reduce((sum, point) => { const v = point[category.name]; return sum + (typeof v === "number" ? v : 0); }, 0), })); const sorted = categoriesWithTotal .sort((a, b) => b.total - a.total) .slice(0, limitNum); const filtered = chartData.map((point) => { const result: { month: string; [key: string]: number | string } = { month: point.month, }; for (const cat of sorted) { result[cat.name] = (point[cat.name] as number) ?? 0; } return result; }); return { topCategories: sorted, filteredChartData: filtered }; }, [categories, chartData, limit]); const chartConfig = React.useMemo(() => { const config: ChartConfig = {}; for (let i = 0; i < topCategories.length; i++) { const cat = topCategories[i]; config[cat.name] = { label: cat.name, color: CATEGORY_COLORS[i % CATEGORY_COLORS.length], }; } return config; }, [topCategories]); if (categories.length === 0 || chartData.length === 0) { return ( } mediaVariant="icon" /> ); } const firstMonth = chartData[0]?.month ?? ""; const lastMonth = chartData[chartData.length - 1]?.month ?? ""; const periodLabel = firstMonth === lastMonth ? firstMonth : `${firstMonth} – ${lastMonth}`; return (
Evolução por Categoria {periodLabel}
{topCategories.map((cat, index) => { const color = CATEGORY_COLORS[index % CATEGORY_COLORS.length]; return ( ); })} } /> {topCategories.map((cat, index) => ( ))} } />
); }