Merge branch 'release/v1.1.49' into develop

This commit is contained in:
ISA
2025-03-11 09:41:09 +01:00
63 changed files with 1608 additions and 3061 deletions

View File

@@ -9,5 +9,10 @@ DB_PORT=3306
# Public Settings (Client braucht IP/Domain)
NEXT_PUBLIC_SERVER_URL="http://10.10.0.70" # oder evtl. später https://nodemap.firma.de
NEXT_PUBLIC_ENABLE_GEOCODER=true
NEXT_PUBLIC_USE_MOCK_API=true
NEXT_PUBLIC_USE_MOCK_API=false
NEXT_PUBLIC_DEBUG_LOG=true
# für Polylines/kabelstecken -> in Konextmenü "Station öffnen" "
NEXT_PUBLIC_BASE_URL=http://10.10.0.70/talas5/devices/
NEXT_PUBLIC_API_BASE_URL=http://10.10.0.70/talas5/ClientData/WebServiceMap.asmx
NEXT_PUBLIC_API_PORT_3000=http://10.10.0.70:3000

185
components/AddPOIModal.js Normal file
View File

@@ -0,0 +1,185 @@
// components/ShowAddStationPopup.js
import React, { useState, useEffect, use } from "react";
import ReactDOM from "react-dom";
import { useRecoilValue, useRecoilState, useSetRecoilState } from "recoil";
import { readPoiMarkersStore } from "../redux/slices/readPoiMarkersStoreSlice.js";
import { poiReadFromDbTriggerAtom } from "../redux/slices/poiReadFromDbTriggerSlice.js";
import { selectGisStationsStatic } from "../redux/slices/webService/gisStationsStaticSlice";
import { useDispatch, useSelector } from "react-redux";
import { fetchPoiTypes } from "../redux/slices/db/poiTypesSlice";
const ShowAddStationPopup = ({ onClose, map, latlng }) => {
const dispatch = useDispatch();
const poiTypData = useSelector((state) => state.poiTypes.data);
const [name, setName] = useState("");
const [poiTypeId, setPoiTypeId] = useState(""); // Initialize as string
const [poiTypeName, setPoiTypeName] = useState(""); // Initialize as string
const [latitude] = useState(latlng.lat.toFixed(5));
const [longitude] = useState(latlng.lng.toFixed(5));
const setLoadData = useSetRecoilState(readPoiMarkersStore);
const setTrigger = useSetRecoilState(poiReadFromDbTriggerAtom);
const [deviceName, setDeviceName] = useState("");
//-----------------------------------------------------
useEffect(() => {
const fetchpoiTypData = async () => {
try {
const response = await fetch("/api/talas_v5_DB/poiTyp/readPoiTyp");
const data = await response.json();
setpoiTypData(data);
if (data && data.length > 0) {
console.log("POI-Typen geladen:", data);
setPoiTypeId(data[0].idPoiTyp); // Setzt den ersten Typ
setPoiTypeName(data[0].name);
}
} catch (error) {
console.error("Fehler beim Abrufen der poiTyp Daten:", error);
}
};
fetchpoiTypData();
}, []);
useEffect(() => {
if (poiTypData.length > 0 && !poiTypeId) {
setPoiTypeId(poiTypData[0].idPoiTyp);
}
}, [poiTypData]);
useEffect(() => {
console.log("Aktueller POI Type:", poiTypeId);
}, [poiTypeId]);
//------------------------------------------------------------------------------------------
const gisStationsStatic = useSelector(selectGisStationsStatic);
const locationDeviceData = gisStationsStatic?.Points ?? [];
console.log("gisStationsStatic aus AddPOIModal:", gisStationsStatic);
useEffect(() => {
if (locationDeviceData?.length > 0) {
console.log("🎯 Gerätedaten erfolgreich geladen:", locationDeviceData);
setDeviceName((prev) => prev || locationDeviceData[0]?.LD_Name || "");
}
}, [locationDeviceData]);
//------------------------------------------------------------------------------------------
//-----------------handleSubmit-------------------
const handleSubmit = async (event) => {
event.preventDefault();
const formData = {
name,
poiTypeId: Number(poiTypeId), // Umwandlung in eine Zahl
latitude,
longitude,
idLD: locationDeviceData.find((device) => device.LD_Name === deviceName)?.IdLD,
};
const response = await fetch("/api/talas_v5_DB/pois/addLocation", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(formData),
});
if (response.ok) {
setTrigger((trigger) => {
console.log("Aktueller Trigger-Wert:", trigger); // Vorheriger Wert
const newTrigger = trigger + 1;
console.log("Neuer Trigger-Wert:", newTrigger); // Aktualisierter Wert
onClose();
return newTrigger;
});
} else {
console.error("Fehler beim Hinzufügen des POI");
}
if (map && typeof map.closePopup === "function") {
map.closePopup();
}
//Seite neu laden
window.location.reload();
};
//-----------------
// POI-Typen aus Redux laden, wenn die Komponente gemountet wird
useEffect(() => {
dispatch(fetchPoiTypes());
}, [dispatch]);
//---------------------
return (
<div className="fixed inset-0 bg-black bg-opacity-50 flex justify-center items-center z-[1000]" onClick={onClose}>
<div className="relative bg-white p-6 rounded-lg shadow-lg w-96 max-w-full" onClick={(e) => e.stopPropagation()}>
{/* Schließen-Button */}
<button onClick={onClose} className="absolute top-2 right-2 text-gray-600 hover:text-gray-900">
</button>
{/* Modal-Inhalt */}
<form onSubmit={handleSubmit} className="m-0 p-2 w-full">
<div className="flex items-center mb-4">
<label htmlFor="name" className="block mr-2 flex-none">
Name:
</label>
<input type="text" id="name" name="name" value={name} onChange={(e) => setName(e.target.value)} placeholder="Name der Station" className="block p-2 w-full border-2 border-gray-200 rounded-md text-sm" />
</div>
<div className="flex items-center mb-4">
<label htmlFor="deviceName" className="block mr-2 flex-none">
Gerät:
</label>
<select id="deviceName" name="deviceName" value={deviceName} onChange={(e) => setDeviceName(e.target.value)} className="block p-2 w-full border-2 border-gray-200 rounded-md text-sm">
<option value="">-- Gerät auswählen --</option>
{locationDeviceData?.length > 0 ? (
locationDeviceData.map((device, index) => (
<option key={device?.IdLD || index} value={device?.LD_Name}>
{device?.LD_Name || "Unbekanntes Gerät"}
</option>
))
) : (
<option disabled>Keine Geräte gefunden</option>
)}
</select>
</div>
<div className="flex items-center mb-4">
<label htmlFor="idPoiTyp2" className="block mr-2 flex-none">
Typ:
</label>
<select
id="idPoiTyp2"
name="idPoiTyp2"
value={poiTypeId}
onChange={(e) => setPoiTypeId(Number(e.target.value))} // Hier ebenfalls umwandeln
className="block p-2 w-full border-2 border-gray-200 rounded-md text-sm"
>
{poiTypData.length === 0 ? (
<option value="" disabled>
Keine POI-Typen verfügbar
</option>
) : (
poiTypData.map((poiTyp) => (
<option key={poiTyp.idPoiTyp} value={poiTyp.idPoiTyp}>
{poiTyp.name}
</option>
))
)}
</select>
</div>
<div className="flex justify-between text-sm text-gray-700 mb-4">
<span>Lat: {latitude}</span>
<span>Lng: {longitude}</span>
</div>
<button type="submit" className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded w-full">
POI hinzufügen
</button>
</form>
</div>
</div>
);
};
export default ShowAddStationPopup;

View File

@@ -0,0 +1,61 @@
import React, { useState, useEffect } from "react";
import { useDispatch, useSelector } from "react-redux";
import { closeAddPoiOnPolylineModal } from "../redux/slices/addPoiOnPolylineSlice";
const AddPOIOnPolyline = () => {
const dispatch = useDispatch();
const { isOpen, latlng } = useSelector((state) => state.addPoiOnPolyline);
const [name, setName] = useState("");
const [latitude, setLatitude] = useState("");
const [longitude, setLongitude] = useState("");
useEffect(() => {
if (latlng) {
setLatitude(latlng.lat.toFixed(5));
setLongitude(latlng.lng.toFixed(5));
}
}, [latlng]);
if (!isOpen) return null;
const handleSubmit = async (event) => {
event.preventDefault();
const formData = { name, latitude, longitude };
console.log("Neuer POI auf Polyline:", formData);
dispatch(closeAddPoiOnPolylineModal()); // Schließt das Modal nach dem Speichern
};
return (
<div className="fixed inset-0 bg-black bg-opacity-50 flex justify-center items-center z-50" onClick={() => dispatch(closeAddPoiOnPolylineModal())}>
<div className="bg-white p-6 rounded-lg shadow-lg w-96 max-w-full" onClick={(e) => e.stopPropagation()}>
<h2 className="text-lg font-bold mb-4">POI auf Polyline hinzufügen</h2>
<form onSubmit={handleSubmit}>
<div className="mb-4">
<label className="block">Name:</label>
<input type="text" value={name} onChange={(e) => setName(e.target.value)} className="border p-2 w-full" required />
</div>
<div className="mb-4">
<label className="block">Latitude:</label>
<input type="text" value={latitude} readOnly className="border p-2 w-full" />
</div>
<div className="mb-4">
<label className="block">Longitude:</label>
<input type="text" value={longitude} readOnly className="border p-2 w-full" />
</div>
<button type="submit" className="bg-blue-500 hover:bg-blue-700 text-white p-2 rounded w-full">
Speichern
</button>
</form>
</div>
</div>
);
};
export default AddPOIOnPolyline;

View File

