All files / src/components/Filter FilterSelect.tsx

51.72% Statements 15/29
10% Branches 2/20
44.44% Functions 4/9
52% Lines 13/25

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            4x               4x             4x   4x 4x 4x   4x   4x 4x   4x                       4x             4x                     8x                    
import React, { FC, useMemo, useRef } from 'react';
import { SvgIcon } from '../SvgIcon';
import { scrollLock, scrollUnlock } from '../../helpers/scrollLock';
import { useTranslation } from 'react-i18next';
import { FilterOptionType } from './index';
 
const styles = require('./Filter.module.css');
 
export const FilterSelect: FC<{
  label?: string;
  options: FilterOptionType[];
  selected?: number | null;
  onClick?: () => void;
  onChange?: (value: number | null) => void
}> = ({
  label,
  options,
  selected,
  onClick,
  onChange
}) => {
  const { t } = useTranslation();
 
  const buttonRef = useRef<HTMLButtonElement>(null);
  const optionsRef = useRef<HTMLUListElement>(null);
  const selectRef = useRef<HTMLDivElement>(null);
 
  const current = useMemo(() => options.find(o => o.id === selected), [selected])
 
  const select = (value: FilterOptionType) => onChange && onChange(value.id);
  const reset = () => onChange && onChange(null);
 
  const show = () => {
    if (buttonRef.current && optionsRef.current && selectRef.current) {
      scrollLock();
      const clientRect = buttonRef.current.getBoundingClientRect();
      optionsRef.current.style.top = clientRect.top + 'px';
      optionsRef.current.style.left = clientRect.left + 'px';
      optionsRef.current.style.minWidth = clientRect.width + 'px';
      selectRef.current.classList.add(styles.open);
      onClick && onClick();
    }
  };
 
  const hide = () => {
    if (buttonRef.current && optionsRef.current && selectRef.current) {
      scrollUnlock();
      selectRef.current.classList.remove(styles.open);
    }
  };
 
  return (
    <div className={styles.FilterSelect} ref={selectRef}>
      <button type="button" className={styles.FilterControl} onClick={show} ref={buttonRef}>
        <span>{current ? current.name : label}</span>
        <SvgIcon icon={{ name: 'sort', width: 12, height: 12, fill: '#144154' }} />
      </button>
 
      <div className={styles.FilterOverlay} onClick={hide}>
        <ul className={styles.FilterOptions} ref={optionsRef}>
          <li className={styles.FilterOption} onClick={reset}>{t('reset')}</li>
          {options.map((option, index) =>
            <li
              key={index}
              className={`${styles.FilterOption} ${option.id === selected ? styles.selected: ''}`}
              onClick={() => select(option)}
            >{option.name}</li>
          )}
        </ul>
      </div>
    </div>
  );
};