diff --git a/admin/inertia/components/maps/MarkerPanel.tsx b/admin/inertia/components/maps/MarkerPanel.tsx index 0a0856f7..c96683aa 100644 --- a/admin/inertia/components/maps/MarkerPanel.tsx +++ b/admin/inertia/components/maps/MarkerPanel.tsx @@ -1,5 +1,5 @@ import { resolveMarkerIcon } from './marker_icons' -import { useMemo, useState } from 'react' +import { useEffect, useMemo, useState } from 'react' import { IconEye, IconEyeOff, @@ -123,6 +123,9 @@ export default function MarkerPanel({ }: MarkerPanelProps) { const [open, setOpen] = useState(false) const [searchQuery, setSearchQuery] = useState('') + // The pin whose delete is armed. Deleting a place is not undoable and the + // names are short and similar, so the trash icon arms rather than deletes. + const [pendingDeleteId, setPendingDeleteId] = useState(null) const [sortField, setSortField] = useState('name') const [sortDirection, setSortDirection] = useState('asc') @@ -187,8 +190,27 @@ export default function MarkerPanel({ }) } + useEffect(() => { + if (pendingDeleteId === null) return + + const stillListed = markers.some((marker) => marker.id === pendingDeleteId) + if (!stillListed) setPendingDeleteId(null) + }, [markers, pendingDeleteId]) + + useEffect(() => { + if (pendingDeleteId === null) return + + const onKeyDown = (event: KeyboardEvent) => { + if (event.key === 'Escape') setPendingDeleteId(null) + } + + window.addEventListener('keydown', onKeyDown) + return () => window.removeEventListener('keydown', onKeyDown) + }, [pendingDeleteId]) + const renderMarkerRow = (marker: MapMarker) => { const MarkerIcon = resolveMarkerIcon(marker.icon) + const confirmingDelete = pendingDeleteId === marker.id return (
  • : } - + {confirmingDelete ? ( + + + + + + ) : ( + + )}
  • ) }