/* global React */ const { useState: useStateQ, useEffect: useEffectQ, useMemo: useMemoQ } = React; /* ============================================================ LOOKBOOK ============================================================ */ function LookbookPage({ onNav, locale }) { const ar = locale === "ar"; const [filter, setFilter] = useStateQ("all"); const [lb, setLb] = useStateQ(null); const [empty, setEmpty] = useStateQ(false); // Combine genuine + stock with provenance const tiles = useMemoQ(() => { const real = [ { src: MEDIA.kaftan, cat: "garment", real: true, label: "Sage-silk kaftan · directory image", caption: "d3 directory · placeholder, rights pending" }, { src: MEDIA.interior, cat: "atelier", real: true, label: "Gallery interior · directory image", caption: "BestThings · placeholder, rights pending" }, ]; const stock = STOCK.map(s => ({ src: s.src, cat: s.cat, real: false, label: s.label, caption: "Stock placeholder — by appointment, real client work to follow" })); return [...real, ...stock]; }, []); const cats = [ { id: "all", label: { en: "All", ar: "الكل" } }, { id: "garment", label: { en: "Garments", ar: "قطع" } }, { id: "material", label: { en: "Materials", ar: "خامات" } }, { id: "atelier", label: { en: "Atelier", ar: "الأتيليه" } }, { id: "fitting", label: { en: "Fittings", ar: "قياسات" } }, ]; const visible = empty ? [] : tiles.filter(t => filter === "all" || t.cat === filter); return (
{ar ? "المعرض" : "Lookbook"}

{ar ? "صور توضيحية، حتى نُعرض ما هو حقيقي." : "Representative, until we can show what's real."}

{ar ? "صورتان من الدليل العام وصور من المخزون المهني — وُضِعت كعناصر نائبة وحسب. كل صورة يجب أن تُستبدَل بصور موكَّل بحقوقها من الأستوديو." : "Two directory images and a set of stock placeholders. None of these are the studio's own work — every tile carries provenance, and all will be replaced with rights-cleared client photography."}

{cats.map(c => ( ))}
{empty ? "0" : visible.length} {ar ? "صورة" : "tiles"} · 2 {ar ? "حقيقية" : "real"} · {visible.length > 0 ? Math.max(0, visible.length - (filter === "all" ? 2 : 0)) : 0} {ar ? "مخزون" : "stock"}
{empty || visible.length === 0 ? ( onNav("appointments")}>{ar ? "اطلب معاينة" : "Request a Preview"}} /> ) : (
{visible.map((t, i) => ( ))}
)}
{ar ? "ملاحظة على المصادر" : "Provenance note"}

{ar ? "الصورتان الحقيقيتان مأخوذتان من الأدلة العامة (d3 وBestThings) ولا تُعدّ ملكية مؤكَّدة لأعمال الاستوديو. باقي البلاطات صور مخزون مناسبة للقطاع، ووجودها هو لملء الواجهة فقط. لا تُعرَض أيٌّ منها على أنّها أعمال \"Only One Design\"." : "The two real tiles are from public directories (d3 and BestThings) and are not confirmed as the studio's own work. The remainder are sector-appropriate stock standing in for client photography. None should be read as Only One Design's portfolio."}

