// Main app — interactive layer over the static HTML // Handles: prayer modal, request form, commitment counter, tweaks panel, scroll reveals const { useState, useEffect, useRef } = React; function t(key) { return (window.I18N && window.I18N.t(key)) || key; } function useLang() { const [lang, setLangState] = useState(() => (window.I18N ? window.I18N.getLang() : 'pt')); useEffect(() => { const h = (e) => setLangState(e.detail.lang); window.addEventListener('langchange', h); return () => window.removeEventListener('langchange', h); }, []); return lang; } const MYSTERY_IDS = ['joyful', 'sorrowful', 'glorious', 'luminous']; // ─── Tweaks defaults ───────────────────────────────────────────── const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{ "palette": ["#3A6CA2","#FFFFFF","#2F6099","#E6C57C"], "fontSize": 19, "showCandles": true, "particleIntensity": "soft" }/*EDITMODE-END*/; // ─── Prayer modal ──────────────────────────────────────────────── function PrayerModal({ open, onClose }) { const lang = useLang(); const [currentPrayer, setCurrentPrayer] = useState('hail-mary'); const [currentMystery, setCurrentMystery] = useState(0); if (!open) return null; const prayerTitle = t('prayer.' + currentPrayer + '.title'); const prayerBody = t('prayer.' + currentPrayer + '.body'); const mysteryId = MYSTERY_IDS[currentMystery]; const mysteryName = t('mystery.' + mysteryId + '.name'); const mysteryDay = t('mystery.' + mysteryId + '.day'); const mysteryList = t('mystery.' + mysteryId + '.list'); function handlePrayerClick(prayerKey, label) { setCurrentPrayer(prayerKey); } return (
e.stopPropagation()} style={{ maxWidth: '900px' }}>
{t('modal.eyebrow')}

{t('modal.title')}

{t('modal.subtitle')}

{t('modal.prayer.label')}

{prayerTitle}

{prayerBody}

{t('modal.mysteries.label')}
{MYSTERY_IDS.map((id, i) => ( ))}

{mysteryDay}

    {mysteryList.map((item, i) => (
  1. {item}
  2. ))}
); } // ─── Commitment counter ───────────────────────────────────────── function CommitmentCounter() { useLang(); // Real-feel counter: starts at a number, increments on commit const STORAGE_KEY = 'apostolado_commit_v1'; const COUNT_KEY = 'apostolado_count_v1'; const initialCount = 12473; const [count, setCount] = useState(() => { const stored = parseInt(localStorage.getItem(COUNT_KEY) || ''); return isNaN(stored) ? initialCount : stored; }); const [committed, setCommitted] = useState(() => localStorage.getItem(STORAGE_KEY) === '1'); const [bump, setBump] = useState(false); const counterRef = useRef(null); // Animate count from initialCount to count on mount useEffect(() => { const el = counterRef.current; if (!el) return; const target = count; const duration = 1800; const start = performance.now(); let frame; function tick(t) { const p = Math.min(1, (t - start) / duration); const eased = 1 - Math.pow(1 - p, 3); const val = Math.round(target * eased); el.textContent = val.toLocaleString('pt-BR'); if (p < 1) frame = requestAnimationFrame(tick); } // Only animate on first mount const seen = sessionStorage.getItem('counter_seen'); if (!seen) { frame = requestAnimationFrame(tick); sessionStorage.setItem('counter_seen', '1'); } else { el.textContent = target.toLocaleString('pt-BR'); } return () => frame && cancelAnimationFrame(frame); }, []); useEffect(() => { if (counterRef.current && sessionStorage.getItem('counter_seen')) { counterRef.current.textContent = count.toLocaleString('pt-BR'); } }, [count]); function handleCommit() { if (committed) return; setCommitted(true); localStorage.setItem(STORAGE_KEY, '1'); const next = count + 1; setCount(next); localStorage.setItem(COUNT_KEY, String(next)); setBump(true); setTimeout(() => setBump(false), 600); } return ( <>
{initialCount.toLocaleString('pt-BR')}
{t('crusade.counter.label')}
{committed && (

{t('crusade.thanks')}
{t('crusade.thanks2')}

)} ); } // ─── Prayer request form ──────────────────────────────────────── function PrayerRequestForm() { useLang(); const [submitted, setSubmitted] = useState(false); const [data, setData] = useState({ name: '', city: '', intention: '' }); function submit(e) { e.preventDefault(); if (!data.name || !data.intention) return; // Persist locally const all = JSON.parse(localStorage.getItem('prayer_requests') || '[]'); all.push({ ...data, at: Date.now() }); localStorage.setItem('prayer_requests', JSON.stringify(all)); setSubmitted(true); } if (submitted) { return (
); } return (
setData({...data, name: e.target.value})} required />
setData({...data, city: e.target.value})} />