// History — chronological timeline of signal events the user has logged.
// Source: GET /api/v1/master-equation/me/events (falls back to
// /api/v1/health-sync/status if events are not yet exposed).
const History = ({ openQuickLog }) => {
const [filter, setFilter] = React.useState('all');
const [events, setEvents] = React.useState(null); // null = loading
const [error, setError] = React.useState(null);
React.useEffect(() => {
let dead = false;
(async () => {
try {
const r = await fetch(window.CHVault.apiRoot + '/api/v1/master-equation/me/events?limit=200', {
credentials: 'include',
headers: { 'Accept': 'application/json' },
});
if (r.status === 404) { if (!dead) setEvents([]); return; }
if (!r.ok) throw new Error('events-' + r.status);
const j = await r.json();
if (dead) return;
setEvents(Array.isArray(j) ? j : (j.events || []));
} catch (e) {
if (dead) return;
setError(e.message || String(e));
setEvents([]);
}
})();
return () => { dead = true; };
}, []);
const AXES = [];
const tintFor = (code) => (window.AXIS_META && window.AXIS_META[code] && window.AXIS_META[code].tint) || 'var(--accent-clinical)';
const filtered = events ? (filter === 'all' ? events : events.filter(e => axisOfSignal(e.signal_id) === filter)) : [];
// Group by day label.
const grouped = filtered.reduce((acc, e) => {
const day = dayLabel(e.recorded_at || e.timestamp_iso || e.created_at);
(acc[day] = acc[day] || []).push(e);
return acc;
}, {});
return (
History
Every axis-lift, settled to chain.
An append-only timeline of signal events your devices and actions produced — readable, filterable by axis, and the exact record researchers reference in any opt-in cohort.
{AXES.map(a => (
))}
{events === null && (
Loading your signal-event log…
)}
{events && events.length === 0 && (
No signal events recorded yet.
The first event will appear here the moment you log a meal, complete a focus block, sync your wearable, or post any action that your iOS, Android, or web client sends to POST /api/v1/master-equation/signal.