@@ -1,8 +1,8 @@
// /componentss/DataSheet.js
import React, { useEffect, useState } from "react";
import { useRecoilState, useRecoilValue, useSetRecoilState } from "recoil";
import { gisStationsStaticDistrictState } from "../redux/slices/gisStationsStaticDistrictSlice";
import { gisSystemStaticState } from "../redux/slices/gisSystemStaticSlice";
import { gisStationsStaticDistrictState } from "../redux/slices/webService/gisStationsStaticDistrictSlice";
import { gisSystemStaticState } from "../redux/slices/webService/gisSystemStaticSlice.js";
import { mapLayersState } from "../redux/slices/mapLayersSlice";
import { selectedAreaState } from "../redux/slices/selectedAreaSlice";
import { zoomTriggerState } from "../redux/slices/zoomTriggerSlice.js";
@@ -10,8 +10,12 @@ 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 { selectGisStationsStaticDistrict } from "../redux/slices/gisStationsStaticDistrictSlice";
import { selectPolylineVisible, setPolylineVisible } from "../redux/slices/polylineLayerVisibleSlice";
import { selectGisSystemStatic } from "../redux/slices/webService/gisSystemStaticSlice";
import { useInitGisStationsStatic } from "../components/mainComponent/hooks/webServices/useInitGisStationsStatic";
import { fetchGisStationsStatic, selectGisStationsStatic } from "../redux/slices/webService/gisStationsStaticSlice";
import { selectGisStationsStaticDistrict } from "../redux/slices/webService/gisStationsStaticDistrictSlice";
function DataSheet() {
const [editMode, setEditMode] = useState(false); // Zustand für editMode
@@ -20,9 +24,10 @@ function DataSheet() {
const [mapLayersVisibility, setMapLayersVisibility] = useRecoilState(mapLayersState);
const [stationListing, setStationListing] = useState([]);
const [systemListing, setSystemListing] = useState([]);
//const GisStationsStaticDistrict = useRecoilValue(gisStationsStaticDistrictState);
const GisStationsStaticDistrict = useSelector(selectGisStationsStaticDistrict);
const GisSystemStatic = useRecoilValue(gisSystemStaticState);
const GisStationsStaticDistrict = useSelector(selectGisStationsStaticDistrict) || [];
const GisSystemStatic = useSelector(selectGisSystemStatic) || [];
const GisStationsStatic = useSelector(selectGisStationsStatic) || []; //Area-Name/Bereiche dropdownmenu
const setZoomTrigger = useSetRecoilState(zoomTriggerState);
const dispatch = useDispatch();
const polylineVisible = useSelector(selectPolylineVisible);
@@ -73,16 +78,18 @@ function DataSheet() {
};
useEffect(() => {
const allowedSystems = new Set(GisSystemStatic.filter((system) => system.Allow === 1).map((system) => system.IdSystem));
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.filter((item) => {
const isUnique = !seenNames.has(item.Area_Name) && allowedSystems.has(item.System);
if (isUnique) {
seenNames.add(item.Area_Name);
}
return isUnique;
});
const filteredAreas = Array.isArray(GisStationsStaticDistrict)
? GisStationsStaticDistrict.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) => ({
@@ -92,13 +99,15 @@ function DataSheet() {
);
const seenSystemNames = new Set();
const filteredSystems = GisSystemStatic.filter((item) => {
const isUnique = !seenSystemNames.has(item.Name) && item.Allow === 1;
if (isUnique) {
seenSystemNames.add(item.Name);
}
return isUnique;
});
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) => ({
@@ -150,6 +159,49 @@ function DataSheet() {
localStorage.setItem("standorteVisible", checked);
};
//------------------------------
useEffect(() => {
// console.log("GisSystemStatic aus Redux:", GisSystemStatic); // ✅ Debugging: Ist es ein Array?
}, [GisSystemStatic]);
//-----------------------------
useInitGisStationsStatic();
//---------------------------
useEffect(() => {
//console.log("🔍 GisStationsStatic Inhalt:", GisStationsStatic);
if (!GisStationsStatic) {
console.warn("⚠️ GisStationsStatic ist `null` oder nicht geladen.");
return;
}
if (typeof GisStationsStatic !== "object") {
console.warn("⚠️ GisStationsStatic ist kein Objekt:", GisStationsStatic);
return;
}
if (!GisStationsStatic.Points || !Array.isArray(GisStationsStatic.Points)) {
//console.warn("⚠️ GisStationsStatic.Points ist nicht vorhanden oder kein Array.", GisStationsStatic);
return;
}
const seenNames = new Set();
const filteredAreas = GisStationsStatic.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;
});
setStationListing(
filteredAreas.map((area, index) => ({
id: area.IdArea || index + 1,
name: area.Area_Name || "Unbekannt",
}))
);
// console.log("📌 stationListing aktualisiert:", filteredAreas);
}, [GisStationsStatic]);
//---------------------------
return (

View File

@@ -1,11 +1,15 @@
// pages/api/poiUpdateModal.js
//
// /components/PoiUpdateModal.js
import React, { useState, useEffect } from "react";
import { useRecoilValue } from "recoil";
import { selectedPoiState } from "../redux/slices/selectedPoiSlice";
import { currentPoiState } from "../redux/slices/currentPoiSlice";
import { fetchLocationDevicesFromDB } from "../redux/slices/db/locationDevicesFromDBSlice";
import { useDispatch, useSelector } from "react-redux";
const PoiUpdateModal = ({ onClose, poiData }) => {
const dispatch = useDispatch();
const devices = useSelector((state) => state.locationDevicesFromDB.devices);
const currentPoi = useRecoilValue(currentPoiState);
const selectedPoi = useRecoilValue(selectedPoiState);
const [poiId, setPoiId] = useState(poiData ? poiData.idPoi : "");
@@ -19,6 +23,10 @@ const PoiUpdateModal = ({ onClose, poiData }) => {
const [description, setDescription] = useState(poiData ? poiData.description : "");
useEffect(() => {
dispatch(fetchLocationDevicesFromDB());
}, [dispatch]);
// Log the initial POI data
useEffect(() => {
if (poiData) {
@@ -117,28 +125,6 @@ const PoiUpdateModal = ({ onClose, poiData }) => {
fetchPoiTypData();
}, [selectedPoi]);
// Fetch device data um den Gerät Namen in den dropdown menu anzuzeigen also erstmal die Liste der Geräte abrufen
useEffect(() => {
const fetchData = async () => {
try {
// const response = await fetch("/api/talas_v5/location_device"); //"/api/talas_v5_DB/locationDevice/location_device"
const response = await fetch("/api/talas_v5_DB/locationDevice/locationDevices");
const data = await response.json();
//console.log("Standort- und Gerätedaten:", data);
setLocationDeviceData(data);
console.log("Standort- und Gerätedaten poiData:", poiData);
if (poiData && poiData.idLD) {
const selectedDevice = data.find((device) => device.id === poiData.idLD);
setDeviceName(selectedDevice ? selectedDevice.id : data[0].id); // Hier wird die ID als initialer Zustand gesetzt
console.log("Selected Device:", selectedDevice);
console.log("Selected devciceName:", deviceName);
}
} catch (error) {
console.error("Fehler beim Abrufen der Standort- und Gerätedaten:", error);
}
};
fetchData();
}, []);
//--------------------------------------------------------------------------------------------
// Fetch device name basierend auf der Geräte-ID

View File

@@ -1,171 +0,0 @@
// components/ShowAddStationPopup.js
import React, { useState, useEffect, use } from "react";
import ReactDOM from "react-dom";
import { useRecoilValue, useRecoilState, useSetRecoilState } from "recoil";
import { readPoiMarkersStore } from "../redux/slices/readPoiMarkersStoreSlice.js";
import { poiReadFromDbTriggerAtom } from "../redux/slices/poiReadFromDbTriggerSlice";
const ShowAddStationPopup = ({ onClose, map, latlng }) => {
const [poiTypData, setpoiTypData] = useState(); // Recoil State verwenden
const [name, setName] = useState("");
const [poiTypeId, setPoiTypeId] = useState(""); // Initialize as string
const [poiTypeName, setPoiTypeName] = useState(""); // Initialize as string
const [latitude] = useState(latlng.lat.toFixed(5));
const [longitude] = useState(latlng.lng.toFixed(5));
const setLoadData = useSetRecoilState(readPoiMarkersStore);
const setTrigger = useSetRecoilState(poiReadFromDbTriggerAtom);
const [locationDeviceData, setLocationDeviceData] = useState([]);
const [deviceName, setDeviceName] = useState("");
useEffect(() => {
const fetchpoiTypData = async () => {
try {
const response = await fetch("/api/talas_v5_DB/poiTyp/readPoiTyp");
const data = await response.json();
setpoiTypData(data);
if (data && data.length > 0) {
setPoiTypeId(data[0].idPoiTyp); // Set initial poiTypeId to the id of the first poiType
setPoiTypeName(data[1].name); // Set initial poiTypeName to the name of the first poiType
console.log("Initial poiTypeId set in ShowAddStationPopup.js :", data[0].idPoiTyp);
}
} catch (error) {
console.error("Fehler beim Abrufen der poiTyp Daten:", error);
}
};
fetchpoiTypData();
}, []);
//---------------------------------------------------------------------------------------
/* useEffect(() => {
// Funktion zum Abrufen der Daten von der API -> DB talas_v5.location_device
const fetchData = async () => {
try {
const response = await fetch("/api/talas_v5/location_device"); // Pfad zu Ihrem API-Endpunkt
const data = await response.json();
setLocationDeviceData(data); // Setzt den Zustand mit den abgerufenen Daten
console.log("Abgerufene Standort- und Gerätedaten:", data);
} catch (error) {
console.error(
"Fehler beim Abrufen der Standort- und Gerätedaten:",
error
);
}
};
fetchData();
}, []); // Leerarray als Dependency, um den Effekt nur beim Laden der Komponente auszuführen */
//------------------------------------------------------------------------------------------
useEffect(() => {
// Funktion zum Abrufen der Daten von der API -> DB talas_v5.location_device
const fetchData = async () => {
try {
const response = await fetch("/api/talas5/location_device");
const data = await response.json();
setLocationDeviceData(data);
if (data.length > 0) {
setDeviceName(data[0].name); // Setzen des anfänglichen Gerätenamens
}
console.log("Abgerufene Standort- und Gerätedaten:", data);
} catch (error) {
console.error("Fehler beim Abrufen der Standort- und Gerätedaten:", error);
}
};
fetchData();
}, []);
//------------------------------------------------------------------------------------------
//-----------------handleSubmit-------------------
const handleSubmit = async (event) => {
event.preventDefault();
const formData = {
name,
poiTypeId,
latitude,
longitude,
idLD: locationDeviceData.find((device) => device.name === deviceName).idLD,
};
const response = await fetch("/api/talas_v5_DB/pois/addLocation", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(formData),
});
if (response.ok) {
setTrigger((trigger) => {
console.log("Aktueller Trigger-Wert:", trigger); // Vorheriger Wert
const newTrigger = trigger + 1;
console.log("Neuer Trigger-Wert:", newTrigger); // Aktualisierter Wert
onClose();
return newTrigger;
});
} else {
console.error("Fehler beim Hinzufügen des POI");
}
if (map && typeof map.closePopup === "function") {
map.closePopup();
}
};
//-----------------handleSubmit-------------------
return (
<form onSubmit={handleSubmit} className="m-0 p-2 w-full ">
<div className="flex items-center mb-4">
<label htmlFor="name" className="block mr-2 flex-none">
Name :
</label>
<input type="text" id="name" name="name" value={name} onChange={(e) => setName(e.target.value)} placeholder="Name der Station" className="block p-2 w-full border-2 border-gray-200 rounded-md text-sm" />
</div>
{/* {locationDeviceData.----------------------------------------------*/}
<div className="flex items-center mb-4">
<label htmlFor="deviceName" className="block mr-2 flex-none">
Gerät :
</label>
<select id="deviceName" name="deviceName" value={deviceName} onChange={(e) => setDeviceName(e.target.value)} className="block p-2 w-full border-2 border-gray-200 rounded-md text-sm">
{locationDeviceData.map((device, index) => (
<option key={index} value={device.name}>
{device.name}
</option>
))}
</select>
</div>
{/* {locationDeviceData.----------------------------------------------*/}
<div className="flex items-center mb-4">
<label htmlFor="idPoiTyp2" className="block mr-2 flex-none">
Typ:
</label>
<select id="idPoiTyp2" name="idPoiTyp2" value={poiTypeId} onChange={(e) => setPoiTypeId(e.target.value)} className="block p-2 w-full border-2 border-gray-200 rounded-md text-sm">
{poiTypData &&
poiTypData.map((poiTyp, index) => (
<option key={poiTyp.idPoiTyp || index} value={poiTyp.idPoiTyp}>
{poiTyp.name}
</option>
))}
</select>
</div>
<div className="flex flex-row items-center justify-center">
<div className="flex items-center mb-4">
<label htmlFor="lat" className="block mr-2 flex-none text-xs">
Lat : {latitude}
</label>
</div>
<div className="flex items-center mb-4">
<label htmlFor="lng" className="block mr-2 flex-none text-xs">
Lng : {longitude}
</label>
</div>
</div>
<button type="submit" className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded w-full">
POI hinzufügen
</button>
</form>
);
};
export default ShowAddStationPopup;

View File

@@ -1,6 +1,6 @@
// components/TestScript.js
import { useEffect } from "react";
import setupPolylinesCode from "!!raw-loader!../utils/setupPolylines.js"; // Lädt die gesamte setupPolylines.js als Text
import setupPolylinesCode from "!!raw-loader!../utils/polylines/setupPolylines.js"; // Lädt die gesamte setupPolylines.js als Text
export default function TestScript() {
useEffect(() => {

View File

@@ -1,77 +1,98 @@
// components/MapComponent.js
// 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 * 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 DataSheet from "../DataSheet.js";
import { useRecoilState, useRecoilValue, useSetRecoilState } from "recoil";
import AddPoiModalWindow from "./pois/AddPoiModalWindow.js";
import AddPoiModalWindow from "../pois/AddPoiModalWindow.js";
import { InformationCircleIcon } from "@heroicons/react/20/solid";
import PoiUpdateModal from "./pois/PoiUpdateModal.js";
import PoiUpdateModal from "../pois/PoiUpdateModal.js";
import { ToastContainer, toast } from "react-toastify";
import plusRoundIcon from "./PlusRoundIcon.js";
import { createAndSetDevices } from "../utils/createAndSetDevices.js";
import { restoreMapSettings, checkOverlappingMarkers } from "../utils/mapUtils.js";
import { APP_VERSION } from "../config/appVersion";
import * as layers from "../config/layers.js";
import { initializeMap } from "../utils/initializeMap.js";
import addItemsToMapContextMenu from "./useMapContextMenu.js";
import useGmaMarkersLayer from "../hooks/layers/useGmaMarkersLayer.js"; // Import the custom hook
import useSmsfunkmodemMarkersLayer from "../hooks/layers/useSmsfunkmodemMarkersLayer.js";
import useBereicheMarkersLayer from "../hooks/layers/useBereicheMarkersLayer.js";
import { setupPolylines } from "../utils/setupPolylines.js";
import { setupPOIs } from "../utils/setupPOIs.js";
import VersionInfoModal from "./VersionInfoModal.js";
import useDrawLines from "../hooks/layers/useDrawLines";
import useFetchPoiData from "../hooks/useFetchPoiData";
import usePoiTypData from "../hooks/usePoiTypData";
import useLayerVisibility from "../hooks/useLayerVisibility";
import useLineData from "../hooks/useLineData.js";
import plusRoundIcon from "../PlusRoundIcon.js";
import { createAndSetDevices } from "../../utils/createAndSetDevices.js";
import { restoreMapSettings, checkOverlappingMarkers } from "../../utils/mapUtils.js";
import { APP_VERSION } from "../../config/appVersion.js";
import * as layers from "../../config/layers.js";
import { initializeMap } from "../../utils/initializeMap.js";
import addItemsToMapContextMenu from "../useMapContextMenu.js";
import useGmaMarkersLayer from "../../hooks/layers/useGmaMarkersLayer.js"; // Import the custom hook
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 useDrawLines from "../../hooks/layers/useDrawLines.js";
import useFetchPoiData from "../../hooks/useFetchPoiData.js";
import usePoiTypData from "../../hooks/usePoiTypData.js";
import useLayerVisibility from "../../hooks/useLayerVisibility.js";
import useLineData from "../../hooks/useLineData.js";
//import { useCreateAndSetDevices } from "../hooks/useCreateAndSetDevices";
import { useMapComponentState } from "../hooks/useMapComponentState";
import { disablePolylineEvents, enablePolylineEvents } from "../utils/setupPolylines";
import { updateLocation } from "../utils/updateBereichUtil";
import { initGeocoderFeature } from "../components/features/GeocoderFeature";
import { useMapComponentState } from "../../hooks/useMapComponentState.js";
import { updateLocation } from "../../utils/updateBereichUtil.js";
import { initGeocoderFeature } from "../features/GeocoderFeature.js";
//--------------------------------------------
//import { currentPoiState } from "../redux/slices/currentPoiSlice.js";
import { selectGisStationsStaticDistrict, setGisStationsStaticDistrict } from "../redux/slices/gisStationsStaticDistrictSlice";
import { mapIdState, userIdState } from "../redux/slices/urlParameterSlice.js";
import { poiLayerVisibleState } from "../redux/slices/poiLayerVisibleSlice.js";
import { selectedPoiState } from "../redux/slices/selectedPoiSlice.js";
import { poiReadFromDbTriggerAtom } from "../redux/slices/poiReadFromDbTriggerSlice";
import { gisStationsStaticDistrictState } from "../redux/slices/gisStationsStaticDistrictSlice";
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 { polylineEventsDisabledState } from "../redux/slices/polylineEventsDisabledSlice";
import { polylineLayerVisibleState } from "../redux/slices/polylineLayerVisibleSlice";
import { mapIdState, userIdState } from "../../redux/slices/urlParameterSlice.js";
import { poiLayerVisibleState } from "../../redux/slices/poiLayerVisibleSlice.js";
import { selectedPoiState } from "../../redux/slices/selectedPoiSlice.js";
import { poiReadFromDbTriggerAtom } from "../../redux/slices/poiReadFromDbTriggerSlice.js";
import { gisSystemStaticState } from "../../redux/slices/webService/gisSystemStaticSlice.js";
import { mapLayersState } from "../../redux/slices/mapLayersSlice.js";
import { selectedAreaState } from "../../redux/slices/selectedAreaSlice.js";
import { zoomTriggerState } from "../../redux/slices/zoomTriggerSlice.js";
import { polylineEventsDisabledState } from "../../redux/slices/polylineEventsDisabledSlice.js";
import { polylineLayerVisibleState } from "../../redux/slices/polylineLayerVisibleSlice.js";
//--------------------------------------------
import { useSelector, useDispatch } from "react-redux";
import { selectCurrentPoi, setCurrentPoi, clearCurrentPoi } from "../redux/slices/currentPoiSlice";
import CoordinateInput from "./CoordinateInput";
import CoordinateModal from "./CoordinateModal";
import CoordinatePopup from "./CoordinatePopup";
import { selectCurrentPoi, setCurrentPoi, clearCurrentPoi } from "../../redux/slices/currentPoiSlice.js";
import CoordinateInput from "../CoordinateInput.js";
import CoordinateModal from "../CoordinateModal.js";
import CoordinatePopup from "../CoordinatePopup.js";
//------------------------Daten aus API--------------------
import { fetchUserRights } from "../services/api/fetchUserRights.js";
import { fetchPoiData } from "../services/api/fetchPoiData.js";
import { fetchGisStationsStaticDistrict } from "../services/api/fetchGisStationsStaticDistrict.js";
import { fetchUserRights } from "../../services/api/fetchUserRights.js";
import { fetchPoiData } from "../../services/api/fetchPoiData.js";
import { fetchGisStationsStaticDistrict } from "../../services/api/fetchGisStationsStaticDistrict.js";
import { fetchGisStationsStatusDistrict } from "../services/api/fetchGisStationsStatusDistrict.js";
import { fetchGisStationsStatusDistrict } from "../../services/api/fetchGisStationsStatusDistrict.js";
import { fetchGisStationsMeasurements } from "../services/api/fetchGisStationsMeasurements.js";
import { fetchGisSystemStatic } from "../services/api/fetchGisSystemStatic.js";
import { usePolylineTooltipLayer } from "../hooks/usePolylineTooltipLayer";
import { selectPolylineVisible, setPolylineVisible } from "../redux/slices/polylineLayerVisibleSlice";
import { fetchGisStationsMeasurements } from "../../services/api/fetchGisStationsMeasurements.js";
import { fetchGisSystemStatic } from "../../services/api/fetchGisSystemStatic.js";
import { usePolylineTooltipLayer } from "../../hooks/usePolylineTooltipLayer.js";
import { selectPolylineVisible, setPolylineVisible } from "../../redux/slices/polylineLayerVisibleSlice.js";
import { useInitLocationDevices } from "./hooks/webServices/useInitLocationDevices";
import { useInitGisStationsStaticDistrict } from "./hooks/webServices/useInitGisStationsStaticDistrict";
import { selectGisStationsStaticDistrict } from "../../redux/slices/webService/gisStationsStaticDistrictSlice";
import { useInitGisStationsStatusDistrict } from "./hooks/webServices/useInitGisStationsStatusDistrict";
import { useInitGisStationsMeasurements } from "./hooks/webServices/useInitGisStationsMeasurements";
import { useInitGisSystemStatic } from "./hooks/webServices/useInitGisSystemStatic";
import { selectGisSystemStatic, setGisSystemStatic } from "../../redux/slices/webService/gisSystemStaticSlice";
import ShowAddStationPopup from "../AddPOIModal.js";
import { useInitGisStationsStatic } from "../mainComponent/hooks/webServices/useInitGisStationsStatic";
import { closeAddPoiModal } from "../../redux/slices/addPoiOnPolylineSlice.js";
import AddPOIOnPolyline from "../AddPOIOnPolyline";
import { enablePolylineEvents, disablePolylineEvents } from "../../utils/polylines/eventHandlers";
import { updateCountdown, closePolylineContextMenu, forceCloseContextMenu } from "../../redux/slices/polylineContextMenuSlice";
//-------------------MapComponent.js hooks--------------------
import useInitializeMap from "./hooks/useInitializeMap";
import useLoadUserRights from "./hooks/useLoadUserRights";
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 contextMenuState = useSelector((state) => state.polylineContextMenu);
const polylinePosition = contextMenuState.position ? L.latLng(contextMenuState.position.lat, contextMenuState.position.lng) : null;
const currentPoi = useSelector(selectCurrentPoi);
//const setCurrentPoi = useSetRecoilState(currentPoiState);
const polylineVisible = useSelector(selectPolylineVisible);
@@ -96,6 +117,8 @@ const MapComponent = ({ locations, onLocationUpdate, lineCoordinates }) => {
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);
@@ -110,7 +133,6 @@ const MapComponent = ({ locations, onLocationUpdate, lineCoordinates }) => {
const setSelectedPoi = useSetRecoilState(selectedPoiState);
const [showPoiUpdateModal, setShowPoiUpdateModal] = useState(false);
const [currentPoiData, setCurrentPoiData] = useState(null);
const [showVersionInfoModal, setShowVersionInfoModal] = useState(false);
const zoomTrigger = useRecoilValue(zoomTriggerState);
const [gisSystemStaticLoaded, setGisSystemStaticLoaded] = useState(false);
@@ -121,11 +143,10 @@ const MapComponent = ({ locations, onLocationUpdate, lineCoordinates }) => {
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, setGisStationsStaticDistrict] = useRecoilState(gisStationsStaticDistrictState);
const GisStationsStaticDistrict = useSelector(selectGisStationsStaticDistrict);
const [GisStationsStatusDistrict, setGisStationsStatusDistrict] = useState([]); // Zustand für Statusdaten
const [GisStationsMeasurements, setGisStationsMeasurements] = useState([]); // Zustand für Messdaten
const [GisSystemStatic, setGisSystemStatic] = useRecoilState(gisSystemStaticState); // Zustand für Systemdaten
const GisSystemStatic = useSelector(selectGisSystemStatic);
// Konstanten für die URLs
const mapGisStationsStaticDistrictUrl = config.mapGisStationsStaticDistrictUrl;
const mapGisStationsStatusDistrictUrl = config.mapGisStationsStatusDistrictUrl;
@@ -133,7 +154,7 @@ const MapComponent = ({ locations, onLocationUpdate, lineCoordinates }) => {
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([]);
@@ -150,7 +171,7 @@ const MapComponent = ({ locations, onLocationUpdate, lineCoordinates }) => {
const [ulafMarkers, setUlafMarkers] = useState([]);
const [sonstigeMarkers, setSonstigeMarkers] = useState([]);
const [tkComponentsMarkers, setTkComponentsMarkers] = useState([]);
//--------------------------------------------
const [lineStatusData, setLineStatusData] = useState([]);
const [linesData, setLinesData] = useState([]);
const mapLayersVisibility = useRecoilValue(mapLayersState);
@@ -160,34 +181,27 @@ const MapComponent = ({ locations, onLocationUpdate, lineCoordinates }) => {
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 [popupCoordinates, setPopupCoordinates] = useState({
lat: 52.52,
lng: 13.405,
});
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 {
@@ -198,75 +212,52 @@ const MapComponent = ({ locations, onLocationUpdate, lineCoordinates }) => {
}
});
const [polylineEventsDisabled, setPolylineEventsDisabled] = useRecoilState(polylineEventsDisabledState); // Recoil State
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);
//---------------------------------------------------------------
/* useEffect(() => {
fetchGisStatusStations(12, 484); // Beispielaufruf mit idMap = 10 und idUser = 484
}, []); */
useEffect(() => {
const params = new URL(window.location.href).searchParams;
setMapId(params.get("m"));
setUserId(params.get("u"));
}, [setMapId, setUserId]);
/* 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
]); */
useEffect(() => {
const fetchAndSetUserRights = async () => {
const rights = await fetchUserRights();
setUserRights(rights);
setIsRightsLoaded(true);
// Sicherstellen, dass `rights` ein Array ist, bevor `.includes()` aufgerufen wird
setHasRights(localStorage.getItem("editMode") && Array.isArray(rights) && rights.includes(56));
};
fetchAndSetUserRights();
}, []);
useGmaMarkersLayer(
map,
gmaMarkers,
GisStationsMeasurements,
layers.MAP_LAYERS.GMA,
oms,
mapLayersVisibility.GMA // Übergebe die Sichtbarkeitsbedingung als Parameter
);
/* useSmsfunkmodemMarkersLayer(
map,
oms,
GisSystemStatic,
priorityConfig,
mapLayersVisibility.SMSFunkmodem // Sichtbarkeitsstatus aus dem State
); */
const useMock = process.env.NEXT_PUBLIC_USE_MOCK_API === "true";
//---------------------------------------------------------------
useEffect(() => {
const fetchWebServiceMap = async () => {
try {
let stationsStaticUrl = useMock ? "/mockData/gisStationsStaticDistrictMock.json" : mapGisStationsStaticDistrictUrl;
let stationsStatusUrl = useMock ? "/mockData/gisStationsStatusDistrictMock.json" : mapGisStationsStatusDistrictUrl;
let stationsMeasurementsUrl = useMock ? "/mockData/gisStationsMeasurementsMock.json" : mapGisStationsMeasurementsUrl;
let systemStaticUrl = useMock ? "/mockData/gisSystemStaticMock.json" : mapGisSystemStaticUrl;
// Zähler für externe API-Aufrufe in localStorage speichern
let requestCount = localStorage.getItem("fetchWebServiceMap") || 0;
requestCount = parseInt(requestCount, 10);
@@ -280,8 +271,8 @@ const MapComponent = ({ locations, onLocationUpdate, lineCoordinates }) => {
// Fetch GIS Stations Static District
/* await fetchGisStationsStaticDistrict(mapGisStationsStaticDistrictUrl, dispatch, fetchOptions);
requestCount++; // Zähler erhöhen
localStorage.setItem("fetchWebServiceMap", requestCount); */
requestCount++; // Zähler erhöhen
localStorage.setItem("fetchWebServiceMap", requestCount); */
//console.log(`fetchWebServiceMap in MapComponent wurde ${requestCount} Mal aufgerufen.`);
// Fetch GIS Stations Status District
@@ -308,7 +299,6 @@ const MapComponent = ({ locations, onLocationUpdate, lineCoordinates }) => {
fetchWebServiceMap();
}, [dispatch, mapGisStationsStaticDistrictUrl]);
//--------------------------------------------------------
useEffect(() => {
const endpoint = "/api/talas_v5_DB/gisLines/readGisLines";
@@ -373,17 +363,6 @@ const MapComponent = ({ locations, onLocationUpdate, lineCoordinates }) => {
fetchPoiData();
}, []);
//--------------------------------------------
/* useEffect(() => {
if (map) {
const dbLayer = new L.LayerGroup().addTo(map); // Define dbLayer here
return () => {
dbLayer.remove();
};
}
}, [map]); */
//--------------------------------------------
// POIs auf die Karte zeichnen
useEffect(() => {
if (map && !poiLayerRef.current) {
@@ -414,28 +393,8 @@ const MapComponent = ({ locations, onLocationUpdate, lineCoordinates }) => {
if (gisSystemStaticLoaded && map) {
}
}, [gisSystemStaticLoaded, map, GisSystemStatic, priorityConfig]);
//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 (map) {
var x = 51.41321407879154;
@@ -450,25 +409,7 @@ const MapComponent = ({ locations, onLocationUpdate, lineCoordinates }) => {
}
}, [map, zoomTrigger]);
//--------------------------------------------
const allMarkers = [
...talasMarkers,
...eciMarkers,
...lteModemMarkers,
...ciscoRouterMarkers,
...wagoMarkers,
...siemensMarkers,
...otdrMarkers,
...wdmMarkers,
...gmaMarkers,
...messstellenMarkers,
...talasiclMarkers,
...dauzMarkers,
...smsfunkmodemMarkers,
...sonstigeMarkers,
...tkComponentsMarkers,
...ulafMarkers,
];
//--------------------------------------------
useEffect(() => {
if (map) {
// Sammle alle Marker in einer einzigen Liste
@@ -515,6 +456,7 @@ const MapComponent = ({ locations, onLocationUpdate, lineCoordinates }) => {
mapLayersVisibility, // Neu: Abhängigkeit für Sichtbarkeitsstatus
]);
//--------------------------------------------
//--------------------------------------------
useEffect(() => {
const fetchData = async () => {
@@ -550,7 +492,7 @@ const MapComponent = ({ locations, onLocationUpdate, lineCoordinates }) => {
fetchData();
}, []);
//--------------------------------------------
//-----------------------------------------------------------------
//Tooltip an mouse position anzeigen für die Linien
useEffect(() => {
if (!map) return;
@@ -619,15 +561,16 @@ const MapComponent = ({ locations, onLocationUpdate, lineCoordinates }) => {
}, [map, linePositions, lineColors, tooltipContents, newPoint, newCoords, tempMarker, polylineVisible]);
//--------------------------------------------
//--------------------------------------------
useEffect(() => {
if (map) {
restoreMapSettings(map);
}
}, [map]);
//--------------------------------------------
useEffect(() => {
if (map) {
console.log("map in MapComponent: ", map);
const handleMapMoveEnd = (event) => {
const newCenter = map.getCenter();
const newZoom = map.getZoom();
@@ -649,22 +592,33 @@ const MapComponent = ({ locations, onLocationUpdate, lineCoordinates }) => {
}
}, [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 = GisStationsStaticDistrict.find((s) => s.Area_Name === selectedArea);
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);
@@ -689,11 +643,7 @@ const MapComponent = ({ locations, onLocationUpdate, lineCoordinates }) => {
fetchPriorityConfig();
}, []);
//--------------------------------------------
useEffect(() => {
if (mapRef.current && !map) {
initializeMap(mapRef, setMap, setOms, setMenuItemAdded, addItemsToMapContextMenu, hasRights, setPolylineEventsDisabled);
}
}, [mapRef, map, hasRights, setPolylineEventsDisabled]);
//--------------------------------------------
useEffect(() => {
if (map) {
@@ -704,6 +654,7 @@ const MapComponent = ({ locations, onLocationUpdate, lineCoordinates }) => {
}
}
}, [map, polylineEventsDisabled]);
//--------------------------------------------
useEffect(() => {
if (map) {
console.log("6- Karteninstanz (map) wurde jetzt erfolgreich initialisiert");
@@ -758,31 +709,47 @@ const MapComponent = ({ locations, onLocationUpdate, lineCoordinates }) => {
// 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); */
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);
//--------------------------------------------
useInitializeMap(map, mapRef, setMap, setOms, setMenuItemAdded, addItemsToMapContextMenu, hasRights, setPolylineEventsDisabled);
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);
useEffect(() => {
if (!gisSystemStaticLoaded || !map) return; // Sicherstellen, dass die Karte und Daten geladen sind
@@ -846,7 +813,19 @@ const MapComponent = ({ locations, onLocationUpdate, lineCoordinates }) => {
// Setze ein Intervall für regelmäßige Updates
const intervalId = setInterval(() => {
updateAllMarkers();
}, 20000); // 20 Sekunden
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 () => {
@@ -935,13 +914,6 @@ const MapComponent = ({ locations, onLocationUpdate, lineCoordinates }) => {
//--------------------------------------------
const fetchGisStationsStaticDistrict = async (idMap, idUser, dispatch) => {
try {
let stationsStaticUrl = useMock ? "/mockData/gisStationsStaticDistrictMock.json" : mapGisStationsStaticDistrictUrl;
let stationsStatusUrl = useMock ? "/mockData/gisStationsStatusDistrictMock.json" : mapGisStationsStatusDistrictUrl;
let stationsMeasurementsUrl = useMock ? "/mockData/gisStationsMeasurementsMock.json" : mapGisStationsMeasurementsUrl;
let systemStaticUrl = useMock ? "/mockData/gisSystemStaticMock.json" : mapGisSystemStaticUrl;
// API-Endpunkt mit Query-Parametern aufrufen
const response = await fetch(`/api/gisStationsStaticDistrict?idMap=${idMap}&idUser=${idUser}`);
@@ -954,7 +926,7 @@ const MapComponent = ({ locations, onLocationUpdate, lineCoordinates }) => {
// Ergebnis im Dispatch speichern oder State aktualisieren
dispatch({ type: "SET_GIS_STATIONS", payload: data });
console.log("Daten erfolgreich geladen:", 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);
@@ -997,12 +969,20 @@ const MapComponent = ({ locations, onLocationUpdate, lineCoordinates }) => {
}
}, [map, menuItemAdded, hasRights]); */
//--------------------------------------------
useEffect(() => {
if (map && !menuItemAdded) {
addItemsToMapContextMenu(map, menuItemAdded, setMenuItemAdded, openPopupWithCoordinates);
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(() => {
@@ -1011,9 +991,76 @@ const MapComponent = ({ locations, onLocationUpdate, lineCoordinates }) => {
}, [dispatch]);
//----------------------------------------------
// speichere location devices in redux store
useInitLocationDevices();
useInitGisStationsStaticDistrict();
useInitGisStationsStatusDistrict();
useInitGisStationsMeasurements();
useInitGisSystemStatic();
useInitGisStationsStatic();
//--------------------------------------
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>

View File

@@ -0,0 +1,13 @@
// /components/mainComponent/hooks/useInitializeMap.js
import { useEffect } from "react";
import { initializeMap } from "../../../utils/initializeMap";
const useInitializeMap = (map, mapRef, setMap, setOms, setMenuItemAdded, addItemsToMapContextMenu, hasRights, setPolylineEventsDisabled) => {
useEffect(() => {
if (mapRef.current && !map) {
initializeMap(mapRef, setMap, setOms, setMenuItemAdded, addItemsToMapContextMenu, hasRights, setPolylineEventsDisabled);
}
}, [mapRef, map, hasRights, setPolylineEventsDisabled]);
};
export default useInitializeMap;

View File

@@ -0,0 +1,20 @@
// /components/mainComponent/hooks/useLoadUserRights.js
import { useEffect } from "react";
import { fetchUserRights } from "../../../services/api/fetchUserRights";
const useLoadUserRights = (setUserRights, setIsRightsLoaded, setHasRights) => {
useEffect(() => {
const fetchAndSetUserRights = async () => {
const rights = await fetchUserRights();
setUserRights(rights);
setIsRightsLoaded(true);
// Sicherstellen, dass `rights` ein Array ist, bevor `.includes()` aufgerufen wird
setHasRights(localStorage.getItem("editMode") && Array.isArray(rights) && rights.includes(56));
};
fetchAndSetUserRights();
}, []);
};
export default useLoadUserRights;

View File

@@ -0,0 +1,38 @@
// components/mainComponent/hooks/useAutoRefreshLocationDevices.js
/*
Das ist erstmal nur so da, falls es gebraucht wird
Diese datei ist zum automatischen aktualisieren der LocationDevices gedacht
jeder 20 Sekunden wird die Funktion fetchLocationDevicesFromDB() aufgerufen
Daten werden dann in der Redux State gespeichert
*/
import { useEffect } from "react";
import { useDispatch } from "react-redux";
import { fetchLocationDevicesFromDB } from "../../../../redux/slices/db/locationDevicesFromDBSlice";
export const useAutoRefreshLocationDevices = (interval = 20000) => {
// alle 20 Sekunden
const dispatch = useDispatch();
useEffect(() => {
const fetchData = () => {
dispatch(fetchLocationDevicesFromDB());
};
fetchData(); // Sofort beim Start holen
const intervalId = setInterval(fetchData, interval);
return () => clearInterval(intervalId); // Cleanup beim Unmount
}, [dispatch, interval]);
};
/*
In MapComponent.js einbinden
import { useAutoRefreshLocationDevices } from "./hooks/useAutoRefreshLocationDevices";
const MapComponent = () => {
useAutoRefreshLocationDevices();
*/

View File

@@ -0,0 +1,12 @@
// /components/mainComponent/hooks/useInitGisStationsMeasurements.js
import { useEffect } from "react";
import { useDispatch } from "react-redux";
import { fetchGisStationsMeasurementsFromWebService } from "../../../../redux/slices/webService/gisStationsMeasurementsSlice";
export const useInitGisStationsMeasurements = () => {
const dispatch = useDispatch();
useEffect(() => {
dispatch(fetchGisStationsMeasurementsFromWebService());
}, [dispatch]);
};

View File

@@ -0,0 +1,21 @@
// /components/mainComponent/hooks/useInitGisStationsStatic.js
//Bereiche/Area-Name Dropdownmenu für Datasheet wird hier initialisiert und in der Komponente verwendet
import { useEffect } from "react";
import { useDispatch, useSelector } from "react-redux";
import { fetchGisStationsStatic, selectGisStationsStatic } from "../../../../redux/slices/webService/gisStationsStaticSlice";
export const useInitGisStationsStatic = () => {
const dispatch = useDispatch();
const gisStationsStatic = useSelector(selectGisStationsStatic);
useEffect(() => {
// console.log("🔍 useInitGisStationsStatic - Aktueller Wert:", gisStationsStatic);
if (!gisStationsStatic || gisStationsStatic === null) {
//console.log("🚀 Starte fetchGisStationsStatic...");
dispatch(fetchGisStationsStatic());
}
}, [gisStationsStatic, dispatch]);
return gisStationsStatic;
};

View File

@@ -0,0 +1,12 @@
// /components/mainComponent/hooks/useInitGisStationsStaticDistrict.js
import { useEffect } from "react";
import { useDispatch } from "react-redux";
import { fetchGisStationsStaticDistrictFromWebService } from "../../../../redux/slices/webService/gisStationsStaticDistrictSlice";
export const useInitGisStationsStaticDistrict = () => {
const dispatch = useDispatch();
useEffect(() => {
dispatch(fetchGisStationsStaticDistrictFromWebService());
}, [dispatch]);
};

View File

@@ -0,0 +1,12 @@
// /componets/mainComponent/hooks/useInitGisStationsStatusDistrict.js
import { useEffect } from "react";
import { useDispatch } from "react-redux";
import { fetchGisStationsStatusDistrictFromWebService } from "../../../../redux/slices/webService/gisStationsStatusDistrictSlice";
export const useInitGisStationsStatusDistrict = () => {
const dispatch = useDispatch();
useEffect(() => {
dispatch(fetchGisStationsStatusDistrictFromWebService());
}, [dispatch]);
};

View File

@@ -0,0 +1,12 @@
// /components/mainComponent/hooks/useInitGisStationsMeasurements.js
import { useEffect } from "react";
import { useDispatch } from "react-redux";
import { fetchGisSystemStaticFromWebService } from "../../../../redux/slices/webService/gisSystemStaticSlice";
export const useInitGisSystemStatic = () => {
const dispatch = useDispatch();
useEffect(() => {
dispatch(fetchGisSystemStaticFromWebService());
}, [dispatch]);
};

View File

@@ -0,0 +1,12 @@
// /components/mainComponent/hooks/useInitLocationDevices.js
import { useEffect } from "react";
import { useDispatch } from "react-redux";
import { fetchLocationDevicesFromDB } from "../../../../redux/slices/db/locationDevicesFromDBSlice";
export const useInitLocationDevices = () => {
const dispatch = useDispatch();
useEffect(() => {
dispatch(fetchLocationDevicesFromDB());
}, [dispatch]);
};

View File

@@ -5,9 +5,14 @@ import { useRecoilState } from "recoil";
import { selectedPoiState } from "../../redux/slices/selectedPoiSlice";
import { currentPoiState } from "../../redux/slices/currentPoiSlice";
import { mapLayersState } from "../../redux/slices/mapLayersSlice";
import { selectCurrentPoi } from "../../redux/slices/currentPoiSlice";
import { fetchLocationDevicesFromDB } from "../../redux/slices/db/locationDevicesFromDBSlice";
import { useSelector, useDispatch } from "react-redux";
const PoiUpdateModal = ({ onClose, poiData, onSubmit }) => {
const currentPoi = useRecoilState(currentPoiState);
const dispatch = useDispatch();
const currentPoi = useSelector(selectCurrentPoi);
const selectedPoi = useRecoilState(selectedPoiState);
const [mapLayersVisibility] = useRecoilState(mapLayersState);
@@ -41,6 +46,12 @@ const PoiUpdateModal = ({ onClose, poiData, onSubmit }) => {
Basisgerät: 200,
};
const devices = useSelector((state) => state.locationDevicesFromDB.devices);
useEffect(() => {
dispatch(fetchLocationDevicesFromDB());
}, [dispatch]);
useEffect(() => {
if (poiData) {
setPoiId(poiData.idPoi);
@@ -84,23 +95,10 @@ const PoiUpdateModal = ({ onClose, poiData, onSubmit }) => {
// Fetch location devices and pre-select the current device
useEffect(() => {
const fetchLocationDevices = async () => {
try {
const response = await fetch("/api/talas5/location_device");
const data = await response.json();
setLocationDeviceData(data);
filterDevices(data);
if (poiData && poiData.idLD) {
const selectedDevice = data.find((device) => device.idLD === poiData.idLD);
setDeviceName(selectedDevice ? { value: selectedDevice.name, label: selectedDevice.name } : null);
}
} catch (error) {
console.error("Fehler beim Abrufen der Standort- und Gerätedaten:", error);
}
};
fetchLocationDevices();
}, [poiData]);
if (devices.length > 0) {
filterDevices(devices); // <-- Filter direkt die Redux-Devices
}
}, [devices]);
// Funktion zum Filtern der Geräte basierend auf den aktiven Systemen (Layern)
const filterDevices = (devices) => {
@@ -168,15 +166,25 @@ const PoiUpdateModal = ({ onClose, poiData, onSubmit }) => {
};
// Erstelle Optionen für react-select
const poiTypeOptions = poiTypData.map((poiTyp) => ({
value: poiTyp.idPoiTyp,
label: poiTyp.name,
}));
const poiTypeOptions = Array.isArray(poiTypData)
? poiTypData.map((poiTyp) => ({
value: poiTyp.idPoiTyp,
label: poiTyp.name,
}))
: []; // Falls kein Array, dann leeres Array zurückgeben
const deviceOptions = filteredDevices.map((device) => ({
value: device.name,
label: device.name,
const deviceOptions = devices.map((device) => ({
value: device.idLD, // idLD ist die eindeutige ID des Geräts
label: device.name, // name ist der Anzeigename im Dropdown
}));
useEffect(() => {
if (poiData && devices.length > 0) {
const selectedDevice = devices.find((device) => device.idLD === poiData.idLD);
if (selectedDevice) {
setDeviceName({ value: selectedDevice.idLD, label: selectedDevice.name });
}
}
}, [poiData, devices]);
// Custom styles for react-select
const customStyles = {

View File

@@ -1,26 +1,17 @@
// components/pois/PoiUpdateModalWrapper.js
import React, { useState } from "react";
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 { setCurrentPoi } from "../../redux/slices/currentPoiSlice";
const PoiUpdateModalWrapper = ({ show, onClose, latlng }) => {
const setSelectedPoi = useSetRecoilState(selectedPoiState);
const setCurrentPoi = useSetRecoilState(currentPoiState);
const currentPoi = useRecoilValue(currentPoiState);
const poiReadTrigger = useRecoilValue(poiReadFromDbTriggerAtom);
const PoiUpdateModalWrapper = ({ show, onClose, latlng, poiData }) => {
const dispatch = useDispatch();
return (
show && (
<PoiUpdateModal
onClose={onClose}
poiData={currentPoi}
onSubmit={() => {}} // Add your submit logic here
latlng={latlng}
/>
)
);
useEffect(() => {
if (show && poiData) {
dispatch(setCurrentPoi(poiData));
}
}, [show, poiData, dispatch]);
const currentPoi = useSelector(selectCurrentPoi); // Direkt aus Redux holen
return show && <PoiUpdateModal onClose={onClose} poiData={currentPoi} onSubmit={() => {}} latlng={latlng} />;
};
export default PoiUpdateModalWrapper;

View File

@@ -3,7 +3,20 @@ import { toast } from "react-toastify";
import { zoomIn, zoomOut, centerHere } from "../utils/zoomAndCenterUtils";
// components/useMapContextMenu.js
const addItemsToMapContextMenu = (map, menuItemAdded, setMenuItemAdded, openPopupWithCoordinates) => {
const addItemsToMapContextMenu = (
map,
menuItemAdded,
setMenuItemAdded,
setShowCoordinatesModal,
setShowPoiModal,
setPopupCoordinates,
openPopupWithCoordinates // Hier wird die Funktion als Parameter hinzugefügt
) => {
const openPoiModal = (e) => {
setShowCoordinatesModal(false); // ✅ Jetzt verfügbar, weil als Parameter übergeben
setPopupCoordinates(e.latlng);
setShowPoiModal(true);
};
if (!menuItemAdded && map && map.contextmenu) {
map.contextmenu.addItem({
text: "Koordinaten anzeigen",
@@ -17,7 +30,15 @@ const addItemsToMapContextMenu = (map, menuItemAdded, setMenuItemAdded, openPopu
text: "Reinzoomen",
icon: "img/zoom_in.png",
callback: (e) => {
map.setZoom(map.getZoom() + 1);
const currentZoom = map.getZoom();
const newZoom = Math.min(15, currentZoom + 3); // Stellt sicher, dass max. 15 erreicht wird
const zoomDifference = Math.abs(newZoom - currentZoom); // Anzahl der Zoom-Stufen
const duration = zoomDifference * 0.5; // Pro Stufe 0.5 Sekunden
map.flyTo(map.getCenter(), newZoom, {
animate: true,
duration: duration,
});
},
});
@@ -25,7 +46,15 @@ const addItemsToMapContextMenu = (map, menuItemAdded, setMenuItemAdded, openPopu
text: "Rauszoomen",
icon: "img/zoom_out.png",
callback: () => {
map.setZoom(map.getZoom() - 1);
const currentZoom = map.getZoom();
const newZoom = Math.max(6, currentZoom - 3); // Stellt sicher, dass min. 6 erreicht wird
const zoomDifference = Math.abs(newZoom - currentZoom); // Anzahl der Zoom-Stufen
const duration = zoomDifference * 0.5; // Pro Stufe 0.5 Sekunden
map.flyTo(map.getCenter(), newZoom, {
animate: true,
duration: duration,
});
},
});
@@ -39,6 +68,19 @@ const addItemsToMapContextMenu = (map, menuItemAdded, setMenuItemAdded, openPopu
setMenuItemAdded(true);
}
if (!menuItemAdded && map && map.contextmenu) {
const editMode = localStorage.getItem("editMode") === "true";
if (editMode) {
console.log("editMode localStorage:", localStorage.getItem("editMode"));
console.log("editMode:", editMode);
map.contextmenu.addItem({
text: "POI hinzufügen",
icon: "/img/add_station.png",
callback: openPoiModal, // Jetzt mit Zugriff auf `setShowPoiModal`
});
}
}
};
export default addItemsToMapContextMenu;

View File

@@ -1,2 +1,2 @@
// /config/appVersion
export const APP_VERSION = "1.1.18";
export const APP_VERSION = "1.1.49";

View File

@@ -1,12 +1,13 @@
// hooks/useMapComponentState.js
// POI -> Kontextmenü -> POI bearbeiten -> Dropdown Geräteauswahl
import { useState, useEffect } from "react";
import usePoiTypData from "./usePoiTypData";
import { useRecoilValue } from "recoil";
import { poiLayerVisibleState } from "../redux/slices/poiLayerVisibleSlice";
import { isMockMode } from "../config/config";
export const useMapComponentState = () => {
const { poiTypData, isPoiTypLoaded } = usePoiTypData("/api/talas_v5_DB/poiTyp/readPoiTyp");
const [poiTypData, setPoiTypData] = useState([]);
const [isPoiTypLoaded, setIsPoiTypLoaded] = useState(false);
const [deviceName, setDeviceName] = useState("");
const [locationDeviceData, setLocationDeviceData] = useState([]);
const [priorityConfig, setPriorityConfig] = useState([]);
@@ -14,29 +15,72 @@ export const useMapComponentState = () => {
const poiLayerVisible = useRecoilValue(poiLayerVisibleState);
useEffect(() => {
const fetchDeviceData = async () => {
const fetchPoiTypData = async () => {
if (isMockMode()) {
console.log("⚠️ Mock-API: Gerätedaten geladen");
console.log("⚠️ Mock-API: POI Typen geladen (Mock)");
const mockData = [{ name: "Mock-Gerät 1" }, { name: "Mock-Gerät 2" }];
setLocationDeviceData(mockData);
setDeviceName(mockData[0].name);
const mockData = [
{ idPoiTyp: 1, name: "Mock Zähleranschlusskasten", icon: 4, onlySystemTyp: 0 },
{ idPoiTyp: 2, name: "Mock Geräteschrank", icon: 2, onlySystemTyp: 0 },
{ idPoiTyp: 4, name: "Mock Parkplatz", icon: 3, onlySystemTyp: 0 },
{ idPoiTyp: 6, name: "Mock Zufahrt", icon: 4, onlySystemTyp: 0 },
{ idPoiTyp: 20, name: "Mock Zählgerät", icon: 5, onlySystemTyp: 110 },
{ idPoiTyp: 21, name: "Mock Messschleife", icon: 6, onlySystemTyp: 110 },
{ idPoiTyp: 25, name: "Mock Sonstige", icon: 0, onlySystemTyp: 0 },
{ idPoiTyp: 33, name: "Mock Autobahnauffahrt", icon: 4, onlySystemTyp: null },
];
setPoiTypData(mockData);
setIsPoiTypLoaded(true);
return;
}
try {
const response = await fetch("/api/talas5/location_device");
const response = await fetch("/api/talas_v5_DB/poiTyp/readPoiTyp");
const data = await response.json();
setLocationDeviceData(data);
setPoiTypData(data);
setIsPoiTypLoaded(true);
} catch (error) {
console.error("❌ Fehler beim Abrufen der POI-Typen:", error);
setPoiTypData([]);
setIsPoiTypLoaded(true);
}
};
if (data.length > 0) {
setDeviceName(data[0].name);
const fetchDeviceData = async () => {
try {
const apiBaseUrl = process.env.NEXT_PUBLIC_API_BASE_URL;
// URL-Parameter aus der aktuellen Browser-URL holen
const params = new URLSearchParams(window.location.search);
const idMap = params.get("idMap") || "12"; // Fallback auf "12" falls nicht gesetzt
const url = `${apiBaseUrl}/GisStationsStatic?idMap=${idMap}`;
//console.log("📡 API Request URL:", url);
const response = await fetch(url);
//console.log("📡 API Response Status:", response.status);
// console.log("📡 API Response Headers:", response.headers.get("content-type"));
const text = await response.text();
//console.log("📡 API Response Text:", text);
// JSON manuell parsen, falls die API keinen JSON-Header sendet
const data = JSON.parse(text);
setLocationDeviceData(data.Points || []);
if (data.Points && data.Points.length > 0) {
setDeviceName(data.Points[0].LD_Name);
}
} catch (error) {
console.error("❌ Fehler beim Abrufen der Gerätedaten:", error);
}
};
fetchPoiTypData();
fetchDeviceData();
}, []);

View File

@@ -1,24 +1,10 @@
// hooks/usePolylineTooltipLayer.js
import { useEffect } from "react";
import L from "leaflet";
import { setupPolylines } from "../utils/setupPolylines";
import { setupPolylines } from "../utils/polylines/setupPolylines";
//Tooltip an mouse position anzeigen für die Linien
export const usePolylineTooltipLayer = (
map,
markers,
polylines,
setMarkers,
setPolylines,
linePositions,
lineColors,
tooltipContents,
setNewCoords,
tempMarker,
polylineVisible,
newPoint,
newCoords
) => {
//Tooltip an mouse position anzeigen für die Linien
export const usePolylineTooltipLayer = (map, markers, polylines, setMarkers, setPolylines, linePositions, lineColors, tooltipContents, setNewCoords, tempMarker, polylineVisible, newPoint, newCoords) => {
useEffect(() => {
if (!map) return;
@@ -81,4 +67,4 @@ export const usePolylineTooltipLayer = (
setMarkers(newMarkers);
setPolylines(newPolylines);
}, [map, linePositions, lineColors, tooltipContents, newPoint, newCoords, tempMarker, polylineVisible]);
};
};

View File

@@ -67,38 +67,57 @@ export class OverlappingMarkerSpiderfier {
return distance < this.nearbyDistance && marker !== m;
});
}
//---------------------------------------------------------------------------------------------
spiderfy(markers) {
const centerPt = this.map.latLngToLayerPoint(markers[0].getLatLng());
markers.forEach((marker, i) => {
const angle = this.circleStartAngle + (i * 2 * Math.PI) / markers.length;
const legLength = this.circleFootSeparation * (2 + i / markers.length);
const newPt = L.point(
centerPt.x + legLength * Math.cos(angle),
centerPt.y + legLength * Math.sin(angle)
);
const newPt = L.point(centerPt.x + legLength * Math.cos(angle), centerPt.y + legLength * Math.sin(angle));
const newLatLng = this.map.layerPointToLatLng(newPt);
if (!marker._oms) {
marker._oms = {}; // Stellt sicher, dass _oms ein Objekt ist
marker._oms = {};
}
// Speichert die aktuelle Position, bevor sie verändert wird
marker._oms.usualPosition = marker.getLatLng();
marker._oms.spidered = true; // Markiert, dass der Marker gespiderfied ist
marker._oms.spidered = true;
// Zeichne eine Linie zwischen ursprünglicher und neuer Position
const leg = L.polyline([marker._oms.usualPosition, newLatLng], {
color: this.legColors.usual,
weight: this.legWeight,
}).addTo(this.map);
marker._oms.leg = leg; // Speichert die Linie im Marker-Objekt
marker.setLatLng(newLatLng);
marker.setZIndexOffset(1000);
});
}
//---------------------------------------------------------------------------------------------
unspiderfy() {
this.markers.forEach((marker) => {
if (marker._oms && marker._oms.spidered) {
// Setzt den Marker nur dann zurück, wenn er gespiderfied war
// Falls eine Linie existiert, entferne sie aus der Karte
if (marker._oms.leg) {
this.map.removeLayer(marker._oms.leg);
marker._oms.leg = null;
}
marker.setLatLng(marker._oms.usualPosition);
marker.setZIndexOffset(0);
marker._oms.spidered = false; // Setzt zurück, dass der Marker nicht mehr gespiderfied ist
marker._oms.spidered = false;
}
});
// 🔥 Künstliches Click-Event auslösen, um die UI zu aktualisieren
setTimeout(() => {
this.map.fire("click");
console.log("Click-Event ausgelöst in OverlappingMarkerspiderfier.js in unspiderfy ");
}, 10); // Kurze Verzögerung, um sicherzustellen, dass die UI neu gerendert wird
}
//---------------------------------------------------------------------------------------------
}

View File

@@ -5,7 +5,7 @@ import { useRecoilState, useRecoilValue } from "recoil";
import { readPoiMarkersStore } from "../redux/slices/readPoiMarkersStoreSlice.js";
import { poiReadFromDbTriggerAtom } from "../redux/slices/poiReadFromDbTriggerSlice";
const MapComponentWithNoSSR = dynamic(() => import("../components/MapComponent"), { ssr: false });
const MapComponentWithNoSSR = dynamic(() => import("../components/mainComponent/MapComponent"), { ssr: false });
const TestScriptWithNoSSR = dynamic(() => import("../components/TestScript"), { ssr: false });
export default function Home() {

File diff suppressed because it is too large Load Diff

View File

@@ -1 +0,0 @@
{ "50922": "CPL Ismael" }

View File

@@ -1,17 +0,0 @@
{
"Name": "Liste aller Messungen der Geraete",
"Zeitstempel": "2025-03-05T12:23:16.0756875+01:00",
"IdMap": "12",
"Statis": [
{
"IdLD": 50951,
"IdL": 24101,
"IdDP": 3,
"Na": "FBT",
"Val": "5",
"Unit": "°C",
"Gr": "GMA",
"Area_Name": "Rastede"
}
]
}

View File

@@ -1,381 +0,0 @@
{
"Name": "Liste aller Geraete einer bestimmten Karte",
"Zeitstempel": "2025-03-05T14:55:10.1184475+01:00",
"IdMap": "12",
"Points": [
{
"LD_Name": "CPL Ismael",
"IdLD": 50922,
"Device": "CPL V3.5 mit 24 Kü",
"Link": "cpl.aspx?ver=35&kue=24&id=50922",
"Location_Name": "Littwin",
"Location_Short": "LTW",
"IdLocation": 24101,
"Area_Name": "Rastede",
"Area_Short": "",
"IdArea": 20998,
"X": 53.246112,
"Y": 8.162241,
"Icon": 20,
"System": 1,
"Active": 1
},
{
"LD_Name": "LTEModem",
"IdLD": 50950,
"Device": "LTE Modem LR77",
"Link": "lr77.aspx?ver=1&id=50950",
"Location_Name": "Littwin",
"Location_Short": "LTW",
"IdLocation": 24101,
"Area_Name": "Rastede",
"Area_Short": "",
"IdArea": 20998,
"X": 53.246112,
"Y": 8.162241,
"Icon": 12,
"System": 5,
"Active": 1
},
{
"LD_Name": "GMA ISA",
"IdLD": 50951,
"Device": "Glättemeldeanlage",
"Link": "gma.aspx?ver=1&id=50951",
"Location_Name": "Littwin",
"Location_Short": "LTW",
"IdLocation": 24101,
"Area_Name": "Rastede",
"Area_Short": "",
"IdArea": 20998,
"X": 53.246112,
"Y": 8.162241,
"Icon": 1,
"System": 11,
"Active": 1
},
{
"LD_Name": "Cisco Router 1841 ISA",
"IdLD": 50953,
"Device": "Cisco 1841",
"Link": "cisco1841.aspx?ver=1&id=50953",
"Location_Name": "Littwin",
"Location_Short": "LTW",
"IdLocation": 24101,
"Area_Name": "Rastede",
"Area_Short": "",
"IdArea": 20998,
"X": 53.246112,
"Y": 8.162241,
"Icon": 21,
"System": 6,
"Active": 1
},
{
"LD_Name": "Cisco Router 1921 ISA",
"IdLD": 50954,
"Device": "Cisco 1921",
"Link": "cisco1921.aspx?ver=1&id=50954",
"Location_Name": "Littwin",
"Location_Short": "LTW",
"IdLocation": 24101,
"Area_Name": "Rastede",
"Area_Short": "",
"IdArea": 20998,
"X": 53.246112,
"Y": 8.162241,
"Icon": 21,
"System": 6,
"Active": 1
},
{
"LD_Name": "Cisco Router 8200 ISA",
"IdLD": 50955,
"Device": "Cisco 8200",
"Link": "cisco8200.aspx?ver=1&id=50955",
"Location_Name": "Littwin",
"Location_Short": "LTW",
"IdLocation": 24101,
"Area_Name": "Rastede",
"Area_Short": "",
"IdArea": 20998,
"X": 53.246112,
"Y": 8.162241,
"Icon": 21,
"System": 6,
"Active": 1
},
{
"LD_Name": "Dauerzählstelle DZ ISA",
"IdLD": 50956,
"Device": "Dauerzählstelle DZ",
"Link": "dauz.aspx?ver=1&id=50956",
"Location_Name": "Littwin",
"Location_Short": "LTW",
"IdLocation": 24101,
"Area_Name": "Rastede",
"Area_Short": "",
"IdArea": 20998,
"X": 53.246112,
"Y": 8.162241,
"Icon": 14,
"System": 110,
"Active": 1
},
{
"LD_Name": "ECI Gerät ISA",
"IdLD": 50957,
"Device": "ECI",
"Link": "eci.aspx?ver=1&id=50957",
"Location_Name": "Littwin",
"Location_Short": "LTW",
"IdLocation": 24101,
"Area_Name": "Rastede",
"Area_Short": "",
"IdArea": 20998,
"X": 53.246112,
"Y": 8.162241,
"Icon": 17,
"System": 2,
"Active": 1
},
{
"LD_Name": "LTE-Modem LR77",
"IdLD": 50958,
"Device": "LTE Modem LR77",
"Link": "lr77.aspx?ver=1&id=50958",
"Location_Name": "Littwin",
"Location_Short": "LTW",
"IdLocation": 24101,
"Area_Name": "Rastede",
"Area_Short": "",
"IdArea": 20998,
"X": 53.246112,
"Y": 8.162241,
"Icon": 12,
"System": 5,
"Active": 1
},
{
"LD_Name": "Glasfaserüberwachung OTU ISA",
"IdLD": 50959,
"Device": "OTU",
"Link": "otu.aspx?ver=1&id=50959",
"Location_Name": "Littwin",
"Location_Short": "LTW",
"IdLocation": 24101,
"Area_Name": "Rastede",
"Area_Short": "",
"IdArea": 20998,
"X": 53.246112,
"Y": 8.162241,
"Icon": 24,
"System": 9,
"Active": 1
},
{
"LD_Name": "Siemens Notrufsystem ISA",
"IdLD": 50960,
"Device": "Notruf Server NRS 2000",
"Link": "nrs_server.aspx?ver=1&id=50960",
"Location_Name": "Littwin",
"Location_Short": "LTW",
"IdLocation": 24101,
"Area_Name": "Rastede",
"Area_Short": "",
"IdArea": 20998,
"X": 53.246112,
"Y": 8.162241,
"Icon": 19,
"System": 8,
"Active": 1
},
{
"LD_Name": "SMS-Modem ISA",
"IdLD": 50961,
"Device": "SMS Funkmodem",
"Link": "sms_modem.aspx?ver=1&id=50961",
"Location_Name": "Littwin",
"Location_Short": "LTW",
"IdLocation": 24101,
"Area_Name": "Rastede",
"Area_Short": "",
"IdArea": 20998,
"X": 53.246112,
"Y": 8.162241,
"Icon": 12,
"System": 111,
"Active": 1
},
{
"LD_Name": "Basisgerät Sonstige ISA",
"IdLD": 50962,
"Device": "Basisgerät",
"Link": "basis.aspx?ver=1&id=50962",
"Location_Name": "Littwin",
"Location_Short": "LTW",
"IdLocation": 24101,
"Area_Name": "Rastede",
"Area_Short": "",
"IdArea": 20998,
"X": 53.246112,
"Y": 8.162241,
"Icon": 31,
"System": 200,
"Active": 0
},
{
"LD_Name": "Talasmeldestation ISA",
"IdLD": 50963,
"Device": "CPL V3.5 mit 16 Kü",
"Link": "cpl.aspx?ver=35&kue=16&id=50963",
"Location_Name": "Littwin",
"Location_Short": "LTW",
"IdLocation": 24101,
"Area_Name": "Rastede",
"Area_Short": "",
"IdArea": 20998,
"X": 53.246112,
"Y": 8.162241,
"Icon": 20,
"System": 1,
"Active": 1
},
{
"LD_Name": "TALAS ICL M4 Meldestation ISA",
"IdLD": 50964,
"Device": "ICL",
"Link": "icl.aspx?ver=1&id=50964",
"Location_Name": "Littwin",
"Location_Short": "LTW",
"IdLocation": 24101,
"Area_Name": "Rastede",
"Area_Short": "",
"IdArea": 20998,
"X": 53.246112,
"Y": 8.162241,
"Icon": 23,
"System": 100,
"Active": 1
},
{
"LD_Name": "TALAS ICL M2 Meldestation ISA",
"IdLD": 50965,
"Device": "ICL",
"Link": "icl.aspx?ver=1&id=50965",
"Location_Name": "Littwin",
"Location_Short": "LTW",
"IdLocation": 24101,
"Area_Name": "Rastede",
"Area_Short": "",
"IdArea": 20998,
"X": 53.246112,
"Y": 8.162241,
"Icon": 23,
"System": 100,
"Active": 1
},
{
"LD_Name": "TALAS ICL M3 Meldestation ISA",
"IdLD": 50966,
"Device": "ICL",
"Link": "icl.aspx?ver=1&id=50966",
"Location_Name": "Littwin",
"Location_Short": "LTW",
"IdLocation": 24101,
"Area_Name": "Rastede",
"Area_Short": "",
"IdArea": 20998,
"X": 53.246112,
"Y": 8.162241,
"Icon": 23,
"System": 100,
"Active": 1
},
{
"LD_Name": "TALAS ICL M1 Meldestation ISA",
"IdLD": 50967,
"Device": "ICL",
"Link": "icl.aspx?ver=1&id=50967",
"Location_Name": "Littwin",
"Location_Short": "LTW",
"IdLocation": 24101,
"Area_Name": "Rastede",
"Area_Short": "",
"IdArea": 20998,
"X": 53.246112,
"Y": 8.162241,
"Icon": 23,
"System": 100,
"Active": 1
},
{
"LD_Name": "TL-Komponente-Router ISA",
"IdLD": 50968,
"Device": "TK-Router",
"Link": "tk_router.aspx?ver=1&id=50968",
"Location_Name": "Littwin",
"Location_Short": "LTW",
"IdLocation": 24101,
"Area_Name": "Rastede",
"Area_Short": "",
"IdArea": 20998,
"X": 53.246112,
"Y": 8.162241,
"Icon": 14,
"System": 30,
"Active": 1
},
{
"LD_Name": "TK-Anlage Alcatel OXO ISA",
"IdLD": 50969,
"Device": "TK-Anlage Alcatel OXO",
"Link": "tk_oxo.aspx?ver=1&id=50969",
"Location_Name": "Littwin",
"Location_Short": "LTW",
"IdLocation": 24101,
"Area_Name": "Rastede",
"Area_Short": "",
"IdArea": 20998,
"X": 53.246112,
"Y": 8.162241,
"Icon": 14,
"System": 30,
"Active": 1
},
{
"LD_Name": "WAGO Klemmen 16 ISA",
"IdLD": 50971,
"Device": "WAGO 16 DE",
"Link": "wago.aspx?ver=1&DE=16&id=50971",
"Location_Name": "Littwin",
"Location_Short": "LTW",
"IdLocation": 24101,
"Area_Name": "Rastede",
"Area_Short": "",
"IdArea": 20998,
"X": 53.246112,
"Y": 8.162241,
"Icon": 9,
"System": 7,
"Active": 1
},
{
"LD_Name": "WAGO Klemmen 32 ISA",
"IdLD": 50972,
"Device": "WAGO 32 DE",
"Link": "wago.aspx?ver=1&DE=32&id=50972",
"Location_Name": "Littwin",
"Location_Short": "LTW",
"IdLocation": 24101,
"Area_Name": "Rastede",
"Area_Short": "",
"IdArea": 20998,
"X": 53.246112,
"Y": 8.162241,
"Icon": 9,
"System": 7,
"Active": 1
}
]
}

View File

@@ -1,115 +0,0 @@
{
"Name": "Liste aller Statis der Geraete",
"Zeitstempel": "2025-03-05T14:56:54.4913452+01:00",
"IdMap": "12",
"Statis": [
{
"IdLD": 50922,
"Na": "system",
"Le": 4,
"Co": "#FF00FF",
"Me": "Eingang DE 01 test5",
"Feld": 4,
"Icon": 0
},
{
"IdLD": 50922,
"Na": "system",
"Le": 4,
"Co": "#FF00FF",
"Me": "Eingang DE 05 kommend",
"Feld": 4,
"Icon": 0
},
{
"IdLD": 50922,
"Na": "system",
"Le": 4,
"Co": "#FF00FF",
"Me": "Eingang DE 17 kommend",
"Feld": 4,
"Icon": 0
},
{
"IdLD": 50922,
"Na": "system",
"Le": 4,
"Co": "#FF00FF",
"Me": "Eingang DE 31 kommend",
"Feld": 4,
"Icon": 0
},
{
"IdLD": 50922,
"Na": "system",
"Le": 4,
"Co": "#FF00FF",
"Me": "Eingang DE 32 kommend",
"Feld": 4,
"Icon": 0
},
{
"IdLD": 50922,
"Na": "system",
"Le": 4,
"Co": "#FF00FF",
"Me": "Station offline",
"Feld": 4,
"Icon": 0
},
{
"IdLD": 50922,
"Na": "minor",
"Le": 3,
"Co": "#FFFF00",
"Me": "Eingang DE 02 kommend",
"Feld": 4,
"Icon": 0
},
{
"IdLD": 50922,
"Na": "minor",
"Le": 3,
"Co": "#FFFF00",
"Me": "KÜG 08: Überspannung gehend",
"Feld": 4,
"Icon": 0
},
{
"IdLD": 50922,
"Na": "major",
"Le": 2,
"Co": "#FF9900",
"Me": "Eingang DE 03 kommend",
"Feld": 4,
"Icon": 0
},
{
"IdLD": 50922,
"Na": "critical",
"Le": 1,
"Co": "#FF0000",
"Me": "KÜG 01: Aderbruch kommend",
"Feld": 4,
"Icon": 0
},
{
"IdLD": 50922,
"Na": "critical",
"Le": 1,
"Co": "#FF0000",
"Me": "KÜG 02: Aderbruch kommend",
"Feld": 4,
"Icon": 0
},
{
"IdLD": 50922,
"Na": "critical",
"Le": 1,
"Co": "#FF0000",
"Me": "KÜG 03: Aderbruch kommend",
"Feld": 4,
"Icon": 0
}
]
}

View File

@@ -1,115 +0,0 @@
{
"Name": "Liste aller Statis der Geraete",
"Zeitstempel": "2025-03-05T15:04:09.206634+01:00",
"IdMap": "12",
"Statis": [
{
"IdLD": 50922,
"Na": "system",
"Le": 4,
"Co": "#FF00FF",
"Me": "Eingang DE 01 kommend",
"Feld": 4,
"Icon": 0
},
{
"IdLD": 50922,
"Na": "system",
"Le": 4,
"Co": "#FF00FF",
"Me": "Eingang DE 05 kommend",
"Feld": 4,
"Icon": 0
},
{
"IdLD": 50922,
"Na": "system",
"Le": 4,
"Co": "#FF00FF",
"Me": "Eingang DE 17 kommend",
"Feld": 4,
"Icon": 0
},
{
"IdLD": 50922,
"Na": "system",
"Le": 4,
"Co": "#FF00FF",
"Me": "Eingang DE 31 kommend",
"Feld": 4,
"Icon": 0
},
{
"IdLD": 50922,
"Na": "system",
"Le": 4,
"Co": "#FF00FF",
"Me": "Eingang DE 32 kommend",
"Feld": 4,
"Icon": 0
},
{
"IdLD": 50922,
"Na": "system",
"Le": 4,
"Co": "#FF00FF",
"Me": "Station offline",
"Feld": 4,
"Icon": 0
},
{
"IdLD": 50922,
"Na": "minor",
"Le": 3,
"Co": "#FFFF00",
"Me": "Eingang DE 02 kommend",
"Feld": 4,
"Icon": 0
},
{
"IdLD": 50922,
"Na": "minor",
"Le": 3,
"Co": "#FFFF00",
"Me": "KÜG 08: Überspannung gehend",
"Feld": 4,
"Icon": 0
},
{
"IdLD": 50922,
"Na": "major",
"Le": 2,
"Co": "#FF9900",
"Me": "Eingang DE 03 kommend",
"Feld": 4,
"Icon": 0
},
{
"IdLD": 50922,
"Na": "critical",
"Le": 1,
"Co": "#FF0000",
"Me": "KÜG 01: Aderbruch kommend",
"Feld": 4,
"Icon": 0
},
{
"IdLD": 50922,
"Na": "critical",
"Le": 1,
"Co": "#FF0000",
"Me": "KÜG 02: Aderbruch kommend",
"Feld": 4,
"Icon": 0
},
{
"IdLD": 50922,
"Na": "critical",
"Le": 1,
"Co": "#FF0000",
"Me": "KÜG 03: Aderbruch kommend",
"Feld": 4,
"Icon": 0
}
]
}

View File

@@ -1,268 +0,0 @@
{
"Name": "Liste aller angezeigten Systeme",
"Zeitstempel": "2025-03-05T15:04:55.2507517+01:00",
"IdMap": "12",
"Systems": [
{
"IdSystem": 1,
"Name": "TALAS",
"Longname": "Talas Meldestationen",
"Allow": 1,
"Icon": 1
},
{
"IdSystem": 2,
"Name": "ECI",
"Longname": "ECI Geräte",
"Allow": 1,
"Icon": 2
},
{
"IdSystem": 3,
"Name": "ULAF",
"Longname": "ULAF Geräte",
"Allow": 0,
"Icon": 3
},
{
"IdSystem": 5,
"Name": "LTE Modem",
"Longname": "LR77 GSM Modems",
"Allow": 1,
"Icon": 5
},
{
"IdSystem": 6,
"Name": "Cisco Router",
"Longname": "Cisco Router",
"Allow": 1,
"Icon": 6
},
{
"IdSystem": 7,
"Name": "WAGO",
"Longname": "WAGO I/O Systeme",
"Allow": 1,
"Icon": 7
},
{
"IdSystem": 8,
"Name": "Siemens",
"Longname": "Siemens Notrufsysteme",
"Allow": 1,
"Icon": 8
},
{
"IdSystem": 9,
"Name": "OTDR",
"Longname": "Glasfaserüberwachung OTU",
"Allow": 1,
"Icon": 9
},
{
"IdSystem": 10,
"Name": "WDM",
"Longname": " Wavelength Division Multiplexing",
"Allow": 1,
"Icon": 10
},
{
"IdSystem": 11,
"Name": "GMA",
"Longname": "Glättemeldeanlagen",
"Allow": 1,
"Icon": 11
},
{
"IdSystem": 13,
"Name": "Messstellen",
"Longname": "Messstellen",
"Allow": 0,
"Icon": 13
},
{
"IdSystem": 30,
"Name": "TK-Komponenten",
"Longname": "TK-Komponenten",
"Allow": 1,
"Icon": 30
},
{
"IdSystem": 100,
"Name": "TALAS ICL",
"Longname": "Talas ICL Unterstationen",
"Allow": 1,
"Icon": 100
},
{
"IdSystem": 110,
"Name": "DAUZ",
"Longname": "Dauerzählstellen",
"Allow": 1,
"Icon": 110
},
{
"IdSystem": 111,
"Name": "SMS Modem",
"Longname": "SMS Modem",
"Allow": 1,
"Icon": 111
},
{
"IdSystem": 200,
"Name": "Sonstige",
"Longname": "Sonstige",
"Allow": 1,
"Icon": 200
}
],
"Rights": [
{
"IdRight": 1
},
{
"IdRight": 2
},
{
"IdRight": 3
},
{
"IdRight": 5
},
{
"IdRight": 6
},
{
"IdRight": 7
},
{
"IdRight": 8
},
{
"IdRight": 10
},
{
"IdRight": 11
},
{
"IdRight": 12
},
{
"IdRight": 20
},
{
"IdRight": 22
},
{
"IdRight": 23
},
{
"IdRight": 25
},
{
"IdRight": 30
},
{
"IdRight": 40
},
{
"IdRight": 41
},
{
"IdRight": 42
},
{
"IdRight": 43
},
{
"IdRight": 44
},
{
"IdRight": 45
},
{
"IdRight": 46
},
{
"IdRight": 47
},
{
"IdRight": 48
},
{
"IdRight": 49
},
{
"IdRight": 50
},
{
"IdRight": 51
},
{
"IdRight": 52
},
{
"IdRight": 55
},
{
"IdRight": 56
},
{
"IdRight": 60
},
{
"IdRight": 61
},
{
"IdRight": 62
},
{
"IdRight": 63
},
{
"IdRight": 64
},
{
"IdRight": 65
},
{
"IdRight": 68
},
{
"IdRight": 69
},
{
"IdRight": 70
},
{
"IdRight": 71
},
{
"IdRight": 72
},
{
"IdRight": 73
},
{
"IdRight": 79
},
{
"IdRight": 80
},
{
"IdRight": 90
},
{
"IdRight": 93
},
{
"IdRight": 94
},
{
"IdRight": 95
},
{
"IdRight": 96
}
]
}

View File

@@ -0,0 +1,8 @@
// /redux/api/fromDB/fetchLocationDevices.js
export const fetchLocationDevices = async () => {
const response = await fetch("/api/talas_v5_DB/locationDevice/locationDevices");
if (!response.ok) {
throw new Error("Geräteliste konnte nicht geladen werden");
}
return await response.json();
};

View File

@@ -0,0 +1,22 @@
// /redux/api/fromWebService/fetchGisStationsMeasurements.js
// http://192.168.10.33/talas5/ClientData/WebServiceMap.asmx/GisStationsMeasurements?idMap=12&idUser=484
const apiBaseUrl = process.env.NEXT_PUBLIC_API_BASE_URL;
export const fetchGisStationsMeasurements = async () => {
const params = new URLSearchParams(window.location.search);
const idMap = params.get("idMap") || process.env.NEXT_PUBLIC_DEFAULT_ID_MAP || "12";
const idUser = params.get("idUser") || process.env.NEXT_PUBLIC_DEFAULT_ID_USER || "484";
//console.log("🔍 fetchGisStationsMeasurements - URL:", `${apiBaseUrl}/GisStationsMeasurements?idMap=${idMap}&idUser=${idUser}`);
const response = await fetch(`${apiBaseUrl}/GisStationsMeasurements?idMap=${idMap}&idUser=${idUser}`);
if (!response.ok) {
throw new Error("GisStationsMeasurements konnte nicht geladen werden");
}
const data = await response.json();
//console.log("✅ fetchGisStationsMeasurements - Daten:", data);
return data;
};

View File

@@ -0,0 +1,25 @@
// /redux/api/fromWebService/fetchGisStationsStatic.js
// z.B. http://192.168.10.33/talas5/ClientData/WebServiceMap.asmx/GisStationsStatic?idMap=12
const apiBaseUrl = process.env.NEXT_PUBLIC_API_BASE_URL;
export const fetchGisStationsStatic = async () => {
try {
const response = await fetch(`${apiBaseUrl}/GisStationsStatic?idMap=12`);
//console.log("📡 API Response Status:", response.status);
//console.log("📡 API Response Headers:", response.headers.get("content-type"));
const text = await response.text();
console.log("📡 API Response Text von fetch:", text);
console.log("📡 API Response response von fetch:", response);
if (!response.ok || !response.headers.get("content-type")?.includes("application/json")) {
throw new Error("❌ Fehler: Antwort ist kein gültiges JSON");
}
return JSON.parse(text);
} catch (error) {
console.error("❌ Fehler beim Abrufen der GIS Stations Static:", error);
return null;
}
};

View File

@@ -0,0 +1,22 @@
// /redux/api/fromWebService/fetchGisStationsStaticDistrict.js
// http://192.168.10.33/talas5/ClientData/WebServiceMap.asmx/GisStationsStaticDistrict?idMap=12&idUser=484
const apiBaseUrl = process.env.NEXT_PUBLIC_API_BASE_URL;
export const fetchGisStationsStaticDistrict = async () => {
const params = new URLSearchParams(window.location.search);
const idMap = params.get("idMap") || process.env.NEXT_PUBLIC_DEFAULT_ID_MAP || "12";
const idUser = params.get("idUser") || process.env.NEXT_PUBLIC_DEFAULT_ID_USER || "484";
// console.log("🔍 fetchGisStationsStaticDistrict - URL:", `${apiBaseUrl}/GisStationsStaticDistrict?idMap=${idMap}&idUser=${idUser}`);
const response = await fetch(`${apiBaseUrl}/GisStationsStaticDistrict?idMap=${idMap}&idUser=${idUser}`);
if (!response.ok) {
throw new Error("GisStationsStaticDistrict konnte nicht geladen werden");
}
const data = await response.json();
// console.log("✅ fetchGisStationsStaticDistrict - Daten:", data);
return data;
};

View File

@@ -0,0 +1,22 @@
// /redux/api/fromWebService/fetchGisStationsStatusDistrict.js
// http://192.168.10.33/talas5/ClientData/WebServiceMap.asmx/GisStationsStatusDistrict?idMap=12&idUser=484
const apiBaseUrl = process.env.NEXT_PUBLIC_API_BASE_URL;
export const fetchGisStationsStatusDistrict = async () => {
const params = new URLSearchParams(window.location.search);
const idMap = params.get("idMap") || process.env.NEXT_PUBLIC_DEFAULT_ID_MAP || "12";
const idUser = params.get("idUser") || process.env.NEXT_PUBLIC_DEFAULT_ID_USER || "484";
//console.log("🔍 fetchGisStationsStatusDistrict - URL:", `${apiBaseUrl}/GisStationsStatusDistrict?idMap=${idMap}&idUser=${idUser}`);
const response = await fetch(`${apiBaseUrl}/GisStationsStatusDistrict?idMap=${idMap}&idUser=${idUser}`);
if (!response.ok) {
throw new Error("GisStationsStatusDistrict konnte nicht geladen werden");
}
const data = await response.json();
//console.log("✅ fetchGisStationsStatusDistrict - Daten:", data);
return data;
};

View File

@@ -0,0 +1,18 @@
// /redux/api/fromWebService/fetchGisSystemStatic.js
// http://192.168.10.33/talas5/ClientData/WebServiceMap.asmx/GisSystemStatic?idMap=12&idUser=484
const apiBaseUrl = process.env.NEXT_PUBLIC_API_BASE_URL;
export async function fetchGisSystemStatic() {
const params = new URLSearchParams(window.location.search);
const idMap = params.get("idMap") || process.env.NEXT_PUBLIC_DEFAULT_ID_MAP || "12";
const idUser = params.get("idUser") || process.env.NEXT_PUBLIC_DEFAULT_ID_USER || "484";
//console.log("🔍 fetchGisSystemStatic - URL:", `${apiBaseUrl}/GisSystemStatic?idMap=${idMap}&idUser=${idUser}`);
const response = await fetch(`${apiBaseUrl}/GisSystemStatic?idMap=${idMap}&idUser=${idUser}`);
const data = await response.json();
//console.log("✅ fetchGisSystemStatic - Daten:", data);
return data;
}

View File

@@ -0,0 +1,24 @@
import { createSlice } from "@reduxjs/toolkit";
const initialState = {
isOpen: false,
latlng: null,
};
const addPoiOnPolylineSlice = createSlice({
name: "addPoiOnPolyline",
initialState,
reducers: {
openAddPoiOnPolylineModal: (state, action) => {
state.isOpen = true;
state.latlng = action.payload;
},
closeAddPoiOnPolylineModal: (state) => {
state.isOpen = false;
state.latlng = null;
},
},
});
export const { openAddPoiOnPolylineModal, closeAddPoiOnPolylineModal } = addPoiOnPolylineSlice.actions;
export default addPoiOnPolylineSlice.reducer;

View File

@@ -0,0 +1,33 @@
// /redux/slices/db/locationDevicesFromDBSlice.js
import { createSlice, createAsyncThunk } from "@reduxjs/toolkit";
import { fetchLocationDevices } from "../../api/fromDB/fetchLocationDevices";
export const fetchLocationDevicesFromDB = createAsyncThunk("locationDevicesFromDB/fetchLocationDevicesFromDB", async () => {
return fetchLocationDevices();
});
const locationDevicesFromDBSlice = createSlice({
name: "locationDevicesFromDB",
initialState: {
devices: [],
status: "idle",
error: null,
},
reducers: {},
extraReducers: (builder) => {
builder
.addCase(fetchLocationDevicesFromDB.pending, (state) => {
state.status = "loading";
})
.addCase(fetchLocationDevicesFromDB.fulfilled, (state, action) => {
state.status = "succeeded";
state.devices = action.payload; // <-- Hier landen die Daten
})
.addCase(fetchLocationDevicesFromDB.rejected, (state, action) => {
state.status = "failed";
state.error = action.error.message;
});
},
});
export default locationDevicesFromDBSlice.reducer;

View File

@@ -0,0 +1,30 @@
// /redux/slices/db/poiTypesSlice.js
import { createSlice, createAsyncThunk } from "@reduxjs/toolkit";
// API-Abruf für POI-Typen
export const fetchPoiTypes = createAsyncThunk("poiTypes/fetchPoiTypes", async () => {
const API_BASE_URL = process.env.NEXT_PUBLIC_API_PORT_3000;
const response = await fetch(`${API_BASE_URL}/api/talas_v5_DB/poiTyp/readPoiTyp`);
return await response.json();
});
const poiTypesSlice = createSlice({
name: "poiTypes",
initialState: { data: [], status: "idle" },
reducers: {},
extraReducers: (builder) => {
builder
.addCase(fetchPoiTypes.pending, (state) => {
state.status = "loading";
})
.addCase(fetchPoiTypes.fulfilled, (state, action) => {
state.data = action.payload;
state.status = "succeeded";
})
.addCase(fetchPoiTypes.rejected, (state) => {
state.status = "failed";
});
},
});
export default poiTypesSlice.reducer;

View File

@@ -1,23 +0,0 @@
// /redux/slices/gisStationsStaticDistrictSlice.js
import { createSlice } from "@reduxjs/toolkit";
const initialState = [];
const gisStationsStaticDistrictSlice = createSlice({
name: "gisStationsStaticDistrict",
initialState,
reducers: {
setGisStationsStaticDistrict: (state, action) => {
return action.payload;
},
clearGisStationsStaticDistrict: () => {
return [];
},
},
});
export const { setGisStationsStaticDistrict, clearGisStationsStaticDistrict } = gisStationsStaticDistrictSlice.actions;
export const selectGisStationsStaticDistrict = (state) => state.gisStationsStaticDistrict;
export default gisStationsStaticDistrictSlice.reducer;

View File

@@ -1,7 +0,0 @@
// /redux/slices/gisSystemStaticSlice.js
import { atom } from "recoil";
export const gisSystemStaticState = atom({
key: "gisSystemStatic", // Eindeutiger Schlüssel (innerhalb des Projekts)
default: [], // Standardwert (Anfangszustand)
});

View File

@@ -0,0 +1,56 @@
// redux/slices/polylineContextMenuSlice.js
import { createSlice } from "@reduxjs/toolkit";
const initialState = {
isOpen: false,
position: null,
forceClose: false,
timerStart: null,
countdown: 20,
countdownActive: false, // **Neu: Redux merkt, ob der Timer aktiv ist**
};
const polylineContextMenuSlice = createSlice({
name: "polylineContextMenu",
initialState,
reducers: {
openPolylineContextMenu: (state, action) => {
state.isOpen = true;
state.position = { lat: action.payload.position.lat, lng: action.payload.position.lng };
state.forceClose = false;
state.timerStart = Date.now();
state.countdown = 20;
state.countdownActive = true; // **Timer aktiv setzen**
},
closePolylineContextMenu: (state) => {
state.isOpen = false;
state.position = null;
state.timerStart = null;
state.countdown = 0;
state.countdownActive = false; // **Timer stoppen**
},
updateCountdown: (state) => {
if (state.timerStart && state.countdownActive) {
const elapsedTime = (Date.now() - state.timerStart) / 1000;
state.countdown = Math.max(20 - elapsedTime, 0);
if (state.countdown <= 2) {
state.isOpen = false;
state.position = null;
state.countdownActive = false;
}
}
},
forceCloseContextMenu: (state) => {
state.isOpen = false;
state.position = null;
state.forceClose = true;
state.timerStart = null;
state.countdown = 0;
state.countdownActive = false;
},
},
});
export const { openPolylineContextMenu, closePolylineContextMenu, updateCountdown, forceCloseContextMenu } = polylineContextMenuSlice.actions;
export default polylineContextMenuSlice.reducer;

View File

@@ -0,0 +1,35 @@
// /redux/slices/webService/gisStationsMeasurementsSlice.js
import { createSlice, createAsyncThunk } from "@reduxjs/toolkit";
import { fetchGisStationsMeasurements } from "../../api/fromWebService/fetchGisStationsMeasurements";
export const fetchGisStationsMeasurementsFromWebService = createAsyncThunk("gisStationsMeasurements/fetchGisStationsMeasurementsFromWebService", async () => {
return fetchGisStationsMeasurements();
});
const gisStationsMeasurementsSlice = createSlice({
name: "gisStationsMeasurements",
initialState: {
data: [],
status: "idle",
error: null,
},
reducers: {},
extraReducers: (builder) => {
builder
.addCase(fetchGisStationsMeasurementsFromWebService.pending, (state) => {
state.status = "loading";
})
.addCase(fetchGisStationsMeasurementsFromWebService.fulfilled, (state, action) => {
state.status = "succeeded";
state.data = action.payload;
})
.addCase(fetchGisStationsMeasurementsFromWebService.rejected, (state, action) => {
state.status = "failed";
state.error = action.error.message;
});
},
});
export const selectGisStationsMeasurements = (state) => state.gisStationsMeasurements.data;
export default gisStationsMeasurementsSlice.reducer;

View File

@@ -0,0 +1,35 @@
// /redux/slices/webService/gisStationsStaticDistrictSlice.js
import { createSlice, createAsyncThunk } from "@reduxjs/toolkit";
import { fetchGisStationsStaticDistrict } from "../../api/fromWebService/fetchGisStationsStaticDistrict";
export const fetchGisStationsStaticDistrictFromWebService = createAsyncThunk("gisStationsStaticDistrict/fetchGisStationsStaticDistrictFromWebService", async () => {
return fetchGisStationsStaticDistrict();
});
const gisStationsStaticDistrictSlice = createSlice({
name: "gisStationsStaticDistrict",
initialState: {
data: [],
status: "idle",
error: null,
},
reducers: {},
extraReducers: (builder) => {
builder
.addCase(fetchGisStationsStaticDistrictFromWebService.pending, (state) => {
state.status = "loading";
})
.addCase(fetchGisStationsStaticDistrictFromWebService.fulfilled, (state, action) => {
state.status = "succeeded";
state.data = action.payload;
})
.addCase(fetchGisStationsStaticDistrictFromWebService.rejected, (state, action) => {
state.status = "failed";
state.error = action.error.message;
});
},
});
export const selectGisStationsStaticDistrict = (state) => state.gisStationsStaticDistrict.data;
export default gisStationsStaticDistrictSlice.reducer;

View File

@@ -0,0 +1,58 @@
// /redux/api/fromDB/fetchLocationDevices.js
// das ist für Datasheet dropdownmenu Bereiche/Area-Name
import { createSlice, createAsyncThunk } from "@reduxjs/toolkit";
// API-Fetch-Funktion für GIS Stations Static mit dynamischem URL-Parameter
export const fetchGisStationsStatic = createAsyncThunk("gisStationsStatic/fetchGisStationsStatic", async (_, { rejectWithValue }) => {
try {
const apiBaseUrl = process.env.NEXT_PUBLIC_API_BASE_URL;
// URL-Parameter aus der aktuellen Browser-URL holen
const params = new URLSearchParams(window.location.search);
const idMap = params.get("idMap") || "12"; // Standardwert "12", falls `idMap` nicht existiert
const url = `${apiBaseUrl}/GisStationsStatic?idMap=${idMap}`;
console.log("📡 API Request URL:", url);
const response = await fetch(url);
if (!response.ok) {
throw new Error("GisStationsStatic konnte nicht geladen werden");
}
const data = await response.json();
return data;
} catch (error) {
return rejectWithValue(error.message);
}
});
// Redux-Slice
const gisStationsStaticSlice = createSlice({
name: "gisStationsStatic",
initialState: {
data: null,
status: "idle",
error: null,
},
reducers: {},
extraReducers: (builder) => {
builder
.addCase(fetchGisStationsStatic.pending, (state) => {
state.status = "loading";
})
.addCase(fetchGisStationsStatic.fulfilled, (state, action) => {
state.status = "succeeded";
state.data = action.payload;
})
.addCase(fetchGisStationsStatic.rejected, (state, action) => {
state.status = "failed";
state.error = action.payload;
});
},
});
// Selector-Funktion
export const selectGisStationsStatic = (state) => state.gisStationsStatic.data;
export default gisStationsStaticSlice.reducer;

View File

@@ -0,0 +1,35 @@
// /redux/slices/webService/gisStationsStatusDistrictSlice.js
import { createSlice, createAsyncThunk } from "@reduxjs/toolkit";
import { fetchGisStationsStatusDistrict } from "../../api/fromWebService/fetchGisStationsStatusDistrict";
export const fetchGisStationsStatusDistrictFromWebService = createAsyncThunk("gisStationsStatusDistrict/fetchGisStationsStatusDistrictFromWebService", async () => {
return fetchGisStationsStatusDistrict();
});
const gisStationsStatusDistrictSlice = createSlice({
name: "gisStationsStatusDistrict",
initialState: {
data: [],
status: "idle",
error: null,
},
reducers: {},
extraReducers: (builder) => {
builder
.addCase(fetchGisStationsStatusDistrictFromWebService.pending, (state) => {
state.status = "loading";
})
.addCase(fetchGisStationsStatusDistrictFromWebService.fulfilled, (state, action) => {
state.status = "succeeded";
state.data = action.payload;
})
.addCase(fetchGisStationsStatusDistrictFromWebService.rejected, (state, action) => {
state.status = "failed";
state.error = action.error.message;
});
},
});
export const selectGisStationsStatusDistrict = (state) => state.gisStationsStatusDistrict.data;
export default gisStationsStatusDistrictSlice.reducer;

View File

@@ -0,0 +1,32 @@
// /redux/slices/webService/gisSystemStaticSlice.js
import { createSlice, createAsyncThunk } from "@reduxjs/toolkit";
import { fetchGisSystemStatic } from "../../api/fromWebService/fetchGisSystemStatic";
export const fetchGisSystemStaticFromWebService = createAsyncThunk("gisSystemStatic/fetchGisSystemStaticFromWebService", async () => {
const response = await fetchGisSystemStatic();
return response.Systems || []; // ✅ Hier sicherstellen, dass nur `Systems` gespeichert wird
});
const gisSystemStaticSlice = createSlice({
name: "gisSystemStatic",
initialState: {
data: [], // ✅ Immer ein Array setzen
status: "idle",
error: null,
},
reducers: {
setGisSystemStatic: (state, action) => {
state.data = action.payload.Systems || []; // ✅ Falls `Systems` fehlt, leeres Array setzen
},
},
extraReducers: (builder) => {
builder.addCase(fetchGisSystemStaticFromWebService.fulfilled, (state, action) => {
state.status = "succeeded";
state.data = action.payload; // ✅ Jetzt sollte `data` direkt das `Systems`-Array enthalten
});
},
});
export const { setGisSystemStatic } = gisSystemStaticSlice.actions;
export default gisSystemStaticSlice.reducer;
export const selectGisSystemStatic = (state) => state.gisSystemStatic.data || [];

View File

@@ -1,14 +1,31 @@
// /redux/store.js
import { configureStore } from "@reduxjs/toolkit";
import lineVisibilityReducer from "./slices/lineVisibilitySlice";
import currentPoiReducer from "./slices/currentPoiSlice";
import gisStationsStaticDistrictReducer from "./slices/gisStationsStaticDistrictSlice";
import polylineLayerVisibleReducer from "./slices/polylineLayerVisibleSlice";
import locationDevicesFromDBReducer from "./slices/db/locationDevicesFromDBSlice";
import gisStationsStaticDistrictReducer from "./slices/webService/gisStationsStaticDistrictSlice";
import gisStationsStatusDistrictReducer from "./slices/webService/gisStationsStatusDistrictSlice";
import gisStationsMeasurementsReducer from "./slices/webService/gisStationsMeasurementsSlice";
import gisSystemStaticReducer from "./slices/webService/gisSystemStaticSlice";
import gisStationsStaticReducer from "./slices/webService/gisStationsStaticSlice";
import poiTypesReducer from "./slices/db/poiTypesSlice";
import addPoiOnPolylineReducer from "./slices/addPoiOnPolylineSlice";
import polylineContextMenuReducer from "./slices/polylineContextMenuSlice";
export const store = configureStore({
reducer: {
lineVisibility: lineVisibilityReducer,
currentPoi: currentPoiReducer,
gisStationsStaticDistrict: gisStationsStaticDistrictReducer,
polylineLayerVisible: polylineLayerVisibleReducer,
locationDevicesFromDB: locationDevicesFromDBReducer,
gisStationsStaticDistrict: gisStationsStaticDistrictReducer,
gisStationsStatusDistrict: gisStationsStatusDistrictReducer,
gisStationsMeasurements: gisStationsMeasurementsReducer,
gisSystemStatic: gisSystemStaticReducer,
gisStationsStatic: gisStationsStaticReducer,
poiTypes: poiTypesReducer,
addPoiOnPolyline: addPoiOnPolylineReducer,
polylineContextMenu: polylineContextMenuReducer,
},
});

View File

@@ -1,4 +1,4 @@
import { setGisStationsStaticDistrict } from "../../redux/slices/gisStationsStaticDistrictSlice";
import { setGisStationsStaticDistrict } from "../../redux/slices/webService/gisStationsStaticDistrictSlice";
export const fetchGisStationsStaticDistrict = async (url, dispatch, fetchOptions) => {
try {

View File

@@ -3,7 +3,7 @@ import L from "leaflet";
import "leaflet.smooth_marker_bouncing";
import { toast } from "react-toastify";
import * as config from "../config/config.js";
import { disablePolylineEvents, enablePolylineEvents } from "./setupPolylines";
import { disablePolylineEvents, enablePolylineEvents } from "./polylines/setupPolylines.js";
import { store } from "../redux/store";
import { updateLineStatus } from "../redux/slices/lineVisibilitySlice";
@@ -40,8 +40,8 @@ export const createAndSetDevices = async (systemId, setMarkersFunction, GisSyste
if (config.isMockMode()) {
console.log("⚠️ Mock-API: Geräte-Daten geladen");
staticDistrictData = await fetchJsonSafely("/mockData/gisStationsStaticDistrictMock.json");
statusDistrictData = await fetchJsonSafely("/mockData/gisStationsStatusDistrictMock.json");
staticDistrictData = await fetchJsonSafely(config.mapGisStationsStaticDistrictUrl);
statusDistrictData = await fetchJsonSafely(config.mapGisStationsStatusDistrictUrl);
} else {
staticDistrictData = await fetchJsonSafely(config.mapGisStationsStaticDistrictUrl);
statusDistrictData = await fetchJsonSafely(config.mapGisStationsStatusDistrictUrl);

View File

@@ -1,6 +1,7 @@
// /utils/markerUtils.js
import circleIcon from "../components/CircleIcon";
import { saveLineData, redrawPolyline } from "./mapUtils";
import { saveLineData } from "./mapUtils";
import { redrawPolyline } from "./mapUtils";
import L from "leaflet";
import { toast } from "react-toastify";
@@ -9,10 +10,7 @@ export const insertNewMarker = (closestPoints, newPoint, lineData, map) => {
icon: circleIcon,
draggable: true,
}).addTo(map);
lineData.coordinates.splice(closestPoints[2], 0, [
newPoint.lat,
newPoint.lng,
]);
lineData.coordinates.splice(closestPoints[2], 0, [newPoint.lat, newPoint.lng]);
// Hier direkt speichern nach Einfügen
saveLineData(lineData);
@@ -39,9 +37,7 @@ export const removeMarker = (marker, lineData, currentZoom, currentCenter) => {
//localStorage.setItem("mapCenter", JSON.stringify(currentCenter));
// Find the index of the coordinate that matches the marker's position
const index = lineData.coordinates.findIndex((coord) =>
L.latLng(coord[0], coord[1]).equals(marker.getLatLng())
);
const index = lineData.coordinates.findIndex((coord) => L.latLng(coord[0], coord[1]).equals(marker.getLatLng()));
if (index !== -1) {
// Remove the coordinate from the line data

View File

@@ -1,6 +1,7 @@
// /utils/poiUtils.js
import circleIcon from "../components/gisPolylines/icons/CircleIcon.js";
import { saveLineData, redrawPolyline } from "./mapUtils.js";
import { saveLineData } from "./mapUtils.js";
import { redrawPolyline } from "./polylines/redrawPolyline.js";
import L from "leaflet";
import "leaflet.smooth_marker_bouncing";
import { toast } from "react-toastify";

View File

@@ -0,0 +1,29 @@
// /utils/polylines/contextMenu.js
export function closePolylineSelectionAndContextMenu(map) {
try {
if (window.selectedPolyline) {
window.selectedPolyline.setStyle({ weight: 3 });
window.selectedPolyline = null;
}
if (map?.contextmenu?.hide) {
map.contextmenu.hide();
}
} catch (error) {
console.error("Fehler beim Schließen des Kontextmenüs:", error);
}
localStorage.removeItem("contextMenuCountdown");
localStorage.removeItem("contextMenuExpired");
}
export function monitorContextMenu(map) {
function checkAndClose() {
if (localStorage.getItem("contextMenuExpired") === "true") {
closePolylineSelectionAndContextMenu(map);
localStorage.removeItem("contextMenuExpired");
}
setTimeout(checkAndClose, 1000);
}
checkAndClose();
}

View File

@@ -0,0 +1,19 @@
// /utils/polylines/eventHandlers.js
export function enablePolylineEvents(polylines, lineColors) {
if (!polylines || polylines.length === 0) {
//console.warn("Keine Polylinien vorhanden oder polylines ist undefined.");
return;
}
polylines.forEach((polyline) => {
polyline.on("mouseover", () => polyline.setStyle({ weight: 14 }));
polyline.on("mouseout", () => polyline.setStyle({ weight: 3 }));
});
}
export function disablePolylineEvents(polylines) {
polylines.forEach((polyline) => {
polyline.off("mouseover");
polyline.off("mouseout");
});
}

View File

@@ -0,0 +1,21 @@
// utils/polylines/monitorContextMenu.js
import { closePolylineSelectionAndContextMenu } from "./contextMenu";
export function monitorContextMenu(map) {
function checkAndClose() {
const isContextMenuExpired = localStorage.getItem("contextMenuExpired") === "true";
if (isContextMenuExpired) {
if (map && map.contextmenu && typeof map.contextmenu.hide === "function") {
closePolylineSelectionAndContextMenu(map);
localStorage.removeItem("contextMenuExpired");
} else {
console.warn("Kontextmenü war nicht verfügbar und konnte nicht geschlossen werden.");
}
}
setTimeout(checkAndClose, 1000); // **Recursive Timeout statt Intervall**
}
checkAndClose();
}

View File

@@ -0,0 +1,17 @@
// utils/polylines/polylineSubscription.js
import { store } from "../../redux/store";
import { closePolylineContextMenu } from "../../redux/slices/polylineContextMenuSlice";
export function subscribeToPolylineContextMenu() {
store.subscribe(() => {
const state = store.getState(); // Redux-Toolkit empfohlene Methode
if (state.polylineContextMenu.forceClose) {
console.log("🚀 Redux-Event erkannt - Kontextmenü wird geschlossen.");
store.dispatch(closePolylineContextMenu());
if (window.map && window.map.contextmenu) {
window.map.contextmenu.hide();
}
}
});
}

View File

@@ -0,0 +1,35 @@
// utils/redrawPolyline.js
export const redrawPolyline = (lineData, lineColors, tooltipContents, map) => {
if (!lineData || !lineColors || !tooltipContents || !map) {
console.error("Invalid parameters for redrawPolyline");
return;
}
if (!lineData.coordinates || !Array.isArray(lineData.coordinates)) {
console.error("Invalid coordinates in lineData");
return;
}
const color = lineColors[lineData.idModul] || "#000000";
const tooltipContent = tooltipContents[lineData.idModul] || "Standard-Tooltip-Inhalt";
if (lineData.polyline) map.removeLayer(lineData.polyline);
lineData.polyline = L.polyline(lineData.coordinates, {
color: color,
}).addTo(map);
lineData.polyline.bindTooltip(tooltipContent, {
permanent: false,
direction: "auto",
});
lineData.polyline.on("mouseover", () => {
lineData.polyline.setStyle({ weight: 10 });
lineData.polyline.bringToFront();
});
lineData.polyline.on("mouseout", () => {
lineData.polyline.setStyle({ weight: 5 });
});
};

View File

@@ -1,91 +1,29 @@
// utils/setupPolylines.js
import { findClosestPoints } from "./geometryUtils";
import handlePoiSelect from "./handlePoiSelect";
import { updateLocationInDatabase } from "../services/api/updateLocationInDatabase";
import { handleEditPoi, insertNewPOI, removePOI } from "./poiUtils";
import { parsePoint } from "./geometryUtils";
import circleIcon from "../components/gisPolylines/icons/CircleIcon";
import startIcon from "../components/gisPolylines/icons/StartIcon";
import endIcon from "../components/gisPolylines/icons/EndIcon";
import { redrawPolyline } from "./mapUtils";
import { openInNewTab } from "./openInNewTab";
// utils/polylines/setupPolylines.js
import { findClosestPoints } from "../geometryUtils";
import handlePoiSelect from "../handlePoiSelect";
import { updateLocationInDatabase } from "../../services/api/updateLocationInDatabase";
import { handleEditPoi, insertNewPOI, removePOI } from "../poiUtils";
import { parsePoint } from "../geometryUtils";
import circleIcon from "../../components/gisPolylines/icons/CircleIcon";
import startIcon from "../../components/gisPolylines/icons/StartIcon";
import endIcon from "../../components/gisPolylines/icons/EndIcon";
import { redrawPolyline } from "./redrawPolyline";
import { openInNewTab } from "../openInNewTab";
import { toast } from "react-toastify";
import { polylineLayerVisibleState } from "../redux/slices/polylineLayerVisibleSlice";
import { useRecoilValue } from "recoil";
import { store } from "../redux/store"; // Importiere den Store
// Funktion zum Deaktivieren der Polyline-Ereignisse
export function disablePolylineEvents(polylines) {
polylines.forEach((polyline) => {
polyline.off("mouseover");
polyline.off("mouseout");
});
}
// Funktion zum Aktivieren der Polyline-Ereignisse
export function enablePolylineEvents(polylines, lineColors) {
// Überprüfe, ob polylines definiert ist und ob es Elemente enthält
if (!polylines || polylines.length === 0) {
//console.warn("Keine Polylinien vorhanden oder polylines ist undefined.");
return;
}
// Falls Polylinien vorhanden sind, wende die Events an
polylines.forEach((polyline) => {
polyline.on("mouseover", (e) => {
//console.log("Mouseover on polyline", polyline.options);
polyline.setStyle({ weight: 14 });
const link = `${process.env.NEXT_PUBLIC_BASE_URL}cpl.aspx?id=${polyline.options.idLD}`;
//localStorage.setItem("lastElementType", "polyline");
//localStorage.setItem("polylineLink", link);
});
polyline.on("mouseout", (e) => {
//console.log("Mouseout from polyline", polyline.options);
polyline.setStyle({ weight: 3 });
});
});
}
// Funktion zum Schließen des Kontextmenüs und Entfernen der Markierung
function closePolylineSelectionAndContextMenu(map) {
try {
// Entferne alle markierten Polylinien
if (window.selectedPolyline) {
window.selectedPolyline.setStyle({ weight: 3 }); // Originalstil wiederherstellen
window.selectedPolyline = null;
}
// Überprüfe, ob map und map.contextmenu definiert sind
if (map && map.contextmenu) {
map.contextmenu.hide(); // Kontextmenü schließen
} else {
console.warn("Kontextmenü ist nicht verfügbar.");
}
} catch (error) {
console.error("Fehler beim Schließen des Kontextmenüs:", error);
window.location.reload();
}
// Countdown-Status zurücksetzen
localStorage.removeItem("contextMenuCountdown");
localStorage.removeItem("contextMenuExpired");
}
// Überprüft regelmäßig den Status in localStorage
function monitorContextMenu(map) {
setInterval(() => {
const isContextMenuExpired = localStorage.getItem("contextMenuExpired") === "true";
if (isContextMenuExpired) {
closePolylineSelectionAndContextMenu(map);
localStorage.removeItem("contextMenuExpired"); // Flagge entfernen, um wiederverwendbar zu sein
}
}, 1000); // Alle 1 Sekunde überprüfen
}
import { polylineLayerVisibleState } from "../../redux/slices/polylineLayerVisibleSlice";
import { store } from "../../redux/store"; // Importiere den Store
import { openAddPoiOnPolylineModal } from "../../redux/slices/addPoiOnPolylineSlice";
import { openPolylineContextMenu, closePolylineContextMenu } from "../../redux/slices/polylineContextMenuSlice";
import { enablePolylineEvents, disablePolylineEvents } from "./eventHandlers";
import { closePolylineSelectionAndContextMenu } from "./contextMenu";
import { monitorContextMenu } from "./monitorContextMenu";
import { subscribeToPolylineContextMenu } from "./polylineSubscription";
import { forceCloseContextMenu } from "../../redux/slices/polylineContextMenuSlice";
//--------------------------------------------
export const setupPolylines = (map, linePositions, lineColors, tooltipContents, setNewCoords, tempMarker, currentZoom, currentCenter, polylineVisible) => {
if (!polylineVisible) {
console.warn("Polylines deaktiviert - keine Zeichnung");
//console.warn("Polylines deaktiviert - keine Zeichnung");
return { markers: [], polylines: [] };
}
@@ -284,14 +222,14 @@ export const setupPolylines = (map, linePositions, lineColors, tooltipContents,
callback: (e) => map.panTo(e.latlng),
},
{ separator: true },
{
/* {
text: "POI hinzufügen",
icon: "/img/add_station.png",
callback: (e) => {
// Hier kannst du die Logik für das Hinzufügen eines POIs implementieren
alert("POI hinzufügen an: " + e.latlng);
store.dispatch(openAddPoiOnPolylineModal(e.latlng));
},
},
*/
{
text: "Stützpunkt hinzufügen",
icon: "/img/icons/gisLines/add-support-point.svg",
@@ -343,15 +281,14 @@ export const setupPolylines = (map, linePositions, lineColors, tooltipContents,
icon: "/img/center_focus.png",
callback: (e) => map.panTo(e.latlng),
},
{ separator: true },
{
{ separator: true }
/* {
text: "POI hinzufügen",
icon: "/img/add_station.png",
callback: (e) => {
// Hier kannst du die Logik für das Hinzufügen eines POIs implementieren
alert("POI hinzufügen an: " + e.latlng);
store.dispatch(openAddPoiOnPolylineModal(e.latlng));
},
}
} */
);
}
@@ -363,56 +300,43 @@ export const setupPolylines = (map, linePositions, lineColors, tooltipContents,
polyline.on("mouseover", (e) => {
const startTime = Date.now(); // Startzeit erfassen
localStorage.setItem("contextMenuStartTime", startTime); // Speichern in localStorage
// Starte einen Intervall-Timer, um die Differenz zu berechnen
/* const countdownInterval = setInterval(() => {
const currentTime = Date.now();
const elapsedTime = (currentTime - startTime) / 1000; // Differenz in Sekunden
// Speichern der abgelaufenen Zeit in localStorage
localStorage.setItem("contextMenuCountdown", elapsedTime);
// Wenn die Zeit 17 Sekunden erreicht, schließe das Menü
if (elapsedTime >= 17) {
clearInterval(countdownInterval);
const contextMenu = map.contextmenu; // Zugriff auf das Kontextmenü
contextMenu.hide(); // Kontextmenü schließen
}
}, 1000); */
// Jede Sekunde
//console.log("Mouseover on polyline", lineData);
polyline.setStyle({ weight: 14 });
const link = `${process.env.NEXT_PUBLIC_BASE_URL}cpl.aspx?ver=35&kue=24&id=${lineData.idLD}`;
console.log("Link der Linie:", link);
//localStorage.setItem("lastElementType", "polyline");
//localStorage.setItem("polylineLink", link);
// console.log("Link der Linie:", link);
});
// error TypeError: Cannot read properties of null (reading 'contextmenu') wenn der Mas auf die Linie bleibt
polyline.on("mouseout", (e) => {
// console.log("Mouseout from polyline", lineData);
polyline.setStyle({ weight: 3 });
// Setze den Countdown auf 0, wenn mouseout ausgelöst wird
localStorage.setItem("contextMenuCountdown", 0);
});
// Speichere den Link bei einem Rechtsklick (Kontextmenü)
/*
polyline.on("contextmenu", (e) => {
const link = `${process.env.NEXT_PUBLIC_BASE_URL}cpl.aspx?ver=35&kue=24&id=${lineData.idLD}`;
console.log("Link der Linie (via Rechtsklick):", link);
localStorage.setItem("lastElementType", "polyline");
localStorage.setItem("polylineLink", link);
});
*/
// Starte den Timer zum Schließen des Kontextmenüs nach 15 Sekunden
polyline.on("contextmenu", function (e) {
const contextMenu = this._map.contextmenu; // Zugriff auf das Kontextmenü
const closeMenu = () => contextMenu.hide(); // Funktion zum Schließen des Menüs
//console.log("🚀 Maus hat die Polyline verlassen - Warten auf Klick außerhalb des Menüs.");
const countdown = parseInt(localStorage.getItem("contextMenuCountdown"), 30);
if (countdown >= 28) {
closeMenu();
}
document.addEventListener("click", function handleOutsideClick(event) {
if (!event.target.closest(".leaflet-contextmenu")) {
//console.log("🛑 Klick außerhalb des Kontextmenüs erkannt - Schließe Menü.");
try {
store.dispatch(closePolylineContextMenu());
store.dispatch(forceCloseContextMenu());
if (window.map?.contextmenu) {
window.map.contextmenu.hide();
}
} catch (error) {
console.error("❌ Fehler beim Schließen des Kontextmenüs:", error);
// **Seite NICHT sofort neuladen, sondern global unterdrücken lassen**
}
document.removeEventListener("click", handleOutsideClick);
}
});
});
polyline.on("contextmenu", (e) => {
store.dispatch(
openPolylineContextMenu({
position: { lat: e.latlng.lat, lng: e.latlng.lng },
polylineId: polyline.options.idLD,
})
);
});
polylines.push(polyline);

View File

@@ -7,9 +7,9 @@ import { parsePoint } from "./geometryUtils";
import circleIcon from "../components/gisPolylines/icons/CircleIcon";
import startIcon from "../components/gisPolylines/icons/StartIcon";
import endIcon from "../components/gisPolylines/icons/EndIcon";
import { redrawPolyline } from "./mapUtils";
import { redrawPolyline } from "./polylines/redrawPolyline";
import { openInNewTab } from "../utils/openInNewTab";
import { disablePolylineEvents, enablePolylineEvents } from "./setupPolylines"; // Importiere die Funktionen
import { disablePolylineEvents, enablePolylineEvents } from "./polylines/setupPolylines"; // Importiere die Funktionen
export const setupPOIs = async (
map,
@@ -83,7 +83,7 @@ export const setupPOIs = async (
`);
marker.on("mouseover", function () {
console.log("Device Name:", marker); // Debugging
//console.log("Device Name:", marker); // Debugging
handlePoiSelect(
{
id: location.idPoi,