// services.jsx — Services page for Version Française Pour Elle // Real HTML menu, verified hair prices, "Book on Fresha" for unverified. function ServicesPage({ lang }) { const D = window.VFPE_DATA; const t = D.t[lang]; const [active, setActive] = React.useState("hair"); // Sticky category nav — IntersectionObserver tracks which section is in view. React.useEffect(() => { const opts = { rootMargin: "-120px 0px -50% 0px", threshold: 0 }; const io = new IntersectionObserver((entries) => { entries.forEach((e) => { if (e.isIntersecting) setActive(e.target.id); }); }, opts); document.querySelectorAll("[data-cat]").forEach((el) => io.observe(el)); return () => io.disconnect(); }, []); const scrollTo = (id) => { const el = document.getElementById(id); if (!el) return; const top = el.getBoundingClientRect().top + window.scrollY - 130; window.scrollTo({ top, behavior: "smooth" }); }; return (
{/* ── Hero band ─────────────────────────────────────────── */}
{lang === "fr" ? "La Carte" : "The Menu"}

{lang === "fr" ? <>Soins & rituels,
tarifs en clair. : <>Treatments & rituals,
prices in plain sight.}

{lang === "fr" ? "Tous les tarifs « cheveux » sont publiés. Pour les autres prestations, réservez sur Fresha — un devis vous est proposé en quelques secondes." : "All hair prices are published. For other treatments, book through Fresha — you'll see your quote in seconds."}

{/* ── Sticky category nav ──────────────────────────────── */}
{D.services.map((s) => ( ))}
{/* ── Category sections ────────────────────────────────── */}
{D.services.map((cat, idx) => ( ))}
{/* ── Book band ────────────────────────────────────────── */}
); } // ── Category section ──────────────────────────────────────────── function CategorySection({ cat, lang, idx }) { const t = window.VFPE_DATA.t[lang]; // Pair each category with a fresha image for context (Tier A only — real Al Wasl rooms). const imageMap = { hair: "media/images/fresha-gallery-02.webp", // hair wash bay nails: "media/images/fresha-gallery-05.webp", // nail suite eyes: "media/images/fresha-gallery-06.webp", // treatment cabin facials: "media/images/fresha-gallery-06.webp", massage: "media/images/fresha-gallery-08.webp", // pedicure/lounge waxing: "media/images/fresha-gallery-06.webp", lycon: "media/images/fresha-gallery-06.webp", moroccan: "media/images/fresha-gallery-07.webp", // hammam }; const imageCaption = { hair: { en: "Hair Wash Bay", fr: "Espace shampooing" }, nails: { en: "Nail Suite", fr: "Espace ongles" }, eyes: { en: "Treatment Cabin",fr: "Cabine de soins" }, facials: { en: "Facial Cabin", fr: "Cabine soins du visage" }, massage: { en: "Body Cabin", fr: "Cabine corps" }, waxing: { en: "Wax Cabin", fr: "Cabine épilation" }, lycon: { en: "Lycon Cabin", fr: "Cabine Lycon" }, moroccan: { en: "Moroccan Hammam",fr: "Hammam marocain" }, }; return (
{/* Left — context image + tag */}
{L(imageCaption[cat.id],
{String(idx + 1).padStart(2, "0")} {L(imageCaption[cat.id], lang)}
{cat.id === "moroccan" ? "Hammam" : L({ en: cat.en, fr: cat.fr }, lang)}
{/* Right — service list */}
{String(idx + 1).padStart(2, "0")} / {window.VFPE_DATA.services.length.toString().padStart(2, "0")}

{L({ en: cat.en, fr: cat.fr }, lang)}

{!cat.verified && (
{lang === "fr" ? "Tarifs sur devis — confirmés sur Fresha à la réservation." : "Prices on request — confirmed on Fresha at booking."}
)}
    {cat.items.map((item, i) => ( ))}
{t.bookOnFresha}
); } // ── Single service row ───────────────────────────────────────── function ServiceRow({ item, lang, verified }) { const t = window.VFPE_DATA.t[lang]; return (
  • {L(item.name, lang)} {item.signature && ( {lang === "fr" ? "Signature" : "Signature"} )}
    {item.duration && {item.duration}} {verified && item.price != null ? ( <> {item.from && {t.from}} {t.aed} {item.price.toLocaleString(lang === "fr" ? "fr-FR" : "en-US")} ) : {t.bookOnFresha} }
  • ); } Object.assign(window, { ServicesPage });