// Sections of the landing page
const { useState, useEffect, useRef } = React;
const M = window.Mockups;
const I = window.Icons;
// Reveal hook
function useReveal() {
const ref = useRef(null);
useEffect(() => {
const el = ref.current;
if (!el) return;
// Immediate check: if element is already in viewport, reveal now
const rect = el.getBoundingClientRect();
if (rect.top < window.innerHeight && rect.bottom > 0) {
el.classList.add('visible');
return;
}
const obs = new IntersectionObserver(
(entries) => {
entries.forEach(e => {
if (e.isIntersecting) {
e.target.classList.add('visible');
obs.unobserve(e.target);
}
});
},
{ threshold: 0.05, rootMargin: '0px 0px -10% 0px' }
);
obs.observe(el);
// Safety fallback: force visible after 1.5s no matter what
const fallback = setTimeout(() => {
el.classList.add('visible');
obs.disconnect();
}, 1500);
return () => { obs.disconnect(); clearTimeout(fallback); };
}, []);
return ref;
}
const Reveal = ({ children, delay = 0, className = "" }) => {
const ref = useReveal();
return (
{children}
);
};
// Logo
const Logo = ({ light = false }) => (
Ecclesia Hub
);
// Header
const Header = ({ lang, setLang, t }) => {
const [scrolled, setScrolled] = useState(false);
const [langOpen, setLangOpen] = useState(false);
const [mobileOpen, setMobileOpen] = useState(false);
useEffect(() => {
const onScroll = () => setScrolled(window.scrollY > 20);
window.addEventListener('scroll', onScroll);
return () => window.removeEventListener('scroll', onScroll);
}, []);
const current = window.LANGS.find(l => l.code === lang);
return (
);
};
// Hero
const Hero = ({ t }) => (
{t.hero.eyebrow}
{t.hero.headline}
{t.hero.sub}
{t.hero.badges.map((b, i) => (
{[, , ][i]}
{b}
))}
);
// Trust Bar
const TrustBar = ({ t }) => {
const icons = [I.Building, I.Users, I.Shield, I.Cloud, I.Lock, I.RefreshCw];
return (
{t.trust.title}
{t.trust.items.map((item, i) => {
const Ic = icons[i];
return (
{item}
{i < t.trust.items.length - 1 && •}
);
})}
);
};
// Features (3 pillars)
const Features = ({ t }) => {
const icons = [I.Globe, I.Users, I.LayoutDashboard];
const colors = ['blue', 'amber', 'emerald'];
return (
3 Pilares
{t.features.title}
{t.features.sub}
{t.features.items.map((f, i) => {
const Ic = icons[i];
const c = colors[i];
return (
0{i + 1}
{f.title}
{f.desc}
);
})}
);
};
// Benefits
const Benefits = ({ t }) => {
const icons = [I.Clock, I.DollarSign, I.BookOpen, I.BarChart, I.Palette, I.Cloud];
return (
Por que Ecclesia Hub
{t.benefits.title}
{t.benefits.sub}
{t.benefits.items.map((b, i) => {
const Ic = icons[i];
return (
);
})}
);
};
// How it works
const HowItWorks = ({ t }) => (
Como Funciona
{t.how.title}
{t.how.sub}
{t.how.steps.map((s, i) => (
))}
);
// Showcase (zigzag)
const Showcase = ({ t }) => {
const mockups = [M.FinancialMockup, M.CheckinMockup, M.EADMockup];
const icons = [I.DollarSign, I.QrCode, I.BookOpen];
const accents = ['blue', 'amber', 'emerald'];
return (
Recursos
{t.showcase.title}
{t.showcase.sub}
{t.showcase.items.map((item, i) => {
const Mock = mockups[i];
const Ic = icons[i];
const c = accents[i];
const reverse = i % 2 === 1;
return (
Recurso {i + 1}
{item.title}
{item.desc}
);
})}
);
};
// Testimonials
const Testimonials = ({ t }) => {
const gradients = ['from-blue-500 to-indigo-600', 'from-amber-500 to-orange-600', 'from-emerald-500 to-teal-600'];
return (
Prova Social
{t.testimonials.title}
{t.testimonials.sub}
{t.testimonials.items.map((tst, i) => {
const initials = tst.name.split(' ').slice(-2).map(w => w[0]).join('');
return (
{[...Array(5)].map((_, j) => )}
"{tst.quote}"
{initials}
{tst.name}
{tst.role} · {tst.church}
{tst.size}
);
})}
);
};
// Pricing
const Pricing = ({ t, currency }) => {
const [yearly, setYearly] = useState(true);
const p = window.PRICING[currency.code];
const fmt = (v) => {
if (currency.code === 'BRL') return `${currency.symbol} ${v}`;
if (currency.code === 'EUR') return `${currency.symbol} ${v}`;
if (currency.code === 'GBP') return `${currency.symbol}${v}`;
return `${currency.symbol}${v}`;
};
return (
Preços
{t.pricing.title}
{t.pricing.sub}
{/* Monthly card */}
{t.pricing.monthlyPlan.label}
{t.pricing.monthlyPlan.name}
{fmt(p.monthly)}
{t.pricing.monthlyPlan.period}
{t.pricing.features.map((f, i) => (
-
{f}
))}
{/* Yearly card */}
{t.pricing.bestValue}
{t.pricing.yearlyPlan.label}
{t.pricing.yearlyPlan.name}
{fmt(p.yearly)}
{t.pricing.yearlyPlan.period}
≈ {fmt(p.perMonthYearly)}/mês · {t.pricing.yearlyPlan.save} {fmt(p.savings)}
{t.pricing.yearlyExtras.map((f, i) => (
-
0 ? 'font-semibold' : ''}>{f}
))}
{t.pricing.features.slice(0, -1).map((f, i) => (
-
{f}
))}
{[I.Lock, I.RefreshCw, I.Check].map((Ic, i) => (
{t.pricing.seals[i]}
))}
);
};
// FAQ
const FAQ = ({ t }) => {
const [open, setOpen] = useState(0);
return (
FAQ
{t.faq.title}
{t.faq.sub}
{t.faq.items.map((item, i) => (
))}
);
};
// Final CTA
const FinalCTA = ({ t }) => (
Junte-se à comunidade
{t.finalCta.title}
{t.finalCta.sub}
{t.finalCta.support}
);
// Footer
const Footer = ({ t }) => {
const socials = [I.Instagram, I.Youtube, I.Facebook];
return (
);
};
window.Sections = { Header, Hero, TrustBar, Features, Benefits, HowItWorks, Showcase, Testimonials, Pricing, FAQ, FinalCTA, Footer };