import { useLatest } from '../hooks/useApi' function fmt(v, unit) { if (v == null) return '—' return `${Number(v).toFixed(1)} ${unit}` } function timeAgo(iso) { if (!iso) return '—' const diff = Date.now() - new Date(iso).getTime() const sec = Math.floor(diff / 1000) if (sec < 60) return `${sec}s ago` const min = Math.floor(sec / 60) if (min < 60) return `${min}m ago` const hr = Math.floor(min / 60) return `${hr}h ago` } export default function NodePopup({ node }) { const { reading } = useLatest(node.mesh_node_id) return (
{node.name || node.mesh_node_id}
{node.mesh_node_id} · {timeAgo(node.last_seen)}
{reading ? (
Temp
{fmt(reading.temperature_c, '°C')}
Humidity
{fmt(reading.humidity_percent, '%')}
Pressure
{fmt(reading.pressure_pa / 100, 'hPa')}
Wind
{fmt(reading.wind_speed_ms, 'm/s')} {reading.wind_direction != null ? `@ ${reading.wind_direction}°` : ''}
PM2.5
{fmt(reading.pm25_ugm3, 'µg/m³')}
PM10
{fmt(reading.pm10_ugm3, 'µg/m³')}
Battery
{fmt(reading.battery_voltage, 'V')}
Solar
{fmt(reading.solar_voltage, 'V')}
) : (
No recent readings available.
)}
) }