Add register + logout auth flows, and batch-5 resources

Auth (hand-built, uses the auth core):
- /register + register() action: validates, hashes with argon2id (hashPassword),
  creates an emulator-compatible users row (accountCreated/ipRegister/ipCurrent/
  look), redirect kept outside try so NEXT_REDIRECT propagates. Login/register
  cross-links; header shows Register (logged-out) and a Logout (signOut) button.

Batch 5 (parallel agents): /admin/rooms (+[id]) search+detail, /admin/vouchers
(CRUD), /admin/subscriptions (read), /admin/calendar (campaigns+rewards read),
/marketplace (public). Header + admin nav extended.

Verified: tsc exit 0, vitest 48/48, next build exit 0 (52 page routes).
This commit is contained in:
2026-06-28 13:52:32 +02:00
parent e8be0461d8
commit 08a9882be8
13 changed files with 1001 additions and 4 deletions
+43
View File
@@ -0,0 +1,43 @@
import Link from "next/link";
import { register } from "@/actions/register";
export default async function RegisterPage({
searchParams,
}: {
searchParams: Promise<{ error?: string }>;
}) {
const { error } = await searchParams;
return (
<main style={{ maxWidth: 400, margin: "2rem auto" }}>
<div className="card" style={{ padding: "1.75rem" }}>
<h1 style={{ marginTop: 0, textAlign: "center" }}>Create account</h1>
<p className="muted" style={{ textAlign: "center", marginTop: 0 }}>
Join the hotel — it only takes a moment.
</p>
<form action={register} style={{ display: "grid", gap: "0.7rem", marginTop: "1rem" }}>
<input name="username" placeholder="Username" autoComplete="username" required />
<input name="mail" type="email" placeholder="Email" autoComplete="email" required />
<input
name="password"
type="password"
placeholder="Password (min 6 chars)"
autoComplete="new-password"
required
/>
<button type="submit" className="btn btn-primary">
Register
</button>
</form>
{error ? (
<p style={{ color: "var(--color-danger)", textAlign: "center", marginBottom: 0 }}>
{error}
</p>
) : null}
<p className="muted" style={{ textAlign: "center", marginBottom: 0, marginTop: "1rem" }}>
Already have an account? <Link href="/login">Sign in</Link>
</p>
</div>
</main>
);
}