/* global React, DATA, Panel, fmtEUR, fmtN, fmtPct, fmtSignPct */ const Compset = () => { const all = Object.values(DATA.competitor); const [mkt, setMkt] = useState('All'); const markets = ['All', ...DATA.market_mix.map(x => x.market)]; const ods = Object.keys(DATA.competitor).sort(); const [od, setOd] = useState(ods.includes('LCA-ATH') ? 'LCA-ATH' : ods[0]); const sel = DATA.competitor[od]; // network undercut table: where cheapest competitor < our fare const undercuts = all.map(c => { if (!c.competitors || !c.competitors.length || c.our_fare == null) return null; const cheapest = c.competitors[0]; const gap = (cheapest.fare - c.our_fare) / c.our_fare * 100; return { od: c.od, market: c.market, our: c.our_fare, carrier: cheapest.carrier, comp: cheapest.fare, gap }; }).filter(Boolean).filter(x => mkt === 'All' || x.market === mkt).sort((a, b) => a.gap - b.gap).slice(0, 40); const fares = sel ? [{ carrier: 'Cyprus Airways', fare: sel.our_fare, us: true }, ...sel.competitors] : []; const maxFare = Math.max(...fares.map(f => f.fare || 0), 1); return React.createElement('div', { className: 'page' }, React.createElement('div', { className: 'page-head' }, React.createElement('div', { className: 'eyebrow', style: { marginBottom: 8 } }, 'Competitive Set'), React.createElement('h1', { className: 'headline', style: { fontSize: 46 } }, 'How we sit ', React.createElement('em', null, 'against the market.')), React.createElement('div', { className: 'subhead' }, 'Latest observed lowest fares versus Aegean, Sky Express, El Al, Wizz Air, Emirates, Middle East Airlines and others — by O&D.')), React.createElement('div', { className: 'grid gap-3', style: { gridTemplateColumns: '1fr 1.4fr', marginBottom: 22 } }, React.createElement(Panel, { title: `${od} · price position`, sub: 'Lowest fare, latest observation', actions: React.createElement('select', { className: 'input', value: od, onChange: e => setOd(e.target.value), style: { width: 130 } }, ods.map(x => React.createElement('option', { key: x, value: x }, x))) }, React.createElement('div', { style: { padding: '4px 2px' } }, fares.sort((a, b) => (a.fare || 0) - (b.fare || 0)).map((f, i) => React.createElement('div', { key: i, style: { marginBottom: 11 } }, React.createElement('div', { className: 'row between', style: { marginBottom: 3 } }, React.createElement('span', { style: { fontWeight: f.us ? 700 : 500, fontSize: 12, color: f.us ? 'var(--accent)' : 'var(--ink)' } }, f.carrier, f.us ? ' ◆' : ''), React.createElement('span', { className: 'mono', style: { fontSize: 11 } }, fmtEUR(f.fare))), React.createElement('div', { style: { height: 8, background: 'var(--paper-edge)', borderRadius: 3, overflow: 'hidden' } }, React.createElement('div', { style: { width: (f.fare / maxFare * 100) + '%', height: '100%', background: f.us ? 'var(--accent)' : 'var(--text-muted)' } })))))), React.createElement(Panel, { title: 'Where competitors undercut us', sub: 'Cheapest competitor below our current fare', flush: true, actions: React.createElement('div', { className: 'filterbar' }, markets.map(x => React.createElement('button', { key: x, className: 'filter-chip' + (mkt === x ? ' active' : ''), onClick: () => setMkt(x) }, x))) }, React.createElement('div', { style: { maxHeight: 420, overflowY: 'auto' } }, React.createElement('table', { className: 'tbl tbl-zebra' }, React.createElement('thead', null, React.createElement('tr', null, ['O&D', 'Market', 'Our fare', 'Cheapest comp', 'Carrier', 'Gap'].map((h, i) => React.createElement('th', { key: i, className: i > 1 ? 'num' : '' }, h)))), React.createElement('tbody', null, undercuts.map((r, i) => React.createElement('tr', { key: i, className: 'clickable', onClick: () => setOd(r.od) }, React.createElement('td', { style: { fontWeight: 600 } }, r.od), React.createElement('td', { className: 'text-muted' }, r.market), React.createElement('td', { className: 'num mono' }, fmtEUR(r.our)), React.createElement('td', { className: 'num mono' }, fmtEUR(r.comp)), React.createElement('td', null, React.createElement('span', { className: 'pill pill-info' }, r.carrier)), React.createElement('td', { className: 'num mono text-neg' }, fmtSignPct(r.gap)))))))) )); }; window.Compset = Compset;