GerardCB's picture
Deploy to Spaces (Final Clean)
4851501
"use client";
import {
PieChart as RechartsPieChart,
Pie,
Cell,
Tooltip,
Legend,
ResponsiveContainer
} from 'recharts';
interface PieChartProps {
data: Array<{ [key: string]: any }>;
title?: string;
height?: number;
donut?: boolean;
nameKey?: string;
valueKey?: string;
}
// Color palette
const COLORS = ['#6366f1', '#10b981', '#f59e0b', '#ef4444', '#8b5cf6', '#06b6d4', '#ec4899', '#84cc16'];
export default function PieChart({
data,
title,
height = 300,
donut = false
}: PieChartProps) {
// Calculate total for percentage
const total = data.reduce((sum, item) => sum + item.value, 0);
return (
<div className="w-full bg-white rounded-xl border border-slate-100 p-4 shadow-sm">
{title && (
<h3 className="text-sm font-semibold text-slate-700 mb-4">{title}</h3>
)}
<ResponsiveContainer width="100%" height={height}>
<RechartsPieChart>
<Pie
data={data}
cx="50%"
cy="50%"
labelLine={false}
label={(props: any) =>
`${props.name} (${((props.percent ?? 0) * 100).toFixed(0)}%)`
}
outerRadius={100}
innerRadius={donut ? 60 : 0}
fill="#8884d8"
dataKey="value"
paddingAngle={donut ? 2 : 0}
>
{data.map((entry, index) => (
<Cell key={`cell-${index}`} fill={COLORS[index % COLORS.length]} />
))}
</Pie>
<Tooltip
formatter={(value: number | undefined) => [
`${(value ?? 0).toLocaleString()} (${(((value ?? 0) / total) * 100).toFixed(1)}%)`,
'Value'
]}
contentStyle={{
background: 'white',
border: '1px solid #e2e8f0',
borderRadius: '8px',
boxShadow: '0 4px 6px -1px rgb(0 0 0 / 0.1)'
}}
/>
<Legend
verticalAlign="bottom"
wrapperStyle={{ fontSize: '12px', paddingTop: '10px' }}
/>
</RechartsPieChart>
</ResponsiveContainer>
{donut && (
<div className="text-center -mt-4">
<span className="text-2xl font-bold text-slate-700">{total.toLocaleString()}</span>
<span className="text-sm text-slate-500 block">Total</span>
</div>
)}
</div>
);
}