({
markets,
activeCategories,
flyToTarget,
timeRange,
onTimeRangeChange,
onToggleCategory,
onToggleFullscreen,
isFullscreen,
onMarketClick,
onCountryClick,
selectedCountry,
selectedMarketId,
colorMode = "category",
onColorModeChange,
region,
onRegionChange,
isWatched,
onToggleWatch,
newMarkets,
whaleTrades,
activeLayers,
onToggleLayer,
onTrade,
onMapTap,
}: WorldMapProps)
| 222 | } |
| 223 | |
| 224 | function WorldMapInner({ |
| 225 | markets, |
| 226 | activeCategories, |
| 227 | flyToTarget, |
| 228 | timeRange, |
| 229 | onTimeRangeChange, |
| 230 | onToggleCategory, |
| 231 | onToggleFullscreen, |
| 232 | isFullscreen, |
| 233 | onMarketClick, |
| 234 | onCountryClick, |
| 235 | selectedCountry, |
| 236 | selectedMarketId, |
| 237 | colorMode = "category", |
| 238 | onColorModeChange, |
| 239 | region, |
| 240 | onRegionChange, |
| 241 | isWatched, |
| 242 | onToggleWatch, |
| 243 | newMarkets, |
| 244 | whaleTrades, |
| 245 | activeLayers, |
| 246 | onToggleLayer, |
| 247 | onTrade, |
| 248 | onMapTap, |
| 249 | }: WorldMapProps) { |
| 250 | const { locale, t } = useI18n(); |
| 251 | const mapContainer = useRef<HTMLDivElement>(null); |
| 252 | const mapRef = useRef<maplibregl.Map | null>(null); |
| 253 | |
| 254 | const [mapReady, setMapReady] = useState(false); |
| 255 | const [currentTier, setCurrentTier] = useState(() => zoomToTier(1.2)); |
| 256 | const marketsLookup = useRef<Map<string, ProcessedMarket>>(new Map()); |
| 257 | const countryLayersAdded = useRef(false); |
| 258 | const pulseRef = useRef<number>(0); |
| 259 | |
| 260 | const newMarketAnimRef = useRef<Map<string, { startTime: number; lng: number; lat: number }>>(new Map()); |
| 261 | |
| 262 | const tradeFlashesRef = useRef<{ key: string; lng: number; lat: number; startTime: number; side: "BUY" | "SELL"; isSmart: boolean }[]>([]); |
| 263 | const seenTradeKeysRef = useRef<Set<string>>(new Set()); |
| 264 | const prevMarketIdsRef = useRef<Map<string, { lng: number; lat: number; color: string }>>(new Map()); |
| 265 | const prevTierRef = useRef<number>(0); |
| 266 | const closedAnimsRef = useRef<Map<string, { startTime: number; lng: number; lat: number; color: string }>>(new Map()); |
| 267 | const reducedMotionCleanup = useRef<(() => void) | null>(null); |
| 268 | const overlayFetched = useRef<Set<OverlayLayer>>(new Set()); |
| 269 | const overlayBurstRef = useRef<{ lng: number; lat: number; startTime: number; color: string }[]>([]); |
| 270 | const [layerAlert, setLayerAlert] = useState<{ emoji: string; label: string; count: number; color: string } | null>(null); |
| 271 | const layerAlertTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null); |
| 272 | |
| 273 | const OVERLAY_META: Partial<Record<OverlayLayer, { emoji: string; label: string; color: string }>> = { |
| 274 | conflicts: { emoji: "💥", label: "conflict zones", color: "#ef4444" }, |
| 275 | intel: { emoji: "🔍", label: "intel hotspots", color: "#a855f7" }, |
| 276 | military: { emoji: "✈️", label: "military flights", color: "#22d3ee" }, |
| 277 | weather: { emoji: "🌩️", label: "weather alerts", color: "#f59e0b" }, |
| 278 | natural: { emoji: "🌍", label: "natural events", color: "#f97316" }, |
| 279 | fires: { emoji: "🔥", label: "fires", color: "#ff6b35" }, |
| 280 | elections: { emoji: "🗳️", label: "elections", color: "#fbbf24" }, |
| 281 | outages: { emoji: "📡", label: "internet outages", color: "#e879f9" }, |
nothing calls this directly
no test coverage detected