// AUTH — login, registro, recuperar, confirmar email
window.AuthPages = {};
// Guarda resultado anónimo pendiente (si hay) al API después del login
async function savePendingResult() {
const raw = localStorage.getItem('sd_pending_result');
if (!raw) return;
try {
const pending = JSON.parse(raw);
const tok = localStorage.getItem('sd_token');
if (!tok) return;
const BASE = window.API_BASE || '/simuladordocente/api';
await fetch(`${BASE}/resultados/anonimo`, {
method: 'POST',
headers: { Authorization: `Bearer ${tok}`, 'Content-Type': 'application/json' },
body: JSON.stringify(pending),
});
localStorage.removeItem('sd_pending_result');
} catch {}
}
window.AuthPages.Login = function Login({ navigate, store }) {
const [email, setEmail] = React.useState('');
const [pass, setPass] = React.useState('');
const [err, setErr] = React.useState('');
const [loading, setLoading] = React.useState(false);
const submit = async (e) => {
e.preventDefault();
setErr('');
if (!email.includes('@') || pass.length < 4) { setErr('Verifica tu correo y contraseña.'); return; }
setLoading(true);
try {
await store.login(email, pass);
// Guardar resultado anónimo pendiente si existe
await savePendingResult();
navigate('/dashboard');
} catch (ex) {
setErr(ex.message || 'Credenciales incorrectas');
} finally { setLoading(false); }
};
return (
Inicia sesión
Accede a tu panel y simuladores.
);
};
window.AuthPages.Registro = function Registro({ navigate }) {
const BASE = window.API_BASE || '/simuladordocente/api';
const [step, setStep] = React.useState(1);
const [data, setData] = React.useState({ nombre: '', email: '', pass: '' });
const [err, setErr] = React.useState('');
const [loading, setLoading] = React.useState(false);
const submit = async (e) => {
e.preventDefault();
setErr('');
if (data.pass.length < 8) { setErr('La contraseña debe tener al menos 8 caracteres.'); return; }
setLoading(true);
try {
const r = await fetch(`${BASE}/auth/registro`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ nombre: data.nombre, email: data.email, password: data.pass }),
});
const d = await r.json();
if (!r.ok) { setErr(d.error || 'Error al registrarse'); setLoading(false); return; }
setStep(2);
} catch {
setErr('No se pudo conectar al servidor. Intenta de nuevo.');
}
setLoading(false);
};
if (step === 2) {
return (
📬
Revisa tu correo
Enviamos un enlace de confirmación a {data.email}.
Haz clic en el enlace del correo para activar tu cuenta. Revisa también la carpeta de spam.
¿No llegó el correo?
- Revisa la carpeta de spam / correo no deseado
- El enlace expira en 24 horas
- Verifica que el correo sea correcto
{localStorage.getItem('sd_pending_result') && (
✓ Tu resultado del diagnóstico se guardará automáticamente al iniciar sesión en este mismo navegador.
)}
);
}
return (
Crea tu cuenta
Empieza con muestras gratis. Pago solo cuando estés listo.
);
};
window.AuthPages.Recuperar = function Recuperar({ navigate }) {
const BASE = window.API_BASE || '/simuladordocente/api';
const [sent, setSent] = React.useState(false);
const [email, setEmail] = React.useState('');
const [loading, setLoading] = React.useState(false);
const submit = async (e) => {
e.preventDefault();
setLoading(true);
try {
await fetch(`${BASE}/auth/recuperar`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ email }),
});
} catch {}
setLoading(false);
setSent(true);
};
if (sent) {
return (
📨
Enlace enviado
Si {email} existe en nuestro sistema,
recibirás un correo con el enlace para restablecer tu contraseña.
Revisa también tu carpeta de spam.
);
}
return (
Recupera tu contraseña
Te enviaremos un enlace para crear una nueva contraseña.
);
};
// Página: restablecer contraseña (llegó desde el link del email)
window.AuthPages.Reset = function Reset({ navigate, token }) {
const BASE = window.API_BASE || '/simuladordocente/api';
const [pass, setPass] = React.useState('');
const [pass2, setPass2] = React.useState('');
const [msg, setMsg] = React.useState('');
const [ok, setOk] = React.useState(false);
const [loading, setLoading] = React.useState(false);
const submit = async (e) => {
e.preventDefault();
if (pass !== pass2) { setMsg('Las contraseñas no coinciden.'); return; }
if (pass.length < 4) { setMsg('Mínimo 4 caracteres.'); return; }
setLoading(true); setMsg('');
try {
const r = await fetch(`${BASE}/auth/reset`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ token, password: pass }),
});
const d = await r.json();
if (!r.ok) { setMsg(d.error || 'Error al restablecer.'); }
else { setOk(true); }
} catch { setMsg('Error de conexión.'); }
setLoading(false);
};
if (ok) {
return (
✅
Contraseña actualizada
Ya puedes iniciar sesión con tu nueva contraseña.
);
}
return (
Nueva contraseña
Elige una contraseña segura para tu cuenta.
);
};
// Página: cuenta confirmada (redirige aquí el backend)
window.AuthPages.Confirmado = function Confirmado({ navigate, error }) {
if (error) {
return (
❌
Enlace inválido
El enlace de confirmación es inválido o ya expiró. Intenta registrarte de nuevo.
);
}
return (
✅
¡Cuenta confirmada!
Tu correo ha sido verificado. Ya puedes acceder a tu panel.
);
};
function AuthShell({ children, navigate }) {
return (
{e.preventDefault();navigate('/');}}>
Practica como en el examen real.
Simuladores construidos con la estructura, dificultad y bloques temáticos del examen USICAMM.
Pago único por materia, acceso permanente.
13 simuladores
$150 por materia
∞ intentos
);
}