255 lines
11 KiB
TypeScript
255 lines
11 KiB
TypeScript
"use client";
|
||
|
||
import Button from "@/components/button/PrimaryButton";
|
||
import { toast } from "@/components/Toast";
|
||
import { Skeleton } from "@/components/ui/skeleton";
|
||
import Prompt from "@/components/utils/Prompt";
|
||
import useToggle from "@/hooks/helpers/useToggle";
|
||
import { extractErrorMessage } from "@/lib/func";
|
||
import ordersTranslations from "@/locales/fa/orders.json";
|
||
import { useQueryClient } from "@tanstack/react-query";
|
||
import clsx from "clsx";
|
||
import { Clock } from "iconsax-react";
|
||
import Image from "next/image";
|
||
import { useParams, useRouter } from "next/navigation";
|
||
import React from "react";
|
||
import { OrderStatus } from "../../checkout/enum/Enum";
|
||
import { useCancelOrder, useGetOrderDetail } from "../../checkout/hooks/useOrderData";
|
||
|
||
const getDeliveryMethodTitle = (method: string) => {
|
||
switch (method) {
|
||
case "deliveryCourier":
|
||
return "ارسال توسط پیک";
|
||
case "deliveryCar":
|
||
return "تحویل به خودرو";
|
||
case "pickup":
|
||
return "تحویل حضوری";
|
||
case "dineIn":
|
||
return "سرو در رستوران";
|
||
default:
|
||
return "روش ارسال";
|
||
}
|
||
};
|
||
|
||
const getPaymentMethodTitle = (method: string, fallback?: string) => {
|
||
const methodKey = method as keyof typeof ordersTranslations.paymentMethod;
|
||
return ordersTranslations.paymentMethod[methodKey] || fallback || "نامشخص";
|
||
};
|
||
|
||
// 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] || "نامشخص";
|
||
};
|
||
|
||
const formatDate = (dateString: string): string => {
|
||
const date = new Date(dateString);
|
||
return date.toLocaleDateString("fa-IR", {
|
||
year: "numeric",
|
||
month: "long",
|
||
day: "numeric",
|
||
});
|
||
};
|
||
|
||
// const formatTime = (dateString: string): string => {
|
||
// const date = new Date(dateString);
|
||
// return date.toLocaleTimeString('fa-IR', {
|
||
// hour: '2-digit',
|
||
// minute: '2-digit'
|
||
// });
|
||
// };
|
||
|
||
function OrderTrackingPage() {
|
||
const { id, name } = useParams();
|
||
const router = useRouter();
|
||
const queryClient = useQueryClient();
|
||
const { state: cancelModal, toggle: toggleCancelModal } = useToggle();
|
||
const { data: orderDetail, isLoading } = useGetOrderDetail(id as string);
|
||
const { mutate: cancelOrder } = useCancelOrder();
|
||
|
||
const onCancelOrder = (e: React.MouseEvent | null) => {
|
||
if (!e || !id) return;
|
||
|
||
cancelOrder(id as string, {
|
||
onSuccess: () => {
|
||
toggleCancelModal();
|
||
queryClient.invalidateQueries({ queryKey: ["order-detail", id] });
|
||
toast("سفارش با موفقیت لغو شد", "success");
|
||
},
|
||
onError: (error) => {
|
||
toast(extractErrorMessage(error), "error");
|
||
},
|
||
});
|
||
};
|
||
|
||
return (
|
||
<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="flex flex-col">
|
||
<div className="flex justify-between items-center h-16 border-b border-border">
|
||
<span className="text-sm text-muted-foreground flex items-center gap-2">
|
||
<Clock className="stroke-current" size={16} />
|
||
زمان سفارش
|
||
</span>
|
||
<div className="flex items-end gap-0.5">
|
||
<span className="text-sm font-semibold">{formatDate(orderDetail.data.createdAt)}</span>
|
||
{/* <span className='text-xs text-muted-foreground'>{formatTime(orderDetail.data.createdAt)}</span> */}
|
||
</div>
|
||
</div>
|
||
<div className="flex justify-between items-center h-16 border-b border-border">
|
||
<span className="text-sm text-muted-foreground">زمان آمادهسازی</span>
|
||
<span className="text-sm font-semibold">
|
||
{orderDetail.data.prepareTime
|
||
? `${orderDetail.data.prepareTime.toLocaleString("fa-IR")} دقیقه`
|
||
: "-"}
|
||
</span>
|
||
</div>
|
||
<div className="flex justify-between items-center h-16 border-b border-border">
|
||
<span className="text-sm text-muted-foreground">نوع ارسال</span>
|
||
<span className="text-sm font-semibold">{orderDetail.data?.deliveryMethod?.description}</span>
|
||
</div>
|
||
{orderDetail.data.carAddress && (
|
||
<div className="flex justify-between items-center h-16 border-b border-border">
|
||
<div className="text-sm text-muted-foreground mb-1">اطلاعات خودرو</div>
|
||
<div className="text-sm font-semibold">
|
||
{orderDetail.data.carAddress.carModel} {orderDetail.data.carAddress.carColor} - پلاک: {orderDetail.data.carAddress.plateNumber}
|
||
</div>
|
||
</div>
|
||
)}
|
||
<div className="flex justify-between items-center h-16 border-b border-border">
|
||
<span className="text-sm text-muted-foreground">شماره سفارش</span>
|
||
<span className="text-sm font-semibold">#{orderDetail.data.orderNumber}</span>
|
||
</div>
|
||
<div className="flex justify-between items-center h-16 border-b border-border">
|
||
<span className="text-sm text-muted-foreground">وضعیت سفارش</span>
|
||
<span className="text-sm font-semibold">{getStatusText(orderDetail.data.status)}</span>
|
||
</div>
|
||
|
||
{orderDetail.data.tableNumber && (
|
||
<div className="flex justify-between items-center h-16 border-b border-border">
|
||
<span className="text-sm text-muted-foreground">شماره میز</span>
|
||
<span className="text-sm 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>
|
||
)}
|
||
|
||
{orderDetail.data.paymentMethod && (
|
||
<div className="flex justify-between items-center h-16 border-b border-border">
|
||
<span className="text-sm text-muted-foreground">نوع پرداخت</span>
|
||
<span className="text-sm font-semibold">{getPaymentMethodTitle(orderDetail.data.paymentMethod.method, orderDetail.data.paymentMethod.description)}</span>
|
||
</div>
|
||
)}
|
||
|
||
{orderDetail.data.payments?.[0]?.description?.trim() && (
|
||
<div className="py-3 border-b border-border">
|
||
<div className="text-sm text-muted-foreground mb-1">توضیحات پرداخت</div>
|
||
<div className="text-sm">{orderDetail.data.payments[0].description}</div>
|
||
</div>
|
||
)}
|
||
|
||
{orderDetail.data.payments?.[0]?.attachments?.length ? (
|
||
<div className="py-3 border-b border-border">
|
||
<div className="text-sm text-muted-foreground mb-2">پیوست پرداخت</div>
|
||
<div className="flex flex-col gap-2">
|
||
{orderDetail.data.payments[0].attachments.map((attachment, index) => (
|
||
<div key={attachment} className="relative w-full h-40 rounded-normal overflow-hidden border border-border">
|
||
<Image src={attachment} alt={`پیوست پرداخت ${index + 1}`} fill className="object-contain" />
|
||
</div>
|
||
))}
|
||
</div>
|
||
</div>
|
||
) : null}
|
||
|
||
<div className="flex justify-between items-center py-4 border-t border-border">
|
||
<span className="text-sm font-medium">مجموع سفارش</span>
|
||
<span className="text-sm font-bold ">{orderDetail.data.total.toLocaleString("fa-IR")} تومان</span>
|
||
</div>
|
||
</div>
|
||
</>
|
||
) : (
|
||
<div className="text-center text-muted-foreground py-12">اطلاعات سفارش یافت نشد</div>
|
||
)}
|
||
</div>
|
||
</div>
|
||
|
||
<div className="p-4 border-t border-border bg-container">
|
||
<div className="max-w-2xl mx-auto grid grid-cols-2 gap-4">
|
||
<Button className="dark:bg-white dark:text-black! dark:hover:bg-gray-100" onClick={() => router.push(`/${name}`)} type="button">
|
||
بازگشت به منو
|
||
</Button>
|
||
<Button
|
||
type="submit"
|
||
onClick={toggleCancelModal}
|
||
className="bg-disabled! text-foreground!"
|
||
disabled={
|
||
orderDetail?.data?.status === 'cancelled' ||
|
||
orderDetail?.data?.status === "delivered" ||
|
||
orderDetail?.data?.status === "delivering"
|
||
}
|
||
>
|
||
لغو سفارش
|
||
</Button>
|
||
</div>
|
||
</div>
|
||
|
||
<div className={clsx("fixed inset-0 z-1001", !cancelModal && "pointer-events-none")}>
|
||
<Prompt
|
||
title={"لغو سفارش"}
|
||
description={"آیا از درخواست خود اطمینان دارید؟"}
|
||
textConfirm={"بله"}
|
||
textCancel={"منصرف شدم"}
|
||
onConfirm={onCancelOrder}
|
||
visible={cancelModal}
|
||
onClick={toggleCancelModal}
|
||
onCancel={toggleCancelModal}
|
||
/>
|
||
</div>
|
||
</div>
|
||
);
|
||
}
|
||
|
||
export default OrderTrackingPage;
|