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