diff --git a/src/search/components/pillar-items-dropdown-content.tsx b/src/search/components/pillar-items-dropdown-content.tsx index c6b13c3..2c562c9 100644 --- a/src/search/components/pillar-items-dropdown-content.tsx +++ b/src/search/components/pillar-items-dropdown-content.tsx @@ -6,7 +6,7 @@ import { useInView } from 'react-intersection-observer'; import { useAsyncList } from 'react-stately'; import { Input } from '@nextui-org/input'; -import { Listbox, ListboxItem } from '@nextui-org/listbox'; +import { Listbox, ListboxItem, ListboxSection } from '@nextui-org/listbox'; import { ScrollShadow } from '@nextui-org/scroll-shadow'; import { Spinner } from '@nextui-org/spinner'; import { useQueryClient } from '@tanstack/react-query'; @@ -76,8 +76,6 @@ export const PillarItemsDropdownContent = (props: Props) => { const pageOffset = !debouncedQuery ? 1 : 0; const page = Math.floor(cursor / ITEMS_PER_PAGE) + pageOffset; - console.log({ cursor, pageOffset, page }); - const queryProps: GetPillarItemsProps = { nav, pillar: pillarSlug, @@ -101,19 +99,53 @@ export const PillarItemsDropdownContent = (props: Props) => { }, }); - const pillarItemsSet = useMemo( - () => new Set(pillarItems.map(({ label }) => normalizeString(label))), - [pillarItems], + const activeItemsSet = useMemo( + () => new Set(activeItems.map(({ label }) => normalizeString(label))), + [activeItems], + ); + + const activePillarItems = useMemo( + () => + pillarItems + .filter((pillarItem) => + activeItemsSet.has(normalizeString(pillarItem.label)), + ) + .map((pillarItem) => pillarItem.label), + [activeItemsSet, pillarItems], + ); + + const activeDropdownItems = useMemo( + () => { + const activeDedupedItems = list.items.filter( + (label) => + activeItemsSet.has(normalizeString(label)) && + !activePillarItems.includes(label), + ); + + if (!debouncedQuery) return [...activePillarItems, ...activeDedupedItems]; + + const filteredItems = [ + ...activePillarItems, + ...activeDedupedItems, + ].filter((item) => + item.toLowerCase().includes(debouncedQuery.toLowerCase()), + ); + + return filteredItems; + }, + // eslint-disable-next-line react-hooks/exhaustive-deps + [list.items.length, debouncedQuery, hiddenItems.length], ); const dropdownItems = useMemo( () => { - const hiddenItemsCopy = [...hiddenItems]; - hiddenItemsCopy.reverse(); + const hiddenItemsCopy = [...hiddenItems] + .reverse() + .filter((label) => !activeDropdownItems.includes(label)); const dedupedItems = list.items.filter( (label) => - !pillarItemsSet.has(normalizeString(label)) && + !activeDropdownItems.includes(label) && !hiddenItemsCopy.includes(label), ); @@ -132,17 +164,12 @@ export const PillarItemsDropdownContent = (props: Props) => { useEffect(() => { list.reload(); // eslint-disable-next-line react-hooks/exhaustive-deps - }, [hiddenItems.length]); - - const itemSlugsSet = useMemo( - () => new Set(activeItems.map(({ label }) => normalizeString(label))), - [activeItems], - ); + }, [activeItems.length, hiddenItems.length]); const onAction = (key: React.Key) => { if (key) { const itemSlug = normalizeString(key as string); - const isActive = itemSlugsSet.has(itemSlug); + const isActive = activeItemsSet.has(itemSlug); const newSearchParams = createToggledPillarItemSearchParam({ itemSlug, pillarParamKey, @@ -200,39 +227,42 @@ export const PillarItemsDropdownContent = (props: Props) => { > - {dropdownItems.length > 0 ? ( - dropdownItems.map((label, i) => { - const isActive = itemSlugsSet.has(normalizeString(label)); - - return ( - + {activeDropdownItems.map((label, i) => ( + : } + > + {label} + + ))} + + + + {dropdownItems.map((label, i) => ( + +
: null} - textValue={label} + ref={i === dropdownItems.length - 1 ? inViewRef : undefined} > -
- {label} -
- - ); - }) - ) : ( - - {list.isLoading ? 'Loading items ...' : 'No results found'} - - )} + {label} +
+
+ ))} +
@@ -256,3 +286,21 @@ const CheckmarkIcon = () => ( /> ); + +const LockIcon = () => ( + +);