dak.c2s/frontend/src/pages/LoginPage.tsx
CCS Admin 4504d4300f fix: remove registration link from login page
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 21:58:01 +00:00

155 lines
5.1 KiB
TypeScript

import { useState } from 'react'
import { useForm } from 'react-hook-form'
import { zodResolver } from '@hookform/resolvers/zod'
import { z } from 'zod'
import { useNavigate } from 'react-router-dom'
import { useAuth } from '@/context/AuthContext'
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
import { Input } from '@/components/ui/input'
import { Button } from '@/components/ui/button'
import { Label } from '@/components/ui/label'
import { Alert, AlertDescription } from '@/components/ui/alert'
import { AlertCircle, Loader2, Moon, Sun } from 'lucide-react'
import { useTheme } from '@/hooks/useTheme'
const loginSchema = z.object({
email: z.string().email('Bitte geben Sie eine gueltige E-Mail-Adresse ein'),
password: z.string().min(1, 'Passwort ist erforderlich'),
mfa_code: z.string().optional(),
})
type LoginFormValues = z.infer<typeof loginSchema>
export function LoginPage() {
const { login } = useAuth()
const { theme, toggleTheme } = useTheme()
const navigate = useNavigate()
const [error, setError] = useState<string | null>(null)
const [showMfa, setShowMfa] = useState(false)
const [isSubmitting, setIsSubmitting] = useState(false)
const {
register,
handleSubmit,
formState: { errors },
} = useForm<LoginFormValues>({
resolver: zodResolver(loginSchema),
defaultValues: {
email: '',
password: '',
mfa_code: '',
},
})
const onSubmit = async (data: LoginFormValues) => {
setError(null)
setIsSubmitting(true)
try {
await login({
email: data.email,
password: data.password,
mfa_code: data.mfa_code || undefined,
})
navigate('/dashboard')
} catch (err: unknown) {
const axiosError = err as { response?: { data?: { detail?: string }; status?: number } }
const detail = axiosError.response?.data?.detail || ''
if (detail.toLowerCase().includes('mfa') || detail.toLowerCase().includes('2fa')) {
setShowMfa(true)
setError('Bitte geben Sie Ihren MFA-Code ein')
} else if (axiosError.response?.status === 401) {
setError('Ungueltige Anmeldedaten')
} else if (axiosError.response?.status === 423) {
setError('Konto gesperrt. Bitte kontaktieren Sie den Administrator.')
} else {
setError(detail || 'Ein Fehler ist aufgetreten')
}
} finally {
setIsSubmitting(false)
}
}
return (
<div className="flex min-h-screen items-center justify-center bg-background px-4">
<Button
variant="ghost"
size="icon"
onClick={toggleTheme}
className="absolute top-4 right-4"
>
{theme === 'dark' ? <Sun className="h-5 w-5" /> : <Moon className="h-5 w-5" />}
<span className="sr-only">Design umschalten</span>
</Button>
<Card className="w-full max-w-md">
<CardHeader className="text-center">
<CardTitle className="text-2xl">DAK Portal</CardTitle>
<CardDescription>Melden Sie sich mit Ihrem Konto an</CardDescription>
</CardHeader>
<CardContent>
<form onSubmit={handleSubmit(onSubmit)} className="space-y-4">
{error && (
<Alert variant="destructive">
<AlertCircle className="h-4 w-4" />
<AlertDescription>{error}</AlertDescription>
</Alert>
)}
<div className="space-y-2">
<Label htmlFor="email">E-Mail</Label>
<Input
id="email"
type="email"
placeholder="name@dak.de"
autoComplete="email"
{...register('email')}
/>
{errors.email && (
<p className="text-sm text-destructive">{errors.email.message}</p>
)}
</div>
<div className="space-y-2">
<Label htmlFor="password">Passwort</Label>
<Input
id="password"
type="password"
autoComplete="current-password"
{...register('password')}
/>
{errors.password && (
<p className="text-sm text-destructive">{errors.password.message}</p>
)}
</div>
{showMfa && (
<div className="space-y-2">
<Label htmlFor="mfa_code">MFA-Code</Label>
<Input
id="mfa_code"
type="text"
inputMode="numeric"
placeholder="123456"
autoComplete="one-time-code"
{...register('mfa_code')}
/>
</div>
)}
<Button type="submit" className="w-full" disabled={isSubmitting}>
{isSubmitting ? (
<>
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
Wird angemeldet...
</>
) : (
'Anmelden'
)}
</Button>
</form>
</CardContent>
</Card>
</div>
)
}