kundencenter/apps/web/src/app/login/page.tsx
2026-09-27 00:51:32 +02:00

45 lines
2.4 KiB
TypeScript

'use client';
import { useEffect, useState, type FormEvent } from 'react';
import { useRouter } from 'next/navigation';
import Link from 'next/link';
import { api, errMsg, setCsrf } from '@/lib/api';
import { useSession } from '@/lib/session';
import { Alert, Field } from '@/components/ui';
export default function Login() {
const r = useRouter(); const { me, reload } = useSession();
const [step, setStep] = useState<'pw' | 'mfa'>('pw');
const [err, setErr] = useState(''); const [busy, setBusy] = useState(false);
useEffect(() => { if (me?.pendingMfa) setStep('mfa'); else if (me) r.replace('/dashboard'); }, [me, r]);
async function submit(e: FormEvent<HTMLFormElement>) {
e.preventDefault(); setErr(''); setBusy(true);
const f = new FormData(e.currentTarget);
try {
if (step === 'pw') {
const res = await api<{ status: string; csrf: string }>('POST', '/auth/login', { email: f.get('email'), password: f.get('password') });
setCsrf(res.csrf);
if (res.status === 'mfa_required') { await reload(); setStep('mfa'); } else { await reload(); r.replace('/dashboard'); }
} else {
await api('POST', '/auth/mfa/verify', { code: f.get('code') });
await reload(); r.replace('/dashboard');
}
} catch (x) { setErr(errMsg(x)); } finally { setBusy(false); }
}
return (
<main id="main" className="center"><div className="auth card">
<h1>{step === 'pw' ? 'Anmelden' : 'Zweiter Faktor'}</h1>
{err && <Alert kind="err">{err}</Alert>}
<form onSubmit={submit}>
{step === 'pw' ? (<>
<Field id="email" label="E-Mail"><input id="email" name="email" type="email" autoComplete="username" required autoFocus /></Field>
<Field id="password" label="Passwort"><input id="password" name="password" type="password" autoComplete="current-password" required /></Field>
</>) : (
<Field id="code" label="Code aus der Authenticator-App" hint="Alternativ ein Wiederherstellungscode."><input id="code" name="code" inputMode="text" autoComplete="one-time-code" required autoFocus /></Field>
)}
<button className="btn primary" disabled={busy} type="submit">{busy ? 'Bitte warten …' : step === 'pw' ? 'Anmelden' : 'Bestätigen'}</button>
</form>
{step === 'pw' && <p className="small" style={{ marginTop: 16 }}><Link href="/passwort-vergessen">Passwort vergessen?</Link></p>}
</div></main>
);
}