1import { FC } from 'react';
2import { UsersIcon } from 'lucide-react';
3import { useTranslation } from 'react-i18next';
4import {
5 SectionWidget,
6 ChartConfig,
7 ChartContainer,
8 ChartTooltip,
9 ChartTooltipContent,
10 ChartLegend,
11 ChartLegendContent,
12} from "@marzneshin/common/components";
13import { Label, Pie, PieChart } from "recharts"
14
15const chartConfig = {
16 active: {
17 label: "Active",
18 color: "#3b82f6",
19 },
20 online: {
21 label: "Online",
22 color: "#10b981",
23 },
24 expired: {
25 label: "Expired",
26 color: "#4b5563",
27 },
28 onHold: {
29 label: "On Hold",
30 color: "#A855F7",
31 },
32 limited: {
33 label: "Limited",
34 color: "#ef4444",
35 },
36} satisfies ChartConfig;
37
38interface UsersStatsProps {
39 limited: number;
40 active: number;
41 expired: number;
42 on_hold: number;
43 online: number;
44 total: number;
45}
46
47export const UsersStatsWidget: FC<UsersStatsProps> = ({ total, limited, active, expired, on_hold, online }) => {
48 const { t } = useTranslation();
49
50 const stats = [
51 { type: "limited", total: limited, fill: "var(--color-limited)" },
52 { type: "active", total: active, fill: "var(--color-active)" },
53 { type: "expired", total: expired, fill: "var(--color-expired)" },
54 { type: "onHold", total: on_hold, fill: "var(--color-onHold)" },
55 { type: "online", total: online, fill: "var(--color-online)" },
56 ]
57
58 return (
59 <SectionWidget
60 title={<> <UsersIcon /> {t('users')} </>}
61 description={t('page.home.users-stats.desc')}
62 className="h-full"
63 >
64 <ChartContainer
65 config={chartConfig}
66 className="mx-auto aspect-square min-h-[300px] w-full"
67 >
68 <PieChart>
69 <ChartTooltip
70 cursor={false}
71 content={<ChartTooltipContent hideLabel />}
72 />
73 <Pie
74 data={stats}
75 dataKey="total"
76 nameKey="type"
77 innerRadius={60}
78 strokeWidth={5}
79 >
80 <Label
81 content={({ viewBox }) => {
82 if (viewBox && "cx" in viewBox && "cy" in viewBox) {
83 return (
84 <text
85 x={viewBox.cx}
86 y={viewBox.cy}
87 textAnchor="middle"
88 dominantBaseline="middle"
89 >
90 <tspan
91 x={viewBox.cx}
92 y={viewBox.cy}
93 className="fill-foreground text-3xl font-bold"
94 >
95 {total || 0}
96 </tspan>
97 <tspan
98 x={viewBox.cx}
99 y={(viewBox.cy || 0) + 24}
100 className="fill-muted-foreground"
101 >
102 {t('users')}
103 </tspan>
104 </text>
105 )
106 }
107 }}
108 />
109 </Pie>
110 <ChartLegend className="flex -translate-y-2 flex-wrap gap-2 [&>*]:basis-1/5 [&>*]:justify-center text-md" content={<ChartLegendContent />} />
111 </PieChart>
112 </ChartContainer>
113 </SectionWidget>
114 );
115};
116