"use client"; import { useEffect, useState } from "react"; import { useRouter } from "next/navigation"; import { formatMessage } from "@/lib/i18n/shared"; import PasskeyManager from "@/components/PasskeyManager"; import { useDict } from "@/components/i18n/LocaleProvider"; function errorMessage( dict: ReturnType, code: string, fallback: string ): string { if (code === "wrong_password") return dict.account.wrongCurrentPassword; if (code === "email_used") return dict.account.emailAlreadyUsed; if (code === "needs_passkey") return dict.account.passwordAuthNeedsPasskey; return fallback; } export default function AccountManager({ role, initialFullName, initialEmail, initialPasswordAuthEnabled, }: { role: string; initialFullName: string; initialEmail: string; initialPasswordAuthEnabled: boolean; }) { const router = useRouter(); const dict = useDict(); const roleLabel = role === "admin" ? dict.common.roleAdmin : dict.common.roleStaff; // Persönliche Daten const [fullName, setFullName] = useState(initialFullName); const [nameError, setNameError] = useState(null); const [nameInfo, setNameInfo] = useState(null); const [nameBusy, setNameBusy] = useState(false); // E-Mail-Adresse const [email, setEmail] = useState(initialEmail); const [emailPassword, setEmailPassword] = useState(""); const [emailError, setEmailError] = useState(null); const [emailInfo, setEmailInfo] = useState(null); const [emailBusy, setEmailBusy] = useState(false); // Passwort const [currentPassword, setCurrentPassword] = useState(""); const [newPassword, setNewPassword] = useState(""); const [newPasswordRepeat, setNewPasswordRepeat] = useState(""); const [pwError, setPwError] = useState(null); const [pwInfo, setPwInfo] = useState(null); const [pwBusy, setPwBusy] = useState(false); // Passwort-Anmeldung an/aus const [passwordAuthEnabled, setPasswordAuthEnabled] = useState( initialPasswordAuthEnabled ); const [passkeyCount, setPasskeyCount] = useState(null); const [authError, setAuthError] = useState(null); const [authInfo, setAuthInfo] = useState(null); const [authBusy, setAuthBusy] = useState(false); useEffect(() => { fetch("/api/auth/passkeys") .then((res) => (res.ok ? res.json() : [])) .then((data) => setPasskeyCount(data.length)); }, []); async function saveName(e: React.FormEvent) { e.preventDefault(); setNameError(null); setNameInfo(null); const name = fullName.trim(); if (!name) { setNameError(dict.account.nameRequired); return; } setNameBusy(true); const res = await fetch("/api/account", { method: "PATCH", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ full_name: name }), }); if (!res.ok) { const data = await res.json().catch(() => ({})); setNameError( formatMessage(dict.account.saveError, { message: errorMessage(dict, data.error, data.error ?? String(res.status)), }) ); } else { setNameInfo(dict.account.nameSaved); router.refresh(); } setNameBusy(false); } async function saveEmail(e: React.FormEvent) { e.preventDefault(); setEmailError(null); setEmailInfo(null); const next = email.trim(); if (!next || next === initialEmail) return; setEmailBusy(true); const res = await fetch("/api/account/email", { method: "PATCH", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ email: next, password: emailPassword }), }); if (!res.ok) { const data = await res.json().catch(() => ({})); setEmailError( formatMessage(dict.account.changeError, { message: errorMessage(dict, data.error, data.error ?? String(res.status)), }) ); } else { setEmailInfo(dict.account.emailChanged); setEmailPassword(""); router.refresh(); } setEmailBusy(false); } async function savePassword(e: React.FormEvent) { e.preventDefault(); setPwError(null); setPwInfo(null); if (newPassword.length < 8) { setPwError(dict.account.passwordTooShort); return; } if (newPassword !== newPasswordRepeat) { setPwError(dict.account.passwordMismatch); return; } setPwBusy(true); const res = await fetch("/api/account/password", { method: "PATCH", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ currentPassword, newPassword }), }); if (!res.ok) { const data = await res.json().catch(() => ({})); setPwError( formatMessage(dict.account.changeError, { message: errorMessage(dict, data.error, data.error ?? String(res.status)), }) ); } else { setPwInfo(dict.account.passwordChanged); setCurrentPassword(""); setNewPassword(""); setNewPasswordRepeat(""); } setPwBusy(false); } async function togglePasswordAuth() { setAuthError(null); setAuthInfo(null); const next = !passwordAuthEnabled; if (!next && (passkeyCount ?? 0) === 0) { setAuthError(dict.account.passwordAuthNeedsPasskey); return; } if (!next && !window.confirm(dict.account.confirmDisablePasswordAuth)) return; setAuthBusy(true); const res = await fetch("/api/account", { method: "PATCH", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ password_auth_enabled: next }), }); if (!res.ok) { const data = await res.json().catch(() => ({})); setAuthError( formatMessage(dict.account.saveError, { message: errorMessage(dict, data.error, data.error ?? String(res.status)), }) ); } else { setPasswordAuthEnabled(next); setAuthInfo( next ? dict.account.passwordAuthEnabled : dict.account.passwordAuthDisabled ); } setAuthBusy(false); } return (

{dict.account.title}

{initialEmail} – {roleLabel}

{dict.account.personalTitle}

setFullName(e.target.value)} required />
{nameError && (

{nameError}

)} {nameInfo &&

{nameInfo}

}

{dict.account.emailTitle}

setEmail(e.target.value)} required />
setEmailPassword(e.target.value)} autoComplete="current-password" required />
{emailError && (

{emailError}

)} {emailInfo &&

{emailInfo}

}

{dict.account.passwordTitle}

setCurrentPassword(e.target.value)} autoComplete="current-password" required />
setNewPassword(e.target.value)} autoComplete="new-password" minLength={8} required />
setNewPasswordRepeat(e.target.value)} autoComplete="new-password" minLength={8} required />
{pwError && (

{pwError}

)} {pwInfo &&

{pwInfo}

}

{dict.account.passwordAuthTitle}

{dict.account.passwordAuthHint}

{authError && (

{authError}

)} {authInfo &&

{authInfo}

}
); }