"use client" import { createFillColorExpression, processDistrictFeature } from "@/app/_utils/map" import { IDistrictLayerProps } from "@/app/_utils/types/map" import { useEffect } from "react" export default function DistrictFillLineLayer({ visible = true, map, onClick, year, month, filterCategory = "all", crimes = [], tilesetId, focusedDistrictId, setFocusedDistrictId, crimeDataByDistrict, }: IDistrictLayerProps) { useEffect(() => { if (!map || !visible) return const handleDistrictClick = (e: any) => { const incidentFeatures = map.queryRenderedFeatures(e.point, { layers: ["unclustered-point", "clusters"], }) if (incidentFeatures && incidentFeatures.length > 0) { return } if (!map || !e.features || e.features.length === 0) return const feature = e.features[0] const districtId = feature.properties.kode_kec // If clicking the same district, deselect it if (focusedDistrictId === districtId) { setFocusedDistrictId(null) // Reset pitch and bearing with animation map.easeTo({ pitch: 0, bearing: 0, duration: 1500, easing: (t) => t * (2 - t), // easeOutQuad }) // Restore fill color for all districts when unfocusing const fillColorExpression = createFillColorExpression(null, crimeDataByDistrict) map.setPaintProperty("district-fill", "fill-color", fillColorExpression as any) // Show all clusters again when unfocusing if (map.getLayer("clusters")) { map.setLayoutProperty("clusters", "visibility", "visible") } if (map.getLayer("unclustered-point")) { map.setLayoutProperty("unclustered-point", "visibility", "visible") } return } else if (focusedDistrictId) { // If we're already focusing on a district and clicking a different one, // we need to reset the current one and move to the new one setFocusedDistrictId(null) // Wait a moment before selecting the new district to ensure clean transitions setTimeout(() => { const district = processDistrictFeature(feature, e, districtId, crimeDataByDistrict, crimes, year, month) if (!district) return setFocusedDistrictId(district.id) // Fly to the new district map.flyTo({ center: [district.longitude, district.latitude], zoom: 14.5, pitch: 75, bearing: 0, duration: 1500, easing: (t) => t * (2 - t), // easeOutQuad }) if (onClick) { onClick(district) } }, 100) return } const district = processDistrictFeature(feature, e, districtId, crimeDataByDistrict, crimes, year, month) if (!district) return // Set the fill color expression immediately to show the focus const focusedFillColorExpression = createFillColorExpression(district.id, crimeDataByDistrict) map.setPaintProperty("district-fill", "fill-color", focusedFillColorExpression as any) setFocusedDistrictId(district.id) // Hide clusters when focusing on a district if (map.getLayer("clusters")) { map.setLayoutProperty("clusters", "visibility", "none") } if (map.getLayer("unclustered-point")) { map.setLayoutProperty("unclustered-point", "visibility", "none") } // Animate to a pitched view focused on the district map.flyTo({ center: [district.longitude, district.latitude], zoom: 14.5, pitch: 75, bearing: 0, duration: 1500, easing: (t) => t * (2 - t), // easeOutQuad }) if (onClick) { onClick(district) } } const onStyleLoad = () => { if (!map) return try { if (!map.getSource("districts")) { const layers = map.getStyle().layers let firstSymbolId: string | undefined for (const layer of layers) { if (layer.type === "symbol") { firstSymbolId = layer.id break } } map.addSource("districts", { type: "vector", url: `mapbox://${tilesetId}`, }) const fillColorExpression = createFillColorExpression(focusedDistrictId, crimeDataByDistrict) if (!map.getLayer("district-fill")) { map.addLayer( { id: "district-fill", type: "fill", source: "districts", "source-layer": "Districts", paint: { "fill-color": fillColorExpression as any, "fill-opacity": 0.6, }, }, firstSymbolId, ) } if (!map.getLayer("district-line")) { map.addLayer( { id: "district-line", type: "line", source: "districts", "source-layer": "Districts", paint: { "line-color": "#ffffff", "line-width": 1, "line-opacity": 0.5, }, }, firstSymbolId, ) } map.on("mouseenter", "district-fill", () => { map.getCanvas().style.cursor = "pointer" }) map.on("mouseleave", "district-fill", () => { map.getCanvas().style.cursor = "" }) map.off("click", "district-fill", handleDistrictClick) map.on("click", "district-fill", handleDistrictClick) } else { if (map.getLayer("district-fill")) { const fillColorExpression = createFillColorExpression(focusedDistrictId, crimeDataByDistrict) map.setPaintProperty("district-fill", "fill-color", fillColorExpression as any) } } } catch (error) { console.error("Error adding district layers:", error) } } if (map.isStyleLoaded()) { onStyleLoad() } else { map.once("style.load", onStyleLoad) } return () => { if (map) { map.off("click", "district-fill", handleDistrictClick) } } }, [ map, visible, tilesetId, crimes, filterCategory, year, month, focusedDistrictId, crimeDataByDistrict, onClick, setFocusedDistrictId, ]) // Add an effect to update the fill color whenever focusedDistrictId changes useEffect(() => { if (!map || !map.getLayer("district-fill")) return; try { const fillColorExpression = createFillColorExpression(focusedDistrictId, crimeDataByDistrict) map.setPaintProperty("district-fill", "fill-color", fillColorExpression as any) } catch (error) { console.error("Error updating district fill colors:", error) } }, [map, focusedDistrictId, crimeDataByDistrict]) return null }