'use client'; import { useState } from 'react'; import { SeriesChart } from '@/components/charts/SeriesChart'; import { adminFetch } from '@/lib/admin-fetch'; import { fmt } from '@/lib/format'; import { COMPONENT_LABEL, COMPONENT_ORDER } from '@/lib/pressure'; import type { AdminConfig, AdminReplay } from '@/lib/types'; import { AdminPage, ErrorNote, Field, Panel, btnPrimary, inputCls, useAdmin } from './shared'; export function Replay() { const { data: cfg } = useAdmin('/config'); const [from, setFrom] = useState(() => new Date(Date.now() - 86400_000).toISOString().slice(0, 16)); const [to, setTo] = useState(() => new Date().toISOString().slice(0, 16)); const [weights, setWeights] = useState | null>(null); const [res, setRes] = useState(null); const [err, setErr] = useState(null); const [busy, setBusy] = useState(false); const w = weights ?? cfg?.pressure_weights ?? Object.fromEntries(COMPONENT_ORDER.map((c) => [c, 0])); const sum = Object.values(w).reduce((a, b) => a + Number(b || 0), 0); const valid = Math.abs(sum - 1) <= 0.001; const run = async () => { setBusy(true); setErr(null); try { setRes(await adminFetch('/replay', { method: 'POST', body: { from: new Date(from + 'Z').toISOString(), to: new Date(to + 'Z').toISOString(), weights: w } })); } catch (e) { setErr(String(e)); } finally { setBusy(false); } }; const diffs = res ? res.points.map((p) => p.pressure_replayed - p.pressure_original) : []; const maxDiff = diffs.length ? Math.max(...diffs.map(Math.abs)) : 0; return (
Σ {fmt(sum, 3)}}>
setFrom(e.target.value)} className={`${inputCls} num w-full`} /> setTo(e.target.value)} className={`${inputCls} num w-full`} />
    {Object.entries(w).map(([id, v]) => (
  • {COMPONENT_LABEL[id as keyof typeof COMPONENT_LABEL] ?? id} setWeights({ ...w, [id]: Number(e.target.value) })} className={`${inputCls} num w-full`} aria-label={`${id} weight`} />
  • ))}
step {res.step_seconds} s · max |Δ| {fmt(maxDiff)} : undefined}> {res ? ( ({ ts: p.ts, value: p.pressure_original })), area: true }, { name: 'replayed', color: '#5B8DEF', points: res.points.map((p) => ({ ts: p.ts, value: p.pressure_replayed })), width: 1.5 }, ]} height={340} /> ) : (

Choose a window and weights, then replay.

)}
); }