Skip to content
Snippets Groups Projects
Select.component.tsx 2.54 KiB
Newer Older
import React from 'react';
import { twMerge } from 'tailwind-merge';
import { useSelect } from 'downshift';
import { Icon } from '@/shared/Icon';

type SelectProps = {
  options: Array<{ id: number | string; name: string }>;
  selectedId: number | string | null;
  onChange: (selectedId: number | string) => void;
  width?: string | number;
};

export const Select = ({
  options,
  selectedId,
  onChange,
  width = '100%',
}: SelectProps): React.JSX.Element => {
  const selectedOption = options.find(option => option.id === selectedId) || null;

  const {
    isOpen,
    highlightedIndex,
    getToggleButtonProps,
    getMenuProps,
    getItemProps,
    selectedItem,
  } = useSelect({
    items: options,
    selectedItem: selectedOption,
    onSelectedItemChange: ({ selectedItem: newSelectedItem }) => {
      if (newSelectedItem) {
        onChange(newSelectedItem.id);
      }
    },
    itemToString: item => (item ? item.name : ''),
  });

  const widthStyle = typeof width === 'number' ? { width: `${width}px` } : { width };

  return (
    <div
      className={twMerge(
        'relative rounded-t bg-white text-xs shadow-primary',
        !isOpen && 'rounded-b',
      )}
      style={widthStyle}
    >
      <div
        className={twMerge(
          'flex cursor-pointer flex-row items-center justify-between rounded-t p-2',
        )}
        {...getToggleButtonProps()}
      >
        <span data-testid="dropdown-button-name" className="font-medium">
          {selectedItem ? selectedItem.name : 'Select an option'}
        </span>
        <Icon
          name="chevron-down"
          className={twMerge('arrow-button h-6 w-6 fill-primary-500', isOpen && 'rotate-180')}
        />
      </div>
      <ul
        className={twMerge(
          'absolute z-20 overflow-auto rounded-b bg-white shadow-lg',
        )}
        style={widthStyle}
        {...getMenuProps()}
      >
        {isOpen &&
          options.map((item, index) => (
            <li
              className={twMerge(
                'border-t',
                highlightedIndex === index && 'text-primary-500',
                selectedItem?.id === item.id && 'font-bold',
                'flex flex-col p-2 shadow-sm',
              )}
              key={item.id}
              {...getItemProps({ item, index })}
            >
              <span>{item.name}</span>
            </li>
          ))}
      </ul>
    </div>
  );
};