optional variant

This commit is contained in:
hamid zarghami
2025-10-27 12:36:00 +03:30
parent 8ed031229c
commit a68323d3ee
3 changed files with 117 additions and 41 deletions
@@ -2,6 +2,7 @@ import Button from '@/components/Button'
import DefaulModal from '@/components/DefaulModal' import DefaulModal from '@/components/DefaulModal'
import Input from '@/components/Input' import Input from '@/components/Input'
import Select from '@/components/Select' import Select from '@/components/Select'
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'
@@ -44,28 +45,34 @@ const CreateVariant: FC = () => {
: Yup.string().required('انتخاب تنوع الزامی است'), : Yup.string().required('انتخاب تنوع الزامی است'),
warrantyId: Yup.string().required('انتخاب گارانتی الزامی است'), warrantyId: Yup.string().required('انتخاب گارانتی الزامی است'),
order_limit: Yup.number().required('محدودیت سفارش الزامی است').min(1, 'حداقل ۱ عدد'), order_limit: Yup.number().required('محدودیت سفارش الزامی است').min(1, 'حداقل ۱ عدد'),
sellerSpecialCode: Yup.string().required('کد ویژه فروشنده الزامی است'), sellerSpecialCode: Yup.string(),
retail_price: Yup.number().required('قیمت فروش الزامی است').min(0, 'قیمت نمی‌تواند منفی باشد'), retail_price: Yup.number().required('قیمت فروش الزامی است').min(0, 'قیمت نمی‌تواند منفی باشد'),
package_weight: Yup.number().required('وزن بسته الزامی است').min(0.1, 'وزن باید حداقل ۰.۱ کیلوگرم باشد'), package_weight: Yup.number().required('وزن بسته الزامی است').min(0.1, 'وزن باید حداقل ۰.۱ کیلوگرم باشد'),
package_height: Yup.number().required('ارتفاع بسته الزامی است').min(1, 'ارتفاع باید حداقل ۱ سانتی‌متر باشد'), package_height: Yup.number().required('ارتفاع بسته الزامی است').min(1, 'ارتفاع باید حداقل ۱ سانتی‌متر باشد'),
package_length: Yup.number().required('طول بسته الزامی است').min(1, 'طول باید حداقل ۱ سانتی‌متر باشد'), package_length: Yup.number().required('طول بسته الزامی است').min(1, 'طول باید حداقل ۱ سانتی‌متر باشد'),
package_width: Yup.number().required('عرض بسته الزامی است').min(1, 'عرض باید حداقل ۱ سانتی‌متر باشد'), package_width: Yup.number().required('عرض بسته الزامی است').min(1, 'عرض باید حداقل ۱ سانتی‌متر باشد'),
postingTime: Yup.number().required('زمان ارسال الزامی است').min(1, 'زمان ارسال باید حداقل ۱ روز باشد'), postingTime: Yup.number().required('زمان ارسال الزامی است').min(1, 'زمان ارسال باید حداقل ۱ روز باشد'),
stock: Yup.number().required('موجودی انبار الزامی است').min(0, 'موجودی نمی‌تواند منفی باشد') stock: Yup.number().required('موجودی انبار الزامی است').min(0, 'موجودی نمی‌تواند منفی باشد'),
specialSale_order_limit: Yup.number().min(0, 'محدودیت فروش ویژه نمی‌تواند منفی باشد'),
specialSale_quantity: Yup.number().min(0, 'تعداد فروش ویژه نمی‌تواند منفی باشد'),
specialSale_endDate: Yup.string()
}) })
const initialValues = { const initialValues = {
variantId: '', variantId: '',
warrantyId: '', warrantyId: '',
order_limit: '', order_limit: '',
sellerSpecialCode: '', sellerSpecialCode: '' as string | undefined,
retail_price: '', retail_price: '',
package_weight: '', package_weight: '',
package_height: '', package_height: '',
package_length: '', package_length: '',
package_width: '', package_width: '',
postingTime: '', postingTime: '',
stock: '' stock: '',
specialSale_order_limit: '',
specialSale_quantity: '',
specialSale_endDate: ''
} }
const getVariantOptions = () => { const getVariantOptions = () => {
@@ -138,6 +145,15 @@ const CreateVariant: FC = () => {
variantData = baseData variantData = baseData
} }
if (!values.sellerSpecialCode) {
variantData.sellerSpecialCode = undefined
}
// اضافه کردن فیلدهای فروش ویژه - اگر خالی بودند undefined ارسال شوند
variantData.specialSale_order_limit = values.specialSale_order_limit ? parseInt(values.specialSale_order_limit) : undefined
variantData.specialSale_quantity = values.specialSale_quantity ? parseInt(values.specialSale_quantity) : undefined
variantData.specialSale_endDate = values.specialSale_endDate || undefined
createProductVariant.mutate(variantData, { createProductVariant.mutate(variantData, {
onSuccess: () => { onSuccess: () => {
setShowModal(false) setShowModal(false)
@@ -390,6 +406,54 @@ const CreateVariant: FC = () => {
</div> </div>
</div> </div>
{/* اطلاعات فروش ویژه */}
<div className="border-t pt-4">
<h3 className="text-lg font-medium mb-4">فروش ویژه (اختیاری)</h3>
<div className="grid grid-cols-2 gap-4">
<div>
<Field name="specialSale_order_limit">
{({ field }: FormikFieldProps) => (
<Input
{...field}
label="محدودیت سفارش فروش ویژه"
placeholder="مثال: 5"
type="number"
value={field.value}
onChange={(e: React.ChangeEvent<HTMLInputElement>) => setFieldValue('specialSale_order_limit', e.target.value)}
/>
)}
</Field>
<ErrorMessage name="specialSale_order_limit" component="div" className="text-red-500 text-sm mt-1" />
</div>
<div>
<Field name="specialSale_quantity">
{({ field }: FormikFieldProps) => (
<Input
{...field}
label="تعداد فروش ویژه"
placeholder="مثال: 100"
type="number"
value={field.value}
onChange={(e: React.ChangeEvent<HTMLInputElement>) => setFieldValue('specialSale_quantity', e.target.value)}
/>
)}
</Field>
<ErrorMessage name="specialSale_quantity" component="div" className="text-red-500 text-sm mt-1" />
</div>
</div>
<div className="mt-4">
<DatePickerComponent
label="تاریخ پایان فروش ویژه"
placeholder="انتخاب تاریخ"
defaulValue={initialValues.specialSale_endDate}
onChange={(date: string) => setFieldValue('specialSale_endDate', date)}
/>
<ErrorMessage name="specialSale_endDate" component="div" className="text-red-500 text-sm mt-1" />
</div>
</div>
{/* دکمه‌ها */} {/* دکمه‌ها */}
<div className="flex gap-3 pt-4 border-t"> <div className="flex gap-3 pt-4 border-t">
<Button <Button
+42 -33
View File
@@ -40,13 +40,18 @@ const UpdateVariant: FC<UpdateVariantProps> = ({ variant, onUpdate }) => {
const validationSchema = Yup.object().shape({ const validationSchema = Yup.object().shape({
retailPrice: Yup.number().required('قیمت فروش الزامی است').min(0, 'قیمت نمی‌تواند منفی باشد'), retailPrice: Yup.number().required('قیمت فروش الزامی است').min(0, 'قیمت نمی‌تواند منفی باشد'),
order_limit: Yup.number().required('محدودیت سفارش الزامی است').min(1, 'حداقل ۱ عدد'), order_limit: Yup.number().required('محدودیت سفارش الزامی است').min(1, 'حداقل ۱ عدد'),
sellerSpecialCode: Yup.string().required('کد ویژه فروشنده الزامی است'), sellerSpecialCode: Yup.string(),
stock: Yup.number().required('موجودی انبار الزامی است').min(0, 'موجودی نمی‌تواند منفی باشد'), stock: Yup.number().required('موجودی انبار الزامی است').min(0, 'موجودی نمی‌تواند منفی باشد'),
discount_type: Yup.string().oneOf(['fixed', 'percent'], 'نوع تخفیف باید fixed یا percent باشد').required('نوع تخفیف الزامی است'), discount_type: Yup.string().oneOf(['fixed', 'percent'], 'نوع تخفیف باید fixed یا percent باشد'),
discount_value: Yup.number().when('discount_type', { discount_value: Yup.lazy((_, context) => {
is: 'fixed', const discountType = context.parent.discount_type
then: (schema) => schema.min(0, 'مقدار تخفیف نمی‌تواند منفی باشد'), if (discountType === 'fixed') {
otherwise: (schema) => schema.min(0, 'تخفیف نمی‌تواند منفی باشد').max(100, 'تخفیف نمی‌تواند بیش از ۱۰۰٪ باشد') return Yup.number().min(0, 'مقدار تخفیف نمی‌تواند منفی باشد')
} else if (discountType === 'percent') {
return Yup.number().min(0, 'تخفیف نمی‌تواند منفی باشد').max(100, 'تخفیف نمی‌تواند بیش از ۱۰۰٪ باشد')
} else {
return Yup.mixed().optional()
}
}), }),
specialSale_order_limit: Yup.number().min(0, 'محدودیت فروش ویژه نمی‌تواند منفی باشد'), specialSale_order_limit: Yup.number().min(0, 'محدودیت فروش ویژه نمی‌تواند منفی باشد'),
specialSale_quantity: Yup.number().min(0, 'تعداد فروش ویژه نمی‌تواند منفی باشد'), specialSale_quantity: Yup.number().min(0, 'تعداد فروش ویژه نمی‌تواند منفی باشد'),
@@ -58,8 +63,8 @@ const UpdateVariant: FC<UpdateVariantProps> = ({ variant, onUpdate }) => {
order_limit: variantData?.results?.productVariant?.price?.order_limit?.toString() || '', order_limit: variantData?.results?.productVariant?.price?.order_limit?.toString() || '',
sellerSpecialCode: variantData?.results?.productVariant?.sellerSpecialCode, sellerSpecialCode: variantData?.results?.productVariant?.sellerSpecialCode,
stock: variantData?.results?.productVariant?.stock?.toString() || '', stock: variantData?.results?.productVariant?.stock?.toString() || '',
discount_type: 'percent', discount_type: '',
discount_value: variantData?.results?.productVariant?.price?.discount_percent?.toString() || '0', discount_value: variantData?.results?.productVariant?.price?.discount_percent?.toString() || '',
specialSale_order_limit: variantData?.results?.productVariant?.price?.specialSale_order_limit?.toString() || '', specialSale_order_limit: variantData?.results?.productVariant?.price?.specialSale_order_limit?.toString() || '',
specialSale_quantity: variantData?.results?.productVariant?.price?.specialSale_quantity?.toString() || '', specialSale_quantity: variantData?.results?.productVariant?.price?.specialSale_quantity?.toString() || '',
specialSale_endDate: variantData?.results?.productVariant?.price?.specialSale_endDate || '' specialSale_endDate: variantData?.results?.productVariant?.price?.specialSale_endDate || ''
@@ -76,15 +81,17 @@ const UpdateVariant: FC<UpdateVariantProps> = ({ variant, onUpdate }) => {
sellerSpecialCode: values.sellerSpecialCode!, sellerSpecialCode: values.sellerSpecialCode!,
stock: parseInt(values.stock as string), stock: parseInt(values.stock as string),
saleFormat: { wholeSale: [] }, // فعلاً خالی می‌گذاریم saleFormat: { wholeSale: [] }, // فعلاً خالی می‌گذاریم
discount_type: values.discount_type as "fixed" | "percent", ...(values.discount_type ? {
...(values.discount_type === 'fixed' ? { discount_type: values.discount_type as "fixed" | "percent",
discount_value: discountValue ...(values.discount_type === 'fixed' ? {
} : { discount_value: discountValue
discount_percent: discountValue } : {
}), discount_percent: discountValue
specialSale_order_limit: parseInt(values.specialSale_order_limit as string) || 0, })
specialSale_quantity: parseInt(values.specialSale_quantity as string) || 0, } : {}),
specialSale_endDate: values.specialSale_endDate || '' specialSale_order_limit: values.specialSale_order_limit ? parseInt(values.specialSale_order_limit as string) : undefined,
specialSale_quantity: values.specialSale_quantity ? parseInt(values.specialSale_quantity as string) : undefined,
specialSale_endDate: values.specialSale_endDate || undefined
} as UpdateVariantRequestType } as UpdateVariantRequestType
updateVariant.mutate(baseData, { updateVariant.mutate(baseData, {
@@ -141,7 +148,7 @@ const UpdateVariant: FC<UpdateVariantProps> = ({ variant, onUpdate }) => {
validationSchema={validationSchema} validationSchema={validationSchema}
onSubmit={handleSubmit} onSubmit={handleSubmit}
> >
{({ setFieldValue }) => ( {({ setFieldValue, values }) => (
<Form className="space-y-4 w-[500px] mt-4"> <Form className="space-y-4 w-[500px] mt-4">
{/* اطلاعات قیمت و موجودی */} {/* اطلاعات قیمت و موجودی */}
<div className="grid grid-cols-2 gap-4"> <div className="grid grid-cols-2 gap-4">
@@ -227,21 +234,23 @@ const UpdateVariant: FC<UpdateVariantProps> = ({ variant, onUpdate }) => {
</div> </div>
</div> </div>
<div> {values.discount_type && (
<Field name="discount_value"> <div>
{({ field, form }: FormikFieldProps) => ( <Field name="discount_value">
<Input {({ field, form }: FormikFieldProps) => (
{...field} <Input
label={form.values.discount_type === 'percent' ? 'درصد تخفیف (%)' : 'مقدار تخفیف (تومان)'} {...field}
placeholder={form.values.discount_type === 'percent' ? 'مثال: 10' : 'مثال: 50000'} label={form.values.discount_type === 'percent' ? 'درصد تخفیف (%)' : 'مقدار تخفیف (تومان)'}
type="number" placeholder={form.values.discount_type === 'percent' ? 'مثال: 10' : 'مثال: 50000'}
value={field.value} type="number"
onChange={(e: React.ChangeEvent<HTMLInputElement>) => setFieldValue('discount_value', e.target.value)} value={field.value}
/> onChange={(e: React.ChangeEvent<HTMLInputElement>) => setFieldValue('discount_value', e.target.value)}
)} />
</Field> )}
<ErrorMessage name="discount_value" component="div" className="text-red-500 text-sm mt-1" /> </Field>
</div> <ErrorMessage name="discount_value" component="div" className="text-red-500 text-sm mt-1" />
</div>
)}
{/* اطلاعات فروش ویژه */} {/* اطلاعات فروش ویژه */}
<div className="border-t pt-4"> <div className="border-t pt-4">
+7 -4
View File
@@ -270,7 +270,7 @@ export type CreateProductVariantRequestType = {
meterageId?: number; meterageId?: number;
warrantyId: number; warrantyId: number;
order_limit: number; order_limit: number;
sellerSpecialCode: string; sellerSpecialCode?: string;
retail_price: number; retail_price: number;
package_weight: number; package_weight: number;
package_height: number; package_height: number;
@@ -278,6 +278,9 @@ export type CreateProductVariantRequestType = {
package_width: number; package_width: number;
postingTime: number; postingTime: number;
stock: number; stock: number;
specialSale_order_limit?: number;
specialSale_quantity?: number;
specialSale_endDate?: string;
}; };
export type CreateProductVariantResponseType = { export type CreateProductVariantResponseType = {
@@ -389,9 +392,9 @@ export type UpdateVariantRequestType = {
discount_type: "fixed" | "percent"; discount_type: "fixed" | "percent";
discount_value?: number; discount_value?: number;
discount_percent?: number; discount_percent?: number;
specialSale_order_limit: number; specialSale_order_limit?: number;
specialSale_quantity: number; specialSale_quantity?: number;
specialSale_endDate: string; specialSale_endDate?: string;
}; };
export type UpdateVariantResponseType = { export type UpdateVariantResponseType = {