update costs
deploy to danak / build_and_deploy (push) Has been cancelled

This commit is contained in:
2026-07-14 10:07:15 +03:30
parent 0b3b7218b9
commit 435fe3e947
7 changed files with 195 additions and 2 deletions
+33 -1
View File
@@ -3,7 +3,8 @@ import {
useGetOrderById, useGetOrderById,
useVerifyPayment, useVerifyPayment,
useChangeOrderStatus, useChangeOrderStatus,
useRefundPayment useRefundPayment,
useUpdateOrderFees,
} from './hooks/useOrderData' } from './hooks/useOrderData'
import { useParams } from 'react-router-dom' import { useParams } from 'react-router-dom'
import { formatFaNumber } from '@/helpers/func' import { formatFaNumber } from '@/helpers/func'
@@ -16,9 +17,11 @@ import OrderItemsDetails from './components/OrderItemsDetails'
import PaymentInfo from './components/PaymentInfo' import PaymentInfo from './components/PaymentInfo'
import PaymentVerificationBox from './components/PaymentVerificationBox' import PaymentVerificationBox from './components/PaymentVerificationBox'
import OrderActions from './components/OrderActions' import OrderActions from './components/OrderActions'
import UpdateOrderFeesModal from './components/UpdateOrderFeesModal'
import { toast } from 'react-toastify' import { toast } from 'react-toastify'
import { extractErrorMessage } from '@/config/func' import { extractErrorMessage } from '@/config/func'
import { printOrderReceipt } from './print/orderReceiptPrint' import { printOrderReceipt } from './print/orderReceiptPrint'
import type { UpdateOrderFeesType } from './types/Types'
const OrderDetails: FC = () => { const OrderDetails: FC = () => {
const { id } = useParams() const { id } = useParams()
@@ -26,9 +29,11 @@ const OrderDetails: FC = () => {
const { mutate: verifyPayment, isPending: isVerifyingPayment } = useVerifyPayment() const { mutate: verifyPayment, isPending: isVerifyingPayment } = useVerifyPayment()
const { mutate: changeOrderStatus, isPending: isChangingStatus } = useChangeOrderStatus() const { mutate: changeOrderStatus, isPending: isChangingStatus } = useChangeOrderStatus()
const { mutate: refundPayment, isPending: isRefunding } = useRefundPayment() const { mutate: refundPayment, isPending: isRefunding } = useRefundPayment()
const { mutate: updateOrderFees, isPending: isUpdatingFees } = useUpdateOrderFees()
const [showCancelModal, setShowCancelModal] = useState(false) const [showCancelModal, setShowCancelModal] = useState(false)
const [showRefundModal, setShowRefundModal] = useState(false) const [showRefundModal, setShowRefundModal] = useState(false)
const [showEditFeesModal, setShowEditFeesModal] = useState(false)
const order = orderData?.data const order = orderData?.data
@@ -95,6 +100,8 @@ const OrderDetails: FC = () => {
const isOrderPaid = order.status === OrderStatus.PAID const isOrderPaid = order.status === OrderStatus.PAID
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 isCompleted = order.status === OrderStatus.COMPLETED
const canEditFees = !isCanceled && !isCompleted
const canCompleteOrder = [ const canCompleteOrder = [
OrderStatus.DELIVERED_TO_WAITER, OrderStatus.DELIVERED_TO_WAITER,
OrderStatus.DELIVERED_TO_RECEPTIONIST, OrderStatus.DELIVERED_TO_RECEPTIONIST,
@@ -225,6 +232,21 @@ const OrderDetails: FC = () => {
printOrderReceipt(order) printOrderReceipt(order)
} }
const handleUpdateOrderFees = (params: UpdateOrderFeesType) => {
updateOrderFees(
{ orderId: order.id, params },
{
onSuccess: () => {
toast.success('هزینه‌های سفارش به‌روزرسانی شد')
setShowEditFeesModal(false)
},
onError: (error) => {
toast.error(extractErrorMessage(error))
},
}
)
}
return ( return (
<div className='mt-5'> <div className='mt-5'>
<div className='flex justify-between items-center'> <div className='flex justify-between items-center'>
@@ -267,6 +289,7 @@ const OrderDetails: FC = () => {
onPrint={handlePrintOrder} onPrint={handlePrintOrder}
showSendToKitchenButton={showSendToKitchenButton} showSendToKitchenButton={showSendToKitchenButton}
showCancelButton={showCancelButton} showCancelButton={showCancelButton}
showEditFeesButton={canEditFees}
isPreparing={isPreparing} isPreparing={isPreparing}
isCourierDelivery={isCourierDelivery} isCourierDelivery={isCourierDelivery}
isDineInOrCarDelivery={isDineInOrCarDelivery} isDineInOrCarDelivery={isDineInOrCarDelivery}
@@ -280,10 +303,19 @@ const OrderDetails: FC = () => {
onDeliverToReceptionist={handleDeliverToReceptionist} onDeliverToReceptionist={handleDeliverToReceptionist}
onCompleteOrder={handleCompleteOrder} onCompleteOrder={handleCompleteOrder}
onCancelOrder={() => setShowCancelModal(true)} onCancelOrder={() => setShowCancelModal(true)}
onEditFees={() => setShowEditFeesModal(true)}
/> />
</div> </div>
</div> </div>
<UpdateOrderFeesModal
isOpen={showEditFeesModal}
onClose={() => setShowEditFeesModal(false)}
order={order}
isLoading={isUpdatingFees}
onSubmit={handleUpdateOrderFees}
/>
{/* مدال کنسل سفارش */} {/* مدال کنسل سفارش */}
<ModalConfrim <ModalConfrim
isOpen={showCancelModal} isOpen={showCancelModal}
+13 -1
View File
@@ -5,6 +5,7 @@ interface OrderActionsProps {
onPrint: () => void onPrint: () => void
showSendToKitchenButton: boolean showSendToKitchenButton: boolean
showCancelButton: boolean showCancelButton: boolean
showEditFeesButton?: boolean
isPreparing: boolean isPreparing: boolean
isCourierDelivery: boolean isCourierDelivery: boolean
isDineInOrCarDelivery: boolean isDineInOrCarDelivery: boolean
@@ -18,12 +19,14 @@ interface OrderActionsProps {
onDeliverToReceptionist: () => void onDeliverToReceptionist: () => void
onCompleteOrder: () => void onCompleteOrder: () => void
onCancelOrder: () => void onCancelOrder: () => void
onEditFees?: () => void
} }
const OrderActions: FC<OrderActionsProps> = ({ const OrderActions: FC<OrderActionsProps> = ({
onPrint, onPrint,
showSendToKitchenButton, showSendToKitchenButton,
showCancelButton, showCancelButton,
showEditFeesButton = false,
isPreparing, isPreparing,
isCourierDelivery, isCourierDelivery,
isDineInOrCarDelivery, isDineInOrCarDelivery,
@@ -36,7 +39,8 @@ const OrderActions: FC<OrderActionsProps> = ({
onDeliverToWaiter, onDeliverToWaiter,
onDeliverToReceptionist, onDeliverToReceptionist,
onCompleteOrder, onCompleteOrder,
onCancelOrder onCancelOrder,
onEditFees,
}) => { }) => {
const [loadingAction, setLoadingAction] = useState<string | null>(null) const [loadingAction, setLoadingAction] = useState<string | null>(null)
@@ -84,6 +88,14 @@ const OrderActions: FC<OrderActionsProps> = ({
className='bg-slate-700 hover:bg-slate-800' className='bg-slate-700 hover:bg-slate-800'
/> />
{showEditFeesButton && onEditFees && (
<Button
label='ویرایش هزینه‌ها'
onClick={onEditFees}
className='bg-transparent border border-slate-700 text-slate-700 hover:bg-slate-50'
/>
)}
{!isCanceled && showSendToKitchenButton && ( {!isCanceled && showSendToKitchenButton && (
<Button <Button
label='ارسال به آشپزخانه' label='ارسال به آشپزخانه'
@@ -115,6 +115,20 @@ const PaymentInfo: FC<PaymentInfoProps> = ({ order, getPaymentStatusColor, getPa
<div>{formatPrice(order.deliveryFee)}</div> <div>{formatPrice(order.deliveryFee)}</div>
</div> </div>
{(order.packingFee ?? 0) > 0 && (
<div className="flex mt-4 text-[13px] font-light justify-between items-center border-b border-border border-dashed pb-4">
<div className="text-description">هزینه بستهبندی</div>
<div>{formatPrice(order.packingFee)}</div>
</div>
)}
{order.prepareTime != null && order.prepareTime > 0 && (
<div className="flex mt-4 text-[13px] font-light justify-between items-center border-b border-border border-dashed pb-4">
<div className="text-description">زمان آمادهسازی</div>
<div>{formatFaNumber(order.prepareTime)} دقیقه</div>
</div>
)}
{order.tax > 0 && ( {order.tax > 0 && (
<div className="flex mt-4 text-[13px] font-light justify-between items-center border-b border-border border-dashed pb-4"> <div className="flex mt-4 text-[13px] font-light justify-between items-center border-b border-border border-dashed pb-4">
<div className="text-description">مالیات</div> <div className="text-description">مالیات</div>
@@ -0,0 +1,97 @@
import { type FC, useEffect, useState } from 'react'
import DefaulModal from '@/components/DefaulModal'
import Button from '@/components/Button'
import Input from '@/components/Input'
import type { Order, UpdateOrderFeesType } from '../types/Types'
interface UpdateOrderFeesModalProps {
isOpen: boolean
onClose: () => void
order: Order
isLoading?: boolean
onSubmit: (params: UpdateOrderFeesType) => void
}
const UpdateOrderFeesModal: FC<UpdateOrderFeesModalProps> = ({
isOpen,
onClose,
order,
isLoading,
onSubmit,
}) => {
const [deliveryFee, setDeliveryFee] = useState(String(order.deliveryFee ?? 0))
const [packingFee, setPackingFee] = useState(String(order.packingFee ?? 0))
const [prepareTime, setPrepareTime] = useState(
order.prepareTime != null ? String(order.prepareTime) : ''
)
useEffect(() => {
if (!isOpen) return
setDeliveryFee(String(order.deliveryFee ?? 0))
setPackingFee(String(order.packingFee ?? 0))
setPrepareTime(order.prepareTime != null ? String(order.prepareTime) : '')
}, [isOpen, order.deliveryFee, order.packingFee, order.prepareTime])
const handleSubmit = () => {
onSubmit({
deliveryFee: Math.max(Number(deliveryFee) || 0, 0),
packingFee: Math.max(Number(packingFee) || 0, 0),
prepareTime: Math.max(Number(prepareTime) || 0, 0),
})
}
return (
<DefaulModal
open={isOpen}
close={onClose}
isHeader
title_header='ویرایش هزینه‌ها'
width={420}
>
<div className='mt-6 space-y-4'>
<Input
label='هزینه ارسال (تومان)'
type='number'
inputMode='numeric'
min={0}
seprator
value={deliveryFee}
onChange={(e) => setDeliveryFee(e.target.value)}
/>
<Input
label='هزینه بسته‌بندی (تومان)'
type='number'
inputMode='numeric'
min={0}
seprator
value={packingFee}
onChange={(e) => setPackingFee(e.target.value)}
/>
<Input
label='زمان آماده‌سازی (دقیقه)'
type='number'
inputMode='numeric'
min={0}
value={prepareTime}
onChange={(e) => setPrepareTime(e.target.value)}
placeholder='مثلاً ۳۰'
/>
<div className='flex gap-4 justify-center pt-4'>
<Button
label='ذخیره'
onClick={handleSubmit}
isloading={isLoading}
/>
<Button
label='انصراف'
className='bg-transparent text-black border border-primary'
onClick={onClose}
/>
</div>
</div>
</DefaulModal>
)
}
export default UpdateOrderFeesModal
+18
View File
@@ -1,6 +1,7 @@
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import * as api from "../service/OrderService"; import * as api from "../service/OrderService";
import type { GetOrdersParams, ChangeOrderStatusParams, RefundPaymentParams } from "../service/OrderService"; import type { GetOrdersParams, ChangeOrderStatusParams, RefundPaymentParams } from "../service/OrderService";
import type { UpdateOrderFeesType } from "../types/Types";
export const useCreateOrder = () => { export const useCreateOrder = () => {
const queryClient = useQueryClient(); const queryClient = useQueryClient();
@@ -72,3 +73,20 @@ export const useRefundPayment = () => {
}, },
}); });
}; };
export const useUpdateOrderFees = () => {
const queryClient = useQueryClient();
return useMutation({
mutationFn: ({
orderId,
params,
}: {
orderId: string;
params: UpdateOrderFeesType;
}) => api.updateOrderFees(orderId, params),
onSuccess: (_, { orderId }) => {
queryClient.invalidateQueries({ queryKey: ["order", orderId] });
queryClient.invalidateQueries({ queryKey: ["orders"] });
},
});
};
+12
View File
@@ -6,6 +6,7 @@ import type {
GetDailyOrderReportResponse, GetDailyOrderReportResponse,
CreateOrderType, CreateOrderType,
CreateOrderResponse, CreateOrderResponse,
UpdateOrderFeesType,
} from "../types/Types"; } from "../types/Types";
export interface GetOrdersParams { export interface GetOrdersParams {
@@ -100,6 +101,17 @@ export const refundPayment = async (
await axios.post(`/admin/orders/${orderId}/refund`, params); await axios.post(`/admin/orders/${orderId}/refund`, params);
}; };
export const updateOrderFees = async (
orderId: string,
params: UpdateOrderFeesType
): Promise<GetOrderByIdResponse> => {
const { data } = await axios.patch<GetOrderByIdResponse>(
`/admin/orders/${orderId}/fees`,
params
);
return data;
};
export interface GetFoodOrderReportParams { export interface GetFoodOrderReportParams {
from?: string; from?: string;
to?: string; to?: string;
+8
View File
@@ -207,6 +207,8 @@ export interface Order extends RowDataType {
subTotal: number; subTotal: number;
tax: number; tax: number;
deliveryFee: number; deliveryFee: number;
packingFee: number;
prepareTime?: number | null;
total: number; total: number;
totalItems: number; totalItems: number;
description: string; description: string;
@@ -218,6 +220,12 @@ export interface Order extends RowDataType {
items: OrderItem[]; items: OrderItem[];
} }
export interface UpdateOrderFeesType {
deliveryFee?: number;
packingFee?: number;
prepareTime?: number;
}
export type PaginationMeta = { export type PaginationMeta = {
total: number; total: number;
page: number; page: number;