/* global React, DATA */ const HotelDetailModal = ({ hotel, onClose }) => { if (!hotel) return null; const adr = hotel.revenue / hotel.pax / (hotel.nights / hotel.bookings) || 0; const mp = hotel.margin / hotel.revenue * 100; const monthly = Array.from({ length: 12 }, (_, i) => ({ label: MONTHS[i+1], rev: (hotel.revenue / 12) * (0.4 + Math.sin(i * 0.5 - 1.2) * 0.6 + (i > 4 && i < 9 ? 0.5 : 0)) / 1e6, pax: (hotel.pax / 12) * (0.4 + Math.sin(i * 0.5 - 1.2) * 0.6 + (i > 4 && i < 9 ? 0.5 : 0)) })); const recos = DATA.top_recommendations.filter(r => r.HotelName === hotel.HotelName).slice(0, 6); const fakeRecos = recos.length ? recos : DATA.top_recommendations.slice(0, 5); // Booking-curve data for this hotel const curveRaw = DATA.booking_curves && DATA.booking_curves[hotel.HotelName]; const revCurve = curveRaw ? curveRaw.map(c => ({ label: c.days_before + 'g', target: c.target_eur, actual: c.actual_eur, projection: c.projection_eur, target_pct: c.target_pct_rev, actual_pct: c.actual_pct_rev, })) : null; const paxCurve = curveRaw ? curveRaw.map(c => ({ label: c.days_before + 'g', target: c.target_pax, actual: c.actual_pax, projection: c.projection_pax, target_pct: c.target_pct_pax, actual_pct: c.actual_pct_pax, })) : null; // Pacing delta = actual vs target at the latest observable bucket let pacingDelta = null; if (curveRaw && curveRaw.length) { const lastObserved = [...curveRaw].reverse().find(c => c.actual_pct_rev != null); if (lastObserved) pacingDelta = lastObserved.actual_pct_rev - lastObserved.target_pct_rev; } return React.createElement('div', { className: 'modal-backdrop', onClick: onClose }, React.createElement('div', { className: 'modal', onClick: e => e.stopPropagation() }, React.createElement('div', { className: 'panel-head', style: { padding: '14px 18px' } }, React.createElement('div', null, React.createElement('div', { className: 'row gap-2', style: { marginBottom: 4 } }, React.createElement('div', { className: 'panel-head-title', style: { fontSize: 14 } }, hotel.HotelName), React.createElement(Stars, { n: hotel.Stars }), React.createElement('span', { className: 'pill pill-outline' }, (hotel.SubRegion || '') + ', ' + (hotel.Region || '')) ), React.createElement('div', { className: 'panel-head-sub' }, `${hotel.Concept || 'Her Şey Dahil'} · ${fmtN(hotel.bookings || 0)} rezervasyon · ${fmtN(hotel.roomnights || 0)} oda gece`) ), React.createElement('div', { className: 'row gap-2' }, React.createElement('button', { className: 'btn btn-sm' }, 'Tahsisleri Düzenle'), React.createElement('button', { className: 'btn btn-sm btn-primary' }, 'Fiyatlamayı Aç'), React.createElement('button', { className: 'btn btn-sm btn-ghost', onClick: onClose }, '✕') ) ), React.createElement('div', { style: { overflowY: 'auto', padding: 16, display: 'flex', flexDirection: 'column', gap: 12 } }, React.createElement('div', { className: 'grid grid-5 gap-3' }, React.createElement(KPI, { label: 'Gelir', value: fmtEurM(hotel.revenue), delta: 4.8 }), React.createElement(KPI, { label: 'Yolcu', value: fmtN(hotel.pax) }), React.createElement(KPI, { label: 'ADR', value: '€' + adr.toFixed(0) }), React.createElement(KPI, { label: 'Marj', value: mp.toFixed(1) + '%', delta: 0.6 }), React.createElement(KPI, { label: 'Tempo (rez. eğrisi)', value: pacingDelta != null ? (pacingDelta >= 0 ? '+' : '') + pacingDelta.toFixed(1) + 'pt' : '—', sub: pacingDelta != null ? (pacingDelta >= 0 ? 'hedefin önünde' : 'hedefin gerisinde') : 'eğri verisi yok', delta: pacingDelta }) ), // Aylık Performans — moved above the booking curves per request React.createElement(Panel, { title: 'Aylık Performans · 2025', sub: '€ gelir · uçan yolcu' }, React.createElement(ComposedChart, { data: monthly, height: 200, barKey: 'rev', lineKey: 'pax', barFormat: v => '€' + v.toFixed(1) + 'M', lineFormat: v => fmtK(v), barColor: 'color-mix(in srgb, var(--text-dim) 40%, transparent)', lineColor: 'var(--brand)', barLabel: 'Gelir', lineLabel: 'Yolcu' }) ), // BOOKING CURVE panels — 2026 Hedef vs 2026 Gerçekleşen, absolute values revCurve && React.createElement(Panel, { title: 'Rezervasyon Eğrisi · Gelir', sub: 'X-ekseni: girişe kalan gün · Y: kümülatif gelir (€) · 2026 Hedef vs 2026 Gerçekleşen' }, React.createElement(LineChart, { data: revCurve, height: 240, format: v => fmtEurM(v), xFormat: v => v, series: [ { key: 'target', label: '2026 Hedef', color: 'color-mix(in srgb, var(--text-dim) 60%, transparent)', width: 1.6, dashed: true, tooltipFormat: d => `2026 Hedef: ${fmtEurM(d.target)} (${d.target_pct.toFixed(1)}%)` }, { key: 'actual', label: '2026 Gerçekleşen', color: 'var(--brand)', width: 2.4, tooltipFormat: d => d.actual != null ? `2026 Gerçekleşen: ${fmtEurM(d.actual)} (${d.actual_pct.toFixed(1)}%)` : '2026 Gerçekleşen: henüz yok' }, { key: 'projection', label: 'Tahmin (mevcut tempoda)', color: 'var(--brand)', width: 2.4, dashed: true, tooltipFormat: d => d.projection != null && d.actual == null ? `Tahmin: ${fmtEurM(d.projection)} (${(d.projection/d.target*100).toFixed(1)}%)` : 'Tahmin · gerçek devam ederse' }, ] }) ), paxCurve && React.createElement(Panel, { title: 'Rezervasyon Eğrisi · Yolcu', sub: 'Aynı eksen yolcu için · 2026 Hedef vs 2026 Gerçekleşen' }, React.createElement(LineChart, { data: paxCurve, height: 200, format: v => fmtK(v), xFormat: v => v, series: [ { key: 'target', label: '2026 Hedef', color: 'color-mix(in srgb, var(--text-dim) 60%, transparent)', width: 1.6, dashed: true, tooltipFormat: d => `2026 Hedef: ${fmtN(d.target)} yolcu (${d.target_pct.toFixed(1)}%)` }, { key: 'actual', label: '2026 Gerçekleşen', color: 'var(--info)', width: 2.4, tooltipFormat: d => d.actual != null ? `2026 Gerçekleşen: ${fmtN(d.actual)} yolcu (${d.actual_pct.toFixed(1)}%)` : '2026 Gerçekleşen: henüz yok' }, { key: 'projection', label: 'Tahmin (mevcut tempoda)', color: 'var(--info)', width: 2.4, dashed: true, tooltipFormat: d => d.projection != null && d.actual == null ? `Tahmin: ${fmtN(d.projection)} yolcu (${(d.projection/Math.max(d.target,1)*100).toFixed(1)}%)` : 'Tahmin · gerçek devam ederse' }, ] }) ), !revCurve && React.createElement('div', { style: { padding: '14px 16px', background: 'var(--paper-edge)', borderLeft: '2px solid var(--amber)', fontSize: 12, fontStyle: 'italic', color: 'var(--text-dim)' } }, 'Bu otel için rezervasyon eğrisi verisi yetersiz (en az 5 adet 2025 + 1 adet 2026 rezervasyonu gerekir).'), React.createElement(Panel, { title: 'Fiyatlama Önerileri · Bu Otel', flush: true }, React.createElement('table', { className: 'tbl' }, React.createElement('thead', null, React.createElement('tr', null, React.createElement('th', null, 'Pazar'), React.createElement('th', null, 'Konaklama'), React.createElement('th', null, 'Oda'), React.createElement('th', { className: 'num' }, 'Mevcut'), React.createElement('th', { className: 'num' }, 'Önerilen'), React.createElement('th', { className: 'num' }, 'Δ'), React.createElement('th', { className: 'num' }, 'Güven') )), React.createElement('tbody', null, fakeRecos.map((r, i) => { const pos = r.PriceChangePct >= 0; return React.createElement('tr', { key: i }, React.createElement('td', null, r.SourceMarket), React.createElement('td', null, MONTHS[r.Month]), React.createElement('td', { className: 'text-muted' }, r.RoomCategory), React.createElement('td', { className: 'num text-muted' }, '€' + fmtN(r.CurrentPrice_EUR)), React.createElement('td', { className: 'num', style: { fontWeight: 600 } }, '€' + fmtN(r.RecommendedPrice_EUR)), React.createElement('td', { className: 'num' }, React.createElement('span', { className: pos?'pill pill-brand':'pill pill-neg' }, (pos?'+':'') + r.PriceChangePct + '%')), React.createElement('td', { className: 'num text-muted' }, r.ConfidencePct + '%') ); })) ) ) ) ) ); }; window.HotelDetailModal = HotelDetailModal;