1import { useState, FC } from 'react';
2import { useTranslation } from 'react-i18next';
3import {
4 SectionWidget,
5 ChartContainer,
6 Awaiting,
7 ChartTooltip,
8 ChartTooltipContent,
9 ChartConfig,
10} from "@marzneshin/common/components";
11import { XAxis, BarChart, YAxis, CartesianGrid, Bar } from "recharts"
12import { format as formatByte } from '@chbphone55/pretty-bytes';
13import { useNodesUsageQuery, NodeType } from "@marzneshin/modules/nodes";
14import {
15 useTransformDateUsageData,
16 ChartDateInterval,
17 SelectDateView,
18 dateXAxisTicks,
19 useFromNowInterval
20} from "@marzneshin/libs/stats-charts";
21
22const chartConfig = {
23 traffic: {
24 label: "Traffic",
25 color: "hsl(var(--chart-1))",
26 },
27} satisfies ChartConfig
28
29export const NodesUsageWidget: FC<{ node: NodeType }> = ({ node }) => {
30 const { t } = useTranslation();
31 const [timeRange, setTimeRange] = useState("1d")
32 const { start, end } = useFromNowInterval(timeRange as ChartDateInterval);
33 const { data } = useNodesUsageQuery({ nodeId: node.id, start, end })
34 const chartData = useTransformDateUsageData(data.usages);
35 const [totalAmount, totalMetric] = formatByte(data.total);
36
37 return (
38 <Awaiting
39 Component={
40 <SectionWidget
41 title={
42 <div className="hstack justify-between w-full">
43 {t("page.nodes.nodes-usage-widget.title")}
44 </div>
45 }
46 description={t("page.nodes.nodes-usage-widget.desc")}
47 options={
48 <div className="vstack justify-end w-full">
49 <span className="text-lg leading-none sm:text-2xl w-full">
50 {totalAmount} {totalMetric}
51 </span>
52 <span className="text-sm flex justify-end text-muted-foreground w-full">
53 Total
54 </span>
55 </div>
56 }
57 footer={
58 <SelectDateView timeRange={timeRange} setTimeRange={setTimeRange} />
59 }
60 >
61 <ChartContainer
62 config={chartConfig}
63 className="aspect-auto h-[320px] w-full"
64 >
65 <BarChart
66 accessibilityLayer
67 data={chartData}
68 margin={{
69 left: 12,
70 top: 13,
71 right: 12,
72 }}
73 >
74 <CartesianGrid vertical={false} />
75 <YAxis
76 tickLine={false}
77 axisLine={false}
78 tickMargin={8}
79 tickFormatter={(value) => {
80 const [amount, metric] = formatByte(value)
81 return `${amount} ${metric}`
82 }}
83 />
84 <XAxis
85 dataKey="datetime"
86 tickLine={false}
87 axisLine={false}
88 tickMargin={8}
89 tickFormatter={(value) => dateXAxisTicks(value, timeRange as ChartDateInterval)}
90 />
91 <ChartTooltip
92 content={
93 <ChartTooltipContent
94 indicator='line'
95 labelFormatter={(value) => {
96 return new Date(value).toLocaleDateString("en-US", {
97 month: "short",
98 day: "numeric",
99 year: "numeric",
100 hour: "numeric"
101 })
102 }}
103 valueFormatter={(value) => {
104 const [amount, metric] = formatByte(value as number)
105 return `${amount} ${metric}`
106 }}
107 />
108 }
109 />
110 <Bar dataKey="traffic" fill={`var(--color-traffic)`} />
111 </BarChart>
112 </ChartContainer>
113 </SectionWidget>
114 }
115 />
116 );
117};