- Add kabelstreckenVisible state with localStorage persistence - Implement dual localStorage variables (kabelstreckenVisible + polylineVisible) for compatibility - Add event system for cross-component polyline visibility updates - Update MapComponent to listen for polylineVisibilityChanged events - Ensure polylines display correctly on browser reload - Migrate from Redux-only state to localStorage-first approach - Add comprehensive debug logging for troubleshooting Fixes issue where Kabelstrecken checkbox state was lost on page reload and polylines were not displayed until manual toggle.
371 lines
14 KiB
JavaScript
371 lines
14 KiB
JavaScript
// /components/uiWidgets/mapLayersControlPanel/MapLayersControlPanel.js
|
||
import React, { useEffect, useState } from "react";
|
||
import { setSelectedArea } from "@/redux/slices/selectedAreaSlice";
|
||
import EditModeToggle from "@/components/uiWidgets/mapLayersControlPanel/EditModeToggle";
|
||
import { useSelector, useDispatch } from "react-redux";
|
||
import {
|
||
selectPolylineVisible,
|
||
setPolylineVisible,
|
||
} from "@/redux/slices/database/polylines/polylineLayerVisibleSlice";
|
||
import { selectGisSystemStatic } from "@/redux/slices/webservice/gisSystemStaticSlice";
|
||
import { selectGisStationsStaticDistrict } from "@/redux/slices/webservice/gisStationsStaticDistrictSlice";
|
||
import { selectMapLayersState, setLayerVisibility } from "@/redux/slices/mapLayersSlice";
|
||
import { setVisible } from "@/redux/slices/database/pois/poiLayerVisibleSlice";
|
||
import { incrementZoomTrigger } from "@/redux/slices/zoomTriggerSlice";
|
||
|
||
function MapLayersControlPanel() {
|
||
const [editMode, setEditMode] = useState(false); // Zustand für editMode
|
||
const [localStorageLoaded, setLocalStorageLoaded] = useState(false); // Tracking ob localStorage geladen wurde
|
||
const [kabelstreckenVisible, setKabelstreckenVisible] = useState(false); // Lokaler State für Kabelstrecken
|
||
const poiVisible = useSelector(state => state.poiLayerVisible.visible);
|
||
const setPoiVisible = value => dispatch(setVisible(value));
|
||
const dispatch = useDispatch();
|
||
const mapLayersVisibility = useSelector(selectMapLayersState);
|
||
const [stationListing, setStationListing] = useState([]);
|
||
const [systemListing, setSystemListing] = useState([]);
|
||
const GisStationsStaticDistrict = useSelector(selectGisStationsStaticDistrict) || [];
|
||
const GisSystemStatic = useSelector(selectGisSystemStatic) || [];
|
||
|
||
// Debug: Kabelstrecken state verfolgen
|
||
useEffect(() => {
|
||
console.log("🎯 kabelstreckenVisible state changed to:", kabelstreckenVisible);
|
||
}, [kabelstreckenVisible]);
|
||
|
||
// Prüfen, ob TALAS (IdSystem 1) erlaubt ist
|
||
const isTalasAllowed = Array.isArray(GisSystemStatic)
|
||
? GisSystemStatic.some(system => system.IdSystem === 1 && system.Allow === 1)
|
||
: false;
|
||
|
||
const handlePolylineCheckboxChange = event => {
|
||
const checked = event.target.checked;
|
||
console.log("🖱️ Kabelstrecken checkbox clicked, new value:", checked);
|
||
|
||
// Beide localStorage-Variablen setzen für Kompatibilität
|
||
setKabelstreckenVisible(checked);
|
||
localStorage.setItem("kabelstreckenVisible", checked.toString());
|
||
localStorage.setItem("polylineVisible", checked.toString()); // Auch die alte Variable setzen
|
||
console.log("💾 Saved to localStorage as kabelstreckenVisible:", checked);
|
||
console.log("💾 Saved to localStorage as polylineVisible:", checked);
|
||
|
||
// Redux für andere Teile der App aktualisieren
|
||
dispatch(setPolylineVisible(checked));
|
||
|
||
// Event auslösen, damit andere Komponenten über die Änderung informiert werden
|
||
setTimeout(() => {
|
||
const event = new Event("polylineVisibilityChanged");
|
||
window.dispatchEvent(event);
|
||
console.log("📢 Event 'polylineVisibilityChanged' dispatched");
|
||
}, 100);
|
||
|
||
if (checked) {
|
||
dispatch(setLayerVisibility({ layer: "TALAS", visibility: true }));
|
||
localStorage.setItem(
|
||
"mapLayersVisibility",
|
||
JSON.stringify({ ...mapLayersVisibility, TALAS: true })
|
||
);
|
||
}
|
||
};
|
||
|
||
useEffect(() => {
|
||
// LocalStorage Werte beim ersten Laden der Komponente wiederherstellen
|
||
console.log("🔄 Loading localStorage values...");
|
||
|
||
const storedPoiVisible = localStorage.getItem("poiVisible");
|
||
console.log("📦 POI localStorage value:", storedPoiVisible);
|
||
if (storedPoiVisible !== null) {
|
||
setPoiVisible(storedPoiVisible === "true");
|
||
}
|
||
|
||
// Neue Variable für Kabelstrecken mit Fallback auf die alte Variable
|
||
let storedKabelstreckenVisible = localStorage.getItem("kabelstreckenVisible");
|
||
const storedPolylineVisible = localStorage.getItem("polylineVisible");
|
||
|
||
// Falls kabelstreckenVisible nicht existiert, aber polylineVisible schon, übernehmen wir den Wert
|
||
if (storedKabelstreckenVisible === null && storedPolylineVisible !== null) {
|
||
storedKabelstreckenVisible = storedPolylineVisible;
|
||
localStorage.setItem("kabelstreckenVisible", storedPolylineVisible);
|
||
console.log("<22> Migrated polylineVisible to kabelstreckenVisible:", storedPolylineVisible);
|
||
}
|
||
|
||
console.log("<22>📦 Kabelstrecken localStorage value:", storedKabelstreckenVisible);
|
||
console.log("📦 Polyline localStorage value:", storedPolylineVisible);
|
||
|
||
if (storedKabelstreckenVisible !== null) {
|
||
const shouldBeVisible = storedKabelstreckenVisible === "true";
|
||
console.log("🎯 Setting kabelstreckenVisible to:", shouldBeVisible);
|
||
setKabelstreckenVisible(shouldBeVisible);
|
||
|
||
// Beide localStorage-Variablen synchronisieren
|
||
localStorage.setItem("polylineVisible", shouldBeVisible.toString());
|
||
// Redux für Konsistenz setzen
|
||
dispatch(setPolylineVisible(shouldBeVisible));
|
||
|
||
// Event auslösen nach dem Laden
|
||
setTimeout(() => {
|
||
const event = new Event("polylineVisibilityChanged");
|
||
window.dispatchEvent(event);
|
||
console.log("📢 Event 'polylineVisibilityChanged' dispatched on load");
|
||
}, 200);
|
||
}
|
||
|
||
const storedMapLayersVisibility = localStorage.getItem("mapLayersVisibility");
|
||
console.log("📦 MapLayers localStorage value:", storedMapLayersVisibility);
|
||
if (storedMapLayersVisibility) {
|
||
const parsedVisibility = JSON.parse(storedMapLayersVisibility);
|
||
Object.keys(parsedVisibility).forEach(key => {
|
||
dispatch(setLayerVisibility({ layer: key, visibility: parsedVisibility[key] }));
|
||
});
|
||
}
|
||
|
||
const storedEditMode = localStorage.getItem("editMode");
|
||
console.log("📦 EditMode localStorage value:", storedEditMode);
|
||
setEditMode(storedEditMode === "true");
|
||
|
||
setLocalStorageLoaded(true);
|
||
}, []); // Läuft nur beim Mount
|
||
|
||
// Entferne den komplexen Konsistenz-Check useEffect - nicht mehr nötig
|
||
// da wir direkt mit localStorage arbeiten
|
||
|
||
const handleAreaChange = event => {
|
||
const selectedIndex = event.target.options.selectedIndex;
|
||
const areaName = event.target.options[selectedIndex].text;
|
||
dispatch(setSelectedArea(areaName));
|
||
};
|
||
|
||
useEffect(() => {
|
||
const allowedSystems = Array.isArray(GisSystemStatic)
|
||
? new Set(GisSystemStatic.filter(system => system.Allow === 1).map(system => system.IdSystem))
|
||
: new Set();
|
||
|
||
const seenNames = new Set();
|
||
const filteredAreas = GisStationsStaticDistrict?.Points?.length
|
||
? GisStationsStaticDistrict.Points.filter(item => {
|
||
const isUnique = !seenNames.has(item.Area_Name) && allowedSystems.has(item.System);
|
||
if (isUnique) {
|
||
seenNames.add(item.Area_Name);
|
||
}
|
||
return isUnique;
|
||
})
|
||
: [];
|
||
|
||
setStationListing(
|
||
filteredAreas.map((area, index) => ({
|
||
id: index + 1,
|
||
name: area.Area_Name,
|
||
}))
|
||
);
|
||
|
||
const seenSystemNames = new Set();
|
||
const filteredSystems = Array.isArray(GisSystemStatic)
|
||
? GisSystemStatic.filter(item => {
|
||
const isUnique = !seenSystemNames.has(item.Name) && item.Allow === 1;
|
||
if (isUnique) {
|
||
seenSystemNames.add(item.Name);
|
||
}
|
||
return isUnique;
|
||
})
|
||
: [];
|
||
|
||
setSystemListing(
|
||
filteredSystems.map((system, index) => ({
|
||
id: index + 1,
|
||
name: system.Name, // Verwende den Originalnamen für die Anzeige
|
||
key: `system-${system.IdSystem}`, // Internen Schlüssel für die MapLayersVisibility-Logik
|
||
}))
|
||
);
|
||
}, [GisStationsStaticDistrict, GisSystemStatic]);
|
||
|
||
const handleCheckboxChange = (key, event) => {
|
||
if (editMode) return;
|
||
const { checked } = event.target;
|
||
|
||
dispatch(setLayerVisibility({ layer: key, visibility: checked }));
|
||
localStorage.setItem(
|
||
"mapLayersVisibility",
|
||
JSON.stringify({ ...mapLayersVisibility, [key]: checked })
|
||
);
|
||
|
||
setTimeout(() => {
|
||
const event = new Event("visibilityChanged");
|
||
window.dispatchEvent(event);
|
||
}, 0);
|
||
};
|
||
|
||
const handlePoiCheckboxChange = event => {
|
||
const { checked } = event.target;
|
||
setPoiVisible(checked);
|
||
localStorage.setItem("poiVisible", checked.toString()); // Store POI visibility in localStorage
|
||
};
|
||
|
||
const handleIconClick = () => {
|
||
setSelectedArea("Station wählen");
|
||
dispatch(incrementZoomTrigger());
|
||
};
|
||
|
||
//------------------------------
|
||
useEffect(() => {
|
||
if (process.env.NEXT_PUBLIC_DEBUG_LOG === "true") {
|
||
window.__debug = window.__debug || {};
|
||
window.__debug.gisStations = GisStationsStaticDistrict;
|
||
}
|
||
|
||
if (!GisStationsStaticDistrict) {
|
||
console.warn("⚠️ GisStationsStaticDistrict ist `null` oder nicht geladen.");
|
||
return;
|
||
}
|
||
|
||
if (typeof GisStationsStaticDistrict !== "object") {
|
||
console.warn("⚠️ GisStationsStaticDistrict ist kein Objekt:", GisStationsStaticDistrict);
|
||
return;
|
||
}
|
||
|
||
if (!GisStationsStaticDistrict.Points || !Array.isArray(GisStationsStaticDistrict.Points)) {
|
||
console.warn(
|
||
"⚠️ GisStationsStaticDistrict.Points ist nicht vorhanden oder kein Array.",
|
||
GisStationsStaticDistrict
|
||
);
|
||
return;
|
||
}
|
||
|
||
const seenNames = new Set();
|
||
const filteredAreas = GisStationsStaticDistrict.Points.filter(item => {
|
||
if (!item.Area_Name) return false; // Sicherstellen, dass Area_Name existiert
|
||
const isUnique = !seenNames.has(item.Area_Name);
|
||
if (isUnique) {
|
||
seenNames.add(item.Area_Name);
|
||
}
|
||
return isUnique;
|
||
});
|
||
if (process.env.NEXT_PUBLIC_DEBUG_LOG === "true") {
|
||
console.log("📌 stationListing aktualisiert:", filteredAreas);
|
||
}
|
||
}, [GisStationsStaticDistrict, GisSystemStatic]);
|
||
//---------------------------
|
||
useEffect(() => {
|
||
const next = (GisStationsStaticDistrict.Points || []).map(p => p.Area_Name).join("|");
|
||
const current = stationListing.map(s => s.name).join("|");
|
||
if (next !== current) {
|
||
setStationListing(
|
||
GisStationsStaticDistrict.Points.map((area, index) => ({
|
||
id: index + 1,
|
||
name: area.Area_Name,
|
||
}))
|
||
);
|
||
}
|
||
}, [GisStationsStaticDistrict]);
|
||
//---------------------------
|
||
|
||
//---------------------------
|
||
return (
|
||
<div
|
||
id="mainDataSheet"
|
||
className="absolute top-3 right-3 w-1/6 min-w-[300px] max-w-[400px] z-10 bg-white p-2 rounded-lg shadow-lg"
|
||
>
|
||
<div className="flex flex-col gap-4 p-4">
|
||
<div className="flex items-center justify-between space-x-2">
|
||
<select
|
||
onChange={handleAreaChange}
|
||
id="stationListing"
|
||
className="border-solid-1 p-2 rounded ml-1 font-semibold"
|
||
style={{ minWidth: "150px", maxWidth: "200px" }}
|
||
>
|
||
<option value="Station wählen">Station wählen</option>
|
||
{[
|
||
...new Map(
|
||
(GisStationsStaticDistrict.Points || [])
|
||
.filter(p => !!p.Area_Name)
|
||
.map(p => [p.Area_Name, p])
|
||
).values(),
|
||
].map((item, index) => (
|
||
<option key={item.Area_Name} value={item.IdLD}>
|
||
{item.Area_Name}
|
||
</option>
|
||
))}
|
||
</select>
|
||
<div className="flex items-center space-x-2">
|
||
<EditModeToggle />
|
||
<img
|
||
src="/img/expand-icon.svg"
|
||
alt="Expand"
|
||
className="h-6 w-6 cursor-pointer"
|
||
onClick={handleIconClick}
|
||
/>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Checkboxen mit Untermenüs */}
|
||
<div className="flex flex-col gap-2">
|
||
{systemListing.map(system => (
|
||
<div key={system.id} className="flex flex-col">
|
||
<div className="flex items-center">
|
||
<input
|
||
type="checkbox"
|
||
checked={mapLayersVisibility[system.key] || false}
|
||
onChange={e => handleCheckboxChange(system.key, e)}
|
||
id={`system-${system.id}`}
|
||
disabled={editMode} // Checkbox deaktiviert, wenn editMode aktiv ist
|
||
/>
|
||
<label htmlFor={`system-${system.id}`} className="text-sm ml-2">
|
||
{system.name}
|
||
</label>
|
||
</div>
|
||
|
||
{/* Untermenü für TALAS */}
|
||
{system.name === "TALAS" && (
|
||
<div className="ml-6 flex flex-col gap-1">
|
||
<div className="flex items-center">
|
||
<input
|
||
type="checkbox"
|
||
checked={kabelstreckenVisible} // Lokaler State statt Redux
|
||
onChange={handlePolylineCheckboxChange}
|
||
id="polyline-checkbox"
|
||
disabled={!isTalasAllowed || editMode}
|
||
/>
|
||
<label htmlFor="polyline-checkbox" className="text-sm ml-2">
|
||
Kabelstrecken
|
||
</label>
|
||
</div>
|
||
</div>
|
||
)}
|
||
</div>
|
||
))}
|
||
|
||
<div className="flex items-center">
|
||
<input
|
||
type="checkbox"
|
||
checked={poiVisible}
|
||
onChange={handlePoiCheckboxChange}
|
||
id="poi-checkbox"
|
||
/>
|
||
<label htmlFor="poi-checkbox" className="text-sm ml-2">
|
||
POIs
|
||
</label>
|
||
</div>
|
||
|
||
{/* Areas
|
||
<div className="flex items-center">
|
||
<input type="checkbox" checked={areaVisible} onChange={handleAreaCheckboxChange} id="area-checkbox" />
|
||
<label htmlFor="area-checkbox" className="text-sm ml-2">
|
||
Bereiche
|
||
</label>
|
||
</div>
|
||
*/}
|
||
|
||
{/* Standorte
|
||
<div className="flex items-center">
|
||
<input type="checkbox" checked={standordVisible} onChange={handleStandorteCheckboxChange} id="area-checkbox" />
|
||
<label htmlFor="area-checkbox" className="text-sm ml-2">
|
||
Standorte
|
||
</label>
|
||
</div>
|
||
|
||
*/}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
);
|
||
}
|
||
|
||
export default MapLayersControlPanel;
|