feat: AreaDropdown separate from MapLayerControlPanel

This commit is contained in:
ISA
2025-09-15 13:38:19 +02:00
parent 59c8680c23
commit d166b2468d
7 changed files with 129 additions and 17 deletions

View File

@@ -23,4 +23,4 @@ NEXT_PUBLIC_USE_MOCKS=true
# z.B. http://10.10.0.13/xyz/index.aspx -> basePath in config.json auf /xyz setzen # z.B. http://10.10.0.13/xyz/index.aspx -> basePath in config.json auf /xyz setzen
# basePath wird jetzt in public/config.json gepflegt # basePath wird jetzt in public/config.json gepflegt
# App-Versionsnummer # App-Versionsnummer
NEXT_PUBLIC_APP_VERSION=1.1.365 NEXT_PUBLIC_APP_VERSION=1.1.366

View File

@@ -24,4 +24,4 @@ NEXT_PUBLIC_USE_MOCKS=false
# basePath wird jetzt in public/config.json gepflegt # basePath wird jetzt in public/config.json gepflegt
# App-Versionsnummer # App-Versionsnummer
NEXT_PUBLIC_APP_VERSION=1.1.365 NEXT_PUBLIC_APP_VERSION=1.1.366

View File

@@ -34,6 +34,7 @@ import CoordinatePopup from "@/components/contextmenu/CoordinatePopup.js";
import MapLayersControlPanel from "@/components/uiWidgets/mapLayersControlPanel/MapLayersControlPanel.js"; import MapLayersControlPanel from "@/components/uiWidgets/mapLayersControlPanel/MapLayersControlPanel.js";
import CoordinateInput from "@/components/uiWidgets/CoordinateInput.js"; import CoordinateInput from "@/components/uiWidgets/CoordinateInput.js";
import VersionInfoModal from "@/components/uiWidgets/VersionInfoModal.js"; import VersionInfoModal from "@/components/uiWidgets/VersionInfoModal.js";
import AreaDropdown from "@/components/uiWidgets/AreaDropdown";
//----------Daten aus API-------------------- //----------Daten aus API--------------------
import { fetchPoiDataService } from "@/services/database/pois/fetchPoiDataByIdService.js"; import { fetchPoiDataService } from "@/services/database/pois/fetchPoiDataByIdService.js";
import AddPOIModal from "@/components/pois/AddPOIModal.js"; import AddPOIModal from "@/components/pois/AddPOIModal.js";
@@ -164,6 +165,7 @@ const MapComponent = ({ locations, onLocationUpdate, lineCoordinates }) => {
const [showVersionInfoModal, setShowVersionInfoModal] = useState(false); const [showVersionInfoModal, setShowVersionInfoModal] = useState(false);
const [poiTypMap, setPoiTypMap] = useState(new Map()); const [poiTypMap, setPoiTypMap] = useState(new Map());
const [showPopup, setShowPopup] = useState(false); const [showPopup, setShowPopup] = useState(false);
const [showAreaDropdown, setShowAreaDropdown] = useState(false);
const poiLayerRef = useRef(null); // Referenz auf die Layer-Gruppe für Datenbank-Marker const poiLayerRef = useRef(null); // Referenz auf die Layer-Gruppe für Datenbank-Marker
const mapRef = useRef(null); // Referenz auf das DIV-Element der Karte const mapRef = useRef(null); // Referenz auf das DIV-Element der Karte
const [map, setMap] = useState(null); // Zustand der Karteninstanz const [map, setMap] = useState(null); // Zustand der Karteninstanz
@@ -1133,7 +1135,8 @@ const MapComponent = ({ locations, onLocationUpdate, lineCoordinates }) => {
{GisStationsStaticDistrict && {GisStationsStaticDistrict &&
GisStationsStaticDistrict.Points?.length > 0 && GisStationsStaticDistrict.Points?.length > 0 &&
showLayersPanel && ( showLayersPanel &&
!showAreaDropdown && (
<MapLayersControlPanel <MapLayersControlPanel
className="z-50" className="z-50"
handlePolylineCheckboxChange={handlePolylineCheckboxChange} handlePolylineCheckboxChange={handlePolylineCheckboxChange}
@@ -1157,13 +1160,14 @@ const MapComponent = ({ locations, onLocationUpdate, lineCoordinates }) => {
)} )}
{/* Marker-Icon (line-md) */} {/* Marker-Icon (line-md) */}
<button <button
onClick={() => {}} onClick={() => setShowAreaDropdown(v => !v)}
aria-label="Marker" aria-label="Marker"
className="rounded-full bg-white/90 hover:bg-white shadow p-1" className="rounded-full bg-white/90 hover:bg-white shadow p-1"
title="Marker" title="Marker"
> >
<MapMarkerIcon className="h-8 w-8" /> <MapMarkerIcon className="h-8 w-8" />
</button> </button>
{showAreaDropdown && <AreaDropdown onClose={() => setShowAreaDropdown(false)} />}
{/*Lupe: Koordinatensuche ein-/ausblenden */} {/*Lupe: Koordinatensuche ein-/ausblenden */}
<button <button
onClick={() => setShowCoordinateInput(v => !v)} onClick={() => setShowCoordinateInput(v => !v)}

View File

@@ -0,0 +1,79 @@
// /components/uiWidgets/AreaDropdown.js
import React, { useEffect, useMemo } from "react";
import { useDispatch, useSelector } from "react-redux";
import { setSelectedArea } from "@/redux/slices/selectedAreaSlice";
import { selectGisStationsStaticDistrict } from "@/redux/slices/webservice/gisStationsStaticDistrictSlice";
import { selectGisSystemStatic } from "@/redux/slices/webservice/gisSystemStaticSlice";
/**
* Kleines Dropdown zur Auswahl der Station (Area_Name),
* nutzt dieselbe Datenquelle wie das MapLayersControlPanel.
*/
const AreaDropdown = ({ onClose }) => {
const dispatch = useDispatch();
const GisStationsStaticDistrict = useSelector(selectGisStationsStaticDistrict) || {};
const GisSystemStatic = useSelector(selectGisSystemStatic) || [];
// Erlaubte Systeme: Allow === 1 und Map === 1
const allowedSystems = useMemo(() => {
return new Set(
(Array.isArray(GisSystemStatic) ? GisSystemStatic : [])
.filter(sys => sys.Allow === 1 && sys.Map === 1)
.map(sys => sys.IdSystem)
);
}, [GisSystemStatic]);
// Uniqe Areas basierend auf Allowed Systems
const areaOptions = useMemo(() => {
const points = GisStationsStaticDistrict?.Points || [];
const seen = new Set();
const filtered = points.filter(p => {
if (!p?.Area_Name) return false;
if (!allowedSystems.has(p.System)) return false;
if (seen.has(p.Area_Name)) return false;
seen.add(p.Area_Name);
return true;
});
return filtered.map(p => ({ label: p.Area_Name, value: p.IdLD }));
}, [GisStationsStaticDistrict, allowedSystems]);
const handleChange = e => {
const selectedIndex = e.target.options.selectedIndex;
const label = e.target.options[selectedIndex].text;
dispatch(setSelectedArea(label));
onClose?.();
};
// Schließe mit ESC
useEffect(() => {
const onKey = e => {
if (e.key === "Escape") onClose?.();
};
window.addEventListener("keydown", onKey);
return () => window.removeEventListener("keydown", onKey);
}, [onClose]);
return (
<div className="absolute top-16 right-3 z-[60]">
<div className="bg-white rounded-md shadow-lg p-3 border border-gray-200 min-w-[220px]">
<div className="text-sm font-semibold mb-2">Station wählen</div>
<select
onChange={handleChange}
className="border p-2 rounded w-full"
defaultValue="__default__"
>
<option value="__default__" disabled>
Bitte wählen
</option>
{areaOptions.map(opt => (
<option key={opt.value} value={opt.value}>
{opt.label}
</option>
))}
</select>
</div>
</div>
);
};
export default AreaDropdown;

View File

@@ -241,28 +241,55 @@ function MapLayersControlPanel({ handlePolylineCheckboxChange }) {
}, [GisStationsStaticDistrict]); }, [GisStationsStaticDistrict]);
//--------------------------- //---------------------------
// Polyline (Kabelstrecken) abhängig von TALAS (system-1)
const onPolylineToggle = checked => {
if (editMode) return;
// Wenn Nutzer Kabelstrecken einschaltet, aber TALAS aktuell ausgeblendet ist,
// dann TALAS automatisch aktivieren (sofern erlaubt)
const talasKey = "system-1";
const talasVisible = !!mapLayersVisibility[talasKey];
if (checked && isTalasAllowed && !talasVisible) {
dispatch(setLayerVisibility({ layer: talasKey, visibility: true }));
// Persistiere Sichtbarkeit map/user-spezifisch
const mapId2 = localStorage.getItem("currentMapId");
const userId2 = localStorage.getItem("currentUserId");
const mapStorageKey =
mapId2 && userId2 ? `mapLayersVisibility_m${mapId2}_u${userId2}` : "mapLayersVisibility";
localStorage.setItem(
mapStorageKey,
JSON.stringify({ ...mapLayersVisibility, [talasKey]: true })
);
// Event feuern wie an anderer Stelle
setTimeout(() => {
const event = new Event("visibilityChanged");
window.dispatchEvent(event);
}, 0);
}
// Sichtbarkeit der Kabelstrecken setzen
handlePolylineCheckboxChange(checked);
};
//--------------------------- //---------------------------
return ( return (
<div <div
id="mainDataSheet" id="mainDataSheet"
className="absolute top-3 right-3 w-1/6 min-w-[300px] max-w-[400px] z-10 bg-white p-2 rounded-lg shadow-lg" className="absolute top-16 right-3 w-1/6 min-w-[300px] max-w-[200px] 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 space-x-2"> <div className="flex items-center justify-between space-x-2">
<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"
style={{ minWidth: "150px", maxWidth: "200px" }} style={{ minWidth: "150px", maxWidth: "200px" }}
> >
<option value="Station wählen">Station wählen</option> <option value="Station wählen">Station wählen</option>
{/*
...new Map(
(GisStationsStaticDistrict.Points || [])
.filter(p => !!p.Area_Name)
.map(p => [p.Area_Name, p])
).values(),
*/}
{[ {[
...new Map( ...new Map(
(GisStationsStaticDistrict.Points || []) (GisStationsStaticDistrict.Points || [])
@@ -275,6 +302,8 @@ function MapLayersControlPanel({ handlePolylineCheckboxChange }) {
</option> </option>
))} ))}
</select> </select>
*/}
{/* {/*
<div className="flex items-center space-x-2"> <div className="flex items-center space-x-2">
<EditModeToggle /> <EditModeToggle />
@@ -312,7 +341,7 @@ function MapLayersControlPanel({ handlePolylineCheckboxChange }) {
<input <input
type="checkbox" type="checkbox"
checked={kabelstreckenVisible} checked={kabelstreckenVisible}
onChange={e => handlePolylineCheckboxChange(e.target.checked)} onChange={e => onPolylineToggle(e.target.checked)}
id="polyline-checkbox" id="polyline-checkbox"
disabled={!isTalasAllowed || editMode} disabled={!isTalasAllowed || editMode}
/> />

4
package-lock.json generated
View File

@@ -1,12 +1,12 @@
{ {
"name": "nodemap", "name": "nodemap",
"version": "1.1.365", "version": "1.1.366",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "nodemap", "name": "nodemap",
"version": "1.1.365", "version": "1.1.366",
"dependencies": { "dependencies": {
"@emotion/react": "^11.13.3", "@emotion/react": "^11.13.3",
"@emotion/styled": "^11.13.0", "@emotion/styled": "^11.13.0",

View File

@@ -1,6 +1,6 @@
{ {
"name": "nodemap", "name": "nodemap",
"version": "1.1.365", "version": "1.1.366",
"dependencies": { "dependencies": {
"@emotion/react": "^11.13.3", "@emotion/react": "^11.13.3",
"@emotion/styled": "^11.13.0", "@emotion/styled": "^11.13.0",