/* global React */ /** * OrbSummary — Live Guardian Orb platform widget (M2 data wiring) * GET /api/v1/health/orb-summary (unauthenticated platform aggregate) * DATA_CONTRACTS: guardian-orb.json */ const { useState, useEffect } = React; const API = "https://api.conceptualhealth.com/api/v1/health/orb-summary"; const REFRESH_MS = 60 * 1000; const DEMO = { state: { color: "#7c6dfa", composite_score: 76.4, trend: "up" }, axes: [{ axis: "PO", score: 7.8 }, { axis: "NM", score: 6.9 }, { axis: "ER", score: 8.1 }, { axis: "SC", score: 7.2 }, { axis: "RS", score: 6.5 }, { axis: "ES", score: 7.9 }, { axis: "TA", score: 8.4 }, { axis: "PV", score: 7.1 }], journal_entries_7d: 142, nutrition_entries_today: 387 }; const AXIS_COLORS = { PO: "#ef4444", NM: "#8b5cf6", ER: "#f97316", SC: "#10b981", RS: "#6366f1", ES: "#06b6d4", TA: "#f59e0b", PV: "#ec4899" }; function OrbSummary() { const [data, setData] = useState(null); const [live, setLive] = useState(false); const fetch_ = () => fetch(API).then(r => r.ok ? r.json() : null).then(j => { if (j) { setData(j); setLive(true); } else { setData(DEMO); setLive(false); } }).catch(() => { setData(DEMO); setLive(false); }); useEffect(() => { fetch_(); const id = setInterval(fetch_, REFRESH_MS); return () => clearInterval(id); }, []); if (!data) return null; const badge = { display: "inline-flex", alignItems: "center", gap: 5, fontSize: 9, fontFamily: "var(--font-mono,monospace)", padding: "3px 9px", borderRadius: 20, background: live ? "rgba(16,185,129,0.12)" : "rgba(156,163,175,0.12)", color: live ? "#10b981" : "#9ca3af", border: live ? "1px solid rgba(16,185,129,0.25)" : "1px solid rgba(156,163,175,0.2)" }; const state = data.state || {}; const axes = data.axes || []; return (
Guardian Orb · platform pulse
{live ? "LIVE" : "DEMO"}
{/* Orb state */}
Platform composite score
{Math.round(state.composite_score || 0)}
trend: {state.trend || "flat"}
{/* Activity */}
Journal entries (7d)
{(data.journal_entries_7d || 0).toLocaleString()}
Nutrition logs today
{(data.nutrition_entries_today || 0).toLocaleString()}
{/* 8-axis mini grid */} {axes.length > 0 && (
{axes.map(a => (
{a.axis}
{a.score != null ? a.score.toFixed(1) : "—"}
))}
)}
); } window.OrbSummary = OrbSummary;