-
- Projects Map
-
-
- {markers.length} of {projects.length} projects with coordinates
-
+
+ {/* Floating Header - Left Side */}
+
+ {/* Title Box */}
+
+
+
+ Projects Map
+
+
+ {markers.length} of {projects.length} projects with coordinates
-
- {/* Status Filter Panel */}
-
+
- {/* Toggle All Button */}
-
-
- {/* Individual Status Filters */}
- {Object.entries(statusConfig).map(([status, config]) => {
- const isActive = statusFilters[status];
- const projectCount = projects.filter(
- (p) => p.project_status === status && p.coordinates
- ).length;
-
- return (
-
- );
- })}
-
-
+ {/* Zoom Controls - Below Title */}
+
+
+
+
+
+ {/* Layer Control Panel - Right Side */}
+
+ {/* Action Buttons */}
-
{" "}
- {/* Stats Panel - Bottom Left */}
- {markers.length > 0 && (
-
-
-
-
-
- {markers.length} of{" "}
- {projects.filter((p) => p.coordinates).length} projects shown
-
-
- {/* Status breakdown */}
-
- {Object.entries(statusConfig).map(([status, config]) => {
- const totalCount = projects.filter(
- (p) => p.project_status === status && p.coordinates
- ).length;
- const visibleCount = markers.filter((m) => {
- const project = projects.find(
- (p) =>
- p.coordinates &&
- p.coordinates
- .split(",")
- .map((c) => parseFloat(c.trim()))
- .toString() === m.position.toString()
- );
- return project && project.project_status === status;
- }).length;
-
- if (totalCount === 0) return null;
-
- return (
-
-
-
- {config.shortLabel}:{" "}
- {statusFilters[status] ? visibleCount : 0}/{totalCount}
-
-
- );
- })}
-
-
- {projects.length > projects.filter((p) => p.coordinates).length && (
-
-
-
- {projects.length -
- projects.filter((p) => p.coordinates).length}{" "}
- missing coordinates
+ {/* Layer Control Panel */}
+
+ {/* Layer Control Header */}
+
+
+
{/* Layer Control Content */}
+
+
+ {/* Base Layers Section */}
+
+
+
+ Base Maps
+
+
+ {mapLayers.base.map((layer, index) => (
+
+ ))}
+
+
+
+ {/* Overlay Layers Section */}
+ {mapLayers.overlays && mapLayers.overlays.length > 0 && (
+
+
+
+ Overlay Layers
+
+ {mapLayers.overlays.map((layer, index) => (
+
+ ))}
+
+
+ )}
+
+
+
+
+ {/* Status Filter Panel - Bottom Left */}
+
+
+
+
+ Filters:
+
+
+ {/* Toggle All Button */}
+
+
+ {/* Individual Status Filters */}
+ {Object.entries(statusConfig).map(([status, config]) => {
+ const isActive = statusFilters[status];
+ const projectCount = projects.filter(
+ (p) => p.project_status === status && p.coordinates
+ ).length;
+
+ return (
+
+ );
+ })}
+
+
{/* Status Panel - Bottom Left */}
+ {markers.length > 0 && (
+
+
+ Filters:
+
+
+ {/* Toggle All Button */}
+
+
+ {/* Individual Status Filters */}
+ {Object.entries(statusConfig).map(([status, config]) => {
+ const isActive = statusFilters[status];
+ const projectCount = projects.filter(
+ (p) => p.project_status === status && p.coordinates
+ ).length;
+
+ return (
+
+ );
+ })}
- )}
- {/* Help Panel - Bottom Right */}
-
-
- Click markers for details • Use 📚 to switch layers
-
-
- {/* Full Screen Map */}
+ )} {/* Full Screen Map */}
{markers.length === 0 ? (
@@ -559,17 +757,18 @@ export default function ProjectsMapPage() {
- ) : (
+ )}
);
}
diff --git a/src/components/ui/LeafletMap.js b/src/components/ui/LeafletMap.js
index dd1abdf..c66fa46 100644
--- a/src/components/ui/LeafletMap.js
+++ b/src/components/ui/LeafletMap.js
@@ -8,7 +8,9 @@ import {
Popup,
LayersControl,
useMapEvents,
+ useMap,
} from "react-leaflet";
+import L from "leaflet";
import "leaflet/dist/leaflet.css";
import { useEffect } from "react";
import { mapLayers } from "./mapLayers";
@@ -70,26 +72,55 @@ function MapEventHandler({ onViewChange }) {
return null;
}
+// Custom zoom control component that handles external events
+function CustomZoomHandler() {
+ const map = useMap();
+
+ useEffect(() => {
+ if (!map) return;
+
+ const handleZoomIn = () => {
+ map.zoomIn();
+ };
+
+ const handleZoomOut = () => {
+ map.zoomOut();
+ };
+
+ // Listen for custom zoom events
+ window.addEventListener('mapZoomIn', handleZoomIn);
+ window.addEventListener('mapZoomOut', handleZoomOut);
+
+ return () => {
+ window.removeEventListener('mapZoomIn', handleZoomIn);
+ window.removeEventListener('mapZoomOut', handleZoomOut);
+ };
+ }, [map]);
+
+ return null;
+}
+
export default function EnhancedLeafletMap({
center,
zoom = 13,
markers = [],
showLayerControl = true,
defaultLayer = "OpenStreetMap",
+ activeOverlays = [],
onViewChange,
}) {
useEffect(() => {
fixLeafletIcons();
- }, []);
- const { BaseLayer, Overlay } = LayersControl;
- return (
+ }, []); const { BaseLayer, Overlay } = LayersControl;
+ return (
- {/* Handle map view changes */}
+
{onViewChange && }
{showLayerControl ? (
@@ -135,13 +166,52 @@ export default function EnhancedLeafletMap({
)}
))}
-
- ) : (
- // Default layer when no layer control
-
+ ) : (
+ // Custom layer rendering when no layer control
+ <>
+ {/* Base Layer */}
+ {(() => {
+ const baseLayer = mapLayers.base.find(layer => layer.name === defaultLayer) || mapLayers.base[0];
+ return (
+
+ );
+ })()}
+
+ {/* Active Overlay Layers */}
+ {mapLayers.overlays && mapLayers.overlays
+ .filter(layer => activeOverlays.includes(layer.name))
+ .map((layer, index) => {
+ if (layer.type === "wms") {
+ return (
+
+ );
+ } else {
+ return (
+
+ );
+ }
+ })
+ }
+ >
)}{" "}
{markers.map((marker, index) => (