diff --git a/src/app/globals.css b/src/app/globals.css index 7edbe08..cfa705c 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -58,3 +58,39 @@ body { .animate-fade-in { animation: fadeIn 0.3s ease-out; } + +/* Full-screen map styles */ +.map-fullscreen-container { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + overflow: hidden; + z-index: 50; +} + +/* Ensure map takes full container */ +.leaflet-container { + height: 100% !important; + width: 100% !important; +} + +/* Override any margin/padding that might cause scrollbars */ +.map-page { + margin: 0 !important; + padding: 0 !important; + overflow: hidden !important; +} + +/* Ensure floating panels are above map controls */ +.map-floating-panel { + z-index: 1000 !important; + backdrop-filter: blur(8px); + -webkit-backdrop-filter: blur(8px); +} + +/* Map controls positioning */ +.leaflet-control-container .leaflet-top.leaflet-right { + top: 80px !important; /* Account for floating header */ +} diff --git a/src/app/projects/map/page.js b/src/app/projects/map/page.js new file mode 100644 index 0000000..1d0491a --- /dev/null +++ b/src/app/projects/map/page.js @@ -0,0 +1,359 @@ +"use client"; + +import React, { useEffect, useState } from "react"; +import Link from "next/link"; +import dynamic from "next/dynamic"; +import Button from "@/components/ui/Button"; + +// Dynamically import the map component to avoid SSR issues +const DynamicMap = dynamic(() => import("@/components/ui/LeafletMap"), { + ssr: false, + loading: () => ( +
+ Loading map... +
+ ), +}); + +export default function ProjectsMapPage() { + const [projects, setProjects] = useState([]); + const [loading, setLoading] = useState(true); + const [mapCenter, setMapCenter] = useState([50.0614, 19.9366]); // Default to Krakow, Poland + // Hide navigation and ensure full-screen layout + useEffect(() => { + // 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 = ""; + }; + }, []); + + useEffect(() => { + fetch("/api/projects") + .then((res) => res.json()) + .then((data) => { + setProjects(data); + + // 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); + }); + }, []); + + // Convert projects to map markers + const markers = projects + .filter((project) => project.coordinates) + .map((project) => { + const [lat, lng] = project.coordinates + .split(",") + .map((coord) => parseFloat(coord.trim())); + + if (isNaN(lat) || isNaN(lng)) { + return null; + } + return { + position: [lat, lng], + 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: + + {project.project_status === "registered" + ? "Zarejestr." + : project.project_status === "in_progress_design" + ? "W real. (P)" + : project.project_status === "in_progress_construction" + ? "W real. (R)" + : project.project_status === "fulfilled" + ? "Zakończony" + : project.project_status} + +
+ )} +
+ +
+ + + +
+
+ ), + }; + }) + .filter((marker) => marker !== null); + if (loading) { + return ( +
+
+
+

Loading projects map...

+

+ Preparing your full-screen map experience +

+
+
+ ); + } + return ( +
+ {/* Floating Header with Controls */} +
+
+
+

+ Projects Map +

+
+ {markers.length} of {projects.length} projects with coordinates +
+
+
+ +
+ + + + + + +
+
+ + {/* Stats Panel - Bottom Left */} + {markers.length > 0 && ( +
+
+
+
+ + {markers.length} projects shown + +
+ {projects.length > markers.length && ( +
+
+ + {projects.length - markers.length} missing coordinates + +
+ )} +
+
+ )} + + {/* Help Panel - Bottom Right */} +
+
+ Click markers for details • Use 📚 to switch layers +
+
+ + {/* Full Screen Map */} + {markers.length === 0 ? ( +
+
+
+ + + +
+

+ No projects with coordinates +

+

+ Projects need coordinates to appear on the map. Add coordinates + when creating or editing projects. +

+
+ + + + + + +
+
+
+ ) : ( +
+ +
+ )} +
+ ); +} diff --git a/src/app/projects/page.js b/src/app/projects/page.js index e592696..9a7be3e 100644 --- a/src/app/projects/page.js +++ b/src/app/projects/page.js @@ -61,24 +61,44 @@ export default function ProjectListPage() { return ( - - - +
+ + + + + + +