Files
AuroraBot-discord/web/src/components/ActivityChart.tsx

126 lines
4.9 KiB
TypeScript

import React from 'react';
import {
AreaChart,
Area,
XAxis,
YAxis,
CartesianGrid,
Tooltip,
ResponsiveContainer,
} from 'recharts';
import type { ActivityData } from '../hooks/use-activity-stats';
interface ActivityChartProps {
data: ActivityData[];
loading?: boolean;
}
const CustomTooltip = ({ active, payload }: any) => {
if (active && payload && payload.length) {
const data = payload[0].payload;
return (
<div className="glass p-3 rounded-lg border border-white/10 text-sm shadow-xl animate-in fade-in zoom-in duration-200">
<p className="font-semibold text-white/90 border-b border-white/10 pb-1 mb-2">
{data.displayTime}
</p>
<div className="space-y-1">
<p className="flex items-center justify-between gap-4">
<span className="text-primary font-medium">Commands</span>
<span className="font-mono">{payload[0].value}</span>
</p>
<p className="flex items-center justify-between gap-4">
<span className="text-[var(--chart-2)] font-medium">Transactions</span>
<span className="font-mono">{payload[1].value}</span>
</p>
</div>
</div>
);
}
return null;
};
export const ActivityChart: React.FC<ActivityChartProps> = ({ data, loading }) => {
if (loading) {
return (
<div className="w-full h-[300px] flex items-center justify-center">
<div className="flex flex-col items-center gap-3">
<div className="w-8 h-8 border-4 border-primary/20 border-t-primary rounded-full animate-spin" />
<p className="text-muted-foreground animate-pulse text-sm">Aggregating stats...</p>
</div>
</div>
);
}
// Format hour for XAxis (e.g., "HH:00")
const chartData = data.map(item => ({
...item,
displayTime: new Date(item.hour).getHours() + ':00'
}));
return (
<div className="w-full h-[300px] mt-4">
<ResponsiveContainer width="100%" height="100%">
<AreaChart
data={chartData}
margin={{ top: 10, right: 10, left: -20, bottom: 0 }}
>
<defs>
<linearGradient id="colorCommands" x1="0" y1="0" x2="0" y2="1">
<stop offset="5%" stopColor="var(--color-primary)" stopOpacity={0.3} />
<stop offset="95%" stopColor="var(--color-primary)" stopOpacity={0} />
</linearGradient>
<linearGradient id="colorTransactions" x1="0" y1="0" x2="0" y2="1">
<stop offset="5%" stopColor="var(--chart-2)" stopOpacity={0.3} />
<stop offset="95%" stopColor="var(--chart-2)" stopOpacity={0} />
</linearGradient>
</defs>
<CartesianGrid
strokeDasharray="3 3"
vertical={false}
stroke="rgba(255,255,255,0.05)"
/>
<XAxis
dataKey="hour"
fontSize={10}
tickFormatter={(str) => {
const date = new Date(str);
return date.getHours() % 4 === 0 ? `${date.getHours()}:00` : '';
}}
axisLine={false}
tickLine={false}
stroke="var(--muted-foreground)"
minTickGap={30}
/>
<YAxis
fontSize={10}
axisLine={false}
tickLine={false}
stroke="var(--muted-foreground)"
width={40}
/>
<Tooltip content={<CustomTooltip />} />
<Area
type="monotone"
dataKey="commands"
stroke="var(--color-primary)"
strokeWidth={2}
fillOpacity={1}
fill="url(#colorCommands)"
animationDuration={1500}
/>
<Area
type="monotone"
dataKey="transactions"
stroke="var(--chart-2)"
strokeWidth={2}
fillOpacity={1}
fill="url(#colorTransactions)"
animationDuration={1500}
/>
</AreaChart>
</ResponsiveContainer>
</div>
);
};