/* Bespoke + Consultation form + Showroom + Contact */ function Bespoke({ onNav }) { const [size, setSize] = useState({ w: 3.0, h: 2.0 }); const [palette, setPalette] = useState('madder'); const [collection, setCollection] = useState('Traditional'); // Pricing model: AED 3,200 per sqm for Traditional, scaled by collection const collectionMultiplier = { Traditional: 1.0, Timeless: 1.15, Modern: 1.05, Tolerance: 1.2, Designer: 1.55, 'Stone Wash': 1.1 }; const sqm = +(size.w * size.h).toFixed(2); const baseRate = 3200; const knots = Math.round(sqm * 145000); const months = Math.max(4, Math.round(sqm * 1.8 + 2)); const price = Math.round(sqm * baseRate * (collectionMultiplier[collection] || 1) / 10) * 10; const palettes = { madder: { name: 'Madder & ivory', swatches: ['#8E3B2E', '#C99A3A', '#EDE2D1', '#231C16'] }, indigo: { name: 'Indigo & saffron', swatches: ['#2E3D5A', '#C99A3A', '#F1EADB', '#15100B'] }, walnut: { name: 'Walnut & bone', swatches: ['#5A4636', '#A88A6B', '#E6DCC5', '#231C16'] }, stone: { name: 'Stone-wash neutrals', swatches: ['#A89881', '#D7C7B0', '#EDE2D1', '#5A4636'] } }; return ( A carpet drawn for one room, woven by one weaver, signed for one client.} lead="From a fabric sample, a floor plan or a photograph — our design studio briefs the loom in Mazar-i-Sharif and ships you a single carpet, signed and certified, between six and fourteen months later." />
{/* Configurator */}
Configurator · live estimate

Brief your piece.

{/* Collection */}
{['Traditional', 'Modern', 'Timeless', 'Tolerance', 'Designer', 'Stone Wash'].map(c => ( ))}
{/* Size */}
{size.w.toFixed(2)} × {size.h.toFixed(2)} m · {sqm} sqm
Width (m)
setSize({ ...size, w: +e.target.value })} style={{ width: '100%' }} />
Height (m)
setSize({ ...size, h: +e.target.value })} style={{ width: '100%' }} />
{/* Visual size preview */}
{size.w.toFixed(1)} × {size.h.toFixed(1)} m
{/* Palette */}
{Object.entries(palettes).map(([k, p]) => ( ))}
{/* Estimate */}
Live estimate
AED {price.toLocaleString('en-US')}
INDICATIVE · FINAL PRICE QUOTED AFTER A DESIGN BRIEF
Collection{collection}
Size{size.w.toFixed(2)} × {size.h.toFixed(2)} m
Area{sqm} sqm
Est. knots~{knots.toLocaleString('en-US')}
Time at loom~{months} months
FoundationCotton warp, wool weft
Palette{palettes[palette].name}

Estimate covers wool, dye, draft, weaving, finishing, certification and Dubai delivery. Strike-off samples are produced before any commission begins — at no additional cost.

How a commission runs

From a first conversation to a signed carpet in your room.

