// W2Go screens — Home, Outlet (kitchen detail), Browse, Item Detail, Cart const { useState: useStateB, useEffect: useEffectB, useRef: useRefB, useMemo: useMemoB } = React; // ─────────────────────────────────────────────────────────────── // 5. HOME — outlets-first // ─────────────────────────────────────────────────────────────── function HomeScreen({ go, address, user, cart, openItem, openOutlet }) { const M = window.W2_MEMBER || {}; const greetTime = (() => { const h = new Date().getHours(); if (h < 11) return 'Good morning'; if (h < 16) return 'Good afternoon'; if (h < 21) return 'Good evening'; return 'Late night'; })(); const firstName = (user?.name || M.name || 'friend').split(' ')[0]; const featured = W2_ITEMS.filter(i => i.hero).slice(0, 8); const collections = window.W2_COLLECTIONS || []; const experiences = window.W2_EXPERIENCES || []; const offers = window.W2_OFFERS || []; const heroCol = collections[0]; return (
{/* Sticky top — greeting + member chip */}
{/* location strip */}
{/* ─── LOYALTY BAR (Starbucks) ─────────────────────────── */}
{/* ─── DISCOVERY HERO — featured collection (Airbnb) ─────── */} {heroCol && (
)} {/* ─── PERSONALIZED OFFERS (Braze intelligence) ─────────── */}
{offers.map(o => { const I = Ic[o.icon] || Ic.Spark; return (
{o.title}
{o.sub}
); })}
{/* ─── KITCHENS (discovery) ────────────────────────────── */}
go('browse')}>See all}/>
{W2_OUTLETS.slice(0, 4).map(o => ( openOutlet(o.id)} size="lg"/> ))}
{/* ─── CURATED COLLECTIONS (Airbnb editorial) ──────────── */} {collections.slice(1).map(col => (
))} {/* ─── CHEFS' PICKS rail ───────────────────────────────── */}
{featured.map(item => ( openItem(item.id)}/> ))}
{/* ─── EXPERIENCES (Airbnb — beyond delivery) ──────────── */}
{experiences.map(x => (
{x.tag}
{x.title}
{x.sub}
))}
{/* ─── ALL KITCHENS grid ───────────────────────────────── */}
All kitchens
{W2_OUTLETS.map(o => ( openOutlet(o.id)} size="sm"/> ))}
W2GO · CRAFTED BY W DOHA
); } const iconBtn = { width: 44, height: 44, borderRadius: 999, background: 'rgba(23,25,25,0.05)', position: 'relative', border: 'none', display: 'flex', alignItems: 'center', justifyContent: 'center', cursor: 'pointer', color: 'var(--w-onyx)' }; function SectionHead({ title, sub, action }) { return (
{title}
{sub &&
{sub}
}
{action}
); } function TextLink({ children, onClick }) { return ( ); } // ─── OUTLET CARD ────────────────────────────────────────────── function OutletCard({ outlet, onClick, size = 'lg' }) { const isLg = size === 'lg'; return ( ); } // ─── CRAVE CARD (item) ─────────────────────────────────────── function CraveCard({ item, onClick }) { const outlet = W2_outlet(item.outlet); return (
{outlet && (
{outlet.short}
)}
{item.name}
{W2_money(item.price)}
{outlet?.rating || 4.8}
); } // ─── ITEM CARD (grid) ──────────────────────────────────────── function ItemCard({ item, onClick }) { const outlet = W2_outlet(item.outlet); return ( ); } // ─────────────────────────────────────────────────────────────── // 6. OUTLET — kitchen menu with category tabs // ─────────────────────────────────────────────────────────────── function OutletScreen({ go, outletId, openItem, switchOutlet }) { const outlet = W2_outlet(outletId) || W2_OUTLETS[0]; const cats = (W2_CATEGORIES[outlet.id] || []); const items = W2_ITEMS.filter(i => i.outlet === outlet.id); const [activeCat, setActiveCat] = useStateB(cats[0]?.id); const [showSwitcher, setShowSwitcher] = useStateB(false); const scrollRef = useRefB(null); const sectionRefs = useRefB({}); // Update activeCat as user scrolls (intersection) useEffectB(() => { if (!scrollRef.current) return; const onScroll = () => { let visible = cats[0]?.id; const top = scrollRef.current.scrollTop; for (const c of cats) { const el = sectionRefs.current[c.id]; if (el && el.offsetTop - 160 <= top) visible = c.id; } setActiveCat(visible); }; const s = scrollRef.current; s.addEventListener('scroll', onScroll, { passive: true }); return () => s.removeEventListener('scroll', onScroll); }, [cats.length]); const jumpTo = (cId) => { setActiveCat(cId); const el = sectionRefs.current[cId]; if (el && scrollRef.current) scrollRef.current.scrollTo({ top: el.offsetTop - 150, behavior: 'smooth' }); }; return (
{/* Hero */}
{outlet.name}
{outlet.cuisine} · {outlet.tag}
{outlet.name}
{/* Info bar */}
{outlet.rating} · {outlet.deliveryMin} min · {W2_money(outlet.deliveryFee)} delivery · min {W2_money(outlet.minOrder)}
{/* Sticky category tabs */}
{cats.map(c => ( ))}
{/* Menu items */}
{cats.map(c => { const inCat = items.filter(i => i.cat === c.id); if (!inCat.length) return null; return (
sectionRefs.current[c.id] = el}>
{c.label.toUpperCase()}
{inCat.map(item => openItem(item.id)}/>)}
); })}
{outlet.blurb}
{/* Outlet switcher pill — floating */} {/* Switcher modal */} {showSwitcher && (
setShowSwitcher(false)} style={{ position: 'absolute', inset: 0, background: 'rgba(11,15,15,0.55)', backdropFilter: 'blur(6px)', zIndex: 10, display: 'flex', alignItems: 'flex-end', animation: 'w-fade-in .25s' }}>
e.stopPropagation()} style={{ width: '100%', background: 'var(--w-cream)', borderRadius: '24px 24px 0 0', padding: '14px 18px 30px', animation: 'w-slide-up .3s ease-out' }}>
Switch kitchen
{W2_OUTLETS.map(o => ( ))}
)}
); } // Single menu row — image right, content left (matches reference screenshots) function OutletMenuRow({ item, outlet, onClick }) { return ( ); } // ─────────────────────────────────────────────────────────────── // 6b. BROWSE — search across ALL outlets // ─────────────────────────────────────────────────────────────── function BrowseScreen({ go, openItem, openOutlet }) { const [q, setQ] = useStateB(''); const [outletFilter, setOutletFilter] = useStateB('all'); const items = W2_ITEMS.filter(i => (outletFilter === 'all' || i.outlet === outletFilter) && (!q || (i.name + ' ' + i.blurb + ' ' + i.tags.join(' ')).toLowerCase().includes(q.toLowerCase())) ); return (
Search
Across all 8 kitchens at W Doha.
setQ(e.target.value)} autoFocus placeholder="Pizza, ceviche, sushi, smoothie…" style={{ flex: 1, border: 'none', outline: 'none', background: 'transparent', fontFamily: 'inherit', fontSize: 14, color: 'var(--w-onyx)' }}/>
{/* Outlet filter */}
setOutletFilter('all')} kind={outletFilter === 'all' ? 'green' : 'default'}>All kitchens {W2_OUTLETS.map(o => ( setOutletFilter(o.id)} kind={outletFilter === o.id ? 'green' : 'default'}>{o.short} ))}
{items.length === 0 &&
Nothing matches. Try a different word.
} {items.map(item => { const outlet = W2_outlet(item.outlet); return ( ); })}
); } // ─────────────────────────────────────────────────────────────── // 7. ITEM DETAIL // ─────────────────────────────────────────────────────────────── function ItemDetailScreen({ go, itemId, addToCart }) { const item = W2_ITEMS.find(i => i.id === itemId) || W2_ITEMS[0]; const outlet = W2_outlet(item.outlet); const [size, setSize] = useStateB('reg'); const [spice, setSpice] = useStateB('med'); const [extras, setExtras] = useStateB([]); const [qty, setQty] = useStateB(1); const [fav, setFav] = useStateB(false); const sizeDelta = W2_DEFAULT_MODIFIERS.size.find(s => s.id === size)?.priceDelta || 0; const extrasDelta = extras.reduce((a, id) => a + (W2_DEFAULT_MODIFIERS.extras.find(e => e.id === id)?.priceDelta || 0), 0); const total = (item.price + sizeDelta + extrasDelta) * qty; const toggle = (arr, set, id) => set(arr.includes(id) ? arr.filter(x => x !== id) : [...arr, id]); return (
{outlet && ( )}
{item.name}
{outlet?.rating || 4.8} (820) · {outlet?.deliveryMin || 45} min
{W2_money(item.price)}
{item.blurb}
{item.tags.length > 0 && (
{item.tags.map(t => ( {t} ))}
)}
REQUIRED}>
{W2_DEFAULT_MODIFIERS.size.map(s => ( ))}
}>
{W2_DEFAULT_MODIFIERS.spice.map(s => ( ))}
OPTIONAL}>
{W2_DEFAULT_MODIFIERS.extras.map(e => { const on = extras.includes(e.id); return ( ); })}