// W2Go — main app: state, routing, iOS frame composition, Tweaks panel const { useState: useStateApp, useEffect: useEffectApp, useMemo: useMemoApp } = React; const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{ "primary": "#004C4B", "accent": "#C24A2C", "background": "#F9F2E8", "dark": false, "showFrame": true, "heroStyle": "editorial", "startScreen": "splash", "rounded": "soft" }/*EDITMODE-END*/; function W2GoApp() { const [tweaks, setTweak] = window.useTweaks(TWEAK_DEFAULTS); // App state const [screen, setScreen] = useStateApp(tweaks.startScreen); const [user, setUser] = useStateApp(null); const [address, setAddress] = useStateApp(W2_ADDRESSES[0]); const [cart, setCart] = useStateApp([]); const [openItemId, setOpenItemId] = useStateApp('su1'); const [openOutletId, setOpenOutletId] = useStateApp('sushi'); const [order, setOrder] = useStateApp(null); // Push CSS vars to :root whenever tweaks change useEffectApp(() => { const r = document.documentElement; r.style.setProperty('--w-green', tweaks.primary); r.style.setProperty('--w-accent', tweaks.accent); r.style.setProperty('--w-cream', tweaks.background); r.style.setProperty('--w-onyx', tweaks.dark ? '#0B0D0D' : '#171919'); r.style.setProperty('--w-charcoal', '#453F47'); }, [tweaks.primary, tweaks.accent, tweaks.background, tweaks.dark]); // jump to start screen when changed in tweaks const lastStart = React.useRef(tweaks.startScreen); useEffectApp(() => { if (lastStart.current !== tweaks.startScreen) { lastStart.current = tweaks.startScreen; // ensure preconditions if (['home', 'browse', 'item', 'cart', 'checkout', 'tracking', 'rate', 'orders', 'account'].includes(tweaks.startScreen)) { if (!user) setUser({ name: 'Mrigank', phone: '+974 9999 369843' }); if (tweaks.startScreen === 'cart' || tweaks.startScreen === 'checkout' || tweaks.startScreen === 'tracking' || tweaks.startScreen === 'rate') { if (cart.length === 0) { seedCart(); } } } setScreen(tweaks.startScreen); } }, [tweaks.startScreen]); function seedCart() { const a = W2_ITEMS.find(i => i.id === 'su4') || W2_ITEMS[0]; const b = W2_ITEMS.find(i => i.id === 'sp4') || W2_ITEMS[0]; const c = W2_ITEMS.find(i => i.id === 'sw4') || W2_ITEMS[0]; setCart([ { item: a, size: 'reg', spice: 'med', extras: ['gi'], qty: 1, unitPrice: a.price + 4 }, { item: b, size: 'reg', spice: 'med', extras: [], qty: 1, unitPrice: b.price }, { item: c, size: 'reg', spice: 'med', extras: [], qty: 2, unitPrice: c.price }, ]); } const go = (s) => setScreen(s); const openItem = (id) => { setOpenItemId(id); setScreen('item'); }; const openOutlet = (id) => { setOpenOutletId(id); setScreen('outlet'); }; const switchOutlet = (id) => { setOpenOutletId(id); }; // Debug — global testing hook useEffectApp(() => { window.W2_go = (s) => { if (!user) setUser({ name: 'Mrigank', phone: '+974 9999 369843' }); if (['cart', 'checkout', 'payment', 'tracking', 'rate'].includes(s) && cart.length === 0) seedCart(); if (s === 'payment' && !order) setOrder({ pay: 'applepay', tip: 10, total: 250, items: cart }); setScreen(s); }; }, [user, cart.length, order]); const addToCart = ({ item, size, spice, extras, qty }) => { 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 unitPrice = item.price + sizeDelta + extrasDelta; setCart([...cart, { item, size, spice, extras, qty, unitPrice }]); }; const placeOrder = (details) => { setOrder({ ...details, items: cart, placedAt: Date.now() }); setScreen('payment'); }; const paymentComplete = () => { setScreen('tracking'); }; const finishOrder = () => { setScreen('rate'); }; const doneRating = () => { setCart([]); setOrder(null); setScreen('home'); }; const signOut = () => { setUser(null); setCart([]); setOrder(null); setScreen('splash'); }; // determine if tab bar should show const tabScreens = ['home', 'browse', 'cart', 'orders', 'account']; const showTabs = tabScreens.includes(screen); const activeTab = screen === 'browse' ? 'search' : screen; const screenEl = (() => { switch (screen) { case 'splash': return ; case 'onboarding': return ; case 'location': return ; case 'auth': return ; case 'home': return ; case 'outlet': return ; case 'browse': return ; case 'item': return ; case 'cart': return ; case 'checkout': return ; case 'payment': return ; case 'tracking': return ; case 'rate': return ; case 'orders': return ; case 'account': return ; default: return ; } })(); const totalQty = cart.reduce((a, c) => a + c.qty, 0); const phoneInner = (
{screenEl} {showTabs && { if (t === 'search') setScreen('browse'); else setScreen(t); }} badge={totalQty}/>}
); return (
{tweaks.showFrame ? ( {phoneInner} ) : (
{phoneInner}
)}
); } // Scales children to fit the viewport while preserving aspect. function FitScale({ baseW, baseH, children }) { const [scale, setScale] = useStateApp(1); useEffectApp(() => { const recompute = () => { const pad = 60; const w = window.innerWidth - pad; const h = window.innerHeight - pad; setScale(Math.min(1, w / baseW, h / baseH)); }; recompute(); window.addEventListener('resize', recompute); return () => window.removeEventListener('resize', recompute); }, [baseW, baseH]); return (
{children}
); } // ─── Tweaks panel ───────────────────────────────────────────── function WTweaks({ tweaks, setTweak }) { const { TweaksPanel, TweakSection, TweakColor, TweakRadio, TweakToggle, TweakSelect } = window; if (!TweaksPanel) return null; return ( setTweak('primary', v)} options={['#004C4B', '#171919', '#2D6A3E', '#C24A2C', '#3A4E8C']}/> setTweak('background', v)} options={['#F9F2E8', '#EFE8DA', '#F4F1EA', '#FFFFFF']}/> setTweak('dark', v === 'dark')}/> setTweak('showFrame', v)}/> setTweak('startScreen', v)} options={[ { value: 'splash', label: '1. Splash' }, { value: 'onboarding', label: '2. Onboarding' }, { value: 'location', label: '3. Location' }, { value: 'auth', label: '4. Sign in' }, { value: 'home', label: '5. Home' }, { value: 'outlet', label: '5b. Outlet' }, { value: 'browse', label: '6. Browse' }, { value: 'item', label: '7. Item detail' }, { value: 'cart', label: '8. Bag' }, { value: 'checkout', label: '9. Checkout' }, { value: 'payment', label: '10. Payment' }, { value: 'tracking', label: '11. Tracking' }, { value: 'rate', label: '12. Rate' }, { value: 'orders', label: '13. Orders' }, { value: 'account', label: '14. Account' }, ]}/> ); } ReactDOM.createRoot(document.getElementById('root')).render();