TIFNGK_E41222719/components/dashboards/SentimentChart.tsx

107 lines
2.6 KiB
TypeScript

import {
PieChart,
Pie,
Cell,
ResponsiveContainer,
Legend,
Tooltip,
} from "recharts";
interface SentimentData {
name: string;
value: number;
color: string;
}
interface SentimentChartProps {
data: SentimentData[];
}
export function SentimentChart({ data }: SentimentChartProps) {
const total = data.reduce((sum, item) => sum + item.value, 0);
const CustomTooltip = ({ active, payload }: any) => {
if (active && payload && payload.length) {
const item = payload[0].payload;
const percentage = ((item.value / total) * 100).toFixed(1);
return (
<div className="rounded-lg border bg-card px-4 py-3 shadow-lg">
<p className="font-semibold" style={{ color: item.color }}>
{item.name}
</p>
<p className="text-sm text-muted-foreground">
{item.value.toLocaleString()} ulasan ({percentage}%)
</p>
</div>
);
}
return null;
};
const renderCustomLabel = ({
cx,
cy,
midAngle,
innerRadius,
outerRadius,
percent,
}: any) => {
if (percent < 0.05) return null;
const RADIAN = Math.PI / 180;
const radius = innerRadius + (outerRadius - innerRadius) * 0.5;
const x = cx + radius * Math.cos(-midAngle * RADIAN);
const y = cy + radius * Math.sin(-midAngle * RADIAN);
return (
<text
x={x}
y={y}
fill="white"
textAnchor="middle"
dominantBaseline="central"
className="text-sm font-semibold"
>
{`${(percent * 100).toFixed(0)}%`}
</text>
);
};
return (
<div className="h-[300px] w-full">
<ResponsiveContainer width="100%" height="100%">
<PieChart>
<Pie
data={data}
cx="50%"
cy="50%"
labelLine={false}
label={renderCustomLabel}
outerRadius={110}
innerRadius={60}
paddingAngle={3}
dataKey="value"
strokeWidth={2}
stroke="hsl(var(--card))"
>
{data.map((entry, index) => (
<Cell
key={`cell-${index}`}
fill={entry.color}
className="transition-all duration-300 hover:opacity-80"
/>
))}
</Pie>
<Tooltip content={<CustomTooltip />} />
<Legend
verticalAlign="bottom"
height={36}
formatter={(value: string) => (
<span className="text-sm text-foreground">{value}</span>
)}
/>
</PieChart>
</ResponsiveContainer>
</div>
);
}