x
This commit is contained in:
1 parent
46d504e483
commit
4950661abf
15 files changed
+151
-123
No files matched your search
@@ -39,36 +39,7 @@ function setLanguageCookie(code: string) {
|
||||
}
|
||||
}
|
||||
|
||||
function createFallbackMenu(categories: Category[]): MegaMenuPayload[] {
|
||||
const categoryLinks = categories.map((category) => {
|
||||
// category.name is a multilingual Record<lang,string> when fetched with lang=all
|
||||
const label: Record<string, string> =
|
||||
typeof category.name === 'string'
|
||||
? { th: category.name, en: category.name }
|
||||
: (category.name as Record<string, string>)
|
||||
return { label, url: `/category/${category.id}` }
|
||||
})
|
||||
|
||||
return [
|
||||
{ id: 'home', label: { th: 'หน้าหลัก', en: 'Home' }, url: '/' },
|
||||
{
|
||||
id: 'shop',
|
||||
label: { th: 'ร้านค้า', en: 'Shop' },
|
||||
url: '/shop',
|
||||
columns: categoryLinks.length
|
||||
? [
|
||||
{
|
||||
title: { th: 'คอลเลกชัน', en: 'Collections' },
|
||||
links: categoryLinks,
|
||||
},
|
||||
]
|
||||
: undefined,
|
||||
},
|
||||
{ id: 'promotions', label: { th: 'โปรโมชัน', en: 'Promotions' }, url: '/coupons' },
|
||||
{ id: 'scent-guide', label: { th: 'คลาสแนะนำกลิ่น', en: 'Scent Guide' }, url: '/scent-guide' },
|
||||
{ id: 'about', label: { th: 'เกี่ยวกับเรา', en: 'About' }, url: '/about' },
|
||||
]
|
||||
}
|
||||
|
||||
export default function Navbar({ categories = [], initialMenu = [], settings = null }: NavbarProps) {
|
||||
const [searchOpen, setSearchOpen] = useState(false)
|
||||
@@ -90,9 +61,7 @@ export default function Navbar({ categories = [], initialMenu = [], settings = n
|
||||
const { t, i18n } = useTranslation()
|
||||
const lang = useLang()
|
||||
|
||||
const fallbackMenu = useMemo(() => createFallbackMenu(categories), [categories])
|
||||
// Use server menu if available, fall back to categories-based menu
|
||||
const menuItems = megaMenu.length > 0 ? megaMenu : fallbackMenu
|
||||
const menuItems = megaMenu
|
||||
|
||||
const changeLanguage = (code: string) => {
|
||||
i18n.changeLanguage(code)
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
import { useState } from 'react'
|
||||
import Image from 'next/image'
|
||||
import Link from './LocalizedLink'
|
||||
import { ShoppingBag } from 'lucide-react'
|
||||
import { ShoppingBag, Layers } from 'lucide-react'
|
||||
import type { Product } from '@homaroma/types'
|
||||
import { getCategoryImage, formatPrice } from '@homaroma/types'
|
||||
import { resolveCategoryName, resolveLocalized } from '../lib/localization'
|
||||
@@ -33,7 +33,26 @@ export default function ProductCard({ product }: ProductCardProps) {
|
||||
vi: 'Thêm vào giỏ',
|
||||
ko: '장바구니에 담기'
|
||||
}
|
||||
const optionsLabels: Record<string, string> = {
|
||||
th: 'ตัวเลือก',
|
||||
en: 'Options',
|
||||
ja: 'オプション',
|
||||
zh: '选项',
|
||||
vi: 'Tùy chọn',
|
||||
ko: '옵션'
|
||||
}
|
||||
const selectOptionsLabels: Record<string, string> = {
|
||||
th: 'เลือกตัวเลือก',
|
||||
en: 'Select Options',
|
||||
ja: 'オプションを選択',
|
||||
zh: '选择选项',
|
||||
vi: 'Chọn tùy chọn',
|
||||
ko: '옵션 선택'
|
||||
}
|
||||
|
||||
const addToCartText = addToCartLabels[lang] || addToCartLabels.en
|
||||
const optionsText = optionsLabels[lang] || optionsLabels.en
|
||||
const selectOptionsText = selectOptionsLabels[lang] || selectOptionsLabels.en
|
||||
|
||||
return (
|
||||
<div className="ui-card ui-card-hover group flex h-full cursor-pointer flex-col overflow-hidden p-2">
|
||||
@@ -69,56 +88,51 @@ export default function ProductCard({ product }: ProductCardProps) {
|
||||
)}
|
||||
</div>
|
||||
|
||||
{product.variants.length > 0 && (
|
||||
<div className="mb-1 mt-2 flex flex-wrap gap-1.5">
|
||||
{product.variants.map((variant) => {
|
||||
const isSelected = selectedVariant?.id === variant.id
|
||||
return (
|
||||
<button
|
||||
key={variant.id}
|
||||
type="button"
|
||||
onClick={(e) => {
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
setSelectedVariant(variant)
|
||||
}}
|
||||
className={`rounded-full border px-3 py-1 text-[10px] font-bold uppercase tracking-wider transition-all cursor-pointer ${
|
||||
isSelected
|
||||
? 'border-brand-primary bg-brand-primary text-surface-card shadow-sm'
|
||||
: 'border-line-primary/20 bg-surface-card text-text-main hover:border-brand-primary/50'
|
||||
}`}
|
||||
>
|
||||
{[variant.option1, variant.option2, variant.option3].filter(Boolean).join(' / ')}
|
||||
</button>
|
||||
)
|
||||
})}
|
||||
{product.variants && product.variants.length > 1 && (
|
||||
<div className="mb-1 mt-2 flex items-center">
|
||||
<span className="inline-flex items-center gap-1 rounded-md bg-surface-page px-2 py-1 text-[10px] font-semibold text-muted-text border border-line-primary/20 shadow-sm transition-colors group-hover:bg-surface-page/80">
|
||||
<Layers className="h-3 w-3 opacity-70" />
|
||||
{product.variants.length} {optionsText}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="mt-auto flex flex-col gap-2 pt-3">
|
||||
<div className="flex items-center justify-between">
|
||||
<span className="text-sm font-black text-brand-primary md:text-lg">
|
||||
{formatPrice(displayPrice)}
|
||||
{formatPrice(selectedVariant?.price ?? product.variants?.[0]?.price ?? product.price)}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{selectedVariant && (
|
||||
{product.variants && product.variants.length > 1 ? (
|
||||
<Link href={`/products/${product.id}`} className="block w-full">
|
||||
<button
|
||||
type="button"
|
||||
className="ui-button-primary w-full gap-1.5 shadow-sm"
|
||||
>
|
||||
{selectOptionsText}
|
||||
</button>
|
||||
</Link>
|
||||
) : (
|
||||
<button
|
||||
type="button"
|
||||
onClick={(e) => {
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
addToCart({
|
||||
productId: product.id,
|
||||
variantId: selectedVariant.id,
|
||||
quantity: 1,
|
||||
price: selectedVariant.price || 0,
|
||||
productName: productName,
|
||||
variantName: [selectedVariant.option1, selectedVariant.option2, selectedVariant.option3].filter(Boolean).join(' / '),
|
||||
productImage: imageUrl
|
||||
})
|
||||
const targetVariant = selectedVariant || product.variants[0];
|
||||
if (targetVariant) {
|
||||
addToCart({
|
||||
productId: product.id,
|
||||
variantId: targetVariant.id,
|
||||
quantity: 1,
|
||||
price: targetVariant.price || product.price || 0,
|
||||
productName: productName,
|
||||
variantName: [targetVariant.option1, targetVariant.option2, targetVariant.option3].filter(Boolean).join(' / '),
|
||||
productImage: imageUrl
|
||||
})
|
||||
}
|
||||
}}
|
||||
className="ui-button-primary w-full gap-1.5 rounded-xl py-2.5 shadow-sm"
|
||||
className="ui-button-primary w-full gap-1.5 shadow-sm"
|
||||
>
|
||||
<ShoppingBag className="h-3.5 w-3.5" />
|
||||
{addToCartText}
|
||||
|
||||
Reference in new issue
Block a user