'use client'; import { useActionState, useState } from 'react'; import { startAuthentication } from '@simplewebauthn/browser'; import { login } from './actions'; import packageJson from '@/package.json'; export default function LoginPage() { const [state, loginAction, isPending] = useActionState(login, undefined); const [showPassword, setShowPassword] = useState(false); const [passkeyBusy, setPasskeyBusy] = useState(false); const [passkeyError, setPasskeyError] = useState(null); async function handlePasskeyLogin() { setPasskeyError(null); setPasskeyBusy(true); try { const optRes = await fetch('/api/passkey/authenticate'); if (!optRes.ok) throw new Error('Optionen konnten nicht geladen werden.'); const optionsJSON = await optRes.json(); const response = await startAuthentication({ optionsJSON }); const verifyRes = await fetch('/api/passkey/authenticate', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ response }), }); if (!verifyRes.ok) { const data = await verifyRes.json().catch(() => null); throw new Error(data?.error ?? 'Anmeldung mit Passkey fehlgeschlagen.'); } window.location.href = '/'; } catch (err) { // Abbruch durch Nutzer (NotAllowedError) nicht als Fehler anzeigen. if (err instanceof Error && err.name === 'NotAllowedError') { setPasskeyError(null); } else { setPasskeyError(err instanceof Error ? err.message : 'Anmeldung mit Passkey fehlgeschlagen.'); } } finally { setPasskeyBusy(false); } } const version = packageJson.version; const buildDate = process.env.NEXT_PUBLIC_BUILD_DATE || new Date().toLocaleDateString('de-DE', { day: '2-digit', month: '2-digit', year: 'numeric' }); return (

Werte - Log

Anmeldung

{state?.error && (
{state.error}
)}
oder
{passkeyError && (
{passkeyError}
)}
{/* Footer */}
); }