/* --- Panos Melekkis · multi-step booking modal --- */ const D3 = window.PM_DATA; const INTERESTS = [ { id: "bespoke", ti: "Bespoke", sub: "Custom design" }, { id: "bridal", ti: "Engagement & Bridal", sub: "Rings, bands, sets" }, { id: "collection", ti: "A collection piece", sub: "From the shop" }, { id: "redesign", ti: "Redesign", sub: "Heirloom stones" }, ]; const LOCATIONS = [ { id: "dubai", ti: "Dubai d3", sub: "By appointment" }, { id: "cyprus", ti: "Limassol HQ", sub: "Boutique hours" }, { id: "video", ti: "Video call", sub: "International" }, ]; function BookingModal({ open, onClose }) { const [step, setStep] = React.useState(0); const [data, setData] = React.useState({ interest: null, location: null, name: "", email: "", phone: "", date: null, // ISO date time: null, notes: "", }); const TIMES = ["10:00", "11:30", "14:00", "15:30", "17:00"]; // make a 14-day date grid starting today const dateGrid = React.useMemo(() => { const today = new Date(); today.setHours(0, 0, 0, 0); return Array.from({ length: 14 }, (_, i) => { const d = new Date(today); d.setDate(today.getDate() + i); return d; }); }, []); React.useEffect(() => { if (open) { document.body.classList.add("is-locked"); } else { document.body.classList.remove("is-locked"); // reset after exit animation const t = setTimeout(() => { setStep(0); }, 380); return () => clearTimeout(t); } return () => document.body.classList.remove("is-locked"); }, [open]); React.useEffect(() => { if (!open) return; const onKey = (e) => { if (e.key === "Escape") onClose(); }; window.addEventListener("keydown", onKey); return () => window.removeEventListener("keydown", onKey); }, [open, onClose]); const set = (k, v) => setData((d) => ({ ...d, [k]: v })); const steps = [ { key: "interest", lab: "Interest" }, { key: "location", lab: "Where" }, { key: "datetime", lab: "When" }, { key: "contact", lab: "Contact" }, { key: "review", lab: "Confirm" }, ]; const canNext = (() => { if (step === 0) return !!data.interest; if (step === 1) return !!data.location; if (step === 2) return !!data.date && !!data.time; if (step === 3) return !!data.name && (!!data.email || !!data.phone); if (step === 4) return true; return false; })(); const isFinal = step === steps.length; // post-confirm state const next = () => { if (step === steps.length - 1) setStep(step + 1); // go to "submitted" else setStep(step + 1); }; const back = () => setStep(Math.max(0, step - 1)); const summary = (k) => { if (k === "interest") return data.interest ? INTERESTS.find(i => i.id === data.interest).ti : "—"; if (k === "location") return data.location ? LOCATIONS.find(i => i.id === data.location).ti : "—"; if (k === "datetime") { if (!data.date) return "—"; const d = new Date(data.date); return d.toLocaleDateString(undefined, { weekday: "short", day: "numeric", month: "long" }) + (data.time ? ` · ${data.time}` : ""); } if (k === "contact") return [data.name, data.email, data.phone].filter(Boolean).join(" · "); if (k === "notes") return data.notes || "—"; return "—"; }; const fmtDay = (d) => d.toLocaleDateString(undefined, { weekday: "short" }).slice(0, 2).toUpperCase(); const fmtNum = (d) => d.getDate(); const fmtMonth = (d) => d.toLocaleDateString(undefined, { month: "short" }); const waMessage = () => { const lines = [ `Hello — I'd like to book a consultation.`, `Interest: ${summary("interest")}.`, `Location: ${summary("location")}.`, `When: ${summary("datetime")}.`, `Name: ${data.name || ""}.`, data.notes ? `Notes: ${data.notes}` : null, ].filter(Boolean).join("\n"); return encodeURIComponent(lines); }; return (
{ if (e.target === e.currentTarget) onClose(); }}>
{/* SIDE */} {/* BODY */}
{!isFinal && ( )} {/* Step 0 — interest */} {step === 0 && ( — Step 01 of 05

What would you like to discuss?

A consultation is approximately 60 minutes. Tell us which conversation to prepare for.

{INTERESTS.map((i) => ( ))}
)} {/* Step 1 — location */} {step === 1 && ( — Step 02 of 05

Where would you like to meet?

Both ateliers are private. The Dubai d3 studio is appointment-only; the Limassol boutique sees walk-ins during opening hours but consultations are reserved.

{LOCATIONS.map((i) => ( ))}
)} {/* Step 2 — date/time */} {step === 2 && ( — Step 03 of 05

When suits you?

Pick any day in the next two weeks. We confirm the exact slot by WhatsApp within the same business day.

{dateGrid.map((d) => { const iso = d.toISOString().slice(0, 10); const isSun = d.getDay() === 0 && data.location === "cyprus"; return ( ); })}
{data.date && (
— Time slot
{TIMES.map((t) => ( ))}
)}
)} {/* Step 3 — contact */} {step === 3 && ( — Step 04 of 05

And how do we reach you?

We need one of email or phone. We use WhatsApp for confirmations — most clients prefer it.

set("name", e.target.value)} placeholder="Full name" />
set("email", e.target.value)} placeholder="you@email.com" />
set("phone", e.target.value)} placeholder="+971 ..." />