Files
dmenu-admin/src/pages/orders/Details.tsx
T
morteza 435fe3e947
deploy to danak / build_and_deploy (push) Has been cancelled
update costs
2026-07-14 10:07:15 +03:30

342 lines
13 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { type FC, useState } from 'react'
import {
useGetOrderById,
useVerifyPayment,
useChangeOrderStatus,
useRefundPayment,
useUpdateOrderFees,
} from './hooks/useOrderData'
import { useParams } from 'react-router-dom'
import { formatFaNumber } from '@/helpers/func'
import { OrderStatus, PaymentStatusEnum } from './enum/Enum'
import { PaymentMethodEnum } from '@/pages/paymentMethods/enum/Enum'
import { DeliveryMethodEnum } from '@/pages/shipmentMethod/enum/Enum'
import ModalConfrim from '@/components/ModalConfrim'
import CustomerInfo from './components/CustomerInfo'
import OrderItemsDetails from './components/OrderItemsDetails'
import PaymentInfo from './components/PaymentInfo'
import PaymentVerificationBox from './components/PaymentVerificationBox'
import OrderActions from './components/OrderActions'
import UpdateOrderFeesModal from './components/UpdateOrderFeesModal'
import { toast } from 'react-toastify'
import { extractErrorMessage } from '@/config/func'
import { printOrderReceipt } from './print/orderReceiptPrint'
import type { UpdateOrderFeesType } from './types/Types'
const OrderDetails: FC = () => {
const { id } = useParams()
const { data: orderData, isLoading } = useGetOrderById(id!)
const { mutate: verifyPayment, isPending: isVerifyingPayment } = useVerifyPayment()
const { mutate: changeOrderStatus, isPending: isChangingStatus } = useChangeOrderStatus()
const { mutate: refundPayment, isPending: isRefunding } = useRefundPayment()
const { mutate: updateOrderFees, isPending: isUpdatingFees } = useUpdateOrderFees()
const [showCancelModal, setShowCancelModal] = useState(false)
const [showRefundModal, setShowRefundModal] = useState(false)
const [showEditFeesModal, setShowEditFeesModal] = useState(false)
const order = orderData?.data
const getStatusColor = (status: string): string => {
const colorMap: Record<string, string> = {
'pendingPayment': '#FFEECC',
'paid': '#E3F2FD',
'preparing': '#FFF3E0',
'ready': '#E3F2FD',
'shipped': '#E3F2FD',
'completed': '#E8F5E9',
'canceled': '#FFEBEE',
}
return colorMap[status] || '#FFEECC'
}
const getPaymentStatusColor = (status: string): string => {
const colorMap: Record<string, string> = {
[PaymentStatusEnum.Paid]: 'bg-green-500',
[PaymentStatusEnum.Pending]: 'bg-yellow-500',
[PaymentStatusEnum.Failed]: 'bg-red-500',
}
return colorMap[status] || 'bg-gray-500'
}
const getPaymentStatusTextColor = (status: string): string => {
const colorMap: Record<string, string> = {
[PaymentStatusEnum.Paid]: 'text-green-500',
[PaymentStatusEnum.Pending]: 'text-yellow-500',
[PaymentStatusEnum.Failed]: 'text-red-500',
}
return colorMap[status] || 'text-gray-500'
}
const getPaymentStatusText = (status: string): string => {
const textMap: Record<string, string> = {
[PaymentStatusEnum.Paid]: 'پرداخت شده',
[PaymentStatusEnum.Pending]: 'در انتظار پرداخت',
[PaymentStatusEnum.Failed]: 'پرداخت ناموفق',
}
return textMap[status] || status
}
if (isLoading) {
return (
<div className='mt-5 flex items-center justify-center h-64'>
<div className='text-lg font-light'>در حال بارگذاری...</div>
</div>
)
}
if (!order) {
return (
<div className='mt-5 flex items-center justify-center h-64'>
<div className='text-lg font-light'>سفارش یافت نشد</div>
</div>
)
}
// منطق نمایش دکمه‌ها
const isCashPayment = order.paymentMethod?.method === PaymentMethodEnum.Cash
const isCreditCardPayment = order.paymentMethod?.method === PaymentMethodEnum.CreditCard
const isPendingPayment = order.status === OrderStatus.PENDING_PAYMENT
const isOrderPaid = order.status === OrderStatus.PAID
const isPreparing = order.status === OrderStatus.PREPARING
const isCanceled = order.status === OrderStatus.CANCELED
const isCompleted = order.status === OrderStatus.COMPLETED
const canEditFees = !isCanceled && !isCompleted
const canCompleteOrder = [
OrderStatus.DELIVERED_TO_WAITER,
OrderStatus.DELIVERED_TO_RECEPTIONIST,
OrderStatus.SHIPPED,
].includes(order.status as OrderStatus)
// بررسی وضعیت پرداخت از payments array یا paymentStatus
// ابتدا از paymentStatus استفاده می‌کنیم، اگر نبود از اولین payment در payments array استفاده می‌کنیم
const paymentStatus = order.paymentStatus || order.payments?.[0]?.status
// بررسی وضعیت pending (هم enum و هم string literal)
const isPaymentPending = paymentStatus === PaymentStatusEnum.Pending || paymentStatus === 'pending'
const isCourierDelivery = order.deliveryMethod?.method === DeliveryMethodEnum.DeliveryCourier
const isDineInOrCarDelivery = order.deliveryMethod?.method === DeliveryMethodEnum.DineIn || order.deliveryMethod?.method === DeliveryMethodEnum.DeliveryCar
const isCustomerPickup = order.deliveryMethod?.method === DeliveryMethodEnum.CustomerPickup
const payment = order.payments?.[0]
const hasPaymentDescription = Boolean(payment?.description)
const hasPaymentAttachments = Boolean(payment?.attachments && payment.attachments.length > 0)
const showPaymentReceiptBox = isCreditCardPayment && (hasPaymentDescription || hasPaymentAttachments)
const showVerifyPaymentButton = (isCashPayment || isCreditCardPayment) && isPaymentPending && !isCanceled
// نمایش دکمه ارسال به آشپزخانه
// برای pendingPayment با پرداخت نقدی یا برای paid
const showSendToKitchenButton = (isPendingPayment && isCashPayment) || isOrderPaid
// نمایش دکمه کنسل
// همیشه نمایش داده می‌شود مگر اینکه سفارش قبلاً کنسل شده باشد
const showCancelButton = !isCanceled
const handleVerifyPayment = () => {
const paymentId = order.paymentId || order.payments?.[0]?.id
if (paymentId) {
verifyPayment(paymentId, {
onSuccess: () => {
// Success handled by query invalidation
},
onError: (error) => {
toast.error(extractErrorMessage(error))
}
})
}
}
const handleSendToKitchen = () => {
changeOrderStatus({
orderId: order.id,
status: OrderStatus.PREPARING
}, {
onError: (error) => {
toast.error(extractErrorMessage(error))
}
})
}
const handleDeliverToCourier = () => {
changeOrderStatus({
orderId: order.id,
status: OrderStatus.SHIPPED
}, {
onError: (error) => {
toast.error(extractErrorMessage(error))
}
})
}
const handleDeliverToWaiter = () => {
changeOrderStatus({
orderId: order.id,
status: OrderStatus.DELIVERED_TO_WAITER
}, {
onError: (error) => {
toast.error(extractErrorMessage(error))
}
})
}
const handleDeliverToReceptionist = () => {
changeOrderStatus({
orderId: order.id,
status: OrderStatus.DELIVERED_TO_RECEPTIONIST
}, {
onError: (error) => {
toast.error(extractErrorMessage(error))
}
})
}
const handleCancelOrder = (description?: string) => {
changeOrderStatus({
orderId: order.id,
status: OrderStatus.CANCELED,
params: description ? { description } : undefined
}, {
onError: (error) => {
toast.error(extractErrorMessage(error))
}
})
setShowCancelModal(false)
}
const handleCompleteOrder = () => {
changeOrderStatus(
{
orderId: order.id,
status: OrderStatus.COMPLETED,
},
{
onError: (error) => {
toast.error(extractErrorMessage(error))
},
}
)
}
const handleRefund = (text?: string) => {
if (!text) return
refundPayment({
orderId: order.id,
params: { description: text }
}, {
onError: (error) => {
toast.error(extractErrorMessage(error))
}
})
setShowRefundModal(false)
}
const handlePrintOrder = () => {
printOrderReceipt(order)
}
const handleUpdateOrderFees = (params: UpdateOrderFeesType) => {
updateOrderFees(
{ orderId: order.id, params },
{
onSuccess: () => {
toast.success('هزینه‌های سفارش به‌روزرسانی شد')
setShowEditFeesModal(false)
},
onError: (error) => {
toast.error(extractErrorMessage(error))
},
}
)
}
return (
<div className='mt-5'>
<div className='flex justify-between items-center'>
<h1 className='text-lg font-light'>
سفارش {formatFaNumber(order.orderNumber)}
</h1>
{/* <div>
<Select
items={statusItems}
value={order.status}
placeholder={t(`order_status.${order.status}`)}
className='w-[200px]'
style={{ backgroundColor: getStatusColor(order.status) }}
/>
</div> */}
</div>
<div className='flex gap-7 mt-9'>
<div className='flex-1 space-y-8'>
<CustomerInfo order={order} />
<OrderItemsDetails order={order} getStatusColor={getStatusColor} />
</div>
<div>
<PaymentInfo
order={order}
getPaymentStatusColor={getPaymentStatusColor}
getPaymentStatusTextColor={getPaymentStatusTextColor}
getPaymentStatusText={getPaymentStatusText}
/>
{showPaymentReceiptBox && (
<PaymentVerificationBox
order={order}
isVerifyingPayment={isVerifyingPayment}
onVerifyPayment={handleVerifyPayment}
showVerifyButton={showVerifyPaymentButton}
/>
)}
<OrderActions
onPrint={handlePrintOrder}
showSendToKitchenButton={showSendToKitchenButton}
showCancelButton={showCancelButton}
showEditFeesButton={canEditFees}
isPreparing={isPreparing}
isCourierDelivery={isCourierDelivery}
isDineInOrCarDelivery={isDineInOrCarDelivery}
isCustomerPickup={isCustomerPickup}
isCanceled={isCanceled}
canCompleteOrder={canCompleteOrder}
isChangingStatus={isChangingStatus}
onSendToKitchen={handleSendToKitchen}
onDeliverToCourier={handleDeliverToCourier}
onDeliverToWaiter={handleDeliverToWaiter}
onDeliverToReceptionist={handleDeliverToReceptionist}
onCompleteOrder={handleCompleteOrder}
onCancelOrder={() => setShowCancelModal(true)}
onEditFees={() => setShowEditFeesModal(true)}
/>
</div>
</div>
<UpdateOrderFeesModal
isOpen={showEditFeesModal}
onClose={() => setShowEditFeesModal(false)}
order={order}
isLoading={isUpdatingFees}
onSubmit={handleUpdateOrderFees}
/>
{/* مدال کنسل سفارش */}
<ModalConfrim
isOpen={showCancelModal}
close={() => setShowCancelModal(false)}
onConfrim={handleCancelOrder}
isloading={isChangingStatus}
label='آیا از لغو سفارش مطمئن هستید؟'
isHasDescription
/>
{/* مدال ریفاند */}
<ModalConfrim
isOpen={showRefundModal}
close={() => setShowRefundModal(false)}
onConfrim={handleRefund}
isloading={isRefunding}
label='آیا از ریفاند این سفارش مطمئن هستید؟'
isHasDescription
/>
</div>
)
}
export default OrderDetails