Add user management

This commit is contained in:
2026-01-01 18:34:02 +01:00
parent 2fcf19c0df
commit 36fb2358dd
26 changed files with 1047 additions and 56 deletions

View File

@ -0,0 +1,24 @@
import { CreateUserForm } from "@/components/users/CreateUserForm";
import { auth } from "@/lib/auth";
import { headers } from "next/headers";
import { redirect } from "next/navigation";
export default async function NewUserPage() {
const session = await auth.api.getSession({ headers: await headers() });
const role = (session as any)?.user?.role;
if (!session) redirect("/login");
if (role !== "admin") redirect("/");
return (
<div className="mx-auto max-w-md p-6">
<h1 className="text-xl font-semibold">Create user</h1>
<p className="mt-1 text-sm text-muted-foreground">
Create a new user account (registration is disabled publicly).
</p>
<div className="mt-6">
<CreateUserForm />
</div>
</div>
);
}

View File

@ -0,0 +1,27 @@
import { UsersTable } from "@/components/users/UsersTable";
import { auth } from "@/lib/auth";
import { headers } from "next/headers";
import { redirect } from "next/navigation";
export default async function UsersPage() {
const session = await auth.api.getSession({ headers: await headers() });
const role = (session as any)?.user?.role as string | undefined;
if (!session) redirect("/login");
if (role !== "admin") redirect("/");
return (
<div className="mx-auto max-w-5xl p-6 space-y-6">
<div className="flex items-end justify-between gap-4">
<div className="space-y-1">
<h1 className="text-2xl font-semibold tracking-tight">Users</h1>
<p className="text-sm text-muted-foreground">
Manage admin accounts and staff users.
</p>
</div>
</div>
<UsersTable />
</div>
);
}

View File

@ -0,0 +1,15 @@
import { ForgotPasswordForm } from "@/components/auth/ForgotPasswordForm";
export default function ForgotPasswordPage() {
return (
<div className="mx-auto max-w-md p-6">
<h1 className="text-xl font-semibold">Forgot password</h1>
<p className="mt-1 text-sm text-muted-foreground">
Enter your email and well send you a reset link.
</p>
<div className="mt-6">
<ForgotPasswordForm />
</div>
</div>
);
}

View File

@ -0,0 +1,20 @@
import { RegisterForm } from "@/components/auth/RegisterForm";
import { prisma } from "@/lib/prisma";
import { redirect } from "next/navigation";
export default async function RegisterPage() {
const count = await prisma.user.count();
if (count !== 0) redirect("/login");
return (
<div className="mx-auto max-w-md p-6">
<h1 className="text-xl font-semibold">Create admin account</h1>
<p className="mt-1 text-sm text-muted-foreground">
This is only available until the first user is created.
</p>
<div className="mt-6">
<RegisterForm />
</div>
</div>
);
}

View File

@ -0,0 +1,19 @@
import { ResetPasswordForm } from "@/components/auth/ResetPasswordForm";
export default function ResetPasswordPage({
searchParams,
}: {
searchParams: { token?: string };
}) {
return (
<div className="mx-auto max-w-md p-6">
<h1 className="text-xl font-semibold">Reset password</h1>
<p className="mt-1 text-sm text-muted-foreground">
Choose a new password.
</p>
<div className="mt-6">
<ResetPasswordForm token={searchParams.token ?? ""} />
</div>
</div>
);
}