// App.jsx — assemble la page d'accueil. La modale de réservation vit dans
// BookingModal.jsx (partagée avec les pages de détail des offres).
const App = () => {
const [bookingOpen, setBookingOpen] = React.useState(false);
const [activeSection, setActiveSection] = React.useState('top');
const [showTop, setShowTop] = React.useState(false);
const [cookieBannerVisible, setCookieBannerVisible] = React.useState(false);
// Surlignage du lien actif (offset = hauteur réelle du nav sticky) + bouton retour-haut (D6)
React.useEffect(() => {
const ids = ['offres', 'preuves', 'methode', 'studio-digital', 'faq'];
const onScroll = () => {
const y = window.scrollY + 80;
let cur = 'top';
for (const id of ids) {
const el = document.getElementById(id);
if (el && el.offsetTop <= y) cur = id;
}
setActiveSection(cur);
setShowTop(window.scrollY > 600);
};
window.addEventListener('scroll', onScroll, { passive: true });
onScroll();
return () => window.removeEventListener('scroll', onScroll);
}, []);
// Scroll vers la section ciblée par le hash au premier rendu (D6) — nécessaire
// car le contenu est monté par React après le chargement de la page : le
// saut d'ancre natif du navigateur arrive trop tôt et rate sa cible quand on
// clique un lien de nav depuis une page satellite (ex. offres/support.html).
React.useEffect(() => {
const hash = window.location.hash.slice(1);
if (!hash) return;
const el = document.getElementById(hash);
if (el) {
requestAnimationFrame(() => window.scrollTo({ top: el.offsetTop - 80 }));
}
}, []);
// Reveal au scroll (A1/A2) — IntersectionObserver, respecte reduced-motion via CSS
React.useEffect(() => {
const els = document.querySelectorAll('.b2a-reveal');
if (!('IntersectionObserver' in window)) {
els.forEach((el) => el.classList.add('b2a-reveal-in'));
return;
}
const io = new IntersectionObserver((entries) => {
entries.forEach((e) => {
if (e.isIntersecting) {
e.target.classList.add('b2a-reveal-in');
io.unobserve(e.target);
}
});
}, { threshold: 0.12, rootMargin: '0px 0px -8% 0px' });
els.forEach((el) => io.observe(el));
return () => io.disconnect();
}, []);
const open = () => setBookingOpen(true);
const toTop = () => window.scrollTo({ top: 0, behavior: 'smooth' });
return (
<>
{bookingOpen && setBookingOpen(false)} />}
>
);
};
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render();