fix(poi): Fehler beim Hinzufügen von POIs behoben (Modal blieb offen)

- Falsche URL im addPoiService korrigiert (/addLocation → /addPoi)
- Redux-Status wird nach erfolgreichem Hinzufügen zurückgesetzt (resetAddPoiStatus)
- Modal schließt jetzt zuverlässig nach dem Dispatch
- Ladeanzeige "Wird hinzugefügt..." verschwindet korrekt
- Version auf 1.1.176 erhöht
This commit is contained in:
ISA
2025-05-26 13:52:17 +02:00
parent ff55481273
commit cd46401f14
12 changed files with 162 additions and 81 deletions

View File

@@ -4,6 +4,31 @@ Alle bedeutenden Änderungen an diesem Projekt werden in dieser Datei dokumentie
---
[1.1.176] 2025-05-26
🐞 Fixed
Problem behoben, dass das Modal „POI hinzufügen“ nach erfolgreichem Submit nicht geschlossen wurde und die Meldung „Wird hinzugefügt…“ dauerhaft sichtbar blieb.
Ursache: Die Service-Datei addPoiService.js verwendete die falsche URL /addLocation statt /addPoi.
Die unwrap()-Verwendung im AddPOIModal.js wurde beibehalten und korrekt abgeschlossen.
✅ Clean
resetAddPoiStatus() wird jetzt direkt nach onClose() dispatcht, um Status in Redux auf idle zurückzusetzen.
Ladeindikator „Wird hinzugefügt...“ wird zuverlässig entfernt.
Fehleranzeige funktioniert weiterhin über Redux (status === "failed" und error).
🧠 Architektur
Vollständige Redux-Anbindung des Modals über addPoiSlice, addPoiThunk, addPoiService und addPoi.js.
Thunk-Erfolg löst incrementTrigger() aus und synchronisiert die Marker auf der Karte durch erneutes Laden via fetchPoiMarkersThunk().
🔧 Version
📦 Version erhöht auf 1.1.176
---
[1.1.174] 2025-05-26
♻️ Refactor
useDrawLines.js vollständig auf Redux umgestellt:

View File

