Files
reui-blocks/blocks/chart-group7.tsx
T

270 lines
7.0 KiB
TypeScript

"use client";
import {
DollarSign,
Eye,
ShoppingCart,
TrendingDown,
TrendingUp,
Users,
} from "lucide-react";
import { Area, AreaChart, CartesianGrid, XAxis, YAxis } from "recharts";
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from "@/components/ui/card";
import {
type ChartConfig,
ChartContainer,
ChartTooltip,
ChartTooltipContent,
} from "@/components/ui/chart";
import { cn } from "@/lib/utils";
interface ChartGroup7Props {
className?: string;
}
const weekdayFormatter = new Intl.DateTimeFormat("fa-IR", {
weekday: "short",
});
const currencyFormatter = new Intl.NumberFormat("fa-IR", {
style: "currency",
currency: "IRR",
minimumFractionDigits: 0,
maximumFractionDigits: 0,
});
const compactCurrencyFormatter = new Intl.NumberFormat("fa-IR", {
style: "currency",
currency: "IRR",
notation: "compact",
minimumFractionDigits: 0,
maximumFractionDigits: 1,
});
const numberFormatter = new Intl.NumberFormat("fa-IR", {
maximumFractionDigits: 0,
});
const percentChangeFormatter = new Intl.NumberFormat("fa-IR", {
maximumFractionDigits: 1,
minimumFractionDigits: 1,
signDisplay: "exceptZero",
});
const chartData = [
{
day: weekdayFormatter.format(new Date(2025, 0, 6)),
revenue: 4200,
orders: 42,
visitors: 1200,
},
{
day: weekdayFormatter.format(new Date(2025, 0, 7)),
revenue: 5100,
orders: 51,
visitors: 1450,
},
{
day: weekdayFormatter.format(new Date(2025, 0, 8)),
revenue: 4800,
orders: 48,
visitors: 1380,
},
{
day: weekdayFormatter.format(new Date(2025, 0, 9)),
revenue: 6200,
orders: 62,
visitors: 1720,
},
{
day: weekdayFormatter.format(new Date(2025, 0, 10)),
revenue: 7100,
orders: 71,
visitors: 1980,
},
{
day: weekdayFormatter.format(new Date(2025, 0, 11)),
revenue: 5400,
orders: 54,
visitors: 1540,
},
{
day: weekdayFormatter.format(new Date(2025, 0, 12)),
revenue: 4100,
orders: 41,
visitors: 1180,
},
];
const chartConfig = {
revenue: { label: "درآمد", color: "var(--chart-1)" },
} satisfies ChartConfig;
const stats = [
{
title: "درآمد",
value: currencyFormatter.format(
chartData.reduce((sum, d) => sum + d.revenue, 0),
),
change: 12.5,
icon: DollarSign,
},
{
title: "سفارش‌ها",
value: numberFormatter.format(
chartData.reduce((sum, d) => sum + d.orders, 0),
),
change: 8.2,
icon: ShoppingCart,
},
{
title: "بازدیدکنندگان",
value: numberFormatter.format(
chartData.reduce((sum, d) => sum + d.visitors, 0),
),
change: -2.1,
icon: Eye,
},
{
title: "مشتریان",
value: numberFormatter.format(284),
change: 15.3,
icon: Users,
},
];
const ChartGroup7 = ({ className }: ChartGroup7Props) => {
return (
<section
dir="rtl"
lang="fa"
className={cn("py-32 text-start", className)}
>
<div className="container space-y-4">
<div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-4">
{stats.map((stat, index) => {
const Icon = stat.icon;
const isPositive = stat.change >= 0;
return (
<Card key={index} className="p-4 text-start">
<div className="flex items-center justify-between">
<div className="flex items-center gap-2">
<Icon
className="size-4 text-muted-foreground"
aria-hidden="true"
/>
<p className="text-sm text-muted-foreground">
{stat.title}
</p>
</div>
<div className="flex items-center gap-1 text-sm tabular-nums">
{isPositive ? (
<TrendingUp
className="size-4 text-green-500"
aria-hidden="true"
/>
) : (
<TrendingDown
className="size-4 text-red-500"
aria-hidden="true"
/>
)}
<span
className={isPositive ? "text-green-500" : "text-red-500"}
>
{percentChangeFormatter.format(stat.change)}٪
</span>
</div>
</div>
<p className="mt-1 text-xl font-bold tabular-nums">
{stat.value}
</p>
</Card>
);
})}
</div>
<Card className="text-start">
<CardHeader>
<CardTitle>درآمد هفتگی</CardTitle>
<CardDescription>درآمد روزانه در هفته گذشته</CardDescription>
</CardHeader>
<CardContent>
<ChartContainer config={chartConfig} className="h-64 w-full">
<AreaChart
data={chartData}
margin={{ top: 10, right: 10, left: 0, bottom: 0 }}
>
<defs>
<linearGradient
id="weeklyGradient"
x1="0"
y1="0"
x2="0"
y2="1"
>
<stop
offset="0%"
stopColor="var(--color-revenue)"
stopOpacity={0.3}
/>
<stop
offset="100%"
stopColor="var(--color-revenue)"
stopOpacity={0}
/>
</linearGradient>
</defs>
<CartesianGrid strokeDasharray="3 3" vertical={false} />
<XAxis
dataKey="day"
axisLine={false}
tickLine={false}
tickMargin={8}
fontSize={12}
/>
<YAxis
axisLine={false}
tickLine={false}
tickMargin={8}
fontSize={10}
width={52}
tickFormatter={(v) =>
compactCurrencyFormatter.format(Number(v))
}
/>
<ChartTooltip
content={
<ChartTooltipContent
formatter={(value) =>
currencyFormatter.format(Number(value))
}
/>
}
cursor={{ stroke: "var(--border)", strokeDasharray: "4 4" }}
/>
<Area
type="monotone"
dataKey="revenue"
stroke="var(--color-revenue)"
strokeWidth={2}
fill="url(#weeklyGradient)"
/>
</AreaChart>
</ChartContainer>
</CardContent>
</Card>
</div>
</section>
);
};
export { ChartGroup7 };