/* sections.jsx — home page sections. Uses window shared primitives. */
const { useState: sS, useEffect: sE, useRef: sR } = React;
/* ---------------------------------- HERO ---------------------------------- */
function Hero({ lang, onNavigate }) {
const T = (v) => window.t(v, lang);
const H = window.OLV.hero, B = window.OLV.brand;
const photoRef = sR(null);
sE(() => {
const el = photoRef.current; if (!el) return;
const onScroll = () => { const y = window.scrollY; if (y < window.innerHeight) el.style.transform = `translateY(${y * 0.06}px) scale(1.04)`; };
window.addEventListener("scroll", onScroll, { passive: true });
return () => window.removeEventListener("scroll", onScroll);
}, []);
return (
);
}
/* --------------------------------- STATS ---------------------------------- */
function StatStrip({ lang }) {
const T = (v) => window.t(v, lang);
return (
{window.OLV.stats.map((s, i) => (
))}
);
}
/* ------------------------------ WHY (PMC) --------------------------------- */
function WhyPMC({ lang }) {
const T = (v) => window.t(v, lang);
const W = window.OLV.why;
return (
{T(W.overline)}
{T(W.title)}
{T(W.lead)}
{W.cards.map((c, i) => (
{c.n}
{T(c.title)}
{T(c.body)}
))}
);
}
/* ------------------------- 4-STAGE SCROLL FLOW ---------------------------- */
const STAGE_SLOTS = [
{ id: "stage-planning-3d", ph: "AI 3D render — planning: isometric blueprint site model, drawings unrolling, gold-on-charcoal" },
{ id: "stage-formulation-3d", ph: "AI 3D render — formulation: 3D building framework / GFC wireframe mid-construction, gold accents" },
{ id: "stage-execution-3d", ph: "AI 3D render — execution: cutaway tower with cranes & progress data overlay, cinematic dark" },
{ id: "stage-interiors-3d", ph: "AI 3D render — interiors: luxury interior with visible MEP/lighting layers, warm gold light" },
];
/* per-stage context overlay layered over the live 3D build */
function SceneHUD({ active, lang }) {
const T = (v) => window.t(v, lang);
const chip = (arr) =>
{arr.map((c, i) => {T(c)} )}
;
const planning = (
{T({ en: "Blueprint & Survey", hi: "ब्लूप्रिंट व सर्वेक्षण" })}
18.0m
{chip([{ en: "Site Survey", hi: "साइट सर्वे" }, { en: "Soil Testing", hi: "मृदा परीक्षण" }, { en: "Master Schedule", hi: "मास्टर शेड्यूल" }])}
);
const formulation = (
{T({ en: "Coordination & Vendors", hi: "समन्वय व वेंडर" })}
{[[{ en: "Tender", hi: "टेंडर" }, 90], [{ en: "GFC Drawings", hi: "जीएफसी" }, 72], [{ en: "MEP Coord.", hi: "एमईपी" }, 58], [{ en: "Mobilise", hi: "मोबिलाइज़" }, 40]].map((r, i) => (
{String(i + 1).padStart(2, "0")}
))}
{chip([{ en: "Vendor Selection", hi: "वेंडर चयन" }, { en: "Fortnightly Reviews", hi: "पाक्षिक समीक्षा" }])}
);
const execution = (
{T({ en: "Monthly Progress Report", hi: "मासिक प्रगति रिपोर्ट" })}
{[34, 46, 55, 63, 72, 84].map((h, i) => )}
84%{T({ en: "on schedule", hi: "समय पर" })}
{chip([{ en: "QA / QC", hi: "क्यूए/क्यूसी" }, { en: "Doc Control", hi: "दस्तावेज़ नियंत्रण" }, { en: "As-Built", hi: "ऐज़-बिल्ट" }])}
);
const integrated = (
{T({ en: "Integrated Works", hi: "एकीकृत कार्य" })}
{[["sparkle", { en: "Lighting", hi: "प्रकाश" }], ["layers", { en: "HVAC", hi: "एचवीएसी" }], ["flame", { en: "Fire Fighting", hi: "अग्निशमन" }], ["cpu", { en: "Automation", hi: "ऑटोमेशन" }], ["leaf", { en: "Landscaping", hi: "भूनिर्माण" }], ["sofa", { en: "Interiors", hi: "इंटीरियर" }]].map((m, i) => (
{T(m[1])}
))}
);
const panels = [planning, formulation, execution, integrated];
return (
{panels.map((p, i) =>
{p}
)}
);
}
function Stages({ lang }) {
const T = (v) => window.t(v, lang);
const S = window.OLV.stages, I = window.OLV.stagesIntro;
const wrapRef = sR(null), railRef = sR(null), canvasRef = sR(null), progRef = sR(null);
const [active, setActive] = sS(0);
const [noWebGL, setNoWebGL] = sS(false);
const activeRef = sR(0);
/* mount the real-time WebGL building (all viewports) */
sE(() => {
if (!canvasRef.current) return;
const B = window.OliveBuilding;
if (!B) { setNoWebGL(true); return; }
if (B.supported && !B.supported()) { setNoWebGL(true); return; }
B.mount(canvasRef.current);
B.setProgress(0);
const ro = new ResizeObserver(() => B.resize && B.resize());
ro.observe(canvasRef.current);
return () => { ro.disconnect(); B.dispose && B.dispose(); };
}, []);
/* scroll → building progress + stepper + rail */
sE(() => {
const wrap = wrapRef.current;
let raf = 0;
const onScroll = () => {
if (raf) return;
raf = requestAnimationFrame(() => {
raf = 0;
const r = wrap.getBoundingClientRect();
const total = wrap.offsetHeight - window.innerHeight;
const passed = Math.min(Math.max(-r.top, 0), total);
const p = total > 0 ? passed / total : 0; // 0..1 through section
const idx = Math.min(S.length - 1, Math.floor(p * S.length + 0.001));
if (railRef.current) railRef.current.style.height = (p * 100).toFixed(2) + "%";
if (progRef.current) progRef.current.textContent = Math.round(p * 100) + "%";
if (window.OliveBuilding) window.OliveBuilding.setProgress(p);
if (idx !== activeRef.current) { activeRef.current = idx; setActive(idx); }
});
};
window.addEventListener("scroll", onScroll, { passive: true });
onScroll();
return () => window.removeEventListener("scroll", onScroll);
}, [lang]);
const goStep = (i) => {
const wrap = wrapRef.current; if (!wrap) return;
const top = wrap.getBoundingClientRect().top + window.scrollY;
const total = wrap.offsetHeight - window.innerHeight;
const targetP = (i + 0.5) / S.length;
window.scrollTo({ top: top + targetP * total, behavior: "smooth" });
};
/* ---- sticky stepper + scroll-driven WebGL building (all viewports) ---- */
return (
{T(I.overline)}
{T(I.title)}
{T({ en: "Scroll — watch the project build itself, stage by stage.", hi: "स्क्रॉल करें — देखें प्रोजेक्ट को चरण-दर-चरण बनते हुए।" })}
{S.map((s, i) => (
goStep(i)} aria-current={i === active}>
{s.no} · {T(s.key)}
{T(s.title)}
))}
{S.map((s, i) => (
{T(s.title)}
{T(s.body)}
{s.points.map((pt, j) => {T(pt)} )}
))}
{noWebGL &&
{T({ en: "Enable WebGL to view the live 3D build.", hi: "लाइव 3D निर्माण देखने हेतु WebGL सक्षम करें।" })}
}
{S[active].no} — {T(S[active].key)}
{T({ en: "Real-time build", hi: "रीयल-टाइम निर्माण" })}
0%
);
}
/* ------------------------------ PILLARS ----------------------------------- */
function Pillars({ lang }) {
const T = (v) => window.t(v, lang);
return (
);
}
function ChooseGrid({ lang }) {
const T = (v) => window.t(v, lang);
const C = window.OLV.choose;
const icons = ["handshake", "shield-check", "clock", "compass", "trending-up", "award"];
return (
{C.items.map((it, i) => (
{T(it.title)} {T(it.body)}
))}
);
}
/* ------------------------------ SERVICES ---------------------------------- */
function Services({ lang, onNavigate }) {
const T = (v) => window.t(v, lang);
const S = window.OLV.services;
return (
{S.items.map((it, i) => (
onNavigate("portfolio")} data-cursor="grab">
{String(i + 1).padStart(2, "0")}
{T(it.title)}
{T(it.body)}
{T({ en: "See related work", hi: "संबंधित कार्य देखें" })}
))}
);
}
/* ------------------------------- ABOUT ------------------------------------ */
function About({ lang }) {
const T = (v) => window.t(v, lang);
const A = window.OLV.about;
return (
Col Satwant Singh Juneja (Retd)
{T(A.role)}
{T(A.overline)}
{T(A.title)}
{A.name}
{T(A.bio)}
);
}
function Partners({ lang }) {
const T = (v) => window.t(v, lang);
const P = window.OLV.partners;
const loop = P.names.concat(P.names); // duplicate for seamless infinite scroll
return (
{T(P.overline)}
{T(P.title)}
{loop.map((n, i) => = P.names.length}>{n} )}
);
}
/* --------------------------- TESTIMONIALS --------------------------------- */
function Testimonials({ lang }) {
const T = (v) => window.t(v, lang);
const S = window.OLV.testimonials;
return (
{T(S.placeholderNote)}
{S.items.map((it, i) => (
{T(it.quote)}
{T(it.author)}
{T(it.role)}
))}
);
}
/* ------------------------------ CONTACT ----------------------------------- */
function Contact({ lang }) {
const T = (v) => window.t(v, lang);
const C = window.OLV.contact, B = window.OLV.brand;
const [status, setStatus] = sS("idle"); // idle | sending | ok | err
const [form, setForm] = sS({ name: "", email: "", phone: "", country: "", type: C.projectTypes[0], location: "", message: "", callback: false, consent: false });
const set = (k) => (e) => setForm((f) => ({ ...f, [k]: e.target.type === "checkbox" ? e.target.checked : e.target.value }));
const submit = async (e) => {
e.preventDefault();
if (!form.consent) return;
setStatus("sending");
try {
// No-backend relay to the OLIVEARCH inbox. Replace the endpoint with your
// own FormSubmit activation / form handler when you deploy.
const res = await fetch("https://formsubmit.co/ajax/" + B.email, {
method: "POST",
headers: { "Content-Type": "application/json", Accept: "application/json" },
body: JSON.stringify({
_subject: "New enquiry — olivearchprojects.com",
Name: form.name, Email: form.email, Phone: form.phone, "Based in": form.country,
"Project Type": form.type, "Project Location": form.location,
"Requests callback": form.callback ? "Yes" : "No", Message: form.message,
}),
});
if (!res.ok) throw new Error("bad");
setStatus("ok");
setForm({ name: "", email: "", phone: "", country: "", type: C.projectTypes[0], location: "", message: "", callback: false, consent: false });
} catch (err) { setStatus("err"); }
};
const info = [
{ ic: "mail", lbl: T({ en: "Email", hi: "ईमेल" }), val: B.email, href: "mailto:" + B.email },
{ ic: "phone", lbl: T({ en: "Phone", hi: "फ़ोन" }), val: B.phones.join(" · "), href: "tel:" + B.phones[0].replace(/\s/g, "") },
{ ic: "map-pin", lbl: T({ en: "Office", hi: "कार्यालय" }), val: T(B.address) },
{ ic: "globe", lbl: T({ en: "Web", hi: "वेब" }), val: B.domain, href: "https://" + B.domain },
];
return (
);
}
Object.assign(window, { Hero, StatStrip, WhyPMC, Stages, Pillars, Services, About, Testimonials, Contact });