Add "Add as waypoint" button to POI popups

Clicking the button in a POI popup adds the POI's location and name as
a new waypoint at the end of the route. Uses event delegation on the
map container to handle clicks on dynamically created popup buttons.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Ullrich Schäfer 2026-04-11 01:56:10 +02:00
parent 8c3fc36d23
commit 3af6aee32c
No known key found for this signature in database
GPG key ID: A32FF691A0F752D9
2 changed files with 24 additions and 3 deletions

View file

@ -361,11 +361,12 @@ export function PlannerMap({ yjs, onRouteRequest, highlightPosition, highlighted
}, [yjs.routeData]);
const addWaypoint = useCallback(
(lat: number, lng: number) => {
(lat: number, lng: number, name?: string) => {
yjs.doc.transact(() => {
const yMap = new Y.Map();
yMap.set("lat", lat);
yMap.set("lon", lng);
if (name) yMap.set("name", name);
yjs.waypoints.push([yMap]);
}, "local");
},
@ -512,7 +513,7 @@ export function PlannerMap({ yjs, onRouteRequest, highlightPosition, highlighted
<NoGoAreaLayer noGoAreas={yjs.noGoAreas} doc={yjs.doc} enabled={noGoDrawing} onToggle={toggleNoGoDraw} />
<NoGoAreaButton active={noGoDrawing} onClick={toggleNoGoDraw} />
<PoiRefresher poiState={poiState} />
<PoiMarkers poiState={poiState} />
<PoiMarkers poiState={poiState} onAddWaypoint={addWaypoint} />
<PoiPanel poiState={poiState} />
{waypoints.map((wp, i) => (

View file

@ -8,6 +8,7 @@ import { Z_POI_MARKER } from "~/lib/z-index";
interface PoiPanelProps {
poiState: PoiState;
onAddWaypoint?: (lat: number, lon: number, name?: string) => void;
}
export function PoiPanel({ poiState }: PoiPanelProps) {
@ -79,7 +80,7 @@ export function PoiPanel({ poiState }: PoiPanelProps) {
);
}
export function PoiMarkers({ poiState }: PoiPanelProps) {
export function PoiMarkers({ poiState, onAddWaypoint }: PoiPanelProps) {
const map = useMap();
const layerRef = useRef<L.LayerGroup>(L.layerGroup());
@ -88,6 +89,22 @@ export function PoiMarkers({ poiState }: PoiPanelProps) {
return () => { layerRef.current.remove(); };
}, [map]);
// Event delegation for "Add as waypoint" buttons in popups
useEffect(() => {
const container = map.getContainer();
const handler = (e: MouseEvent) => {
const btn = (e.target as HTMLElement).closest(".poi-add-wp") as HTMLElement | null;
if (!btn || !onAddWaypoint) return;
const lat = parseFloat(btn.dataset.lat!);
const lon = parseFloat(btn.dataset.lon!);
const name = btn.dataset.name || undefined;
onAddWaypoint(lat, lon, name);
map.closePopup();
};
container.addEventListener("click", handler);
return () => container.removeEventListener("click", handler);
}, [map, onAddWaypoint]);
useEffect(() => {
const group = layerRef.current;
group.clearLayers();
@ -126,6 +143,9 @@ export function PoiMarkers({ poiState }: PoiPanelProps) {
if (poi.tags.opening_hours) popupLines.push(`🕐 ${poi.tags.opening_hours}`);
if (poi.tags.website) popupLines.push(`<a href="${poi.tags.website}" target="_blank" rel="noopener">Website</a>`);
popupLines.push(`<a href="https://www.openstreetmap.org/node/${poi.id}" target="_blank" rel="noopener" style="font-size:11px;color:#666">OSM</a>`);
if (onAddWaypoint) {
popupLines.push(`<button class="poi-add-wp" data-lat="${poi.lat}" data-lon="${poi.lon}" data-name="${(poi.name ?? "").replace(/"/g, "&quot;")}" style="margin-top:4px;padding:2px 8px;font-size:11px;background:#2563eb;color:white;border:none;border-radius:4px;cursor:pointer">+ Add as waypoint</button>`);
}
marker.bindPopup(popupLines.join("<br>"), { maxWidth: 200 });
group.addLayer(marker);