import { useState, useRef } from 'react' import './LiveDemo.css' // API URL - set via VITE_API_URL env var (points to Render backend) const API_URL = import.meta.env.VITE_API_URL || 'https://fairrelay-brain.onrender.com' const DEMO_DRIVERS = [ { id: 'drv_001', name: 'Rajesh Kumar', hours_today: 4.5, hours_since_rest: 2.1, is_ill: false, gender: 'M', vehicle_capacity_kg: 500, preferred_language: 'hi' }, { id: 'drv_002', name: 'Priya Sharma', hours_today: 8.1, hours_since_rest: 0.5, is_ill: false, gender: 'F', vehicle_capacity_kg: 400, preferred_language: 'hi' }, { id: 'drv_003', name: 'Amit Patel', hours_today: 3.2, hours_since_rest: 3.0, is_ill: false, gender: 'M', vehicle_capacity_kg: 600, preferred_language: 'en' }, ] const DEMO_PACKAGES = [ { id: 'pkg_001', weight_kg: 12.5, fragility_level: 2, address: 'Andheri West, Mumbai', latitude: 19.1364, longitude: 72.8296, priority: 'normal' }, { id: 'pkg_002', weight_kg: 8.0, fragility_level: 1, address: 'Bandra East, Mumbai', latitude: 19.0596, longitude: 72.8495, priority: 'high' }, { id: 'pkg_003', weight_kg: 22.0, fragility_level: 3, address: 'Powai, Mumbai', latitude: 19.1176, longitude: 72.9060, priority: 'normal' }, { id: 'pkg_004', weight_kg: 5.5, fragility_level: 1, address: 'Goregaon East, Mumbai', latitude: 19.1663, longitude: 72.8526, priority: 'express' }, { id: 'pkg_005', weight_kg: 15.0, fragility_level: 2, address: 'Juhu, Mumbai', latitude: 19.0883, longitude: 72.8264, priority: 'normal' }, { id: 'pkg_006', weight_kg: 9.8, fragility_level: 1, address: 'Malad West, Mumbai', latitude: 19.1874, longitude: 72.8484, priority: 'normal' }, ] const DEMO_ROUTES = [ { id: 'rt_mumbai_pune', distance_km: 148, difficulty: 'medium', is_night_route: false }, { id: 'rt_pune_nashik', distance_km: 215, difficulty: 'hard', is_night_route: true }, { id: 'rt_nashik_aurangabad', distance_km: 98, difficulty: 'easy', is_night_route: false }, ] // Fallback mock result for when backend is unavailable const MOCK_RESULT = { success: true, data: { allocations: [ { driver: 'drv_001', driver_name: 'Rajesh Kumar', route: 'rt_nashik_aurangabad', route_label: 'Nashik → Aurangabad (98km)', wellness_score: 92 }, { driver: 'drv_002', driver_name: 'Priya Sharma', route: 'rt_mumbai_pune', route_label: 'Mumbai → Pune (148km)', wellness_score: 61 }, { driver: 'drv_003', driver_name: 'Amit Patel', route: 'rt_pune_nashik', route_label: 'Pune → Nashik (215km)', wellness_score: 95 }, ] }, meta: { gini_index: 0.12, fairness_grade: 'A', carbon_kg: 87.4, latency_ms: 312, explanation: 'Priya has worked 8.1h today — assigned shorter route. Night route routed to Amit (highest wellness). Gini = 0.12 — excellent fairness.', source: 'mock', } } interface DemoResult { success: boolean data: { allocations: Array<{ driver: string driver_name: string route: string route_label: string wellness_score: number }> } meta: { gini_index: number fairness_grade: string carbon_kg: number latency_ms: number explanation: string source?: string } } export default function LiveDemo() { const [status, setStatus] = useState<'idle' | 'loading' | 'done'>('idle') const [result, setResult] = useState(null) const [apiSource, setApiSource] = useState<'live' | 'fallback'>('live') const resultRef = useRef(null) const runDemo = async () => { setStatus('loading') setResult(null) const startTime = Date.now() try { // Try calling real backend API const response = await fetch(`${API_URL}/api/v1/allocate`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ drivers: DEMO_DRIVERS.map(d => ({ id: d.id, name: d.name, vehicle_capacity_kg: d.vehicle_capacity_kg, preferred_language: d.preferred_language, })), packages: DEMO_PACKAGES, warehouse: { lat: 19.0760, lng: 72.8777 }, allocation_date: new Date().toISOString().split('T')[0], }), signal: AbortSignal.timeout(15000), // 15s timeout }) if (response.ok) { const data = await response.json() const latency = Date.now() - startTime // Transform real API response into demo format const allocations = (data.assignments || []).map((a: any) => ({ driver: a.driver_external_id || a.driver_id, driver_name: a.driver_name || a.driver_external_id, route: a.route_id, route_label: `Route ${a.route_summary?.num_stops || '?'} stops · ${a.route_summary?.total_weight_kg?.toFixed(1) || '?'}kg · ${a.route_summary?.estimated_time_minutes?.toFixed(0) || '?'}min`, wellness_score: Math.round((a.fairness_score || 0.8) * 100), })) setResult({ success: true, data: { allocations }, meta: { gini_index: data.global_fairness?.gini_index ?? 0.15, fairness_grade: (data.global_fairness?.gini_index ?? 0.15) < 0.2 ? 'A' : (data.global_fairness?.gini_index ?? 0.3) < 0.35 ? 'B' : 'C', carbon_kg: allocations.length * 28.5, latency_ms: latency, explanation: `Real-time allocation via FairRelay API. ${allocations.length} drivers assigned with Gini = ${(data.global_fairness?.gini_index ?? 0.15).toFixed(2)}. Fairness-optimized in ${latency}ms.`, source: 'live', } }) setApiSource('live') } else { throw new Error(`API returned ${response.status}`) } } catch (err) { // Fallback to mock with realistic delay console.warn('[LiveDemo] Backend unavailable, using fallback:', err) await new Promise(r => setTimeout(r, 800)) setResult({ ...MOCK_RESULT, meta: { ...MOCK_RESULT.meta, latency_ms: Date.now() - startTime, source: 'fallback', } }) setApiSource('fallback') } setStatus('done') setTimeout(() => resultRef.current?.scrollIntoView({ behavior: 'smooth', block: 'nearest' }), 100) } return (
Live Demo

