Refactor LeafletMap to implement custom WMSLayer component and remove WMSTileLayer usage; update mapLayers configuration for improved readability and maintainability; delete obsolete page_backup.js file.
This commit is contained in:
@@ -29,7 +29,8 @@ export default function ProjectsMapPage() {
|
||||
in_progress_design: true,
|
||||
in_progress_construction: true,
|
||||
fulfilled: true,
|
||||
}); const [activeBaseLayer, setActiveBaseLayer] = useState("Polish Geoportal Orthophoto");
|
||||
});
|
||||
const [activeBaseLayer, setActiveBaseLayer] = useState("OpenStreetMap");
|
||||
const [activeOverlays, setActiveOverlays] = useState([]);
|
||||
const [showLayerPanel, setShowLayerPanel] = useState(true);
|
||||
const [currentTool, setCurrentTool] = useState("move"); // Current map tool
|
||||
@@ -103,10 +104,10 @@ export default function ProjectsMapPage() {
|
||||
// Update URL with current map state (debounced to avoid too many updates)
|
||||
const updateURL = (center, zoom) => {
|
||||
const params = new URLSearchParams();
|
||||
params.set('lat', center[0].toFixed(6));
|
||||
params.set('lng', center[1].toFixed(6));
|
||||
params.set('zoom', zoom.toString());
|
||||
|
||||
params.set("lat", center[0].toFixed(6));
|
||||
params.set("lng", center[1].toFixed(6));
|
||||
params.set("zoom", zoom.toString());
|
||||
|
||||
// Use replace to avoid cluttering browser history
|
||||
router.replace(`/projects/map?${params.toString()}`, { scroll: false });
|
||||
};
|
||||
@@ -115,7 +116,7 @@ export default function ProjectsMapPage() {
|
||||
const handleMapViewChange = (center, zoom) => {
|
||||
setMapCenter(center);
|
||||
setMapZoom(zoom);
|
||||
|
||||
|
||||
// Debounce URL updates to avoid too many history entries
|
||||
clearTimeout(window.mapUpdateTimeout);
|
||||
window.mapUpdateTimeout = setTimeout(() => {
|
||||
@@ -126,9 +127,9 @@ export default function ProjectsMapPage() {
|
||||
// Hide navigation and ensure full-screen layout
|
||||
useEffect(() => {
|
||||
// Check for URL parameters for coordinates and zoom
|
||||
const lat = searchParams.get('lat');
|
||||
const lng = searchParams.get('lng');
|
||||
const zoom = searchParams.get('zoom');
|
||||
const lat = searchParams.get("lat");
|
||||
const lng = searchParams.get("lng");
|
||||
const zoom = searchParams.get("zoom");
|
||||
|
||||
if (lat && lng) {
|
||||
const latitude = parseFloat(lat);
|
||||
@@ -154,7 +155,7 @@ export default function ProjectsMapPage() {
|
||||
// Prevent scrolling on body
|
||||
document.body.style.overflow = "hidden";
|
||||
document.documentElement.style.overflow = "hidden";
|
||||
|
||||
|
||||
// Cleanup when leaving page
|
||||
return () => {
|
||||
if (nav) {
|
||||
@@ -162,7 +163,7 @@ export default function ProjectsMapPage() {
|
||||
}
|
||||
document.body.style.overflow = "";
|
||||
document.documentElement.style.overflow = "";
|
||||
|
||||
|
||||
// Clear any pending URL updates
|
||||
if (window.mapUpdateTimeout) {
|
||||
clearTimeout(window.mapUpdateTimeout);
|
||||
@@ -177,9 +178,9 @@ export default function ProjectsMapPage() {
|
||||
setProjects(data);
|
||||
|
||||
// Only calculate center based on projects if no URL parameters are provided
|
||||
const lat = searchParams.get('lat');
|
||||
const lng = searchParams.get('lng');
|
||||
|
||||
const lat = searchParams.get("lat");
|
||||
const lng = searchParams.get("lng");
|
||||
|
||||
if (!lat || !lng) {
|
||||
// Calculate center based on projects with coordinates
|
||||
const projectsWithCoords = data.filter((p) => p.coordinates);
|
||||
@@ -348,9 +349,7 @@ export default function ProjectsMapPage() {
|
||||
);
|
||||
}
|
||||
return (
|
||||
<div
|
||||
className="fixed inset-0 bg-gray-50 overflow-hidden"
|
||||
>
|
||||
<div className="fixed inset-0 bg-gray-50 overflow-hidden">
|
||||
{/* Floating Header - Left Side */}
|
||||
<div className="absolute top-4 left-4 z-[1000]">
|
||||
{/* Title Box */}
|
||||
@@ -362,187 +361,183 @@ export default function ProjectsMapPage() {
|
||||
<div className="text-sm text-gray-600">
|
||||
{markers.length} of {projects.length} projects with coordinates
|
||||
</div>
|
||||
</div> </div>
|
||||
</div>{" "}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Zoom Controls - Below Title */}
|
||||
<div className="absolute top-20 left-4 z-[1000]">
|
||||
<div className="bg-white/95 backdrop-blur-sm rounded-lg shadow-lg border border-gray-200 flex flex-col">
|
||||
<button
|
||||
<button
|
||||
className="px-3 py-2 hover:bg-gray-50 transition-colors duration-200 border-b border-gray-200 text-gray-700 font-medium text-lg"
|
||||
onClick={() => {
|
||||
// This will be handled by the map component
|
||||
const event = new CustomEvent('mapZoomIn');
|
||||
const event = new CustomEvent("mapZoomIn");
|
||||
window.dispatchEvent(event);
|
||||
}}
|
||||
title="Zoom In"
|
||||
>
|
||||
+
|
||||
</button>
|
||||
<button
|
||||
<button
|
||||
className="px-3 py-2 hover:bg-gray-50 transition-colors duration-200 text-gray-700 font-medium text-lg"
|
||||
onClick={() => {
|
||||
// This will be handled by the map component
|
||||
const event = new CustomEvent('mapZoomOut');
|
||||
const event = new CustomEvent("mapZoomOut");
|
||||
window.dispatchEvent(event);
|
||||
}}
|
||||
title="Zoom Out"
|
||||
>
|
||||
−
|
||||
</button> </div>
|
||||
</div> {/* Tool Panel - Below Zoom Controls */}
|
||||
<div className="absolute top-48 left-4 z-[1000]"> <div className="bg-white/95 backdrop-blur-sm rounded-lg shadow-lg border border-gray-200 flex flex-col"> {/* Move Tool */}
|
||||
<button
|
||||
</button>{" "}
|
||||
</div>
|
||||
</div>{" "}
|
||||
{/* Tool Panel - Below Zoom Controls */}
|
||||
<div className="absolute top-48 left-4 z-[1000]">
|
||||
{" "}
|
||||
<div className="bg-white/95 backdrop-blur-sm rounded-lg shadow-lg border border-gray-200 flex flex-col">
|
||||
{" "}
|
||||
{/* Move Tool */}
|
||||
<button
|
||||
className={`p-3 transition-colors duration-200 border-b border-gray-200 ${
|
||||
currentTool === "move"
|
||||
? "bg-blue-100 text-blue-700"
|
||||
currentTool === "move"
|
||||
? "bg-blue-100 text-blue-700"
|
||||
: "text-gray-700 hover:bg-gray-50"
|
||||
}`}
|
||||
onClick={() => setCurrentTool("move")}
|
||||
title="Move Tool (Pan Map)"
|
||||
>
|
||||
<svg
|
||||
className="w-5 h-5"
|
||||
fill="currentColor"
|
||||
viewBox="0 0 512 512"
|
||||
>
|
||||
<path d="M256 0c-25.3 0-47.2 14.7-57.6 36c-7-2.6-14.5-4-22.4-4c-35.3 0-64 28.7-64 64l0 165.5-2.7-2.7c-25-25-65.5-25-90.5 0s-25 65.5 0 90.5L106.5 437c48 48 113.1 75 181 75l8.5 0 8 0c1.5 0 3-.1 4.5-.4c91.7-6.2 165-79.4 171.1-171.1c.3-1.5 .4-3 .4-4.5l0-176c0-35.3-28.7-64-64-64c-5.5 0-10.9 .7-16 2l0-2c0-35.3-28.7-64-64-64c-7.9 0-15.4 1.4-22.4 4C303.2 14.7 281.3 0 256 0zM240 96.1l0-.1 0-32c0-8.8 7.2-16 16-16s16 7.2 16 16l0 31.9 0 .1 0 136c0 13.3 10.7 24 24 24s24-10.7 24-24l0-136c0 0 0 0 0-.1c0-8.8 7.2-16 16-16s16 7.2 16 16l0 55.9c0 0 0 .1 0 .1l0 80c0 13.3 10.7 24 24 24s24-10.7 24-24l0-71.9c0 0 0-.1 0-.1c0-8.8 7.2-16 16-16s16 7.2 16 16l0 172.9c-.1 .6-.1 1.3-.2 1.9c-3.4 69.7-59.3 125.6-129 129c-.6 0-1.3 .1-1.9 .2l-4.9 0-8.5 0c-55.2 0-108.1-21.9-147.1-60.9L52.7 315.3c-6.2-6.2-6.2-16.4 0-22.6s16.4-6.2 22.6 0L119 336.4c6.9 6.9 17.2 8.9 26.2 5.2s14.8-12.5 14.8-22.2L160 96c0-8.8 7.2-16 16-16c8.8 0 16 7.1 16 15.9L192 232c0 13.3 10.7 24 24 24s24-10.7 24-24l0-135.9z"/>
|
||||
<svg className="w-5 h-5" fill="currentColor" viewBox="0 0 512 512">
|
||||
<path d="M256 0c-25.3 0-47.2 14.7-57.6 36c-7-2.6-14.5-4-22.4-4c-35.3 0-64 28.7-64 64l0 165.5-2.7-2.7c-25-25-65.5-25-90.5 0s-25 65.5 0 90.5L106.5 437c48 48 113.1 75 181 75l8.5 0 8 0c1.5 0 3-.1 4.5-.4c91.7-6.2 165-79.4 171.1-171.1c.3-1.5 .4-3 .4-4.5l0-176c0-35.3-28.7-64-64-64c-5.5 0-10.9 .7-16 2l0-2c0-35.3-28.7-64-64-64c-7.9 0-15.4 1.4-22.4 4C303.2 14.7 281.3 0 256 0zM240 96.1l0-.1 0-32c0-8.8 7.2-16 16-16s16 7.2 16 16l0 31.9 0 .1 0 136c0 13.3 10.7 24 24 24s24-10.7 24-24l0-136c0 0 0 0 0-.1c0-8.8 7.2-16 16-16s16 7.2 16 16l0 55.9c0 0 0 .1 0 .1l0 80c0 13.3 10.7 24 24 24s24-10.7 24-24l0-71.9c0 0 0-.1 0-.1c0-8.8 7.2-16 16-16s16 7.2 16 16l0 172.9c-.1 .6-.1 1.3-.2 1.9c-3.4 69.7-59.3 125.6-129 129c-.6 0-1.3 .1-1.9 .2l-4.9 0-8.5 0c-55.2 0-108.1-21.9-147.1-60.9L52.7 315.3c-6.2-6.2-6.2-16.4 0-22.6s16.4-6.2 22.6 0L119 336.4c6.9 6.9 17.2 8.9 26.2 5.2s14.8-12.5 14.8-22.2L160 96c0-8.8 7.2-16 16-16c8.8 0 16 7.1 16 15.9L192 232c0 13.3 10.7 24 24 24s24-10.7 24-24l0-135.9z" />
|
||||
</svg>
|
||||
</button>
|
||||
|
||||
{/* Select Tool */}
|
||||
<button
|
||||
<button
|
||||
className={`p-3 transition-colors duration-200 border-b border-gray-200 ${
|
||||
currentTool === "select"
|
||||
? "bg-blue-100 text-blue-700"
|
||||
currentTool === "select"
|
||||
? "bg-blue-100 text-blue-700"
|
||||
: "text-gray-700 hover:bg-gray-50"
|
||||
}`}
|
||||
onClick={() => setCurrentTool("select")}
|
||||
title="Select Tool"
|
||||
>
|
||||
<svg
|
||||
className="w-5 h-5"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
<svg
|
||||
className="w-5 h-5"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="M15 15l-2 5L9 9l11 4-5 2zm0 0l5 5M7.188 2.239l.777 2.897M5.136 7.965l-2.898-.777M13.95 4.05l-2.122 2.122m-5.657 5.656l-2.12 2.122"
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="M15 15l-2 5L9 9l11 4-5 2zm0 0l5 5M7.188 2.239l.777 2.897M5.136 7.965l-2.898-.777M13.95 4.05l-2.122 2.122m-5.657 5.656l-2.12 2.122"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
|
||||
{/* Measure Tool */}
|
||||
<button
|
||||
<button
|
||||
className={`p-3 transition-colors duration-200 border-b border-gray-200 ${
|
||||
currentTool === "measure"
|
||||
? "bg-blue-100 text-blue-700"
|
||||
currentTool === "measure"
|
||||
? "bg-blue-100 text-blue-700"
|
||||
: "text-gray-700 hover:bg-gray-50"
|
||||
}`}
|
||||
onClick={() => setCurrentTool("measure")}
|
||||
title="Measure Distance"
|
||||
>
|
||||
<svg
|
||||
className="w-5 h-5"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
<svg
|
||||
className="w-5 h-5"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="M7 21l10-10M7 21H3v-4l10-10 4 4M7 21l4-4M17 7l4-4M17 7l-4-4M17 7l-4 4"
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="M7 21l10-10M7 21H3v-4l10-10 4 4M7 21l4-4M17 7l4-4M17 7l-4-4M17 7l-4 4"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
|
||||
{/* Draw Tool */}
|
||||
<button
|
||||
<button
|
||||
className={`p-3 transition-colors duration-200 border-b border-gray-200 ${
|
||||
currentTool === "draw"
|
||||
? "bg-blue-100 text-blue-700"
|
||||
currentTool === "draw"
|
||||
? "bg-blue-100 text-blue-700"
|
||||
: "text-gray-700 hover:bg-gray-50"
|
||||
}`}
|
||||
onClick={() => setCurrentTool("draw")}
|
||||
title="Draw/Markup"
|
||||
>
|
||||
<svg
|
||||
className="w-5 h-5"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
<svg
|
||||
className="w-5 h-5"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="M15.232 5.232l3.536 3.536m-2.036-5.036a2.5 2.5 0 113.536 3.536L6.5 21.036H3v-3.572L16.732 3.732z"
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="M15.232 5.232l3.536 3.536m-2.036-5.036a2.5 2.5 0 113.536 3.536L6.5 21.036H3v-3.572L16.732 3.732z"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
|
||||
{/* Pin/Marker Tool */}
|
||||
<button
|
||||
<button
|
||||
className={`p-3 transition-colors duration-200 border-b border-gray-200 ${
|
||||
currentTool === "pin"
|
||||
? "bg-blue-100 text-blue-700"
|
||||
currentTool === "pin"
|
||||
? "bg-blue-100 text-blue-700"
|
||||
: "text-gray-700 hover:bg-gray-50"
|
||||
}`}
|
||||
onClick={() => setCurrentTool("pin")}
|
||||
title="Add Pin/Marker"
|
||||
>
|
||||
<svg
|
||||
className="w-5 h-5"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
<svg
|
||||
className="w-5 h-5"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="M17.657 16.657L13.414 20.9a1.998 1.998 0 01-2.827 0l-4.244-4.243a8 8 0 1111.314 0z"
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="M17.657 16.657L13.414 20.9a1.998 1.998 0 01-2.827 0l-4.244-4.243a8 8 0 1111.314 0z"
|
||||
/>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="M15 11a3 3 0 11-6 0 3 3 0 016 0z"
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="M15 11a3 3 0 11-6 0 3 3 0 016 0z"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
|
||||
{/* Area Tool */}
|
||||
<button
|
||||
<button
|
||||
className={`p-3 transition-colors duration-200 ${
|
||||
currentTool === "area"
|
||||
? "bg-blue-100 text-blue-700"
|
||||
currentTool === "area"
|
||||
? "bg-blue-100 text-blue-700"
|
||||
: "text-gray-700 hover:bg-gray-50"
|
||||
}`}
|
||||
onClick={() => setCurrentTool("area")}
|
||||
title="Measure Area"
|
||||
>
|
||||
<svg
|
||||
className="w-5 h-5"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
<svg
|
||||
className="w-5 h-5"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="M4 8V6a2 2 0 012-2h2M4 16v2a2 2 0 002 2h2m8-16h2a2 2 0 012 2v2m-4 12h2a2 2 0 002-2v-2"
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="M4 8V6a2 2 0 012-2h2M4 16v2a2 2 0 002 2h2m8-16h2a2 2 0 012 2v2m-4 12h2a2 2 0 002-2v-2"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Layer Control Panel - Right Side */}
|
||||
<div className="absolute top-4 right-4 z-[1000] flex flex-col gap-3">
|
||||
{/* Action Buttons */}
|
||||
@@ -635,10 +630,15 @@ export default function ProjectsMapPage() {
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
</div> {/* Layer Control Content */}
|
||||
<div className={`transition-all duration-300 ease-in-out ${
|
||||
showLayerPanel ? "max-h-[70vh] opacity-100 overflow-visible" : "max-h-0 opacity-0 overflow-hidden"
|
||||
}`}>
|
||||
</div>{" "}
|
||||
{/* Layer Control Content */}
|
||||
<div
|
||||
className={`transition-all duration-300 ease-in-out ${
|
||||
showLayerPanel
|
||||
? "max-h-[70vh] opacity-100 overflow-visible"
|
||||
: "max-h-0 opacity-0 overflow-hidden"
|
||||
}`}
|
||||
>
|
||||
<div className="p-4 min-w-80 max-w-96 max-h-[60vh] overflow-y-auto">
|
||||
{/* Base Layers Section */}
|
||||
<div className="mb-4">
|
||||
@@ -697,7 +697,8 @@ export default function ProjectsMapPage() {
|
||||
/>
|
||||
</svg>
|
||||
Overlay Layers
|
||||
</h3> <div className="space-y-2">
|
||||
</h3>{" "}
|
||||
<div className="space-y-2">
|
||||
{mapLayers.overlays.map((layer, index) => (
|
||||
<label
|
||||
key={index}
|
||||
@@ -718,9 +719,9 @@ export default function ProjectsMapPage() {
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div> </div>
|
||||
</div>{" "}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Status Filter Panel - Bottom Left */}
|
||||
<div className="absolute bottom-4 left-4 z-[1000]">
|
||||
<div className="bg-white/95 backdrop-blur-sm rounded-lg shadow-lg px-4 py-3 border border-gray-200">
|
||||
@@ -728,7 +729,6 @@ export default function ProjectsMapPage() {
|
||||
<span className="text-sm font-medium text-gray-700 mr-2">
|
||||
Filters:
|
||||
</span>
|
||||
|
||||
{/* Toggle All Button */}
|
||||
<button
|
||||
onClick={toggleAllFilters}
|
||||
@@ -754,7 +754,6 @@ export default function ProjectsMapPage() {
|
||||
: "Show All"}
|
||||
</span>
|
||||
</button>
|
||||
|
||||
{/* Individual Status Filters */}
|
||||
{Object.entries(statusConfig).map(([status, config]) => {
|
||||
const isActive = statusFilters[status];
|
||||
@@ -795,10 +794,13 @@ export default function ProjectsMapPage() {
|
||||
</span>
|
||||
</button>
|
||||
);
|
||||
})} </div>
|
||||
})}{" "}
|
||||
</div>
|
||||
</div>
|
||||
</div> {/* Status Panel - Bottom Left */}
|
||||
{markers.length > 0 && ( <div className="bg-white/95 backdrop-blur-sm rounded-lg shadow-lg px-4 py-3 border border-gray-200">
|
||||
</div>{" "}
|
||||
{/* Status Panel - Bottom Left */}
|
||||
{markers.length > 0 && (
|
||||
<div className="bg-white/95 backdrop-blur-sm rounded-lg shadow-lg px-4 py-3 border border-gray-200">
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="text-sm font-medium text-gray-700 mr-2">
|
||||
Filters:
|
||||
@@ -873,7 +875,8 @@ export default function ProjectsMapPage() {
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
)} {/* Full Screen Map */}
|
||||
)}{" "}
|
||||
{/* Full Screen Map */}
|
||||
{markers.length === 0 ? (
|
||||
<div className="h-full w-full flex items-center justify-center bg-gray-100">
|
||||
<div className="text-center max-w-md mx-auto p-8 bg-white rounded-lg shadow-lg">
|
||||
@@ -919,6 +922,7 @@ export default function ProjectsMapPage() {
|
||||
onViewChange={handleMapViewChange}
|
||||
/>
|
||||
</div>
|
||||
)} </div>
|
||||
)}{" "}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user