/* Página de entrada (27-oct-2026). - Si ya hay sesión, salta directo a donde ibas (nginx manda aquí con #/ruta/original). - Entrar: POST /api/entrar → el servidor pone la cookie de sesión; el mensaje dice qué pasó. - Avisos públicos del sitio (incidencias marcadas «publica») y reporte sin sesión (POST /api/incidencias/publica). */ (function () { var $ = function (id) { return document.getElementById(id); }; function destino() { // Solo rutas de ESTE sitio: se arma la URL completa y se exige el mismo origen (un «/\t/otro.com» o «/\\otro.com» // se vuelve «//otro.com» en el navegador: comparar el origen lo cierra). Nunca regresa a la entrada. var h = ''; try { h = decodeURIComponent((location.hash || '').slice(1)); } catch (e) { h = ''; } if (!h || h.charAt(0) !== '/') return '/'; try { var u = new URL(h, location.origin); if (u.origin !== location.origin || /^\/entrar\.html/.test(u.pathname)) return '/'; return u.href; // absoluta y del mismo origen (un «/.//otro.com» relativo sería otro sitio) } catch (e) { return '/'; } } function ir() { location.replace(destino()); } function mensaje(el, html, bien) { el.className = 'en-msg ' + (bien ? 'ok' : 'err'); el.innerHTML = html; } function esc(s) { var d = document.createElement('div'); d.textContent = s == null ? '' : String(s); return d.innerHTML; } // ¿ya hay sesión? fetch('/api/sesion', { cache: 'no-store', credentials: 'same-origin' }) .then(function (r) { return r.ok ? r.json() : null; }) .then(function (j) { if (j && j.sesion) ir(); }) .catch(function () {}); // usuario recordado (solo el nombre, nunca la contraseña) try { var u0 = localStorage.getItem('hbox.usuario'); if (u0) { $('usuario').value = u0; } } catch (e) {} ($('usuario').value ? $('password') : $('usuario')).focus(); $('ver').addEventListener('click', function () { var p = $('password'), mostrar = p.type === 'password'; p.type = mostrar ? 'text' : 'password'; this.textContent = mostrar ? 'Ocultar' : 'Ver'; this.setAttribute('aria-pressed', mostrar ? 'true' : 'false'); this.setAttribute('aria-label', mostrar ? 'Ocultar la contraseña' : 'Mostrar la contraseña'); }); function revisarMayus(ev) { if (ev.getModifierState) $('mayus').hidden = !ev.getModifierState('CapsLock'); } $('password').addEventListener('keydown', revisarMayus); $('password').addEventListener('keyup', revisarMayus); $('fEntrar').addEventListener('submit', function (ev) { ev.preventDefault(); var b = $('bEntrar'), msg = $('msg'); var usuario = $('usuario').value.trim(), password = $('password').value; if (!usuario || !password) { mensaje(msg, 'Escribe tu usuario y tu contraseña.', false); return; } b.disabled = true; b.textContent = 'Entrando…'; fetch('/api/entrar', { method: 'POST', credentials: 'same-origin', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ usuario: usuario, password: password, recordar: $('recordar').checked }) }).then(function (r) { return r.json().catch(function () { return { ok: false, error: 'El servidor no respondió bien (HTTP ' + r.status + ').' }; }); }).then(function (j) { if (j && j.ok) { try { localStorage.setItem('hbox.usuario', usuario); } catch (e) {} mensaje(msg, 'Listo, ' + esc(j.user) + '. Abriendo el sitio…', true); ir(); return; } var t = esc((j && j.error) || 'No se pudo entrar.'); if (j && j.codigo === 'contrasena') { $('password').value = ''; $('password').focus(); } else if (j && j.codigo === 'usuario') { $('usuario').focus(); } if (j && (j.codigo === 'bloqueado' || j.codigo === 'contrasena')) { t += ' Reportar el problema.'; } mensaje(msg, t, false); var a = $('abrirAyuda'); if (a) a.addEventListener('click', function (e) { e.preventDefault(); abrirAyuda(); }); }).catch(function () { mensaje(msg, 'No pude contactar al servidor. Revisa tu conexión e intenta otra vez; si sigue, repórtalo abajo.', false); }).then(function () { b.disabled = false; b.textContent = 'Entrar'; }); }); function abrirAyuda() { var d = $('ayuda'); d.open = true; if (!$('rNombre').value) $('rNombre').value = $('usuario').value.trim(); d.scrollIntoView({ behavior: 'smooth', block: 'start' }); setTimeout(function () { $('rDesc').focus(); }, 300); } $('ayuda').addEventListener('toggle', function () { if (this.open && !$('rNombre').value) $('rNombre').value = $('usuario').value.trim(); }); $('fReporte').addEventListener('submit', function (ev) { ev.preventDefault(); var b = $('bReporte'), msg = $('msgR'); var tipo = (document.querySelector('input[name="rTipo"]:checked') || {}).value || 'acceso'; var cuerpo = { nombre: $('rNombre').value.trim(), contacto: $('rContacto').value.trim(), descripcion: $('rDesc').value.trim(), tipo: tipo, sitio_web: $('rTrampa').value, pantalla: screen.width + '×' + screen.height }; if (cuerpo.descripcion.length < 5) { mensaje(msg, 'Cuéntanos qué pasa (aunque sea una línea).', false); return; } if (!cuerpo.nombre && !cuerpo.contacto) { mensaje(msg, 'Dinos quién eres o cómo contactarte.', false); return; } b.disabled = true; b.textContent = 'Enviando…'; fetch('/api/incidencias/publica', { method: 'POST', credentials: 'same-origin', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(cuerpo) }).then(function (r) { return r.json().catch(function () { return { ok: false, error: 'HTTP ' + r.status }; }); }) .then(function (j) { if (j && j.ok) { mensaje(msg, 'Recibido: ' + esc(j.id) + '. Se revisa todos los días; si dejaste cómo contactarte, te buscamos. ' + 'Guarda el folio por si preguntas.', true); $('rDesc').value = ''; } else { mensaje(msg, esc((j && j.error) || 'No se pudo enviar.'), false); } }) .catch(function () { mensaje(msg, 'No pude contactar al servidor. Avísale a Leo o a Gibran por mensaje.', false); }) .then(function () { b.disabled = false; b.textContent = 'Enviar reporte'; }); }); // avisos públicos fetch('/api/incidencias/publicas', { cache: 'no-store', credentials: 'same-origin' }) .then(function (r) { return r.ok ? r.json() : null; }) .then(function (j) { if (!j || !j.ok || !j.avisos || !j.avisos.length) return; var ul = $('avisosLista'); j.avisos.forEach(function (a) { var li = document.createElement('li'); li.innerHTML = '' + (a.resuelta ? 'Resuelto' : 'En atención') + '' + '' + esc(a.titulo) + ' ' + esc(a.actualizado) + ''; ul.appendChild(li); }); $('avisos').hidden = false; }) .catch(function () {}); })();