import type { WeatherSample } from '../types'
interface Props {
weather: WeatherSample[]
}
function avg(values: number[]): number {
if (values.length === 0) return 0
return values.reduce((sum, val) => sum + val, 0) / values.length
}
function formatNumber(value: number, digits = 1): string {
return Number.isFinite(value) ? value.toFixed(digits) : '—'
}
function formatTime(date: string): string {
if (!date) return '—'
const parsed = new Date(date)
if (Number.isNaN(parsed.getTime())) return date
return parsed.toLocaleTimeString('en-GB', {
hour: '2-digit',
minute: '2-digit',
})
}
export function WeatherView({ weather }: Props) {
if (weather.length === 0) {
return (
Weather samples not ingested. Run box-box --ingest-session <key>{' '}
to load this dataset.
)
}
const rows = [...weather].sort((a, b) => a.date.localeCompare(b.date))
const latest = rows[rows.length - 1]
const rainfallSamples = rows.filter((sample) => sample.rainfall > 0).length
return (
| Summary |
Value |
| Latest sample |
{formatTime(latest.date)} |
| Avg air / track |
{formatNumber(avg(rows.map((sample) => sample.air_temperature)))}C /{' '}
{formatNumber(avg(rows.map((sample) => sample.track_temperature)))}C
|
| Rain samples |
{rainfallSamples} |
| Time |
Air |
Track |
Humidity |
Rain |
Wind |
{rows.slice(-12).map((sample) => (
|
{formatTime(sample.date)}
|
{formatNumber(sample.air_temperature)}C |
{formatNumber(sample.track_temperature)}C |
{formatNumber(sample.humidity, 0)}% |
{formatNumber(sample.rainfall)} |
{formatNumber(sample.wind_speed)} m/s |
))}
)
}