/* eslint-disable */ /* global React, window, PAIN_LANDINGS */ const { useEffect, useMemo, useRef, useState } = React; const PAIN_KEYS = Object.keys(PAIN_LANDINGS); const GATEWAY_ROUTE_VERSION = '20260519-gateway-stagevideos'; const TRANSITION_MS = 520; const ACTIVATION_TAIL_MS = 1000; const BASE_IMAGE = '01_inicial_meditacion_fondo_negro'; const DIAGNOSTIC_VIDEOS = ['activation-01', 'activation-02', 'activation-03']; const STAGE_ACTIVATION_VIDEOS = ['activation-01', 'activation-02', 'activation-03']; const VISUAL_STATES = { neutral: { label: 'Calibración inicial', short: 'Sistema Cortex', video: 'activation-01', poster: BASE_IMAGE, }, sueno: { label: 'Ruido nocturno', short: 'Sueño', video: 'activation-02', poster: 'activation-02-poster', }, ruido: { label: 'Interferencia mental', short: 'Ruido mental', video: 'activation-02', poster: 'activation-02-poster', }, decisiones: { label: 'Opciones abiertas', short: 'Decisión', video: 'activation-02', poster: 'activation-02-poster', }, burnout: { label: 'Energía drenada', short: 'Energía', video: 'activation-01', poster: 'activation-01-poster', }, foco: { label: 'Atención dispersa', short: 'Foco', video: 'activation-03', poster: 'activation-03-poster', }, }; const PRELOAD_ASSETS = [ { id: BASE_IMAGE, type: 'image', url: 'assets/diagnostico/01_inicial_meditacion_fondo_negro.webp' }, { id: 'activation-01-poster', type: 'image', url: 'assets/diagnostico/activation-01-poster.jpg' }, { id: 'activation-02-poster', type: 'image', url: 'assets/diagnostico/activation-02-poster.jpg' }, { id: 'activation-03-poster', type: 'image', url: 'assets/diagnostico/activation-03-poster.jpg' }, ...DIAGNOSTIC_VIDEOS.map((id) => ({ id, type: 'video', url: `assets/diagnostico/${id}.mp4` })), ]; const QUESTIONS = [ { label: '01 / Lo que más pesa', title: <>¿Qué te está afectando más hoy?, help: 'Elige la frase que más se parece a tu día real.', options: [ { text: 'No puedo dormir o me despierto de madrugada', score: { sueno: 5 } }, { text: 'Mi cabeza no para y no logro cortar', score: { ruido: 5 } }, { text: 'Tengo información, pero sigo sin decidir', score: { decisiones: 5 } }, { text: 'Estoy agotado aunque sigo funcionando', score: { burnout: 5 } }, { text: 'Me disperso y no termino lo que empiezo', score: { foco: 5 } }, ], }, { label: '02 / Cuándo aparece', title: <>¿En qué momento se vuelve más evidente?, help: 'Esto afina la ruta sin hacerte contestar un formulario largo.', options: [ { text: 'De noche, cuando debería apagar', score: { sueno: 3, ruido: 2 } }, { text: 'Al despertar, cuando ya arranco sin energía', score: { burnout: 3, sueno: 1 } }, { text: 'Frente a una decisión importante', score: { decisiones: 4, ruido: 1 } }, { text: 'Cuando trabajo con pantalla, pestañas o redes', score: { foco: 4, burnout: 1 } }, { text: 'Después de conversaciones o estrés', score: { ruido: 3, burnout: 2 } }, ], }, { label: '03 / Primer cambio', title: <>Si esto mejora, ¿qué notarías primero?, help: 'La landing siguiente va a hablarte desde esa prioridad.', options: [ { text: 'Dormir de corrido y levantarme más liviano', score: { sueno: 4 } }, { text: 'Tener silencio mental aunque el día esté intenso', score: { ruido: 4 } }, { text: 'Decidir sin postergar tres meses', score: { decisiones: 4 } }, { text: 'Recuperar energía sin apilar más hábitos', score: { burnout: 4 } }, { text: 'Sostener foco real durante la mañana', score: { foco: 4 } }, ], }, ]; function gwAsset(path) { const prefix = window.CORTEX_ASSET_PREFIX || '../'; return `${prefix}${path}`; } function scoreToPain(scores) { const ranked = [...PAIN_KEYS].sort((a, b) => scores[b] - scores[a]); return ranked[0] || 'ruido'; } function visualPainFromScores(scores) { const hasScore = Object.values(scores).some((score) => score > 0); return hasScore ? scoreToPain(scores) : 'neutral'; } function optionTarget(option) { return Object.entries(option.score) .sort((a, b) => b[1] - a[1])[0]?.[0] || 'neutral'; } function emptyScores() { return PAIN_KEYS.reduce((acc, key) => ({ ...acc, [key]: 0 }), {}); } function scoresFromSelections(selections) { const nextScores = emptyScores(); Object.values(selections).forEach((option) => { Object.entries(option.score).forEach(([key, value]) => { nextScores[key] += value; }); }); return nextScores; } function answersFromSelections(selections) { return Object.keys(selections) .map(Number) .sort((a, b) => a - b) .map((index) => selections[index].text); } function safeStoreResult(pain, answers) { try { window.sessionStorage.setItem('cortex-gateway-result', JSON.stringify({ pain: pain.slug, answers, createdAt: new Date().toISOString(), })); } catch (_) { // Some embedded browsers block storage. The click must still navigate. } } function GatewayChrome() { return (
Academia Cortex
); } function GatewaySlideIndicator({ activeStep, onSelect }) { return ( ); } function GatewayLoading({ progress }) { return (
Academia Cortex {progress}%

Cargando diagnóstico

); } function GatewayMedia({ visualPain, activeVideoId, isHolding, videoSources, videoRefs }) { const visual = VISUAL_STATES[visualPain] || VISUAL_STATES.neutral; return ( ); } function HoldCue({ isHolding, hasHeld }) { return ( ); } function GatewayQuestion({ question, questionIndex, onPick, getHref, disabled, selectedText }) { return (
{question.label}

{question.title}

{question.help}

{question.options.map((option, index) => { const target = optionTarget(option); const content = ( <> {String(index + 1).padStart(2, '0')} {option.text} ); const href = getHref ? getHref(option) : null; const isSelected = selectedText === option.text; if (href) { return ( onPick(option, questionIndex, event)} aria-disabled={disabled ? 'true' : undefined} > {content} ); } return ( ); })}
); } function Gateway() { const videoRefs = useRef({}); const holdTimerRef = useRef(null); const stageRef = useRef(null); const slideRefs = useRef([]); const [activeStep, setActiveStep] = useState(0); const [selectedOptions, setSelectedOptions] = useState({}); const [activePulse, setActivePulse] = useState(null); const [hasHeld, setHasHeld] = useState(false); const [isHolding, setIsHolding] = useState(false); const [isTransitioning, setIsTransitioning] = useState(false); const [isExiting, setIsExiting] = useState(false); const [loadProgress, setLoadProgress] = useState(0); const [isReady, setIsReady] = useState(false); const [videoSources, setVideoSources] = useState({}); const transitionRef = useRef(null); const scores = useMemo(() => scoresFromSelections(selectedOptions), [selectedOptions]); const visualPain = activePulse || visualPainFromScores(scores); const visual = VISUAL_STATES[visualPain] || VISUAL_STATES.neutral; const activeVideoId = STAGE_ACTIVATION_VIDEOS[activeStep] || visual.video; useEffect(() => { let cancelled = false; const objectUrls = []; async function preload() { const sources = {}; let completed = 0; await Promise.all(PRELOAD_ASSETS.map(async (asset) => { try { const response = await fetch(gwAsset(asset.url), { cache: 'force-cache' }); if (!response.ok) throw new Error(`Could not load ${asset.url}`); const blob = await response.blob(); if (asset.type === 'video') { const objectUrl = URL.createObjectURL(blob); objectUrls.push(objectUrl); sources[asset.id] = objectUrl; } } catch (_) { if (asset.type === 'video') sources[asset.id] = gwAsset(asset.url); } finally { completed += 1; if (!cancelled) { setLoadProgress(Math.round((completed / PRELOAD_ASSETS.length) * 100)); } } })); if (!cancelled) { setVideoSources(sources); setLoadProgress(100); window.setTimeout(() => { if (!cancelled) setIsReady(true); }, 160); } } preload(); return () => { cancelled = true; objectUrls.forEach((url) => URL.revokeObjectURL(url)); }; }, []); useEffect(() => { if (!isReady) return; Object.values(videoRefs.current).forEach((video) => { video.muted = true; video.playsInline = true; video.loop = true; video.currentTime = 0.01; const promise = video.play(); if (promise?.catch) promise.catch(() => {}); }); }, [isReady, videoSources]); useEffect(() => { if (!isReady) return undefined; const stop = () => stopHold(); window.addEventListener('pointerup', stop); window.addEventListener('pointercancel', stop); window.addEventListener('touchend', stop, { passive: true }); window.addEventListener('touchcancel', stop, { passive: true }); window.addEventListener('mouseup', stop); window.addEventListener('blur', stop); return () => { window.removeEventListener('pointerup', stop); window.removeEventListener('pointercancel', stop); window.removeEventListener('touchend', stop); window.removeEventListener('touchcancel', stop); window.removeEventListener('mouseup', stop); window.removeEventListener('blur', stop); window.clearTimeout(holdTimerRef.current); }; }, [isReady, visualPain]); useEffect(() => { if (!isReady) return undefined; const stage = stageRef.current; if (!stage) return undefined; let frame = 0; const updateActiveStep = () => { frame = 0; const slideHeight = stage.clientHeight || window.innerHeight || 1; const nextStep = Math.max(0, Math.min(QUESTIONS.length - 1, Math.round(stage.scrollTop / slideHeight))); setActiveStep(nextStep); }; const handleScroll = () => { if (frame) return; frame = window.requestAnimationFrame(updateActiveStep); }; updateActiveStep(); stage.addEventListener('scroll', handleScroll, { passive: true }); return () => { stage.removeEventListener('scroll', handleScroll); if (frame) window.cancelAnimationFrame(frame); }; }, [isReady]); function clearTransition() { if (transitionRef.current) window.clearTimeout(transitionRef.current); } function scrollToStep(index, behavior = 'smooth') { const safeIndex = Math.max(0, Math.min(QUESTIONS.length - 1, index)); const stage = stageRef.current; const slide = slideRefs.current[safeIndex]; setActiveStep(safeIndex); if (stage && slide) { stage.scrollTo({ top: slide.offsetTop, behavior }); } } function startHold(event) { if (!isReady) return; if (event?.pointerType === 'mouse' && event.button !== 0) return; window.clearTimeout(holdTimerRef.current); setHasHeld(true); setIsHolding(true); const activeVideo = videoRefs.current[activeVideoId]; if (activeVideo) { const promise = activeVideo.play(); if (promise?.catch) promise.catch(() => {}); } } function stopHold() { window.clearTimeout(holdTimerRef.current); holdTimerRef.current = window.setTimeout(() => { setIsHolding(false); }, ACTIVATION_TAIL_MS); } function pick(option, questionIndex, event) { if (isTransitioning) { event?.preventDefault?.(); return; } const nextSelections = { ...selectedOptions, [questionIndex]: option }; const nextScores = scoresFromSelections(nextSelections); const nextAnswers = answersFromSelections(nextSelections); const isFinalStep = questionIndex + 1 >= QUESTIONS.length; const painKey = isFinalStep ? optionTarget(option) : scoreToPain(nextScores); const pain = PAIN_LANDINGS[painKey]; event?.currentTarget?.blur?.(); setSelectedOptions(nextSelections); setActivePulse(painKey); setIsTransitioning(true); stopHold(); if (isFinalStep) { event?.preventDefault?.(); safeStoreResult(pain, nextAnswers); setIsExiting(true); clearTransition(); transitionRef.current = window.setTimeout(() => { window.location.href = `${pain.slug}/?v=${GATEWAY_ROUTE_VERSION}`; }, TRANSITION_MS + 180); return; } clearTransition(); window.setTimeout(() => scrollToStep(questionIndex + 1), 40); transitionRef.current = window.setTimeout(() => { setActivePulse(null); setIsTransitioning(false); setIsHolding(false); }, TRANSITION_MS); } const routePreview = useMemo(() => { const pain = PAIN_LANDINGS[visualPain]; return pain?.short || visual.short; }, [visualPain, visual.short]); return (
event.preventDefault()} > {!isReady && }
{QUESTIONS.map((question, index) => (
{ if (node) slideRefs.current[index] = node; }} > = QUESTIONS.length ? (option) => `${PAIN_LANDINGS[optionTarget(option)].slug}/?v=${GATEWAY_ROUTE_VERSION}` : null} />
))}
{isExiting && (

Abriendo tu VSL personalizada

)}
); } window.Gateway = Gateway;