feat: email+password auth with db-backed sessions
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.7
parent
692ffa97c5
commit
5f8746cfae
@@ -0,0 +1,21 @@
|
||||
"use client";
|
||||
import { useActionState } from "react";
|
||||
|
||||
export type FormResult = { ok?: boolean; error?: string } | null;
|
||||
|
||||
export function AuthForm({ action, submit, fields }: {
|
||||
action: (state: FormResult, fd: FormData) => Promise<FormResult>;
|
||||
submit: string;
|
||||
fields: { name: string; label: string; type: string; autoComplete?: string; help?: string }[];
|
||||
}) {
|
||||
const [state, formAction, pending] = useActionState<FormResult, FormData>(action, null);
|
||||
return <form action={formAction} className="card" style={{ display: "grid", gap: "var(--qai-space-md)" }}>
|
||||
{fields.map((f) => <div key={f.name} style={{ display: "grid", gap: "var(--qai-space-xs)" }}>
|
||||
<label className="label" htmlFor={f.name}>{f.label}</label>
|
||||
<input className="field" id={f.name} name={f.name} type={f.type} autoComplete={f.autoComplete} required />
|
||||
{f.help && <span style={{ fontSize: "var(--qai-text-xs)", color: "var(--qai-ink-muted)" }}>{f.help}</span>}
|
||||
</div>)}
|
||||
{state && !state.ok && <p role="alert" style={{ color: "var(--qai-danger)" }}>{state.error}</p>}
|
||||
<button className="btn btn-primary" disabled={pending}>{submit}</button>
|
||||
</form>;
|
||||
}
|
||||
Reference in New Issue
Block a user