// ===================================================================== // Pantalla de entrada · Magic Login // Dos caminos al mismo sitio: acceso rápido por rol (demo) o correo. // ===================================================================== import { api, esc, ficha, brindis, activarCopiado } from './ui.mjs'; const $ = (s) => document.querySelector(s); const MOTIVOS = { invalido: 'Ese enlace no es válido. Genera uno nuevo.', 'ya-usado': 'Ese enlace ya se usó. Los enlaces de acceso sirven una sola vez.', vencido: 'El enlace venció. Genera uno nuevo.', 'usuario-inactivo': 'Tu cuenta está desactivada. Habla con dirección.', }; function mostrarError(texto) { const caja = $('#error-entrada'); caja.hidden = false; caja.className = 'aviso aviso--error'; caja.textContent = texto; } // Si venimos rebotados de /acceso/:token con un problema, decirlo aquí. const motivo = new URLSearchParams(location.search).get('error'); if (motivo) mostrarError(MOTIVOS[motivo] ?? 'No se pudo validar el enlace.'); /** Genera el enlace y lo canjea de inmediato: es el flujo real, sin el correo. */ async function entrar(email, boton) { const previo = boton?.textContent; if (boton) { boton.disabled = true; boton.textContent = 'Generando enlace…'; } $('#error-entrada').hidden = true; $('#resultado').innerHTML = ''; try { const r = await api('/auth/enlace', { method: 'POST', body: { email } }); $('#resultado').innerHTML = `
Enlace listo para ${esc(r.usuario.nombre)} · ${esc(r.usuario.rol_nombre)}. Vence en ${esc(r.expiraEnMinutos)} minutos y sirve una sola vez. ${r.enlace ? `${esc(location.origin + r.enlace)}` : ''}
`; if (!r.token) { brindis('Enlace enviado a tu correo'); return; } // En producción esto lo haría la persona al abrir su correo. await api('/auth/consumir', { method: 'POST', body: { token: r.token } }); location.href = '/portal'; } catch (err) { mostrarError(err.message); if (boton) { boton.disabled = false; boton.textContent = previo; } } } // ---- accesos rápidos por rol ---------------------------------------- try { const { usuarios, vigenciaMinutos } = await api('/auth/demo'); $('#vigencia').textContent = vigenciaMinutos; $('#roles').innerHTML = usuarios.map((u) => ` `).join(''); $('#roles').addEventListener('click', (ev) => { const btn = ev.target.closest('.tarjeta-rol'); if (!btn) return; entrar(btn.dataset.email, btn); }); } catch { $('#roles').innerHTML = `
No se pudo hablar con el servidor. Revisa que esté corriendo npm start y que el contenedor de MySQL esté arriba.
`; } $('#forma').addEventListener('submit', (ev) => { ev.preventDefault(); const email = $('#email').value.trim(); if (!email) return mostrarError('Escribe tu correo institucional.'); entrar(email, $('#enviar')); }); activarCopiado();