"use client";
/**
* Live ops wall side panel — Level 1 (region) and Level 2 (incident) of the
* approved mockup (design-canvas/live-ops-wall-mockup.html).
*/
import Link from "next/link";
import { useEffect, useMemo, useState } from "react";
import type {
AircraftTrack, CallRecord, Camera, CameraCredit, CameraProviderFeed, IncidentRecord, Ny511Event, NodeRecord, VesselTrack,
} from "@/lib/types";
import { isKnownSeverity, SEVERITY_COLORS, SEVERITY_LABEL } from "@/lib/severity";
import { CameraFeed } from "@/components/CameraFeed";
import { MachineOutputNotice } from "@/components/ui/MachineOutputNotice";
import { SourceCredit, fetchedLabel } from "@/components/SourceCredit";
import { CONTEXT_KM, NEAR_CAMERA_KM, contextFor, sampleRadarDbz, type LatLon, type NearCamera } from "@/lib/liveWall";
function sevColor(s: string | null | undefined) {
return isKnownSeverity(s) ? SEVERITY_COLORS[s] : "var(--ink-muted)";
}
function sevLabel(s: string | null | undefined) {
return isKnownSeverity(s) ? SEVERITY_LABEL[s] : "Unknown";
}
function elapsed(iso: string): string {
const m = Math.max(0, Math.round((Date.now() - new Date(iso).getTime()) / 60_000));
return m < 60 ? `${m}m` : `${Math.floor(m / 60)}h ${m % 60}m`;
}
function hhmm(iso: string): string {
return new Date(iso).toLocaleTimeString([], { hour: "2-digit", minute: "2-digit", hour12: false });
}
const H3 = "text-[11px] uppercase tracking-wide text-ink-muted font-medium mb-1.5";
const SEC = "px-4 py-3 border-b border-line";
export function CameraTile({ cam, feed, km, onOpen }: { cam: Camera; feed?: CameraProviderFeed; km?: number; onOpen: () => void }) {
return (
);
}
function NoCameras({ servingCount, radiusKm }: { servingCount: number; radiusKm: number }) {
return (
{servingCount === 0
? <>No camera provider is enabled. An admin turns them on under Admin → Camera providers.>
: `No public camera within ${radiusKm} km.`}
Off-screen and hidden-tab tiles stop fetching; at most two live streams play at once.
Feeds
ADS-B{aircraftCount} aircraft heard by your nodes
AIS{vesselCount} vessels / aids to navigation
511NY{eventsOff ? "road events off (Admin → Camera providers)" : `${events.length} road events in region`}
{providers.map((p) => (
CAM{p.name}: {p.total_in_bbox} in region{p.error ? " · feed error" : ""}{p.fetched_at ? ` · list ${fetchedLabel(p.fetched_at)}` : ""}
))}
NEXRADWeather Radar layer (map menu); sampled per incident
Nodes
{nodes.map((n) => (
{n.name}{n.status}
))}
Region → click an incident for its path, summary, units and nearest cameras → click a camera to open it. Esc steps back up.
Bookmark a view with #inc=…&cam=…&tour.