diff --git a/src/config/Pages.ts b/src/config/Pages.ts
index 2cb1106..d7dce85 100644
--- a/src/config/Pages.ts
+++ b/src/config/Pages.ts
@@ -188,6 +188,7 @@ export const Pages = {
detailUser: "/orders/detail-user/",
detailSeller: "/orders/detail-seller/",
return: "/orders/returns",
+ returnDetails: "/orders/return-details/",
},
shipment: {
list: "/shipment/list",
diff --git a/src/pages/orders/ReturnDetails.tsx b/src/pages/orders/ReturnDetails.tsx
new file mode 100644
index 0000000..6d65fca
--- /dev/null
+++ b/src/pages/orders/ReturnDetails.tsx
@@ -0,0 +1,319 @@
+import { type FC, useState } from 'react'
+import { useParams, useNavigate } from 'react-router-dom'
+import { useGetReturnDetails, useApproveReturn, useRejectReturn } from './hooks/useOrderData'
+import PageTitle from '@/components/PageTitle'
+import PageLoading from '@/components/PageLoading'
+import { formatPrice } from '@/helpers/func'
+import StatusWithText from '@/components/StatusWithText'
+import { Calendar, Money3, Box, Location, CloseCircle, TickCircle, Shop } from 'iconsax-react'
+import Button from '@/components/Button'
+import { useQueryClient } from '@tanstack/react-query'
+import ModalConfrim from '@/components/ModalConfrim'
+import { toast } from 'react-toastify'
+import { extractErrorMessage } from '@/helpers/utils'
+
+const ReturnDetails: FC = () => {
+ const { id } = useParams()
+ const navigate = useNavigate()
+ const queryClient = useQueryClient()
+ const { data, isLoading, error } = useGetReturnDetails(id!)
+ const approveReturn = useApproveReturn()
+ const rejectReturn = useRejectReturn()
+
+ const [showApproveModal, setShowApproveModal] = useState(false)
+ const [showRejectModal, setShowRejectModal] = useState(false)
+
+ const handleApprove = async () => {
+ try {
+ await approveReturn.mutateAsync(id!)
+ queryClient.invalidateQueries({ queryKey: ['return-details', id] })
+ queryClient.invalidateQueries({ queryKey: ['order-returns'] })
+ setShowApproveModal(false)
+ navigate('/orders/returns')
+ } catch (error) {
+ console.error(error)
+ }
+ }
+
+ const handleReject = async () => {
+ await rejectReturn.mutateAsync(id!, {
+ onSuccess: () => {
+ queryClient.invalidateQueries({ queryKey: ['return-details', id] })
+ queryClient.invalidateQueries({ queryKey: ['order-returns'] })
+ setShowRejectModal(false)
+ navigate('/orders/returns')
+ },
+ onError: (error) => {
+ toast.error(extractErrorMessage(error))
+ }
+ })
+ }
+
+ if (isLoading) {
+ return
+ }
+
+ if (error) {
+ return (
+
+
+
خطا در بارگذاری دادهها
+
لطفا دوباره تلاش کنید
+
+
+ )
+ }
+
+ if (!data?.results?.returnOrder) {
+ return (
+
+ )
+ }
+
+ const returnOrder = data.results.returnOrder
+
+ const getStatusVariant = (status: string): 'success' | 'error' | 'warning' => {
+ switch (status) {
+ case 'Approved':
+ return 'success'
+ case 'Rejected':
+ return 'error'
+ case 'Pending':
+ return 'warning'
+ default:
+ return 'warning'
+ }
+ }
+
+ const getStatusText = (status: string): string => {
+ switch (status) {
+ case 'Approved':
+ return 'تایید شده'
+ case 'Rejected':
+ return 'رد شده'
+ case 'Pending':
+ return 'در انتظار'
+ default:
+ return status
+ }
+ }
+
+ return (
+
+
+
+ {/* هدر */}
+
+
+
جزئیات مرجوعی
+
+
+
+ شماره سفارش: #{returnOrder.order._id}
+
+
+
+ {/* دکمههای عملیات */}
+ {data?.results?.returnOrder?.status === 'Pending' && (
+
+
+
+
+ )}
+
+ {/* کارتهای اطلاعاتی */}
+
+ {/* اطلاعات فروشگاه */}
+
+
+
+
{returnOrder.shopName}
+
+
+
+ {returnOrder.createdAt}
+
+
+
+
+
+ {/* مبلغ کل */}
+
+
+
+
+ {formatPrice(returnOrder.total_price)} تومان
+
+
+
+
+ {/* آدرس */}
+
+
+
+
{returnOrder.order.shipmentAddress.address}
+
+
استان: {returnOrder.order.shipmentAddress.province}
+
شهر: {returnOrder.order.shipmentAddress.city}
+
پلاک: {returnOrder.order.shipmentAddress.plaque}
+
کد پستی: {returnOrder.order.shipmentAddress.postalCode}
+
تلفن: {returnOrder.order.shipmentAddress.phone}
+
+
+
+
+
+ {/* آیتمهای مرجوعی */}
+
+
+
+
+
+
آیتمهای مرجوعی
+
+
+
+ {returnOrder.returnOrderItems.map((item, index) => (
+
+ {/* هدر با وضعیت */}
+
+
محصول مرجوعی
+
+
+
+ {/* اطلاعات محصول با تصویر */}
+
+
+ {/* تصویر محصول */}
+
+

+
+
+ {/* جزئیات محصول */}
+
+
{item.shipmentItem.product.title_fa}
+
+
+ تعداد مرجوعی: {item.quantity}
+
+
+ قیمت واحد: {formatPrice(item.shipmentItem.selling_price)} تومان
+
+
+ مبلغ کل: {formatPrice(item.quantity * item.shipmentItem.selling_price)} تومان
+
+ {item.shipmentItem.discount_percent > 0 && (
+
+ تخفیف: {item.shipmentItem.discount_percent}%
+
+ )}
+
+ قیمت خردهفروشی: {formatPrice(item.shipmentItem.retail_price)} تومان
+
+
+ هزینه ارسال: {formatPrice(item.shipmentItem.shipmentCost)} تومان
+
+ {item.shipmentItem.isFreeShip && (
+
+ ارسال رایگان
+
+ )}
+
+
+
+
+
+ {/* دلیل مرجوعی */}
+
+
دلیل مرجوعی:
+
{item.reason.title}
+ {item.reason.is_mandatory_picture && (
+
+ * نیازمند تصویر
+
+ )}
+ {item.reason.fineRule && (
+
+ جریمه: {item.reason.fineRule.title} ({item.reason.fineRule.fine_percentage}%)
+
+ )}
+
+
+ {/* توضیحات کاربر */}
+ {item.comment && (
+
+
توضیحات کاربر:
+
{item.comment}
+
+ )}
+
+ ))}
+
+
+
+ {/* مودالها */}
+
setShowApproveModal(false)}
+ onConfrim={handleApprove}
+ label="آیا از تایید این مرجوعی اطمینان دارید؟"
+ isLoading={approveReturn.isPending}
+ />
+
+ setShowRejectModal(false)}
+ onConfrim={handleReject}
+ label="آیا از رد این مرجوعی اطمینان دارید؟"
+ isLoading={rejectReturn.isPending}
+ />
+
+ )
+}
+
+export default ReturnDetails
\ No newline at end of file
diff --git a/src/pages/orders/Returns.tsx b/src/pages/orders/Returns.tsx
index a73e674..4071f6d 100644
--- a/src/pages/orders/Returns.tsx
+++ b/src/pages/orders/Returns.tsx
@@ -10,6 +10,8 @@ import { formatDateShort, formatPrice } from '@/helpers/func'
import { type ReturnOrderType } from '@/pages/orders/types/ReturnTypes'
import { Eye } from 'iconsax-react'
import ReturnItemsModal from '@/pages/orders/components/ReturnItemsModal'
+import { Link } from 'react-router-dom'
+import { Pages } from '@/config/Pages'
const Returns: FC = () => {
const [currentPage, setCurrentPage] = useState(1)
@@ -93,13 +95,10 @@ const Returns: FC = () => {
|
|
-
+
|
))
diff --git a/src/pages/orders/hooks/useOrderData.ts b/src/pages/orders/hooks/useOrderData.ts
index 6881eb9..267ceef 100644
--- a/src/pages/orders/hooks/useOrderData.ts
+++ b/src/pages/orders/hooks/useOrderData.ts
@@ -84,3 +84,23 @@ export const useAddTrackCode = () => {
mutationFn: api.addTrackCode,
});
};
+
+export const useGetReturnDetails = (id: string) => {
+ return useQuery({
+ queryKey: ["return-details", id],
+ queryFn: () => api.getReturnDetails(id),
+ enabled: !!id,
+ });
+};
+
+export const useApproveReturn = () => {
+ return useMutation({
+ mutationFn: api.approveReturn,
+ });
+};
+
+export const useRejectReturn = () => {
+ return useMutation({
+ mutationFn: api.rejectReturn,
+ });
+};
diff --git a/src/pages/orders/service/OrderService.ts b/src/pages/orders/service/OrderService.ts
index 174adfb..fcbe0e7 100644
--- a/src/pages/orders/service/OrderService.ts
+++ b/src/pages/orders/service/OrderService.ts
@@ -6,6 +6,7 @@ import type {
CreateReturnReasonType,
NativeOrdersResponseType,
OrderDetailResponseType,
+ ReturnOrderDetailResponseType,
ReturnReasonsResponseType,
} from "../types/Types";
@@ -86,3 +87,20 @@ export const addTrackCode = async (params: AddTrackCodeType) => {
);
return data;
};
+
+export const getReturnDetails = async (
+ id: string
+): Promise => {
+ const { data } = await axios.get(`/admin/orders/returns/${id}`);
+ return data;
+};
+
+export const approveReturn = async (id: string) => {
+ const { data } = await axios.post(`/admin/orders/returns/${id}/approve`);
+ return data;
+};
+
+export const rejectReturn = async (id: string) => {
+ const { data } = await axios.post(`/admin/orders/returns/${id}/reject`);
+ return data;
+};
diff --git a/src/pages/orders/types/Types.ts b/src/pages/orders/types/Types.ts
index 5075aef..5b2a3b6 100644
--- a/src/pages/orders/types/Types.ts
+++ b/src/pages/orders/types/Types.ts
@@ -337,3 +337,129 @@ export type CreateReturnReasonType = {
is_mandatory_picture: boolean;
fineRule: string;
};
+
+// تایپهای مربوط به جزئیات مرجوعی
+export type ReturnOrderDetailShipmentItemType = {
+ _id: string;
+ product: number;
+ 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 ReturnOrderDetailOrderItemType = {
+ _id: string;
+ order: number;
+ shop: string;
+ shipmentItems: ReturnOrderDetailShipmentItemType[];
+ 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 ReturnOrderDetailProductType = {
+ _id: number;
+ title_fa: string;
+ title_en: string;
+ seoTitle: string;
+ seoDescription: string | null;
+ model: string;
+ source: string;
+ description: string;
+ metaDescription: string;
+ tags: string[];
+ advantages: string[];
+ disAdvantages: string[];
+ totalRate: number;
+ category: string;
+ shop: string;
+ brand: string;
+ status: string;
+ adminComments: string | null;
+ step: number;
+ isFake: boolean;
+ variants: string[];
+ voice: string | null;
+ deleted: boolean;
+ specifications: unknown[];
+ createdAt: string;
+ updatedAt: string;
+ __v: number;
+ imagesUrl: ImagesUrlType;
+ rate: number;
+};
+
+export type ReturnOrderDetailReturnItemShipmentItemType = {
+ _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 ReturnOrderDetailReturnItemType = {
+ _id: string;
+ returnOrderId: string;
+ orderItem: ReturnOrderDetailOrderItemType;
+ shipmentItem: ReturnOrderDetailReturnItemShipmentItemType;
+ quantity: number;
+ comment: string;
+ reason: ReturnReasonType;
+ status: string;
+ createdAt: string;
+ updatedAt: string;
+ __v: number;
+};
+
+export type ReturnOrderDetailOrderType = {
+ _id: number;
+ user: string;
+ payment: string;
+ shipmentAddress: ShipmentAddressType;
+ orderStatus: string;
+ createdAt: string;
+ updatedAt: string;
+ __v: number;
+};
+
+export type ReturnOrderDetailType = {
+ _id: string;
+ order: ReturnOrderDetailOrderType;
+ status: string;
+ total_price: number;
+ shopName: string;
+ createdAt: string;
+ updatedAt: string;
+ returnOrderItems: ReturnOrderDetailReturnItemType[];
+};
+
+export type ReturnOrderDetailResponseType = {
+ status: number;
+ success: boolean;
+ results: {
+ returnOrder: ReturnOrderDetailType;
+ };
+};
diff --git a/src/router/Main.tsx b/src/router/Main.tsx
index 3a777c4..de916ad 100644
--- a/src/router/Main.tsx
+++ b/src/router/Main.tsx
@@ -81,6 +81,7 @@ import TicketMessages from '@/pages/ticket/TicketMessages'
import Reviews from '@/pages/products/Reviews'
import Questions from '@/pages/products/Questions'
import Returns from '@/pages/orders/Returns'
+import ReturnDetails from '@/pages/orders/ReturnDetails'
const MainRouter: FC = () => {
const { hasSubMenu } = useSharedStore()
@@ -199,6 +200,7 @@ const MainRouter: FC = () => {
} />
} />
+ } />