22 placeholder images · awaiting rights-cleared media
{lb && setLb(null)} />}
); } /* ============================================================ ATELIER ============================================================ */ function AtelierPage({ onNav, locale }) { const ar = locale === "ar"; return (
{ar ? "الأتيليه" : "The atelier"}

{ar ? "غرفة هادئة في d3." : "A quiet room in d3."}

{ar ? "في الطابق الثاني من مبنى 07 بحي دبي للتصميم، يفتح الاستوديو بابه بالموعد فقط. ضوء أبيض، خرسانة مصقولة، قضبان عرض نحاسية — والقليل من الأشياء الصامتة، تترك المساحة للقماش." : "On the second floor of Building 07 in Dubai Design District, the studio opens by appointment. White light, polished concrete, brass display rails — and very little else, so the fabric can speak."}

CLIENT-FILL · founder / origin / philosophy
Gallery interior with brass display rails and orchids
BestThings · interior placeholder
{ar ? "الموقع" : "Location"}
d3 · Bldg 07
{ar ? "المكتب" : "Office"}
No. B203 · confirm
{ar ? "الزيارة" : "Visits"}
{ar ? "بالموعد" : "By appointment"}
{ar ? "اللغات" : "Languages"}
EN · AR · RU · ZH
{ar ? "تفاصيل المساحة" : "Details from the room"}

{ar ? "اللوحة تأتي من المساحة." : "The palette is taken from the room."}

{ar ? "هذه اللوحة مأخوذة مباشرة من الصورتين الحقيقيتين المتاحتين — قفطان الحرير ذو التطريز الذهبي وداخلية الجاليري. ستظل ساكنة حتى يمدّنا العميل بصور حقيقية." : "This palette is taken directly from the two real images on record — the embroidered silk kaftan and the gallery interior. It will remain restrained until client photography arrives."}

); } function PaletteSwatch({ hex, name, note, dark }) { return (
{hex}
{name}
{note}
); } /* ============================================================ APPOINTMENTS ============================================================ */ function AppointmentsPage({ onNav, locale, callConfirmed, waConfirmed, toast }) { const ar = locale === "ar"; const [form, setForm] = useStateQ({ name: "", phone: "", email: "", date: "", time: "", purpose: "consultation", message: "", }); const [submitted, setSubmitted] = useStateQ(false); const [touched, setTouched] = useStateQ({}); const purposes = [ { id: "consultation", title: { en: "Consultation", ar: "استشارة" }, sub: { en: "First visit", ar: "زيارة أولى" } }, { id: "fitting", title: { en: "Fitting", ar: "قياس" }, sub: { en: "Existing brief", ar: "موجز قائم" } }, { id: "alteration", title: { en: "Alteration", ar: "تعديل" }, sub: { en: "Adjust a piece", ar: "تعديل قطعة" } }, { id: "enquiry", title: { en: "Enquiry", ar: "استفسار" }, sub: { en: "Not sure yet", ar: "لست متأكدًا" } }, ]; const times = ["10:00", "11:00", "12:00", "14:00", "15:00", "16:00", "17:00", "18:00"]; const tomorrow = useMemoQ(() => { const d = new Date(); d.setDate(d.getDate() + 1); return d.toISOString().slice(0, 10); }, []); const set = (k, v) => setForm(f => ({ ...f, [k]: v })); const valid = form.name && form.phone && form.date && form.time; const submit = (e) => { e.preventDefault(); setTouched({ name: true, phone: true, date: true, time: true }); if (!valid) return; setSubmitted(true); toast(ar ? "تم استلام طلبك. سنؤكّد قريبًا." : "Request received. We'll confirm shortly."); }; const purposeLabel = (id) => { const p = purposes.find(x => x.id === id); return ar ? p.title.ar : p.title.en; }; return (
{ar ? "احجز موعدًا" : "Book an appointment"}

{ar ? "اختر وقتًا. نُؤكِّد." : "Pick a time. We'll confirm."}

{ar ? "نستقبل عميلًا واحدًا في كل مرة. شارك تفاصيلك أدناه وسنتواصل لتأكيد الموعد. لا توجد دفعات إلكترونية." : "We see one client at a time. Share your details below and we'll be in touch to confirm. No online payments."}

{submitted ? ( { setSubmitted(false); setForm({ name:"", phone:"", email:"", date:"", time:"", purpose:"consultation", message:"" }); }} locale={locale} waConfirmed={waConfirmed} /> ) : (
{ar ? "01 — الغرض من الزيارة" : "01 — Purpose"}
{purposes.map(p => ( ))}
{ar ? "02 — تفاصيلك" : "02 — Your details"}
set("name", e.target.value)} onBlur={() => setTouched(t => ({ ...t, name: true }))} aria-invalid={touched.name && !form.name} />
set("phone", e.target.value)} onBlur={() => setTouched(t => ({ ...t, phone: true }))} aria-invalid={touched.phone && !form.phone} placeholder="+971 …" />
set("email", e.target.value)} />
{ar ? "03 — التاريخ والوقت" : "03 — Date & time"}
set("date", e.target.value)} />
{times.map(t => { const disabled = (t === "13:00"); return ( ); })}
{ar ? "04 — ملاحظة (اختياري)" : "04 — Note (optional)"}