Files
2025-12-15 18:09:38 +00:00

68 lines
2.1 KiB
TypeScript

"use client"
import Link from "next/link"
import { usePathname } from "next/navigation"
import { useRef } from "react"
import type { LucideIcon } from "lucide-react"
import type React from "react"
import { cn } from "@/lib/utils/styles"
interface NavItemProps {
href: string
icon: LucideIcon
children: React.ReactNode
onClick?: () => void
}
export const NavItem: React.FC<NavItemProps> = ({ href, icon: Icon, children, onClick }) => {
const pathname = usePathname()
// More precise active state detection:
// - Exact match: pathname === href
// - Sub-path match: pathname starts with href + '/' (but exclude /dashboard and /dashboard/admin from matching sub-paths)
const isExactMatch = pathname === href
const isSubPathMatch = pathname?.startsWith(href + '/')
// Exclude parent routes that should only match exactly
const shouldOnlyMatchExactly = href === '/dashboard' || href === '/dashboard/admin'
const isActive = isExactMatch || (isSubPathMatch && !shouldOnlyMatchExactly)
const isNavigatingRef = useRef(false)
const handleClick = (e: React.MouseEvent<HTMLAnchorElement>) => {
// Prevent rapid double-clicks
if (isNavigatingRef.current) {
e.preventDefault()
return
}
// Mark as navigating to prevent double-clicks
isNavigatingRef.current = true
// Always allow navigation - close mobile menu if needed
if (onClick) {
onClick()
}
// Reset flag after navigation completes
setTimeout(() => {
isNavigatingRef.current = false
}, 500)
}
return (
<Link
href={href}
onClick={handleClick}
className={cn(
"flex items-center px-3 py-2 text-sm rounded-md transition-colors",
"text-muted-foreground hover:text-foreground hover:bg-accent",
"active:scale-[0.98] transition-transform duration-75",
"touch-manipulation will-change-transform",
isActive && "bg-accent text-foreground font-medium"
)}
prefetch={true}
style={{ WebkitTapHighlightColor: 'transparent' }}
>
<Icon className="h-4 w-4 mr-3 flex-shrink-0" />
{children}
</Link>
)
}