"use client"; import { useState } from "react"; import { useRouter } from "next/navigation"; import Link from "next/link"; import { startAuthentication } from "@simplewebauthn/browser"; import { formatMessage } from "@/lib/i18n/shared"; import { useDict } from "@/components/i18n/LocaleProvider"; import LanguageSwitcher from "@/components/i18n/LanguageSwitcher"; import type { Dict } from "@/lib/i18n/shared"; function authErrorMessage(dict: Dict, code: string): string { if (code === "invalid_credentials") return dict.login.errorInvalidCredentials; if (code === "password_disabled") return dict.login.errorPasswordDisabled; if (code === "oidc_invalid_state") return dict.login.errorOidcInvalidState; if (code === "oidc_unknown_user") return dict.login.errorOidcUnknownUser; if (code === "oidc_failed") return dict.login.errorOidcFailed; if (/cancelled|aborted|NotAllowedError/i.test(code)) return dict.login.errorPasskeyCancelled; return formatMessage(dict.login.errorGeneric, { message: code }); } function redirectPath(role: string): string { return role === "admin" ? "/admin" : "/intern"; } export default function LoginForm({ oidcEnabled, initialError, }: { oidcEnabled: boolean; initialError: string | null; }) { const router = useRouter(); const dict = useDict(); const [email, setEmail] = useState(""); const [password, setPassword] = useState(""); const [error, setError] = useState(() => initialError ? authErrorMessage(dict, initialError) : null ); const [busy, setBusy] = useState(false); async function signInWithPassword(e: React.FormEvent) { e.preventDefault(); setError(null); setBusy(true); const res = await fetch("/api/auth/login", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ email, password }), }); const data = await res.json().catch(() => ({})); if (!res.ok) { setError(authErrorMessage(dict, data.error ?? "unknown")); setBusy(false); return; } router.replace(redirectPath(data.role)); router.refresh(); } async function signInWithPasskey() { setError(null); setBusy(true); try { const optionsRes = await fetch("/api/auth/passkeys/login-options", { method: "POST" }); const options = await optionsRes.json(); const response = await startAuthentication({ optionsJSON: options }); const verifyRes = await fetch("/api/auth/passkeys/login-verify", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ response }), }); const data = await verifyRes.json().catch(() => ({})); if (!verifyRes.ok) { setError(authErrorMessage(dict, data.error ?? "unknown")); setBusy(false); return; } router.replace(redirectPath(data.role)); router.refresh(); } catch (err) { setError(authErrorMessage(dict, err instanceof Error ? err.message : String(err))); setBusy(false); } } return (

{dict.login.title}

setEmail(e.target.value)} autoComplete="username webauthn" required />
setPassword(e.target.value)} autoComplete="current-password" required />
{error &&

{error}

}
{dict.login.or}
{oidcEnabled && ( {dict.login.ssoButton} )}

{dict.login.backToMenu}

); }