34124/frontend/src/components/NavBarItem.tsx
2025-09-17 03:58:32 +00:00

150 lines
4.3 KiB
TypeScript

import React, { useEffect, useRef } from 'react';
import Link from 'next/link';
import { useState } from 'react';
import { mdiChevronUp, mdiChevronDown } from '@mdi/js';
import BaseDivider from './BaseDivider';
import BaseIcon from './BaseIcon';
import UserAvatarCurrentUser from './UserAvatarCurrentUser';
import NavBarMenuList from './NavBarMenuList';
import { useAppDispatch, useAppSelector } from '../stores/hooks';
import { MenuNavBarItem } from '../interfaces';
import { setDarkMode } from '../stores/styleSlice';
import { logoutUser } from '../stores/authSlice';
import { useRouter } from 'next/router';
import ClickOutside from './ClickOutside';
type Props = {
item: MenuNavBarItem;
};
export default function NavBarItem({ item }: Props) {
const router = useRouter();
const dispatch = useAppDispatch();
const excludedRef = useRef(null);
const navBarItemLabelActiveColorStyle = useAppSelector(
(state) => state.style.navBarItemLabelActiveColorStyle,
);
const navBarItemLabelStyle = useAppSelector(
(state) => state.style.navBarItemLabelStyle,
);
const navBarItemLabelHoverStyle = useAppSelector(
(state) => state.style.navBarItemLabelHoverStyle,
);
const currentUser = useAppSelector((state) => state.auth.currentUser);
const userName = `${currentUser?.firstName ? currentUser?.firstName : ''} ${
currentUser?.lastName ? currentUser?.lastName : ''
}`;
const [isDropdownActive, setIsDropdownActive] = useState(false);
useEffect(() => {
return () => setIsDropdownActive(false);
}, [router.pathname]);
const componentClass = [
'block lg:flex items-center relative cursor-pointer',
isDropdownActive
? `${navBarItemLabelActiveColorStyle} dark:text-slate-400`
: `${navBarItemLabelStyle} dark:text-white dark:hover:text-slate-400 ${navBarItemLabelHoverStyle}`,
item.menu ? 'lg:py-2 lg:px-3' : 'py-2 px-3',
item.isDesktopNoLabel ? 'lg:w-16 lg:justify-center' : '',
].join(' ');
const itemLabel = item.isCurrentUser ? userName : item.label;
const handleMenuClick = () => {
if (item.menu) {
setIsDropdownActive(!isDropdownActive);
}
if (item.isToggleLightDark) {
dispatch(setDarkMode(null));
}
if (item.isLogout) {
dispatch(logoutUser());
router.push('/login');
}
};
const getItemId = (label) => {
switch (label) {
case 'Light/Dark':
return 'themeToggle';
case 'Log out':
return 'logout';
default:
return undefined;
}
};
const NavBarItemComponentContents = (
<>
<div
id={getItemId(itemLabel)}
className={`flex items-center ${
item.menu
? 'bg-gray-100 dark:bg-dark-800 lg:bg-transparent lg:dark:bg-transparent p-3 lg:p-0'
: 'w-full'
}`}
onClick={handleMenuClick}
>
{item.icon && (
<BaseIcon path={item.icon} size={22} className='transition-colors' />
)}
<span
className={`px-2 transition-colors w-40 grow ${
item.isDesktopNoLabel && item.icon ? 'lg:hidden' : ''
}`}
>
{itemLabel}
</span>
{item.isCurrentUser && (
<UserAvatarCurrentUser className='w-6 h-6 mr-3 inline-flex' />
)}
{item.menu && (
<BaseIcon
path={isDropdownActive ? mdiChevronUp : mdiChevronDown}
className='hidden lg:inline-flex transition-colors'
/>
)}
</div>
{item.menu && (
<div
className={`${
!isDropdownActive ? 'lg:hidden' : ''
} text-sm border-b border-gray-100 lg:border lg:bg-midnightBlueTheme-cardColor lg:absolute lg:top-full lg:left-0 lg:min-w-full lg:z-20 lg:rounded-lg lg:shadow-lg lg:dark:bg-dark-900 dark:border-dark-700`}
>
<ClickOutside
onClickOutside={() => setIsDropdownActive(false)}
excludedElements={[excludedRef]}
>
<NavBarMenuList menu={item.menu} />
</ClickOutside>
</div>
)}
</>
);
if (item.isDivider) {
return <BaseDivider navBar />;
}
if (item.href) {
return (
<Link href={item.href} target={item.target} className={componentClass}>
{NavBarItemComponentContents}
</Link>
);
}
return (
<div className={componentClass} ref={excludedRef}>
{NavBarItemComponentContents}
</div>
);
}