import { useState } from 'react' import { useNavigate, useSearchParams } from 'react-router-dom' import { Loader2, ShieldCheck } from 'lucide-react' import { authApi, type EnrollResult } from '../lib/auth' import { useAuth } from '../lib/useAuth' type Step = 'set' | 'enroll' // AcceptInvite handles an authority bounded invite link (/accept?token=...): set a password, then enroll // the mandatory TOTP. On an active session it navigates to the app. export function AcceptInvite() { const { refresh } = useAuth() const nav = useNavigate() const [params] = useSearchParams() const token = params.get('token') ?? '' const [step, setStep] = useState('set') const [password, setPassword] = useState('') const [confirm, setConfirm] = useState('') const [code, setCode] = useState('') const [enroll, setEnroll] = useState(null) const [err, setErr] = useState('') const [busy, setBusy] = useState(false) async function onSet(e: React.FormEvent) { e.preventDefault() setErr('') if (password.length < 8) { setErr('Use at least 8 characters.') return } if (password !== confirm) { setErr('Passwords do not match.') return } setBusy(true) try { const r = await authApi.inviteAccept(token, password) if (!r.mfa_required) { // MFA is disabled for this pilot: the account is active after setting a password, go straight in. await refresh() nav('/') return } setEnroll(await authApi.mfaEnroll()) setStep('enroll') } catch { setErr('This invite link is invalid or expired.') } finally { setBusy(false) } } async function onActivate(e: React.FormEvent) { e.preventDefault() setErr('') setBusy(true) try { await authApi.mfaActivate(code.trim()) await refresh() nav('/') } catch { setErr('Invalid code. Make sure your authenticator time is correct.') setBusy(false) } } if (!token) { return (

This invite link is missing its token.

) } return (
missionMATCH
{step === 'set' && (

Accept your invitation

Set a password to create your account.

{err &&

{err}

} )} {step === 'enroll' && enroll && (

Set up two factor authentication

Add this account to your authenticator app, then enter the code.

Setup key
{enroll.secret}
Open in authenticator
{err &&

{err}

} )}
) } function Input({ label, value, onChange, type = 'text', autoFocus, maxLength, }: { label: string value: string onChange: (v: string) => void type?: string autoFocus?: boolean maxLength?: number }) { return ( ) } function Go({ busy, label }: { busy: boolean; label: string }) { return ( ) }