This commit is contained in:
Your Name committed 2026-06-25 19:57:14 -04:00
1 parent 46d504e483
commit 4950661abf
15 files changed
+151 -123

No files matched your search

+25 -37
View File
@@ -2,7 +2,7 @@ import { useNavigate } from 'react-router-dom';
import { useState } from 'react';
import type { Product, TranslatableString } from '../types';
import { getCategoryImage, formatPrice } from '../types';
import { Heart, ShoppingBag } from 'lucide-react';
import { Heart, ShoppingBag, Layers } from 'lucide-react';
import { useWishlistStore } from '../store/wishlistStore';
import { useCartStore } from '../store/cartStore';
import { useTranslation } from 'react-i18next';
@@ -99,36 +99,19 @@ export default function ProductCard({ product, enableQuickShop = false, category
</p>
</div>
{enableQuickShop && product.variants && 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-pop-black bg-pop-black text-pop-bg shadow-sm'
: 'border-pop-black/10 bg-transparent text-pop-black/70 hover:border-pop-black/30 hover:bg-pop-black/5'
}`}
>
{[variant.option1, variant.option2, variant.option3].filter(Boolean).map(opt => resolveOptionValue(opt, product.options, i18n.language)).join(' / ')}
</button>
);
})}
{enableQuickShop && 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-pop-black/5 px-2 py-1 text-[10px] font-semibold text-pop-black/70 border border-pop-black/10 shadow-sm transition-colors group-hover:bg-pop-black/10">
<Layers className="h-3 w-3 opacity-70" />
{product.variants.length} {t('product.variantsAvailable', 'Options')}
</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-pop-pink md:text-lg">
{formatPrice(selectedVariant?.price ?? product.variants[0]?.price)}
{formatPrice(selectedVariant?.price ?? product.variants?.[0]?.price ?? product.price)}
</span>
{!enableQuickShop && (
<span className="flex items-center gap-1 text-[10px] font-bold uppercase tracking-widest text-pop-black transition-transform group-hover:translate-x-1 group-hover:text-pop-pink md:text-xs">
@@ -137,26 +120,31 @@ export default function ProductCard({ product, enableQuickShop = false, category
)}
</div>
{enableQuickShop && selectedVariant && (
{enableQuickShop && (
<button
type="button"
onClick={(e) => {
e.preventDefault();
e.stopPropagation();
addToCart({
productId: product.id,
variantId: selectedVariant.id,
quantity: 1,
price: selectedVariant.price || 0,
productName: displayName,
variantName: [selectedVariant.option1, selectedVariant.option2, selectedVariant.option3].filter(Boolean).map(opt => resolveOptionValue(opt, product.options, i18n.language)).join(' / '),
productImage: product.images?.[0]?.url || getCategoryImage(displayCategoryName)
});
if (product.variants && product.variants.length > 1) {
navigate(`/products/${product.id}`);
} else if (selectedVariant || product.variants?.[0]) {
const targetVariant = selectedVariant || product.variants[0];
addToCart({
productId: product.id,
variantId: targetVariant.id,
quantity: 1,
price: targetVariant.price || product.price || 0,
productName: displayName,
variantName: [targetVariant.option1, targetVariant.option2, targetVariant.option3].filter(Boolean).map(opt => resolveOptionValue(opt, product.options, i18n.language)).join(' / '),
productImage: product.images?.[0]?.url || getCategoryImage(displayCategoryName)
});
}
}}
className="ui-button-primary w-full gap-1.5 rounded-xl py-2.5 shadow-sm"
>
<ShoppingBag className="w-3.5 h-3.5" />
{t('cart.addToCart')}
{!(product.variants && product.variants.length > 1) && <ShoppingBag className="w-3.5 h-3.5" />}
{product.variants && product.variants.length > 1 ? t('product.selectOptions', 'Select Options') : t('cart.addToCart')}
</button>
)}
</div>
+3 -1
View File
@@ -61,7 +61,9 @@
"relatedProducts": "Related Products",
"moreRelated": "More {{category}}",
"reviews": "Reviews",
"viewDetails": "View Details →"
"viewDetails": "View Details →",
"variantsAvailable": "Options",
"selectOptions": "Select Options"
},
"checkout": {
"title": "Checkout",
+3 -1
View File
@@ -58,6 +58,8 @@
"relatedProducts": "関連商品",
"moreRelated": "関連する {{category}}",
"reviews": "レビュー",
"viewDetails": "詳細を見る →"
"viewDetails": "詳細を見る →",
"variantsAvailable": "オプション",
"selectOptions": "オプションを選択"
}
}
+3 -1
View File
@@ -58,6 +58,8 @@
"relatedProducts": "관련 상품",
"moreRelated": "더 많은 {{category}}",
"reviews": "리뷰",
"viewDetails": "상세 보기 →"
"viewDetails": "상세 보기 →",
"variantsAvailable": "옵션",
"selectOptions": "옵션 선택"
}
}
+3 -1
View File
@@ -61,7 +61,9 @@
"relatedProducts": "สินค้าที่เกี่ยวข้อง",
"moreRelated": "เพิ่มเติมในหมวด {{category}}",
"reviews": "รีวิว",
"viewDetails": "ดูรายละเอียด →"
"viewDetails": "ดูรายละเอียด →",
"variantsAvailable": "ตัวเลือก",
"selectOptions": "เลือกตัวเลือก"
},
"checkout": {
"title": "ชำระเงิน",
+3 -1
View File
@@ -58,6 +58,8 @@
"relatedProducts": "Sản phẩm liên quan",
"moreRelated": "Thêm {{category}}",
"reviews": "Đánh giá",
"viewDetails": "Xem chi tiết →"
"viewDetails": "Xem chi tiết →",
"variantsAvailable": "Tùy chọn",
"selectOptions": "Chọn tùy chọn"
}
}
+3 -1
View File
@@ -58,6 +58,8 @@
"relatedProducts": "相关商品",
"moreRelated": "更多 {{category}}",
"reviews": "评价",
"viewDetails": "查看详情 →"
"viewDetails": "查看详情 →",
"variantsAvailable": "选项",
"selectOptions": "选择选项"
}
}