diff --git a/CHANGELOG.md b/CHANGELOG.md
index 59de6a2cc..a9b98058a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,43 @@ Alle bedeutenden Änderungen an diesem Projekt werden in dieser Datei dokumentie
---
+📦 [1.1.183] – 2025-05-27
+♻️ Refactor
+Die Hilfsfunktion saveLineData() wurde vollständig entfernt:
+
+In markerUtils.js und poiUtils.js ersetzt durch updatePolylineCoordinatesThunk via Redux
+
+Zentrale Dispatch-Hilfsfunktion savePolylineRedux() erstellt für alle Linienaktionen (Einfügen, Verschieben, Entfernen)
+
+Einheitliche Verwendung des Redux-Dispatch in Utility-Dateien:
+
+Kein direktes fetch() mehr
+
+Fehlerbehandlung über .unwrap().catch(...) integriert
+
+Map-Utilities und POI-Utilities sind nun Redux-kompatibel und testbar
+
+✅ Clean
+saveLineData aus mapUtils.js gelöscht
+
+Alle Marker-Operationen speichern ihre Koordinaten ausschließlich über Redux
+
+🧠 Architektur
+Redux-Toolkit Standardstruktur umgesetzt:
+
+updatePolylineCoordinatesService.js
+
+updatePolylineCoordinatesThunk.js
+
+Nutzung außerhalb React-Komponenten über store.dispatch(...)
+
+Leaflet-Logik (z. B. marker.setLatLng(), map.removeLayer()) bleibt in Utility-Dateien – Redux kümmert sich nur um Daten
+
+🔧 Version
+📦 Version erhöht auf 1.1.183
+
+---
+
## [1.1.182] – 2025-05-27
### ♻️ Refactor
diff --git a/config/appVersion.js b/config/appVersion.js
index a668d587c..0dbebcc21 100644
--- a/config/appVersion.js
+++ b/config/appVersion.js
@@ -1,2 +1,2 @@
// /config/appVersion
-export const APP_VERSION = "1.1.183";
+export const APP_VERSION = "1.1.184";
diff --git a/redux/slices/database/locationDevice/locationDevicesSlice.js b/redux/slices/database/locationDevice/locationDevicesSlice.js
new file mode 100644
index 000000000..9b22f04b5
--- /dev/null
+++ b/redux/slices/database/locationDevice/locationDevicesSlice.js
@@ -0,0 +1,41 @@
+// /redux/slices/database/locationDevice/locationDevicesSlice.js
+
+import { createSlice } from "@reduxjs/toolkit";
+import { fetchLocationDevicesThunk } from "../../../thunks/database/locationDevice/fetchLocationDevicesThunk";
+
+const locationDevicesSlice = createSlice({
+ name: "locationDevices",
+ initialState: {
+ data: [],
+ status: "idle",
+ error: null,
+ },
+ reducers: {
+ clearLocationDevices: (state) => {
+ state.data = [];
+ state.status = "idle";
+ state.error = null;
+ },
+ },
+ extraReducers: (builder) => {
+ builder
+ .addCase(fetchLocationDevicesThunk.pending, (state) => {
+ state.status = "loading";
+ })
+ .addCase(fetchLocationDevicesThunk.fulfilled, (state, action) => {
+ state.status = "succeeded";
+ state.data = action.payload;
+ })
+ .addCase(fetchLocationDevicesThunk.rejected, (state, action) => {
+ state.status = "failed";
+ state.error = action.error.message;
+ });
+ },
+});
+
+export const { clearLocationDevices } = locationDevicesSlice.actions;
+
+export const selectLocationDevices = (state) => state.locationDevices.data;
+export const selectLocationDeviceStatus = (state) => state.locationDevices.status;
+
+export default locationDevicesSlice.reducer;
diff --git a/redux/thunks/database/locationDevice/fetchLocationDevicesThunk.js b/redux/thunks/database/locationDevice/fetchLocationDevicesThunk.js
new file mode 100644
index 000000000..e797f4545
--- /dev/null
+++ b/redux/thunks/database/locationDevice/fetchLocationDevicesThunk.js
@@ -0,0 +1,8 @@
+// /redux/thunks/database/locationDevice/fetchLocationDevicesThunk.js
+
+import { createAsyncThunk } from "@reduxjs/toolkit";
+import { fetchLocationDevicesService } from "../../../services/database/locationDevice/fetchLocationDevicesService";
+
+export const fetchLocationDevicesThunk = createAsyncThunk("locationDevices/fetchAll", async () => {
+ return await fetchLocationDevicesService();
+});
diff --git a/services/database/locationDevice/fetchLocationDevicesService.js b/services/database/locationDevice/fetchLocationDevicesService.js
new file mode 100644
index 000000000..d93dae642
--- /dev/null
+++ b/services/database/locationDevice/fetchLocationDevicesService.js
@@ -0,0 +1,12 @@
+// /services/database/locationDevice/fetchLocationDevicesService.js
+
+export const fetchLocationDevicesService = async () => {
+ const response = await fetch("/api/talas_v5_DB/locationDevice/locationDevices");
+
+ if (!response.ok) {
+ const error = await response.json();
+ throw new Error(error.message || "Fehler beim Abrufen der Gerätedaten");
+ }
+
+ return await response.json();
+};
diff --git a/utils/handlePoiSelect.js b/utils/handlePoiSelect.js
deleted file mode 100644
index 46252b236..000000000
--- a/utils/handlePoiSelect.js
+++ /dev/null
@@ -1,37 +0,0 @@
-// utils/handlePoiSelect.js
-const handlePoiSelect = async (poiData, setSelectedPoi, setLocationDeviceData, setDeviceName, poiLayerRef, poiTypMap) => {
- setSelectedPoi(poiData); // Setzt das ausgewählte POI
-
- try {
- const response = await fetch("/api/talas_v5_DB/locationDevice/locationDevices");
- const data = await response.json();
- setLocationDeviceData(data);
-
- const currentDevice = data.find((device) => device.idLD === poiData.deviceId);
- if (currentDevice) {
- setDeviceName(currentDevice.name);
-
- // Hier speichern wir den POI-Typ im localStorage
- const poiTypeName = poiTypMap.get(poiData.idPoiTyp);
- localStorage.setItem("selectedPoiType", poiTypeName);
-
- // Optional: Update des Markers mit dem POI-Typ
- const marker = poiLayerRef.current.getLayers().find((m) => m.options.id === poiData.id);
- if (marker) {
- marker.setPopupContent(`
-
- ${poiData.description || "Unbekannt"}
- ${currentDevice.name}
- ${poiTypeName || "Unbekannt"}
-
- `);
- marker.openPopup();
- }
- }
- } catch (error) {
- console.error("Fehler beim Abrufen der Gerätedaten:", error);
- setLocationDeviceData([]);
- }
-};
-
-export default handlePoiSelect;
diff --git a/utils/mapUtils.js b/utils/mapUtils.js
index 89d13493b..cdab9e214 100644
--- a/utils/mapUtils.js
+++ b/utils/mapUtils.js
@@ -1,31 +1,6 @@
// /utils/mapUtils.js
import L from "leaflet";
-export const saveLineData = (lineData) => {
- fetch("/api/talas_v5_DB/gisLines/updateLineCoordinates", {
- method: "POST",
- headers: {
- "Content-Type": "application/json",
- },
- body: JSON.stringify({
- idModul: lineData.idModul,
- idLD: lineData.idLD,
- newCoordinates: lineData.coordinates,
- }),
- })
- .then((response) => {
- if (!response.ok) {
- throw new Error("Fehler beim Speichern der Linienänderungen");
- }
- return response.json();
- })
- .then((data) => {
- //console.log("Linienänderungen gespeichert:", data);
- })
- .catch((error) => {
- console.error("Fehler beim Speichern der Linienänderungen:", error);
- });
-};
// Call this function on page load to restore zoom and center
export const restoreMapSettings = (map) => {
const savedZoom = localStorage.getItem("mapZoom");
diff --git a/utils/markerUtils.js b/utils/markerUtils.js
index ea3bd062b..114a6de27 100644
--- a/utils/markerUtils.js
+++ b/utils/markerUtils.js
@@ -1,107 +1,75 @@
// /utils/markerUtils.js
-import circleIcon from "../components/CircleIcon";
-import { saveLineData } from "./mapUtils";
-import { redrawPolyline } from "./mapUtils";
import L from "leaflet";
import { toast } from "react-toastify";
+import circleIcon from "../components/CircleIcon";
+import { store } from "../redux/store";
+import { updatePolylineCoordinatesThunk } from "../redux/thunks/database/polylines/updatePolylineCoordinatesThunk";
+import { redrawPolyline } from "./mapUtils";
+
+const savePolylineRedux = (lineData) => {
+ return store
+ .dispatch(
+ updatePolylineCoordinatesThunk({
+ idModul: lineData.idModul,
+ idLD: lineData.idLD,
+ newCoordinates: lineData.coordinates,
+ })
+ )
+ .unwrap()
+ .catch((error) => {
+ console.error("Fehler beim Speichern der Linienkoordinaten:", error.message);
+ });
+};
export const insertNewMarker = (closestPoints, newPoint, lineData, map) => {
const newMarker = L.marker(newPoint, {
icon: circleIcon,
draggable: true,
}).addTo(map);
+
lineData.coordinates.splice(closestPoints[2], 0, [newPoint.lat, newPoint.lng]);
-
- // Hier direkt speichern nach Einfügen
- saveLineData(lineData);
-
+ savePolylineRedux(lineData); // ✅ Nutzung der Hilfsfunktion
redrawPolyline(lineData);
- // Event-Listener für das Verschieben des Markers hinzufügen
newMarker.on("dragend", () => {
const newCoords = newMarker.getLatLng();
- setNewCoords(newCoords);
const newCoordinates = [...lineData.coordinates];
newCoordinates[closestPoints[2]] = [newCoords.lat, newCoords.lng];
lineData.coordinates = newCoordinates;
- redrawPolyline(lineData);
+ redrawPolyline(lineData);
updateMarkerPosition(newMarker.getLatLng(), lineData, newMarker);
- saveLineData(lineData); // Speichern der neuen Koordinaten nach dem Verschieben
+ savePolylineRedux(lineData); // ✅ Wiederverwendung
});
};
export const removeMarker = (marker, lineData, currentZoom, currentCenter) => {
- // Save zoom and center to localStorage
- //localStorage.setItem("mapZoom", currentZoom);
- //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()));
if (index !== -1) {
- // Remove the coordinate from the line data
lineData.coordinates.splice(index, 1);
-
- // Redraw the polyline with the updated coordinates
redrawPolyline(lineData);
-
- // Remove the marker from the map
marker.remove();
-
- // Save the updated line data
- saveLineData(lineData);
-
- // Refresh the browser
+ savePolylineRedux(lineData); // ✅ Wiederverwendung
window.location.reload();
}
};
-export const handleEditPoi = (
- marker,
- userRights,
- setCurrentPoiData,
- setShowPoiUpdateModal,
- fetchPoiData,
- toast // Hier toast als Parameter erhalten
-) => {
- console.log("Selected Marker ID (idPoi):", marker.options.id);
- console.log("Selected Marker Description:", marker.options.description);
- console.log("User Rights:", userRights);
-
- // Sicherstellen, dass userRights ein Array ist
+export const handleEditPoi = (marker, userRights, setCurrentPoiData, setShowPoiUpdateModal, fetchPoiData, toast) => {
if (!Array.isArray(userRights)) {
- console.error("User Rights is not an array:", userRights);
toast.error("Benutzerrechte sind ungültig.", {
position: "top-center",
autoClose: 5000,
- hideProgressBar: false,
- closeOnClick: true,
- pauseOnHover: true,
- draggable: true,
- progress: undefined,
});
return;
}
- console.log(
- "User Rights include 56:",
- userRights.some((r) => r.IdRight === 56)
- );
-
- // Prüfung, ob der Benutzer die notwendigen Rechte hat
if (!userRights.some((r) => r.IdRight === 56)) {
toast.error("Benutzer hat keine Berechtigung zum Bearbeiten.", {
position: "top-center",
autoClose: 5000,
- hideProgressBar: false,
- closeOnClick: true,
- pauseOnHover: true,
- draggable: true,
- progress: undefined,
});
- console.log("Benutzer hat keine Berechtigung zum Bearbeiten.");
- return; // Beendet die Funktion frühzeitig, wenn keine Berechtigung vorliegt
+ return;
}
setCurrentPoiData({
@@ -111,6 +79,5 @@ export const handleEditPoi = (
});
fetchPoiData(marker.options.id);
-
setShowPoiUpdateModal(true);
};
diff --git a/utils/poiUtils.js b/utils/poiUtils.js
index beedf88da..08e76ee39 100644
--- a/utils/poiUtils.js
+++ b/utils/poiUtils.js
@@ -1,124 +1,66 @@
// /utils/poiUtils.js
-import circleIcon from "../components/gisPolylines/icons/CircleIcon.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";
+import circleIcon from "../components/gisPolylines/icons/CircleIcon.js";
+import { redrawPolyline } from "./polylines/redrawPolyline.js";
+
+import { store } from "../redux/store";
+import { updatePolylineCoordinatesThunk } from "../redux/thunks/database/polylines/updatePolylineCoordinatesThunk";
+
+// 🧠 Zentrale Redux-Dispatch-Hilfsfunktion
+const savePolylineRedux = (lineData) => {
+ return store
+ .dispatch(
+ updatePolylineCoordinatesThunk({
+ idModul: lineData.idModul,
+ idLD: lineData.idLD,
+ newCoordinates: lineData.coordinates,
+ })
+ )
+ .unwrap()
+ .catch((error) => {
+ console.error("Fehler beim Speichern der Linienkoordinaten:", error.message);
+ });
+};
export const insertNewPOI = (closestPoints, newPoint, lineData, map) => {
const newMarker = L.marker(newPoint, {
icon: circleIcon,
draggable: true,
}).addTo(map);
+
+ // Stützpunkt in Koordinatenliste einfügen
lineData.coordinates.splice(closestPoints[2], 0, [newPoint.lat, newPoint.lng]);
- // Hier direkt speichern nach Einfügen
- saveLineData(lineData);
-
+ // Redux: Speichern der neuen Koordinaten
+ savePolylineRedux(lineData);
redrawPolyline(lineData);
- // Event-Listener für das Verschieben des Markers hinzufügen
newMarker.on("dragend", () => {
- console.log("Marker wurde verschoben in insertNewPOI");
const newCoords = newMarker.getLatLng();
- setNewCoords(newCoords);
const newCoordinates = [...lineData.coordinates];
newCoordinates[closestPoints[2]] = [newCoords.lat, newCoords.lng];
lineData.coordinates = newCoordinates;
- redrawPolyline(lineData);
- updateMarkerPosition(newMarker.getLatLng(), lineData, newMarker);
- saveLineData(lineData); // Speichern der neuen Koordinaten nach dem Verschieben
+ redrawPolyline(lineData);
+ updateMarkerPosition(newCoords, lineData, newMarker);
+ savePolylineRedux(lineData);
});
};
export const removePOI = (marker, lineData, currentZoom, currentCenter) => {
- // Save zoom and center to localStorage
- //localStorage.setItem("mapZoom", currentZoom);
- //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()));
if (index !== -1) {
- // Remove the coordinate from the line data
lineData.coordinates.splice(index, 1);
-
- // Redraw the polyline with the updated coordinates
redrawPolyline(lineData);
-
- // Remove the marker from the map
marker.remove();
-
- // Save the updated line data
- saveLineData(lineData);
-
- // Refresh the browser
+ savePolylineRedux(lineData);
window.location.reload();
}
};
-export const handleEditPoi = (
- marker,
- userRights,
- setCurrentPoiData,
- setShowPoiUpdateModal,
- fetchPoiData,
- toast // Hier toast als Parameter erhalten
-) => {
- const editMode = localStorage.getItem("editMode") === "true";
- userRights = editMode ? userRights : undefined;
- //console.log("Selected Marker ID (idPoi):", marker.options.id);
- //console.log("Selected Marker Description:", marker.options.description);
- //console.log("User Rights:", userRights);
-
- // Sicherstellen, dass userRights ein Array ist
- if (!userRights.some((r) => r.IdRight === 56)) {
- console.error("User Rights is not an array:", userRights);
- toast.error("Benutzerrechte sind ungültig.", {
- position: "top-center",
- autoClose: 5000,
- hideProgressBar: false,
- closeOnClick: true,
- pauseOnHover: true,
- draggable: true,
- progress: undefined,
- });
- return;
- }
-
- console.log(
- "User Rights include 56:",
- userRights.some((r) => r.IdRight === 56)
- );
-
- // Prüfung, ob der Benutzer die notwendigen Rechte hat
- if (!userRights.some((r) => r.IdRight === 56)) {
- toast.error("Benutzer hat keine Berechtigung zum Bearbeiten.", {
- position: "top-center",
- autoClose: 5000,
- hideProgressBar: false,
- closeOnClick: true,
- pauseOnHover: true,
- draggable: true,
- progress: undefined,
- });
- console.log("Benutzer hat keine Berechtigung zum Bearbeiten.");
- return; // Beendet die Funktion frühzeitig, wenn keine Berechtigung vorliegt
- }
-
- setCurrentPoiData({
- idPoi: marker.options.id,
- name: marker.options.name,
- description: marker.options.description,
- idLD: marker.options.idLD,
- idPoiTyp: marker.options.idPoiTyp,
- });
-
- fetchPoiData(marker.options.id);
-
- setShowPoiUpdateModal(true);
- console.log("POI option idPoiTyp:", marker.options.idPoiTyp);
+export const updateMarkerPosition = (newCoords, lineData, marker) => {
+ if (!marker) return;
+ marker.setLatLng([newCoords.lat, newCoords.lng]);
};
-//-------------------------------------------------------------------