polylines tooltip content

This commit is contained in:
ISA
2024-08-10 10:32:37 +02:00
parent b1f7b700ca
commit b7116a1e6f
142 changed files with 14451 additions and 4281 deletions

3
.babelrc Normal file
View File

@@ -0,0 +1,3 @@
{
"presets": ["@babel/preset-env", "@babel/preset-react"]
}

View File

@@ -1,10 +1,45 @@
#.env.local
#je nach dem Mysql Server, ob localhost freigegeben ist oder die IP Adresse des Servers, manchmal die beide und manchmal nur eine
DB_HOST=localhost #DB_HOST=10.10.0.30
#DB_HOST=192.168.10.58 #DB_USER=root
#DB_HOST=10.10.0.13 #DB_PASSWORD="root#$"
#DB_NAME=talas_v5
#DB_PORT=3306
#########################
#NEXT_PUBLIC_BASE_URL="http://10.10.0.30/talas5/devices/"
#NEXT_PUBLIC_SERVER_URL="http://10.10.0.30"
#NEXT_PUBLIC_PROXY_TARGET="http://10.10.0.30"
#NEXT_PUBLIC_ONLINE_TILE_LAYER="http://10.10.0.30:3000/mapTiles/{z}/{x}/{y}.png"
#########################
#DB_HOST=10.10.0.70
#DB_USER=root
#DB_PASSWORD="root#$"
#DB_NAME=talas_v5
#DB_PORT=3306
#########################
#NEXT_PUBLIC_BASE_URL="http://10.10.0.70/talas5/devices/"
#NEXT_PUBLIC_SERVER_URL="http://10.10.0.70"
#NEXT_PUBLIC_PROXY_TARGET="http://10.10.0.70"
#NEXT_PUBLIC_ONLINE_TILE_LAYER="http://10.10.0.13:3000/mapTiles/{z}/{x}/{y}.png"
#########################
DB_HOST=192.168.10.167
DB_USER=root DB_USER=root
DB_PASSWORD="root#$" DB_PASSWORD="root#$"
DB_NAME=talas_v5 DB_NAME=talas_v5
DB_PORT=3306 DB_PORT=3306
######################### Kontetmenü -> Station in tab öffnen #########################
#BASE_URL=http://10.10.0.13/talas5/devices/ #URLs für den Client (clientseitig)
NEXT_PUBLIC_BASE_URL="http://192.168.10.167/talas5/devices/"
NEXT_PUBLIC_SERVER_URL="http://192.168.10.167"
NEXT_PUBLIC_PROXY_TARGET="http://192.168.10.167"
NEXT_PUBLIC_ONLINE_TILE_LAYER="http://192.168.10.14:3000/mapTiles/{z}/{x}/{y}.png"

1
.gitignore vendored
View File

@@ -26,3 +26,4 @@ trace
# Ignore specific Next.js build files # Ignore specific Next.js build files
pages-manifest.json pages-manifest.json
nodeMap für 13 am 16.07.2024.zip

3
.prettierrc Normal file
View File

@@ -0,0 +1,3 @@
{
"printWidth": 250
}

1
.vscode/settings.json vendored Normal file
View File

@@ -0,0 +1 @@
{}

77
Jenkinsfile vendored
View File

@@ -1,96 +1,37 @@
pipeline { pipeline {
agent any agent any
environment {
NODE_ENV = 'production'
}
tools {
nodejs 'nodejs' // Ensure this matches the name defined in Jenkins
}
stages { stages {
stage('Checkout') { stage('Checkout SCM') {
steps { steps {
script { checkout([$class: 'GitSCM', branches: [[name: '**']],
try { doGenerateSubmoduleConfigurations: false,
// Code aus dem Repository holen extensions: [],
git branch: 'develop', url: 'http://172.19.0.2:3000/Ismail/NodeMap.git' userRemoteConfigs: [[url: 'http://172.20.0.2:3000/Ismail/NodeMap', credentialsId: 'd378f013-2f24-417b-9afd-33df5d410ab8']]])
} catch (Exception e) {
error "Branch 'develop' exists nicht im Repository"
} }
} }
}
}
stage('Check Node.js Version') { stage('Check Node.js Version') {
steps { steps {
script { script {
sh 'node --version' def nodeVersion = sh(script: 'node --version', returnStdout: true).trim()
echo "Node.js version: ${nodeVersion}"
} }
} }
} }
stage('Install Dependencies') { stage('Install Dependencies') {
steps { steps {
script { script {
try {
// Install dependencies
sh 'npm install' sh 'npm install'
} catch (Exception e) {
error "Dependency Installation failed: ${e.message}"
} }
} }
} }
} stage('Run Unit Tests') {
stage('Build') {
steps { steps {
script { script {
try {
// Build the project
sh 'npm run build'
} catch (Exception e) {
error "Build failed: ${e.message}"
}
}
}
}
stage('Test') {
steps {
script {
try {
// Run tests
sh 'npm test' sh 'npm test'
} catch (Exception e) {
error "Tests failed: ${e.message}"
} }
} }
} }
} // Weitere Stages ...
stage('Deploy') {
steps {
script {
try {
// Add your deployment steps here
// For example: sh 'npm run deploy'
echo 'Deployment steps go here'
} catch (Exception e) {
error "Deployment failed: ${e.message}"
}
}
}
}
}
post {
success {
echo 'Build, tests, and deployment were successful!'
}
failure {
echo 'Build, tests, or deployment failed.'
}
} }
} }

47
MapTypC.aspx.txt Normal file
View File

@@ -0,0 +1,47 @@
<%@ Page Title="" Language="C#" MasterPageFile="~/Standard.Master" AutoEventWireup="true" CodeBehind="MapTypC.aspx.cs" Inherits="TALAS_V5.MessagesMap.MapTypC" %>
<%@ Register assembly="DevExpress.Web.v19.2, Version=19.2.6.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a" namespace="DevExpress.Web" tagprefix="dx" %>
<asp:Content ID="NaviContent" ContentPlaceHolderID="NaviContent" runat="server">
</asp:Content>
<asp:Content ID="Content" ContentPlaceHolderID="MainContent" runat="server">
<style>
.responsive-iframe-wrapper {
position: relative !important;
width: 100% !important;
height: 97.2vh !important; /* Setzt die Höhe des Wrappers auf die Höhe des Viewports */
overflow: hidden !important; /* Verhindert Scrollbalken innerhalb des Wrappers */
padding: 0 0 0 0 !important;
margin: 0 0 0 0 !important;
}
.responsive-iframe-wrapper iframe {
position: absolute !important;
top: 0 !important;
left: 0 !important;
width: 100% !important;
height: 100% !important;
border: none !important; /* Removes the border */
}
</style>
<div class="responsive-iframe-wrapper">
<iframe frameborder="0"></iframe>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
var url = new URL(window.location.href);
var mValue = url.searchParams.get("m");
var uValue = url.searchParams.get("u");
// Setzen der src-Eigenschaft des iframe mit den abgerufenen Parametern
document.querySelector('.responsive-iframe-wrapper iframe').src =
// "http://10.10.0.70:3000?m=" + encodeURIComponent(mValue) + "&u=" + encodeURIComponent(uValue);
"http://10.10.0.13:3000?m=" + encodeURIComponent(mValue) + "&u=" + encodeURIComponent(uValue);
//"http://localhost:3000?m=" + encodeURIComponent(mValue) + "&u=" + encodeURIComponent(uValue);
});
</script>
</asp:Content>

View File

@@ -146,7 +146,7 @@ Bei Problemen während der Weiterentwicklung könnte es hilfreich sein, die Seit
- **DataSheet.js**: Verantwortlich für die Anzeige und Interaktion mit den Layer- und Stationsauswahlen. Ermöglicht das Aktivieren/Deaktivieren von Layern und zeigt Informationen zu geografischen Punkten. - **DataSheet.js**: Verantwortlich für die Anzeige und Interaktion mit den Layer- und Stationsauswahlen. Ermöglicht das Aktivieren/Deaktivieren von Layern und zeigt Informationen zu geografischen Punkten.
- **MapComponent.js**: Kernkomponente für die Darstellung der Karte. Beinhaltet Logik für das Hinzufügen von Layern, Zoom-Funktionen und andere interaktive Elemente. - **MapComponent.js**: Kernkomponente für die Darstellung der Karte. Beinhaltet Logik für das Hinzufügen von Layern, Zoom-Funktionen und andere interaktive Elemente.
- **PoiUpdateModal.js**:Komponente zum Aktualisieren(update) und löschen von Pois. - **PoiUpdateModal.js**:Komponente zum Aktualisieren(update) und löschen von Pois.
- **ShowAddStationPopup.js**:Komponente zum hinzufügen von Pois. - **AddPoiModalWindow.js**:Komponente zum hinzufügen von Pois.
### /public ### /public

23
__mocks__/leaflet.js Normal file
View File

