/* Me2You - Main App: routing, header, footer, state management */
/* global React, ReactDOM, Icon, PageTransition, SearchBar, Price,
MarketplaceHero, CategoryRail, ProductGrid, ProductDetail, CartView, CheckoutView, OrderSuccess, OrdersList, DisputeForm,
SwapOfferFlow, OTPCollectionConfirm,
SellerDashboard, CreateListing, AdminPanel, DriverApp,
AuthLogin, AuthRegister, AuthForgot, SellerOTPVerify, ProfilePage, PrivacyPolicy, AdminPayoutRun,
ToastProvider, useToast, OrderTracking, MobileBottomNav,
NotificationBell, SearchSuggestions, BrowseFilters,
WishlistPage, SellerStorefront, ChatList, ChatThread, FeedScreen, CommunityScreen,
PayFastRedirect, OnboardingTour, EarningsChart, AdminAuditLog, PWAInstallBanner,
PRODUCTS, CATEGORIES, SAMPLE_ORDERS,
btnPrimary, btnGhost, panelStyle,
TweaksPanel, useTweaks, TweakSection, TweakRadio, TweakToggle, TweakSlider, TweakSelect, TweakColor, TweakButton */
const { useState, useEffect, useMemo, useCallback } = React;
const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
"surface": "marketplace",
"theme": "light",
"animationLevel": "lively",
"trustBadges": true,
"heroVariant": "seller",
"cardDensity": "comfortable",
"navStyle": "top"
}/*EDITMODE-END*/;
/* --- App Header --- */
function AppHeader({ surface, onSurface, cartCount, onNav, search, onSearch, onSelectProduct }) {
return (
{ e.preventDefault(); onNav('home'); }} style={{display:'inline-flex',alignItems:'center',gap:8,borderBottom:0}}>
Me2You
{/* Surface tabs */}
{[
{key:'marketplace',label:'Items'},
{key:'property',label:'Property'},
{key:'vehicles',label:'Vehicles'},
{key:'seller',label:'Seller'},
{key:'admin',label:'Admin'},
{key:'driver',label:'Driver'},
].map(s => (
))}
{surface === 'marketplace' && (
{ if (onSelectProduct) onSelectProduct(p); }}/>
)}
);
}
const headerNavBtn = {
display:'inline-flex',alignItems:'center',gap:8,
padding:'10px 14px',borderRadius:'var(--radius-md)',
background:'transparent',border:'none',cursor:'pointer',
fontFamily:'var(--font-body)',fontWeight:600,fontSize:14,color:'var(--ink-700)',
};
/* --- App Footer --- */
function AppFooter() {
return (
);
}
/* --- Main App --- */
function App() {
const [tweaks, setTweak] = useTweaks(TWEAK_DEFAULTS);
const [surface, setSurface] = useState(tweaks.surface);
const [route, setRoute] = useState('home');
const [cart, setCart] = useState([]);
const [search, setSearch] = useState('');
const [activeCat, setActiveCat] = useState('all');
const [selected, setSelected] = useState(null);
const [saved, setSaved] = useState([]);
const [watched, setWatched] = useState([]);
const [deliveryMethod, setDeliveryMethod] = useState('pickup');
const [chatThread, setChatThread] = useState(null);
const [showOnboarding, setShowOnboarding] = useState(true);
const [showPWA, setShowPWA] = useState(false);
const [browseView, setBrowseView] = useState('grid');
const toast = useToast();
useEffect(() => {
const t = setTimeout(() => setShowPWA(true), 8000);
return () => clearTimeout(t);
}, []);
const toggleSave = useCallback((id) => {
setSaved(prev => prev.includes(id) ? prev.filter(x => x !== id) : [...prev, id]);
if (toast) toast(saved.includes(id) ? 'Removed from saved' : 'Saved for later');
}, [toast, saved]);
const toggleWatch = useCallback((id) => {
setWatched(prev => prev.includes(id) ? prev.filter(x => x !== id) : [...prev, id]);
if (toast) toast(watched.includes(id) ? 'Stopped watching' : 'Watching for price drops');
}, [toast, watched]);
const cartCount = cart.reduce((n,i) => n + i.qty, 0);
const addToCart = useCallback((p) => {
setCart(prev => {
const ex = prev.find(i => i.product.id === p.id);
if (ex) return prev.map(i => i.product.id === p.id ? {...i, qty:i.qty+1} : i);
return [...prev, {product:p, qty:1}];
});
if (toast) toast(`${p.title} added to cart`);
setRoute('cart');
}, [toast]);
const updateQty = useCallback((id, delta) => {
setCart(prev => prev.map(i => i.product.id === id ? {...i, qty: Math.max(1, i.qty + delta)} : i));
}, []);
const removeFromCart = useCallback((id) => {
setCart(prev => prev.filter(i => i.product.id !== id));
}, []);
const filteredProducts = useMemo(() => {
let list = PRODUCTS;
if (activeCat !== 'all') list = list.filter(p => p.cat === activeCat);
if (search) list = list.filter(p => p.title.toLowerCase().includes(search.toLowerCase()) || p.location.toLowerCase().includes(search.toLowerCase()));
return list;
}, [activeCat, search]);
const handleSurface = (s) => {
setSurface(s);
setRoute('home');
setTweak('surface', s);
};
const isDark = tweaks.theme === 'dark';
return (
{ setSurface('marketplace'); setRoute(r); }}
search={search} onSearch={setSearch}
onSelectProduct={p => { setSurface('marketplace'); setSelected(p); setRoute('product'); }}/>
{surface === 'admin' ? (
) : surface === 'driver' ? (
) : surface === 'property' ? (
{route === 'property-detail' && selected ? (
{ setSelected(null); setRoute('home'); }}
onMessage={() => { setSurface('marketplace'); setRoute('messages'); }}/>
) : (
{ setSelected(p); setRoute('property-detail'); }}/>
)}
) : surface === 'vehicles' ? (
{route === 'vehicle-detail' && selected ? (
{ setSelected(null); setRoute('home'); }}
onMessage={() => { setSurface('marketplace'); setRoute('messages'); }}/>
) : (
{ setSelected(v); setRoute('vehicle-detail'); }}/>
)}
) : (
{surface === 'marketplace' && route === 'home' && (
<>
setRoute('home')} onSell={() => handleSurface('seller')}/>
{tweaks.trustBadges && (
{[
{icon:'shield-check', title:'Escrow protected', desc:'Payment held until delivery confirmed'},
{icon:'truck', title:'Three delivery flows', desc:'Door-to-door, pickup locker, or self-collect OTP'},
{icon:'star', title:'Built for trust', desc:'Ratings, disputes, POPIA-compliant'},
].map(t => (
))}
)}
Browse the marketplace
{browseView === 'grid' ? (
<>
{ setSelected(p); setRoute('product'); }} onAddToCart={addToCart}/>
>
) : (
{ setSelected(p); setRoute('product'); }}/>
)}
>
)}
{surface === 'marketplace' && route === 'feed' && (
{ setSelected(p); setRoute('product'); }}
onMessage={() => setRoute('messages')}/>
)}
{surface === 'marketplace' && route === 'community' && (
{ setSelected(p); setRoute('product'); }}/>
)}
{surface === 'marketplace' && route === 'product' && (
setRoute('home')} onAddToCart={addToCart}
onSwap={p => { setSelected(p); setRoute('swap'); }}
onWatch={toggleWatch} watched={selected ? watched.includes(selected.id) : false}/>
)}
{surface === 'marketplace' && route === 'swap' && (
setRoute('product')}/>
)}
{surface === 'marketplace' && route === 'otp-collect' && (
{ setCart([]); setRoute('home'); }}
onConfirmed={() => {}}/>
)}
{surface === 'marketplace' && route === 'cart' && (
setRoute('checkout')} onBrowse={() => setRoute('home')}/>
)}
{surface === 'marketplace' && route === 'checkout' && (
{ setDeliveryMethod(method || 'pickup'); setRoute('payfast'); }}/>
)}
{surface === 'marketplace' && route === 'success' && (
{ setCart([]); setRoute('home'); }}
onConfirmCollect={() => setRoute('otp-collect')}/>
)}
{surface === 'marketplace' && route === 'orders' && (
setRoute('tracking')}/>
)}
{surface === 'marketplace' && route === 'dispute' && (
setRoute('orders')}/>
)}
{surface === 'marketplace' && route === 'login' && (
setRoute('home')} onRegister={() => setRoute('register')} onForgot={() => setRoute('forgot')}/>
)}
{surface === 'marketplace' && route === 'register' && (
setRoute('home')} onLogin={() => setRoute('login')}/>
)}
{surface === 'marketplace' && route === 'forgot' && (
setRoute('login')}/>
)}
{surface === 'marketplace' && route === 'profile' && (
)}
{surface === 'marketplace' && route === 'privacy' && (
setRoute('home')}/>
)}
{surface === 'marketplace' && route === 'tracking' && (
setRoute('orders')} onDispute={() => setRoute('dispute')}/>
)}
{surface === 'marketplace' && route === 'verify' && (
setRoute('profile')} onBack={() => setRoute('profile')}/>
)}
{surface === 'marketplace' && route === 'proof' && (
Proof of ownership
)}
{surface === 'marketplace' && route === '2fa' && (
Two-factor authentication
)}
{surface === 'marketplace' && route === 'safe-meetup' && (
Safe meet-up locations
)}
{surface === 'marketplace' && route === 'saved' && (
{ setSelected(p); setRoute('product'); }}
onUnsave={toggleSave} onToggleWatch={toggleWatch}/>
)}
{surface === 'marketplace' && route === 'messages' && !chatThread && (
setChatThread(t)}/>
)}
{surface === 'marketplace' && route === 'messages' && chatThread && (
setChatThread(null)}/>
)}
{surface === 'marketplace' && route === 'storefront' && (
setRoute(selected ? 'product' : 'home')}
onSelect={p => { setSelected(p); setRoute('product'); }}/>
)}
{surface === 'marketplace' && route === 'payfast' && (
s + i.product.price * i.qty, 0) + 60}
onComplete={() => setRoute(deliveryMethod === 'self' ? 'otp-collect' : 'success')}/>
)}
{surface === 'seller' && route === 'home' && (
setRoute('create')} onNav={setRoute}/>
)}
{surface === 'seller' && route === 'create' && (
setRoute('home')} onPublish={() => setRoute('home')}/>
)}
{surface === 'seller' && route === 'otp' && (
setRoute('home')}/>
)}
)}
{surface !== 'driver' && }
{/* Mobile bottom nav */}
{surface === 'marketplace' && (
{ if (k === 'sell') handleSurface('seller'); else if (k === 'browse') { setActiveCat('all'); setRoute('home'); } else setRoute(k); }}/>
)}
{/* Onboarding tour */}
{showOnboarding && setShowOnboarding(false)}/>}
{/* PWA install banner */}
{showPWA && setShowPWA(false)}/>}
{/* Tweaks Panel */}
handleSurface(v)}/>
setTweak('theme', v)}/>
setTweak('trustBadges', v)}/>
setTweak('cardDensity', v)}/>
setTweak('animationLevel', v)}/>
);
}
const root = ReactDOM.createRoot(document.getElementById('app'));
root.render();