// Fetches real BQ data from /api/data and sets window.FABCOM_DATA // Must execute before the UI React components try to read from window.FABCOM_DATA. (function(){ const LOADER_EL_ID = "__fabcom_loader__"; function showLoader(msg) { let el = document.getElementById(LOADER_EL_ID); if (!el) { el = document.createElement("div"); el.id = LOADER_EL_ID; el.style.cssText = "position:fixed;inset:0;display:flex;align-items:center;justify-content:center;background:#0a0e1c;color:#e6e9f2;font-family:system-ui;font-size:14px;z-index:9999"; document.body.appendChild(el); } el.textContent = msg; } function hideLoader() { const el = document.getElementById(LOADER_EL_ID); if (el) el.remove(); } async function loadData() { showLoader("Loading ads settings from BigQuery…"); try { const r = await fetch("/api/data", {headers: {"Accept": "application/json"}}); if (!r.ok) throw new Error(`HTTP ${r.status}`); const data = await r.json(); window.FABCOM_DATA = data; window.FX = data.meta.fx; // helpers — match original shape window.fmtHKD = (n) => (n == null ? "—" : ("HK$" + Math.round(n).toLocaleString("en-HK"))); window.fmtCCY = (n, ccy) => (n == null ? "—" : (new Intl.NumberFormat("en-HK", {style: "currency", currency: ccy, maximumFractionDigits: 0})).format(n)); window.toHKD = (amt, ccy) => amt * (window.FX[ccy] || 1); window.pct = (a, b) => b ? Math.round((a/b)*100) : 0; window.timeAgo = (ts) => { if (!ts) return "—"; const d = Date.now() - ts; const m = Math.round(d / 60000); if (m < 1) return "just now"; if (m < 60) return `${m}m ago`; const h = Math.round(m / 60); if (h < 24) return `${h}h ago`; const dy = Math.round(h / 24); if (dy < 14) return `${dy}d ago`; const w = Math.round(dy/7); return `${w}w ago`; }; window.formatFullTs = (ts) => { if (!ts) return "—"; const d = new Date(ts); return d.toLocaleString("en-HK", {month:"short", day:"numeric", hour:"2-digit", minute:"2-digit"}); }; hideLoader(); // Kick off React mount if app.jsx already waited for this if (typeof window.__fabcomMount === "function") window.__fabcomMount(); } catch (e) { showLoader("Failed to load: " + e.message + " — check /api/health"); console.error(e); } } // Expose so app.jsx can await, but also trigger load immediately window.__fabcomLoadData = loadData; loadData(); })();