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:
25
CHANGELOG.md
25
CHANGELOG.md
@@ -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:
|
||||
|
||||
62
README.md
62
README.md
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
// /config/appVersion
|
||||
export const APP_VERSION = "1.1.175";
|
||||
export const APP_VERSION = "1.1.177";
|
||||
|
||||
@@ -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) {
|
||||
@@ -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) {
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
|
||||
44
redux/slices/database/pois/poiMarkersSlice.js
Normal file
44
redux/slices/database/pois/poiMarkersSlice.js
Normal 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;
|
||||
@@ -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,
|
||||
},
|
||||
});
|
||||
|
||||
8
redux/thunks/database/pois/fetchPoiMarkersThunk.js
Normal file
8
redux/thunks/database/pois/fetchPoiMarkersThunk.js
Normal 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();
|
||||
});
|
||||
@@ -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),
|
||||
|
||||
6
services/database/pois/fetchPoiMarkersService.js
Normal file
6
services/database/pois/fetchPoiMarkersService.js
Normal 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();
|
||||
};
|
||||
Reference in New Issue
Block a user