/* ─── Quote Modal: configurable wizard ────────────────────────── Configuration comes from window.HOOPOE_QUOTE (defined in index.html). - services: list of options shown in step 1 - showServiceStep: hide step 1 entirely (becomes a 2-step wizard) - timelines / budgets: chips in the scope step ───────────────────────────────────────────────────────────────── */ function _getQuoteConfig() { const c = window.HOOPOE_QUOTE || {}; return { services: c.services || [], showServiceStep: c.showServiceStep !== false, timelines: c.timelines || ['< 1 week', '1–2 weeks', '2–4 weeks', '1–3 months', 'Flexible'], budgets: c.budgets || ['Under AED 5K', 'AED 5–25K', 'AED 25–100K', 'AED 100K+', 'Not sure'], }; } function QuoteModal({ open, onClose, initialService }) { const cfg = _getQuoteConfig(); const QUOTE_SERVICES = cfg.services; const TIMELINE_OPTIONS = cfg.timelines; const BUDGET_OPTIONS = cfg.budgets; // Build the active step list based on config const stepDefs = [ cfg.showServiceStep ? 'services' : null, 'scope', 'contact', ].filter(Boolean); const totalSteps = stepDefs.length; const [stepIdx, setStepIdx] = React.useState(0); const stepKey = stepDefs[stepIdx]; const [data, setData] = React.useState({ services: [], timeline: '', budget: '', name: '', email: '', phone: '', company: '', notes: '', }); React.useEffect(() => { if (open) { setStepIdx(0); setData(d => ({ ...d, services: initialService ? [initialService] : [] })); } }, [open, initialService]); React.useEffect(() => { if (!open) return; const onKey = (e) => { if (e.key === 'Escape') onClose(); }; window.addEventListener('keydown', onKey); document.body.style.overflow = 'hidden'; return () => { window.removeEventListener('keydown', onKey); document.body.style.overflow = ''; }; }, [open, onClose]); if (!open) return null; const toggleService = (id) => { setData(d => ({ ...d, services: d.services.includes(id) ? d.services.filter(s => s !== id) : [...d.services, id] })); }; const submitted = stepIdx >= totalSteps; const progress = submitted ? 100 : ((stepIdx + 1) / totalSteps) * 100; const canAdvance = (stepKey === 'services' && data.services.length > 0) || (stepKey === 'scope' && data.timeline && data.budget) || (stepKey === 'contact' && data.name && data.email); const next = () => stepIdx < totalSteps - 1 ? setStepIdx(stepIdx + 1) : submit(); const prev = () => stepIdx > 0 ? setStepIdx(stepIdx - 1) : onClose(); const submit = () => setStepIdx(totalSteps); const serviceLabel = (id) => (QUOTE_SERVICES.find(x => x.id === id) || {}).label || id; return (
Select one or more services. You can refine the details next.
Helps us route your enquiry to the right team and reply with accurate lead times.
We'll respond within one business day with a proposal and timeline.
Thank you, {data.name || 'team'}. Our production lead will email you at {data.email} within one business day. Reference: HPT-{Math.floor(Math.random()*9000+1000)}