// Wander — Browse, Search, Saved, Profile, Paywall (Stripe), Completion, Offline // ─── BROWSE ─────────────────────────────────────────────────────────────────── function BrowseScreen({ onOpenTour, onTab, onSearch, dense }) { const { TOURS } = window.WANDER_DATA; const [cat, setCat] = React.useState('All'); const cats = ['All','Free','Food','History','Architecture','Nature','After dark']; const featured = TOURS[1]; const list = cat==='Free' ? TOURS.filter(t=>t.tier==='free') : TOURS; return (
Tours · Singapore

Where to next?

{cats.map(c => ( ))}
All tours
{list.map(t => ( ))}
); } // ─── SEARCH ─────────────────────────────────────────────────────────────────── function SearchScreen({ onClose, onOpenTour }) { const { TOURS } = window.WANDER_DATA; const [q, setQ] = React.useState(''); const recent = ['Hawker','Sunset spots','Free tours','Architecture','Family-friendly']; const matches = q ? TOURS.filter(t => t.title.toLowerCase().includes(q.toLowerCase()) || t.subtitle.toLowerCase().includes(q.toLowerCase())) : []; return (
setQ(e.target.value)} placeholder="Search tours…" style={{ flex:1, border:'none', outline:'none', background:'transparent', fontFamily:'inherit', fontSize:15, color:'var(--w-ink)' }}/>
{!q ? (
Recent
{recent.map(r => (
setQ(r)} style={{ display:'flex', alignItems:'center', gap:12, padding:'14px 0', borderBottom:'1px solid var(--w-line)', cursor:'pointer' }}> {r}
))}
Trending in Singapore
{['Chinatown food','Sunset Marina','Hidden gardens','Heritage shophouses','Peranakan Joo Chiat'].map(t => ( ))}
) : (
{matches.length} {matches.length===1?'result':'results'}
{matches.map(t => (
onOpenTour(t.id)} style={{ display:'flex', gap:12, padding:'12px 0', cursor:'pointer', borderBottom:'1px solid var(--w-line)', alignItems:'center' }}>
{t.title}
{t.subtitle}
))}
)}
); } // ─── SAVED ──────────────────────────────────────────────────────────────────── function SavedScreen({ onTab, onOpenTour, onOpenOffline, dense }) { const { TOURS } = window.WANDER_DATA; const saved = TOURS.slice(0,4); return (
Saved

Your library

{['Wishlist','Downloaded','Completed'].map((t,i) => ( ))}
{saved.map(t => (
onOpenTour(t.id)} style={{ background:'var(--w-paper)', borderRadius:22, padding:12, display:'flex', gap:14, alignItems:'center', boxShadow:'var(--sh-card)', cursor:'pointer' }}>
{t.title}
{t.duration} · {t.stops} stops
{t.formats.slice(0,3).map(f=>formatIcon(f,13,'var(--w-mute)'))}
))}
); } // ─── PROFILE ────────────────────────────────────────────────────────────────── function ProfileScreen({ onTab, dense }) { const stats = [{label:'Tours',v:'12'},{label:'Cities',v:'4'},{label:'Steps',v:'38k'}]; const badges = ['🦁 Singapore explorer','🌅 Sunrise walker','🍜 Hawker hunter','📜 History buff']; return (
You
🧭
Alex Lim
Wandering since April 2025
{stats.map(s => (
{s.v}
{s.label}
))}
Wander Pro
All tours, every city
$4.99/month after trial
Badges
{badges.map(b => {b})}
Settings
{['Language · English','Voice · Mei Ling','Notifications','Help & Feedback'].map((s,i,a) => (
{s}
))}
); } // ─── PAYWALL (with Stripe) ──────────────────────────────────────────────────── function PaywallScreen({ tourId, onClose, onSuccess }) { const { TOURS } = window.WANDER_DATA; const tour = TOURS.find(t => t.id===tourId) || TOURS[1]; const [plan, setPlan] = React.useState('pro'); const [loading, setLoading] = React.useState(false); const [error, setError] = React.useState(null); const plans = [ { id:'tour', label:'Just this tour', price:'$'+tour.price, sub:'one-time', highlight:false }, { id:'pro', label:'Wander Pro', price:'$4.99', sub:'per month · 7-day free trial', highlight:true }, ]; // Listen for payment success from popup window React.useEffect(() => { const handler = (e) => { if (e.data?.type==='WANDER_PAYMENT_SUCCESS') onSuccess(); }; window.addEventListener('message', handler); return () => window.removeEventListener('message', handler); }, [onSuccess]); // Check if we landed back from Stripe redirect with ?unlocked=1 React.useEffect(() => { const params = new URLSearchParams(window.location.search); if (params.get('unlocked')==='1') { window.history.replaceState({}, '', '/'); onSuccess(); } }, []); const handlePay = async () => { setLoading(true); setError(null); try { const res = await fetch('/api/stripe/checkout', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ tourId, plan }), }); const data = await res.json(); if (!res.ok) throw new Error(data.error || 'Payment failed'); // Open Stripe Checkout in a small popup (stays inside the prototype view) const popup = window.open(data.url, 'stripe_checkout', 'width=480,height=700,left=200,top=100'); if (!popup) { // Fallback: redirect current tab window.location.href = data.url; } } catch (e) { if (e.message.includes('not configured')) { // Demo mode — simulate success setTimeout(() => onSuccess(), 1200); } else { setError(e.message); } } finally { setLoading(false); } }; return (
{tour.emoji}
Unlock pro tour

{tour.title}

{tour.blurb}

{plans.map(p => ( ))}
    {['Unlimited tours in 47 cities','Offline downloads & maps','AR overlays + bonus stops','Cancel anytime'].map(t => (
  • {t}
  • ))}
{error &&
{error}
}
Charged after 7 days. Cancel anytime in Settings.
); } // ─── COMPLETION ─────────────────────────────────────────────────────────────── function CompletionScreen({ tourId, onDone }) { const { TOURS, STOPS } = window.WANDER_DATA; const tour = TOURS.find(t=>t.id===tourId) || TOURS[0]; const [stars, setStars] = React.useState(5); return (
{Array.from({length:20}).map((_,i) => { const colors=['#FFC93C','#FF6B5A','#2DD4A7','#9B7EDC','#4FB7E8']; return
; })}
🏆
Tour complete

You wandered like a local.

{tour.title} · all {STOPS.length} stops · 1.8 km on foot

{[{l:'Time',v:'47 min'},{l:'Steps',v:'2,840'},{l:'Discoveries',v:'7'}].map(s => (
{s.v}
{s.l}
))}
🦁
Badge unlocked
Marina Bay Master
Rate this tour
{[1,2,3,4,5].map(n => )}