| | 'use client'; |
| |
|
| | import { ChartData } from '@/types/chart'; |
| | import { |
| | Cell, |
| | Legend, |
| | Pie, |
| | PieChart, |
| | ResponsiveContainer, |
| | Tooltip, |
| | } from 'recharts'; |
| |
|
| | type ChartPieProps = { |
| | loading: boolean |
| | data: ChartData[] |
| | } |
| |
|
| | export function ChartPie({ loading, data }: ChartPieProps) { |
| | const items = 5; |
| |
|
| | |
| | const dataWithPercentages = data ? (() => { |
| | const total = data.reduce((sum, item) => sum + item.value, 0); |
| | return data.map(item => ({ |
| | ...item, |
| | percentage: total > 0 ? Number(((item.value / total) * 100).toFixed(1)) : 0 |
| | })); |
| | })() : []; |
| |
|
| | const total = dataWithPercentages.reduce((sum, item) => sum + item.value, 0); |
| |
|
| | if (loading) { |
| | return ( |
| | <div className="w-full flex items-center justify-center gap-10 animate-pulse"> |
| | <div className="relative"> |
| | <div className="w-48 h-48 bg-gray-200 rounded-full" /> |
| | <div className="absolute inset-6 bg-white rounded-full" /> |
| | </div> |
| | <div className="flex flex-col gap-4"> |
| | {Array.from({ length: items }).map((_, index) => ( |
| | <div key={index} className="flex items-center gap-3"> |
| | <div className="w-4 h-4 bg-gray-200 rounded-sm" /> |
| | <div className="h-4 bg-gray-200 rounded w-32" /> |
| | </div> |
| | ))} |
| | </div> |
| | </div> |
| | ); |
| | } |
| |
|
| | if (!data || data.length === 0) { |
| | return ( |
| | <div className="w-full h-60 flex flex-col items-center justify-center text-gray-400"> |
| | <div className="w-40 h-40 border-4 border-dashed border-gray-200 rounded-full mb-4" /> |
| | <p className="text-sm">No data available</p> |
| | </div> |
| | ); |
| | } |
| |
|
| | return ( |
| | <div className="space-y-4"> |
| | {/* Total Count */} |
| | <div className="text-center"> |
| | <p className="text-sm text-gray-600">Total</p> |
| | <p className="text-2xl font-bold text-gray-800">{total}</p> |
| | </div> |
| | |
| | <ResponsiveContainer width="100%" |
| | height={Math.max(250, dataWithPercentages.length * 40)} |
| | // height={300} |
| | > |
| | <PieChart> |
| | <Pie |
| | data={dataWithPercentages} |
| | dataKey="value" |
| | label={({ percentage }) => `${percentage}%`} |
| | > |
| | {dataWithPercentages.map((entry, index) => ( |
| | <Cell key={`cell-${index}`} fill={entry.color} /> |
| | ))} |
| | </Pie> |
| | <Tooltip |
| | formatter={(value: number, name: string, props: any) => [ |
| | `${value} (${props.payload.percentage}%)`, |
| | name |
| | ]} |
| | /> |
| | <Legend |
| | formatter={(value: string, entry: any) => |
| | `${value}: ${entry.payload.value} (${entry.payload.percentage}%)` |
| | } |
| | /> |
| | </PieChart> |
| | </ResponsiveContainer> |
| | </div> |
| | ); |
| | } |