cancel order
This commit is contained in:
@@ -0,0 +1,108 @@
|
|||||||
|
'use client'
|
||||||
|
import React from 'react'
|
||||||
|
import { useForm } from 'react-hook-form'
|
||||||
|
import { yupResolver } from '@hookform/resolvers/yup'
|
||||||
|
import * as yup from 'yup'
|
||||||
|
import Select from '@/components/Select'
|
||||||
|
import { Button } from '@/components/ui/button'
|
||||||
|
|
||||||
|
interface CancelFormData {
|
||||||
|
reason: string
|
||||||
|
description: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface CancelFormProps {
|
||||||
|
onSubmit: (data: CancelFormData) => void
|
||||||
|
isLoading: boolean
|
||||||
|
cancelReasons: Array<{ _id: string; title: string }>
|
||||||
|
selectedItemsCount: number
|
||||||
|
}
|
||||||
|
|
||||||
|
const cancelFormSchema = yup.object({
|
||||||
|
reason: yup.string().required('دلیل لغو سفارش را انتخاب کنید'),
|
||||||
|
description: yup.string().required('توضیحات را وارد کنید').min(10, 'توضیحات باید حداقل ۱۰ کاراکتر باشد')
|
||||||
|
})
|
||||||
|
|
||||||
|
const CancelForm: React.FC<CancelFormProps> = ({
|
||||||
|
onSubmit,
|
||||||
|
isLoading,
|
||||||
|
cancelReasons,
|
||||||
|
selectedItemsCount
|
||||||
|
}) => {
|
||||||
|
const {
|
||||||
|
register,
|
||||||
|
handleSubmit,
|
||||||
|
watch,
|
||||||
|
setValue,
|
||||||
|
formState: { errors },
|
||||||
|
reset
|
||||||
|
} = useForm<CancelFormData>({
|
||||||
|
resolver: yupResolver(cancelFormSchema)
|
||||||
|
})
|
||||||
|
|
||||||
|
const handleFormSubmit = (data: CancelFormData) => {
|
||||||
|
onSubmit(data)
|
||||||
|
reset()
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className='space-y-6'>
|
||||||
|
<h3 className='text-lg font-semibold'>دلیل لغو و توضیحات</h3>
|
||||||
|
|
||||||
|
<form onSubmit={handleSubmit(handleFormSubmit)} className='space-y-6'>
|
||||||
|
<Select
|
||||||
|
placeholder='دلیل لغو سفارش'
|
||||||
|
items={cancelReasons.map((item) => ({
|
||||||
|
label: item.title,
|
||||||
|
value: item._id
|
||||||
|
}))}
|
||||||
|
className='bg-white border'
|
||||||
|
value={watch('reason')}
|
||||||
|
name='reason'
|
||||||
|
onChange={(e) => setValue('reason', e.target.value)}
|
||||||
|
error_text={errors.reason?.message}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<div className="text-sm font-medium mb-2">توضیحات :</div>
|
||||||
|
<textarea
|
||||||
|
{...register('description')}
|
||||||
|
className='h-[123px] rounded-xl p-3 text-sm border w-full resize-none focus:outline-none focus:ring-2 focus:ring-primary/20'
|
||||||
|
placeholder='متن توضیحات خود را بنویسید (حداقل ۱۰ کاراکتر)'
|
||||||
|
/>
|
||||||
|
{errors.description && (
|
||||||
|
<div className='text-xs text-red-500 mt-1'>
|
||||||
|
{errors.description.message}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<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">
|
||||||
|
<span className="text-primary text-xs">!</span>
|
||||||
|
</div>
|
||||||
|
<span>
|
||||||
|
توجه داشته باشید که بعد از ثبت لغو سفارش طبق
|
||||||
|
</span>
|
||||||
|
<span className='text-primary font-medium'>
|
||||||
|
جدول جرائم
|
||||||
|
</span>
|
||||||
|
<span>
|
||||||
|
جریمه میشود
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
type="submit"
|
||||||
|
className='w-full'
|
||||||
|
disabled={isLoading || selectedItemsCount === 0}
|
||||||
|
isLoading={isLoading}
|
||||||
|
>
|
||||||
|
لغو سفارش ({selectedItemsCount} آیتم)
|
||||||
|
</Button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default CancelForm
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
'use client'
|
||||||
|
import React from 'react'
|
||||||
|
import Image from 'next/image'
|
||||||
|
import { Checkbox } from '@/components/ui/checkbox'
|
||||||
|
import { ShipmentItemDetail } from '../../../types/Types'
|
||||||
|
|
||||||
|
interface ProductSelectionProps {
|
||||||
|
items: ShipmentItemDetail[]
|
||||||
|
selectedItems: string[]
|
||||||
|
onItemSelect: (itemId: string, checked: boolean) => void
|
||||||
|
}
|
||||||
|
|
||||||
|
const ProductSelection: React.FC<ProductSelectionProps> = ({
|
||||||
|
items,
|
||||||
|
selectedItems,
|
||||||
|
onItemSelect
|
||||||
|
}) => {
|
||||||
|
return (
|
||||||
|
<div className='space-y-4'>
|
||||||
|
<h3 className='mb-4'>انتخاب آیتمهای مورد نظر برای کنسل کردن</h3>
|
||||||
|
{items.map((item) => {
|
||||||
|
const availableQuantity = item.quantity - item.cancelled_quantity - item.returned_quantity
|
||||||
|
const canCancel = availableQuantity > 0
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div key={item._id} className={`p-4 border rounded-lg ${!canCancel ? 'opacity-50' : ''}`}>
|
||||||
|
<div className='flex items-start gap-4'>
|
||||||
|
<Checkbox
|
||||||
|
id={item._id}
|
||||||
|
checked={selectedItems.includes(item._id)}
|
||||||
|
onCheckedChange={(checked) => onItemSelect(item._id, checked as boolean)}
|
||||||
|
disabled={!canCancel}
|
||||||
|
className='mt-1'
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Image
|
||||||
|
src={item.product.imagesUrl.cover}
|
||||||
|
width={60}
|
||||||
|
height={60}
|
||||||
|
className='w-15 h-15 object-cover rounded-lg border flex-shrink-0'
|
||||||
|
alt={item.product.title_fa}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div className='flex-1 min-w-0'>
|
||||||
|
<div className='font-medium truncate'>
|
||||||
|
{item.product.title_fa}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className='mt-2 text-sm text-gray-600 space-y-1'>
|
||||||
|
<div>تعداد کل: {item.quantity}</div>
|
||||||
|
<div>قابل کنسل: {availableQuantity}</div>
|
||||||
|
<div className='text-primary font-medium'>
|
||||||
|
{Intl.NumberFormat('fa-IR').format(item.selling_price)} تومان
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{!canCancel && (
|
||||||
|
<div className='text-xs text-red-500 mt-2'>
|
||||||
|
این آیتم قابل کنسل کردن نیست
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ProductSelection
|
||||||
@@ -0,0 +1,131 @@
|
|||||||
|
'use client'
|
||||||
|
import Layout from '@/hoc/Layout'
|
||||||
|
import { type NextPage } from 'next'
|
||||||
|
import { useParams, useRouter } from 'next/navigation'
|
||||||
|
import { useState } from 'react'
|
||||||
|
import { useGetOrderDetail, useCancelOrder, useGetCancelReasons } from '../../hooks/useOrdersData'
|
||||||
|
import ProductSelection from './components/ProductSelection'
|
||||||
|
import CancelForm from './components/CancelForm'
|
||||||
|
import { toast } from '@/components/Toast'
|
||||||
|
import { extractErrorMessage } from '@/helpers/errorUtils'
|
||||||
|
|
||||||
|
const CancelOrderPage: NextPage = () => {
|
||||||
|
const { id } = useParams()
|
||||||
|
const router = useRouter()
|
||||||
|
const { data: order, isLoading: isOrderLoading } = useGetOrderDetail(id as string)
|
||||||
|
const cancelOrderMutation = useCancelOrder()
|
||||||
|
const { data: cancelReasons } = useGetCancelReasons()
|
||||||
|
const [selectedItems, setSelectedItems] = useState<string[]>([])
|
||||||
|
|
||||||
|
const handleItemSelect = (itemId: string, checked: boolean) => {
|
||||||
|
if (checked) {
|
||||||
|
setSelectedItems(prev => [...prev, itemId])
|
||||||
|
} else {
|
||||||
|
setSelectedItems(prev => prev.filter(id => id !== itemId))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleCancelSubmit = async (formData: { reason: string; description: string }) => {
|
||||||
|
if (selectedItems.length === 0) {
|
||||||
|
toast('هیچ آیتمی انتخاب نشده است', 'error')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const cancelItems = 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
|
||||||
|
|
||||||
|
const availableQuantity = shipmentItem.quantity - shipmentItem.cancelled_quantity - shipmentItem.returned_quantity
|
||||||
|
|
||||||
|
return {
|
||||||
|
orderItemId: orderItem._id,
|
||||||
|
shipmentItemId: shipmentItem._id,
|
||||||
|
quantity: availableQuantity,
|
||||||
|
comment: formData.description,
|
||||||
|
reason: formData.reason
|
||||||
|
}
|
||||||
|
}).filter(Boolean) as { orderItemId: string; shipmentItemId: string; quantity: number; comment: string; reason: string }[]
|
||||||
|
|
||||||
|
await cancelOrderMutation.mutateAsync({
|
||||||
|
orderId: Number(id),
|
||||||
|
items: cancelItems
|
||||||
|
}, {
|
||||||
|
onSuccess: () => {
|
||||||
|
toast('درخواست لغو سفارش با موفقیت ثبت شد', 'success')
|
||||||
|
router.push(`/profile/orders/${id}`)
|
||||||
|
},
|
||||||
|
onError: (error) => {
|
||||||
|
toast(extractErrorMessage(error), 'error')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Flatten all shipment items from all order items
|
||||||
|
const allShipmentItems = order?.results.order.orderItems
|
||||||
|
.flatMap(orderItem => orderItem.shipmentItems) || []
|
||||||
|
|
||||||
|
if (isOrderLoading) {
|
||||||
|
return (
|
||||||
|
<Layout>
|
||||||
|
<div className='mt-14 px-4 sm:px-8 lg:px-20'>
|
||||||
|
<div className='flex justify-center items-center min-h-[400px]'>
|
||||||
|
<div className='text-center'>
|
||||||
|
<div className='animate-spin rounded-full h-8 w-8 border-b-2 border-primary mx-auto mb-4'></div>
|
||||||
|
<p>در حال بارگذاری...</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Layout>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!order) {
|
||||||
|
return (
|
||||||
|
<Layout>
|
||||||
|
<div className='mt-14 px-4 sm:px-8 lg:px-20'>
|
||||||
|
<div className='text-center min-h-[400px] flex items-center justify-center'>
|
||||||
|
<p>سفارش یافت نشد</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Layout>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Layout>
|
||||||
|
<div className='mt-14 px-4 sm:px-8 lg:px-20 mx-auto'>
|
||||||
|
<div className='mb-8'>
|
||||||
|
<h1 className='text-2xl font-bold mb-2'>لغو سفارش</h1>
|
||||||
|
<p className='text-gray-600'>شماره سفارش: {order.results.order._id}</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className='space-y-8'>
|
||||||
|
<ProductSelection
|
||||||
|
items={allShipmentItems}
|
||||||
|
selectedItems={selectedItems}
|
||||||
|
onItemSelect={handleItemSelect}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{selectedItems.length > 0 && (
|
||||||
|
<CancelForm
|
||||||
|
onSubmit={handleCancelSubmit}
|
||||||
|
isLoading={cancelOrderMutation.isPending}
|
||||||
|
cancelReasons={cancelReasons?.results.reasons || []}
|
||||||
|
selectedItemsCount={selectedItems.length}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Layout>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default CancelOrderPage
|
||||||
@@ -3,6 +3,8 @@ import React from 'react'
|
|||||||
import Image from 'next/image'
|
import Image from 'next/image'
|
||||||
import { MessageText, ShieldTick, Truck, CloseCircle } from 'iconsax-react'
|
import { MessageText, ShieldTick, Truck, CloseCircle } from 'iconsax-react'
|
||||||
import { ShipmentItemDetail } from '../../types/Types'
|
import { ShipmentItemDetail } from '../../types/Types'
|
||||||
|
import Link from 'next/link'
|
||||||
|
import { useParams } from 'next/navigation'
|
||||||
|
|
||||||
interface OrderProductItemProps {
|
interface OrderProductItemProps {
|
||||||
item: ShipmentItemDetail
|
item: ShipmentItemDetail
|
||||||
@@ -10,7 +12,10 @@ interface OrderProductItemProps {
|
|||||||
onCancelClick: () => void
|
onCancelClick: () => void
|
||||||
}
|
}
|
||||||
|
|
||||||
const OrderProductItem: React.FC<OrderProductItemProps> = ({ item, shipperName, onCancelClick }) => {
|
const OrderProductItem: React.FC<OrderProductItemProps> = ({ item, shipperName }) => {
|
||||||
|
|
||||||
|
const { id } = useParams()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='mt-8 py-7 border-t items-start flex gap-6 sm:flex-row flex-col'>
|
<div className='mt-8 py-7 border-t items-start flex gap-6 sm:flex-row flex-col'>
|
||||||
<Image
|
<Image
|
||||||
@@ -80,13 +85,14 @@ const OrderProductItem: React.FC<OrderProductItemProps> = ({ item, shipperName,
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{item.quantity !== item.cancelled_quantity && (
|
{item.quantity !== item.cancelled_quantity && (
|
||||||
<button
|
<Link href={`/profile/orders/${id}/cancel`}>
|
||||||
onClick={onCancelClick}
|
<button
|
||||||
className='flex cursor-pointer gap-2 text-[#B3261E] hover:bg-red-50 p-2 rounded-lg transition-colors'
|
className='flex items-center cursor-pointer gap-2 text-[#B3261E] hover:bg-red-50 p-2 rounded-lg transition-colors'
|
||||||
>
|
>
|
||||||
<div>لغو سفارش</div>
|
<div>لغو سفارش</div>
|
||||||
<CloseCircle size={16} />
|
<CloseCircle className='mt-0.5' color='#B3261E' size={16} />
|
||||||
</button>
|
</button>
|
||||||
|
</Link>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -8,8 +8,7 @@ import Menu from '../../components/Menu'
|
|||||||
import OrderSidebar from './components/OrderSidebar'
|
import OrderSidebar from './components/OrderSidebar'
|
||||||
import OrderMainContent from './components/OrderMainContent'
|
import OrderMainContent from './components/OrderMainContent'
|
||||||
import CancelOrderModal from './components/CancelOrderModal'
|
import CancelOrderModal from './components/CancelOrderModal'
|
||||||
import { useGetOrderDetail } from '../hooks/useOrdersData'
|
import { useCancelOrder, useGetOrderDetail } from '../hooks/useOrdersData'
|
||||||
import * as api from '../service/Service'
|
|
||||||
import { toast } from '@/components/Toast'
|
import { toast } from '@/components/Toast'
|
||||||
|
|
||||||
|
|
||||||
@@ -17,7 +16,7 @@ const OrderDetail: FC = () => {
|
|||||||
const { id } = useParams()
|
const { id } = useParams()
|
||||||
const { data: orderDetail } = useGetOrderDetail(id as string)
|
const { data: orderDetail } = useGetOrderDetail(id as string)
|
||||||
const [showModalCancel, setShowModalCancel] = useState<boolean>(false)
|
const [showModalCancel, setShowModalCancel] = useState<boolean>(false)
|
||||||
const [isLoading, setIsLoading] = useState<boolean>(false)
|
const cancelOrderMutation = useCancelOrder()
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
|
|
||||||
const getStatusText = (status: string) => {
|
const getStatusText = (status: string) => {
|
||||||
@@ -32,11 +31,24 @@ const OrderDetail: FC = () => {
|
|||||||
|
|
||||||
const onSubmit = async (cancelData: { reason: string; count: string; description: string }) => {
|
const onSubmit = async (cancelData: { reason: string; count: string; description: string }) => {
|
||||||
try {
|
try {
|
||||||
setIsLoading(true)
|
// Prepare cancel items from all order items
|
||||||
await api.cancelOrder(id as string, {
|
const cancelItems = orderDetail?.results.order.orderItems.flatMap(orderItem =>
|
||||||
reason: cancelData.reason,
|
orderItem.shipmentItems.map(shipmentItem => {
|
||||||
count: parseInt(cancelData.count),
|
const availableQuantity = shipmentItem.quantity - shipmentItem.cancelled_quantity - shipmentItem.returned_quantity
|
||||||
description: cancelData.description
|
|
||||||
|
return {
|
||||||
|
orderItemId: orderItem._id,
|
||||||
|
shipmentItemId: shipmentItem._id,
|
||||||
|
quantity: availableQuantity,
|
||||||
|
comment: cancelData.description,
|
||||||
|
reason: cancelData.reason
|
||||||
|
}
|
||||||
|
})
|
||||||
|
) || []
|
||||||
|
|
||||||
|
await cancelOrderMutation.mutateAsync({
|
||||||
|
orderId: Number(id),
|
||||||
|
items: cancelItems
|
||||||
})
|
})
|
||||||
|
|
||||||
toast("درخواست لغو سفارش با موفقیت ثبت شد", "success")
|
toast("درخواست لغو سفارش با موفقیت ثبت شد", "success")
|
||||||
@@ -45,8 +57,6 @@ const OrderDetail: FC = () => {
|
|||||||
router.push('/profile/orders')
|
router.push('/profile/orders')
|
||||||
} catch {
|
} catch {
|
||||||
toast("مشکلی در ثبت درخواست لغو سفارش رخ داد", "error")
|
toast("مشکلی در ثبت درخواست لغو سفارش رخ داد", "error")
|
||||||
} finally {
|
|
||||||
setIsLoading(false)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,7 +76,7 @@ const OrderDetail: FC = () => {
|
|||||||
<div className="text-lg font-semibold">جزئیات سفارش</div>
|
<div className="text-lg font-semibold">جزئیات سفارش</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{isLoading ? (
|
{cancelOrderMutation.isPending ? (
|
||||||
<PageLoading />
|
<PageLoading />
|
||||||
) : orderDetail?.results.order ? (
|
) : orderDetail?.results.order ? (
|
||||||
<div className='mt-6 lg:flex-row flex-col flex gap-6 items-start'>
|
<div className='mt-6 lg:flex-row flex-col flex gap-6 items-start'>
|
||||||
@@ -99,7 +109,7 @@ const OrderDetail: FC = () => {
|
|||||||
showModalCancel={showModalCancel}
|
showModalCancel={showModalCancel}
|
||||||
setShowModalCancel={setShowModalCancel}
|
setShowModalCancel={setShowModalCancel}
|
||||||
onSubmit={onSubmit}
|
onSubmit={onSubmit}
|
||||||
isLoading={isLoading}
|
isLoading={cancelOrderMutation.isPending}
|
||||||
cancelReasons={orderDetail?.results.order.cancelReasons}
|
cancelReasons={orderDetail?.results.order.cancelReasons}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
import { NextPage } from 'next'
|
||||||
|
|
||||||
|
const ReturnPage: NextPage = () => {
|
||||||
|
return (
|
||||||
|
<div>page</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ReturnPage
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import { useQuery } from "@tanstack/react-query";
|
import { useQuery, useMutation } from "@tanstack/react-query";
|
||||||
import * as api from "../service/Service";
|
import * as api from "../service/Service";
|
||||||
import { OrdersResponse, OrderDetailResponse } from "../types/Types";
|
import { OrdersResponse, OrderDetailResponse } from "../types/Types";
|
||||||
|
|
||||||
@@ -17,3 +17,16 @@ export const useGetOrderDetail = (orderId: string) => {
|
|||||||
enabled: !!orderId,
|
enabled: !!orderId,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const useCancelOrder = () => {
|
||||||
|
return useMutation({
|
||||||
|
mutationFn: api.cancelOrder,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useGetCancelReasons = () => {
|
||||||
|
return useQuery({
|
||||||
|
queryKey: ["cancelReasons"],
|
||||||
|
queryFn: api.getCancelReasons,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|||||||
@@ -1,5 +1,10 @@
|
|||||||
import axios from "@/config/axios";
|
import axios from "@/config/axios";
|
||||||
import { OrdersResponse, OrderDetailResponse } from "../types/Types";
|
import {
|
||||||
|
OrdersResponse,
|
||||||
|
OrderDetailResponse,
|
||||||
|
CancelOrderType,
|
||||||
|
CancelReasonsResponse,
|
||||||
|
} from "../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}`);
|
||||||
@@ -13,21 +18,19 @@ export const getOrderDetail = async (
|
|||||||
return data;
|
return data;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const cancelOrder = async (
|
|
||||||
orderId: string,
|
|
||||||
cancelData: {
|
|
||||||
reason: string;
|
|
||||||
count: number;
|
|
||||||
description: string;
|
|
||||||
}
|
|
||||||
) => {
|
|
||||||
const { data } = await axios.post(`/order/${orderId}/cancel`, cancelData);
|
|
||||||
return data;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getInvoice = async (orderId: string) => {
|
export const getInvoice = async (orderId: string) => {
|
||||||
const { data } = await axios.get(`/order/${orderId}/invoice`, {
|
const { data } = await axios.get(`/order/${orderId}/invoice`, {
|
||||||
responseType: "blob",
|
responseType: "blob",
|
||||||
});
|
});
|
||||||
return data;
|
return data;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const getCancelReasons = async (): Promise<CancelReasonsResponse> => {
|
||||||
|
const { data } = await axios.get(`/cancel/reasons`);
|
||||||
|
return data;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const cancelOrder = async (params: CancelOrderType) => {
|
||||||
|
const { data } = await axios.post(`/cancel/user`, params);
|
||||||
|
return data;
|
||||||
|
};
|
||||||
|
|||||||
@@ -259,6 +259,15 @@ export interface OrderItemDetail {
|
|||||||
export interface CancelReason {
|
export interface CancelReason {
|
||||||
_id: string;
|
_id: string;
|
||||||
title: string;
|
title: string;
|
||||||
|
deleted: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CancelReasonsResponse {
|
||||||
|
status: number;
|
||||||
|
success: boolean;
|
||||||
|
results: {
|
||||||
|
reasons: CancelReason[];
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface OrderDetail {
|
export interface OrderDetail {
|
||||||
@@ -291,3 +300,16 @@ export interface OrdersResponse {
|
|||||||
createdAt: string;
|
createdAt: string;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface CancelOrderItem {
|
||||||
|
orderItemId: string;
|
||||||
|
shipmentItemId: string;
|
||||||
|
quantity: number;
|
||||||
|
comment: string;
|
||||||
|
reason: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CancelOrderType {
|
||||||
|
orderId: number;
|
||||||
|
items: CancelOrderItem[];
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user