// 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.chevLeft({ size: 21 })}
{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) =>
setTier(i)} style={{ flex: 1, padding: 12, borderRadius: 12, border: `1.5px solid ${tier === i ? C.accent : C.line2}`, background: tier === i ? C.accentSoft : 'transparent', cursor: 'pointer', fontFamily: G2THEME.BODY_FONT }}>{tr.d}
{G2THEME.money(tr.p, tw.currency)}
)}
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 => setRoute(x.id)} style={{ display: 'flex', alignItems: 'center', gap: 10, padding: '12px 14px', borderRadius: 12, border: `1.5px solid ${route === x.id ? C.accent : C.line2}`, background: route === x.id ? C.accentSoft : 'transparent', cursor: 'pointer', fontFamily: G2THEME.BODY_FONT }}>{Icon.plane({ size: 17 })} {lang === 'en' ? x.en : x.label} {G2THEME.money(x.price, tw.currency)} )}
{D.VEHICLES.map(x => setVeh(x.id)} style={{ flex: 1, padding: '11px 6px', borderRadius: 12, border: `1.5px solid ${veh === x.id ? C.accent : C.line2}`, background: veh === x.id ? C.accentSoft : 'transparent', cursor: 'pointer', fontFamily: G2THEME.BODY_FONT, display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 5 }}>{Icon.car({ size: 18 })} {x.label} {x.cap} {t.people} )}
setRound(r => !r)} style={{ display: 'flex', alignItems: 'center', gap: 10, padding: '12px 14px', borderRadius: 12, border: `1.5px solid ${round ? C.accent : C.line2}`, background: round ? C.accentSoft : 'transparent', cursor: 'pointer', fontFamily: G2THEME.BODY_FONT }}>{round && Icon.check({ size: 13, style: { color: '#fff' } })} {t.roundTrip}
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 (
{[[t.wifiName, D.BRAND.wifiSsid], [t.wifiPass, D.BRAND.wifiPass]].map(([k, v], i) => (
copy(v)} style={{ display: 'inline-flex', alignItems: 'center', gap: 6, padding: '8px 13px', borderRadius: 10, border: 'none', background: C.accentSoft, color: C.onAccentSoft, fontSize: 12.5, fontWeight: 700, cursor: 'pointer', fontFamily: G2THEME.BODY_FONT }}>{Icon.copy({ size: 14 })}{t.copy}
))}
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;