"use client";
import { useState } from "react";
import { Cell, Label, Pie, PieChart, Tooltip } from "recharts";
import { ChartConfig, ChartContainer } from "@/components/ui/chart/Chart";
import { ChartLegend } from "./shared/chart-legend";
import { DonutDataPoint } from "./types";
interface DonutChartProps {
data: DonutDataPoint[];
height?: number;
innerRadius?: number;
outerRadius?: number;
showLegend?: boolean;
centerLabel?: {
value: string | number;
label: string;
};
}
const CustomTooltip = ({ active, payload }: any) => {
if (!active || !payload || !payload.length) return null;
const entry = payload[0];
const name = entry.name;
const percentage = entry.payload?.percentage;
const color = entry.color || entry.payload?.color;
const change = entry.payload?.change;
return (
{/* Title with color chip */}
{/* Change percentage row */}
{change !== undefined && (
{change > 0 ? "+" : ""}
{change}% Since last scan
)}
);
};
const CustomLegend = ({ payload }: any) => {
const items = payload.map((entry: any) => ({
label: `${entry.value} (${entry.payload.percentage}%)`,
color: entry.color,
}));
return ;
};
export function DonutChart({
data,
innerRadius = 68,
outerRadius = 86,
showLegend = true,
centerLabel,
}: DonutChartProps) {
const [hoveredIndex, setHoveredIndex] = useState(null);
const chartConfig = data.reduce(
(config, item) => ({
...config,
[item.name]: {
label: item.name,
color: item.color,
},
}),
{} as ChartConfig,
);
const chartData = data.map((item) => ({
name: item.name,
value: item.value,
fill: item.color,
color: item.color,
percentage: item.percentage,
change: item.change,
}));
const total = chartData.reduce((sum, d) => sum + (Number(d.value) || 0), 0);
const isEmpty = total <= 0;
const emptyData = [
{
name: "No data",
value: 1,
fill: "var(--chart-border-emphasis)",
color: "var(--chart-border-emphasis)",
percentage: 0,
change: undefined,
},
];
const legendPayload = (isEmpty ? emptyData : chartData).map((entry) => ({
value: isEmpty ? "No data" : entry.name,
color: entry.color,
payload: {
percentage: isEmpty ? 0 : entry.percentage,
},
}));
return (
<>
{!isEmpty && } />}
{(isEmpty ? emptyData : chartData).map((entry, index) => {
const opacity =
hoveredIndex === null ? 1 : hoveredIndex === index ? 1 : 0.5;
return (
setHoveredIndex(index)}
onMouseLeave={() => setHoveredIndex(null)}
/>
);
})}
{(centerLabel || isEmpty) && (
|
{showLegend && }
>
);
}