Add admin foundation + Users resource (Filament replacement, slice 1)
Plain App Router admin (aligned to habbo-next, no Refine): - rank surfaced on the NextAuth session; staff guard isStaff() [pure, unit-tested] + requireStaff() reading min_staff_rank, gating /admin. - /admin dashboard (counts), /admin/users (paginated + search), /admin/users/[id] detail. - src/actions/admin-users.ts: staff-gated server actions wiring the user editor to the existing services — giveCurrency (RCON or DB fallback), setMotto/setRank (DB + RCON), alertUser, disconnectUser. Verified: tsc exit 0, vitest 45/45, next build exit 0 (/admin routes).
This commit is contained in:
1 parent
d9a8ce532f
commit
9f81096f05
10 files changed
+334
-3
No files matched your search
@@ -0,0 +1,33 @@
|
||||
import { prisma } from "@/lib/prisma";
|
||||
|
||||
export const dynamic = "force-dynamic";
|
||||
|
||||
export default async function AdminDashboard() {
|
||||
const [users, online, articles] = await Promise.all([
|
||||
prisma.user.count(),
|
||||
prisma.user.count({ where: { online: "1" } }),
|
||||
prisma.websiteArticles.count(),
|
||||
]);
|
||||
|
||||
const stats = [
|
||||
{ label: "Users", value: users },
|
||||
{ label: "Online now", value: online },
|
||||
{ label: "Articles", value: articles },
|
||||
];
|
||||
|
||||
return (
|
||||
<main>
|
||||
<h1>Dashboard</h1>
|
||||
<div className="grid cols-2">
|
||||
{stats.map((s) => (
|
||||
<div key={s.label} className="card">
|
||||
<h2 style={{ margin: 0 }}>{s.value}</h2>
|
||||
<p className="muted" style={{ margin: 0 }}>
|
||||
{s.label}
|
||||
</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user