Files
discord-rpg-concept/web/src/pages/Dashboard.tsx
2026-01-09 16:18:52 +01:00

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>
);
}