dress/resources/js/components/charts/bar-chart.tsx

124 lines
3.9 KiB
TypeScript

"use client"
import React, { useMemo } from "react"
import { Bar, BarChart, CartesianGrid, LabelList, XAxis, YAxis } from "recharts"
import { formatCurrency } from "@/lib/formatters"
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from "@/components/ui/card"
import {
ChartContainer,
ChartTooltip,
ChartTooltipContent
} from "@/components/ui/chart"
import type {ChartConfig} from "@/components/ui/chart";
export const CustomBarChart = React.memo(function CustomBarChart({
title,
description,
data,
colorOffset = 0,
isCurrency = false
}: {
title: string
description: string
data: any[]
colorOffset?: number
isCurrency?: boolean
}) {
const { config, chartData } = useMemo(() => {
const cfg: ChartConfig = {
total: { label: "Total" },
}
const formattedData = data.map((item, index) => {
const key = String(item.name).toLowerCase().replace(/[^a-z0-9]/g, '_')
const hue = Math.floor((index * 137.5 + colorOffset) % 360)
cfg[key] = {
label: String(item.name),
color: `hsl(${hue}, 60%, 65%)`,
}
return {
...item,
fill: `var(--color-${key})`,
name: String(item.name),
total: Number(item.total)
}
})
return { config: cfg, chartData: formattedData }
}, [data, colorOffset])
const formatValue = (val: any) => {
if (!isCurrency) {
return val;
}
return formatCurrency(val);
};
return (
<Card>
<CardHeader>
<CardTitle>{title}</CardTitle>
<CardDescription>{description}</CardDescription>
</CardHeader>
<CardContent>
<ChartContainer config={config} className="[&_.recharts-wrapper]:outline-none [&_.recharts-surface]:outline-none">
<BarChart
accessibilityLayer
data={chartData}
layout="vertical"
margin={{
right: isCurrency ? 90 : 32, // More space if currency
left: 0
}}
style={{ outline: "none" }}
>
<CartesianGrid horizontal={false} vertical={false} />
<YAxis
dataKey="name"
type="category"
tickLine={false}
tickMargin={10}
axisLine={false}
hide
/>
<XAxis dataKey="total" type="number" hide />
<ChartTooltip
cursor={false}
content={<ChartTooltipContent indicator="line" valueFormatter={formatValue} />}
/>
<Bar dataKey="total" radius={4}>
<LabelList
dataKey="name"
position="insideLeft"
offset={8}
className="fill-white drop-shadow-md"
fontSize={12}
/>
<LabelList
dataKey="total"
position="right"
offset={8}
className="fill-foreground"
fontSize={12}
formatter={formatValue}
/>
</Bar>
</BarChart>
</ChartContainer>
</CardContent>
</Card>
)
})