Gängige Praxis: *Slice.js Verwendung: Wenn du Redux Toolkit und createSlice nutzt, ist der Postfix Slice gängiger. Begründung: createSlice ist ein Begriff aus Redux Toolkit. Der Name vermittelt, dass die Datei nicht nur den Reducer enthält, sondern auch Aktionen und den initialen Zustand. Häufig in modernen Projekten verwendet.
257 lines
9.6 KiB
JavaScript
257 lines
9.6 KiB
JavaScript
// /components/pois/PoiUpdateModal.js
|
|
import React, { useState, useEffect } from "react";
|
|
import Select from "react-select"; // Importiere react-select
|
|
import { useRecoilState } from "recoil";
|
|
import { selectedPoiState } from "../../redux/slices/selectedPoiSlice";
|
|
import { currentPoiState } from "../../redux/slices/currentPoiSlice";
|
|
import { mapLayersState } from "../../redux/slices/mapLayersSlice";
|
|
|
|
const PoiUpdateModal = ({ onClose, poiData, onSubmit }) => {
|
|
const currentPoi = useRecoilState(currentPoiState);
|
|
const selectedPoi = useRecoilState(selectedPoiState);
|
|
const [mapLayersVisibility] = useRecoilState(mapLayersState);
|
|
|
|
const [poiId, setPoiId] = useState(poiData ? poiData.idPoi : "");
|
|
const [name, setName] = useState(poiData ? poiData.name : "");
|
|
const [poiTypData, setPoiTypData] = useState([]);
|
|
const [poiTypeId, setPoiTypeId] = useState(null); // Verwende null für react-select
|
|
const [locationDeviceData, setLocationDeviceData] = useState([]);
|
|
const [filteredDevices, setFilteredDevices] = useState([]);
|
|
const [deviceName, setDeviceName] = useState(poiData ? poiData.deviceName : null); // Verwende null für react-select
|
|
const [idLD, setIdLD] = useState(poiData ? poiData.idLD : "");
|
|
const [description, setDescription] = useState(poiData ? poiData.description : "");
|
|
|
|
// Map von Systemnamen zu IDs (wie zuvor)
|
|
const systemNameToIdMap = {
|
|
TALAS: 1,
|
|
ECI: 2,
|
|
ULAF: 3,
|
|
GSMModem: 5,
|
|
CiscoRouter: 6,
|
|
WAGO: 7,
|
|
Siemens: 8,
|
|
OTDR: 9,
|
|
WDM: 10,
|
|
GMA: 11,
|
|
Messdatensammler: 12,
|
|
Messstellen: 13,
|
|
TALASICL: 100,
|
|
DAUZ: 110,
|
|
SMSFunkmodem: 111,
|
|
Basisgerät: 200,
|
|
};
|
|
|
|
useEffect(() => {
|
|
if (poiData) {
|
|
setPoiId(poiData.idPoi);
|
|
setName(poiData.name);
|
|
setPoiTypeId(poiData.idPoiTyp); // Setze den Typ-ID
|
|
setIdLD(poiData.idLD);
|
|
setDescription(poiData.description);
|
|
}
|
|
}, [poiData]);
|
|
|
|
// Fetch POI types and set the current POI type in the react-select dropdown
|
|
useEffect(() => {
|
|
const fetchPoiTypData = async () => {
|
|
try {
|
|
const response = await fetch("/api/talas_v5_DB/poiTyp/readPoiTyp");
|
|
const data = await response.json();
|
|
setPoiTypData(data);
|
|
|
|
// Prüfe den gespeicherten Typ im localStorage
|
|
const storedPoiType = localStorage.getItem("selectedPoiType");
|
|
|
|
// Finde den passenden Typ in den abgerufenen Daten und setze ihn als ausgewählt
|
|
if (storedPoiType) {
|
|
const matchingType = data.find((type) => type.name === storedPoiType);
|
|
if (matchingType) {
|
|
setPoiTypeId({ value: matchingType.idPoiTyp, label: matchingType.name });
|
|
}
|
|
} else if (poiData && poiData.idPoiTyp) {
|
|
// Falls kein Typ im localStorage ist, setze den Typ von poiData
|
|
const matchingType = data.find((type) => type.idPoiTyp === poiData.idPoiTyp);
|
|
if (matchingType) {
|
|
setPoiTypeId({ value: matchingType.idPoiTyp, label: matchingType.name });
|
|
}
|
|
}
|
|
} catch (error) {
|
|
console.error("Fehler beim Abrufen der poiTyp Daten:", error);
|
|
}
|
|
};
|
|
fetchPoiTypData();
|
|
}, [poiData]);
|
|
|
|
// Fetch location devices and pre-select the current device
|
|
useEffect(() => {
|
|
const fetchLocationDevices = async () => {
|
|
try {
|
|
const response = await fetch("/api/talas5/location_device");
|
|
const data = await response.json();
|
|
setLocationDeviceData(data);
|
|
filterDevices(data);
|
|
|
|
if (poiData && poiData.idLD) {
|
|
const selectedDevice = data.find((device) => device.idLD === poiData.idLD);
|
|
setDeviceName(selectedDevice ? { value: selectedDevice.name, label: selectedDevice.name } : null);
|
|
}
|
|
} catch (error) {
|
|
console.error("Fehler beim Abrufen der Standort- und Gerätedaten:", error);
|
|
}
|
|
};
|
|
fetchLocationDevices();
|
|
}, [poiData]);
|
|
|
|
// Funktion zum Filtern der Geräte basierend auf den aktiven Systemen (Layern)
|
|
const filterDevices = (devices) => {
|
|
const activeSystems = Object.keys(mapLayersVisibility).filter((system) => mapLayersVisibility[system]);
|
|
|
|
// Mappe aktive Systeme auf ihre ids
|
|
const activeSystemIds = activeSystems.map((system) => systemNameToIdMap[system]).filter((id) => id !== undefined);
|
|
|
|
// Filtere die Geräte nach aktiven Systemen basierend auf idsystem_typ
|
|
const filtered = devices.filter((device) => activeSystemIds.includes(device.idsystem_typ));
|
|
setFilteredDevices(filtered);
|
|
};
|
|
|
|
const handleSubmit = async (event) => {
|
|
event.preventDefault();
|
|
const idLDResponse = await fetch(`/api/talas_v5_DB/locationDevice/getDeviceId?deviceName=${encodeURIComponent(deviceName?.value)}`);
|
|
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?.value, // Den ausgewählten Typ mitsenden
|
|
idLD: idLD,
|
|
}),
|
|
});
|
|
|
|
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.");
|
|
}
|
|
};
|
|
|
|
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) {
|
|
onClose();
|
|
window.location.reload(); // Aktualisiert die Seite nach dem Löschen
|
|
} else {
|
|
throw new Error("Fehler beim Löschen des POI.");
|
|
}
|
|
} catch (error) {
|
|
console.error("Fehler beim Löschen des POI:", error);
|
|
alert("Fehler beim Löschen des POI.");
|
|
}
|
|
}
|
|
};
|
|
|
|
// Erstelle Optionen für react-select
|
|
const poiTypeOptions = poiTypData.map((poiTyp) => ({
|
|
value: poiTyp.idPoiTyp,
|
|
label: poiTyp.name,
|
|
}));
|
|
|
|
const deviceOptions = filteredDevices.map((device) => ({
|
|
value: device.name,
|
|
label: device.name,
|
|
}));
|
|
|
|
// Custom styles for react-select
|
|
const customStyles = {
|
|
control: (provided) => ({
|
|
...provided,
|
|
width: "100%",
|
|
minWidth: "300px", // Minimum width for the dropdown
|
|
maxWidth: "100%", // Maximum width (you can adjust this if needed)
|
|
}),
|
|
menu: (provided) => ({
|
|
...provided,
|
|
width: "100%",
|
|
minWidth: "300px", // Ensure the dropdown menu stays at the minimum width
|
|
}),
|
|
};
|
|
|
|
return (
|
|
<div className="fixed inset-0 bg-black bg-opacity-10 flex justify-center items-center z-[1000]" onClick={onClose}>
|
|
<div className="relative bg-white p-6 rounded-lg shadow-lg" onClick={(e) => e.stopPropagation()}>
|
|
<button onClick={onClose} className="absolute top-0 right-0 mt-2 mr-2 p-1 text-gray-700 hover:text-gray-900 focus:outline-none focus:ring-2 focus:ring-gray-600" aria-label="Close">
|
|
<svg xmlns="http://www.w3.org/2000/svg" className="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
|
|
</svg>
|
|
</button>
|
|
<form onSubmit={handleSubmit} className="m-0 p-2 w-full">
|
|
<div className="flex flex-col mb-4">
|
|
<label htmlFor="description" className="block mb-2 font-bold text-sm text-gray-700">
|
|
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>
|
|
|
|
{/* React Select for Devices */}
|
|
<div className="flex flex-col mb-4">
|
|
<label htmlFor="deviceName" className="block mb-2 font-bold text-sm text-gray-700">
|
|
Gerät:
|
|
</label>
|
|
<Select
|
|
id="deviceName"
|
|
value={deviceName}
|
|
onChange={setDeviceName}
|
|
options={deviceOptions} // Options for filtering
|
|
placeholder="Gerät auswählen..."
|
|
isClearable={true} // Allow clearing the selection
|
|
styles={customStyles} // Apply custom styles
|
|
/>
|
|
</div>
|
|
|
|
{/* React Select for POI Types */}
|
|
<div className="flex flex-col mb-4">
|
|
<label htmlFor="idPoiTyp" className="block mb-2 font-bold text-sm text-gray-700">
|
|
Typ:
|
|
</label>
|
|
<Select
|
|
id="idPoiTyp"
|
|
value={poiTypeId}
|
|
onChange={setPoiTypeId}
|
|
options={poiTypeOptions} // Options for filtering
|
|
placeholder="Typ auswählen..."
|
|
isClearable={true}
|
|
styles={customStyles} // Apply custom styles
|
|
/>
|
|
</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>
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default PoiUpdateModal;
|