Initial commit of Vellum, an event photo product for guest uploads, host moderation, and original-quality galleries.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,98 @@
|
||||
import { createServerCaller } from "@/trpc/server";
|
||||
import { getPlatformRole } from "@/server/roles";
|
||||
import { auth } from "@/server/auth";
|
||||
import { headers } from "next/headers";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
CardDescription,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
} from "@/components/ui/card";
|
||||
import { PlatformUsers } from "./platform-users";
|
||||
import { PlatformCodes } from "./platform-codes";
|
||||
|
||||
export default async function AdminPage() {
|
||||
const session = await auth.api.getSession({ headers: await headers() });
|
||||
const role = session ? await getPlatformRole(session.user.id) : null;
|
||||
const caller = await createServerCaller();
|
||||
const [groups, events, audit] = await Promise.all([
|
||||
caller.platform.groups(),
|
||||
caller.platform.events(),
|
||||
caller.platform.audit(),
|
||||
]);
|
||||
const canManageUsers = role === "super_admin" || role === "admin";
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-8">
|
||||
<div>
|
||||
<h1 className="text-4xl font-semibold tracking-tight">Platform</h1>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
Full access for deployment operators.
|
||||
</p>
|
||||
</div>
|
||||
<div className="grid gap-4 md:grid-cols-2">
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Groups</CardTitle>
|
||||
<CardDescription>{groups.length} groups</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className="flex flex-col gap-2 text-sm">
|
||||
{groups.map((group) => (
|
||||
<div key={group.id} className="flex justify-between gap-3">
|
||||
<span>{group.name}</span>
|
||||
<span className="text-muted-foreground">
|
||||
{group.quota.unlimited
|
||||
? "unlimited"
|
||||
: `${group.quota.used}/${group.quota.eventLimit ?? 0}`}
|
||||
{group.quota.complimentary ? " · comp" : ""}
|
||||
</span>
|
||||
</div>
|
||||
))}
|
||||
</CardContent>
|
||||
</Card>
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Events</CardTitle>
|
||||
<CardDescription>{events.length} events</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className="flex flex-col gap-2 text-sm">
|
||||
{events.map((event) => (
|
||||
<div key={event.id} className="flex justify-between gap-3">
|
||||
<span>{event.title}</span>
|
||||
<div className="flex gap-1">
|
||||
<Badge variant="secondary">{event.status}</Badge>
|
||||
{event.listed ? <Badge variant="outline">listed</Badge> : null}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
{canManageUsers ? <PlatformUsers /> : null}
|
||||
{canManageUsers ? (
|
||||
<PlatformCodes groups={groups.map((group) => ({ id: group.id, name: group.name }))} />
|
||||
) : null}
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Audit</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<ul className="flex flex-col gap-2 text-sm">
|
||||
{audit.slice(0, 40).map((row) => (
|
||||
<li key={row.id} className="flex justify-between gap-3">
|
||||
<span>
|
||||
{row.action} · {row.subjectType}
|
||||
</span>
|
||||
<span className="text-muted-foreground">
|
||||
{new Date(row.createdAt).toLocaleString()}
|
||||
</span>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user