forked from syntaxbullet/AuroraBot-discord
178 lines
8.6 KiB
TypeScript
178 lines
8.6 KiB
TypeScript
import React from "react";
|
|
import { Link } from "react-router-dom";
|
|
import { useSocket } from "../hooks/use-socket";
|
|
import { Badge } from "../components/ui/badge";
|
|
import { StatCard } from "../components/stat-card";
|
|
import { RecentActivity } from "../components/recent-activity";
|
|
import { LootdropCard } from "../components/lootdrop-card";
|
|
import { Server, Users, Terminal, Activity, Coins, TrendingUp, Flame, Package } from "lucide-react";
|
|
import { cn } from "../lib/utils";
|
|
|
|
export function Dashboard() {
|
|
const { isConnected, stats } = useSocket();
|
|
|
|
return (
|
|
<div className="min-h-screen bg-aurora-page text-foreground font-outfit overflow-x-hidden">
|
|
{/* Navigation */}
|
|
<nav className="fixed top-0 w-full z-50 glass-card border-b border-border/50 py-4 px-8 flex justify-between items-center">
|
|
<div className="flex items-center gap-3">
|
|
{/* Bot Avatar */}
|
|
{stats?.bot?.avatarUrl ? (
|
|
<img
|
|
src={stats.bot.avatarUrl}
|
|
alt="Aurora Avatar"
|
|
className="w-8 h-8 rounded-full border border-primary/20 shadow-sm object-cover"
|
|
/>
|
|
) : (
|
|
<div className="w-8 h-8 rounded-full bg-aurora sun-flare shadow-sm" />
|
|
)}
|
|
|
|
<span className="text-xl font-bold tracking-tight text-primary">Aurora</span>
|
|
|
|
{/* Live Status Badge */}
|
|
<div className={`flex items-center gap-1.5 px-2 py-0.5 rounded-full border transition-colors duration-500 ${isConnected
|
|
? "bg-emerald-500/10 border-emerald-500/20 text-emerald-500"
|
|
: "bg-red-500/10 border-red-500/20 text-red-500"
|
|
}`}>
|
|
<div className="relative flex h-2 w-2">
|
|
{isConnected && (
|
|
<span className="animate-ping absolute inline-flex h-full w-full rounded-full bg-emerald-500 opacity-75"></span>
|
|
)}
|
|
<span className={`relative inline-flex rounded-full h-2 w-2 ${isConnected ? "bg-emerald-500" : "bg-red-500"}`}></span>
|
|
</div>
|
|
<span className="text-[10px] font-bold tracking-wider uppercase">
|
|
{isConnected ? "Live" : "Offline"}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="flex items-center gap-6">
|
|
<Link to="/" className="text-step--1 font-medium text-muted-foreground hover:text-primary transition-colors">
|
|
Home
|
|
</Link>
|
|
<Link to="/design-system" className="text-step--1 font-medium text-muted-foreground hover:text-primary transition-colors">
|
|
Design System
|
|
</Link>
|
|
</div>
|
|
</nav>
|
|
|
|
{/* Dashboard Content */}
|
|
<main className="pt-32 px-8 max-w-7xl mx-auto space-y-8">
|
|
|
|
{/* Stats Grid */}
|
|
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-4 animate-in fade-in slide-up">
|
|
<StatCard
|
|
title="Total Servers"
|
|
icon={Server}
|
|
isLoading={!stats}
|
|
value={stats?.guilds.count.toLocaleString()}
|
|
subtitle={stats?.guilds.changeFromLastMonth
|
|
? `${stats.guilds.changeFromLastMonth > 0 ? '+' : ''}${stats.guilds.changeFromLastMonth} from last month`
|
|
: "Active Guilds"
|
|
}
|
|
/>
|
|
|
|
<StatCard
|
|
title="Total Users"
|
|
icon={Users}
|
|
isLoading={!stats}
|
|
value={stats?.users.total.toLocaleString()}
|
|
subtitle={stats ? `${stats.users.active.toLocaleString()} active now` : undefined}
|
|
className="delay-100"
|
|
/>
|
|
|
|
<StatCard
|
|
title="Commands"
|
|
icon={Terminal}
|
|
isLoading={!stats}
|
|
value={stats?.commands.total.toLocaleString()}
|
|
subtitle={stats ? `${stats.commands.active} active · ${stats.commands.disabled} disabled` : undefined}
|
|
className="delay-200"
|
|
/>
|
|
|
|
<StatCard
|
|
title="System Ping"
|
|
icon={Activity}
|
|
isLoading={!stats}
|
|
value={stats ? `${Math.round(stats.ping.avg)}ms` : undefined}
|
|
subtitle="Average latency"
|
|
className="delay-300"
|
|
valueClassName={stats ? cn(
|
|
"transition-colors duration-300",
|
|
stats.ping.avg < 100 ? "text-emerald-500" :
|
|
stats.ping.avg < 200 ? "text-yellow-500" : "text-red-500"
|
|
) : undefined}
|
|
/>
|
|
</div>
|
|
|
|
<div className="grid gap-8 lg:grid-cols-3 animate-in fade-in slide-up delay-300">
|
|
{/* Economy Stats */}
|
|
<div className="lg:col-span-2 space-y-4">
|
|
<h2 className="text-xl font-semibold tracking-tight">Economy Overview</h2>
|
|
<div className="grid gap-4 md:grid-cols-2">
|
|
<StatCard
|
|
title="Total Wealth"
|
|
icon={Coins}
|
|
isLoading={!stats}
|
|
value={stats ? `${Number(stats.economy.totalWealth).toLocaleString()} AU` : undefined}
|
|
subtitle="Astral Units in circulation"
|
|
valueClassName="text-primary"
|
|
iconClassName="text-primary"
|
|
/>
|
|
|
|
<StatCard
|
|
title="Items Circulating"
|
|
icon={Package}
|
|
isLoading={!stats}
|
|
value={stats?.economy.totalItems?.toLocaleString()}
|
|
subtitle="Total items owned by users"
|
|
className="delay-75"
|
|
valueClassName="text-blue-500"
|
|
iconClassName="text-blue-500"
|
|
/>
|
|
|
|
<StatCard
|
|
title="Average Level"
|
|
icon={TrendingUp}
|
|
isLoading={!stats}
|
|
value={stats ? `Lvl ${stats.economy.avgLevel}` : undefined}
|
|
subtitle="Global player average"
|
|
className="delay-100"
|
|
valueClassName="text-secondary"
|
|
iconClassName="text-secondary"
|
|
/>
|
|
|
|
<StatCard
|
|
title="Top /daily Streak"
|
|
icon={Flame}
|
|
isLoading={!stats}
|
|
value={stats?.economy.topStreak}
|
|
subtitle="Days daily streak"
|
|
className="delay-200"
|
|
valueClassName="text-destructive"
|
|
iconClassName="text-destructive"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Recent Activity */}
|
|
{/* Recent Activity & Lootdrops */}
|
|
<div className="space-y-4">
|
|
<LootdropCard
|
|
drop={stats?.activeLootdrops?.[0]}
|
|
state={stats?.lootdropState}
|
|
isLoading={!stats}
|
|
/>
|
|
<h2 className="text-xl font-semibold tracking-tight">Live Feed</h2>
|
|
<RecentActivity
|
|
events={stats?.recentEvents || []}
|
|
isLoading={!stats}
|
|
className="h-[calc(100%-2rem)]"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</main>
|
|
</div>
|
|
);
|
|
}
|