import { Layer, Source } from "react-map-gl/mapbox"; import { useMemo, useEffect } from "react"; import { ICrimes } from "@/app/_utils/types/crimes"; import { manageLayerVisibility } from "@/app/_utils/map/layer-visibility"; import type mapboxgl from "mapbox-gl"; interface HeatmapLayerProps { crimes: ICrimes[]; year: string; month: string; filterCategory: string | "all"; visible?: boolean; useAllData?: boolean; enableInteractions?: boolean; setFocusedDistrictId?: (id: string | null, isMarkerClick?: boolean) => void; map?: mapboxgl.Map | null; } export default function HeatmapLayer({ crimes, visible = true, useAllData = false, filterCategory, year, month, enableInteractions = true, setFocusedDistrictId, map }: HeatmapLayerProps) { // Define layer IDs for consistent management const LAYER_IDS = ['crime-heatmap']; // Convert crime data to GeoJSON format for the heatmap const heatmapData = useMemo(() => { const features = crimes.flatMap(crime => crime.crime_incidents .filter(incident => { // Enhanced filtering logic if (!incident.locations?.latitude || !incident.locations?.longitude) { return false; } // Filter by category if specified if (filterCategory !== "all" && incident.crime_categories?.name !== filterCategory) { return false; } // Filter by year and month if not using all data if (!useAllData && year && month) { const incidentDate = new Date(incident.timestamp); const incidentYear = incidentDate.getFullYear().toString(); const incidentMonth = (incidentDate.getMonth() + 1).toString(); if (incidentYear !== year || incidentMonth !== month) { return false; } } return true; }) .map(incident => ({ type: "Feature" as const, properties: { id: incident.id, category: incident.crime_categories?.name || "Unknown", intensity: 1, // Base intensity value timestamp: incident.timestamp ? new Date(incident.timestamp).getTime() : null, districtId: crime.district_id // Add district ID for potential interactions }, geometry: { type: "Point" as const, coordinates: [incident.locations!.longitude, incident.locations!.latitude], }, })) ); return { type: "FeatureCollection" as const, features, }; }, [crimes, filterCategory, useAllData, year, month]); // Manage layer visibility useEffect(() => { if (!map) return; return manageLayerVisibility(map, LAYER_IDS, visible); }, [map, visible]); if (!visible) return null; return ( ); }