gitscope
← marzneshin / v0.6.4 / dashboard/src/modules/users/components/widgets/users-stats-widget/index.tsx
https://dev.kronoz.win/r/marzneshin.git
dashboard/src/modules/users/components/widgets/users-stats-widget/index.tsx · TypeScript
Blame Raw
  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