diff --git a/resources/js/components/ui/chart.tsx b/resources/js/components/ui/chart.tsx index c7e0d39..bb6dc22 100644 --- a/resources/js/components/ui/chart.tsx +++ b/resources/js/components/ui/chart.tsx @@ -278,9 +278,13 @@ function ChartLegendContent({ payload, verticalAlign = "bottom", nameKey, + onItemClick, + activeName, }: React.ComponentProps<"div"> & { hideIcon?: boolean nameKey?: string + onItemClick?: (name: string) => void + activeName?: string } & RechartsPrimitive.DefaultLegendContentProps) { const { config } = useChart() @@ -301,13 +305,20 @@ function ChartLegendContent({ .map((item, index) => { const key = `${nameKey ?? item.dataKey ?? "value"}` const itemConfig = getPayloadConfigFromPayload(config, item, key) + const label = typeof itemConfig?.label === 'string' ? itemConfig.label : '' + const isInactive = activeName !== undefined && activeName !== label return (
svg]:h-3 [&>svg]:w-3 [&>svg]:text-muted-foreground" + "flex items-center gap-1.5 [&>svg]:h-3 [&>svg]:w-3 [&>svg]:text-muted-foreground", + onItemClick && "cursor-pointer select-none hover:opacity-80", + isInactive && "opacity-40" )} + onClick={() => { + if (label) onItemClick?.(label) + }} > {itemConfig?.icon && !hideIcon ? ( diff --git a/resources/js/pages/admin/analysis/index.tsx b/resources/js/pages/admin/analysis/index.tsx index b844d59..3d66f7e 100644 --- a/resources/js/pages/admin/analysis/index.tsx +++ b/resources/js/pages/admin/analysis/index.tsx @@ -267,6 +267,8 @@ type DashboardPieChartProps = { function DashboardPieChart({ title, data, dataKey, nameKey }: DashboardPieChartProps) { const hasData = data.length > 0 && data.some((d) => d.count > 0); + const [activeName, setActiveName] = useState(undefined); + const pieColors = useMemo(() => generateRandomColors(5), []); const chartConfig = useMemo(() => { @@ -287,6 +289,17 @@ function DashboardPieChart({ title, data, dataKey, nameKey }: DashboardPieChartP })); }, [data, pieColors]); + const handlePieClick = (_: unknown, index: number) => { + const name = chartData[index]?.name; + if (name) { + setActiveName((prev) => (prev === name ? undefined : name)); + } + }; + + const handleLegendClick = (name: string) => { + setActiveName((prev) => (prev === name ? undefined : name)); + }; + return ( @@ -311,9 +324,24 @@ function DashboardPieChart({ title, data, dataKey, nameKey }: DashboardPieChartP data={chartData} dataKey={dataKey} nameKey={nameKey} - /> + onClick={handlePieClick} + > + {chartData.map((item, index) => ( + + ))} + } + content={ + + } className="-translate-y-2 flex-wrap gap-2 *:basis-1/4 *:justify-center" /> diff --git a/resources/js/pages/dashboard.tsx b/resources/js/pages/dashboard.tsx index 8744170..1c01871 100644 --- a/resources/js/pages/dashboard.tsx +++ b/resources/js/pages/dashboard.tsx @@ -18,7 +18,7 @@ import { UserCheck, } from 'lucide-react'; import { useEffect, useMemo, useState } from 'react'; -import { Pie, PieChart } from 'recharts'; +import { Cell, Pie, PieChart } from 'recharts'; import { toast } from 'sonner'; type TodayAttendance = { @@ -463,6 +463,8 @@ type DashboardPieChartProps = { function DashboardPieChart({ title, data, dataKey, nameKey }: DashboardPieChartProps) { const hasData = data.length > 0 && data.some((d) => d.count > 0); + const [activeName, setActiveName] = useState(undefined); + const pieColors = useMemo(() => generateRandomColors(5), []); const chartConfig = useMemo(() => { @@ -483,6 +485,17 @@ function DashboardPieChart({ title, data, dataKey, nameKey }: DashboardPieChartP })); }, [data, pieColors]); + const handlePieClick = (_: unknown, index: number) => { + const name = chartData[index]?.name; + if (name) { + setActiveName((prev) => (prev === name ? undefined : name)); + } + }; + + const handleLegendClick = (name: string) => { + setActiveName((prev) => (prev === name ? undefined : name)); + }; + return ( @@ -507,9 +520,24 @@ function DashboardPieChart({ title, data, dataKey, nameKey }: DashboardPieChartP data={chartData} dataKey={dataKey} nameKey={nameKey} - /> + onClick={handlePieClick} + > + {chartData.map((item, index) => ( + + ))} + } + content={ + + } className="-translate-y-2 flex-wrap gap-2 *:basis-1/4 *:justify-center" />