variant
This commit is contained in:
@@ -75,8 +75,43 @@ const BaseInformation: FC<BaseInformationProps> = ({ product, stats }) => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* نمایش variant ها */}
|
{/* نمایش variant ها */}
|
||||||
|
{product.variants.length > 0 && (
|
||||||
<div className='mt-4 sm:mt-6'>
|
<div className='mt-4 sm:mt-6'>
|
||||||
|
{/* بررسی وجود فیلدهای خاص در variant ها */}
|
||||||
|
{(() => {
|
||||||
|
const hasMeterage = product.variants.some(v => v.meterage)
|
||||||
|
const hasColor = product.variants.some(v => v.color)
|
||||||
|
const hasSize = product.variants.some(v => v.size)
|
||||||
|
const hasThemeValue = product.variants.some(v => v.themeValue)
|
||||||
|
|
||||||
|
// اگر هیچ فیلد خاصی وجود نداشت، نمایش عمومی
|
||||||
|
if (!hasMeterage && !hasColor && !hasSize && !hasThemeValue) {
|
||||||
|
return (
|
||||||
|
<div className='flex flex-wrap items-center gap-1.5'>
|
||||||
|
{product.variants.map((variant, index) => {
|
||||||
|
const isSelected = variantId === variant._id
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
key={variant._id}
|
||||||
|
onClick={() => handleVariantSelect(variant._id)}
|
||||||
|
className={`text-[13px] px-4 py-2 border border-border rounded-lg whitespace-nowrap transition-colors ${isSelected
|
||||||
|
? 'bg-primary text-white border-primary'
|
||||||
|
: 'hover:border-primary/50'
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
گزینه {index + 1}
|
||||||
|
</button>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// نمایش فیلدهای خاص
|
||||||
|
return (
|
||||||
|
<>
|
||||||
{/* متراژ */}
|
{/* متراژ */}
|
||||||
|
{hasMeterage && (
|
||||||
<div className='flex flex-wrap items-center gap-1.5 mb-4'>
|
<div className='flex flex-wrap items-center gap-1.5 mb-4'>
|
||||||
{product.variants.map((variant) => {
|
{product.variants.map((variant) => {
|
||||||
if (variant.meterage) {
|
if (variant.meterage) {
|
||||||
@@ -97,8 +132,10 @@ const BaseInformation: FC<BaseInformationProps> = ({ product, stats }) => {
|
|||||||
return null
|
return null
|
||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
{/* رنگ ها */}
|
{/* رنگ ها */}
|
||||||
|
{hasColor && (
|
||||||
<div className='flex flex-wrap items-center gap-1.5 mb-4'>
|
<div className='flex flex-wrap items-center gap-1.5 mb-4'>
|
||||||
{product.variants.map((variant) => {
|
{product.variants.map((variant) => {
|
||||||
if (variant.color) {
|
if (variant.color) {
|
||||||
@@ -123,9 +160,11 @@ const BaseInformation: FC<BaseInformationProps> = ({ product, stats }) => {
|
|||||||
return null
|
return null
|
||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
{/* سایزها */}
|
{/* سایزها */}
|
||||||
<div className='flex flex-wrap items-center gap-1.5'>
|
{hasSize && (
|
||||||
|
<div className='flex flex-wrap items-center gap-1.5 mb-4'>
|
||||||
{product.variants.map((variant) => {
|
{product.variants.map((variant) => {
|
||||||
if (variant.size) {
|
if (variant.size) {
|
||||||
const isSelected = variantId === variant._id
|
const isSelected = variantId === variant._id
|
||||||
@@ -145,7 +184,84 @@ const BaseInformation: FC<BaseInformationProps> = ({ product, stats }) => {
|
|||||||
return null
|
return null
|
||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* themeValue ها - نمایش داینامیک */}
|
||||||
|
{hasThemeValue && (() => {
|
||||||
|
// گروهبندی variantها بر اساس theme
|
||||||
|
const themeGroups = new Map<string, typeof product.variants>()
|
||||||
|
|
||||||
|
product.variants.forEach(variant => {
|
||||||
|
if (variant.themeValue) {
|
||||||
|
const theme = variant.themeValue.theme
|
||||||
|
if (!themeGroups.has(theme)) {
|
||||||
|
themeGroups.set(theme, [])
|
||||||
|
}
|
||||||
|
themeGroups.get(theme)!.push(variant)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// تابع برای بررسی hex بودن value
|
||||||
|
const isHexColor = (value: string | number): boolean => {
|
||||||
|
if (typeof value !== 'string') return false
|
||||||
|
const hexPattern = /^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/
|
||||||
|
return hexPattern.test(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
return Array.from(themeGroups.entries()).map(([theme, variants]) => (
|
||||||
|
<div key={theme} className='flex flex-wrap items-center gap-1.5 mb-4'>
|
||||||
|
{variants.map((variant) => {
|
||||||
|
if (variant.themeValue) {
|
||||||
|
const isSelected = variantId === variant._id
|
||||||
|
const value = typeof variant.themeValue.value === 'string'
|
||||||
|
? variant.themeValue.value
|
||||||
|
: String(variant.themeValue.value)
|
||||||
|
const isHex = isHexColor(value)
|
||||||
|
|
||||||
|
// اگر hex بود، دایره رنگی نمایش بده
|
||||||
|
if (isHex) {
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
key={variant._id}
|
||||||
|
onClick={() => handleVariantSelect(variant._id)}
|
||||||
|
className={clx(
|
||||||
|
'size-10 rounded-full flex justify-center items-center',
|
||||||
|
value === '#FFFFFF' ? 'border border-border' : ''
|
||||||
|
)}
|
||||||
|
style={{ backgroundColor: value }}
|
||||||
|
>
|
||||||
|
{isSelected && <Image src='/images/tick.svg' alt='check' width={20} height={20} className={clx(
|
||||||
|
'size-5',
|
||||||
|
value === '#FFFFFF' ? 'filterBlack' : ''
|
||||||
|
)} />}
|
||||||
|
</button>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// اگر hex نبود، name را نمایش بده
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
key={variant._id}
|
||||||
|
onClick={() => handleVariantSelect(variant._id)}
|
||||||
|
className={`text-[13px] px-4 py-2 border border-border rounded-lg whitespace-nowrap transition-colors ${isSelected
|
||||||
|
? 'bg-primary text-white border-primary'
|
||||||
|
: 'hover:border-primary/50'
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
{variant.themeValue.name}
|
||||||
|
</button>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
})}
|
||||||
</div>
|
</div>
|
||||||
|
))
|
||||||
|
})()}
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
})()}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
{
|
{
|
||||||
product.specifications.length > 0 ?
|
product.specifications.length > 0 ?
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ const CategoryModal: FC<Props> = ({ isOpen, onClose }) => {
|
|||||||
onClick={() => handleMainCategoryClick(category._id)}
|
onClick={() => handleMainCategoryClick(category._id)}
|
||||||
>
|
>
|
||||||
<div className="w-12 h-12 bg-white rounded-full flex items-center justify-center mb-1 shadow-sm">
|
<div className="w-12 h-12 bg-white rounded-full flex items-center justify-center mb-1 shadow-sm">
|
||||||
{category.icon ? (
|
{category.icon && category.icon.trim() !== '' && (category.icon.startsWith('http://') || category.icon.startsWith('https://') || category.icon.startsWith('/')) ? (
|
||||||
<Image
|
<Image
|
||||||
src={category.icon}
|
src={category.icon}
|
||||||
alt={category.title_fa}
|
alt={category.title_fa}
|
||||||
@@ -147,7 +147,7 @@ const CategoryModal: FC<Props> = ({ isOpen, onClose }) => {
|
|||||||
onClick={() => handleCategoryNavigate(item)}
|
onClick={() => handleCategoryNavigate(item)}
|
||||||
>
|
>
|
||||||
<div className="w-14 h-14 bg-white rounded-full flex items-center justify-center mb-3 border border-gray-200">
|
<div className="w-14 h-14 bg-white rounded-full flex items-center justify-center mb-3 border border-gray-200">
|
||||||
{item.icon ? (
|
{item.icon && item.icon.trim() !== '' && (item.icon.startsWith('http://') || item.icon.startsWith('https://') || item.icon.startsWith('/')) ? (
|
||||||
<Image
|
<Image
|
||||||
src={item.icon}
|
src={item.icon}
|
||||||
alt={item.title_fa}
|
alt={item.title_fa}
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ const Menu: FC = () => {
|
|||||||
onClick={() => handleCategoryClick(category)}
|
onClick={() => handleCategoryClick(category)}
|
||||||
>
|
>
|
||||||
<div className='flex items-center gap-3'>
|
<div className='flex items-center gap-3'>
|
||||||
{category.icon && (
|
{category.icon && category.icon.trim() !== '' && (category.icon.startsWith('http://') || category.icon.startsWith('https://') || category.icon.startsWith('/')) && (
|
||||||
<Image
|
<Image
|
||||||
src={category.icon}
|
src={category.icon}
|
||||||
alt={category.title_fa}
|
alt={category.title_fa}
|
||||||
|
|||||||
@@ -38,10 +38,10 @@ export interface ProductShop {
|
|||||||
shopCode: number;
|
shopCode: number;
|
||||||
owner: string;
|
owner: string;
|
||||||
shopDescription: string;
|
shopDescription: string;
|
||||||
telephoneNumber: string;
|
telephoneNumber: string | null;
|
||||||
isChatActive: boolean;
|
isChatActive: boolean;
|
||||||
shopPostalCode: string;
|
shopPostalCode: string | null;
|
||||||
logo: string;
|
logo: string | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ShipmentMethod {
|
export interface ShipmentMethod {
|
||||||
@@ -52,6 +52,17 @@ export interface ShipmentMethod {
|
|||||||
deliveryType: string;
|
deliveryType: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface SaleFormat {
|
||||||
|
wholeSale: unknown[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ThemeValue {
|
||||||
|
_id: string;
|
||||||
|
theme: string;
|
||||||
|
name: string;
|
||||||
|
value: number | string;
|
||||||
|
}
|
||||||
|
|
||||||
export interface ProductVariant {
|
export interface ProductVariant {
|
||||||
_id: string;
|
_id: string;
|
||||||
market_status: string;
|
market_status: string;
|
||||||
@@ -61,8 +72,10 @@ export interface ProductVariant {
|
|||||||
isFreeShip: boolean;
|
isFreeShip: boolean;
|
||||||
isWholeSale: boolean;
|
isWholeSale: boolean;
|
||||||
shop: ProductShop;
|
shop: ProductShop;
|
||||||
|
saleFormat: SaleFormat;
|
||||||
shipmentMethod: ShipmentMethod[];
|
shipmentMethod: ShipmentMethod[];
|
||||||
warranty: ProductWarranty;
|
warranty: ProductWarranty;
|
||||||
|
themeValue: ThemeValue;
|
||||||
size?: ProductSize;
|
size?: ProductSize;
|
||||||
color?: ProductColor;
|
color?: ProductColor;
|
||||||
meterage?: ProductMeterage;
|
meterage?: ProductMeterage;
|
||||||
@@ -86,7 +99,7 @@ export interface ProductCategory {
|
|||||||
theme: string;
|
theme: string;
|
||||||
description: string;
|
description: string;
|
||||||
leaf: boolean;
|
leaf: boolean;
|
||||||
parent: string;
|
parent: string | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ProductSpecification {
|
export interface ProductSpecification {
|
||||||
@@ -146,7 +159,7 @@ export interface Product {
|
|||||||
url: string;
|
url: string;
|
||||||
title_fa: string;
|
title_fa: string;
|
||||||
title_en: string;
|
title_en: string;
|
||||||
seoTitle: string | null;
|
seoTitle: string;
|
||||||
seoDescription: string | null;
|
seoDescription: string | null;
|
||||||
source: string;
|
source: string;
|
||||||
description: string;
|
description: string;
|
||||||
@@ -173,6 +186,7 @@ export interface ProductDetailResponse {
|
|||||||
reviews?: Review[];
|
reviews?: Review[];
|
||||||
questions?: Question[];
|
questions?: Question[];
|
||||||
stats: {
|
stats: {
|
||||||
|
product: number;
|
||||||
commentsCount: number;
|
commentsCount: number;
|
||||||
averageRate: number;
|
averageRate: number;
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user