detail of order
This commit is contained in:
@@ -0,0 +1,14 @@
|
|||||||
|
export const enum OrderStatus {
|
||||||
|
NEW = "new",
|
||||||
|
PENDING_PAYMENT = "pendingPayment",
|
||||||
|
PAID = "paid",
|
||||||
|
CONFIRMED = "confirmed",
|
||||||
|
PREPARING = "preparing",
|
||||||
|
READY = "ready",
|
||||||
|
SHIPPED = "shipped",
|
||||||
|
COMPLETED = "completed",
|
||||||
|
|
||||||
|
CANCELED = "canceled",
|
||||||
|
FAILED = "failed",
|
||||||
|
REFUNDED = "refunded",
|
||||||
|
}
|
||||||
@@ -9,6 +9,8 @@ import {
|
|||||||
applyCoupon,
|
applyCoupon,
|
||||||
removeCoupon,
|
removeCoupon,
|
||||||
setTableNumber,
|
setTableNumber,
|
||||||
|
getOrderDetail,
|
||||||
|
cancelOrder,
|
||||||
} from "../service/OrderService";
|
} from "../service/OrderService";
|
||||||
|
|
||||||
export const useGetShipmentMethod = () => {
|
export const useGetShipmentMethod = () => {
|
||||||
@@ -76,3 +78,17 @@ export const useSetTableNumber = () => {
|
|||||||
mutationFn: setTableNumber,
|
mutationFn: setTableNumber,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const useGetOrderDetail = (id: string) => {
|
||||||
|
return useQuery({
|
||||||
|
queryKey: ["order-detail", id],
|
||||||
|
queryFn: () => getOrderDetail(id),
|
||||||
|
enabled: !!id,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useCancelOrder = () => {
|
||||||
|
return useMutation({
|
||||||
|
mutationFn: cancelOrder,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import {
|
|||||||
ShipmentMethodsResponse,
|
ShipmentMethodsResponse,
|
||||||
PaymentMethodsResponse,
|
PaymentMethodsResponse,
|
||||||
CreateOrderResponse,
|
CreateOrderResponse,
|
||||||
|
OrderDetailResponse,
|
||||||
} from "../types/Types";
|
} from "../types/Types";
|
||||||
|
|
||||||
export const getShipmentMethod = async (): Promise<ShipmentMethodsResponse> => {
|
export const getShipmentMethod = async (): Promise<ShipmentMethodsResponse> => {
|
||||||
@@ -59,3 +60,15 @@ export const setTableNumber = async (number: number) => {
|
|||||||
});
|
});
|
||||||
return data;
|
return data;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const getOrderDetail = async (
|
||||||
|
id: string
|
||||||
|
): Promise<OrderDetailResponse> => {
|
||||||
|
const { data } = await api.get<OrderDetailResponse>(`/public/orders/${id}`);
|
||||||
|
return data;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const cancelOrder = async (id: string) => {
|
||||||
|
const { data } = await api.patch(`/public/orders/${id}/cancel`);
|
||||||
|
return data;
|
||||||
|
};
|
||||||
|
|||||||
@@ -250,3 +250,163 @@ export interface CreateOrderData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export type CreateOrderResponse = BaseResponse<CreateOrderData>;
|
export type CreateOrderResponse = BaseResponse<CreateOrderData>;
|
||||||
|
|
||||||
|
export interface OrderDetailUser {
|
||||||
|
id: string;
|
||||||
|
createdAt: string;
|
||||||
|
updatedAt: string;
|
||||||
|
deletedAt: string | null;
|
||||||
|
firstName: string;
|
||||||
|
lastName: string;
|
||||||
|
birthDate: string;
|
||||||
|
marriageDate: string;
|
||||||
|
referrer: string | null;
|
||||||
|
isActive: boolean;
|
||||||
|
gender: boolean;
|
||||||
|
avatarUrl: string | null;
|
||||||
|
phone: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface RestaurantScore {
|
||||||
|
scoreAmount: string;
|
||||||
|
scoreCredit: string;
|
||||||
|
birthdayScore: string;
|
||||||
|
purchaseScore: string;
|
||||||
|
referrerScore: string;
|
||||||
|
registerScore: string;
|
||||||
|
purchaseAmount: string;
|
||||||
|
marriageDateScore: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface OrderDetailRestaurant {
|
||||||
|
id: string;
|
||||||
|
createdAt: string;
|
||||||
|
updatedAt: string;
|
||||||
|
deletedAt: string | null;
|
||||||
|
name: string;
|
||||||
|
slug: string;
|
||||||
|
logo: string | null;
|
||||||
|
address: string | null;
|
||||||
|
menuColor: string | null;
|
||||||
|
latitude: number | null;
|
||||||
|
longitude: number | null;
|
||||||
|
serviceArea: ServiceArea;
|
||||||
|
isActive: boolean;
|
||||||
|
establishedYear: number | null;
|
||||||
|
phone: string;
|
||||||
|
instagram: string | null;
|
||||||
|
telegram: string | null;
|
||||||
|
whatsapp: string | null;
|
||||||
|
description: string | null;
|
||||||
|
seoTitle: string | null;
|
||||||
|
seoDescription: string | null;
|
||||||
|
tagNames: string | null;
|
||||||
|
images: string | null;
|
||||||
|
vat: number;
|
||||||
|
domain: string;
|
||||||
|
score: RestaurantScore;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface OrderDetailDeliveryMethod {
|
||||||
|
id: string;
|
||||||
|
createdAt: string;
|
||||||
|
updatedAt: string;
|
||||||
|
deletedAt: string | null;
|
||||||
|
method: "dineIn" | "pickup" | "deliveryCar" | "deliveryCourier";
|
||||||
|
restaurant: string;
|
||||||
|
deliveryFee: number;
|
||||||
|
deliveryFeeType: "fixed" | "percentage";
|
||||||
|
kilometerNumber: number | null;
|
||||||
|
deliveryFeeForKilometer: number | null;
|
||||||
|
minOrderPrice: number;
|
||||||
|
description: string;
|
||||||
|
enabled: boolean;
|
||||||
|
order: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface OrderDetailPaymentMethod {
|
||||||
|
id: string;
|
||||||
|
createdAt: string;
|
||||||
|
updatedAt: string;
|
||||||
|
deletedAt: string | null;
|
||||||
|
restaurant: string;
|
||||||
|
method: "CardOnDelivery" | "Cash" | "Online";
|
||||||
|
gateway: string | null;
|
||||||
|
description: string;
|
||||||
|
enabled: boolean;
|
||||||
|
order: number;
|
||||||
|
merchantId: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface OrderDetailFood {
|
||||||
|
id: string;
|
||||||
|
createdAt: string;
|
||||||
|
updatedAt: string;
|
||||||
|
deletedAt: string | null;
|
||||||
|
restaurant: string;
|
||||||
|
category: string;
|
||||||
|
title: string;
|
||||||
|
desc: string;
|
||||||
|
content: string[];
|
||||||
|
price: number;
|
||||||
|
order: number | null;
|
||||||
|
prepareTime: number | null;
|
||||||
|
weekDays: number[];
|
||||||
|
mealTypes: string[];
|
||||||
|
isActive: boolean;
|
||||||
|
images: string[];
|
||||||
|
inPlaceServe: boolean;
|
||||||
|
pickupServe: boolean;
|
||||||
|
score: number;
|
||||||
|
discount: number;
|
||||||
|
isSpecialOffer: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface OrderDetailItem {
|
||||||
|
id: string;
|
||||||
|
createdAt: string;
|
||||||
|
updatedAt: string;
|
||||||
|
deletedAt: string | null;
|
||||||
|
order: string;
|
||||||
|
food: OrderDetailFood;
|
||||||
|
quantity: number;
|
||||||
|
unitPrice: number;
|
||||||
|
discount: number;
|
||||||
|
totalPrice: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface OrderDetail {
|
||||||
|
id: string;
|
||||||
|
createdAt: string;
|
||||||
|
updatedAt: string;
|
||||||
|
deletedAt: string | null;
|
||||||
|
user: OrderDetailUser;
|
||||||
|
restaurant: OrderDetailRestaurant;
|
||||||
|
deliveryMethod: OrderDetailDeliveryMethod;
|
||||||
|
userAddress: OrderAddress | null;
|
||||||
|
carAddress: string | null;
|
||||||
|
paymentMethod: OrderDetailPaymentMethod;
|
||||||
|
orderNumber: number;
|
||||||
|
couponDiscount: number;
|
||||||
|
couponDetail: string | null;
|
||||||
|
itemsDiscount: number;
|
||||||
|
totalDiscount: number;
|
||||||
|
subTotal: number;
|
||||||
|
tax: number;
|
||||||
|
deliveryFee: number;
|
||||||
|
total: number;
|
||||||
|
totalItems: number;
|
||||||
|
description: string | null;
|
||||||
|
tableNumber: string;
|
||||||
|
status:
|
||||||
|
| "new"
|
||||||
|
| "preparing"
|
||||||
|
| "ready"
|
||||||
|
| "delivering"
|
||||||
|
| "delivered"
|
||||||
|
| "cancelled";
|
||||||
|
paymentStatus: "pending" | "paid" | "failed" | "refunded";
|
||||||
|
items: OrderDetailItem[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export type OrderDetailResponse = BaseResponse<OrderDetail>;
|
||||||
|
|||||||
@@ -1,163 +1,177 @@
|
|||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { useParams, useRouter, useSearchParams } from 'next/navigation';
|
import { useParams, useRouter } from 'next/navigation';
|
||||||
import React, { useState, useEffect } from 'react';
|
import React from 'react';
|
||||||
import dynamic from 'next/dynamic';
|
|
||||||
import AnimatedBottomSheet from '@/components/bottomsheet/AnimatedBottomSheet';
|
|
||||||
import Button from '@/components/button/PrimaryButton';
|
import Button from '@/components/button/PrimaryButton';
|
||||||
import { Skeleton } from '@/components/ui/skeleton';
|
import { Skeleton } from '@/components/ui/skeleton';
|
||||||
import { MarkerData } from '@/app/[name]/(Profile)/profile/address/types/Types';
|
|
||||||
import { HandPlatter, Package } from 'lucide-react';
|
import { HandPlatter, Package } from 'lucide-react';
|
||||||
import AnimatedBar from '@/components/utils/AnimatedBar';
|
import AnimatedBar from '@/components/utils/AnimatedBar';
|
||||||
import { Clock } from 'iconsax-react';
|
import { Clock } from 'iconsax-react';
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import useToggle from '@/hooks/helpers/useToggle';
|
import useToggle from '@/hooks/helpers/useToggle';
|
||||||
import Prompt from '@/components/utils/Prompt';
|
import Prompt from '@/components/utils/Prompt';
|
||||||
|
import { useGetOrderDetail } from '../../checkout/hooks/useOrderData';
|
||||||
|
import ordersTranslations from '@/locales/fa/orders.json';
|
||||||
|
|
||||||
const CustomMap = dynamic(
|
const getDeliveryMethodTitle = (method: string) => {
|
||||||
() => import('@/components/map/CustomMap'),
|
switch (method) {
|
||||||
{ ssr: false } // Leaflet requires browser APIs
|
case 'deliveryCourier':
|
||||||
);
|
return 'ارسال توسط پیک رستوران';
|
||||||
|
case 'deliveryCar':
|
||||||
|
return 'ارسال توسط خودرو';
|
||||||
|
case 'pickup':
|
||||||
|
return 'تحویل حضوری';
|
||||||
|
case 'dineIn':
|
||||||
|
return 'سرو در محل';
|
||||||
|
default:
|
||||||
|
return 'روش ارسال';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const getStatusPercentage = (status: string) => {
|
||||||
|
switch (status) {
|
||||||
|
case 'new':
|
||||||
|
case 'pendingPayment':
|
||||||
|
return 0;
|
||||||
|
case 'paid':
|
||||||
|
case 'confirmed':
|
||||||
|
return 20;
|
||||||
|
case 'preparing':
|
||||||
|
return 40;
|
||||||
|
case 'ready':
|
||||||
|
return 60;
|
||||||
|
case 'shipped':
|
||||||
|
case 'delivering':
|
||||||
|
return 80;
|
||||||
|
case 'completed':
|
||||||
|
case 'delivered':
|
||||||
|
return 100;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const getStatusText = (status: string): string => {
|
||||||
|
const statusKey = status as keyof typeof ordersTranslations.status;
|
||||||
|
return ordersTranslations.status[statusKey] || 'نامشخص';
|
||||||
|
};
|
||||||
|
|
||||||
function OrderTrackingPage() {
|
function OrderTrackingPage() {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
||||||
const { id } = useParams();
|
const { id } = useParams();
|
||||||
const params = useSearchParams();
|
|
||||||
// const [selectedPosition, setSelectedPosition] = useState<[number, number] | null>(null);
|
|
||||||
// const [selectedAddress, setSelectedAddress] = useState<NominatimReverseGeocodingResponse | null>(null);
|
|
||||||
const [markers, setMarkers] = useState<MarkerData[]>([]);
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
||||||
const [mapCenter, setMapCenter] = useState<[number, number]>([Number(params?.get('lon')) || 35.6892, Number(params?.get('lon')) || 51.3890]);
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { state: cancelModal, toggle: toggleCancelModal } = useToggle();
|
const { state: cancelModal, toggle: toggleCancelModal } = useToggle();
|
||||||
|
const { data: orderDetail, isLoading } = useGetOrderDetail(id as string);
|
||||||
useEffect(() => {
|
|
||||||
// Initialize markers on the client side
|
|
||||||
const initializeMarkers = async () => {
|
|
||||||
// Dynamic import of Leaflet on the client side
|
|
||||||
const L = (await import('leaflet')).default;
|
|
||||||
|
|
||||||
const iconHtml = `
|
|
||||||
<div style="display: flex; flex-direction: column; align-items: center; text-align: center;">
|
|
||||||
<img src="/icons/restaurant-marker.svg" alt="موقعیت رستوران" style="width: 24px; height: 30px; display: block;" />
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
|
|
||||||
setMarkers([
|
|
||||||
{
|
|
||||||
position: mapCenter,
|
|
||||||
title: 'موقعیت رستوران',
|
|
||||||
icon: L.divIcon({
|
|
||||||
html: iconHtml,
|
|
||||||
className: 'custom-restaurant-marker',
|
|
||||||
iconSize: [32, 32],
|
|
||||||
iconAnchor: [16, 32],
|
|
||||||
popupAnchor: [0, -32],
|
|
||||||
})
|
|
||||||
}
|
|
||||||
]);
|
|
||||||
};
|
|
||||||
|
|
||||||
initializeMarkers();
|
|
||||||
}, [mapCenter]);
|
|
||||||
|
|
||||||
|
|
||||||
const handleZoomChange = (zoom: number) => {
|
|
||||||
console.log('Zoom level:', zoom);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleMapClick = (e: L.LeafletMouseEvent) => {
|
|
||||||
console.log('Map clicked at:', e.latlng);
|
|
||||||
};
|
|
||||||
|
|
||||||
const onCancelOrder = (e: React.MouseEvent | null) => {
|
const onCancelOrder = (e: React.MouseEvent | null) => {
|
||||||
if (!e) return;
|
if (!e) return;
|
||||||
|
// TODO: Implement cancel order logic
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="fixed inset-0 bg-gray-50">
|
<div className="fixed inset-0 bg-container flex flex-col">
|
||||||
|
<div className='flex-1 overflow-y-auto px-4 py-6'>
|
||||||
|
<div className='max-w-2xl mx-auto flex flex-col gap-6'>
|
||||||
|
{isLoading ? (
|
||||||
|
<>
|
||||||
|
<Skeleton className='h-6 w-48 mx-auto' />
|
||||||
|
<div className='flex flex-col gap-4'>
|
||||||
|
<Skeleton className='h-5 w-full' />
|
||||||
|
<Skeleton className='h-5 w-full' />
|
||||||
|
<Skeleton className='h-20 w-full' />
|
||||||
|
<Skeleton className='h-5 w-full' />
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
) : orderDetail?.data ? (
|
||||||
|
<>
|
||||||
|
<h1 className='text-lg font-semibold text-center'>
|
||||||
|
{getDeliveryMethodTitle(orderDetail.data.deliveryMethod.method)}
|
||||||
|
</h1>
|
||||||
|
|
||||||
<div className="absolute inset-0">
|
<div className='flex flex-col gap-4'>
|
||||||
<CustomMap
|
<div className='flex justify-between items-center py-3 border-b border-border'>
|
||||||
initialPosition={mapCenter}
|
<span className='text-sm text-muted-foreground'>شماره سفارش</span>
|
||||||
zoom={14}
|
<span className='text-base font-semibold'>#{orderDetail.data.orderNumber}</span>
|
||||||
markers={markers}
|
</div>
|
||||||
onZoomChange={handleZoomChange}
|
|
||||||
onClick={handleMapClick}
|
{orderDetail.data.tableNumber && (
|
||||||
markerActive={false}
|
<div className='flex justify-between items-center py-3 border-b border-border'>
|
||||||
searchEnabled={false}
|
<span className='text-sm text-muted-foreground'>شماره میز</span>
|
||||||
/>
|
<span className='text-base font-semibold'>{orderDetail.data.tableNumber}</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{orderDetail.data.userAddress && (
|
||||||
|
<div className='py-3 border-b border-border'>
|
||||||
|
<div className='text-sm text-muted-foreground mb-1'>آدرس تحویل</div>
|
||||||
|
<div className='text-sm'>{orderDetail.data.userAddress.address}</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<div className='py-4 bg-card rounded-lg flex flex-col gap-4'>
|
||||||
|
<div className='px-4'>
|
||||||
|
<div className='text-xs text-muted-foreground mb-1'>وضعیت سفارش</div>
|
||||||
|
<div className='text-base font-semibold text-primary'>
|
||||||
|
{getStatusText(orderDetail.data.status)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className='px-4 flex gap-2 items-center'>
|
||||||
|
<HandPlatter className='text-muted-foreground' size={24} />
|
||||||
|
<div className='flex-1'>
|
||||||
|
<AnimatedBar percentage={getStatusPercentage(orderDetail.data.status)} />
|
||||||
|
</div>
|
||||||
|
<Package className='text-muted-foreground' size={24} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className='px-4 flex gap-2 items-center text-muted-foreground'>
|
||||||
|
<Clock className='stroke-current' size={20} />
|
||||||
|
<span className='text-sm'>
|
||||||
|
{new Date(orderDetail.data.createdAt).toLocaleDateString('fa-IR', {
|
||||||
|
year: 'numeric',
|
||||||
|
month: 'long',
|
||||||
|
day: 'numeric',
|
||||||
|
hour: '2-digit',
|
||||||
|
minute: '2-digit'
|
||||||
|
})}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className='flex justify-between items-center py-4 border-t border-border'>
|
||||||
|
<span className='text-base font-medium'>مجموع سفارش</span>
|
||||||
|
<span className='text-lg font-bold text-primary'>
|
||||||
|
{orderDetail.data.total.toLocaleString('fa-IR')} تومان
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<div className='text-center text-muted-foreground py-12'>
|
||||||
|
اطلاعات سفارش یافت نشد
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="absolute bottom-0 left-0 right-0 z-[1000]">
|
<div className='p-4 border-t border-border bg-container'>
|
||||||
<div className='relative w-full h-full' >
|
<div className='max-w-2xl mx-auto grid grid-cols-2 gap-4'>
|
||||||
|
<Button
|
||||||
<AnimatedBottomSheet
|
onClick={() => router.back()}
|
||||||
bgOpacity={0}
|
type='button'>
|
||||||
inDuration={0}
|
بازگشت به منو
|
||||||
blurOpacity={null}
|
</Button>
|
||||||
noBlur
|
<Button
|
||||||
visible={true}
|
type='submit'
|
||||||
showCloseButton={false}
|
|
||||||
showTitle={false}
|
|
||||||
title='آدرس'
|
|
||||||
onClick={toggleCancelModal}
|
onClick={toggleCancelModal}
|
||||||
overrideClassName='pt-1! bg-container!'
|
className='bg-disabled! text-foreground!'
|
||||||
|
disabled={
|
||||||
|
orderDetail?.data?.status === 'cancelled' ||
|
||||||
|
orderDetail?.data?.status === 'delivered' ||
|
||||||
|
orderDetail?.data?.status === 'delivering'
|
||||||
|
}
|
||||||
>
|
>
|
||||||
<div className='px-4'>
|
لغو سفارش
|
||||||
<div className='px-4 mt-2 bg-container flex flex-col gap-6'>
|
</Button>
|
||||||
<div className='w-[35px] place-self-center border-2 border-border dark:border-disabled rounded'></div>
|
|
||||||
<h1 className='text-base font-medium text-center'>ارسال توسط پیک رستوران</h1>
|
|
||||||
<hr className='border border-border ' />
|
|
||||||
<div className='text-sm'>
|
|
||||||
<Skeleton
|
|
||||||
className='h-6 w-full'
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className='text-sm2'>
|
|
||||||
<Skeleton
|
|
||||||
className='h-6 w-full'
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<hr className='border border-border' />
|
|
||||||
<div className='text-sm'>
|
|
||||||
<Skeleton
|
|
||||||
className='h-6 w-full'
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className='text-sm2 flex gap-2 items-center'>
|
|
||||||
<Clock className='stroke-primary dark:stroke-neutral-300 size-5' />
|
|
||||||
<Skeleton
|
|
||||||
className='h-6 w-full'
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className='flex gap-2'>
|
|
||||||
<HandPlatter className='text-disabled-text ' size={24} />
|
|
||||||
<AnimatedBar percentage={50} />
|
|
||||||
<Package className='text-disabled-text' size={24} />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className='grid grid-cols-2 gap-4 mt-11'>
|
|
||||||
|
|
||||||
<Button
|
|
||||||
onClick={() => router.back()}
|
|
||||||
type='button'>
|
|
||||||
بازگشت به منو
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
type='submit'
|
|
||||||
onClick={toggleCancelModal}
|
|
||||||
className='bg-disabled! text-foreground!'
|
|
||||||
>
|
|
||||||
لغو سفارش
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</AnimatedBottomSheet>
|
|
||||||
|
|
||||||
{/* Logout Modal */}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -166,7 +180,7 @@ function OrderTrackingPage() {
|
|||||||
!cancelModal && 'pointer-events-none'
|
!cancelModal && 'pointer-events-none'
|
||||||
)}>
|
)}>
|
||||||
<Prompt
|
<Prompt
|
||||||
title={'لفو سفارش'}
|
title={'لغو سفارش'}
|
||||||
description={'آیا از درخواست خود اطمینان دارید؟'}
|
description={'آیا از درخواست خود اطمینان دارید؟'}
|
||||||
textConfirm={'بله'}
|
textConfirm={'بله'}
|
||||||
textCancel={'منصرف شدم'}
|
textCancel={'منصرف شدم'}
|
||||||
|
|||||||
@@ -18,5 +18,21 @@
|
|||||||
"Cash": "پرداخت نقدی",
|
"Cash": "پرداخت نقدی",
|
||||||
"Online": "پرداخت آنلاین",
|
"Online": "پرداخت آنلاین",
|
||||||
"Wallet": "پرداخت با کیف پول"
|
"Wallet": "پرداخت با کیف پول"
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
"new": "سفارش جدید",
|
||||||
|
"pendingPayment": "در انتظار پرداخت",
|
||||||
|
"paid": "پرداخت شده",
|
||||||
|
"confirmed": "تایید شده",
|
||||||
|
"preparing": "در حال آمادهسازی",
|
||||||
|
"ready": "آماده تحویل",
|
||||||
|
"shipped": "ارسال شده",
|
||||||
|
"delivering": "در حال ارسال",
|
||||||
|
"completed": "تکمیل شده",
|
||||||
|
"delivered": "تحویل داده شده",
|
||||||
|
"canceled": "لغو شده",
|
||||||
|
"cancelled": "لغو شده",
|
||||||
|
"failed": "ناموفق",
|
||||||
|
"refunded": "بازگشت وجه"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user