Search code examples
reactjstypescriptinterfacemappingnavbar

How to add onclick with mapping in typescript react?


So i have this code

Dropdown.tsx

export interface IDropdownOptions {
  id: number
  title: string
  href: string
  typeIcon: IconType
  action?: (event: React.MouseEvent) => void
}

interface IDropdownProps {
  options: IDropdownOptions[]
  className?: string
}

const DropdownComponent: React.FC<IDropdownProps> = ({ className, options }) => {
  return (
    <div
      className={classNames(
        'dropdown dropdown-bottom dropdown-end border-[1px] w-[180px] h-[36px] gap-[8px] items-center flex rounded-[8px] border-[#D5D5D5] px-[12px] py-[9px] cursor-pointer',
        className
      )}
    >
      <div tabIndex={0} className='flex gap-[4px] items-center'>
        <div className='w-[16px] h-[16px] flex items-center justify-center'>
          <Icon className='w-[12px] h-[12px]' type='User' />
        </div>
        <div className='text-[12px] font-normal leading-[18px] w-[116px]'>Username</div>
      </div>
      <div className='w-[16px] h-[16px] flex items-center justify-center'>
        <Icon className='w-[8px] h-[4px]' type='Dropdown' />
      </div>
      <ul
        tabIndex={0}
        className='dropdown-content menu p-2 shadow bg-base-100 w-[180px] rounded-[8px]'
      >
        {options.map((option) => (
          <li
            key={option.id}
            className='my-1 items-center flex cursor-pointer justify-center'
            onClick={option.action}
          >
            <a href={option.href}>
              <div className='flex gap-[4px] items-center w-full'>
                <div className='w-[16px] h-[16px] flex items-center justify-center'>
                  <Icon className='w-[12px] h-[12px]' type={option.typeIcon} />
                </div>
                <div className='text-[12px] font-normal leading-[18px] w-[116px]'>
                  {option.title}
                </div>
              </div>
            </a>
          </li>
        ))}
      </ul>
    </div>
  )
}

Navbar.tsx

const optionsDropdown: IDropdownOptions[] = [
  {
    id: 1,
    title: 'Chat',
    href: '/',
    typeIcon: 'User',
  },
  {
    id: 2,
    title: 'Notifications',
    href: '/',
    typeIcon: 'User',
  },
  {
    id: 3,
    title: 'Settings',
    href: '/',
    typeIcon: 'User',
  },
  {
    id: 4,
    title: 'Logout',
    href: '/',
    typeIcon: 'User',
  },
]

const Navbar = () => {
  const dispatch = useDispatch()
  const navigate = useNavigate()
  const { auth } = useAuth()
  const [activePath, setActivePath] = useState<string>('/')
  const location = useLocation()

  useEffect(() => {
    setActivePath(location.pathname)
  }, [location.pathname])

  const handleLogout = () => {
    dispatch(logout())
    navigate('/login')
  }

  return (
    <>
      {auth && (
        <div className='border-b border-grey-outline'>
          <div className='navbar container mx-auto'>
            <div className='navbar-start'>
              <div className='dropdown'>
                <label tabIndex={0} className='btn btn-ghost lg:hidden'>
                  <svg
                    xmlns='http://www.w3.org/2000/svg'
                    className='h-5 w-5'
                    fill='none'
                    viewBox='0 0 24 24'
                    stroke='currentColor'
                  >
                    <path
                      strokeLinecap='round'
                      strokeLinejoin='round'
                      strokeWidth='2'
                      d='M4 6h16M4 12h8m-8 6h16'
                    />
                  </svg>
                </label>
                <ul
                  tabIndex={0}
                  className='menu menu-compact dropdown-content mt-3 p-2 shadow bg-base-100 rounded-box w-52'
                >
                  {navigationData.map((item) => (
                    <li key={item.name}>
                      <Link
                        to={item.href}
                        className={`text-white font-medium hover:bg-blue-surface active:bg-blue-surface active:text-blue ${
                          activePath === item.href ? 'bg-blue-surface text-blue' : ''
                        }`}
                      >
                        {item.name}
                      </Link>
                    </li>
                  ))}
                </ul>
              </div>
              <a className='normal-case text-[24px] text-blue mr-[34px]'>Industry.</a>
              <ul className='menu menu-horizontal px-1 hidden lg:flex gap-[32px]'>
                {navigationData.map((item) => (
                  <li key={item.name}>
                    <Link
                      to={item.href}
                      className={`text-white font-medium hover:bg-blue-surface active:bg-blue-surface active:text-blue ${
                        activePath === item.href ? 'bg-blue-surface text-blue' : ''
                      }`}
                    >
                      {item.name}
                    </Link>
                  </li>
                ))}
              </ul>
            </div>

            <div className='navbar-end'>
              <DropdownComponent options={optionsDropdown} />
            </div>
          </div>
        </div>
      )}
    </>
  )
}

The problem is I want to add a different functions when i clicked on different dropdown button but I don't know how to do it.

I already tried to add

actions: {handleLogout}

to the interface on the optionsDropdown but still it won't work. How do i implement handleLogout to the actions?


Solution

  • Define the functions directly in optionsDropdown declaration:

    const Navbar = () => {
      ...
      const optionsDropdown: IDropdownOptions[] = [
        {
          id: 1,
          title: 'Chat',
          href: '/',
          typeIcon: 'User',
          action: () => {
            console.log('do something');
          },
        },
        {
          id: 2,
          title: 'Notifications',
          href: '/',
          typeIcon: 'User',
          action: () => {
            console.log('do something');
          },
        },
        {
          id: 3,
          title: 'Settings',
          href: '/',
          typeIcon: 'User',
          action: () => {
            console.log('do something');
          },
        },
        {
          id: 4,
          title: 'Logout',
          href: '/',
          typeIcon: 'User',
          action: () => {
            dispatch(logout());
            navigate('/login');
          },
        },
      ];
    };
    

    Change IDropdownOptions interface to:

    export interface IDropdownOptions {
      id: number
      title: string
      href: string
      typeIcon: IconType
      action: () => void
    }
    

    And call the action with:

    <li
      key={option.id}
      className='my-1 items-center flex cursor-pointer justify-center'
      onClick={() => option.action()}
    >