CodeLens / dashboard /src /components /Leaderboard.tsx
ArshVerma's picture
Switch dashboard to Light Mode Premium Aesthetic
3fc3cc7
Raw
History Blame Contribute Delete
3.61 kB
import React, { useState } from "react";
import { useQuery } from "@tanstack/react-query";
import { Trophy, RefreshCw } from "lucide-react";
import { TaskId } from "../types";
import { fetchLeaderboard } from "../api";
import LeaderboardTable from "./LeaderboardTable";
import { clsx } from "clsx";
const Leaderboard: React.FC = () => {
const [activeTab, setActiveTab] = useState<TaskId>("bug_detection");
const { data: entries, isLoading, refetch, isRefetching } = useQuery({
queryKey: ["leaderboard", activeTab],
queryFn: () => fetchLeaderboard(activeTab),
});
const tabs: { id: TaskId; label: string }[] = [
{ id: "bug_detection", label: "Bug Detection" },
{ id: "security_audit", label: "Security Audit" },
{ id: "architectural_review", label: "Arch. Review" },
];
return (
<div
className="glass-panel overflow-hidden flex flex-col h-[600px] rounded-3xl"
>
{/* Header */}
<div
className="px-7 py-5 flex items-center justify-between"
style={{ borderBottom: "1px solid var(--color-border)" }}
>
<div className="flex items-center gap-3">
<div className="p-2 bg-amber-50 rounded-xl shadow-sm">
<Trophy className="w-5 h-5 text-amber-600" />
</div>
<h2 className="text-lg font-extrabold tracking-tight" style={{ color: "var(--color-heading)" }}>
Leaderboard
</h2>
</div>
<button
onClick={() => refetch()}
disabled={isLoading || isRefetching}
className="p-2.5 hover:bg-zinc-100 rounded-xl transition-colors disabled:opacity-40"
style={{ color: "var(--color-muted)" }}
>
<RefreshCw className={clsx("w-4 h-4", (isLoading || isRefetching) && "animate-spin")} />
</button>
</div>
{/* Tabs */}
<div className="px-7" style={{ borderBottom: "1px solid var(--color-border)" }}>
<div className="flex gap-6 overflow-x-auto">
{tabs.map((tab) => (
<button
key={tab.id}
onClick={() => setActiveTab(tab.id)}
className={clsx(
"py-3.5 text-sm font-semibold transition-all relative whitespace-nowrap",
activeTab === tab.id
? "text-zinc-900"
: "text-zinc-500 hover:text-zinc-700"
)}
>
{tab.label}
{activeTab === tab.id && (
<div className="absolute bottom-0 left-0 right-0 h-[2px] bg-zinc-900 rounded-full" />
)}
</button>
))}
</div>
</div>
{/* Content */}
<div className="flex-1 overflow-auto">
{isLoading ? (
<div className="flex items-center justify-center h-full gap-3" style={{ color: "var(--color-muted)" }}>
<RefreshCw className="w-5 h-5 animate-spin" />
<span className="text-sm font-medium">Loading entries...</span>
</div>
) : entries && entries.length > 0 ? (
<LeaderboardTable entries={entries} />
) : (
<div className="flex flex-col items-center justify-center h-full space-y-4">
<div className="p-5 bg-zinc-50 rounded-2xl shadow-sm border border-zinc-100">
<Trophy className="w-10 h-10 text-zinc-300" />
</div>
<p className="text-xs font-bold uppercase tracking-[0.15em]" style={{ color: "var(--color-muted)" }}>
No rankings yet
</p>
</div>
)}
</div>
</div>
);
};
export default Leaderboard;