import { useEffect, useState } from 'react' import { useI18n } from '../i18n' import { localizeError } from '../utils/errors' import { Button, Field, Callout, Spinner } from '../components/ui' import { PasskeyEnvWarnings, OpenInNewTabBanner } from '../components/d2' import { PasskeyCancelled, PasskeyUnsupported } from '../auth/passkey' import { signIn, demoQuickSession, getIdentityStatus } from '../api/identity' type Busy = 'passkey' | 'handle' | 'demo' | null type Msg = { tone: 'ok' | 'bad' | 'info'; text: string } | null export function D2SignInPage({ onNav }: { onNav: (r: string) => void }) { const { t } = useI18n() const [busy, setBusy] = useState(null) const [msg, setMsg] = useState(null) const [showHandle, setShowHandle] = useState(false) const [handle, setHandle] = useState('') const [demoOpen, setDemoOpen] = useState(false) useEffect(() => { let alive = true // Tolerate a mocked/absent status call (undefined return) as well as a 404 (D2/demo off). Promise.resolve(getIdentityStatus?.()) .then((s) => { if (alive && s) setDemoOpen(!!s.demo_open_enroll) }) .catch(() => {}) return () => { alive = false } }, []) async function runDemo(role: 'customer' | 'operator' = 'customer') { setBusy('demo'); setMsg(null) try { // No-passkey demo session: works in the HF iframe and on any device (no WebAuthn). const r = await demoQuickSession(role) setMsg({ tone: 'ok', text: t('d2.signin.success', { name: r.account.display_alias }) }) onNav(role === 'operator' ? 'id/operator' : 'finance') } catch (e) { setMsg({ tone: 'bad', text: localizeError(e, t, 'd2.signin.error') }) } finally { setBusy(null) } } async function run(which: 'passkey' | 'handle') { if (which === 'handle' && !handle.trim()) { setMsg({ tone: 'info', text: t('d2.signin.needHandle') }); return } setBusy(which); setMsg(null) try { const r = await signIn(which === 'handle' ? handle.trim() : undefined) setMsg({ tone: 'ok', text: t('d2.signin.success', { name: r.account.display_alias }) }) onNav('id/account') } catch (e) { if (e instanceof PasskeyUnsupported) setMsg({ tone: 'info', text: t('d2.unsupported') }) else if (e instanceof PasskeyCancelled) setMsg({ tone: 'info', text: t('d2.cancelled') }) else setMsg({ tone: 'bad', text: localizeError(e, t, 'd2.signin.error') }) } finally { setBusy(null) } } return (

{t('d2.signin.title')}

{t('d2.signin.intro')}

{demoOpen && (
{t('d2.signin.demoTitle')} {t('d2.signin.demoHint')}
)}
{t('d2.signin.withPasskey')}

{showHandle && ( <> setHandle(e.target.value)} autoComplete="username" />

{t('d2.signin.handleHint')}

)}

{busy ? t('d2.working') : ''}

{msg && {msg.text}}
) }