Files
nodeMap/components/mainComponent/MapComponent.js
2025-05-20 13:58:53 +02:00

1026 lines
40 KiB
JavaScript

// components/mainComponent/MapComponent.js
import React, { useEffect, useRef, useState, useCallback } from "react";
import L from "leaflet";
import "leaflet/dist/leaflet.css";
import "leaflet-contextmenu/dist/leaflet.contextmenu.css";
import "leaflet-contextmenu";
import * as config from "../../config/config.js";
import "leaflet.smooth_marker_bouncing";
import OverlappingMarkerSpiderfier from "overlapping-marker-spiderfier-leaflet"; //sieht deaktiviert aber ist das nicht so und wird benötigt
import "react-toastify/dist/ReactToastify.css";
import DataSheet from "../DataSheet.js";
import { InformationCircleIcon } from "@heroicons/react/20/solid";
import PoiUpdateModal from "../pois/PoiUpdateModal.js";
import { ToastContainer, toast } from "react-toastify";
import plusRoundIcon from "../PlusRoundIcon.js";
import { createAndSetDevices } from "../../utils/devices/createAndSetDevices.js";
import { restoreMapSettings, checkOverlappingMarkers } from "../../utils/mapUtils.js";
import { APP_VERSION } from "../../config/appVersion.js";
import * as layers from "../../config/layers.js";
import addItemsToMapContextMenu from "../useMapContextMenu.js";
import useGmaMarkersLayer from "../../hooks/layers/useGmaMarkersLayer.js";
import useSmsfunkmodemMarkersLayer from "../../hooks/layers/useSmsfunkmodemMarkersLayer.js";
import useBereicheMarkersLayer from "../../hooks/layers/useBereicheMarkersLayer.js";
import { setupPolylines } from "../../utils/polylines/setupPolylines.js";
import { setupPOIs } from "../../utils/setupPOIs.js";
import VersionInfoModal from "../VersionInfoModal.js";
import useLayerVisibility from "../../hooks/useLayerVisibility.js";
import useLineData from "../../hooks/useLineData.js";
import { useMapComponentState } from "../../hooks/useMapComponentState.js";
import { updateLocation } from "../../utils/updateBereichUtil.js";
import { selectMapLayersState } from "../../redux/slices/mapLayersSlice";
import { useSelector, useDispatch } from "react-redux";
import { setCurrentPoi } from "../../redux/slices/currentPoiSlice.js";
import CoordinateInput from "../CoordinateInput.js";
import CoordinateModal from "../CoordinateModal.js";
import CoordinatePopup from "../CoordinatePopup.js";
//------------------------Daten aus API--------------------
import { fetchPoiDataService } from "../../services/database/fetchPoiDataService.js";
import { fetchGisStationsMeasurementsService } from "../../services/webservice/fetchGisStationsMeasurementsService.js";
import { selectPolylineVisible, setPolylineVisible } from "../../redux/slices/polylineLayerVisibleSlice.js";
import { fetchLocationDevicesFromDB } from "../../redux/slices/db/locationDevicesFromDBSlice";
import { fetchGisStationsStaticDistrictFromWebService } from "../../redux/slices/webService/gisStationsStaticDistrictSlice";
import { selectGisStationsStaticDistrict } from "../../redux/slices/webService/gisStationsStaticDistrictSlice";
import { fetchGisStationsStatusDistrictFromWebService } from "../../redux/slices/webService/gisStationsStatusDistrictSlice";
import { fetchGisStationsMeasurementsFromWebService } from "../../redux/slices/webService/gisStationsMeasurementsSlice";
import { fetchGisSystemStaticFromWebService } from "../../redux/slices/webService/gisSystemStaticSlice";
import { selectGisSystemStatic, setGisSystemStatic } from "../../redux/slices/webService/gisSystemStaticSlice";
import ShowAddStationPopup from "../AddPOIModal.js";
import { fetchGisStationsStatic } from "../../redux/slices/webService/gisStationsStaticSlice";
import AddPOIOnPolyline from "../AddPOIOnPolyline";
import { enablePolylineEvents, disablePolylineEvents } from "../../utils/polylines/eventHandlers";
import { updateCountdown, closePolylineContextMenu } from "../../redux/slices/polylineContextMenuSlice";
//-------------------MapComponent.js hooks--------------------
import useInitializeMap from "./hooks/useInitializeMap";
import useLoadUserRights from "./hooks/useLoadUserRights";
import useFetchWebServiceMap from "./hooks/useFetchWebServiceMap";
import useFetchPoiData from "./hooks/useFetchPoiData.js";
import useRestoreMapSettings from "./hooks/useRestoreMapSettings";
import { setSelectedPoi } from "../../redux/slices/selectedPoiSlice";
import { setDisabled } from "../../redux/slices/polylineEventsDisabledSlice";
import { setMapId, setUserId } from "../../redux/slices/urlParameterSlice";
import { fetchPoiTypes } from "../../redux/slices/db/poiTypesSlice";
const MapComponent = ({ locations, onLocationUpdate, lineCoordinates }) => {
const dispatch = useDispatch();
const countdown = useSelector((state) => state.polylineContextMenu.countdown);
const countdownActive = useSelector((state) => state.polylineContextMenu.countdownActive);
const isPolylineContextMenuOpen = useSelector((state) => state.polylineContextMenu.isOpen);
const polylineVisible = useSelector(selectPolylineVisible);
const { deviceName, setDeviceName } = useMapComponentState();
const poiTypStatus = useSelector((state) => state.poiTypes.status);
const isPoiTypLoaded = useSelector((state) => state.poiTypes.status === "succeeded");
const [locationDeviceData, setLocationDeviceData] = useState([]);
const [priorityConfig, setPriorityConfig] = useState([]);
const [menuItemAdded, setMenuItemAdded] = useState(false);
const [isPopupOpen, setIsPopupOpen] = useState(false);
const openPopupWithCoordinates = (e) => {
const coordinates = `${e.latlng.lat.toFixed(5)}, ${e.latlng.lng.toFixed(5)}`;
setCurrentCoordinates(coordinates);
setIsPopupOpen(true);
setPopupCoordinates(e.latlng);
setPopupVisible(true);
};
const closePopup = () => setIsPopupOpen(false);
const [currentCoordinates, setCurrentCoordinates] = useState("");
const poiLayerVisible = useSelector((state) => state.poiLayerVisible.visible);
const [isRightsLoaded, setIsRightsLoaded] = useState(false);
const [hasRights, setHasRights] = useState(false);
const [AddPoiModalWindowState, setAddPoiModalWindowState] = useState(false);
const [userRights, setUserRights] = useState(null);
const [showPoiUpdateModal, setShowPoiUpdateModal] = useState(false);
const [currentPoiData, setCurrentPoiData] = useState(null);
const [showVersionInfoModal, setShowVersionInfoModal] = useState(false);
const zoomTrigger = useSelector((state) => state.zoomTrigger.trigger);
const [gisSystemStaticLoaded, setGisSystemStaticLoaded] = useState(false);
const [poiTypMap, setPoiTypMap] = useState(new Map());
const [showPopup, setShowPopup] = useState(false);
const poiReadTrigger = useSelector((state) => state.poiReadFromDbTrigger.trigger);
const poiLayerRef = useRef(null); // Referenz auf die Layer-Gruppe für Datenbank-Marker
const mapRef = useRef(null); // Referenz auf das DIV-Element der Karte
const [map, setMap] = useState(null); // Zustand der Karteninstanz
const [oms, setOms] = useState(null); // State für OMS-Instanz
const GisStationsStaticDistrict = useSelector(selectGisStationsStaticDistrict);
const [GisStationsStatusDistrict, setGisStationsStatusDistrict] = useState([]); // Zustand für Statusdaten
const [GisStationsMeasurements, setGisStationsMeasurements] = useState([]); // Zustand für Messdaten
const GisSystemStatic = useSelector(selectGisSystemStatic);
// Konstanten für die URLs
const mapGisStationsStatusDistrictUrl = config.mapGisStationsStatusDistrictUrl;
const mapGisStationsMeasurementsUrl = config.mapGisStationsMeasurementsUrl;
const mapGisSystemStaticUrl = config.mapGisSystemStaticUrl;
const webserviceGisLinesStatusUrl = config.webserviceGisLinesStatusUrl;
//console.log("priorityConfig in MapComponent1: ", priorityConfig);
//-----------------------------------------
const [gmaMarkers, setGmaMarkers] = useState([]); //--------------------station.System === 11 alle sind untetschiedlich Nummern
const [talasMarkers, setTalasMarkers] = useState([]);
const [eciMarkers, setEciMarkers] = useState([]);
const [lteModemMarkers, setlteModemMarkers] = useState([]);
const [ciscoRouterMarkers, setCiscoRouterMarkers] = useState([]);
const [wagoMarkers, setWagoMarkers] = useState([]);
const [siemensMarkers, setSiemensMarkers] = useState([]);
const [otdrMarkers, setOtdrMarkers] = useState([]);
const [wdmMarkers, setWdmMarkers] = useState([]);
const [messstellenMarkers, setMessstellenMarkers] = useState([]);
const [talasiclMarkers, setTalasiclMarkers] = useState([]);
const [dauzMarkers, setDauzMarkers] = useState([]);
const [smsfunkmodemMarkers, setSmsfunkmodemMarkers] = useState([]);
const [ulafMarkers, setUlafMarkers] = useState([]);
const [sonstigeMarkers, setSonstigeMarkers] = useState([]);
const [tkComponentsMarkers, setTkComponentsMarkers] = useState([]);
//--------------------------------------------
const [lineStatusData, setLineStatusData] = useState([]);
const [linesData, setLinesData] = useState([]);
const mapLayersVisibility = useSelector(selectMapLayersState) || {};
const selectedArea = useSelector((state) => state.selectedArea.area);
const [linePositions, setLinePositions] = useState([]);
const { lineColors, tooltipContents } = useLineData(webserviceGisLinesStatusUrl, setLineStatusData);
const [polylines, setPolylines] = useState([]);
const [markers, setMarkers] = useState([]);
const [newPoint, setNewPoint] = useState(null);
const [newCoords, setNewCoords] = useState(null);
const [tempMarker, setTempMarker] = useState(null);
const [showPoiModal, setShowPoiModal] = useState(false);
const [showCoordinatesModal, setShowCoordinatesModal] = useState(false);
const [popupCoordinates, setPopupCoordinates] = useState(null);
const [popupVisible, setPopupVisible] = useState(false);
const handleAddStation = (stationData) => {
setAddPoiModalWindowState(false);
closePopup(); // Schließt das Popup nach dem Hinzufügen
};
const openVersionInfoModal = () => {
setShowVersionInfoModal(true);
};
const closeVersionInfoModal = () => {
setShowVersionInfoModal(false);
};
const [currentZoom, setCurrentZoom] = useState(() => {
const storedZoom = localStorage.getItem("mapZoom");
return storedZoom ? parseInt(storedZoom, 10) : 12;
});
const [currentCenter, setCurrentCenter] = useState(() => {
const storedCenter = localStorage.getItem("mapCenter");
try {
return storedCenter ? JSON.parse(storedCenter) : [53.111111, 8.4625];
} catch (e) {
console.error("Error parsing stored map center:", e);
return [53.111111, 8.4625];
}
});
const polylineEventsDisabled = useSelector((state) => state.polylineEventsDisabled.disabled);
const allMarkers = [
...talasMarkers,
...eciMarkers,
...lteModemMarkers,
...ciscoRouterMarkers,
...wagoMarkers,
...siemensMarkers,
...otdrMarkers,
...wdmMarkers,
...gmaMarkers,
...messstellenMarkers,
...talasiclMarkers,
...dauzMarkers,
...smsfunkmodemMarkers,
...sonstigeMarkers,
...tkComponentsMarkers,
...ulafMarkers,
];
const useMock = process.env.NEXT_PUBLIC_USE_MOCK_API === "true";
//--------------------------------------------
const gmaLayerRef = useRef(null);
const talasLayerRef = useRef(null);
const eciMarkersLayerRef = useRef(null);
const lteModemMarkersLayerRef = useRef(null);
const ciscoRouterMarkersLayerRef = useRef(null);
const wagoMarkersLayerRef = useRef(null);
const siemensMarkersLayerRef = useRef(null);
const otdrMarkersLayerRef = useRef(null);
const wdmMarkersLayerRef = useRef(null);
const messstellenMarkersLayerRef = useRef(null);
const talasiclMarkersLayerRef = useRef(null);
const dauzMarkersLayerRef = useRef(null);
const smsfunkmodemMarkersLayerRef = useRef(null);
const ulafMarkersLayerRef = useRef(null);
const sonstigeMarkersLayerRef = useRef(null);
const tkComponentsMarkersRef = useRef(null);
useInitializeMap(map, mapRef, setMap, setOms, setMenuItemAdded, addItemsToMapContextMenu, hasRights, (value) => dispatch(setDisabled(value)));
//---------------------------------------------------------------
useEffect(() => {
const params = new URL(window.location.href).searchParams;
dispatch(setMapId(params.get("m")));
dispatch(setUserId(params.get("u")));
}, [dispatch]);
//---------------------------------------------------------------
useFetchWebServiceMap(mapGisStationsStatusDistrictUrl, mapGisStationsMeasurementsUrl, mapGisSystemStaticUrl, setGisStationsStatusDistrict, setGisStationsMeasurements, setGisSystemStatic, setGisSystemStaticLoaded);
//--------------------------------------------------------
useEffect(() => {
const endpoint = "/api/talas_v5_DB/gisLines/readGisLines";
fetch(endpoint)
.then((response) => response.json())
.then((data) => {
if (data.message) {
console.warn(data.message);
return; // Falls die Tabelle nicht existiert, keine weitere Verarbeitung
}
const newLinePositions = data.map((item) => {
if (item.points && Array.isArray(item.points)) {
return {
coordinates: item.points.map((point) => [point.x, point.y]),
idModul: item.idModul,
idLD: item.idLD,
};
}
throw new Error("Points missing or not an array");
});
setLinePositions(newLinePositions);
})
.catch((error) => {
console.error("Error fetching data:", error.message);
});
}, []);
//--------------------------------------------
const [poiData, setPoiData] = useState([]);
// POIs Popup Informationen anzeigen
useFetchPoiData(setPoiTypMap, setPoiData);
//--------------------------------------------
// POIs auf die Karte zeichnen
useEffect(() => {
if (map && !poiLayerRef.current) {
poiLayerRef.current = new L.LayerGroup().addTo(map);
}
return () => {
if (map && poiLayerRef.current) {
map.removeLayer(poiLayerRef.current);
poiLayerRef.current = new L.LayerGroup().addTo(map);
}
locations.forEach((location) => {});
};
//console.log("trigger in MapComponent.js:", poiReadTrigger);
}, [map, locations, poiReadTrigger]);
//--------------------------------------------
// POIs auf die Karte zeichnen
useEffect(() => {
if (poiData.length === 0) return;
setupPOIs(
map,
locations,
poiData,
poiTypMap,
userRights,
poiLayerRef,
setSelectedPoi,
setLocationDeviceData,
setDeviceName,
setCurrentPoi,
poiLayerVisible,
fetchPoiDataService,
toast,
setShowPoiUpdateModal,
setCurrentPoiData,
deviceName,
dispatch
);
}, [map, locations, onLocationUpdate, poiReadTrigger, isPoiTypLoaded, userRights, poiLayerVisible, poiData, poiTypMap, dispatch]);
//---------------------------------------------
//console.log("priorityConfig in MapComponent2: ", priorityConfig);
useEffect(() => {
if (gisSystemStaticLoaded && map) {
}
}, [gisSystemStaticLoaded, map, GisSystemStatic, priorityConfig]);
//--------------------------------------------
useEffect(() => {
if (map) {
var x = 51.41321407879154;
var y = 7.739617925303934;
var zoom = 7;
if (map && map.flyTo) {
map.flyTo([x, y], zoom);
} else {
console.error("Map object is not ready or does not have flyTo method");
}
}
}, [map, zoomTrigger]);
//--------------------------------------------
useEffect(() => {
if (map) {
// Sammle alle Marker in einer einzigen Liste
const editMode = localStorage.getItem("editMode") === "true"; // EditMode prüfen
const visibility = mapLayersVisibility || {};
allMarkers.forEach((marker) => {
const layerKey = marker.options?.layerKey; // Layer-Key aus den Marker-Optionen
const isVisible = visibility[layerKey]; // Sichtbarkeitsstatus prüfen
if (!layerKey || isVisible === undefined) return;
if (editMode || !isVisible) {
// Entferne Marker, wenn EditMode aktiv ist oder Layer unsichtbar
if (map.hasLayer(marker)) map.removeLayer(marker);
} else {
// Füge Marker hinzu, wenn EditMode deaktiviert ist und Layer sichtbar
if (!map.hasLayer(marker)) marker.addTo(map);
}
});
// Überprüfe überlappende Marker und füge das "Plus"-Icon hinzu
checkOverlappingMarkers(map, allMarkers, plusRoundIcon);
}
}, [
map,
talasMarkers,
eciMarkers,
lteModemMarkers,
ciscoRouterMarkers,
wagoMarkers,
siemensMarkers,
otdrMarkers,
wdmMarkers,
gmaMarkers,
messstellenMarkers,
talasiclMarkers,
dauzMarkers,
smsfunkmodemMarkers,
sonstigeMarkers,
tkComponentsMarkers,
ulafMarkers,
mapLayersVisibility, // Neu: Abhängigkeit für Sichtbarkeitsstatus
]);
//--------------------------------------------
useEffect(() => {
if (poiTypStatus === "idle") {
dispatch(fetchPoiTypes());
}
}, [poiTypStatus, dispatch]);
//--------------------------------------------
useEffect(() => {
const fetchData = async () => {
try {
const response1 = await fetch(webserviceGisLinesStatusUrl);
const data1 = await response1.json();
//console.log("data1.Statis", data1.Statis);
const reversedData = data1.Statis.reverse();
setLineStatusData(reversedData);
const response2 = await fetch("/api/talas_v5_DB/gisLines/readGisLines");
const data2 = await response2.json();
const colorsByModule = {};
reversedData.forEach((stat) => {
if (!Array.isArray(data2)) {
console.warn("WARNUNG: gis_lines ist kein Array, wird ignoriert.");
return;
}
const matchingLine = data2.find((item) => item.idLD === stat.IdLD && item.idModul === stat.Modul);
if (matchingLine) {
colorsByModule[matchingLine.idModul] = stat.PrioColor;
//console.log("Übereinstimmung gefunden für: ", stat);
setLinesData(matchingLine);
}
});
//setLineColors(colorsByModule);
} catch (error) {
console.error("Error fetching data:", error);
}
};
fetchData();
}, []);
//-----------------------------------------------------------------
//Tooltip an mouse position anzeigen für die Linien
useEffect(() => {
if (!map) return;
// Entferne alte Marker und Polylinien
markers.forEach((marker) => marker.remove());
polylines.forEach((polyline) => polyline.remove());
// Setze neue Marker und Polylinien mit den aktuellen Daten
const { markers: newMarkers, polylines: newPolylines } = setupPolylines(
map,
linePositions,
lineColors,
tooltipContents,
setNewCoords,
tempMarker,
currentZoom,
currentCenter,
polylineVisible // kommt aus Redux
);
newPolylines.forEach((polyline, index) => {
//console.log("polyline: ", polyline);
const tooltipContent = tooltipContents[`${linePositions[index].idLD}-${linePositions[index].idModul}`] || "Standard-Tooltip-Inhalt";
polyline.bindTooltip(tooltipContent, {
permanent: false,
direction: "auto",
sticky: true,
offset: [20, 0],
pane: "tooltipPane",
});
polyline.on("mouseover", (e) => {
const tooltip = polyline.getTooltip();
if (tooltip) {
const mousePos = e.containerPoint;
const mapSize = map.getSize();
let direction = "right";
if (mousePos.x > mapSize.x - 100) {
direction = "left";
} else if (mousePos.x < 100) {
direction = "right";
}
if (mousePos.y > mapSize.y - 100) {
direction = "top";
} else if (mousePos.y < 100) {
direction = "bottom";
}
tooltip.options.direction = direction;
polyline.openTooltip(e.latlng);
}
});
polyline.on("mouseout", () => {
polyline.closeTooltip();
});
});
setMarkers(newMarkers);
setPolylines(newPolylines);
}, [map, linePositions, lineColors, tooltipContents, newPoint, newCoords, tempMarker, polylineVisible]);
//--------------------------------------------
useRestoreMapSettings(map);
//Test in useEffect
useEffect(() => {
if (map) {
console.log("🗺️ Map-Einstellungen werden wiederhergestellt...");
restoreMapSettings(map);
}
}, [map]);
//--------------------------------------------
useEffect(() => {
if (map) {
console.log("map in MapComponent: ", map);
const handleMapMoveEnd = (event) => {
const newCenter = map.getCenter();
const newZoom = map.getZoom();
setCurrentCenter([newCenter.lat, newCenter.lng]);
setCurrentZoom(newZoom);
localStorage.setItem("mapCenter", JSON.stringify([newCenter.lat, newCenter.lng]));
localStorage.setItem("mapZoom", newZoom);
};
map.on("moveend", handleMapMoveEnd);
map.on("zoomend", handleMapMoveEnd);
return () => {
map.off("moveend", handleMapMoveEnd);
map.off("zoomend", handleMapMoveEnd);
};
}
}, [map]);
//--------------------------------------------
// Bereich in DataSheet ->dropdownmenu
useEffect(() => {
//console.log("🔍 GisStationsStaticDistrict Inhalt:", GisStationsStaticDistrict);
// Sicherstellen, dass `Points` existiert und ein Array ist
const points = GisStationsStaticDistrict?.Points;
if (selectedArea && map) {
const station = points.find((s) => s.Area_Name === selectedArea);
if (station) {
console.log("📌 Gefundene Station:", station);
map.flyTo([station.X, station.Y], 14);
} else {
console.warn("⚠️ Keine passende Station für die Area gefunden:", selectedArea);
}
}
}, [selectedArea, map, GisStationsStaticDistrict]);
//-------------------------------------
useEffect(() => {
if (zoomTrigger && map) {
map.flyTo([51.41321407879154, 7.739617925303934], 7);
}
}, [zoomTrigger, map]);
//--------------------------------------------
useEffect(() => {
if (map && poiLayerRef.current && isPoiTypLoaded && !menuItemAdded && isRightsLoaded) {
addItemsToMapContextMenu(map, menuItemAdded, setMenuItemAdded, hasRights, setShowPopup, setPopupCoordinates);
}
}, [map, poiLayerRef, isPoiTypLoaded, menuItemAdded, hasRights, isRightsLoaded]);
//--------------------------------------------
// rote Marker ganz oben wenn überlappen sind
useEffect(() => {
const fetchPriorityConfig = async () => {
try {
const res = await fetch("/api/talas_v5_DB/priorityConfig");
if (!res.ok) {
throw new Error(`HTTP error! status: ${res.status}`);
}
const data = await res.json();
setPriorityConfig(data);
} catch (error) {
console.error("Failed to load priority configuration:", error);
}
};
fetchPriorityConfig();
}, []);
//--------------------------------------------
useEffect(() => {
if (map) {
if (polylineEventsDisabled) {
disablePolylineEvents(window.polylines);
} else {
enablePolylineEvents(window.polylines, window.lineColors);
}
}
}, [map, polylineEventsDisabled]);
//--------------------------------------------
useEffect(() => {
if (map) {
console.log("6- Karteninstanz (map) wurde jetzt erfolgreich initialisiert");
}
}, [map]);
//--------------------------------------------
useEffect(() => {
const initializeContextMenu = () => {
if (map) {
map.whenReady(() => {
setTimeout(() => {
if (map.contextmenu) {
//console.log("Contextmenu ist vorhanden");
} else {
console.warn("Contextmenu ist nicht verfügbar.");
}
}, 500);
});
}
};
initializeContextMenu();
}, [map]);
//--------------------------------------------
//Tooltip Werte aktualisieren
useEffect(() => {
if (!map) return; // Stelle sicher, dass die Karte initialisiert ist
const updateGmaData = async () => {
try {
const fetchOptions = {
method: "GET",
headers: {
Connection: "close",
},
};
// Aktualisiere die Messdaten
await fetchGisStationsMeasurements(mapGisStationsMeasurementsUrl, setGisStationsMeasurements, fetchOptions);
// Aktualisiere die Marker-Layer
// useGmaMarkersLayer(map, gmaMarkers, GisStationsMeasurements, layers.MAP_LAYERS.GMA, oms);
} catch (error) {
console.error("Fehler beim Aktualisieren der GMA-Daten:", error);
}
};
// Initialer Datenabruf
updateGmaData();
// Setze ein Intervall, um die Daten alle 5 Sekunden zu aktualisieren
/* const intervalId = setInterval(() => {
updateGmaData();
}, 5000);
// Cleanup-Funktion, um das Intervall zu entfernen, wenn die Komponente entladen wird
return () => clearInterval(intervalId); */
}, [map, gmaMarkers, layers.MAP_LAYERS.GMA, oms, mapGisStationsMeasurementsUrl]);
//---------------------------------
//--------------hokks-------------------------------------------
useLoadUserRights(setUserRights, setIsRightsLoaded, setHasRights);
useGmaMarkersLayer(
map,
gmaMarkers,
GisStationsMeasurements,
layers.MAP_LAYERS.GMA,
oms,
mapLayersVisibility.GMA // Übergebe die Sichtbarkeitsbedingung als Parameter
);
//--------------------------------------------
//useCreateAndSetDevices(1, talasMarkers, GisSystemStatic, priorityConfig);
useLayerVisibility(map, talasMarkers, mapLayersVisibility, "TALAS", oms);
useLayerVisibility(map, eciMarkers, mapLayersVisibility, "ECI", oms);
useLayerVisibility(map, lteModemMarkers, mapLayersVisibility, "LTEModem", oms);
useLayerVisibility(map, ciscoRouterMarkers, mapLayersVisibility, "CiscoRouter", oms);
//useLayerVisibility(map, lteModemMarkers, mapLayersVisibility, "LTEModem", oms);
useLayerVisibility(map, wagoMarkers, mapLayersVisibility, "WAGO", oms);
useLayerVisibility(map, siemensMarkers, mapLayersVisibility, "Siemens", oms);
useLayerVisibility(map, otdrMarkers, mapLayersVisibility, "OTDR", oms);
useLayerVisibility(map, wdmMarkers, mapLayersVisibility, "WDM", oms);
useLayerVisibility(map, gmaMarkers, mapLayersVisibility, "GMA", oms);
useLayerVisibility(map, sonstigeMarkers, mapLayersVisibility, "Sonstige", oms);
useLayerVisibility(map, tkComponentsMarkers, mapLayersVisibility, "TKKomponenten", oms);
useLayerVisibility(map, talasiclMarkers, mapLayersVisibility, "TALASICL", oms);
useLayerVisibility(map, dauzMarkers, mapLayersVisibility, "DAUZ", oms);
useLayerVisibility(map, smsfunkmodemMarkers, mapLayersVisibility, "SMSModem", oms);
useLayerVisibility(map, messstellenMarkers, mapLayersVisibility, "Messstellen", oms);
useLayerVisibility(map, ulafMarkers, mapLayersVisibility, "ULAF", oms);
//--------------------------------------------
useEffect(() => {
if (!gisSystemStaticLoaded || !map) return; // Sicherstellen, dass die Karte und Daten geladen sind
const layerGroups = [
{ ref: gmaLayerRef, id: 11, setState: setGmaMarkers },
{ ref: talasLayerRef, id: 1, setState: setTalasMarkers },
{ ref: eciMarkersLayerRef, id: 2, setState: setEciMarkers },
{ ref: lteModemMarkersLayerRef, id: 5, setState: setlteModemMarkers },
{ ref: ciscoRouterMarkersLayerRef, id: 6, setState: setCiscoRouterMarkers },
{ ref: wagoMarkersLayerRef, id: 7, setState: setWagoMarkers },
{ ref: siemensMarkersLayerRef, id: 8, setState: setSiemensMarkers },
{ ref: otdrMarkersLayerRef, id: 9, setState: setOtdrMarkers },
{ ref: wdmMarkersLayerRef, id: 10, setState: setWdmMarkers },
{ ref: messstellenMarkersLayerRef, id: 13, setState: setMessstellenMarkers },
{ ref: talasiclMarkersLayerRef, id: 100, setState: setTalasiclMarkers },
{ ref: dauzMarkersLayerRef, id: 110, setState: setDauzMarkers },
{ ref: smsfunkmodemMarkersLayerRef, id: 111, setState: setSmsfunkmodemMarkers },
{ ref: ulafMarkersLayerRef, id: 0, setState: setUlafMarkers },
{ ref: sonstigeMarkersLayerRef, id: 200, setState: setSonstigeMarkers },
{ ref: tkComponentsMarkersRef, id: 30, setState: setTkComponentsMarkers },
];
// Initialisiere LayerGroups nur einmal
layerGroups.forEach(({ ref }) => {
if (!ref.current) {
ref.current = new L.LayerGroup().addTo(map);
}
});
//--------------------------------------------
const updateMarkers = ({ ref, id, setState }) => {
if (ref.current) {
ref.current.clearLayers(); // Entferne alte Marker
}
// Erstelle und füge neue Marker hinzu
createAndSetDevices(
id,
(newMarkers) => {
setState(newMarkers); // Zustand aktualisieren
newMarkers.forEach((marker) => ref.current.addLayer(marker)); // Marker zur LayerGroup hinzufügen
// Überprüfe auf überlappende Marker und füge das Plus-Icon hinzu
checkOverlappingMarkers(map, newMarkers, plusRoundIcon);
},
GisSystemStatic,
priorityConfig
);
};
// Aktualisiere alle Marker-Gruppen
const updateAllMarkers = () => {
layerGroups.forEach(updateMarkers);
};
// Initiales Update
updateAllMarkers();
// Setze ein Intervall für regelmäßige Updates
const intervalId = setInterval(() => {
updateAllMarkers();
if (map) {
// console.log("🔥 Automatischer Klick-Event ausgelöst, um Spiderfy zu aktualisieren.");
map.fire("click");
}
if (isPolylineContextMenuOpen) {
dispatch(closePolylineContextMenu()); // Schließe das Kontextmenü, bevor das nächste Update passiert
}
if (map) {
// console.log("🔥 nochmal klick.");
map.fire("click");
}
}, 20000);
// Aufräumen bei Komponentenentladung
return () => {
clearInterval(intervalId); // Entferne Intervall
// LayerGroups leeren
layerGroups.forEach(({ ref }) => {
if (ref.current) {
ref.current.clearLayers();
}
});
};
}, [gisSystemStaticLoaded, map, GisSystemStatic, priorityConfig]);
//---------------------------------------
// Initialisiere Leaflet-Karte
// Rufe useBereicheMarkersLayer direkt auf
//const [bereichUrl, setBereichUrl] = useState(null);
const urlParams = new URLSearchParams(window.location.search); // URL-Parameter parsen
const mValue = urlParams.get("m"); // Wert von "m" holen
const hostname = window.location.hostname; // Dynamischer Hostname
const port = 3000; // Definiere den gewünschten Port
const bereichUrl = `http://${hostname}:${port}/api/talas_v5_DB/bereich/readBereich?m=${mValue}`; // Dynamischer Hostname und Port
// Bereichs-Marker basierend auf dynamischer URL laden
const handleLocationUpdate = async (idLocation, idMap, newCoords) => {
try {
const result = await updateLocation(idLocation, idMap, newCoords); // Update-API
console.log("Koordinaten erfolgreich aktualisiert:", result);
} catch (error) {
console.error("Fehler beim Aktualisieren der Location:", error);
}
};
// Bereichs-Marker basierend auf dynamischer URL laden
const bereicheMarkers = useBereicheMarkersLayer(map, oms, bereichUrl, handleLocationUpdate);
/*
Bereichsmarker werden jetzt nur angezeigt, wenn der editMode aktiviert ist.
Marker werden bei deaktiviertem editMode aus der Karte entfernt.
Dynamische Überwachung von Änderungen im editMode über localStorage und Event Listener implementiert.
Dragging für Marker im editMode aktiviert und Z-Index angepasst.
*/
useEffect(() => {
const editMode = localStorage.getItem("editMode") === "true";
// Prüfe, ob der editMode deaktiviert ist
if (!editMode) {
// Entferne alle Marker aus der Karte
if (!map) return; // Sicherstellen, dass map existiert
bereicheMarkers.forEach((marker) => {
if (map.hasLayer(marker)) {
map.removeLayer(marker);
}
});
} else {
// Wenn editMode aktiviert ist, füge die Marker hinzu und aktiviere Dragging
bereicheMarkers.forEach((marker) => {
if (!map.hasLayer(marker)) {
marker.addTo(map); // Layer hinzufügen
}
marker.dragging.enable();
marker.setZIndexOffset(1000); // Marker nach oben setzen
});
}
}, [bereicheMarkers, map]);
//----------------------------------
useEffect(() => {
const handleVisibilityChange = () => {
// Erneut die Marker-Überprüfung auslösen
checkOverlappingMarkers(map, allMarkers, plusRoundIcon);
};
window.addEventListener("visibilityChanged", handleVisibilityChange);
return () => {
window.removeEventListener("visibilityChanged", handleVisibilityChange);
};
}, [map, allMarkers]);
//---------------------------------------
useEffect(() => {
if (map) {
// initGeocoderFeature(map); // Geocoder-Feature initialisieren, kann von .env.local ausgeschaltet werden
}
}, [map]);
//--------------------------------------------
const fetchGisStationsStaticDistrict = async (idMap, idUser, dispatch) => {
try {
// API-Endpunkt mit Query-Parametern aufrufen
const response = await fetch(`/api/gisStationsStaticDistrict?m=${idMap}&u=${idUser}`);
if (!response.ok) {
throw new Error("Netzwerkantwort war nicht ok.");
}
const data = await response.json();
// Ergebnis im Dispatch speichern oder State aktualisieren
dispatch({ type: "SET_GIS_STATIONS", payload: data });
//console.log("Daten erfolgreich geladen:", data);
return data; // Optional: Rückgabe der Daten
} catch (error) {
console.error("Fehler beim Laden der GIS-Daten:", error);
throw error;
}
};
const [isDataLoaded, setIsDataLoaded] = useState(false);
useEffect(() => {
const fetchData = async () => {
try {
const idMap = 12; // Beispielwert für die Map-ID
const idUser = 484; // Beispielwert für die Benutzer-ID
// Daten aus der API abrufen
await fetchGisStationsStaticDistrict(idMap, idUser, dispatch);
setIsDataLoaded(true); // Daten erfolgreich geladen
} catch (error) {
console.error("Fehler beim Laden der Daten:", error);
setIsDataLoaded(false); // Fehler beim Laden
}
};
fetchData();
}, [dispatch]);
//--------------------------------------------
const handleCoordinatesSubmit = (coords) => {
const [lat, lng] = coords.split(",").map(Number);
if (map && lat && lng) {
map.flyTo([lat, lng], 12); // Zentriere die Karte auf die Koordinaten
}
};
//--------------------------------------------
useEffect(() => {
if (map && !menuItemAdded) {
addItemsToMapContextMenu(
map,
menuItemAdded,
setMenuItemAdded,
setShowCoordinatesModal,
setShowPoiModal,
setPopupCoordinates,
openPopupWithCoordinates // Diese Funktion wird jetzt übergeben!
);
}
}, [map, menuItemAdded]);
//--------------------------------------------
// Beim ersten Client-Render den Wert aus localStorage laden
useEffect(() => {
const storedPolylineVisible = localStorage.getItem("polylineVisible") === "true";
dispatch(setPolylineVisible(storedPolylineVisible));
}, [dispatch]);
//----------------------------------------------
// speichere location devices in redux store
useEffect(() => {
dispatch(fetchLocationDevicesFromDB());
}, [dispatch]);
useEffect(() => {
dispatch(fetchGisStationsStaticDistrictFromWebService());
}, [dispatch]);
useEffect(() => {
dispatch(fetchGisStationsStatusDistrictFromWebService());
}, [dispatch]);
useEffect(() => {
dispatch(fetchGisStationsMeasurementsFromWebService());
}, [dispatch]);
useEffect(() => {
dispatch(fetchGisSystemStaticFromWebService());
}, [dispatch]);
const gisStationsStatic = useSelector((state) => state.gisStationsStatic.data);
useEffect(() => {
if (!gisStationsStatic) {
dispatch(fetchGisStationsStatic());
}
}, [gisStationsStatic, dispatch]);
//--------------------------------------
useEffect(() => {
if (isPolylineContextMenuOpen && countdownActive) {
//console.log("🔄 Starte Redux-Countdown für Kontextmenü!");
const interval = setInterval(() => {
dispatch(updateCountdown());
// console.log(`⏳ Redux Countdown: ${countdown} Sekunden`);
if (countdown <= 2) {
console.log("🚀 Kontextmenü wird wegen Countdown < 2 geschlossen.");
dispatch(closePolylineContextMenu());
if (window.map?.contextmenu) {
window.map.contextmenu.hide();
}
clearInterval(interval);
}
}, 1000);
return () => {
clearInterval(interval);
};
}
}, [isPolylineContextMenuOpen, countdown, countdownActive, dispatch, window.map]);
//----------------------------------
useEffect(() => {
if (map) {
window.map = map;
console.log("✅ window.map wurde gesetzt:", window.map);
}
}, [map]);
//---------------------------------------
useEffect(() => {
window.onerror = function (message, source, lineno, colno, error) {
if (message.includes("Cannot read properties of null (reading 'contextmenu')")) {
console.warn("⚠️ Fehler mit `contextmenu` erkannt - Neuladen der Seite.");
setTimeout(() => {
window.location.reload();
}, 0); // **Seite nach Sekunde neu laden**
return true; // **Fehler unterdrücken, damit React ihn nicht anzeigt**
}
};
return () => {
window.onerror = null; // **Fehlerbehandlung entfernen, wenn Komponente unmounted wird**
};
}, []);
//---------------------------------------------
//--------------------------------------------
return (
<>
{useSelector((state) => state.addPoiOnPolyline.isOpen) && <AddPOIOnPolyline />}
{/* Zeigt das Koordinaten-Modal, wenn `showCoordinatesModal` true ist */}
{showCoordinatesModal && <CoordinateModal latlng={popupCoordinates} onClose={() => setShowCoordinatesModal(false)} />}
{/* Zeigt das POI-Modal, wenn `showPoiModal` true ist */}
{showPoiModal && <ShowAddStationPopup latlng={popupCoordinates} onClose={() => setShowPoiModal(false)} />}
<ToastContainer />
<div>{showPoiUpdateModal && <PoiUpdateModal onClose={() => setShowPoiUpdateModal(false)} poiData={currentPoiData} onSubmit={() => {}} latlng={popupCoordinates} />}</div>
<div>
{showPopup && (
<div className="fixed inset-0 bg-black bg-opacity-10 flex justify-center items-center z-[1000]" onClick={closePopup}>
<div className="relative bg-white p-6 rounded-lg shadow-lg" onClick={(e) => e.stopPropagation()}>
<button onClick={closePopup} className="absolute top-0 right-0 mt-2 mr-2 p-1 text-gray-700 hover:text-gray-900 focus:outline-none focus:ring-2 focus:ring-gray-600" aria-label="Close">
<svg xmlns="http://www.w3.org/2000/svg" className="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
</div>
</div>
)}
</div>
{isDataLoaded && <DataSheet className="z-50" />}
<CoordinateInput onCoordinatesSubmit={handleCoordinatesSubmit} />
<div id="map" ref={mapRef} className="z-0" style={{ height: "100vh", width: "100vw" }}></div>
<CoordinatePopup isOpen={isPopupOpen} coordinates={currentCoordinates} onClose={closePopup} />
<div className="absolute bottom-3 left-3 w-72 p-4 bg-white rounded-lg shadow-md z-50">
<div className="flex justify-between items-center">
<div>
<span className="text-black text-lg font-semibold"> TALAS.Map </span>
<br />
<span className="text-black text-lg">Version {APP_VERSION}</span>
</div>
<div>
<button onClick={openVersionInfoModal}>
<InformationCircleIcon className="text-blue-900 h-8 w-8 pr-1" title="Weitere Infos" />
</button>
</div>
</div>
</div>
<VersionInfoModal showVersionInfoModal={showVersionInfoModal} closeVersionInfoModal={closeVersionInfoModal} APP_VERSION={APP_VERSION} />
</>
);
};
export default MapComponent;