Files
dmenu-plus-front/src/app/[name]/(Dialogs)/order/track/[id]/page.tsx
T
morteza 07ea4a961b
Build and Deploy Docker Images / build_and_deploy (push) Has been cancelled
add prepare time
2026-07-19 16:14:23 +03:30

255 lines
11 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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.
"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;