@@ -116,13 +116,24 @@ redux/ → globale Zustände (Slices)
📦redux
┣ 📂slices
┃ ┣ 📂database
┃ ┃ ┣ 📜addPoiSlice.js
┃ ┃ ┣ 📜gisLinesSlice.js
┃ ┃ ┣ 📂pois
┃ ┃ ┣ 📜addPoiOnPolylineSlice.js
┃ ┃ ┃ ┣ 📜addPoiSlice.js
┃ ┃ ┃ ┣ 📜currentPoiSlice.js
┃ ┃ ┃ ┣ 📜poiIconsDataSlice.js
┃ ┃ ┃ ┣ 📜poiLayerVisibleSlice.js
┃ ┃ ┃ ┣ 📜poiReadFromDbTriggerSlice.js
┃ ┃ ┃ ┣ 📜poiTypesSlice.js
┃ ┃ ┃ ┣ 📜poiTypSlice.js
┃ ┃ ┃ ┣ 📜readPoiMarkersStoreSlice.js
┃ ┃ ┃ ┗ 📜selectedPoiSlice.js
┃ ┃ ┣ 📂polylines
┃ ┃ ┃ ┣ 📜gisLinesSlice.js
┃ ┃ ┃ ┣ 📜polylineContextMenuSlice.js
┃ ┃ ┃ ┣ 📜polylineEventsDisabledSlice.js
┃ ┃ ┃ ┗ 📜polylineLayerVisibleSlice.js
┃ ┃ ┣ 📜locationDevicesFromDBSlice.js
┃ ┃ ┣ 📜locationDevicesSlice.js
┃ ┃ ┣ 📜poiIconsDataSlice.js
┃ ┃ ┣ 📜poiTypesSlice.js
┃ ┃ ┣ 📜poiTypSlice.js
┃ ┃ ┗ 📜priorityConfigSlice.js
┃ ┣ 📂webservice
┃ ┃ ┣ 📜gisLinesStatusSlice.js
@@ -131,29 +142,25 @@ redux/ → globale Zustände (Slices)
┃ ┃ ┣ 📜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
┃ ┃ ┣ 📂pois
┃ ┃ ┣ 📜addPoiThunk.js
┃ ┃ ┃ ┣ 📜deletePoiThunk.js
┃ ┃ ┃ ┣ 📜fetchPoiIconsDataThunk.js
┃ ┃ ┃ ┣ 📜fetchPoiTypThunk.js
┃ ┃ ┃ ┗ 📜updatePoiThunk.js
┃ ┃ ┣ 📂polylines
┃ ┃ ┃ ┗ 📜fetchGisLinesThunk.js
┃ ┃ ┣ 📜fetchLocationDevicesThunk.js
┃ ┃ ┣ 📜fetchPoiIconsDataThunk.js
┃ ┃ 📜fetchPoiTypThunk.js
┃ ┃ ┗ 📜fetchPriorityConfigThunk.js
┃ ┃ ┣ 📜fetchPriorityConfigThunk.js
┃ ┃ 📜getDeviceIdByNameThunk.js
┃ ┗ 📂webservice
┃ ┃ ┣ 📜fetchGisLinesStatusThunk.js
┃ ┃ ┣ 📜fetchGisStationsMeasurementsThunk.js
@@ -166,15 +173,20 @@ redux/ → globale Zustände (Slices)
services/ → API-Kommunikation, Mock-Logik
📦services
┣ 📂database
┃ ┣ 📜addPoiService.js
┃ ┣ 📂pois
┃ ┃ ┣ 📜addPoiService.js
┃ ┃ ┣ 📜deletePoiService.js
┃ ┃ ┣ 📜fetchPoiDataByIdService.js
┃ ┃ ┣ 📜fetchPoiDataService.js
┃ ┃ ┣ 📜fetchPoiIconsDataService.js
┃ ┃ ┣ 📜fetchPoiTypService.js
┃ ┃ ┗ 📜updatePoiService.js
┃ ┣ 📂polylines
┃ ┃ ┗ 📜fetchGisLinesService.js
┃ ┣ 📜fetchDeviceNameByIdService.js
┃ ┣ 📜fetchGisLinesService.js
┃ ┣ 📜fetchLocationDevicesService.js
┃ ┣ 📜fetchPoiDataByIdService.js
┃ ┣ 📜fetchPoiDataService.js
┃ ┣ 📜fetchPoiIconsDataService.js
┃ ┣ 📜fetchPoiTypService.js
┃ ┣ 📜fetchPriorityConfigService.js
┃ ┣ 📜getDeviceIdByNameService.js
┃ ┗ 📜updateLocationInDatabaseService.js
┣ 📂utils
┃ ┗ 📜fetchWithTimeout.js

View File

