mirror of
https://gitlab.com/mbugroup/lti-web-client.git
synced 2026-05-20 13:32:00 +00:00
feat(FE-40): create MainDrawer component
This commit is contained in:
@@ -0,0 +1,205 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { useState } from 'react';
|
||||||
|
import { usePathname } from 'next/navigation';
|
||||||
|
|
||||||
|
import Image from 'next/image';
|
||||||
|
import { Icon } from '@iconify/react';
|
||||||
|
import Drawer from '@/components/Drawer';
|
||||||
|
import Menu from '@/components/menu/Menu';
|
||||||
|
import MenuItem from '@/components/menu/MenuItem';
|
||||||
|
import Navbar from '@/components/Navbar';
|
||||||
|
import Collapse from '@/components/Collapse';
|
||||||
|
|
||||||
|
import { useUiStore } from '@/stores/ui/ui.store';
|
||||||
|
import { MAIN_DRAWER_LINKS } from '@/config/constant';
|
||||||
|
import { cn } from '@/lib/helper';
|
||||||
|
|
||||||
|
type CollapseMenuProps = {
|
||||||
|
title: string;
|
||||||
|
link: string;
|
||||||
|
icon: string;
|
||||||
|
submenu?: CollapseMenuProps[];
|
||||||
|
depth?: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
const isPathActive = (pathname: string, link?: string) => {
|
||||||
|
if (!link) return false;
|
||||||
|
|
||||||
|
const splittedPathname = pathname.split('/');
|
||||||
|
const splittedLink = link.split('/');
|
||||||
|
|
||||||
|
return splittedPathname.every((pathnameChunk, idx) => {
|
||||||
|
return pathnameChunk === splittedLink[idx];
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const isCollapseActive = (pathname: string, link?: string) => {
|
||||||
|
if (!link) return false;
|
||||||
|
|
||||||
|
return pathname === link || pathname.startsWith(link);
|
||||||
|
};
|
||||||
|
|
||||||
|
const CollapseMenu = ({
|
||||||
|
title,
|
||||||
|
link,
|
||||||
|
icon,
|
||||||
|
submenu,
|
||||||
|
depth = 0,
|
||||||
|
}: CollapseMenuProps) => {
|
||||||
|
const pathname = usePathname();
|
||||||
|
const [open, setOpen] = useState(isCollapseActive(pathname, link));
|
||||||
|
|
||||||
|
const menuCollapseTitle = (
|
||||||
|
<div
|
||||||
|
className={cn(
|
||||||
|
'w-full px-3 py-2 rounded-md text-base font-semibold transition-colors flex flex-row justify-between items-center gap-2 hover:bg-primary/10',
|
||||||
|
{
|
||||||
|
'bg-primary/10': open,
|
||||||
|
}
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<div className='flex flex-row items-center gap-2'>
|
||||||
|
<Icon icon={icon} width={20} height={20} />
|
||||||
|
<span>{title}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Icon
|
||||||
|
icon='cuida:caret-up-outline'
|
||||||
|
width={20}
|
||||||
|
height={20}
|
||||||
|
className={cn('transition-transform', {
|
||||||
|
'rotate-90': !open,
|
||||||
|
'rotate-180': open,
|
||||||
|
})}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
const paddingLeftDepth = `pl-${4 * (depth + 1)}`;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Collapse
|
||||||
|
open={open}
|
||||||
|
title={menuCollapseTitle}
|
||||||
|
onOpenChange={setOpen}
|
||||||
|
titleClassName='p-0!'
|
||||||
|
>
|
||||||
|
<Menu className={cn('py-0.5', paddingLeftDepth)}>
|
||||||
|
{submenu?.map((item, idx) => {
|
||||||
|
const hasSubmenu = item.submenu && item.submenu.length > 0;
|
||||||
|
|
||||||
|
if (!hasSubmenu) {
|
||||||
|
return (
|
||||||
|
<MenuItem
|
||||||
|
key={idx}
|
||||||
|
title={item.title}
|
||||||
|
href={item.link}
|
||||||
|
icon={item.icon}
|
||||||
|
active={isPathActive(pathname, item.link)}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<CollapseMenu
|
||||||
|
key={idx}
|
||||||
|
title={item.title}
|
||||||
|
link={item.link}
|
||||||
|
icon={item.icon}
|
||||||
|
submenu={item.submenu}
|
||||||
|
depth={depth + 1}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</Menu>
|
||||||
|
</Collapse>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const MainDrawerMenu = () => {
|
||||||
|
const pathname = usePathname();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Menu>
|
||||||
|
{MAIN_DRAWER_LINKS.map((item, idx) => {
|
||||||
|
const hasSubmenu = item.submenu && item.submenu.length > 0;
|
||||||
|
|
||||||
|
if (!hasSubmenu) {
|
||||||
|
return (
|
||||||
|
<MenuItem
|
||||||
|
key={idx}
|
||||||
|
title={item.title}
|
||||||
|
href={item.link}
|
||||||
|
icon={item.icon}
|
||||||
|
active={pathname.startsWith(item.link)}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<CollapseMenu
|
||||||
|
key={idx}
|
||||||
|
title={item.title}
|
||||||
|
link={item.link}
|
||||||
|
icon={item.icon}
|
||||||
|
submenu={item.submenu}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</Menu>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const MainDrawerContent = () => {
|
||||||
|
return (
|
||||||
|
<div className='w-full p-4 flex flex-col gap-4'>
|
||||||
|
<div className='flex items-center gap-4'>
|
||||||
|
<Image
|
||||||
|
src='/assets/img/lti-logo.png'
|
||||||
|
alt='MBU Logo'
|
||||||
|
width={256}
|
||||||
|
height={256}
|
||||||
|
className='w-full max-w-16 h-auto'
|
||||||
|
/>
|
||||||
|
|
||||||
|
<h1 className='text-xl font-bold'>LTI ERP</h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<MainDrawerMenu />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
const MainDrawer = ({
|
||||||
|
children,
|
||||||
|
}: Readonly<{
|
||||||
|
children: React.ReactNode;
|
||||||
|
}>) => {
|
||||||
|
const { mainDrawerOpen, setMainDrawerOpen } = useUiStore();
|
||||||
|
const pathname = usePathname();
|
||||||
|
|
||||||
|
const pageTitle = MAIN_DRAWER_LINKS.find((item) =>
|
||||||
|
pathname.startsWith(item.link)
|
||||||
|
)?.title;
|
||||||
|
|
||||||
|
const toggleSidebar = () => {
|
||||||
|
setMainDrawerOpen(!mainDrawerOpen);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Drawer
|
||||||
|
open={mainDrawerOpen}
|
||||||
|
setOpen={setMainDrawerOpen}
|
||||||
|
openOnLarge
|
||||||
|
sidebarContent={<MainDrawerContent />}
|
||||||
|
>
|
||||||
|
<main className='w-full h-full flex flex-col gap-4'>
|
||||||
|
<Navbar title={pageTitle as string} toggleSidebar={toggleSidebar} />
|
||||||
|
|
||||||
|
{children}
|
||||||
|
</main>
|
||||||
|
</Drawer>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default MainDrawer;
|
||||||
Reference in New Issue
Block a user