feat: enhance district layer and popup with improved data handling and logging
This commit is contained in:
parent
0d6f9acf66
commit
fdc0403b81
|
@ -105,25 +105,6 @@ export default function CrimeMap() {
|
|||
})
|
||||
}, [filteredByYearAndMonth, selectedCategory])
|
||||
|
||||
// Extract all incidents from all districts for marker display
|
||||
// const allIncidents = useMemo(() => {
|
||||
// if (!filteredCrimes) return []
|
||||
|
||||
// return filteredCrimes.flatMap((crime) =>
|
||||
// crime.crime_incidents.map((incident) => ({
|
||||
// id: incident.id,
|
||||
// timestamp: incident.timestamp,
|
||||
// description: incident.description,
|
||||
// status: incident.status,
|
||||
// category: incident.crime_categories.name,
|
||||
// type: incident.crime_categories.type,
|
||||
// address: incident.locations.address,
|
||||
// latitude: incident.locations.latitude,
|
||||
// longitude: incident.locations.longitude,
|
||||
// }))
|
||||
// )
|
||||
// }, [filteredCrimes])
|
||||
|
||||
// Handle incident marker click
|
||||
const handleIncidentClick = (incident: CrimeIncident) => {
|
||||
console.log("Incident clicked directly:", incident);
|
||||
|
@ -184,10 +165,12 @@ export default function CrimeMap() {
|
|||
|
||||
// Handle district click
|
||||
const handleDistrictClick = (feature: DistrictFeature) => {
|
||||
console.log("District clicked in CrimeMap:", feature.name);
|
||||
|
||||
// When a district is clicked, clear any selected incident
|
||||
setSelectedIncident(null);
|
||||
|
||||
// Set the selected district
|
||||
// Set the selected district (for the sidebar or other components)
|
||||
setSelectedDistrict(feature);
|
||||
}
|
||||
|
||||
|
@ -250,7 +233,16 @@ export default function CrimeMap() {
|
|||
!sidebarCollapsed && isFullscreen && "ml-[400px]"
|
||||
)}>
|
||||
<MapView mapStyle="mapbox://styles/mapbox/dark-v11" className="h-[600px] w-full rounded-md">
|
||||
{/* District Layer with crime data */}
|
||||
{/* District Layer with crime data - don't pass onClick if we want internal popup */}
|
||||
<DistrictLayer
|
||||
crimes={filteredCrimes || []}
|
||||
year={selectedYear.toString()}
|
||||
month={selectedMonth.toString()}
|
||||
filterCategory={selectedCategory}
|
||||
/>
|
||||
|
||||
{/* Pass onClick if you want to handle districts externally */}
|
||||
{/*
|
||||
<DistrictLayer
|
||||
onClick={handleDistrictClick}
|
||||
crimes={filteredCrimes || []}
|
||||
|
@ -258,6 +250,7 @@ export default function CrimeMap() {
|
|||
month={selectedMonth.toString()}
|
||||
filterCategory={selectedCategory}
|
||||
/>
|
||||
*/}
|
||||
|
||||
{/* Popup for selected incident */}
|
||||
{selectedIncident && selectedIncident.latitude && selectedIncident.longitude && (
|
||||
|
|
|
@ -12,7 +12,6 @@ import { ICrimes } from "@/app/_utils/types/crimes"
|
|||
export interface DistrictFeature {
|
||||
id: string
|
||||
name: string
|
||||
properties: Record<string, any>
|
||||
longitude: number
|
||||
latitude: number
|
||||
number_of_crime: number
|
||||
|
@ -45,56 +44,14 @@ export interface DistrictFeature {
|
|||
selectedMonth?: string
|
||||
}
|
||||
|
||||
// Updated interface to match the structure in crimes.ts
|
||||
// export interface ICrimeData {
|
||||
// id: string
|
||||
// district_id: string
|
||||
// districts: {
|
||||
// name: string
|
||||
// geographics: {
|
||||
// address: string | null
|
||||
// land_area: number | null
|
||||
// year: number | null
|
||||
// latitude: number
|
||||
// longitude: number
|
||||
// }[]
|
||||
// demographics: {
|
||||
// number_of_unemployed: number
|
||||
// population: number
|
||||
// population_density: number
|
||||
// year: number
|
||||
// }[]
|
||||
// }
|
||||
// number_of_crime: number
|
||||
// level: $Enums.crime_rates
|
||||
// score: number
|
||||
// month: number
|
||||
// year: number
|
||||
// crime_incidents: Array<{
|
||||
// id: string
|
||||
// timestamp: Date
|
||||
// description: string
|
||||
// status: string
|
||||
// crime_categories: {
|
||||
// name: string
|
||||
// type: string | null
|
||||
// }
|
||||
// locations: {
|
||||
// address: string | null
|
||||
// latitude: number
|
||||
// longitude: number
|
||||
// }
|
||||
// }>
|
||||
// }
|
||||
|
||||
// District layer props
|
||||
export interface DistrictLayerProps {
|
||||
visible?: boolean
|
||||
onClick?: (feature: DistrictFeature) => void
|
||||
year?: string
|
||||
month?: string
|
||||
filterCategory?: string | "all"
|
||||
crimes?: ICrimes[]
|
||||
year: string
|
||||
month: string
|
||||
filterCategory: string | "all"
|
||||
crimes: ICrimes[]
|
||||
tilesetId?: string
|
||||
}
|
||||
|
||||
|
@ -179,8 +136,34 @@ export default function DistrictLayer({
|
|||
})
|
||||
|
||||
const firstDistrictCrime = districtCrimes.length > 0 ? districtCrimes[0] : null
|
||||
const demographics = firstDistrictCrime?.districts.demographics?.[0]
|
||||
const geographics = firstDistrictCrime?.districts.geographics?.[0]
|
||||
|
||||
const selectedYearNum = year ? parseInt(year) : new Date().getFullYear();
|
||||
|
||||
let demographics = firstDistrictCrime?.districts.demographics?.find(
|
||||
d => d.year === selectedYearNum
|
||||
);
|
||||
|
||||
if (!demographics && firstDistrictCrime?.districts.demographics?.length) {
|
||||
demographics = firstDistrictCrime.districts.demographics
|
||||
.sort((a, b) => b.year - a.year)[0];
|
||||
console.log(`Tidak ada data demografis untuk tahun ${selectedYearNum}, menggunakan data tahun ${demographics.year}`);
|
||||
}
|
||||
|
||||
let geographics = firstDistrictCrime?.districts.geographics?.find(
|
||||
g => g.year === selectedYearNum
|
||||
);
|
||||
|
||||
if (!geographics && firstDistrictCrime?.districts.geographics?.length) {
|
||||
const validGeographics = firstDistrictCrime.districts.geographics
|
||||
.filter(g => g.year !== null)
|
||||
.sort((a, b) => (b.year || 0) - (a.year || 0));
|
||||
|
||||
geographics = validGeographics.length > 0 ?
|
||||
validGeographics[0] :
|
||||
firstDistrictCrime.districts.geographics[0];
|
||||
|
||||
console.log(`Tidak ada data geografis untuk tahun ${selectedYearNum}, menggunakan data ${geographics.year ? `tahun ${geographics.year}` : 'tanpa tahun'}`);
|
||||
}
|
||||
|
||||
const clickLng = e.lngLat ? e.lngLat.lng : null
|
||||
const clickLat = e.lngLat ? e.lngLat.lat : null
|
||||
|
@ -198,7 +181,7 @@ export default function DistrictLayer({
|
|||
const district: DistrictFeature = {
|
||||
id: districtId,
|
||||
name: feature.properties.nama || feature.properties.kecamatan || "Unknown District",
|
||||
properties: feature.properties,
|
||||
// properties: feature.properties,
|
||||
longitude: geographics.longitude || clickLng || 0,
|
||||
latitude: geographics.latitude || clickLat || 0,
|
||||
number_of_crime: crimeData.number_of_crime || 0,
|
||||
|
@ -227,6 +210,7 @@ export default function DistrictLayer({
|
|||
}
|
||||
|
||||
selectedDistrictRef.current = district;
|
||||
console.log("District clicked, selectedDistrictRef set to:", selectedDistrictRef.current);
|
||||
|
||||
if (onClick) {
|
||||
onClick(district);
|
||||
|
@ -300,6 +284,7 @@ export default function DistrictLayer({
|
|||
}, [map]);
|
||||
|
||||
const handleCloseDistrictPopup = useCallback(() => {
|
||||
console.log("Closing district popup");
|
||||
selectedDistrictRef.current = null;
|
||||
setSelectedDistrict(null);
|
||||
}, []);
|
||||
|
@ -685,8 +670,30 @@ export default function DistrictLayer({
|
|||
const districtCrime = crimes.find(crime => crime.district_id === districtId);
|
||||
|
||||
if (districtCrime) {
|
||||
const demographics = districtCrime.districts.demographics?.[0];
|
||||
const geographics = districtCrime.districts.geographics?.[0];
|
||||
const selectedYearNum = year ? parseInt(year) : new Date().getFullYear();
|
||||
|
||||
let demographics = districtCrime.districts.demographics?.find(
|
||||
d => d.year === selectedYearNum
|
||||
);
|
||||
|
||||
if (!demographics && districtCrime.districts.demographics?.length) {
|
||||
demographics = districtCrime.districts.demographics
|
||||
.sort((a, b) => b.year - a.year)[0];
|
||||
}
|
||||
|
||||
let geographics = districtCrime.districts.geographics?.find(
|
||||
g => g.year === selectedYearNum
|
||||
);
|
||||
|
||||
if (!geographics && districtCrime.districts.geographics?.length) {
|
||||
const validGeographics = districtCrime.districts.geographics
|
||||
.filter(g => g.year !== null)
|
||||
.sort((a, b) => (b.year || 0) - (a.year || 0));
|
||||
|
||||
geographics = validGeographics.length > 0 ?
|
||||
validGeographics[0] :
|
||||
districtCrime.districts.geographics[0];
|
||||
}
|
||||
|
||||
if (!demographics || !geographics) {
|
||||
console.error("Missing district data:", { demographics, geographics });
|
||||
|
@ -749,17 +756,17 @@ export default function DistrictLayer({
|
|||
|
||||
return (
|
||||
<>
|
||||
{selectedDistrictRef.current ? (
|
||||
{selectedDistrict && (
|
||||
<DistrictPopup
|
||||
longitude={selectedDistrictRef.current.longitude || 0}
|
||||
latitude={selectedDistrictRef.current.latitude || 0}
|
||||
longitude={selectedDistrict.longitude || 0}
|
||||
latitude={selectedDistrict.latitude || 0}
|
||||
onClose={handleCloseDistrictPopup}
|
||||
district={selectedDistrictRef.current}
|
||||
district={selectedDistrict}
|
||||
year={year}
|
||||
month={month}
|
||||
filterCategory={filterCategory}
|
||||
/>
|
||||
) : null}
|
||||
)}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
"use client"
|
||||
|
||||
import { useState, useMemo } from "react"
|
||||
import { useState, useMemo, useEffect } from "react"
|
||||
import { Popup } from "react-map-gl/mapbox"
|
||||
import { Badge } from "@/app/_components/ui/badge"
|
||||
import { Card } from "@/app/_components/ui/card"
|
||||
|
@ -46,6 +46,16 @@ export default function DistrictPopup({
|
|||
}: DistrictPopupProps) {
|
||||
const [activeTab, setActiveTab] = useState("overview")
|
||||
|
||||
// Add debug log when the component is rendered
|
||||
useEffect(() => {
|
||||
console.log("DistrictPopup mounted:", {
|
||||
district: district.name,
|
||||
coords: [longitude, latitude],
|
||||
year,
|
||||
month
|
||||
});
|
||||
}, [district, longitude, latitude, year, month]);
|
||||
|
||||
// Extract all crime incidents from the district data and apply filtering if needed
|
||||
const allCrimeIncidents = useMemo(() => {
|
||||
// Check if there are crime incidents in the district object
|
||||
|
|
Loading…
Reference in New Issue