Kiosko: auto-turno solo por escáner (ráfaga <35ms o Enter), nunca a mano

Escribir manualmente ya no dispara el turno: la persona oprime el botón.
El lector de cédula sí lo dispara porque mete los dígitos en ráfaga
(<35ms entre cada uno) o termina con Enter. Guard contra doble envío.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Lizandro Guarnizo
2026-06-23 09:51:58 -05:00
co-authored by Claude Opus 4.8
parent 71d29f35fa
commit 506f3469b4
+44 -13
View File
@@ -503,20 +503,44 @@ unset($p);
});
}
// ── Scanner detector (un solo listener, fuera de seleccionarPrioridad) ──
let _timerAutoSubmit = null;
let _lastKeyAt = 0;
// ── Detector de escáner ──────────────────────────────────────────
// Escribir a mano NUNCA dispara el turno (la persona oprime el botón).
// Solo el lector de cédula lo dispara: mete los dígitos en ráfaga
// (<35 ms entre cada uno, imposible a mano) y/o termina con Enter.
let _keyTimes = []; // timestamps de cada pulsación
let _timerRafaga = null;
let _timerInactividad = null;
const _inpCedula = document.getElementById('inp-cedula');
document.getElementById('inp-cedula').addEventListener('input', () => {
clearTimeout(_timerAutoSubmit);
// Solo es ráfaga de escáner si TODAS las pulsaciones (≥5) llegaron <35 ms
function esRafagaScanner() {
if (_keyTimes.length < 5) return false;
for (let i = 1; i < _keyTimes.length; i++) {
if (_keyTimes[i] - _keyTimes[i - 1] > 35) return false;
}
return true;
}
_inpCedula.addEventListener('input', () => {
resetInactividad();
const now = Date.now();
const gap = now - _lastKeyAt;
_lastKeyAt = now;
const val = document.getElementById('inp-cedula').value.trim();
if (/^\d{5,15}$/.test(val) && gap < 80) {
_timerAutoSubmit = setTimeout(() => confirmarTurno(), 300);
_keyTimes.push(Date.now());
if (_keyTimes.length > 25) _keyTimes.shift();
// Tras una breve pausa revisamos: si fue ráfaga → escáner → disparar.
// Si fue escritura a mano (gaps grandes) esRafagaScanner() = false → no dispara.
clearTimeout(_timerRafaga);
_timerRafaga = setTimeout(() => {
const val = _inpCedula.value.trim();
if (/^\d{5,15}$/.test(val) && esRafagaScanner()) confirmarTurno();
}, 120);
});
// El lector casi siempre envía Enter al final → disparar de inmediato.
_inpCedula.addEventListener('keydown', (e) => {
if (e.key === 'Enter') {
e.preventDefault();
const val = _inpCedula.value.trim();
if (/^\d{5,15}$/.test(val)) confirmarTurno();
}
});
@@ -540,14 +564,18 @@ unset($p);
const inpCedula = document.getElementById('inp-cedula');
inpCedula.focus();
inpCedula.value = '';
_lastKeyAt = 0;
clearTimeout(_timerAutoSubmit);
_keyTimes = [];
clearTimeout(_timerRafaga);
resetInactividad();
}
function volverPrioridades() { clearTimeout(_timerInactividad); mostrar('screen-prio'); }
let _enviando = false;
async function confirmarTurno() {
if (_enviando) return; // evita doble disparo (ráfaga + Enter)
clearTimeout(_timerRafaga);
clearTimeout(_timerInactividad);
const cedula = document.getElementById('inp-cedula').value.trim();
const cel = document.getElementById('inp-cel').value.trim();
@@ -555,6 +583,7 @@ unset($p);
if (!/^\d{5,15}$/.test(cedula)) { mostrarError('La cédula debe tener solo dígitos (mínimo 5).'); return; }
if (cel && !/^\+?\d{7,15}$/.test(cel.replace(/\s/g,''))) { mostrarError('Ingrese un número de WhatsApp válido.'); return; }
_enviando = true;
setSpinner(true);
try {
const res = await fetch(API_URL, {
@@ -568,6 +597,8 @@ unset($p);
} catch (err) {
mostrarError(err.message);
setSpinner(false);
} finally {
_enviando = false;
}
}