// ───────────────────────────────────────────────────────────── // main.jsx — App shell, state, routing, PDF wire-up // ───────────────────────────────────────────────────────────── const { useState, useEffect, useRef, useCallback } = React; // Detect if we are inside an iframe (e.g. embedded in WordPress). // Adds .is-embedded to
so CSS can collapse `min-height: 100vh`, // which would otherwise force the body to fill the iframe and make // auto-resize stick to the tallest screen ever rendered. if (typeof window !== 'undefined' && window.parent && window.parent !== window) { try { document.body.classList.add('is-embedded'); } catch (e) { /* noop */ } } const IS_EMBEDDED = typeof window !== 'undefined' && window.parent && window.parent !== window; // Reports our own content height to the parent page. The iframe measures // itself — the parent never reads our DOM, so this works regardless of // cross-origin rules, CSP, or the parent's script environment. function reportHeight() { if (!IS_EMBEDDED) return; try { const h = Math.max( document.body.scrollHeight, document.body.offsetHeight, document.documentElement.offsetHeight ); window.parent.postMessage({ type: 'alfa-diag:height', height: h }, '*'); } catch (e) { /* noop */ } } // Keep the parent in sync: on load, on resize, and whenever our own // content box changes size (view switches, answers expanding, fonts). if (IS_EMBEDDED) { window.addEventListener('load', reportHeight); window.addEventListener('resize', reportHeight); try { new ResizeObserver(reportHeight).observe(document.documentElement); } catch (e) { setInterval(reportHeight, 500); } setInterval(reportHeight, 1000); // safety net } // Scrolls the diagnostic view to top. // When embedded inside an iframe (e.g. WordPress page), also notifies // the parent so the OUTER page scrolls to the iframe's top — otherwise // the user sees the bottom of the iframe after each view change. function scrollDiagToTop() { try { window.scrollTo({ top: 0, behavior: 'smooth' }); } catch (e) { /* noop */ } if (IS_EMBEDDED) { try { window.parent.postMessage({ type: 'alfa-diag:scroll-to-top' }, '*'); } catch (e) { /* cross-origin / silent */ } } // Height changes with the view — report right away and again after paint. reportHeight(); setTimeout(reportHeight, 60); setTimeout(reportHeight, 400); } function App() { const [view, setView] = useState('inicio'); // inicio | encuesta | resultados | gracias const [areaIdx, setAreaIdx] = useState(0); const [respuestas, setRespuestas] = useState({}); const [resultados, setResultados] = useState(null); const [leadData, setLeadData] = useState(null); const [pdfBlob, setPdfBlob] = useState(null); const [isSubmitting, setIsSubmitting] = useState(false); const [leadFormError, setLeadFormError] = useState(null); function handleStart() { setView('encuesta'); setAreaIdx(0); scrollDiagToTop(); } function handleAnswer(key, value) { setRespuestas(prev => ({...prev, [key]: value})); } function handleNextArea() { if (areaIdx === AREAS.length - 1) { // compute results const res = computeResultados(respuestas); setResultados(res); setView('resultados'); scrollDiagToTop(); } else { setAreaIdx(prev => prev + 1); scrollDiagToTop(); } } function handlePrevArea() { setAreaIdx(prev => Math.max(0, prev - 1)); scrollDiagToTop(); } async function handleLeadSubmit(form) { setLeadFormError(null); if (!form.nombre || !form.empresa || !form.cargo || !form.email || !form.email.includes('@')) { setLeadFormError('Por favor completa todos los campos con información válida.'); return; } setIsSubmitting(true); setLeadData(form); // Fire-and-forget submission to ActiveCampaign. // We do NOT await this — the PDF download must never be blocked // by network conditions or AC availability. if (typeof window.submitToActiveCampaign === 'function') { window.submitToActiveCampaign(form); } try { const blob = await generatePDF(form, resultados); setPdfBlob(blob); triggerDownload(blob, form); setView('gracias'); scrollDiagToTop(); } catch (err) { console.error(err); setLeadFormError('Hubo un error generando el PDF. Intenta de nuevo.'); } finally { setIsSubmitting(false); } } function handleReDownload() { if (pdfBlob && leadData) triggerDownload(pdfBlob, leadData); } // progress const totalQ = AREAS.length * 6; const respCount = Object.keys(respuestas).length; const pct = Math.round((respCount / totalQ) * 100); return ( <>