feat: Add translation support for map-related components and improve loading messages
This commit is contained in:
@@ -4,22 +4,15 @@ 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";
|
||||
|
||||
// Dynamically import the map component to avoid SSR issues
|
||||
const DynamicMap = dynamic(() => import("@/components/ui/LeafletMap"), {
|
||||
ssr: false,
|
||||
loading: () => (
|
||||
<div className="w-full h-96 bg-gray-100 animate-pulse rounded-lg flex items-center justify-center">
|
||||
<span className="text-gray-500">Loading map...</span>
|
||||
</div>
|
||||
),
|
||||
});
|
||||
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
|
||||
@@ -36,31 +29,41 @@ function ProjectsMapPageContent() {
|
||||
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: () => (
|
||||
<div className="w-full h-96 bg-gray-100 animate-pulse rounded-lg flex items-center justify-center">
|
||||
<span className="text-gray-500">{t('map.loadingMap')}</span>
|
||||
</div>
|
||||
),
|
||||
});
|
||||
|
||||
// Status configuration with colors and labels
|
||||
const statusConfig = {
|
||||
registered: {
|
||||
color: "#6B7280",
|
||||
label: "Registered",
|
||||
label: formatProjectStatus("registered"),
|
||||
shortLabel: "Zarejestr.",
|
||||
},
|
||||
in_progress_design: {
|
||||
color: "#3B82F6",
|
||||
label: "In Progress (Design)",
|
||||
label: formatProjectStatus("in_progress_design"),
|
||||
shortLabel: "W real. (P)",
|
||||
},
|
||||
in_progress_construction: {
|
||||
color: "#F59E0B",
|
||||
label: "In Progress (Construction)",
|
||||
label: formatProjectStatus("in_progress_construction"),
|
||||
shortLabel: "W real. (R)",
|
||||
},
|
||||
fulfilled: {
|
||||
color: "#10B981",
|
||||
label: "Completed",
|
||||
label: formatProjectStatus("fulfilled"),
|
||||
shortLabel: "Zakończony",
|
||||
},
|
||||
cancelled: {
|
||||
color: "#EF4444",
|
||||
label: "Cancelled",
|
||||
label: formatProjectStatus("cancelled"),
|
||||
shortLabel: "Wycofany",
|
||||
},
|
||||
};
|
||||
@@ -331,7 +334,7 @@ function ProjectsMapPageContent() {
|
||||
d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z"
|
||||
/>
|
||||
</svg>
|
||||
View Project Details
|
||||
{t('map.viewProjectDetails')}
|
||||
</Button>
|
||||
</Link>
|
||||
</div>
|
||||
@@ -346,9 +349,9 @@ function ProjectsMapPageContent() {
|
||||
<div className="fixed inset-0 bg-gray-50 flex items-center justify-center">
|
||||
<div className="text-center">
|
||||
<div className="w-12 h-12 mx-auto mb-4 border-4 border-blue-200 border-t-blue-600 rounded-full animate-spin"></div>
|
||||
<p className="text-gray-600 font-medium">Loading projects map...</p>
|
||||
<p className="text-gray-600 font-medium">{t('map.loadingProjectsMap')}</p>
|
||||
<p className="text-sm text-gray-500 mt-2">
|
||||
Preparing your full-screen map experience
|
||||
{t('map.preparingMap')}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -362,10 +365,10 @@ function ProjectsMapPageContent() {
|
||||
<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-3">
|
||||
<h1 className="text-lg font-semibold text-gray-900">
|
||||
Projects Map
|
||||
{t('map.projectsMap')}
|
||||
</h1>
|
||||
<div className="text-sm text-gray-600">
|
||||
{markers.length} of {projects.length} projects with coordinates
|
||||
{markers.length} of {projects.length} {t('map.projectsWithCoordinates')}
|
||||
</div>
|
||||
</div>{" "}
|
||||
</div>
|
||||
@@ -380,7 +383,7 @@ function ProjectsMapPageContent() {
|
||||
const event = new CustomEvent("mapZoomIn");
|
||||
window.dispatchEvent(event);
|
||||
}}
|
||||
title="Zoom In"
|
||||
title={t('map.zoomIn')}
|
||||
>
|
||||
+
|
||||
</button>
|
||||
@@ -391,7 +394,7 @@ function ProjectsMapPageContent() {
|
||||
const event = new CustomEvent("mapZoomOut");
|
||||
window.dispatchEvent(event);
|
||||
}}
|
||||
title="Zoom Out"
|
||||
title={t('map.zoomOut')}
|
||||
>
|
||||
−
|
||||
</button>{" "}
|
||||
@@ -410,7 +413,7 @@ function ProjectsMapPageContent() {
|
||||
: "text-gray-700 hover:bg-gray-50"
|
||||
}`}
|
||||
onClick={() => setCurrentTool("move")}
|
||||
title="Move Tool (Pan Map)"
|
||||
title={t('map.moveTool')}
|
||||
>
|
||||
<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" />
|
||||
@@ -424,7 +427,7 @@ function ProjectsMapPageContent() {
|
||||
: "text-gray-700 hover:bg-gray-50"
|
||||
}`}
|
||||
onClick={() => setCurrentTool("select")}
|
||||
title="Select Tool"
|
||||
title={t('map.selectTool')}
|
||||
>
|
||||
<svg
|
||||
className="w-5 h-5"
|
||||
@@ -448,7 +451,7 @@ function ProjectsMapPageContent() {
|
||||
: "text-gray-700 hover:bg-gray-50"
|
||||
}`}
|
||||
onClick={() => setCurrentTool("measure")}
|
||||
title="Measure Distance"
|
||||
title={t('map.measureDistance')}
|
||||
>
|
||||
<svg
|
||||
className="w-5 h-5"
|
||||
@@ -472,7 +475,7 @@ function ProjectsMapPageContent() {
|
||||
: "text-gray-700 hover:bg-gray-50"
|
||||
}`}
|
||||
onClick={() => setCurrentTool("draw")}
|
||||
title="Draw/Markup"
|
||||
title={t('map.drawMarkup')}
|
||||
>
|
||||
<svg
|
||||
className="w-5 h-5"
|
||||
@@ -496,7 +499,7 @@ function ProjectsMapPageContent() {
|
||||
: "text-gray-700 hover:bg-gray-50"
|
||||
}`}
|
||||
onClick={() => setCurrentTool("pin")}
|
||||
title="Add Pin/Marker"
|
||||
title={t('map.addPinMarker')}
|
||||
>
|
||||
<svg
|
||||
className="w-5 h-5"
|
||||
@@ -526,7 +529,7 @@ function ProjectsMapPageContent() {
|
||||
: "text-gray-700 hover:bg-gray-50"
|
||||
}`}
|
||||
onClick={() => setCurrentTool("area")}
|
||||
title="Measure Area"
|
||||
title={t('map.measureArea')}
|
||||
>
|
||||
<svg
|
||||
className="w-5 h-5"
|
||||
@@ -567,7 +570,7 @@ function ProjectsMapPageContent() {
|
||||
d="M4 6h16M4 10h16M4 14h16M4 18h16"
|
||||
/>
|
||||
</svg>
|
||||
List View
|
||||
{t('map.listView')}
|
||||
</Button>
|
||||
</Link>
|
||||
<Link href="/projects/new">
|
||||
@@ -585,7 +588,7 @@ function ProjectsMapPageContent() {
|
||||
d="M12 4v16m8-8H4"
|
||||
/>
|
||||
</svg>
|
||||
Add Project
|
||||
{t('map.addProject')}
|
||||
</Button>
|
||||
</Link>
|
||||
</div>
|
||||
@@ -597,7 +600,7 @@ function ProjectsMapPageContent() {
|
||||
<button
|
||||
onClick={toggleLayerPanel}
|
||||
className="flex items-center justify-between w-full text-left layer-toggle-button"
|
||||
title="Toggle Layer Controls"
|
||||
title={t('map.toggleLayerControls')}
|
||||
>
|
||||
<div className="flex items-center gap-2">
|
||||
<svg
|
||||
@@ -614,10 +617,10 @@ function ProjectsMapPageContent() {
|
||||
/>
|
||||
</svg>
|
||||
<span className="text-sm font-medium text-gray-700">
|
||||
Map Layers
|
||||
{t('map.mapLayers')}
|
||||
</span>
|
||||
<span className="text-xs text-gray-500 bg-gray-100 px-2 py-0.5 rounded-full">
|
||||
{1 + activeOverlays.length} active
|
||||
{1 + activeOverlays.length} {t('map.active')}
|
||||
</span>
|
||||
</div>
|
||||
<svg
|
||||
@@ -662,7 +665,7 @@ function ProjectsMapPageContent() {
|
||||
d="M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z"
|
||||
/>
|
||||
</svg>
|
||||
Base Maps
|
||||
{t('map.baseMaps')}
|
||||
</h3>
|
||||
<div className="space-y-2">
|
||||
{mapLayers.base.map((layer, index) => (
|
||||
@@ -702,7 +705,7 @@ function ProjectsMapPageContent() {
|
||||
d="M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6L16 6a5 5 0 011 9.9M9 19l3 3m0 0l3-3m-3 3V10"
|
||||
/>
|
||||
</svg>
|
||||
Overlay Layers
|
||||
{t('map.overlayLayers')}
|
||||
</h3>{" "}
|
||||
<div className="space-y-2">
|
||||
{mapLayers.overlays.map((layer, index) => (
|
||||
@@ -733,7 +736,7 @@ function ProjectsMapPageContent() {
|
||||
<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:
|
||||
{t('map.filters')}
|
||||
</span>
|
||||
{/* Toggle All Button */}
|
||||
<button
|
||||
@@ -774,7 +777,7 @@ function ProjectsMapPageContent() {
|
||||
className={`flex items-center gap-1 px-2 py-1 rounded text-xs font-medium transition-all duration-200 hover:bg-gray-100 ${
|
||||
isActive ? "opacity-100 scale-100" : "opacity-40 scale-95"
|
||||
}`}
|
||||
title={`Toggle ${config.label} (${projectCount} projects)`}
|
||||
title={`Toggle ${config.label} (${projectCount} ${t('map.projects')})`}
|
||||
>
|
||||
<div
|
||||
className={`w-3 h-3 rounded-full border-2 transition-all duration-200 ${
|
||||
@@ -809,7 +812,7 @@ function ProjectsMapPageContent() {
|
||||
<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:
|
||||
{t('map.filters')}
|
||||
</span>
|
||||
|
||||
{/* Toggle All Button */}
|
||||
@@ -833,8 +836,8 @@ function ProjectsMapPageContent() {
|
||||
</svg>
|
||||
<span className="text-gray-600">
|
||||
{Object.values(statusFilters).every((v) => v)
|
||||
? "Hide All"
|
||||
: "Show All"}
|
||||
? t('map.hideAll')
|
||||
: t('map.showAll')}
|
||||
</span>
|
||||
</button>
|
||||
|
||||
@@ -852,7 +855,7 @@ function ProjectsMapPageContent() {
|
||||
className={`flex items-center gap-1 px-2 py-1 rounded text-xs font-medium transition-all duration-200 hover:bg-gray-100 ${
|
||||
isActive ? "opacity-100 scale-100" : "opacity-40 scale-95"
|
||||
}`}
|
||||
title={`Toggle ${config.label} (${projectCount} projects)`}
|
||||
title={`Toggle ${config.label} (${projectCount} ${t('map.projects')})`}
|
||||
>
|
||||
<div
|
||||
className={`w-3 h-3 rounded-full border-2 transition-all duration-200 ${
|
||||
@@ -900,18 +903,17 @@ function ProjectsMapPageContent() {
|
||||
</svg>
|
||||
</div>
|
||||
<h3 className="text-lg font-medium text-gray-900 mb-2">
|
||||
No projects with coordinates
|
||||
{t('map.noProjectsWithCoordinates')}
|
||||
</h3>
|
||||
<p className="text-gray-500 mb-6">
|
||||
Projects need coordinates to appear on the map. Add coordinates
|
||||
when creating or editing projects.
|
||||
{t('map.noProjectsMessage')}
|
||||
</p>
|
||||
<div className="flex gap-3 justify-center">
|
||||
<Link href="/projects">
|
||||
<Button variant="outline">View All Projects</Button>
|
||||
<Button variant="outline">{t('map.viewAllProjects')}</Button>
|
||||
</Link>
|
||||
<Link href="/projects/new">
|
||||
<Button variant="primary">Add Project</Button>
|
||||
<Button variant="primary">{t('map.addProject')}</Button>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user