/* global React, FLEET */
const { useState, useMemo } = React;
/* ============================================================
BOOKING — multi-step quote with live recommendation
============================================================ */
function BookingFlow() {
const [step, setStep] = useState(0);
const [data, setData] = useState({
from: 'PRG', fromName: 'Prague',
to: 'LCY', toName: 'London City',
distance: 1050,
date: '2026-05-12', time: '09:00',
pax: 4,
aircraft: null,
catering: 'standard',
extras: [],
});
const update = (k, v) => setData(d => ({ ...d, [k]: v }));
// recommend aircraft based on pax + distance
const recommended = useMemo(() => {
const candidates = window.FLEET.filter(a => {
const rangeKm = parseInt(a.range.replace(/[,\s]/g, ''));
return a.seats >= data.pax && rangeKm >= data.distance * 1.15;
});
return candidates.sort((a, b) => a.seats - b.seats).slice(0, 3);
}, [data.pax, data.distance]);
// estimated price (rough — for prototype only)
const priceEst = useMemo(() => {
const a = data.aircraft || recommended[0];
if (!a) return 0;
const ratePerKm = { 'learjet-75': 9, 'gulfstream-g200': 11, 'gulfstream-g280': 13, 'challenger-605': 15, 'global-6000': 22 };
const base = (ratePerKm[a.id] || 12) * data.distance * 2;
const cateringExtra = { standard: 0, premium: 1200, signature: 3500 }[data.catering] || 0;
return Math.round((base + cateringExtra) / 100) * 100;
}, [data.aircraft, data.catering, data.distance, recommended]);
const steps = ['Route', 'Passengers', 'Aircraft', 'Details', 'Quote'];
const next = () => setStep(s => Math.min(s + 1, steps.length - 1));
const prev = () => setStep(s => Math.max(s - 1, 0));
return (
04 — Instant quote
Plan your
flight in five steps.
Tell us where, when and how many — we'll suggest the right aircraft and a live price band.
A real dispatcher confirms within four working hours.
{/* LEFT — form */}
{/* Step bar */}
{steps.map((s, i) => (
))}
{/* Step content */}
{step === 0 && (
Where to?
update('from', v.toUpperCase())} mono/>
update('to', v.toUpperCase())} mono/>
update('date', v)}/>
update('time', v)}/>
{[
['PRG → LCY', 1050, 'PRG', 'Prague', 'LCY', 'London City'],
['PRG → DXB', 4350, 'PRG', 'Prague', 'DXB', 'Dubai'],
['PRG → CDG', 880, 'PRG', 'Prague', 'CDG', 'Paris CDG'],
['PRG → LJU', 480, 'PRG', 'Prague', 'LJU', 'Ljubljana'],
].map(p => (
))}
)}
{step === 1 && (
How many?
Passengers
{[2, 4, 6, 8, 10, 12].map(n => (
))}
With {data.pax} passengers and a leg of {data.distance} km,
we have {recommended.length} aircraft that fit.
)}
{step === 2 && (
Pick your aircraft
{recommended.length === 0 && (
No aircraft in the fleet match these requirements. Adjust passenger count or contact dispatch.
)}
{recommended.map((a, i) => {
const sel = (data.aircraft?.id || recommended[0]?.id) === a.id;
return (
);
})}
)}
{step === 3 && (
Onboard preferences
Catering
{[
{ id: 'standard', t: 'Standard', d: 'Sandwiches, fresh fruit, soft drinks', p: 'Included' },
{ id: 'premium', t: 'Premium', d: 'Three-course menu by Prague chef, full bar', p: '+ €1,200' },
{ id: 'signature', t: 'Signature', d: 'Bespoke menu — sourced and prepped to your spec', p: '+ €3,500' },
].map(c => {
const sel = data.catering === c.id;
return (
);
})}
Extras
{['VIP Lounge', 'Ground transfer', 'Pet onboard', 'Cargo hold'].map(x => {
const sel = data.extras.includes(x);
return (
);
})}
)}
{step === 4 && (
Your estimate
Indicative. A dispatcher confirms binding price within 4 working hours.
Estimated price band
€{(priceEst * 0.92).toLocaleString('en-US', { maximumFractionDigits: 0 })}
—
€{(priceEst * 1.08).toLocaleString('en-US', { maximumFractionDigits: 0 })}
Round trip · all taxes & fees · positioning included
)}
{/* Nav buttons */}
{step < steps.length - 1 && (
)}
{/* RIGHT — live summary */}
Your quote · LIVE
{/* Route visual */}
FROM
{data.from}
{data.fromName}
TO
{data.to}
{data.toName}
Estimated · indicative only
€{priceEst.toLocaleString('en-US', { maximumFractionDigits: 0 })}
± 8% · all-in · round trip
);
}
function Field({ label, value, onChange, type = 'text', mono }) {
return (
);
}
function SummaryRow({ l, v }) {
return (
{l}
{v}
);
}
Object.assign(window, { BookingFlow });