fix: fix kesalahan oengambilan properti distance pada units layer
This commit is contained in:
parent
58f033d0e4
commit
849b3c1ae3
|
@ -1,42 +1,42 @@
|
|||
"use client";
|
||||
// "use client";
|
||||
|
||||
import { useState, useEffect } from 'react';
|
||||
import mapboxgl from 'mapbox-gl';
|
||||
import EWSAlertLayer from '../layers/ews-alert-layer';
|
||||
// import { useState, useEffect } from 'react';
|
||||
// import mapboxgl from 'mapbox-gl';
|
||||
// import EWSAlertLayer from '../layers/ews-alert-layer';
|
||||
|
||||
import { IIncidentLog } from '@/app/_utils/types/ews';
|
||||
// import { IIncidentLog } from '@/app/_utils/types/ews';
|
||||
|
||||
interface AlertLayerContainerProps {
|
||||
map: mapboxgl.Map | null;
|
||||
activeLayer: string;
|
||||
incidents: IIncidentLog[];
|
||||
onIncidentResolved?: (id: string) => void;
|
||||
}
|
||||
// interface AlertLayerContainerProps {
|
||||
// map: mapboxgl.Map | null;
|
||||
// activeLayer: string;
|
||||
// incidents: IIncidentLog[];
|
||||
// onIncidentResolved?: (id: string) => void;
|
||||
// }
|
||||
|
||||
export default function AlertLayerContainer({
|
||||
map,
|
||||
activeLayer,
|
||||
incidents,
|
||||
onIncidentResolved,
|
||||
}: AlertLayerContainerProps) {
|
||||
const [ewsVisible, setEwsVisible] = useState(false);
|
||||
// export default function AlertLayerContainer({
|
||||
// map,
|
||||
// activeLayer,
|
||||
// incidents,
|
||||
// onIncidentResolved,
|
||||
// }: AlertLayerContainerProps) {
|
||||
// const [ewsVisible, setEwsVisible] = useState(false);
|
||||
|
||||
// Determine which layers to show based on activeLayer
|
||||
useEffect(() => {
|
||||
const isAlertLayer = activeLayer === 'alerts';
|
||||
setEwsVisible(isAlertLayer);
|
||||
}, [activeLayer]);
|
||||
// // Determine which layers to show based on activeLayer
|
||||
// useEffect(() => {
|
||||
// const isAlertLayer = activeLayer === 'alerts';
|
||||
// setEwsVisible(isAlertLayer);
|
||||
// }, [activeLayer]);
|
||||
|
||||
|
||||
return (
|
||||
<>
|
||||
{/* EWS Alert Layer for emergency notifications */}
|
||||
<EWSAlertLayer
|
||||
map={map}
|
||||
incidents={incidents}
|
||||
onIncidentResolved={onIncidentResolved}
|
||||
visible={ewsVisible}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
// return (
|
||||
// <>
|
||||
// {/* EWS Alert Layer for emergency notifications */}
|
||||
// <EWSAlertLayer
|
||||
// map={map}
|
||||
// incidents={incidents}
|
||||
// onIncidentResolved={onIncidentResolved}
|
||||
// visible={ewsVisible}
|
||||
// />
|
||||
// </>
|
||||
// );
|
||||
// }
|
||||
|
|
|
@ -25,6 +25,11 @@ import Layers from "./layers/layers"
|
|||
|
||||
import { useGetUnitsQuery } from "@/app/(pages)/(admin)/dashboard/crime-management/units/_queries/queries"
|
||||
import { IDistrictFeature } from "@/app/_utils/types/map"
|
||||
import EWSAlertLayer from "./layers/ews-alert-layer"
|
||||
import { IIncidentLog } from "@/app/_utils/types/ews"
|
||||
import { addMockIncident, getAllIncidents, resolveIncident } from "@/app/_utils/mock/ews-data"
|
||||
import { useMap } from "react-map-gl/mapbox"
|
||||
import PanicButtonDemo from "./controls/panic-button-demo"
|
||||
|
||||
export default function CrimeMap() {
|
||||
const [sidebarCollapsed, setSidebarCollapsed] = useState(true)
|
||||
|
@ -45,9 +50,16 @@ export default function CrimeMap() {
|
|||
const [useAllYears, setUseAllYears] = useState<boolean>(false)
|
||||
const [useAllMonths, setUseAllMonths] = useState<boolean>(false)
|
||||
const [showEWS, setShowEWS] = useState<boolean>(true)
|
||||
const [ewsIncidents, setEwsIncidents] = useState<IIncidentLog[]>([])
|
||||
const [showPanicDemo, setShowPanicDemo] = useState(true)
|
||||
const [displayPanicDemo, setDisplayPanicDemo] = useState(showEWS && showPanicDemo)
|
||||
|
||||
const mapContainerRef = useRef<HTMLDivElement>(null)
|
||||
|
||||
const { current: mapInstance } = useMap()
|
||||
|
||||
const mapboxMap = mapInstance?.getMap() || null
|
||||
|
||||
const { isFullscreen } = useFullscreen(mapContainerRef)
|
||||
|
||||
const { data: availableSourceTypes, isLoading: isTypeLoading } = useGetCrimeTypes()
|
||||
|
@ -142,6 +154,29 @@ export default function CrimeMap() {
|
|||
}
|
||||
}, [selectedSourceType, activeControl]);
|
||||
|
||||
useEffect(() => {
|
||||
setEwsIncidents(getAllIncidents())
|
||||
}, [])
|
||||
|
||||
const handleTriggerAlert = useCallback((priority: "high" | "medium" | "low") => {
|
||||
const newIncident = addMockIncident({ priority })
|
||||
setEwsIncidents(getAllIncidents())
|
||||
}, [])
|
||||
|
||||
const handleResolveIncident = useCallback((id: string) => {
|
||||
resolveIncident(id)
|
||||
setEwsIncidents(getAllIncidents())
|
||||
}, [])
|
||||
|
||||
const handleResolveAllAlerts = useCallback(() => {
|
||||
ewsIncidents.forEach((incident) => {
|
||||
if (incident.status === "active") {
|
||||
resolveIncident(incident.id)
|
||||
}
|
||||
})
|
||||
setEwsIncidents(getAllIncidents())
|
||||
}, [ewsIncidents])
|
||||
|
||||
const handleSourceTypeChange = useCallback((sourceType: string) => {
|
||||
setSelectedSourceType(sourceType);
|
||||
|
||||
|
@ -283,6 +318,7 @@ export default function CrimeMap() {
|
|||
sourceType={selectedSourceType}
|
||||
/>
|
||||
|
||||
|
||||
{isFullscreen && (
|
||||
<>
|
||||
<div className="absolute flex w-full p-2">
|
||||
|
@ -304,6 +340,19 @@ export default function CrimeMap() {
|
|||
/>
|
||||
</div>
|
||||
|
||||
{mapboxMap && (
|
||||
<EWSAlertLayer map={mapboxMap} incidents={ewsIncidents} onIncidentResolved={handleResolveIncident} />
|
||||
)}
|
||||
{displayPanicDemo && (
|
||||
<div className="absolute top-0 right-20 z-50 p-2">
|
||||
<PanicButtonDemo
|
||||
onTriggerAlert={handleTriggerAlert}
|
||||
onResolveAllAlerts={handleResolveAllAlerts}
|
||||
activeIncidents={ewsIncidents.filter((inc) => inc.status === "active")}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<CrimeSidebar
|
||||
crimes={filteredCrimes || []}
|
||||
defaultCollapsed={sidebarCollapsed}
|
||||
|
@ -312,18 +361,18 @@ export default function CrimeMap() {
|
|||
selectedMonth={selectedMonth}
|
||||
sourceType={selectedSourceType} // Pass the sourceType
|
||||
/>
|
||||
{isFullscreen && (
|
||||
<div className="absolute bottom-20 right-0 z-20 p-2">
|
||||
{showClusters && (
|
||||
<MapLegend position="bottom-right" />
|
||||
)}
|
||||
{showUnclustered && !showClusters && (
|
||||
<MapLegend position="bottom-right" />
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{isFullscreen && showUnitsLayer && (
|
||||
<div className="absolute bottom-20 right-0 z-20 p-2">
|
||||
{showClusters && (
|
||||
<MapLegend position="bottom-right" />
|
||||
)}
|
||||
{showUnclustered && !showClusters && (
|
||||
<MapLegend position="bottom-right" />
|
||||
)}
|
||||
</div>
|
||||
|
||||
|
||||
{showUnitsLayer && (
|
||||
<div className="absolute bottom-20 right-0 z-10 p-2">
|
||||
<UnitsLegend
|
||||
categories={categories}
|
||||
|
@ -332,7 +381,7 @@ export default function CrimeMap() {
|
|||
</div>
|
||||
)}
|
||||
|
||||
{isFullscreen && showTimelineLayer && (
|
||||
{showTimelineLayer && (
|
||||
<div className="absolute flex bottom-20 right-0 z-10 p-2">
|
||||
<TimelineLegend position="bottom-right" />
|
||||
</div>
|
||||
|
@ -340,17 +389,17 @@ export default function CrimeMap() {
|
|||
</>
|
||||
)}
|
||||
|
||||
{isFullscreen && (
|
||||
<div className="absolute flex w-full bottom-0">
|
||||
<CrimeTimelapse
|
||||
startYear={2020}
|
||||
endYear={2024}
|
||||
autoPlay={false}
|
||||
onChange={handleTimelineChange}
|
||||
onPlayingChange={handleTimelinePlayingChange}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="absolute flex w-full bottom-0">
|
||||
<CrimeTimelapse
|
||||
startYear={2020}
|
||||
endYear={2024}
|
||||
autoPlay={false}
|
||||
onChange={handleTimelineChange}
|
||||
onPlayingChange={handleTimelinePlayingChange}
|
||||
/>
|
||||
</div>
|
||||
|
||||
</MapView>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -93,6 +93,7 @@ export default function Layers({
|
|||
sourceType = "cbt",
|
||||
}: LayersProps) {
|
||||
const animationRef = useRef<number | null>(null)
|
||||
|
||||
const { current: map } = useMap()
|
||||
|
||||
if (!map) {
|
||||
|
@ -115,28 +116,28 @@ export default function Layers({
|
|||
const [showPanicDemo, setShowPanicDemo] = useState(true)
|
||||
const [displayPanicDemo, setDisplayPanicDemo] = useState(showEWS && showPanicDemo)
|
||||
|
||||
useEffect(() => {
|
||||
setEwsIncidents(getAllIncidents())
|
||||
}, [])
|
||||
// useEffect(() => {
|
||||
// setEwsIncidents(getAllIncidents())
|
||||
// }, [])
|
||||
|
||||
const handleTriggerAlert = useCallback((priority: "high" | "medium" | "low") => {
|
||||
const newIncident = addMockIncident({ priority })
|
||||
setEwsIncidents(getAllIncidents())
|
||||
}, [])
|
||||
// const handleTriggerAlert = useCallback((priority: "high" | "medium" | "low") => {
|
||||
// const newIncident = addMockIncident({ priority })
|
||||
// setEwsIncidents(getAllIncidents())
|
||||
// }, [])
|
||||
|
||||
const handleResolveIncident = useCallback((id: string) => {
|
||||
resolveIncident(id)
|
||||
setEwsIncidents(getAllIncidents())
|
||||
}, [])
|
||||
// const handleResolveIncident = useCallback((id: string) => {
|
||||
// resolveIncident(id)
|
||||
// setEwsIncidents(getAllIncidents())
|
||||
// }, [])
|
||||
|
||||
const handleResolveAllAlerts = useCallback(() => {
|
||||
ewsIncidents.forEach((incident) => {
|
||||
if (incident.status === "active") {
|
||||
resolveIncident(incident.id)
|
||||
}
|
||||
})
|
||||
setEwsIncidents(getAllIncidents())
|
||||
}, [ewsIncidents])
|
||||
// const handleResolveAllAlerts = useCallback(() => {
|
||||
// ewsIncidents.forEach((incident) => {
|
||||
// if (incident.status === "active") {
|
||||
// resolveIncident(incident.id)
|
||||
// }
|
||||
// })
|
||||
// setEwsIncidents(getAllIncidents())
|
||||
// }, [ewsIncidents])
|
||||
|
||||
const handlePopupClose = useCallback(() => {
|
||||
selectedDistrictRef.current = null
|
||||
|
@ -534,9 +535,9 @@ export default function Layers({
|
|||
|
||||
<FaultLinesLayer map={mapboxMap} />
|
||||
|
||||
{showEWS && <EWSAlertLayer map={mapboxMap} incidents={ewsIncidents} onIncidentResolved={handleResolveIncident} />}
|
||||
{/* {showEWS && <EWSAlertLayer map={mapboxMap} incidents={ewsIncidents} onIncidentResolved={handleResolveIncident} />} */}
|
||||
|
||||
{showEWS && displayPanicDemo && (
|
||||
{/* {showEWS && displayPanicDemo && (
|
||||
<div className="absolute top-0 right-20 z-50 p-2">
|
||||
<PanicButtonDemo
|
||||
onTriggerAlert={handleTriggerAlert}
|
||||
|
@ -544,7 +545,7 @@ export default function Layers({
|
|||
activeIncidents={ewsIncidents.filter((inc) => inc.status === "active")}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
)} */}
|
||||
|
||||
|
||||
</>
|
||||
|
|
|
@ -30,6 +30,20 @@ interface IDistrictIncidents {
|
|||
timestamp: Date
|
||||
}
|
||||
|
||||
// New interface to better type the incident properties
|
||||
interface IncidentProperties {
|
||||
id: string
|
||||
description: string
|
||||
category: string
|
||||
date: string
|
||||
district: string
|
||||
district_id: string
|
||||
categoryColor: string
|
||||
distance_to_unit: number | "Unknown"
|
||||
longitude: number
|
||||
latitude: number
|
||||
}
|
||||
|
||||
export default function UnitsLayer({ crimes, units = [], filterCategory, visible = false, map }: UnitsLayerProps) {
|
||||
const [loadedUnits, setLoadedUnits] = useState<IUnits[]>([])
|
||||
const loadedUnitsRef = useRef<IUnits[]>([])
|
||||
|
@ -50,6 +64,9 @@ export default function UnitsLayer({ crimes, units = [], filterCategory, visible
|
|||
5
|
||||
)
|
||||
|
||||
// Add a ref to store pre-processed incidents by district for optimization
|
||||
const districtIncidentsCache = useRef<Map<string, IDistrictIncidents[]>>(new Map());
|
||||
|
||||
// Use either provided units or loaded units
|
||||
const unitsData = useMemo(() => {
|
||||
return units.length > 0 ? units : loadedUnits || []
|
||||
|
@ -105,7 +122,15 @@ export default function UnitsLayer({ crimes, units = [], filterCategory, visible
|
|||
const incidentsGeoJSON = useMemo(() => {
|
||||
const features: any[] = []
|
||||
|
||||
// Also build the district incidents cache while processing crime data
|
||||
const newDistrictIncidentsCache = new Map<string, IDistrictIncidents[]>();
|
||||
|
||||
crimes.forEach((crime) => {
|
||||
// Initialize the array for this district if it doesn't exist yet
|
||||
if (!newDistrictIncidentsCache.has(crime.district_id)) {
|
||||
newDistrictIncidentsCache.set(crime.district_id, []);
|
||||
}
|
||||
|
||||
crime.crime_incidents.forEach((incident) => {
|
||||
// Skip incidents without location data or filtered by category
|
||||
if (
|
||||
|
@ -115,6 +140,22 @@ export default function UnitsLayer({ crimes, units = [], filterCategory, visible
|
|||
)
|
||||
return
|
||||
|
||||
// Ensure distance_to_unit is properly initialized
|
||||
const distance = incident.locations.distance_to_unit !== undefined
|
||||
? incident.locations.distance_to_unit
|
||||
: "Unknown";
|
||||
|
||||
// Add to district incidents cache for quicker lookup
|
||||
if (incident.locations.distance_to_unit !== undefined) {
|
||||
newDistrictIncidentsCache.get(crime.district_id)?.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,
|
||||
});
|
||||
}
|
||||
|
||||
features.push({
|
||||
type: "Feature" as const,
|
||||
properties: {
|
||||
|
@ -125,7 +166,7 @@ export default function UnitsLayer({ crimes, units = [], filterCategory, visible
|
|||
district: crime.districts.name,
|
||||
district_id: crime.district_id,
|
||||
categoryColor: categoryColorMap[incident.crime_categories.name] || "#22c55e",
|
||||
distance_to_unit: incident.locations.distance_to_unit || "Unknown",
|
||||
distance_to_unit: distance,
|
||||
},
|
||||
geometry: {
|
||||
type: "Point" as const,
|
||||
|
@ -135,6 +176,9 @@ export default function UnitsLayer({ crimes, units = [], filterCategory, visible
|
|||
})
|
||||
})
|
||||
|
||||
// Update the cache ref with our new data
|
||||
districtIncidentsCache.current = newDistrictIncidentsCache;
|
||||
|
||||
return {
|
||||
type: "FeatureCollection" as const,
|
||||
features,
|
||||
|
@ -245,32 +289,43 @@ export default function UnitsLayer({ crimes, units = [], filterCategory, visible
|
|||
|
||||
setIsLoading(true)
|
||||
|
||||
// Find all incidents in the same district as the unit
|
||||
const districtIncidents: IDistrictIncidents[] = []
|
||||
crimes.forEach((crime) => {
|
||||
// Early exit if district_id is not available
|
||||
if (!unit.district_id) {
|
||||
console.log("Unit has no district ID")
|
||||
setUnitIncident([])
|
||||
setIsLoading(false)
|
||||
return
|
||||
}
|
||||
|
||||
console.log("Processing crime:", crime.district_id, unit.district_id) // Debug log
|
||||
// Use the pre-processed district incidents from cache
|
||||
let districtIncidents = districtIncidentsCache.current.get(unit.district_id) || [];
|
||||
|
||||
// Check if this crime is in the same district as the unit
|
||||
if (crime.district_id === unit.district_id) {
|
||||
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,
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
// If we don't have them in cache for some reason, compute them now
|
||||
if (districtIncidents.length === 0) {
|
||||
const tempIncidents: IDistrictIncidents[] = [];
|
||||
|
||||
// Only process crimes for this specific district
|
||||
crimes
|
||||
.filter(crime => crime.district_id === unit.district_id)
|
||||
.forEach(crime => {
|
||||
crime.crime_incidents.forEach(incident => {
|
||||
if (incident.locations && typeof incident.locations.distance_to_unit !== "undefined") {
|
||||
tempIncidents.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,
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
districtIncidents = tempIncidents;
|
||||
}
|
||||
|
||||
// Sort by distance (closest first)
|
||||
districtIncidents.sort((a, b) => a.distance_meters - b.distance_meters)
|
||||
|
||||
// console.log("Sorted district incidents:", districtIncidents)
|
||||
districtIncidents.sort((a, b) => a.distance_meters - b.distance_meters);
|
||||
|
||||
// Update the state with the distance results
|
||||
setUnitIncident(districtIncidents)
|
||||
|
@ -350,6 +405,10 @@ export default function UnitsLayer({ crimes, units = [], filterCategory, visible
|
|||
duration: BASE_DURATION,
|
||||
})
|
||||
|
||||
// Ensure distance_to_unit has a value - use the value from GeoJSON properties directly
|
||||
// This ensures we use the same data that was calculated for the GeoJSON
|
||||
let distanceToUnit = properties.distance_to_unit;
|
||||
|
||||
// Create incident object from properties
|
||||
const incident = {
|
||||
id: properties.id,
|
||||
|
@ -358,14 +417,11 @@ export default function UnitsLayer({ crimes, units = [], filterCategory, visible
|
|||
date: properties.date,
|
||||
district: properties.district,
|
||||
district_id: properties.district_id,
|
||||
distance_to_unit: properties.distance_to_unit,
|
||||
distance_to_unit: distanceToUnit,
|
||||
longitude,
|
||||
latitude,
|
||||
}
|
||||
|
||||
// Debug log
|
||||
console.log("Incident clicked:", incident)
|
||||
|
||||
// Set the selected incident and query parameters
|
||||
setSelectedIncident(incident)
|
||||
setSelectedUnit(null) // Clear any selected unit
|
||||
|
@ -386,6 +442,7 @@ export default function UnitsLayer({ crimes, units = [], filterCategory, visible
|
|||
district: properties.district,
|
||||
category: properties.category,
|
||||
description: properties.description,
|
||||
distance_to_unit: distanceToUnit,
|
||||
longitude,
|
||||
latitude,
|
||||
},
|
||||
|
@ -438,11 +495,11 @@ export default function UnitsLayer({ crimes, units = [], filterCategory, visible
|
|||
if (!map || !visible) return
|
||||
|
||||
// Debug log untuk memeriksa keberadaan layer
|
||||
console.log("Setting up event handlers, map layers:",
|
||||
map.getStyle().layers?.filter(l =>
|
||||
l.id === "units-points" || l.id === "incidents-points"
|
||||
).map(l => l.id)
|
||||
)
|
||||
// console.log("Setting up event handlers, map layers:",
|
||||
// map.getStyle().layers?.filter(l =>
|
||||
// l.id === "units-points" || l.id === "incidents-points"
|
||||
// ).map(l => l.id)
|
||||
// )
|
||||
|
||||
// Define event handlers that can be referenced for both adding and removing
|
||||
const handleMouseEnter = () => {
|
||||
|
@ -461,7 +518,7 @@ export default function UnitsLayer({ crimes, units = [], filterCategory, visible
|
|||
map.on("click", "units-points", unitClickHandler)
|
||||
map.on("mouseenter", "units-points", handleMouseEnter)
|
||||
map.on("mouseleave", "units-points", handleMouseLeave)
|
||||
console.log("✅ Unit points handler attached")
|
||||
// console.log("✅ Unit points handler attached")
|
||||
} else {
|
||||
console.log("❌ units-points layer not found")
|
||||
}
|
||||
|
@ -472,7 +529,7 @@ export default function UnitsLayer({ crimes, units = [], filterCategory, visible
|
|||
map.on("click", "incidents-points", incidentClickHandler)
|
||||
map.on("mouseenter", "incidents-points", handleMouseEnter)
|
||||
map.on("mouseleave", "incidents-points", handleMouseLeave)
|
||||
console.log("✅ Incident points handler attached")
|
||||
// console.log("✅ Incident points handler attached")
|
||||
} else {
|
||||
console.log("❌ incidents-points layer not found")
|
||||
}
|
||||
|
@ -516,7 +573,7 @@ export default function UnitsLayer({ crimes, units = [], filterCategory, visible
|
|||
|
||||
// Reset map filters when popup is closed
|
||||
const handleClosePopup = useCallback(() => {
|
||||
console.log("Closing popup, clearing selected states")
|
||||
// console.log("Closing popup, clearing selected states")
|
||||
setSelectedUnit(null)
|
||||
setSelectedIncident(null)
|
||||
setSelectedEntityId(undefined)
|
||||
|
@ -545,13 +602,13 @@ export default function UnitsLayer({ crimes, units = [], filterCategory, visible
|
|||
}, [visible, handleClosePopup])
|
||||
|
||||
// Debug untuk komponen render
|
||||
useEffect(() => {
|
||||
console.log("Render state:", {
|
||||
selectedUnit: selectedUnit?.code_unit,
|
||||
selectedIncident: selectedIncident?.id,
|
||||
visible
|
||||
})
|
||||
}, [selectedUnit, selectedIncident, visible])
|
||||
// useEffect(() => {
|
||||
// console.log("Render state:", {
|
||||
// selectedUnit: selectedUnit?.code_unit,
|
||||
// selectedIncident: selectedIncident?.id,
|
||||
// visible
|
||||
// })
|
||||
// }, [selectedUnit, selectedIncident, visible])
|
||||
|
||||
if (!visible) return null
|
||||
|
||||
|
|
|
@ -117,28 +117,6 @@ export default function TimelinePopup({
|
|||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
{/* Connection line */}
|
||||
<div
|
||||
className="absolute top-0 left-1/2 transform -translate-x-1/2 -translate-y-full"
|
||||
style={{
|
||||
width: '2px',
|
||||
height: '20px',
|
||||
backgroundColor: 'red',
|
||||
boxShadow: '0 0 4px rgba(0, 0, 0, 0.3)'
|
||||
}}
|
||||
/>
|
||||
{/* Connection dot */}
|
||||
<div
|
||||
className="absolute top-0 left-1/2 transform -translate-x-1/2 -translate-y-full"
|
||||
style={{
|
||||
width: '6px',
|
||||
height: '6px',
|
||||
backgroundColor: 'red',
|
||||
borderRadius: '50%',
|
||||
marginBottom: '20px',
|
||||
boxShadow: '0 0 4px rgba(0, 0, 0, 0.3)'
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</Popup>
|
||||
)
|
||||
|
|
Loading…
Reference in New Issue