import { Layer, Source } from "react-map-gl/mapbox"; import { useMemo } from "react"; import { ICrimes } from "@/app/_utils/types/crimes"; interface HeatmapLayerProps { crimes: ICrimes[]; year: string; month: string; filterCategory: string | "all"; visible?: boolean; useAllData?: boolean; enableInteractions?: boolean; // Add new prop setFocusedDistrictId?: (id: string | null, isMarkerClick?: boolean) => void; // Add new prop } export default function HeatmapLayer({ crimes, visible = true, useAllData = false, filterCategory, year, month, enableInteractions = true, setFocusedDistrictId }: HeatmapLayerProps) { // 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]); if (!visible) return null; // The heatmap layer doesn't generally support direct interactions like clicks, // but we're including the props to maintain consistency with other layers // and to support future interaction patterns if needed return ( ); }