"use client"; import { addDays, differenceInDays, format as formatDate, startOfDay, subDays, subMonths, } from "date-fns"; import { faIR } from "date-fns/locale"; import { CalendarIcon, TrendingDown, TrendingUp } from "lucide-react"; import { useMemo, useState } from "react"; import type { DateRange } from "react-day-picker"; import { Area, AreaChart, Bar, BarChart, CartesianGrid, Pie, PieChart, XAxis, YAxis, } from "recharts"; import { Button } from "@/components/ui/button"; import { Calendar } from "@/components/ui/calendar"; import { Card, CardContent, CardDescription, CardHeader, CardTitle, } from "@/components/ui/card"; import { type ChartConfig, ChartContainer, ChartTooltip, ChartTooltipContent, } from "@/components/ui/chart"; import { Popover, PopoverContent, PopoverTrigger, } from "@/components/ui/popover"; import { cn } from "@/lib/utils"; interface ChartGroup12Props { className?: string; } const seededRandom = (seed: number) => { const x = Math.sin(seed) * 10000; return x - Math.floor(x); }; 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 oneDecimalFormatter = new Intl.NumberFormat("fa-IR", { maximumFractionDigits: 1, minimumFractionDigits: 1, }); const percentChangeFormatter = new Intl.NumberFormat("fa-IR", { maximumFractionDigits: 1, minimumFractionDigits: 1, signDisplay: "exceptZero", }); const formatPercent = (value: number) => `${oneDecimalFormatter.format(value)}٪`; const generateDataForRange = (from: Date, to: Date) => { const data = []; const days = differenceInDays(to, from) + 1; for (let i = 0; i < days; i++) { const date = addDays(startOfDay(from), i); const seed = date.getTime() / 86400000; data.push({ date: date, dateStr: formatDate(date, "d MMM", { locale: faIR }), revenue: Math.floor(seededRandom(seed) * 8000) + 3000, orders: Math.floor(seededRandom(seed + 1000) * 80) + 30, visitors: Math.floor(seededRandom(seed + 2000) * 2000) + 500, }); } return data; }; const categoryData = [ { name: "الکترونیک", value: 4200, fill: "var(--chart-1)" }, { name: "پوشاک", value: 3100, fill: "var(--chart-2)" }, { name: "خانه", value: 2400, fill: "var(--chart-3)" }, { name: "ورزش", value: 1800, fill: "var(--chart-4)" }, ]; const categoryConfig = { الکترونیک: { label: "الکترونیک", color: "var(--chart-1)" }, پوشاک: { label: "پوشاک", color: "var(--chart-2)" }, خانه: { label: "خانه", color: "var(--chart-3)" }, ورزش: { label: "ورزش", color: "var(--chart-4)" }, } satisfies ChartConfig; const sourceData = [ { name: "ارگانیک", value: 42 }, { name: "پولی", value: 28 }, { name: "شبکه‌های اجتماعی", value: 18 }, { name: "ارجاع", value: 12 }, ]; const presets = [ { label: "۷ روز اخیر", days: 7 }, { label: "۳۰ روز اخیر", days: 30 }, { label: "۹۰ روز اخیر", days: 90 }, ]; const revenueConfig = { revenue: { label: "درآمد", color: "var(--chart-1)" }, } satisfies ChartConfig; const sourceConfig = { value: { label: "درصد", color: "var(--chart-2)" }, } satisfies ChartConfig; const ChartGroup12 = ({ className }: ChartGroup12Props) => { const [dateRange, setDateRange] = useState({ from: subDays(new Date(), 30), to: new Date(), }); const filteredData = useMemo(() => { const from = dateRange?.from ?? subDays(new Date(), 30); const to = dateRange?.to ?? new Date(); return generateDataForRange(from, to); }, [dateRange]); const totalRevenue = filteredData.reduce( (sum, item) => sum + item.revenue, 0, ); const totalOrders = filteredData.reduce((sum, item) => sum + item.orders, 0); const totalVisitors = filteredData.reduce( (sum, item) => sum + item.visitors, 0, ); const conversionRate = totalVisitors > 0 ? (totalOrders / totalVisitors) * 100 : 0; const handlePreset = (days: number) => { setDateRange({ from: subDays(new Date(), days), to: new Date(), }); }; const stats = [ { title: "مجموع درآمد", value: currencyFormatter.format(totalRevenue), change: 12.5, }, { title: "مجموع سفارش‌ها", value: numberFormatter.format(totalOrders), change: 8.2, }, { title: "بازدیدکنندگان", value: numberFormatter.format(totalVisitors), change: -2.4, }, { title: "نرخ تبدیل", value: formatPercent(conversionRate), change: 5.1, }, ]; const avgOrderValue = totalOrders > 0 ? Math.round(totalRevenue / totalOrders) : 0; const ordersPerDay = filteredData.length > 0 ? Math.round(totalOrders / filteredData.length) : 0; const revenuePerDay = filteredData.length > 0 ? Math.round(totalRevenue / filteredData.length) : 0; const visitorsPerDay = filteredData.length > 0 ? Math.round(totalVisitors / filteredData.length) : 0; return (

مرور داشبورد

پیگیری عملکرد کسب‌وکار شما

{presets.map((preset) => ( ))}
{stats.map((stat, index) => (

{stat.title}

{stat.value}

{stat.change >= 0 ? ( ) : ( )} = 0 ? "text-green-500" : "text-red-500", "tabular-nums", )} > {percentChangeFormatter.format(stat.change)}٪
))}
روند درآمد درآمد روزانه در بازه انتخاب‌شده compactCurrencyFormatter.format(Number(v)) } /> currencyFormatter.format(Number(value)) } /> } cursor={{ stroke: "var(--border)", strokeDasharray: "4 4" }} /> فروش به تفکیک دسته تفکیک درآمد بر اساس دسته
currencyFormatter.format(Number(value)) } /> } cursor={false} />
{categoryData.map((item, index) => (
{item.name}
))}
منابع ترافیک منشأ بازدیدکنندگان شما formatPercent(Number(v))} /> formatPercent(Number(value))} /> } cursor={{ fillOpacity: 0.05 }} /> آمار سریع خلاصه شاخص‌های کلیدی
میانگین ارزش سفارش {currencyFormatter.format(avgOrderValue)}
سفارش در روز {numberFormatter.format(ordersPerDay)}
درآمد در روز {currencyFormatter.format(revenuePerDay)}
بازدید در روز {numberFormatter.format(visitorsPerDay)}
); }; export { ChartGroup12 };