(function() { 'use strict'; // State let currentStep = 1; let selectedSlot = null; let identificacionData = null; // DOM refs const $ = (sel) => document.querySelector(sel); const $$ = (sel) => document.querySelectorAll(sel); // Steps const steps = $$('.step'); const panels = $$('.step-panel'); function showStep(n) { currentStep = n; steps.forEach((s, i) => { s.classList.toggle('active', i < n); s.classList.toggle('current', i === n - 1); }); panels.forEach((p, i) => { p.classList.toggle('active', i === n - 1); }); if (n === 3) loadAvailability(); if (n === 4) setupCaptcha(); window.scrollTo({ top: 0, behavior: 'smooth' }); } // Step 1 -> 2 $('#btn-step1').addEventListener('click', () => showStep(2)); // Step 2 -> 3 $('#form-identificacion').addEventListener('submit', function(e) { e.preventDefault(); const fd = new FormData(this); const data = Object.fromEntries(fd.entries()); // Basic validation if (!data.tipo_documento || !data.documento || !data.nombre) return alert('Complete los campos obligatorios.'); if (!data.telefono || !data.email) return alert('Complete los campos obligatorios.'); identificacionData = data; showStep(3); }); // Back buttons $('#btn-back-2').addEventListener('click', () => showStep(1)); $('#btn-back-4').addEventListener('click', () => showStep(3)); // Step 3: Load availability async function loadAvailability() { const loading = $('#availability-loading'); const empty = $('#availability-empty'); const list = $('#availability-slots'); loading.style.display = 'block'; empty.style.display = 'none'; list.style.display = 'none'; try { const res = await fetch('/api/availability'); const json = await res.json(); loading.style.display = 'none'; if (!json.available || json.slots.length === 0) { empty.style.display = 'block'; return; } list.innerHTML = ''; json.slots.forEach(slot => { const div = document.createElement('div'); div.className = 'slot-item'; div.innerHTML = `
Error al consultar disponibilidad. Inténtelo de nuevo.
'; console.error(err); } } // Step 4: Captcha function setupCaptcha() { const banner = $('#test-mode-banner'); const submitBtn = $('#btn-submit-reserva'); // Check test mode from backend fetch('/health').then(r => r.json()).then(() => { // In test mode, show banner and auto-enable submit banner.style.display = 'block'; submitBtn.disabled = false; }).catch(() => { // Load real reCAPTCHA const script = document.createElement('script'); script.src = 'https://www.google.com/recaptcha/api.js'; script.onload = function() { try { grecaptcha.render('g-recaptcha', { sitekey: document.body.dataset.sitekey || '', callback: function(token) { $('#captcha-token').value = token; submitBtn.disabled = false; } }); } catch(e) { console.warn('reCAPTCHA load failed:', e); } }; document.head.appendChild(script); }); submitBtn.addEventListener('click', submitReservation); } // Step 5: Submit reservation async function submitReservation() { const submitBtn = $('#btn-submit-reserva'); submitBtn.disabled = true; submitBtn.textContent = 'Procesando...'; try { // Validate captcha server-side if not test mode const token = $('#captcha-token').value; if (!document.querySelector('.test-mode-banner')) { const capRes = await fetch('/api/captcha/validate', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ token }) }); const capJson = await capRes.json(); if (!capJson.valid) { alert('Verificación de seguridad fallida. Inténtelo de nuevo.'); submitBtn.disabled = false; submitBtn.textContent = 'Confirmar reserva'; return; } } // Submit reservation const res = await fetch('/api/reservas', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ slot_id: selectedSlot.id, identificacion: identificacionData, captcha_token: token, }) }); const json = await res.json(); if (res.ok) { showConfirmation(json.reserva); } else { alert(json.detail || 'Error al reservar. Inténtelo de nuevo.'); submitBtn.disabled = false; submitBtn.textContent = 'Confirmar reserva'; } } catch (err) { alert('Error de conexi\u00f3n. Int\u00e9ntelo de nuevo.'); console.error(err); } } function showConfirmation(reserva) { const details = $('#confirmation-details'); const docMask = reserva.documento.length > 4 ? reserva.documento.substring(0, 2) + '****' + reserva.documento.slice(-1) : '****'; details.innerHTML = `C\u00f3digo de reserva: ${reserva.codigo}
Fecha: ${reserva.fecha}
Hora: ${reserva.hora}
Oficina: ${reserva.oficina}
Nombre: ${reserva.nombre}
Documento: ${docMask}
Email: ${reserva.email}
Guarde este c\u00f3digo para consultar su reserva.
`; showStep(5); } // Init showStep(1); })();