"use client"; import { useEffect, useMemo, useState } from "react"; import { useRouter } from "next/navigation"; import { createClient } from "@/lib/supabase/client"; import PasskeyManager from "@/components/PasskeyManager"; const ROLE_LABELS: Record = { admin: "Administrator", staff: "Kantinenmitarbeiter", }; function germanAuthError(message: string): string { if (/invalid login credentials/i.test(message)) return "Das aktuelle Passwort ist falsch."; if (/should be at least/i.test(message)) return "Das neue Passwort ist zu kurz (mindestens 8 Zeichen)."; if (/email.*already|already.*registered/i.test(message)) return "Diese E-Mail-Adresse wird bereits verwendet."; return message; } export default function AccountManager({ role, initialFullName, initialEmail, initialPasswordAuthEnabled, }: { role: string; initialFullName: string; initialEmail: string; initialPasswordAuthEnabled: boolean; }) { const supabase = useMemo(() => createClient(), []); const router = useRouter(); // 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 [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(() => { supabase.auth.passkey .list() .then(({ data }) => setPasskeyCount((data ?? []).length)); }, [supabase]); async function saveName(e: React.FormEvent) { e.preventDefault(); setNameError(null); setNameInfo(null); const name = fullName.trim(); if (!name) { setNameError("Bitte einen Namen angeben."); return; } setNameBusy(true); const { error } = await supabase .from("profiles") .update({ full_name: name }) .eq("id", (await supabase.auth.getUser()).data.user?.id ?? ""); if (error) setNameError(`Speichern fehlgeschlagen: ${error.message}`); else { setNameInfo("Name gespeichert."); 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 { error } = await supabase.auth.updateUser({ email: next }); if (error) { setEmailError(`Ändern fehlgeschlagen: ${germanAuthError(error.message)}`); } else { setEmailInfo( "Bestätigungs-E-Mails wurden verschickt. Die neue Adresse wird erst nach Bestätigung des Links aktiv." ); } setEmailBusy(false); } async function savePassword(e: React.FormEvent) { e.preventDefault(); setPwError(null); setPwInfo(null); if (newPassword.length < 8) { setPwError("Das neue Passwort muss mindestens 8 Zeichen lang sein."); return; } if (newPassword !== newPasswordRepeat) { setPwError("Die Passwörter stimmen nicht überein."); return; } setPwBusy(true); // Zur Verifizierung: aktuelles Passwort gegenprüfen, bevor geändert wird. const { error: verifyError } = await supabase.auth.signInWithPassword({ email: initialEmail, password: currentPassword, }); if (verifyError) { setPwError(germanAuthError(verifyError.message)); setPwBusy(false); return; } const { error } = await supabase.auth.updateUser({ password: newPassword }); if (error) { setPwError(`Ändern fehlgeschlagen: ${germanAuthError(error.message)}`); } else { setPwInfo("Passwort geändert."); setCurrentPassword(""); setNewPassword(""); setNewPasswordRepeat(""); } setPwBusy(false); } async function togglePasswordAuth() { setAuthError(null); setAuthInfo(null); const next = !passwordAuthEnabled; if (!next && (passkeyCount ?? 0) === 0) { setAuthError( "Ohne registrierten Passkey kannst du die Passwort-Anmeldung nicht deaktivieren – sonst wärst du ausgesperrt. Registriere zuerst einen Passkey weiter unten." ); return; } if ( !next && !window.confirm( "Anmeldung mit E-Mail und Passwort wirklich deaktivieren? Du kannst dich danach nur noch per Passkey anmelden." ) ) return; setAuthBusy(true); const { error } = await supabase .from("profiles") .update({ password_auth_enabled: next }) .eq("id", (await supabase.auth.getUser()).data.user?.id ?? ""); if (error) { setAuthError(`Speichern fehlgeschlagen: ${error.message}`); } else { setPasswordAuthEnabled(next); setAuthInfo( next ? "Passwort-Anmeldung aktiviert." : "Passwort-Anmeldung deaktiviert." ); } setAuthBusy(false); } return (

Mein Konto

{initialEmail} – {ROLE_LABELS[role] ?? role}

Persönliche Daten

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

{nameError}

)} {nameInfo &&

{nameInfo}

}

E-Mail-Adresse

setEmail(e.target.value)} required />
{emailError && (

{emailError}

)} {emailInfo &&

{emailInfo}

}

Passwort ändern

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}

}

Anmeldung mit Passwort

Du kannst die Anmeldung mit E-Mail und Passwort für dein Konto deaktivieren und dich künftig ausschließlich per Passkey anmelden. Dafür muss mindestens ein Passkey registriert sein.

{authError && (

{authError}

)} {authInfo &&

{authInfo}

}
); }