/* global React, ReactDOM */ /* ============================================================================ social/wow/SocialSummary.jsx — M2 live-data widget Fetches GET /api/v1/public/social/summary · unauthenticated · 60s refresh Exports window.SocialLive = { SocialSummary } ============================================================================ */ (function () { "use strict"; const { useState, useEffect } = React; const API = "/api/v1"; const ACCENT = "#4A7C59"; function Tile({ label, value, live, sub }) { return (
{label} {live ? value : "—"} {sub && {sub}}
); } function SocialSummaryWidget() { const [data, setData] = useState(null); const [live, setLive] = useState(false); const [ts, setTs] = useState(null); useEffect(() => { let cancelled = false; async function poll() { try { const r = await fetch(API + "/public/social/summary"); if (!r.ok) { if (!cancelled) { setLive(false); setData(null); } return; } const d = await r.json(); if (!cancelled) { setData(d); setLive(true); setTs(new Date()); } } catch (_) { if (!cancelled) { setLive(false); setData(null); } } } poll(); const id = setInterval(poll, 60000); return () => { cancelled = true; clearInterval(id); }; }, []); return (
{live ? "● LIVE" : "◌ DEMO"} SOCIAL LIVE DATA {ts && {ts.toLocaleTimeString("en-US", { hour: "2-digit", minute: "2-digit", second: "2-digit" })}}
); } window.SocialLive = { SocialSummary: SocialSummaryWidget }; /* ---- self-mount before #root ------------------------------------------- */ function mountWidget() { const root = document.getElementById("root"); if (!root) return; const el = document.createElement("div"); el.id = "social-live-root"; root.before(el); ReactDOM.createRoot(el).render(React.createElement(SocialSummaryWidget)); } if (document.readyState === "loading") { document.addEventListener("DOMContentLoaded", mountWidget); } else { mountWidget(); } })();