/* global React, Icon, Chip, Btn, Price, VehicleCard, SectionHead */ const { useState, useEffect, useMemo, useRef } = React; // ─── Fleet listing page ────────────────────────────────────────────────── function FleetPage({ onSelect, initialCategory }) { const [search, setSearch] = useState(""); const [category, setCategory] = useState(initialCategory || "all"); const [body, setBody] = useState("all"); const [seats, setSeats] = useState("all"); const [priceMax, setPriceMax] = useState(3500); const [transmission, setTransmission] = useState("all"); const [fuel, setFuel] = useState("all"); const [sort, setSort] = useState("featured"); const [view, setView] = useState("grid"); const filtered = useMemo(() => { let arr = [...window.FLEET]; if (search) arr = arr.filter(v => (v.make + " " + v.model).toLowerCase().includes(search.toLowerCase())); if (category !== "all") arr = arr.filter(v => v.category === category); if (body !== "all") arr = arr.filter(v => v.body === body); if (seats !== "all") arr = arr.filter(v => v.seats >= Number(seats)); if (transmission !== "all") arr = arr.filter(v => v.transmission === transmission); if (fuel !== "all") arr = arr.filter(v => v.fuel === fuel); arr = arr.filter(v => v.price == null || v.price <= priceMax); if (sort === "priceAsc") arr.sort((a,b) => (a.price ?? 99999) - (b.price ?? 99999)); if (sort === "priceDesc") arr.sort((a,b) => (b.price ?? 99999) - (a.price ?? 99999)); if (sort === "featured") arr.sort((a,b) => (b.featured?1:0) - (a.featured?1:0)); return arr; }, [search, category, body, seats, priceMax, transmission, fuel, sort]); const FilterGroup = ({ label, value, options, onChange }) => (
{label}
{options.map(o => { const val = Array.isArray(o) ? o[0] : o; const lbl = Array.isArray(o) ? o[1] : o; const active = value === val; return ( ); })}
); return (
{/* Header band */}
The Fleet · {filtered.length} of {window.FLEET.length} shown

Pick your ride.

setSearch(e.target.value)} placeholder="Search make or model…" style={{ background:"var(--surface)", border:"1px solid var(--border)", color:"var(--text)", borderRadius: 4, padding:"11px 14px 11px 36px", fontSize: 13, width: 280, outline:"none" }}/>
{/* Sidebar filters */} {/* Results */}
{filtered.length === 0 ? (
No vehicles match your filters. Try widening the range.
) : view === "grid" ? (
{filtered.map(v => )}
) : (
{filtered.map(v => )}
)}
); } window.FleetPage = FleetPage; function FleetListRow({ v, onSelect }) { const [hover, setHover] = useState(false); return (
onSelect(v)} onMouseEnter={() => setHover(true)} onMouseLeave={() => setHover(false)} style={{ background:"var(--surface)", border:"1px solid", borderColor: hover ? "var(--primary)" : "var(--border)", borderRadius: 8, padding: 16, display:"grid", gridTemplateColumns:"180px 1fr auto auto", gap: 24, alignItems:"center", cursor:"pointer", transition:"border-color .2s ease" }}>
{v.make}

{v.model}

{v.category} {v.body} {v.seats} seats {v.fuel} {v.tags.map(t => {t})}
Book
); } // ─── Vehicle Detail ────────────────────────────────────────────────────── function VehicleDetail({ v, onClose, onBook }) { if (!v) return null; const similar = window.FLEET.filter(x => x.category === v.category && x.id !== v.id).slice(0, 4); const specs = [ { label:"Category", value: v.category }, { label:"Body", value: v.body }, { label:"Seats", value: v.seats }, { label:"Transmission", value: v.transmission }, { label:"Fuel", value: v.fuel }, { label:"Engine", value: v.power } ]; return (
{/* Crumb */}
{ e.preventDefault(); window.go("home"); }} style={{ color:"var(--muted)", textDecoration:"none" }}>Home { e.preventDefault(); window.go("fleet"); }} style={{ color:"var(--muted)", textDecoration:"none" }}>Fleet {v.make} {v.model}
{/* Gallery */}
{`${v.make}
No deposit {v.tags.map(t => {t})}
{/* Thumb strip — placeholder */}
{[0,1,2,3].map(i => (
{i === 3 &&
+12
}
))}
{/* Spec table */}
The spec
{specs.map((s, i) => (
{s.label} {s.value}
))}

Spec fields shown only when verified by the live fleet feed. Year, mileage and plate confirmed at handover.

{/* Inclusions */}
What's in the price
{[ { icon:"shield", title:"Basic insurance", body:"Comprehensive cover included by default." }, { icon:"pin", title:"Delivery & return", body:"To any hotel, airport or address in Dubai." }, { icon:"bolt", title:"250 km / day", body:"Extra km charged at AED 2. No hidden fees." }, { icon:"clock", title:"24/7 support", body:"Real human on WhatsApp, English / Arabic / Russian." } ].map(it => (
{it.title}
{it.body}
))}
{/* Booking column */}
{/* Similar */}
{similar.map(s => { window.scrollTo(0, 0); window.openVehicle(x); }}/>)}
); } window.VehicleDetail = VehicleDetail; // ─── Booking Drawer ───────────────────────────────────────────────────── function BookingDrawer({ vehicle, open, onClose }) { const [step, setStep] = useState(1); const [form, setForm] = useState({ pickup:"", dropoff:"", location:"DXB Airport", customLocation:"", driverStatus:"tourist", name:"", phone:"", email:"", notes:"" }); const [submitted, setSubmitted] = useState(false); useEffect(() => { if (open) { const today = new Date(); const t3 = new Date(); t3.setDate(today.getDate()+3); setForm(f => ({ ...f, pickup: today.toISOString().slice(0,10), dropoff: t3.toISOString().slice(0,10) })); setStep(1); setSubmitted(false); } }, [open]); const days = useMemo(() => { if (!form.pickup || !form.dropoff) return 0; const ms = new Date(form.dropoff) - new Date(form.pickup); return Math.max(1, Math.ceil(ms / (1000*60*60*24))); }, [form.pickup, form.dropoff]); if (!open || !vehicle) return null; const total = vehicle.price ? vehicle.price * days : null; const update = (k) => (e) => setForm({ ...form, [k]: e.target?.value ?? e }); return ( <>
{/* Drawer header */}
Booking enquiry · Step {submitted ? "✓" : step} / 3
{vehicle.make} {vehicle.model}
{/* Progress */} {!submitted && (
{[1,2,3].map(n => (
))}
)} {/* Body */}
{submitted ? ( ) : step === 1 ? ( ) : step === 2 ? ( ) : ( )}
{/* Footer actions */} {!submitted && (
1 ? "space-between" : "flex-end" }}> {step > 1 && setStep(step-1)}>Back} {step < 3 ? ( setStep(step+1)}>Continue ) : ( setSubmitted(true)}>Send enquiry )}
)}
); } window.BookingDrawer = BookingDrawer; // Booking sub-steps ─────────────────────────────────────────────────────── function FieldShell({ label, icon, children, sub }) { return ( ); } const inputCss = { background:"var(--bg)", border:"1px solid var(--border)", color:"var(--text)", padding:"12px 14px", borderRadius: 4, fontSize: 14, fontFamily:"inherit", outline:"none", width:"100%", colorScheme:"dark" }; function Step1({ form, update, days, total, vehicle }) { return (

When & where

{form.location.startsWith("Other") && ( )}
); } function Step2({ form, update }) { return (

Driver status

So we can pre-fill the rental contract with the right documents.

{[ { id:"tourist", label:"Tourist", body:"Passport + visa + IDP + home licence" }, { id:"resident", label:"UAE Resident", body:"Emirates ID + UAE driving licence" } ].map(opt => { const active = form.driverStatus === opt.id; return ( ); })}
Add-ons (optional)
{[ { id:"chauffeur", label:"Chauffeur service", body:"Add a uniformed driver, English / Arabic / Russian." }, { id:"insurance", label:"Premium insurance top-up", body:"Reduce excess to zero. From AED 75/day." }, { id:"airport", label:"Meet & greet at airport", body:"We'll be at arrivals with your name on a plaque." } ].map(a => ( ))}
); } function Step3({ form, update, vehicle, days, total }) { return (

Your details

We'll confirm by WhatsApp in ~5 min. No card on file. No deposit.