return order
This commit is contained in:
@@ -44,7 +44,7 @@ const Resume: FC<ResumeProps> = ({ jobId }) => {
|
|||||||
const uploadFileMutation = useMutation({
|
const uploadFileMutation = useMutation({
|
||||||
mutationFn: api.uploadSingleFile,
|
mutationFn: api.uploadSingleFile,
|
||||||
onSuccess: (data) => {
|
onSuccess: (data) => {
|
||||||
setValue('resumeUrl', data?.results?.url?.url)
|
setValue('resumeUrl', data?.results?.data?.url?.url)
|
||||||
toast('فایل با موفقیت آپلود شد', 'success')
|
toast('فایل با موفقیت آپلود شد', 'success')
|
||||||
},
|
},
|
||||||
onError: () => {
|
onError: () => {
|
||||||
|
|||||||
@@ -36,17 +36,20 @@ export type ResumeType = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export interface FileUrl {
|
export interface FileUrl {
|
||||||
originalname: string;
|
|
||||||
size: number;
|
size: number;
|
||||||
url: string;
|
url: string;
|
||||||
type: string;
|
type: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface UploadResults {
|
export interface UploadData {
|
||||||
message: string;
|
message: string;
|
||||||
url: FileUrl;
|
url: FileUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface UploadResults {
|
||||||
|
data: UploadData;
|
||||||
|
}
|
||||||
|
|
||||||
export interface UploadResponse {
|
export interface UploadResponse {
|
||||||
status: number;
|
status: number;
|
||||||
success: boolean;
|
success: boolean;
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ interface ReturnConfirmationProps {
|
|||||||
quantities: { [key: string]: number }
|
quantities: { [key: string]: number }
|
||||||
reason: string
|
reason: string
|
||||||
description: string
|
description: string
|
||||||
images: File[]
|
images: { [key: string]: File }
|
||||||
imagePreviewUrls: string[]
|
imagePreviewUrls: { [key: string]: string }
|
||||||
returnReasons: Array<{ _id: string; title: string }>
|
returnReasons: Array<{ _id: string; title: string }>
|
||||||
onSubmit: () => void
|
onSubmit: () => void
|
||||||
onBack: () => void
|
onBack: () => void
|
||||||
@@ -39,7 +39,7 @@ const ReturnConfirmation: React.FC<ReturnConfirmationProps> = ({
|
|||||||
<div className='space-y-4'>
|
<div className='space-y-4'>
|
||||||
<h4 className='font-medium'>محصولات انتخاب شده</h4>
|
<h4 className='font-medium'>محصولات انتخاب شده</h4>
|
||||||
{selectedItems.map((item) => (
|
{selectedItems.map((item) => (
|
||||||
<div key={item._id} className='p-4 border rounded-lg'>
|
<div key={item._id} className='p-4 border rounded-lg space-y-3'>
|
||||||
<div className='flex items-center gap-4'>
|
<div className='flex items-center gap-4'>
|
||||||
<Image
|
<Image
|
||||||
src={item.product.imagesUrl.cover}
|
src={item.product.imagesUrl.cover}
|
||||||
@@ -58,6 +58,19 @@ const ReturnConfirmation: React.FC<ReturnConfirmationProps> = ({
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{/* تصویر این آیتم */}
|
||||||
|
{imagePreviewUrls[item._id] && (
|
||||||
|
<div>
|
||||||
|
<div className='text-xs text-gray-600 mb-2'>تصویر آپلود شده:</div>
|
||||||
|
<Image
|
||||||
|
src={imagePreviewUrls[item._id]}
|
||||||
|
width={100}
|
||||||
|
height={100}
|
||||||
|
className='max-w-[150px] max-h-[150px] object-contain rounded border'
|
||||||
|
alt='تصویر محصول'
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
@@ -79,26 +92,6 @@ const ReturnConfirmation: React.FC<ReturnConfirmationProps> = ({
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* تصاویر آپلود شده */}
|
|
||||||
{imagePreviewUrls.length > 0 && (
|
|
||||||
<div className='space-y-4'>
|
|
||||||
<h4 className='font-medium'>تصاویر آپلود شده</h4>
|
|
||||||
<div className='grid grid-cols-2 md:grid-cols-3 gap-4'>
|
|
||||||
{imagePreviewUrls.map((url, index) => (
|
|
||||||
<div key={index} className='relative'>
|
|
||||||
<Image
|
|
||||||
src={url}
|
|
||||||
width={100}
|
|
||||||
height={100}
|
|
||||||
className='max-w-[200px] max-h-[200px] object-contain rounded border'
|
|
||||||
alt={`تصویر ${index + 1}`}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{/* اخطار */}
|
{/* اخطار */}
|
||||||
<div className='flex gap-2 text-xs text-[#7F7F7F] p-3 bg-primary/10 rounded-lg'>
|
<div className='flex gap-2 text-xs text-[#7F7F7F] p-3 bg-primary/10 rounded-lg'>
|
||||||
<div className="size-5 bg-primary/20 rounded-full flex items-center justify-center">
|
<div className="size-5 bg-primary/20 rounded-full flex items-center justify-center">
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ interface ReturnFormData {
|
|||||||
|
|
||||||
interface ReturnFormProps {
|
interface ReturnFormProps {
|
||||||
selectedItems: ShipmentItemDetail[]
|
selectedItems: ShipmentItemDetail[]
|
||||||
onSubmit: (data: { quantities: { [key: string]: number }; reason: string; description: string; images: File[] }) => void
|
onSubmit: (data: { quantities: { [key: string]: number }; reason: string; description: string; images: { [key: string]: File } }) => void
|
||||||
onBack: () => void
|
onBack: () => void
|
||||||
isLoading: boolean
|
isLoading: boolean
|
||||||
returnReasons: Array<{ _id: string; title: string }>
|
returnReasons: Array<{ _id: string; title: string }>
|
||||||
@@ -47,9 +47,8 @@ const ReturnForm: React.FC<ReturnFormProps> = ({
|
|||||||
isLoading,
|
isLoading,
|
||||||
returnReasons
|
returnReasons
|
||||||
}) => {
|
}) => {
|
||||||
const [images, setImages] = useState<File[]>([])
|
const [images, setImages] = useState<{ [key: string]: File }>({})
|
||||||
const [imagePreviewUrls, setImagePreviewUrls] = useState<string[]>([])
|
const [imagePreviewUrls, setImagePreviewUrls] = useState<{ [key: string]: string }>({})
|
||||||
const fileInputRef = useRef<HTMLInputElement>(null)
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
register,
|
register,
|
||||||
@@ -78,30 +77,33 @@ const ReturnForm: React.FC<ReturnFormProps> = ({
|
|||||||
reset()
|
reset()
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleImageUpload = (event: React.ChangeEvent<HTMLInputElement>) => {
|
const handleImageUpload = (itemId: string, event: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
const files = Array.from(event.target.files || [])
|
const file = event.target.files?.[0]
|
||||||
const validFiles = files.filter(file => {
|
if (!file) return
|
||||||
const isValidType = file.type === 'image/jpeg' || file.type === 'image/png'
|
|
||||||
const isValidSize = file.size <= 10 * 1024 * 1024 // 10MB
|
|
||||||
return isValidType && isValidSize
|
|
||||||
})
|
|
||||||
|
|
||||||
if (validFiles.length !== files.length) {
|
const isValidType = file.type === 'image/jpeg' || file.type === 'image/png'
|
||||||
|
const isValidSize = file.size <= 10 * 1024 * 1024 // 10MB
|
||||||
|
|
||||||
|
if (!isValidType || !isValidSize) {
|
||||||
alert('فقط فایلهای JPG و PNG با حداکثر حجم ۱۰ مگابایت مجاز هستند')
|
alert('فقط فایلهای JPG و PNG با حداکثر حجم ۱۰ مگابایت مجاز هستند')
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const newImages = [...images, ...validFiles].slice(0, 5) // حداکثر ۵ عکس
|
setImages(prev => ({ ...prev, [itemId]: file }))
|
||||||
setImages(newImages)
|
setImagePreviewUrls(prev => ({ ...prev, [itemId]: URL.createObjectURL(file) }))
|
||||||
|
|
||||||
const newPreviewUrls = newImages.map(file => URL.createObjectURL(file))
|
|
||||||
setImagePreviewUrls(newPreviewUrls)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const removeImage = (index: number) => {
|
const removeImage = (itemId: string) => {
|
||||||
const newImages = images.filter((_, i) => i !== index)
|
setImages(prev => {
|
||||||
const newPreviewUrls = imagePreviewUrls.filter((_, i) => i !== index)
|
const newImages = { ...prev }
|
||||||
setImages(newImages)
|
delete newImages[itemId]
|
||||||
setImagePreviewUrls(newPreviewUrls)
|
return newImages
|
||||||
|
})
|
||||||
|
setImagePreviewUrls(prev => {
|
||||||
|
const newUrls = { ...prev }
|
||||||
|
delete newUrls[itemId]
|
||||||
|
return newUrls
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -110,12 +112,12 @@ const ReturnForm: React.FC<ReturnFormProps> = ({
|
|||||||
|
|
||||||
{/* انتخاب تعداد مرجوعی برای هر آیتم */}
|
{/* انتخاب تعداد مرجوعی برای هر آیتم */}
|
||||||
<div className='space-y-4'>
|
<div className='space-y-4'>
|
||||||
<h4 className='font-medium'>تعداد مرجوعی</h4>
|
<h4 className='font-medium'>تعداد مرجوعی و آپلود تصویر</h4>
|
||||||
{selectedItems.map((item) => {
|
{selectedItems.map((item) => {
|
||||||
const availableQuantity = item.quantity - item.cancelled_quantity - item.returned_quantity
|
const availableQuantity = item.quantity - item.cancelled_quantity - item.returned_quantity
|
||||||
return (
|
return (
|
||||||
<div key={item._id} className='p-4 border rounded-lg'>
|
<div key={item._id} className='p-4 border rounded-lg space-y-3'>
|
||||||
<div className='flex items-center gap-4 mb-2'>
|
<div className='flex items-center gap-4'>
|
||||||
<Image
|
<Image
|
||||||
src={item.product.imagesUrl.cover}
|
src={item.product.imagesUrl.cover}
|
||||||
width={40}
|
width={40}
|
||||||
@@ -143,6 +145,48 @@ const ReturnForm: React.FC<ReturnFormProps> = ({
|
|||||||
className='w-20 px-2 py-1 border rounded text-center'
|
className='w-20 px-2 py-1 border rounded text-center'
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* آپلود تصویر برای این آیتم */}
|
||||||
|
<div>
|
||||||
|
<div className='text-xs text-gray-600 mb-2'>
|
||||||
|
تصویر محصول (JPG یا PNG، حداکثر ۱۰ مگابایت)
|
||||||
|
</div>
|
||||||
|
{imagePreviewUrls[item._id] ? (
|
||||||
|
<div className='relative inline-block'>
|
||||||
|
<Image
|
||||||
|
src={imagePreviewUrls[item._id]}
|
||||||
|
width={100}
|
||||||
|
height={100}
|
||||||
|
className='max-w-[150px] max-h-[150px] object-contain rounded border'
|
||||||
|
alt='تصویر محصول'
|
||||||
|
/>
|
||||||
|
<button
|
||||||
|
type='button'
|
||||||
|
onClick={() => removeImage(item._id)}
|
||||||
|
className='absolute -top-2 -right-2 bg-red-500 text-white rounded-full w-6 h-6 flex items-center justify-center'
|
||||||
|
>
|
||||||
|
<CloseCircle color='white' size={14} />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div>
|
||||||
|
<input
|
||||||
|
type='file'
|
||||||
|
accept='image/jpeg,image/png'
|
||||||
|
onChange={(e) => handleImageUpload(item._id, e)}
|
||||||
|
className='hidden'
|
||||||
|
id={`file-${item._id}`}
|
||||||
|
/>
|
||||||
|
<label
|
||||||
|
htmlFor={`file-${item._id}`}
|
||||||
|
className='flex items-center gap-2 px-4 py-2 border-2 border-dashed border-gray-300 rounded-lg hover:border-primary transition-colors cursor-pointer inline-flex'
|
||||||
|
>
|
||||||
|
<DocumentUpload color='gray' size={20} />
|
||||||
|
<span className='text-sm'>انتخاب تصویر</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
})}
|
})}
|
||||||
@@ -178,60 +222,6 @@ const ReturnForm: React.FC<ReturnFormProps> = ({
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* آپلود عکس */}
|
|
||||||
<div>
|
|
||||||
<div className="text-sm font-medium mb-2">آپلود عکس</div>
|
|
||||||
<div className='text-xs text-gray-600 mb-3'>
|
|
||||||
اگر ایراد کالا قابل مشاهده است به صورتی عکس بگیرید که مشخص باشد (با فرمت JPG یا PNG و هر عکس حداکثر ۱۰ مگابایت)
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* نمایش عکسهای آپلود شده */}
|
|
||||||
{imagePreviewUrls.length > 0 && (
|
|
||||||
<div className='grid grid-cols-2 md:grid-cols-3 gap-4 mb-4'>
|
|
||||||
{imagePreviewUrls.map((url, index) => (
|
|
||||||
<div key={index} className='relative'>
|
|
||||||
<Image
|
|
||||||
src={url}
|
|
||||||
width={100}
|
|
||||||
height={100}
|
|
||||||
className='max-w-[200px] max-h-[200px] object-contain rounded border'
|
|
||||||
alt={`تصویر ${index + 1}`}
|
|
||||||
/>
|
|
||||||
<button
|
|
||||||
type='button'
|
|
||||||
onClick={() => removeImage(index)}
|
|
||||||
className='absolute -top-2 -right-2 bg-red-500 text-white rounded-full w-6 h-6 flex items-center justify-center'
|
|
||||||
>
|
|
||||||
<CloseCircle color='white' size={14} />
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{/* دکمه آپلود */}
|
|
||||||
{images.length < 5 && (
|
|
||||||
<div>
|
|
||||||
<input
|
|
||||||
ref={fileInputRef}
|
|
||||||
type='file'
|
|
||||||
accept='image/jpeg,image/png'
|
|
||||||
multiple
|
|
||||||
onChange={handleImageUpload}
|
|
||||||
className='hidden'
|
|
||||||
/>
|
|
||||||
<button
|
|
||||||
type='button'
|
|
||||||
onClick={() => fileInputRef.current?.click()}
|
|
||||||
className='flex items-center gap-2 px-4 py-2 border-2 border-dashed border-gray-300 rounded-lg hover:border-primary transition-colors'
|
|
||||||
>
|
|
||||||
<DocumentUpload color='gray' size={20} />
|
|
||||||
<span>انتخاب عکس</span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* دکمههای عملیات */}
|
{/* دکمههای عملیات */}
|
||||||
<div className='flex gap-3 justify-center'>
|
<div className='flex gap-3 justify-center'>
|
||||||
<Button
|
<Button
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import Layout from '@/hoc/Layout'
|
|||||||
import { type NextPage } from 'next'
|
import { type NextPage } from 'next'
|
||||||
import { useParams, useRouter } from 'next/navigation'
|
import { useParams, useRouter } from 'next/navigation'
|
||||||
import { useState } from 'react'
|
import { useState } from 'react'
|
||||||
import { useGetOrderDetail, useReturnOrder, useGetReturnReasons } from '../../hooks/useOrdersData'
|
import { useGetOrderDetail, useReturnOrder, useGetReturnReasons, useUploadReturnImage } from '../../hooks/useOrdersData'
|
||||||
import ProductSelection from './components/ProductSelection'
|
import ProductSelection from './components/ProductSelection'
|
||||||
import ReturnForm from './components/ReturnForm'
|
import ReturnForm from './components/ReturnForm'
|
||||||
import ReturnConfirmation from './components/ReturnConfirmation'
|
import ReturnConfirmation from './components/ReturnConfirmation'
|
||||||
@@ -17,7 +17,7 @@ interface FormData {
|
|||||||
quantities: { [key: string]: number }
|
quantities: { [key: string]: number }
|
||||||
reason: string
|
reason: string
|
||||||
description: string
|
description: string
|
||||||
images: File[]
|
images: { [key: string]: File }
|
||||||
}
|
}
|
||||||
|
|
||||||
const ReturnPage: NextPage = () => {
|
const ReturnPage: NextPage = () => {
|
||||||
@@ -26,11 +26,12 @@ const ReturnPage: NextPage = () => {
|
|||||||
const { data: order, isLoading: isOrderLoading } = useGetOrderDetail(id as string)
|
const { data: order, isLoading: isOrderLoading } = useGetOrderDetail(id as string)
|
||||||
const returnOrderMutation = useReturnOrder()
|
const returnOrderMutation = useReturnOrder()
|
||||||
const { data: returnReasons } = useGetReturnReasons()
|
const { data: returnReasons } = useGetReturnReasons()
|
||||||
|
const uploadImageMutation = useUploadReturnImage()
|
||||||
|
|
||||||
const [currentStep, setCurrentStep] = useState<Step>(1)
|
const [currentStep, setCurrentStep] = useState<Step>(1)
|
||||||
const [selectedItems, setSelectedItems] = useState<string[]>([])
|
const [selectedItems, setSelectedItems] = useState<string[]>([])
|
||||||
const [formData, setFormData] = useState<FormData | null>(null)
|
const [formData, setFormData] = useState<FormData | null>(null)
|
||||||
const [imagePreviewUrls, setImagePreviewUrls] = useState<string[]>([])
|
const [imagePreviewUrls, setImagePreviewUrls] = useState<{ [key: string]: string }>({})
|
||||||
|
|
||||||
const handleItemSelect = (itemId: string, checked: boolean) => {
|
const handleItemSelect = (itemId: string, checked: boolean) => {
|
||||||
if (checked) {
|
if (checked) {
|
||||||
@@ -43,7 +44,10 @@ const ReturnPage: NextPage = () => {
|
|||||||
const handleFormSubmit = (data: FormData) => {
|
const handleFormSubmit = (data: FormData) => {
|
||||||
setFormData(data)
|
setFormData(data)
|
||||||
// ایجاد preview URLs برای تصاویر
|
// ایجاد preview URLs برای تصاویر
|
||||||
const previewUrls = data.images.map(file => URL.createObjectURL(file))
|
const previewUrls: { [key: string]: string } = {}
|
||||||
|
Object.entries(data.images).forEach(([itemId, file]) => {
|
||||||
|
previewUrls[itemId] = URL.createObjectURL(file)
|
||||||
|
})
|
||||||
setImagePreviewUrls(previewUrls)
|
setImagePreviewUrls(previewUrls)
|
||||||
setCurrentStep(3)
|
setCurrentStep(3)
|
||||||
}
|
}
|
||||||
@@ -54,55 +58,65 @@ const ReturnPage: NextPage = () => {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// تبدیل تصاویر به base64 یا URL
|
try {
|
||||||
const imagePromises = formData.images.map(async (file) => {
|
const returnItems = []
|
||||||
return new Promise<string>((resolve) => {
|
|
||||||
const reader = new FileReader()
|
// آپلود تصاویر به صورت ترتیبی (یکی یکی)
|
||||||
reader.onload = () => resolve(reader.result as string)
|
for (const itemId of selectedItems) {
|
||||||
reader.readAsDataURL(file)
|
// Find the order item that contains this shipment item
|
||||||
|
const orderItem = order?.results.order.orderItems.find(orderItem =>
|
||||||
|
orderItem.shipmentItems.some(shipmentItem => shipmentItem._id === itemId)
|
||||||
|
)
|
||||||
|
|
||||||
|
const shipmentItem = orderItem?.shipmentItems.find(item => item._id === itemId)
|
||||||
|
|
||||||
|
if (!orderItem || !shipmentItem) continue
|
||||||
|
|
||||||
|
// آپلود تصویر این آیتم
|
||||||
|
let imageUrl = ''
|
||||||
|
if (formData.images[itemId]) {
|
||||||
|
try {
|
||||||
|
const response = await uploadImageMutation.mutateAsync(formData.images[itemId])
|
||||||
|
imageUrl = response.results.data.url.url
|
||||||
|
} catch (error) {
|
||||||
|
toast(`خطا در آپلود تصویر: ${extractErrorMessage(error)}`, 'error')
|
||||||
|
throw error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
returnItems.push({
|
||||||
|
orderItemId: orderItem._id,
|
||||||
|
shipmentItemId: shipmentItem._id,
|
||||||
|
quantity: formData.quantities[itemId],
|
||||||
|
comment: formData.description,
|
||||||
|
reason: formData.reason,
|
||||||
|
imagesUrl: imageUrl
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// ارسال درخواست مرجوعی به سرور
|
||||||
|
await returnOrderMutation.mutateAsync({
|
||||||
|
orderId: Number(id),
|
||||||
|
items: returnItems
|
||||||
|
}, {
|
||||||
|
onSuccess: () => {
|
||||||
|
toast('درخواست مرجوعی با موفقیت ثبت شد', 'success')
|
||||||
|
router.push(`/profile/orders/${id}/return/success`)
|
||||||
|
},
|
||||||
|
onError: (error) => {
|
||||||
|
toast(extractErrorMessage(error), 'error')
|
||||||
|
}
|
||||||
})
|
})
|
||||||
})
|
} catch (error) {
|
||||||
|
// خطا در آپلود تصاویر یا ارسال درخواست
|
||||||
const imageUrls = await Promise.all(imagePromises)
|
console.error('Error in handleFinalSubmit:', error)
|
||||||
|
}
|
||||||
const returnItems = selectedItems.map(itemId => {
|
|
||||||
// Find the order item that contains this shipment item
|
|
||||||
const orderItem = order?.results.order.orderItems.find(orderItem =>
|
|
||||||
orderItem.shipmentItems.some(shipmentItem => shipmentItem._id === itemId)
|
|
||||||
)
|
|
||||||
|
|
||||||
const shipmentItem = orderItem?.shipmentItems.find(item => item._id === itemId)
|
|
||||||
|
|
||||||
if (!orderItem || !shipmentItem) return null
|
|
||||||
|
|
||||||
return {
|
|
||||||
orderItemId: orderItem._id,
|
|
||||||
shipmentItemId: shipmentItem._id,
|
|
||||||
quantity: formData.quantities[itemId],
|
|
||||||
comment: formData.description,
|
|
||||||
reason: formData.reason,
|
|
||||||
images: imageUrls
|
|
||||||
}
|
|
||||||
}).filter(Boolean) as { orderItemId: string; shipmentItemId: string; quantity: number; comment: string; reason: string; images: string[] }[]
|
|
||||||
|
|
||||||
await returnOrderMutation.mutateAsync({
|
|
||||||
orderId: Number(id),
|
|
||||||
items: returnItems
|
|
||||||
}, {
|
|
||||||
onSuccess: () => {
|
|
||||||
toast('درخواست مرجوعی با موفقیت ثبت شد', 'success')
|
|
||||||
router.push(`/profile/orders/${id}/return/success`)
|
|
||||||
},
|
|
||||||
onError: (error) => {
|
|
||||||
toast(extractErrorMessage(error), 'error')
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleBackToStep1 = () => {
|
const handleBackToStep1 = () => {
|
||||||
setCurrentStep(1)
|
setCurrentStep(1)
|
||||||
setFormData(null)
|
setFormData(null)
|
||||||
setImagePreviewUrls([])
|
setImagePreviewUrls({})
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleBackToStep2 = () => {
|
const handleBackToStep2 = () => {
|
||||||
|
|||||||
@@ -50,3 +50,9 @@ export const useGetReturnOrder = () => {
|
|||||||
queryFn: api.getReturnOrder,
|
queryFn: api.getReturnOrder,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const useUploadReturnImage = () => {
|
||||||
|
return useMutation({
|
||||||
|
mutationFn: api.uploadReturnImage,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import {
|
|||||||
ReturnReasonsResponse,
|
ReturnReasonsResponse,
|
||||||
ReturnOrdersResponse,
|
ReturnOrdersResponse,
|
||||||
} from "../types/Types";
|
} from "../types/Types";
|
||||||
|
import { UploadResponse } from "@/app/jobs/types/Types";
|
||||||
|
|
||||||
export const getOrders = async (activeTab: string): Promise<OrdersResponse> => {
|
export const getOrders = async (activeTab: string): Promise<OrdersResponse> => {
|
||||||
const { data } = await axios.get(`/user/profile/orders?status=${activeTab}`);
|
const { data } = await axios.get(`/user/profile/orders?status=${activeTab}`);
|
||||||
@@ -45,3 +46,12 @@ export const getReturnOrder = async (): Promise<ReturnOrdersResponse> => {
|
|||||||
const { data } = await axios.get(`/returns/user`);
|
const { data } = await axios.get(`/returns/user`);
|
||||||
return data;
|
return data;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const uploadReturnImage = async (
|
||||||
|
file: File
|
||||||
|
): Promise<UploadResponse> => {
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append("image", file);
|
||||||
|
const { data } = await axios.post(`/returns/image/upload`, formData);
|
||||||
|
return data;
|
||||||
|
};
|
||||||
|
|||||||
@@ -339,7 +339,7 @@ export interface ReturnOrderItem {
|
|||||||
quantity: number;
|
quantity: number;
|
||||||
comment: string;
|
comment: string;
|
||||||
reason: string;
|
reason: string;
|
||||||
images: string[];
|
imagesUrl: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ReturnOrderType {
|
export interface ReturnOrderType {
|
||||||
|
|||||||
Reference in New Issue
Block a user