diff --git a/admin/inertia/components/maps/MarkerPanel.tsx b/admin/inertia/components/maps/MarkerPanel.tsx index 1bf448e..cafe63b 100644 --- a/admin/inertia/components/maps/MarkerPanel.tsx +++ b/admin/inertia/components/maps/MarkerPanel.tsx @@ -1,5 +1,6 @@ -import { useState } from 'react' +import { useMemo, useState } from 'react' import { IconMapPinFilled, IconTrash, IconMapPin, IconX } from '@tabler/icons-react' + import { PIN_COLORS } from '~/hooks/useMapMarkers' import type { MapMarker } from '~/hooks/useMapMarkers' @@ -11,26 +12,62 @@ interface MarkerPanelProps { selectedMarkerId: number | null } +const getColorSortValue = (color: string) => { + const preset = PIN_COLORS.find((pinColor) => pinColor.id === color) + + if (preset) return preset.label + + return color.replace('#', '').toLowerCase() +} + +type SortField = 'name' | 'color' +type SortDirection = 'asc' | 'desc' + export default function MarkerPanel({ - markers, - onDelete, - onFlyTo, - onSelect, - selectedMarkerId, -}: MarkerPanelProps) { + markers, + onDelete, + onFlyTo, + onSelect, + selectedMarkerId, + }: MarkerPanelProps) { const [open, setOpen] = useState(false) + const [searchQuery, setSearchQuery] = useState('') + const [sortField, setSortField] = useState('name') + const [sortDirection, setSortDirection] = useState('asc') + + const visibleMarkers = useMemo(() => { + const query = searchQuery.trim().toLowerCase() + + return [...markers] + .filter((marker) => { + if (!query) return true + return marker.name.toLowerCase().includes(query) + }) + .sort((a, b) => { + const aValue = sortField === 'name' ? a.name : getColorSortValue(a.color) + const bValue = sortField === 'name' ? b.name : getColorSortValue(b.color) + + const result = aValue.localeCompare(bValue, undefined, { + sensitivity: 'base', + }) + + return sortDirection === 'asc' ? result : -result + }) + }, [markers, searchQuery, sortField, sortDirection]) if (!open) { return ( - {/* Marker list */} -
+
+ setSearchQuery(e.target.value)} + className="block w-full rounded border border-border-default bg-surface-primary px-2 py-1 text-sm text-text-primary placeholder:text-text-muted focus:border-desert-green focus:outline-none" + /> + +
+ + + +
+
+ +
{markers.length === 0 ? (
-

- Click anywhere on the map to drop a pin -

+

Click anywhere on the map to drop a pin

+
+ ) : visibleMarkers.length === 0 ? ( +
+

No pins match your search.

) : (
    - {markers.map((marker) => ( + {visibleMarkers.map((marker) => (
  • c.id === marker.color)?.hex ?? '#a84a12' }} + style={{ + color: PIN_COLORS.find((color) => color.id === marker.color)?.hex ?? '#a84a12', + }} /> + +