Files
zero-fucks-given/apps/admin/src/app/layouts/04__TwoColumnSidebar/components/SidebarMenuDashboard.tsx
T

162 lines
4.9 KiB
TypeScript
Executable File

import { Badge, ChevronDown, FileText, Settings, SquareCode, UserCircle } from 'lucide-react';
import { useCallback, useMemo } from 'react';
import { Link, useLocation } from 'react-router-dom';
import { AccordionMenu, AccordionMenuClassNames, AccordionMenuGroup, AccordionMenuItem, AccordionMenuLabel } from '#shared/ui/AccordionMenu';
import { Button } from '#shared/ui/Button';
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from '#shared/ui/DropdownMenu';
interface DropdownItem {
title: string;
path: string;
icon: React.ComponentType<{ className?: string }>;
active?: boolean;
}
interface MenuItem {
title: string;
path?: string;
active?: boolean;
}
interface MenuLabel {
label: string;
}
type MenuNode = MenuItem | MenuLabel;
export function SidebarMenuDashboard() {
const { pathname } = useLocation();
const dropdownItems: DropdownItem[] = [
{
title: 'Client API',
path: '/account/home/user-profile',
icon: SquareCode,
active: true
},
{
title: 'Profile',
path: '/public-profile/profiles/company',
icon: UserCircle
},
{
title: 'My Account',
path: '/account/integrations',
icon: Settings
},
{
title: 'Projects',
path: '/public-profile/projects/3-columns',
icon: FileText
},
{
title: 'Personal info',
path: '/public-profile/profiles/creator',
icon: Badge
}
];
const currentDropdownItem = dropdownItems[0];
const menuItems = useMemo<MenuNode[]>(
() => [
{ label: 'Configuration' },
{ title: 'API Setup', path: '/account/api-keys' },
{ title: 'Team Settings', path: '/account/home/settings-sidebar' },
{ title: 'Authentication', path: '/authentication/classic/sign-in' },
{ title: 'Endpoints Configs', path: '/account/appearance' },
{ title: 'Rate Limiting', path: '/public-profile/network' },
{ label: 'Security' },
{ title: 'Data Encryption', path: '/account/billing/enterprise' },
{ title: 'Text', path: '/account/security/overview' },
{ title: 'Access Control', path: '/account/security/privacy-settings' },
{ label: 'Analytics' },
{
title: 'Incident Response',
path: '/account/security/current-sessions'
},
{ title: 'Fetching Data', path: '/account/members/team-info' },
{ title: 'Custom Reports', path: '/account/home/user-profile' },
{
title: 'Real Time Analytics',
path: '/account/home/settings-enterprise'
},
{ title: 'Exporting Data', path: '/account/members/import-members' },
{ title: 'Dashboard Integration', path: '/account/members/team-info' }
],
[]
);
const classNames: AccordionMenuClassNames = {
root: 'space-y-1',
label: 'uppercase text-xs font-medium text-muted-foreground/80 pt-6 mb-2 pb-0',
item: 'h-8 hover:bg-background border-accent text-accent-foreground hover:text-primary data-[selected=true]:text-primary data-[selected=true]:bg-background data-[selected=true]:font-medium'
};
const matchPath = useCallback(
(path: string): boolean => path === pathname || (path.length > 1 && pathname.startsWith(path)),
[pathname]
);
const buildDropdown = () => {
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="outline" mode="input" className="w-full justify-between">
<span className="flex items-center gap-2">
<currentDropdownItem.icon />
{currentDropdownItem.title}
</span>
<ChevronDown className="size-3.5" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent className="w-(--radix-dropdown-menu-trigger-width)">
{dropdownItems.map((item, index) => (
<DropdownMenuItem key={index} asChild>
<Link to={item.path}>
<item.icon />
<span>{item.title}</span>
</Link>
</DropdownMenuItem>
))}
</DropdownMenuContent>
</DropdownMenu>
);
};
const buildMenu = () => {
return (
<AccordionMenu
selectedValue={'/account/home/settings-sidebar'}
matchPath={matchPath}
type="single"
collapsible
classNames={classNames}
>
<AccordionMenuGroup>
{menuItems.map((item, index) =>
'label' in item ? (
<AccordionMenuLabel key={index}>{item.label}</AccordionMenuLabel>
) : (
<AccordionMenuItem
key={index}
value={item.path || `item-${index}`}
className="text-sm"
>
<Link to={item.path || '#'}>{item.title}</Link>
</AccordionMenuItem>
)
)}
</AccordionMenuGroup>
</AccordionMenu>
);
};
return (
<div className="w-full space-y-1">
{buildDropdown()}
{buildMenu()}
</div>
);
}