feat: POI-Erstellung, -Bearbeitung und -Löschung vollständig überarbeitet

- POI-Tooltip zeigt jetzt den korrekten Gerätenamen aus Redux (gisStationsStaticDistrict)
- Bearbeitungsmodal (PoiUpdateModal) verwendet Redux-Daten (idLD → Gerätelabel) zur Initialisierung
- Fix: Geräte-Dropdown im Modal zeigt nun den ausgewählten POI korrekt an
- Refactor: `handleUpdatePoi()` nutzt `description` statt `name`
- Fehlerbehandlung im Modal verbessert (alert bei leerem Feld, besseres Logging)
- Redux-Thunk `updatePoiThunk` + `updatePoiService` stabilisiert
- Map aktualisiert POIs nach Bearbeitung automatisch

📦 Version erhöht auf 1.1.253
🗓️ 11.06.2025
This commit is contained in:
ISA
2025-06-11 07:41:10 +02:00
parent 8e5dac82b5
commit 0a97c359d8
11 changed files with 76 additions and 56 deletions

View File

@@ -12,7 +12,7 @@ NEXT_PUBLIC_DEBUG_LOG=false
#auf dem Entwicklungsrechner dev läuft auf Port 3000 und auf dem Server prod auf Port 80, aber der WebService ist immer auf PORT 80 #auf dem Entwicklungsrechner dev läuft auf Port 3000 und auf dem Server prod auf Port 80, aber der WebService ist immer auf PORT 80
NEXT_PUBLIC_API_PORT_MODE=prod
NEXT_PUBLIC_USE_MOCKS=false NEXT_PUBLIC_USE_MOCKS=false
# Der Unterordner talas5 gleich hinter der IP-Adresse (oder Servername) muss konfigurierbar sein. # Der Unterordner talas5 gleich hinter der IP-Adresse (oder Servername) muss konfigurierbar sein.

View File

@@ -4,6 +4,31 @@ Alle bedeutenden Änderungen an diesem Projekt werden in dieser Datei dokumentie
--- ---
## [1.1.253] 2025-06-11
### ✨ Features
- POIs lassen sich jetzt vollständig erstellen, bearbeiten und löschen
- Tooltip zeigt den korrekten Gerätenamen (aus `gisStationsStaticDistrict`)
- Bearbeitungsdialog lädt initial die richtige Gerätezuteilung (Dropdown)
- Redux-Anbindung für `updatePoiService`, `updatePoiThunk`, `handlers.js` konsolidiert
### 🛠 Fixed
- Fehler beim Aktualisieren behoben (idLD und leeres Name-Feld)
- Dropdown im Modal zeigt jetzt korrekt das zum POI zugehörige Gerät
### 🧠 Architektur
- Kein direkter Zugriff mehr auf Name nur `description` und `idLD`
- Fehlerhandling und Zustandskontrolle über Redux (Status, Error)
### 🔧 Version
- 📦 `appVersion.js` auf Version **1.1.253** erhöht
---
## [1.1.240] 2025-06-06 ## [1.1.240] 2025-06-06
### ✨ UI-Verbesserung ### ✨ UI-Verbesserung

View File

