()
| 10 | import { Button } from "@/components/ui/button" |
| 11 | |
| 12 | export default function AdminDashboard() { |
| 13 | const isAdmin = useQuery(api.admin.isAdmin) |
| 14 | // Only fetch counts after confirming user is admin to avoid unauthorized errors |
| 15 | const counts = useQuery(api.admin.getCounts, isAdmin ? {} : "skip") |
| 16 | |
| 17 | if (isAdmin === false) { |
| 18 | return ( |
| 19 | <div className="min-h-screen bg-[var(--color-bg)]"> |
| 20 | <Header /> |
| 21 | <section className="border-b border-[var(--color-border-weak)] px-[var(--padding)] py-[var(--vertical-padding)]"> |
| 22 | <div className="mx-auto max-w-[67.5rem]"> |
| 23 | <h1 className="text-2xl font-semibold text-[var(--color-text-strong)]">Access Denied</h1> |
| 24 | </div> |
| 25 | </section> |
| 26 | <main className="px-[var(--padding)] py-[var(--vertical-padding)]"> |
| 27 | <div className="mx-auto max-w-[67.5rem]"> |
| 28 | <p className="text-[var(--color-text)]">You do not have permission to access the admin area.</p> |
| 29 | </div> |
| 30 | </main> |
| 31 | </div> |
| 32 | ) |
| 33 | } |
| 34 | |
| 35 | if (isAdmin === undefined || counts === undefined) { |
| 36 | return ( |
| 37 | <div className="min-h-screen bg-[var(--color-bg)]"> |
| 38 | <Header /> |
| 39 | <div className="mx-auto max-w-[67.5rem] px-[var(--padding)] py-[var(--vertical-padding)]"> |
| 40 | <div className="animate-pulse"> |
| 41 | <div className="h-8 w-48 rounded bg-[var(--color-bg-weak)]" /> |
| 42 | <div className="mt-8 grid gap-4 md:grid-cols-4"> |
| 43 | {[...Array(4)].map((_, i) => ( |
| 44 | <div key={i} className="h-32 rounded-md border border-[var(--color-border-weak)] bg-[var(--color-bg-weak)]" /> |
| 45 | ))} |
| 46 | </div> |
| 47 | </div> |
| 48 | </div> |
| 49 | </div> |
| 50 | ) |
| 51 | } |
| 52 | |
| 53 | return ( |
| 54 | <div className="min-h-screen bg-[var(--color-bg)]"> |
| 55 | <Header /> |
| 56 | |
| 57 | {/* Hero */} |
| 58 | <section className="border-b border-[var(--color-border-weak)] px-[var(--padding)] py-[var(--vertical-padding)]"> |
| 59 | <div className="mx-auto max-w-[67.5rem]"> |
| 60 | <h1 className="text-2xl font-semibold text-[var(--color-text-strong)]">Admin Dashboard</h1> |
| 61 | <p className="mt-1 text-[var(--color-text)]">Manage extension submissions and approvals</p> |
| 62 | </div> |
| 63 | </section> |
| 64 | |
| 65 | {/* Content */} |
| 66 | <main className="px-[var(--padding)] py-[var(--vertical-padding)]"> |
| 67 | <div className="mx-auto max-w-[67.5rem]"> |
| 68 | {/* Stats Cards */} |
| 69 | <div className="grid gap-4 md:grid-cols-4"> |
nothing calls this directly
no outgoing calls
no test coverage detected