change variant crud

This commit is contained in:
hamid zarghami
2025-11-29 12:09:42 +03:30
parent 7cf27823ee
commit 9646f76001
4 changed files with 42 additions and 69 deletions
+3 -16
View File
@@ -1,6 +1,6 @@
import { type FC } from 'react'
import PageTitle from '../../components/PageTitle'
import { useGetProductVariants, useGetProductById } from './hooks/useProductData'
import { useGetProductVariants } from './hooks/useProductData'
import { useParams } from 'react-router-dom'
import PageLoading from '@/components/PageLoading'
import type { ProductVariantDetailType } from './types/Types'
@@ -13,26 +13,13 @@ const ProductVariant: FC = () => {
const { id } = useParams()
const { data, isLoading, refetch } = useGetProductVariants(id!)
const { data: productData } = useGetProductById(id!)
const categoryTheme = productData?.results?.product?.category?.theme
const getVariantColumnHeader = () => {
switch (categoryTheme) {
case 'Size': return 'سایز'
case 'Color': return 'رنگ'
case 'Meterage': return 'متریاژ'
default: return 'تنوع'
}
return 'تنوع'
}
const getVariantValue = (variant: ProductVariantDetailType) => {
switch (categoryTheme) {
case 'Size': return variant.size?.value || '-'
case 'Color': return variant.color?.name || '-'
case 'Meterage': return variant.meterage?.value || '-'
default: return '-'
}
return variant.themeValue?.name || variant.themeValue?.value?.toString() || '-'
}
const getMarketStatusVariant = (status: string) => {
+23 -47
View File
@@ -6,8 +6,8 @@ import DatePickerComponent from '@/components/DatePicker'
import { useState, type FC } from 'react'
import { useParams } from 'react-router-dom'
import { useCreateProductVariant, useGetProductById, useGetProductVariants } from '../hooks/useProductData'
import { useGetCategoryVariants } from '@/pages/category'
import type { CreateProductVariantRequestType } from '../types/Types'
import { useGetThemeValues } from '@/pages/theme/hooks/useThemeData'
import { useGetWarranties } from '@/pages/warranty/hooks/useWarrantyData'
import { toast } from 'react-toastify'
import { extractErrorMessage } from '@/helpers/utils'
@@ -26,7 +26,7 @@ const CreateVariant: FC = () => {
const queryClient = useQueryClient()
const { data: productData } = useGetProductById(id!)
const { data: categoryData } = useGetCategoryVariants(productData?.results?.product?.category?._id ?? '')
const { data: themeValues } = useGetThemeValues(productData?.results?.product?.category?.theme as string)
const { data: variantsData, refetch: refetchVariants } = useGetProductVariants(id!)
const createProductVariant = useCreateProductVariant()
const { data: warrantiesData } = useGetWarranties()
@@ -34,13 +34,15 @@ const CreateVariant: FC = () => {
const [showModal, setShowModal] = useState<boolean>(false)
const categoryTheme = productData?.results?.product?.category?.theme
const categoryVariants = categoryData?.results?.data?.category?.categoryVariants
const isNoVariantTheme = categoryTheme === 'noColor_noSize'
const isThemeNull = !categoryTheme
const existingVariantsCount = variantsData?.results?.count || 0
const canCreateVariant = !isNoVariantTheme || existingVariantsCount === 0
const canCreateVariant = (isThemeNull || isNoVariantTheme)
? existingVariantsCount === 0
: true
const validationSchema = Yup.object().shape({
variantId: isNoVariantTheme
themeValueId: (isNoVariantTheme || isThemeNull)
? Yup.string().optional()
: Yup.string().required('انتخاب تنوع الزامی است'),
warrantyId: Yup.string().required('انتخاب گارانتی الزامی است'),
@@ -59,7 +61,7 @@ const CreateVariant: FC = () => {
})
const initialValues = {
variantId: '',
themeValueId: '',
warrantyId: '',
order_limit: '',
sellerSpecialCode: '' as string | undefined,
@@ -76,34 +78,14 @@ const CreateVariant: FC = () => {
}
const getVariantOptions = () => {
switch (categoryTheme) {
case 'Size':
return categoryVariants?.sizes?.map(size => ({
value: size._id.toString(),
label: size.value
return themeValues?.results?.data?.map(themeValue => ({
value: themeValue._id,
label: themeValue.name || themeValue.value?.toString() || '-'
})) || []
case 'Color':
return categoryVariants?.colors?.map((color, index) => ({
value: index.toString(), // استفاده از index به عنوان ID موقت
label: color.name
})) || []
case 'Meterage':
return categoryVariants?.meterages?.map(meterage => ({
value: meterage._id.toString(),
label: meterage.value
})) || []
default:
return []
}
}
const getVariantLabel = () => {
switch (categoryTheme) {
case 'Size': return 'سایز'
case 'Color': return 'رنگ'
case 'Meterage': return 'متریاژ'
default: return 'تنوع'
}
return categoryTheme ? 'تنوع' : 'تنوع'
}
const getWarrantyOptions = () => {
@@ -131,18 +113,11 @@ const CreateVariant: FC = () => {
// اضافه کردن variant بر اساس theme
let variantData: CreateProductVariantRequestType
if (isNoVariantTheme) {
// در حالت noColor_noSize هیچ variantId ارسال نمی‌شود
if (isNoVariantTheme || isThemeNull) {
// در حالت noColor_noSize یا theme null هیچ themeValueId ارسال نمی‌شود
variantData = baseData
} else if (categoryTheme === 'Size') {
variantData = { ...baseData, sizeId: parseInt(values.variantId) }
} else if (categoryTheme === 'Color') {
// برای رنگ‌ها از index به عنوان ID استفاده می‌کنیم
variantData = { ...baseData, colorId: parseInt(values.variantId) + 1 } // +1 برای اینکه ID از 1 شروع شود
} else if (categoryTheme === 'Meterage') {
variantData = { ...baseData, meterageId: parseInt(values.variantId) }
} else {
variantData = baseData
variantData = { ...baseData, themeValueId: values.themeValueId }
}
if (!values.sellerSpecialCode) {
@@ -160,8 +135,9 @@ const CreateVariant: FC = () => {
toast.success('تنوع جدید با موفقیت ایجاد شد')
// Refetch لیست تنوع‌ها
refetchVariants()
// یا می‌توانید از invalidateQueries استفاده کنید
// Invalidate لیست تنوع‌ها و جزئیات محصول
queryClient.invalidateQueries({ queryKey: ['product-variants', id] })
queryClient.invalidateQueries({ queryKey: ['product-by-id', id] })
},
onError: (error) => {
toast.error(extractErrorMessage(error))
@@ -199,29 +175,29 @@ const CreateVariant: FC = () => {
>
{({ setFieldValue }) => (
<Form className="space-y-4 w-[500px] mt-4">
{/* انتخاب variant - فقط در صورتی که theme نوع noColor_noSize نباشد */}
{!isNoVariantTheme && (
{/* انتخاب variant - فقط در صورتی که theme معتبر باشد و نوع noColor_noSize نباشد */}
{!isNoVariantTheme && !isThemeNull && (
<div>
<label className="text-sm font-medium text-gray-700 mb-1 block">
{getVariantLabel()}
</label>
<Field name="variantId">
<Field name="themeValueId">
{({ field }: FormikFieldProps) => (
<Select
{...field}
placeholder={`انتخاب ${getVariantLabel().toLowerCase()}`}
value={field.value}
onChange={(e: React.ChangeEvent<HTMLSelectElement>) => setFieldValue('variantId', e.target.value)}
onChange={(e: React.ChangeEvent<HTMLSelectElement>) => setFieldValue('themeValueId', e.target.value)}
items={getVariantOptions()}
/>
)}
</Field>
<ErrorMessage name="variantId" component="div" className="text-red-500 text-sm mt-1" />
<ErrorMessage name="themeValueId" component="div" className="text-red-500 text-sm mt-1" />
</div>
)}
{/* پیام اطلاع‌رسانی برای محصولات بدون تنوع */}
{isNoVariantTheme && (
{(isNoVariantTheme || isThemeNull) && (
<div className="p-3 bg-blue-50 border border-blue-200 rounded-lg">
<p className="text-sm text-blue-800">
این محصول تنوع ندارد. فقط میتوانید یک نسخه از محصول ایجاد کنید.
@@ -12,6 +12,7 @@ import { extractErrorMessage } from '@/helpers/utils'
import { Formik, Form, Field, ErrorMessage } from 'formik'
import type { FieldInputProps } from 'formik'
import * as Yup from 'yup'
import { useQueryClient } from '@tanstack/react-query'
interface FormikFieldProps {
field: FieldInputProps<string | number | undefined>
@@ -26,6 +27,7 @@ interface UpdateVariantProps {
const UpdateVariant: FC<UpdateVariantProps> = ({ variant, onUpdate }) => {
const { id } = useParams()
const queryClient = useQueryClient()
const { data: variantData, isLoading, error } = useGetVariantById(id!, variant._id)
const updateVariant = useUpdateVariant()
@@ -104,7 +106,12 @@ const UpdateVariant: FC<UpdateVariantProps> = ({ variant, onUpdate }) => {
onSuccess: () => {
setShowModal(false)
toast.success('تنوع با موفقیت بروزرسانی شد')
// Refetch لیست تنوع‌ها
onUpdate?.()
// Invalidate لیست تنوع‌ها و جزئیات محصول
queryClient.invalidateQueries({ queryKey: ['product-variants', id] })
queryClient.invalidateQueries({ queryKey: ['product-by-id', id] })
queryClient.invalidateQueries({ queryKey: ['variant-by-id', id, variant._id] })
},
onError: (error) => {
toast.error(extractErrorMessage(error))
+8 -5
View File
@@ -242,6 +242,11 @@ export type ProductVariantDetailType = {
isFreeShip: boolean;
isWholeSale: boolean;
saleFormat: SaleFormatType;
themeValue?: {
_id: string;
name: string;
value: number;
};
size?: SizeType;
color?: ColorType;
meterage?: MeterageType;
@@ -266,9 +271,7 @@ export type GetVariantByIdResponseType = {
export type CreateProductVariantRequestType = {
productId: string;
colorId?: number;
sizeId?: number;
meterageId?: number;
themeValueId?: string;
warrantyId: number;
order_limit: number;
sellerSpecialCode?: string;
@@ -305,14 +308,14 @@ export type ProductCategoryType = {
icon: string;
imageUrl: string;
description: string;
theme: string;
variants: number[];
hierarchy: string[];
leaf: boolean;
parent: string;
parent: string | null;
deleted: boolean;
createdAt: string;
updatedAt: string;
theme: string;
url: string;
children: ProductCategoryType[];
};