Merge branch 'develop'
This commit is contained in:
@@ -5,58 +5,75 @@ import { gisSystemStaticState } from "../store/atoms/gisSystemState";
|
||||
import { mapLayersState } from "../store/atoms/mapLayersState";
|
||||
import { selectedAreaState } from "../store/atoms/selectedAreaState";
|
||||
import { zoomTriggerState } from "../store/atoms/zoomTriggerState";
|
||||
import { poiLayerVisibleState } from "../store/atoms/poiLayerVisible";
|
||||
import { poiLayerVisibleState } from "../store/atoms/poiLayerVisibleState";
|
||||
import EditModeToggle from "./EditModeToggle";
|
||||
import { polylineLayerVisibleState } from "../store/atoms/polylineLayerVisibleState"; // Import für Polyline-Visibility
|
||||
|
||||
function DataSheet() {
|
||||
const [poiVisible, setPoiVisible] = useRecoilState(poiLayerVisibleState);
|
||||
const setSelectedArea = useSetRecoilState(selectedAreaState);
|
||||
const [mapLayersVisibility, setMapLayersVisibility] =
|
||||
useRecoilState(mapLayersState);
|
||||
const [mapLayersVisibility, setMapLayersVisibility] = useRecoilState(mapLayersState);
|
||||
const [stationListing, setStationListing] = useState([]);
|
||||
const [systemListing, setSystemListing] = useState([]);
|
||||
const GisStationsStaticDistrict = useRecoilValue(
|
||||
gisStationsStaticDistrictState
|
||||
);
|
||||
const GisStationsStaticDistrict = useRecoilValue(gisStationsStaticDistrictState);
|
||||
const GisSystemStatic = useRecoilValue(gisSystemStaticState);
|
||||
const setZoomTrigger = useSetRecoilState(zoomTriggerState);
|
||||
const [polylineVisible, setPolylineVisible] = useRecoilState(polylineLayerVisibleState); // Zustand für Polylines
|
||||
useEffect(() => {
|
||||
const storedPoiVisible = localStorage.getItem("poiVisible");
|
||||
if (storedPoiVisible !== null) {
|
||||
setPoiVisible(storedPoiVisible === "true");
|
||||
}
|
||||
const storedPolylineVisible = localStorage.getItem("polylineVisible");
|
||||
if (storedPolylineVisible !== null) {
|
||||
setPolylineVisible(storedPolylineVisible === "true");
|
||||
}
|
||||
|
||||
const storedMapLayersVisibility = localStorage.getItem("mapLayersVisibility");
|
||||
if (storedMapLayersVisibility) {
|
||||
setMapLayersVisibility(JSON.parse(storedMapLayersVisibility));
|
||||
}
|
||||
}, [setPoiVisible, setMapLayersVisibility]);
|
||||
|
||||
const handleAreaChange = (event) => {
|
||||
const selectedIndex = event.target.options.selectedIndex;
|
||||
const areaName = event.target.options[selectedIndex].text;
|
||||
setSelectedArea(areaName);
|
||||
console.log("Area selected oder areaName in DataSheet.js:", areaName);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const allowedSystems = new Set(
|
||||
GisSystemStatic.filter((system) => system.Allow === 1).map(
|
||||
(system) => system.IdSystem
|
||||
)
|
||||
);
|
||||
const allowedSystems = new Set(GisSystemStatic.filter((system) => system.Allow === 1).map((system) => system.IdSystem));
|
||||
|
||||
const seenNames = new Set();
|
||||
const filteredAreas = GisStationsStaticDistrict.filter((item) => {
|
||||
const isUnique =
|
||||
!seenNames.has(item.Area_Name) && allowedSystems.has(item.System);
|
||||
const isUnique = !seenNames.has(item.Area_Name) && allowedSystems.has(item.System);
|
||||
if (isUnique) {
|
||||
seenNames.add(item.Area_Name);
|
||||
}
|
||||
return isUnique;
|
||||
});
|
||||
console.log("filterdArea GisStationsStaticDistrict:", filteredAreas);
|
||||
console.log("GisSystemStatic:", GisSystemStatic);
|
||||
console.log("allowedSystems:", allowedSystems);
|
||||
|
||||
setStationListing(
|
||||
filteredAreas.map((area, index) => ({
|
||||
id: index + 1,
|
||||
name: area.Area_Name,
|
||||
}))
|
||||
);
|
||||
|
||||
const seenSystemNames = new Set();
|
||||
const filteredSystems = GisSystemStatic.filter((item) => {
|
||||
const formattedName = item.Name.replace(/[\s\-]+/g, "");
|
||||
console.log(formattedName);
|
||||
const isUnique = !seenSystemNames.has(formattedName) && item.Allow === 1;
|
||||
if (isUnique) {
|
||||
seenSystemNames.add(formattedName);
|
||||
}
|
||||
return isUnique;
|
||||
});
|
||||
|
||||
setSystemListing(
|
||||
filteredSystems.map((system, index) => ({
|
||||
id: index + 1,
|
||||
@@ -67,35 +84,38 @@ function DataSheet() {
|
||||
|
||||
const handleCheckboxChange = (name, event) => {
|
||||
const { checked } = event.target;
|
||||
console.log(`Checkbox ${name} checked state:`, checked);
|
||||
|
||||
setMapLayersVisibility((prev) => {
|
||||
const newState = {
|
||||
...prev,
|
||||
[name]: checked,
|
||||
};
|
||||
console.log(`New mapLayersVisibility state:`, newState);
|
||||
localStorage.setItem("mapLayersVisibility", JSON.stringify(newState)); // Store in localStorage
|
||||
return newState;
|
||||
});
|
||||
};
|
||||
|
||||
const handlePoiCheckboxChange = (event) => {
|
||||
const { checked } = event.target;
|
||||
setPoiVisible(checked);
|
||||
localStorage.setItem("poiVisible", checked); // Store POI visibility in localStorage
|
||||
};
|
||||
|
||||
const handleIconClick = () => {
|
||||
setSelectedArea("Station wählen");
|
||||
setZoomTrigger((current) => current + 1);
|
||||
};
|
||||
const handlePolylineCheckboxChange = (event) => {
|
||||
const { checked } = event.target;
|
||||
setPolylineVisible(checked);
|
||||
localStorage.setItem("polylineVisible", checked); // Store Polyline visibility in localStorage
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
id="mainDataSheet"
|
||||
className="absolute top-3 right-3 w-1/6 min-w-[300px] z-10 bg-white p-2 rounded-lg shadow-lg"
|
||||
>
|
||||
<div id="mainDataSheet" className="absolute top-3 right-3 w-1/6 min-w-[300px] max-w-[400px] z-10 bg-white p-2 rounded-lg shadow-lg">
|
||||
<div className="flex flex-col gap-4 p-4">
|
||||
<div className="flex items-center justify-between">
|
||||
<select
|
||||
onChange={handleAreaChange}
|
||||
id="stationListing"
|
||||
className="border-solid-1 p-2 rounded ml-1 font-semibold"
|
||||
>
|
||||
<div className="flex items-center justify-between space-x-2">
|
||||
<select onChange={handleAreaChange} id="stationListing" className="border-solid-1 p-2 rounded ml-1 font-semibold" style={{ minWidth: "150px", maxWidth: "200px" }}>
|
||||
<option value="Station wählen">Station wählen</option>
|
||||
{stationListing.map((station) => (
|
||||
<option key={station.id} value={station.id}>
|
||||
@@ -103,37 +123,38 @@ function DataSheet() {
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
<img
|
||||
src="/img/expand-icon.svg"
|
||||
alt="Expand"
|
||||
className="h-6 w-6 ml-2 cursor-pointer"
|
||||
onClick={handleIconClick}
|
||||
/>
|
||||
<div className="flex items-center space-x-2">
|
||||
<EditModeToggle />
|
||||
<img src="/img/expand-icon.svg" alt="Expand" className="h-6 w-6 cursor-pointer" onClick={handleIconClick} />
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
|
||||
{/* Checkboxen in einem gemeinsamen Container */}
|
||||
<div className="flex flex-col gap-2">
|
||||
{systemListing.map((system) => (
|
||||
<React.Fragment key={system.id}>
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={mapLayersVisibility[system.name] || false}
|
||||
onChange={(e) => handleCheckboxChange(system.name, e)}
|
||||
/>
|
||||
<label className="text-sm ml-2">{system.name}</label>
|
||||
<br />
|
||||
<div className="flex items-center">
|
||||
<input type="checkbox" checked={mapLayersVisibility[system.name] || false} onChange={(e) => handleCheckboxChange(system.name, e)} id={`system-${system.id}`} />
|
||||
<label htmlFor={`system-${system.id}`} className="text-sm ml-2">
|
||||
{system.name}
|
||||
</label>
|
||||
</div>
|
||||
</React.Fragment>
|
||||
))}
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={poiVisible}
|
||||
onChange={(e) => {
|
||||
const checked = e.target.checked;
|
||||
setPoiVisible(checked);
|
||||
console.log(
|
||||
`POIs sind jetzt ${checked ? "sichtbar" : "nicht sichtbar"}.`
|
||||
);
|
||||
}}
|
||||
/>
|
||||
<label className="text-sm ml-2">POIs</label>
|
||||
|
||||
<div className="flex items-center">
|
||||
<input type="checkbox" checked={poiVisible} onChange={handlePoiCheckboxChange} id="poi-checkbox" />
|
||||
<label htmlFor="poi-checkbox" className="text-sm ml-2">
|
||||
POIs
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center">
|
||||
<input type="checkbox" checked={polylineVisible} onChange={handlePolylineCheckboxChange} id="polyline-checkbox" />
|
||||
<label htmlFor="polyline-checkbox" className="text-sm ml-2">
|
||||
Kabelstrecken
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
38
components/EditModeToggle.js
Normal file
38
components/EditModeToggle.js
Normal file
@@ -0,0 +1,38 @@
|
||||
// /components/EditModeToggle.js
|
||||
import React, { useState, useEffect } from "react";
|
||||
import EditOffIcon from "@mui/icons-material/EditOff";
|
||||
import ModeEditIcon from "@mui/icons-material/ModeEdit";
|
||||
import Tooltip from "@mui/material/Tooltip"; // Importiere Tooltip von Material-UI
|
||||
|
||||
function EditModeToggle() {
|
||||
const [editMode, setEditMode] = useState(() => localStorage.getItem("editMode") === "true");
|
||||
|
||||
const toggleEditMode = () => {
|
||||
const newEditMode = !editMode;
|
||||
setEditMode(newEditMode);
|
||||
localStorage.setItem("editMode", newEditMode);
|
||||
//Browser neu laden, um die Änderungen anzuwenden
|
||||
window.location.reload();
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const storedMode = localStorage.getItem("editMode") === "true";
|
||||
setEditMode(storedMode);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div onClick={toggleEditMode} style={{ cursor: "pointer" }}>
|
||||
{editMode ? (
|
||||
<Tooltip title="Bearbeitungsmodus deaktivieren" placement="top">
|
||||
<EditOffIcon />
|
||||
</Tooltip>
|
||||
) : (
|
||||
<Tooltip title="Bearbeitungsmodus aktivieren" placement="top">
|
||||
<ModeEditIcon />
|
||||
</Tooltip>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default EditModeToggle;
|
||||
File diff suppressed because it is too large
Load Diff
@@ -16,9 +16,7 @@ const PoiUpdateModal = ({ onClose, poiData }) => {
|
||||
const [deviceName, setDeviceName] = useState("");
|
||||
const [idLD, setIdLD] = useState(poiData ? poiData.idLD : "");
|
||||
|
||||
const [description, setDescription] = useState(
|
||||
poiData ? poiData.description : ""
|
||||
);
|
||||
const [description, setDescription] = useState(poiData ? poiData.description : "");
|
||||
|
||||
useEffect(() => {
|
||||
if (poiData) {
|
||||
@@ -37,16 +35,11 @@ const PoiUpdateModal = ({ onClose, poiData }) => {
|
||||
const fetchDeviceId = async () => {
|
||||
if (poiData && poiData.idLD) {
|
||||
try {
|
||||
const response = await fetch(
|
||||
`/api/talas_v5_DB/locationDevice/getDeviceIdById?idLD=${poiData.idLD}`
|
||||
);
|
||||
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
|
||||
);
|
||||
console.error("Fehler beim Abrufen der Geräteinformation in PoiUpdateModel.js: ", error);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -57,12 +50,9 @@ const PoiUpdateModal = ({ onClose, poiData }) => {
|
||||
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",
|
||||
}
|
||||
);
|
||||
const response = await fetch(`/api/talas_v5_DB/pois/deletePoi?id=${poiId}`, {
|
||||
method: "DELETE",
|
||||
});
|
||||
if (response.ok) {
|
||||
alert("POI wurde erfolgreich gelöscht.");
|
||||
onClose();
|
||||
@@ -71,7 +61,7 @@ const PoiUpdateModal = ({ onClose, poiData }) => {
|
||||
throw new Error("Fehler beim Löschen des POI.");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Fehler beim Löschen des POI:", error);
|
||||
console.error("Fehler beim Löschen des POI 1:", error);
|
||||
alert("Fehler beim Löschen des POI.");
|
||||
}
|
||||
}
|
||||
@@ -106,16 +96,13 @@ const PoiUpdateModal = ({ onClose, poiData }) => {
|
||||
const data = await response.json();
|
||||
setLocationDeviceData(data);
|
||||
if (poiData && poiData.idLD) {
|
||||
const selectedDevice = data.find(
|
||||
(device) => device.id === poiData.idLD
|
||||
);
|
||||
setDeviceName(selectedDevice ? selectedDevice.id : data[0].id);
|
||||
const selectedDevice = data.find((device) => device.id === poiData.idLD);
|
||||
setDeviceName(selectedDevice ? selectedDevice.id : data[0].id); // Hier wird die ID als initialer Zustand gesetzt
|
||||
console.log("Selected Device:", selectedDevice);
|
||||
console.log("Selected devciceName:", deviceName);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(
|
||||
"Fehler beim Abrufen der Standort- und Gerätedaten:",
|
||||
error
|
||||
);
|
||||
console.error("Fehler beim Abrufen der Standort- und Gerätedaten:", error);
|
||||
}
|
||||
};
|
||||
fetchData();
|
||||
@@ -126,9 +113,10 @@ const PoiUpdateModal = ({ onClose, poiData }) => {
|
||||
.then((response) => response.json())
|
||||
.then((data) => {
|
||||
setLocationDeviceData(data);
|
||||
const currentDevice = data.find(
|
||||
(device) => device.idLD === currentPoi.idLD
|
||||
);
|
||||
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);
|
||||
}
|
||||
@@ -141,9 +129,7 @@ const PoiUpdateModal = ({ onClose, poiData }) => {
|
||||
|
||||
const handleSubmit = async (event) => {
|
||||
event.preventDefault();
|
||||
const idLDResponse = await fetch(
|
||||
`/api/talas_v5_DB/locationDevice/getDeviceId?deviceName=${encodeURIComponent(deviceName)}`
|
||||
);
|
||||
const idLDResponse = await fetch(`/api/talas_v5_DB/locationDevice/getDeviceId?deviceName=${encodeURIComponent(deviceName)}`);
|
||||
const idLDData = await idLDResponse.json();
|
||||
const idLD = idLDData.idLD;
|
||||
try {
|
||||
@@ -166,9 +152,7 @@ const PoiUpdateModal = ({ onClose, poiData }) => {
|
||||
window.location.reload();
|
||||
} else {
|
||||
const errorResponse = await response.json();
|
||||
throw new Error(
|
||||
errorResponse.error || "Fehler beim Aktualisieren des POI."
|
||||
);
|
||||
throw new Error(errorResponse.error || "Fehler beim Aktualisieren des POI.");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Fehler beim Aktualisieren des POI:", error);
|
||||
@@ -176,39 +160,37 @@ const PoiUpdateModal = ({ onClose, poiData }) => {
|
||||
}
|
||||
};
|
||||
|
||||
//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"
|
||||
/>
|
||||
<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) => (
|
||||
<option key={index} value={device.id}>
|
||||
{device.name}
|
||||
</option>
|
||||
))}
|
||||
<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>
|
||||
|
||||
@@ -216,13 +198,7 @@ const PoiUpdateModal = ({ onClose, poiData }) => {
|
||||
<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"
|
||||
>
|
||||
<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}
|
||||
@@ -239,10 +215,7 @@ const PoiUpdateModal = ({ onClose, poiData }) => {
|
||||
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"
|
||||
>
|
||||
<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>
|
||||
|
||||
@@ -23,6 +23,7 @@ export const addMarkersToMap = (markers, map, layerGroup) => {
|
||||
marker.on("mouseover", () => marker.openPopup());
|
||||
marker.on("mouseout", () => marker.closePopup());
|
||||
marker.on("dragend", (e) => {
|
||||
console.log("Marker wurde verschoben in addMarkersToMap");
|
||||
const newLat = e.target.getLatLng().lat;
|
||||
const newLng = e.target.getLatLng().lng;
|
||||
const markerId = e.target.options.id;
|
||||
@@ -32,11 +33,7 @@ export const addMarkersToMap = (markers, map, layerGroup) => {
|
||||
};
|
||||
|
||||
// Funktion zum Aktualisieren der Standorte in der Datenbank
|
||||
export const updateLocationInDatabase = async (
|
||||
id,
|
||||
newLatitude,
|
||||
newLongitude
|
||||
) => {
|
||||
export const updateLocationInDatabase = async (id, newLatitude, newLongitude) => {
|
||||
const response = await fetch("/api/talas_v5_DB/pois/updateLocation", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
|
||||
37
components/TestScript.js
Normal file
37
components/TestScript.js
Normal file
@@ -0,0 +1,37 @@
|
||||
// components/TestScript.js
|
||||
import { useEffect } from "react";
|
||||
import setupPolylinesCode from "!!raw-loader!../utils/setupPolylines.js"; // Lädt die gesamte setupPolylines.js als Text
|
||||
|
||||
export default function TestScript() {
|
||||
useEffect(() => {
|
||||
// Regulärer Ausdruck für "Stützpunkt entfernen" im Kontextmenü
|
||||
const removeRegex = /marker\.on\("mouseover", function \(\) {\s*this\.bindContextMenu\({\s*contextmenuItems: \[\s*\{\s*text: "Stützpunkt entfernen"/;
|
||||
|
||||
// Regulärer Ausdruck für "Stützpunkt hinzufügen" im Kontextmenü
|
||||
const addRegex = /contextmenuItems: \[\s*\{\s*text: "Stützpunkt hinzufügen"/;
|
||||
|
||||
// Stilvorlagen für das Konsolen-Logging
|
||||
const successStyle = "color: #fff; background-color: #28a745; padding: 4px 8px; font-size: 14px; border-radius: 4px;";
|
||||
const failStyle = "color: #fff; background-color: #dc3545; padding: 4px 8px; font-size: 14px; border-radius: 4px;";
|
||||
const neutralStyle = "color: #006400; font-size: 14px; background-color: #f0f0f0; padding: 4px 8px; border-radius: 4px;";
|
||||
|
||||
// Überprüfung für "Stützpunkt entfernen"
|
||||
if (removeRegex.test(setupPolylinesCode)) {
|
||||
console.log("%c✔ Test bestanden: Der Text für 'Stützpunkt entfernen' wurde gefunden.", successStyle);
|
||||
} else {
|
||||
console.log("%c✘ Test fehlgeschlagen: Der Text für 'Stützpunkt entfernen' wurde nicht gefunden.", failStyle);
|
||||
}
|
||||
|
||||
// Überprüfung für "Stützpunkt hinzufügen"
|
||||
if (addRegex.test(setupPolylinesCode)) {
|
||||
console.log("%c✔ Test bestanden: Der Text für 'Stützpunkt hinzufügen' wurde gefunden.", successStyle);
|
||||
} else {
|
||||
//console.log("%c✘ Test fehlgeschlagen: Der Text für 'Stützpunkt hinzufügen' wurde nicht gefunden.", failStyle);
|
||||
}
|
||||
|
||||
// Beispiel einer neutralen Nachricht (falls benötigt)
|
||||
console.log("%cℹ️ Info: Überprüfung abgeschlossen.", neutralStyle);
|
||||
}, []);
|
||||
|
||||
return null; // Keine visuelle Ausgabe erforderlich
|
||||
}
|
||||
30
components/VersionInfoModal.js
Normal file
30
components/VersionInfoModal.js
Normal file
@@ -0,0 +1,30 @@
|
||||
// components/VersionInfoModal.js
|
||||
import React from "react";
|
||||
|
||||
const VersionInfoModal = ({ showVersionInfoModal, closeVersionInfoModal, MAP_VERSION }) => {
|
||||
return (
|
||||
<>
|
||||
{showVersionInfoModal && (
|
||||
<div className="fixed inset-0 flex items-center justify-center z-50">
|
||||
<div className="fixed inset-0 bg-black bg-opacity-50" onClick={closeVersionInfoModal}></div>
|
||||
<div className="bg-white p-6 rounded-lg shadow-lg z-60 max-w-lg mx-auto">
|
||||
<img src="img/Logo_TALAS.png" alt="TALAS V5 Logo" className="w-1/2 mx-auto my-4" />
|
||||
<div className="bg-white border p-6 rounded-lg shadow-lg z-60 max-w-lg mx-auto">
|
||||
<h2 className="text-xl font-bold mb-6 text-start leading-tight">Littwin Systemtechnik GmbH & Co. KG</h2>
|
||||
<h4 className="text-lg font-bold mb-2 text-start leading-tight">Bürgermeister-Brötje Str. 28</h4>
|
||||
<h4 className="text-lg font-bold mb-2 text-start leading-tight">D-26180 Rastede</h4>
|
||||
<h5 className="text-md mb-2 text-start leading-snug">T: +49 4402 9725 77-0</h5>
|
||||
<h5 className="text-md mb-2 text-start leading-snug">E: kontakt@littwin-systemtechnik.de</h5>
|
||||
</div>
|
||||
<p className="text-gray-700 text-center font-bold mt-4 leading-relaxed">TALAS.Map Version {MAP_VERSION}</p>
|
||||
<button onClick={closeVersionInfoModal} className="mt-4 bg-blue-500 text-white px-4 py-2 rounded hover:bg-blue-700 mx-auto block">
|
||||
Schließen
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default VersionInfoModal;
|
||||
26
components/gisPolylines/PolylineContextMenu.js
Normal file
26
components/gisPolylines/PolylineContextMenu.js
Normal file
@@ -0,0 +1,26 @@
|
||||
// /components/gisPolylines/PolylineContextMenu.js
|
||||
import React from "react";
|
||||
|
||||
const PolylineContextMenu = ({ position, onAddPoint, onRemovePoint, onClose }) => {
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
position: "absolute",
|
||||
top: position.y,
|
||||
left: position.x,
|
||||
backgroundColor: "white",
|
||||
border: "1px solid black",
|
||||
padding: "10px",
|
||||
zIndex: 1000,
|
||||
}}
|
||||
>
|
||||
<ul>
|
||||
<li onClick={onAddPoint}>Stützpunkt hinzufügen</li>
|
||||
<li onClick={onRemovePoint}>Stützpunkt entfernen</li>
|
||||
<li onClick={onClose}>Schließen</li>
|
||||
</ul>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default PolylineContextMenu;
|
||||
12
components/gisPolylines/icons/CircleIcon.js
Normal file
12
components/gisPolylines/icons/CircleIcon.js
Normal file
@@ -0,0 +1,12 @@
|
||||
// /components/gisPolylines/icons/CircleIcon.js
|
||||
import L from "leaflet";
|
||||
import "leaflet/dist/leaflet.css";
|
||||
|
||||
const CircleIcon = new L.DivIcon({
|
||||
className: "custom-circle-icon leaflet-marker-icon",
|
||||
html: '<div style="background-color:gray; width:10px; height:10px; border-radius:50%; border: solid black 1px;"></div>',
|
||||
iconSize: [25, 25],
|
||||
iconAnchor: [5, 5],
|
||||
});
|
||||
|
||||
export default CircleIcon;
|
||||
11
components/gisPolylines/icons/EndIcon.js
Normal file
11
components/gisPolylines/icons/EndIcon.js
Normal file
@@ -0,0 +1,11 @@
|
||||
// /components/gisPolylines/icons/EndIcon.js
|
||||
// Viereck als End-Icon für die Route
|
||||
import L from "leaflet";
|
||||
const EndIcon = L.divIcon({
|
||||
className: "custom-end-icon",
|
||||
html: "<div style='background-color: gray; width: 14px; height: 14px; border: solid black 2px;'></div>", // Graues Viereck
|
||||
iconSize: [14, 14],
|
||||
iconAnchor: [7, 7], // Mittelpunkt des Vierecks als Anker
|
||||
});
|
||||
|
||||
export default EndIcon;
|
||||
17
components/gisPolylines/icons/StartIcon.js
Normal file
17
components/gisPolylines/icons/StartIcon.js
Normal file
@@ -0,0 +1,17 @@
|
||||
// /components/gisPolylines/icons/StartIcon.js
|
||||
//Custom triangle icon for draggable markers
|
||||
import L from "leaflet";
|
||||
|
||||
const StartIcon = L.divIcon({
|
||||
className: "custom-start-icon",
|
||||
html: `
|
||||
<svg width="18" height="18" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
|
||||
<polygon points="10,2 18,18 2,18" fill="black" />
|
||||
<polygon points="10,5 16,16 4,16" fill="gray" />
|
||||
</svg>
|
||||
`, // Schwarzes Dreieck innerhalb eines grauen Dreiecks
|
||||
iconSize: [18, 18],
|
||||
iconAnchor: [9, 10],
|
||||
});
|
||||
|
||||
export default StartIcon;
|
||||
27
components/gisPolylines/icons/SupportPointIcons.js
Normal file
27
components/gisPolylines/icons/SupportPointIcons.js
Normal file
@@ -0,0 +1,27 @@
|
||||
// komponents/gisPolylines/icons/SupportPointIcons
|
||||
import L from "leaflet";
|
||||
import "leaflet/dist/leaflet.css";
|
||||
|
||||
// Icon für Stützpunkt hinzufügen
|
||||
export const AddSupportPointIcon = L.divIcon({
|
||||
className: "custom-add-support-point-icon",
|
||||
html: `
|
||||
<div style='background-color:green;border-radius:50%;width:12px;height:12px;border: solid white 2px;'>
|
||||
<div style='color: white; font-size: 10px; text-align: center; line-height: 12px;'>+</div>
|
||||
</div>
|
||||
`,
|
||||
iconSize: [24, 24],
|
||||
iconAnchor: [12, 12],
|
||||
});
|
||||
|
||||
// Icon für Stützpunkt entfernen
|
||||
export const RemoveSupportPointIcon = L.divIcon({
|
||||
className: "custom-remove-support-point-icon",
|
||||
html: `
|
||||
<div style='background-color:red;border-radius:50%;width:12px;height:12px;border: solid white 2px;'>
|
||||
<div style='color: white; font-size: 10px; text-align: center; line-height: 12px;'>-</div>
|
||||
</div>
|
||||
`,
|
||||
iconSize: [24, 24],
|
||||
iconAnchor: [12, 12],
|
||||
});
|
||||
162
components/imports.js
Normal file
162
components/imports.js
Normal file
@@ -0,0 +1,162 @@
|
||||
// imports.js
|
||||
import React, { useEffect, useRef, useState, useCallback } from "react";
|
||||
import L, { marker } from "leaflet";
|
||||
import "leaflet/dist/leaflet.css";
|
||||
import "leaflet-contextmenu/dist/leaflet.contextmenu.css";
|
||||
import "leaflet-contextmenu";
|
||||
import * as config from "../config/config.js";
|
||||
import * as urls from "../config/urls.js";
|
||||
import "leaflet.smooth_marker_bouncing";
|
||||
import OverlappingMarkerSpiderfier from "overlapping-marker-spiderfier-leaflet";
|
||||
import DataSheet from "./DataSheet.js";
|
||||
import { useRecoilState, useRecoilValue, useSetRecoilState } from "recoil";
|
||||
import { gisStationsStaticDistrictState } from "../store/atoms/gisStationState.js";
|
||||
import { gisSystemStaticState } from "../store/atoms/gisSystemState.js";
|
||||
import { mapLayersState } from "../store/atoms/mapLayersState.js";
|
||||
import { selectedAreaState } from "../store/atoms/selectedAreaState.js";
|
||||
import { zoomTriggerState } from "../store/atoms/zoomTriggerState.js";
|
||||
import { poiTypState } from "../store/atoms/poiTypState.js";
|
||||
import AddPoiModalWindow from "./pois/AddPoiModalWindow.js";
|
||||
import { poiReadFromDbTriggerAtom } from "../store/atoms/poiReadFromDbTriggerAtom.js";
|
||||
import { InformationCircleIcon } from "@heroicons/react/20/solid"; // oder 'outline'
|
||||
import PoiUpdateModal from "./pois/PoiUpdateModal.js";
|
||||
import { selectedPoiState } from "../store/atoms/poiState.js";
|
||||
import { currentPoiState } from "../store/atoms/currentPoiState.js";
|
||||
import { ToastContainer, toast } from "react-toastify";
|
||||
import "react-toastify/dist/ReactToastify.css";
|
||||
import { mapIdState, userIdState } from "../store/atoms/urlParameterState.js";
|
||||
import { poiLayerVisibleState } from "../store/atoms/poiLayerVisibleState.js";
|
||||
import plusRoundIcon from "./PlusRoundIcon.js";
|
||||
import { parsePoint, findClosestPoints } from "../utils/geometryUtils.js";
|
||||
import { insertNewPOI, removePOI, handleEditPoi } from "../utils/poiUtils.js";
|
||||
import { createAndSetDevices } from "../utils/createAndSetDevices.js";
|
||||
import { redrawPolyline, restoreMapSettings, checkOverlappingMarkers } from "../utils/mapUtils.js";
|
||||
import circleIcon from "./gisPolylines/icons/CircleIcon.js";
|
||||
import startIcon from "./gisPolylines/icons/StartIcon.js";
|
||||
import endIcon from "./gisPolylines/icons/EndIcon.js";
|
||||
import { fetchGisStatusStations, fetchPriorityConfig, fetchPoiData, updateLocationInDatabase, fetchUserRights, fetchDeviceNameById } from "../services/apiService.js";
|
||||
import { addContextMenuToMarker } from "../utils/addContextMenuToMarker.js";
|
||||
import { MAP_VERSION } from "../config/settings.js";
|
||||
import * as layers from "../config/layers.js";
|
||||
import { zoomIn, zoomOut, centerHere } from "../utils/zoomAndCenterUtils.js";
|
||||
import { initializeMap } from "../utils/initializeMap.js";
|
||||
import { addItemsToMapContextMenu } from "./useMapContextMenu.js";
|
||||
import useGmaMarkersLayer from "../hooks/layers/useGmaMarkersLayer.js"; // Import the custom hook
|
||||
import useTalasMarkersLayer from "../hooks/layers/useTalasMarkersLayer.js"; // Import the custom hook
|
||||
import useEciMarkersLayer from "../hooks/layers/useEciMarkersLayer.js";
|
||||
import useGsmModemMarkersLayer from "../hooks/layers/useGsmModemMarkersLayer.js";
|
||||
import useCiscoRouterMarkersLayer from "../hooks/layers/useCiscoRouterMarkersLayer.js";
|
||||
import useWagoMarkersLayer from "../hooks/layers/useWagoMarkersLayer.js";
|
||||
import useSiemensMarkersLayer from "../hooks/layers/useSiemensMarkersLayer.js";
|
||||
import useOtdrMarkersLayer from "../hooks/layers/useOtdrMarkersLayer.js";
|
||||
import useWdmMarkersLayer from "../hooks/layers/useWdmMarkersLayer.js";
|
||||
import useMessstellenMarkersLayer from "../hooks/layers/useMessstellenMarkersLayer.js";
|
||||
import useTalasiclMarkersLayer from "../hooks/layers/useTalasiclMarkersLayer.js";
|
||||
import useDauzMarkersLayer from "../hooks/layers/useDauzMarkersLayer.js";
|
||||
import useSmsfunkmodemMarkersLayer from "../hooks/layers/useSmsfunkmodemMarkersLayer.js";
|
||||
import useUlafMarkersLayer from "../hooks/layers/useUlafMarkersLayer.js";
|
||||
import useSonstigeMarkersLayer from "../hooks/layers/useSonstigeMarkersLayer.js";
|
||||
import handlePoiSelect from "../utils/handlePoiSelect.js";
|
||||
import { fetchGisStationsStaticDistrict, fetchGisStationsStatusDistrict, fetchGisStationsMeasurements, fetchGisSystemStatic } from "../services/fetchData.js";
|
||||
import { setupPolylines } from "../utils/setupPolylines.js";
|
||||
import { setupPOIs } from "../utils/setupPOIs.js";
|
||||
import VersionInfoModal from "./VersionInfoModal.js";
|
||||
//--------------------------------------------
|
||||
import PoiUpdateModalWrapper from "./pois/PoiUpdateModalWrapper";
|
||||
import AddPoiModalWindowWrapper from "./pois/AddPoiModalWindowWrapper";
|
||||
import useFetchPoiData from "../hooks/useFetchPoiData";
|
||||
import usePoiTypData from "../hooks/usePoiTypData";
|
||||
import useMarkerLayers from "../hooks/useMarkerLayers";
|
||||
import useLayerVisibility from "../hooks/useLayerVisibility";
|
||||
import useLineData from "../hooks/useLineData.js";
|
||||
|
||||
export {
|
||||
React,
|
||||
useEffect,
|
||||
useRef,
|
||||
useState,
|
||||
useCallback,
|
||||
L,
|
||||
marker,
|
||||
config,
|
||||
urls,
|
||||
OverlappingMarkerSpiderfier,
|
||||
DataSheet,
|
||||
useRecoilState,
|
||||
useRecoilValue,
|
||||
useSetRecoilState,
|
||||
gisStationsStaticDistrictState,
|
||||
gisSystemStaticState,
|
||||
mapLayersState,
|
||||
selectedAreaState,
|
||||
zoomTriggerState,
|
||||
poiTypState,
|
||||
AddPoiModalWindow,
|
||||
poiReadFromDbTriggerAtom,
|
||||
InformationCircleIcon,
|
||||
PoiUpdateModal,
|
||||
selectedPoiState,
|
||||
currentPoiState,
|
||||
ToastContainer,
|
||||
toast,
|
||||
mapIdState,
|
||||
userIdState,
|
||||
poiLayerVisibleState,
|
||||
plusRoundIcon,
|
||||
parsePoint,
|
||||
findClosestPoints,
|
||||
insertNewPOI,
|
||||
removePOI,
|
||||
createAndSetDevices,
|
||||
handleEditPoi,
|
||||
redrawPolyline,
|
||||
restoreMapSettings,
|
||||
checkOverlappingMarkers,
|
||||
circleIcon,
|
||||
startIcon,
|
||||
endIcon,
|
||||
fetchGisStatusStations,
|
||||
fetchPriorityConfig,
|
||||
fetchPoiData,
|
||||
updateLocationInDatabase,
|
||||
fetchUserRights,
|
||||
fetchDeviceNameById,
|
||||
addContextMenuToMarker,
|
||||
MAP_VERSION,
|
||||
layers,
|
||||
zoomIn,
|
||||
zoomOut,
|
||||
centerHere,
|
||||
initializeMap,
|
||||
addItemsToMapContextMenu,
|
||||
useGmaMarkersLayer,
|
||||
useTalasMarkersLayer,
|
||||
useEciMarkersLayer,
|
||||
useGsmModemMarkersLayer,
|
||||
useCiscoRouterMarkersLayer,
|
||||
useWagoMarkersLayer,
|
||||
useSiemensMarkersLayer,
|
||||
useOtdrMarkersLayer,
|
||||
useWdmMarkersLayer,
|
||||
useMessstellenMarkersLayer,
|
||||
useTalasiclMarkersLayer,
|
||||
useDauzMarkersLayer,
|
||||
useSmsfunkmodemMarkersLayer,
|
||||
useUlafMarkersLayer,
|
||||
useSonstigeMarkersLayer,
|
||||
handlePoiSelect,
|
||||
fetchGisStationsStaticDistrict,
|
||||
fetchGisStationsStatusDistrict,
|
||||
fetchGisStationsMeasurements,
|
||||
fetchGisSystemStatic,
|
||||
setupPolylines,
|
||||
setupPOIs,
|
||||
VersionInfoModal,
|
||||
PoiUpdateModalWrapper,
|
||||
AddPoiModalWindowWrapper,
|
||||
useFetchPoiData,
|
||||
usePoiTypData,
|
||||
useMarkerLayers,
|
||||
useLayerVisibility,
|
||||
useLineData,
|
||||
};
|
||||
217
components/pois/AddPoiModalWindow.js
Normal file
217
components/pois/AddPoiModalWindow.js
Normal file
@@ -0,0 +1,217 @@
|
||||
// components/pois/AddPoiModalWindow.js
|
||||
import React, { useState, useEffect } from "react";
|
||||
import Select from "react-select"; // Importiere react-select
|
||||
import { useSetRecoilState, useRecoilState } from "recoil";
|
||||
import { mapLayersState } from "../../store/atoms/mapLayersState";
|
||||
import { poiReadFromDbTriggerAtom } from "../../store/atoms/poiReadFromDbTriggerAtom";
|
||||
|
||||
const AddPoiModalWindow = ({ onClose, map, latlng }) => {
|
||||
const [poiTypData, setpoiTypData] = useState([]);
|
||||
const [name, setName] = useState("");
|
||||
const [poiTypeId, setPoiTypeId] = useState(null); // Verwende null für react-select
|
||||
const [latitude] = useState(latlng.lat.toFixed(5));
|
||||
const [longitude] = useState(latlng.lng.toFixed(5));
|
||||
const setTrigger = useSetRecoilState(poiReadFromDbTriggerAtom); // Verwende useSetRecoilState
|
||||
const [locationDeviceData, setLocationDeviceData] = useState([]);
|
||||
const [filteredDevices, setFilteredDevices] = useState([]); // Gefilterte Geräte
|
||||
const [deviceName, setDeviceName] = useState(null); // Verwende null für react-select
|
||||
const [mapLayersVisibility] = useRecoilState(mapLayersState); // Um die aktiven Layer zu erhalten
|
||||
|
||||
// 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,
|
||||
};
|
||||
|
||||
// API-Abfrage, um die Geräte zu laden
|
||||
useEffect(() => {
|
||||
const fetchInitialData = async () => {
|
||||
try {
|
||||
const [poiTypResponse, locationDeviceResponse] = await Promise.all([fetch("/api/talas_v5_DB/poiTyp/readPoiTyp"), fetch("/api/talas5/location_device")]);
|
||||
|
||||
const poiTypData = await poiTypResponse.json();
|
||||
setpoiTypData(poiTypData);
|
||||
|
||||
const locationDeviceData = await locationDeviceResponse.json();
|
||||
console.log("Geräte von der API:", locationDeviceData); // Geräte-Daten aus der API anzeigen
|
||||
setLocationDeviceData(locationDeviceData);
|
||||
|
||||
// Filtere die Geräte basierend auf den sichtbaren Systemen
|
||||
filterDevices(locationDeviceData);
|
||||
} catch (error) {
|
||||
console.error("Fehler beim Abrufen der Daten:", error);
|
||||
}
|
||||
};
|
||||
|
||||
fetchInitialData();
|
||||
}, []);
|
||||
|
||||
// Funktion zum Filtern der Geräte basierend auf den aktiven Systemen (Layern)
|
||||
const filterDevices = (devices) => {
|
||||
const activeSystems = Object.keys(mapLayersVisibility).filter((system) => mapLayersVisibility[system]);
|
||||
console.log("Aktive Systeme:", activeSystems); // Anzeigen der aktiven Systeme
|
||||
|
||||
// Mappe aktive Systeme auf ihre ids
|
||||
const activeSystemIds = activeSystems.map((system) => systemNameToIdMap[system]).filter((id) => id !== undefined);
|
||||
console.log("Aktive System-IDs:", activeSystemIds); // Anzeigen der aktiven System-IDs
|
||||
|
||||
// Filtere die Geräte nach aktiven Systemen basierend auf idsystem_typ
|
||||
const filtered = devices.filter((device) => activeSystemIds.includes(device.idsystem_typ));
|
||||
console.log("Gefilterte Geräte:", filtered); // Gefilterte Geräte anzeigen
|
||||
|
||||
setFilteredDevices(filtered); // Setze die gefilterten Geräte
|
||||
};
|
||||
|
||||
// Wenn mapLayersVisibility sich ändert, filtere die Geräte erneut
|
||||
useEffect(() => {
|
||||
if (locationDeviceData.length > 0) {
|
||||
filterDevices(locationDeviceData);
|
||||
}
|
||||
}, [mapLayersVisibility, locationDeviceData]);
|
||||
|
||||
const handleSubmit = async (event) => {
|
||||
event.preventDefault();
|
||||
|
||||
if (!poiTypeId) {
|
||||
alert("Bitte wählen Sie einen Typ aus.");
|
||||
return;
|
||||
}
|
||||
|
||||
const formData = {
|
||||
name,
|
||||
poiTypeId: poiTypeId.value,
|
||||
latitude,
|
||||
longitude,
|
||||
idLD: filteredDevices.find((device) => device.name === deviceName?.value).idLD,
|
||||
};
|
||||
|
||||
const response = await fetch("/api/talas_v5_DB/pois/addLocation", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify(formData),
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
setTrigger((trigger) => trigger + 1); // Verwenden des Triggers zur Aktualisierung
|
||||
onClose();
|
||||
window.location.reload();
|
||||
} else {
|
||||
console.error("Fehler beim Hinzufügen des POI");
|
||||
}
|
||||
|
||||
if (map && typeof map.closePopup === "function") {
|
||||
map.closePopup();
|
||||
}
|
||||
};
|
||||
|
||||
// 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
|
||||
}),
|
||||
};
|
||||
|
||||
// Style für größere Breite des Modals und für Inputs
|
||||
const modalStyles = {
|
||||
// width: "300px", // größere Breite für das Modal
|
||||
//maxWidth: "100%", // responsive, passt sich an
|
||||
//padding: "20px", // Polsterung für das Modal
|
||||
//backgroundColor: "white", // Hintergrundfarbe
|
||||
//borderRadius: "8px", // Abgerundete Ecken
|
||||
//boxShadow: "0px 4px 12px rgba(0, 0, 0, 0.1)", // Schatten für das Modal
|
||||
};
|
||||
|
||||
return (
|
||||
<form onSubmit={handleSubmit} style={modalStyles} className="m-0 p-2 w-full">
|
||||
<div className="flex flex-col mb-4">
|
||||
<label htmlFor="name" className="block mb-2 font-bold text-sm text-gray-700">
|
||||
Beschreibung :
|
||||
</label>
|
||||
<input type="text" id="name" value={name} onChange={(e) => setName(e.target.value)} 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}
|
||||
placeholder="Gerät auswählen..."
|
||||
isClearable
|
||||
styles={customStyles} // Apply custom styles here
|
||||
/>
|
||||
</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}
|
||||
placeholder="Typ auswählen..."
|
||||
styles={customStyles} // Apply custom styles here
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-row items-center justify-between mb-4">
|
||||
<div className="flex flex-col items-center">
|
||||
<label htmlFor="lat" className="block mb-2 text-xs text-gray-700">
|
||||
Lat : {latitude}
|
||||
</label>
|
||||
</div>
|
||||
<div className="flex flex-col items-center">
|
||||
<label htmlFor="lng" className="block mb-2 text-xs text-gray-700">
|
||||
Lng : {longitude}
|
||||
</label>
|
||||
</div>
|
||||
</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
|
||||
</button>
|
||||
</form>
|
||||
);
|
||||
};
|
||||
|
||||
export default AddPoiModalWindow;
|
||||
24
components/pois/AddPoiModalWindowPopup.js
Normal file
24
components/pois/AddPoiModalWindowPopup.js
Normal file
@@ -0,0 +1,24 @@
|
||||
// components/pois/AddPoiModalWindowPopup.js
|
||||
import React from "react";
|
||||
import AddPoiModalWindow from "./AddPoiModalWindow.js";
|
||||
|
||||
const AddPoiModalWindowPopup = ({ showPopup, closePopup, handleAddStation, popupCoordinates }) => {
|
||||
return (
|
||||
<>
|
||||
{showPopup && (
|
||||
<div className="fixed inset-0 bg-black bg-opacity-10 flex justify-center items-center z-[1000]" onClick={closePopup}>
|
||||
<div className="relative bg-white p-6 rounded-lg shadow-lg" onClick={(e) => e.stopPropagation()}>
|
||||
<button onClick={closePopup} 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>
|
||||
<AddPoiModalWindow onClose={closePopup} onSubmit={handleAddStation} latlng={popupCoordinates} />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default AddPoiModalWindowPopup;
|
||||
30
components/pois/AddPoiModalWindowWrapper.js
Normal file
30
components/pois/AddPoiModalWindowWrapper.js
Normal file
@@ -0,0 +1,30 @@
|
||||
// components/pois/AddPoiModalWindowWrapper.js
|
||||
import React from "react";
|
||||
import AddPoiModalWindow from "./AddPoiModalWindow";
|
||||
|
||||
const AddPoiModalWindowWrapper = ({ show, onClose, latlng, handleAddStation }) => {
|
||||
return (
|
||||
show && (
|
||||
<div
|
||||
className="fixed inset-0 bg-black bg-opacity-10 flex justify-center items-center z-[1000]"
|
||||
onClick={onClose}
|
||||
data-testid="modal-overlay" // Hinzugefügt, um den Hintergrund zu identifizieren
|
||||
>
|
||||
<div
|
||||
className="relative bg-white p-6 rounded-lg shadow-lg"
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
role="dialog" // Hinzugefügt, um das Dialog-Element zu identifizieren
|
||||
>
|
||||
<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>
|
||||
<AddPoiModalWindow onClose={onClose} onSubmit={handleAddStation} latlng={latlng} />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
);
|
||||
};
|
||||
|
||||
export default AddPoiModalWindowWrapper;
|
||||
256
components/pois/PoiUpdateModal.js
Normal file
256
components/pois/PoiUpdateModal.js
Normal file
@@ -0,0 +1,256 @@
|
||||
// /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 "../../store/atoms/poiState";
|
||||
import { currentPoiState } from "../../store/atoms/currentPoiState";
|
||||
import { mapLayersState } from "../../store/atoms/mapLayersState";
|
||||
|
||||
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;
|
||||
9
components/pois/PoiUpdateModalWindow.js
Normal file
9
components/pois/PoiUpdateModalWindow.js
Normal file
@@ -0,0 +1,9 @@
|
||||
// components/pois/PoiUpdateModalWindow.js
|
||||
import React from "react";
|
||||
import PoiUpdateModal from "./PoiUpdateModal.js";
|
||||
|
||||
const PoiUpdateModalWindow = ({ showPoiUpdateModal, closePoiUpdateModal, currentPoiData, popupCoordinates }) => {
|
||||
return <>{showPoiUpdateModal && <PoiUpdateModal onClose={closePoiUpdateModal} poiData={currentPoiData} onSubmit={() => {}} latlng={popupCoordinates} />}</>;
|
||||
};
|
||||
|
||||
export default PoiUpdateModalWindow;
|
||||
26
components/pois/PoiUpdateModalWrapper.js
Normal file
26
components/pois/PoiUpdateModalWrapper.js
Normal file
@@ -0,0 +1,26 @@
|
||||
// components/pois/PoiUpdateModalWrapper.js
|
||||
import React, { useState } from "react";
|
||||
import PoiUpdateModal from "./PoiUpdateModal";
|
||||
import { useRecoilValue, useSetRecoilState } from "recoil";
|
||||
import { currentPoiState, selectedPoiState } from "../../store/atoms/poiState";
|
||||
import { poiReadFromDbTriggerAtom } from "../../store/atoms/poiReadFromDbTriggerAtom";
|
||||
|
||||
const PoiUpdateModalWrapper = ({ show, onClose, latlng }) => {
|
||||
const setSelectedPoi = useSetRecoilState(selectedPoiState);
|
||||
const setCurrentPoi = useSetRecoilState(currentPoiState);
|
||||
const currentPoi = useRecoilValue(currentPoiState);
|
||||
const poiReadTrigger = useRecoilValue(poiReadFromDbTriggerAtom);
|
||||
|
||||
return (
|
||||
show && (
|
||||
<PoiUpdateModal
|
||||
onClose={onClose}
|
||||
poiData={currentPoi}
|
||||
onSubmit={() => {}} // Add your submit logic here
|
||||
latlng={latlng}
|
||||
/>
|
||||
)
|
||||
);
|
||||
};
|
||||
|
||||
export default PoiUpdateModalWrapper;
|
||||
53
components/pois/PoiUtils.js
Normal file
53
components/pois/PoiUtils.js
Normal file
@@ -0,0 +1,53 @@
|
||||
// components/pois/PoiUtils.js
|
||||
import L from "leaflet";
|
||||
|
||||
// Funktion, um POI Markers zu erstellen
|
||||
export const createPoiMarkers = (poiData, iconPath) => {
|
||||
return poiData.map((location) => {
|
||||
return L.marker([location.latitude, location.longitude], {
|
||||
icon: L.icon({
|
||||
iconUrl: iconPath,
|
||||
iconSize: [25, 41],
|
||||
iconAnchor: [12, 41],
|
||||
popupAnchor: [1, -34],
|
||||
draggable: true,
|
||||
}),
|
||||
id: location.idPoi,
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
// Funktion zum Hinzufügen von Markern zur Karte und zum Umgang mit Events
|
||||
export const addMarkersToMap = (markers, map, layerGroup) => {
|
||||
markers.forEach((marker) => {
|
||||
marker.addTo(layerGroup);
|
||||
marker.on("mouseover", () => marker.openPopup());
|
||||
marker.on("mouseout", () => marker.closePopup());
|
||||
marker.on("dragend", (e) => {
|
||||
console.log("Marker wurde verschoben in addMarkersToMap");
|
||||
const newLat = e.target.getLatLng().lat;
|
||||
const newLng = e.target.getLatLng().lng;
|
||||
const markerId = e.target.options.id;
|
||||
updateLocationInDatabase(markerId, newLat, newLng);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
// Funktion zum Aktualisieren der Standorte in der Datenbank
|
||||
export const updateLocationInDatabase = async (id, newLatitude, newLongitude) => {
|
||||
const response = await fetch("/api/talas_v5_DB/pois/updateLocation", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
id,
|
||||
latitude: newLatitude,
|
||||
longitude: newLongitude,
|
||||
}),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
console.error("Fehler beim Aktualisieren der Position");
|
||||
}
|
||||
};
|
||||
|
||||
// Weitere Funktionen können hier hinzugefügt werden
|
||||
@@ -1,22 +1,85 @@
|
||||
import { useState, useCallback } from "react";
|
||||
// /components/useMapContextMenu.js
|
||||
import { toast } from "react-toastify";
|
||||
import { zoomIn, zoomOut, centerHere } from "../utils/zoomAndCenterUtils"; // Assuming these are imported correctly
|
||||
|
||||
const useMapContextMenu = (map, hasRights, addStationCallback) => {
|
||||
const [menuItemAdded, setMenuItemAdded] = useState(false);
|
||||
const zoomInCallback = (e, map) => {
|
||||
zoomIn(e, map);
|
||||
};
|
||||
|
||||
const addItemsToMapContextMenu = useCallback(() => {
|
||||
if (map && !menuItemAdded) {
|
||||
const zoomOutCallback = (map) => {
|
||||
zoomOut(map);
|
||||
};
|
||||
|
||||
const centerHereCallback = (e, map) => {
|
||||
centerHere(e, map);
|
||||
};
|
||||
// Funktion zum Anzeigen der Koordinaten
|
||||
const showCoordinates = (e) => {
|
||||
alert("Breitengrad: " + e.latlng.lat.toFixed(5) + "\nLängengrad: " + e.latlng.lng.toFixed(5));
|
||||
};
|
||||
// Kontextmenü Callback für "POI hinzufügen"
|
||||
const addStationCallback = (event, hasRights, setShowPopup, setPopupCoordinates) => {
|
||||
const editMode = localStorage.getItem("editMode") === "true";
|
||||
hasRights = editMode ? hasRights : undefined;
|
||||
if (hasRights) {
|
||||
setPopupCoordinates(event.latlng);
|
||||
setShowPopup(true);
|
||||
} else {
|
||||
toast.error("Benutzer hat keine Berechtigung zum Hinzufügen.", {
|
||||
position: "top-center",
|
||||
autoClose: 5000,
|
||||
hideProgressBar: false,
|
||||
closeOnClick: true,
|
||||
pauseOnHover: true,
|
||||
draggable: true,
|
||||
progress: undefined,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export const addItemsToMapContextMenu = (map, menuItemAdded, setMenuItemAdded, hasRights, setShowPopup, setPopupCoordinates) => {
|
||||
// Überprüfe den Bearbeitungsmodus in localStorage
|
||||
const editMode = localStorage.getItem("editMode") === "true";
|
||||
hasRights = editMode ? hasRights : undefined;
|
||||
|
||||
if (!menuItemAdded && map && map.contextmenu) {
|
||||
map.contextmenu.addItem({
|
||||
text: "Koordinaten anzeigen",
|
||||
icon: "img/not_listed_location.png",
|
||||
callback: showCoordinates,
|
||||
});
|
||||
|
||||
map.contextmenu.addItem({ separator: true });
|
||||
|
||||
map.contextmenu.addItem({
|
||||
text: "Reinzoomen",
|
||||
icon: "img/zoom_in.png",
|
||||
callback: (e) => zoomInCallback(e, map),
|
||||
});
|
||||
|
||||
map.contextmenu.addItem({
|
||||
text: "Rauszoomen",
|
||||
icon: "img/zoom_out.png",
|
||||
callback: () => zoomOutCallback(map),
|
||||
});
|
||||
|
||||
map.contextmenu.addItem({
|
||||
text: "Hier zentrieren",
|
||||
icon: "img/center_focus.png",
|
||||
callback: (e) => centerHereCallback(e, map),
|
||||
});
|
||||
|
||||
// wenn localStorage Variable editMode true ist, dann wird der Button "POI hinzufügen" angezeigt
|
||||
if (editMode) {
|
||||
map.contextmenu.addItem({ separator: true });
|
||||
map.contextmenu.addItem({
|
||||
text: "POI hinzufügen",
|
||||
icon: "img/add_station.png",
|
||||
className: "background-red",
|
||||
callback: (event) => addStationCallback(event, hasRights),
|
||||
callback: (event) => addStationCallback(event, hasRights, setShowPopup, setPopupCoordinates),
|
||||
});
|
||||
|
||||
setMenuItemAdded(true); // Menüpunkt wurde hinzugefült, Zustand aktualisieren
|
||||
}
|
||||
}, [map, menuItemAdded, hasRights, addStationCallback]);
|
||||
|
||||
return { addItemsToMapContextMenu };
|
||||
setMenuItemAdded(true);
|
||||
}
|
||||
};
|
||||
|
||||
export default useMapContextMenu;
|
||||
|
||||
Reference in New Issue
Block a user