From 0a1c0e5fbe534c703bbd0dcc1e14a3339c142fb6 Mon Sep 17 00:00:00 2001 From: ISA Date: Fri, 23 May 2025 11:14:13 +0200 Subject: [PATCH] =?UTF-8?q?refactor:=20POI-Daten=20vollst=C3=A4ndig=20in?= =?UTF-8?q?=20Redux=20integriert?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - useFetchPoiData.js entfernt - Neue Redux-Slices für POI-Typen und POI-Icons erstellt - Neue Services und Thunks hinzugefügt - fetch-Aufrufe durch zentralisierte Redux-Logik ersetzt - store.js aktualisiert und neue States registriert --- CHANGELOG.md | 22 ++ README.md | 109 +++++++- components/PoiUpdateModal.js | 249 ------------------ .../{ => contextmenu}/CoordinatePopup.js | 0 .../{ => contextmenu}/useMapContextMenu.js | 2 +- .../devices/overlapping}/PlusRoundIcon.js | 1 + components/mainComponent/MapComponent.js | 45 +++- .../mainComponent/hooks/useFetchPoiData.js | 51 ---- .../mapLayersControlPanel}/EditModeToggle.js | 0 .../MapLayersControlPanel.js | 16 +- config/appVersion.js | 2 +- redux/slices/database/poiIconsDataSlice.js | 33 +++ redux/slices/database/poiTypSlice.js | 33 +++ redux/store.js | 4 + .../thunks/database/fetchPoiIconsDataThunk.js | 11 + redux/thunks/database/fetchPoiTypThunk.js | 11 + services/database/fetchPoiDataByIdService.js | 18 ++ services/database/fetchPoiDataService.js | 22 +- services/database/fetchPoiIconsDataService.js | 6 + services/database/fetchPoiTypService.js | 6 + 20 files changed, 304 insertions(+), 337 deletions(-) delete mode 100644 components/PoiUpdateModal.js rename components/{ => contextmenu}/CoordinatePopup.js (100%) rename components/{ => contextmenu}/useMapContextMenu.js (97%) rename components/{ => icons/devices/overlapping}/PlusRoundIcon.js (91%) delete mode 100644 components/mainComponent/hooks/useFetchPoiData.js rename components/{ => uiWidgets/mapLayersControlPanel}/EditModeToggle.js (100%) rename components/uiWidgets/{ => mapLayersControlPanel}/MapLayersControlPanel.js (94%) create mode 100644 redux/slices/database/poiIconsDataSlice.js create mode 100644 redux/slices/database/poiTypSlice.js create mode 100644 redux/thunks/database/fetchPoiIconsDataThunk.js create mode 100644 redux/thunks/database/fetchPoiTypThunk.js create mode 100644 services/database/fetchPoiDataByIdService.js create mode 100644 services/database/fetchPoiIconsDataService.js create mode 100644 services/database/fetchPoiTypService.js diff --git a/CHANGELOG.md b/CHANGELOG.md index 750e1ec9e..6ff9a01ab 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,28 @@ Alle bedeutenden Änderungen an diesem Projekt werden in dieser Datei dokumentie --- +## [1.1.153] - 2025-05-22 + +### ✨ Features + +- Neue Redux-Slices erstellt: `poiIconsDataSlice` und `poiTypSlice` +- Neue Services erstellt: `fetchPoiIconsDataService.js`, `fetchPoiTypService.js` +- Neue Thunks: `fetchPoiIconsDataThunk.js`, `fetchPoiTypThunk.js` +- State-Management für POI-Typen und POI-Icons vollständig in Redux überführt +- Komponente `useFetchPoiData.js` entfernt und durch Redux ersetzt + +### ♻️ Refactoring + +- Alle direkten `fetch`-Aufrufe durch Redux-Thunk ersetzt +- Architektur auf eine zentralisierte, testbare Datenflussstruktur verbessert +- Zustand der POI-Daten über Redux `store.js` global verwaltet + +### ✅ Cleanup + +- `useFetchPoiData.js` gelöscht, da Funktionalität durch Thunks ersetzt wurde + +--- + ## [1.1.150] - 2025-05-22 ### Removed diff --git a/README.md b/README.md index 705663550..0b1a673d7 100644 --- a/README.md +++ b/README.md @@ -66,15 +66,120 @@ npm run dev ```bash components/ → UI-Komponenten inkl. Karte und Layer-Control-Panel (`MapLayersControlPanel`) + +📦components + ┣ 📂contextmenu + ┃ ┣ 📜CoordinatePopup.js + ┃ ┗ 📜useMapContextMenu.js + ┣ 📂gisPolylines + ┃ ┣ 📂icons + ┃ ┃ ┣ 📜CircleIcon.js + ┃ ┃ ┣ 📜EndIcon.js + ┃ ┃ ┣ 📜StartIcon.js + ┃ ┃ ┗ 📜SupportPointIcons.js + ┃ ┗ 📜PolylineContextMenu.js + ┣ 📂icons + ┃ ┗ 📂devices + ┃ ┃ ┗ 📂overlapping + ┃ ┃ ┃ ┗ 📜PlusRoundIcon.js + ┣ 📂mainComponent + ┃ ┣ 📂hooks + ┃ ┃ ┣ 📜useFetchPoiData.js + ┃ ┃ ┣ 📜useInitializeMap.js + ┃ ┃ ┗ 📜useRestoreMapSettings.js + ┃ ┗ 📜MapComponent.js + ┣ 📂pois + ┃ ┣ 📜AddPOIModal.js + ┃ ┗ 📜PoiUpdateModal.js + ┣ 📂uiWidgets + ┃ ┣ 📂mapLayersControlPanel + ┃ ┃ ┣ 📜EditModeToggle.js + ┃ ┃ ┗ 📜MapLayersControlPanel.js + ┃ ┣ 📜CoordinateInput.js + ┃ ┗ 📜VersionInfoModal.js + ┗ 📜TestScript.js + + config/ → zentrale Variablen (.env.local) + hooks/ → eigene React-Hooks -redux/ → globale Zustände (Slices) -services/ → API-Kommunikation, Mock-Logik + utils/ → POI- und Linienverarbeitung + lib/ → Formatierungen, Umrechnungen + public/ → mapTiles, Bilder, Icons + pages/ → Next.js Seiten & Routen + scripts/ → lokale Tools (nur Dev) + +redux/ → globale Zustände (Slices) +📦redux + ┣ 📂slices + ┃ ┣ 📂database + ┃ ┃ ┣ 📜addPoiSlice.js + ┃ ┃ ┣ 📜gisLinesSlice.js + ┃ ┃ ┣ 📜locationDevicesFromDBSlice.js + ┃ ┃ ┣ 📜locationDevicesSlice.js + ┃ ┃ ┣ 📜poiTypesSlice.js + ┃ ┃ ┗ 📜priorityConfigSlice.js + ┃ ┣ 📂webservice + ┃ ┃ ┣ 📜gisLinesStatusSlice.js + ┃ ┃ ┣ 📜gisStationsMeasurementsSlice.js + ┃ ┃ ┣ 📜gisStationsStaticDistrictSlice.js + ┃ ┃ ┣ 📜gisStationsStatusDistrictSlice.js + ┃ ┃ ┣ 📜gisSystemStaticSlice.js + ┃ ┃ ┗ 📜userRightsSlice.js + ┃ ┣ 📜addPoiOnPolylineSlice.js + ┃ ┣ 📜currentPoiSlice.js + ┃ ┣ 📜lineVisibilitySlice.js + ┃ ┣ 📜mapLayersSlice.js + ┃ ┣ 📜poiLayerVisibleSlice.js + ┃ ┣ 📜poiReadFromDbTriggerSlice.js + ┃ ┣ 📜polylineContextMenuSlice.js + ┃ ┣ 📜polylineEventsDisabledSlice.js + ┃ ┣ 📜polylineLayerVisibleSlice.js + ┃ ┣ 📜readPoiMarkersStoreSlice.js + ┃ ┣ 📜selectedAreaSlice.js + ┃ ┣ 📜selectedDeviceSlice.js + ┃ ┣ 📜selectedPoiSlice.js + ┃ ┣ 📜urlParameterSlice.js + ┃ ┗ 📜zoomTriggerSlice.js + ┣ 📂thunks + ┃ ┣ 📂database + ┃ ┃ ┣ 📜addPoiThunk.js + ┃ ┃ ┣ 📜fetchGisLinesThunk.js + ┃ ┃ ┣ 📜fetchLocationDevicesThunk.js + ┃ ┃ ┗ 📜fetchPriorityConfigThunk.js + ┃ ┗ 📂webservice + ┃ ┃ ┣ 📜fetchGisLinesStatusThunk.js + ┃ ┃ ┣ 📜fetchGisStationsMeasurementsThunk.js + ┃ ┃ ┣ 📜fetchGisStationsStaticDistrictThunk.js + ┃ ┃ ┣ 📜fetchGisStationsStatusDistrictThunk.js + ┃ ┃ ┣ 📜fetchGisSystemStaticThunk.js + ┃ ┃ ┗ 📜fetchUserRightsThunk.js + ┗ 📜store.js + +services/ → API-Kommunikation, Mock-Logik +📦services + ┣ 📂database + ┃ ┣ 📜addPoiService.js + ┃ ┣ 📜fetchDeviceNameByIdService.js + ┃ ┣ 📜fetchGisLinesService.js + ┃ ┣ 📜fetchLocationDevicesService.js + ┃ ┣ 📜fetchPoiDataService.js + ┃ ┣ 📜fetchPriorityConfigService.js + ┃ ┗ 📜updateLocationInDatabaseService.js + ┣ 📂utils + ┃ ┗ 📜fetchWithTimeout.js + ┗ 📂webservice + ┃ ┣ 📜fetchGisLinesStatusService.js + ┃ ┣ 📜fetchGisStationsMeasurementsService.js + ┃ ┣ 📜fetchGisStationsStaticDistrictService.js + ┃ ┣ 📜fetchGisStationsStatusDistrictService.js + ┃ ┣ 📜fetchGisSystemStaticService.js + ┃ ┗ 📜fetchUserRightsService.js ``` --- diff --git a/components/PoiUpdateModal.js b/components/PoiUpdateModal.js deleted file mode 100644 index 5de3f3fa6..000000000 --- a/components/PoiUpdateModal.js +++ /dev/null @@ -1,249 +0,0 @@ -// /components/PoiUpdateModal.js -import React, { useState, useEffect } from "react"; - - -import { fetchLocationDevicesFromDB } from "../redux/slices/db/locationDevicesFromDBSlice"; -import { useDispatch, useSelector } from "react-redux"; -import { selectCurrentPoi } from "../redux/slices/currentPoiSlice"; - -const PoiUpdateModal = ({ onClose, poiData }) => { - const dispatch = useDispatch(); - const devices = useSelector((state) => state.locationDevicesFromDB.devices); - - const currentPoi = useSelector(selectCurrentPoi); - const selectedPoi = useSelector((state) => state.selectedPoi); - const [poiId, setPoiId] = useState(poiData ? poiData.idPoi : ""); - const [name, setName] = useState(poiData ? poiData.name : ""); - const [poiTypData, setPoiTypData] = useState([]); - const [poiTypeId, setPoiTypeId] = useState(""); - const [locationDeviceData, setLocationDeviceData] = useState([]); - const [deviceName, setDeviceName] = useState(""); - const [idLD, setIdLD] = useState(poiData ? poiData.idLD : ""); - const [idLocationDevice, setIdLocationDevice] = useState(""); - - const [description, setDescription] = useState(poiData ? poiData.description : ""); - - useEffect(() => { - dispatch(fetchLocationDevicesFromDB()); - }, [dispatch]); - - // Log the initial POI data - useEffect(() => { - if (poiData) { - setPoiId(poiData.idPoi); - setName(poiData.name); - setPoiTypeId(poiData.idPoiTyp); - setIdLD(poiData.idLD); - - setDescription(poiData.description); - setDeviceName(poiData.idLD); - console.log("Loaded POI Data for editing:", poiData); - console.log("POI ID:", poiData.idPoi); - console.log("POI Name:", poiData.name); - console.log("POI Typ ID:", poiData.idPoiTyp); - console.log("POI Beschreibung:", poiData.description); - console.log("POI Geräte-ID:", poiData.idLD); - } - }, [poiData]); - - /* const fetchDeviceNameById = async (idLD) => { - try { - const response = await fetch(`/api/getDeviceNameById?idLD=${idLD}`); - const data = await response.json(); - setDeviceName(data.deviceName); - } catch (error) { - console.error("Error fetching device name:", error); - } - }; */ - - /* const fetchDeviceNameById = async (idLD) => { - try { - const response = await fetch(`/api/talas_v5_DB/locationDevice/locationDeviceNameById?idLD=${idLD}`); - const data = await response.json(); - setDeviceName(data.deviceName); - } catch (error) { - console.error("Error fetching device name:", error); - } - }; */ - - // Beim Öffnen des Modals die Geräte-ID basierend auf dem Gerätenamen abrufen, wenn vorhanden - useEffect(() => { - const fetchDeviceId = async () => { - if (poiData && poiData.idLD) { - try { - const response = await fetch(`/api/talas_v5_DB/locationDevice/getDeviceIdById?idLD=${poiData.idLD}`); - const data = await response.json(); - if (data) setDeviceName(data.name); - } catch (error) { - console.error("Fehler beim Abrufen der Geräteinformation in PoiUpdateModel.js: ", error); - } - } - }; - - fetchDeviceId(); - }, [poiData]); - - // Function to handle deleting a POI - const handleDeletePoi = async () => { - if (confirm("Sind Sie sicher, dass Sie diesen POI löschen möchten?")) { - try { - const response = await fetch(`/api/talas_v5_DB/pois/deletePoi?id=${poiId}`, { - method: "DELETE", - }); - if (response.ok) { - alert("POI wurde erfolgreich gelöscht."); - onClose(); // Close the modal - //Browser neu laden, um die aktualisierte Liste anzuzeigen - window.location.reload(); - } else { - throw new Error("Fehler beim Löschen des POI."); - } - } catch (error) { - console.error("Fehler beim Löschen des POI 1:", error); - alert("Fehler beim Löschen des POI."); - } - } - }; - - // Fetch POI types - useEffect(() => { - const fetchPoiTypData = async () => { - try { - const response = await fetch("/api/talas_v5_DB/poiTyp/readPoiTyp"); - const data = await response.json(); - setPoiTypData(data); - if (selectedPoi && data) { - const matchingType = data.find((pt) => pt.name === selectedPoi.typ); - if (matchingType) { - setPoiTypeId(matchingType.idPoiTyp); - } - } - } catch (error) { - console.error("Fehler beim Abrufen der poiTyp Daten:", error); - } - }; - fetchPoiTypData(); - }, [selectedPoi]); - - //-------------------------------------------------------------------------------------------- - // Fetch device name basierend auf der Geräte-ID - - useEffect(() => { - console.log("currentPoi von PoiUpdateModal.js : ", currentPoi.idLD); - const API_BASE_URL = `${window.location.origin}:3000`; -const response = await fetch(`${API_BASE_URL}/api/talas_v5_DB/locationDevice/locationDevices`); - - .then((response) => response.json()) - .then((data) => { - setLocationDeviceData(data); - console.log("Standort- und Gerätedaten 3:", data); - console.log("Standort- und Gerätedaten 3 poiData:", poiData); - // Findet das Gerät, das der aktuellen IDLD entspricht - const currentDevice = data.find((device) => device.idLD === currentPoi.idLD); - if (currentDevice) { - setDeviceName(currentDevice.name); - } - }) - .catch((error) => { - console.error("Fehler beim Abrufen der Gerätedaten:", error); - setLocationDeviceData([]); - }); - }, [poiData?.idLD, currentPoi]); - - //-------------------------------------------------------------------------------------------- - // Angenommen, deviceName enthält die Geräte-ID - //const idLD = deviceName; // Stellen Sie sicher, dass dies eine ID ist und kein Name - - const handleSubmit = async (event) => { - event.preventDefault(); - const idLDResponse = await fetch(`/api/talas_v5_DB/locationDevice/getDeviceId?deviceName=${encodeURIComponent(deviceName)}`); - const idLDData = await idLDResponse.json(); - const idLD = idLDData.idLD; - try { - const response = await fetch("/api/talas_v5_DB/pois/updatePoi", { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ - idPoi: poiId, - name: name, - description: description, - idPoiTyp: poiTypeId, - idLD: idLD, - //idLD: parseInt(deviceName, 10), // Konvertieren in eine Ganzzahl - }), - }); - - if (response.ok) { - onClose(); - window.location.reload(); - } else { - const errorResponse = await response.json(); - throw new Error(errorResponse.error || "Fehler beim Aktualisieren des POI."); - } - } catch (error) { - console.error("Fehler beim Aktualisieren des POI:", error); - alert("Fehler beim Aktualisieren des POI."); - } - }; - - //ausgewählte poi Informationen in Console anzeigen - console.log("Selected POI:", selectedPoi); - console.log("Selected POI Gerät id in poiUpdateModal.js:", selectedPoi.id); - console.log("Selected POI Typ name in poiUpdateModal.js:", selectedPoi.typ); //als Typ in dropdown menu - console.log("Selected POI Beschreibung in poiUpdateModal.js:", selectedPoi.description); - console.log("Selected POI Gerät deviceId in poiUpdateModal.js:", selectedPoi.deviceId); - - return ( -
-
- - setDescription(e.target.value)} placeholder="Beschreibung der Station" className="block p-2 w-full border-2 border-gray-200 rounded-md text-sm" /> -
- -
- - -
- -
- - -
- - - - -
- ); -}; - -export default PoiUpdateModal; diff --git a/components/CoordinatePopup.js b/components/contextmenu/CoordinatePopup.js similarity index 100% rename from components/CoordinatePopup.js rename to components/contextmenu/CoordinatePopup.js diff --git a/components/useMapContextMenu.js b/components/contextmenu/useMapContextMenu.js similarity index 97% rename from components/useMapContextMenu.js rename to components/contextmenu/useMapContextMenu.js index 31ad629ef..eba447e87 100644 --- a/components/useMapContextMenu.js +++ b/components/contextmenu/useMapContextMenu.js @@ -1,6 +1,6 @@ // components/useMapContextMenu.js import { toast } from "react-toastify"; -import { zoomIn, zoomOut, centerHere } from "../utils/zoomAndCenterUtils"; +import { zoomIn, zoomOut, centerHere } from "../../utils/zoomAndCenterUtils"; // components/useMapContextMenu.js const addItemsToMapContextMenu = ( diff --git a/components/PlusRoundIcon.js b/components/icons/devices/overlapping/PlusRoundIcon.js similarity index 91% rename from components/PlusRoundIcon.js rename to components/icons/devices/overlapping/PlusRoundIcon.js index d0f1c31db..21dc59f1e 100644 --- a/components/PlusRoundIcon.js +++ b/components/icons/devices/overlapping/PlusRoundIcon.js @@ -1,3 +1,4 @@ +// /components/PlusRoundIcon.js const plusRoundIcon = L.icon({ //iconUrl: "/img/plus_round.png", // Update with your actual path iconUrl: "/img/plus_round.png", // Update with your actual path diff --git a/components/mainComponent/MapComponent.js b/components/mainComponent/MapComponent.js index c6536ad1f..8461ef7e5 100644 --- a/components/mainComponent/MapComponent.js +++ b/components/mainComponent/MapComponent.js @@ -7,17 +7,17 @@ import "leaflet-contextmenu"; 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 MapLayersControlPanel from "../uiWidgets/MapLayersControlPanel.js"; +import MapLayersControlPanel from "../uiWidgets/mapLayersControlPanel/MapLayersControlPanel.js"; import { InformationCircleIcon } from "@heroicons/react/20/solid"; import PoiUpdateModal from "../pois/PoiUpdateModal.js"; import { ToastContainer, toast } from "react-toastify"; -import plusRoundIcon from "../PlusRoundIcon.js"; +import plusRoundIcon from "../icons/devices/overlapping/PlusRoundIcon.js"; import { createAndSetDevices } from "../../utils/devices/createAndSetDevices.js"; import { restoreMapSettings, checkOverlappingMarkers } from "../../utils/mapUtils.js"; import { APP_VERSION } from "../../config/appVersion.js"; import * as layers from "../../config/layers.js"; -import addItemsToMapContextMenu from "../useMapContextMenu.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"; @@ -32,9 +32,9 @@ import { selectMapLayersState } from "../../redux/slices/mapLayersSlice"; import { useSelector, useDispatch } from "react-redux"; import { setCurrentPoi } from "../../redux/slices/currentPoiSlice.js"; import CoordinateInput from "../uiWidgets/CoordinateInput.js"; -import CoordinatePopup from "../CoordinatePopup.js"; +import CoordinatePopup from "../contextmenu/CoordinatePopup.js"; //------------------------Daten aus API-------------------- -import { fetchPoiDataService } from "../../services/database/fetchPoiDataService.js"; +import { fetchPoiDataService } from "../../services/database/fetchPoiDataByIdService.js"; import { selectPolylineVisible, setPolylineVisible } from "../../redux/slices/polylineLayerVisibleSlice.js"; import { selectGisStationsStaticDistrict } from "../../redux/slices/webservice/gisStationsStaticDistrictSlice.js"; import { selectGisSystemStatic, setGisSystemStatic } from "../../redux/slices/webservice/gisSystemStaticSlice.js"; @@ -44,7 +44,6 @@ import { updateCountdown, closePolylineContextMenu } from "../../redux/slices/po //-------------------MapComponent.js hooks-------------------- import useInitializeMap from "./hooks/useInitializeMap"; -import useFetchPoiData from "./hooks/useFetchPoiData.js"; import useRestoreMapSettings from "./hooks/useRestoreMapSettings"; import { setSelectedPoi } from "../../redux/slices/selectedPoiSlice"; import { setDisabled } from "../../redux/slices/polylineEventsDisabledSlice"; @@ -66,6 +65,11 @@ import { selectGisLinesStatus } from "../../redux/slices/webservice/gisLinesStat import { selectGisLinesStatusFromWebservice } from "../../redux/slices/webservice/gisLinesStatusSlice"; import { selectGisUserRightsFromWebservice } from "../../redux/slices/webservice/userRightsSlice"; +import { fetchPoiIconsDataThunk } from "../../redux/thunks/database/fetchPoiIconsDataThunk"; +import { fetchPoiTypThunk } from "../../redux/thunks/database/fetchPoiTypThunk"; +import { selectPoiIconsData, selectPoiIconsStatus } from "../../redux/slices/database/poiIconsDataSlice"; +import { selectPoiTypData, selectPoiTypStatus } from "../../redux/slices/database/poiTypSlice"; + const MapComponent = ({ locations, onLocationUpdate, lineCoordinates }) => { //------------------------------- const dispatch = useDispatch(); @@ -73,7 +77,7 @@ const MapComponent = ({ locations, onLocationUpdate, lineCoordinates }) => { const countdownActive = useSelector((state) => state.polylineContextMenu.countdownActive); const isPolylineContextMenuOpen = useSelector((state) => state.polylineContextMenu.isOpen); const polylineVisible = useSelector(selectPolylineVisible); - const poiTypStatus = useSelector((state) => state.poiTypes.status); + const isPoiTypLoaded = useSelector((state) => state.poiTypes.status === "succeeded"); const statusMeasurements = useSelector((state) => state.gisStationsMeasurements.status); const statusSystem = useSelector((state) => state.gisSystemStatic.status); @@ -94,6 +98,13 @@ const MapComponent = ({ locations, onLocationUpdate, lineCoordinates }) => { const { data: gisLinesStatusData, status: statusGisLinesStatus } = useSelector(selectGisLinesStatusFromWebservice); + const poiIconsData = useSelector(selectPoiIconsData); + const poiIconsStatus = useSelector(selectPoiIconsStatus); + + const poiTypData = useSelector(selectPoiTypData); + const poiTypStatus = useSelector((state) => state.poiTypes.status); + //const poiTypStatus = useSelector(selectPoiTypStatus); + /* useEffect(() => { console.log("✅ Redux: gisLinesStatusData:", gisLinesStatusData); }, [gisLinesStatusData]); @@ -233,7 +244,11 @@ const MapComponent = ({ locations, onLocationUpdate, lineCoordinates }) => { //-------------------------------------------- const [poiData, setPoiData] = useState([]); // POIs Popup Informationen anzeigen - useFetchPoiData(setPoiTypMap, setPoiData); + + useEffect(() => { + dispatch(fetchPoiIconsDataThunk()); + dispatch(fetchPoiTypThunk()); + }, [dispatch]); //-------------------------------------------- // POIs auf die Karte zeichnen @@ -857,6 +872,20 @@ const MapComponent = ({ locations, onLocationUpdate, lineCoordinates }) => { window.onerror = null; // **Fehlerbehandlung entfernen, wenn Komponente unmounted wird** }; }, []); + //------------------------------------------------ + useEffect(() => { + if (poiTypStatus === "succeeded" && Array.isArray(poiTypData)) { + const map = new Map(); + poiTypData.forEach((item) => map.set(item.idPoiTyp, item.name)); + setPoiTypMap(map); + } + }, [poiTypData, poiTypStatus]); + //------------------------------------------------ + useEffect(() => { + if (poiIconsStatus === "succeeded") { + setPoiData(poiIconsData); + } + }, [poiIconsData, poiIconsStatus]); //--------------------------------------------- //-------------------------------------------- diff --git a/components/mainComponent/hooks/useFetchPoiData.js b/components/mainComponent/hooks/useFetchPoiData.js deleted file mode 100644 index ab0a0c9d9..000000000 --- a/components/mainComponent/hooks/useFetchPoiData.js +++ /dev/null @@ -1,51 +0,0 @@ -// /components/mainComponent/hooks/useFetchPoiData.js -import { useEffect, useState } from "react"; - -const API_BASE_URL = typeof window !== "undefined" ? `${window.location.protocol}//${window.location.hostname}:3000` : ""; - -const useFetchPoiData = (setPoiTypMap, setPoiData) => { - useEffect(() => { - //console.log(`🌍 API_BASE_URL aus .env.local: ${API_BASE_URL}`); - - //console.log("✅ useFetchPoiData wurde gestartet..."); - // console.log(`🌍 API_BASE_URL: ${API_BASE_URL}`); // Debugging: Prüfen, ob die Umgebungsvariable korrekt geladen wird - - const fetchPoiTypData = async () => { - try { - console.log("📡 Lade POI-Typ-Daten..."); - const response = await fetch(`${API_BASE_URL}/api/talas_v5_DB/poiTyp/readPoiTyp`); - const data = await response.json(); - if (!Array.isArray(data)) { - console.warn(`⚠️ Unerwartetes Format: ${JSON.stringify(data)}`); - throw new Error("Daten sind kein Array"); - } - const map = new Map(); - data.forEach((item) => map.set(item.idPoiTyp, item.name)); - setPoiTypMap(map); - //console.log("✅ POI-Typ-Daten erfolgreich geladen!"); - } catch (error) { - console.error("❌ Fehler beim Abrufen der POI-Typ-Daten:", error); - } - }; - - const fetchPoiData = async () => { - try { - //console.log("📡 Lade POI-Icons..."); - const response = await fetch(`${API_BASE_URL}/api/talas_v5_DB/pois/poi-icons`); - if (!response.ok) { - throw new Error(`Netzwerkantwort war nicht ok, Status: ${response.status}`); - } - const data = await response.json(); - setPoiData(data); - //console.log("✅ POI-Icons erfolgreich geladen!", data); - } catch (error) { - console.error("❌ Fehler beim Abrufen der POI-Daten:", error); - } - }; - - fetchPoiTypData(); - fetchPoiData(); - }, [setPoiTypMap, setPoiData]); -}; - -export default useFetchPoiData; diff --git a/components/EditModeToggle.js b/components/uiWidgets/mapLayersControlPanel/EditModeToggle.js similarity index 100% rename from components/EditModeToggle.js rename to components/uiWidgets/mapLayersControlPanel/EditModeToggle.js diff --git a/components/uiWidgets/MapLayersControlPanel.js b/components/uiWidgets/mapLayersControlPanel/MapLayersControlPanel.js similarity index 94% rename from components/uiWidgets/MapLayersControlPanel.js rename to components/uiWidgets/mapLayersControlPanel/MapLayersControlPanel.js index 857aacb5e..f3dca149f 100644 --- a/components/uiWidgets/MapLayersControlPanel.js +++ b/components/uiWidgets/mapLayersControlPanel/MapLayersControlPanel.js @@ -1,14 +1,14 @@ // /componentss/MapLayersControlPanel.js import React, { useEffect, useState } from "react"; -import { setSelectedArea } from "../../redux/slices/selectedAreaSlice"; -import EditModeToggle from "../EditModeToggle"; +import { setSelectedArea } from "../../../redux/slices/selectedAreaSlice"; +import EditModeToggle from "./EditModeToggle"; import { useSelector, useDispatch } from "react-redux"; -import { selectPolylineVisible, setPolylineVisible } from "../../redux/slices/polylineLayerVisibleSlice"; -import { selectGisSystemStatic } from "../../redux/slices/webservice/gisSystemStaticSlice"; -import { selectGisStationsStaticDistrict } from "../../redux/slices/webservice/gisStationsStaticDistrictSlice"; -import { selectMapLayersState, setLayerVisibility } from "../../redux/slices/mapLayersSlice"; -import { setVisible } from "../../redux/slices/poiLayerVisibleSlice"; -import { incrementZoomTrigger } from "../../redux/slices/zoomTriggerSlice"; +import { selectPolylineVisible, setPolylineVisible } from "../../../redux/slices/polylineLayerVisibleSlice"; +import { selectGisSystemStatic } from "../../../redux/slices/webservice/gisSystemStaticSlice"; +import { selectGisStationsStaticDistrict } from "../../../redux/slices/webservice/gisStationsStaticDistrictSlice"; +import { selectMapLayersState, setLayerVisibility } from "../../../redux/slices/mapLayersSlice"; +import { setVisible } from "../../../redux/slices/poiLayerVisibleSlice"; +import { incrementZoomTrigger } from "../../../redux/slices/zoomTriggerSlice"; function MapLayersControlPanel() { const [editMode, setEditMode] = useState(false); // Zustand für editMode diff --git a/config/appVersion.js b/config/appVersion.js index 37bcff8e8..ba2679883 100644 --- a/config/appVersion.js +++ b/config/appVersion.js @@ -1,2 +1,2 @@ // /config/appVersion -export const APP_VERSION = "1.1.153"; +export const APP_VERSION = "1.1.154"; diff --git a/redux/slices/database/poiIconsDataSlice.js b/redux/slices/database/poiIconsDataSlice.js new file mode 100644 index 000000000..e1c3e842f --- /dev/null +++ b/redux/slices/database/poiIconsDataSlice.js @@ -0,0 +1,33 @@ +// /redux/slices/database/poiIconsDataSlice.js +import { createSlice } from "@reduxjs/toolkit"; +import { fetchPoiIconsDataThunk } from "../../thunks/database/fetchPoiIconsDataThunk"; + +const initialState = { + data: [], + status: "idle", + error: null, +}; + +const poiIconsDataSlice = createSlice({ + name: "poiIconsData", + initialState, + reducers: {}, + extraReducers: (builder) => { + builder + .addCase(fetchPoiIconsDataThunk.pending, (state) => { + state.status = "loading"; + }) + .addCase(fetchPoiIconsDataThunk.fulfilled, (state, action) => { + state.status = "succeeded"; + state.data = action.payload; + }) + .addCase(fetchPoiIconsDataThunk.rejected, (state, action) => { + state.status = "failed"; + state.error = action.payload; + }); + }, +}); + +export default poiIconsDataSlice.reducer; +export const selectPoiIconsData = (state) => state.poiIconsData.data; +export const selectPoiIconsStatus = (state) => state.poiIconsData.status; diff --git a/redux/slices/database/poiTypSlice.js b/redux/slices/database/poiTypSlice.js new file mode 100644 index 000000000..f815434c8 --- /dev/null +++ b/redux/slices/database/poiTypSlice.js @@ -0,0 +1,33 @@ +// /redux/slices/database/poiTypSlice.js +import { createSlice } from "@reduxjs/toolkit"; +import { fetchPoiTypThunk } from "../../thunks/database/fetchPoiTypThunk"; + +const initialState = { + data: [], + status: "idle", + error: null, +}; + +const poiTypSlice = createSlice({ + name: "poiTyp", + initialState, + reducers: {}, + extraReducers: (builder) => { + builder + .addCase(fetchPoiTypThunk.pending, (state) => { + state.status = "loading"; + }) + .addCase(fetchPoiTypThunk.fulfilled, (state, action) => { + state.status = "succeeded"; + state.data = action.payload; + }) + .addCase(fetchPoiTypThunk.rejected, (state, action) => { + state.status = "failed"; + state.error = action.payload; + }); + }, +}); + +export default poiTypSlice.reducer; +export const selectPoiTypData = (state) => state.poiTyp.data; +export const selectPoiTypStatus = (state) => state.poiTyp.status; diff --git a/redux/store.js b/redux/store.js index a36c586cf..0f5212b78 100644 --- a/redux/store.js +++ b/redux/store.js @@ -20,6 +20,8 @@ import priorityConfigReducer from "./slices/database/priorityConfigSlice"; import poiTypesReducer from "./slices/database/poiTypesSlice"; import locationDevicesFromDBReducer from "./slices/database/locationDevicesFromDBSlice"; import gisLinesFromDatabaseReducer from "./slices/database/gisLinesSlice"; +import poiTypReducer from "./slices/database/poiTypSlice"; +import poiIconsDataReducer from "./slices/database/poiIconsDataSlice"; //----webservice------------ import gisStationsStaticDistrictReducer from "./slices/webservice/gisStationsStaticDistrictSlice"; import gisStationsStatusDistrictReducer from "./slices/webservice/gisStationsStatusDistrictSlice"; @@ -57,5 +59,7 @@ export const store = configureStore({ urlParameter: urlParameterReducer, priorityConfig: priorityConfigReducer, addPoi: addPoiReducer, + poiTyp: poiTypReducer, + poiIconsData: poiIconsDataReducer, }, }); diff --git a/redux/thunks/database/fetchPoiIconsDataThunk.js b/redux/thunks/database/fetchPoiIconsDataThunk.js new file mode 100644 index 000000000..ab96fb20d --- /dev/null +++ b/redux/thunks/database/fetchPoiIconsDataThunk.js @@ -0,0 +1,11 @@ +// /redux/thunks/database/fetchPoiIconsDataThunk.js +import { createAsyncThunk } from "@reduxjs/toolkit"; +import { fetchPoiIconsDataService } from "../../../services/database/fetchPoiIconsDataService"; + +export const fetchPoiIconsDataThunk = createAsyncThunk("poiIconsData/fetch", async (_, thunkAPI) => { + try { + return await fetchPoiIconsDataService(); + } catch (err) { + return thunkAPI.rejectWithValue(err.message); + } +}); diff --git a/redux/thunks/database/fetchPoiTypThunk.js b/redux/thunks/database/fetchPoiTypThunk.js new file mode 100644 index 000000000..25dff03fa --- /dev/null +++ b/redux/thunks/database/fetchPoiTypThunk.js @@ -0,0 +1,11 @@ +// /redux/thunks/database/fetchPoiTypThunk.js +import { createAsyncThunk } from "@reduxjs/toolkit"; +import { fetchPoiTypService } from "../../../services/database/fetchPoiTypService"; + +export const fetchPoiTypThunk = createAsyncThunk("poiTyp/fetch", async (_, thunkAPI) => { + try { + return await fetchPoiTypService(); + } catch (err) { + return thunkAPI.rejectWithValue(err.message); + } +}); diff --git a/services/database/fetchPoiDataByIdService.js b/services/database/fetchPoiDataByIdService.js new file mode 100644 index 000000000..f7723b783 --- /dev/null +++ b/services/database/fetchPoiDataByIdService.js @@ -0,0 +1,18 @@ +// /services/database/fetchPoiDataService.js + +export const fetchPoiDataService = async (idPoi) => { + try { + const response = await fetch(`/api/talas_v5_DB/pois/getPoiById?idPoi=${idPoi}`); + if (!response.ok) throw new Error("Fehler beim Abrufen der POI-Daten"); + const data = await response.json(); + return { + idPoi, + name: data.name, + description: data.description, + idLD: data.idLD, + }; + } catch (error) { + console.error("Fehler beim Abrufen der POI-Daten", error); + return null; + } +}; diff --git a/services/database/fetchPoiDataService.js b/services/database/fetchPoiDataService.js index f7723b783..4c006cf3b 100644 --- a/services/database/fetchPoiDataService.js +++ b/services/database/fetchPoiDataService.js @@ -1,18 +1,6 @@ -// /services/database/fetchPoiDataService.js - -export const fetchPoiDataService = async (idPoi) => { - try { - const response = await fetch(`/api/talas_v5_DB/pois/getPoiById?idPoi=${idPoi}`); - if (!response.ok) throw new Error("Fehler beim Abrufen der POI-Daten"); - const data = await response.json(); - return { - idPoi, - name: data.name, - description: data.description, - idLD: data.idLD, - }; - } catch (error) { - console.error("Fehler beim Abrufen der POI-Daten", error); - return null; - } +// fetchPoiDataService.js +export const fetchPoiDataService = async () => { + const res = await fetch(`${window.location.origin}/api/talas_v5_DB/pois/poi-icons`); + if (!res.ok) throw new Error("Fehler beim Abrufen der POI-Daten"); + return await res.json(); }; diff --git a/services/database/fetchPoiIconsDataService.js b/services/database/fetchPoiIconsDataService.js new file mode 100644 index 000000000..4dc5f0e1b --- /dev/null +++ b/services/database/fetchPoiIconsDataService.js @@ -0,0 +1,6 @@ +// /services/database/fetchPoiIconsDataService.js +export const fetchPoiIconsDataService = async () => { + const res = await fetch(`${window.location.origin}/api/talas_v5_DB/pois/poi-icons`); + if (!res.ok) throw new Error("Fehler beim Abrufen der POI-Icon-Daten"); + return await res.json(); +}; diff --git a/services/database/fetchPoiTypService.js b/services/database/fetchPoiTypService.js new file mode 100644 index 000000000..10efbc21b --- /dev/null +++ b/services/database/fetchPoiTypService.js @@ -0,0 +1,6 @@ +// /services/database/fetchPoiTypService.js +export const fetchPoiTypService = async () => { + const res = await fetch(`${window.location.origin}/api/talas_v5_DB/poiTyp/readPoiTyp`); + if (!res.ok) throw new Error("Fehler beim Abrufen der POI-Typen"); + return await res.json(); +};