mirror of
https://github.com/complexcaresolutions/dak.c2s.git
synced 2026-03-17 16:03:41 +00:00
155 lines
5.1 KiB
TypeScript
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>
|
|
)
|
|
}
|