@@ -0,0 +1,23 @@
// __mocks__/leaflet.js
const L = {
divIcon: jest.fn(() => new L.DivIcon()),
DivIcon: function () {
this.options = {
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>
`,
iconSize: [18, 18],
iconAnchor: [9, 10],
};
},
};
L.DivIcon.prototype = {
constructor: L.DivIcon,
};
module.exports = L;

View File

@@ -0,0 +1,82 @@
// __tests__/components/DataSheet.test.js
import React from "react";
import { render, screen, waitFor } from "@testing-library/react";
import "@testing-library/jest-dom";
import userEvent from "@testing-library/user-event";
import DataSheet from "../../components/DataSheet";
import { RecoilRoot } from "recoil";
import * as Recoil from "recoil";
import { useRecoilState, useRecoilValue, useSetRecoilState } from "recoil";
import { gisStationsStaticDistrictState } from "../../store/atoms/gisStationState";
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/poiLayerVisibleState";
// Stelle sicher, dass alle notwendigen Atome korrekt gemockt sind
jest.mock("../../store/atoms/gisStationState", () => ({
gisStationState: {
subscribe: jest.fn(),
getSnapshot: jest.fn(() => []), // Mocked return value
},
}));
jest.mock("../../store/atoms/gisSystemState", () => ({
gisSystemStaticState: {
subscribe: jest.fn(),
getSnapshot: jest.fn(() => []), // Mocked return value
},
}));
describe("DataSheet Component", () => {
//--------------------------------------------------------------------------------
it("renders the basic fields and initial station/system listings", async () => {
render(
<RecoilRoot>
<DataSheet />
</RecoilRoot>
);
// Waiting for asynchronous tasks to complete
await waitFor(() => {
// Check if the specific elements are present after data processing
expect(screen.getByRole("combobox")).toBeInTheDocument();
expect(screen.getByLabelText("POIs")).toBeInTheDocument();
expect(screen.getByRole("option", { name: "Station wählen" })).toBeInTheDocument();
});
// Optionally print out the full DOM for debugging
screen.debug();
});
//--------------------------------------------------------------------------------
test("should open dropdown on click", async () => {
render(
<RecoilRoot>
<DataSheet />
</RecoilRoot>
);
const combobox = screen.getByRole("combobox");
userEvent.click(combobox);
// Überprüfe, ob die Dropdown-Optionen angezeigt werden
expect(screen.getByRole("option", { name: "Station wählen" })).toBeInTheDocument();
});
//--------------------------------------------------------------------------------
test("should toggle checkbox", async () => {
render(
<RecoilRoot>
<DataSheet />
</RecoilRoot>
);
const checkbox = screen.getByLabelText("POIs");
// Stelle sicher, dass die Checkbox nicht angekreuzt ist
expect(checkbox).not.toBeChecked();
// Klicke auf die Checkbox
userEvent.click(checkbox);
// Jetzt sollte sie angekreuzt sein
expect(checkbox).toBeChecked();
});
//--------------------------------------------------------------------------------
});

View File

@@ -0,0 +1,89 @@
// __tests__/MapComponent.test.js
// Ein einfacher Testfall, der sicherstellt, dass die Addition korrekt ist
test("simple addition", () => {
const a = 1;
const b = 2;
const c = a + b;
expect(c).toBe(3); // Überprüft, ob c gleich 3 ist
});
//import L from "leaflet";
//import { checkOverlappingMarkers } from "../utils/mapUtils"; // Passe den Pfad entsprechend an
/* describe("checkOverlappingMarkers", () => {
let map;
beforeEach(() => {
// Erstelle eine neue Leaflet-Karte für jeden Test
map = L.map(document.createElement("div"));
});
it("should group markers by coordinates and add plus icons for overlapping markers", () => {
// Erstelle einige Beispielmarker
const markers = [
L.marker([51.505, -0.09]),
L.marker([51.505, -0.09]),
L.marker([51.51, -0.1]),
];
const plusIcon = L.divIcon({ className: "plus-icon" });
// Rufe die Funktion auf
checkOverlappingMarkers(map, markers, plusIcon);
// Überprüfe, dass die Marker zu Gruppen hinzugefügt wurden
const overlappingGroups = map._layers;
expect(Object.keys(overlappingGroups).length).toBeGreaterThan(0);
// Überprüfe, dass die Plus-Marker hinzugefügt wurden
const plusMarkers = Object.values(overlappingGroups).filter(
(layer) =>
layer.options.icon &&
layer.options.icon.options.className === "plus-icon"
);
expect(plusMarkers.length).toBeGreaterThan(0);
});
it("should handle non-array markers argument gracefully", () => {
const plusIcon = L.divIcon({ className: "plus-icon" });
// Rufe die Funktion mit einem ungültigen Argument auf
checkOverlappingMarkers(map, null, plusIcon);
// Stelle sicher, dass keine Marker hinzugefügt wurden
const layers = map._layers;
expect(Object.keys(layers).length).toBe(0);
});
it("should not add plus markers if there are no overlaps", () => {
// Erstelle einige Beispielmarker
const markers = [
L.marker([51.505, -0.09]),
L.marker([51.51, -0.1]),
L.marker([51.52, -0.12]),
];
const plusIcon = L.divIcon({ className: "plus-icon" });
// Rufe die Funktion auf
checkOverlappingMarkers(map, markers, plusIcon);
// Überprüfe, dass keine Plus-Marker hinzugefügt wurden
const plusMarkers = Object.values(map._layers).filter(
(layer) =>
layer.options.icon &&
layer.options.icon.options.className === "plus-icon"
);
expect(plusMarkers.length).toBe(0);
});
}); */
/*
In diesem Test:
Wird eine neue Leaflet-Karte vor jedem Test erstellt.
checkOverlappingMarkers wird aufgerufen, um zu überprüfen, ob die Funktion die Marker richtig gruppiert und Plus-Icons für überlappende Marker hinzufügt.
Der Test überprüft auch, ob die Funktion ungültige Argumente (wie null für Marker) korrekt behandelt.
Es wird sichergestellt, dass keine Plus-Marker hinzugefügt werden, wenn keine Überlappungen vorliegen.
Stelle sicher, dass du die Pfade und Importe entsprechend deiner Projektstruktur anpasst.
*/

View File

@@ -0,0 +1,40 @@
// __tests__/components/gisPolylines/icons/CircleIcon.test.js
jest.mock("leaflet", () => {
const actualLeaflet = jest.requireActual("leaflet");
return {
...actualLeaflet,
DivIcon: jest.fn().mockImplementation((options) => ({
...options,
options,
_leaflet_id: Math.random(),
})),
};
});
import L from "leaflet";
import CircleIcon from "../../../components/gisPolylines/icons/CircleIcon";
describe("CircleIcon", () => {
test("should be a Leaflet divIcon with correct properties", () => {
// console.log("CircleIcon options:", CircleIcon.options);
expect(CircleIcon).toEqual(
expect.objectContaining({
options: expect.objectContaining({
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],
}),
})
);
expect(CircleIcon.options.className).toContain("custom-circle-icon");
expect(CircleIcon.options.html).toContain("<div");
expect(CircleIcon.options.html).toContain("background-color:gray");
expect(CircleIcon.options.html).toContain("border-radius:50%");
expect(CircleIcon.options.html).toContain("width:10px");
expect(CircleIcon.options.html).toContain("height:10px");
expect(CircleIcon.options.html).toContain("border: solid black 1px");
expect(CircleIcon.options.iconSize).toEqual([25, 25]);
expect(CircleIcon.options.iconAnchor).toEqual([5, 5]);
});
});

View File

@@ -0,0 +1,24 @@
// __tests__/components/gisPolylines/icons/EndIcon.test.js
jest.mock("leaflet", () => {
const actualLeaflet = jest.requireActual("leaflet");
return {
...actualLeaflet,
DivIcon: jest.fn().mockImplementation((options) => ({
...options,
options,
_leaflet_id: Math.random(),
})),
};
});
import L from "leaflet";
import EndIcon from "../../../../components/gisPolylines/icons/EndIcon";
//console.log("console log EndIcon: ", EndIcon);
describe("endIcon", () => {
test("should be a custom-end-icon with correct HTML and styles", () => {
expect(EndIcon.options.className).toBe("custom-end-icon");
expect(EndIcon.options.html).toBe("<div style='background-color: gray; width: 14px; height: 14px; border: solid black 2px;'></div>");
expect(EndIcon.options.iconSize).toEqual([14, 14]);
expect(EndIcon.options.iconAnchor).toEqual([7, 7]);
});
});

View File

@@ -0,0 +1,41 @@
// __tests__/components/gisPolylines/icons/StartIcon.test.js
jest.mock("leaflet", () => {
const actualLeaflet = jest.requireActual("leaflet");
return {
...actualLeaflet,
DivIcon: jest.fn().mockImplementation((options) => ({
...options,
options,
_leaflet_id: Math.random(),
_createIcon: jest.fn(),
_createImg: jest.fn(),
_getIconUrl: jest.fn(),
_initHooks: [],
_initHooksCalled: true,
_setIconStyles: jest.fn(),
callInitHooks: jest.fn(),
createIcon: jest.fn(),
createShadow: jest.fn(),
initialize: jest.fn(),
})),
};
});
import L from "leaflet";
import StartIcon from "../../../../../components/gisPolylines/icons/StartIcon";
describe("StartIcon", () => {
test("should be a Leaflet divIcon with correct properties", () => {
//console.log("StartIcon options:", StartIcon.options);
expect(StartIcon).toEqual(
expect.objectContaining({
options: expect.objectContaining({
className: "custom-start-icon",
html: expect.stringContaining("<svg"),
iconSize: [18, 18],
iconAnchor: [9, 10],
}),
})
);
});
});

View File

@@ -0,0 +1,42 @@
import { renderHook, act, waitFor } from "@testing-library/react";
import useLineData from "../../../hooks/useLineData";
import React from "react";
const mockUrl = "http://mockurl.com";
const mockData1 = {
Statis: [{ IdLD: 1, Modul: "mod1", PrioColor: "red", ModulName: "Module 1", ModulTyp: "Type 1", Message: "Message 1", PrioName: "High", DpName: "DP 1", Value: "Value 1" }],
};
const mockData2 = [{ idLD: 1, idModul: "mod1" }];
global.fetch = jest.fn((url) => {
if (url === mockUrl) {
return Promise.resolve({
json: () => Promise.resolve(mockData1),
});
} else {
return Promise.resolve({
json: () => Promise.resolve(mockData2),
});
}
});
describe("useLineData", () => {
test("should fetch line data and set line colors and tooltip contents", async () => {
const setLineStatusData = jest.fn();
const { result } = renderHook(() => useLineData(mockUrl, setLineStatusData));
await waitFor(
() => {
expect(setLineStatusData).toHaveBeenCalledWith(expect.any(Array));
expect(result.current).toEqual(
expect.objectContaining({
lineColors: expect.any(Object),
tooltipContents: expect.any(Object),
})
);
},
{ timeout: 5000 } // Increase the timeout to 5000ms
);
});
});

View File

@@ -0,0 +1,86 @@
// __tests__/components/pois/AddPoiModalWindow.test.js
import React from "react";
import { render, screen, fireEvent, waitFor, act } from "@testing-library/react";
import "@testing-library/jest-dom";
import AddPoiModalWindow from "../../../components/pois/AddPoiModalWindow";
import { RecoilRoot } from "recoil";
// Mock für die fetch-Funktion
global.fetch = jest.fn((url) => {
if (url === "/api/talas_v5_DB/poiTyp/readPoiTyp") {
return Promise.resolve({
json: () => Promise.resolve([{ idPoiTyp: "1", name: "Type1" }]),
});
} else if (url === "/api/talas5/location_device") {
return Promise.resolve({
json: () => Promise.resolve([{ idLD: "1", name: "Device1" }]),
});
} else if (url === "/api/talas_v5_DB/pois/addLocation") {
return Promise.resolve({ ok: true });
}
});
describe("AddPoiModalWindow", () => {
const mockOnClose = jest.fn();
const mockMap = {
closePopup: jest.fn(),
};
const mockLatLng = { lat: 52.52, lng: 13.405 };
// Mock window.location.reload
beforeAll(() => {
Object.defineProperty(window, "location", {
value: {
...window.location,
reload: jest.fn(),
},
writable: true,
});
});
beforeEach(() => {
fetch.mockClear();
window.location.reload.mockClear(); // Clear the mock before each test
});
test("renders correctly and allows form submission", async () => {
await act(async () => {
render(
<RecoilRoot>
<AddPoiModalWindow onClose={mockOnClose} map={mockMap} latlng={mockLatLng} />
</RecoilRoot>
);
});
// Überprüfen, ob die Formularelemente gerendert werden
expect(screen.getByLabelText(/Name/i)).toBeInTheDocument();
expect(screen.getByLabelText(/Gerät/i)).toBeInTheDocument();
expect(screen.getByLabelText(/Typ/i)).toBeInTheDocument();
expect(screen.getByText(/Lat/i)).toHaveTextContent(`Lat : ${mockLatLng.lat.toFixed(5)}`);
expect(screen.getByText(/Lng/i)).toHaveTextContent(`Lng : ${mockLatLng.lng.toFixed(5)}`);
// Simulieren der Eingabe in das Namensfeld
fireEvent.change(screen.getByLabelText(/Name/i), { target: { value: "New POI" } });
expect(screen.getByLabelText(/Name/i)).toHaveValue("New POI");
// Simulieren der Auswahl eines Geräts
fireEvent.change(screen.getByLabelText(/Gerät/i), { target: { value: "Device1" } });
expect(screen.getByLabelText(/Gerät/i)).toHaveValue("Device1");
// Simulieren der Auswahl eines Typs
fireEvent.change(screen.getByLabelText(/Typ/i), { target: { value: "1" } });
expect(screen.getByLabelText(/Typ/i)).toHaveValue("1");
// Simulieren des Formulareingabeverfahrens
fireEvent.submit(screen.getByRole("button", { name: /POI hinzufügen/i }));
// Warten auf die Formulareinreichung und Überprüfen der Ergebnisse
await waitFor(() => {
expect(mockOnClose).toHaveBeenCalled();
expect(mockMap.closePopup).toHaveBeenCalled();
expect(fetch).toHaveBeenCalledWith("/api/talas_v5_DB/pois/addLocation", expect.any(Object));
expect(window.location.reload).toHaveBeenCalled(); // Verify that reload was called
});
});
});

View File

@@ -0,0 +1,77 @@
// __tests__/components/pois/AddPoiModalWindowPopup.test.js
import React from "react";
import { render, screen, fireEvent } from "@testing-library/react";
import "@testing-library/jest-dom";
import AddPoiModalWindowPopup from "../../../components/pois/AddPoiModalWindowPopup";
// Mock the AddPoiModalWindow component
jest.mock("../../../components/pois/AddPoiModalWindow", () => ({ onClose, onSubmit, latlng }) => (
<div data-testid="add-poi-modal-window">
<button onClick={() => console.log("Mocked Close Modal Click")}>Close Modal</button>
<button onClick={onSubmit}>Submit</button>
<div>
Coordinates: {latlng.lat}, {latlng.lng}
</div>
</div>
));
describe("AddPoiModalWindowPopup", () => {
const closePopupMock = jest.fn();
const handleAddStationMock = jest.fn();
const popupCoordinatesMock = { lat: 52.52, lng: 13.405 };
// Suppress console.log for the duration of these tests
beforeAll(() => {
jest.spyOn(console, "log").mockImplementation(() => {});
});
// Restore console.log after all tests
afterAll(() => {
console.log.mockRestore();
});
beforeEach(() => {
closePopupMock.mockClear();
handleAddStationMock.mockClear();
});
test("renders the popup when showPopup is true", () => {
render(<AddPoiModalWindowPopup showPopup={true} closePopup={closePopupMock} handleAddStation={handleAddStationMock} popupCoordinates={popupCoordinatesMock} />);
expect(screen.getByTestId("add-poi-modal-window")).toBeInTheDocument();
expect(screen.getByText("Coordinates: 52.52, 13.405")).toBeInTheDocument();
});
test("does not render the popup when showPopup is false", () => {
render(<AddPoiModalWindowPopup showPopup={false} closePopup={closePopupMock} handleAddStation={handleAddStationMock} popupCoordinates={popupCoordinatesMock} />);
expect(screen.queryByTestId("add-poi-modal-window")).not.toBeInTheDocument();
});
test("closes the popup when the top right close button is clicked", () => {
render(<AddPoiModalWindowPopup showPopup={true} closePopup={closePopupMock} handleAddStation={handleAddStationMock} popupCoordinates={popupCoordinatesMock} />);
// Use the aria-label to uniquely identify the close button in the outer component
const closeButton = screen.getByRole("button", { name: "Close" });
// Click the button with aria-label "Close"
fireEvent.click(closeButton);
expect(closePopupMock).toHaveBeenCalledTimes(1);
});
test("submits the form when the submit button is clicked", () => {
render(<AddPoiModalWindowPopup showPopup={true} closePopup={closePopupMock} handleAddStation={handleAddStationMock} popupCoordinates={popupCoordinatesMock} />);
fireEvent.click(screen.getByText("Submit"));
expect(handleAddStationMock).toHaveBeenCalledTimes(1); // This should now pass
});
test('clicking the "Close Modal" button inside AddPoiModalWindow should not close the popup', () => {
render(<AddPoiModalWindowPopup showPopup={true} closePopup={closePopupMock} handleAddStation={handleAddStationMock} popupCoordinates={popupCoordinatesMock} />);
// Click the "Close Modal" button inside the mock
fireEvent.click(screen.getByText("Close Modal"));
expect(closePopupMock).toHaveBeenCalledTimes(0); // Should not call the popup close
});
});

View File

@@ -0,0 +1,75 @@
// __tests__/components/pois/AddPoiModalWindowWrapper.test.js
import React from "react";
import { render, screen, fireEvent } from "@testing-library/react";
import "@testing-library/jest-dom";
import AddPoiModalWindowWrapper from "../../../components/pois/AddPoiModalWindowWrapper";
// Mock the AddPoiModalWindow component to avoid testing its internal implementation here
jest.mock("../../../components/pois/AddPoiModalWindow", () => ({ onClose, onSubmit, latlng }) => (
<div data-testid="add-poi-modal-window">
<button onClick={onClose}>Mocked Close</button>
<button onClick={onSubmit}>Mocked Submit</button>
<div>
Mocked Coordinates: {latlng.lat}, {latlng.lng}
</div>
</div>
));
describe("AddPoiModalWindowWrapper", () => {
const onCloseMock = jest.fn();
const handleAddStationMock = jest.fn();
const latlngMock = { lat: 52.52, lng: 13.405 };
beforeEach(() => {
onCloseMock.mockClear();
handleAddStationMock.mockClear();
});
test("renders the modal when 'show' is true", () => {
render(<AddPoiModalWindowWrapper show={true} onClose={onCloseMock} handleAddStation={handleAddStationMock} latlng={latlngMock} />);
// Check if the modal and its contents are in the document
expect(screen.getByTestId("add-poi-modal-window")).toBeInTheDocument();
expect(screen.getByText("Mocked Coordinates: 52.52, 13.405")).toBeInTheDocument();
});
test("does not render the modal when 'show' is false", () => {
render(<AddPoiModalWindowWrapper show={false} onClose={onCloseMock} handleAddStation={handleAddStationMock} latlng={latlngMock} />);
// Check if the modal is not in the document
expect(screen.queryByTestId("add-poi-modal-window")).not.toBeInTheDocument();
});
test("calls onClose when the close button is clicked", () => {
render(<AddPoiModalWindowWrapper show={true} onClose={onCloseMock} handleAddStation={handleAddStationMock} latlng={latlngMock} />);
// Click the close button
fireEvent.click(screen.getByRole("button", { name: "Close" }));
expect(onCloseMock).toHaveBeenCalledTimes(1);
});
test("calls onClose when the background is clicked", () => {
render(<AddPoiModalWindowWrapper show={true} onClose={onCloseMock} handleAddStation={handleAddStationMock} latlng={latlngMock} />);
// Click the background overlay
fireEvent.click(screen.getByTestId("modal-overlay"));
expect(onCloseMock).toHaveBeenCalledTimes(1);
});
test("does not call onClose when the modal content is clicked", () => {
render(<AddPoiModalWindowWrapper show={true} onClose={onCloseMock} handleAddStation={handleAddStationMock} latlng={latlngMock} />);
// Click the modal content
fireEvent.click(screen.getByRole("dialog"));
expect(onCloseMock).toHaveBeenCalledTimes(0);
});
test("calls handleAddStation when the submit button is clicked", () => {
render(<AddPoiModalWindowWrapper show={true} onClose={onCloseMock} handleAddStation={handleAddStationMock} latlng={latlngMock} />);
// Click the submit button
fireEvent.click(screen.getByText("Mocked Submit"));
expect(handleAddStationMock).toHaveBeenCalledTimes(1);
});
});

View File

@@ -0,0 +1,117 @@
// __tests__/components/pois/PoiUpdateModal.test.js
import React from "react";
import { render, screen, fireEvent, waitFor, act } from "@testing-library/react";
import "@testing-library/jest-dom";
import PoiUpdateModal from "../../../components/pois/PoiUpdateModal";
import { useRecoilValue } from "recoil";
import { selectedPoiState, currentPoiState } from "../../../store/atoms/poiState";
// Mock the recoil states
jest.mock("recoil");
describe("PoiUpdateModal", () => {
const mockOnClose = jest.fn();
const mockOnSubmit = jest.fn();
const poiDataMock = {
idPoi: "123",
name: "Test POI",
description: "Test Description",
idPoiTyp: "1",
idLD: "2",
};
const selectedPoiMock = {
idPoi: "123",
typ: "Type1",
};
const currentPoiMock = {
idLD: "2",
};
beforeEach(() => {
useRecoilValue.mockImplementation((state) => {
if (state === selectedPoiState) return selectedPoiMock;
if (state === currentPoiState) return currentPoiMock;
});
mockOnClose.mockClear();
mockOnSubmit.mockClear();
global.fetch = jest.fn((url) => {
if (url === "/api/talas_v5_DB/poiTyp/readPoiTyp") {
return Promise.resolve({
json: () => Promise.resolve([{ idPoiTyp: "1", name: "Type1" }]),
});
} else if (url === "/api/talas_v5_DB/locationDevice/locationDevices") {
return Promise.resolve({
json: () => Promise.resolve([{ id: "2", name: "Device1" }]),
});
} else if (url.startsWith("/api/talas_v5_DB/locationDevice/getDeviceId")) {
return Promise.resolve({
json: () => Promise.resolve({ idLD: "2", name: "Device1" }),
});
} else if (url.startsWith("/api/talas_v5_DB/pois/deletePoi")) {
return Promise.resolve({ ok: true });
} else if (url === "/api/talas_v5_DB/pois/updatePoi") {
return Promise.resolve({ ok: true });
}
});
global.alert = jest.fn(); // Mock alert
delete window.location;
window.location = { reload: jest.fn() }; // Mock location.reload
});
test("renders modal with correct data", async () => {
await act(async () => {
render(<PoiUpdateModal onClose={mockOnClose} poiData={poiDataMock} onSubmit={mockOnSubmit} />);
});
expect(screen.getByDisplayValue("Test Description")).toBeInTheDocument();
expect(screen.getByDisplayValue("Device1")).toBeInTheDocument();
expect(screen.getByDisplayValue("Type1")).toBeInTheDocument();
});
test("handles POI update submission", async () => {
await act(async () => {
render(<PoiUpdateModal onClose={mockOnClose} poiData={poiDataMock} onSubmit={mockOnSubmit} />);
});
fireEvent.change(screen.getByLabelText("Beschreibung:"), { target: { value: "Updated Description" } });
fireEvent.click(screen.getByText("POI aktualisieren"));
await waitFor(() => {
expect(global.fetch).toHaveBeenCalledWith("/api/talas_v5_DB/pois/updatePoi", expect.any(Object));
expect(mockOnClose).toHaveBeenCalledTimes(1);
});
});
test("handles POI deletion", async () => {
window.confirm = jest.fn().mockImplementation(() => true); // Mock confirm dialog to always accept
await act(async () => {
render(<PoiUpdateModal onClose={mockOnClose} poiData={poiDataMock} onSubmit={mockOnSubmit} />);
});
fireEvent.click(screen.getByText("POI löschen"));
await waitFor(() => {
expect(global.fetch).toHaveBeenCalledWith(expect.stringContaining("/api/talas_v5_DB/pois/deletePoi"), { method: "DELETE" });
expect(mockOnClose).toHaveBeenCalledTimes(1);
expect(window.location.reload).toHaveBeenCalledTimes(1);
expect(global.alert).toHaveBeenCalledWith("POI wurde erfolgreich gelöscht.");
});
});
test("closes the modal when the close button is clicked", async () => {
await act(async () => {
render(<PoiUpdateModal onClose={mockOnClose} poiData={poiDataMock} onSubmit={mockOnSubmit} />);
});
fireEvent.click(screen.getByLabelText("Close"));
expect(mockOnClose).toHaveBeenCalledTimes(1);
});
});

View File

@@ -0,0 +1,57 @@
// __tests__/components/pois/PoiUpdateModalWindow.test.js
import React from "react";
import { render, screen } from "@testing-library/react";
import "@testing-library/jest-dom";
import PoiUpdateModalWindow from "../../../components/pois/PoiUpdateModalWindow";
import PoiUpdateModal from "../../../components/pois/PoiUpdateModal";
// Mock the PoiUpdateModal component to avoid testing its internal implementation here
jest.mock("../../../components/pois/PoiUpdateModal", () => ({ onClose, poiData, onSubmit, latlng }) => (
<div data-testid="poi-update-modal">
<button onClick={onClose}>Close</button>
<div>POI Data: {poiData ? poiData.name : "No Data"}</div>
<div>LatLng: {latlng ? `${latlng.lat}, ${latlng.lng}` : "No Coordinates"}</div>
</div>
));
describe("PoiUpdateModalWindow", () => {
const closePoiUpdateModalMock = jest.fn();
const currentPoiDataMock = {
idPoi: "123",
name: "Test POI",
description: "Test Description",
idPoiTyp: "1",
idLD: "2",
};
const popupCoordinatesMock = { lat: 52.52, lng: 13.405 };
beforeEach(() => {
closePoiUpdateModalMock.mockClear();
});
test("renders PoiUpdateModal when showPoiUpdateModal is true", () => {
render(<PoiUpdateModalWindow showPoiUpdateModal={true} closePoiUpdateModal={closePoiUpdateModalMock} currentPoiData={currentPoiDataMock} popupCoordinates={popupCoordinatesMock} />);
// Check if the modal and its contents are in the document
expect(screen.getByTestId("poi-update-modal")).toBeInTheDocument();
expect(screen.getByText("POI Data: Test POI")).toBeInTheDocument();
expect(screen.getByText("LatLng: 52.52, 13.405")).toBeInTheDocument();
});
test("does not render PoiUpdateModal when showPoiUpdateModal is false", () => {
render(<PoiUpdateModalWindow showPoiUpdateModal={false} closePoiUpdateModal={closePoiUpdateModalMock} currentPoiData={currentPoiDataMock} popupCoordinates={popupCoordinatesMock} />);
// Check if the modal is not in the document
expect(screen.queryByTestId("poi-update-modal")).not.toBeInTheDocument();
});
test("calls closePoiUpdateModal when the close button is clicked", () => {
render(<PoiUpdateModalWindow showPoiUpdateModal={true} closePoiUpdateModal={closePoiUpdateModalMock} currentPoiData={currentPoiDataMock} popupCoordinates={popupCoordinatesMock} />);
// Click the close button
screen.getByText("Close").click();
expect(closePoiUpdateModalMock).toHaveBeenCalledTimes(1);
});
});

View File

@@ -0,0 +1,79 @@
// __tests__/components/pois/PoiUpdateModalWrapper.test.js
import React from "react";
import { render, screen, fireEvent, act } from "@testing-library/react";
import "@testing-library/jest-dom";
import PoiUpdateModalWrapper from "../../../components/pois/PoiUpdateModalWrapper";
import { useRecoilValue, useSetRecoilState } from "recoil";
import { currentPoiState, selectedPoiState } from "../../../store/atoms/poiState";
import { poiReadFromDbTriggerAtom } from "../../../store/atoms/poiReadFromDbTriggerAtom";
// Mock Recoil hooks
jest.mock("recoil");
describe("PoiUpdateModalWrapper", () => {
const mockOnClose = jest.fn();
const currentPoiMock = {
idPoi: "123",
name: "Test POI",
description: "Test Description",
idPoiTyp: "1",
idLD: "2",
};
const latlngMock = { lat: 52.52, lng: 13.405 };
beforeEach(() => {
// Mock the recoil values
useRecoilValue.mockImplementation((atom) => {
if (atom === currentPoiState) return currentPoiMock;
if (atom === poiReadFromDbTriggerAtom) return 0;
});
useSetRecoilState.mockImplementation(() => jest.fn());
mockOnClose.mockClear();
// Mock global fetch
global.fetch = jest.fn((url) =>
Promise.resolve({
json: () => {
if (url.includes("getDeviceIdById")) {
return Promise.resolve({ idLD: "2", name: "Device1" });
}
if (url.includes("readPoiTyp")) {
return Promise.resolve([{ idPoiTyp: "1", name: "Type1" }]);
}
if (url.includes("locationDevices")) {
return Promise.resolve([{ id: "2", name: "Device1" }]);
}
return Promise.resolve({});
},
})
);
});
test("renders PoiUpdateModal when 'show' is true", async () => {
await act(async () => {
render(<PoiUpdateModalWrapper show={true} onClose={mockOnClose} latlng={latlngMock} />);
});
// Check if the modal and its contents are in the document
expect(screen.getByDisplayValue("Test Description")).toBeInTheDocument();
});
test("does not render PoiUpdateModal when 'show' is false", () => {
render(<PoiUpdateModalWrapper show={false} onClose={mockOnClose} latlng={latlngMock} />);
// Check if the modal is not in the document
expect(screen.queryByDisplayValue("Test POI")).not.toBeInTheDocument();
});
test("calls onClose when the modal close button is clicked", async () => {
await act(async () => {
render(<PoiUpdateModalWrapper show={true} onClose={mockOnClose} latlng={latlngMock} />);
});
// Simulate closing the modal
fireEvent.click(screen.getByLabelText("Close"));
expect(mockOnClose).toHaveBeenCalledTimes(1);
});
});

View File

@@ -0,0 +1,111 @@
// __tests__/components/pois/PoiUtils.test.js
import { createPoiMarkers, addMarkersToMap, updateLocationInDatabase } from "../../../components/pois/PoiUtils";
// Mock Leaflet
jest.mock("leaflet", () => {
const Leaflet = {
marker: jest.fn((latlng, options) => ({
addTo: jest.fn(),
on: jest.fn(),
options: options,
getLatLng: jest.fn(() => ({
lat: latlng[0],
lng: latlng[1],
})),
})),
icon: jest.fn((options) => options),
};
return Leaflet;
});
describe("PoiUtils", () => {
describe("createPoiMarkers", () => {
it("should create markers with correct coordinates and icon", () => {
const poiData = [
{ idPoi: "1", latitude: 52.52, longitude: 13.405 },
{ idPoi: "2", latitude: 48.8566, longitude: 2.3522 },
];
const iconPath = "path/to/icon.png";
const markers = createPoiMarkers(poiData, iconPath);
expect(markers).toHaveLength(2);
markers.forEach((marker, index) => {
expect(marker.options.icon.iconUrl).toBe(iconPath);
expect(marker.options.icon.iconSize).toEqual([25, 41]);
expect(marker.options.id).toBe(poiData[index].idPoi);
});
});
});
describe("addMarkersToMap", () => {
it("should add markers to map and bind events", () => {
const mockMap = {};
const mockLayerGroup = { addLayer: jest.fn() };
const mockMarker = {
addTo: jest.fn(),
on: jest.fn(),
};
const markers = [mockMarker, mockMarker];
addMarkersToMap(markers, mockMap, mockLayerGroup);
markers.forEach((marker) => {
expect(marker.addTo).toHaveBeenCalledWith(mockLayerGroup);
expect(marker.on).toHaveBeenCalledWith("mouseover", expect.any(Function));
expect(marker.on).toHaveBeenCalledWith("mouseout", expect.any(Function));
expect(marker.on).toHaveBeenCalledWith("dragend", expect.any(Function));
});
});
});
describe("updateLocationInDatabase", () => {
beforeEach(() => {
global.fetch = jest.fn(() =>
Promise.resolve({
ok: true,
json: () => Promise.resolve({}),
})
);
});
afterEach(() => {
jest.clearAllMocks();
});
it("should call fetch with correct parameters", async () => {
const id = "1";
const newLatitude = 52.52;
const newLongitude = 13.405;
await updateLocationInDatabase(id, newLatitude, newLongitude);
expect(fetch).toHaveBeenCalledWith("/api/talas_v5_DB/pois/updateLocation", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
id,
latitude: newLatitude,
longitude: newLongitude,
}),
});
});
it("should log error when fetch response is not ok", async () => {
console.error = jest.fn();
global.fetch = jest.fn(() =>
Promise.resolve({
ok: false,
json: () => Promise.resolve({}),
})
);
await updateLocationInDatabase("1", 52.52, 13.405);
expect(console.error).toHaveBeenCalledWith("Fehler beim Aktualisieren der Position");
});
});
});

View File

@@ -0,0 +1,6 @@
// __tests__/utils/mapUtils.test.js
describe("Dummy test suite", () => {
test("dummy test", () => {
expect(true).toBe(true);
});
});

3
babel.config.js Normal file
View File

@@ -0,0 +1,3 @@
module.exports = {
presets: ["@babel/preset-env", "@babel/preset-react"],
};

View File

@@ -1,3 +1,4 @@
// components/DataSheet.js
import React, { useEffect, useState } from "react"; import React, { useEffect, useState } from "react";
import { useRecoilState, useRecoilValue, useSetRecoilState } from "recoil"; import { useRecoilState, useRecoilValue, useSetRecoilState } from "recoil";
import { gisStationsStaticDistrictState } from "../store/atoms/gisStationState"; import { gisStationsStaticDistrictState } from "../store/atoms/gisStationState";
@@ -5,18 +6,15 @@ import { gisSystemStaticState } from "../store/atoms/gisSystemState";
import { mapLayersState } from "../store/atoms/mapLayersState"; import { mapLayersState } from "../store/atoms/mapLayersState";
import { selectedAreaState } from "../store/atoms/selectedAreaState"; import { selectedAreaState } from "../store/atoms/selectedAreaState";
import { zoomTriggerState } from "../store/atoms/zoomTriggerState"; import { zoomTriggerState } from "../store/atoms/zoomTriggerState";
import { poiLayerVisibleState } from "../store/atoms/poiLayerVisible"; import { poiLayerVisibleState } from "../store/atoms/poiLayerVisibleState";
function DataSheet() { function DataSheet() {
const [poiVisible, setPoiVisible] = useRecoilState(poiLayerVisibleState); const [poiVisible, setPoiVisible] = useRecoilState(poiLayerVisibleState);
const setSelectedArea = useSetRecoilState(selectedAreaState); const setSelectedArea = useSetRecoilState(selectedAreaState);
const [mapLayersVisibility, setMapLayersVisibility] = const [mapLayersVisibility, setMapLayersVisibility] = useRecoilState(mapLayersState);
useRecoilState(mapLayersState);
const [stationListing, setStationListing] = useState([]); const [stationListing, setStationListing] = useState([]);
const [systemListing, setSystemListing] = useState([]); const [systemListing, setSystemListing] = useState([]);
const GisStationsStaticDistrict = useRecoilValue( const GisStationsStaticDistrict = useRecoilValue(gisStationsStaticDistrictState);
gisStationsStaticDistrictState
);
const GisSystemStatic = useRecoilValue(gisSystemStaticState); const GisSystemStatic = useRecoilValue(gisSystemStaticState);
const setZoomTrigger = useSetRecoilState(zoomTriggerState); const setZoomTrigger = useSetRecoilState(zoomTriggerState);
@@ -24,30 +22,31 @@ function DataSheet() {
const selectedIndex = event.target.options.selectedIndex; const selectedIndex = event.target.options.selectedIndex;
const areaName = event.target.options[selectedIndex].text; const areaName = event.target.options[selectedIndex].text;
setSelectedArea(areaName); setSelectedArea(areaName);
console.log("Area selected oder areaName in DataSheet.js:", areaName);
}; };
useEffect(() => { useEffect(() => {
const allowedSystems = new Set( console.log("GisStationsStaticDistrict:", GisStationsStaticDistrict);
GisSystemStatic.filter((system) => system.Allow === 1).map( console.log("GisSystemStatic:", GisSystemStatic);
(system) => system.IdSystem const allowedSystems = new Set(GisSystemStatic.filter((system) => system.Allow === 1).map((system) => system.IdSystem));
) console.log("allowedSystems:", allowedSystems);
);
const seenNames = new Set(); const seenNames = new Set();
const filteredAreas = GisStationsStaticDistrict.filter((item) => { const filteredAreas = GisStationsStaticDistrict.filter((item) => {
const isUnique = const isUnique = !seenNames.has(item.Area_Name) && allowedSystems.has(item.System);
!seenNames.has(item.Area_Name) && allowedSystems.has(item.System);
if (isUnique) { if (isUnique) {
seenNames.add(item.Area_Name); seenNames.add(item.Area_Name);
} }
return isUnique; return isUnique;
}); });
setStationListing( setStationListing(
filteredAreas.map((area, index) => ({ filteredAreas.map((area, index) => ({
id: index + 1, id: index + 1,
name: area.Area_Name, name: area.Area_Name,
})) }))
); );
//console.log("filteredAreas:", filteredAreas);
const seenSystemNames = new Set(); const seenSystemNames = new Set();
const filteredSystems = GisSystemStatic.filter((item) => { const filteredSystems = GisSystemStatic.filter((item) => {
const formattedName = item.Name.replace(/[\s\-]+/g, ""); const formattedName = item.Name.replace(/[\s\-]+/g, "");
@@ -57,6 +56,7 @@ function DataSheet() {
} }
return isUnique; return isUnique;
}); });
setSystemListing( setSystemListing(
filteredSystems.map((system, index) => ({ filteredSystems.map((system, index) => ({
id: index + 1, id: index + 1,
@@ -64,19 +64,21 @@ function DataSheet() {
})) }))
); );
}, [GisStationsStaticDistrict, GisSystemStatic]); }, [GisStationsStaticDistrict, GisSystemStatic]);
//}, []);
//-----------------------------------------
//-----------------------------------------
const handleCheckboxChange = (name, event) => { const handleCheckboxChange = (name, event) => {
const { checked } = event.target; const { checked } = event.target;
console.log(`Checkbox ${name} checked state:`, checked);
setMapLayersVisibility((prev) => { setMapLayersVisibility((prev) => {
const newState = { const newState = {
...prev, ...prev,
[name]: checked, [name]: checked,
}; };
console.log(`New mapLayersVisibility state:`, newState);
return newState; return newState;
}); });
console.log("mapLayersVisibility:", mapLayersVisibility);
}; };
const handleIconClick = () => { const handleIconClick = () => {
@@ -85,16 +87,14 @@ function DataSheet() {
}; };
return ( return (
<div <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">
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 className="flex flex-col gap-4 p-4"> <div className="flex flex-col gap-4 p-4">
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<select <select
onChange={handleAreaChange} onChange={handleAreaChange}
id="stationListing" id="stationListing"
className="border-solid-1 p-2 rounded ml-1 font-semibold" className="border-solid-1 p-2 rounded ml-1 font-semibold"
role="combobox" // Ensure the correct role is set
> >
<option value="Station wählen">Station wählen</option> <option value="Station wählen">Station wählen</option>
{stationListing.map((station) => ( {stationListing.map((station) => (
@@ -103,22 +103,15 @@ function DataSheet() {
</option> </option>
))} ))}
</select> </select>
<img <img src="/img/expand-icon.svg" alt="Expand" className="h-6 w-6 ml-2 cursor-pointer" onClick={handleIconClick} />
src="/img/expand-icon.svg"
alt="Expand"
className="h-6 w-6 ml-2 cursor-pointer"
onClick={handleIconClick}
/>
</div> </div>
<div> <div>
{systemListing.map((system) => ( {systemListing.map((system) => (
<React.Fragment key={system.id}> <React.Fragment key={system.id}>
<input <input type="checkbox" checked={mapLayersVisibility[system.name] || false} onChange={(e) => handleCheckboxChange(system.name, e)} id={`system-${system.id}`} />
type="checkbox" <label htmlFor={`system-${system.id}`} className="text-sm ml-2">
checked={mapLayersVisibility[system.name] || false} {system.name}
onChange={(e) => handleCheckboxChange(system.name, e)} </label>
/>
<label className="text-sm ml-2">{system.name}</label>
<br /> <br />
</React.Fragment> </React.Fragment>
))} ))}
@@ -128,12 +121,12 @@ function DataSheet() {
onChange={(e) => { onChange={(e) => {
const checked = e.target.checked; const checked = e.target.checked;
setPoiVisible(checked); setPoiVisible(checked);
console.log(
`POIs sind jetzt ${checked ? "sichtbar" : "nicht sichtbar"}.`
);
}} }}
id="poi-checkbox"
/> />
<label className="text-sm ml-2">POIs</label> <label htmlFor="poi-checkbox" className="text-sm ml-2">
POIs
</label>
</div> </div>
</div> </div>
</div> </div>

File diff suppressed because it is too large Load Diff

View 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;

View 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;

View 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;

View 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;

View 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],
});

160
components/imports.js Normal file
View File

@@ -0,0 +1,160 @@
// 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 { insertNewMarker, removeMarker, createAndSetMarkers, handleEditPoi } from "../utils/markerUtils.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/contextMenuUtils.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/mapInitialization.js";
import { addItemsToMapContextMenu } from "./useMapContextMenu.js";
import useGmaMarkersLayer from "../hooks/useGmaMarkersLayer.js"; // Import the custom hook
import useTalasMarkersLayer from "../hooks/talasMarkersLayer.js"; // Import the custom hook
import useEciMarkersLayer from "../hooks/useEciMarkersLayer.js";
import useGsmModemMarkersLayer from "../hooks/useGsmModemMarkersLayer.js";
import useCiscoRouterMarkersLayer from "../hooks/useCiscoRouterMarkersLayer.js";
import useWagoMarkersLayer from "../hooks/useWagoMarkersLayer.js";
import useSiemensMarkersLayer from "../hooks/useSiemensMarkersLayer.js";
import useOtdrMarkersLayer from "../hooks/useOtdrMarkersLayer.js";
import useWdmMarkersLayer from "../hooks/useWdmMarkersLayer.js";
import useMessstellenMarkersLayer from "../hooks/useMessstellenMarkersLayer.js";
import useTalasiclMarkersLayer from "../hooks/useTalasiclMarkersLayer.js";
import useDauzMarkersLayer from "../hooks/useDauzMarkersLayer.js";
import useSmsfunkmodemMarkersLayer from "../hooks/useSmsfunkmodemMarkersLayer.js";
import useUlafMarkersLayer from "../hooks/useUlafMarkersLayer.js";
import useSonstigeMarkersLayer from "../hooks/useSonstigeMarkersLayer.js";
import handlePoiSelect from "../utils/handlePoiSelect.js";
import { fetchGisStationsStaticDistrict, fetchGisStationsStatusDistrict, fetchGisStationsMeasurements, fetchGisSystemStatic } from "../services/fetchData.js";
import { setupPolylines, setupMarkers } from "../utils/mapFeatures.js"; // Import the functions
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,
insertNewMarker,
removeMarker,
createAndSetMarkers,
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,
setupMarkers,
VersionInfoModal,
PoiUpdateModalWrapper,
AddPoiModalWindowWrapper,
useFetchPoiData,
usePoiTypData,
useMarkerLayers,
useLayerVisibility,
useLineData,
};

View File

@@ -0,0 +1,145 @@
// components/pois/AddPoiModalWindow.js
import React, { useState, useEffect, use } from "react";
import ReactDOM from "react-dom";
import { useRecoilValue, useRecoilState, useSetRecoilState } from "recoil";
import { readPoiMarkersStore } from "../../store/selectors/readPoiMarkersStore";
import { poiReadFromDbTriggerAtom } from "../../store/atoms/poiReadFromDbTriggerAtom";
const AddPoiModalWindow = ({ onClose, map, latlng }) => {
const [poiTypData, setpoiTypData] = useState(); // Recoil State verwenden
const [name, setName] = useState("");
const [poiTypeId, setPoiTypeId] = useState(""); // Initialize as string
const [poiTypeName, setPoiTypeName] = useState(""); // Initialize as string
const [latitude] = useState(latlng.lat.toFixed(5));
const [longitude] = useState(latlng.lng.toFixed(5));
const setLoadData = useSetRecoilState(readPoiMarkersStore);
const setTrigger = useSetRecoilState(poiReadFromDbTriggerAtom);
const [locationDeviceData, setLocationDeviceData] = useState([]);
const [deviceName, setDeviceName] = useState("");
//------------------------------------------------------------------------------------------
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);
if (poiTypData.length > 0) {
setPoiTypeId(poiTypData[0].idPoiTyp); // Set initial poiTypeId to the id of the first poiType
if (poiTypData[1]) {
setPoiTypeName(poiTypData[1].name);
}
}
const locationDeviceData = await locationDeviceResponse.json();
setLocationDeviceData(locationDeviceData);
if (locationDeviceData.length > 0) {
setDeviceName(locationDeviceData[0].name); // Set initial device name
}
} catch (error) {
console.error("Fehler beim Abrufen der Daten:", error);
}
};
fetchInitialData();
}, []);
//------------------------------------------------------------------------------------------
//-----------------handleSubmit-------------------
const handleSubmit = async (event) => {
event.preventDefault();
const formData = {
name,
poiTypeId,
latitude,
longitude,
idLD: locationDeviceData.find((device) => device.name === deviceName).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) => {
//console.log("Aktueller Trigger-Wert:", trigger); // Vorheriger Wert
const newTrigger = trigger + 1;
//console.log("Neuer Trigger-Wert:", newTrigger); // Aktualisierter Wert
onClose();
return newTrigger;
});
// Browser aktualisieren
window.location.reload();
} else {
console.error("Fehler beim Hinzufügen des POI");
}
if (map && typeof map.closePopup === "function") {
map.closePopup();
}
};
//-----------------handleSubmit-------------------
return (
<form onSubmit={handleSubmit} className="m-0 p-2 w-full ">
<div className="flex items-center mb-4">
<label htmlFor="name" className="block mr-2 flex-none">
Name :
</label>
<input type="text" id="name" name="name" value={name} onChange={(e) => setName(e.target.value)} placeholder="Name der Station" className="block p-2 w-full border-2 border-gray-200 rounded-md text-sm" />
</div>
{/* {locationDeviceData.----------------------------------------------*/}
<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.name}>
{device.name}
</option>
))}
</select>
</div>
{/* {locationDeviceData.----------------------------------------------*/}
<div className="flex items-center mb-4">
<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">
{poiTypData &&
poiTypData.map((poiTyp, index) => (
<option key={poiTyp.idPoiTyp || index} value={poiTyp.idPoiTyp}>
{poiTyp.name}
</option>
))}
</select>
</div>
<div className="flex flex-row items-center justify-center">
<div className="flex items-center mb-4">
<label htmlFor="lat" className="block mr-2 flex-none text-xs">
Lat : {latitude}
</label>
</div>
<div className="flex items-center mb-4">
<label htmlFor="lng" className="block mr-2 flex-none text-xs">
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;

View 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;

View 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;

View File

@@ -0,0 +1,213 @@
// components/pois/poiUpdateModal.js
import React, { useState, useEffect } from "react";
import { useRecoilValue } from "recoil";
import { selectedPoiState } from "../../store/atoms/poiState";
import { currentPoiState } from "../../store/atoms/currentPoiState";
const PoiUpdateModal = ({ onClose, poiData, onSubmit }) => {
const currentPoi = useRecoilValue(currentPoiState);
const selectedPoi = useRecoilValue(selectedPoiState);
const [poiId, setPoiId] = useState(poiData ? poiData.idPoi : "");
const [name, setName] = useState(poiData ? poiData.name : "");
const [poiTypData, setPoiTypData] = useState([]);
const [poiTypeId, setPoiTypeId] = useState("");
const [locationDeviceData, setLocationDeviceData] = useState([]);
const [deviceName, setDeviceName] = useState("");
const [idLD, setIdLD] = useState(poiData ? poiData.idLD : "");
const [description, setDescription] = useState(poiData ? poiData.description : "");
useEffect(() => {
if (poiData) {
//console.log("Initial poiData:", poiData);
setPoiId(poiData.idPoi);
setName(poiData.name);
setPoiTypeId(poiData.idPoiTyp);
setIdLD(poiData.idLD);
setDescription(poiData.description);
setDeviceName(poiData.idLD);
//console.log("Loaded POI Data for editing:", poiData);
}
}, [poiData]);
useEffect(() => {
const fetchDeviceId = async () => {
if (poiData && poiData.idLD) {
try {
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);
}
}
};
fetchDeviceId();
}, [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",
});
if (response.ok) {
alert("POI wurde erfolgreich gelöscht.");
onClose();
window.location.reload();
} 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.");
}
}
};
useEffect(() => {
const fetchPoiTypData = async () => {
try {
const response = await fetch("/api/talas_v5_DB/poiTyp/readPoiTyp");
const data = await response.json();
setPoiTypData(data);
if (selectedPoi && data) {
const matchingType = data.find((pt) => pt.name === selectedPoi.typ);
if (matchingType) {
setPoiTypeId(matchingType.idPoiTyp);
}
}
} catch (error) {
console.error("Fehler beim Abrufen der poiTyp Daten:", error);
}
};
fetchPoiTypData();
}, [selectedPoi]);
useEffect(() => {
const fetchData = async () => {
try {
// const response = await fetch("/api/talas_v5/location_device"); //"/api/talas_v5_DB/locationDevice/location_device"
const response = await fetch("/api/talas_v5_DB/locationDevice/locationDevices");
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);
//console.log("Selected Device in poiUpdate:", selectedDevice);
}
} catch (error) {
console.error("Fehler beim Abrufen der Standort- und Gerätedaten:", error);
}
};
fetchData();
}, []);
useEffect(() => {
fetch("/api/talas_v5_DB/locationDevice/locationDevices")
.then((response) => response.json())
.then((data) => {
setLocationDeviceData(data);
const currentDevice = data.find((device) => device.idLD === currentPoi.idLD);
if (currentDevice) {
setDeviceName(currentDevice.name);
//console.log("Current Device name in poiUpdate:", currentDevice.name);
}
})
.catch((error) => {
console.error("Fehler beim Abrufen der Gerätedaten:", error);
setLocationDeviceData([]);
});
}, [poiData?.idLD, currentPoi]);
const handleSubmit = async (event) => {
event.preventDefault();
const idLDResponse = await fetch(`/api/talas_v5_DB/locationDevice/getDeviceId?deviceName=${encodeURIComponent(deviceName)}`);
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,
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.");
}
};
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 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" />
</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>
</div>
<div className="flex items-center mb-4">
<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">
{poiTypData.map((poiTyp, index) => (
<option key={index} value={poiTyp.idPoiTyp}>
{poiTyp.name}
</option>
))}
</select>
</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;

View 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;

View 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;

View File

@@ -0,0 +1,52 @@
// 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) => {
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

View File

@@ -0,0 +1,77 @@
// /components/useMapContextMenu.js
import { toast } from "react-toastify";
import { zoomIn, zoomOut, centerHere } from "../utils/zoomAndCenterUtils"; // Assuming these are imported correctly
const zoomInCallback = (e, map) => {
zoomIn(e, map);
};
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) => {
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) => {
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),
});
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, setShowPopup, setPopupCoordinates),
});
setMenuItemAdded(true);
}
};

View File

@@ -1,18 +1,21 @@
// Definieren der grundlegenden Umgebungseinstellungen und Konfigurationen der Karte // /config/config.js
import * as urls from "../config/urls.js";
// Definieren der grundlegenden Umgebungseinstellungen und Konfigurationen der Karte
const mapVersion = "0.5.3"; // Die Version der verwendeten Karte const mapVersion = "0.5.3"; // Die Version der verwendeten Karte
const standardSideMenu = true; // Einstellung, ob ein standardmäßiges Seitenmenü verwendet wird const standardSideMenu = true; // Einstellung, ob ein standardmäßiges Seitenmenü verwendet wird
const fullSideMenu = false; // Einstellung, ob ein vollständiges Seitenmenü verwendet wird const fullSideMenu = false; // Einstellung, ob ein vollständiges Seitenmenü verwendet wird
const serverURL = "/api"; // Die Basis-URL des Servers, von dem Daten bezogen werden //const serverURL = "/api"; // Die Basis-URL des Servers, von dem Daten bezogen werden
//const serverURL = "http://10.10.0.13";
//const serverURL = "http://10.10.0.70";
const serverURL = process.env.NEXT_PUBLIC_SERVER_URL;
if (!serverURL) {
throw new Error("Die Umgebungsvariable NEXT_PUBLIC_SERVER_URL ist nicht gesetzt!");
}
console.log("serverURL in config:", serverURL);
// Initialisieren von Variablen, die später im Browserkontext gesetzt werden // Initialisieren von Variablen, die später im Browserkontext gesetzt werden
let windowHeight, url_string, url, c, user; let windowHeight, url_string, url, idMap, idUser;
//Online Daten //Online Daten
let mapGisStationsStaticDistrictUrl, let mapGisStationsStaticDistrictUrl, mapGisStationsStatusDistrictUrl, mapGisStationsMeasurementsUrl, mapGisSystemStaticUrl, mapDataIconUrl, webserviceGisLinesStatusUrl;
mapGisStationsStatusDistrictUrl,
mapGisStationsMeasurementsUrl,
mapGisSystemStaticUrl,
mapDataIconUrl,
webserviceGisLinesStatusUrl;
// Prüfen, ob das Code im Browser ausgeführt wird // Prüfen, ob das Code im Browser ausgeführt wird
if (typeof window !== "undefined") { if (typeof window !== "undefined") {
@@ -20,28 +23,31 @@ if (typeof window !== "undefined") {
windowHeight = window.innerHeight; // Die Höhe des Browserfensters windowHeight = window.innerHeight; // Die Höhe des Browserfensters
url_string = window.location.href; // Die vollständige URL als String url_string = window.location.href; // Die vollständige URL als String
url = new URL(url_string); // Die URL als URL-Objekt, um Teile der URL einfacher zu handhaben url = new URL(url_string); // Die URL als URL-Objekt, um Teile der URL einfacher zu handhaben
c = url.searchParams.get("m"); // Ein Parameter aus der URL, Standardwert ist '10' console.log("URL in config:", url);
user = url.searchParams.get("u"); // Ein weiterer Parameter aus der URL, Standardwert ist '484 admin zu testen von Stationen ausblenden und einblenden in der Card' console.log("URL origin in config:", url.origin); //http://localhost:3000
idMap = url.searchParams.get("m"); // Ein Parameter aus der URL, Standardwert ist '10'
idUser = url.searchParams.get("u"); // Ein weiterer Parameter aus der URL, Standardwert ist '484 admin zu testen von Stationen ausblenden und einblenden in der Card'
console.log(`Parameter 'idMap' : ${c}`); console.log(`Parameter 'idMap' : ${idMap}`);
console.log(`Parameter 'idUser': ${user}`); console.log(`Parameter 'idUser': ${idUser}`);
console.log(`Parameter 'idMap' : ${c}`);
console.log(`Parameter 'idUser': ${user}`);
// Konstruktion von URLs, die auf spezifische Ressourcen auf dem Server zeigen // Konstruktion von URLs, die auf spezifische Ressourcen auf dem Server zeigen
//http://localhost:3000/?m=10&u=485 //http://localhost:3000/?m=10&u=485
//-----------------Von WebService------------------------------------------------ //-----------------Von WebService------------------------------------------------
mapGisStationsStaticDistrictUrl = `${serverURL}/talas5/ClientData/WebserviceMap.asmx/GisStationsStaticDistrict?idMap=${c}&idUser=${user}`; //idMap: 10, idUser: 484 mapGisStationsStaticDistrictUrl = `${serverURL}/talas5/ClientData/WebserviceMap.asmx/GisStationsStaticDistrict?idMap=${idMap}&idUser=${idUser}`; //idMap: 10, idUser: 484
mapGisStationsStatusDistrictUrl = `${serverURL}/talas5/ClientData/WebserviceMap.asmx/GisStationsStatusDistrict?idMap=${c}&idUser=${user}`; mapGisStationsStatusDistrictUrl = `${serverURL}/talas5/ClientData/WebserviceMap.asmx/GisStationsStatusDistrict?idMap=${idMap}&idUser=${idUser}`;
mapGisStationsMeasurementsUrl = `${serverURL}/talas5/ClientData/WebserviceMap.asmx/GisStationsMeasurements?idMap=${c}`; mapGisStationsMeasurementsUrl = `${serverURL}/talas5/ClientData/WebserviceMap.asmx/GisStationsMeasurements?idMap=${idMap}`;
mapGisSystemStaticUrl = `${serverURL}/talas5/ClientData/WebserviceMap.asmx/GisSystemStatic?idMap=${c}&idUser=${user}`; mapGisSystemStaticUrl = `${serverURL}/talas5/ClientData/WebserviceMap.asmx/GisSystemStatic?idMap=${idMap}&idUser=${idUser}`;
mapDataIconUrl = `${serverURL}/talas5/ClientData/WebserviceMap.asmx/GetIconsStatic`; mapDataIconUrl = `${serverURL}/talas5/ClientData/WebserviceMap.asmx/GetIconsStatic`;
//webserviceGisLinesStatusUrl = `http://10.10.0.13/talas5/ClientData/WebServiceMap.asmx/GisLinesStatus?idMap=${c}`; //webserviceGisLinesStatusUrl = `http://10.10.0.13/talas5/ClientData/WebServiceMap.asmx/GisLinesStatus?idMap=${idMap}`;
webserviceGisLinesStatusUrl = `http://localhost:3000/api/linesColorApi`; //webserviceGisLinesStatusUrl = `http://localhost:3000/api/linesColorApi`;
//webserviceGisLinesStatusUrl = `http://192.168.10.14/talas5/ClientData/WebServiceMap.asmx/GisLinesStatus?idMap=${c}`; //webserviceGisLinesStatusUrl = `http://localhost:3000/api/linesColorApi`;
//webserviceGisLinesStatusUrl = `${"serverURL"}:3000/api/linesColorApi`;
// webserviceGisLinesStatusUrl = `http://localhost:3000/api/linesColorApi`;
//webserviceGisLinesStatusUrl = `http://192.168.10.14/talas5/ClientData/WebServiceMap.asmx/GisLinesStatus?idMap=${idMap}`;
webserviceGisLinesStatusUrl = `${serverURL}/talas5/ClientData/WebServiceMap.asmx/GisLinesStatus?idMap=${idMap}`;
//http://10.10.0.13/talas5/ClientData/WebserviceMap.asmx/GisSystemStatic?idMap=12&idUser=484 //http://10.10.0.13/talas5/ClientData/WebserviceMap.asmx/GisSystemStatic?idMap=12&idUser=484
@@ -51,11 +57,11 @@ if (typeof window !== "undefined") {
mapGisSystemStaticUrl = `${serverURL}/talas5/ClientData/WebserviceMap.asmx/GisSystemStatic`; mapGisSystemStaticUrl = `${serverURL}/talas5/ClientData/WebserviceMap.asmx/GisSystemStatic`;
mapDataIconUrl = `${serverURL}/talas5/ClientData/WebserviceMap.asmx/GetIconsStatic`; */ mapDataIconUrl = `${serverURL}/talas5/ClientData/WebserviceMap.asmx/GetIconsStatic`; */
/* mapGisStationsStaticDistrictUrl = `${serverURL}/api/talas5/webserviceMap/GisStationsStaticDistrict?idMap=${c}&idUser=${user}`; /* mapGisStationsStaticDistrictUrl = `${serverURL}/api/talas5/webserviceMap/GisStationsStaticDistrict?idMap=${idMap}&idUser=${idUser}`;
mapGisStationsStatusDistrictUrl = `${serverURL}/api/talas5/webserviceMap/GisStationsStatusDistrict?idMap=${c}&idUser=${user}`; mapGisStationsStatusDistrictUrl = `${serverURL}/api/talas5/webserviceMap/GisStationsStatusDistrict?idMap=${idMap}&idUser=${idUser}`;
mapGisStationsMeasurementsUrl = `${serverURL}/api/talas5/webserviceMap/GisStationsMeasurements?idMap=${c}`; mapGisStationsMeasurementsUrl = `${serverURL}/api/talas5/webserviceMap/GisStationsMeasurements?idMap=${idMap}`;
mapGisStationsMeasurementsUrl = `${serverURL}/api/talas5/webserviceMap/gisStationsMeasurementsSQL?idMap=${c}`; mapGisStationsMeasurementsUrl = `${serverURL}/api/talas5/webserviceMap/gisStationsMeasurementsSQL?idMap=${idMap}`;
mapGisSystemStaticUrl = `${serverURL}/api/talas5/webserviceMap/GisSystemStatic?idMap=${c}&idUser=${user}`; mapGisSystemStaticUrl = `${serverURL}/api/talas5/webserviceMap/GisSystemStatic?idMap=${idMap}&idUser=${idUser}`;
mapDataIconUrl = `${serverURL}/api/talas5/webserviceMap/GetIconsStatic`; */ mapDataIconUrl = `${serverURL}/api/talas5/webserviceMap/GetIconsStatic`; */
} }
@@ -68,8 +74,8 @@ export {
windowHeight, windowHeight,
url_string, url_string,
url, url,
c, idMap,
user, idUser,
mapGisStationsStaticDistrictUrl, mapGisStationsStaticDistrictUrl,
mapGisStationsStatusDistrictUrl, mapGisStationsStatusDistrictUrl,
mapGisStationsMeasurementsUrl, mapGisStationsMeasurementsUrl,
@@ -77,3 +83,9 @@ export {
mapDataIconUrl, mapDataIconUrl,
webserviceGisLinesStatusUrl, webserviceGisLinesStatusUrl,
}; };
/*
Access to fetch at 'http://localhost:3000/api/linesColorApi' from origin 'http://10.10.0.13:3000' has been blocked by CORS policy:
No 'Access-Control-Allow-Origin' header is present on the requested resource.
If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
*/

17
config/layers.js Normal file
View File

@@ -0,0 +1,17 @@
import L from "leaflet";
export const MAP_LAYERS = {
TALAS: new L.layerGroup(),
ECI: new L.layerGroup(),
ULAF: new L.layerGroup(),
GSMModem: new L.layerGroup(),
CiscoRouter: new L.layerGroup(),
WAGO: new L.layerGroup(),
Siemens: new L.layerGroup(),
OTDR: new L.layerGroup(),
WDM: new L.layerGroup(),
GMA: new L.layerGroup(),
Sonstige: new L.layerGroup(),
TALASICL: new L.layerGroup(),
lineLayer: new L.LayerGroup(),
};

5
config/settings.js Normal file
View File

@@ -0,0 +1,5 @@
// /config/settings.js
// Definieren der grundlegenden Umgebungseinstellungen und Konfigurationen der Karte
export const MAP_VERSION = "1.0.0";
//export const STANDARD_SIDE_MENU = true;
//export const FULL_SIDE_MENU = false;

45
config/urls.js Normal file
View File

@@ -0,0 +1,45 @@
// /config/urls.js
export const BASE_URL = process.env.NEXT_PUBLIC_BASE_URL; //Station in Tab öffnen
export const SERVER_URL = process.env.NEXT_PUBLIC_SERVER_URL; //Die Konstante ist in MapComponent.js und useLineData.js verwendet
export const PROXY_TARGET = process.env.NEXT_PUBLIC_PROXY_TARGET; // damit nodejs auf Port 3000 auf dem Server Talas5 auf Port 80 aufgerufen kann, ansonsten gibt CORS Fehler
export const ONLINE_TILE_LAYER = process.env.NEXT_PUBLIC_ONLINE_TILE_LAYER; //Map von Talas_v5 Server
//-----------------------------------
//export const ONLINE_TILE_LAYER = "http://10.10.0.13:3000/mapTiles/{z}/{x}/{y}.png"; //Map von Talas_v5 Server
// export const PROXY_TARGET = "http://10.10.0.70"; // damit nodejs auf Port 3000 auf dem Server Talas5 auf Port 80 aufgerufen kann, ansonsten gibt CORS Fehler
// export const SERVER_URL = "http://10.10.0.70"; //Die Konstante ist in MapComponent.js und useLineData.js verwendet
// export const BASE_URL = "http://10.10.0.70/talas5/devices/"; //Station in Tab öffnen
// //-----------------------------------
/* export const ONLINE_TILE_LAYER = "http://192.168.10.14:3000/mapTiles/{z}/{x}/{y}.png"; //Map von Talas_v5 Server
export const PROXY_TARGET = "http://192.168.10.167"; // damit nodejs auf Port 3000 auf dem Server Talas5 auf Port 80 aufgerufen kann, ansonsten gibt CORS Fehler
export const SERVER_URL = "http://192.168.10.167"; //Die Konstante ist in MapComponent.js und useLineData.js verwendet
export const BASE_URL = "http://192.168.10.167/talas5/devices/"; //Station in Tab öffnen */
//-----------------------------------
// export const ONLINE_TILE_LAYER = "http://192.168.10.14:3000/mapTiles/{z}/{x}/{y}.png"; //Map von Talas_v5 Server */
// export const PROXY_TARGET = "http://localhost"; // damit nodejs auf Port 3000 auf dem Server Talas5 auf Port 80 aufgerufen kann, ansonsten gibt CORS Fehler
// export const SERVER_URL = "http://localhost"; //in MapComponent.js wird es verwendet
// export const BASE_URL = "http://localhost/talas5/devices/"; //Station in Tab öffnen
//-----------------------------------
//-----------------------------------
// weil ich keine API habe, ansonsten serverURL ist localhost(IP-Adresse) für GisSystemStatic für die Benutzerrechte
//const serverURL = `${protocol}//${hostname}`;
//const serverURL = `${protocol}//${hostname}${port ? `:${port}` : ""}`;
//const serverURL = "http://localhost:3000";
//export const SERVER_URL = "http://10.10.0.13";
//export const SERVER_URL = "http://10.10.0.70";
// Online Daten URLs
/* export const MAP_GIS_STATIONS_STATIC_DISTRICT_URL = `${SERVER_URL}/talas5/ClientData/WebserviceMap.asmx/GisStationsStaticDistrict?idMap=${c}&idUser=${user}`; //idMap: 10, idUser: 484
export const MAP_GIS_STATIONS_STATUS_DISTRICT_URL = `${SERVER_URL}/talas5/ClientData/WebserviceMap.asmx/GisStationsStatusDistrict?idMap=${c}&idUser=${user}`;
export const MAP_GIS_STATIONS_MEASUREMENTS_URL = `${SERVER_URL}/talas5/ClientData/WebserviceMap.asmx/GisStationsMeasurements?idMap=${c}`;
export const MAP_GIS_SYSTEM_STATIC_URL = `${SERVER_URL}/talas5/ClientData/WebserviceMap.asmx/GisSystemStatic?idMap=${c}&idUser=${user}`;
export const MAP_DATA_ICON_URL = `${SERVER_URL}/talas5/ClientData/WebserviceMap.asmx/GetIconsStatic`;
export const WEBSERVICE_GIS_LINES_STATUS_URL =
"http://localhost:3000/api/linesColorApi";
*/
/*
Access to fetch at 'http://localhost:3000/api/linesColorApi' from origin 'http://10.10.0.13:3000' has been blocked by CORS policy:
No 'Access-Control-Allow-Origin' header is present on the requested resource.
If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
*/

View File

@@ -0,0 +1,47 @@
import { useEffect, useState } from "react";
import L from "leaflet";
import { createAndSetMarkers } from "../utils/markerUtils";
import { addContextMenuToMarker } from "../utils/contextMenuUtils";
import { checkOverlappingMarkers } from "../utils/mapUtils";
const useTalasMarkersLayer = (map, oms, GisSystemStatic, priorityConfig) => {
const [talasMarkers, setTalasMarkers] = useState([]);
useEffect(() => {
if (GisSystemStatic && GisSystemStatic.length && map) {
createAndSetMarkers(1, setTalasMarkers, GisSystemStatic, priorityConfig); // TALAS-System
}
}, [GisSystemStatic, map, priorityConfig]);
useEffect(() => {
if (map && talasMarkers.length) {
talasMarkers.forEach((marker) => {
marker.addTo(map);
oms.addMarker(marker);
// Popup beim Überfahren mit der Maus öffnen und schließen
marker.on("mouseover", function () {
this.openPopup();
});
marker.on("mouseout", function () {
this.closePopup();
});
addContextMenuToMarker(marker);
});
// Disable map context menu
map.options.contextmenu = false;
map.options.contextmenuItems = [];
oms.map.options.contextmenu = false;
oms.map.options.contextmenuItems = [];
// Call the function to check for overlapping markers
checkOverlappingMarkers(oms, map);
}
}, [map, talasMarkers]);
return talasMarkers;
};
export default useTalasMarkersLayer;

View File

@@ -0,0 +1,49 @@
// hooks/useCiscoRouterMarkersLayer.js
import { useEffect, useState } from "react";
import L from "leaflet";
import { createAndSetMarkers } from "../utils/markerUtils";
import { addContextMenuToMarker } from "../utils/contextMenuUtils";
import { checkOverlappingMarkers } from "../utils/mapUtils";
const useCiscoRouterMarkersLayer = (map, oms, GisSystemStatic, priorityConfig) => {
const [ciscoRouterMarkers, setCiscoRouterMarkers] = useState([]);
useEffect(() => {
if (GisSystemStatic && GisSystemStatic.length && map) {
createAndSetMarkers(6, setCiscoRouterMarkers, GisSystemStatic, priorityConfig); // Cisco Router
}
}, [GisSystemStatic, map, priorityConfig]);
useEffect(() => {
if (map && ciscoRouterMarkers.length) {
ciscoRouterMarkers.forEach((marker) => {
marker.addTo(map);
oms.addMarker(marker);
// Popup on mouseover and mouseout
marker.on("mouseover", function () {
this.openPopup();
});
marker.on("mouseout", function () {
this.closePopup();
});
addContextMenuToMarker(marker);
});
// Disable map context menu
map.options.contextmenu = false;
map.options.contextmenuItems = [];
oms.map.options.contextmenu = false;
oms.map.options.contextmenuItems = [];
// Call the function to check for overlapping markers
checkOverlappingMarkers(oms, map);
}
}, [map, ciscoRouterMarkers]);
return ciscoRouterMarkers;
};
export default useCiscoRouterMarkersLayer;

View File

@@ -0,0 +1,45 @@
// hooks/useDauzMarkersLayer.js
import { useEffect, useState } from "react";
import L from "leaflet";
import { addContextMenuToMarker } from "../utils/contextMenuUtils";
import { createAndSetMarkers } from "../utils/markerUtils";
const useDauzMarkersLayer = (map, oms, GisSystemStatic, priorityConfig) => {
const [dauzMarkers, setDauzMarkers] = useState([]);
useEffect(() => {
if (GisSystemStatic && GisSystemStatic.length && map) {
createAndSetMarkers(110, setDauzMarkers, GisSystemStatic, priorityConfig); // DAUZ
}
}, [GisSystemStatic, map, priorityConfig]);
useEffect(() => {
if (map && dauzMarkers.length) {
dauzMarkers.forEach((marker) => {
marker.addTo(map);
oms.addMarker(marker);
// Popup on mouseover and mouseout
marker.on("mouseover", function () {
this.openPopup();
});
marker.on("mouseout", function () {
this.closePopup();
});
addContextMenuToMarker(marker);
});
// Disable map context menu
map.options.contextmenu = false;
map.options.contextmenuItems = [];
oms.map.options.contextmenu = false;
oms.map.options.contextmenuItems = [];
}
}, [map, dauzMarkers, oms]);
return dauzMarkers;
};
export default useDauzMarkersLayer;

View File

@@ -0,0 +1,47 @@
import { useEffect, useState } from "react";
import L from "leaflet";
import { createAndSetMarkers } from "../utils/markerUtils";
import { addContextMenuToMarker } from "../utils/contextMenuUtils";
import { checkOverlappingMarkers } from "../utils/mapUtils";
const useEciMarkersLayer = (map, oms, GisSystemStatic, priorityConfig) => {
const [eciMarkers, setEciMarkers] = useState([]);
useEffect(() => {
if (GisSystemStatic && GisSystemStatic.length && map) {
createAndSetMarkers(2, setEciMarkers, GisSystemStatic, priorityConfig); // ECI-System
}
}, [GisSystemStatic, map, priorityConfig]);
useEffect(() => {
if (map && eciMarkers.length) {
eciMarkers.forEach((marker) => {
marker.addTo(map);
oms.addMarker(marker);
// Popup beim Überfahren mit der Maus öffnen und schließen
marker.on("mouseover", function () {
this.openPopup();
});
marker.on("mouseout", function () {
this.closePopup();
});
addContextMenuToMarker(marker);
});
// Disable map context menu
map.options.contextmenu = false;
map.options.contextmenuItems = [];
oms.map.options.contextmenu = false;
oms.map.options.contextmenuItems = [];
// Call the function to check for overlapping markers
checkOverlappingMarkers(oms, map);
}
}, [map, eciMarkers]);
return eciMarkers;
};
export default useEciMarkersLayer;

25
hooks/useFetchPoiData.js Normal file
View File

@@ -0,0 +1,25 @@
// hooks/useFetchPoiData.js
import { useState, useEffect } from "react";
const useFetchPoiData = (url) => {
const [poiData, setPoiData] = useState([]);
useEffect(() => {
const fetchPoiData = async () => {
try {
const response = await fetch(url);
if (!response.ok) throw new Error("Network response was not ok");
const data = await response.json();
setPoiData(data);
} catch (error) {
console.error("Fehler beim Abrufen der poiData:", error);
}
};
fetchPoiData();
}, [url]);
return poiData;
};
export default useFetchPoiData;

View File

@@ -0,0 +1,63 @@
import { useEffect } from "react";
import { addContextMenuToMarker } from "../utils/contextMenuUtils";
const useGmaMarkersLayer = (map, gmaMarkers, GisStationsMeasurements, GMA, oms) => {
useEffect(() => {
if (map && gmaMarkers.length) {
const gmaMeasurements = GisStationsMeasurements.filter((m) => m.Gr === "GMA");
let area_name = "";
let measurements = {};
gmaMeasurements.forEach((m) => {
area_name = m.Area_Name;
measurements[m.Na] = m.Val;
});
gmaMarkers.forEach((marker) => {
marker.addTo(map);
oms.addMarker(marker);
// Logging the data to debug
//console.log("Marker Data:", { area_name, measurements });
marker.bindTooltip(
`
<div class="p-0 rounded-lg bg-white bg-opacity-90">
<div class="font-bold text-sm text-black">
<span>${area_name}</span>
</div>
<div class="font-bold text-xxs text-blue-700">
<span>LT : ${measurements.LT} °C</span>
</div>
<div class="font-bold text-xxs text-red-700">
<span>FBT : ${measurements.FBT} °C</span>
</div>
<div class="font-bold text-xxs text-yellow-500">
<span>GT : ${measurements.GT === "nicht ermittelbar" ? measurements.GT : `${measurements.GT} °C`}</span>
</div>
<div class="font-bold text-xxs text-green-700">
<span>RLF : ${measurements.RLF} %</span>
</div>
</div>
`,
{
permanent: true,
direction: "auto",
offset: [20, 0],
},
);
marker.on("mouseover", function () {
this.openPopup();
});
marker.on("mouseout", function () {
this.closePopup();
});
addContextMenuToMarker(marker);
});
map.addLayer(GMA);
}
}, [map, gmaMarkers, GisStationsMeasurements, GMA, oms]);
};
export default useGmaMarkersLayer;

View File

@@ -0,0 +1,47 @@
// hooks/useGsmModemMarkersLayer.js
import { useEffect, useState } from "react";
import L from "leaflet";
import { createAndSetMarkers } from "../utils/markerUtils";
import { addContextMenuToMarker } from "../utils/contextMenuUtils";
import { checkOverlappingMarkers } from "../utils/mapUtils";
const useGsmModemMarkersLayer = (map, oms, GisSystemStatic, priorityConfig) => {
const [gsmModemMarkers, setGsmModemMarkers] = useState([]);
useEffect(() => {
if (GisSystemStatic && GisSystemStatic.length && map) {
createAndSetMarkers(5, setGsmModemMarkers, GisSystemStatic, priorityConfig); // GSM-Modem
}
}, [GisSystemStatic, map, priorityConfig]);
useEffect(() => {
if (map && gsmModemMarkers.length) {
gsmModemMarkers.forEach((marker) => {
marker.addTo(map);
oms.addMarker(marker);
// Popup beim Überfahren mit der Maus öffnen und schließen
marker.on("mouseover", function () {
this.openPopup();
});
marker.on("mouseout", function () {
this.closePopup();
});
addContextMenuToMarker(marker);
});
// Disable map context menu
map.options.contextmenu = false;
map.options.contextmenuItems = [];
oms.map.options.contextmenu = false;
oms.map.options.contextmenuItems = [];
// Call the function to check for overlapping markers
checkOverlappingMarkers(oms, map);
}
}, [map, gsmModemMarkers]);
return gsmModemMarkers;
};
export default useGsmModemMarkersLayer;

View File

@@ -0,0 +1,24 @@
// hooks/useLayerVisibility.js
import { useEffect } from "react";
import { useRecoilValue } from "recoil";
import { mapLayersState } from "../store/atoms/mapLayersState";
const useLayerVisibility = (map, markers, mapLayersVisibility, layerKey) => {
useEffect(() => {
if (!map || !markers) return;
const toggleLayer = (isVisible) => {
markers.forEach((marker) => {
if (isVisible) {
marker.addTo(map);
} else {
map.removeLayer(marker);
}
});
};
toggleLayer(mapLayersVisibility[layerKey]);
}, [map, markers, mapLayersVisibility, layerKey]);
};
export default useLayerVisibility;

View File

@@ -0,0 +1,64 @@
// /hooks/useLineData.js
import { useEffect, useState } from "react";
import { SERVER_URL } from "../config/urls";
const useLineData = (webserviceGisLinesStatusUrl, setLineStatusData) => {
const [lineColors, setLineColors] = useState({});
const [tooltipContents, setTooltipContents] = useState({});
useEffect(() => {
const fetchData = async () => {
try {
const response1 = await fetch(webserviceGisLinesStatusUrl);
const data1 = await response1.json();
const response2 = await fetch(`${SERVER_URL}:3000/api/talas_v5_DB/gisLines/readGisLines`);
const data2 = await response2.json();
const colorsByModule = {};
const newTooltipContents = {};
const reversedData = data1.Statis ? data1.Statis.reverse() : [];
reversedData.forEach((stat) => {
const matchingLine = data2.find((item) => item.idLD === stat.IdLD && item.idModul === stat.Modul);
if (matchingLine) {
// Check if PrioColor is #ffffff and change it to green
const prioColor = stat.PrioColor === "#ffffff" ? "green" : stat.PrioColor;
colorsByModule[matchingLine.idModul] = prioColor;
newTooltipContents[matchingLine.idModul] = `
<div class="bg-white rounded-lg m-0 p-2 w-[210px]">
<span class="text-lg font-semibold text-gray-900">${stat.ModulName || "Unknown"}</span>
<br>
<span class="text-md font-bold text-gray-800">${stat.ModulTyp || "N/A"}</span>
<br>
<span class="text-md font-bold text-gray-800">Slot: ${stat.Modul || "N/A"}</span>
<br>
<div style="max-width: 100%; overflow-wrap: break-word; word-break: break-word; white-space: normal;">
<span class="inline-block w-2 h-2 rounded-full mr-2" style="background-color: ${prioColor || "#000000"};"></span>
<span class="inline-block text-gray-800">${stat.Message || "N/A"}</span>
</div>
<span class="text-gray-800" style="color: ${prioColor || "#000000"};">(${stat.PrioName || "N/A"})</span>
<br>
<div style="max-width: 100%; overflow-wrap: break-word; word-break: break-word; white-space: normal;">
<span class="inline-block text-gray-800">${stat.DpName || "N/A"}</span>
: <span class="inline-block text-gray-800">${stat.Value || "N/A"}</span>
</div>
</div>
`;
}
});
setLineColors(colorsByModule);
setTooltipContents(newTooltipContents);
setLineStatusData(reversedData);
} catch (error) {
console.error("Error fetching data:", error);
}
};
fetchData();
}, [webserviceGisLinesStatusUrl, setLineStatusData]);
return { lineColors, tooltipContents };
};
export default useLineData;

View File

@@ -0,0 +1,93 @@
// /hooks/useLineData.js
import { useEffect, useState } from "react";
import { SERVER_URL } from "../config/urls";
const useLineData = (webserviceGisLinesStatusUrl, setLineStatusData) => {
const [lineColors, setLineColors] = useState({});
const [tooltipContents, setTooltipContents] = useState({});
const [locationDevices, setLocationDevices] = useState([]);
// Funktion zum Abrufen der Stationsnamen
useEffect(() => {
const fetchLocationDevices = async () => {
try {
const response = await fetch(`${process.env.NEXT_PUBLIC_SERVER_URL}:3000/api/talas_v5_DB/station/getStationNameByIdLD`);
const data = await response.json();
setLocationDevices(data);
console.log("Stationen namen:", data);
} catch (error) {
console.error("Fehler beim Abrufen der Stationen:", error);
}
};
fetchLocationDevices();
}, []);
useEffect(() => {
const fetchData = async () => {
try {
const response1 = await fetch(webserviceGisLinesStatusUrl);
const data1 = await response1.json();
const response2 = await fetch(`${SERVER_URL}:3000/api/talas_v5_DB/gisLines/readGisLines`);
const data2 = await response2.json();
const colorsByModule = {};
const newTooltipContents = {};
const reversedData = data1.Statis ? data1.Statis.reverse() : [];
reversedData.forEach((stat) => {
// Finden der passenden Linie
const matchingLine = data2.find((item) => item.idLD === stat.IdLD && item.idModul === stat.Modul);
if (matchingLine) {
// Ermitteln der Farbe basierend auf PrioColor
const prioColor = stat.PrioColor === "#ffffff" ? "green" : stat.PrioColor;
colorsByModule[matchingLine.idModul] = prioColor;
// Finden des passenden Stationsnamens
const locationDevice = locationDevices.find((device) => device.idLD === stat.IdLD);
newTooltipContents[matchingLine.idModul] = `
<div class="bg-white rounded-lg m-0 p-2 w-[210px]">
<span class="text-lg font-semibold text-gray-900">${stat.ModulName || "Unknown"}</span>
<br>
<span class="text-md font-bold text-gray-800">Station: ${locationDevice ? locationDevice.name : "Unbekannt"}</span>
<br>
<span class="text-md font-bold text-gray-800">${stat.ModulTyp || "N/A"}</span>
<br>
<span class="text-md font-bold text-gray-800">Slot: ${stat.Modul || "N/A"}</span>
<br>
<div style="max-width: 100%; overflow-wrap: break-word; word-break: break-word; white-space: normal;">
<span class="inline-block w-2 h-2 rounded-full mr-2" style="background-color: ${prioColor || "#000000"};"></span>
<span class="inline-block text-gray-800">${stat.Message || "N/A"}</span>
</div>
<span class="text-gray-800" style="color: ${prioColor || "#000000"};">(${stat.PrioName || "N/A"})</span>
<br>
<div style="max-width: 100%; overflow-wrap: break-word; word-break: break-word; white-space: normal;">
<span class="inline-block text-gray-800">${stat.DpName || "N/A"}</span>
: <span class="inline-block text-gray-800">${stat.Value || "N/A"}</span>
</div>
</div>
`;
}
});
setLineColors(colorsByModule);
setTooltipContents(newTooltipContents);
setLineStatusData(reversedData);
} catch (error) {
console.error("Error fetching data:", error);
}
};
fetchData();
const interval = setInterval(fetchData, 300000); // 300000 ms = 5 Minuten
return () => clearInterval(interval);
}, [webserviceGisLinesStatusUrl, setLineStatusData, locationDevices]);
return { lineColors, tooltipContents };
};
export default useLineData;

152
hooks/useLineData.js Normal file
View File

@@ -0,0 +1,152 @@
// /hooks/useLineData.js
import { useEffect, useState } from "react";
import { SERVER_URL } from "../config/urls";
const useLineData = (webserviceGisLinesStatusUrl, setLineStatusData) => {
const [lineColors, setLineColors] = useState({});
const [tooltipContents, setTooltipContents] = useState({});
useEffect(() => {
const fetchData = async () => {
try {
console.log("Daten werden abgerufen...");
const response1 = await fetch(webserviceGisLinesStatusUrl);
const data1 = await response1.json();
console.log("Daten vom Webservice:", data1);
const response2 = await fetch(`${SERVER_URL}:3000/api/talas_v5_DB/gisLines/readGisLines`);
const data2 = await response2.json();
console.log("GIS Linien Daten:", data2);
const colorsByModule = {};
const newTooltipContents = {};
const valueMap = {};
// Hier führen wir die Gruppierung durch und loggen sie
logGroupedData(data1.Statis);
data1.Statis.forEach((statis) => {
const key = `${statis.IdLD}-${statis.Modul}`;
if (!valueMap[key]) {
valueMap[key] = {
messages: [],
messwert: undefined,
schleifenwert: undefined,
};
}
if (statis.DpName.includes("_Messwert") && statis.Value !== "True" && valueMap[key].messwert === undefined) {
valueMap[key].messwert = statis.Value;
}
if (statis.DpName.includes("_Schleifenwert") && valueMap[key].schleifenwert === undefined) {
valueMap[key].schleifenwert = statis.Value;
}
if (statis.Message && statis.Message !== "?") {
valueMap[key].messages.push(statis.Message);
}
});
data1.Statis.reverse().forEach((statis) => {
const matchingLine = data2.find((item) => item.idLD === statis.IdLD && item.idModul === statis.Modul);
if (matchingLine) {
const prioColor = statis.PrioColor === "#ffffff" ? "green" : statis.PrioColor;
const key = `${matchingLine.idLD}-${matchingLine.idModul}`;
const values = valueMap[key];
const messageDisplay = values.messages.map((msg) => (msg ? `<span class="inline-block text-gray-800">${msg}</span><br>` : "")).join("");
const prioNameDisplay = statis.PrioName && statis.PrioName !== "?" ? `(${statis.PrioName})` : "";
colorsByModule[matchingLine.idModul] = prioColor;
newTooltipContents[matchingLine.idModul] = `
<div class="bg-white rounded-lg m-0 p-2 w-[210px]">
<span class="text-lg font-semibold text-gray-900">${statis.ModulName || "Unknown"}</span>
<br>
<span class="text-md font-bold text-gray-800">${statis.ModulTyp || "N/A"}</span>
<br>
<span class="text-md font-bold text-gray-800">Slot: ${statis.Modul || "N/A"}</span>
<br>
<div style="max-width: 100%; overflow-wrap: break-word; word-break: break-word; white-space: normal;">
<span class="inline-block w-2 h-2 rounded-full mr-2" style="background-color: ${prioColor || "#000000"};"></span>
${messageDisplay}
</div>
<span class="text-gray-800" style="color: ${prioColor || "#000000"};">${prioNameDisplay}</span>
<br>
${values.messwert ? `<span class="inline-block text-gray-800">Messwert: ${values.messwert}</span><br>` : ""}
${values.schleifenwert ? `<span class="inline-block text-gray-800">Schleifenwert: ${values.schleifenwert}</span>` : ""}
</div>
`;
}
});
setLineColors(colorsByModule);
setTooltipContents(newTooltipContents);
setLineStatusData(data1.Statis);
} catch (error) {
console.error("Fehler beim Abrufen der Daten:", error);
}
};
fetchData();
}, [webserviceGisLinesStatusUrl, setLineStatusData]);
return { lineColors, tooltipContents };
};
//----------------------------------------------------------
// Funktion zum Loggen der gruppierten und aggregierten Daten
function logGroupedData(statisList) {
const grouped = statisList.reduce((acc, item) => {
const { IdLD, Modul, Level, PrioColor, PrioName, ModulName, ModulTyp, Message } = item;
if (!acc[IdLD]) {
acc[IdLD] = {};
}
if (!acc[IdLD][Modul]) {
acc[IdLD][Modul] = {
ModulName: ModulName || "Unknown",
ModulTyp: ModulTyp || "N/A",
TotalLevel: 0,
PrioColors: new Set(),
PrioNames: new Set(),
Messages: [],
};
}
// Aggregiere die Level und sammle Prioritätsinformationen und Nachrichten
acc[IdLD][Modul].TotalLevel += Level;
acc[IdLD][Modul].PrioColors.add(PrioColor);
acc[IdLD][Modul].PrioNames.add(PrioName);
if (Message && Message !== "?") {
acc[IdLD][Modul].Messages.push(Message);
}
return acc;
}, {});
// Formatierte Ausgabe der gruppierten Daten, Entfernen von Modulen ohne Namen und Stationen mit leeren Arrays
const formattedData = {};
Object.entries(grouped).forEach(([stationId, modules]) => {
const filteredModules = Object.entries(modules)
.filter(([modulId, data]) => data.ModulName !== "?")
.map(([modulId, data]) => ({
Modul: modulId,
ModulName: data.ModulName,
ModulTyp: data.ModulTyp,
TotalLevel: data.TotalLevel,
PrioColors: Array.from(data.PrioColors).join(", "),
PrioNames: Array.from(data.PrioNames).join(", "),
Messages: data.Messages.join(" | "),
}));
if (filteredModules.length > 0) {
formattedData[stationId] = filteredModules;
}
});
console.log("Aggregierte und gruppierte Daten (gefiltert):", formattedData);
}
// Beispielaufruf der Funktion
// const statisList = data1.Statis; // Verwende die Liste aus deinem API-Aufruf
// logGroupedData(statisList);
//----------------------------------------------------------
export default useLineData;

View File

@@ -0,0 +1,28 @@
// hooks/useMapComponentState.js
import { useState, useRef } from "react";
import usePoiTypData from "./usePoiTypData";
import { useRecoilValue } from "recoil";
import { poiLayerVisibleState } from "../store/atoms/poiLayerVisibleState";
export const useMapComponentState = () => {
const { poiTypData, isPoiTypLoaded } = usePoiTypData("/api/talas_v5_DB/poiTyp/readPoiTyp");
const [deviceName, setDeviceName] = useState("");
const [locationDeviceData, setLocationDeviceData] = useState([]);
const [priorityConfig, setPriorityConfig] = useState([]);
const [menuItemAdded, setMenuItemAdded] = useState(false);
const poiLayerVisible = useRecoilValue(poiLayerVisibleState);
return {
poiTypData,
isPoiTypLoaded,
deviceName,
setDeviceName,
locationDeviceData,
setLocationDeviceData,
priorityConfig,
setPriorityConfig,
menuItemAdded,
setMenuItemAdded,
poiLayerVisible,
};
};

26
hooks/useMarkerLayers.js Normal file
View File

@@ -0,0 +1,26 @@
// hooks/useMarkerLayers.js
import { useEffect } from "react";
import { useRecoilValue } from "recoil";
import { mapLayersState } from "../store/atoms/mapLayersState";
const useMarkerLayers = (map, markers, layerType) => {
const mapLayersVisibility = useRecoilValue(mapLayersState);
useEffect(() => {
if (!map || !markers) return;
const toggleLayer = (isVisible) => {
markers.forEach((marker) => {
if (isVisible) {
marker.addTo(map);
} else {
map.removeLayer(marker);
}
});
};
toggleLayer(mapLayersVisibility[layerType]);
}, [map, markers, mapLayersVisibility, layerType]);
};
export default useMarkerLayers;

View File

@@ -0,0 +1,37 @@
import { useEffect, useState } from "react";
import L from "leaflet";
import { addContextMenuToMarker } from "../utils/contextMenuUtils";
import { createAndSetMarkers } from "../utils/markerUtils";
const useMessstellenMarkersLayer = (map, oms, GisSystemStatic, priorityConfig) => {
const [messstellenMarkers, setMessstellenMarkers] = useState([]);
useEffect(() => {
if (GisSystemStatic && GisSystemStatic.length && map) {
createAndSetMarkers(13, setMessstellenMarkers, GisSystemStatic, priorityConfig); // Messstellen
}
}, [GisSystemStatic, map, priorityConfig]);
useEffect(() => {
if (map && messstellenMarkers.length) {
messstellenMarkers.forEach((marker) => {
marker.addTo(map);
oms.addMarker(marker);
// Popup on mouseover and mouseout
marker.on("mouseover", function () {
this.openPopup();
});
marker.on("mouseout", function () {
this.closePopup();
});
addContextMenuToMarker(marker);
});
}
}, [map, messstellenMarkers, oms]);
return messstellenMarkers;
};
export default useMessstellenMarkersLayer;

View File

@@ -0,0 +1,45 @@
// hooks/useOtdrMarkersLayer.js
import { useEffect, useState } from "react";
import L from "leaflet";
import { addContextMenuToMarker } from "../utils/contextMenuUtils";
import { createAndSetMarkers } from "../utils/markerUtils"; // Assuming this function is in markerUtils
const useOtdrMarkersLayer = (map, oms, GisSystemStatic, priorityConfig) => {
const [otdrMarkers, setOtdrMarkers] = useState([]);
useEffect(() => {
if (GisSystemStatic && GisSystemStatic.length && map) {
createAndSetMarkers(9, setOtdrMarkers, GisSystemStatic, priorityConfig); // OTDR
}
}, [GisSystemStatic, map, priorityConfig]);
useEffect(() => {
if (map && otdrMarkers.length) {
otdrMarkers.forEach((marker) => {
marker.addTo(map);
oms.addMarker(marker);
// Popup on mouseover and mouseout
marker.on("mouseover", function () {
this.openPopup();
});
marker.on("mouseout", function () {
this.closePopup();
});
addContextMenuToMarker(marker);
});
// Disable map context menu
map.options.contextmenu = false;
map.options.contextmenuItems = [];
oms.map.options.contextmenu = false;
oms.map.options.contextmenuItems = [];
}
}, [map, otdrMarkers, oms]);
return otdrMarkers;
};
export default useOtdrMarkersLayer;

26
hooks/usePoiTypData.js Normal file
View File

@@ -0,0 +1,26 @@
// hooks/usePoiTypData.js
import { useState, useEffect } from "react";
const usePoiTypData = (url) => {
const [poiTypData, setPoiTypData] = useState([]);
const [isPoiTypLoaded, setIsPoiTypLoaded] = useState(false);
useEffect(() => {
const fetchPoiTypData = async () => {
try {
const response = await fetch(url);
const data = await response.json();
setPoiTypData(data);
setIsPoiTypLoaded(true);
} catch (error) {
console.error("Fehler beim Abrufen der poiTyp-Daten:", error);
}
};
fetchPoiTypData();
}, [url]);
return { poiTypData, isPoiTypLoaded };
};
export default usePoiTypData;

View File

@@ -0,0 +1,49 @@
// hooks/useSiemensMarkersLayer.js
import { useState, useEffect } from "react";
import L from "leaflet";
import { addContextMenuToMarker } from "../utils/contextMenuUtils";
import { createAndSetMarkers } from "../utils/markerUtils";
import { checkOverlappingMarkers } from "../utils/mapUtils";
const useSiemensMarkersLayer = (map, oms, gisSystemStatic, priorityConfig) => {
const [siemensMarkers, setSiemensMarkers] = useState([]);
useEffect(() => {
if (gisSystemStatic && gisSystemStatic.length && map) {
createAndSetMarkers(8, setSiemensMarkers, gisSystemStatic, priorityConfig); // Siemens-System
}
}, [gisSystemStatic, map, priorityConfig]);
useEffect(() => {
if (map && siemensMarkers.length) {
siemensMarkers.forEach((marker) => {
marker.addTo(map);
oms.addMarker(marker);
// Popup on mouseover and mouseout
marker.on("mouseover", function () {
this.openPopup();
});
marker.on("mouseout", function () {
this.closePopup();
});
addContextMenuToMarker(marker);
});
// Disable map context menu
map.options.contextmenu = false;
map.options.contextmenuItems = [];
oms.map.options.contextmenu = false;
oms.map.options.contextmenuItems = [];
// Call the function to check for overlapping markers
checkOverlappingMarkers(oms, map);
}
}, [map, siemensMarkers, oms]);
return siemensMarkers;
};
export default useSiemensMarkersLayer;

View File

@@ -0,0 +1,54 @@
// hooks/useSmsfunkmodemMarkersLayer.js
import { useEffect, useState } from "react";
import L from "leaflet";
import "leaflet-contextmenu";
import { addContextMenuToMarker } from "../utils/contextMenuUtils";
const useSmsfunkmodemMarkersLayer = (map, oms, GisSystemStatic, priorityConfig) => {
const [smsfunkmodemMarkers, setSmsfunkmodemMarkers] = useState([]);
useEffect(() => {
if (map && GisSystemStatic) {
const markers = GisSystemStatic.filter((station) => station.System === 111).map((station) => {
const marker = L.marker([station.Latitude, station.Longitude], {
icon: L.icon({
iconUrl: "/img/icons/pois/sms-funkmodem.png",
iconSize: [25, 41],
iconAnchor: [12, 41],
popupAnchor: [1, -34],
}),
id: station.id,
areaName: station.Area_Name,
draggable: false,
}).bindPopup(`
<div>
<b class="text-xl text-black-700">${station.Area_Name || "Unbekannt"}</b><br>
${station.Description || "No Description"}<br>
</div>
`);
marker.on("mouseover", function () {
this.openPopup();
});
marker.on("mouseout", function () {
this.closePopup();
});
addContextMenuToMarker(marker);
return marker;
});
setSmsfunkmodemMarkers(markers);
markers.forEach((marker) => {
marker.addTo(map);
oms.addMarker(marker);
});
}
}, [map, GisSystemStatic, priorityConfig]);
return smsfunkmodemMarkers;
};
export default useSmsfunkmodemMarkersLayer;

View File

@@ -0,0 +1,45 @@
// hooks/useSonstigeMarkersLayer.js
import { useEffect, useState } from "react";
import L from "leaflet";
import { addContextMenuToMarker } from "../utils/contextMenuUtils";
import { createAndSetMarkers } from "../utils/markerUtils";
const useSonstigeMarkersLayer = (map, oms, GisSystemStatic, priorityConfig) => {
const [sonstigeMarkers, setSonstigeMarkers] = useState([]);
useEffect(() => {
if (GisSystemStatic && GisSystemStatic.length && map) {
createAndSetMarkers(200, setSonstigeMarkers, GisSystemStatic, priorityConfig); // Sonstige
}
}, [GisSystemStatic, map, priorityConfig]);
useEffect(() => {
if (map && sonstigeMarkers.length) {
sonstigeMarkers.forEach((marker) => {
marker.addTo(map);
oms.addMarker(marker);
// Popup on mouseover and mouseout
marker.on("mouseover", function () {
this.openPopup();
});
marker.on("mouseout", function () {
this.closePopup();
});
addContextMenuToMarker(marker);
});
// Disable map context menu
map.options.contextmenu = false;
map.options.contextmenuItems = [];
oms.map.options.contextmenu = false;
oms.map.options.contextmenuItems = [];
}
}, [map, sonstigeMarkers, oms]);
return sonstigeMarkers;
};
export default useSonstigeMarkersLayer;

102
hooks/useTalasMarkers.js Normal file
View File

@@ -0,0 +1,102 @@
// /hooks/useTalasMarkers.js
import { useEffect, useState } from "react";
import L from "leaflet";
import "leaflet-contextmenu";
import { useRecoilValue } from "recoil";
import { mapLayersState } from "../store/atoms/mapLayersState.js";
import { selectedAreaState } from "../store/atoms/selectedAreaState.js";
import { zoomTriggerState } from "../store/atoms/zoomTriggerState.js";
import { addContextMenuToMarker } from "../utils/contextMenuUtils.js";
import { checkOverlappingMarkers } from "../utils/mapUtils.js";
import plusRoundIcon from "../components/PlusRoundIcon.js";
import { gisStationsStaticDistrictState } from "../store/atoms/gisStationState.js";
const useTalasMarkers = (map, oms, layers, priorityConfig) => {
const [talasMarkers, setTalasMarkers] = useState([]);
const mapLayersVisibility = useRecoilValue(mapLayersState);
const selectedArea = useRecoilValue(selectedAreaState);
const zoomTrigger = useRecoilValue(zoomTriggerState);
const GisStationsStaticDistrict = useRecoilValue(gisStationsStaticDistrictState);
// Funktion zum Erstellen und Setzen der Marker
const createAndSetMarkers = (systemId, setMarkers, GisSystemStatic, priorityConfig) => {
const markers = GisSystemStatic.filter((station) => station.System === systemId).map((station) => {
const marker = L.marker([station.Latitude, station.Longitude], {
title: station.Name,
contextmenu: true,
contextmenuItems: [],
});
marker.bindPopup(`<b>${station.Name}</b><br>${station.Description}`);
if (priorityConfig.includes(station.Priority)) {
marker.setIcon(
L.icon({
iconUrl: `/icons/priority_${station.Priority}.png`,
iconSize: [25, 41],
iconAnchor: [12, 41],
popupAnchor: [1, -34],
}),
);
}
return marker;
});
setMarkers(markers);
};
useEffect(() => {
if (map && talasMarkers.length) {
talasMarkers.forEach((marker) => {
marker.addTo(map);
oms.addMarker(marker);
marker.on("mouseover", function () {
this.openPopup();
});
marker.on("mouseout", function () {
this.closePopup();
});
addContextMenuToMarker(marker);
});
map.addLayer(layers.TALAS);
checkOverlappingMarkers(oms, map, plusRoundIcon);
}
}, [map, talasMarkers]);
useEffect(() => {
if (!map || !talasMarkers) return;
const toggleLayer = (isVisible) => {
if (isVisible) {
talasMarkers.forEach((marker) => marker.addTo(map));
} else {
talasMarkers.forEach((marker) => map.removeLayer(marker));
}
};
toggleLayer(mapLayersVisibility.TALAS);
}, [map, talasMarkers, mapLayersVisibility.TALAS]);
useEffect(() => {
if (selectedArea && map) {
const station = GisStationsStaticDistrict.find((s) => s.Area_Name === selectedArea);
if (station) {
map.flyTo([station.X, station.Y], 14);
}
}
}, [selectedArea, map, GisStationsStaticDistrict]);
useEffect(() => {
if (zoomTrigger && map) {
map.flyTo([51.41321407879154, 7.739617925303934], 7);
}
}, [zoomTrigger, map]);
return [talasMarkers, setTalasMarkers, createAndSetMarkers];
};
export default useTalasMarkers;

View File

@@ -0,0 +1,45 @@
// hooks/useTalasiclMarkersLayer.js
import { useEffect, useState } from "react";
import L from "leaflet";
import { addContextMenuToMarker } from "../utils/contextMenuUtils";
import { createAndSetMarkers } from "../utils/markerUtils";
const useTalasiclMarkersLayer = (map, oms, GisSystemStatic, priorityConfig) => {
const [talasiclMarkers, setTalasiclMarkers] = useState([]);
useEffect(() => {
if (GisSystemStatic && GisSystemStatic.length && map) {
createAndSetMarkers(100, setTalasiclMarkers, GisSystemStatic, priorityConfig); // TALASICL
}
}, [GisSystemStatic, map, priorityConfig]);
useEffect(() => {
if (map && talasiclMarkers.length) {
talasiclMarkers.forEach((marker) => {
marker.addTo(map);
oms.addMarker(marker);
// Popup on mouseover and mouseout
marker.on("mouseover", function () {
this.openPopup();
});
marker.on("mouseout", function () {
this.closePopup();
});
addContextMenuToMarker(marker);
});
// Disable map context menu
map.options.contextmenu = false;
map.options.contextmenuItems = [];
oms.map.options.contextmenu = false;
oms.map.options.contextmenuItems = [];
}
}, [map, talasiclMarkers, oms]);
return talasiclMarkers;
};
export default useTalasiclMarkersLayer;

View File

@@ -0,0 +1,76 @@
// hooks/useUlafMarkersLayer.js
import { useEffect, useState } from "react";
import L from "leaflet";
import { addContextMenuToMarker } from "../utils/contextMenuUtils";
//import { fetchDeviceNameById } from "../services/apiService";
const useUlafMarkersLayer = (map, oms, GisSystemStatic, priorityConfig) => {
const [ulafMarkers, setUlafMarkers] = useState([]);
useEffect(() => {
if (!map || !GisSystemStatic) return;
const markers = [];
GisSystemStatic.forEach((station) => {
if (station.System === 0) {
// Adjust the condition to match ULAF system identification
const marker = L.marker([station.Lat, station.Lon], {
icon: L.icon({
iconUrl: "/img/icons/ulaf.png",
iconSize: [25, 41],
iconAnchor: [12, 41],
popupAnchor: [1, -34],
}),
id: station.id,
name: station.name,
description: station.description,
});
marker.bindPopup(`
<div>
<b class="text-xl text-black-700">${station.name || "Unbekannt"}</b><br>
${station.description || "Keine Beschreibung"}
</div>
`);
marker.on("mouseover", function () {
this.openPopup();
});
marker.on("mouseout", function () {
this.closePopup();
});
marker.on("click", async () => {
//const deviceName = await fetchDeviceNameById(station.idLD);
marker
.bindPopup(
`
<div>
<b class="text-xl text-black-700">${station.name || "Unbekannt"}</b><br>
${deviceName}<br>
${station.description || "Keine Beschreibung"}
</div>
`,
)
.openPopup();
});
markers.push(marker);
if (map) marker.addTo(map);
if (oms) oms.addMarker(marker);
addContextMenuToMarker(marker);
}
});
setUlafMarkers(markers);
return () => {
markers.forEach((marker) => map.removeLayer(marker));
};
}, [map, GisSystemStatic, oms, priorityConfig]);
return ulafMarkers;
};
export default useUlafMarkersLayer;

View File

@@ -0,0 +1,49 @@
// hooks/useWagoMarkersLayer.js
import { useState, useEffect } from "react";
import L from "leaflet";
import { addContextMenuToMarker } from "../utils/contextMenuUtils";
import { createAndSetMarkers } from "../utils/markerUtils";
import { checkOverlappingMarkers } from "../utils/mapUtils";
const useWagoMarkersLayer = (map, oms, gisSystemStatic, priorityConfig) => {
const [wagoMarkers, setWagoMarkers] = useState([]);
useEffect(() => {
if (gisSystemStatic && gisSystemStatic.length && map) {
createAndSetMarkers(7, setWagoMarkers, gisSystemStatic, priorityConfig); // WAGO-System
}
}, [gisSystemStatic, map, priorityConfig]);
useEffect(() => {
if (map && wagoMarkers.length) {
wagoMarkers.forEach((marker) => {
marker.addTo(map);
oms.addMarker(marker);
// Popup on mouseover and mouseout
marker.on("mouseover", function () {
this.openPopup();
});
marker.on("mouseout", function () {
this.closePopup();
});
addContextMenuToMarker(marker);
});
// Disable map context menu
map.options.contextmenu = false;
map.options.contextmenuItems = [];
oms.map.options.contextmenu = false;
oms.map.options.contextmenuItems = [];
// Call the function to check for overlapping markers
checkOverlappingMarkers(oms, map);
}
}, [map, wagoMarkers, oms]);
return wagoMarkers;
};
export default useWagoMarkersLayer;

View File

@@ -0,0 +1,45 @@
// hooks/useWdmMarkersLayer.js
import { useEffect, useState } from "react";
import L from "leaflet";
import { addContextMenuToMarker } from "../utils/contextMenuUtils";
import { createAndSetMarkers } from "../utils/markerUtils";
const useWdmMarkersLayer = (map, oms, GisSystemStatic, priorityConfig) => {
const [wdmMarkers, setWdmMarkers] = useState([]);
useEffect(() => {
if (GisSystemStatic && GisSystemStatic.length && map) {
createAndSetMarkers(10, setWdmMarkers, GisSystemStatic, priorityConfig); // WDM
}
}, [GisSystemStatic, map, priorityConfig]);
useEffect(() => {
if (map && wdmMarkers.length) {
wdmMarkers.forEach((marker) => {
marker.addTo(map);
oms.addMarker(marker);
// Popup on mouseover and mouseout
marker.on("mouseover", function () {
this.openPopup();
});
marker.on("mouseout", function () {
this.closePopup();
});
addContextMenuToMarker(marker);
});
// Disable map context menu
map.options.contextmenu = false;
map.options.contextmenuItems = [];
oms.map.options.contextmenu = false;
oms.map.options.contextmenuItems = [];
}
}, [map, wdmMarkers, oms]);
return wdmMarkers;
};
export default useWdmMarkersLayer;

11
jest.config.js Normal file
View File

@@ -0,0 +1,11 @@
module.exports = {
setupFilesAfterEnv: ["<rootDir>/jest.setup.js"],
testEnvironment: "jest-environment-jsdom",
testPathIgnorePatterns: ["<rootDir>/.next/", "<rootDir>/node_modules/"],
transform: {
"^.+\\.(js|jsx|ts|tsx)$": "babel-jest",
},
moduleNameMapper: {
"\\.(css|less|scss|sass)$": "identity-obj-proxy",
},
};

3
jest.setup.js Normal file
View File

@@ -0,0 +1,3 @@
// jest.setup.js
global.fetch = require("jest-fetch-mock");
jest.setMock("node-fetch", fetch);

8499
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,36 +1,43 @@
{ {
"dependencies": { "dependencies": {
"@heroicons/react": "^2.1.3", "@heroicons/react": "^2.1.5",
"express": "^4.19.2", "autoprefixer": "^10.4.19",
"dotenv": "^16.4.5",
"http-proxy-middleware": "^3.0.0", "http-proxy-middleware": "^3.0.0",
"leaflet": "^1.9.4", "leaflet": "^1.9.4",
"leaflet-contextmenu": "^1.4.0", "leaflet-contextmenu": "^1.4.0",
"leaflet.smooth_marker_bouncing": "^3.0.3", "leaflet.smooth_marker_bouncing": "^3.1.0",
"lodash": "^4.17.21",
"mysql": "^2.18.1", "mysql": "^2.18.1",
"mysql2": "^3.10.1", "mysql2": "^3.11.0",
"next": "^14.2.3", "next": "^14.2.5",
"nextjs-cors": "^2.2.0",
"overlapping-marker-spiderfier-leaflet": "^0.2.7", "overlapping-marker-spiderfier-leaflet": "^0.2.7",
"react": "^18.2.0", "postcss": "^8.4.40",
"react": "^18.3.1",
"react-dom": "^18.3.1", "react-dom": "^18.3.1",
"react-leaflet": "^4.2.1",
"react-toastify": "^10.0.5", "react-toastify": "^10.0.5",
"recoil": "^0.7.7" "recoil": "^0.7.7",
"tailwindcss": "^3.4.7"
}, },
"scripts": { "scripts": {
"dev": "next dev", "dev": "next dev",
"build": "next build", "build": "next build",
"start": "next start", "start": "next start",
"export": "next export" "export": "next export",
"test": "jest"
}, },
"devDependencies": { "devDependencies": {
"@types/leaflet": "^1.9.12", "@babel/core": "^7.25.2",
"@types/leaflet-contextmenu": "^1.4.3", "@babel/preset-env": "^7.25.2",
"@types/react": "^18.3.1", "@babel/preset-react": "^7.24.7",
"@types/react-dom": "^18.3.0", "@testing-library/jest-dom": "^6.4.8",
"autoprefixer": "^10.4.19", "@testing-library/react": "^16.0.0",
"postcss": "^8.4.38", "@testing-library/user-event": "^14.5.2",
"prettier": "^3.2.5", "babel-jest": "^29.7.0",
"tailwindcss": "^3.4.3" "identity-obj-proxy": "^3.0.0",
"jest": "^29.7.0",
"jest-environment-jsdom": "^29.7.0",
"jest-fetch-mock": "^3.0.3",
"node-fetch": "^3.3.2"
} }
} }

View File

@@ -1,5 +1,6 @@
// Pfad: pages/_app.js // Pfad: pages/_app.js
import { RecoilRoot } from 'recoil'; import React from "react";
import { RecoilRoot } from "recoil";
import "../styles/global.css"; import "../styles/global.css";
function MyApp({ Component, pageProps }) { function MyApp({ Component, pageProps }) {

View File

@@ -0,0 +1,20 @@
// pages/api/[...path].js
import { createProxyMiddleware } from "http-proxy-middleware";
import { SERVER_URL } from "../config/urls.js";
console.log("SERVER_URL:", SERVER_URL); // Debug-Ausgabe
export default createProxyMiddleware({
//target: "http://192.168.10.58:3001",
// Stationen bekommen
//target: "http://10.10.0.13", // Ziel-URL des Proxys // API Aufruf zum mapGisStationsStaticDistrictUrl, mapGisStationsStatusDistrictUrl, mapGisStationsMeasurementsUrl, mapGisSystemStaticUrl und mapDataIconUrl
target: `${SERVER_URL}`, //
//target: urls.PROXY_TARGET,
//target: "http://localhost:3000", // Ziel-URL des Proxys
//target: "http://192.168.10.187:3000", // Ziel-URL des Proxys
//target: "http://192.168.10.14",
changeOrigin: true,
pathRewrite: {
"^/api": "/", // Optional: Entfernt /api aus dem Pfad, wenn das Backend dies nicht erfordert
},
logLevel: "debug", // Setzt das Logging-Level auf "debug" für detaillierte Ausgaben
});

View File

@@ -0,0 +1,20 @@
// pages/api/get-talasIP.js
export default function handler(req, res) {
// Der x-forwarded-for Header könnte mehrere IP-Adressen enthalten, getrennt durch Kommas
let clientIp =
req.headers["x-forwarded-for"]?.split(",").map((ip) => ip.trim())[0] ||
req.socket.remoteAddress;
// Entfernen möglicher IPv6 "mapped" IPv4 Adressen
if (clientIp?.includes("::ffff:")) {
clientIp = clientIp.split("::ffff:")[1];
}
// Nur IPv4 Adressen weitergeben, IPv6 Adressen ausschließen
if (clientIp && clientIp.includes(":")) {
clientIp = ""; // Dies setzt die IP auf leer, wenn es sich um eine IPv6-Adresse handelt
}
res.status(200).json({ ip: clientIp });
}

View File

@@ -0,0 +1,34 @@
// /pages/api/gis-proxy.js
// Importieren der erforderlichen Module
import httpProxy from "http-proxy";
import Cookies from "cookies";
// Erstellen eines Proxy-Servers
const proxy = httpProxy.createProxyServer();
export default (req, res) => {
return new Promise((resolve) => {
// CORS-Headers einstellen
res.setHeader("Access-Control-Allow-Credentials", true);
res.setHeader("Access-Control-Allow-Origin", "*");
// Cookies initialisieren
const cookies = new Cookies(req, res);
const targetUrl = `${process.env.NEXT_PUBLIC_SERVER_URL}/talas5/ClientData/WebserviceMap.asmx/GisSystemStatic`;
// Proxy-Konfiguration und Event-Listener
req.on("data", () => {});
req.on("end", () => {
proxy.web(req, res, { target: targetUrl, changeOrigin: true, selfHandleResponse: false }, (e) => {
if (e) {
console.error(e);
res.status(500).json({ error: "Proxy-Fehler", e });
}
resolve();
});
});
// Weiterleitung der Headers
req.headers.cookie = cookies.get("cookie-name") || "";
});
};

View File

@@ -0,0 +1,64 @@
// /pages/api/linesColorApi.js
// http://10.10.0.13/talas5/ClientData/WebServiceMap.asmx/GisStationsStatusDistrict
//In DB gis_lines idLD und idModul anpassen entsprechend
// /pages/api/linesColorApi.js
import NextCors from "nextjs-cors";
export default async function handler(req, res) {
// Run the cors middleware
await NextCors(req, res, {
// Options
methods: ["GET", "HEAD", "PUT", "PATCH", "POST", "DELETE"],
origin: "*", // Erlauben Sie alle Ursprünge, oder geben Sie spezifische Ursprünge an
optionsSuccessStatus: 200, // Legacy-Browser-Unterstützung für 204
});
const response = {
Name: "Liste aller Statis der Linien",
Zeitstempel: new Date().toISOString(), // Aktuellen Zeitstempel hinzufügen
IdMap: "10",
Statis: [
/* {
IdLD: 50922,
Modul: 1,
DpName: "KUE01_Ausfall",
ModulName: "42 Wippershain Sender",
// ModulTyp: "nicht vorhanden",
ModulTyp: "KÜ705-FO",
Message: "KUEG 01: 42 Wippershain Sender Messwerkausfall kommend",
Level: 4,
PrioColor: "#FFFF00",
PrioName: "system",
Value: "10 MOhm",
},
{
IdLD: 25440,
Modul: 3,
DpName: "KUE03_Ausfall",
ModulName: "42 Solz Sender",
//ModulTyp: "nicht vorhanden",
ModulTyp: "KÜSS V2",
Message: "KUEG 03: 42 Solz Sender Messwerkausfall kommend",
Level: 4,
PrioColor: "#FF0000",
PrioName: "system",
Value: "10 MOhm",
},
{
IdLD: 25440,
Modul: 4,
DpName: "KUE04_Ausfall",
ModulName: "42/13 Bad Hersfeld Gaswerk",
ModulTyp: "Kue705-FO",
Message: "KUEG 04: 42/13 Bad Hersfeld Gaswerk Messwerkausfall kommend",
Level: 4,
PrioColor: "#FF00FF",
PrioName: "system",
Value: "10 MOhm",
}, */
],
};
res.status(200).json(response);
}

View File

@@ -0,0 +1,29 @@
// pages/api/rights.js
export default function handler(req, res) {
const { idMap, idUser } = req.query;
// Beispielhafte Rechte, die je nach idMap und idUser variieren können
const rights = {
'10': [
{ IdRight: 1, Name: "Zugriff auf Dashboard" },
{ IdRight: 56, Name: "Erweiterte Berechtigungen" }
],
'2': [
{ IdRight: 2, Name: "Zugriff auf Einstellungen" }
],
'1': [
{ IdRight: 10, Name: "Admin-Zugriff" },
{ IdRight: 11, Name: "Zugriff auf alle Daten" }
]
};
// Prüfung, ob eine gültige idMap und idUser vorhanden sind
if (rights[idMap] && idUser === '484') {
// Rückgabe der spezifischen Rechte basierend auf der idMap und idUser
res.status(200).json({ Rights: rights[idMap] });
} else {
// Rückgabe leerer Rechte für ungültige idMap oder andere Benutzer
res.status(200).json({ Rights: [] });
}
}

View File

@@ -0,0 +1,40 @@
// pages/api/talas_v5/area.js
// Lesen von talas_v5 MySQL-Datenbank -> area Tabelle enthält DAUZ Geräte
// Wenn gebraucht wird, dann nutzen ansonsten löschen
import mysql from "mysql";
const dbConfig = {
host: process.env.DB_HOST,
user: process.env.DB_USER,
password: process.env.DB_PASSWORD,
database: process.env.DB_NAME,
port: process.env.DB_PORT,
};
//console.log("my dbconfig: ", dbConfig);
export default function handler(req, res) {
const connection = mysql.createConnection(dbConfig);
connection.connect((err) => {
if (err) {
console.error("Fehler beim Verbinden:", err.stack);
res.status(500).json({ error: "Verbindungsfehler zur Datenbank" });
return;
}
//console.log("Verbunden als ID", connection.threadId);
//Fehler weil, existiertdie Tabelle auf localhost:3000 nicht
connection.query("SELECT ..., ..., ..., ... FROM ... WHERE ... = ...", (error, results) => {
if (error) {
console.error("Fehler beim Abrufen der API", error);
res.status(500).json({ error: "Fehler bei der Abfrage" });
return;
}
// Wichtig: Senden Sie die Antwort zurück
res.status(200).json(results);
connection.end();
});
});
}

View File

@@ -0,0 +1,39 @@
// pages/api/talas_v5/location_device.js
// talas_v5 Datenbank -> location_device Tabelle enthält DAUZ Geräte
import mysql from "mysql";
const dbConfig = {
host: process.env.DB_HOST,
user: process.env.DB_USER,
password: process.env.DB_PASSWORD,
database: process.env.DB_NAME,
port: process.env.DB_PORT,
};
//console.log("my dbconfig: ", dbConfig);
export default function handler(req, res) {
const connection = mysql.createConnection(dbConfig);
connection.connect((err) => {
if (err) {
console.error("Fehler beim Verbinden:", err.stack);
res.status(500).json({ error: "Verbindungsfehler zur Datenbank" });
return;
}
//console.log("Verbunden als ID", connection.threadId);
//Fehler weil, existiertdie Tabelle auf localhost:3000 nicht
connection.query("SELECT idLD, iddevice, iddevice, name FROM location_device WHERE iddevice = 160", (error, results) => {
if (error) {
console.error("Fehler beim Abrufen der API", error);
res.status(500).json({ error: "Fehler bei der Abfrage" });
return;
}
// Wichtig: Senden Sie die Antwort zurück
res.status(200).json(results);
connection.end();
});
});
}

View File

@@ -0,0 +1,116 @@
// /pages/api/talas5/webserviceMap/GisStationsMeasurements.js
const GisStationsMeasurements = {
"Name": "Liste aller Messungen der Geraete",
"Zeitstempel": "2024-05-31T15:25:32.5047629+02:00",
"IdMap": "10",
"Statis": [
{
"IdLD": 50004,
"IdL": 18624,
"IdDP": 3,
"Na": "FBT",
"Val": "20.5",
"Unit": "°C",
"Gr": "GMA",
"Area_Name": "Renzenhof (RG)"
},
{
"IdLD": 50004,
"IdL": 18624,
"IdDP": 10,
"Na": "GT",
"Val": "nicht ermittelbar",
"Unit": "°C",
"Gr": "GMA",
"Area_Name": "Renzenhof (RG)"
},
{
"IdLD": 50004,
"IdL": 18624,
"IdDP": 2,
"Na": "LT",
"Val": "Datenlücke",
"Unit": "°C",
"Gr": "GMA",
"Area_Name": "Renzenhof (RG)"
},
{
"IdLD": 50004,
"IdL": 18624,
"IdDP": 6,
"Na": "RLF",
"Val": "100.0",
"Unit": "%",
"Gr": "GMA",
"Area_Name": "Renzenhof (RG)"
},
{
"IdLD": 50004,
"IdL": 18624,
"IdDP": 11,
"Na": "TPT",
"Val": "8.3",
"Unit": "°C",
"Gr": "GMA",
"Area_Name": "Renzenhof (RG)"
},
{
"IdLD": 50004,
"IdL": 18624,
"IdDP": 12,
"Na": "TT1",
"Val": "---",
"Unit": "°C",
"Gr": "GMA",
"Area_Name": "Renzenhof (RG)"
},
{
"IdLD": 50004,
"IdL": 18624,
"IdDP": 16,
"Na": "WFD",
"Val": "0.12",
"Unit": "mm",
"Gr": "GMA",
"Area_Name": "Renzenhof (RG)"
},
{
"IdLD": 50004,
"IdL": 18624,
"IdDP": 8,
"Na": "WGM",
"Val": "---",
"Unit": "m/s",
"Gr": "GMA",
"Area_Name": "Renzenhof (RG)"
},
{
"IdLD": 50004,
"IdL": 18624,
"IdDP": 9,
"Na": "WGS",
"Val": "---",
"Unit": "m/s",
"Gr": "GMA",
"Area_Name": "Renzenhof (RG)"
}
]
}
// Export an async function handler for the API route.
export default async function handler(req, res) {
// Initialize an empty params object to store query parameters.
const params = {
idMap: req.query.idMap,
};
// Check if the requested ID map and user match certain conditions.
if (params.idMap === '10') {
// If the conditions are met, return the GisStationsMeasurements object with a 200 status code.
res.status(200).json(GisStationsMeasurements);
} else {
// If not, return a 404 error with the message "Not Found".
res.status(404).send('Not Found');
}
};

View File

@@ -0,0 +1,281 @@
// /pages/api/talas5/webserviceMap/GisStationsStaticDistrict.js
const GisStationsStaticDistrict = {
"Name": "Liste aller Geraete einer bestimmten Karte",
"Zeitstempel": "2024-05-31T15:26:56.9235766+02:00",
"IdMap": "10",
"Points": [
{
"LD_Name": "CPL Bentheim",
"IdLD": 50017,
"Device": "CPL V3.5 mit 16 Kü",
"Link": "cpl.aspx?ver=35&kue=16&id=50017",
"Location_Name": "Technikraum",
"Location_Short": "BEHE",
"IdLocation": 17448,
"Area_Name": "Bad-Bentheim",
"Area_Short": "BEHE--00",
"IdArea": 16418,
"X": 51.5728,
"Y": 9.00056,
"Icon": 20,
"System": 1,
"Active": 0
},
{
"LD_Name": "Drucker",
"IdLD": 50084,
"Device": "Basisgerät",
"Link": "basis.aspx?ver=1&id=50084",
"Location_Name": "Technikraum",
"Location_Short": "SLUE",
"IdLocation": 17776,
"Area_Name": "Schlüchtern II",
"Area_Short": "SLUE--00",
"IdArea": 14688,
"X": 53.2455,
"Y": 8.1614,
"Icon": 14,
"System": 200,
"Active": 0
},
{
"LD_Name": "Türkontakt",
"IdLD": 50666,
"Device": "ECI",
"Link": "eci.aspx?ver=1&id=50666",
"Location_Name": "Technikraum",
"Location_Short": "SLUE",
"IdLocation": 17776,
"Area_Name": "Schlüchtern II",
"Area_Short": "SLUE--00",
"IdArea": 14688,
"X": 53.2455,
"Y": 8.1614,
"Icon": 17,
"System": 2,
"Active": 0
},
{
"LD_Name": "Triptis",
"IdLD": 50888,
"Device": "CPL 200",
"Link": "cpl.aspx?ver=30&kue=16&id=50888",
"Location_Name": "Technikraum",
"Location_Short": "SLUE",
"IdLocation": 17776,
"Area_Name": "Schlüchtern II",
"Area_Short": "SLUE--00",
"IdArea": 14688,
"X": 53.2455,
"Y": 8.1614,
"Icon": 20,
"System": 1,
"Active": 0
},
{
"LD_Name": "Rodaborn I",
"IdLD": 50889,
"Device": "cpl.mio V>6",
"Link": "cplmio.aspx?ver=1&id=50889",
"Location_Name": "Technikraum",
"Location_Short": "SLUE",
"IdLocation": 17776,
"Area_Name": "Schlüchtern II",
"Area_Short": "SLUE--00",
"IdArea": 14688,
"X": 53.2455,
"Y": 8.1614,
"Icon": 20,
"System": 1,
"Active": 0
},
{
"LD_Name": "Rodaborn II",
"IdLD": 50900,
"Device": "cpl.mio V>6",
"Link": "cplmio.aspx?ver=1&id=50900",
"Location_Name": "Technikraum",
"Location_Short": "SLUE",
"IdLocation": 17776,
"Area_Name": "Schlüchtern II",
"Area_Short": "SLUE--00",
"IdArea": 14688,
"X": 53.2455,
"Y": 8.1614,
"Icon": 20,
"System": 1,
"Active": 0
},
{
"LD_Name": "Hermsdorf",
"IdLD": 50901,
"Device": "CPL V3.5 mit 24 Kü",
"Link": "cpl.aspx?ver=35&kue=24&id=50901",
"Location_Name": "Technikraum",
"Location_Short": "SLUE",
"IdLocation": 17776,
"Area_Name": "Schlüchtern II",
"Area_Short": "SLUE--00",
"IdArea": 14688,
"X": 53.2455,
"Y": 8.1614,
"Icon": 20,
"System": 1,
"Active": 1
},
{
"LD_Name": "GMA Littwin (TEST)",
"IdLD": 50004,
"Device": "Glättemeldeanlage",
"Link": "gma.aspx?ver=1&id=50004",
"Location_Name": "RG Relaisraum",
"Location_Short": "REZR",
"IdLocation": 18624,
"Area_Name": "Renzenhof (RG)",
"Area_Short": "REZHRG00",
"IdArea": 16570,
"X": 53.246036,
"Y": 8.163293,
"Icon": 1,
"System": 11,
"Active": 0
},
{
"LD_Name": "NRS Testserver",
"IdLD": 50005,
"Device": "Notruf Server",
"Link": "nrs_server.aspx?ver=1&id=50005",
"Location_Name": "(EV Ammersricht BZR REL)",
"Location_Short": "AMME",
"IdLocation": 21118,
"Area_Name": "Ammersricht BZR (FGN)",
"Area_Short": "AMMER--00",
"IdArea": 15958,
"X": 52.52726,
"Y": 12.165488,
"Icon": 19,
"System": 8,
"Active": 0
},
{
"LD_Name": "Gateway 2",
"IdLD": 50007,
"Device": "Notruf Server",
"Link": "nrs_server.aspx?ver=1&id=50007",
"Location_Name": "(EV Ammersricht BZR REL)",
"Location_Short": "AMME",
"IdLocation": 21118,
"Area_Name": "Ammersricht BZR (FGN)",
"Area_Short": "AMMER--00",
"IdArea": 15958,
"X": 52.52726,
"Y": 12.165488,
"Icon": 19,
"System": 8,
"Active": 0
},
{
"LD_Name": "Basisgerät mit SNMP MVP",
"IdLD": 50669,
"Device": "Basisgerät + SNMP",
"Link": "basisSNMP.aspx?&ver=1&id=50669",
"Location_Name": "Mylinghauserstraße Engelbert",
"Location_Short": "G-GEVELSBE-1",
"IdLocation": 24012,
"Area_Name": "Gevelsberg",
"Area_Short": "GMA-GEVELSBE",
"IdArea": 20919,
"X": 51.316799,
"Y": 7.33281,
"Icon": 14,
"System": 200,
"Active": 1
},
{
"LD_Name": "Server 3",
"IdLD": 50009,
"Device": "Notruf Server",
"Link": "nrs_server.aspx?ver=1&id=50009",
"Location_Name": "Militärringstraße Militärringstraße",
"Location_Short": "G-KÃLN-1",
"IdLocation": 24015,
"Area_Name": "Köln",
"Area_Short": "GMA-KÃLN",
"IdArea": 20921,
"X": 50.898399,
"Y": 6.92278,
"Icon": 19,
"System": 8,
"Active": 0
},
{
"LD_Name": "ICL Test 5",
"IdLD": 50054,
"Device": "ICL",
"Link": "icl.aspx?ver=1&id=50054",
"Location_Name": "Recheder Mühlenweg Dortmund-Ems-Kanal",
"Location_Short": "G-OLFEN-SE-1",
"IdLocation": 24022,
"Area_Name": "Olfen-Selm",
"Area_Short": "GMA-OLFEN-SE",
"IdArea": 20926,
"X": 51.702202,
"Y": 7.40822,
"Icon": 23,
"System": 100,
"Active": 0
},
{
"LD_Name": "ICL Test 3",
"IdLD": 50052,
"Device": "ICL",
"Link": "icl.aspx?ver=1&id=50052",
"Location_Name": "Weidenstraße Hestenberg",
"Location_Short": "G-PLETTENB-1",
"IdLocation": 24024,
"Area_Name": "Plettenberg",
"Area_Short": "GMA-PLETTENB",
"IdArea": 20928,
"X": 51.224098,
"Y": 7.86969,
"Icon": 23,
"System": 100,
"Active": 0
},
{
"LD_Name": "Test Februar Kai",
"IdLD": 50912,
"Device": "Dauerzählstelle DZ",
"Link": "dauz.aspx?ver=1&id=50912",
"Location_Name": "In der Hoffnung Kiesberg - BG Ost",
"Location_Short": "G-WUPPERTA-4",
"IdLocation": 24039,
"Area_Name": "Wuppertal",
"Area_Short": "GMA-WUPPERTA",
"IdArea": 20937,
"X": 51.238899,
"Y": 7.12715,
"Icon": 14,
"System": 110,
"Active": 1
}
]
}
// Export an async function handler for the API route.
export default async function handler(req, res) {
// Initialize an empty params object to store query parameters.
const params = {
idMap: req.query.idMap,
idUser: req.query.idUser
};
// Check if the requested ID map and user match certain conditions.
if (params.idMap === '10' && params.idUser === '484') {
// If the conditions are met, return the GisStationsStaticDistrict object with a 200 status code.
res.status(200).json(GisStationsStaticDistrict);
} else {
// If not, return a 404 error with the message "Not Found".
res.status(404).send('Not Found');
}
};

View File

@@ -0,0 +1,100 @@
import mysql from "mysql2/promise";
const dbConfig = {
host: process.env.DB_HOST,
user: process.env.DB_USER,
password: process.env.DB_PASSWORD,
database: process.env.DB_NAME,
port: process.env.DB_PORT,
};
export default async function handler(req, res) {
const { idMap, idUser } = req.query;
if (!idMap || !idUser) {
res.status(400).json({ error: "idMap and idUser are required" });
return;
}
let connection;
try {
connection = await mysql.createConnection(dbConfig);
let onlySystem = -1;
let districtCounter = 0;
// Get onlySystem
const [mapResult] = await connection.execute(
"SELECT idsystem_typ FROM maps WHERE id = ?",
[idMap]
);
if (mapResult.length > 0) {
onlySystem = mapResult[0].idsystem_typ ?? -1;
}
// Get districtCounter
if (idUser > 0) {
const [userLayerResult] = await connection.execute(
"SELECT count(*) as count FROM user_User_layer1 WHERE iduser = ?",
[idUser]
);
districtCounter = userLayerResult[0].count;
}
// Get GisStatusStations
let query = `
SELECT ld.idLD, dc.message, p.level, p.name, p.color, ld.idDevice, de.isService, dc.idIcon
FROM location as l
LEFT JOIN location_coordinates AS co ON l.idLocation = co.idLocation and co.idMaps = ?
LEFT JOIN location_device AS ld ON ld.idLocation = l.idLocation
LEFT JOIN datapoint as d ON d.idLD = ld.idLD
LEFT JOIN datapoint_conditions AS dc ON dc.idcondition = d.last_message_condition
LEFT JOIN prio AS p ON p.idPrio = dc.idprio
LEFT JOIN devices AS de ON de.idDevice = ld.idDevice
LEFT JOIN area as a on a.idArea = l.idArea
WHERE p.level < 100 AND co.X > 0
`;
if (districtCounter > 0) {
query += ` AND a.iddistrict IN (SELECT iddistrict FROM user_user_layer1 WHERE iduser = ?)`;
}
if (onlySystem >= 0) {
query += ` AND de.idsystem_typ = ?`;
}
query += ` ORDER BY p.level desc`;
const queryParams = [idMap];
if (districtCounter > 0) {
queryParams.push(idUser);
}
if (onlySystem >= 0) {
queryParams.push(onlySystem);
}
const [results] = await connection.execute(query, queryParams);
const mpss = {
IdMap: idMap.toString(),
Statis: results.map((row) => ({
IdLD: row.idLD ?? -1,
Le: row.level ?? -1,
Me: row.message ?? "?",
Na: row.name ?? "?",
Co: row.color ?? "#ffffff",
Feld: row.idDevice ?? -1,
Icon: row.idIcon ?? 0,
})),
};
res.status(200).json(mpss);
} catch (error) {
console.error("Fehler beim Laden der Daten:", error);
res.status(500).json({ error: "Interner Serverfehler" });
} finally {
if (connection) {
await connection.end();
}
}
}

View File

@@ -0,0 +1,273 @@
// /pages/api/webServiceMap.js
const gisSystemStatic = {
"Name": "Liste aller angezeigten Systeme",
"Zeitstempel": "2024-05-31T15:08:49.8599542+02:00",
"IdMap": "10",
"Systems": [
{
"IdSystem": 1,
"Name": "TALAS",
"Longname": "Talas Meldestationen",
"Allow": 1,
"Icon": 1
},
{
"IdSystem": 2,
"Name": "ECI",
"Longname": "ECI Geräte",
"Allow": 1,
"Icon": 2
},
{
"IdSystem": 5,
"Name": "GSM Modem",
"Longname": "LR77 GSM Modems",
"Allow": 1,
"Icon": 5
},
{
"IdSystem": 6,
"Name": "Cisco Router",
"Longname": "Cisco Router",
"Allow": 1,
"Icon": 6
},
{
"IdSystem": 7,
"Name": "WAGO",
"Longname": "WAGO I/O Systeme",
"Allow": 1,
"Icon": 7
},
{
"IdSystem": 8,
"Name": "Siemens",
"Longname": "Siemens Notrufsystem",
"Allow": 0,
"Icon": 8
},
{
"IdSystem": 9,
"Name": "OTDR",
"Longname": "Glasfaserüberwachung OTU",
"Allow": 0,
"Icon": 9
},
{
"IdSystem": 10,
"Name": "WDM",
"Longname": " Wavelength Division Multiplexing",
"Allow": 0,
"Icon": 10
},
{
"IdSystem": 11,
"Name": "GMA",
"Longname": "Glättemeldeanlagen",
"Allow": 1,
"Icon": 11
},
{
"IdSystem": 13,
"Name": "Messstellen",
"Longname": "Messstellen",
"Allow": 0,
"Icon": 13
},
{
"IdSystem": 100,
"Name": "TALAS ICL",
"Longname": "Talas ICL Unterstationen",
"Allow": 1,
"Icon": 100
},
{
"IdSystem": 110,
"Name": "DAUZ",
"Longname": "Dauerzählstellen",
"Allow": 1,
"Icon": 110
},
{
"IdSystem": 111,
"Name": "SMS-Funkmodem",
"Longname": "SMS-Funkmodem",
"Allow": 0,
"Icon": 111
},
{
"IdSystem": 200,
"Name": "Sonstige",
"Longname": "Sonstige",
"Allow": 1,
"Icon": 200
}
],
"Rights": [
{
"IdRight": 1
},
{
"IdRight": 2
},
{
"IdRight": 3
},
{
"IdRight": 5
},
{
"IdRight": 6
},
{
"IdRight": 7
},
{
"IdRight": 8
},
{
"IdRight": 10
},
{
"IdRight": 11
},
{
"IdRight": 12
},
{
"IdRight": 20
},
{
"IdRight": 22
},
{
"IdRight": 23
},
{
"IdRight": 25
},
{
"IdRight": 30
},
{
"IdRight": 40
},
{
"IdRight": 41
},
{
"IdRight": 42
},
{
"IdRight": 43
},
{
"IdRight": 44
},
{
"IdRight": 45
},
{
"IdRight": 46
},
{
"IdRight": 47
},
{
"IdRight": 48
},
{
"IdRight": 49
},
{
"IdRight": 50
},
{
"IdRight": 51
},
{
"IdRight": 52
},
{
"IdRight": 55
},
{
"IdRight": 56
},
{
"IdRight": 60
},
{
"IdRight": 61
},
{
"IdRight": 62
},
{
"IdRight": 63
},
{
"IdRight": 64
},
{
"IdRight": 65
},
{
"IdRight": 68
},
{
"IdRight": 69
},
{
"IdRight": 70
},
{
"IdRight": 71
},
{
"IdRight": 72
},
{
"IdRight": 73
},
{
"IdRight": 79
},
{
"IdRight": 80
},
{
"IdRight": 90
},
{
"IdRight": 93
},
{
"IdRight": 94
},
{
"IdRight": 95
},
{
"IdRight": 96
}
]
}
// Export an async function handler for the API route.
export default async function handler(req, res) {
// Initialize an empty params object to store query parameters.
const params = {
idMap: req.query.idMap,
idUser: req.query.idUser
};
// Check if the requested ID map and user match certain conditions.
if (params.idMap === '10' && params.idUser === '484') {
// If the conditions are met, return the gisSystemStatic object with a 200 status code.
res.status(200).json(gisSystemStatic);
} else {
// If not, return a 404 error with the message "Not Found".
res.status(404).send('Not Found');
}
};

View File

@@ -0,0 +1,70 @@
import mysql from "mysql";
const dbConfig = {
host: process.env.DB_HOST,
user: process.env.DB_USER,
password: process.env.DB_PASSWORD,
database: process.env.DB_NAME,
port: process.env.DB_PORT,
};
const connection = mysql.createConnection(dbConfig);
connection.connect((err) => {
if (err) {
console.error("Fehler beim Verbinden:", err.stack);
return;
}
console.log("Database connected successfully.");
});
export default function handler(req, res) {
const idMap = req.query.idMap;
if (req.method !== "GET") {
return res.status(405).json({ error: "Nur GET Methode erlaubt" });
}
connection.query(`
SELECT
ld.idLD,
dp.idDP,
dp.name AS Na,
dp.value AS Val,
dp.unit AS Unit,
mg.name AS Gr,
ld.idLocation,
area.Name AS Area_Name
FROM location_device as ld
LEFT JOIN location_coordinates AS co ON ld.idLocation = co.idLocation and co.idMaps = ${idMap}
LEFT JOIN devices AS de ON de.idDevice = ld.idDevice
LEFT JOIN datapoint AS dp ON ld.idLD = dp.idLD
LEFT JOIN message_group AS mg ON dp.idmessage_group = mg.idmessage_group
LEFT JOIN location AS loc ON ld.idLocation = loc.idLocation
LEFT JOIN area AS area ON loc.idArea = area.idArea
WHERE co.X > 0 AND dp.idmessage_group>0 AND length(dp.unit)> 0 AND length(dp.value)> 0
`, (error, results) => {
if (error) {
console.error("Fehler beim Abrufen der gis_lines:", error);
return res
.status(500)
.json({ error: "Fehler beim Abrufen der gis_lines" });
}
const response = {
"Name": "Liste aller Messungen der Geraete",
"Zeitstempel": new Date().toISOString(),
"IdMap":idMap,
"Statis": results.map((row) => ({
IdLD: row.idLD,
IdDP: row.idDP,
Na: row.Na,
Val: row.Val,
Unit: row.Unit,
Gr: row.Gr,
IdLocation: row.IdLocation,
Area_Name: row.Area_Name,
})),
};
res.json(response);
});
}

View File

@@ -0,0 +1,37 @@
// /pages/api/talas_v5_DB/gisLines/readGisLines.js
import mysql from "mysql";
const dbConfig = {
host: process.env.DB_HOST,
user: process.env.DB_USER,
password: process.env.DB_PASSWORD,
database: process.env.DB_NAME,
port: process.env.DB_PORT,
};
const connection = mysql.createConnection(dbConfig);
connection.connect((err) => {
if (err) {
console.error("Fehler beim Verbinden:", err.stack);
return;
}
//console.log("Database connected successfully.");
});
export default function handler(req, res) {
if (req.method !== "GET") {
return res.status(405).json({ error: "Nur GET Methode erlaubt" });
}
const query = "SELECT * FROM talas_v5.gis_lines;";
connection.query(query, (error, results) => {
if (error) {
console.error("Fehler beim Abrufen der gis_lines:", error);
return res.status(500).json({ error: "Fehler beim Abrufen der gis_lines" });
}
if (results.length > 0) {
res.json(results);
} else {
res.status(404).json({ error: "Gerät nicht gefunden" });
}
});
}

View File

@@ -0,0 +1,61 @@
// /pages/api/talas_v5_DB/gisLines/updateLineCoordinates.js
import mysql from "mysql";
const dbConfig = {
host: process.env.DB_HOST,
user: process.env.DB_USER,
password: process.env.DB_PASSWORD,
database: process.env.DB_NAME,
port: process.env.DB_PORT,
};
const connection = mysql.createConnection(dbConfig);
connection.connect((err) => {
if (err) {
console.error("Fehler beim Verbinden:", err.stack);
return;
}
//console.log("Database connected successfully.");
});
export default function handler(req, res) {
if (req.method !== "POST") {
return res.status(405).json({ error: "Nur POST Methode erlaubt" });
}
const { idLD, idModul, newCoordinates } = req.body;
if (!idLD || !idModul || !newCoordinates) {
return res.status(400).json({ error: "Fehlende Daten" });
}
const newLineString = `LINESTRING(${newCoordinates.map((coord) => `${coord[0]} ${coord[1]}`).join(",")})`;
const query = "UPDATE talas_v5.gis_lines SET points = ST_GeomFromText(?) WHERE idLD = ? AND idModul = ?;";
connection.beginTransaction((err) => {
if (err) {
throw err;
}
connection.query(query, [newLineString, idLD, idModul], (error, results, fields) => {
if (error) {
return connection.rollback(() => {
console.error("Fehler beim Aktualisieren der gis_lines:", error);
res.status(500).json({ error: "Fehler beim Aktualisieren der gis_lines" });
});
}
connection.commit((err) => {
if (err) {
return connection.rollback(() => {
throw err;
});
}
console.log("Transaction Complete.");
res.status(200).json({
success: "Updated successfully.",
affectedRows: results.affectedRows,
});
});
});
});
}

View File

@@ -0,0 +1,40 @@
// API in /api/talas_v5_DB/locationDevice/getDeviceId.js
import mysql from "mysql";
const dbConfig = {
host: process.env.DB_HOST,
user: process.env.DB_USER,
password: process.env.DB_PASSWORD,
database: process.env.DB_NAME,
port: process.env.DB_PORT,
};
const connection = mysql.createConnection(dbConfig);
connection.connect((err) => {
if (err) {
console.error("Fehler beim Verbinden:", err.stack);
return;
}
});
export default function handler(req, res) {
if (req.method !== "GET") {
return res.status(405).json({ error: "Nur GET Methode erlaubt" });
}
const { deviceName } = req.query;
const query = "SELECT idLD FROM location_device WHERE name = ?";
connection.query(query, [deviceName], (error, results) => {
if (error) {
console.error("Fehler beim Abrufen der Geräte-ID:", error);
return res
.status(500)
.json({ error: "Fehler beim Abrufen der Geräte-ID" });
}
if (results.length > 0) {
res.json({ idLD: results[0].idLD });
} else {
res.status(404).json({ error: "Gerät nicht gefunden" });
}
});
}

View File

@@ -0,0 +1,46 @@
// API in /api/talas_v5_DB/locationDevice/locationDeviceNameById.js
import mysql from "mysql";
const dbConfig = {
host: process.env.DB_HOST,
user: process.env.DB_USER,
password: process.env.DB_PASSWORD,
database: process.env.DB_NAME,
port: process.env.DB_PORT,
};
const connection = mysql.createConnection(dbConfig);
connection.connect((err) => {
if (err) {
console.error("Fehler beim Verbinden:", err.stack);
return;
}
});
export default async function handler(req, res) {
if (req.method !== "GET") {
return res.status(405).json({ error: "Nur GET Methode erlaubt" });
}
const { idLD } = req.query;
try {
const query = "SELECT name FROM location_device WHERE idLD = ?";
const [results] = await new Promise((resolve, reject) => {
connection.query(query, [idLD], (error, results) => {
if (error) {
return reject(error);
}
resolve(results);
});
});
if (results.length > 0) {
res.json({ name: results[0].name });
} else {
res.status(404).json({ error: "Gerät nicht gefunden", idLD, results });
}
} catch (error) {
console.error("Fehler beim Abrufen des Gerätenamens in locationDeviceNameById.js :", error);
res.status(500).json({ error: "Fehler beim Abrufen des Gerätenamens" });
}
}

View File

@@ -0,0 +1,35 @@
// API in /api/talas_v5_DB/locationDevice/locationDevices.js
import mysql from "mysql";
const dbConfig = {
host: process.env.DB_HOST,
user: process.env.DB_USER,
password: process.env.DB_PASSWORD,
database: process.env.DB_NAME,
port: process.env.DB_PORT,
};
const connection = mysql.createConnection(dbConfig);
connection.connect((err) => {
if (err) {
console.error("Fehler beim Verbinden:", err.stack);
return;
}
});
export default function handler(req, res) {
if (req.method !== "GET") {
return res.status(405).json({ error: "Nur GET Methode erlaubt" });
}
const query = "SELECT * FROM location_device WHERE iddevice = 160";
connection.query(query, (error, results) => {
if (error) {
console.error("Fehler beim Abrufen der Geräteinformationen:", error);
return res
.status(500)
.json({ error: "Fehler beim Abrufen der Geräteinformationen" });
}
res.json(results);
});
}

View File

@@ -0,0 +1,33 @@
// pages/api/talas_v5_DB/poiTyp/readPoiTyp.js
import mysql from "mysql";
const pool = mysql.createPool({
//connectionLimit: 10,
host: process.env.DB_HOST,
user: process.env.DB_USER,
password: process.env.DB_PASSWORD,
database: process.env.DB_NAME,
port: process.env.DB_PORT,
});
export default function handler(req, res) {
if (req.method === "GET") {
const query = "SELECT * FROM poityp";
pool.query(query, (error, results) => {
if (error) {
console.error("Fehler beim Abfragen der Datenbank:", error);
return res.status(500).json({ error: "Ein Fehler ist aufgetreten" });
}
if (results.length === 0) {
return res.status(404).json({ message: "Keine Einträge gefunden" });
}
res.status(200).json(results);
});
} else {
res.setHeader("Allow", ["GET"]);
res.status(405).end(`Method ${req.method} Not Allowed`);
}
}

View File

@@ -0,0 +1,38 @@
// pages/api/talas_v5_DB/pois/addLocation.js
import mysql from "mysql";
const dbConfig = {
host: process.env.DB_HOST,
user: process.env.DB_USER,
password: process.env.DB_PASSWORD,
database: process.env.DB_NAME,
port: process.env.DB_PORT,
};
export default function handler(req, res) {
if (req.method === "POST") {
const { name, poiTypeId, latitude, longitude, idLD } = req.body;
console.log("Received data:", req.body); // Überprüfen der empfangenen Daten
const connection = mysql.createConnection(dbConfig);
const query =
"INSERT INTO poi (description, idPoiTyp, position, idLD) VALUES (?, ?, ST_GeomFromText(?),?)";
const point = `POINT(${longitude} ${latitude})`;
const values = [name, poiTypeId, point, idLD]; // Stellen Sie sicher, dass poiTypeId korrekt ist
connection.query(query, values, (error, results) => {
connection.end();
if (error) {
console.error("Fehler beim Einfügen des Standorts:", error);
return res.status(500).json({ error: "Ein Fehler ist aufgetreten" });
}
res.status(200).json({
id: results.insertId,
message: "Standort erfolgreich hinzugefügt",
});
});
} else {
res.setHeader("Allow", ["POST"]);
res.status(405).end(`Method ${req.method} Not Allowed`);
}
}

View File

@@ -0,0 +1,45 @@
// pages/api/talas_v5_DB/pois/deletePoi.js
import mysql from "mysql";
// Datenbankkonfiguration
const dbConfig = {
host: process.env.DB_HOST,
user: process.env.DB_USER,
password: process.env.DB_PASSWORD,
database: process.env.DB_NAME,
port: process.env.DB_PORT,
};
const connection = mysql.createConnection(dbConfig);
connection.connect((err) => {
if (err) {
console.error("Fehler beim Verbinden:", err.stack);
return;
}
console.log("Verbunden als ID", connection.threadId);
});
export default function handler(req, res) {
if (req.method !== "DELETE") {
return res.status(405).json({ error: "Nur DELETE Methode erlaubt" });
}
const { id } = req.query; // ID aus der Anfrage holen
if (!id) {
return res.status(400).json({ error: "POI ID ist erforderlich" });
}
const query = "DELETE FROM poi WHERE idPoi = ?";
connection.query(query, [id], (error, results) => {
if (error) {
console.error("Fehler beim Löschen des POI:", error);
return res.status(500).json({ error: "Fehler beim Löschen des POI" });
}
if (results.affectedRows > 0) {
res.json({ message: "POI erfolgreich gelöscht" });
} else {
res.status(404).json({ error: "POI nicht gefunden" });
}
});
}

View File

@@ -0,0 +1,42 @@
// pages/api/talas_v5_DB/pois/getPoiById.js
import mysql from "mysql";
const dbConfig = {
host: process.env.DB_HOST,
user: process.env.DB_USER,
password: process.env.DB_PASSWORD,
database: process.env.DB_NAME,
port: process.env.DB_PORT,
};
export default function handler(req, res) {
if (req.method === "GET") {
const { idPoi } = req.query;
const connection = mysql.createConnection(dbConfig);
connection.connect((err) => {
if (err) {
console.error("Fehler beim Verbinden:", err.stack);
return res
.status(500)
.json({ error: "Verbindungsfehler zur Datenbank" });
}
const query = "SELECT description FROM poi WHERE idPoi = ?";
connection.query(query, [idPoi], (error, results) => {
connection.end();
if (error) {
console.error("Fehler bei der Abfrage:", error);
return res.status(500).json({ error: "Fehler bei der Abfrage" });
}
if (results.length === 0) {
return res.status(404).json({ error: "POI nicht gefunden" });
}
res.status(200).json(results[0]);
});
});
} else {
res.setHeader("Allow", ["GET"]);
res.status(405).end(`Method ${req.method} Not Allowed`);
}
}

View File

@@ -0,0 +1,42 @@
// pages/api/talas_v5_DB/pois/poi-icons.js
import mysql from "mysql";
const dbConfig = {
host: process.env.DB_HOST,
user: process.env.DB_USER,
password: process.env.DB_PASSWORD,
database: process.env.DB_NAME,
port: process.env.DB_PORT,
};
const connection = mysql.createConnection(dbConfig);
connection.connect((err) => {
if (err) {
console.error("Fehler beim Verbinden:", err.stack);
return;
}
});
export default function handler(req, res) {
if (req.method !== "GET") {
return res.status(405).json({ error: "Nur GET Methode erlaubt" });
}
const query = `SELECT p.idPoi, i.path
FROM poi p
JOIN poiTyp pt ON p.idPoiTyp = pt.idPoiTyp
JOIN poiicons i ON pt.icon = i.idpoiicons;`;
connection.query(query, (error, results) => {
try {
if (error) {
throw error;
}
res.json(results);
} catch (err) {
console.error("Fehler beim Abrufen der icons:", err);
res.status(500).json({ error: "Fehler beim Abrufen der icons" });
}
});
}

View File

@@ -0,0 +1,42 @@
// pages/api/talas_v5_DB/pois/readLocations.js
import mysql from "mysql";
const dbConfig = {
host: process.env.DB_HOST,
user: process.env.DB_USER,
password: process.env.DB_PASSWORD,
database: process.env.DB_NAME,
port: process.env.DB_PORT,
};
//console.log("my dbconfig: ", dbConfig);
export default function handler(req, res) {
const connection = mysql.createConnection(dbConfig);
connection.connect((err) => {
if (err) {
console.error("Fehler beim Verbinden:", err.stack);
res.status(500).json({ error: "Verbindungsfehler zur Datenbank" });
return;
}
//console.log("Verbunden als ID", connection.threadId);
connection.query("SELECT idPoi, description, idPoiTyp, idLD, ST_AsText(position) AS position FROM poi", (error, results) => {
if (error) {
console.error("Fehler beim Abrufen der API", error);
res.status(500).json({ error: "Fehler bei der Abfrage" });
return;
}
// Wichtig: Senden Sie die Antwort zurück
res.status(200).json(results);
/* console.log(
"--------------- location.js ---------------",
"results in location.js : ",
results,
"---------------------- location.js end ---------------------------"
); */
connection.end();
});
});
}

View File

@@ -0,0 +1,39 @@
// pages/api/talas_v5_DB/pois/updateLocation.js
import mysql from "mysql";
import util from "util";
const dbConfig = {
host: process.env.DB_HOST,
user: process.env.DB_USER,
password: process.env.DB_PASSWORD,
database: process.env.DB_NAME,
port: process.env.DB_PORT,
charset: "utf8mb4",
};
export default async function handler(req, res) {
if (req.method !== "POST") {
res.setHeader("Allow", ["POST"]);
return res.status(405).end(`Method ${req.method} Not Allowed`);
}
const { id, latitude, longitude } = req.body;
const connection = mysql.createConnection(dbConfig);
// Promisify the query method
const query = util.promisify(connection.query).bind(connection);
try {
await query("UPDATE poi SET position = POINT(?, ?) WHERE idPoi = ?", [
longitude,
latitude,
id,
]);
res.status(200).json({ success: true });
} catch (error) {
console.error(error);
res.status(500).json({ error: "Ein Fehler ist aufgetreten" });
} finally {
connection.end();
}
}

View File

@@ -0,0 +1,46 @@
// pages/api/talas_v5_DB/pois/updatePoi.js
import mysql from "mysql";
const dbConfig = {
host: process.env.DB_HOST,
user: process.env.DB_USER,
password: process.env.DB_PASSWORD,
database: process.env.DB_NAME,
port: process.env.DB_PORT,
};
const connection = mysql.createConnection(dbConfig);
connection.connect((err) => {
if (err) {
console.error("Fehler beim Verbinden:", err.stack);
return;
}
//console.log("Verbunden als ID", connection.threadId);
});
export default function handler(req, res) {
if (req.method !== "POST") {
return res.status(405).json({ error: "Nur POST Methode erlaubt" });
}
const { idPoi, description, idPoiTyp, idLD } = req.body; // Stellen Sie sicher, dass die Felder korrekt benannt sind
//console.log("Empfangene Daten:", req.body); // Loggen der empfangenen Daten zur Überprüfung
if (!idPoi) {
return res.status(400).json({ error: "POI ID ist erforderlich" });
}
const query = "UPDATE talas_v5.poi SET description = ?, idPoiTyp = ?, idLD = ? WHERE idPoi = ?";
connection.query(query, [description, idPoiTyp, idLD, idPoi], (error, results) => {
if (error) {
console.error("Fehler beim Aktualisieren des POI:", error);
return res.status(500).json({ error: "Fehler beim Aktualisieren des POI" });
}
if (results.affectedRows > 0) {
res.json({ message: "POI erfolgreich aktualisiert" });
} else {
res.status(404).json({ error: "POI nicht gefunden" });
}
});
}

View File

@@ -0,0 +1,40 @@
// pages/api/talas_v5_DB/priorityConfig.js
// in tals5 http://10.10.0.13/talas5/Management/PriorityConfig.aspx beinhaltet die Tabelle prio die Prioritäten der Meldungen (Level 1-4) oder (0-4) je nachdem DB-Design
// das ist die API, die die Prioritäten zurückgibt
import mysql from "mysql";
const dbConfig = {
host: process.env.DB_HOST,
user: process.env.DB_USER,
password: process.env.DB_PASSWORD,
database: process.env.DB_NAME,
port: process.env.DB_PORT,
};
//console.log("my dbconfig: ", dbConfig);
export default function handler(req, res) {
const connection = mysql.createConnection(dbConfig);
connection.connect((err) => {
if (err) {
console.error("Fehler beim Verbinden:", err.stack);
res.status(500).json({ error: "Verbindungsfehler zur Datenbank" });
return;
}
//console.log("Verbunden als ID", connection.threadId);
//Fehler weil, existiertdie Tabelle auf localhost:3000 nicht
connection.query("SELECT idprio, level, name, color FROM prio ", (error, results) => {
if (error) {
console.error("Fehler beim Abrufen der API", error);
res.status(500).json({ error: "Fehler bei der Abfrage" });
return;
}
// Wichtig: Senden Sie die Antwort zurück
res.status(200).json(results);
connection.end();
});
});
}

View File

@@ -1,11 +1,14 @@
// pages/api/[...path].js // pages/api/[...path].js
import { createProxyMiddleware } from "http-proxy-middleware"; import { createProxyMiddleware } from "http-proxy-middleware";
//import { SERVER_URL } from "../config/urls.js";
//console.log("SERVER_URL:", SERVER_URL); // Debug-Ausgabe
export default createProxyMiddleware({ export default createProxyMiddleware({
//target: "http://192.168.10.58:3001", //target: "http://192.168.10.58:3001",
// Stationen bekommen // Stationen bekommen
target: "http://10.10.0.13", // Ziel-URL des Proxys // API Aufruf zum mapGisStationsStaticDistrictUrl, mapGisStationsStatusDistrictUrl, mapGisStationsMeasurementsUrl, mapGisSystemStaticUrl und mapDataIconUrl //target: "http://10.10.0.13", // Ziel-URL des Proxys // API Aufruf zum mapGisStationsStaticDistrictUrl, mapGisStationsStatusDistrictUrl, mapGisStationsMeasurementsUrl, mapGisSystemStaticUrl und mapDataIconUrl
target: `${process.env.NEXT_PUBLIC_SERVER_URL}`, //
//target: urls.PROXY_TARGET,
//target: "http://localhost:3000", // Ziel-URL des Proxys //target: "http://localhost:3000", // Ziel-URL des Proxys
//target: "http://192.168.10.187:3000", // Ziel-URL des Proxys //target: "http://192.168.10.187:3000", // Ziel-URL des Proxys
//target: "http://192.168.10.14", //target: "http://192.168.10.14",

Some files were not shown because too many files have changed in this diff Show More