refactor: POI-Daten vollständig in Redux integriert

- 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
This commit is contained in:
ISA
2025-05-23 11:14:13 +02:00
parent 08679761fb
commit 0a1c0e5fbe
20 changed files with 304 additions and 337 deletions

View File

@@ -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 (
<form onSubmit={handleSubmit} className="m-0 p-2 w-full">
<div className="flex items-center mb-4">
<label htmlFor="description" className="block mr-2 flex-none">
Beschreibung:
</label>
<input type="text" id="description" name="description" value={description} onChange={(e) => setDescription(e.target.value)} placeholder="Beschreibung 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">
{locationDeviceData.map(
(device, index) => (
console.log("device.id und name:", device),
(
<option key={index} value={device.id}>
{device.name}
</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(e.target.value)} className="block p-2 w-full border-2 border-gray-200 rounded-md text-sm">
{poiTypData.map((poiTyp, index) => (
<option key={index} value={poiTyp.idPoiTyp}>
{poiTyp.name}
</option>
))}
</select>
</div>
<button type="button" onClick={handleDeletePoi} className="bg-red-400 hover:bg-red-600 text-white font-bold py-2 px-4 rounded w-full mb-4">
POI löschen
</button>
<button type="submit" className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded w-full">
POI aktualisieren
</button>
</form>
);
};
export default PoiUpdateModal;

View File

@@ -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 = (

View File

@@ -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

View File

@@ -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]);
//---------------------------------------------
//--------------------------------------------

View File

@@ -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;

View File

@@ -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