142 lines
6.1 KiB
TypeScript
142 lines
6.1 KiB
TypeScript
'use client'
|
||
import { HambergerMenu, ArrowLeft2 } from 'iconsax-react'
|
||
import { FC, useState, useRef, useEffect } from 'react'
|
||
import Image from 'next/image'
|
||
import { useRouter } from 'next/navigation'
|
||
import { useGetCategories } from '../hooks/useShareData'
|
||
import { Category } from '../types/SharedTypes'
|
||
|
||
const Menu: FC = () => {
|
||
const [isOpen, setIsOpen] = useState(false)
|
||
const [hoveredPath, setHoveredPath] = useState<Category[]>([])
|
||
const [menuPosition, setMenuPosition] = useState({ top: 0, right: 0 })
|
||
const { data, isLoading } = useGetCategories()
|
||
const menuRef = useRef<HTMLDivElement>(null)
|
||
const router = useRouter()
|
||
|
||
useEffect(() => {
|
||
const handleClickOutside = (event: MouseEvent) => {
|
||
if (menuRef.current && !menuRef.current.contains(event.target as Node)) {
|
||
setIsOpen(false)
|
||
setHoveredPath([])
|
||
}
|
||
}
|
||
|
||
document.addEventListener('mousedown', handleClickOutside)
|
||
return () => document.removeEventListener('mousedown', handleClickOutside)
|
||
}, [])
|
||
|
||
useEffect(() => {
|
||
if (isOpen && menuRef.current) {
|
||
const rect = menuRef.current.getBoundingClientRect()
|
||
setMenuPosition({
|
||
top: rect.bottom + window.scrollY + 8,
|
||
right: window.innerWidth - rect.right - window.scrollX
|
||
})
|
||
}
|
||
}, [isOpen])
|
||
|
||
const parentCategories = data?.results?.data?.filter(cat => !cat.parent) || []
|
||
|
||
const handleCategoryHover = (category: Category, level: number) => {
|
||
const newPath = [...hoveredPath.slice(0, level), category]
|
||
setHoveredPath(newPath)
|
||
}
|
||
|
||
const handleCategoryClick = (category: Category) => {
|
||
router.push(`/products/${category.title_en}`)
|
||
setIsOpen(false)
|
||
setHoveredPath([])
|
||
}
|
||
|
||
const renderCategoryLevel = (categories: Category[], level: number) => {
|
||
return (
|
||
<div className='w-48 md:w-64 border-l border-gray-200 last:border-l-0 flex flex-col min-h-0'>
|
||
<div className='p-2 overflow-y-auto max-h-[calc(100vh-200px)]'>
|
||
{categories.map((category) => (
|
||
<div
|
||
key={category._id}
|
||
className={`p-3 rounded-lg cursor-pointer transition-colors hover:bg-gray-50 ${hoveredPath[level]?._id === category._id ? 'bg-gray-50' : ''
|
||
}`}
|
||
onMouseEnter={() => handleCategoryHover(category, level)}
|
||
onClick={() => handleCategoryClick(category)}
|
||
>
|
||
<div className='flex items-center gap-3'>
|
||
{category.icon && (
|
||
<Image
|
||
src={category.icon}
|
||
alt={category.title_fa}
|
||
width={20}
|
||
height={20}
|
||
className='w-5 h-5 object-contain'
|
||
/>
|
||
)}
|
||
<span className='text-sm text-gray-800 flex-1'>{category.title_fa}</span>
|
||
{category.children?.length > 0 && (
|
||
<ArrowLeft2 size={16} color='#666' />
|
||
)}
|
||
</div>
|
||
</div>
|
||
))}
|
||
</div>
|
||
</div>
|
||
)
|
||
}
|
||
|
||
return (
|
||
<div className='relative' ref={menuRef}>
|
||
<div
|
||
className='flex items-center gap-2.5 cursor-pointer'
|
||
onClick={() => setIsOpen(!isOpen)}
|
||
onMouseEnter={() => setIsOpen(true)}
|
||
>
|
||
<HambergerMenu size={24} color='#333333' />
|
||
<div className='text-[#333333] hidden md:block'>دسته بندی کالاها</div>
|
||
<div className='text-[#333333] md:hidden text-xs'>دستهها</div>
|
||
</div>
|
||
|
||
{isOpen && (
|
||
<div
|
||
className='fixed bg-white rounded-xl shadow-lg border border-gray-200 z-[9999] flex max-w-[90vw] md:max-w-none max-h-[80vh] overflow-hidden'
|
||
style={{
|
||
top: `${menuPosition.top}px`,
|
||
right: `${menuPosition.right}px`
|
||
}}
|
||
onMouseLeave={() => {
|
||
setIsOpen(false)
|
||
setHoveredPath([])
|
||
}}
|
||
>
|
||
{/* دستههای اصلی (سطح اول) */}
|
||
{isLoading ? (
|
||
<div className='w-48 md:w-64 border-l border-gray-200 flex items-center justify-center h-40'>
|
||
<div className='text-gray-500'>در حال بارگذاری...</div>
|
||
</div>
|
||
) : parentCategories.length > 0 ? (
|
||
<>
|
||
{renderCategoryLevel(parentCategories, 0)}
|
||
|
||
{/* سطوح بعدی (recursive) */}
|
||
{hoveredPath.map((category, index) => {
|
||
if (category.children && category.children.length > 0) {
|
||
return (
|
||
<div key={`level-${index + 1}-${category._id}`}>
|
||
{renderCategoryLevel(category.children, index + 1)}
|
||
</div>
|
||
)
|
||
}
|
||
return null
|
||
})}
|
||
</>
|
||
) : (
|
||
<div className='w-48 md:w-64 border-l border-gray-200 flex items-center justify-center h-40'>
|
||
<div className='text-gray-500'>دستهبندیای یافت نشد</div>
|
||
</div>
|
||
)}
|
||
</div>
|
||
)}
|
||
</div>
|
||
)
|
||
}
|
||
|
||
export default Menu |