165 lines
5.3 KiB
TypeScript
165 lines
5.3 KiB
TypeScript
import { useState } from "react";
|
|
import { useMutation } from "@tanstack/react-query";
|
|
import { useAuth } from "@/client/components/auth-provider";
|
|
import { queryClient } from "@/client/rpc-client";
|
|
|
|
export function UserProfile() {
|
|
const { user, sessionId, logout } = useAuth();
|
|
const [showPasswordChange, setShowPasswordChange] = useState(false);
|
|
const [currentPassword, setCurrentPassword] = useState("");
|
|
const [newPassword, setNewPassword] = useState("");
|
|
const [confirmPassword, setConfirmPassword] = useState("");
|
|
const [message, setMessage] = useState("");
|
|
const [error, setError] = useState("");
|
|
|
|
const { mutate: changePassword, isPending } = useMutation(
|
|
queryClient.auth.changePassword.mutationOptions()
|
|
);
|
|
|
|
const handlePasswordChange = (e: React.FormEvent) => {
|
|
e.preventDefault();
|
|
setError("");
|
|
setMessage("");
|
|
|
|
if (newPassword !== confirmPassword) {
|
|
setError("Neue Passwörter stimmen nicht überein");
|
|
return;
|
|
}
|
|
|
|
if (newPassword.length < 6) {
|
|
setError("Neues Passwort muss mindestens 6 Zeichen lang sein");
|
|
return;
|
|
}
|
|
|
|
if (!sessionId) {
|
|
setError("Keine gültige Sitzung");
|
|
return;
|
|
}
|
|
|
|
changePassword({
|
|
sessionId,
|
|
currentPassword,
|
|
newPassword,
|
|
}, {
|
|
onSuccess: () => {
|
|
setMessage("Passwort erfolgreich geändert");
|
|
setCurrentPassword("");
|
|
setNewPassword("");
|
|
setConfirmPassword("");
|
|
setShowPasswordChange(false);
|
|
},
|
|
onError: (err) => {
|
|
setError(err instanceof Error ? err.message : "Fehler beim Ändern des Passworts");
|
|
}
|
|
});
|
|
};
|
|
|
|
if (!user) return null;
|
|
|
|
return (
|
|
<div className="bg-white rounded-lg shadow-lg p-6 max-w-2xl mx-auto">
|
|
<div className="flex justify-between items-center mb-6">
|
|
<h2 className="text-2xl font-bold text-gray-900">Benutzerprofil</h2>
|
|
<button
|
|
onClick={logout}
|
|
className="bg-red-600 text-white px-4 py-2 rounded-md hover:bg-red-700 font-medium"
|
|
>
|
|
Abmelden
|
|
</button>
|
|
</div>
|
|
|
|
<div className="space-y-4 mb-6">
|
|
<div>
|
|
<label className="block text-sm font-medium text-gray-700">Benutzername</label>
|
|
<p className="mt-1 text-lg text-gray-900">{user.username}</p>
|
|
</div>
|
|
|
|
<div>
|
|
<label className="block text-sm font-medium text-gray-700">E-Mail</label>
|
|
<p className="mt-1 text-lg text-gray-900">{user.email}</p>
|
|
</div>
|
|
|
|
<div>
|
|
<label className="block text-sm font-medium text-gray-700">Rolle</label>
|
|
<p className="mt-1 text-lg text-gray-900 capitalize">{user.role === "owner" ? "Inhaber" : "Kunde"}</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div>
|
|
<button
|
|
onClick={() => setShowPasswordChange(!showPasswordChange)}
|
|
className="bg-pink-600 text-white px-4 py-2 rounded-md hover:bg-pink-700 font-medium"
|
|
>
|
|
{showPasswordChange ? "Abbrechen" : "Passwort ändern"}
|
|
</button>
|
|
</div>
|
|
|
|
{showPasswordChange && (
|
|
<form onSubmit={handlePasswordChange} className="mt-6 space-y-4 border-t pt-6">
|
|
<h3 className="text-lg font-semibold text-gray-900">Passwort ändern</h3>
|
|
|
|
{error && (
|
|
<div className="bg-red-50 border border-red-200 text-red-700 px-4 py-3 rounded">
|
|
{error}
|
|
</div>
|
|
)}
|
|
|
|
{message && (
|
|
<div className="bg-green-50 border border-green-200 text-green-700 px-4 py-3 rounded">
|
|
{message}
|
|
</div>
|
|
)}
|
|
|
|
<div>
|
|
<label className="block text-sm font-medium text-gray-700 mb-2">
|
|
Aktuelles Passwort
|
|
</label>
|
|
<input
|
|
type="password"
|
|
value={currentPassword}
|
|
onChange={(e) => setCurrentPassword(e.target.value)}
|
|
className="w-full p-3 border border-gray-300 rounded-md focus:ring-2 focus:ring-pink-500 focus:border-pink-500"
|
|
required
|
|
/>
|
|
</div>
|
|
|
|
<div>
|
|
<label className="block text-sm font-medium text-gray-700 mb-2">
|
|
Neues Passwort
|
|
</label>
|
|
<input
|
|
type="password"
|
|
value={newPassword}
|
|
onChange={(e) => setNewPassword(e.target.value)}
|
|
className="w-full p-3 border border-gray-300 rounded-md focus:ring-2 focus:ring-pink-500 focus:border-pink-500"
|
|
minLength={6}
|
|
required
|
|
/>
|
|
</div>
|
|
|
|
<div>
|
|
<label className="block text-sm font-medium text-gray-700 mb-2">
|
|
Neues Passwort bestätigen
|
|
</label>
|
|
<input
|
|
type="password"
|
|
value={confirmPassword}
|
|
onChange={(e) => setConfirmPassword(e.target.value)}
|
|
className="w-full p-3 border border-gray-300 rounded-md focus:ring-2 focus:ring-pink-500 focus:border-pink-500"
|
|
minLength={6}
|
|
required
|
|
/>
|
|
</div>
|
|
|
|
<button
|
|
type="submit"
|
|
disabled={isPending}
|
|
className="bg-pink-600 text-white px-4 py-2 rounded-md hover:bg-pink-700 disabled:opacity-50 font-medium"
|
|
>
|
|
{isPending ? "Ändern..." : "Passwort ändern"}
|
|
</button>
|
|
</form>
|
|
)}
|
|
</div>
|
|
);
|
|
} |