2026-07-14 11:51:32 +02:00
|
|
|
'use client';
|
|
|
|
|
|
|
|
|
|
import { useState, FormEvent } from 'react';
|
|
|
|
|
import { useRouter } from 'next/navigation';
|
|
|
|
|
import { Button } from '@/components/ui/Button';
|
|
|
|
|
import { Input } from '@/components/ui/Input';
|
|
|
|
|
import { Card } from '@/components/ui/Card';
|
2026-07-14 20:16:15 +02:00
|
|
|
import { ToastProvider, useToast } from '@/components/ui/Toast';
|
|
|
|
|
import { I18nProvider, useI18n } from '@/lib/i18n';
|
|
|
|
|
import { login as apiLogin, setTokens } from '@/lib/api';
|
2026-07-14 11:51:32 +02:00
|
|
|
|
2026-07-14 20:16:15 +02:00
|
|
|
function LoginForm() {
|
2026-07-14 11:51:32 +02:00
|
|
|
const router = useRouter();
|
|
|
|
|
const { t } = useI18n();
|
|
|
|
|
const { showToast } = useToast();
|
|
|
|
|
const [email, setEmail] = useState('');
|
|
|
|
|
const [password, setPassword] = useState('');
|
|
|
|
|
const [loading, setLoading] = useState(false);
|
|
|
|
|
const [errors, setErrors] = useState<{ email?: string; password?: string }>({});
|
|
|
|
|
|
|
|
|
|
const validate = (): boolean => {
|
2026-07-14 20:16:15 +02:00
|
|
|
const newErrors: { email?: string; password?: string } = {};
|
2026-07-14 11:51:32 +02:00
|
|
|
if (!email) {
|
2026-07-14 20:16:15 +02:00
|
|
|
newErrors.email = t('login.error.emailRequired');
|
2026-07-14 11:51:32 +02:00
|
|
|
} else if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) {
|
2026-07-14 20:16:15 +02:00
|
|
|
newErrors.email = t('login.error.emailInvalid');
|
2026-07-14 11:51:32 +02:00
|
|
|
}
|
|
|
|
|
if (!password) {
|
2026-07-14 20:16:15 +02:00
|
|
|
newErrors.password = t('login.error.passwordRequired');
|
2026-07-14 11:51:32 +02:00
|
|
|
}
|
|
|
|
|
setErrors(newErrors);
|
|
|
|
|
return Object.keys(newErrors).length === 0;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const handleSubmit = async (e: FormEvent) => {
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
if (!validate()) return;
|
|
|
|
|
|
|
|
|
|
setLoading(true);
|
|
|
|
|
try {
|
2026-07-14 20:16:15 +02:00
|
|
|
const tokens = await apiLogin(email, password);
|
|
|
|
|
setTokens(tokens);
|
|
|
|
|
showToast(t('login.success'), 'success');
|
2026-07-19 16:49:50 +02:00
|
|
|
router.push('/de/fahrzeuge');
|
2026-07-14 11:51:32 +02:00
|
|
|
} catch (err) {
|
2026-07-14 20:16:15 +02:00
|
|
|
const message = (err as any)?.error?.message || t('login.error.invalidCredentials');
|
2026-07-14 11:51:32 +02:00
|
|
|
showToast(message, 'error');
|
|
|
|
|
} finally {
|
|
|
|
|
setLoading(false);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return (
|
2026-07-14 20:16:15 +02:00
|
|
|
<div className="min-h-screen flex items-center justify-center p-4">
|
|
|
|
|
<Card className="w-full max-w-md" title={t('login.title')}>
|
2026-07-14 11:51:32 +02:00
|
|
|
<form onSubmit={handleSubmit} className="space-y-4" data-testid="login-form">
|
|
|
|
|
<Input
|
2026-07-14 20:16:15 +02:00
|
|
|
label={t('login.email')}
|
2026-07-14 11:51:32 +02:00
|
|
|
type="email"
|
|
|
|
|
value={email}
|
|
|
|
|
onChange={(e) => setEmail(e.target.value)}
|
|
|
|
|
error={errors.email}
|
2026-07-14 20:16:15 +02:00
|
|
|
placeholder="user@example.com"
|
|
|
|
|
data-testid="login-email"
|
2026-07-14 11:51:32 +02:00
|
|
|
/>
|
|
|
|
|
<Input
|
2026-07-14 20:16:15 +02:00
|
|
|
label={t('login.password')}
|
2026-07-14 11:51:32 +02:00
|
|
|
type="password"
|
|
|
|
|
value={password}
|
|
|
|
|
onChange={(e) => setPassword(e.target.value)}
|
|
|
|
|
error={errors.password}
|
|
|
|
|
placeholder="********"
|
2026-07-14 20:16:15 +02:00
|
|
|
data-testid="login-password"
|
2026-07-14 11:51:32 +02:00
|
|
|
/>
|
|
|
|
|
<Button
|
|
|
|
|
type="submit"
|
|
|
|
|
loading={loading}
|
|
|
|
|
className="w-full"
|
2026-07-14 20:16:15 +02:00
|
|
|
data-testid="login-submit"
|
2026-07-14 11:51:32 +02:00
|
|
|
>
|
2026-07-14 20:16:15 +02:00
|
|
|
{t('login.submit')}
|
2026-07-14 11:51:32 +02:00
|
|
|
</Button>
|
|
|
|
|
</form>
|
|
|
|
|
</Card>
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
}
|
2026-07-14 20:16:15 +02:00
|
|
|
|
|
|
|
|
export default function LoginPage() {
|
|
|
|
|
return (
|
|
|
|
|
<I18nProvider initialLocale="de">
|
|
|
|
|
<ToastProvider>
|
|
|
|
|
<LoginForm />
|
|
|
|
|
</ToastProvider>
|
|
|
|
|
</I18nProvider>
|
|
|
|
|
);
|
|
|
|
|
}
|