@@ -5,6 +5,7 @@ import { selectGisStationsStaticDistrict } from "../../redux/slices/webservice/g
import { fetchPoiTypes } from "../../redux/slices/database/pois/poiTypesSlice";
import { incrementTrigger } from "../../redux/slices/database/pois/poiReadFromDbTriggerSlice";
import { addPoiThunk } from "../../redux/thunks/database/pois/addPoiThunk";
import { resetAddPoiStatus } from "../../redux/slices/database/pois/addPoiSlice";
import { fetchPoiIconsDataThunk } from "../../redux/thunks/database/pois/fetchPoiIconsDataThunk";
const AddPOIModal = ({ onClose, map, latlng }) => {
@@ -54,9 +55,10 @@ const AddPOIModal = ({ onClose, map, latlng }) => {
try {
await dispatch(addPoiThunk(formData)).unwrap();
dispatch(incrementTrigger());
dispatch(resetAddPoiStatus()); // ✅ Status zurücksetzen
onClose();
// Icons im Hintergrund nachladen (nicht blockierend)
// Icons im Hintergrund nachladen
setTimeout(() => {
dispatch(fetchPoiIconsDataThunk());
}, 100);
@@ -123,7 +125,7 @@ const AddPOIModal = ({ onClose, map, latlng }) => {
</div>
{status === "loading" && <div className="text-blue-500 mb-2 text-sm">Wird hinzugefügt...</div>}
{status === "failed" && error && <div className="text-red-500 mb-2 text-sm">Fehler: {error}</div>}
{status === "failed" && error && <div className="text-red-500 mb-2 text-sm"> Fehler: {error}</div>}
<button type="submit" className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded w-full">
POI hinzufügen

View File

@@ -1,2 +1,2 @@
// /config/appVersion
export const APP_VERSION = "1.1.175";
export const APP_VERSION = "1.1.177";

View File

@@ -1,4 +1,4 @@
// pages/api/talas_v5_DB/pois/addLocation.js
// pages/api/talas_v5_DB/pois/addPoi.js
import getPool from "../../../../utils/mysqlPool"; // Singleton-Pool importieren
export default async function handler(req, res) {

View File

@@ -1,4 +1,4 @@
// pages/api/talas_v5_DB/pois/readLocations.js
// pages/api/talas_v5_DB/pois/readAllPOIs.js
import getPool from "../../../../utils/mysqlPool"; // Singleton-Pool importieren
export default async function handler(req, res) {

View File

@@ -1,84 +1,66 @@
"use client";
import React, { useEffect, useState } from "react";
import dynamic from "next/dynamic";
import { setPoiMarkers } from "../redux/slices/database/pois/readPoiMarkersStoreSlice.js";
import { useSelector, useDispatch } from "react-redux";
import { fetchPoiMarkersThunk } from "../redux/thunks/database/pois/fetchPoiMarkersThunk";
import { addPoiThunk } from "../redux/thunks/database/pois/addPoiThunk";
import { selectPoiMarkers } from "../redux/slices/database/pois/poiMarkersSlice";
import { selectAddPoiStatus, selectAddPoiError } from "../redux/slices/database/pois/addPoiSlice";
const MapComponentWithNoSSR = dynamic(() => import("../components/mainComponent/MapComponent"), { ssr: false });
const TestScriptWithNoSSR = dynamic(() => import("../components/TestScript"), { ssr: false });
export default function Home() {
const poiReadTrigger = useSelector((state) => state.poiReadFromDbTrigger.trigger);
const dispatch = useDispatch();
const locations = useSelector((state) => state.readPoiMarkersStore.poiMarkers);
// Redux State
const locations = useSelector(selectPoiMarkers);
const poiReadTrigger = useSelector((state) => state.poiReadFromDbTrigger.trigger);
const addPoiStatus = useSelector(selectAddPoiStatus);
const addPoiError = useSelector(selectAddPoiError);
// Lokale State (für URL-Parameter)
const [mParam, setMParam] = useState("");
const [uParam, setUParam] = useState("");
// Daten abrufen
const loadData = async () => {
try {
const response = await fetch("/api/talas_v5_DB/pois/readLocations");
if (!response.ok) {
throw new Error("Fehler beim Laden der Standortdaten");
}
const data = await response.json();
dispatch(setPoiMarkers(data));
} catch (error) {
console.error(error.message);
}
};
// Verhindert mehrfaches Laden durch doppelte Registrierung
// URL-Parameter auslesen und POIs laden
useEffect(() => {
let isMounted = true;
function getURLParameter(name) {
const getURLParameter = (name) => {
const params = new URLSearchParams(window.location.search);
return params.get(name);
}
};
setMParam(getURLParameter("m"));
setUParam(getURLParameter("u"));
const fetchData = async () => {
await loadData();
};
dispatch(fetchPoiMarkersThunk());
}, [dispatch, poiReadTrigger]);
if (isMounted) {
fetchData();
}
// POI hinzufügen über Redux-Thunk
const handleAddLocation = async (name, poiTypeId, lat, lng) => {
const idLD = 0; // ⬅️ Falls IDLD dynamisch bestimmt werden soll, anpassen
const formData = { name, poiTypeId, latitude: lat, longitude: lng, idLD };
return () => {
isMounted = false;
};
}, [poiReadTrigger]); // Nur einmal bei Änderung von poiReadTrigger ausführen
// POI hinzufügen
const handleAddLocation = async (name, type, lat, lng) => {
try {
const response = await fetch("/api/talas_v5_DB/pois/addLocation", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ name, type, latitude: lat, longitude: lng }),
});
if (!response.ok) {
throw new Error("Fehler beim Hinzufügen des Standorts");
const resultAction = await dispatch(addPoiThunk(formData));
if (addPoiThunk.fulfilled.match(resultAction)) {
dispatch(fetchPoiMarkersThunk()); // neu laden
} else {
console.error("❌ Fehler beim Hinzufügen:", resultAction.payload);
}
loadData();
} catch (error) {
console.error(error.message);
console.error("❌ Fehler im addPoiThunk:", error.message);
}
};
// Standort aktualisieren
const handleLocationUpdate = (id, newLatitude, newLongitude) => {
setLocations((prevLocations) => prevLocations.map((location) => (location.idPoi === id ? { ...location, position: `POINT(${newLongitude} ${newLatitude})` } : location)));
};
return (
<div>
<MapComponentWithNoSSR locations={locations} onAddLocation={handleAddLocation} onLocationUpdate={handleLocationUpdate} />
<MapComponentWithNoSSR locations={locations} onAddLocation={handleAddLocation} />
<TestScriptWithNoSSR />
{addPoiStatus === "failed" && <p className="text-red-600"> Fehler: {addPoiError}</p>}
</div>
);
}

View File

@@ -0,0 +1,44 @@
// /redux/slices/database/pois/poiMarkersSlice.js
import { createSlice } from "@reduxjs/toolkit";
import { fetchPoiMarkersThunk } from "../../../thunks/database/pois/fetchPoiMarkersThunk";
const initialState = {
data: [],
status: "idle",
error: null,
};
const poiMarkersSlice = createSlice({
name: "poiMarkers",
initialState,
reducers: {
setPoiMarkers: (state, action) => {
state.data = action.payload;
},
clearPoiMarkers: (state) => {
state.data = [];
},
},
extraReducers: (builder) => {
builder
.addCase(fetchPoiMarkersThunk.pending, (state) => {
state.status = "loading";
})
.addCase(fetchPoiMarkersThunk.fulfilled, (state, action) => {
state.status = "succeeded";
state.data = action.payload;
})
.addCase(fetchPoiMarkersThunk.rejected, (state, action) => {
state.status = "failed";
state.error = action.error.message;
});
},
});
export const { setPoiMarkers, clearPoiMarkers } = poiMarkersSlice.actions;
export const selectPoiMarkers = (state) => state.poiMarkers.data;
export const selectPoiMarkersStatus = (state) => state.poiMarkers.status;
export const selectPoiMarkersError = (state) => state.poiMarkers.error;
export default poiMarkersSlice.reducer;

View File

@@ -11,6 +11,7 @@ import selectedPoiReducer from "./slices/database/pois/selectedPoiSlice";
import currentPoiReducer from "./slices/database/pois/currentPoiSlice";
import poiReadFromDbTriggerReducer from "./slices/database/pois/poiReadFromDbTriggerSlice";
import readPoiMarkersStoreReducer from "./slices/database/pois/readPoiMarkersStoreSlice";
import poiMarkersReducer from "./slices/database/pois/poiMarkersSlice";
//--polylines------------
import gisLinesFromDatabaseReducer from "./slices/database/polylines/gisLinesSlice";
import polylineLayerVisibleReducer from "./slices/database/polylines/polylineLayerVisibleSlice";
@@ -66,5 +67,6 @@ export const store = configureStore({
addPoi: addPoiReducer,
poiTyp: poiTypReducer,
poiIconsData: poiIconsDataReducer,
poiMarkers: poiMarkersReducer,
},
});

View File

@@ -0,0 +1,8 @@
// /redux/thunks/database/pois/fetchPoiMarkersThunk.js
import { createAsyncThunk } from "@reduxjs/toolkit";
import { fetchPoiMarkersService } from "../../../../services/database/pois/fetchPoiMarkersService";
// Einheitlicher Name passend zur Slice-Datei
export const fetchPoiMarkersThunk = createAsyncThunk("poiMarkers/fetchAll", async () => {
return await fetchPoiMarkersService();
});

View File

@@ -1,6 +1,6 @@
// /services/database/addPoiService.js
export const addPoiService = async (formData) => {
const response = await fetch("/api/talas_v5_DB/pois/addLocation", {
const response = await fetch("/api/talas_v5_DB/pois/addPoi", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(formData),

View File

@@ -0,0 +1,6 @@
// /services/database/pois/fetchPoiMarkersService.js
export const fetchPoiMarkersService = async () => {
const response = await fetch("/api/talas_v5_DB/pois/readAllPOIs");
if (!response.ok) throw new Error("Fehler beim Laden der POIs");
return await response.json();
};