diff --git a/components/map/GeofenceLayer.tsx b/components/map/GeofenceLayer.tsx new file mode 100644 index 0000000..8ea9fec --- /dev/null +++ b/components/map/GeofenceLayer.tsx @@ -0,0 +1,96 @@ +"use client"; + +import { useEffect, useState } from "react"; +import { Circle, Popup } from "react-leaflet"; +import { Geofence } from "@/lib/types"; + +interface GeofenceLayerProps { + visible: boolean; +} + +export default function GeofenceLayer({ visible }: GeofenceLayerProps) { + const [geofences, setGeofences] = useState([]); + const [loading, setLoading] = useState(true); + + useEffect(() => { + if (!visible) return; + + fetchGeofences(); + + // Refresh every 30 seconds + const interval = setInterval(fetchGeofences, 30000); + return () => clearInterval(interval); + }, [visible]); + + const fetchGeofences = async () => { + try { + const response = await fetch("/api/geofences"); + if (!response.ok) throw new Error("Failed to fetch geofences"); + + const data = await response.json(); + setGeofences(data.geofences || []); + } catch (err) { + console.error("Failed to fetch geofences", err); + } finally { + setLoading(false); + } + }; + + if (!visible || loading) return null; + + return ( + <> + {geofences + .filter((g) => g.is_active === 1) + .map((geofence) => ( + + +
+

+ + {geofence.name} +

+ {geofence.description && ( +

{geofence.description}

+ )} +
+

+ 📍 Device: {geofence.device_id} +

+

+ 📏 Radius:{" "} + {geofence.radius_meters >= 1000 + ? `${(geofence.radius_meters / 1000).toFixed(1)} km` + : `${geofence.radius_meters} m`} +

+

+ 🎯 Center:{" "} + {geofence.center_latitude.toFixed(4)},{" "} + {geofence.center_longitude.toFixed(4)} +

+

+ + Active +

+
+
+
+
+ ))} + + ); +} diff --git a/components/map/MapView.tsx b/components/map/MapView.tsx index 9ff70d0..3ec98e2 100644 --- a/components/map/MapView.tsx +++ b/components/map/MapView.tsx @@ -13,6 +13,7 @@ import { LayersControl, useMap, } from "react-leaflet"; +import GeofenceLayer from "./GeofenceLayer"; interface MapViewProps { selectedDevice: string; @@ -73,6 +74,7 @@ export default function MapView({ selectedDevice, timeFilter, isPaused, filterMo const [error, setError] = useState(null); const [mapCenter, setMapCenter] = useState<[number, number] | null>(null); const [currentZoom, setCurrentZoom] = useState(12); + const [showGeofences, setShowGeofences] = useState(true); const intervalRef = useRef(null); // Add animation styles for latest marker @@ -226,7 +228,22 @@ export default function MapView({ selectedDevice, timeFilter, isPaused, filterMo } return ( -
+
+ {/* Geofence Toggle Button */} +
+ +
+ ); })} + + {/* Geofence Layer */} +
);