diff --git a/frontend/src/components/LoginForm.tsx b/frontend/src/components/LoginForm.tsx new file mode 100644 index 0000000..cf4e5de --- /dev/null +++ b/frontend/src/components/LoginForm.tsx @@ -0,0 +1,149 @@ +import { useState } from 'react' + +interface Props { + loginUrl: string + successUrl: string + csrfToken: string +} + +type LoginResponse = { + success?: boolean + alert?: boolean + locked?: boolean + error?: string +} + +export function LoginForm({ loginUrl, successUrl, csrfToken }: Props) { + const [email, setEmail] = useState('') + const [password, setPassword] = useState('') + const [showPassword, setShowPassword] = useState(false) + const [buttonText, setButtonText] = useState('Conectar') + const [busy, setBusy] = useState(false) + const [message, setMessage] = useState<{ kind: 'ok' | 'err'; text: string } | null>(null) + + function transientError(text: string) { + setMessage({ kind: 'err', text }) + setBusy(false) + setButtonText('Conectar') + setTimeout(() => setMessage(null), 5000) + } + + async function handleSubmit(e: React.FormEvent) { + e.preventDefault() + if (busy) return + + if (email.trim() === '' || password.trim() === '') { + transientError('Por favor rellene todos los campos.') + return + } + + setBusy(true) + setButtonText('Conectando') + setMessage(null) + + const body = new URLSearchParams() + body.set('email', email.trim()) + body.set('password', password.trim()) + body.set('csrfmiddlewaretoken', csrfToken) + + try { + const resp = await fetch(loginUrl, { + method: 'POST', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + 'X-CSRFToken': csrfToken, + Accept: 'application/json', + }, + credentials: 'same-origin', + body: body.toString(), + }) + if (!resp.ok) throw new Error(`HTTP ${resp.status}`) + const data: LoginResponse = await resp.json() + + if (data.success === true) { + setButtonText('Conectado') + setMessage({ kind: 'ok', text: 'Conexión exitosa. Redirigiendo…' }) + setTimeout(() => { + window.location.href = successUrl + }, 3000) + } else if (data.alert === true) { + setButtonText('Sancionado') + setBusy(false) + } else if (data.locked === true) { + setButtonText('Seguridad') + setBusy(false) + } else { + transientError(data.error || 'Nombre de usuario / Contraseña incorrectos.') + } + } catch { + setTimeout(() => { + alert('Algo ha salido mal. Por favor intente más tarde') + window.location.reload() + }, 2000) + } + } + + return ( + <> +
+