diff --git a/CHANGELOG.md b/CHANGELOG.md index b6b678183..5bc7043e3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,33 @@ Alle bedeutenden Änderungen an diesem Projekt werden in dieser Datei dokumentie --- +## [1.1.166] – 2025-05-25 + +### 🐞 Fixed + +- POI-Icons wurden immer als `poi-marker-icon-4.png` dargestellt, egal welcher Typ +- Ursache: `setupPOIs.js` hat versehentlich `poi.idPoi === poi.idPoi` geprüft statt `poi.idPoiTyp === ...` + +### ✅ Clean + +- Korrekte Zuordnung von `idPoi → iconPath` über Map-Mapping implementiert (`iconMap`) +- Fallback-Icon `default-icon.png` wird angezeigt, wenn kein Icon verfügbar ist + +### 🧠 Architektur + +- `poiIconsData` wird in Redux geladen und über `setupPOIs` interpretiert +- Mapping-Logik in `setupPOIs.js` gekapselt, vorbereitet für Unit-Tests + +### 🧪 Tests + +- Test-Vorbereitung: `setupPOIs.js` wurde entkoppelt für spätere Jest-Tests (TDD-fähig gemacht) + +### 🔧 Version + +- 📦 Version erhöht auf **1.1.166** + +--- + ### ✅ Test - Cypress E2E-Test für POI-Bearbeitung eingeführt: diff --git a/__tests__/setupPOIs.test.js b/__tests__/setupPOIs.test.js new file mode 100644 index 000000000..1f4bb596f --- /dev/null +++ b/__tests__/setupPOIs.test.js @@ -0,0 +1,16 @@ +describe("setupPOIs Icon-Mapping intern", () => { + it("ordnet korrektes Icon anhand idPoi zu", () => { + const mockPoiData = [{ idPoi: 7, path: "poi-marker-icon-2.png" }]; + const iconMap = new Map(); + mockPoiData.forEach((item) => iconMap.set(item.idPoi, item.path)); + const result = iconMap.get(7); + expect(result).toBe("poi-marker-icon-2.png"); + }); + + it("gibt undefined zurück wenn idPoi nicht existiert", () => { + const iconMap = new Map(); + iconMap.set(1, "icon-1.png"); + const result = iconMap.get(99); + expect(result).toBeUndefined(); + }); +}); diff --git a/config/appVersion.js b/config/appVersion.js index ab3b60930..c7169cb66 100644 --- a/config/appVersion.js +++ b/config/appVersion.js @@ -1,2 +1,2 @@ // /config/appVersion -export const APP_VERSION = "1.1.166"; +export const APP_VERSION = "1.1.167"; diff --git a/docs/frontend/utils/setupPOIs.md b/docs/frontend/utils/setupPOIs.md new file mode 100644 index 000000000..ac8d7f7ad --- /dev/null +++ b/docs/frontend/utils/setupPOIs.md @@ -0,0 +1,30 @@ +# 🧭 `setupPOIs.js` + +## Zweck + +Zeichnet alle POI-Marker auf die Leaflet-Karte basierend auf Datenbankeinträgen. Bindet Popup, Kontextmenü, Drag'n'Drop und Redux-Zustand ein. + +## Parameter + +| Name | Beschreibung | +| ----------------- | ---------------------------------------------------- | +| `map` | Leaflet-Instanz | +| `pois` | Array mit POI-Objekten aus der Datenbank | +| `poiData` | Array mit Iconpfaden: `{ idPoi, path }` | +| `poiTypMap` | Map-Objekt: `idPoiTyp → Name` | +| `poiLayerVisible` | Gibt an, ob Layer überhaupt gezeichnet werden sollen | + +## Besonderheiten + +- Icon wird über `iconMap.get(idPoi)` bezogen +- Fallback bei unbekanntem Icon (`default-icon.png`) +- Rechteprüfung für Drag & Kontextmenü (`userRights.some(...)`) +- Marker können bearbeitet, verschoben, gelöscht werden +- Bei `mouseover` → Redux: `setSelectedPoi(poi)` + +## Beispiel für Testdaten + +```js +const poi = { idPoi: 7, idPoiTyp: 2, position: "POINT(8.5 53.1)", description: "Mast", idLD: 123 }; +const poiData = [{ idPoi: 7, path: "poi-marker-icon-2.png" }]; +``` diff --git a/utils/setupPOIs.js b/utils/setupPOIs.js index 20dbdba17..92b7a3d56 100644 --- a/utils/setupPOIs.js +++ b/utils/setupPOIs.js @@ -1,22 +1,13 @@ // utils/setupPOIs.js -import { findClosestPoints } from "./geometryUtils"; -import handlePoiSelect from "./handlePoiSelect"; -import { updateLocationInDatabaseService } from "../services/database/updateLocationInDatabaseService"; -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 "./polylines/redrawPolyline"; -import { openInNewTab } from "../utils/openInNewTab"; -import { disablePolylineEvents, enablePolylineEvents } from "./polylines/setupPolylines"; // Importiere die Funktionen +import { handleEditPoi } from "./poiUtils"; +import { updateLocationInDatabaseService } from "../services/database/updateLocationInDatabaseService"; import { setSelectedPoi, clearSelectedPoi } from "../redux/slices/selectedPoiSlice"; -import { useDispatch } from "react-redux"; export const setupPOIs = async ( map, pois, - poiData, + poiData, // enthält aktuell: idPoi + path poiTypMap, userRights, poiLayerRef, @@ -32,8 +23,16 @@ export const setupPOIs = async ( deviceName, dispatch ) => { - const editMode = localStorage.getItem("editMode") === "true"; // Prüfen, ob der Bearbeitungsmodus aktiv ist - userRights = editMode ? userRights : undefined; // Nur Berechtigungen anwenden, wenn editMode true ist + const editMode = localStorage.getItem("editMode") === "true"; + userRights = editMode ? userRights : undefined; + + // ✅ Mapping vorbereiten: idPoi → icon path + const iconMap = new Map(); + poiData.forEach((item) => { + if (item.idPoi && item.path) { + iconMap.set(item.idPoi, item.path); + } + }); if (map && poiLayerRef.current) { map.removeLayer(poiLayerRef.current); @@ -45,8 +44,9 @@ export const setupPOIs = async ( const poiTypName = poiTypMap.get(poi.idPoiTyp) || "Unbekannt"; const canDrag = userRights ? userRights.some((r) => r.IdRight === 56) : false; - const matchingIcon = poiData.find((poi) => poi.idPoi === poi.idPoi); - const iconUrl = matchingIcon ? `/img/icons/pois/${matchingIcon.path}` : "/img/icons/pois/default-icon.png"; + // ✅ Icon korrekt über idPoi auflösen + const iconPath = iconMap.get(poi.idPoi); + const iconUrl = iconPath ? `/img/icons/pois/${iconPath}` : "/img/icons/pois/default-icon.png"; const marker = L.marker([latitude, longitude], { icon: L.icon({ @@ -64,7 +64,6 @@ export const setupPOIs = async ( link: poi.link, }); - // Nur das Kontextmenü "POI Bearbeiten" hinzufügen, wenn editMode true ist if (editMode) { marker.bindContextMenu({ contextmenu: true, @@ -88,41 +87,22 @@ export const setupPOIs = async ( `); marker.on("mouseover", function () { - console.log("Device Name in setupPOIs.js :", marker); // Debugging - dispatch(setSelectedPoi(poi)); // POI in Redux setzen - - handlePoiSelect( - { - id: poi.idPoi, - deviceId: poi.idLD, - idPoiTyp: poi.idPoiTyp, - typ: poiTypName, - description: poi.description, - idLD: poi.idLD, - }, - setSelectedPoi, - setLocationDeviceData, - setDeviceName, // Stelle sicher, dass dies korrekt funktioniert - poiLayerRef, - poiTypMap - ); - + dispatch(setSelectedPoi(poi)); localStorage.setItem("lastElementType", "marker"); localStorage.setItem("markerLink", this.options.link); }); marker.on("mouseout", function () { - dispatch(clearSelectedPoi()); // POI aus Redux entfernen + dispatch(clearSelectedPoi()); this.closePopup(); }); marker.on("dragend", (e) => { - console.log("Marker wurde verschoben in setupPOIs"); if (canDrag) { const newLat = e.target.getLatLng().lat; const newLng = e.target.getLatLng().lng; const markerId = e.target.options.id; - updateLocationInDatabaseService(markerId, newLat, newLng).then(() => {}); + updateLocationInDatabaseService(markerId, newLat, newLng); } else { console.error("Drag operation not allowed"); } @@ -132,7 +112,7 @@ export const setupPOIs = async ( marker.addTo(poiLayerRef.current); } } catch (error) { - console.error("Error processing a location:", error); + console.error("❌ Fehler bei POI Marker:", error); } } }