@@ -86,17 +86,16 @@ umgesetzt.
2. **ZIP-Paket vorbereiten (lokal):** 2. **ZIP-Paket vorbereiten (lokal):**
- Verzeichnis `.next/` - Verzeichnis `.next/`
- Verzeichnisse `public/`, `node_modules/` falls nich vorhanden sind oder etwas hinzugefügt wurd - Verzeichnisse `public/`, `node_modules/` falls nicht vorhanden sind oder etwas hinzugefügt
(Bilder oder Bibliothek) wurde (Bilder oder Bibliothek)
- Dateien `.env.production`, `package.json` falls nich vorhanden sind oder etwas hinzugefügt wurd - Dateien `.env.production`, `package.json` falls nicht vorhanden sind oder etwas hinzugefügt
(Umgebungsvariablen oder Bibliothek) wurde (Umgebungsvariablen oder Bibliothek)
- optional: `nssm.exe`, `StartNodeApp.bat`, `Start-Dev.ps1` um Windows Dienst zu erstellen falls - `nssm.exe`, `StartNodeApp.bat`, `Start-Dev.ps1` um Windows Dienst zu erstellen falls noch nicht
noch nicht vorhanden ist Download: vorhanden ist Download:
[nssm](https://littwinsystemtechnik.sharepoint.com/:f:/r/sites/LittwinSystemtechnik/Freigegebene%20Dokumente/Projekte/Masterkarte%20V2%20setup%20files?csf=1&web=1&e=Sm1wwt) [nssm](https://littwinsystemtechnik.sharepoint.com/:f:/r/sites/LittwinSystemtechnik/Freigegebene%20Dokumente/Projekte/Masterkarte%20V2%20setup%20files?csf=1&web=1&e=Sm1wwt)
3. **Auf Server kopieren nach:** Ein Ordner temp auf dem Desktop erstellen->ZIP-Paket 3. **Auf Server kopieren nach:** Ein Ordner temp auf dem Desktop erstellen->ZIP-Paket
einfügen->entpacken->Inhalt in folgende Verzeichnis einfügen, weil verhindert Windows Server einfügen->entpacken->Inhalt in folgende Verzeichnis einfügen
direkt kopieren in folgende Verzeichnis
``` ```
C:\inetpub\wwwroot\talas5\nodeMap\ C:\inetpub\wwwroot\talas5\nodeMap\

View File

@@ -48,5 +48,6 @@
optimiert besser als setInterval, zuerst nur für TALAS.web WebServices erstellen, irgendwann soll optimiert besser als setInterval, zuerst nur für TALAS.web WebServices erstellen, irgendwann soll
die Daten von DB auch mit WebSocket gelöst werden die Daten von DB auch mit WebSocket gelöst werden
- [ ] TODO: POI bearbeiten funktioniert es nicht - [x] TODO: POI bearbeiten funktioniert es nicht
- [ ] TODO: Linien Links noch mit Port 3000 - [ ] TODO: Linien Links noch mit Port 3000
- [ ] TODO: Checkliste für README.md vorbereiten

View File

@@ -8,7 +8,6 @@ import { selectMapLayersState } from "@/redux/slices/mapLayersSlice";
import { selectPoiTypData, selectPoiTypStatus } from "@/redux/slices/database/pois/poiTypSlice"; import { selectPoiTypData, selectPoiTypStatus } from "@/redux/slices/database/pois/poiTypSlice";
import { deletePoiThunk } from "@/redux/thunks/database/pois/deletePoiThunk"; import { deletePoiThunk } from "@/redux/thunks/database/pois/deletePoiThunk";
import { updatePoiThunk } from "@/redux/thunks/database/pois/updatePoiThunk"; import { updatePoiThunk } from "@/redux/thunks/database/pois/updatePoiThunk";
import { selectSelectedPoi } from "@/redux/slices/database/pois/selectedPoiSlice";
import { handleSubmit } from "@/components/pois/poiUpdateModal/utils/handlers"; import { handleSubmit } from "@/components/pois/poiUpdateModal/utils/handlers";
import { selectCurrentPoi } from "@/redux/slices/database/pois/currentPoiSlice"; import { selectCurrentPoi } from "@/redux/slices/database/pois/currentPoiSlice";
import { selectGisStationsStaticDistrict } from "@/redux/slices/webservice/gisStationsStaticDistrictSlice"; import { selectGisStationsStaticDistrict } from "@/redux/slices/webservice/gisStationsStaticDistrictSlice";
@@ -56,17 +55,6 @@ const PoiUpdateModal = ({ onClose, poiData }) => {
} }
}, [dispatch, poiTypStatus]); }, [dispatch, poiTypStatus]);
/* useEffect(() => {
console.log("devices in PoiUpdateModal:", devices);
if (poi && devices.length > 0) {
const selectedDevice = devices.find(device => Number(device.idLD) === Number(poi.idLD));
console.log("Selected Device:", selectedDevice);
if (selectedDevice) {
setDeviceName({ value: selectedDevice.idLD, label: selectedDevice.name });
}
}
}, [poi, devices]); */
useEffect(() => { useEffect(() => {
console.log("poiTypData in PoiUpdateModal:", poiTypData); console.log("poiTypData in PoiUpdateModal:", poiTypData);
if (poi && poiTypData.length > 0) { if (poi && poiTypData.length > 0) {
@@ -80,13 +68,13 @@ const PoiUpdateModal = ({ onClose, poiData }) => {
useEffect(() => { useEffect(() => {
console.log("availableDevices in PoiUpdateModal:", availableDevices); console.log("availableDevices in PoiUpdateModal:", availableDevices);
if (poiData && availableDevices.length > 0) { if (poi && availableDevices.length > 0) {
const selectedDevice = availableDevices.find(device => device.idLD === poiData.idLD); const selectedDevice = availableDevices.find(device => device.IdLD === poi.idLD);
if (selectedDevice) { if (selectedDevice) {
setDeviceName({ value: selectedDevice.idLD, label: selectedDevice.LD_Name }); // ✅ auch hier korrigieren setDeviceName({ value: selectedDevice.IdLD, label: selectedDevice.LD_Name });
} }
} }
}, [poiData, availableDevices]); }, [poi, availableDevices]);
const filterDevices = () => { const filterDevices = () => {
const activeSystems = Object.keys(mapLayersVisibility).filter( const activeSystems = Object.keys(mapLayersVisibility).filter(
@@ -106,7 +94,7 @@ const PoiUpdateModal = ({ onClose, poiData }) => {
: []; : [];
const deviceOptions = availableDevices.map(device => ({ const deviceOptions = availableDevices.map(device => ({
value: device.idLD, value: device.IdLD,
label: device.LD_Name, label: device.LD_Name,
})); }));
@@ -153,7 +141,22 @@ const PoiUpdateModal = ({ onClose, poiData }) => {
/> />
</svg> </svg>
</button> </button>
<form onSubmit={handleSubmit} className="m-0 p-2 w-full"> <form
onSubmit={event =>
handleSubmit({
event,
dispatch,
poiId,
name,
description,
poiTypeId,
deviceName,
poi,
onClose,
})
}
className="m-0 p-2 w-full"
>
<div className="flex flex-col mb-4"> <div className="flex flex-col mb-4">
<label htmlFor="description" className="block mb-2 font-bold text-sm text-gray-700"> <label htmlFor="description" className="block mb-2 font-bold text-sm text-gray-700">
Beschreibung: Beschreibung:

View File

@@ -1,8 +1,11 @@
// @/components/pois/poiUpdateModal/utils/handlers.js
import { updatePoiThunk } from "@/redux/thunks/database/pois/updatePoiThunk";
import { deletePoiThunk } from "@/redux/thunks/database/pois/deletePoiThunk";
export const handleSubmit = async ({ export const handleSubmit = async ({
event, event,
dispatch, dispatch,
poiId, poiId,
name,
description, description,
poiTypeId, poiTypeId,
deviceName, deviceName,
@@ -10,16 +13,18 @@ export const handleSubmit = async ({
onClose, onClose,
}) => { }) => {
event.preventDefault(); event.preventDefault();
const payload = {
idPoi: poiId,
name: description, // 💡 <- Das ist die entscheidende Änderung!
description,
idPoiTyp: poiTypeId?.value ?? poi?.idPoiTyp,
idLD: deviceName?.value,
};
console.log("🔍 POI Update Payload:", payload);
try { try {
await dispatch( await dispatch(updatePoiThunk(payload)).unwrap();
updatePoiThunk({
idPoi: poiId,
name,
description,
idPoiTyp: poiTypeId?.value ?? poi?.idPoiTyp,
idLD: deviceName?.value,
})
).unwrap();
onClose(); onClose();
window.location.reload(); window.location.reload();
} catch (error) { } catch (error) {

View File

@@ -1,2 +1,2 @@
// /config/appVersion // /config/appVersion
export const APP_VERSION = "1.1.253"; export const APP_VERSION = "1.1.254";

View File

@@ -1,10 +1,6 @@
// pages/api/[...path].js // pages/api/[...path].js
import { createProxyMiddleware } from "http-proxy-middleware"; import { createProxyMiddleware } from "http-proxy-middleware";
const mode = process.env.NEXT_PUBLIC_API_PORT_MODE;
const target = mode === "dev" ? "http://localhost:80" : "http://localhost";
export default createProxyMiddleware({ export default createProxyMiddleware({
target, target,
changeOrigin: true, changeOrigin: true,

View File

@@ -115,7 +115,7 @@ app.prepare().then(() => {
// fetchData immer ausführen unabhängig vom Modus // fetchData immer ausführen unabhängig vom Modus
fetchData(); fetchData();
const interval = setInterval(fetchData, 5000); const interval = setInterval(fetchData, 12000); // 12 Sekunden ,TALAS.web nutzt auch 12 Sekunden
socket.on("disconnect", () => { socket.on("disconnect", () => {
clearInterval(interval); clearInterval(interval);
console.log("❌ WebSocket getrennt"); console.log("❌ WebSocket getrennt");

View File

@@ -1,6 +1,5 @@
// /services/database/updatePoiService.js // /services/database/updatePoiService.js
export const updatePoiService = async poi => {
export const updatePoiService = async (poi) => {
const response = await fetch("/api/talas_v5_DB/pois/updatePoi", { const response = await fetch("/api/talas_v5_DB/pois/updatePoi", {
method: "POST", method: "POST",
headers: { headers: {

View File

@@ -227,11 +227,7 @@ export const setupPolylines = (
callback: e => { callback: e => {
const mode = process.env.NEXT_PUBLIC_API_PORT_MODE; const mode = process.env.NEXT_PUBLIC_API_PORT_MODE;
const baseUrl = const baseUrl = `${window.location.protocol}//${window.location.hostname}:80${basePath}/`;
mode === "dev"
? `${window.location.protocol}//${window.location.hostname}:80${basePath}/`
: `${window.location.origin}${basePath}/`;
const link = `${baseUrl}devices/cpl.aspx?ver=35&kue=24&id=${lineData.idLD}`; const link = `${baseUrl}devices/cpl.aspx?ver=35&kue=24&id=${lineData.idLD}`;
window.open(link, "_blank"); window.open(link, "_blank");
@@ -291,11 +287,7 @@ export const setupPolylines = (
polyline.setStyle({ weight: 14 }); polyline.setStyle({ weight: 14 });
const mode = process.env.NEXT_PUBLIC_API_PORT_MODE; const mode = process.env.NEXT_PUBLIC_API_PORT_MODE;
const baseUrl = const baseUrl = `${window.location.protocol}//${window.location.hostname}:80${basePath}/`;
mode === "dev"
? `${window.location.protocol}//${window.location.hostname}:80${basePath}/`
: `${window.location.origin}${basePath}/`;
const link = `${baseUrl}cpl.aspx?ver=35&kue=24&id=${lineData.idLD}`; const link = `${baseUrl}cpl.aspx?ver=35&kue=24&id=${lineData.idLD}`;
}); });
// error TypeError: Cannot read properties of null (reading 'contextmenu') wenn der Mas auf die Linie bleibt // error TypeError: Cannot read properties of null (reading 'contextmenu') wenn der Mas auf die Linie bleibt