import { useMemo, useState } from 'react'; import { useSession } from '../context/SessionContext.jsx'; import { useTelemetryFrame } from '../context/TelemetryContext.jsx'; function formatMetric(value, fallback = '--') { if (value == null || value === '') return fallback; return value; } export default function TelemetryPanel() { const { connected, session, requestControl } = useSession(); const roverId = session?.assignment?.roverId; const frame = useTelemetryFrame(roverId); const sensors = frame?.sensors || {}; const voltage = sensors.voltageMv != null ? `${(sensors.voltageMv / 1000).toFixed(2)} V` : null; const current = sensors.currentMa != null ? `${sensors.currentMa} mA` : null; const charge = sensors.batteryChargeMah; const capacity = sensors.batteryCapacityMah; const updated = frame?.receivedAt ? new Date(frame.receivedAt).toLocaleTimeString() : null; const rawSnippet = frame?.raw ? (frame.raw.length > 80 ? `${frame.raw.slice(0, 80)}…` : frame.raw) : null; const roster = session?.roster ?? []; const isAdmin = useMemo( () => session?.role === 'admin' || session?.role === 'lockdown' || session?.role === 'lockdown-admin', [session?.role], ); const [pending, setPending] = useState({}); async function handleRequest(roverId) { if (!roverId) return; setPending((prev) => ({ ...prev, [roverId]: true })); try { await requestControl(roverId); } catch (err) { alert(err.message); } finally { setPending((prev) => ({ ...prev, [roverId]: false })); } } return (
{connected ? 'online' : 'offline'} · role {session?.role || 'unknown'} · mode {session?.mode || '--'} {updated && · sensors {updated}}
{!roverId ? (

Assign a rover to view sensors.

) : !frame ? (

Waiting for sensor frames…

) : (
)} {rawSnippet && (
          {rawSnippet}
        
)}

Rovers

{roster.length === 0 ? (

No roster data.

) : ( )}
); } function Metric({ label, value }) { return ( //
// {label} // {value} //
{label}: {value}
); }