"use client" import { useEffect, useMemo } from "react" import { Layer, Source, useMap, Popup } from "react-map-gl/mapbox" import { useState } from "react" import { IGeoJSONPolygon } from "@/app/_utils/types/map" import { CRIME_COLORS, CRIME_RATES } from "@/app/_utils/const/crime" export type DistrictFeature = { id: string name: string cityName: string code: string polygon: IGeoJSONPolygon crimeRate: "low" | "medium" | "high" | "no_data" crimeCount: number year: number } type DistrictLayerProps = { data: DistrictFeature[] visible?: boolean onClick?: (feature: any) => void } type hoverInfoType = { feature: { properties: { crimeRate: "low" | "medium" | "high" | "no_data" name: string cityName: string crimeCount: number } geometry: { coordinates: number[][][] } } x: number y: number } export default function DistrictLayer({ data, visible = true, onClick }: DistrictLayerProps) { const { current: map } = useMap() const [hoverInfo, setHoverInfo] = useState(null) // Convert data to GeoJSON const geojson = useMemo(() => { return { type: "FeatureCollection", features: data .filter((district) => district.polygon) // Only include districts with polygon data .map((district) => ({ type: "Feature", properties: { id: district.id, name: district.name, cityName: district.cityName, crimeRate: district.crimeRate, crimeCount: district.crimeCount, color: CRIME_COLORS[district.crimeRate], }, geometry: district.polygon, })), } }, [data]) // Handle hover events useEffect(() => { if (!map) return const onHover = (event: any) => { const { features, point } = event const hoveredFeature = features && features[0] // Update hover state setHoverInfo( hoveredFeature ? { feature: hoveredFeature, x: point.x, y: point.y, } : null, ) } // Change cursor on hover const onMouseEnter = () => { if (map) map.getCanvas().style.cursor = "pointer" } const onMouseLeave = () => { if (map) map.getCanvas().style.cursor = "" setHoverInfo(null) } // Add event listeners map.on("mousemove", "district-fills", onHover) map.on("mouseenter", "district-fills", onMouseEnter) map.on("mouseleave", "district-fills", onMouseLeave) map.on("click", "district-fills", (e) => { if (onClick && e.features && e.features[0]) { onClick(e.features[0]) } }) // Clean up return () => { map.off("mousemove", "district-fills", onHover) map.off("mouseenter", "district-fills", onMouseEnter) map.off("mouseleave", "district-fills", onMouseLeave) map.off("click", "district-fills", onClick as any) } }, [map, onClick]) if (!visible) return null return ( <> {/* Popup on hover */} {hoverInfo && (

{hoverInfo.feature.properties.name}

City: {hoverInfo.feature.properties.cityName}

Crime Rate: {CRIME_RATES[hoverInfo.feature.properties.crimeRate]}

Crime Count: {hoverInfo.feature.properties.crimeCount}

)} ) }