Files
Epicure/apps/web/app/admin/invites/page.tsx
T
Arnaud e0e1ac49d9 feat: signup toggle, invite links, admin-created users
- New invites table: token-gated signup, optional email lock,
  role/tier override, single-use, expiry.
- SIGNUPS_DISABLED site setting toggle at /admin/settings.
- databaseHooks.user.create gate in auth/server.ts blocks new account
  creation (email + Google OAuth) when disabled unless a valid invite
  cookie is present; applies invite role/tier and marks it consumed.
- /admin/invites: create/list/revoke shareable invite links.
- /admin/users: "Create user" dialog — admin sets email/role/tier,
  account is pre-verified, user gets a set-password email (admin
  never sees a password).
- Signup page reads ?invite=, validates via public
  /api/v1/invites/[token], locks the form when signups are closed
  and no valid invite is present.
- proxy.ts: allowlist /api/v1/invites/ for anonymous invite checks.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-03 21:36:40 +02:00

35 lines
1.1 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import type { Metadata } from "next";
import { listInvites } from "@/lib/invites";
import { InvitesManager } from "@/components/admin/invites-manager";
export const metadata: Metadata = { title: "Invites Admin" };
export default async function AdminInvitesPage() {
const invites = await listInvites();
const appUrl = process.env["BETTER_AUTH_URL"] ?? "http://localhost:3000";
return (
<div className="space-y-6">
<div>
<h1 className="text-2xl font-bold tracking-tight">Invites</h1>
<p className="text-muted-foreground text-sm mt-1">
Generate shareable signup links. Required when signups are disabled in{" "}
<span className="font-medium">Settings</span>.
</p>
</div>
<InvitesManager
invites={invites.map((i) => ({
id: i.id,
token: i.token,
email: i.email,
role: i.role,
tier: i.tier,
createdAt: i.createdAt.toISOString(),
expiresAt: i.expiresAt?.toISOString() ?? null,
}))}
appUrl={appUrl}
/>
</div>
);
}