See it run right now

Real FairRelay logic. Tap the button to allocate 3 drivers to 3 routes and see the fairness score.

3 Drivers
{DEMO_DRIVERS.map(d => (
{d.name.split(' ').map(n => n[0]).join('')}
{d.name}
{d.hours_today}h today · {d.is_ill ? '🤒 Ill' : '✅ Healthy'}
))}
FairRelay
3 Routes
{DEMO_ROUTES.map(r => (
🗺
{r.id.replace(/rt_|_/g, m => m === 'rt_' ? '' : ' → ').replace(/^\w/, c => c.toUpperCase())}
{r.distance_km}km · {r.difficulty} {r.is_night_route ? '🌙 Night' : ''}
))}
{status === 'done' && (
{apiSource === 'live' ? '● Connected to live API' : '● Using demo fallback (backend warming up)'}
)}
{status === 'done' && result && (
Gini {result.meta.gini_index} Fairness index
Grade {result.meta.fairness_grade} Fairness grade
{result.meta.carbon_kg} kg CO₂ est.
{result.meta.latency_ms}ms Latency
{result.data.allocations.map(a => (
{a.driver_name.split(' ').map(n => n[0]).join('')}
{a.driver_name}
{a.route_label}
= 80 ? '#10b981' : a.wellness_score >= 60 ? '#f59e0b' : '#ef4444' }}> ♥ {a.wellness_score}
))}
{result.meta.explanation}
)}
) }