"use client" import Link from '../LocalizedLink' import Image from 'next/image' import { useState, useRef, useEffect } from 'react' import { ArrowRight, ChevronRight, Star, Sparkles, Box, } from 'lucide-react' import type { MegaMenuPayload, MenuColumn } from './menuTypes' import { getLocalizedMenuText } from './menuTypes' import { ICON_REGISTRY, type AvailableIcons } from './iconRegistry' function DynamicIcon({ iconName, defaultIcon: DefaultIcon, className, strokeWidth }: { iconName?: string, defaultIcon: any, className?: string, strokeWidth?: number }) { const IconComponent = (iconName && ICON_REGISTRY[iconName as AvailableIcons]) ? ICON_REGISTRY[iconName as AvailableIcons] : DefaultIcon; return ; } interface DesktopMegaMenuProps { items: MegaMenuPayload[] lang: string currentPath: string } const MAX_TOP_LEVEL_LINKS = 5 const MAX_INLINE_CHILD_LINKS = 3 const getMoreLabel = (count: number, lang: string) => { if (lang === 'th') return `+ อีก ${count} รายการ` if (lang === 'ja') return `+ 他${count}件` if (lang === 'zh') return `+ 还有 ${count} 项` if (lang === 'vi') return `+ ${count} mục khác` if (lang === 'ko') return `+ ${count}개 더` return `+ ${count} more` } // Render a 1:1 image using next/image for optimization (website uses CDN images) function MenuImage({ src, alt, placeholder, className = '', style, }: { src?: string | null alt: string placeholder?: string className?: string style?: React.CSSProperties }) { const [loaded, setLoaded] = useState(false) if (!src) { if (!placeholder) return null return ( {placeholder} ) } return ( {alt} setLoaded(true)} loading="lazy" /> ) } export function DesktopMegaMenu({ items, lang, currentPath }: DesktopMegaMenuProps) { const [openId, setOpenId] = useState(null) const [hoveredLinkImage, setHoveredLinkImage] = useState(null) const [activeTabByMenu, setActiveTabByMenu] = useState>({}) const closeTimer = useRef | null>(null) // Automatically close mega menu when route changes useEffect(() => { if (closeTimer.current) clearTimeout(closeTimer.current) setOpenId(null) setHoveredLinkImage(null) }, [currentPath]) const handleOpen = (id: string) => { if (closeTimer.current) clearTimeout(closeTimer.current) if (openId !== id) setHoveredLinkImage(null) setOpenId(id) } const handleClose = () => { closeTimer.current = setTimeout(() => { setOpenId(null) setHoveredLinkImage(null) }, 150) } const handleLinkClick = () => { if (closeTimer.current) clearTimeout(closeTimer.current) setOpenId(null) setHoveredLinkImage(null) } const getFirstImageLink = (columns: MenuColumn[] = []) => { for (const column of columns) { const found = column.links.find((link) => link.imageUrl) if (found) return found } return columns[0]?.links[0] } return (
{items.map((item, index) => { const uniqueId = item.nodeId || item.id || `menu-${item.url || index}` const isOpen = openId === uniqueId const hasColumns = !!item.columns?.length const isActive = item.url ? currentPath === item.url : false const layout = item.layout || 'columns' const isClassic = layout === 'classic' const isTabbed = layout === 'tabbed' const isVisualCards = layout === 'visual-cards' const configuredCols = item.layoutConfig?.columnCount || (item.columns?.length ? Math.min(Math.max(item.columns.length, 2), 4) : 2) const visibleColumns = item.columns?.slice(0, configuredCols) ?? [] const featuredLink = getFirstImageLink(item.columns) const featuredConfig = item.featured const showFeatured = (item.layoutConfig?.showFeatured !== false) && (featuredConfig?.enabled !== false) && !isClassic && !isVisualCards && !isTabbed && ( !!(featuredConfig?.imageUrl || featuredConfig?.title || featuredConfig?.sectionTitle || featuredLink?.imageUrl) ) const configuredImage = featuredConfig?.imageUrl || null const featuredImage = hoveredLinkImage ?? configuredImage ?? featuredLink?.imageUrl ?? item.rootImageUrl const focalPoint = featuredConfig?.focalPoint const objectPosition = focalPoint ? `${focalPoint.x} ${focalPoint.y}` : 'center' const featuredHeading = getLocalizedMenuText(featuredConfig?.sectionTitle, lang) || 'Featured' const featuredBadge = getLocalizedMenuText(featuredConfig?.badge, lang) || 'Recommended' const featuredTitle = getLocalizedMenuText(featuredConfig?.title, lang) || getLocalizedMenuText(featuredLink?.label, lang) || getLocalizedMenuText(item.label, lang) const featuredSubtitle = getLocalizedMenuText(featuredConfig?.subtitle, lang) || (item.columns?.[0] ? getLocalizedMenuText(item.columns[0].title, lang) : getLocalizedMenuText(item.label, lang)) const featuredHref = featuredConfig?.url || featuredLink?.url || item.url || '#' const featuredCta = getLocalizedMenuText(featuredConfig?.ctaLabel, lang) || 'View details' const getMegaContainerClass = (cols: number, hasFeatured: boolean) => { if (hasFeatured) { if (cols >= 4) return 'w-[min(100vw-2rem,1260px)]' if (cols === 3) return 'w-[min(100vw-2rem,1120px)]' return 'w-[min(100vw-2rem,980px)]' } if (cols >= 4) return 'w-[min(100vw-2rem,1180px)]' if (cols === 3) return 'w-[min(100vw-2rem,960px)]' return 'w-[min(100vw-2rem,720px)]' } const getMegaGridColsClass = (cols: number, hasFeatured: boolean) => { if (hasFeatured) { if (cols >= 4) return 'grid-cols-[1fr_1fr_1fr_1fr_260px]' if (cols === 3) return 'grid-cols-[1fr_1fr_1fr_270px]' return 'grid-cols-[1fr_1fr_270px]' } if (cols >= 4) return 'grid-cols-4' if (cols === 3) return 'grid-cols-3' return 'grid-cols-2' } return (
handleOpen(uniqueId)} onMouseLeave={handleClose} > {getLocalizedMenuText(item.label, lang)} {hasColumns && ( )} {hasColumns && isClassic && (
handleOpen(uniqueId)} onMouseLeave={handleClose} >
{item.columns?.map((column, columnIndex) => (
0 ? 'mt-2 border-t border-line-primary/10 pt-2' : ''}> {getLocalizedMenuText(column.title, lang) && item.columns && item.columns.length > 1 && (
{getLocalizedMenuText(column.title, lang)}
)}
    {column.links.map((link, linkIndex) => (
  • {link.icon && ( )} {getLocalizedMenuText(link.label, lang)} {link.links?.length ? ( ) : null} {link.links && link.links.length > 0 && (
      {link.links.map((child, childIdx) => (
    • {getLocalizedMenuText(child.label, lang)}
    • ))}
    )}
  • ))}
))}
)} {hasColumns && isTabbed && (
handleOpen(uniqueId)} onMouseLeave={handleClose} >
{/* Left Category Tabs Sidebar */}
{lang === 'th' ? 'หมวดหมู่หลัก' : 'Categories'}
{item.columns?.map((column, colIdx) => { const activeIdx = activeTabByMenu[uniqueId] ?? 0 const isSelected = activeIdx === colIdx return ( ) })}
{/* Right Content Panel for Selected Tab */} {(() => { const activeIdx = activeTabByMenu[uniqueId] ?? 0 const activeCol = item.columns?.[activeIdx] || item.columns?.[0] if (!activeCol) return null return (

{getLocalizedMenuText(activeCol.title, lang)}

{lang === 'th' ? 'ดูรายการทั้งหมด' : 'View all'}
{activeCol.links.map((link, lIdx) => (
setHoveredLinkImage(link.imageUrl || null)} onMouseLeave={() => setHoveredLinkImage(null)} > {getLocalizedMenuText(link.label, lang)} {link.links && link.links.length > 0 && (
{link.links.slice(0, 3).map((child, cIdx) => ( {getLocalizedMenuText(child.label, lang)} ))}
)}
))}
{item.columns?.length || 0} {lang === 'th' ? 'หมวดหมู่ย่อย' : 'categories'} {getLocalizedMenuText(item.label, lang)}
) })()}
)} {hasColumns && isVisualCards && (
handleOpen(uniqueId)} onMouseLeave={handleClose} >

{getLocalizedMenuText(item.label, lang)}

{lang === 'th' ? 'ดูทั้งหมด' : 'Explore all'}
{item.columns?.slice(0, 4).map((column, colIdx) => { const cardImg = column.iconUrl || column.links?.[0]?.imageUrl || configuredImage || item.rootImageUrl const cardHref = column.links?.[0]?.url || item.url || '#' const cardTitle = getLocalizedMenuText(column.title, lang) const firstSubLink = column.links?.[0] const subText = firstSubLink ? getLocalizedMenuText(firstSubLink.label, lang) : null return (
{cardTitle} {subText && ( {subText} )}
) })}
)} {hasColumns && !isClassic && !isTabbed && !isVisualCards && (
handleOpen(uniqueId)} onMouseLeave={handleClose} >
{visibleColumns.map((column, columnIndex) => (
0 ? 'border-l border-line-primary/15 pl-8' : ''}`} >

{getLocalizedMenuText(column.title, lang)}

    {column.links.slice(0, MAX_TOP_LEVEL_LINKS).map((link, linkIndex) => { const hasNestedLinks = !!link.links?.length const visibleChildLinks = link.links?.slice(0, MAX_INLINE_CHILD_LINKS) ?? [] const hiddenChildCount = Math.max((link.links?.length ?? 0) - MAX_INLINE_CHILD_LINKS, 0) const moreChildHref = link.url || link.links?.[MAX_INLINE_CHILD_LINKS]?.url || link.links?.[0]?.url || '#' return (
  • setHoveredLinkImage(link.imageUrl || null)} onMouseLeave={() => setHoveredLinkImage(null)} > {getLocalizedMenuText(link.label, lang)} {getLocalizedMenuText(column.title, lang)} {hasNestedLinks && (
      {visibleChildLinks.map((childLink, childIndex) => (
    • setHoveredLinkImage(childLink.imageUrl || link.imageUrl || null)} > {getLocalizedMenuText(childLink.label, lang)}
    • ))} {hiddenChildCount > 0 && (
    • {getMoreLabel(hiddenChildCount, lang)}
    • )}
    )}
  • ) })}
{getLocalizedMenuText(item.label, lang)}
))} {showFeatured && (

{featuredHeading}

setHoveredLinkImage(configuredImage ?? featuredLink?.imageUrl ?? null)} onMouseLeave={() => setHoveredLinkImage(null)} >
{featuredBadge && ( {featuredBadge} )}

{featuredTitle}

{featuredSubtitle && (

{featuredSubtitle}

)} {featuredConfig?.price && (

{featuredConfig.price}

)}
{featuredCta}
)}
)}
) })}
) }