157 lines
4.3 KiB
TypeScript
157 lines
4.3 KiB
TypeScript
import { useMapStore } from "_store/mapStore";
|
|
import { Marker as LMarker } from "leaflet";
|
|
import { Fragment, useEffect, useRef } from "react";
|
|
import { Marker, Polygon, Popup } from "react-leaflet";
|
|
import L from "leaflet";
|
|
import { useQuery } from "@tanstack/react-query";
|
|
import { getMissionsAPI } from "querys/missions";
|
|
import { OSMWay } from "@repo/db";
|
|
import { usePannelStore } from "_store/pannelStore";
|
|
|
|
export const SearchElements = () => {
|
|
const { searchElements, searchPopup, setSearchPopup, setContextMenu, openMissionMarker } =
|
|
useMapStore();
|
|
const { missionFormValues, setMissionFormValues } = usePannelStore((state) => state);
|
|
const missions = useQuery({
|
|
queryKey: ["missions"],
|
|
queryFn: () =>
|
|
getMissionsAPI({
|
|
OR: [
|
|
{
|
|
state: "draft",
|
|
},
|
|
{
|
|
state: "running",
|
|
},
|
|
],
|
|
}),
|
|
});
|
|
const poppupRef = useRef<LMarker>(null);
|
|
const searchPopupElement = searchElements.find(
|
|
(element) => element.wayID === searchPopup?.elementId,
|
|
);
|
|
|
|
const SearchElement = ({
|
|
element,
|
|
isActive = false,
|
|
}: {
|
|
element: (typeof searchElements)[1];
|
|
isActive?: boolean;
|
|
}) => {
|
|
const ref = useRef<L.Polygon>(null);
|
|
|
|
useEffect(() => {
|
|
if (ref.current) {
|
|
ref.current.on("click", () => {
|
|
const center = ref.current?.getBounds().getCenter();
|
|
if (center && searchPopup?.elementId !== element.wayID) {
|
|
setSearchPopup({
|
|
lat: center.lat,
|
|
lng: center.lng,
|
|
elementId: element.wayID,
|
|
});
|
|
} else {
|
|
setSearchPopup(null);
|
|
}
|
|
setContextMenu(null);
|
|
});
|
|
}
|
|
}, [element.wayID]);
|
|
|
|
if (!element.nodes) return null;
|
|
return (
|
|
<Polygon
|
|
positions={element.nodes.map((node) => [node.lat, node.lon])}
|
|
color={searchPopup?.elementId === element.wayID || isActive ? "#ff4500" : "#46b7a3"}
|
|
eventHandlers={{
|
|
click: () => {
|
|
const addressOSMways = missionFormValues?.addressOSMways || [];
|
|
|
|
addressOSMways.push(JSON.parse(JSON.stringify(element)));
|
|
|
|
setMissionFormValues({
|
|
...missionFormValues,
|
|
addressOSMways,
|
|
});
|
|
},
|
|
}}
|
|
ref={ref}
|
|
/>
|
|
);
|
|
};
|
|
|
|
const SearchElementPopup = ({ element }: { element: (typeof searchElements)[1] }) => {
|
|
if (!searchPopup) return null;
|
|
return (
|
|
<Popup
|
|
autoPan={false}
|
|
position={[searchPopup.lat, searchPopup.lng]}
|
|
autoClose={false}
|
|
closeOnClick={false}
|
|
>
|
|
<div className="bg-base-100/70 border border-rescuetrack w-[250px] text-white pointer-events-auto p-2">
|
|
<h3 className="text-lg font-bold">
|
|
{element.tags?.building === "yes" ? "Gebäude" : element.tags?.building}
|
|
{!element.tags?.building && "unbekannt"}
|
|
</h3>
|
|
<p className="">
|
|
{element.tags?.["addr:street"]} {element.tags?.["addr:housenumber"]}
|
|
</p>
|
|
<p className="">
|
|
{element.tags?.["addr:suburb"]} {element.tags?.["addr:postcode"]}
|
|
</p>
|
|
<div className="flex flex-col gap-2 mt-2">
|
|
<button className="btn bg-rescuetrack-highlight">Zum Einsatz Hinzufügen</button>
|
|
</div>
|
|
</div>
|
|
</Popup>
|
|
);
|
|
};
|
|
|
|
return (
|
|
<>
|
|
{openMissionMarker.map(({ id }) => {
|
|
const mission = missions.data?.find((m) => m.id === id);
|
|
if (!mission) return null;
|
|
return (
|
|
<Fragment key={`mission-osm-${mission.id}`}>
|
|
{(mission.addressOSMways as (OSMWay | null)[])
|
|
.filter((element): element is OSMWay => element !== null)
|
|
.map((element: OSMWay, i) => (
|
|
<SearchElement
|
|
key={`mission-elem-${element.wayID}-${i}`}
|
|
element={element}
|
|
isActive
|
|
/>
|
|
))}
|
|
</Fragment>
|
|
);
|
|
})}
|
|
{searchElements.map((element, i) => {
|
|
if (
|
|
missions.data?.some(
|
|
(mission) =>
|
|
(mission.addressOSMways as (OSMWay | null)[])
|
|
.filter((e): e is OSMWay => e !== null)
|
|
.some((e) => e.wayID === element.wayID) &&
|
|
openMissionMarker.some((m) => m.id === mission.id),
|
|
)
|
|
)
|
|
return null;
|
|
return <SearchElement key={`mission-elem-${element.wayID}-${i}`} element={element} />;
|
|
})}
|
|
{searchPopup && (
|
|
<Marker
|
|
position={[searchPopup.lat, searchPopup.lng]}
|
|
ref={poppupRef}
|
|
icon={new L.DivIcon()}
|
|
opacity={0}
|
|
>
|
|
{!searchPopupElement && <div className="w-20 border border-rescuetrack"></div>}
|
|
</Marker>
|
|
)}
|
|
{searchPopupElement && <SearchElementPopup element={searchPopupElement} />}
|
|
</>
|
|
);
|
|
};
|