/* global React, ReactDOM, DATA */ const { useState, useEffect, useRef } = React; const NAV = [ { group: 'NETWORK DESK', items: [ { id: 'overview', label: 'Network Overview', n: '01' }, { id: 'network', label: 'Routes & Markets', n: '02' }, { id: 'pace', label: 'Booking Pace', n: '03' }, { id: 'pricing', label: 'Pricing & Fares', n: '04' }, { id: 'compset', label: 'Competitive Set', n: '05' }, { id: 'forecast', label: 'Demand Forecast', n: '06' }, ]}, { group: 'A · FORECASTING & DEMAND', items: [ { id: 'a1', label: 'Event-Impact Agent', n: 'A1' }, { id: 'a2', label: 'Demand Sensing', n: 'A2' }, { id: 'a3', label: 'Anomaly Explain', n: 'A3' }, ]}, { group: 'B · PRICING AGENTS', items: [ { id: 'b1', label: 'Bid-Price Agent', n: 'B1' }, { id: 'b2', label: 'Competitive Response', n: 'B2' }, { id: 'b3', label: 'Overbooking & No-Show', n: 'B3' }, { id: 'b4', label: 'Class Closure', n: 'B4' }, ]}, { group: 'C · ANALYST COPILOTS', items: [ { id: 'copilot', label: 'Conversational Workbench', n: 'C1' }, { id: 'briefing', label: 'Daily Briefing', n: 'C2' }, { id: 'scenario', label: 'Scenario Sim', n: 'C3' }, ]}, { group: 'D · COMMERCIAL WORKFLOWS', items: [ { id: 'd1', label: 'Group & Charter Quote', n: 'D1' }, { id: 'd2', label: 'Ancillary Personalization', n: 'D2' }, { id: 'd3', label: 'IROPS Recovery', n: 'D3' }, ]}, { group: 'E · EXPLAINABILITY & GOV.', items: [ { id: 'e1', label: 'Explainability Layer', n: 'E1' }, { id: 'e2', label: 'Pricing Audit', n: 'E2' }, { id: 'overrides', label: 'Override Log', n: '08' }, ]}, ]; const AGENT_CODES = ['a1', 'a2', 'a3', 'b1', 'b2', 'b3', 'b4', 'd1', 'd2', 'd3', 'e1', 'e2']; const PAGES = { overview: () => React.createElement(window.Overview), network: () => React.createElement(window.Network), pace: () => React.createElement(window.Pace), pricing: () => React.createElement(window.Pricing), compset: () => React.createElement(window.Compset), forecast: () => React.createElement(window.Forecast), briefing: () => React.createElement(window.Briefing), scenario: () => React.createElement(window.Scenario), overrides: () => React.createElement(window.Overrides), }; AGENT_CODES.forEach(c => { PAGES[c] = () => React.createElement(window.AgentView, { code: c.toUpperCase() }); }); const Sidebar = ({ page, setPage, openCopilot }) => React.createElement('aside', { className: 'sidebar' }, React.createElement('div', { className: 'sidebar-brand' }, React.createElement('div', { className: 'sidebar-wordmark' }, 'fly', React.createElement('em', null, 'nas')), React.createElement('div', { className: 'sidebar-tag' }, 'REVENUE MANAGEMENT')), React.createElement('div', { className: 'sidebar-edition' }, React.createElement('div', { className: 'sidebar-edition-label' }, 'AI-Native RM · 15 use cases'), React.createElement('div', { className: 'sidebar-edition-value' }, 'Vol. ', React.createElement('span', { style: { fontStyle: 'italic' } }, 'XIX'), ' · No. 145')), React.createElement('nav', { className: 'sidebar-nav' }, NAV.map((g, gi) => React.createElement('div', { key: gi, style: { padding: '10px 0 4px' } }, React.createElement('div', { className: 'nav-group-label' }, g.group), g.items.map(it => React.createElement('div', { key: it.id, className: 'nav-item' + (page === it.id ? ' active' : ''), onClick: () => it.id === 'copilot' ? openCopilot() : setPage(it.id) }, React.createElement('span', { className: 'nav-num' }, it.n), React.createElement('span', { className: 'nav-label' }, it.label))))) ), React.createElement('div', { className: 'sidebar-footer' }, React.createElement('div', { className: 'sidebar-footer-label', style: { marginBottom: 6 } }, 'Warehouse'), React.createElement('div', { style: { display: 'flex', alignItems: 'center', gap: 8, marginBottom: 4 } }, React.createElement('span', { className: 'dot dot-pos' }), React.createElement('span', { style: { color: 'var(--text-on-ink-dim)' } }, 'RDS · flynas_rm synced')), React.createElement('div', { className: 'mono', style: { fontSize: 9.5, color: 'var(--text-on-ink-faint)' } }, 'Built ' + (DATA.meta.build_ts || '').slice(0, 10)))); const TopBar = ({ copilotOpen, toggleCopilot, onSearch }) => React.createElement('div', { className: 'topbar' }, React.createElement('div', { className: 'masthead' }, React.createElement('div', { className: 'masthead-issue' }, 'Sunday · 24 May 2026'), React.createElement('div', { style: { width: 1, height: 18, background: 'var(--rule-soft)' } }), React.createElement('div', { className: 'masthead-issue' }, 'FY 2026 ▾'), React.createElement('div', { className: 'masthead-issue' }, 'All Markets ▾'), React.createElement('div', { className: 'masthead-issue' }, 'All Hubs ▾'), React.createElement('div', { className: 'masthead-divider' }), React.createElement('div', { className: 'masthead-live' }, React.createElement('span', { className: 'masthead-live-dot' }), React.createElement('span', null, 'Live'), React.createElement('em', null, '· Hajj 1447 inbound peak'))), React.createElement('div', { className: 'topbar-actions' }, React.createElement('div', { className: 'topbar-search', onClick: onSearch }, React.createElement('span', null, 'Search the desk…'), React.createElement('span', { className: 'mono', style: { fontSize: 10, color: 'var(--text-faint)', marginLeft: 'auto' } }, '⌘K')), React.createElement('button', { className: 'btn btn-sm btn-ghost' }, 'Export'), React.createElement('button', { className: 'btn btn-sm' + (copilotOpen ? ' btn-primary' : ''), onClick: toggleCopilot }, 'Copilot'), React.createElement('div', { className: 'avatar', title: 'flynas Revenue Management' }, 'f'))); const StatusBar = () => { const k = DATA.kpi; return React.createElement('div', { className: 'statusbar' }, React.createElement('div', { className: 'statusbar-section' }, React.createElement('span', { className: 'dot dot-pos' }), React.createElement('span', null, 'CONNECTED'), React.createElement('span', { style: { color: 'var(--text-faint)' } }, 'rds · flynas_rm')), React.createElement('div', { className: 'statusbar-section' }, React.createElement('span', null, 'Revenue TTM'), React.createElement('span', { style: { color: 'var(--ink)', fontWeight: 600 } }, fmtSAR(k.revenue)), React.createElement('span', { style: { color: 'var(--text-faint)' } }, '·'), React.createElement('span', null, fmtSignPct(k.revenue_yoy), ' YoY')), React.createElement('div', { className: 'statusbar-section' }, React.createElement('span', null, 'Load factor'), React.createElement('span', { style: { color: 'var(--accent)', fontWeight: 600 } }, fmtPct(k.lf)), React.createElement('span', { style: { color: 'var(--text-faint)' } }, '·'), React.createElement('span', null, 'Fleet ' + DATA.meta.fleet_count)), React.createElement('div', { className: 'statusbar-section', style: { marginLeft: 'auto' } }, React.createElement('span', { style: { color: 'var(--text-faint)' } }, '15 AI use cases · A–E'), React.createElement('span', { style: { color: 'var(--text-faint)' } }, 'powered by Claude'))); }; const CommandPalette = ({ open, onClose, setPage }) => { const [q, setQ] = useState(''); useEffect(() => { if (open) setQ(''); }, [open]); if (!open) return null; const items = [ ...NAV.flatMap(g => g.items.filter(it => it.id !== 'copilot').map(it => ({ type: it.n, label: it.label, action: () => { setPage(it.id); onClose(); } }))), ...DATA.route_table.slice(0, 50).map(r => ({ type: 'O&D', label: r.od + ' · ' + r.market, action: () => { setPage('network'); onClose(); } })), ]; const filtered = (q ? items.filter(i => i.label.toLowerCase().includes(q.toLowerCase())) : items).slice(0, 12); return React.createElement('div', { onClick: onClose, style: { position: 'fixed', inset: 0, background: 'rgba(10,10,10,.5)', display: 'flex', justifyContent: 'center', paddingTop: '15vh', zIndex: 100 } }, React.createElement('div', { onClick: e => e.stopPropagation(), style: { width: 640, maxWidth: '90vw', background: 'var(--paper)', border: '1px solid var(--ink)', height: 'fit-content' } }, React.createElement('div', { style: { padding: '12px 16px 8px', borderBottom: '1px solid var(--ink)' } }, React.createElement('div', { className: 'eyebrow', style: { marginBottom: 4 } }, 'Index'), React.createElement('input', { autoFocus: true, placeholder: 'Jump to a use case or O&D…', value: q, onChange: e => setQ(e.target.value), style: { width: '100%', height: 36, border: 'none', outline: 'none', background: 'transparent', fontSize: 18, fontFamily: 'var(--serif)', color: 'var(--ink)' } })), React.createElement('div', { style: { maxHeight: 400, overflowY: 'auto', padding: 4 } }, filtered.map((it, i) => React.createElement('div', { key: i, onClick: it.action, style: { padding: '9px 12px', fontSize: 12.5, cursor: 'pointer', display: 'flex', gap: 10, borderBottom: '1px solid var(--rule-dim)' }, onMouseEnter: e => e.currentTarget.style.background = 'var(--paper-edge)', onMouseLeave: e => e.currentTarget.style.background = '' }, React.createElement('span', { style: { fontSize: 9.5, letterSpacing: '.1em', textTransform: 'uppercase', color: 'var(--accent)', fontWeight: 700, minWidth: 42, fontFamily: 'var(--mono)' } }, it.type), React.createElement('span', null, it.label)))))); }; class ErrorBoundary extends React.Component { constructor(p) { super(p); this.state = { err: null }; } static getDerivedStateFromError(err) { return { err }; } render() { if (!this.state.err) return this.props.children; return React.createElement('div', { style: { padding: 32, maxWidth: 880, margin: '0 auto' } }, React.createElement('div', { className: 'eyebrow' }, 'Page error'), React.createElement('h1', { className: 'headline', style: { fontSize: 32 } }, 'This section failed to load.'), React.createElement('pre', { style: { fontFamily: 'var(--mono)', fontSize: 11, background: 'var(--paper-edge)', padding: 14, borderLeft: '3px solid var(--neg)', overflow: 'auto' } }, (this.state.err.stack || String(this.state.err)).split('\n').slice(0, 12).join('\n')), React.createElement('button', { className: 'btn btn-primary', style: { marginTop: 16 }, onClick: () => this.setState({ err: null }) }, 'Retry')); } } const App = () => { const [page, setPage] = useState('overview'); const [copilotOpen, setCopilotOpen] = useState(false); const [paletteOpen, setPaletteOpen] = useState(false); useEffect(() => { const h = (e) => { if ((e.metaKey || e.ctrlKey) && e.key === 'k') { e.preventDefault(); setPaletteOpen(true); } if ((e.metaKey || e.ctrlKey) && e.key === '/') { e.preventDefault(); setCopilotOpen(o => !o); } if (e.key === 'Escape') setPaletteOpen(false); if (e.altKey) { const map = { o: 'overview', n: 'network', f: 'forecast', b: 'pace', p: 'pricing', c: 'compset' }; if (map[e.key.toLowerCase()]) { e.preventDefault(); setPage(map[e.key.toLowerCase()]); } } }; window.addEventListener('keydown', h); return () => window.removeEventListener('keydown', h); }, []); return React.createElement(React.Fragment, null, React.createElement('div', { className: 'app' }, React.createElement(Sidebar, { page, setPage, openCopilot: () => setCopilotOpen(true) }), React.createElement('main', { className: 'main' }, React.createElement(TopBar, { copilotOpen, toggleCopilot: () => setCopilotOpen(o => !o), onSearch: () => setPaletteOpen(true) }), React.createElement('div', { className: 'workspace' }, React.createElement('div', { className: 'content' }, React.createElement(ErrorBoundary, { key: page }, PAGES[page]())), React.createElement(window.Copilot, { open: copilotOpen, onClose: () => setCopilotOpen(false) })), React.createElement(StatusBar))), React.createElement(CommandPalette, { open: paletteOpen, onClose: () => setPaletteOpen(false), setPage })); }; function __mount() { ReactDOM.createRoot(document.getElementById('root')).render(React.createElement(App)); } if (window.DATA) __mount(); else window.addEventListener('__data_ready', __mount);