dstpabuaran.com/resources/js/components/layout/app-header.tsx
Yoga Pangestu 7d21a1e6db feat: add cart context and functionality, update welcome page with new components and styles
- Implemented CartContext for managing cart state, including adding, removing, and updating items.
- Added CartDrawer component to display cart items.
- Updated AppHeader to include cart item count.
- Enhanced welcome page with new layout, improved product image handling, and updated call-to-action buttons.
- Refactored homepage data types to accommodate new features and removed unused properties.
2026-08-13 17:19:56 +07:00

180 lines
8.3 KiB
TypeScript

import { AppLogo, AppLogoIcon } from '@/components/brand';
import { Breadcrumbs } from '@/components/layout';
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar';
import { Button } from '@/components/ui/button';
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuTrigger,
} from '@/components/ui/dropdown-menu';
import {
NavigationMenu,
NavigationMenuItem,
NavigationMenuList,
navigationMenuTriggerStyle,
} from '@/components/ui/navigation-menu';
import {
Sheet,
SheetContent,
SheetHeader,
SheetTitle,
SheetTrigger,
} from '@/components/ui/sheet';
import { UserMenuContent } from '@/components/user';
import { useCurrentUrl } from '@/hooks/use-current-url';
import { useInitials } from '@/hooks/use-initials';
import { cn } from '@/lib/utils';
import { dashboard } from '@/routes';
import type { BreadcrumbItem, NavItem } from '@/types';
import { Link, usePage } from '@inertiajs/react';
import { LayoutGrid, Menu } from 'lucide-react';
type Props = {
breadcrumbs?: BreadcrumbItem[];
};
const mainNavItems: NavItem[] = [
{
title: 'Dashboard',
href: dashboard(),
icon: LayoutGrid,
},
];
const activeItemStyles =
'text-neutral-900 dark:bg-neutral-800 dark:text-neutral-100';
export function AppHeader({ breadcrumbs = [] }: Props) {
const page = usePage();
const { auth } = page.props;
const getInitials = useInitials();
const { isCurrentUrl, whenCurrentUrl } = useCurrentUrl();
return (
<div className="sticky top-0 z-50 bg-background">
<div className="border-b border-sidebar-border/80">
<div className="mx-auto flex h-16 items-center px-4 md:max-w-7xl">
{/* Mobile Menu */}
<div className="lg:hidden">
<Sheet>
<SheetTrigger asChild>
<Button
variant="ghost"
size="icon"
className="mr-2 h-[34px] w-[34px]"
>
<Menu className="h-5 w-5" />
</Button>
</SheetTrigger>
<SheetContent
side="left"
className="flex h-full w-64 flex-col items-stretch justify-between bg-sidebar"
>
<SheetTitle className="sr-only">
Navigation menu
</SheetTitle>
<SheetHeader className="flex justify-start text-left">
<AppLogoIcon className="h-6 w-6 fill-current text-black dark:text-white" />
</SheetHeader>
<div className="flex h-full flex-1 flex-col space-y-4 p-4">
<div className="flex h-full flex-col justify-between text-sm">
<div className="flex flex-col space-y-4">
{mainNavItems.map((item) => (
<Link
key={item.title}
href={item.href}
className="flex items-center space-x-2 font-medium"
>
{item.icon && (
<item.icon className="h-5 w-5" />
)}
<span>{item.title}</span>
</Link>
))}
</div>
</div>
</div>
</SheetContent>
</Sheet>
</div>
<Link
href={dashboard()}
prefetch
className="flex items-center space-x-2"
>
<AppLogo />
</Link>
{/* Desktop Navigation */}
<div className="ml-6 hidden h-full items-center space-x-6 lg:flex">
<NavigationMenu className="flex h-full items-stretch">
<NavigationMenuList className="flex h-full items-stretch space-x-2">
{mainNavItems.map((item, index) => (
<NavigationMenuItem
key={index}
className="relative flex h-full items-center"
>
<Link
href={item.href}
className={cn(
navigationMenuTriggerStyle(),
whenCurrentUrl(
item.href,
activeItemStyles,
),
'h-9 cursor-pointer px-3',
)}
>
{item.icon && (
<item.icon className="mr-2 h-4 w-4" />
)}
{item.title}
</Link>
{isCurrentUrl(item.href) && (
<div className="absolute bottom-0 left-0 h-0.5 w-full translate-y-px bg-black dark:bg-white"></div>
)}
</NavigationMenuItem>
))}
</NavigationMenuList>
</NavigationMenu>
</div>
<div className="ml-auto flex items-center space-x-2">
<DropdownMenu>k
<DropdownMenuTrigger asChild>
<Button
variant="ghost"
className="size-10 rounded-full p-1"
>
<Avatar className="size-8 overflow-hidden rounded-full">
<AvatarImage
src={auth.user?.avatar}
alt={auth.user?.name}
/>
<AvatarFallback className="rounded-lg bg-neutral-200 text-black dark:bg-neutral-700 dark:text-white">
{getInitials(auth.user?.name ?? '')}
</AvatarFallback>
</Avatar>
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent className="w-56" align="end">
{auth.user && (
<UserMenuContent user={auth.user} />
)}
</DropdownMenuContent>
</DropdownMenu>
</div>
</div>
</div>
{breadcrumbs.length > 1 && (
<div className="flex w-full border-b border-sidebar-border/70">
<div className="mx-auto flex h-12 w-full items-center justify-start px-4 text-neutral-500 md:max-w-7xl">
<Breadcrumbs breadcrumbs={breadcrumbs} />
</div>
</div>
)}
</div>
);
}