120 lines
3.5 KiB
TypeScript
120 lines
3.5 KiB
TypeScript
"use client";
|
|
|
|
import {
|
|
Card,
|
|
CardContent,
|
|
CardDescription,
|
|
CardHeader,
|
|
CardTitle,
|
|
} from "@/components/ui/card";
|
|
import { cn } from "@/lib/utils";
|
|
|
|
interface FunnelStep {
|
|
label: string;
|
|
value: number;
|
|
color?: string;
|
|
}
|
|
|
|
interface ChartCard21Props {
|
|
title?: string;
|
|
description?: string;
|
|
data?: FunnelStep[];
|
|
className?: string;
|
|
}
|
|
|
|
const numberFormatter = new Intl.NumberFormat("fa-IR", {
|
|
maximumFractionDigits: 0,
|
|
});
|
|
|
|
const oneDecimalFormatter = new Intl.NumberFormat("fa-IR", {
|
|
maximumFractionDigits: 1,
|
|
minimumFractionDigits: 1,
|
|
});
|
|
|
|
const defaultData: FunnelStep[] = [
|
|
{ label: "بازدیدکنندگان", value: 10000 },
|
|
{ label: "سرنخها", value: 6500 },
|
|
{ label: "واجد شرایط", value: 3200 },
|
|
{ label: "پیشنهادها", value: 1800 },
|
|
{ label: "بستهشده", value: 950 },
|
|
];
|
|
|
|
const ChartCard21 = ({
|
|
title = "قیف فروش",
|
|
description = "نرخ تبدیل در مراحل قیف",
|
|
data = defaultData,
|
|
className,
|
|
}: ChartCard21Props) => {
|
|
const maxValue = Math.max(...data.map((d) => d.value));
|
|
const colors = [
|
|
"ارزش افزوده(--chart-1)",
|
|
"ارزش افزوده(--chart-2)",
|
|
"ارزش افزوده(--chart-3)",
|
|
"ارزش افزوده(--chart-4)",
|
|
"ارزش افزوده(--chart-5)",
|
|
];
|
|
|
|
return (
|
|
<Card
|
|
dir="rtl"
|
|
lang="fa"
|
|
className={cn("w-full max-w-2xl text-start", className)}
|
|
>
|
|
<CardHeader>
|
|
<CardTitle>{title}</CardTitle>
|
|
<CardDescription>{description}</CardDescription>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div className="space-y-3">
|
|
{data.map((step, index) => {
|
|
const widthPercent = (step.value / maxValue) * 100;
|
|
const conversionRate =
|
|
index > 0
|
|
? (step.value / data[index - 1].value) * 100
|
|
: null;
|
|
|
|
return (
|
|
<div key={step.label} className="space-y-1">
|
|
<div className="flex items-center justify-between text-sm">
|
|
<span className="font-medium">{step.label}</span>
|
|
<div className="flex items-center gap-2 tabular-nums">
|
|
<span className="text-muted-foreground">
|
|
{numberFormatter.format(step.value)}
|
|
</span>
|
|
{conversionRate !== null && (
|
|
<span className="text-xs text-muted-foreground">
|
|
({oneDecimalFormatter.format(conversionRate)}٪)
|
|
</span>
|
|
)}
|
|
</div>
|
|
</div>
|
|
<div className="h-8 w-full rounded-sm bg-muted">
|
|
<div
|
|
className="flex h-full items-center justify-center rounded-sm transition-all duration-500"
|
|
style={{
|
|
width: `${widthPercent}%`,
|
|
backgroundColor:
|
|
step.color || colors[index % colors.length],
|
|
}}
|
|
>
|
|
{widthPercent > 15 && (
|
|
<span className="text-xs font-medium text-white tabular-nums">
|
|
{numberFormatter.format(
|
|
Math.round((step.value / maxValue) * 100),
|
|
)}
|
|
٪
|
|
</span>
|
|
)}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
})}
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
);
|
|
};
|
|
|
|
export { ChartCard21 };
|