347 lines
13 KiB
TypeScript
347 lines
13 KiB
TypeScript
'use client';
|
|
|
|
import { useState } from 'react';
|
|
import { Button } from '@/components/ui/button';
|
|
import { Card, CardContent, CardHeader, CardTitle, CardDescription } from '@/components/ui/card';
|
|
import { Input } from '@/components/ui/input';
|
|
import { Label } from '@/components/ui/label';
|
|
import { updateUserProfile, updateCompanyDetails } from '@/lib/actions/users';
|
|
import { updatePassword } from '@/lib/actions/auth';
|
|
import { Save, KeyRound, Loader2 } from 'lucide-react';
|
|
|
|
interface AccountSettingsFormProps {
|
|
userId: string;
|
|
profile: any;
|
|
company: any;
|
|
}
|
|
|
|
export function AccountSettingsForm({ userId, profile, company }: AccountSettingsFormProps) {
|
|
// Profil State
|
|
const [firstName, setFirstName] = useState(profile?.first_name || '');
|
|
const [lastName, setLastName] = useState(profile?.last_name || '');
|
|
const [profileMessage, setProfileMessage] = useState<{ type: 'success' | 'error'; text: string } | null>(null);
|
|
const [isUpdatingProfile, setIsUpdatingProfile] = useState(false);
|
|
|
|
// Company State
|
|
const [street, setStreet] = useState(company?.street || '');
|
|
const [zip, setZip] = useState(company?.zip || '');
|
|
const [city, setCity] = useState(company?.city || '');
|
|
const [companyEmail, setCompanyEmail] = useState(company?.email || '');
|
|
const [companyMessage, setCompanyMessage] = useState<{ type: 'success' | 'error'; text: string } | null>(null);
|
|
const [isUpdatingCompany, setIsUpdatingCompany] = useState(false);
|
|
|
|
// Passwort State
|
|
const [newPassword, setNewPassword] = useState('');
|
|
const [confirmPassword, setConfirmPassword] = useState('');
|
|
const [passwordMessage, setPasswordMessage] = useState<{ type: 'success' | 'error'; text: string } | null>(null);
|
|
const [isUpdatingPassword, setIsUpdatingPassword] = useState(false);
|
|
|
|
// Profil speichern
|
|
const handleUpdateProfile = async (e: React.FormEvent) => {
|
|
e.preventDefault();
|
|
setProfileMessage(null);
|
|
setIsUpdatingProfile(true);
|
|
|
|
try {
|
|
const res = await updateUserProfile(userId, {
|
|
first_name: firstName || null,
|
|
last_name: lastName || null,
|
|
});
|
|
|
|
if (res.success) {
|
|
setProfileMessage({ type: 'success', text: 'Persönliche Daten erfolgreich aktualisiert.' });
|
|
} else {
|
|
setProfileMessage({ type: 'error', text: res.error || 'Fehler beim Aktualisieren des Profils.' });
|
|
}
|
|
} catch (err: any) {
|
|
setProfileMessage({ type: 'error', text: err.message || 'Ein unerwarteter Fehler ist aufgetreten.' });
|
|
} finally {
|
|
setIsUpdatingProfile(false);
|
|
}
|
|
};
|
|
|
|
// Company speichern
|
|
const handleUpdateCompany = async (e: React.FormEvent) => {
|
|
e.preventDefault();
|
|
if (!company?.id) return;
|
|
setCompanyMessage(null);
|
|
setIsUpdatingCompany(true);
|
|
|
|
try {
|
|
const res = await updateCompanyDetails(company.id, {
|
|
street: street || null,
|
|
zip: zip || null,
|
|
city: city || null,
|
|
email: companyEmail || null,
|
|
});
|
|
|
|
if (res.success) {
|
|
setCompanyMessage({ type: 'success', text: 'Unternehmensdaten erfolgreich aktualisiert.' });
|
|
} else {
|
|
setCompanyMessage({ type: 'error', text: res.error || 'Fehler beim Aktualisieren der Unternehmensdaten.' });
|
|
}
|
|
} catch (err: any) {
|
|
setCompanyMessage({ type: 'error', text: err.message || 'Ein unerwarteter Fehler ist aufgetreten.' });
|
|
} finally {
|
|
setIsUpdatingCompany(false);
|
|
}
|
|
};
|
|
|
|
// Passwort speichern
|
|
const handleUpdatePassword = async (e: React.FormEvent) => {
|
|
e.preventDefault();
|
|
setPasswordMessage(null);
|
|
|
|
if (newPassword.length < 6) {
|
|
setPasswordMessage({ type: 'error', text: 'Das Passwort muss mindestens 6 Zeichen lang sein.' });
|
|
return;
|
|
}
|
|
|
|
if (newPassword !== confirmPassword) {
|
|
setPasswordMessage({ type: 'error', text: 'Die Passwörter stimmen nicht überein.' });
|
|
return;
|
|
}
|
|
|
|
setIsUpdatingPassword(true);
|
|
|
|
try {
|
|
const res = await updatePassword(newPassword);
|
|
if (res.success) {
|
|
setPasswordMessage({ type: 'success', text: 'Passwort erfolgreich geändert.' });
|
|
setNewPassword('');
|
|
setConfirmPassword('');
|
|
} else {
|
|
setPasswordMessage({ type: 'error', text: res.error || 'Fehler beim Ändern des Passworts.' });
|
|
}
|
|
} catch (err: any) {
|
|
setPasswordMessage({ type: 'error', text: err.message || 'Ein unerwarteter Fehler ist aufgetreten.' });
|
|
} finally {
|
|
setIsUpdatingPassword(false);
|
|
}
|
|
};
|
|
|
|
return (
|
|
<div className="space-y-8">
|
|
{/* 1. Persönliche Daten */}
|
|
<Card className="glass-dark border-white/10">
|
|
<CardHeader>
|
|
<CardTitle className="text-xl">Persönliche Daten</CardTitle>
|
|
<CardDescription className="text-slate-400">
|
|
Aktualisieren Sie Ihren Vor- und Nachnamen.
|
|
</CardDescription>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<form onSubmit={handleUpdateProfile} className="space-y-4">
|
|
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
|
<div className="space-y-2">
|
|
<Label htmlFor="firstName">Vorname</Label>
|
|
<Input
|
|
id="firstName"
|
|
value={firstName}
|
|
onChange={(e) => setFirstName(e.target.value)}
|
|
className="bg-slate-950 border-white/10 focus:border-primary text-white"
|
|
placeholder="Max"
|
|
/>
|
|
</div>
|
|
<div className="space-y-2">
|
|
<Label htmlFor="lastName">Nachname</Label>
|
|
<Input
|
|
id="lastName"
|
|
value={lastName}
|
|
onChange={(e) => setLastName(e.target.value)}
|
|
className="bg-slate-950 border-white/10 focus:border-primary text-white"
|
|
placeholder="Mustermann"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
{profileMessage && (
|
|
<div
|
|
className={`p-3 rounded-lg text-sm border ${
|
|
profileMessage.type === 'success'
|
|
? 'bg-green-500/10 border-green-500/20 text-green-400'
|
|
: 'bg-red-500/10 border-red-500/20 text-red-400'
|
|
}`}
|
|
>
|
|
{profileMessage.text}
|
|
</div>
|
|
)}
|
|
|
|
<div className="flex justify-end">
|
|
<Button type="submit" disabled={isUpdatingProfile} className="gap-2">
|
|
{isUpdatingProfile ? (
|
|
<>
|
|
<Loader2 className="w-4 h-4 animate-spin" /> Speichern...
|
|
</>
|
|
) : (
|
|
<>
|
|
<Save className="w-4 h-4" /> Profil speichern
|
|
</>
|
|
)}
|
|
</Button>
|
|
</div>
|
|
</form>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
{/* 2. Unternehmensdaten */}
|
|
{company && (
|
|
<Card className="glass-dark border-white/10">
|
|
<CardHeader>
|
|
<CardTitle className="text-xl">Unternehmensdaten</CardTitle>
|
|
<CardDescription className="text-slate-400">
|
|
Verwalten Sie die Adressdaten Ihres Partner-Unternehmens.
|
|
</CardDescription>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<form onSubmit={handleUpdateCompany} className="space-y-4">
|
|
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
|
<div className="space-y-2 sm:col-span-2">
|
|
<Label htmlFor="companyName">Firmenname (nicht änderbar)</Label>
|
|
<Input
|
|
id="companyName"
|
|
value={company.name}
|
|
disabled
|
|
className="bg-slate-950/50 border-white/5 text-slate-400 cursor-not-allowed"
|
|
/>
|
|
</div>
|
|
<div className="space-y-2 sm:col-span-2">
|
|
<Label htmlFor="street">Straße & Hausnummer</Label>
|
|
<Input
|
|
id="street"
|
|
value={street}
|
|
onChange={(e) => setStreet(e.target.value)}
|
|
className="bg-slate-950 border-white/10 focus:border-primary text-white"
|
|
placeholder="Musterstraße 12"
|
|
/>
|
|
</div>
|
|
<div className="space-y-2">
|
|
<Label htmlFor="zip">Postleitzahl</Label>
|
|
<Input
|
|
id="zip"
|
|
value={zip}
|
|
onChange={(e) => setZip(e.target.value)}
|
|
className="bg-slate-950 border-white/10 focus:border-primary text-white"
|
|
placeholder="12345"
|
|
/>
|
|
</div>
|
|
<div className="space-y-2">
|
|
<Label htmlFor="city">Ort</Label>
|
|
<Input
|
|
id="city"
|
|
value={city}
|
|
onChange={(e) => setCity(e.target.value)}
|
|
className="bg-slate-950 border-white/10 focus:border-primary text-white"
|
|
placeholder="Musterstadt"
|
|
/>
|
|
</div>
|
|
<div className="space-y-2 sm:col-span-2">
|
|
<Label htmlFor="companyEmail">E-Mail für Rechnungen / Anfragen</Label>
|
|
<Input
|
|
id="companyEmail"
|
|
type="email"
|
|
value={companyEmail}
|
|
onChange={(e) => setCompanyEmail(e.target.value)}
|
|
className="bg-slate-950 border-white/10 focus:border-primary text-white"
|
|
placeholder="partner@firma.de"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
{companyMessage && (
|
|
<div
|
|
className={`p-3 rounded-lg text-sm border ${
|
|
companyMessage.type === 'success'
|
|
? 'bg-green-500/10 border-green-500/20 text-green-400'
|
|
: 'bg-red-500/10 border-red-500/20 text-red-400'
|
|
}`}
|
|
>
|
|
{companyMessage.text}
|
|
</div>
|
|
)}
|
|
|
|
<div className="flex justify-end">
|
|
<Button type="submit" disabled={isUpdatingCompany} className="gap-2">
|
|
{isUpdatingCompany ? (
|
|
<>
|
|
<Loader2 className="w-4 h-4 animate-spin" /> Speichern...
|
|
</>
|
|
) : (
|
|
<>
|
|
<Save className="w-4 h-4" /> Firmendaten speichern
|
|
</>
|
|
)}
|
|
</Button>
|
|
</div>
|
|
</form>
|
|
</CardContent>
|
|
</Card>
|
|
)}
|
|
|
|
{/* 3. Sicherheit / Passwort ändern */}
|
|
<Card className="glass-dark border-white/10">
|
|
<CardHeader>
|
|
<CardTitle className="text-xl">Passwort ändern</CardTitle>
|
|
<CardDescription className="text-slate-400">
|
|
Geben Sie ein neues Passwort für Ihren Zugang ein.
|
|
</CardDescription>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<form onSubmit={handleUpdatePassword} className="space-y-4">
|
|
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
|
<div className="space-y-2">
|
|
<Label htmlFor="newPassword">Neues Passwort</Label>
|
|
<Input
|
|
id="newPassword"
|
|
type="password"
|
|
value={newPassword}
|
|
onChange={(e) => setNewPassword(e.target.value)}
|
|
className="bg-slate-950 border-white/10 focus:border-primary text-white"
|
|
placeholder="••••••••"
|
|
/>
|
|
</div>
|
|
<div className="space-y-2">
|
|
<Label htmlFor="confirmPassword">Passwort bestätigen</Label>
|
|
<Input
|
|
id="confirmPassword"
|
|
type="password"
|
|
value={confirmPassword}
|
|
onChange={(e) => setConfirmPassword(e.target.value)}
|
|
className="bg-slate-950 border-white/10 focus:border-primary text-white"
|
|
placeholder="••••••••"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
{passwordMessage && (
|
|
<div
|
|
className={`p-3 rounded-lg text-sm border ${
|
|
passwordMessage.type === 'success'
|
|
? 'bg-green-500/10 border-green-500/20 text-green-400'
|
|
: 'bg-red-500/10 border-red-500/20 text-red-400'
|
|
}`}
|
|
>
|
|
{passwordMessage.text}
|
|
</div>
|
|
)}
|
|
|
|
<div className="flex justify-end">
|
|
<Button type="submit" disabled={isUpdatingPassword} className="gap-2">
|
|
{isUpdatingPassword ? (
|
|
<>
|
|
<Loader2 className="w-4 h-4 animate-spin" /> Ändern...
|
|
</>
|
|
) : (
|
|
<>
|
|
<KeyRound className="w-4 h-4" /> Passwort aktualisieren
|
|
</>
|
|
)}
|
|
</Button>
|
|
</div>
|
|
</form>
|
|
</CardContent>
|
|
</Card>
|
|
</div>
|
|
);
|
|
}
|