"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 ( setLoaded(true)} loading="lazy" /> ) } export function DesktopMegaMenu({ items, lang, currentPath }: DesktopMegaMenuProps) { const [openId, setOpenId] = useState(null) const [hoveredLinkImage, setHoveredLinkImage] = useState(null) 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 visibleColumns = item.columns?.slice(0, 2) ?? [] const featuredLink = getFirstImageLink(item.columns) const featuredConfig = item.featured const showFeatured = featuredConfig?.enabled !== false 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' return ( handleOpen(uniqueId)} onMouseLeave={handleClose} > {getLocalizedMenuText(item.label, lang)} {hasColumns && ( )} {hasColumns && ( 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} )} )} ) })} ) }
{featuredTitle}
{featuredSubtitle}
{featuredConfig.price}