/* global React, DATA, Panel, fmtN, fmtPct, fmtSignPct, Delta */ /* Günlük RM Brifingi — deterministik fact-pack → Claude tek sayfa anlatı (C2). */ const _brfInline = (s) => (s || '').replace(/\*\*(.+?)\*\*/g, '$1'); const renderBriefingMd = (md) => { const out = []; let key = 0; (md || '').split('\n').forEach((line) => { const t = line.trim(); if (!t) return; if (t.startsWith('## ')) { out.push(React.createElement('div', { key: key++, className: 'brf-h' }, t.slice(3))); } else if (t.startsWith('### ')) { out.push(React.createElement('div', { key: key++, className: 'brf-h' }, t.slice(4))); } else { const num = t.match(/^(\d+)\.\s+(.*)/); if (num) { out.push(React.createElement('div', { key: key++, className: 'brf-li' }, React.createElement('span', { className: 'brf-num' }, num[1]), React.createElement('span', { dangerouslySetInnerHTML: { __html: _brfInline(num[2]) } }))); } else if (t.startsWith('- ') || t.startsWith('• ')) { out.push(React.createElement('div', { key: key++, className: 'brf-li brf-dash', dangerouslySetInnerHTML: { __html: _brfInline(t.slice(2)) } })); } else { out.push(React.createElement('div', { key: key++, className: 'brf-p', dangerouslySetInnerHTML: { __html: _brfInline(t) } })); } } }); return out; }; const BrfStat = ({ label, value }) => React.createElement('div', { className: 'brf-stat' }, React.createElement('div', { className: 'brf-stat-l' }, label), React.createElement('div', { className: 'brf-stat-v' }, value)); const BrfMoversTable = ({ title, rows, deltaKey, labelKey, sub, showRev }) => React.createElement(Panel, { title, sub, flush: true }, React.createElement('table', { className: 'tbl' }, React.createElement('tbody', null, rows.map((r, i) => React.createElement('tr', { key: i }, React.createElement('td', { style: { fontWeight: 500 } }, r[labelKey]), r.bolge ? React.createElement('td', { className: 'text-muted' }, r.bolge) : null, showRev && r.gelir_M != null ? React.createElement('td', { className: 'num mono text-muted' }, '€' + r.gelir_M + 'M') : null, React.createElement('td', { className: 'num' }, r[deltaKey] != null ? React.createElement(Delta, { value: r[deltaKey] }) : '—')))))); // ── Fact-pack side panel (switches on desk) ── const HotelFactPack = ({ ctx }) => { const p = ctx.ytd_performans || {}, b = ctx.tam_yil_butce || {}; return React.createElement('div', { style: { display: 'flex', flexDirection: 'column', gap: 12 } }, React.createElement(Panel, { title: 'Fact-pack', sub: 'Anlatının arkasındaki deterministik girdiler' }, React.createElement('div', { className: 'grid grid-2 gap-2' }, React.createElement(BrfStat, { label: 'Gelir YTD', value: '€' + p.gelir_2026_M + 'M' }), React.createElement(BrfStat, { label: 'YoY', value: fmtSignPct(p.gelir_yoy_pct) }), React.createElement(BrfStat, { label: 'ADR YTD', value: '€' + p.adr_2026 }), React.createElement(BrfStat, { label: 'Marj YTD', value: '€' + p.marj_2026_M + 'M' }), React.createElement(BrfStat, { label: 'Bütçe temposu', value: '%' + b.hedefin_yuzdesi_pct }), React.createElement(BrfStat, { label: 'YoY tempo', value: fmtSignPct(b.yoy_tempo_pct) }))), (ctx.yukselen_oteller || []).length ? React.createElement(BrfMoversTable, { title: 'En hızlı büyüyen oteller', sub: 'YTD YoY · gelir', rows: ctx.yukselen_oteller, labelKey: 'otel', deltaKey: 'yoy_pct', showRev: true }) : null, (ctx.dusen_oteller || []).length ? React.createElement(BrfMoversTable, { title: 'En çok daralan oteller', sub: 'YTD YoY · gelir', rows: ctx.dusen_oteller, labelKey: 'otel', deltaKey: 'yoy_pct', showRev: true }) : null, (ctx.rakip_altinda_kaldigimiz || []).length ? React.createElement(Panel, { title: 'Rakip ortalamasının üstündeyiz', sub: 'Talep kaybı riski', flush: true }, React.createElement('table', { className: 'tbl' }, React.createElement('tbody', null, ctx.rakip_altinda_kaldigimiz.map((r, i) => React.createElement('tr', { key: i }, React.createElement('td', { style: { fontWeight: 500 } }, r.otel), React.createElement('td', { className: 'num mono' }, '€' + r.bizim_adr), React.createElement('td', { className: 'num mono text-muted' }, 'rakip €' + r.rakip_ort_adr), React.createElement('td', { className: 'num mono text-pos' }, fmtSignPct(-r.fark_pct))))))) : null, React.createElement(Panel, { title: 'Sıkı doluluk pencereleri', sub: 'Tükenme riski', flush: true }, React.createElement('table', { className: 'tbl' }, React.createElement('tbody', null, (ctx.siki_doluluk || []).map((r, i) => React.createElement('tr', { key: i }, React.createElement('td', { style: { fontWeight: 500 } }, r.bolge), React.createElement('td', { className: 'text-muted' }, r.ay), React.createElement('td', { className: 'num mono text-pos' }, '%' + r.doluluk_pct))))))); }; const FlightFactPack = ({ ctx }) => { const p = ctx.ytd_performans || {}; return React.createElement('div', { style: { display: 'flex', flexDirection: 'column', gap: 12 } }, React.createElement(Panel, { title: 'Fact-pack', sub: 'Anlatının arkasındaki deterministik girdiler' }, React.createElement('div', { className: 'grid grid-2 gap-2' }, React.createElement(BrfStat, { label: 'Gelir YTD', value: '€' + p.gelir_2026_M + 'M' }), React.createElement(BrfStat, { label: 'YoY', value: fmtSignPct(p.gelir_yoy_pct) }), React.createElement(BrfStat, { label: 'LF YTD', value: '%' + p.lf_2026_pct }), React.createElement(BrfStat, { label: 'Koltuk fiyatı', value: '€' + p.koltuk_fiyati_2026 }), React.createElement(BrfStat, { label: 'Uçuş YoY', value: fmtSignPct(p.ucus_yoy_pct) }), React.createElement(BrfStat, { label: 'Yolcu YoY', value: fmtSignPct(p.yolcu_yoy_pct) }))), (ctx.pazarlar_yoy || []).length ? React.createElement(BrfMoversTable, { title: 'Kaynak pazarlar', sub: 'YTD · gelir · YoY', rows: ctx.pazarlar_yoy.slice(0, 6), labelKey: 'pazar', deltaKey: 'yoy_pct' }) : null, (ctx.en_iyi_rotalar || []).length ? React.createElement(Panel, { title: 'En iyi rotalar', sub: 'gelir · LF', flush: true }, React.createElement('table', { className: 'tbl' }, React.createElement('tbody', null, ctx.en_iyi_rotalar.map((r, i) => React.createElement('tr', { key: i }, React.createElement('td', { style: { fontWeight: 500 } }, r.rota), React.createElement('td', { className: 'num mono' }, '€' + r.gelir_M + 'M'), React.createElement('td', { className: 'num mono text-muted' }, '%' + r.lf_pct)))))) : null, (ctx.zayif_lf_rotalar || []).length ? React.createElement(Panel, { title: 'En zayıf LF rotaları', sub: 'doldurma riski', flush: true }, React.createElement('table', { className: 'tbl' }, React.createElement('tbody', null, ctx.zayif_lf_rotalar.map((r, i) => React.createElement('tr', { key: i }, React.createElement('td', { style: { fontWeight: 500 } }, r.rota), React.createElement('td', { className: 'num mono text-neg' }, '%' + r.lf_pct), React.createElement('td', { className: 'num mono text-muted' }, '€' + r.gelir_M + 'M')))))) : null); }; const Briefing = () => { const desks = [{ id: 'hotels', label: 'Oteller' }, { id: 'flights', label: 'Uçuşlar' }]; const [desk, setDesk] = useState('hotels'); const [data, setData] = useState(null); const [loading, setLoading] = useState(false); const [err, setErr] = useState(null); const cacheRef = useRef({}); const run = async (d, force) => { // Pre-baked briefing (bundled in ai-cache.js) — instant, no wait. The // "↻ Yeniden üret" button still forces a fresh live generation. const baked = (typeof window !== 'undefined' && window.AI_BRIEFINGS && window.AI_BRIEFINGS[d]); if (!force && baked) { setDesk(d); setData(baked); cacheRef.current[d] = baked; setErr(null); return; } if (!force && cacheRef.current[d]) { setDesk(d); setData(cacheRef.current[d]); setErr(null); return; } setDesk(d); setLoading(true); setErr(null); if (force) setData(null); try { const base = (typeof window !== 'undefined' && window.API_BASE_URL) || ''; const res = await fetch(base + '/api/briefing', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ desk: d }) }); if (!res.ok) throw new Error('HTTP ' + res.status); const j = await res.json(); cacheRef.current[d] = j; setData(j); if (j.configured === false) setErr('demo'); } catch (e) { setErr('demo'); } finally { setLoading(false); } }; useEffect(() => { run('hotels'); }, []); const ctx = data && data.context; const FactPack = desk === 'flights' ? FlightFactPack : HotelFactPack; let narrative; if (loading) { narrative = React.createElement('div', { className: 'insight-loading', style: { padding: 26 } }, React.createElement('span', { className: 'insight-shimmer' }), 'brifing yazarı gece raporlarını okuyor…'); } else if (err === 'demo') { narrative = React.createElement('div', { className: 'insight-demo', style: { padding: 22 } }, 'Brifing canlı veri ambarına bağlandığında her sabah otomatik üretilir. (Demo modu — Copilot servisi şu anda kapalı.)'); } else if (data) { narrative = React.createElement('div', { className: 'brf-paper' }, renderBriefingMd(data.markdown)); } return React.createElement('div', { style: { padding: 16, display: 'flex', flexDirection: 'column', gap: 14 } }, React.createElement('div', null, React.createElement('div', { className: 'eyebrow', style: { marginBottom: 6 } }, 'Günlük RM Brifingi · C2'), React.createElement('h1', { className: 'headline', style: { fontSize: 40, margin: 0 } }, 'Masanın ', React.createElement('em', { style: { fontStyle: 'italic' } }, 'sabah okuması.')), React.createElement('div', { style: { fontSize: 13.5, color: 'var(--text-dim)', marginTop: 6, maxWidth: 720, lineHeight: 1.5 } }, 'Her sabah masa bazında üretilen tek sayfa: ne değişti, neden, rakipler ne yaptı, ajan ne öneriyor ve bugün insan kararı gerektiren ne var.')), React.createElement('div', { className: 'row between', style: { flexWrap: 'wrap', gap: 8 } }, React.createElement('div', { className: 'filterbar', style: { border: 'none', padding: 0, gap: 6 } }, desks.map(d => React.createElement('div', { key: d.id, className: 'filter-chip' + (desk === d.id ? ' active' : ''), onClick: () => run(d.id) }, d.label, ' masası'))), React.createElement('button', { className: 'btn btn-sm btn-primary', onClick: () => run(desk, true), disabled: loading }, loading ? 'Üretiliyor…' : '↻ Yeniden üret')), React.createElement('div', { className: 'grid gap-3', style: { gridTemplateColumns: '1.55fr 1fr', alignItems: 'start' } }, React.createElement(Panel, { title: `${desk === 'flights' ? 'Uçuşlar' : 'Oteller'} masası brifingi`, sub: data ? `${data.as_of} · Anthropic Claude` : 'yükleniyor…' }, narrative), ctx ? React.createElement(FactPack, { ctx }) : null)); }; window.Briefing = Briefing;