diff --git a/components/DataSheet.js b/components/DataSheet.js index f46dba6e3..da5723b0b 100644 --- a/components/DataSheet.js +++ b/components/DataSheet.js @@ -4,16 +4,14 @@ import { gisStationsStaticDistrictState } from "../redux/slices/gisStationsStati import { gisSystemStaticState } from "../redux/slices/gisSystemStaticSlice"; import { mapLayersState } from "../redux/slices/mapLayersSlice"; import { selectedAreaState } from "../redux/slices/selectedAreaSlice"; -//import { zoomTriggerState } from "../redux/slices/zoomTriggerSlice.js"; +import { zoomTriggerState } from "../redux/slices/zoomTriggerSlice.js"; import { poiLayerVisibleState } from "../redux/slices/poiLayerVisibleSlice"; import EditModeToggle from "./EditModeToggle"; import { polylineLayerVisibleState } from "../redux/slices/polylineLayerVisibleSlice"; // Import für Polyline-Visibility -import { useSelector, useDispatch } from "react-redux"; +import { useSelector } from "react-redux"; import { selectGisStationsStaticDistrict } from "../redux/slices/gisStationsStaticDistrictSlice"; -import { incrementZoomTrigger, selectZoomTrigger } from "../redux/slices/zoomTriggerSlice"; function DataSheet() { - const dispatch = useDispatch(); const [editMode, setEditMode] = useState(false); // Zustand für editMode const [poiVisible, setPoiVisible] = useRecoilState(poiLayerVisibleState); const setSelectedArea = useSetRecoilState(selectedAreaState); @@ -23,7 +21,7 @@ function DataSheet() { //const GisStationsStaticDistrict = useRecoilValue(gisStationsStaticDistrictState); const GisStationsStaticDistrict = useSelector(selectGisStationsStaticDistrict); const GisSystemStatic = useRecoilValue(gisSystemStaticState); - const setZoomTrigger = useSelector(selectZoomTrigger); + const setZoomTrigger = useSetRecoilState(zoomTriggerState); const [polylineVisible, setPolylineVisible] = useRecoilState(polylineLayerVisibleState); // Zustand für Polylines const [bereicheVisible, setBereicheVisible] = useState(false); // NEU: Bereiche-Status const [standordVisible, setStandorteVisible] = useState(false); // NEU: Standorte-Status diff --git a/components/MapComponent.js b/components/MapComponent.js index 2d0ee01fd..638790fb7 100644 --- a/components/MapComponent.js +++ b/components/MapComponent.js @@ -56,15 +56,12 @@ import { gisStationsStaticDistrictState } from "../redux/slices/gisStationsStati import { gisSystemStaticState } from "../redux/slices/gisSystemStaticSlice"; import { mapLayersState } from "../redux/slices/mapLayersSlice"; import { selectedAreaState } from "../redux/slices/selectedAreaSlice"; -//import { zoomTriggerState } from "../redux/slices/zoomTriggerSlice.js"; -import { incrementZoomTrigger, selectZoomTrigger } from "../redux/slices/zoomTriggerSlice.js"; +import { zoomTriggerState } from "../redux/slices/zoomTriggerSlice.js"; import { polylineEventsDisabledState } from "../redux/slices/polylineEventsDisabledSlice"; import { polylineLayerVisibleState } from "../redux/slices/polylineLayerVisibleSlice"; //-------------------------------------------- import { useSelector, useDispatch } from "react-redux"; import { selectCurrentPoi, setCurrentPoi, clearCurrentPoi } from "../redux/slices/currentPoiSlice"; -import { selectMapId, selectUserId, setMapId, setUserId } from "../redux/slices/urlParameterSlice"; -import { setSelectedPoi } from "../redux/slices/selectedPoiSlice"; const MapComponent = ({ locations, onLocationUpdate, lineCoordinates }) => { const dispatch = useDispatch(); @@ -81,19 +78,16 @@ const MapComponent = ({ locations, onLocationUpdate, lineCoordinates }) => { const poiLayerVisible = useRecoilValue(poiLayerVisibleState); const [isRightsLoaded, setIsRightsLoaded] = useState(false); const [hasRights, setHasRights] = useState(false); - //const [mapId, setMapId] = useRecoilState(mapIdState); - //const [userId, setUserId] = useRecoilState(userIdState); - const mapId = useSelector(selectMapId); - const userId = useSelector(selectUserId); + const [mapId, setMapId] = useRecoilState(mapIdState); + const [userId, setUserId] = useRecoilState(userIdState); const [AddPoiModalWindowState, setAddPoiModalWindowState] = useState(false); const [userRights, setUserRights] = useState(null); - //const setSelectedPoi = useSetRecoilState(selectedPoiState); - dispatch(setSelectedPoi(poiData)); + const setSelectedPoi = useSetRecoilState(selectedPoiState); const [showPoiUpdateModal, setShowPoiUpdateModal] = useState(false); const [currentPoiData, setCurrentPoiData] = useState(null); const [showVersionInfoModal, setShowVersionInfoModal] = useState(false); - const zoomTrigger = useSelector(selectZoomTrigger); + const zoomTrigger = useRecoilValue(zoomTriggerState); const [gisSystemStaticLoaded, setGisSystemStaticLoaded] = useState(false); const [poiTypMap, setPoiTypMap] = useState(new Map()); const [showPopup, setShowPopup] = useState(false); @@ -182,31 +176,44 @@ const MapComponent = ({ locations, onLocationUpdate, lineCoordinates }) => { }); const [polylineEventsDisabled, setPolylineEventsDisabled] = useRecoilState(polylineEventsDisabledState); // Recoil State - //---------------------------------------------------------------############################################ + //--------------------------------------------------------------- + + /* useEffect(() => { + fetchGisStatusStations(12, 484); // Beispielaufruf mit idMap = 10 und idUser = 484 + }, []); */ - // Zustand aktualisieren useEffect(() => { const params = new URL(window.location.href).searchParams; + setMapId(params.get("m")); + setUserId(params.get("u")); + }, [setMapId, setUserId]); - const mapId = params.get("m"); - const userId = params.get("u"); - - if (!mapId || !userId) { - alert("Fehlende URL-Parameter: 'm' und 'u' sind erforderlich."); // Fehlermeldung anzeigen - console.error("Fehlende Parameter: 'm' und/oder 'u'"); - return; // Abbrechen, wenn Parameter fehlen + /* useEffect(() => { + if (map && poiLayerRef.current && isPoiTypLoaded && !menuItemAdded && isRightsLoaded) { + //console.log("Überprüfung der Berechtigung vor addItemsToMapContextMenu: ", hasRights); + addItemsToMapContextMenu(hasRights); } + }, [ + map, + poiLayerRef, + isPoiTypLoaded, + menuItemAdded, // Hinzufügen zu den Abhängigkeiten, um den Effekt korrekt zu steuern + hasRights, // Sicherstellen, dass hasRights berücksichtigt wird + isRightsLoaded, // Überprüfung, ob die Rechte geladen sind + ]); */ - // Werte setzen - dispatch(setMapId(mapId)); - dispatch(setUserId(userId)); - }, [dispatch]); + useEffect(() => { + const fetchAndSetUserRights = async () => { + const rights = await fetchUserRights(); + setUserRights(rights); + setIsRightsLoaded(true); - //--------------------------------------------------------------- - // Benutzerrechte abrufen und setzen - useFetchUserRights(setUserRights, setIsRightsLoaded, setHasRights); + // Sicherstellen, dass `rights` ein Array ist, bevor `.includes()` aufgerufen wird + setHasRights(localStorage.getItem("editMode") && Array.isArray(rights) && rights.includes(56)); + }; - //--------------------------------------------------------------- + fetchAndSetUserRights(); + }, []); useGmaMarkersLayer( map, @@ -216,7 +223,7 @@ const MapComponent = ({ locations, onLocationUpdate, lineCoordinates }) => { oms, mapLayersVisibility.GMA // Übergebe die Sichtbarkeitsbedingung als Parameter ); - //--------------------------------------------------------------- + /* useSmsfunkmodemMarkersLayer( map, oms, @@ -224,18 +231,51 @@ const MapComponent = ({ locations, onLocationUpdate, lineCoordinates }) => { priorityConfig, mapLayersVisibility.SMSFunkmodem // Sichtbarkeitsstatus aus dem State ); */ - //--------------------------------------------------------------- - useFetchWebServiceMap( - dispatch, - mapGisStationsStaticDistrictUrl, - mapGisStationsStatusDistrictUrl, - mapGisStationsMeasurementsUrl, - mapGisSystemStaticUrl, - setGisStationsStatusDistrict, - setGisStationsMeasurements, - setGisSystemStatic, - setGisSystemStaticLoaded - ); + + useEffect(() => { + const fetchWebServiceMap = async () => { + try { + // Zähler für externe API-Aufrufe in localStorage speichern + let requestCount = localStorage.getItem("fetchWebServiceMap") || 0; + requestCount = parseInt(requestCount, 10); + + const fetchOptions = { + method: "GET", + headers: { + Connection: "close", // Keep-Alive-Header hinzufügen + }, + }; + + // Fetch GIS Stations Static District + await fetchGisStationsStaticDistrict(mapGisStationsStaticDistrictUrl, dispatch, fetchOptions); + requestCount++; // Zähler erhöhen + localStorage.setItem("fetchWebServiceMap", requestCount); + //console.log(`fetchWebServiceMap in MapComponent wurde ${requestCount} Mal aufgerufen.`); + + // Fetch GIS Stations Status District + await fetchGisStationsStatusDistrict(mapGisStationsStatusDistrictUrl, setGisStationsStatusDistrict, fetchOptions); + requestCount++; // Zähler erhöhen + localStorage.setItem("fetchWebServiceMap", requestCount); + //console.log(`fetchWebServiceMap in MapComponent wurde ${requestCount} Mal aufgerufen.`); + + // Fetch GIS Stations Measurements + await fetchGisStationsMeasurements(mapGisStationsMeasurementsUrl, setGisStationsMeasurements, fetchOptions); + requestCount++; // Zähler erhöhen + localStorage.setItem("fetchWebServiceMap", requestCount); + //console.log(`fetchWebServiceMap in MapComponent wurde ${requestCount} Mal aufgerufen.`); + + // Fetch GIS System Static + await fetchGisSystemStatic(mapGisSystemStaticUrl, setGisSystemStatic, setGisSystemStaticLoaded, fetchOptions); + requestCount++; // Zähler erhöhen + localStorage.setItem("fetchWebServiceMap", requestCount); + //console.log(`fetchWebServiceMap in MapComponent wurde ${requestCount} Mal aufgerufen.`); + } catch (error) { + console.error("Error fetching data:", error); + } + }; + + fetchWebServiceMap(); + }, [dispatch, mapGisStationsStaticDistrictUrl]); //-------------------------------------------------------- useDrawLines(setLinePositions); // Linien auf die Karte zeichnen @@ -408,14 +448,103 @@ const MapComponent = ({ locations, onLocationUpdate, lineCoordinates }) => { sonstigeMarkers, tkComponentsMarkers, ulafMarkers, - mapLayersVisibility, + mapLayersVisibility, // Neu: Abhängigkeit für Sichtbarkeitsstatus ]); //-------------------------------------------- - useFetchLineStatusData(webserviceGisLinesStatusUrl, setLineStatusData, setLinesData); - //-------------------------------------------- + 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) => { + 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, + polylineVisible // polylineVisible wird jetzt korrekt übergeben + ); + + newPolylines.forEach((polyline, index) => { + 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]); - usePolylineTooltipLayer(map, markers, polylines, setMarkers, setPolylines, linePositions, lineColors, tooltipContents, setNewCoords, tempMarker, polylineVisible, newPoint, newCoords); //-------------------------------------------- useEffect(() => { @@ -470,7 +599,22 @@ const MapComponent = ({ locations, onLocationUpdate, lineCoordinates }) => { }, [map, poiLayerRef, isPoiTypLoaded, menuItemAdded, hasRights, isRightsLoaded]); //-------------------------------------------- // rote Marker ganz oben wenn überlappen sind - useFetchPriorityConfig(setPriorityConfig); + 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 (mapRef.current && !map) { @@ -514,7 +658,39 @@ const MapComponent = ({ locations, onLocationUpdate, lineCoordinates }) => { }, [map]); //-------------------------------------------- //Tooltip Werte aktualisieren - useUpdateGmaData(map, setGisStationsMeasurements, mapGisStationsMeasurementsUrl, gmaMarkers, layers, oms); + 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]); //--------------------------------- diff --git a/components/PoiUpdateModal.js b/components/PoiUpdateModal.js index e00e4ec72..9e4919dbc 100644 --- a/components/PoiUpdateModal.js +++ b/components/PoiUpdateModal.js @@ -4,13 +4,10 @@ import React, { useState, useEffect } from "react"; import { useRecoilValue } from "recoil"; import { selectedPoiState } from "../redux/slices/selectedPoiSlice"; import { currentPoiState } from "../redux/slices/currentPoiSlice"; -import { useSelector } from "react-redux"; -import { selectSelectedPoi } from "../../redux/slices/selectedPoiSlice"; const PoiUpdateModal = ({ onClose, poiData }) => { const currentPoi = useRecoilValue(currentPoiState); - //const selectedPoi = useRecoilValue(selectedPoiState); - const selectedPoi = useSelector(selectSelectedPoi); + const selectedPoi = useRecoilValue(selectedPoiState); const [poiId, setPoiId] = useState(poiData ? poiData.idPoi : ""); const [name, setName] = useState(poiData ? poiData.name : ""); const [poiTypData, setPoiTypData] = useState([]); diff --git a/components/pois/PoiUpdateModalWrapper.js b/components/pois/PoiUpdateModalWrapper.js index 9c0a16e6d..4916c9cd6 100644 --- a/components/pois/PoiUpdateModalWrapper.js +++ b/components/pois/PoiUpdateModalWrapper.js @@ -4,13 +4,9 @@ import PoiUpdateModal from "./PoiUpdateModal"; import { useRecoilValue, useSetRecoilState } from "recoil"; import { currentPoiState, selectedPoiState } from "../../redux/slices/currentPoiSlice"; import { poiReadFromDbTriggerAtom } from "../../redux/slices/poiReadFromDbTriggerSlice"; -import { useDispatch } from "react-redux"; -import { setSelectedPoi } from "../../redux/slices/selectedPoiSlice"; const PoiUpdateModalWrapper = ({ show, onClose, latlng }) => { - const dispatch = useDispatch(); - //const setSelectedPoi = useSetRecoilState(selectedPoiState); - dispatch(setSelectedPoi(poiData)); + const setSelectedPoi = useSetRecoilState(selectedPoiState); const setCurrentPoi = useSetRecoilState(currentPoiState); const currentPoi = useRecoilValue(currentPoiState); const poiReadTrigger = useRecoilValue(poiReadFromDbTriggerAtom); diff --git a/config/appVersion.js b/config/appVersion.js index 70fc54f22..503c61edb 100644 --- a/config/appVersion.js +++ b/config/appVersion.js @@ -1,2 +1,2 @@ // /config/appVersion -export const APP_VERSION = "1.0.17.0"; +export const APP_VERSION = "1.0.18.0"; diff --git a/redux/reducer.js b/redux/reducer.js index 65929113b..2d75946d6 100644 --- a/redux/reducer.js +++ b/redux/reducer.js @@ -2,16 +2,10 @@ import { combineReducers } from "redux"; import currentPoiReducer from "./slices/currentPoiSlice"; import gisStationsStaticDistrictReducer from "./slices/gisStationsStaticDistrictSlice"; -import zoomTriggerReducer from "./slices/zoomTriggerSlice"; -import urlParameterReducer from "./slices/urlParameterSlice"; // Import hinzufügen -import selectedPoiReducer from "./slices/selectedPoiSlice"; const rootReducer = combineReducers({ currentPoi: currentPoiReducer, gisStationsStaticDistrict: gisStationsStaticDistrictReducer, - zoomTrigger: zoomTriggerReducer, - urlParameter: urlParameterReducer, - selectedPoi: selectedPoiReducer, }); export default rootReducer; diff --git a/redux/slices/selectedPoiSlice.js b/redux/slices/selectedPoiSlice.js index d724050e1..e6c6761cf 100644 --- a/redux/slices/selectedPoiSlice.js +++ b/redux/slices/selectedPoiSlice.js @@ -1,31 +1,8 @@ // redux/slices/selectedPoiSlice.js //Ist gedacht um ausgewählte Poi Informationen zu speichern und zu PoiUpdateModal.js zu übergeben -import { createSlice } from "@reduxjs/toolkit"; +import { atom } from "recoil"; -// Initialer Zustand -const initialState = { - selectedPoi: null, -}; - -// Slice erstellen -const selectedPoiSlice = createSlice({ - name: "selectedPoi", - initialState, - reducers: { - setSelectedPoi(state, action) { - state.selectedPoi = action.payload; // Setzt den ausgewählten POI - }, - clearSelectedPoi(state) { - state.selectedPoi = null; // Löscht den ausgewählten POI - }, - }, +export const selectedPoiState = atom({ + key: "poiState", // Einzigartiger Key (mit der gesamten Anwendung) + default: null, // Standardwert }); - -// Aktionen exportieren -export const { setSelectedPoi, clearSelectedPoi } = selectedPoiSlice.actions; - -// Selektor exportieren -export const selectSelectedPoi = (state) => state.selectedPoi.selectedPoi; - -// Reducer exportieren -export default selectedPoiSlice.reducer; diff --git a/redux/slices/urlParameterSlice.js b/redux/slices/urlParameterSlice.js index dd9a59937..053529ebc 100644 --- a/redux/slices/urlParameterSlice.js +++ b/redux/slices/urlParameterSlice.js @@ -1,32 +1,14 @@ // /redux/slices/urlParameterSlice.js -import { createSlice } from "@reduxjs/toolkit"; +import { atom } from "recoil"; -// Initialer Zustand -const initialState = { - mapId: "", // Standardwert z.B m=12 - userId: "", // Standardwert z.B. u=484 -}; - -// Slice erstellen -const urlParameterSlice = createSlice({ - name: "urlParameter", - initialState, - reducers: { - setMapId(state, action) { - state.mapId = action.payload; // Aktualisiere mapId - }, - setUserId(state, action) { - state.userId = action.payload; // Aktualisiere userId - }, - }, +// Atom für die Speicherung der mapId aus der URL +export const mapIdState = atom({ + key: "mapIdState", // Eindeutiger Schlüssel (innerhalb des gesamten Projekts) + default: "10", // Standardwert }); -// Aktionen exportieren -export const { setMapId, setUserId } = urlParameterSlice.actions; - -// Selektoren exportieren -export const selectMapId = (state) => state.urlParameter.mapId; -export const selectUserId = (state) => state.urlParameter.userId; - -// Reducer exportieren -export default urlParameterSlice.reducer; +// Atom für die Speicherung der userId aus der URL +export const userIdState = atom({ + key: "userIdState", + default: "484", +}); diff --git a/redux/slices/zoomTriggerSlice.js b/redux/slices/zoomTriggerSlice.js index 46cd926ea..848665d42 100644 --- a/redux/slices/zoomTriggerSlice.js +++ b/redux/slices/zoomTriggerSlice.js @@ -1,23 +1,7 @@ // redux/slices/zoomTriggerSlice.js -import { createSlice } from "@reduxjs/toolkit"; +import { atom } from "recoil"; -const initialState = { - zoomTrigger: 0, -}; - -const zoomTriggerSlice = createSlice({ - name: "zoomTrigger", - initialState, - reducers: { - incrementZoomTrigger(state) { - state.zoomTrigger += 1; // Zustand erhöhen - }, - resetZoomTrigger(state) { - state.zoomTrigger = 0; // Zustand zurücksetzen - }, - }, +export const zoomTriggerState = atom({ + key: "zoomTriggerState", + default: 0, // Dies kann eine einfache Zählvariable sein, die inkrementiert wird. }); - -export const { incrementZoomTrigger, resetZoomTrigger } = zoomTriggerSlice.actions; -export const selectZoomTrigger = (state) => state.zoomTrigger.zoomTrigger; -export default zoomTriggerSlice.reducer;