"use client"; import { useState, use } from "react"; import { useRouter } from "next/navigation"; import { PASSWORD_MIN_LENGTH, PASSWORD_POLICY_MESSAGE } from "@nexus/shared"; import { trpc } from "~/lib/trpc/client.js"; export default function AcceptInvitePage({ params }: { params: Promise<{ token: string }> }) { const { token } = use(params); const router = useRouter(); const [password, setPassword] = useState(""); const [confirm, setConfirm] = useState(""); const [formError, setFormError] = useState(null); const [done, setDone] = useState(false); const { data: invite, isLoading, error: inviteError, } = trpc.invite.getInvite.useQuery({ token }, { retry: false }); const acceptMutation = trpc.invite.acceptInvite.useMutation({ onSuccess: () => setDone(true), onError: (err) => setFormError(err.message), }); async function handleSubmit(e: React.FormEvent) { e.preventDefault(); setFormError(null); if (password.length < PASSWORD_MIN_LENGTH) { setFormError(PASSWORD_POLICY_MESSAGE); return; } if (password !== confirm) { setFormError("Passwords do not match."); return; } await acceptMutation.mutateAsync({ token, password }); } if (isLoading) { return (

Loading…

); } if (inviteError || !invite) { return (
đź”—

Invite link invalid or expired

{inviteError?.message ?? "This invite link is no longer valid. Please request a new invitation from your administrator."}

); } if (done) { return (
âś…

Account created

Your account has been set up successfully.

); } return (

Accept invitation

You have been invited as {invite.role} to Nexus. Set a password to activate your account ({invite.email}).

{formError && (
{formError}
)}
setPassword(e.target.value)} required minLength={PASSWORD_MIN_LENGTH} placeholder={`At least ${PASSWORD_MIN_LENGTH} characters`} className="w-full rounded-lg border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-900 px-3 py-2 text-sm text-gray-900 dark:text-gray-100 focus:outline-none focus:ring-2 focus:ring-brand-400" />
setConfirm(e.target.value)} required placeholder="Repeat your password" className="w-full rounded-lg border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-900 px-3 py-2 text-sm text-gray-900 dark:text-gray-100 focus:outline-none focus:ring-2 focus:ring-brand-400" />
); }