const t = window.t || (k => k); const Auth = () => { const {go, login, route} = useApp(); const [mode, setMode] = useState(route.params?.mode || 'login'); const [email, setEmail] = useState(''); const [pass, setPass] = useState(''); const [name, setName] = useState(''); const [phone, setPhone] = useState(''); const [isInstructor, setIsInstructor] = useState(false); const [err, setErr] = useState(''); const [busy, setBusy] = useState(false); const [forgotMsg, setForgotMsg] = useState(''); const [resetToken, setResetToken] = useState(''); useEffect(() => { const params = new URLSearchParams(window.location.search); const token = params.get('reset'); if (token) { setResetToken(token); setMode('reset'); window.history.replaceState({}, '', window.location.pathname); } }, []); const hasBackend = async () => { try { return !!(await window.__backendReady); } catch(e){ return false; } }; const submit = async (e) => { e && e.preventDefault(); setErr(''); setForgotMsg(''); if (mode === 'reset') { if (!pass || pass.length < 8) { setErr(t('auth.pass_short')); return; } setBusy(true); try { await window.api.resetPassword(resetToken, pass); setForgotMsg(t('auth.reset_ok')); setMode('login'); } catch (er) { setErr(er.error === 'token_invalid' ? t('auth.token_invalid') : 'Error: ' + (er.error || 'desconocido')); } setBusy(false); return; } if (mode === 'forgot') { if (!email) { setErr(t('auth.enter_email')); return; } setBusy(true); try { await window.api.forgotPassword(email); setForgotMsg(t('auth.forgot_sent')); } catch (er) { // Show success message even on error to prevent email enumeration setForgotMsg(t('auth.forgot_sent')); } setBusy(false); return; } if (!email || !pass) { setErr(t('auth.fill_all')); return; } if (mode === 'signup' && !name) { setErr(t('auth.tell_name')); return; } if (mode === 'signup' && !phone) { setErr(t('auth.phone_required') || 'Introduce tu teléfono'); return; } if (mode === 'signup' && phone.replace(/[^0-9]/g,'').length < 9) { setErr(t('auth.phone_invalid') || 'Teléfono inválido (mínimo 9 dígitos)'); return; } setBusy(true); try { if (mode === 'signup') { // Backend is REQUIRED for registration — no demo fallback const backendUp = await window.isBackendReady(); if (!backendUp) { setErr(t('auth.server_unavailable') || 'Servidor no disponible. Inténtalo de nuevo en unos segundos.'); setBusy(false); return; } try { await window.api.register({ email, password: pass, name, license: isInstructor ? 'INSTRUCTOR' : '', phone }); } catch (er) { if (er.error === 'email_taken') { setErr(t('auth.email_taken')); setBusy(false); return; } if (er.error === 'password_too_short') { setErr(t('auth.pass_short')); setBusy(false); return; } if (er.error === 'network_error') { setErr(t('auth.server_unavailable') || 'Servidor no disponible. Inténtalo de nuevo.'); setBusy(false); return; } setErr(er.error || 'No se pudo crear la cuenta'); setBusy(false); return; } } const r = await login(email, pass); if (!r || r.ok === false) { setErr(r && r.error === 'credentials_invalid' ? t('auth.bad_creds') : r && r.error === 'account_blocked' ? t('auth.blocked') : (r && r.error) || 'Error al iniciar sesión'); } } finally { setBusy(false); } }; return
AeroPlan

{mode==='login'?t('auth.welcome'):mode==='forgot'?t('auth.recover'):mode==='reset'?t('auth.new_password'):t('auth.create_account')}

{mode==='login'?t('auth.login_subtitle'):mode==='forgot'?t('auth.forgot_subtitle'):mode==='reset'?t('auth.reset_subtitle'):t('auth.signup_subtitle')}

{mode==='signup' && <>
setName(e.target.value)} placeholder="Jesús Soler"/>
{const v=e.target.value.replace(/[^0-9+\s()-]/g,'');setPhone(v);}} placeholder="+34 612 345 678" maxLength={18}/>
} {mode!=='reset' &&
setEmail(e.target.value)} placeholder="piloto@ejemplo.com"/>
} {mode!=='forgot' &&
setPass(e.target.value)} placeholder="••••••••"/>
} {err &&
{err}
} {forgotMsg &&
{forgotMsg}
}
{mode === 'login' &&
}
{mode==='login'?<>{t('auth.no_account')} :mode==='forgot'?<>{t('auth.remember')} :mode==='reset'?<> :<>{t('auth.has_account')} }
; }; window.Auth = Auth;