details order refactor

This commit is contained in:
hamid zarghami
2025-12-23 15:20:22 +03:30
parent 14bc394801
commit 508c50152a
5 changed files with 124 additions and 55 deletions
+56 -27
View File
@@ -15,6 +15,8 @@ import CustomerInfo from './components/CustomerInfo'
import OrderItemsDetails from './components/OrderItemsDetails' import OrderItemsDetails from './components/OrderItemsDetails'
import PaymentInfo from './components/PaymentInfo' import PaymentInfo from './components/PaymentInfo'
import OrderActions from './components/OrderActions' import OrderActions from './components/OrderActions'
import { toast } from 'react-toastify'
import { extractErrorMessage } from '@/config/func'
const OrderDetails: FC = () => { const OrderDetails: FC = () => {
const { id } = useParams() const { id } = useParams()
@@ -32,7 +34,6 @@ const OrderDetails: FC = () => {
const colorMap: Record<string, string> = { const colorMap: Record<string, string> = {
'pendingPayment': '#FFEECC', 'pendingPayment': '#FFEECC',
'paid': '#E3F2FD', 'paid': '#E3F2FD',
'confirmed': '#E3F2FD',
'preparing': '#FFF3E0', 'preparing': '#FFF3E0',
'ready': '#E3F2FD', 'ready': '#E3F2FD',
'shipped': '#E3F2FD', 'shipped': '#E3F2FD',
@@ -89,51 +90,51 @@ const OrderDetails: FC = () => {
const isCashPayment = order.paymentMethod?.method === PaymentMethodEnum.Cash const isCashPayment = order.paymentMethod?.method === PaymentMethodEnum.Cash
const isPendingPayment = order.status === OrderStatus.PENDING_PAYMENT const isPendingPayment = order.status === OrderStatus.PENDING_PAYMENT
const isOrderPaid = order.status === OrderStatus.PAID const isOrderPaid = order.status === OrderStatus.PAID
const isConfirmed = order.status === OrderStatus.CONFIRMED
const isPreparing = order.status === OrderStatus.PREPARING const isPreparing = order.status === OrderStatus.PREPARING
const isCanceled = order.status === OrderStatus.CANCELED const isCanceled = order.status === OrderStatus.CANCELED
const isOnlineOrWalletPayment = order.paymentMethod?.method === PaymentMethodEnum.Online || order.paymentMethod?.method === PaymentMethodEnum.Wallet // بررسی وضعیت پرداخت از 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 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 showVerifyCashPaymentButton = isCashPayment && isPendingPayment // وقتی روش پرداخت نقدی است و وضعیت پرداخت Pending باشد
const showVerifyCashPaymentButton = isCashPayment && isPaymentPending
// نمایش دکمه تایید سفارش (confirm)
// سفارشات پرداخت آنلاین و کیف پولی فقط در صورتی می‌توانند confirm شوند که status آنها paid باشد
// سفارشات پرداخت نقدی می‌توانند تایید شوند
const canConfirm = !isConfirmed && !isPreparing && !isCanceled && (
isCashPayment ||
(isOnlineOrWalletPayment && isOrderPaid)
)
// نمایش دکمه ارسال به آشپزخانه // نمایش دکمه ارسال به آشپزخانه
const showSendToKitchenButton = isConfirmed // برای pendingPayment با پرداخت نقدی یا برای paid
const showSendToKitchenButton = (isPendingPayment && isCashPayment) || isOrderPaid
// نمایش دکمه کنسل (ادمین همیشه می‌تواند، مگر اینکه سفارش کنسل شده باشد) // نمایش دکمه کنسل
// همیشه نمایش داده می‌شود مگر اینکه سفارش قبلاً کنسل شده باشد
const showCancelButton = !isCanceled const showCancelButton = !isCanceled
const handleVerifyCashPayment = () => { const handleVerifyCashPayment = () => {
const paymentId = order.paymentId || order.paymentMethod?.id const paymentId = order.paymentId || order.payments?.[0]?.id
if (paymentId) { if (paymentId) {
verifyCashPayment(paymentId, { verifyCashPayment(paymentId, {
onSuccess: () => { onSuccess: () => {
// Success handled by query invalidation // Success handled by query invalidation
},
onError: (error) => {
toast.error(extractErrorMessage(error))
} }
}) })
} }
} }
const handleConfirmOrder = () => {
changeOrderStatus({
orderId: order.id,
status: OrderStatus.CONFIRMED
})
}
const handleSendToKitchen = () => { const handleSendToKitchen = () => {
changeOrderStatus({ changeOrderStatus({
orderId: order.id, orderId: order.id,
status: OrderStatus.PREPARING status: OrderStatus.PREPARING
}, {
onError: (error) => {
toast.error(extractErrorMessage(error))
}
}) })
} }
@@ -141,13 +142,32 @@ const OrderDetails: FC = () => {
changeOrderStatus({ changeOrderStatus({
orderId: order.id, orderId: order.id,
status: OrderStatus.SHIPPED status: OrderStatus.SHIPPED
}, {
onError: (error) => {
toast.error(extractErrorMessage(error))
}
}) })
} }
const handleOrderReady = () => { const handleDeliverToWaiter = () => {
changeOrderStatus({ changeOrderStatus({
orderId: order.id, orderId: order.id,
status: OrderStatus.READY 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))
}
}) })
} }
@@ -156,6 +176,10 @@ const OrderDetails: FC = () => {
orderId: order.id, orderId: order.id,
status: OrderStatus.CANCELED, status: OrderStatus.CANCELED,
params: description ? { description } : undefined params: description ? { description } : undefined
}, {
onError: (error) => {
toast.error(extractErrorMessage(error))
}
}) })
setShowCancelModal(false) setShowCancelModal(false)
} }
@@ -165,6 +189,10 @@ const OrderDetails: FC = () => {
refundPayment({ refundPayment({
orderId: order.id, orderId: order.id,
params: { description: text } params: { description: text }
}, {
onError: (error) => {
toast.error(extractErrorMessage(error))
}
}) })
setShowRefundModal(false) setShowRefundModal(false)
} }
@@ -201,19 +229,20 @@ const OrderDetails: FC = () => {
/> />
<OrderActions <OrderActions
showVerifyCashPaymentButton={showVerifyCashPaymentButton} showVerifyCashPaymentButton={showVerifyCashPaymentButton}
canConfirm={canConfirm}
showSendToKitchenButton={showSendToKitchenButton} showSendToKitchenButton={showSendToKitchenButton}
showCancelButton={showCancelButton} showCancelButton={showCancelButton}
isPreparing={isPreparing} isPreparing={isPreparing}
isCourierDelivery={isCourierDelivery} isCourierDelivery={isCourierDelivery}
isDineInOrCarDelivery={isDineInOrCarDelivery}
isCustomerPickup={isCustomerPickup}
isCanceled={isCanceled} isCanceled={isCanceled}
isVerifyingPayment={isVerifyingPayment} isVerifyingPayment={isVerifyingPayment}
isChangingStatus={isChangingStatus} isChangingStatus={isChangingStatus}
onVerifyCashPayment={handleVerifyCashPayment} onVerifyCashPayment={handleVerifyCashPayment}
onConfirmOrder={handleConfirmOrder}
onSendToKitchen={handleSendToKitchen} onSendToKitchen={handleSendToKitchen}
onDeliverToCourier={handleDeliverToCourier} onDeliverToCourier={handleDeliverToCourier}
onOrderReady={handleOrderReady} onDeliverToWaiter={handleDeliverToWaiter}
onDeliverToReceptionist={handleDeliverToReceptionist}
onCancelOrder={() => setShowCancelModal(true)} onCancelOrder={() => setShowCancelModal(true)}
/> />
</div> </div>
+62 -26
View File
@@ -1,41 +1,76 @@
import Button from '@/components/Button' import Button from '@/components/Button'
import type { FC } from 'react' import { type FC, useState, useEffect } from 'react'
interface OrderActionsProps { interface OrderActionsProps {
showVerifyCashPaymentButton: boolean showVerifyCashPaymentButton: boolean
canConfirm: boolean
showSendToKitchenButton: boolean showSendToKitchenButton: boolean
showCancelButton: boolean showCancelButton: boolean
isPreparing: boolean isPreparing: boolean
isCourierDelivery: boolean isCourierDelivery: boolean
isDineInOrCarDelivery: boolean
isCustomerPickup: boolean
isCanceled: boolean isCanceled: boolean
isVerifyingPayment: boolean isVerifyingPayment: boolean
isChangingStatus: boolean isChangingStatus: boolean
onVerifyCashPayment: () => void onVerifyCashPayment: () => void
onConfirmOrder: () => void
onSendToKitchen: () => void onSendToKitchen: () => void
onDeliverToCourier: () => void onDeliverToCourier: () => void
onOrderReady: () => void onDeliverToWaiter: () => void
onDeliverToReceptionist: () => void
onCancelOrder: () => void onCancelOrder: () => void
} }
const OrderActions: FC<OrderActionsProps> = ({ const OrderActions: FC<OrderActionsProps> = ({
showVerifyCashPaymentButton, showVerifyCashPaymentButton,
canConfirm,
showSendToKitchenButton, showSendToKitchenButton,
showCancelButton, showCancelButton,
isPreparing, isPreparing,
isCourierDelivery, isCourierDelivery,
isDineInOrCarDelivery,
isCustomerPickup,
isCanceled, isCanceled,
isVerifyingPayment, isVerifyingPayment,
isChangingStatus, isChangingStatus,
onVerifyCashPayment, onVerifyCashPayment,
onConfirmOrder,
onSendToKitchen, onSendToKitchen,
onDeliverToCourier, onDeliverToCourier,
onOrderReady, onDeliverToWaiter,
onDeliverToReceptionist,
onCancelOrder onCancelOrder
}) => { }) => {
const [loadingAction, setLoadingAction] = useState<string | null>(null)
useEffect(() => {
if (!isChangingStatus && !isVerifyingPayment) {
setLoadingAction(null)
}
}, [isChangingStatus, isVerifyingPayment])
const handleSendToKitchen = () => {
setLoadingAction('sendToKitchen')
onSendToKitchen()
}
const handleDeliverToCourier = () => {
setLoadingAction('deliverToCourier')
onDeliverToCourier()
}
const handleDeliverToWaiter = () => {
setLoadingAction('deliverToWaiter')
onDeliverToWaiter()
}
const handleDeliverToReceptionist = () => {
setLoadingAction('deliverToReceptionist')
onDeliverToReceptionist()
}
const handleCancelOrder = () => {
setLoadingAction('cancelOrder')
onCancelOrder()
}
if (isCanceled) return null if (isCanceled) return null
return ( return (
@@ -49,19 +84,11 @@ const OrderActions: FC<OrderActionsProps> = ({
/> />
)} )}
{canConfirm && (
<Button
label='تایید سفارش'
onClick={onConfirmOrder}
isloading={isChangingStatus}
/>
)}
{showSendToKitchenButton && ( {showSendToKitchenButton && (
<Button <Button
label='ارسال به آشپزخانه' label='ارسال به آشپزخانه'
onClick={onSendToKitchen} onClick={handleSendToKitchen}
isloading={isChangingStatus} isloading={isChangingStatus && loadingAction === 'sendToKitchen'}
className='bg-orange-600 hover:bg-orange-700' className='bg-orange-600 hover:bg-orange-700'
/> />
)} )}
@@ -69,26 +96,35 @@ const OrderActions: FC<OrderActionsProps> = ({
{isPreparing && isCourierDelivery && ( {isPreparing && isCourierDelivery && (
<Button <Button
label='تحویل به پیک' label='تحویل به پیک'
onClick={onDeliverToCourier} onClick={handleDeliverToCourier}
isloading={isChangingStatus} isloading={isChangingStatus && loadingAction === 'deliverToCourier'}
className='bg-blue-600 hover:bg-blue-700' className='bg-blue-600 hover:bg-blue-700'
/> />
)} )}
{isPreparing && !isCourierDelivery && ( {isPreparing && isDineInOrCarDelivery && (
<Button <Button
label='غذا آماده است' label='تحویل به گارسون'
onClick={onOrderReady} onClick={handleDeliverToWaiter}
isloading={isChangingStatus} isloading={isChangingStatus && loadingAction === 'deliverToWaiter'}
className='bg-green-600 hover:bg-green-700' className='bg-purple-600 hover:bg-purple-700'
/>
)}
{isPreparing && isCustomerPickup && (
<Button
label='تحویل به رسپشنیست'
onClick={handleDeliverToReceptionist}
isloading={isChangingStatus && loadingAction === 'deliverToReceptionist'}
className='bg-indigo-600 hover:bg-indigo-700'
/> />
)} )}
{showCancelButton && ( {showCancelButton && (
<Button <Button
label='لغو سفارش' label='لغو سفارش'
onClick={onCancelOrder} onClick={handleCancelOrder}
isloading={isChangingStatus} isloading={isChangingStatus && loadingAction === 'cancelOrder'}
className='bg-red-600 hover:bg-red-700' className='bg-red-600 hover:bg-red-700'
/> />
)} )}
@@ -18,7 +18,6 @@ const getStatusVariant = (status: string): 'success' | 'error' | 'warning' | 'in
const variantMap: Record<string, 'success' | 'error' | 'warning' | 'info' | 'pending'> = { const variantMap: Record<string, 'success' | 'error' | 'warning' | 'info' | 'pending'> = {
'pendingPayment': 'pending', 'pendingPayment': 'pending',
'paid': 'info', 'paid': 'info',
'confirmed': 'info',
'preparing': 'warning', 'preparing': 'warning',
'ready': 'info', 'ready': 'info',
'shipped': 'info', 'shipped': 'info',
+2 -1
View File
@@ -1,9 +1,10 @@
export enum OrderStatus { export enum OrderStatus {
PENDING_PAYMENT = "pendingPayment", PENDING_PAYMENT = "pendingPayment",
PAID = "paid", PAID = "paid",
CONFIRMED = "confirmed",
PREPARING = "preparing", PREPARING = "preparing",
READY = "ready", READY = "ready",
DELIVERED_TO_WAITER = "deliveredToWaiter",
DELIVERED_TO_RECEPTIONIST = "deliveredToReceptionist",
SHIPPED = "shipped", SHIPPED = "shipped",
COMPLETED = "completed", COMPLETED = "completed",
CANCELED = "canceled", CANCELED = "canceled",
@@ -1,11 +1,15 @@
import { type FC } from 'react' import { type FC } from 'react'
import { Cell, LabelList, Pie, PieChart, ResponsiveContainer } from 'recharts' import { Cell, LabelList, Pie, PieChart, ResponsiveContainer } from 'recharts'
import { useGetFoodSalesPieChart } from '../hooks/useStatsData';
interface FoodSalesChartProps { interface FoodSalesChartProps {
data?: Array<{ name: string; value: number; color: string }> data?: Array<{ name: string; value: number; color: string }>
} }
const FoodSalesChart: FC<FoodSalesChartProps> = ({ data }) => { const FoodSalesChart: FC<FoodSalesChartProps> = ({ data }) => {
useGetFoodSalesPieChart()
const defaultData = [ const defaultData = [
{ name: 'پیتزا', value: 50, color: '#6B7FED' }, { name: 'پیتزا', value: 50, color: '#6B7FED' },
{ name: 'برگر', value: 25, color: '#A78BFA' }, { name: 'برگر', value: 25, color: '#A78BFA' },