From 9878efb2ca03d091bde7187c2c20748a7944b1de Mon Sep 17 00:00:00 2001 From: Christian Vidal Wolf Date: Mon, 20 Apr 2026 20:34:28 +0200 Subject: [PATCH] feat: enhance PricingView search bar with a searchable dropdown list --- src/components/PricingView.tsx | 93 +++++++++++++++++++++++++++------- 1 file changed, 74 insertions(+), 19 deletions(-) diff --git a/src/components/PricingView.tsx b/src/components/PricingView.tsx index 3473037..f1f6d01 100644 --- a/src/components/PricingView.tsx +++ b/src/components/PricingView.tsx @@ -63,6 +63,29 @@ export function PricingView({ data, headers, onSaveRow, onCaptureState, onEdit, const [outerHFilter, setOuterHFilter] = useState([]); const [dynamicColFilters, setDynamicColFilters] = useState>({}); + const [isSearchOpen, setIsSearchOpen] = useState(false); + const searchDropdownRef = useRef(null); + + // Close search dropdown on click outside + useEffect(() => { + const handleClickOutside = (event: MouseEvent) => { + if (searchDropdownRef.current && !searchDropdownRef.current.contains(event.target as Node)) { + setIsSearchOpen(false); + } + }; + document.addEventListener('mousedown', handleClickOutside); + return () => document.removeEventListener('mousedown', handleClickOutside); + }, []); + + const searchSuggestions = useMemo(() => { + if (!search) return data.slice(0, 50); // Show first 50 as default + const s = search.toLowerCase(); + return data.filter(r => + String(r[COLUMNS.ARTICLE_NO] || '').toLowerCase().includes(s) || + String(r[COLUMNS.ARTICLE_NAME] || '').toLowerCase().includes(s) + ).slice(0, 50); + }, [data, search]); + // ── Dynamic column detection ────────────────────────────────────────────── const { uvpIdx, srpCols, containerCols } = useMemo(() => { const uvpIdx = findCol(headers, 'uvp'); @@ -407,25 +430,57 @@ export function PricingView({ data, headers, onSaveRow, onCaptureState, onEdit, )}
- {/* ── Search bar ── */} -
- setSearch(e.target.value)} - className="w-full pl-4 pr-10 py-2 bg-slate-800 border border-slate-700 rounded-lg text-sm text-white focus:outline-none focus:border-blue-500 focus:ring-1 focus:ring-blue-500 transition-all" - /> - {search ? ( - - ) : ( -
- + {/* ── Search bar with Dropdown ── */} +
+
+ { + setSearch(e.target.value); + setIsSearchOpen(true); + }} + onFocus={() => setIsSearchOpen(true)} + className="w-full pl-4 pr-10 py-2 bg-slate-800 border border-slate-700 rounded-lg text-sm text-white focus:outline-none focus:border-blue-500 focus:ring-1 focus:ring-blue-500 transition-all" + /> + {search ? ( + + ) : ( +
+ +
+ )} +
+ + {/* Search Dropdown Panel */} + {isSearchOpen && searchSuggestions.length > 0 && ( +
+
+ {searchSuggestions.map((row, idx) => ( + + ))} +
+ {searchSuggestions.length === 50 && ( +
+ Showing first 50 results... +
+ )}
)}