'use client'; import { API_BASE } from '@/lib/api'; import React, { useMemo, useState, useEffect, useCallback, useRef } from 'react'; import Map, { Source, Layer, MapRef, ViewState, Popup, Marker, MapLayerMouseEvent, AttributionControl, } from 'react-map-gl/maplibre'; import 'maplibre-gl/dist/maplibre-gl.css'; import { computeNightPolygon } from '@/utils/solarTerminator'; import { darkStyle, lightStyle } from '@/components/map/styles/mapStyles'; import maplibregl from 'maplibre-gl'; import { AlertTriangle, Radio, Activity, Play, Satellite, ExternalLink, Info } from 'lucide-react'; import WikiImage from '@/components/WikiImage'; import FishingDestinationRoute from '@/components/map/FishingDestinationRoute'; import { useTheme } from '@/lib/ThemeContext'; import { PIN_CATEGORY_LABELS, PIN_CATEGORY_COLORS, type PinCategory } from '@/types/aiIntel'; import { getAllPinIcons } from '@/components/map/pinIcons'; import { AIIntelPinDetail } from '@/components/map/AIIntelPinDetail'; import { svgPlaneCyan, svgPlaneYellow, svgPlaneOrange, svgPlanePurple, svgFighter, svgHeli, svgHeliCyan, svgHeliDimCyan, svgHeliOrange, svgHeliPurple, svgHeliSlate, svgHeliAmber, svgTanker, svgRecon, svgPlanePink, svgPlaneAlertRed, svgPlaneDarkBlue, svgPlaneWhiteAlert, svgHeliPink, svgHeliAlertRed, svgHeliDarkBlue, svgHeliBlue, svgHeliLime, svgHeliWhiteAlert, svgPlaneBlack, svgHeliBlack, svgDrone, svgDataCenter, svgPowerPlant, svgRadioTower, svgShipGray, svgShipRed, svgShipYellow, svgShipBlue, svgShipWhite, svgShipPink, svgShipGreyBlue, svgShipAmber, svgCarrier, svgCctv, svgSatDish, svgLoRaSat, svgScannerTower, svgWarning, svgThreat, svgTriangleYellow, svgTriangleRed, svgTrianglePink, svgTriangleGreen, svgFireYellow, svgFireOrange, svgFireRed, svgFireDarkRed, svgFireClusterSmall, svgFireClusterMed, svgFireClusterLarge, svgFireClusterXL, svgPotusPlane, svgPotusHeli, svgAirlinerCyan, svgAirlinerDimCyan, svgAirlinerOrange, svgAirlinerPurple, svgAirlinerSlate, svgAirlinerYellow, svgAirlinerAmber, svgAirlinerPink, svgAirlinerRed, svgAirlinerDarkBlue, svgAirlinerBlue, svgAirlinerLime, svgAirlinerBlack, svgAirlinerWhite, svgTurbopropCyan, svgTurbopropDimCyan, svgTurbopropOrange, svgTurbopropPurple, svgTurbopropSlate, svgTurbopropYellow, svgTurbopropAmber, svgTurbopropPink, svgTurbopropRed, svgTurbopropDarkBlue, svgTurbopropBlue, svgTurbopropLime, svgTurbopropBlack, svgTurbopropWhite, svgBizjetCyan, svgBizjetDimCyan, svgBizjetOrange, svgBizjetPurple, svgBizjetSlate, svgBizjetYellow, svgBizjetAmber, svgBizjetPink, svgBizjetRed, svgBizjetDarkBlue, svgBizjetBlue, svgBizjetLime, svgBizjetBlack, svgBizjetWhite, svgAirlinerGrey, svgTurbopropGrey, svgBizjetGrey, svgHeliGrey, GROUNDED_ICON_MAP, COLOR_MAP_COMMERCIAL, COLOR_MAP_PRIVATE, COLOR_MAP_JETS, COLOR_MAP_MILITARY, MIL_SPECIAL_MAP, makeMilBaseSvg, makeMilBaseCircleSvg, MILBASE_ICON_SPECS, makeVolcanoSvg, VOLCANO_ICON_SPECS, WEATHER_ICON_SPECS, CT_ICON_SPECS, } from '@/components/map/icons/AircraftIcons'; import { makeSatSvg, makeISSSvg, makeTrainSvg } from '@/components/map/icons/SatelliteIcons'; import { makeUfoSvg, makeUfoClusterSvg, makeWaterDropSvg, makeWaterDropClusterSvg } from '@/components/map/icons/OverlayIcons'; import { EMPTY_FC } from '@/components/map/mapConstants'; import { useImperativeSource } from '@/components/map/hooks/useImperativeSource'; import { useDynamicMapLayersWorker } from '@/components/map/hooks/useDynamicMapLayersWorker'; import { useStaticMapLayersWorker } from '@/components/map/hooks/useStaticMapLayersWorker'; import { ClusterCountLabels, TrackedFlightLabels, CarrierLabels, TrackedYachtLabels, UavLabels, EarthquakeLabels, ThreatMarkers, } from '@/components/map/MapMarkers'; import type { DashboardData, KiwiSDR, MaplibreViewerProps, Scanner, SigintSignal } from '@/types/dashboard'; import { useDataKeys } from '@/hooks/useDataStore'; import { useInterpolation } from '@/components/map/hooks/useInterpolation'; import { useClusterLabels } from '@/components/map/hooks/useClusterLabels'; import { spreadAlertItems } from '@/utils/alertSpread'; import { useViewportBounds } from '@/components/map/hooks/useViewportBounds'; import { MeasurementLayers } from '@/components/map/layers/MeasurementLayers'; import { buildCctvProxyUrl } from '@/lib/cctvProxy'; import { CctvFullscreenModal } from '@/components/MaplibreViewer/CctvFullscreenModal'; import { SatellitePopup } from '@/components/MaplibreViewer/popups/SatellitePopup'; import { ShipPopup } from '@/components/MaplibreViewer/popups/ShipPopup'; import { SigintPopup } from '@/components/MaplibreViewer/popups/SigintPopup'; import { CorrelationPopup } from '@/components/MaplibreViewer/popups/CorrelationPopup'; import { WastewaterPopup } from '@/components/MaplibreViewer/popups/WastewaterPopup'; import { MilitaryBasePopup } from '@/components/MaplibreViewer/popups/MilitaryBasePopup'; import { RegionDossierPanel } from '@/components/MaplibreViewer/popups/RegionDossierPanel'; import { buildSentinelTileUrl, hasSentinelCredentials, getSentinelToken, registerSentinelProtocol, } from '@/lib/sentinelHub'; import { buildEarthquakesGeoJSON, buildJammingGeoJSON, buildCorrelationsGeoJSON, buildTinygsGeoJSON, buildShodanGeoJSON, buildAIIntelGeoJSON, type AIIntelPinData, buildFrontlineGeoJSON, buildUavGeoJSON, buildSatellitesGeoJSON, buildCarriersGeoJSON, findSelectedEntity, buildPredictiveGeoJSON, buildProximityRingsGeoJSON, buildUkraineAlertsGeoJSON, buildUkraineAlertLabelsGeoJSON, buildWeatherAlertsGeoJSON, buildWeatherAlertLabelsGeoJSON, buildSarAnomaliesGeoJSON, buildSarAoisGeoJSON, type FlightLayerConfig, } from '@/components/map/geoJSONBuilders'; type ViewBounds = { south: number; west: number; north: number; east: number }; type DynamicRoute = { orig_loc?: [number, number]; dest_loc?: [number, number]; origin_name?: string; dest_name?: string; }; type GeoExtras = { lat?: number; lng?: number; lon?: number; geometry?: { coordinates?: [number, number] }; }; type KiwiProps = Partial & GeoExtras; type ScannerProps = Partial & GeoExtras; type SigintProps = Partial & GeoExtras; const MAP_EXTRA_DATA_KEYS = [ 'air_quality', 'cctv', 'commercial_flights', 'correlations', 'crowdthreat', 'datacenters', 'firms_fires', 'fishing_activity', 'frontlines', 'gps_jamming', 'internet_outages', 'kiwisdr', 'military_bases', 'military_flights', 'power_plants', 'private_flights', 'private_jets', 'psk_reporter', 'sar_anomalies', 'satellite_analysis', 'satellites', 'satnogs_stations', 'scanners', 'sigint', 'tinygs_satellites', 'trains', 'uap_sightings', 'ukraine_alerts', 'viirs_change_nodes', 'volcanoes', 'wastewater', 'weather_alerts', ] as const satisfies readonly (keyof DashboardData)[]; const VIIRS_TILE_TEMPLATES = [ // The older daily Day/Night Band path now 404s in GIBS. Black Marble is the // current stable night-lights product and has a best-available endpoint. 'https://gibs.earthdata.nasa.gov/wmts/epsg3857/best/VIIRS_Black_Marble/default/GoogleMapsCompatible_Level8/{z}/{y}/{x}.png', 'https://gibs.earthdata.nasa.gov/wmts/epsg3857/best/VIIRS_Black_Marble/default/2016-01-01/GoogleMapsCompatible_Level8/{z}/{y}/{x}.png', ]; function buildProbeRasterUrl(tileTemplate: string): string { return tileTemplate .replace('{z}', '0') .replace('{y}', '0') .replace('{x}', '0'); } function probeRasterTile(url: string): Promise { return new Promise((resolve) => { const img = new Image(); let settled = false; const finish = (ok: boolean) => { if (settled) return; settled = true; img.onload = null; img.onerror = null; resolve(ok); }; img.onload = () => finish(true); img.onerror = () => finish(false); img.referrerPolicy = 'no-referrer'; img.src = url; }); } function buildPolymarketUrl(prediction: { slug?: string; title?: string } | null | undefined): string { const slug = String(prediction?.slug || '').trim(); if (slug) return `https://polymarket.com/event/${encodeURIComponent(slug)}`; const title = String(prediction?.title || '').trim(); return title ? `https://polymarket.com/search?query=${encodeURIComponent(title)}` : 'https://polymarket.com/markets'; } const MaplibreViewer = ({ activeLayers, activeFilters, onEntityClick, flyToLocation, selectedEntity, onMouseCoords, onRightClick, regionDossier, regionDossierLoading, onViewStateChange, measureMode, onMeasureClick, measurePoints, gibsDate, gibsOpacity, sentinelDate, sentinelOpacity, sentinelPreset, viewBoundsRef, setTrackedSdr, setTrackedScanner, shodanResults, shodanStyle, pinPlacementMode, onPinPlaced, sarAoiDropMode, onSarAoiDropped, sarAoiListVersion, }: Omit) => { const coreData = useDataKeys([ 'tracked_flights', 'news', 'ships', 'uavs', 'earthquakes', 'gdelt', 'liveuamap', ]); const extraData = useDataKeys(MAP_EXTRA_DATA_KEYS); const data = useMemo(() => ({ ...coreData, ...extraData }) as DashboardData, [coreData, extraData]); const mapRef = useRef(null); const mapInitRef = useRef(false); const [mapReady, setMapReady] = useState(false); const { theme } = useTheme(); const mapThemeStyle = useMemo( () => (theme === 'light' ? lightStyle : darkStyle) as maplibregl.StyleSpecification, [theme], ); const initialViewState = useMemo( () => ({ longitude: 0, latitude: 20, zoom: 2, bearing: 0, pitch: 0, padding: { top: 0, bottom: 0, left: 0, right: 0 }, }), [], ); const viewStateRef = useRef(initialViewState); const [mapZoom, setMapZoom] = useState(initialViewState.zoom); const [dismissedAlerts, setDismissedAlerts] = useState>(new Set()); const [viirsResolvedTileTemplate, setViirsResolvedTileTemplate] = useState(null); const [isMapInteracting, setIsMapInteracting] = useState(false); // Pin placement state const [pendingPin, setPendingPin] = useState<{ lat: number; lng: number; entity: { entity_type: string; entity_id: string; entity_label: string } | null; } | null>(null); const [pinLabel, setPinLabel] = useState(''); const [pinNotes, setPinNotes] = useState(''); const [pinCategory, setPinCategory] = useState('custom'); const [pinSaving, setPinSaving] = useState(false); const [aiIntelPins, setAiIntelPins] = useState([]); const [aiIntelRefreshTick, setAiIntelRefreshTick] = useState(0); // Currently-open AI Intel pin detail popup (pin id) const [openPinDetailId, setOpenPinDetailId] = useState(null); const pinLabelInputRef = useRef(null); // Force focus to the label input whenever the pin dialog opens — the // maplibre canvas otherwise keeps focus and global hotkeys eat keystrokes. useEffect(() => { if (!pendingPin) return; const t = setTimeout(() => pinLabelInputRef.current?.focus(), 50); return () => clearTimeout(t); }, [pendingPin]); const handleSavePin = useCallback(async () => { if (!pendingPin || !pinLabel.trim()) return; setPinSaving(true); try { const body: Record = { lat: pendingPin.lat, lng: pendingPin.lng, label: pinLabel.trim(), description: pinNotes.trim(), source: 'user', category: pinCategory, }; if (pendingPin.entity) { body.entity_attachment = pendingPin.entity; } await fetch(`${API_BASE}/api/ai/pins`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(body), }); setPendingPin(null); setPinLabel(''); setPinNotes(''); setPinCategory('custom'); setAiIntelRefreshTick((t) => t + 1); onPinPlaced?.(); } catch (err) { console.error('Failed to save pin:', err); } setPinSaving(false); }, [pendingPin, pinLabel, pinNotes, pinCategory, onPinPlaced]); const showImageryReferenceOverlay = activeLayers.highres_satellite || activeLayers.gibs_imagery || activeLayers.viirs_nightlights || activeLayers.sentinel_hub; const imageryReferenceOverlayOpacity = activeLayers.viirs_nightlights ? 1 : 0.9; const backendViewportSyncEnabled = activeLayers.ships_military || activeLayers.ships_cargo || activeLayers.ships_civilian || activeLayers.ships_passenger || activeLayers.ships_tracked_yachts; const { mapBounds, inView, updateBounds } = useViewportBounds( mapRef, viewBoundsRef as React.MutableRefObject | undefined, backendViewportSyncEnabled, ); useEffect(() => { if (backendViewportSyncEnabled) { updateBounds(); } }, [backendViewportSyncEnabled, updateBounds]); const viirsProbeDayKey = new Date().toISOString().slice(0, 10); useEffect(() => { if (!activeLayers.viirs_nightlights) { setViirsResolvedTileTemplate(null); return undefined; } let cancelled = false; const resolveViirsDate = async () => { for (const tileTemplate of VIIRS_TILE_TEMPLATES) { const ok = await probeRasterTile(buildProbeRasterUrl(tileTemplate)); if (cancelled) return; if (ok) { setViirsResolvedTileTemplate(tileTemplate); return; } } if (!cancelled) { setViirsResolvedTileTemplate(VIIRS_TILE_TEMPLATES[0] ?? null); } }; void resolveViirsDate(); return () => { cancelled = true; }; }, [activeLayers.viirs_nightlights, viirsProbeDayKey]); const [dynamicRoute, setDynamicRoute] = useState(null); const prevCallsign = useRef(null); // Oracle region intel for map entity popups const [oracleIntel, setOracleIntel] = useState<{ found: boolean; top_headline?: string; oracle_score?: number; tier?: string; avg_sentiment?: number; nearby_count?: number; market?: { title: string; consensus_pct: number | null } | null; } | null>(null); // Global Incidents popup: dismiss no longer permanently removes alerts. // Clicking × just deselects, allowing re-opening from the right-panel feed. // --- Smooth interpolation via extracted hook --- const { interpFlight, interpShip, interpSat, interpTick, dtSeconds, resetTimestamp, } = useInterpolation(); // Track when flight/ship/satellite data actually changes (new fetch arrived) useEffect(() => { resetTimestamp(); }, [ data?.commercial_flights, data?.private_flights, data?.military_flights, data?.private_jets, data?.tracked_flights, data?.ships, data?.satellites, resetTimestamp, ]); // --- Solar Terminator: recompute the night polygon every 60 seconds --- const [nightGeoJSON, setNightGeoJSON] = useState(() => computeNightPolygon(), ); useEffect(() => { const timer = setInterval(() => setNightGeoJSON(computeNightPolygon()), 60000); return () => clearInterval(timer); }, []); useEffect(() => { let isMounted = true; let callsign = null; let entityLat = 0; let entityLng = 0; if (selectedEntity && data) { let entity = null; if (selectedEntity.type === 'flight') entity = data?.commercial_flights?.find((f) => f.icao24 === selectedEntity.id); else if (selectedEntity.type === 'private_flight') entity = data?.private_flights?.find((f) => f.icao24 === selectedEntity.id); else if (selectedEntity.type === 'military_flight') entity = data?.military_flights?.find((f) => f.icao24 === selectedEntity.id); else if (selectedEntity.type === 'private_jet') entity = data?.private_jets?.find((f) => f.icao24 === selectedEntity.id); else if (selectedEntity.type === 'tracked_flight') entity = data?.tracked_flights?.find((f) => f.icao24 === selectedEntity.id); if (entity && entity.callsign) { callsign = entity.callsign; entityLat = entity.lat ?? 0; entityLng = entity.lng ?? 0; } } if (callsign && callsign !== prevCallsign.current) { prevCallsign.current = callsign; fetch(`${API_BASE}/api/route/${callsign}?lat=${entityLat}&lng=${entityLng}`) .then((res) => res.json()) .then((routeData) => { if (isMounted) setDynamicRoute(routeData); }) .catch(() => { if (isMounted) setDynamicRoute(null); }); } else if (!callsign) { prevCallsign.current = null; if (isMounted) setDynamicRoute(null); } return () => { isMounted = false; }; }, [selectedEntity, data]); // Fetch oracle region intel for entity popups useEffect(() => { if (!selectedEntity) { setOracleIntel(null); return; } const oracleTypes = ['military_base', 'liveuamap', 'gps_jamming', 'earthquake', 'conflict_zone']; if (!oracleTypes.includes(selectedEntity.type)) { setOracleIntel(null); return; } const lat = selectedEntity.extra?.lat; const lng = selectedEntity.extra?.lng; if (lat == null || lng == null) { setOracleIntel(null); return; } let alive = true; fetch(`${API_BASE}/api/oracle/region-intel?lat=${lat}&lng=${lng}`) .then(r => r.json()) .then(d => { if (alive) setOracleIntel(d); }) .catch(() => { if (alive) setOracleIntel(null); }); return () => { alive = false; }; }, [selectedEntity]); useEffect(() => { if (flyToLocation && mapRef.current) { mapRef.current.flyTo({ center: [flyToLocation.lng, flyToLocation.lat], zoom: 8, duration: 1500, }); } }, [flyToLocation]); const earthquakesGeoJSON = useMemo( () => (activeLayers.earthquakes ? buildEarthquakesGeoJSON(data?.earthquakes) : null), [activeLayers.earthquakes, data?.earthquakes], ); const jammingGeoJSON = useMemo( () => (activeLayers.gps_jamming ? buildJammingGeoJSON(data?.gps_jamming) : null), [activeLayers.gps_jamming, data?.gps_jamming], ); const correlationsGeoJSON = useMemo( () => { if (!activeLayers.correlations && !activeLayers.contradictions) return null; const alerts = data?.correlations?.filter((a) => { if (a.type === 'contradiction') return activeLayers.contradictions; return activeLayers.correlations; }); return buildCorrelationsGeoJSON(alerts); }, [activeLayers.correlations, activeLayers.contradictions, data?.correlations], ); const tinygsGeoJSON = useMemo( () => { void interpTick; return activeLayers.tinygs ? buildTinygsGeoJSON(data?.tinygs_satellites, inView, interpSat) : null; }, [activeLayers.tinygs, data?.tinygs_satellites, inView, interpSat, interpTick], ); const shodanGeoJSON = useMemo( () => (activeLayers.shodan_overlay ? buildShodanGeoJSON(shodanResults) : null), [activeLayers.shodan_overlay, shodanResults], ); // AI Intel layer — pins from OpenClaw and the AI co-pilot useEffect(() => { if (!activeLayers.ai_intel) return; let cancelled = false; const poll = async () => { try { const resp = await fetch(`${API_BASE}/api/ai/pins/geojson`); if (!resp.ok || cancelled) return; const gj = await resp.json(); const pins = (gj.features || []).map((f: any) => ({ ...f.properties, lat: f.geometry?.coordinates?.[1], lng: f.geometry?.coordinates?.[0], })); if (!cancelled) setAiIntelPins(pins); } catch {} }; poll(); const tid = setInterval(poll, 15_000); // poll every 15s return () => { cancelled = true; clearInterval(tid); }; }, [activeLayers.ai_intel, aiIntelRefreshTick]); const aiIntelGeoJSON = useMemo( () => (activeLayers.ai_intel ? buildAIIntelGeoJSON(aiIntelPins, data) : null), [activeLayers.ai_intel, aiIntelPins, data], ); const ukraineAlertsGeoJSON = useMemo( () => (activeLayers.ukraine_alerts ? buildUkraineAlertsGeoJSON(data?.ukraine_alerts) : null), [activeLayers.ukraine_alerts, data?.ukraine_alerts], ); const ukraineAlertLabelsGeoJSON = useMemo( () => (activeLayers.ukraine_alerts ? buildUkraineAlertLabelsGeoJSON(data?.ukraine_alerts) : null), [activeLayers.ukraine_alerts, data?.ukraine_alerts], ); const weatherAlertsGeoJSON = useMemo( () => (activeLayers.weather_alerts ? buildWeatherAlertsGeoJSON(data?.weather_alerts) : null), [activeLayers.weather_alerts, data?.weather_alerts], ); const weatherAlertLabelsGeoJSON = useMemo( () => (activeLayers.weather_alerts ? buildWeatherAlertLabelsGeoJSON(data?.weather_alerts) : null), [activeLayers.weather_alerts, data?.weather_alerts], ); // Sentinel Hub — tile URL (only built when layer is active + credentials are set) const sentinelTileUrl = useMemo(() => { if (!activeLayers.sentinel_hub) return null; if (!hasSentinelCredentials()) return null; return buildSentinelTileUrl(sentinelPreset || 'TRUE-COLOR', sentinelDate || ''); }, [activeLayers.sentinel_hub, sentinelPreset, sentinelDate]); // Register sentinel:// custom protocol for Process API tile fetching useEffect(() => { registerSentinelProtocol(maplibregl); }, []); // Pre-fetch Sentinel Hub token when layer is toggled on useEffect(() => { if (!activeLayers.sentinel_hub) return; getSentinelToken().catch((err) => console.warn('Sentinel Hub token error:', err)); }, [activeLayers.sentinel_hub, sentinelPreset, sentinelDate]); // Initialize images/sources as soon as the local style is available. // Do not wait for remote basemap tiles to load, because blocked tile hosts // would otherwise prevent the map "load" event from ever firing. const initializeMap = useCallback((map: maplibregl.Map) => { if (mapInitRef.current) return; mapInitRef.current = true; // Track which images are still loading so we can retry on styleimagemissing const pendingImages: Record = {}; const loadImg = (id: string, url: string) => { if (!map.hasImage(id)) { pendingImages[id] = url; const img = new Image(); img.crossOrigin = 'anonymous'; img.src = url; img.onload = () => { if (!map.hasImage(id)) map.addImage(id, img); delete pendingImages[id]; }; } }; // Suppress "image not found" warnings — retry when the async load finishes map.on('styleimagemissing', (ev: maplibregl.MapStyleImageMissingEvent) => { const id = ev.id; const url = pendingImages[id]; if (url) { const img = new Image(); img.crossOrigin = 'anonymous'; img.src = url; img.onload = () => { if (!map.hasImage(id)) map.addImage(id, img); delete pendingImages[id]; }; } }); // AI Intel teardrop pin icons — one per category color for (const [id, url] of getAllPinIcons()) { loadImg(id, url); } // Critical icons — needed immediately for default-on layers loadImg('svgPlaneCyan', svgPlaneCyan); loadImg('svgPlaneYellow', svgPlaneYellow); loadImg('svgPlaneOrange', svgPlaneOrange); loadImg('svgPlanePurple', svgPlanePurple); loadImg('svgHeli', svgHeli); loadImg('svgHeliCyan', svgHeliCyan); loadImg('svgHeliDimCyan', svgHeliDimCyan); loadImg('svgHeliOrange', svgHeliOrange); loadImg('svgHeliPurple', svgHeliPurple); loadImg('svgHeliSlate', svgHeliSlate); loadImg('svgHeliAmber', svgHeliAmber); loadImg('svgHeliBlue', svgHeliBlue); loadImg('svgHeliLime', svgHeliLime); loadImg('svgFighter', svgFighter); loadImg('svgTanker', svgTanker); loadImg('svgRecon', svgRecon); loadImg('svgAirlinerCyan', svgAirlinerCyan); loadImg('svgAirlinerDimCyan', svgAirlinerDimCyan); loadImg('svgAirlinerOrange', svgAirlinerOrange); loadImg('svgAirlinerPurple', svgAirlinerPurple); loadImg('svgAirlinerSlate', svgAirlinerSlate); loadImg('svgAirlinerYellow', svgAirlinerYellow); loadImg('svgAirlinerAmber', svgAirlinerAmber); loadImg('svgTurbopropCyan', svgTurbopropCyan); loadImg('svgTurbopropDimCyan', svgTurbopropDimCyan); loadImg('svgTurbopropOrange', svgTurbopropOrange); loadImg('svgTurbopropPurple', svgTurbopropPurple); loadImg('svgTurbopropSlate', svgTurbopropSlate); loadImg('svgTurbopropYellow', svgTurbopropYellow); loadImg('svgTurbopropAmber', svgTurbopropAmber); loadImg('svgBizjetCyan', svgBizjetCyan); loadImg('svgBizjetDimCyan', svgBizjetDimCyan); loadImg('svgBizjetOrange', svgBizjetOrange); loadImg('svgBizjetPurple', svgBizjetPurple); loadImg('svgBizjetSlate', svgBizjetSlate); loadImg('svgBizjetYellow', svgBizjetYellow); loadImg('svgBizjetAmber', svgBizjetAmber); loadImg('svgAirlinerGrey', svgAirlinerGrey); loadImg('svgTurbopropGrey', svgTurbopropGrey); loadImg('svgBizjetGrey', svgBizjetGrey); loadImg('svgHeliGrey', svgHeliGrey); loadImg('svgShipGray', svgShipGray); loadImg('svgShipRed', svgShipRed); loadImg('svgShipYellow', svgShipYellow); loadImg('svgShipBlue', svgShipBlue); loadImg('svgShipWhite', svgShipWhite); loadImg('svgShipPink', svgShipPink); loadImg('svgShipGreyBlue', svgShipGreyBlue); loadImg('svgShipAmber', svgShipAmber); loadImg('svgCarrier', svgCarrier); loadImg('svgWarning', svgWarning); loadImg('icon-threat', svgThreat); // Deferred icons — for off-by-default layers and rare variants // Loaded in next frame to avoid blocking initial map render setTimeout(() => { loadImg('svgRadioTower', svgRadioTower); loadImg('svgSatDish', svgSatDish); loadImg('svgLoRaSat', svgLoRaSat); loadImg('svgScannerTower', svgScannerTower); loadImg('svgPlanePink', svgPlanePink); loadImg('svgPlaneAlertRed', svgPlaneAlertRed); loadImg('svgPlaneDarkBlue', svgPlaneDarkBlue); loadImg('svgPlaneWhiteAlert', svgPlaneWhiteAlert); loadImg('svgPlaneBlack', svgPlaneBlack); loadImg('svgHeliPink', svgHeliPink); loadImg('svgHeliAlertRed', svgHeliAlertRed); loadImg('svgHeliDarkBlue', svgHeliDarkBlue); loadImg('svgHeliWhiteAlert', svgHeliWhiteAlert); loadImg('svgHeliBlack', svgHeliBlack); loadImg('svgPotusPlane', svgPotusPlane); loadImg('svgPotusHeli', svgPotusHeli); loadImg('svgAirlinerPink', svgAirlinerPink); loadImg('svgAirlinerRed', svgAirlinerRed); loadImg('svgAirlinerDarkBlue', svgAirlinerDarkBlue); loadImg('svgAirlinerBlue', svgAirlinerBlue); loadImg('svgAirlinerLime', svgAirlinerLime); loadImg('svgAirlinerBlack', svgAirlinerBlack); loadImg('svgAirlinerWhite', svgAirlinerWhite); loadImg('svgTurbopropPink', svgTurbopropPink); loadImg('svgTurbopropRed', svgTurbopropRed); loadImg('svgTurbopropDarkBlue', svgTurbopropDarkBlue); loadImg('svgTurbopropBlue', svgTurbopropBlue); loadImg('svgTurbopropLime', svgTurbopropLime); loadImg('svgTurbopropBlack', svgTurbopropBlack); loadImg('svgTurbopropWhite', svgTurbopropWhite); loadImg('svgBizjetPink', svgBizjetPink); loadImg('svgBizjetRed', svgBizjetRed); loadImg('svgBizjetDarkBlue', svgBizjetDarkBlue); loadImg('svgBizjetBlue', svgBizjetBlue); loadImg('svgBizjetLime', svgBizjetLime); loadImg('svgBizjetBlack', svgBizjetBlack); loadImg('svgBizjetWhite', svgBizjetWhite); loadImg('svgDrone', svgDrone); loadImg('svgCctv', svgCctv); loadImg('icon-liveua-yellow', svgTriangleYellow); loadImg('icon-liveua-red', svgTriangleRed); loadImg('icon-aprs-triangle', svgTrianglePink); loadImg('icon-mesh-triangle', svgTriangleGreen); // FIRMS fire icons loadImg('fire-yellow', svgFireYellow); loadImg('fire-orange', svgFireOrange); loadImg('fire-red', svgFireRed); loadImg('fire-darkred', svgFireDarkRed); loadImg('fire-cluster-sm', svgFireClusterSmall); loadImg('fire-cluster-md', svgFireClusterMed); loadImg('fire-cluster-lg', svgFireClusterLarge); loadImg('fire-cluster-xl', svgFireClusterXL); // Data center icon loadImg('datacenter', svgDataCenter); // Power plant icon loadImg('power-plant', svgPowerPlant); // Satellite mission-type icons loadImg('sat-mil', makeSatSvg('#ff3333')); loadImg('sat-sar', makeSatSvg('#00e5ff')); loadImg('sat-sigint', makeSatSvg('#ffffff')); loadImg('sat-nav', makeSatSvg('#4488ff')); loadImg('sat-ew', makeSatSvg('#ff00ff')); loadImg('sat-com', makeSatSvg('#44ff44')); loadImg('sat-station', makeSatSvg('#ffdd00')); loadImg('sat-gen', makeSatSvg('#aaaaaa')); // ISS special icon (larger, with built-in halo ring) loadImg('sat-iss', makeISSSvg()); // Train icons loadImg('train-amtrak', makeTrainSvg('#ffffff')); loadImg('train-fin', makeTrainSvg('#ffffff')); // Military base icons (square with X or circle) for (const spec of MILBASE_ICON_SPECS) { loadImg( spec.id, spec.svg ?? (spec.shape === 'circle' ? makeMilBaseCircleSvg(spec.fill, spec.inner) : makeMilBaseSvg(spec.fill, spec.inner)), ); } // Volcano icons (triangle cone) for (const spec of VOLCANO_ICON_SPECS) { loadImg(spec.id, makeVolcanoSvg(spec.fill)); } // Weather alert icons for (const spec of WEATHER_ICON_SPECS) { loadImg(spec.id, spec.svg); } // CrowdThreat category icons for (const spec of CT_ICON_SPECS) { loadImg(spec.id, spec.svg); } // UAP (UFO) icons — individual + cluster loadImg('ufo-icon', makeUfoSvg()); loadImg('ufo-cluster', makeUfoClusterSvg()); // Wastewater water drop icons — individual + cluster loadImg('ww-clean', makeWaterDropSvg('#00e5ff')); loadImg('ww-alert', makeWaterDropSvg('#ff2222', '#ff4444')); loadImg('ww-stale', makeWaterDropSvg('#556677')); loadImg('ww-cluster', makeWaterDropClusterSvg('#00e5ff')); }, 0); }, []); // Load Images into the Map Style once loaded const onMapLoad = useCallback((e: { target: maplibregl.Map }) => { initializeMap(e.target); setMapReady(true); }, [initializeMap]); const onMapStyleData = useCallback((e: { target: maplibregl.Map }) => { initializeMap(e.target); setMapReady(true); }, [initializeMap]); useEffect(() => { const map = mapRef.current?.getMap(); if (map) { initializeMap(map); setMapReady(true); } }, [initializeMap, theme]); // Build a set of tracked icao24s to exclude from other flight layers const trackedIcaoSet = useMemo(() => { const s = new Set(); if (data?.tracked_flights) { for (const t of data.tracked_flights) { if (t.icao24) s.add(t.icao24.toLowerCase()); } } return s; }, [data?.tracked_flights]); // Satellite GeoJSON with interpolated positions const satellitesGeoJSON = useMemo( () => { void interpTick; return activeLayers.satellites ? buildSatellitesGeoJSON(data?.satellites, inView, interpSat) : null; }, [activeLayers.satellites, data?.satellites, inView, interpSat, interpTick], ); const commConfig = useMemo( () => ({ colorMap: COLOR_MAP_COMMERCIAL, groundedMap: GROUNDED_ICON_MAP, typeLabel: 'flight', idPrefix: 'flight-', useTrackHeading: true, }), [], ); const privConfig = useMemo( () => ({ colorMap: COLOR_MAP_PRIVATE, groundedMap: GROUNDED_ICON_MAP, typeLabel: 'private_flight', idPrefix: 'pflight-', }), [], ); const jetsConfig = useMemo( () => ({ colorMap: COLOR_MAP_JETS, groundedMap: GROUNDED_ICON_MAP, typeLabel: 'private_jet', idPrefix: 'pjet-', }), [], ); const milConfig = useMemo( () => ({ colorMap: COLOR_MAP_MILITARY, groundedMap: GROUNDED_ICON_MAP, typeLabel: 'military_flight', idPrefix: 'mflight-', milSpecialMap: MIL_SPECIAL_MAP, }), [], ); const shipsLayerEnabled = backendViewportSyncEnabled; const sigintLayerEnabled = activeLayers.sigint_meshtastic || activeLayers.sigint_aprs; const globalIncidentsEnabled = activeLayers.global_incidents; const dynamicCommercialFlights = activeLayers.flights ? data?.commercial_flights : undefined; const dynamicPrivateFlights = activeLayers.private ? data?.private_flights : undefined; const dynamicPrivateJets = activeLayers.jets ? data?.private_jets : undefined; const dynamicMilitaryFlights = activeLayers.military ? data?.military_flights : undefined; const dynamicTrackedFlights = activeLayers.tracked ? data?.tracked_flights : undefined; const dynamicShips = shipsLayerEnabled ? data?.ships : undefined; const dynamicSigint = sigintLayerEnabled ? data?.sigint : undefined; const staticCctv = activeLayers.cctv ? data?.cctv : undefined; const staticKiwisdr = activeLayers.kiwisdr ? data?.kiwisdr : undefined; const staticPskReporter = activeLayers.psk_reporter ? data?.psk_reporter : undefined; const staticSatnogsStations = activeLayers.satnogs ? data?.satnogs_stations : undefined; const staticScanners = activeLayers.scanners ? data?.scanners : undefined; const staticFirmsFires = activeLayers.firms ? data?.firms_fires : undefined; const staticInternetOutages = activeLayers.internet_outages ? data?.internet_outages : undefined; const staticDatacenters = activeLayers.datacenters ? data?.datacenters : undefined; const staticPowerPlants = activeLayers.power_plants ? data?.power_plants : undefined; const staticViirsChangeNodes = activeLayers.viirs_nightlights ? data?.viirs_change_nodes : undefined; const staticMilitaryBases = activeLayers.military_bases ? data?.military_bases : undefined; const staticGdelt = globalIncidentsEnabled ? data?.gdelt : undefined; const staticLiveuamap = globalIncidentsEnabled ? data?.liveuamap : undefined; const staticAirQuality = activeLayers.air_quality ? data?.air_quality : undefined; const staticVolcanoes = activeLayers.volcanoes ? data?.volcanoes : undefined; const staticFishingActivity = activeLayers.fishing_activity ? data?.fishing_activity : undefined; const staticTrains = activeLayers.trains ? data?.trains : undefined; const staticUapSightings = activeLayers.uap_sightings ? data?.uap_sightings : undefined; const staticWastewater = activeLayers.wastewater ? data?.wastewater : undefined; const staticCrowdthreat = activeLayers.crowdthreat ? data?.crowdthreat : undefined; const dynamicMapLayers = useDynamicMapLayersWorker( { commercialFlights: dynamicCommercialFlights, privateFlights: dynamicPrivateFlights, privateJets: dynamicPrivateJets, militaryFlights: dynamicMilitaryFlights, trackedFlights: dynamicTrackedFlights, ships: dynamicShips, sigint: dynamicSigint, commConfig, privConfig, jetsConfig, milConfig, }, [ dynamicCommercialFlights, dynamicPrivateFlights, dynamicPrivateJets, dynamicMilitaryFlights, dynamicTrackedFlights, dynamicShips, dynamicSigint, commConfig, privConfig, jetsConfig, milConfig, ], { bounds: mapBounds, dtSeconds: dtSeconds.current, trackedIcaos: Array.from(trackedIcaoSet), activeLayers: { flights: activeLayers.flights, private: activeLayers.private, jets: activeLayers.jets, military: activeLayers.military, tracked: activeLayers.tracked, ships_military: activeLayers.ships_military, ships_cargo: activeLayers.ships_cargo, ships_civilian: activeLayers.ships_civilian, ships_passenger: activeLayers.ships_passenger, ships_tracked_yachts: activeLayers.ships_tracked_yachts, sigint_meshtastic: activeLayers.sigint_meshtastic, sigint_aprs: activeLayers.sigint_aprs, }, activeFilters: activeFilters || {}, }, [ mapBounds, interpTick, trackedIcaoSet, activeLayers.flights, activeLayers.private, activeLayers.jets, activeLayers.military, activeLayers.tracked, activeLayers.ships_military, activeLayers.ships_cargo, activeLayers.ships_civilian, activeLayers.ships_passenger, activeLayers.ships_tracked_yachts, activeLayers.sigint_meshtastic, activeLayers.sigint_aprs, activeFilters, ], ); const staticMapLayers = useStaticMapLayersWorker( { cctv: staticCctv, kiwisdr: staticKiwisdr, pskReporter: staticPskReporter, satnogsStations: staticSatnogsStations, scanners: staticScanners, firmsFires: staticFirmsFires, internetOutages: staticInternetOutages, datacenters: staticDatacenters, powerPlants: staticPowerPlants, viirsChangeNodes: staticViirsChangeNodes, militaryBases: staticMilitaryBases, gdelt: staticGdelt, liveuamap: staticLiveuamap, airQuality: staticAirQuality, volcanoes: staticVolcanoes, fishingActivity: staticFishingActivity, ships: data?.ships, trains: staticTrains, uapSightings: staticUapSightings, wastewater: staticWastewater, crowdthreat: staticCrowdthreat, }, [ staticCctv, staticKiwisdr, staticPskReporter, staticSatnogsStations, staticScanners, staticFirmsFires, staticInternetOutages, staticDatacenters, staticPowerPlants, staticViirsChangeNodes, staticMilitaryBases, staticGdelt, staticLiveuamap, staticAirQuality, staticVolcanoes, staticFishingActivity, data?.ships, staticTrains, staticUapSightings, staticWastewater, staticCrowdthreat, ], { bounds: mapBounds, activeLayers: { cctv: activeLayers.cctv, kiwisdr: activeLayers.kiwisdr, psk_reporter: activeLayers.psk_reporter, satnogs: activeLayers.satnogs, scanners: activeLayers.scanners, firms: activeLayers.firms, internet_outages: activeLayers.internet_outages, datacenters: activeLayers.datacenters, power_plants: activeLayers.power_plants, viirs_nightlights: activeLayers.viirs_nightlights, military_bases: activeLayers.military_bases, global_incidents: activeLayers.global_incidents, air_quality: activeLayers.air_quality, volcanoes: activeLayers.volcanoes, fishing_activity: activeLayers.fishing_activity, trains: activeLayers.trains, uap_sightings: activeLayers.uap_sightings, wastewater: activeLayers.wastewater, crowdthreat: activeLayers.crowdthreat, }, }, [ mapBounds, activeLayers.cctv, activeLayers.kiwisdr, activeLayers.psk_reporter, activeLayers.satnogs, activeLayers.scanners, activeLayers.firms, activeLayers.internet_outages, activeLayers.datacenters, activeLayers.power_plants, activeLayers.viirs_nightlights, activeLayers.military_bases, activeLayers.global_incidents, activeLayers.air_quality, activeLayers.volcanoes, activeLayers.fishing_activity, activeLayers.trains, activeLayers.uap_sightings, activeLayers.wastewater, activeLayers.crowdthreat, ], ); const { commercialFlightsGeoJSON: commFlightsGeoJSON, privateFlightsGeoJSON: privFlightsGeoJSON, privateJetsGeoJSON: privJetsGeoJSON, militaryFlightsGeoJSON: milFlightsGeoJSON, trackedFlightsGeoJSON, shipsGeoJSON, meshtasticGeoJSON, aprsGeoJSON, } = dynamicMapLayers; const { cctvGeoJSON, kiwisdrGeoJSON, pskReporterGeoJSON, satnogsGeoJSON, scannerGeoJSON, firmsGeoJSON, internetOutagesGeoJSON, dataCentersGeoJSON, powerPlantsGeoJSON, viirsChangeNodesGeoJSON, militaryBasesGeoJSON, gdeltGeoJSON, liveuaGeoJSON, airQualityGeoJSON, volcanoesGeoJSON, fishingGeoJSON, trainsGeoJSON, uapSightingsGeoJSON, wastewaterGeoJSON, crowdthreatGeoJSON, } = staticMapLayers; // Extract cluster label positions via shared hook const shipClusters = useClusterLabels(mapRef, 'ships-clusters-layer', shipsGeoJSON); const eqClusters = useClusterLabels(mapRef, 'eq-clusters-layer', earthquakesGeoJSON); const carriersGeoJSON = useMemo( () => (activeLayers.ships_military ? buildCarriersGeoJSON(data?.ships) : null), [activeLayers.ships_military, data?.ships], ); // SAR anomaly pins (Mode B) + AOI watchbox circles. AOIs render whenever // the SAR layer is on; anomalies only appear when Mode B has produced // something. The render path is fully imperative via useImperativeSource. // // AOIs come from their own endpoint (/api/sar/aois) rather than the // dashboard payload because they're operator-managed metadata, not a // polled feed — the list rarely changes and we don't want to bloat // dashboard responses with it. const [sarAoisList, setSarAoisList] = useState< import('@/types/dashboard').SarAoi[] >([]); useEffect(() => { if (!activeLayers.sar) return; let cancelled = false; const run = async () => { try { const res = await fetch(`${API_BASE}/api/sar/aois`, { credentials: 'include', }); if (!res.ok || cancelled) return; const body = await res.json(); if (!cancelled && Array.isArray(body?.aois)) { setSarAoisList(body.aois); } } catch { // ignore — AOIs are a nice-to-have } }; run(); // Refresh every 2 minutes while the layer is on so operator edits // propagate without a full page reload. const iv = setInterval(run, 120_000); return () => { cancelled = true; clearInterval(iv); }; }, [activeLayers.sar, sarAoiListVersion]); const sarAnomaliesGeoJSON = useMemo( () => (activeLayers.sar ? buildSarAnomaliesGeoJSON(data?.sar_anomalies) : null), [activeLayers.sar, data?.sar_anomalies], ); const sarAoisGeoJSON = useMemo( () => (activeLayers.sar ? buildSarAoisGeoJSON(sarAoisList) : null), [activeLayers.sar, sarAoisList], ); const getSelectedEntityLiveCoords = useCallback( (entity: ReturnType): [number, number] | null => { if (!entity || entity.lat == null || entity.lng == null) return null; switch (selectedEntity?.type) { case 'ship': return interpShip(entity); case 'flight': case 'private_flight': case 'military_flight': case 'private_jet': case 'tracked_flight': case 'uav': return interpFlight(entity); default: return [entity.lng, entity.lat]; } }, [interpFlight, interpShip, selectedEntity?.type], ); const activeRouteGeoJSON = useMemo(() => { void interpTick; const entity = findSelectedEntity(selectedEntity, data); if (!entity) return null; const currentLoc = getSelectedEntityLiveCoords(entity) ?? [entity.lng, entity.lat]; let originLoc = 'origin_loc' in entity ? entity.origin_loc : null; let destLoc = 'dest_loc' in entity ? entity.dest_loc : null; let originName = 'origin_name' in entity ? entity.origin_name : ''; let destName = 'dest_name' in entity ? entity.dest_name : ''; if (dynamicRoute && dynamicRoute.orig_loc && dynamicRoute.dest_loc) { originLoc = dynamicRoute.orig_loc; destLoc = dynamicRoute.dest_loc; originName = dynamicRoute.origin_name || originName; destName = dynamicRoute.dest_name || destName; } if (!originLoc && !destLoc) return null; const features: GeoJSON.Feature[] = []; // Extract IATA codes from "IATA: Airport Name" format const originCode = (originName || '').split(':')[0]?.trim() || ''; const destCode = (destName || '').split(':')[0]?.trim() || ''; if (originLoc) { features.push({ type: 'Feature', properties: { type: 'route-origin' }, geometry: { type: 'LineString', coordinates: [currentLoc, originLoc] }, }); features.push({ type: 'Feature', properties: { type: 'airport', code: originCode, role: 'DEP' }, geometry: { type: 'Point', coordinates: originLoc }, }); } if (destLoc) { features.push({ type: 'Feature', properties: { type: 'route-dest' }, geometry: { type: 'LineString', coordinates: [currentLoc, destLoc] }, }); features.push({ type: 'Feature', properties: { type: 'airport', code: destCode, role: 'ARR' }, geometry: { type: 'Point', coordinates: destLoc }, }); } if (features.length === 0) return null; return { type: 'FeatureCollection' as const, features }; }, [selectedEntity, data, dynamicRoute, getSelectedEntityLiveCoords, interpTick]); // Trail history GeoJSON: shows where the SELECTED aircraft has been const trailGeoJSON = useMemo(() => { void interpTick; const entity = findSelectedEntity(selectedEntity, data); if (!entity || !('trail' in entity) || !entity.trail || entity.trail.length < 2) return null; // Parse trail points — backend sends [lat, lng, alt, ts] arrays type TrailPt = { lng: number; lat: number; alt: number; ts: number }; const points: TrailPt[] = ( entity.trail as Array<{ lat?: number; lng?: number; alt?: number; ts?: number } | number[]> ).map((p) => { if (Array.isArray(p)) { return { lat: p[0] as number, lng: p[1] as number, alt: (p[2] as number) || 0, ts: (p[3] as number) || 0 }; } return { lat: p.lat ?? 0, lng: p.lng ?? 0, alt: p.alt ?? 0, ts: p.ts ?? 0 }; }).filter((p) => p.lat !== 0 || p.lng !== 0); const currentLoc = getSelectedEntityLiveCoords(entity); if (currentLoc && points.length > 0) { const lastPt = points[points.length - 1]; points.push({ lng: currentLoc[0], lat: currentLoc[1], alt: lastPt.alt, ts: Date.now() / 1000 }); } if (points.length < 2) return null; // Split into segments colored by altitude for gradient effect // Color ramp: ground(magenta) → low(blue) → mid(cyan) → high(green) → very high(yellow) → max(orange/red) const altToColor = (altM: number): string => { const ft = altM / 0.3048; if (ft < 1000) return '#ff44ff'; // magenta — ground/taxi if (ft < 5000) return '#6366f1'; // indigo — low if (ft < 15000) return '#22d3ee'; // cyan — mid climb/descent if (ft < 25000) return '#22c55e'; // green — medium if (ft < 35000) return '#eab308'; // yellow — high return '#f97316'; // orange — cruise }; const features: GeoJSON.Feature[] = []; for (let i = 0; i < points.length - 1; i++) { const a = points[i], b = points[i + 1]; const progress = i / (points.length - 1); features.push({ type: 'Feature' as const, properties: { type: 'trail', color: altToColor((a.alt + b.alt) / 2), opacity: 0.4 + progress * 0.5, // older segments more transparent segIndex: i, }, geometry: { type: 'LineString' as const, coordinates: [[a.lng, a.lat], [b.lng, b.lat]], }, }); } return { type: 'FeatureCollection' as const, features }; }, [selectedEntity, data, getSelectedEntityLiveCoords, interpTick]); // Predictive vector GeoJSON: dotted line projecting ~5 min ahead based on heading + speed // Skip when entity has a known route (origin+dest) — the route line already shows where it's going const predictiveGeoJSON = useMemo(() => { void interpTick; const entity = findSelectedEntity(selectedEntity, data); if (dynamicRoute?.orig_loc || dynamicRoute?.dest_loc) { return null; } if ( entity && 'dest_name' in entity && entity.dest_name && entity.dest_name !== 'UNKNOWN' ) { return null; } const currentLoc = getSelectedEntityLiveCoords(entity); if (!entity || !currentLoc) return buildPredictiveGeoJSON(entity); return buildPredictiveGeoJSON({ ...entity, lng: currentLoc[0], lat: currentLoc[1], }); }, [selectedEntity, data, dynamicRoute, getSelectedEntityLiveCoords, interpTick]); // Proximity range rings: 10nm, 50nm, 100nm around selected entity const proximityRingsGeoJSON = useMemo(() => { void interpTick; const entity = findSelectedEntity(selectedEntity, data); const currentLoc = getSelectedEntityLiveCoords(entity); if (!currentLoc) return null; return buildProximityRingsGeoJSON(currentLoc[1], currentLoc[0], [10, 50, 100]); }, [selectedEntity, data, getSelectedEntityLiveCoords, interpTick]); const spreadAlerts = useMemo(() => { if (!data?.news) return []; // Limit visible alerts by zoom: at low zoom show only top threats, // at high zoom show more. Prevents map clutter with dozens of boxes. const maxAlerts = mapZoom < 4 ? 6 : mapZoom < 6 ? 10 : 16; const sorted = [...data.news].sort((a, b) => (b.risk_score || 0) - (a.risk_score || 0)); return spreadAlertItems(sorted.slice(0, maxAlerts), mapZoom, dismissedAlerts); }, [data?.news, mapZoom, dismissedAlerts]); const uavGeoJSON = useMemo( () => (activeLayers.military ? buildUavGeoJSON(data?.uavs, inView) : null), [activeLayers.military, data?.uavs, inView], ); // UAV range circles removed — real ADS-B drones don't have a fixed orbit center const frontlineGeoJSON = useMemo( () => (activeLayers.ukraine_frontline ? buildFrontlineGeoJSON(data?.frontlines) : null), [activeLayers.ukraine_frontline, data?.frontlines], ); // Interactive layer IDs for click handling const activeInteractiveLayerIds = [ commFlightsGeoJSON && 'commercial-flights-layer', privFlightsGeoJSON && 'private-flights-layer', privJetsGeoJSON && 'private-jets-layer', milFlightsGeoJSON && 'military-flights-layer', shipsGeoJSON && 'ships-clusters-layer', shipsGeoJSON && 'ships-layer', carriersGeoJSON && 'carriers-layer', trackedFlightsGeoJSON && 'tracked-flights-layer', uavGeoJSON && 'uav-layer', gdeltGeoJSON && 'gdelt-layer', liveuaGeoJSON && 'liveuamap-layer', frontlineGeoJSON && 'ukraine-frontline-layer', earthquakesGeoJSON && 'earthquakes-layer', satellitesGeoJSON && 'satellites-layer', cctvGeoJSON && 'cctv-clusters', cctvGeoJSON && 'cctv-cluster-count', cctvGeoJSON && 'cctv-layer', kiwisdrGeoJSON && 'kiwisdr-clusters', kiwisdrGeoJSON && 'kiwisdr-layer', pskReporterGeoJSON && 'psk-reporter-clusters', pskReporterGeoJSON && 'psk-reporter-layer', satnogsGeoJSON && 'satnogs-clusters', satnogsGeoJSON && 'satnogs-layer', tinygsGeoJSON && 'tinygs-layer', scannerGeoJSON && 'scanner-clusters', scannerGeoJSON && 'scanner-layer', internetOutagesGeoJSON && 'internet-outages-layer', dataCentersGeoJSON && 'datacenters-layer', powerPlantsGeoJSON && 'power-plants-layer', viirsChangeNodesGeoJSON && 'viirs-change-nodes-layer', shodanGeoJSON && 'shodan-clusters', shodanGeoJSON && 'shodan-cluster-count', shodanGeoJSON && 'shodan-layer', militaryBasesGeoJSON && 'military-bases-layer', firmsGeoJSON && 'firms-viirs-layer', meshtasticGeoJSON && 'meshtastic-clusters', meshtasticGeoJSON && 'meshtastic-cluster-count', meshtasticGeoJSON && 'meshtastic-circles', aprsGeoJSON && 'aprs-clusters', aprsGeoJSON && 'aprs-cluster-count', aprsGeoJSON && 'aprs-triangles', ukraineAlertsGeoJSON && 'ukraine-alerts-fill', weatherAlertsGeoJSON && 'weather-alerts-fill', weatherAlertLabelsGeoJSON && 'weather-alert-icons', airQualityGeoJSON && 'air-quality-layer', volcanoesGeoJSON && 'volcanoes-layer', fishingGeoJSON && 'fishing-clusters', fishingGeoJSON && 'fishing-layer', trainsGeoJSON && 'trains-layer', uapSightingsGeoJSON && 'uap-sightings-cluster-bg', uapSightingsGeoJSON && 'uap-sightings-clusters', uapSightingsGeoJSON && 'uap-sightings-dot', uapSightingsGeoJSON && 'uap-sightings-layer', wastewaterGeoJSON && 'wastewater-cluster-bg', wastewaterGeoJSON && 'wastewater-clusters', wastewaterGeoJSON && 'wastewater-dot', wastewaterGeoJSON && 'wastewater-layer', crowdthreatGeoJSON && 'crowdthreat-layer', sarAnomaliesGeoJSON && 'sar-anomalies-layer', sarAoisGeoJSON && 'sar-aois-fill', aiIntelGeoJSON && 'ai-intel-clusters', aiIntelGeoJSON && 'ai-intel-pin-layer', correlationsGeoJSON && 'corr-rf-fill', correlationsGeoJSON && 'corr-mil-fill', correlationsGeoJSON && 'corr-infra-fill', correlationsGeoJSON && 'corr-contra-fill', correlationsGeoJSON && 'corr-analysis-fill', ].filter(Boolean) as string[]; useEffect(() => { const map = mapRef.current?.getMap(); if (!map) return; const emphasizedLayers = [ 'uap-sightings-cluster-bg', 'uap-sightings-clusters', 'uap-sightings-dot', 'uap-sightings-layer', 'wastewater-cluster-bg', 'wastewater-clusters', 'wastewater-dot', 'wastewater-layer', ]; const moveEmphasizedLayersToTop = () => { for (const layerId of emphasizedLayers) { if (map.getLayer(layerId)) { map.moveLayer(layerId); } } }; const rafId = window.requestAnimationFrame(moveEmphasizedLayersToTop); const timeoutId = window.setTimeout(moveEmphasizedLayersToTop, 120); return () => { window.cancelAnimationFrame(rafId); window.clearTimeout(timeoutId); }; }, [activeLayers.uap_sightings, activeLayers.wastewater, theme]); // --- Imperative source updates: bypass React reconciliation for GeoJSON layers --- const mapForHook = mapReady ? mapRef.current : null; useImperativeSource(mapForHook, 'commercial-flights', commFlightsGeoJSON); useImperativeSource(mapForHook, 'private-flights', privFlightsGeoJSON); useImperativeSource(mapForHook, 'private-jets', privJetsGeoJSON); useImperativeSource(mapForHook, 'military-flights', milFlightsGeoJSON); useImperativeSource(mapForHook, 'tracked-flights', trackedFlightsGeoJSON); useImperativeSource(mapForHook, 'uavs', uavGeoJSON); useImperativeSource(mapForHook, 'satellites', satellitesGeoJSON); useImperativeSource(mapForHook, 'tinygs', tinygsGeoJSON); useImperativeSource(mapForHook, 'cctv', cctvGeoJSON, 75); useImperativeSource(mapForHook, 'kiwisdr', kiwisdrGeoJSON, 75); useImperativeSource(mapForHook, 'psk-reporter', pskReporterGeoJSON, 75); useImperativeSource(mapForHook, 'satnogs', satnogsGeoJSON, 75); useImperativeSource(mapForHook, 'scanners', scannerGeoJSON, 75); useImperativeSource(mapForHook, 'firms-fires', firmsGeoJSON, 900); useImperativeSource(mapForHook, 'internet-outages', internetOutagesGeoJSON, 100); useImperativeSource(mapForHook, 'datacenters', dataCentersGeoJSON, 120); useImperativeSource(mapForHook, 'power-plants', powerPlantsGeoJSON, 140); useImperativeSource(mapForHook, 'viirs-change-nodes', viirsChangeNodesGeoJSON, 120); useImperativeSource(mapForHook, 'military-bases', militaryBasesGeoJSON, 75); useImperativeSource(mapForHook, 'gdelt', gdeltGeoJSON, 75); useImperativeSource(mapForHook, 'liveuamap', liveuaGeoJSON, 75); useImperativeSource(mapForHook, 'air-quality-source', airQualityGeoJSON, 100); useImperativeSource(mapForHook, 'volcanoes-source', volcanoesGeoJSON, 100); useImperativeSource(mapForHook, 'fishing-source', fishingGeoJSON, 100); useImperativeSource(mapForHook, 'uap-sightings-source', uapSightingsGeoJSON, 100); useImperativeSource(mapForHook, 'wastewater-source', wastewaterGeoJSON, 100); useImperativeSource(mapForHook, 'crowdthreat-source', crowdthreatGeoJSON, 100); useImperativeSource(mapForHook, 'ships', shipsGeoJSON, 75); useImperativeSource(mapForHook, 'meshtastic-source', meshtasticGeoJSON, 60); useImperativeSource(mapForHook, 'aprs-source', aprsGeoJSON, 60); useImperativeSource(mapForHook, 'trains', trainsGeoJSON, 60); useImperativeSource(mapForHook, 'sar-aois', sarAoisGeoJSON, 120); useImperativeSource(mapForHook, 'sar-anomalies', sarAnomaliesGeoJSON, 120); const handleMouseMove = useCallback( (evt: MapLayerMouseEvent) => { if (onMouseCoords) onMouseCoords({ lat: evt.lngLat.lat, lng: evt.lngLat.lng }); }, [onMouseCoords], ); // eslint-disable-next-line @typescript-eslint/no-explicit-any const opacityFilter: any = selectedEntity ? [ 'case', [ 'all', ['==', ['get', 'type'], selectedEntity.type], ['==', ['get', 'id'], selectedEntity.id], ], 1.0, 0.0, ] : 1.0; return (
{ setIsMapInteracting((prev) => (prev ? prev : true)); }} onMove={(evt) => { viewStateRef.current = evt.viewState; }} onMoveEnd={() => { setIsMapInteracting(false); const currentViewState = viewStateRef.current; setMapZoom((prevZoom) => Math.abs(prevZoom - currentViewState.zoom) > 0.01 ? currentViewState.zoom : prevZoom, ); onViewStateChange?.({ zoom: currentViewState.zoom, latitude: currentViewState.latitude, }); updateBounds(); }} onMouseMove={handleMouseMove} onContextMenu={(evt) => { evt.preventDefault(); onRightClick?.({ lat: evt.lngLat.lat, lng: evt.lngLat.lng }); }} mapStyle={mapThemeStyle} mapLib={maplibregl} attributionControl={false} onLoad={onMapLoad} onStyleData={onMapStyleData} onIdle={() => { setIsMapInteracting(false); updateBounds(); }} interactiveLayerIds={activeInteractiveLayerIds} onClick={(e) => { // Measurement mode: place waypoints instead of selecting entities if (measureMode && onMeasureClick) { onMeasureClick({ lat: e.lngLat.lat, lng: e.lngLat.lng }); return; } // SAR AOI drop mode if (sarAoiDropMode) { onSarAoiDropped?.({ lat: e.lngLat.lat, lng: e.lngLat.lng }); return; } // Pin placement mode if (pinPlacementMode) { const clickedFeature = e.features?.[0]; const clickedProps = clickedFeature?.properties || {}; const isEntity = clickedFeature && clickedProps.type && clickedProps.id && !clickedProps.cluster; setPendingPin({ lat: e.lngLat.lat, lng: e.lngLat.lng, entity: isEntity ? { entity_type: String(clickedProps.type || ''), entity_id: String(clickedProps.id || ''), entity_label: String(clickedProps.name || clickedProps.callsign || clickedProps.label || ''), } : null, }); return; } // AI Intel pin click → open detail popup (takes precedence over entity selection) if (e.features && e.features.length > 0) { const aiPin = e.features.find( (f) => f.layer?.id === 'ai-intel-pin-layer' && !(f.properties as Record | null)?.cluster, ); if (aiPin && aiPin.properties?.id) { setOpenPinDetailId(String(aiPin.properties.id)); return; } } if (selectedEntity) { onEntityClick?.(null); } else if (e.features && e.features.length > 0) { // SAR AOI fill spans large polygons (often hundreds of km wide) // and renders above entity layers. If an entity (flight, ship, // SDR receiver, etc.) is also under the cursor, prefer it — the // AOI should only win when the user clicks empty space inside it. const nonAoiFeature = e.features.find( (f) => f.layer?.id !== 'sar-aois-fill', ); const feature = nonAoiFeature ?? e.features[0]; const props = feature.properties || {}; // If the clicked feature is a cluster, zoom into it instead of selecting an entity if (props.cluster) { const targetZoom = (mapRef.current?.getMap().getZoom() ?? mapZoom) + 2; mapRef.current?.flyTo({ center: [e.lngLat.lng, e.lngLat.lat], zoom: targetZoom, duration: 500, }); return; } onEntityClick?.({ id: props.id, type: props.type, name: props.name, media_url: props.media_url, extra: props, }); } else { onEntityClick?.(null); } }} > © OpenStreetMap contributors', 'CARTO', 'adsb.lol (ODbL)', 'OpenSky', 'CelesTrak', 'aisstream.io', 'Meshtastic map by Liam Cottle', 'NASA · NOAA · USGS · GDELT', 'full sources', ]} /> {/* Esri World Imagery — high-res static satellite (zoom 0-18+) */} {activeLayers.highres_satellite && ( )} {/* NASA GIBS MODIS Terra — daily satellite imagery overlay */} {activeLayers.gibs_imagery && gibsDate && ( )} {/* NASA GIBS VIIRS Night Lights — Black Marble night-lights overlay */} {activeLayers.viirs_nightlights && viirsResolvedTileTemplate && (() => { const viirsTileTemplate = viirsResolvedTileTemplate; return ( ); })()} {/* Sentinel Hub — user-provided Copernicus CDSE WMTS tiles */} {activeLayers.sentinel_hub && sentinelTileUrl && ( )} {/* Esri Reference Overlay — borders, labels, and places on top of imagery layers */} {showImageryReferenceOverlay && ( )} {/* NASA FIRMS VIIRS — fire hotspot icons from FIRMS CSV feed */} {/* firms-fires: data pushed imperatively via useImperativeSource */} {/* Cluster fire icons — flame shape to differentiate from Global Incidents circles */} {/* Individual fire icons — flame shape sized by FRP */} {/* SOLAR TERMINATOR — night overlay */} {activeLayers.day_night && nightGeoJSON && ( )} {/* ═══ GROUND OVERLAYS — rendered below ships, mesh, and flights ═══ */} {/* Earthquake cluster circles */} {/* Individual (unclustered) earthquake icons */} {/* GPS Jamming Zones — red translucent grid squares */} {/* Correlation Alerts — Emergent Intelligence grid squares */} {/* RF Anomaly — grey */} {/* Military Buildup — red dashed */} {/* Infrastructure Cascade — black */} {/* Possible Contradiction — amber pulsing, hypothesis not verdict */} {/* Analysis Zone fill */} {/* Analysis Zone dashed outline */} {/* Analysis Zone label */} {/* CCTV Cameras — clustered white dots */} {/* Cluster circles — white, sized by count */} {/* Cluster count labels */} {/* Individual camera dots */} {/* KiwiSDR Receivers — radio tower icons with pulse rings */} {/* Pulse ring behind clusters */} {/* Clusters — tower icon with count */} {/* Pulse ring behind individual towers */} {/* Individual tower icons */} {/* PSK Reporter — green HF digital mode spots with clustering */} {/* Pulse ring behind clusters */} {/* Clusters — count */} {/* Individual spots — small green dots */} {/* SatNOGS Ground Stations — teal satellite dish icons with clustering */} {/* TinyGS LoRa Satellites — purple satellite icons (no clustering, small count) */} {/* Police Scanners (OpenMHZ) — red scanner icons with clusters */} {/* Pulse ring behind clusters */} {/* Cluster icons + count */} {/* Pulse ring behind individual scanners */} {/* Individual scanner icons */} {/* Internet Outages — region-level grey markers with % and labels */} {/* Outer ring */} {/* Inner solid circle — all grey, size conveys severity */} {/* Severity % inside circle */} ', ['get', 'severity'], 0], ['concat', ['to-string', ['get', 'severity']], '%'], '!', ], 'text-size': 9, 'text-font': ['Noto Sans Bold'], 'text-allow-overlap': true, 'text-ignore-placement': true, }} paint={{ 'text-color': '#ffffff', 'text-halo-color': 'rgba(0,0,0,0.8)', 'text-halo-width': 1, }} /> {/* Region name label below — grey */} {/* Data Center positions */} {/* Cluster circles */} {/* Individual DC icons */} {/* Power Plant positions */} {powerPlantsGeoJSON && ( {/* Cluster circles */} {/* Individual power plant icons */} )} {/* VIIRS Change Detection Nodes */} {viirsChangeNodesGeoJSON && ( )} {/* SAR AOIs — operator watchbox circles, drawn beneath anomaly pins */} {sarAoisGeoJSON && ( )} {/* SAR Anomalies — Mode B pre-processed findings (OPERA/EGMS/GFM/EMS/UNOSAT) */} {sarAnomaliesGeoJSON && ( )} {/* Shodan — operator-triggered local overlay, clustered and clearly distinct */} {(() => { const sc = shodanStyle ?? { shape: 'circle' as const, color: '#16a34a', size: 'md' as const }; const sizeMap = { sm: [3, 4, 5] as const, md: [4, 6, 8] as const, lg: [6, 9, 12] as const }; const textSizeMap = { sm: 10, md: 14, lg: 20 }; const shapeGlyphs: Record = { triangle: '▲', diamond: '◆', square: '■' }; const radii = sizeMap[sc.size] ?? sizeMap.md; const isCircle = sc.shape === 'circle'; const labelOffset = isCircle ? 1.1 : (sc.size === 'lg' ? 1.6 : sc.size === 'sm' ? 0.9 : 1.2); return ( {/* Cluster circles — always circles, inherit color */} {/* Individual markers — circle layer (hidden when non-circle shape) */} {isCircle && ( )} {/* Individual markers — symbol layer for triangle/diamond/square */} {!isCircle && ( )} {/* Labels */} ); })()} {/* AI Intel Layer — pins from OpenClaw / AI co-pilot */} {aiIntelGeoJSON && ( )} {/* Military Bases — per-country colors */} {/* Ukraine Air Raid Alerts — red/orange oblast polygons */} {/* Weather Alerts — severity-colored polygons with icon + label overlay */} {/* Air Quality — AQI-colored circles */} {/* Volcanoes — activity-colored triangle icons */} {/* Fishing Activity — AIS-style ship clusters and icons */} {/* UAP Sightings — purple UFO icons with detail labels */} {/* Cluster glow — faint backdrop behind UFO icon */} {/* Cluster UFO icon + count */} {/* Individual glow — faint backdrop behind UFO icon */} {/* Individual UFO icon overlay */} {/* WastewaterSCAN — pathogen surveillance network (water drops) */} {/* Cluster glow — faint backdrop behind water drop icon */} {/* Cluster water drop icon + count */} {/* Individual glow — faint backdrop behind water drop icon */} ', ['get', 'alert_count'], 0], 'rgba(255, 34, 34, 0.20)', 'rgba(0, 229, 255, 0.20)'], 'circle-stroke-width': 0.75, 'circle-stroke-color': ['case', ['>', ['get', 'alert_count'], 0], 'rgba(255, 82, 82, 0.25)', 'rgba(128, 222, 234, 0.25)'], }} /> {/* Individual water drop icon overlay */} ', ['get', 'alert_count'], 0], '#ff5252', '#80deea'], 'text-halo-color': 'rgba(0,0,0,0.98)', 'text-halo-width': 1.25, }} /> {/* CrowdThreat — crowdsourced threat intelligence with category icons */} {/* Ships — rendered below flights (water surface level) */} {/* Clustered circles */} {/* Cluster count - rendered via HTML markers below */} {/* Unclustered individual ships (Cargo, Tankers, etc.) */} {/* Meshtastic — green triangle clusters that break apart on zoom */} {/* APRS / JS8Call — pink triangles with clustering */} {/* ═══ FLIGHTS — always rendered above ground/ship/mesh layers ═══ */} {/* Airport dots at origin/destination */} {/* IATA code labels at airports */} {/* Flight trail history (where the aircraft has been) — altitude-colored gradient */} {/* Predictive vector (where entity is heading — 5 min forward projection) */} {/* Proximity range rings (10nm, 50nm, 100nm around selected entity) */} {/* GDELT & LiveUA — ground-level incidents, rendered below flights */} {/* tracked-flights & UAVs: rendered above ground layers (airborne) */} {/* Gold halo ring — POTUS aircraft only (Air Force One/Two, Marine One) */} {/* HTML labels for ship cluster counts (hidden when any entity popup is active) */} {shipsGeoJSON && !selectedEntity && !isMapInteracting && ( )} {/* HTML labels for tracked flights — color-matched, zoom-gated for non-HVA */} {trackedFlightsGeoJSON && !selectedEntity && !isMapInteracting && data?.tracked_flights && ( )} {/* HTML labels for carriers (orange names, with ESTIMATED badge for OSINT positions) */} {carriersGeoJSON && !selectedEntity && !isMapInteracting && data?.ships && ( )} {/* HTML labels for tracked yachts (pink owner names) */} {shipsGeoJSON && activeLayers.ships_tracked_yachts && !selectedEntity && !isMapInteracting && data?.ships && ( )} {/* HTML labels for earthquake cluster counts (hidden when any entity popup is active) */} {earthquakesGeoJSON && !selectedEntity && !isMapInteracting && ( )} {/* HTML labels for UAVs (orange names) */} {uavGeoJSON && !selectedEntity && !isMapInteracting && data?.uavs && ( )} {/* HTML labels for earthquakes (yellow) - only show when zoomed in (~2000 miles = zoom ~5) */} {earthquakesGeoJSON && !selectedEntity && !isMapInteracting && mapZoom >= 5 && data?.earthquakes && ( )} {/* Maplibre HTML Custom Markers for high-importance Threat Overlays (highest z-index) */} {activeLayers.global_incidents && !isMapInteracting && ( { setDismissedAlerts((prev) => new Set(prev).add(alertKey)); onEntityClick?.(null); }} /> )} {/* Satellite positions — mission-type icons */} {/* satellites: data pushed imperatively */} {/* Golden halo ring — ISS only */} {/* Train positions */} {/* Satellite click popup (with ISS live feed + maneuver alerts) */} {selectedEntity?.type === 'satellite' && (() => { const sat = data?.satellites?.find((s) => s.id === selectedEntity.id); if (!sat) return null; const maneuverAlert = data?.satellite_analysis?.maneuvers?.find( (m) => m.norad_id === sat.id ); return ( onEntityClick?.(null)} /> ); })()} {/* Correlation / Contradiction click popup */} {selectedEntity?.type === 'correlation' && (() => { const corrIndex = typeof selectedEntity.extra?.corr_index === 'number' ? selectedEntity.extra.corr_index : parseInt(String(selectedEntity.id).replace('corr-', ''), 10); const alert = data?.correlations?.[corrIndex]; if (!alert) return null; return ( onEntityClick?.(null)} /> ); })()} {/* UAP Sighting popup */} {selectedEntity?.type === 'uap_sighting' && (() => { const props = selectedEntity.extra || {}; const sighting = data?.uap_sightings?.find((s) => s.id === selectedEntity.id); const lat = sighting?.lat ?? props.lat; const lng = sighting?.lng ?? props.lng; if (lat == null || lng == null) return null; const location = [props.city, props.state, props.country].filter(Boolean).join(', ') || 'Unknown location'; const count = props.count ?? 1; const hasShape = props.shape && props.shape !== 'unknown'; const hasSummary = props.summary && props.summary !== 'Sighting reported' && !props.summary?.match(/^\d+ sighting\(s\) reported$/); return ( onEntityClick?.(null)} className="threat-popup" maxWidth="320px">
👽 UAP Sighting
{/* Core details */}
Location: {location}
{props.date_time &&
Date: {props.date_time}
} {count > 1 &&
Sightings: {count}
} {/* Enriched details from NUFORC database */} {(hasShape || props.duration) && (
{hasShape && (
Shape: {props.shape_raw || props.shape}
)} {props.duration && (
Duration: {props.duration}
)}
)} {/* Witness summary */} {hasSummary && (
WITNESS REPORT
“{props.summary}”
)}
{props.source || 'NUFORC'} — UAP SIGHTING REPORT
); })()} {/* Wastewater plant popup */} {selectedEntity?.type === 'wastewater' && (() => { const plant = data?.wastewater?.find((w) => w.id === selectedEntity.id); if (!plant) return null; return ( onEntityClick?.(null)} /> ); })()} {/* CrowdThreat popup */} {selectedEntity?.type === 'crowdthreat' && (() => { const props = selectedEntity.extra || {}; const ct = data?.crowdthreat?.find((c) => `ct-${c.id}` === selectedEntity.id); const lat = ct?.lat ?? props.lat; const lng = ct?.lng ?? props.lng; if (lat == null || lng == null) return null; const accent = props.category_colour || '#6b7280'; const location = [props.address || props.city, props.country].filter(Boolean).join(', ') || 'Unknown'; return ( onEntityClick?.(null)} className="threat-popup" maxWidth="320px">
{props.title}
{props.summary && (
{props.summary}
)}
Category: {props.category}
{props.subcategory &&
Subcategory: {props.subcategory}
} {props.threat_type &&
Type: {props.threat_type}
}
Location: {location}
{props.occurred &&
Occurred: {props.occurred}
} {props.timeago &&
Reported: {props.timeago}
} {props.verification && (
Status: {props.verification.toUpperCase()}
)} {props.severity && (
Severity: {props.severity}
)} {props.source_url && ( )}
CROWDTHREAT — VERIFIED THREAT INTELLIGENCE
); })()} {/* Train click popup */} {selectedEntity?.type === 'train' && (() => { const train = data?.trains?.find((t) => t.id === selectedEntity.id); if (!train) return null; const isAmtrak = train.source === 'amtrak'; const sourceLabel = train.source_label || train.source.toUpperCase(); const subtitleParts = [sourceLabel]; if (train.operator && train.operator !== sourceLabel) subtitleParts.push(train.operator); return ( onEntityClick?.(null)} anchor="bottom" offset={12} >
{train.name}
{subtitleParts.join(' / ')}{train.number ? ` — #${train.number}` : ''}
{train.country && (
Country: {train.country}
)} {train.route && (
Route: {train.route}
)} {train.speed_kmh != null && (
Speed: {train.speed_kmh} km/h
)}
Status: {train.status || 'Active'}
); })()} {/* UAV click popup — real ADS-B detected drones */} {selectedEntity?.type === 'uav' && (() => { const uav = data?.uavs?.find((u) => u.id === selectedEntity.id); if (!uav) return null; return ( onEntityClick?.(null)} anchor="bottom" offset={12} >
{uav.callsign}
LIVE ADS-B TRANSPONDER
{uav.aircraft_model && (
Model: {uav.aircraft_model}
)} {uav.uav_type && (
Classification: {uav.uav_type}
)} {uav.country && (
Registration: {uav.country}
)} {uav.icao24 && (
ICAO: {uav.icao24}
)}
Altitude: {uav.alt?.toLocaleString()} m
{(uav.speed_knots ?? 0) > 0 && (
Speed: {uav.speed_knots} kn
)} {uav.squawk && (
Squawk: {uav.squawk}
)} {uav.wiki && (
)}
); })()} {/* KiwiSDR Receivers Popup */} {selectedEntity?.type === 'kiwisdr' && (() => { const receiver = data?.kiwisdr?.find( (k) => k.name === selectedEntity.name || k.name === String(selectedEntity.id), ); // use extra if available from the click event, otherwise fallback const props = (selectedEntity.extra || receiver || {}) as KiwiProps; const lat = props.lat ?? selectedEntity.extra?.lat ?? selectedEntity.extra?.geometry?.coordinates?.[1]; const lng = props.lon ?? props.lng ?? selectedEntity.extra?.lon ?? selectedEntity.extra?.geometry?.coordinates?.[0]; if (lat == null || lng == null) return null; return ( onEntityClick?.(null)} anchor="bottom" offset={12} >
{(props.name || 'UNKNOWN SDR RECEIVER').toUpperCase()}
PUBLIC NETWORK RECEIVER
{props.location && (
Location: {props.location}
)} {props.users !== undefined && (
Active Users:{' '} = (props.users_max || 4) ? 'text-red-400' : 'text-amber-400' } > {props.users} / {props.users_max || '?'}
)} {props.antenna && (
Antenna: {props.antenna}
)} {props.bands && (
Bands:{' '} {(Number(props.bands.split('-')[0]) / 1e6).toFixed(0)}- {(Number(props.bands.split('-')[1]) / 1e6).toFixed(0)} MHz
)}
{props.url && ( )}
); })()} {/* SatNOGS Ground Station Popup */} {selectedEntity?.type === 'satnogs_station' && (() => { const props = (selectedEntity.extra || {}) as Record; const lat = (props.lat as number) ?? selectedEntity.extra?.geometry?.coordinates?.[1]; const lng = (props.lng as number) ?? selectedEntity.extra?.geometry?.coordinates?.[0]; if (lat == null || lng == null) return null; return ( onEntityClick?.(null)} anchor="bottom" offset={12} >
{((props.name as string) || 'UNKNOWN STATION').toUpperCase()}
SATNOGS GROUND STATION
{String(props.antenna || '') !== '' && (
Antenna: {String(props.antenna)}
)} {Number(props.observations || 0) > 0 && (
Observations: {Number(props.observations).toLocaleString()}
)} {String(props.last_seen || '') !== '' && (
Last seen: {new Date(String(props.last_seen)).toLocaleString()}
)}
{lat.toFixed(4)}°, {lng.toFixed(4)}°
); })()} {/* TinyGS LoRa Satellite Popup */} {selectedEntity?.type === 'tinygs_satellite' && (() => { const props = (selectedEntity.extra || {}) as Record; const lat = (props.lat as number) ?? selectedEntity.extra?.geometry?.coordinates?.[1]; const lng = (props.lng as number) ?? selectedEntity.extra?.geometry?.coordinates?.[0]; if (lat == null || lng == null) return null; return ( onEntityClick?.(null)} anchor="bottom" offset={12} >
{String(props.name || 'UNKNOWN SATELLITE').toUpperCase()}
LORA SATELLITE {props.tinygs_confirmed ? ( TINYGS LIVE ) : props.sgp4_propagated ? ( SGP4 ORBIT ) : null}
{Number(props.alt_km || 0) > 0 && (
Altitude: {Number(props.alt_km).toFixed(0)} km
)} {String(props.modulation || '') !== '' && (
Modulation: {String(props.modulation)}
)} {String(props.frequency || '') !== '' && (
Frequency: {String(props.frequency)} MHz
)} {String(props.status || '') !== '' && (
Status: {String(props.status)}
)}
{lat.toFixed(4)}°, {lng.toFixed(4)}°
); })()} {/* CCTV popup removed — now handled by fullscreen OPTIC INTERCEPT modal */} {/* Police Scanner click popup */} {selectedEntity?.type === 'scanner' && (() => { const props = (selectedEntity.extra || {}) as ScannerProps; const lat = props.lat ?? selectedEntity.extra?.geometry?.coordinates?.[1]; const lng = props.lng ?? selectedEntity.extra?.geometry?.coordinates?.[0]; if (lat == null || lng == null) return null; return ( onEntityClick?.(null)} anchor="bottom" offset={12} >
{(props.name || 'UNKNOWN SYSTEM').toUpperCase()}
TRUNKED RADIO SYSTEM
{(props.city || props.state) && (
Location:{' '} {[props.city, props.state].filter(Boolean).join(', ')}
)}
Active Listeners: {props.clientCount || 0}
{props.description && (
{String(props.description).slice(0, 120)}
)}
); })()} {/* SIGINT signal click popup */} {selectedEntity?.type === 'sigint' && (() => { const props = (selectedEntity.extra || {}) as SigintProps; const sig = data?.sigint?.find( (s) => `${s.source}:${s.callsign}` === selectedEntity.id, ); const d = sig || props; const lat = sig?.lat ?? props.geometry?.coordinates?.[1]; const lng = sig?.lng ?? props.geometry?.coordinates?.[0]; if (lat == null || lng == null) return null; return ( onEntityClick?.(null)} /> ); })()} {/* Ship / carrier click popup */} {selectedEntity?.type === 'ship' && (() => { const ship = data?.ships?.find((s, i: number) => { return ( (s.mmsi || s.name || `ship-${i}`) === selectedEntity.id || (s.mmsi || s.name || `carrier-${i}`) === selectedEntity.id ); }); if (!ship) return null; const [iLng, iLat] = interpShip(ship); return ( onEntityClick?.(null)} /> ); })()} {/* SAR anomaly click popup */} {selectedEntity?.type === 'sar_anomaly' && (() => { const extra = (selectedEntity.extra || {}) as Record; const anomaly = data?.sar_anomalies?.find( (a) => a.anomaly_id === selectedEntity.id, ); const a = anomaly || extra; const lat = typeof a.lat === 'number' ? a.lat : Number(extra.center_lat); const lng = typeof (a as { lon?: number }).lon === 'number' ? (a as { lon: number }).lon : Number(extra.center_lon); if (!Number.isFinite(lat) || !Number.isFinite(lng)) return null; const kind = String(a.kind || extra.kind || 'anomaly'); const title = String(a.title || extra.title || `SAR ${kind}`); const summary = String(a.summary || extra.summary || ''); const solver = String(a.solver || extra.solver || ''); const constellation = String( (a as { source_constellation?: string }).source_constellation || extra.source_constellation || '', ); const magnitude = Number(a.magnitude ?? extra.magnitude ?? 0); const unit = String(a.magnitude_unit || extra.magnitude_unit || ''); const confidence = Number(a.confidence ?? extra.confidence ?? 0); const lastSeen = Number(a.last_seen ?? extra.last_seen ?? 0); const provenance = String(a.provenance_url || extra.provenance_url || ''); const aoiId = String(a.aoi_id || extra.aoi_id || ''); const color = String(extra.color || '#eab308'); return ( onEntityClick?.(null)} className="threat-popup" maxWidth="320px" >
{title}
{summary && (
{summary}
)}
Kind:{' '} {kind.replace(/_/g, ' ')}
{solver && (
Solver: {solver}
)} {constellation && (
Source: {constellation}
)} {magnitude !== 0 && (
Magnitude:{' '} {magnitude.toFixed(3)} {unit}
)}
Confidence:{' '} {(confidence * 100).toFixed(0)}%
{lastSeen > 0 && (
Last seen:{' '} {new Date(lastSeen * 1000).toISOString().replace('T', ' ').slice(0, 19)}Z
)} {aoiId && (
AOI: {aoiId}
)} {provenance && ( )}
); })()} {/* SAR AOI click popup — operator watchbox details */} {selectedEntity?.type === 'sar_aoi' && (() => { const extra = (selectedEntity.extra || {}) as Record; const lat = Number(extra.center_lat); const lng = Number(extra.center_lon); if (!Number.isFinite(lat) || !Number.isFinite(lng)) return null; const name = String(extra.name || selectedEntity.id); const description = String(extra.description || ''); const category = String(extra.category || 'watchlist'); const radius = Number(extra.radius_km || 0); return ( onEntityClick?.(null)} className="threat-popup" maxWidth="300px" >
AOI · {name}
{description && (
{description}
)}
Category:{' '} {category}
Radius: {radius.toFixed(0)} km
Center:{' '} {lat.toFixed(3)}, {lng.toFixed(3)}
); })()} {/* Data Center click popup */} {selectedEntity?.type === 'datacenter' && (() => { const dc = data?.datacenters?.find((_, i: number) => `dc-${i}` === selectedEntity.id); if (!dc) return null; // Check if any internet outage is in the same country const outagesInCountry = (data?.internet_outages || []).filter( (o) => o.country_name && dc.country && o.country_name.toLowerCase() === dc.country.toLowerCase(), ); return ( onEntityClick?.(null)} className="threat-popup" maxWidth="280px" >
{dc.name}
{dc.company && (
Operator: {dc.company}
)} {dc.street && (
Address:{' '} {dc.street} {dc.zip ? ` ${dc.zip}` : ''}
)} {dc.city && (
Location:{' '} {dc.city} {dc.country ? `, ${dc.country}` : ''}
)} {!dc.city && dc.country && (
Country: {dc.country}
)} {outagesInCountry.length > 0 && (
OUTAGE IN REGION —{' '} {outagesInCountry.map((o) => `${o.region_name} (${o.severity}%)`).join(', ')}
)}
DATA CENTER
); })()} {/* Power Plant click popup */} {selectedEntity?.type === 'power_plant' && (() => { const pp = data?.power_plants?.find((_: any, i: number) => `pp-${i}` === selectedEntity.id); if (!pp) return null; return ( onEntityClick?.(null)} className="threat-popup" maxWidth="280px" >
{pp.name}
{pp.fuel_type && (
Fuel: {pp.fuel_type}
)} {pp.capacity_mw != null && (
Capacity: {pp.capacity_mw.toLocaleString()} MW
)} {pp.owner && (
Operator: {pp.owner}
)} {pp.country && (
Country: {pp.country}
)}
POWER PLANT
); })()} {/* VIIRS Change Node click popup */} {selectedEntity?.type === 'viirs_change_node' && (() => { const node = data?.viirs_change_nodes?.find( (_: any, i: number) => `viirs-${i}` === selectedEntity.id ); if (!node) return null; const isLoss = node.mean_change_pct < 0; return ( onEntityClick?.(null)} className="threat-popup" maxWidth="280px" >
VIIRS NIGHT LIGHTS
Region: {node.aoi_name}
Change: {isLoss ? '' : '+'}{node.mean_change_pct.toFixed(1)}%
Severity: {node.severity.replace('_', ' ')}
{isLoss ? 'LIGHTS WENT DARK' : 'LIGHTS INCREASED'}
); })()} {selectedEntity?.type === 'military_base' && (() => { const base = data?.military_bases?.find( (_, i: number) => `milbase-${i}` === selectedEntity.id, ); if (!base) return null; return ( onEntityClick?.(null)} /> ); })()} {/* Ukraine Air Raid Alert popup */} {selectedEntity?.type === 'ukraine_alert' && (() => { const alert = data?.ukraine_alerts?.find((a) => String(a.id) === String(selectedEntity.id)); if (!alert) return null; const accent = alert.color || '#ef4444'; const geom = alert.geometry; const coords = geom?.type === 'Polygon' ? geom.coordinates?.[0]?.[0] : geom?.type === 'MultiPolygon' ? geom.coordinates?.[0]?.[0]?.[0] : null; if (!coords) return null; const started = alert.started_at ? new Date(alert.started_at) : null; const durationMin = started ? Math.round((Date.now() - started.getTime()) / 60000) : null; const durationStr = durationMin != null ? (durationMin >= 60 ? `${Math.floor(durationMin / 60)}h ${durationMin % 60}m` : `${durationMin}m`) : ''; const alertLabel = ({ air_raid: 'AIR RAID', artillery_shelling: 'SHELLING', urban_fights: 'URBAN COMBAT', chemical: 'CHEMICAL', nuclear: 'NUCLEAR' } as Record)[alert.alert_type] || alert.alert_type.toUpperCase(); return ( onEntityClick?.(null)} className="threat-popup" maxWidth="300px">
{alertLabel}
{alert.name_en || alert.location_title}
Oblast: {alert.location_title}
{started &&
Since: {started.toLocaleTimeString()}
} {durationStr &&
Duration: {durationStr}
}
UKRAINE AIR RAID — ALERTS.IN.UA
); })()} {/* Weather Alert popup */} {selectedEntity?.type === 'weather_alert' && (() => { const alert = data?.weather_alerts?.find((a) => a.id === selectedEntity.id); if (!alert) return null; const sevColors: Record = { Extreme: '#ef4444', Severe: '#f97316', Moderate: '#eab308', Minor: '#3b82f6' }; const accent = sevColors[alert.severity] || '#3b82f6'; const geom = alert.geometry; const coords = geom?.type === 'Polygon' ? geom.coordinates?.[0]?.[0] : geom?.type === 'MultiPolygon' ? geom.coordinates?.[0]?.[0]?.[0] : null; if (!coords) return null; return ( onEntityClick?.(null)} className="threat-popup" maxWidth="300px">
{alert.event}
{alert.headline}
Severity: {alert.severity}
{alert.expires &&
Expires: {new Date(alert.expires).toLocaleString()}
}
{alert.description}
); })()} {/* Air Quality popup */} {selectedEntity?.type === 'air_quality' && (() => { const station = data?.air_quality?.find((s) => `aq-${s.id}` === selectedEntity.id); if (!station) return null; const aqiColors: Record = { Good: '#22c55e', Moderate: '#eab308', 'Unhealthy (Sensitive)': '#f97316', Unhealthy: '#ef4444', 'Very Unhealthy': '#a855f7', Hazardous: '#7f1d1d' }; const label = station.aqi <= 50 ? 'Good' : station.aqi <= 100 ? 'Moderate' : station.aqi <= 150 ? 'Unhealthy (Sensitive)' : station.aqi <= 200 ? 'Unhealthy' : station.aqi <= 300 ? 'Very Unhealthy' : 'Hazardous'; const accent = aqiColors[label] || '#22c55e'; return ( onEntityClick?.(null)} className="threat-popup" maxWidth="260px">
{station.name}
AQI: {station.aqi} ({label})
PM2.5: {station.pm25} µg/m³
{station.country &&
Country: {station.country}
}
AIR QUALITY — OPENAQ
); })()} {/* Volcano popup */} {selectedEntity?.type === 'volcano' && (() => { const idx = parseInt(String(selectedEntity.id).replace('volcano-', ''), 10); const volcano = data?.volcanoes?.[idx]; if (!volcano) return null; const now = new Date().getFullYear(); const yearsAgo = volcano.last_eruption_year ? now - volcano.last_eruption_year : null; const accent = yearsAgo !== null && yearsAgo <= 50 ? '#ef4444' : yearsAgo !== null && yearsAgo <= 500 ? '#f97316' : '#6b7280'; return ( onEntityClick?.(null)} className="threat-popup" maxWidth="260px">
{volcano.name}
Type: {volcano.type}
Country: {volcano.country}
{volcano.region &&
Region: {volcano.region}
}
Elevation: {volcano.elevation?.toLocaleString()}m
Last Eruption: {volcano.last_eruption_year || 'Unknown'}
VOLCANO — SMITHSONIAN GVP
); })()} {/* Fishing Event popup — cross-references with AIS when available */} {selectedEntity?.type === 'fishing_event' && (() => { const event = data?.fishing_activity?.find((e) => (e.id || '') === selectedEntity.id); if (!event) return null; // Cross-reference with AIS ships by vessel name const vesselNameUpper = (event.vessel_name || '').toUpperCase().trim(); const aisMatch = vesselNameUpper && data?.ships?.find((s) => { const shipName = (s.name || '').toUpperCase().trim(); return shipName && (shipName === vesselNameUpper || shipName.includes(vesselNameUpper) || vesselNameUpper.includes(shipName)); }); return ( onEntityClick?.(null)} className="threat-popup" maxWidth="320px">
{event.vessel_name}
Flag: {event.vessel_flag || 'Unknown'}
Activity: {event.type}
Duration: {event.duration_hrs}h
{event.start &&
Start: {new Date(event.start).toLocaleDateString()}
} {/* AIS cross-reference data */} {aisMatch && (
AIS CROSS-REFERENCE
{aisMatch.mmsi &&
MMSI: {aisMatch.mmsi}
} {aisMatch.callsign &&
Callsign: {aisMatch.callsign}
} {aisMatch.type &&
Vessel Type: {aisMatch.type}
} {aisMatch.destination &&
Destination: {aisMatch.destination}
} {aisMatch.sog > 0 &&
Speed: {aisMatch.sog} kts
} {aisMatch.cog > 0 &&
Course: {Math.round(aisMatch.cog)}°
} {aisMatch.country &&
Country: {aisMatch.country}
} {aisMatch.imo &&
IMO: {aisMatch.imo}
}
)}
FISHING — GLOBAL FISHING WATCH {aisMatch && + AIS}
); })()} {/* Fishing vessel → AIS destination route line */} {selectedEntity?.type === 'fishing_event' && (() => { const event = data?.fishing_activity?.find((e) => (e.id || '') === selectedEntity.id); if (!event) return null; const vesselNameUpper = (event.vessel_name || '').toUpperCase().trim(); if (!vesselNameUpper) return null; const aisMatch = data?.ships?.find((s) => { const shipName = (s.name || '').toUpperCase().trim(); return shipName && (shipName === vesselNameUpper || shipName.includes(vesselNameUpper) || vesselNameUpper.includes(shipName)); }); const dest = aisMatch?.destination; if (!dest || dest === 'UNKNOWN') return null; return ; })()} {(() => { if (selectedEntity?.type !== 'gdelt' || !data?.gdelt) return null; const item = data.gdelt.find( (g) => (g.properties?.name || String(g.geometry?.coordinates)) === selectedEntity.id, ); if (!item?.geometry?.coordinates) return null; return ( onEntityClick?.(null)} anchor="bottom" offset={15} >

NEWS ON THE GROUND

LOCATION {item.properties?.name || 'UNKNOWN REGION'}
{/* Enriched GDELT fields */} {item.properties?.event_date && (
DATE {String(item.properties.event_date).replace(/(\d{4})(\d{2})(\d{2})/, '$1-$2-$3')}
)} {((item.properties?.actors?.length ?? 0) > 0) && (
ACTORS {item.properties.actors!.join(' vs ')}
)} {item.properties?.goldstein != null && item.properties.goldstein !== 0 && (
INTENSITY {item.properties.goldstein > 0 ? '+' : ''}{item.properties.goldstein} Goldstein
)}
EVENTS {item.properties?.count || 1}
{(item.properties?.num_sources ?? 0) > 0 && (
SOURCES {item.properties.num_sources}
)} {(item.properties?.num_articles ?? 0) > 0 && (
ARTICLES {item.properties.num_articles}
)}
LATEST REPORTS: ({(item.properties?._urls_list || []).length})
{(() => { const urls: string[] = item.properties?._urls_list || []; const headlines: string[] = item.properties?._headlines_list || []; const snippets: string[] = item.properties?._snippets_list || []; if (urls.length === 0) return ( No articles available. ); return urls.map((url: string, idx: number) => { const headline = headlines[idx] || ''; const snippet = snippets[idx] || ''; let domain = ''; try { domain = new URL(url).hostname.replace('www.', ''); } catch { domain = ''; } return ( e.stopPropagation()} className="block py-2 border-b border-[var(--border-primary)]/50 last:border-0 cursor-pointer group" style={{ pointerEvents: 'all' }} > {headline || domain || 'View Article'} {snippet && ( {snippet} )} {domain && ( {domain} )} ); }); })()}
); })()} {selectedEntity?.type === 'liveuamap' && data?.liveuamap?.find((l) => String(l.id) === String(selectedEntity.id)) && (() => { const item = data.liveuamap.find((l) => String(l.id) === String(selectedEntity.id)); if (!item) return null; return ( onEntityClick?.(null)} anchor="bottom" offset={15} >

REGIONAL TACTICAL EVENT

{item.title}
{item.description && (
{item.description}
)}
REGION {item.region || 'Unknown'}
TIME {item.date || (item.timestamp ? new Date(Number(item.timestamp) * 1000).toLocaleString() : 'UNKNOWN')}
{item.category && (
TYPE {item.category}
)} {item.source && (
SOURCE {item.source}
)} {item.link && ( )} {oracleIntel?.found && (
ORACLE INTEL
{oracleIntel.tier} {' // '} {oracleIntel.avg_sentiment != null ? `${oracleIntel.avg_sentiment > 0 ? '+' : ''}${oracleIntel.avg_sentiment.toFixed(2)} SENT` : ''} {oracleIntel.market && ( {' // '}{oracleIntel.market.consensus_pct}% )}
{oracleIntel.top_headline && (
{oracleIntel.top_headline}
)}
)}
); })()} {/* ── THREAT INTERCEPT — fullscreen intelligence dossier modal ── */} {(() => { if (selectedEntity?.type !== 'news' || !data?.news) return null; const item = data.news.find((n: any) => { const key = (n as any).alertKey || `${n.title}|${n.coords?.[0]},${n.coords?.[1]}`; return key === selectedEntity.id; }) as any; if (!item) return null; const rs = item.risk_score ?? 0; let threatHex = '#eab308'; let threatColor = 'text-yellow-400'; let borderColor = 'border-yellow-800'; let bgHeaderColor = 'bg-yellow-950/50'; if (rs >= 8) { threatHex = '#ef4444'; threatColor = 'text-red-400'; borderColor = 'border-red-700'; bgHeaderColor = 'bg-red-950/50'; } else if (rs <= 4) { threatHex = '#22c55e'; threatColor = 'text-green-400'; borderColor = 'border-green-800'; bgHeaderColor = 'bg-green-950/50'; } const sent = item.sentiment as number | undefined; const oScore = item.oracle_score as number | undefined; const oTier = oScore != null ? (oScore >= 8 ? 'CRITICAL' : oScore >= 6 ? 'ELEVATED' : oScore >= 4 ? 'MODERATE' : 'LOW') : null; const oTierColor = oScore != null ? (oScore >= 8 ? 'text-red-400' : oScore >= 6 ? 'text-orange-400' : oScore >= 4 ? 'text-yellow-400' : 'text-green-400') : ''; const oTierBg = oScore != null ? (oScore >= 8 ? 'bg-red-500/10 border-red-500/30' : oScore >= 6 ? 'bg-orange-500/10 border-orange-500/30' : oScore >= 4 ? 'bg-yellow-500/10 border-yellow-500/30' : 'bg-green-500/10 border-green-500/30') : ''; const sentColor = sent != null ? (sent < -0.1 ? 'text-red-400' : sent > 0.1 ? 'text-green-400' : 'text-gray-400') : ''; const sentBg = sent != null ? (sent < -0.1 ? 'bg-red-500/10 border-red-500/30' : sent > 0.1 ? 'bg-green-500/10 border-green-500/30' : 'bg-gray-500/10 border-gray-500/30') : ''; const sentArrow = sent != null ? (sent < -0.1 ? '▼' : sent > 0.1 ? '▲' : '—') : ''; const sentLabel = sent != null ? (sent < -0.1 ? 'NEGATIVE' : sent > 0.1 ? 'POSITIVE' : 'NEUTRAL') : ''; const pred = item.prediction_odds as any; const articles = (item.articles as any[]) || []; const clusterCount = (item.cluster_count as number) || 1; const isBreaking = item.breaking === true; return (
{ if (e.target === e.currentTarget) onEntityClick?.(null); }} onKeyDown={(e: React.KeyboardEvent) => { if (e.key === 'Escape') onEntityClick?.(null); }} tabIndex={-1} ref={(el) => el?.focus()} >
{/* ══════ HEADER ══════ */}
{isBreaking ? 'BREAKING INTERCEPT' : 'THREAT INTERCEPT'} {isBreaking && LIVE}
= 8 ? 'animate-pulse' : ''}`}> ALERT LVL: {rs}/10
{/* ══════ SCROLLABLE BODY ══════ */}
{/* ── HEADLINE ── */}

{item.title}

{item.source || 'UNKNOWN'} {item.published && • {item.published}} {clusterCount > 1 && • {clusterCount} SOURCES REPORTING} {item.coords && ( {item.coords[0].toFixed(3)}°, {item.coords[1].toFixed(3)}° )}
{/* ── INTEL GRID: Oracle + Sentiment + Risk ── */}
{/* Oracle Score */} {/* Sentiment */} {/* Threat Level */}
{/* ── PREDICTION MARKET ANALYSIS ── */} {pred && pred.consensus_pct != null && (
PREDICTION MARKET ANALYSIS
{pred.polymarket_pct != null && ( )}
"{pred.title}"
{/* Progress bar */}
{pred.consensus_pct}% CONSENSUS PROBABILITY
{pred.polymarket_pct != null && ( )} {pred.kalshi_pct != null && (
Kalshi {pred.kalshi_pct}%
)} {pred.match_score != null && ( headline match: {(pred.match_score * 100).toFixed(0)}% )}
)} {/* ── SYS.ANALYSIS ── */} {item.machine_assessment && (
>_ SYS.ANALYSIS: {item.machine_assessment}
)} {/* ── CORROBORATING SOURCES ── */} {articles.length > 1 && (
CORROBORATING SOURCES ({articles.length})
{articles.map((sub: any, si: number) => { const subRs = sub.risk_score ?? 0; const subColor = subRs >= 8 ? 'text-red-400' : subRs >= 6 ? 'text-orange-400' : subRs >= 4 ? 'text-yellow-400' : 'text-green-400'; return (
sub.link && window.open(sub.link, '_blank', 'noopener,noreferrer')} onKeyDown={(e) => { if (e.key === 'Enter' && sub.link) window.open(sub.link, '_blank', 'noopener,noreferrer'); }} className="flex items-start gap-3 py-2 px-3 border-l-2 border-cyan-800/40 bg-black/30 rounded-r hover:bg-cyan-950/30 transition-colors group cursor-pointer" >
{sub.source} LVL: {subRs}/10 {sub.published && {sub.published}}
{sub.title}
); })}
)} {/* ── FOOTER ── */}
{item.link ? ( ) : }
); })()} {/* REGION DOSSIER — location pin on map (full intel shown in right panel) */} {selectedEntity?.type === 'region_dossier' && selectedEntity.extra && (
{/* Pulsing ring */}
{/* Pin dot */}
{/* Label */}
{regionDossierLoading ? 'COMPILING...' : '▶ INTEL TARGET'}
)} {/* SENTINEL-2 IMAGERY — fullscreen overlay modal */} {selectedEntity?.type === 'region_dossier' && selectedEntity.extra && regionDossier?.sentinel2 && ( onEntityClick(null)} /> )} {/* OPTIC INTERCEPT — fullscreen CCTV camera modal */} {selectedEntity?.type === 'cctv' && (() => { const props = (selectedEntity.extra || {}) as Record; const rawUrl = String(selectedEntity.media_url || props.media_url || ''); const mt = String(props.media_type || ( rawUrl.includes('.mp4') || rawUrl.includes('.webm') ? 'video' : rawUrl.includes('.m3u8') || rawUrl.includes('hls') ? 'hls' : rawUrl.includes('.mjpg') || rawUrl.includes('.mjpeg') || rawUrl.includes('mjpg') ? 'mjpeg' : 'image' )); // Proxy external URLs through backend to bypass CORS const url = buildCctvProxyUrl(rawUrl); const isVideo = mt === 'video' || mt === 'hls'; const cameraName = String(selectedEntity.name || props.name || 'UNKNOWN MOUNT').toUpperCase(); const sourceAgency = String(props.source_agency || 'CCTV').toUpperCase(); return ( onEntityClick(null)} /> ); })()} {/* ── AI Intel Pin Detail popup ── */} {openPinDetailId && ( setOpenPinDetailId(null)} onDeleted={() => { setOpenPinDetailId(null); setAiIntelRefreshTick((t) => t + 1); onPinPlaced?.(); }} onUpdated={() => setAiIntelRefreshTick((t) => t + 1)} /> )} {/* ── Pin Placement Dialog (offset marker + connecting line) ── */} {pendingPin && (
e.stopPropagation()} onMouseDown={(e) => e.stopPropagation()} onKeyDown={(e) => { // Prevent global hotkeys (l/r/m/s/k/f/space) from firing while // typing in the pin dialog — the maplibre canvas is still in // the document and document-level listeners otherwise fire. e.stopPropagation(); e.nativeEvent.stopImmediatePropagation(); }} onKeyUp={(e) => { e.stopPropagation(); e.nativeEvent.stopImmediatePropagation(); }} > {/* Connecting line + dot at actual pin location */} {/* Arrow triangle pointing down to pin */}
{/* Dialog box */}
{/* Close button */}
{pendingPin.entity ? 'PIN TO ENTITY' : 'PIN TO LOCATION'}
{pendingPin.entity && (
Tracking: {pendingPin.entity.entity_label || pendingPin.entity.entity_id} ({pendingPin.entity.entity_type})
)} {/* Category selector */} setPinLabel(e.target.value)} placeholder="Label..." autoFocus className="w-full px-2 py-1.5 text-[12px] font-mono bg-black/50 border border-violet-500/30 text-white placeholder:text-gray-600 focus:border-violet-500/60 outline-none mb-1.5" onKeyDown={(e) => { e.stopPropagation(); e.nativeEvent.stopImmediatePropagation(); if (e.key === 'Enter' && pinLabel.trim()) { e.preventDefault(); handleSavePin(); } if (e.key === 'Escape') { setPendingPin(null); setPinLabel(''); setPinNotes(''); setPinCategory('custom'); } }} />