mhsf-dev/apps/www/src/components/feat/server-page/stats/stats-main-row.tsx

191 lines
5.0 KiB
TypeScript
Raw Normal View History

2025-03-15 16:58:24 -05:00
"use client";
2025-03-08 15:21:26 -06:00
import { Separator } from "@/components/ui/separator";
import type { ServerResponse } from "@/lib/types/mh-server";
2025-03-15 16:58:24 -05:00
import { Area, AreaChart, CartesianGrid, XAxis } from "recharts";
2025-03-08 15:21:26 -06:00
2025-03-15 16:58:24 -05:00
import {
2025-04-04 21:10:56 -05:00
type ChartConfig,
ChartContainer,
ChartTooltip,
ChartTooltipContent,
2025-03-15 16:58:24 -05:00
} from "@/components/ui/chart";
import type { useMHSFServer } from "@/lib/hooks/use-mhsf-server";
import { cn } from "@/lib/utils";
import { useQueryState } from "nuqs";
import { Badge } from "@/components/ui/badge";
import { convert } from "../util";
import { Material } from "@/components/ui/material";
2025-04-04 21:10:56 -05:00
import { Spinner } from "@/components/ui/spinner";
import { Placeholder } from "@/components/ui/placeholder";
import { CircleSlash } from "lucide-react";
2025-03-15 16:58:24 -05:00
export function StatisticsMainRow({
2025-04-04 21:10:56 -05:00
server,
mhsfData,
2025-03-15 16:58:24 -05:00
}: {
2025-04-04 21:10:56 -05:00
server: ServerResponse;
mhsfData: ReturnType<typeof useMHSFServer>;
2025-03-15 16:58:24 -05:00
}) {
2025-04-04 21:10:56 -05:00
const [statisticType, setStatisticType] = useQueryState("st", {
defaultValue: "playerCount",
});
2025-03-15 16:58:24 -05:00
2025-04-04 21:10:56 -05:00
return (
<Material
className="relative col-span-2 h-[250px] max-lg:mt-3"
padding="none"
>
<div className="p-4">
<span className="flex gap-4 mb-2">
2025-04-18 21:44:38 -05:00
<strong className="text-lg max-lg:hidden">Statistics</strong>
2025-04-04 21:10:56 -05:00
<button
type="button"
className={cn(
"text-sm cursor-pointer hover:bg-slate-100 dark:hover:bg-zinc-700/30 transition-all duration-75 disabled:opacity-50 disabled:pointer-events-none",
"rounded-xl px-2 flex items-center gap-2",
statisticType === "playerCount" &&
"bg-slate-100 dark:bg-zinc-700/30 font-medium",
)}
onClick={() => setStatisticType("playerCount")}
>
Player Count
<Badge className="px-1">
<code>{convert(server.joins)}</code>
</Badge>
</button>
<button
type="button"
className={cn(
"text-sm cursor-pointer hover:bg-slate-100 dark:hover:bg-zinc-700/30 transition-all duration-75 disabled:opacity-50 disabled:pointer-events-none",
"rounded-xl px-2 flex items-center gap-2",
statisticType === "favorites" &&
"bg-slate-100 dark:bg-zinc-700/30 font-medium",
)}
onClick={() => setStatisticType("favorites")}
>
Favorites
<Badge className="px-1">
<code>
{convert(
mhsfData.server?.favoriteData.favoriteNumber as number,
)}
</code>
</Badge>
</button>
</span>
<Separator />
</div>
2025-04-18 21:44:38 -05:00
<div className="mt-2 max-lg:mt-9">
2025-04-04 21:10:56 -05:00
{!mhsfData.loading ? (
<>
{(statisticType === "playerCount"
? mhsfData.server?.playerData.historically
: mhsfData.server?.favoriteData.favoriteHistoricalData
)?.length !== 0 ? (
<StatisticsChart
data={
statisticType === "playerCount"
? mhsfData.server?.playerData.historically
: mhsfData.server?.favoriteData.favoriteHistoricalData
}
mainDataPoint={statisticType}
/>
) : (
<span className="w-full h-full items-center justify-center flex">
<Placeholder
icon={<CircleSlash />}
title="There is no data to be collected"
description="This server probably never had any data collected in your choosen timespan."
/>
</span>
)}
</>
) : (
<Spinner />
)}
</div>
</Material>
);
2025-03-15 16:58:24 -05:00
}
const chartConfig = {
2025-04-04 21:10:56 -05:00
playerCount: {
label: "Joins",
color: "hsl(var(--chart-1))",
},
favorites: {
label: "Favorites",
color: "hsl(var(--chart-2))",
},
2025-03-15 16:58:24 -05:00
} satisfies ChartConfig;
export function StatisticsChart({
2025-04-04 21:10:56 -05:00
data,
mainDataPoint,
2025-03-15 16:58:24 -05:00
}: {
2025-04-04 21:10:56 -05:00
data: any;
mainDataPoint: string;
2025-03-15 16:58:24 -05:00
}) {
2025-04-04 21:10:56 -05:00
console.log(data);
return (
<ChartContainer config={chartConfig} className="max-h-[202px] min-w-full">
<AreaChart
accessibilityLayer
data={data.slice(data.length - 30, data.length)}
margin={{
top: 30,
}}
className="rounded-b-xl"
>
<CartesianGrid vertical={false} horizontal={false} />
<XAxis dataKey="date" tickLine={false} axisLine={false} tick={false} />
<ChartTooltip
content={
<ChartTooltipContent
className="w-[150px]"
nameKey={mainDataPoint}
indicator="line"
labelFormatter={(value) => {
return `${new Date(value).toLocaleDateString("en-US", {
day: "numeric",
month: "short",
})} ${new Date(value).toLocaleTimeString("en-US", {
timeStyle: "short",
})}`;
}}
/>
}
/>
<defs>
<linearGradient
id={`fill${mainDataPoint}`}
x1="0"
y1="0"
x2="0"
y2="1"
>
<stop
offset="25%"
stopColor={`var(--color-${mainDataPoint})`}
stopOpacity={0.8}
/>
<stop
offset="95%"
stopColor={`var(--color-${mainDataPoint})`}
stopOpacity={0.1}
/>
</linearGradient>
</defs>
<Area
dataKey={mainDataPoint}
type="natural"
fill={`url(#fill${mainDataPoint})`}
fillOpacity={0.4}
stroke={`var(--color-${mainDataPoint})`}
stackId="a"
/>
</AreaChart>
</ChartContainer>
);
2025-03-08 15:21:26 -06:00
}