// aerOS Guest v3 — Hotel services (spa booking, transfer, wifi, events, content) — v2 themed. const { useState: _s3S, useEffect: _s3E } = React; // Guest content service key -> backend static_page.page_key aliases. Lets the // real CMS page back a fixed guest tile (e.g. the "Şehir Turu" tile -> turist). const PAGE_KEY_ALIAS = { tour: ['turist', 'tour', 'city_tour', 'sehir_turu'], news: ['newspaper', 'news', 'gazete'], tv: ['tv_guide', 'tv'], meeting: ['meeting', 'toplanti'], social: ['social', 'social_media'], gallery: ['gallery', 'galeri'] }; function findStaticPage(service) { const pages = (window.G2DATA && window.G2DATA.PAGES) || []; const keys = PAGE_KEY_ALIAS[service] || [service]; return pages.find((p) => keys.includes((p.key || '').toLowerCase())) || null; } function G3SvcHeader({ C, t, tw, title, color, icon, onBack }) { return (
{icon && {icon({ size: 22 })}}

{title}

); } function G3Field({ label, children, C }) { return
{label}{children}
; } function G3Input({ value, onChange, placeholder, icon, type = 'text', C }) { return (
{icon && {icon({ size: 17 })}} onChange(e.target.value)} placeholder={placeholder} style={{ flex: 1, border: 'none', background: 'transparent', outline: 'none', fontSize: 14.5, fontFamily: G2THEME.BODY_FONT, color: C.ink }} />
); } function G3Services({ C, t, lang, tw, service, onBack, toast }) { const D = window.G2DATA; const m = D.SERVICE_META[service] || { icon: 'image', color: C.accent }; const color = m.color; return (
{service === 'spa' && } {service === 'transfer' && } {service === 'wifi' && } {service === 'events' && } {['tour', 'gallery', 'news', 'tv', 'meeting', 'social'].includes(service) && }
); } function SpaMod({ C, t, lang, tw, toast }) { const D = window.G2DATA; const [book, setBook] = _s3S(null); const [tier, setTier] = _s3S(0); const [f, setF] = _s3S({ surname: '', date: '', time: '' }); return ( <>
{D.SPA_SERVICES.map(s => (
{lang === 'en' ? s.en : s.name}
{s.tiers.map((tr, i) => {tr.d} · {G2THEME.money(tr.p, tw.currency)})}
{ setBook(s); setTier(0); }}>{t.book}
))}
setBook(null)} C={C} animate={tw.animate}> {book &&

{lang === 'en' ? book.en : book.name}

{t.selectTier}
{book.tiers.map((tr, i) => )}
setF({ ...f, surname: v })} icon={Icon.user} C={C} />
setF({ ...f, date: v })} type="date" icon={Icon.calendar} C={C} />
setF({ ...f, time: v })} type="time" icon={Icon.clock} C={C} />
{ const tr = book.tiers[tier] || {}; const when = f.date ? (f.date + 'T' + (f.time || '12:00') + ':00') : new Date().toISOString().slice(0, 19); try { await window.guestApi.bookSpa(book.id, parseInt(tr.d, 10) || null, tr.p || null, { surname: f.surname, when, note: null }); toast(t.reserved); setBook(null); } catch (e) { toast(lang === 'en' ? 'Could not send request' : 'Talep gönderilemedi'); } }}>{t.book} · {G2THEME.money(book.tiers[tier].p, tw.currency)}
}
); } function TransferMod({ C, t, lang, tw, toast }) { const D = window.G2DATA; const [route, setRoute] = _s3S((D.ROUTES[0] || {}).id); const [veh, setVeh] = _s3S((D.VEHICLES[0] || {}).id); const [round, setRound] = _s3S(false); const [f, setF] = _s3S({ surname: '', flight: '', date: '', pax: '2' }); if (!D.ROUTES.length || !D.VEHICLES.length) { return
{lang === 'en' ? 'No transfer options available.' : 'Transfer seçeneği bulunmuyor.'}
; } const r = D.ROUTES.find(x => x.id === route) || D.ROUTES[0], v = D.VEHICLES.find(x => x.id === veh) || D.VEHICLES[0]; const price = Math.round(r.price * v.mult * (round ? 1.9 : 1)); return (
{D.ROUTES.map(x => )}
{D.VEHICLES.map(x => )}
setF({ ...f, surname: v })} icon={Icon.user} C={C} />
setF({ ...f, pax: v })} type="number" C={C} />
setF({ ...f, flight: v })} placeholder="TK1980" icon={Icon.plane} C={C} />
setF({ ...f, date: v })} placeholder="08.06" icon={Icon.calendar} C={C} />
{t.total} {G2THEME.money(price, tw.currency)}
{ try { await window.guestApi.requestTransfer({ surname: f.surname, route: (lang === 'en' ? r.en : r.label), car: v.label, price, flight: f.flight, round, remarks: `${f.pax} ${t.people} · ${f.date || ''}`.trim(), }); toast(t.reserved); } catch (e) { toast(lang === 'en' ? 'Could not send request' : 'Talep gönderilemedi'); } }}>{t.request}
); } function WifiMod({ C, t, toast }) { const D = window.G2DATA; const copy = (v) => { try { navigator.clipboard.writeText(v); } catch {} toast(t.copied); }; return (
{window.QRCode ? :
}
{[[t.wifiName, D.BRAND.wifiSsid], [t.wifiPass, D.BRAND.wifiPass]].map(([k, v], i) => (
{k}
{v}
))}
toast(t.connect)}>{t.connect}
); } function EventsMod({ C, t, lang, tw }) { const D = window.G2DATA; return (
{D.EVENTS.map(e => (
{lang === 'en' ? e.en : e.title}
{Icon.calendar({ size: 14 })}{e.date}
))}
); } // Real CMS-backed content page: loads the tenant's static page (sections / rich // body / images) for this guest tile. No hard-coded demo content — when the // tenant hasn't authored a page, a neutral empty state shows instead. function ContentMod({ C, t, lang, tw, service, color, icon }) { const en = lang === 'en'; const [page, setPage] = _s3S(null); const [loading, setLoading] = _s3S(true); _s3E(() => { let on = true; (async () => { try { const meta = findStaticPage(service); if (!meta) { if (on) { setPage(null); setLoading(false); } return; } const full = window.guestApi && window.guestApi.staticPage ? await window.guestApi.staticPage(meta.id) : null; if (on) { setPage(full || null); setLoading(false); } } catch (e) { if (on) { setPage(null); setLoading(false); } } })(); return () => { on = false; }; }, [service]); if (loading) return
; const sections = (page && Array.isArray(page.sections)) ? page.sections : []; const body = page ? (en ? (page.content_en || page.content_tr) : (page.content_tr || page.content_en)) : ''; if (!page || (!sections.length && !body)) { return (
{icon({ size: 26 })}
{en ? 'Content coming soon.' : 'İçerik yakında eklenecek.'}
); } // Gallery: render the page's section images as a grid. if (service === 'gallery') { const imgs = sections.map((s) => s.image).filter(Boolean); if (!imgs.length) return
{en ? 'No photos yet.' : 'Henüz fotoğraf yok.'}
; return
{imgs.map((src, i) => )}
; } // Body HTML comes from the tenant's own staff CMS (Quill editor) — first-party, // not guest input. Rendered as-is; if untrusted authors are ever added, sanitize here. return (
{sections.map((s, i) => { const title = en ? (s.title_en || s.title_tr) : (s.title_tr || s.title_en); const sBody = en ? (s.body_en || s.body_tr) : (s.body_tr || s.body_en); return (
{s.image && }
{title &&
{title}
} {sBody &&
}
); })} {!sections.length && body && (
)}
); } window.G3Services = G3Services;