From 834d4b02cff20d9e1ea5f050a2027effd8395485 Mon Sep 17 00:00:00 2001 From: vergiLgood1 Date: Wed, 14 May 2025 08:56:08 +0700 Subject: [PATCH] feat: Enhance unit popup to display nearby incidents and loading state --- .../_components/map/layers/units-layer.tsx | 49 ++++++++++++++++- .../app/_components/map/pop-up/unit-popup.tsx | 54 ++++++++----------- 2 files changed, 69 insertions(+), 34 deletions(-) diff --git a/sigap-website/app/_components/map/layers/units-layer.tsx b/sigap-website/app/_components/map/layers/units-layer.tsx index 50036d2..be7b369 100644 --- a/sigap-website/app/_components/map/layers/units-layer.tsx +++ b/sigap-website/app/_components/map/layers/units-layer.tsx @@ -18,6 +18,14 @@ interface UnitsLayerProps { map?: mapboxgl.Map | null } +interface IDistrictIncidents { + incident_id: string + category_name: string + incident_description: string + distance_meters: number + timestamp: Date +} + export default function UnitsLayer({ crimes, units = [], filterCategory, visible = false, map }: UnitsLayerProps) { const [loadedUnits, setLoadedUnits] = useState([]) const loadedUnitsRef = useRef([]) @@ -28,6 +36,8 @@ export default function UnitsLayer({ crimes, units = [], filterCategory, visible const [selectedEntityId, setSelectedEntityId] = useState() const [isUnitSelected, setIsUnitSelected] = useState(false) const [selectedDistrictId, setSelectedDistrictId] = useState() + const [unitIncident, setUnitIncident] = useState([]) + const [isLoading, setIsLoading] = useState(false) // Use either provided units or loaded units const unitsData = useMemo(() => { @@ -230,6 +240,39 @@ export default function UnitsLayer({ crimes, units = [], filterCategory, visible return; } + + // Find all incidents in the same district as the unit + const districtIncidents: IDistrictIncidents[] = [] + crimes.forEach(crime => { + // Check if this crime is in the same district as the unit + + console.log("Checking district ID:", crime.district_id, "against unit district ID:", unit.district_id); + + if (crime.districts.name === unit.district_name) { + crime.crime_incidents.forEach(incident => { + if (incident.locations && typeof incident.locations.distance_to_unit !== 'undefined') { + districtIncidents.push({ + incident_id: incident.id, + category_name: incident.crime_categories.name, + incident_description: incident.description || 'No description', + distance_meters: incident.locations.distance_to_unit!, + timestamp: incident.timestamp + }) + } + }) + } + }) + + // Sort by distance (closest first) + districtIncidents.sort((a, b) => a.distance_meters - b.distance_meters) + + + console.log("Sorted district incidents:", districtIncidents); + + // Update the state with the distance results + setUnitIncident(districtIncidents) + + // Fly to the unit location map.flyTo({ center: [unit.longitude || 0, unit.latitude || 0], @@ -266,7 +309,7 @@ export default function UnitsLayer({ crimes, units = [], filterCategory, visible map.getCanvas().dispatchEvent(customEvent) document.dispatchEvent(customEvent) }, - [], + [crimes], // Add crimes as a dependency ) // Handle incident click @@ -441,6 +484,8 @@ export default function UnitsLayer({ crimes, units = [], filterCategory, visible setSelectedIncident(null) setSelectedEntityId(undefined) setSelectedDistrictId(undefined) + setUnitIncident([]) + setIsLoading(false) if (map && map.getLayer("units-connection-lines")) { map.setFilter("units-connection-lines", ["has", "unit_id"]) @@ -540,6 +585,8 @@ export default function UnitsLayer({ crimes, units = [], filterCategory, visible district: selectedUnit.district_name || "No district", district_id: selectedUnit.district_id, }} + incidents={unitIncident} + isLoadingIncidents={isLoading} /> )} diff --git a/sigap-website/app/_components/map/pop-up/unit-popup.tsx b/sigap-website/app/_components/map/pop-up/unit-popup.tsx index 83ab2b5..38a6181 100644 --- a/sigap-website/app/_components/map/pop-up/unit-popup.tsx +++ b/sigap-website/app/_components/map/pop-up/unit-popup.tsx @@ -23,17 +23,26 @@ interface UnitPopupProps { district?: string district_id?: string } - distances?: IDistanceResult[] - isLoadingDistances?: boolean + incidents?: IDistrictIncidents[] + isLoadingIncidents?: boolean } +interface IDistrictIncidents { + incident_id: string + category_name: string + incident_description: string + distance_meters: number + timestamp: Date +} + + export default function UnitPopup({ longitude, latitude, onClose, unit, - distances = [], - isLoadingDistances = false + incidents = [], + isLoadingIncidents = false }: UnitPopupProps) { // Format distance to be more readable @@ -53,12 +62,12 @@ export default function UnitPopup({ closeOnClick={false} onClose={onClose} anchor="top" - maxWidth="320px" + maxWidth="420px" className="unit-popup z-50" >
{/* Custom close button */} @@ -114,7 +123,7 @@ export default function UnitPopup({ )}
- {/* Distances to incidents section */} + {/* Incidents to incidents section */}
@@ -123,16 +132,16 @@ export default function UnitPopup({ Nearby Incidents - {isLoadingDistances ? ( + {isLoadingIncidents ? (
- ) : distances.length > 0 ? ( + ) : incidents.length > 0 ? (
- {distances.map((item) => ( + {incidents.map((item) => (

{item.category_name || "Unknown"}

@@ -140,7 +149,7 @@ export default function UnitPopup({ {item.incident_description || "No description"}

- + {formatDistance(item.distance_meters)}
@@ -163,28 +172,7 @@ export default function UnitPopup({
- {/* Connection line */} -
- {/* Connection dot */} -
+
)