components/DropDown/CustomDropDown.tsx

src/ui/components/widgets/SpeedLimitSection/components/DropDown/CustomDropDown.tsx
mail@pastecode.io avatar
unknown
typescript
a month ago
5.7 kB
1
Indexable
Never
import { useSearchParams } from '@Hooks'
import React, { useCallback, useEffect, useRef, useState } from 'react'
import { useLocation } from 'react-router-dom'

interface MultiselectDropdownProps {
  options: { value: string; label: string }[]
  placeholder?: string
  txtSelected?: string
  txtAll?: string
  txtRemove?: string
  txtSearch?: string
  search?: boolean
  height?: string
  onChange?: (selected: string[]) => void
}

const CustomDropDown: React.FC<MultiselectDropdownProps> = ({
  options,
  placeholder = 'select',
  txtSelected = 'selected',
  txtAll = 'All',
  txtRemove = 'Remove',
  txtSearch = 'search',
  search = true,
  height = '15rem',
  onChange
}) => {
  const searchParams = useSearchParams()
  const location = useLocation()
  const [selectedOptions, setSelectedOptions] = useState<string[]>([])
  const [dropdownOpen, setDropdownOpen] = useState(false)
  const [searchText, setSearchText] = useState('')
  const dropdownRef = useRef<HTMLDivElement>(null)

  const toggleOption = useCallback(
    (value: string) => {
      setSelectedOptions(prevSelected => {
        const newSelected = prevSelected.includes(value)
          ? prevSelected.filter(opt => opt !== value)
          : [...prevSelected, value]
        if (onChange) {
          onChange(newSelected)
        }
        return newSelected
      })
    },
    [onChange]
  )

  const handleOutsideClick = useCallback((event: MouseEvent) => {
    if (
      dropdownRef.current &&
      !dropdownRef.current.contains(event.target as Node)
    ) {
      setDropdownOpen(false)
    }
  }, [])

  useEffect(() => {
    const selectedOptions = searchParams.getSearchParam('type')?.split(',')
    console.log('🚀 ~ useEffect ~ selectedOptions:', selectedOptions)
    if (selectedOptions) {
      setTimeout(() => {
        setSelectedOptions(selectedOptions)
      }, 200)
    }
  }, [])

  useEffect(() => {
    document.addEventListener('click', handleOutsideClick)
    return () => {
      document.removeEventListener('click', handleOutsideClick)
    }
  }, [handleOutsideClick])

  const filteredOptions = options.filter(option =>
    option.label.toLowerCase().includes(searchText.toLowerCase())
  )

  return (
    <div className="inline-block relative w-full h-[35px]" ref={dropdownRef}>
      <div
        className="p-[6px] border border-gray-300 rounded cursor-pointer bg-white h-full"
        onClick={() => setDropdownOpen(!dropdownOpen)}
      >
        {selectedOptions.length === 0 ? (
          <span className="text-gray-400 block text-center">{placeholder}</span>
        ) : selectedOptions.length > 3 ? (
          <span>
            {selectedOptions.length} {txtSelected}
          </span>
        ) : (
          selectedOptions.map(value => (
            <span
              key={value}
              className="inline-block bg-gray-200 font-medium rounded text-[12px] px-1 py-[2px] mr-1 "
            >
              {options.find(option => option.value === value)?.label}
              <span
                className="ml-1 cursor-pointer text-gray-600 hover:text-gray-800"
                onClick={e => {
                  e.stopPropagation()
                  toggleOption(value)
                }}
              >
                🗙
              </span>
            </span>
          ))
        )}
      </div>
      {dropdownOpen && (
        <div className="absolute  border border-gray-300 rounded-xl bg-white z-10 shadow-lg w-full overflow-hidden">
          {search && (
            <div className="p-2">
              <input
                type="text"
                className="w-full border border-gray-300 rounded p-1"
                placeholder={txtSearch}
                value={searchText}
                onChange={e => {
                  setSearchText(e.target.value)
                }}
              />
            </div>
          )}
          <div className="overflow-y-auto">
            {options.length > 0 && (
              <div
                className="p-2 cursor-pointer hover:bg-gray-200"
                onClick={() => {
                  const allSelected = selectedOptions.length === options.length
                  const newSelected = allSelected
                    ? []
                    : options.map(opt => opt.value)
                  setSelectedOptions(newSelected)
                  if (onChange) {
                    onChange(newSelected)
                  }
                }}
              >
                <input
                  type="checkbox"
                  className="mr-2"
                  checked={selectedOptions.length === options.length}
                  onChange={e => {}}
                />
                {txtAll}
              </div>
            )}
            {filteredOptions.map(option => (
              <div
                key={option.value}
                className={`p-2 cursor-pointer hover:bg-gray-200 ${
                  selectedOptions.includes(option.value) ? 'bg-gray-100' : ''
                }`}
                onClick={() => toggleOption(option.value)}
              >
                <input
                  type="checkbox"
                  className="mr-2"
                  checked={selectedOptions.includes(option.value)}
                  onChange={e => {
                    toggleOption(option.value)
                  }}
                  onClick={e => e.stopPropagation()}
                />
                {option.label}
              </div>
            ))}
          </div>
        </div>
      )}
    </div>
  )
}

export default CustomDropDown
Leave a Comment