Files
var-monorepo/apps/dispatch/app/(dispatch)/_components/map/ContextMenu.tsx
2025-04-08 17:53:06 -07:00

102 lines
2.7 KiB
TypeScript

import { useMapStore } from "_store/mapStore";
import { MapPinned, Search } from "lucide-react";
import { useEffect } from "react";
import { Popup, useMap } from "react-leaflet";
export const ContextMenu = () => {
const map = useMap();
const { popup, setSearchElements, setPopup, setSearchPopup } = useMapStore();
useEffect(() => {
map.on("contextmenu", (e) => {
setPopup({ isOpen: true, lat: e.latlng.lat, lng: e.latlng.lng });
setSearchPopup(undefined);
});
}, [popup]);
if (!popup) return null;
return (
<Popup position={[popup.lat, popup.lng]}>
{/* // TODO: maske: */}
<div className="absolute transform -translate-y-1/2 z-1000 opacity-100 pointer-events-auto p-3">
<button
className="btn btn-sm rounded-full bg-amber-600 hover:bg-amber-700 aspect-square"
onClick={async () => {
const address = await fetch(
`https://nominatim.openstreetmap.org/reverse?lat=${popup.lat}&lon=${popup.lng}&format=json`,
);
const data = (await address.json()) as {
address: {
ISO3166_2_lvl4: string;
country: string;
country_code: string;
county: string;
hamlet: string;
municipality: string;
postcode: string;
road: string;
state: string;
town: string;
};
display_name: string;
importance: number;
lat: string;
licence: string;
lon: string;
name: string;
osm_id: number;
osm_type: string;
place_id: number;
place_rank: number;
type: string;
};
}}
>
<MapPinned size={20} />
</button>
<button
className="btn btn-sm rounded-full bg-amber-600 hover:bg-amber-700 aspect-square"
onClick={async () => {
const res = await fetch(
`https://overpass-api.de/api/interpreter?data=${encodeURIComponent(`
[out:json];
(
way["building"](around:100, ${popup.lat}, ${popup.lng});
relation["building"](around:100, ${popup.lat}, ${popup.lng});
);
out body;
>;
out skel qt;
`)}`,
);
const data = await res.json();
setSearchElements(
data.elements
.filter((e: any) => e.type === "way")
.map((e: any) => {
return {
id: e.id,
nodes: e.nodes.map((nodeId: string) => {
const node = data.elements.find(
(element: any) => element.id === nodeId,
);
return {
lat: node.lat,
lon: node.lon,
};
}),
tags: e.tags,
type: e.type,
};
}),
);
}}
>
<Search size={20} />
</button>
</div>
</Popup>
);
};