'use client'; import { Combobox, ComboboxButton, ComboboxInput, ComboboxOption, ComboboxOptions } from '@headlessui/react'; import { ChevronDownIcon } from '@heroicons/react/16/solid'; import Spinner from 'components/spinner'; import { useDebounce } from 'hooks/use-debounce'; import get from 'lodash.get'; import { useCallback, useEffect, useRef, useState } from 'react'; import { useInView } from 'react-intersection-observer'; type FilterFieldProps = { options: T[]; selectedValue: T | null; // eslint-disable-next-line no-unused-vars onChange: (value: T | null) => void; label: string; displayKey?: string; // eslint-disable-next-line no-unused-vars getId: (option: T) => string; disabled?: boolean; autoFocus?: boolean; isLoading?: boolean; // eslint-disable-next-line no-unused-vars loadMore?: (reset?: boolean) => void; hasNextPage?: boolean; }; const FilterField = ({ options, selectedValue, onChange, label, displayKey = 'name', getId, disabled, isLoading, autoFocus = false, loadMore, hasNextPage }: FilterFieldProps) => { const [query, setQuery] = useState(''); const getDisplayValue = useCallback( (option: T | null) => { if (!option) return ''; if (typeof option[displayKey] === 'string') { return option[displayKey] as string; } return get(option, `${displayKey}.value`) as string; }, [displayKey] ); const [scrollTrigger, isInView] = useInView(); const filteredOptions = query === '' ? options : options.filter((option) => { return getDisplayValue(option).toLocaleLowerCase().includes(query.toLowerCase()); }); const loadMoreFnRef = useRef(); useEffect(() => { loadMoreFnRef.current = loadMore; }, [loadMore]); useEffect(() => { if (isInView && hasNextPage) { loadMoreFnRef.current?.(); } }, [isInView, hasNextPage]); const debouncedQuery = useDebounce(query); useEffect(() => { if (debouncedQuery && !filteredOptions.length) { loadMoreFnRef.current?.(true); } }, [debouncedQuery, filteredOptions.length]); return (
setQuery('')} immediate disabled={disabled || isLoading} >
setQuery(event.target.value)} className="w-full rounded border border-gray-200 py-1.5 pl-3 pr-8 text-sm ring-2 ring-transparent focus:outline-none focus-visible:outline-none data-[disabled]:cursor-not-allowed data-[autofocus]:border-0 data-[focus]:border-transparent data-[disabled]:opacity-50 data-[focus]:ring-2 data-[autofocus]:ring-secondary data-[focus]:ring-secondary data-[focus]:ring-offset-0" autoFocus={autoFocus} /> {isLoading ? ( ) : ( )}
{filteredOptions.map((option) => ( {getDisplayValue(option)} ))}
); }; export default FilterField;