Stand vor Einführung des Nacht-Agenten
This commit is contained in:
commit
4763548bfb
168 changed files with 12726 additions and 0 deletions
45
apps/web/src/app/login/page.tsx
Normal file
45
apps/web/src/app/login/page.tsx
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
'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>
|
||||
);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue