"use client"; import { useEffect, useState } from "react"; import { useRouter } from "next/navigation"; type InviteInfo = { email: string; role: string; org: { id: string; name: string; slug: string }; expiresAt: string; }; export default function InviteAcceptForm({ token }: { token: string }) { const router = useRouter(); const [invite, setInvite] = useState(null); const [loading, setLoading] = useState(true); const [submitting, setSubmitting] = useState(false); const [error, setError] = useState(null); const [name, setName] = useState(""); const [password, setPassword] = useState(""); useEffect(() => { let alive = true; async function loadInvite() { setLoading(true); setError(null); try { const res = await fetch(`/api/invites/${token}`, { cache: "no-store" }); const data = await res.json().catch(() => ({})); if (!res.ok || !data.ok) { throw new Error(data.error || "Invite not found"); } if (alive) setInvite(data.invite); } catch (err: any) { if (alive) setError(err?.message || "Invite not found"); } finally { if (alive) setLoading(false); } } loadInvite(); return () => { alive = false; }; }, [token]); async function onSubmit(e: React.FormEvent) { e.preventDefault(); setError(null); setSubmitting(true); try { const res = await fetch(`/api/invites/${token}`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ name, password }), }); const data = await res.json().catch(() => ({})); if (!res.ok || !data.ok) { throw new Error(data.error || "Invite acceptance failed"); } router.push("/machines"); router.refresh(); } catch (err: any) { setError(err?.message || "Invite acceptance failed"); } finally { setSubmitting(false); } } if (loading) { return (
Loading invite...
); } if (!invite) { return (
{error || "Invite not found."}
); } return (

Join {invite.org.name}

Accept the invite for {invite.email} as {invite.role}.

setName(e.target.value)} autoComplete="name" />
setPassword(e.target.value)} autoComplete="new-password" />
{error &&
{error}
}
); }