refactor(area): Bereichsaktualisierung von util auf Redux umgestellt
- updateAreaUtil.js entfernt - updateAreaService, updateAreaThunk, updateAreaSlice eingeführt - useAreaMarkersLayer nutzt jetzt updateAreaThunk - MapComponent umgestellt auf Redux-Dispatch - Version erhöht auf 1.1.182
This commit is contained in:
32
CHANGELOG.md
32
CHANGELOG.md
@@ -4,6 +4,38 @@ Alle bedeutenden Änderungen an diesem Projekt werden in dieser Datei dokumentie
|
||||
|
||||
---
|
||||
|
||||
## [1.1.182] – 2025-05-27
|
||||
|
||||
### ♻️ Refactor
|
||||
|
||||
- Bereichsaktualisierung (`updateAreaUtil.js`) vollständig ersetzt durch Redux-Architektur:
|
||||
- 🔁 Neue Dateien: `updateAreaService.js`, `updateAreaThunk.js`, `updateAreaSlice.js`
|
||||
- ❌ Alte fetch-Methode entfernt, durch Redux-Thunk ersetzt
|
||||
- Bereichskoordinaten werden jetzt via `dispatch(updateAreaThunk(...))` aktualisiert
|
||||
|
||||
### 🧠 Architektur
|
||||
|
||||
- Einhaltung des Musters: `Service → Thunk → Slice`
|
||||
- Status-Handling und Fehleranzeige über `updateAreaSlice` möglich
|
||||
- `useAreaMarkersLayer.js` nutzt jetzt Redux-Thunk und optionalen `onUpdateSuccess`-Callback
|
||||
- Redux-Version kompatibel mit DevTools und zentraler Fehlerbehandlung
|
||||
|
||||
### ✅ Clean
|
||||
|
||||
- `updateAreaUtil.js` ist überflüssig und wurde entfernt
|
||||
- MapComponent verwendet jetzt `updateAreaThunk` direkt für Bereichsmarker
|
||||
|
||||
### 📄 README.md (optional)
|
||||
|
||||
- Wenn gewünscht, kann in `README.md` ein neuer Punkt unter `🚀 Funktionen` ergänzt werden:
|
||||
> - Bereichsaktualisierung via Redux (statt direkter fetch-Aufrufe)
|
||||
|
||||
### 🔧 Version
|
||||
|
||||
- 📦 Version erhöht auf **1.1.182**
|
||||
|
||||
---
|
||||
|
||||
[1.1.181] – 2025-05-26
|
||||
♻️ Refactor
|
||||
setupPolylines.js von direktem fetch() auf sauberes Redux-Muster umgestellt:
|
||||
|
||||
@@ -18,13 +18,13 @@ import * as layers from "../../config/layers.js";
|
||||
import addItemsToMapContextMenu from "../contextmenu/useMapContextMenu.js";
|
||||
import useGmaMarkersLayer from "../../hooks/layers/useGmaMarkersLayer.js";
|
||||
import useSmsfunkmodemMarkersLayer from "../../hooks/layers/useSmsfunkmodemMarkersLayer.js";
|
||||
import useBereicheMarkersLayer from "../../hooks/layers/useBereicheMarkersLayer.js";
|
||||
import useAreaMarkersLayer from "../../hooks/layers/useAreaMarkersLayer.js";
|
||||
import { setupPolylines } from "../../utils/polylines/setupPolylines.js";
|
||||
import { setupPOIs } from "../../utils/setupPOIs.js";
|
||||
import useLayerVisibility from "../../hooks/useLayerVisibility.js";
|
||||
import useLineData from "../../hooks/useLineData.js";
|
||||
import { useMapComponentState } from "../../hooks/useMapComponentState.js";
|
||||
import { updateLocation } from "../../utils/updateBereichUtil.js";
|
||||
|
||||
import CoordinatePopup from "../contextmenu/CoordinatePopup.js";
|
||||
//----------Ui Widgets----------------
|
||||
import MapLayersControlPanel from "../uiWidgets/mapLayersControlPanel/MapLayersControlPanel.js";
|
||||
@@ -67,6 +67,7 @@ import { fetchGisLinesStatusThunk } from "../../redux/thunks/webservice/fetchGis
|
||||
import { fetchUserRightsThunk } from "../../redux/thunks/webservice/fetchUserRightsThunk";
|
||||
import { fetchPoiIconsDataThunk } from "../../redux/thunks/database/pois/fetchPoiIconsDataThunk.js";
|
||||
import { fetchPoiTypThunk } from "../../redux/thunks/database/pois/fetchPoiTypThunk.js";
|
||||
import { updateAreaThunk } from "../../redux/thunks/database/area/updateAreaThunk";
|
||||
|
||||
//-----------------------------------------------------------------------------------------------------
|
||||
const MapComponent = ({ locations, onLocationUpdate, lineCoordinates }) => {
|
||||
@@ -463,7 +464,7 @@ const MapComponent = ({ locations, onLocationUpdate, lineCoordinates }) => {
|
||||
}
|
||||
}, [map]);
|
||||
//--------------------------------------------
|
||||
// Bereich in DataSheet ->dropdownmenu
|
||||
// Area in DataSheet ->dropdownmenu
|
||||
useEffect(() => {
|
||||
//console.log("🔍 GisStationsStaticDistrict Inhalt:", GisStationsStaticDistrict);
|
||||
|
||||
@@ -653,28 +654,28 @@ const MapComponent = ({ locations, onLocationUpdate, lineCoordinates }) => {
|
||||
|
||||
//---------------------------------------
|
||||
// Initialisiere Leaflet-Karte
|
||||
// Rufe useBereicheMarkersLayer direkt auf
|
||||
//const [bereichUrl, setBereichUrl] = useState(null);
|
||||
// Rufe useAreaMarkersLayer direkt auf
|
||||
//const [areaUrl, setAreaUrl] = useState(null);
|
||||
const urlParams = new URLSearchParams(window.location.search); // URL-Parameter parsen
|
||||
const mValue = urlParams.get("m"); // Wert von "m" holen
|
||||
const hostname = window.location.hostname; // Dynamischer Hostname
|
||||
const port = 3000; // Definiere den gewünschten Port
|
||||
const bereichUrl = `http://${hostname}:${port}/api/talas_v5_DB/bereich/readBereich?m=${mValue}`; // Dynamischer Hostname und Port
|
||||
const areaUrl = `http://${hostname}:${port}/api/talas_v5_DB/area/readArea?m=${mValue}`; // Dynamischer Hostname und Port
|
||||
|
||||
// Bereichs-Marker basierend auf dynamischer URL laden
|
||||
// Areas-Marker basierend auf dynamischer URL laden
|
||||
const handleLocationUpdate = async (idLocation, idMap, newCoords) => {
|
||||
try {
|
||||
const result = await updateLocation(idLocation, idMap, newCoords); // Update-API
|
||||
await dispatch(updateAreaThunk({ idLocation, idMap, newCoords })).unwrap();
|
||||
console.log("Koordinaten erfolgreich aktualisiert:", result);
|
||||
} catch (error) {
|
||||
console.error("Fehler beim Aktualisieren der Location:", error);
|
||||
}
|
||||
};
|
||||
|
||||
// Bereichs-Marker basierend auf dynamischer URL laden
|
||||
const bereicheMarkers = useBereicheMarkersLayer(map, oms, bereichUrl, handleLocationUpdate);
|
||||
// Areas-Marker basierend auf dynamischer URL laden
|
||||
const areaMarkers = useAreaMarkersLayer(map, oms, areaUrl, handleLocationUpdate);
|
||||
/*
|
||||
Bereichsmarker werden jetzt nur angezeigt, wenn der editMode aktiviert ist.
|
||||
Areamarker werden jetzt nur angezeigt, wenn der editMode aktiviert ist.
|
||||
Marker werden bei deaktiviertem editMode aus der Karte entfernt.
|
||||
Dynamische Überwachung von Änderungen im editMode über localStorage und Event Listener implementiert.
|
||||
Dragging für Marker im editMode aktiviert und Z-Index angepasst.
|
||||
@@ -687,14 +688,14 @@ const MapComponent = ({ locations, onLocationUpdate, lineCoordinates }) => {
|
||||
// Entferne alle Marker aus der Karte
|
||||
if (!map) return; // Sicherstellen, dass map existiert
|
||||
|
||||
bereicheMarkers.forEach((marker) => {
|
||||
areaMarkers.forEach((marker) => {
|
||||
if (map.hasLayer(marker)) {
|
||||
map.removeLayer(marker);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// Wenn editMode aktiviert ist, füge die Marker hinzu und aktiviere Dragging
|
||||
bereicheMarkers.forEach((marker) => {
|
||||
areaMarkers.forEach((marker) => {
|
||||
if (!map.hasLayer(marker)) {
|
||||
marker.addTo(map); // Layer hinzufügen
|
||||
}
|
||||
@@ -702,7 +703,7 @@ const MapComponent = ({ locations, onLocationUpdate, lineCoordinates }) => {
|
||||
marker.setZIndexOffset(1000); // Marker nach oben setzen
|
||||
});
|
||||
}
|
||||
}, [bereicheMarkers, map]);
|
||||
}, [areaMarkers, map]);
|
||||
|
||||
//----------------------------------
|
||||
useEffect(() => {
|
||||
|
||||
@@ -224,10 +224,10 @@ function MapLayersControlPanel() {
|
||||
</label>
|
||||
</div>
|
||||
|
||||
{/* Bereiche
|
||||
{/* Areas
|
||||
<div className="flex items-center">
|
||||
<input type="checkbox" checked={bereicheVisible} onChange={handleBereicheCheckboxChange} id="bereiche-checkbox" />
|
||||
<label htmlFor="bereiche-checkbox" className="text-sm ml-2">
|
||||
<input type="checkbox" checked={areaVisible} onChange={handleAreaCheckboxChange} id="area-checkbox" />
|
||||
<label htmlFor="area-checkbox" className="text-sm ml-2">
|
||||
Bereiche
|
||||
</label>
|
||||
</div>
|
||||
@@ -235,8 +235,8 @@ function MapLayersControlPanel() {
|
||||
|
||||
{/* Standorte
|
||||
<div className="flex items-center">
|
||||
<input type="checkbox" checked={standordVisible} onChange={handleStandorteCheckboxChange} id="bereiche-checkbox" />
|
||||
<label htmlFor="bereiche-checkbox" className="text-sm ml-2">
|
||||
<input type="checkbox" checked={standordVisible} onChange={handleStandorteCheckboxChange} id="area-checkbox" />
|
||||
<label htmlFor="area-checkbox" className="text-sm ml-2">
|
||||
Standorte
|
||||
</label>
|
||||
</div>
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
// /config/appVersion
|
||||
export const APP_VERSION = "1.1.182";
|
||||
export const APP_VERSION = "1.1.183";
|
||||
|
||||
@@ -22,7 +22,7 @@ describe("contextmenuTest", () => {
|
||||
cy.get('img[src*="img/icons/marker-icon-20.svg"]') // Marker suchen
|
||||
.filter(":visible") // Nur sichtbare Marker
|
||||
.first() // Ersten Marker auswählen
|
||||
.scrollIntoView() // Marker in den sichtbaren Bereich scrollen
|
||||
.scrollIntoView() // Marker in den sichtbaren Area scrollen
|
||||
.should("be.visible") // Sicherstellen, dass Marker sichtbar ist
|
||||
.trigger("mouseover") // Mouseover simulieren
|
||||
.wait(500) // Wartezeit nach Mouseover
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
// /hooks/layers/useBereicheMarkersLayer.js
|
||||
// /hooks/layers/useAreaMarkersLayer.js
|
||||
import { useEffect, useState, useRef } from "react";
|
||||
import L from "leaflet";
|
||||
import "leaflet/dist/leaflet.css";
|
||||
import { updateLocation } from "../../utils/updateBereichUtil";
|
||||
import { useDispatch } from "react-redux";
|
||||
import { updateAreaThunk } from "../../redux/thunks/database/area/updateAreaThunk";
|
||||
|
||||
// Definiere ein Standard-Icon
|
||||
const customIcon = new L.Icon({
|
||||
iconUrl: "/img/bereich.png",
|
||||
iconSize: [25, 41],
|
||||
@@ -14,22 +14,21 @@ const customIcon = new L.Icon({
|
||||
shadowSize: [41, 41],
|
||||
});
|
||||
|
||||
const useBereicheMarkersLayer = (map, oms, apiUrl) => {
|
||||
const [bereicheMarkers, setBereicheMarkers] = useState([]);
|
||||
const prevVisibility = useRef(null); // Referenz, um vorherige Sichtbarkeitsdaten zu speichern
|
||||
const useAreaMarkersLayer = (map, oms, apiUrl, onUpdateSuccess) => {
|
||||
const dispatch = useDispatch();
|
||||
const [areaMarkers, setAreaMarkers] = useState([]);
|
||||
const prevVisibility = useRef(null);
|
||||
|
||||
const updateMarkersVisibility = () => {
|
||||
if (!map || bereicheMarkers.length === 0) return;
|
||||
if (!map || areaMarkers.length === 0) return;
|
||||
|
||||
const mapLayersVisibility = JSON.parse(localStorage.getItem("mapLayersVisibility")) || {};
|
||||
|
||||
const areAllLayersInvisible = Object.values(mapLayersVisibility).every((visibility) => !visibility);
|
||||
const areAllLayersInvisible = Object.values(mapLayersVisibility).every((v) => !v);
|
||||
|
||||
if (areAllLayersInvisible === prevVisibility.current) return;
|
||||
|
||||
prevVisibility.current = areAllLayersInvisible;
|
||||
|
||||
bereicheMarkers.forEach((marker) => {
|
||||
areaMarkers.forEach((marker) => {
|
||||
if (areAllLayersInvisible) {
|
||||
marker.addTo(map);
|
||||
if (oms) oms.addMarker(marker);
|
||||
@@ -49,25 +48,19 @@ const useBereicheMarkersLayer = (map, oms, apiUrl) => {
|
||||
};
|
||||
|
||||
window.addEventListener("storage", handleStorageChange);
|
||||
|
||||
const intervalId = setInterval(() => {
|
||||
updateMarkersVisibility();
|
||||
}, 500);
|
||||
const intervalId = setInterval(updateMarkersVisibility, 500);
|
||||
|
||||
return () => {
|
||||
window.removeEventListener("storage", handleStorageChange);
|
||||
clearInterval(intervalId);
|
||||
};
|
||||
}, [map, bereicheMarkers, oms]);
|
||||
}, [map, areaMarkers, oms]);
|
||||
|
||||
useEffect(() => {
|
||||
const fetchBereiche = async () => {
|
||||
const fetchArea = async () => {
|
||||
try {
|
||||
const response = await fetch(apiUrl);
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`API-Fehler: ${response.status} ${response.statusText}`);
|
||||
}
|
||||
if (!response.ok) throw new Error(`API-Fehler: ${response.status} ${response.statusText}`);
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
@@ -78,10 +71,8 @@ const useBereicheMarkersLayer = (map, oms, apiUrl) => {
|
||||
});
|
||||
|
||||
marker.bindTooltip(
|
||||
`
|
||||
<strong>Bereich:</strong> ${item.location_name} <br />
|
||||
<strong>Standort:</strong> ${item.area_name} <br />
|
||||
`,
|
||||
`<strong>Bereich:</strong> ${item.location_name} <br />
|
||||
<strong>Standort:</strong> ${item.area_name}`,
|
||||
{
|
||||
permanent: false,
|
||||
direction: "top",
|
||||
@@ -92,39 +83,46 @@ const useBereicheMarkersLayer = (map, oms, apiUrl) => {
|
||||
marker.on("dragend", async (e) => {
|
||||
const { lat, lng } = e.target.getLatLng();
|
||||
try {
|
||||
await updateLocation(item.idLocation, item.idMaps, { x: lat, y: lng });
|
||||
console.log("Koordinaten erfolgreich aktualisiert:", { lat, lng });
|
||||
await dispatch(
|
||||
updateAreaThunk({
|
||||
idLocation: item.idLocation,
|
||||
idMap: item.idMaps,
|
||||
newCoords: { x: lat, y: lng },
|
||||
})
|
||||
).unwrap();
|
||||
console.log("✔️ Koordinaten erfolgreich aktualisiert:", { lat, lng });
|
||||
onUpdateSuccess?.(); // optionaler Callback
|
||||
} catch (error) {
|
||||
console.error("Fehler beim Aktualisieren der Koordinaten:", error);
|
||||
console.error("❌ Fehler beim Aktualisieren der Koordinaten:", error);
|
||||
}
|
||||
});
|
||||
|
||||
return marker;
|
||||
});
|
||||
|
||||
setBereicheMarkers(markers);
|
||||
setAreaMarkers(markers);
|
||||
} catch (error) {
|
||||
console.error("Fehler beim Laden der Bereiche:", error.message);
|
||||
setBereicheMarkers([]); // Wichtig: Leere Liste setzen, kein reload oder Ausnahme erzeugen
|
||||
setAreaMarkers([]);
|
||||
}
|
||||
};
|
||||
|
||||
fetchBereiche();
|
||||
}, [apiUrl]);
|
||||
fetchArea();
|
||||
}, [apiUrl, dispatch]);
|
||||
|
||||
useEffect(() => {
|
||||
if (map) {
|
||||
bereicheMarkers.forEach((marker) => marker.addTo(map));
|
||||
areaMarkers.forEach((marker) => marker.addTo(map));
|
||||
}
|
||||
|
||||
return () => {
|
||||
if (map) {
|
||||
bereicheMarkers.forEach((marker) => map.removeLayer(marker));
|
||||
areaMarkers.forEach((marker) => map.removeLayer(marker));
|
||||
}
|
||||
};
|
||||
}, [map, bereicheMarkers]);
|
||||
}, [map, areaMarkers]);
|
||||
|
||||
return bereicheMarkers;
|
||||
return areaMarkers;
|
||||
};
|
||||
|
||||
export default useBereicheMarkersLayer;
|
||||
export default useAreaMarkersLayer;
|
||||
@@ -1,4 +1,4 @@
|
||||
// /pages/api/talas_v5_DB/bereich/readBereich.js
|
||||
// /pages/api/talas_v5_DB/area/readArea.js
|
||||
import getPool from "../../../../utils/mysqlPool"; // Singleton-Pool importieren
|
||||
|
||||
export default async function handler(req, res) {
|
||||
@@ -1,4 +1,4 @@
|
||||
// /pages/api/talas_v5_DB/bereich/updateBereich.js
|
||||
// /pages/api/talas_v5_DB/area/updateArea.js
|
||||
import getPool from "../../../../utils/mysqlPool";
|
||||
|
||||
export default async function handler(req, res) {
|
||||
@@ -37,16 +37,12 @@ export default async function handler(req, res) {
|
||||
return res.status(500).json({ error: "Interner Serverfehler beim Aktualisieren der Koordinaten" });
|
||||
} finally {
|
||||
if (connection) {
|
||||
connection.release();
|
||||
connection.release();
|
||||
}
|
||||
|
||||
// Sicherheitshalber eine Standardantwort senden, falls keine vorherige Antwort existiert
|
||||
if (!res.headersSent) {
|
||||
res.status(500).json({ error: "Keine Antwort vom Server" });
|
||||
res.status(500).json({ error: "Keine Antwort vom Server" });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
34
redux/slices/database/area/updateAreaSlice.js
Normal file
34
redux/slices/database/area/updateAreaSlice.js
Normal file
@@ -0,0 +1,34 @@
|
||||
// /redux/slices/database/area/updateAreaSlice.js
|
||||
|
||||
import { createSlice } from "@reduxjs/toolkit";
|
||||
import { updateAreaThunk } from "../../../thunks/database/area/updateAreaThunk";
|
||||
|
||||
const updateAreaSlice = createSlice({
|
||||
name: "updateArea",
|
||||
initialState: {
|
||||
status: "idle",
|
||||
error: null,
|
||||
},
|
||||
reducers: {
|
||||
resetUpdateAreaStatus: (state) => {
|
||||
state.status = "idle";
|
||||
state.error = null;
|
||||
},
|
||||
},
|
||||
extraReducers: (builder) => {
|
||||
builder
|
||||
.addCase(updateAreaThunk.pending, (state) => {
|
||||
state.status = "loading";
|
||||
})
|
||||
.addCase(updateAreaThunk.fulfilled, (state) => {
|
||||
state.status = "succeeded";
|
||||
})
|
||||
.addCase(updateAreaThunk.rejected, (state, action) => {
|
||||
state.status = "failed";
|
||||
state.error = action.error.message;
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
export const { resetUpdateAreaStatus } = updateAreaSlice.actions;
|
||||
export default updateAreaSlice.reducer;
|
||||
8
redux/thunks/database/area/updateAreaThunk.js
Normal file
8
redux/thunks/database/area/updateAreaThunk.js
Normal file
@@ -0,0 +1,8 @@
|
||||
// /redux/thunks/database/area/updateAreaThunk.js
|
||||
|
||||
import { createAsyncThunk } from "@reduxjs/toolkit";
|
||||
import { updateAreaService } from "../../../../services/database/area/updateAreaService";
|
||||
|
||||
export const updateAreaThunk = createAsyncThunk("area/update", async (payload) => {
|
||||
return await updateAreaService(payload);
|
||||
});
|
||||
23
services/database/area/updateAreaService.js
Normal file
23
services/database/area/updateAreaService.js
Normal file
@@ -0,0 +1,23 @@
|
||||
// /services/database/area/updateAreaService.js
|
||||
|
||||
export const updateAreaService = async ({ idLocation, idMap, newCoords }) => {
|
||||
const response = await fetch("/api/talas_v5_DB/area/updateArea", {
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
idLocation,
|
||||
idMap,
|
||||
x: newCoords.x,
|
||||
y: newCoords.y,
|
||||
}),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const error = await response.json();
|
||||
throw new Error(error.message || "Fehler beim Aktualisieren der Fläche");
|
||||
}
|
||||
|
||||
return await response.json();
|
||||
};
|
||||
@@ -1,27 +0,0 @@
|
||||
export const updateLocation = async (idLocation, idMap, newCoords) => {
|
||||
try {
|
||||
const response = await fetch("/api/talas_v5_DB/bereich/updateBereich", {
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
idLocation,
|
||||
idMap,
|
||||
x: newCoords.x,
|
||||
y: newCoords.y,
|
||||
}),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error("Fehler beim Aktualisieren der Koordinaten");
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
console.log("Koordinaten erfolgreich aktualisiert:", data);
|
||||
return data;
|
||||
} catch (error) {
|
||||
console.error("Fehler beim Aufruf von updateLocation:", error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user