All files / components/search/select index.tsx

90% Statements 27/30
77.78% Branches 7/9
77.78% Functions 7/9
100% Lines 26/26

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90                    4x   4x 10x 10x   10x   10x       10x   10x 1x   60x 2x   2x 2x   2x 2x     10x 1x   1x 1x     10x 3x   3x     10x   10x   10x                                           60x                          
import { useRef, useState, MouseEvent, FocusEvent } from 'react';
 
import { events } from 'app';
import { useForceUpdate } from 'hooks';
 
import { debounce, filterArrayByQueryMatch } from 'utils';
 
import { Entities } from 'types';
import * as S from './styles';
 
const OPTIONS = Object.values(Entities) as unknown as Entities[];
 
const Select = () => {
  const inputRef = useRef<HTMLInputElement>(null);
  const dropdownRef = useRef<HTMLDivElement>(null);
 
  const forceUpdate = useForceUpdate();
 
  const [selectedOption, setSelectedOption] = useState<Entities>(
    Entities.CHARACTERS
  );
 
  const [isDropdownOpen, setIsDropdownOpen] = useState(false);
 
  const clearInputValue = () =>
    !!inputRef.current && (inputRef.current.value = '');
 
  const handleSelect = (option: Entities) => (e: MouseEvent) => {
    e.stopPropagation();
 
    setSelectedOption(option);
    setIsDropdownOpen(false);
 
    events.search.make({ entity: option });
    setTimeout(() => clearInputValue(), 200);
  };
 
  const handleBlur = (event: FocusEvent) => {
    Iif (dropdownRef.current?.contains(event.relatedTarget as Node)) return;
 
    setIsDropdownOpen(false);
    clearInputValue();
  };
 
  const handleOpenDropdown = () => {
    setIsDropdownOpen(true);
 
    setTimeout(() => inputRef.current?.focus(), 0);
  };
 
  const { value = '' } = inputRef.current || {};
 
  const filteredOptions = filterArrayByQueryMatch<Entities>(value, OPTIONS);
 
  return (
    <S.Container onClick={handleOpenDropdown}>
      <S.Input
        ref={inputRef}
        isSelected={!!selectedOption}
        placeholder={selectedOption}
        onInput={debounce(forceUpdate, 200)}
        onFocus={handleOpenDropdown}
        onBlur={handleBlur}
        aria-label="Open drop down select"
      />
 
      <S.ChevronRightIcon />
 
      <S.Dropdown
        ref={dropdownRef}
        open={isDropdownOpen}
        aria-hidden={!isDropdownOpen}
        aria-label="drop down select"
      >
        {!!filteredOptions.length ? (
          filteredOptions.map(option => (
            <S.Option key={option} type="button" onClick={handleSelect(option)}>
              {option}
            </S.Option>
          ))
        ) : (
          <S.Option>No result for &quot;{value}&quot;</S.Option>
        )}
      </S.Dropdown>
    </S.Container>
  );
};
 
export { Select };