{[ { w: 'Week 0', t: 'Consultation', d: 'Forty-five minutes in d3 or by video. Floor plan, palette, brief.' }, { w: 'Week 2', t: 'Studio brief', d: 'Two or three drawings, palette card, wool samples sent to you.' }, { w: 'Week 6', t: 'Strike-off', d: 'A 40 × 40 cm sample is hand-knotted and shipped for sign-off.' }, { w: 'Week 8', t: 'Loom starts', d: 'A loom in Mazar-i-Sharif is assigned. We send you the weaver’s name.' }, { w: 'Month 6–14', t: 'Weaving', d: 'Monthly photographs from the loom. You can stop, change colour, redraw.' }, { w: 'Delivery', t: 'Signed & shipped', d: 'Cut off, washed, signed, certified, freighted to your door.' } ].map((s, i) => (
{s.w.toUpperCase()}

{s.t}

{s.d}

))}
); } function Consultation({ onNav, onSubmit }) { const [step, setStep] = useState(0); const [form, setForm] = useState({ role: '', name: '', company: '', email: '', phone: '', project: 'bespoke', sqm: '', timeline: '6-12', budget: '', palette: '', notes: '', when: '', channel: 'showroom', file: null }); const [submitted, setSubmitted] = useState(false); const update = (k, v) => setForm(f => ({ ...f, [k]: v })); const canNext = (() => { if (step === 0) return !!form.role; if (step === 1) return form.name && form.email; if (step === 2) return true; return true; })(); const submit = () => { setSubmitted(true); if (onSubmit) onSubmit(form); }; if (submitted) { return ( Thank you, {form.name.split(' ')[0] || 'we have it'}. We will be back within one working day.} lead={`A confirmation has been sent to ${form.email}. Our concierge will call ${form.phone || 'you'} to set the meeting time. In the meantime, a few links below.`} />
While you wait

Three things worth a look before we meet.

YOUR BRIEF · REF #{Math.random().toString(36).slice(2, 8).toUpperCase()}
Role
{form.role || '—'}
Project
{form.project}
Timeline
{form.timeline} months
); } return ( Forty-five minutes with our design team — in d3, by video, or at your studio.} lead="Tell us a little about the project. We do not ask for the brief here — that is what the meeting is for." />
{['You', 'Contact', 'Project', 'Meeting'].map((label, i) => ( ))}
{step === 0 && (

Who are you briefing on behalf of?

{window.ZULEYA.ROLES.map(r => ( ))}

THIS HELPS US ASSIGN THE RIGHT CONSULTANT TO YOU.

)} {step === 1 && (

How should we reach you?

update('name', e.target.value)} placeholder="Jane Hassan" />
update('company', e.target.value)} placeholder="Studio name" />
update('email', e.target.value)} placeholder="you@studio.com" />
update('phone', e.target.value)} placeholder="+971 …" />
)} {step === 2 && (

Tell us about the project.

update('file', form.file ? null : 'mood-board.jpg')}>
{form.file ? '✓ mood-board.jpg attached — click to remove' : 'Drop a mood board, floor plan or fabric photo'}
PDF, JPG, PNG up to 16 MB. We treat all files as confidential.
)} {step === 3 && (

How would you like to meet?

{[ { id: 'showroom', t: 'In the d3 showroom', s: 'Dubai Design District, building 2' }, { id: 'video', t: 'Video call', s: 'Teams or Google Meet, 45 min' }, { id: 'visit', t: 'You visit us / we visit you', s: 'Studio, site, residence — anywhere in the UAE' } ].map(c => ( ))}
Our concierge will confirm a slot within one working day.
YOUR BRIEF SO FAR
Role{form.role || '—'}
Project{form.project}
Timeline{form.timeline} months
Area{form.sqm || '—'}
)}
{step < 3 && ( )} {step === 3 && ( )}
); } function Showroom({ onNav }) { return ( The carpets — and their cartoons — in one room in d3.} lead="A working showroom: every carpet on the floor, the cartoons on the wall, wool samples on the table, and one of the design team to walk you around. Walk-ins welcome; consultations by appointment." />
Find us

Showroom 1, Building 2, Dubai Design District.

{[ { k: 'Address', v: 'Showroom 1, Building 2 · Dubai Design District (d3) · PO Box 27677, Dubai, UAE' }, { k: 'Hours', v: 'Saturday – Thursday · 10:00 – 22:00 · Friday · 16:00 – 22:00' }, { k: 'Parking', v: 'Free underground parking, level B1, lifts to ground floor.' }, { k: 'Metro', v: 'Creek metro station, 12 minutes by taxi. d3 is on the RTA Dubai Bus 88 route.' }, { k: 'Phone', v: 'FBMI · +971 4 243 2327 · Zuleya · 800 ZULEYA' }, { k: 'Email', v: 'hello@zuleya.ae · info@fbmi.ae' } ].map(r => (
{r.k} {r.v}
))}
Open in maps
{/* Stylised map */}
{/* roads */} {/* buildings */} {/* pin */} Zuleya · d3 SHOWROOM 1 · BUILDING 2
); } function Contact({ onNav, onSubmit }) { const [form, setForm] = useState({ name: '', email: '', subject: 'general', message: '' }); const [sent, setSent] = useState(false); const submit = (e) => { e.preventDefault(); setSent(true); if (onSubmit) onSubmit(form); }; return ( Write to us. Phone us. Walk in.} lead="One mailbox for press, one for the trade, one for collectors. We reply within one working day." />
{sent ? (
Thank you

We have your note, {form.name.split(' ')[0] || 'there'}.

A confirmation has been sent to {form.email}. We reply within one working day.

) : (
Send a note

Short or long — both are read.

setForm({ ...form, name: e.target.value })} required />
setForm({ ...form, email: e.target.value })} required />
)}
Direct lines
{[ { k: 'Trade & design', v: 'trade@zuleya.ae · +971 4 243 2327' }, { k: 'Press', v: 'press@fbmi.ae' }, { k: 'Showroom (d3)', v: '+971 4 243 2327 · open today 10:00 – 22:00' }, { k: 'Mazar-i-Sharif loom', v: 'Visits welcome by prior arrangement only' }, { k: 'Postal', v: 'PO Box 27677, Dubai, UAE' } ].map(r => (
{r.k}
{r.v}
))}
); } Object.assign(window, { Bespoke, Consultation, Showroom, Contact });