Skip to content
Snippets Groups Projects

Resolve "[MIN-56] Autocomplete input"

Merged Piotr Gawron requested to merge 24-min-56-autocomplete-input into development
14 files
+ 111
7
Compare changes
  • Side-by-side
  • Inline
Files
14
import {
autocompleteChemicalSelector,
autocompleteDrugSelector,
autocompleteSearchSelector,
} from '@/redux/autocomplete/autocomplete.selectors';
import {
currentSelectedSearchElement,
searchDrawerOpenSelector,
@@ -14,23 +19,33 @@ import {
import { getSearchData } from '@/redux/search/search.thunks';
import Image from 'next/image';
import { useRouter } from 'next/router';
import { ChangeEvent, KeyboardEvent, useCallback, useEffect, useState } from 'react';
import { useCallback, KeyboardEvent, useEffect, useState } from 'react';
import { useSelector } from 'react-redux';
import { ONE, ZERO } from '@/constants/common';
import { FIVE, ONE, ZERO } from '@/constants/common';
import Autosuggest from 'react-autosuggest';
import { clearEntityNumberData } from '@/redux/entityNumber/entityNumber.slice';
import { getDefaultSearchTab, getSearchValuesArrayAndTrimToSeven } from './SearchBar.utils';
import './autocomplete.css';
type Suggestion = {
name: string;
};
const ENTER_KEY_CODE = 'Enter';
export const SearchBar = (): JSX.Element => {
const [searchValue, setSearchValue] = useState<string>('');
const [filteredSuggestions, setFilteredSuggestions] = useState<Suggestion[]>([]);
const isPendingSearchStatus = useSelector(isPendingSearchStatusSelector);
const isSearchDrawerOpen = useSelector(searchDrawerOpenSelector);
const isPerfectMatch = useSelector(perfectMatchSelector);
const searchValueState = useSelector(searchValueSelector);
const currentTab = useSelector(currentSelectedSearchElement);
const searchAutocompleteState = useSelector(autocompleteSearchSelector);
const drugAutocompleteState = useSelector(autocompleteDrugSelector);
const chemicalAutocompleteState = useSelector(autocompleteChemicalSelector);
const dispatch = useAppDispatch();
const router = useRouter();
const currentTab = useSelector(currentSelectedSearchElement);
const updateSearchValueFromQueryParam = useCallback((): void => {
const { searchValue: searchValueQueryParam } = router.query;
@@ -53,10 +68,6 @@ export const SearchBar = (): JSX.Element => {
}
};
const onSearchChange = (event: ChangeEvent<HTMLInputElement>): void => {
setSearchValue(event.target.value);
};
const onSearchClick = (): void => {
const searchValues = getSearchValuesArrayAndTrimToSeven(searchValue);
@@ -82,6 +93,60 @@ export const SearchBar = (): JSX.Element => {
openSearchDrawerIfClosed(currentTab);
};
const suggestions = searchAutocompleteState.searchValues
.concat(drugAutocompleteState.searchValues, chemicalAutocompleteState.searchValues)
.map(entry => {
return { name: entry };
})
.sort((a: Suggestion, b: Suggestion) => a.name.localeCompare(b.name));
const getSuggestions = (value: string): Suggestion[] => {
const inputValue = value.trim().toLowerCase();
const inputLength = inputValue.length;
if (inputLength === ZERO) {
return [];
}
return suggestions
.filter(lang => lang.name.toLowerCase().slice(ZERO, inputLength) === inputValue)
.slice(ZERO, FIVE);
};
const renderSuggestion = (suggestion: Suggestion): JSX.Element => {
return <div>{suggestion.name}</div>;
};
// Autosuggest will call this function every time you need to update suggestions.
// You already implemented this logic above, so just use it.
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
const onSuggestionsFetchRequested = ({ value }): void => {
setFilteredSuggestions(getSuggestions(value));
};
// Autosuggest will call this function every time you need to clear suggestions.
const onSuggestionsClearRequested = (): void => {
setFilteredSuggestions([]);
};
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
const onChange = (event, { newValue }): void => {
setSearchValue(newValue);
};
// Autosuggest will pass through all these props to the input.
const inputProps = {
placeholder: '',
value: searchValue,
name: 'search-input',
onChange,
onKeyDown: handleKeyPress,
onClick: handleSearchClick,
'data-testid': 'search-input',
disabled: isPendingSearchStatus,
};
const getSuggestionValue = (suggestion: Suggestion): string => suggestion.name;
useEffect(() => {
updateSearchValueFromQueryParam();
}, [updateSearchValueFromQueryParam]);
@@ -89,19 +154,34 @@ export const SearchBar = (): JSX.Element => {
clearSearchValueFromClearedState();
}, [clearSearchValueFromClearedState]);
const theme = {
input:
'h-9 w-72 rounded-[64px] border border-transparent bg-cultured px-4 py-2.5 text-xs font-medium text-font-400 outline-none hover:border-greyscale-600 focus:border-greyscale-600',
container: 'react-autosuggest__container',
inputFocused: 'react-autosuggest__input--focused',
suggestionsContainer: 'react-autosuggest__suggestions-container',
suggestionsContainerOpen: 'react-autosuggest__suggestions-container--open',
suggestionsList: 'react-autosuggest__suggestions-list',
suggestion: 'react-autosuggest__suggestion',
suggestionFirst: 'react-autosuggest__suggestion--first',
suggestionHighlighted: 'bg-primary-100',
sectionContainer: 'react-autosuggest__section-container',
sectionContainerFirst: 'react-autosuggest__section-container--first',
sectionTitle: 'react-autosuggest__section-title',
};
return (
<div className="relative" data-testid="search-bar">
<input
value={searchValue}
name="search-input"
aria-label="search-input"
data-testid="search-input"
onKeyDown={handleKeyPress}
onChange={onSearchChange}
disabled={isPendingSearchStatus}
onClick={handleSearchClick}
className="h-9 w-72 rounded-[64px] border border-transparent bg-cultured px-4 py-2.5 text-xs font-medium text-font-400 outline-none hover:border-greyscale-600 focus:border-greyscale-600"
<div className="relative mt-5" data-testid="search-bar">
<Autosuggest
suggestions={filteredSuggestions}
onSuggestionsFetchRequested={onSuggestionsFetchRequested}
onSuggestionsClearRequested={onSuggestionsClearRequested}
getSuggestionValue={getSuggestionValue}
renderSuggestion={renderSuggestion}
inputProps={inputProps}
theme={theme}
/>
<button
disabled={isPendingSearchStatus}
type="button"
Loading