cancel compelete

This commit is contained in:
hamid zarghami
2025-11-08 09:25:37 +03:30
parent b3d60bd384
commit 24689bf932
9 changed files with 816 additions and 4 deletions
+1
View File
@@ -189,6 +189,7 @@ export const Pages = {
detailSeller: "/orders/detail-seller/",
return: "/orders/returns",
returnDetails: "/orders/return-details/",
cancels: "/orders/cancels",
},
shipment: {
list: "/shipment/list",
+144
View File
@@ -0,0 +1,144 @@
import PageTitle from '@/components/PageTitle'
import { type FC, useState } from 'react'
import { useGetCancels } from './hooks/useOrderData'
import PageLoading from '@/components/PageLoading'
import Error from '@/components/Error'
import PaginationUi from '@/components/PaginationUi'
import Td from '@/components/Td'
import StatusWithText from '@/components/StatusWithText'
import { formatDateShort, formatPrice } from '@/helpers/func'
import { type CancelOrderType } from '@/pages/orders/types/Types'
import { Eye } from 'iconsax-react'
import CancelItemsModal from '@/pages/orders/components/CancelItemsModal'
import { type PagerType as ProductPagerType } from '@/pages/products/types/Types'
const Cancels: FC = () => {
const [currentPage, setCurrentPage] = useState(1)
const [isModalOpen, setIsModalOpen] = useState(false)
const [selectedCancel, setSelectedCancel] = useState<CancelOrderType | null>(null)
const { data, isLoading, error } = useGetCancels(currentPage)
if (isLoading) {
return (
<div className="flex justify-center items-center min-h-[400px]">
<PageLoading />
</div>
)
}
if (error) {
return (
<div className="flex justify-center items-center min-h-[400px]">
<Error errorText="خطا در بارگذاری کنسلی‌ها" />
</div>
)
}
const cancelsOrders = data?.results?.cancelsOrders || []
const pager = data?.results?.pager
const getStatusVariant = (status: string) => {
switch (status) {
case 'Approved': return 'success'
case 'Completed': return 'success'
case 'Rejected': return 'error'
case 'Pending':
default: return 'warning'
}
}
const getStatusText = (status: string) => {
switch (status) {
case 'Approved': return 'تایید شده'
case 'Completed': return 'تکمیل شده'
case 'Rejected': return 'رد شده'
case 'Pending': return 'در انتظار'
default: return status
}
}
const handleEyeClick = (cancel: CancelOrderType) => {
setSelectedCancel(cancel)
setIsModalOpen(true)
}
return (
<div>
<PageTitle title1="کنسلی ها" />
<div className='relative overflow-x-auto rounded-3xl mt-5 w-full'>
<table className='w-full text-sm'>
<thead className='thead'>
<tr>
<Td text={'شماره سفارش'} />
<Td text={'کنسل‌کننده'} />
<Td text={'محصول'} />
<Td text={'وضعیت'} />
<Td text={'مبلغ کل'} />
<Td text={'تاریخ ثبت'} />
<Td text={'تعداد'} />
<Td text={'جزئیات'} />
</tr>
</thead>
<tbody>
{cancelsOrders.length === 0 ? (
<tr className='tr'>
<td colSpan={8} className='text-center py-8 text-muted-foreground'>
کنسلی یافت نشد
</td>
</tr>
) : (
cancelsOrders.map((cancel: CancelOrderType) => {
const totalQuantity = cancel?.cancelOrderItems?.quantity || 0
const orderId = cancel?.order?._id || null
const productName = cancel?.cancelOrderItems?.shipmentItem?.product?.title_fa || '-'
const cancellerName = cancel?.cancellerDetails?.fullName || '-'
return (
<tr key={cancel._id} className='tr'>
<Td text={orderId ? `#${orderId}` : '-'} />
<Td text={cancellerName} />
<Td text={productName} />
<Td text=''>
<StatusWithText
variant={getStatusVariant(cancel?.status)}
text={getStatusText(cancel?.status)}
/>
</Td>
<Td text={`${formatPrice(Number(cancel?.total_price || 0))} تومان`} />
<Td text={formatDateShort(cancel?.createdAt)} />
<Td text={String(totalQuantity)} />
<Td text="">
<button
onClick={() => handleEyeClick(cancel)}
className="cursor-pointer hover:opacity-70 transition-opacity"
>
<Eye size={16} color="#4B5563" />
</button>
</Td>
</tr>
)
})
)}
</tbody>
</table>
</div>
<PaginationUi
pager={pager ? {
...pager,
nextPage: pager.nextPage ? String(pager.nextPage) : null,
} as ProductPagerType : null}
onPageChange={(page) => setCurrentPage(page)}
/>
<CancelItemsModal
open={isModalOpen}
close={() => { setIsModalOpen(false); setSelectedCancel(null); }}
data={selectedCancel}
/>
</div>
)
}
export default Cancels
@@ -0,0 +1,375 @@
import { type FC, Fragment, useState } from 'react'
import DefaulModal from '@/components/DefaulModal'
import StatusWithText from '@/components/StatusWithText'
import { formatDateShort, formatPrice } from '@/helpers/func'
import { type CancelOrderType } from '@/pages/orders/types/Types'
import Button from '@/components/Button'
import { DocumentUpload } from 'iconsax-react'
import CompleteCancelModal from '@/pages/orders/components/CompleteCancelModal'
type Props = {
open: boolean
close: () => void
data: CancelOrderType | null
}
const getStatusVariant = (status: string) => {
switch (status) {
case 'Approved': return 'success'
case 'Completed': return 'success'
case 'Rejected': return 'error'
case 'Pending':
default: return 'warning'
}
}
const getStatusText = (status: string) => {
switch (status) {
case 'Approved': return 'تایید شده'
case 'Completed': return 'تکمیل شده'
case 'Rejected': return 'رد شده'
case 'Pending': return 'در انتظار'
default: return status
}
}
const CancelItemsModal: FC<Props> = ({ open, close, data }) => {
const cancelItem = data?.cancelOrderItems
const [isCompleteModalOpen, setIsCompleteModalOpen] = useState(false)
return (
<DefaulModal open={open} close={close} isHeader title_header='جزئیات کنسلی' width={900}>
{!data ? (
<div className='py-6 text-center text-muted-foreground'>دادهای برای نمایش وجود ندارد</div>
) : (
<Fragment>
{data.status === 'Pending' && (
<div className='flex justify-end my-4'>
<Button
onClick={() => setIsCompleteModalOpen(true)}
className='bg-blue-600 hover:bg-blue-700 text-white w-fit'
>
<div className='flex items-center gap-2'>
<DocumentUpload color='#fff' size={18} />
<span>تکمیل کنسلی</span>
</div>
</Button>
</div>
)}
{/* اطلاعات سفارش */}
<div className='my-4'>
<h3 className='text-base font-semibold mb-3'>اطلاعات سفارش</h3>
<div className='grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-3'>
<div className='p-2 rounded-lg border border-border'>
<div className='text-[11px] text-muted-foreground'>شماره سفارش</div>
<div className='mt-0.5 text-sm font-medium'>
{data.order?._id ? `#${data.order._id}` : '-'}
</div>
</div>
<div className='p-2 rounded-lg border border-border'>
<div className='text-[11px] text-muted-foreground'>وضعیت سفارش</div>
<div className='mt-0.5 text-sm font-medium'>
{data.order?.orderStatus || '-'}
</div>
</div>
<div className='p-2 rounded-lg border border-border'>
<div className='text-[11px] text-muted-foreground'>وضعیت کنسلی</div>
<div className='mt-0.5'>
<StatusWithText variant={getStatusVariant(data.status)} text={getStatusText(data.status)} />
</div>
</div>
<div className='p-2 rounded-lg border border-border'>
<div className='text-[11px] text-muted-foreground'>مبلغ کل</div>
<div className='mt-0.5 text-sm font-medium'>{formatPrice(Number(data.total_price || 0))} تومان</div>
</div>
<div className='p-2 rounded-lg border border-border'>
<div className='text-[11px] text-muted-foreground'>تاریخ ثبت کنسلی</div>
<div className='mt-0.5 text-sm font-medium'>{formatDateShort(data.createdAt)}</div>
</div>
{data.cancellDate && (
<div className='p-2 rounded-lg border border-border'>
<div className='text-[11px] text-muted-foreground'>تاریخ تایید کنسلی</div>
<div className='mt-0.5 text-sm font-medium'>{formatDateShort(data.cancellDate)}</div>
</div>
)}
</div>
</div>
{/* اطلاعات کنسل‌کننده */}
{data.cancellerDetails && (
<div className='mb-4'>
<h3 className='text-base font-semibold mb-3'>اطلاعات کنسلکننده</h3>
<div className='grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-3'>
<div className='p-2 rounded-lg border border-border'>
<div className='text-[11px] text-muted-foreground'>نام</div>
<div className='mt-0.5 text-sm font-medium'>
{data.cancellerDetails.fullName || '-'}
</div>
</div>
<div className='p-2 rounded-lg border border-border'>
<div className='text-[11px] text-muted-foreground'>شماره تماس</div>
<div className='mt-0.5 text-sm font-medium'>
{data.cancellerDetails.phoneNumber || '-'}
</div>
</div>
<div className='p-2 rounded-lg border border-border'>
<div className='text-[11px] text-muted-foreground'>نوع کنسلکننده</div>
<div className='mt-0.5 text-sm font-medium'>
{data.cancellerRef === 'User' ? 'کاربر' : data.cancellerRef || '-'}
</div>
</div>
</div>
</div>
)}
{/* آدرس ارسال */}
{data.order?.shipmentAddress && (
<div className='mb-4'>
<h3 className='text-base font-semibold mb-3'>آدرس ارسال</h3>
<div className='grid grid-cols-1 md:grid-cols-2 gap-3'>
<div className='p-2 rounded-lg border border-border'>
<div className='text-[11px] text-muted-foreground'>شهر</div>
<div className='mt-0.5 text-sm font-medium'>
{data.order.shipmentAddress.city || '-'}
</div>
</div>
<div className='p-2 rounded-lg border border-border'>
<div className='text-[11px] text-muted-foreground'>استان</div>
<div className='mt-0.5 text-sm font-medium'>
{data.order.shipmentAddress.province || '-'}
</div>
</div>
<div className='p-2 rounded-lg border border-border col-span-full'>
<div className='text-[11px] text-muted-foreground'>آدرس کامل</div>
<div className='mt-0.5 text-sm font-medium'>
{data.order.shipmentAddress.address || '-'}
</div>
</div>
<div className='p-2 rounded-lg border border-border'>
<div className='text-[11px] text-muted-foreground'>کد پستی</div>
<div className='mt-0.5 text-sm font-medium'>
{data.order.shipmentAddress.postalCode || '-'}
</div>
</div>
<div className='p-2 rounded-lg border border-border'>
<div className='text-[11px] text-muted-foreground'>تلفن</div>
<div className='mt-0.5 text-sm font-medium'>
{data.order.shipmentAddress.phone || '-'}
</div>
</div>
</div>
</div>
)}
{/* اطلاعات محصول کنسل‌شده */}
{cancelItem && (
<div className='mb-4'>
<h3 className='text-base font-semibold mb-3'>اطلاعات محصول کنسلشده</h3>
{/* کارت محصول */}
<div className='p-4 rounded-lg border border-border mb-4'>
<div className='flex gap-4'>
{cancelItem.shipmentItem?.product?.imagesUrl?.cover && (
<img
src={cancelItem.shipmentItem.product.imagesUrl.cover}
alt={cancelItem.shipmentItem.product.title_fa}
className='w-24 h-24 object-cover rounded-lg'
/>
)}
<div className='flex-1'>
<h4 className='font-medium mb-2'>
{cancelItem.shipmentItem?.product?.title_fa || '-'}
</h4>
<div className='grid grid-cols-2 md:grid-cols-3 gap-2 text-xs'>
<div>
<span className='text-muted-foreground'>قیمت فروش: </span>
<span className='font-medium'>
{formatPrice(cancelItem.shipmentItem?.selling_price || 0)} تومان
</span>
</div>
<div>
<span className='text-muted-foreground'>قیمت خردهفروشی: </span>
<span className='font-medium'>
{formatPrice(cancelItem.shipmentItem?.retail_price || 0)} تومان
</span>
</div>
<div>
<span className='text-muted-foreground'>هزینه ارسال: </span>
<span className='font-medium'>
{cancelItem.shipmentItem?.isFreeShip
? 'رایگان'
: `${formatPrice(cancelItem.shipmentItem?.shipmentCost || 0)} تومان`}
</span>
</div>
<div>
<span className='text-muted-foreground'>تعداد سفارش: </span>
<span className='font-medium'>{cancelItem.shipmentItem?.quantity || 0}</span>
</div>
<div>
<span className='text-muted-foreground'>تعداد کنسلشده: </span>
<span className='font-medium text-red-600'>
{cancelItem.shipmentItem?.cancelled_quantity || 0}
</span>
</div>
<div>
<span className='text-muted-foreground'>تعداد مرجوعشده: </span>
<span className='font-medium text-orange-600'>
{cancelItem.shipmentItem?.returned_quantity || 0}
</span>
</div>
{cancelItem.shipmentItem?.discount_percent !== undefined && cancelItem.shipmentItem?.discount_percent > 0 && (
<div>
<span className='text-muted-foreground'>درصد تخفیف: </span>
<span className='font-medium text-green-600'>
{cancelItem.shipmentItem.discount_percent}%
</span>
</div>
)}
</div>
</div>
</div>
</div>
{/* اطلاعات فروشگاه و وضعیت */}
<div className='grid grid-cols-1 md:grid-cols-3 gap-3 mb-4'>
{cancelItem.orderItem?.shipmentItems?.product?.shop?.shopName && (
<div className='p-2 rounded-lg border border-border'>
<div className='text-[11px] text-muted-foreground'>نام فروشگاه</div>
<div className='mt-0.5 text-sm font-medium'>
{cancelItem.orderItem.shipmentItems.product.shop.shopName}
</div>
</div>
)}
{cancelItem.orderItem?.shipmentItems?.product?.shop?.shopCode && (
<div className='p-2 rounded-lg border border-border'>
<div className='text-[11px] text-muted-foreground'>کد فروشگاه</div>
<div className='mt-0.5 text-sm font-medium'>
{cancelItem.orderItem.shipmentItems.product.shop.shopCode}
</div>
</div>
)}
{cancelItem.orderItem?.status && (
<div className='p-2 rounded-lg border border-border'>
<div className='text-[11px] text-muted-foreground'>وضعیت آیتم سفارش</div>
<div className='mt-0.5 text-sm font-medium'>
{cancelItem.orderItem.status}
</div>
</div>
)}
</div>
{/* دلیل و توضیحات کنسلی */}
<div className='grid grid-cols-1 gap-3'>
<div className='p-2 rounded-lg border border-border'>
<div className='text-[11px] text-muted-foreground'>دلیل کنسلی</div>
<div className='mt-0.5 text-sm font-medium'>
{cancelItem.reason?.title || '-'}
</div>
</div>
{cancelItem.comment && (
<div className='p-2 rounded-lg border border-border'>
<div className='text-[11px] text-muted-foreground'>توضیحات کاربر</div>
<div className='mt-0.5 text-sm font-medium'>
{cancelItem.comment}
</div>
</div>
)}
{data.cancellComment && (
<div className='p-2 rounded-lg border border-border'>
<div className='text-[11px] text-muted-foreground'>توضیحات ادمین</div>
<div className='mt-0.5 text-sm font-medium'>
{data.cancellComment}
</div>
</div>
)}
</div>
</div>
)}
{/* اطلاعات ارسال */}
{cancelItem?.orderItem && (
<div className='mb-4'>
<h3 className='text-base font-semibold mb-3'>اطلاعات ارسال</h3>
<div className='grid grid-cols-1 md:grid-cols-3 gap-3'>
<div className='p-2 rounded-lg border border-border'>
<div className='text-[11px] text-muted-foreground'>روش ارسال</div>
<div className='mt-0.5 text-sm font-medium'>
{cancelItem.orderItem.shipper || '-'}
</div>
</div>
{cancelItem.orderItem.trackCode && (
<div className='p-2 rounded-lg border border-border'>
<div className='text-[11px] text-muted-foreground'>کد رهگیری</div>
<div className='mt-0.5 text-sm font-medium'>
{cancelItem.orderItem.trackCode}
</div>
</div>
)}
{cancelItem.orderItem.postingDate && (
<div className='p-2 rounded-lg border border-border'>
<div className='text-[11px] text-muted-foreground'>تاریخ ارسال</div>
<div className='mt-0.5 text-sm font-medium'>
{formatDateShort(cancelItem.orderItem.postingDate)}
</div>
</div>
)}
<div className='p-2 rounded-lg border border-border'>
<div className='text-[11px] text-muted-foreground'>تعداد آیتمها</div>
<div className='mt-0.5 text-sm font-medium'>
{cancelItem.orderItem.itemsCount || 0}
</div>
</div>
</div>
</div>
)}
{/* اطلاعات مالی */}
{cancelItem?.orderItem && (
<div className='mb-4'>
<h3 className='text-base font-semibold mb-3'>اطلاعات مالی</h3>
<div className='grid grid-cols-2 md:grid-cols-4 gap-3'>
<div className='p-2 rounded-lg border border-border'>
<div className='text-[11px] text-muted-foreground'>مبلغ فروش</div>
<div className='mt-0.5 text-sm font-medium'>
{formatPrice(cancelItem.orderItem.totalSellingPrice || 0)} تومان
</div>
</div>
<div className='p-2 rounded-lg border border-border'>
<div className='text-[11px] text-muted-foreground'>هزینه ارسال</div>
<div className='mt-0.5 text-sm font-medium'>
{formatPrice(cancelItem.orderItem.totalShipmentCost || 0)} تومان
</div>
</div>
<div className='p-2 rounded-lg border border-border'>
<div className='text-[11px] text-muted-foreground'>تخفیف کوپن</div>
<div className='mt-0.5 text-sm font-medium'>
{formatPrice(cancelItem.orderItem.totalCouponDiscount || 0)} تومان
</div>
</div>
<div className='p-2 rounded-lg border border-border'>
<div className='text-[11px] text-muted-foreground'>مبلغ نهایی</div>
<div className='mt-0.5 text-sm font-medium'>
{formatPrice(cancelItem.orderItem.totalPaymentPrice || 0)} تومان
</div>
</div>
</div>
</div>
)}
</Fragment>
)}
<CompleteCancelModal
open={isCompleteModalOpen}
onClose={() => setIsCompleteModalOpen(false)}
cancelId={data?._id ?? ''}
onSuccess={() => {
setIsCompleteModalOpen(false)
close()
}}
/>
</DefaulModal>
)
}
export default CancelItemsModal
@@ -0,0 +1,137 @@
import { type FC, useEffect, useState } from 'react'
import DefaulModal from '@/components/DefaulModal'
import DatePicker from '@/components/DatePicker'
import Textarea from '@/components/Textarea'
import UploadBox from '@/components/UploadBox'
import Button from '@/components/Button'
import { useCompleteCancel } from '@/pages/orders/hooks/useOrderData'
import { useUploadSingle } from '@/pages/uploader/hooks/useUploaderData'
import { useQueryClient } from '@tanstack/react-query'
import { toast } from 'react-toastify'
import { extractErrorMessage } from '@/helpers/utils'
type Props = {
open: boolean
onClose: () => void
cancelId: string
onSuccess?: () => void
}
const CompleteCancelModal: FC<Props> = ({ open, onClose, cancelId, onSuccess }) => {
const [refundDate, setRefundDate] = useState('')
const [refundComment, setRefundComment] = useState('')
const [refundReceiptFile, setRefundReceiptFile] = useState<File[]>([])
const [isUploading, setIsUploading] = useState(false)
const completeCancel = useCompleteCancel()
const uploadSingle = useUploadSingle()
const queryClient = useQueryClient()
const resetForm = () => {
setRefundDate('')
setRefundComment('')
setRefundReceiptFile([])
setIsUploading(false)
}
useEffect(() => {
if (!open) {
resetForm()
}
}, [open])
const handleClose = () => {
resetForm()
onClose()
}
const handleSubmit = async () => {
if (!cancelId) {
toast.error('شناسه کنسلی نامعتبر است')
return
}
try {
setIsUploading(true)
let receiptUrl = ''
if (refundReceiptFile.length > 0) {
const uploadResponse = await uploadSingle.mutateAsync(refundReceiptFile[0])
receiptUrl = uploadResponse?.results?.url?.url || ''
}
await completeCancel.mutateAsync({
id: cancelId,
params: {
refundDate,
refundComment,
refundReceipt: receiptUrl,
},
})
await queryClient.invalidateQueries({ queryKey: ['cancels'] })
toast.success('کنسلی با موفقیت تکمیل شد')
handleClose()
onSuccess?.()
} catch (error) {
toast.error(extractErrorMessage(error))
} finally {
setIsUploading(false)
}
}
return (
<DefaulModal
open={open}
close={handleClose}
isHeader
title_header='تکمیل کنسلی'
>
<div className='space-y-4 mt-4 w-full sm:w-[420px]'>
<div>
<DatePicker
label='تاریخ بازگشت وجه'
placeholder='تاریخ را انتخاب کنید'
onChange={(date) => setRefundDate(date)}
defaulValue={refundDate}
/>
</div>
<Textarea
label='توضیحات بازگشت وجه'
placeholder='توضیحات را وارد کنید'
value={refundComment}
onChange={(event) => setRefundComment(event.target.value)}
rows={4}
/>
<UploadBox
label='رسید بازگشت وجه'
onChange={(files) => setRefundReceiptFile(files)}
isReset={!open}
/>
<div className='flex justify-end items-center pt-4'>
<div className='flex gap-3'>
<Button
onClick={handleClose}
className='bg-gray-200 hover:bg-gray-300 text-gray-700 w-fit'
>
انصراف
</Button>
<Button
onClick={handleSubmit}
className='bg-blue-600 hover:bg-blue-700 text-white w-fit'
disabled={!refundDate || !refundComment || isUploading || completeCancel.isPending}
>
{isUploading || completeCancel.isPending ? 'در حال انجام...' : 'تکمیل کنسلی'}
</Button>
</div>
</div>
</div>
</DefaulModal>
)
}
export default CompleteCancelModal
+15
View File
@@ -2,6 +2,7 @@ import { useMutation, useQuery } from "@tanstack/react-query";
import * as api from "../service/OrderService";
import { useSharedStore } from "@/shared/store/sharedStore";
import type { CompleteReturnType } from "../types/ReturnTypes";
import type { CompleteCancelType } from "../types/Types";
export const useGetNativeOrders = (
page: number = 1,
@@ -112,3 +113,17 @@ export const useCompleteReturn = () => {
api.compeleteReturn(id, params),
});
};
export const useGetCancels = (page: number = 1) => {
return useQuery({
queryKey: ["cancels", page],
queryFn: () => api.getCancels(page),
});
};
export const useCompleteCancel = () => {
return useMutation({
mutationFn: ({ id, params }: { id: string; params: CompleteCancelType }) =>
api.completeCancel(id, params),
});
};
+22
View File
@@ -5,6 +5,8 @@ import type {
} from "../types/ReturnTypes";
import type {
CancelReasonsResponseType,
CancelsResponseType,
CompleteCancelType,
CreateCancelReasonType,
CreateReturnReasonType,
NativeOrdersResponseType,
@@ -118,3 +120,23 @@ export const compeleteReturn = async (
);
return data;
};
export const getCancels = async (
page: number = 1
): Promise<CancelsResponseType> => {
const { data } = await axios.get(`/admin/orders/cancel`, {
params: { page },
});
return data;
};
export const completeCancel = async (
id: string,
params: CompleteCancelType
) => {
const { data } = await axios.post(
`/admin/orders/cancel/${id}/complete`,
params
);
return data;
};
+111 -1
View File
@@ -209,7 +209,7 @@ export type PagerType = {
totalItems: number;
totalPages: number;
prevPage: boolean | null;
nextPage: string | null;
nextPage: boolean | null;
};
export type OrdersResponseType = {
@@ -464,3 +464,113 @@ export type ReturnOrderDetailResponseType = {
returnOrder: ReturnOrderDetailType;
};
};
// تایپ‌های مربوط به کنسلی‌ها
export type CancellerDetailsType = {
_id: string;
fullName: string;
phoneNumber: string;
dateOfBirth: string | null;
address: string;
nationalCode: string | null;
homeNumber: string | null;
createdAt: string;
updatedAt: string;
__v: number;
};
export type CancelOrderOrderType = {
_id: number;
user: string;
payment: string;
shipmentAddress: ShipmentAddressType;
orderStatus: string;
createdAt: string;
updatedAt: string;
__v: number;
};
export type CancelOrderItemOrderItemType = {
_id: string;
order: number;
shop: string;
shipmentItems: {
product: {
shop: ShopType;
};
};
shipper: number;
totalSellingPrice: number;
totalRetailPrice: number;
totalShipmentCost: number;
totalCouponDiscount: number;
totalPaymentPrice: number;
itemsCount: number;
trackCode: string | null;
postingDate: string | null;
postingReceipt: string | null;
status: string;
createdAt: string;
updatedAt: string;
__v: number;
};
export type CancelOrderItemShipmentItemType = {
_id: string;
product: ReturnOrderDetailProductType;
variant: string;
quantity: number;
cancelled_quantity: number;
returned_quantity: number;
selling_price: number;
retail_price: number;
discount_percent: number;
shipmentCost: number;
isFreeShip: boolean;
};
export type CancelOrderItemType = {
quantity: number;
comment: string;
reason: CancelReasonType;
_id: string;
cancelOrderId: string;
orderItem: CancelOrderItemOrderItemType;
shipmentItem: CancelOrderItemShipmentItemType;
status: string;
createdAt: string;
updatedAt: string;
__v: number;
};
export type CancelOrderType = {
_id: string;
order: CancelOrderOrderType;
status: string;
total_price: number;
createdAt: string;
updatedAt: string;
cancelOrderItems: CancelOrderItemType;
canceller: string;
cancellerRef: string;
cancellReceipt: string | null;
cancellComment: string | null;
cancellDate: string | null;
__v: number;
cancellerDetails: CancellerDetailsType;
};
export type CancelsResponseType = {
status: number;
success: boolean;
results: {
pager: PagerType;
cancelsOrders: CancelOrderType[];
};
};
export type CompleteCancelType = {
refundDate: string;
refundComment: string;
refundReceipt: string;
};
+2
View File
@@ -82,6 +82,7 @@ import Reviews from '@/pages/products/Reviews'
import Questions from '@/pages/products/Questions'
import Returns from '@/pages/orders/Returns'
import ReturnDetails from '@/pages/orders/ReturnDetails'
import Cancels from '@/pages/orders/Cancels'
const MainRouter: FC = () => {
const { hasSubMenu } = useSharedStore()
@@ -201,6 +202,7 @@ const MainRouter: FC = () => {
<Route path={Pages.orders.return} element={<Returns />} />
<Route path={`${Pages.orders.returnDetails}:id`} element={<ReturnDetails />} />
<Route path={Pages.orders.cancels} element={<Cancels />} />
</Routes>
</div>
</div>
+9 -3
View File
@@ -22,13 +22,13 @@ const OrdersSubMenu: FC = () => {
</div>
<div className='flex flex-col mt-10 gap-4'>
<SubMenuItem
{/* <SubMenuItem
title={'لیست سفارشات (فروشندگان)'}
isActive={isActive('/seller')}
link={Pages.orders.sellers}
/>
/> */}
<SubMenuItem
title={'لیست سفارشات (مدیر)'}
title={'همه ی سفارشات'}
isActive={isActive('Admin')}
link={Pages.orders.admin}
/>
@@ -58,6 +58,12 @@ const OrdersSubMenu: FC = () => {
isActive={isActive('return')}
link={Pages.orders.return}
/>
<SubMenuItem
title={'کنسلی ها'}
isActive={isActive('cancels')}
link={Pages.orders.cancels}
/>
</div>
</div>
)