94 lines
2.8 KiB
TypeScript

"use client";
import * as React from "react";
import { useQuery } from "@tanstack/react-query";
import type { ActivitySeries } from "@/types/analytics";
import {
ResponsiveContainer,
AreaChart,
Area,
XAxis,
YAxis,
Tooltip,
CartesianGrid,
Legend,
} from "recharts";
async function fetchActivity(
from?: string,
to?: string,
interval: "day" | "week" | "month" = "day",
): Promise<ActivitySeries> {
const url = new URL("/api/analytics/activity", window.location.origin);
if (from) url.searchParams.set("from", from);
if (to) url.searchParams.set("to", to);
url.searchParams.set("interval", interval);
const res = await fetch(url.toString(), { cache: "no-store" });
if (!res.ok) {
const payload = await res.json().catch(() => ({}));
throw new Error(payload?.message || `Failed to load activity (${res.status})`);
}
return (await res.json()) as ActivitySeries;
}
export function ActivityChart() {
const q = useQuery({
queryKey: ["analytics", "activity", "day"],
queryFn: () => fetchActivity(undefined, undefined, "day"),
});
const data =
q.data?.points.map((p) => ({
date: p.date.slice(0, 10),
uploaded: p.uploaded ?? 0,
modified: p.modified ?? 0,
})) ?? [];
return (
<div className="rounded-md border p-3">
<div className="text-sm font-medium mb-2">Activity</div>
<div className="h-64">
{q.isLoading ? (
<div className="text-xs text-muted-foreground">Loading</div>
) : data.length === 0 ? (
<div className="text-xs text-muted-foreground">No data</div>
) : (
<ResponsiveContainer width="100%" height="100%">
<AreaChart data={data}>
<CartesianGrid strokeDasharray="3 3" stroke="hsl(var(--border))" />
<XAxis dataKey="date" tick={{ fontSize: 11 }} />
<YAxis tick={{ fontSize: 11 }} />
<Tooltip
contentStyle={{
background: "hsl(var(--popover))",
border: "1px solid hsl(var(--border))",
color: "hsl(var(--popover-foreground))",
}}
/>
<Legend />
<Area
type="monotone"
dataKey="uploaded"
name="Uploaded"
stroke="hsl(var(--chart-2))"
fill="hsl(var(--chart-2))"
fillOpacity={0.25}
strokeWidth={2}
/>
<Area
type="monotone"
dataKey="modified"
name="Modified"
stroke="hsl(var(--chart-1))"
fill="hsl(var(--chart-1))"
fillOpacity={0.25}
strokeWidth={2}
/>
</AreaChart>
</ResponsiveContainer>
)}
</div>
</div>
);
}