This commit is contained in:
unknown committed 2026-06-25 16:58:13 +07:00
1 parent 07e9413a6b
commit 46d504e483
4 files changed
+112 -38

No files matched your search

@@ -7,6 +7,30 @@ import { useCartStore } from '../store/cartStore'
import { resolveCategoryName, resolveLocalized } from '../lib/localization'
import { useLang } from '../hooks/useLang'
function getBaseString(val: any): string {
if (!val) return '';
if (typeof val === 'string') return val;
return val['th'] || val['en'] || Object.values(val)[0] || '';
}
function resolveOptionValue(val: string, options: any[] | null | undefined, lang: string): string {
if (!val) return '';
if (!options || !Array.isArray(options)) return val;
for (const option of options) {
if (!option.values || !Array.isArray(option.values)) continue;
for (const v of option.values) {
const baseStr = typeof v === 'string' ? v : (v['th'] || v['en'] || Object.values(v)[0] || '');
if (baseStr === val) {
if (typeof v === 'string') return v;
return v[lang] ?? v[lang.slice(0, 2)] ?? v['th'] ?? v['en'] ?? Object.values(v)[0] ?? baseStr;
}
}
}
return val;
}
interface Props {
product: Product
}
@@ -66,7 +90,10 @@ export default function AddToCartSection({ product }: Props) {
const handleAddToCart = () => {
if (!currentVariant) return
const variantName = [currentVariant.option1, currentVariant.option2, currentVariant.option3].filter(Boolean).join(' / ');
const variantName = [currentVariant.option1, currentVariant.option2, currentVariant.option3]
.filter(Boolean)
.map(opt => resolveOptionValue(opt, product.options, lang))
.join(' / ');
addToCart({
productId: product.id,
@@ -80,7 +107,12 @@ export default function AddToCartSection({ product }: Props) {
toggleCart(true)
}
const currentVariantName = currentVariant ? [currentVariant.option1, currentVariant.option2, currentVariant.option3].filter(Boolean).join(' / ') : null;
const currentVariantName = currentVariant
? [currentVariant.option1, currentVariant.option2, currentVariant.option3]
.filter(Boolean)
.map(opt => resolveOptionValue(opt, product.options, lang))
.join(' / ')
: null;
return (
<>
@@ -108,34 +140,40 @@ export default function AddToCartSection({ product }: Props) {
{product.options && product.options.length > 0 && (
<div className="space-y-6">
{product.options.map((option, optIndex) => (
<div key={option.name} className="space-y-3">
<p className="text-xs font-bold uppercase tracking-widest text-muted-text">Select {option.name}</p>
<div className="flex flex-wrap gap-3">
{option.values.map(val => {
const isSelected = selectedOptions[optIndex] === val;
const isAvailable = isOptionAvailable(optIndex, val);
return (
<button
key={val}
disabled={!isAvailable}
onClick={() => handleOptionChange(optIndex, val)}
className={`rounded-xl border px-5 py-3 text-sm font-bold uppercase tracking-widest transition ${
isSelected
? 'border-brand-primary bg-brand-primary text-surface-card shadow-card'
: isAvailable
? 'border-line-primary/20 bg-surface-card text-muted-text hover:border-brand-primary hover:text-brand-primary'
: 'border-line-primary/10 bg-surface-card/50 text-muted-text/30 cursor-not-allowed'
}`}
>
{val}
</button>
);
})}
{product.options.map((option, optIndex) => {
const optNameBase = getBaseString(option.name);
const optNameDisplay = resolveLocalized(option.name, lang);
return (
<div key={optNameBase} className="space-y-3">
<p className="text-xs font-bold uppercase tracking-widest text-muted-text">Select {optNameDisplay}</p>
<div className="flex flex-wrap gap-3">
{option.values.map(val => {
const baseVal = getBaseString(val);
const displayVal = resolveLocalized(val, lang);
const isSelected = selectedOptions[optIndex] === baseVal;
const isAvailable = isOptionAvailable(optIndex, baseVal);
return (
<button
key={baseVal}
disabled={!isAvailable}
onClick={() => handleOptionChange(optIndex, baseVal)}
className={`rounded-xl border px-5 py-3 text-sm font-bold uppercase tracking-widest transition ${
isSelected
? 'border-brand-primary bg-brand-primary text-surface-card shadow-card'
: isAvailable
? 'border-line-primary/20 bg-surface-card text-muted-text hover:border-brand-primary hover:text-brand-primary'
: 'border-line-primary/10 bg-surface-card/50 text-muted-text/30 cursor-not-allowed'
}`}
>
{displayVal}
</button>
);
})}
</div>
</div>
</div>
))}
);
})}
</div>
)}