This commit is contained in:
+2
-1
@@ -855,7 +855,8 @@
|
||||
"canceled": "لغو شده",
|
||||
"deliveredToWaiter": "تحویل به گارسون",
|
||||
"deliveredToReceptionist": "تحویل به پیشخوان",
|
||||
"deliveredToRecepient": "تحویل به گیرنده"
|
||||
"deliveredToRecepient": "تحویل به گیرنده",
|
||||
"needConfirmation": "در انتظار تایید فروشگاه"
|
||||
},
|
||||
"reviews": {
|
||||
"reviews": "نظرات",
|
||||
|
||||
@@ -88,6 +88,7 @@ const OrderDetails: FC = () => {
|
||||
|
||||
// منطق نمایش دکمهها
|
||||
const isCashPayment = order.paymentMethod?.method === PaymentMethodEnum.Cash
|
||||
const isNeedConfirmation = order.status === OrderStatus.NEED_CONFIRMATION
|
||||
const isPendingPayment = order.status === OrderStatus.PENDING_PAYMENT
|
||||
const isOrderPaid = order.status === OrderStatus.PAID
|
||||
const isPreparing = order.status === OrderStatus.PREPARING
|
||||
@@ -159,6 +160,17 @@ const OrderDetails: FC = () => {
|
||||
})
|
||||
}
|
||||
|
||||
const handleConfirmQuantities = () => {
|
||||
changeOrderStatus({
|
||||
orderId: order.id,
|
||||
status: OrderStatus.PENDING_PAYMENT
|
||||
}, {
|
||||
onError: (error) => {
|
||||
toast.error(extractErrorMessage(error))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const handleCancelOrder = (description?: string) => {
|
||||
changeOrderStatus({
|
||||
orderId: order.id,
|
||||
@@ -205,7 +217,7 @@ const OrderDetails: FC = () => {
|
||||
<div className='flex gap-7 mt-9'>
|
||||
<div className='flex-1 space-y-8'>
|
||||
<CustomerInfo order={order} />
|
||||
<OrderItemsDetails order={order} getStatusColor={getStatusColor} />
|
||||
<OrderItemsDetails order={order} getStatusColor={getStatusColor} isNeedConfirmation={isNeedConfirmation} iconColor='#7c3aed' />
|
||||
</div>
|
||||
|
||||
<div>
|
||||
@@ -223,6 +235,7 @@ const OrderDetails: FC = () => {
|
||||
isCourierDelivery={isCourierDelivery}
|
||||
isCustomerPickup={isCustomerPickup}
|
||||
isCanceled={isCanceled}
|
||||
isNeedConfirmation={isNeedConfirmation}
|
||||
isVerifyingPayment={isVerifyingPayment}
|
||||
isChangingStatus={isChangingStatus}
|
||||
onVerifyCashPayment={handleVerifyCashPayment}
|
||||
@@ -230,6 +243,7 @@ const OrderDetails: FC = () => {
|
||||
onDeliverToCourier={handleDeliverToCourier}
|
||||
onDeliverToReceptionist={handleDeliverToReceptionist}
|
||||
onCancelOrder={() => setShowCancelModal(true)}
|
||||
onConfirmQuantities={handleConfirmQuantities}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -9,6 +9,7 @@ interface OrderActionsProps {
|
||||
isCourierDelivery: boolean
|
||||
isCustomerPickup: boolean
|
||||
isCanceled: boolean
|
||||
isNeedConfirmation: boolean
|
||||
isVerifyingPayment: boolean
|
||||
isChangingStatus: boolean
|
||||
onVerifyCashPayment: () => void
|
||||
@@ -16,6 +17,7 @@ interface OrderActionsProps {
|
||||
onDeliverToCourier: () => void
|
||||
onDeliverToReceptionist: () => void
|
||||
onCancelOrder: () => void
|
||||
onConfirmQuantities: () => void
|
||||
}
|
||||
|
||||
const OrderActions: FC<OrderActionsProps> = ({
|
||||
@@ -26,13 +28,15 @@ const OrderActions: FC<OrderActionsProps> = ({
|
||||
isCourierDelivery,
|
||||
isCustomerPickup,
|
||||
isCanceled,
|
||||
isNeedConfirmation,
|
||||
isVerifyingPayment,
|
||||
isChangingStatus,
|
||||
onVerifyCashPayment,
|
||||
onSendToKitchen,
|
||||
onDeliverToCourier,
|
||||
onDeliverToReceptionist,
|
||||
onCancelOrder
|
||||
onCancelOrder,
|
||||
onConfirmQuantities
|
||||
}) => {
|
||||
const [loadingAction, setLoadingAction] = useState<string | null>(null)
|
||||
|
||||
@@ -64,8 +68,22 @@ const OrderActions: FC<OrderActionsProps> = ({
|
||||
|
||||
if (isCanceled) return null
|
||||
|
||||
const handleConfirmQuantities = () => {
|
||||
setLoadingAction('confirmQuantities')
|
||||
onConfirmQuantities()
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='mt-6 flex flex-col gap-3'>
|
||||
{isNeedConfirmation && (
|
||||
<Button
|
||||
label='تایید مقدار'
|
||||
onClick={handleConfirmQuantities}
|
||||
isloading={isChangingStatus && loadingAction === 'confirmQuantities'}
|
||||
className='bg-purple-600 hover:bg-purple-700'
|
||||
/>
|
||||
)}
|
||||
|
||||
{showVerifyCashPaymentButton && (
|
||||
<Button
|
||||
label='پرداخت شده'
|
||||
|
||||
@@ -1,11 +1,17 @@
|
||||
import Table from '@/components/Table'
|
||||
import { ShoppingCart, Calendar, Clock, Tag } from 'iconsax-react'
|
||||
import type { FC } from 'react'
|
||||
import { ShoppingCart, Calendar, Clock, Tag, Edit2 } from 'iconsax-react'
|
||||
import { type FC, useState } from 'react'
|
||||
import type { ColumnType, RowDataType } from '@/components/types/TableTypes'
|
||||
import type { Order, OrderItem as OrderItemType } from '../types/Types'
|
||||
import { formatOptionalDate, formatPrice, formatFaNumber } from '@/helpers/func'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import OrderSummary from './OrderSummary'
|
||||
import { useUpdateOrderItemQuantity } from '../hooks/useOrderData'
|
||||
import { toast } from 'react-toastify'
|
||||
import { extractErrorMessage } from '@/config/func'
|
||||
import DefaulModal from '@/components/DefaulModal'
|
||||
import Input from '@/components/Input'
|
||||
import Button from '@/components/Button'
|
||||
|
||||
interface OrderItemTable extends RowDataType {
|
||||
image: string
|
||||
@@ -19,9 +25,97 @@ interface OrderItemTable extends RowDataType {
|
||||
interface OrderItemsDetailsProps {
|
||||
order: Order
|
||||
getStatusColor: (status: string) => string
|
||||
isNeedConfirmation?: boolean
|
||||
iconColor?: string
|
||||
}
|
||||
|
||||
const OrderItemsDetails: FC<OrderItemsDetailsProps> = ({ order, getStatusColor }) => {
|
||||
interface EditQuantityModalProps {
|
||||
item: OrderItemType
|
||||
orderId: string
|
||||
isOpen: boolean
|
||||
onClose: () => void
|
||||
}
|
||||
|
||||
const EditQuantityModal: FC<EditQuantityModalProps> = ({ item, orderId, isOpen, onClose }) => {
|
||||
const [value, setValue] = useState(String(item.quantity))
|
||||
const { mutate: updateQuantity, isPending } = useUpdateOrderItemQuantity()
|
||||
|
||||
const handleSave = () => {
|
||||
const parsed = parseFloat(value)
|
||||
if (isNaN(parsed) || parsed <= 0) return
|
||||
updateQuantity(
|
||||
{ orderId, orderItemId: item.id, quantity: parsed },
|
||||
{
|
||||
onSuccess: onClose,
|
||||
onError: (error) => {
|
||||
toast.error(extractErrorMessage(error))
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<DefaulModal open={isOpen} close={onClose} isHeader title_header='ویرایش تعداد'>
|
||||
<div className='mt-6 space-y-6'>
|
||||
<Input
|
||||
label='تعداد'
|
||||
allowDecimal
|
||||
value={value}
|
||||
onChange={(e) => setValue(e.target.value)}
|
||||
placeholder='مقدار جدید را وارد کنید'
|
||||
autoFocus
|
||||
/>
|
||||
<div className='flex gap-3 justify-end'>
|
||||
<Button
|
||||
label='ذخیره'
|
||||
onClick={handleSave}
|
||||
isloading={isPending}
|
||||
className='min-w-[90px]'
|
||||
/>
|
||||
<Button
|
||||
label='انصراف'
|
||||
onClick={onClose}
|
||||
className='bg-transparent text-black border border-primary min-w-[90px]'
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</DefaulModal>
|
||||
)
|
||||
}
|
||||
|
||||
interface QuantityWithEditProps {
|
||||
item: OrderItemType
|
||||
orderId: string
|
||||
iconColor?: string
|
||||
}
|
||||
|
||||
const QuantityWithEdit: FC<QuantityWithEditProps> = ({ item, orderId, iconColor = '#6d28d9' }) => {
|
||||
const [modalOpen, setModalOpen] = useState(false)
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className='flex items-center justify-center gap-2'>
|
||||
<span>{formatFaNumber(item.quantity)}</span>
|
||||
<button
|
||||
onClick={() => setModalOpen(true)}
|
||||
className='flex items-center justify-center hover:opacity-70 transition-opacity'
|
||||
>
|
||||
<Edit2 size={15} color={iconColor} />
|
||||
</button>
|
||||
</div>
|
||||
{modalOpen && (
|
||||
<EditQuantityModal
|
||||
item={item}
|
||||
orderId={orderId}
|
||||
isOpen={modalOpen}
|
||||
onClose={() => setModalOpen(false)}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
const OrderItemsDetails: FC<OrderItemsDetailsProps> = ({ order, getStatusColor, isNeedConfirmation, iconColor }) => {
|
||||
const { t } = useTranslation('global')
|
||||
|
||||
const orderItems: OrderItemTable[] = order.items.map((item: OrderItemType) => ({
|
||||
@@ -63,7 +157,15 @@ const OrderItemsDetails: FC<OrderItemsDetailsProps> = ({ order, getStatusColor }
|
||||
title: 'تعداد',
|
||||
key: 'quantity',
|
||||
align: 'center',
|
||||
render: (item) => formatFaNumber(item.quantity)
|
||||
render: (item) => {
|
||||
if (isNeedConfirmation) {
|
||||
const originalItem = order.items.find(i => i.id === item.id)
|
||||
if (originalItem) {
|
||||
return <QuantityWithEdit item={originalItem} orderId={order.id} iconColor={iconColor} />
|
||||
}
|
||||
}
|
||||
return formatFaNumber(item.quantity)
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'قیمت واحد',
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
export enum OrderStatus {
|
||||
NEED_CONFIRMATION = "needConfirmation",
|
||||
PENDING_PAYMENT = "pendingPayment",
|
||||
PAID = "paid",
|
||||
PREPARING = "preparing",
|
||||
|
||||
@@ -2,6 +2,7 @@ import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
||||
import * as api from "../service/OrderService";
|
||||
import type { GetOrdersParams, ChangeOrderStatusParams, RefundPaymentParams } from "../service/OrderService";
|
||||
|
||||
|
||||
export const useGetOrders = (params?: GetOrdersParams) => {
|
||||
return useQuery({
|
||||
queryKey: ["orders", params],
|
||||
@@ -62,3 +63,15 @@ export const useRefundPayment = () => {
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const useUpdateOrderItemQuantity = () => {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: ({ orderId, orderItemId, quantity }: { orderId: string; orderItemId: string; quantity: number }) =>
|
||||
api.updateOrderItemQuantity(orderId, orderItemId, quantity),
|
||||
onSuccess: (_, { orderId }) => {
|
||||
queryClient.invalidateQueries({ queryKey: ["order", orderId] });
|
||||
queryClient.invalidateQueries({ queryKey: ["orders"] });
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
@@ -82,3 +82,11 @@ export const refundPayment = async (
|
||||
): Promise<void> => {
|
||||
await axios.post(`/admin/orders/${orderId}/refund`, params);
|
||||
};
|
||||
|
||||
export const updateOrderItemQuantity = async (
|
||||
orderId: string,
|
||||
orderItemId: string,
|
||||
quantity: number
|
||||
): Promise<void> => {
|
||||
await axios.patch(`/admin/orders/${orderId}/items/${orderItemId}/quantity`, { quantity });
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user