"use client"; import * as React from "react"; import { Label, Pie, PieChart as RechartsPieChart } from "recharts"; import { Card, CardContent, CardDescription, CardHeader, CardTitle, } from "@/components/ui/card"; import { ChartConfig, ChartContainer, ChartTooltip, ChartTooltipContent, } from "@/components/ui/chart"; import { JsonViewPopup } from "../json-view-popup"; import { sanitizeCssVariableName } from "./shared.tool-invocation"; // PieChart component props interface export interface PieChartProps { // Chart title (required) title: string; // Chart data array (required) data: Array<{ label: string; // Item label value: number; // Item value }>; // Value unit (optional, e.g., "visitors", "users", etc.) unit?: string; // Chart description (optional) description?: string; prefix?: string; jsonView?: boolean; } // Color variable names (chart-1 ~ chart-5) const chartColors = [ "var(--chart-1)", "var(--chart-2)", "var(--chart-3)", "var(--chart-4)", "var(--chart-5)", ]; // Function to format large numbers with k, M, B, T units function formatLargeNumber(num: number | null | undefined): string { // Handle null, undefined, or invalid numbers if (num == null || isNaN(num) || !isFinite(num)) { return "0"; } // Handle negative numbers if (num < 0) { return `-${formatLargeNumber(-num)}`; } // Handle zero if (num === 0) { return "0"; } if (num < 1000) { return num.toString(); } const units = [ "", "k", "M", "B", "T", "Qa", "Qi", "Sx", "Sp", "Oc", "No", "Dc", ]; let unitIndex = 0; let value = num; while (value >= 1000 && unitIndex < units.length - 1) { value /= 1000; unitIndex++; } return `${value.toFixed(1)}${units[unitIndex]}`; } export function PieChart(props: PieChartProps) { const { title, data, unit, description, prefix, jsonView = true } = props; // Calculate total value const total = React.useMemo(() => { return data.reduce((acc, curr) => acc + curr.value, 0); }, [data]); // Generate chart configuration dynamically const chartConfig = React.useMemo(() => { const config: ChartConfig = {}; // Set value unit if (unit) { config.value = { label: unit, }; } // Configure each data item data.forEach((item, index) => { // Colors cycle through chart-1 ~ chart-5 const colorIndex = index % chartColors.length; config[sanitizeCssVariableName(item.label)] = { label: item.label, color: chartColors[colorIndex], }; }); return config; }, [data, unit]); // Generate actual chart data const chartData = React.useMemo(() => { return data.map((item) => ({ name: item.label, label: item.label, value: item.value, // Add fill property if needed fill: `var(--color-${sanitizeCssVariableName(item.label)})`, })); }, [data]); return ( {prefix ?? "Pie Chart - "} {title} {jsonView && (
)}
{description && {description}}
} />
); }