feat(lugar): formulario embebido como modal en lugar de iframe inline

- Botón "Abrir formulario de firma" en ficha abre modal overlay
- Modal con iframe cargando ver_formulario_enviado.php?embed=1
- postMessage 'turneroFirmado' cierra modal, refresca consentimientos y oculta botón
- Token pre-cargado al abrir ficha para apertura rápida del modal

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Lizandro Guarnizo
2026-07-03 12:16:22 -05:00
co-authored by Claude Sonnet 4.6
parent 27135e4d2f
commit a0189a61eb
+97 -27
View File
@@ -322,16 +322,12 @@ require_once __DIR__ . '/../../../shared/components/sidebar.php';
</div>
<!-- ── Sección: Consentimientos ── -->
<!-- ── Formulario embebido (modo=embebido) ── -->
<!-- ── Botón firma embebida (modo=embebido) ── -->
<div class="ficha-sec d-none" id="sec-form-embebido">
<h6><i class="fas fa-file-alt me-1"></i>Formulario de consentimiento</h6>
<div id="form-embebido-loading" class="text-muted small py-2">
<i class="fas fa-spinner fa-spin me-1"></i>Cargando formulario...
</div>
<iframe id="form-embebido-iframe" src="" frameborder="0"
style="width:100%;min-height:520px;border-radius:8px;border:1px solid #e2e8f0;display:none"
onload="this.style.display='block';document.getElementById('form-embebido-loading').style.display='none'">
</iframe>
<h6><i class="fas fa-file-signature me-1"></i>Consentimiento informado</h6>
<button class="btn btn-primary w-100" onclick="abrirModalConsentimiento()">
<i class="fas fa-pen me-2"></i>Abrir formulario de firma
</button>
</div>
<div class="ficha-sec" id="sec-consent">
@@ -393,6 +389,38 @@ require_once __DIR__ . '/../../../shared/components/sidebar.php';
</div><!-- /lugar-layout -->
</main>
<!-- ── Modal de consentimiento embebido ──────────────────────── -->
<div id="modal-consentimiento" style="
display:none;position:fixed;inset:0;z-index:9000;
background:rgba(0,0,0,.55);align-items:center;justify-content:center;padding:16px">
<div style="
background:#fff;border-radius:14px;box-shadow:0 8px 40px rgba(0,0,0,.25);
width:min(96vw,680px);max-height:92vh;
display:flex;flex-direction:column;overflow:hidden">
<!-- Header modal -->
<div style="
display:flex;align-items:center;justify-content:space-between;
padding:12px 18px;border-bottom:1px solid #e2e8f0;flex-shrink:0">
<span style="font-weight:700;font-size:.95rem;color:#1e293b">
<i class="fas fa-file-signature me-2 text-primary"></i>Formulario de consentimiento
</span>
<button onclick="cerrarModalConsentimiento()"
style="background:none;border:none;font-size:1.2rem;color:#94a3b8;cursor:pointer;padding:2px 6px">
<i class="fas fa-times"></i>
</button>
</div>
<!-- Loading -->
<div id="modal-consent-loading" style="padding:32px;text-align:center;color:#64748b;flex-shrink:0">
<i class="fas fa-spinner fa-spin fa-2x mb-2 d-block"></i>Cargando formulario…
</div>
<!-- Iframe -->
<iframe id="modal-consent-iframe" src="" frameborder="0"
style="flex:1;border:none;display:none;min-height:60vh"
onload="document.getElementById('modal-consent-loading').style.display='none';this.style.display='block'">
</iframe>
</div>
</div>
<script>
// ── Estado global ─────────────────────────────────────────────
@@ -858,41 +886,83 @@ async function cambiarEstadoTurno(nuevoEstado) {
}
}
// ── Reset ─────────────────────────────────────────────────────
// ── Embebido como modal ───────────────────────────────────────
let _consentTokenCache = null; // { turnoId, token }
async function cargarFormEmbebido(turnoId) {
const sec = document.getElementById('sec-form-embebido');
const iframe = document.getElementById('form-embebido-iframe');
const load = document.getElementById('form-embebido-loading');
if (!sec || !iframe) return;
sec.classList.remove('d-none');
iframe.style.display = 'none';
load.style.display = '';
const sec = document.getElementById('sec-form-embebido');
if (sec) sec.classList.remove('d-none');
// Pre-cargar token para que el modal abra rápido
try {
const res = await fetch(`${API}get_consent_token.php?turno_id=${turnoId}&lugar_id=${lugarId}`);
const json = await res.json();
if (json.ok && json.token) {
iframe.src = `${BASE_WA}ver_formulario_enviado.php?token=${encodeURIComponent(json.token)}&embed=1`;
_consentTokenCache = { turnoId, token: json.token };
} else {
load.innerHTML = '<span class="text-danger small"><i class="fas fa-exclamation-triangle me-1"></i>' + (json.error || 'No hay formulario configurado') + '</span>';
_consentTokenCache = null;
if (sec) sec.innerHTML = `<h6><i class="fas fa-file-signature me-1"></i>Consentimiento informado</h6>
<div class="text-danger small"><i class="fas fa-exclamation-triangle me-1"></i>${json.error || 'Sin formulario configurado'}</div>`;
}
} catch (e) {
load.innerHTML = '<span class="text-danger small"><i class="fas fa-exclamation-triangle me-1"></i>Error al cargar formulario</span>';
_consentTokenCache = null;
}
}
function abrirModalConsentimiento() {
if (!_consentTokenCache) { mostrarError('Token de consentimiento no disponible.'); return; }
const modal = document.getElementById('modal-consentimiento');
const iframe = document.getElementById('modal-consent-iframe');
const load = document.getElementById('modal-consent-loading');
iframe.style.display = 'none';
iframe.src = '';
load.style.display = '';
modal.style.display = 'flex';
// Pequeño delay para que el modal sea visible antes de cargar el iframe
setTimeout(() => {
iframe.src = `${BASE_WA}ver_formulario_enviado.php?token=${encodeURIComponent(_consentTokenCache.token)}&embed=1`;
}, 80);
}
function cerrarModalConsentimiento() {
const modal = document.getElementById('modal-consentimiento');
const iframe = document.getElementById('modal-consent-iframe');
modal.style.display = 'none';
iframe.src = '';
iframe.style.display = 'none';
document.getElementById('modal-consent-loading').style.display = '';
// Refrescar estado del consentimiento
if (turnoActivo) actualizarConsentimientos(turnoActivo.id);
}
// Cerrar modal si se firma desde el iframe
window.addEventListener('message', function(e) {
if (e.data && e.data.type === 'turneroFirmado') {
cerrarModalConsentimiento();
mostrarToast('Consentimiento firmado ✓', 'success', 3000);
if (turnoActivo) actualizarConsentimientos(turnoActivo.id);
// Ocultar botón de firma
const sec = document.getElementById('sec-form-embebido');
if (sec) sec.classList.add('d-none');
}
});
function resetFicha() {
clearInterval(pollingConsentId);
turnoActivo = null;
tieneConsent = false;
hayPendientes = false;
_consentTokenCache = null;
// Limpiar iframe embebido
const iframe = document.getElementById('form-embebido-iframe');
const sec = document.getElementById('sec-form-embebido');
const load = document.getElementById('form-embebido-loading');
if (iframe) { iframe.src = ''; iframe.style.display = 'none'; }
if (sec) { sec.classList.add('d-none'); }
if (load) { load.style.display = ''; load.innerHTML = '<i class="fas fa-spinner fa-spin me-1"></i>Cargando formulario...'; }
// Limpiar modal embebido
cerrarModalConsentimiento();
const sec = document.getElementById('sec-form-embebido');
if (sec) {
sec.classList.add('d-none');
sec.innerHTML = `<h6><i class="fas fa-file-signature me-1"></i>Consentimiento informado</h6>
<button class="btn btn-primary w-100" onclick="abrirModalConsentimiento()">
<i class="fas fa-pen me-2"></i>Abrir formulario de firma
</button>`;
}
document.getElementById('ficha-turno').classList.add('d-none');
document.getElementById('ficha-placeholder').classList.remove('d-none');