This commit is contained in:
hamid zarghami
2025-11-29 15:13:15 +03:30
parent 1368ea8807
commit 8b89cc99ca
4 changed files with 203 additions and 73 deletions
+181 -65
View File
@@ -75,77 +75,193 @@ const BaseInformation: FC<BaseInformationProps> = ({ product, stats }) => {
</div>
{/* نمایش variant ها */}
<div className='mt-4 sm:mt-6'>
{/* متراژ */}
<div className='flex flex-wrap items-center gap-1.5 mb-4'>
{product.variants.map((variant) => {
if (variant.meterage) {
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'
}`}
>
{variant.meterage.value}
</button>
)
}
return null
})}
</div>
{product.variants.length > 0 && (
<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)
{/* رنگ ها */}
<div className='flex flex-wrap items-center gap-1.5 mb-4'>
{product.variants.map((variant) => {
if (variant.color) {
const isSelected = variantId === variant._id
// اگر هیچ فیلد خاصی وجود نداشت، نمایش عمومی
if (!hasMeterage && !hasColor && !hasSize && !hasThemeValue) {
return (
<button
key={variant._id}
onClick={() => handleVariantSelect(variant._id)}
className={clx(
'size-10 rounded-full flex justify-center items-center',
variant.color.hexColor === '#FFFFFF' ? 'border border-border' : ''
)}
style={{ backgroundColor: variant.color.hexColor }}
>
{isSelected && <Image src='/images/tick.svg' alt='check' width={20} height={20} className={clx(
'size-5',
variant.color.hexColor === '#FFFFFF' ? 'filterBlack' : ''
)} />}
</button>
<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 null
})}
</div>
{/* سایزها */}
<div className='flex flex-wrap items-center gap-1.5'>
{product.variants.map((variant) => {
if (variant.size) {
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'
}`}
>
{variant.size.value}
</button>
)
}
return null
})}
// نمایش فیلدهای خاص
return (
<>
{/* متراژ */}
{hasMeterage && (
<div className='flex flex-wrap items-center gap-1.5 mb-4'>
{product.variants.map((variant) => {
if (variant.meterage) {
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'
}`}
>
{variant.meterage.value}
</button>
)
}
return null
})}
</div>
)}
{/* رنگ ها */}
{hasColor && (
<div className='flex flex-wrap items-center gap-1.5 mb-4'>
{product.variants.map((variant) => {
if (variant.color) {
const isSelected = variantId === variant._id
return (
<button
key={variant._id}
onClick={() => handleVariantSelect(variant._id)}
className={clx(
'size-10 rounded-full flex justify-center items-center',
variant.color.hexColor === '#FFFFFF' ? 'border border-border' : ''
)}
style={{ backgroundColor: variant.color.hexColor }}
>
{isSelected && <Image src='/images/tick.svg' alt='check' width={20} height={20} className={clx(
'size-5',
variant.color.hexColor === '#FFFFFF' ? 'filterBlack' : ''
)} />}
</button>
)
}
return null
})}
</div>
)}
{/* سایزها */}
{hasSize && (
<div className='flex flex-wrap items-center gap-1.5 mb-4'>
{product.variants.map((variant) => {
if (variant.size) {
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'
}`}
>
{variant.size.value}
</button>
)
}
return null
})}
</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 ?
+2 -2
View File
@@ -67,7 +67,7 @@ const CategoryModal: FC<Props> = ({ isOpen, onClose }) => {
onClick={() => handleMainCategoryClick(category._id)}
>
<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
src={category.icon}
alt={category.title_fa}
@@ -147,7 +147,7 @@ const CategoryModal: FC<Props> = ({ isOpen, onClose }) => {
onClick={() => handleCategoryNavigate(item)}
>
<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
src={item.icon}
alt={item.title_fa}
+1 -1
View File
@@ -62,7 +62,7 @@ const Menu: FC = () => {
onClick={() => handleCategoryClick(category)}
>
<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
src={category.icon}
alt={category.title_fa}
+19 -5
View File
@@ -38,10 +38,10 @@ export interface ProductShop {
shopCode: number;
owner: string;
shopDescription: string;
telephoneNumber: string;
telephoneNumber: string | null;
isChatActive: boolean;
shopPostalCode: string;
logo: string;
shopPostalCode: string | null;
logo: string | null;
}
export interface ShipmentMethod {
@@ -52,6 +52,17 @@ export interface ShipmentMethod {
deliveryType: string;
}
export interface SaleFormat {
wholeSale: unknown[];
}
export interface ThemeValue {
_id: string;
theme: string;
name: string;
value: number | string;
}
export interface ProductVariant {
_id: string;
market_status: string;
@@ -61,8 +72,10 @@ export interface ProductVariant {
isFreeShip: boolean;
isWholeSale: boolean;
shop: ProductShop;
saleFormat: SaleFormat;
shipmentMethod: ShipmentMethod[];
warranty: ProductWarranty;
themeValue: ThemeValue;
size?: ProductSize;
color?: ProductColor;
meterage?: ProductMeterage;
@@ -86,7 +99,7 @@ export interface ProductCategory {
theme: string;
description: string;
leaf: boolean;
parent: string;
parent: string | null;
}
export interface ProductSpecification {
@@ -146,7 +159,7 @@ export interface Product {
url: string;
title_fa: string;
title_en: string;
seoTitle: string | null;
seoTitle: string;
seoDescription: string | null;
source: string;
description: string;
@@ -173,6 +186,7 @@ export interface ProductDetailResponse {
reviews?: Review[];
questions?: Question[];
stats: {
product: number;
commentsCount: number;
averageRate: number;
};