tasko/app/(platform)/(dashboard)/_components/nav-item.tsx

118 lines
3.1 KiB
TypeScript
Raw Normal View History

2024-02-16 01:49:19 +00:00
'use client';
2024-02-15 02:30:10 +00:00
2024-02-16 01:49:19 +00:00
import Image from 'next/image';
import { Activity, CreditCard, Layout, Settings } from 'lucide-react';
import { usePathname, useRouter } from 'next/navigation';
2024-02-15 02:30:10 +00:00
import {
AccordionContent,
AccordionItem,
AccordionTrigger,
2024-02-16 01:49:19 +00:00
} from '@/components/ui/accordion';
import { cn } from '@/lib/utils';
import { Button } from '@/components/ui/button';
import { Skeleton } from '@/components/ui/skeleton';
2024-02-15 02:30:10 +00:00
export type Organization = {
id: string;
slug: string;
imageUrl: string;
name: string;
};
interface NavItemsProps {
isExpanded: boolean;
isActive: boolean;
organization: Organization;
onExpand: (id: string) => void;
}
export const NavItem = ({
isExpanded,
isActive,
organization,
onExpand,
}: NavItemsProps) => {
const router = useRouter();
const pathname = usePathname();
const routes = [
{
2024-02-16 01:49:19 +00:00
label: 'Boards',
icon: <Layout className='mr-2 h-4 w-4' />,
2024-02-15 02:30:10 +00:00
href: `/organization/${organization.id}`,
},
{
2024-02-16 01:49:19 +00:00
label: 'Activity',
icon: <Activity className='mr-2 h-4 w-4' />,
2024-02-15 02:30:10 +00:00
href: `/organization/${organization.id}/activity`,
},
{
2024-02-16 01:49:19 +00:00
label: 'Settings',
icon: <Settings className='mr-2 h-4 w-4' />,
2024-02-15 02:30:10 +00:00
href: `/organization/${organization.id}/settings`,
},
{
2024-02-16 01:49:19 +00:00
label: 'Billing',
icon: <CreditCard className='mr-2 h-4 w-4' />,
2024-02-15 02:30:10 +00:00
href: `/organization/${organization.id}/billing`,
},
];
const onClick = (href: string) => {
router.push(href);
};
return (
2024-02-16 01:49:19 +00:00
<AccordionItem value={organization.id} className='border-none'>
2024-02-15 02:30:10 +00:00
<AccordionTrigger
onClick={() => onExpand(organization.id)}
className={cn(
2024-02-16 01:49:19 +00:00
'flex items-center gap-x-2 rounded-md p-1.5 text-start text-neutral-700 no-underline transition hover:bg-neutral-500/10 hover:no-underline',
isActive && !isExpanded && 'bg-sky-500/10 text-sky-700'
2024-02-15 02:30:10 +00:00
)}
>
2024-02-16 01:49:19 +00:00
<div className='flex items-center gap-x-2'>
<div className='relative h-7 w-7'>
2024-02-15 02:30:10 +00:00
<Image
fill
src={organization.imageUrl}
alt={organization.name}
2024-02-16 01:49:19 +00:00
className='rounded-sm object-cover'
2024-02-15 02:30:10 +00:00
/>
</div>
2024-02-16 01:49:19 +00:00
<span className='text-sm font-medium'>{organization.name}</span>
2024-02-15 02:30:10 +00:00
</div>
</AccordionTrigger>
2024-02-16 01:49:19 +00:00
<AccordionContent className='pt-1 text-neutral-700'>
2024-02-15 02:30:10 +00:00
{routes.map((route) => (
<Button
key={route.href}
2024-02-16 01:49:19 +00:00
size='sm'
2024-02-15 02:30:10 +00:00
onClick={() => onClick(route.href)}
className={cn(
2024-02-16 01:49:19 +00:00
'mb-1 w-full justify-start pl-10 font-normal',
pathname === route.href && 'bg-sky-500/10 text-sky-700'
2024-02-15 02:30:10 +00:00
)}
2024-02-16 01:49:19 +00:00
variant='ghost'
2024-02-15 02:30:10 +00:00
>
{route.icon}
{route.label}
</Button>
))}
</AccordionContent>
</AccordionItem>
);
};
NavItem.Skeleton = function SkeletonNavItem() {
return (
2024-02-16 01:49:19 +00:00
<div className='flex items-center gap-x-2'>
<div className='relative h-10 w-10 shrink-0'>
<Skeleton className='absolute h-full w-full' />
2024-02-15 02:30:10 +00:00
</div>
2024-02-16 01:49:19 +00:00
<Skeleton className='h-4 w-full' />
2024-02-15 02:30:10 +00:00
</div>
);
};