Rollen Chunk 4: Benutzerkonto, Abmelde-Icon und fremde Einstellungen
Docker Image / test (push) Canceled after 0s
Docker Image / image (push) Canceled after 0s

This commit is contained in:
loki committed 2026-10-11 19:14:06 +02:00
1 parent 34cb089406
commit 472738b0d6
1 file changed
+132
+132
View File
@@ -0,0 +1,132 @@
"use client";
import { useState } from "react";
import { ApiError } from "@/lib/api-client";
import { changeEmail, changePassword } from "@/lib/auth-client";
export function AccountSection({
email,
onEmailChanged,
}: {
email: string;
onEmailChanged?: (email: string) => void;
}) {
const [currentPassword, setCurrentPassword] = useState("");
const [newPassword, setNewPassword] = useState("");
const [newEmail, setNewEmail] = useState("");
const [busy, setBusy] = useState(false);
const [passwordMessage, setPasswordMessage] = useState<string | null>(null);
const [passwordError, setPasswordError] = useState<string | null>(null);
const [emailMessage, setEmailMessage] = useState<string | null>(null);
const [emailError, setEmailError] = useState<string | null>(null);
async function submitPassword(event: React.FormEvent) {
event.preventDefault();
setBusy(true);
setPasswordMessage(null);
setPasswordError(null);
try {
await changePassword(currentPassword, newPassword);
setCurrentPassword("");
setNewPassword("");
setPasswordMessage("Passwort geändert.");
} catch (passwordFailure) {
if (passwordFailure instanceof ApiError && passwordFailure.status === 400) {
setPasswordError("Aktuelles Passwort falsch.");
} else {
setPasswordError(
passwordFailure instanceof Error
? passwordFailure.message
: "Passwortwechsel fehlgeschlagen.",
);
}
} finally {
setBusy(false);
}
}
async function submitEmail(event: React.FormEvent) {
event.preventDefault();
setBusy(true);
setEmailMessage(null);
setEmailError(null);
try {
await changeEmail(newEmail.trim());
setEmailMessage("E-Mail geändert.");
setNewEmail("");
onEmailChanged?.(newEmail.trim());
} catch (emailFailure) {
setEmailError(
emailFailure instanceof Error
? emailFailure.message
: "E-Mail-Wechsel fehlgeschlagen.",
);
} finally {
setBusy(false);
}
}
return (
<section aria-label="Benutzerkonto">
<h2>Benutzerkonto</h2>
<p>
Angemeldet als <strong>{email}</strong>.
</p>
<form onSubmit={submitPassword} aria-label="Passwort ändern">
<h3>Passwort ändern</h3>
<label>
Aktuelles Passwort
<input
type="password"
autoComplete="current-password"
value={currentPassword}
onChange={(event) => setCurrentPassword(event.target.value)}
required
/>
</label>
<label>
Neues Passwort
<input
type="password"
autoComplete="new-password"
value={newPassword}
onChange={(event) => setNewPassword(event.target.value)}
required
/>
</label>
<button type="submit" className="btn-primary" disabled={busy}>
Passwort ändern
</button>
</form>
{passwordMessage && <p className="form-message">{passwordMessage}</p>}
{passwordError && (
<p role="alert" className="form-error">
{passwordError}
</p>
)}
<form onSubmit={submitEmail} aria-label="E-Mail ändern">
<h3>E-Mail ändern</h3>
<p className="muted-note">Gilt sofort, ohne Bestätigungs-E-Mail.</p>
<label>
Neue E-Mail
<input
type="email"
autoComplete="email"
value={newEmail}
onChange={(event) => setNewEmail(event.target.value)}
required
/>
</label>
<button type="submit" className="btn-primary" disabled={busy}>
E-Mail ändern
</button>
</form>
{emailMessage && <p className="form-message">{emailMessage}</p>}
{emailError && (
<p role="alert" className="form-error">
{emailError}
</p>
)}
</section>
);
}