// W2Go screens — Checkout, Tracking, Order Done, Orders list, Account const { useState: useStateC, useEffect: useEffectC, useRef: useRefC } = React; // ─────────────────────────────────────────────────────────────── // 9. CHECKOUT // ─────────────────────────────────────────────────────────────── function CheckoutScreen({ go, cart, address, placeOrder }) { const [dropoff, setDropoff] = useStateC('door'); // door | hand | leave const [pay, setPay] = useStateC('applepay'); const [tip, setTip] = useStateC(10); const [notes, setNotes] = useStateC(''); const sub = cart.reduce((a, c) => a + c.unitPrice * c.qty, 0); const delivery = 8, fee = 4; const total = sub + delivery + fee + tip; const tips = [0, 5, 10, 15, 20]; return (
go('cart')} title="Checkout"/> {/* Address */} go('location')} style={btnLink}>Change}>
{address?.label || 'Home'}
{address?.line || 'Tower 2, The Pearl'} · {address?.city || 'Doha, Qatar'}
{/* Drop-off */}
{[ { id: 'door', label: 'Hand it to me at the door', icon: Ic.Door }, { id: 'leave', label: 'Leave at the door', icon: Ic.Box }, { id: 'hand', label: 'Meet outside', icon: Ic.User }, ].map(o => { const I = o.icon; const on = dropoff === o.id; return ( ); })} setNotes(e.target.value)} placeholder="Note to rider (apt buzzer, gate code…)" style={{ marginTop: 4, padding: '12px 14px', borderRadius: 12, fontSize: 13, border: '1.5px solid rgba(23,25,25,0.08)', background: '#fff', outline: 'none', fontFamily: 'inherit' }}/>
{/* Payment */}
{[ { id: 'applepay', label: 'Apple Pay', sub: 'Touch ID', icon: Ic.Apple, bg: '#000', fg: '#fff' }, { id: 'card', label: 'Visa ••4821', sub: 'Default', icon: Ic.Card, bg: 'var(--w-green)', fg: 'var(--w-cream)' }, { id: 'cash', label: 'Cash on delivery', sub: 'Exact change preferred', icon: Ic.Wallet, bg: 'var(--w-onyx)', fg: 'var(--w-cream)' }, ].map(p => { const I = p.icon; const on = pay === p.id; return ( ); })}
{/* Tip */} 100% TO RIDER}>
{tips.map(t => ( ))}
{/* Summary */} {cart.map((l, i) => (
{l.qty}×{l.item.name} {W2_money(l.unitPrice * l.qty)}
))}
placeOrder({ dropoff, pay, tip, notes, total })} iconRight={}>Place order · {W2_money(total)}
Tap to confirm — you can cancel for free for the first 2 minutes.
); } // ─────────────────────────────────────────────────────────────── // 9.5 PAYMENT — Apple Pay-style sheet → success → tracking // ─────────────────────────────────────────────────────────────── function PaymentScreen({ go, order, paymentComplete }) { const [stage, setStage] = useStateC('ready'); // ready | auth | processing | success const total = order?.total || 0; const pay = order?.pay || 'applepay'; const tip = order?.tip || 0; const items = order?.items || []; useEffectC(() => { if (stage === 'auth') { const t = setTimeout(() => setStage('processing'), 1400); return () => clearTimeout(t); } if (stage === 'processing') { const t = setTimeout(() => setStage('success'), 1600); return () => clearTimeout(t); } if (stage === 'success') { const t = setTimeout(() => paymentComplete(), 1200); return () => clearTimeout(t); } }, [stage]); const payMeta = { applepay: { label: 'Apple Pay', sub: 'Face ID', bg: '#000', fg: '#fff', icon: Ic.Apple }, card: { label: 'Visa •• 4821', sub: 'Card', bg: 'var(--w-green)', fg: 'var(--w-cream)', icon: Ic.Card }, cash: { label: 'Cash on delivery', sub: 'Pay rider', bg: 'var(--w-onyx)', fg: 'var(--w-cream)', icon: Ic.Wallet }, }[pay] || {}; // Cash: skip processing — just confirm const isCash = pay === 'cash'; return (
{/* dim photographic bg */}
{/* close */}
{/* Brand */}
{stage === 'success' ? 'PAYMENT CONFIRMED' : 'PAY WITH'}
{/* Payment card */}
{payMeta.label}
{payMeta.sub}
{W2_money(total)}
{/* Bill stub */}
ORDER · W2-{Math.floor(Math.random()*9000+1000)} {items.length} {items.length === 1 ? 'item' : 'items'}
{items.slice(0, 3).map((l, i) => (
{l.qty}×{l.item.name} {W2_money(l.unitPrice * l.qty)}
))} {items.length > 3 && (
+ {items.length - 3} more
)}
Delivery · service{W2_money(12)}
Rider tip{W2_money(tip)}
{/* Center action: face-id / spinner / check */}
{stage === 'ready' && ( <>
{pay === 'applepay' ? : (pay === 'card' ? : )}
{pay === 'applepay' && 'Double-click side button'} {pay === 'card' && 'Confirm with card'} {pay === 'cash' && 'Confirm cash order'}
{pay === 'applepay' && 'Then Face ID will authorize the payment.'} {pay === 'card' && 'Your card will be charged once the rider picks up.'} {pay === 'cash' && 'Hand the rider exact change if possible.'}
)} {stage === 'auth' && ( <>
Authorizing…
Hold still, just a moment.
)} {stage === 'processing' && ( <>
Sending to kitchen…
{isCash ? 'Order locked in.' : 'Payment cleared.'} Cooking starts now.
)} {stage === 'success' && ( <>
Cravings locked.
Your order is in the W Doha kitchen.
We'll text you when the rider's rolling.
)}
{stage === 'ready' && ( setStage(isCash ? 'processing' : 'auth')} iconRight={}> {pay === 'applepay' && 'Pay ' + W2_money(total)} {pay === 'card' && 'Confirm ' + W2_money(total)} {pay === 'cash' && 'Place order'} )} {(stage === 'auth' || stage === 'processing') && ( Please wait… )} {stage === 'success' && ( }> Track your order )}
Secured by W2GO · 256-bit TLS · Doha, Qatar
); } // Face-ID style icon function FaceID({ color = 'currentColor' }) { return ( ); } // Spinner function Spinner({ size = 56, color = 'var(--w-cream)' }) { return (
); } const btnLink = { background: 'none', border: 'none', color: 'var(--w-green)', fontWeight: 700, fontSize: 12, cursor: 'pointer', fontFamily: 'inherit' }; function Block({ title, action, children }) { return (
{title}
{action}
{children}
); } // ─────────────────────────────────────────────────────────────── // 10. TRACKING // ─────────────────────────────────────────────────────────────── const TRACK_STAGES = [ { id: 'placed', label: 'Order placed', sub: 'We got it.', t: 0 }, { id: 'cook', label: 'Cooking', sub: 'Pans on, heat up.', t: 4 }, { id: 'pack', label: 'Packed', sub: 'Sealed & rider-ready', t: 9 }, { id: 'rider', label: 'Rider on the way', sub: 'Heading to you', t: 14 }, { id: 'delivered', label: 'Delivered', sub: 'Eat the vibe.', t: 23 }, ]; function TrackingScreen({ go, order, finishOrder }) { const [t, setT] = useStateC(0); // 0..23 useEffectC(() => { const iv = setInterval(() => setT(x => Math.min(x + 1, 23)), 1400); return () => clearInterval(iv); }, []); const stageIdx = TRACK_STAGES.findIndex((s, i) => i === TRACK_STAGES.length - 1 || t < TRACK_STAGES[i + 1].t); const stage = TRACK_STAGES[stageIdx]; const minsLeft = Math.max(0, 23 - t); const rider = W2_RIDERS[0]; return (
{/* Map */}
{/* roads */} {/* origin */} W2GO Kitchen {/* destination */} You · The Pearl {/* rider position — interp along path */} {(() => { const p = Math.min(1, t / 23); const x = 40 + (378 - 40) * p; const y = 358 - (358 - 82) * (p ** 0.7); return (
); })()} {/* back */}
{/* Sheet */}
ARRIVING IN
{minsLeft} min
{stage.label} · {stage.sub}
{/* progress bar */}
{TRACK_STAGES.map((s, i) => (
))}
{/* timeline */}
{TRACK_STAGES.map((s, i) => { const done = i < stageIdx; const live = i === stageIdx; return (
{done ? : null} {live && }
{s.label}
{i === stageIdx ? 'now' : (done ? '✓' : `${TRACK_STAGES[i].t} min`)}
); })}
{/* Rider card */} {stageIdx >= 3 && (
{rider.name.slice(0, 1)}
{rider.name}
{rider.rating} · {rider.vehicle}
)} {stageIdx === TRACK_STAGES.length - 1 && (
Rate your delivery
)}
); } // ─────────────────────────────────────────────────────────────── // 11. RATE / ORDER DONE // ─────────────────────────────────────────────────────────────── function RateScreen({ go, doneRating }) { const [stars, setStars] = useStateC(0); const [tags, setTags] = useStateC([]); const toggle = (t) => setTags(tags.includes(t) ? tags.filter(x => x !== t) : [...tags, t]); return (
go('home')}/>
DELIVERED · ENJOY
How did
that hit?
{[1,2,3,4,5].map(n => ( ))}
{stars === 0 ? 'Tap to rate.' : stars < 3 ? 'We can do better.' : stars < 5 ? 'Pretty solid.' : 'Crave Worthy.'}
What made it good?
{['Tasted fresh', 'Hot on arrival', 'Sealed & tidy', 'Quick rider', 'Portion on point', 'Worth the price'].map(t => ( toggle(t)} kind={tags.includes(t) ? 'green' : 'default'}>{t} ))}