// aerOS Guest v3 — Concierge chat + Services list screen (v2 themed). const { useState: _cc3S, useEffect: _cc3E, useRef: _cc3R } = React; function G3Concierge({ C, t, lang, tw }) { const room = (window.G2CTX && (window.G2CTX.room || window.G2CTX.table)) || '-'; const tkey = 'aeros-guest-thread-' + (window.aerosApi ? (window.aerosApi.getTenant() || '') : '') + '-' + room; const [threadId, setThreadId] = _cc3S(() => { try { return localStorage.getItem(tkey) || null; } catch { return null; } }); const [msgs, setMsgs] = _cc3S([]); const [draft, setDraft] = _cc3S(''); const [closed, setClosed] = _cc3S(false); const scroller = _cc3R(null); const alive = _cc3R(true); _cc3E(() => () => { alive.current = false; }, []); const now = lang === 'en' ? 'now' : 'şimdi'; const fmt = (iso) => (iso || '').slice(11, 16) || now; const mapMsgs = (rows) => (rows || []).map(m => ({ from: m.sender === 'staff' ? 'staff' : 'guest', text: m.body, time: fmt(m.created_at) })); const reload = async (tid) => { try { const r = await window.guestApi.conciergeMessages(tid); if (alive.current) setMsgs(mapMsgs(r)); } catch (e) {} }; _cc3E(() => { if (scroller.current) scroller.current.scrollTop = scroller.current.scrollHeight; }, [msgs]); // Pick up the room's active thread on open. _cc3E(() => { (async () => { try { const tid = await window.guestApi.conciergeActive(room); if (tid) { try { localStorage.setItem(tkey, tid); } catch (e) {} setThreadId(String(tid)); } else { setThreadId(null); setMsgs([]); } } catch (e) {} })(); }, []); // Poll for staff replies + detect archival. _cc3E(() => { if (!threadId || closed) return; let stop = false; const tick = async () => { try { const [, act] = await Promise.all([reload(threadId), window.guestApi.conciergeActive(room)]); if (!stop && String(act || '') !== String(threadId)) setClosed(true); } catch (e) {} }; tick(); const id = setInterval(tick, 6000); return () => { stop = true; clearInterval(id); }; }, [threadId, closed]); const startFresh = () => { try { localStorage.removeItem(tkey); } catch (e) {} setClosed(false); setThreadId(null); setMsgs([]); setDraft(''); }; const push = async (txt) => { if (closed) return; setMsgs(m => [...m, { from: 'guest', text: txt, time: now }]); try { if (!threadId) { const res = await window.guestApi.startConcierge(room, txt, 'Oda ' + room); if (res && res.thread_id) { try { localStorage.setItem(tkey, res.thread_id); } catch (e) {} setThreadId(String(res.thread_id)); } } else { try { await window.guestApi.sendConcierge(threadId, txt); reload(threadId); } catch (e2) { setClosed(true); } } } catch (e) {} }; const send = () => { if (!draft.trim()) return; push(draft.trim()); setDraft(''); }; const quick = lang === 'en' ? ['May I get towels?', 'Dinner reservation', 'Late check-out?'] : ['Havlu rica edebilir miyim?', 'Akşam için rezervasyon', 'Geç check-out mümkün mü?']; return (
{Icon.headset({ size: 22 })}
{t.concierge}
{t.conciergeSub}
{msgs.map((m, i) => (
{m.text}
{m.time}
))}
{closed ? (
{lang === 'en' ? 'Conversation closed. Start a new one to message again.' : 'Görüşme kapandı. Yeni mesaj için yeni görüşme başlatın.'}
{lang === 'en' ? 'New conversation' : 'Yeni görüşme başlat'}
) : (<>
{quick.map(q => )}
setDraft(e.target.value)} onKeyDown={e => e.key === 'Enter' && send()} placeholder={t.msgPlaceholder} style={{ flex: 1, border: 'none', background: 'transparent', outline: 'none', fontSize: 14.5, fontFamily: G2THEME.BODY_FONT, color: C.ink }} />
)}
); } function G3ServiceList({ C, t, lang, tw, onService }) { const D = window.G2DATA; const all = [...D.SERVICE_TILES, 'tv', 'social', 'concierge']; return (

{t.services}

{all.map(s => { const m = D.SERVICE_META[s]; if (!m) return null; return ( ); })}
); } Object.assign(window, { G3Concierge, G3ServiceList });