import { noop } from 'lodash-es' import { Check, ChevronsUpDown } from 'lucide-react' import { useEffect, useRef, useState } from 'react' import { Button_Shadcn_ as Button, cn, Command_Shadcn_ as Command, CommandGroup_Shadcn_ as CommandGroup, CommandInput_Shadcn_ as CommandInput, CommandItem_Shadcn_ as CommandItem, CommandList_Shadcn_ as CommandList, Popover_Shadcn_ as Popover, PopoverContent_Shadcn_ as PopoverContent, PopoverTrigger_Shadcn_ as PopoverTrigger, ScrollArea, } from 'ui' import ShimmeringLoader from 'ui-patterns/ShimmeringLoader' import { useIntersectionObserver } from '~/hooks/useIntersectionObserver' export interface ComboBoxOption { id: string value: string displayName: string } export function ComboBox({ isLoading, disabled, name, options, selectedOption, selectedDisplayName, onSelectOption = noop, className, search = '', hasNextPage = false, isFetching = false, isFetchingNextPage = false, fetchNextPage, setSearch = () => {}, useCommandSearch = true, }: { isLoading: boolean disabled?: boolean name: string options: Opt[] selectedOption?: string selectedDisplayName?: string onSelectOption?: (newValue: string) => void className?: string search?: string hasNextPage?: boolean isFetching?: boolean isFetchingNextPage?: boolean fetchNextPage?: () => void setSearch?: (value: string) => void useCommandSearch?: boolean }) { const [open, setOpen] = useState(false) const scrollRootRef = useRef(null) const [sentinelRef, entry] = useIntersectionObserver({ root: scrollRootRef.current, threshold: 0, rootMargin: '0px', }) useEffect(() => { if (!isLoading && !isFetching && !isFetchingNextPage && hasNextPage && entry?.isIntersecting) { fetchNextPage?.() } }, [isLoading, isFetching, isFetchingNextPage, hasNextPage, entry?.isIntersecting, fetchNextPage]) return ( { setOpen(value) if (!value) setSearch('') }} > setSearch('')} /> {isLoading ? (
) : ( <> {search.length > 0 && options.length === 0 && (

No {name}s found based on your search

)} 7 ? 'h-[210px]' : ''}> {options.map((option) => ( { setOpen(false) onSelectOption(selectedValue) }} className="cursor-pointer" > {option.displayName} ))}
{hasNextPage && } )} ) }