"use client"; import React, { useEffect, useState, Suspense } from "react"; import Link from "next/link"; import dynamic from "next/dynamic"; import { useSearchParams, useRouter } from "next/navigation"; import { useTranslation } from "@/lib/i18n"; import Button from "@/components/ui/Button"; import { mapLayers } from "@/components/ui/mapLayers"; import { formatProjectStatus } from "@/lib/utils"; function ProjectsMapPageContent() { const searchParams = useSearchParams(); const router = useRouter(); const { t } = useTranslation(); const [projects, setProjects] = useState([]); const [loading, setLoading] = useState(true); const [mapCenter, setMapCenter] = useState([50.0614, 19.9366]); // Default to Krakow, Poland const [mapZoom, setMapZoom] = useState(10); // Default zoom level const [statusFilters, setStatusFilters] = useState({ registered: true, in_progress_design: true, in_progress_construction: true, fulfilled: true, cancelled: true, }); const [activeBaseLayer, setActiveBaseLayer] = useState("OpenStreetMap"); const [activeOverlays, setActiveOverlays] = useState([]); const [showLayerPanel, setShowLayerPanel] = useState(true); const [currentTool, setCurrentTool] = useState("move"); // Current map tool // Dynamically import the map component to avoid SSR issues const DynamicMap = dynamic(() => import("@/components/ui/LeafletMap"), { ssr: false, loading: () => (
{t('map.loadingMap')}
), }); // Status configuration with colors and labels const statusConfig = { registered: { color: "#6B7280", label: formatProjectStatus("registered"), shortLabel: "Zarejestr.", }, in_progress_design: { color: "#3B82F6", label: formatProjectStatus("in_progress_design"), shortLabel: "W real. (P)", }, in_progress_construction: { color: "#F59E0B", label: formatProjectStatus("in_progress_construction"), shortLabel: "W real. (R)", }, fulfilled: { color: "#10B981", label: formatProjectStatus("fulfilled"), shortLabel: "Zakończony", }, cancelled: { color: "#EF4444", label: formatProjectStatus("cancelled"), shortLabel: "Wycofany", }, }; // Toggle all status filters const toggleAllFilters = () => { const allActive = Object.values(statusFilters).every((value) => value); const newState = allActive ? Object.keys(statusFilters).reduce( (acc, key) => ({ ...acc, [key]: false }), {} ) : Object.keys(statusFilters).reduce( (acc, key) => ({ ...acc, [key]: true }), {} ); setStatusFilters(newState); }; // Toggle status filter const toggleStatusFilter = (status) => { setStatusFilters((prev) => ({ ...prev, [status]: !prev[status], })); }; // Layer control functions const handleBaseLayerChange = (layerName) => { setActiveBaseLayer(layerName); }; const toggleOverlay = (layerName) => { setActiveOverlays((prev) => { if (prev.includes(layerName)) { return prev.filter((name) => name !== layerName); } else { return [...prev, layerName]; } }); }; const toggleLayerPanel = () => { setShowLayerPanel(!showLayerPanel); }; // 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()); // Use replace to avoid cluttering browser history router.replace(`/projects/map?${params.toString()}`, { scroll: false }); }; // Handle map view changes with debouncing const handleMapViewChange = (center, zoom) => { setMapCenter(center); setMapZoom(zoom); // Debounce URL updates to avoid too many history entries clearTimeout(window.mapUpdateTimeout); window.mapUpdateTimeout = setTimeout(() => { updateURL(center, zoom); }, 500); // Wait 500ms after the last move to update URL }; // 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"); if (lat && lng) { const latitude = parseFloat(lat); const longitude = parseFloat(lng); if (!isNaN(latitude) && !isNaN(longitude)) { setMapCenter([latitude, longitude]); } } if (zoom) { const zoomLevel = parseInt(zoom); if (!isNaN(zoomLevel) && zoomLevel >= 1 && zoomLevel <= 20) { setMapZoom(zoomLevel); } } // Hide navigation bar for full-screen experience const nav = document.querySelector("nav"); if (nav) { nav.style.display = "none"; } // Prevent scrolling on body document.body.style.overflow = "hidden"; document.documentElement.style.overflow = "hidden"; // Cleanup when leaving page return () => { if (nav) { nav.style.display = ""; } document.body.style.overflow = ""; document.documentElement.style.overflow = ""; // Clear any pending URL updates if (window.mapUpdateTimeout) { clearTimeout(window.mapUpdateTimeout); } }; }, [searchParams]); useEffect(() => { fetch("/api/projects") .then((res) => res.json()) .then((data) => { setProjects(data); // Only calculate center based on projects if no URL parameters are provided 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); if (projectsWithCoords.length > 0) { const avgLat = projectsWithCoords.reduce((sum, p) => { const [lat] = p.coordinates .split(",") .map((coord) => parseFloat(coord.trim())); return sum + lat; }, 0) / projectsWithCoords.length; const avgLng = projectsWithCoords.reduce((sum, p) => { const [, lng] = p.coordinates .split(",") .map((coord) => parseFloat(coord.trim())); return sum + lng; }, 0) / projectsWithCoords.length; setMapCenter([avgLat, avgLng]); } } setLoading(false); }) .catch((error) => { console.error("Error fetching projects:", error); setLoading(false); }); }, [searchParams]); // Convert projects to map markers with filtering const markers = projects .filter((project) => project.coordinates) .filter((project) => statusFilters[project.project_status] !== false) .map((project) => { const [lat, lng] = project.coordinates .split(",") .map((coord) => parseFloat(coord.trim())); if (isNaN(lat) || isNaN(lng)) { return null; } const statusInfo = statusConfig[project.project_status] || statusConfig.registered; return { position: [lat, lng], color: statusInfo.color, popup: (

{project.project_name}

{project.project_number && (
{project.project_number}
)}
{project.address && (
{project.address} {project.city && ( , {project.city} )}
)}
{project.wp && (
WP:{" "} {project.wp}
)} {project.plot && (
Plot:{" "} {project.plot}
)}
{project.project_status && (
Status: {statusInfo.shortLabel}
)}
), }; }) .filter((marker) => marker !== null); if (loading) { return (

{t('map.loadingProjectsMap')}

{t('map.preparingMap')}

); } return (
{/* Floating Header - Left Side */}
{/* Title Box */}

{t('map.projectsMap')}

{markers.length} of {projects.length} {t('map.projectsWithCoordinates')}
{" "}
{/* Zoom Controls - Below Title */}
{" "}
{" "} {/* Tool Panel - Below Zoom Controls */}
{" "}
{" "} {/* Move Tool */} {/* Select Tool */} {/* Measure Tool */} {/* Draw Tool */} {/* Pin/Marker Tool */} {/* Area Tool */}
{/* Layer Control Panel - Right Side */}
{/* Action Buttons */}
{/* Layer Control Panel */}
{/* Layer Control Header */}
{" "} {/* Layer Control Content */}
{/* Base Layers Section */}

{t('map.baseMaps')}

{mapLayers.base.map((layer, index) => ( ))}
{/* Overlay Layers Section */} {mapLayers.overlays && mapLayers.overlays.length > 0 && (

{t('map.overlayLayers')}

{" "}
{mapLayers.overlays.map((layer, index) => ( ))}
)}
{" "}
{/* Status Filter Panel - Bottom Left */}
{t('map.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 && (
{t('map.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 ( ); })}
)}{" "} {/* Full Screen Map */} {markers.length === 0 ? (

{t('map.noProjectsWithCoordinates')}

{t('map.noProjectsMessage')}

) : (
)}{" "}
); } export default function ProjectsMapPage() { return (

Loading map...

}>
); }