update design
Build and Deploy Docker Images / build_and_deploy (push) Has been cancelled

This commit is contained in:
hamid zarghami
2026-06-16 08:55:31 +03:30
parent 97e4d81b09
commit fc8ac729f7
3 changed files with 375 additions and 431 deletions
+180 -210
View File
@@ -1,38 +1,38 @@
'use client';
"use client";
import { useParams, useRouter } from 'next/navigation';
import Image from 'next/image';
import React from 'react';
import Button from '@/components/button/PrimaryButton';
import { Skeleton } from '@/components/ui/skeleton';
import { Clock } from 'iconsax-react';
import clsx from 'clsx';
import useToggle from '@/hooks/helpers/useToggle';
import Prompt from '@/components/utils/Prompt';
import { useCancelOrder, useGetOrderDetail } from '../../checkout/hooks/useOrderData';
import ordersTranslations from '@/locales/fa/orders.json';
import { toast } from '@/components/Toast';
import { extractErrorMessage } from '@/lib/func';
import { useQueryClient } from '@tanstack/react-query';
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 { 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 'روش ارسال';
}
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 methodKey = method as keyof typeof ordersTranslations.paymentMethod;
return ordersTranslations.paymentMethod[methodKey] || fallback || "نامشخص";
};
// const getStatusPercentage = (status: string) => {
@@ -59,17 +59,17 @@ const getPaymentMethodTitle = (method: string, fallback?: string) => {
// };
const getStatusText = (status: string): string => {
const statusKey = status as keyof typeof ordersTranslations.status;
return ordersTranslations.status[statusKey] || 'نامشخص';
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 date = new Date(dateString);
return date.toLocaleDateString("fa-IR", {
year: "numeric",
month: "long",
day: "numeric",
});
};
// const formatTime = (dateString: string): string => {
@@ -81,191 +81,161 @@ const formatDate = (dateString: string): string => {
// };
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 { 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) => {
const onCancelOrder = (e: React.MouseEvent | null) => {
if (!e || !id) return;
if (!e || !id) return;
cancelOrder(id as string, {
onSuccess: () => {
toggleCancelModal();
queryClient.invalidateQueries({ queryKey: ["order-detail", id] });
toast("سفارش با موفقیت لغو شد", "success");
},
onError: (error) => {
toast(extractErrorMessage(error), "error");
},
});
};
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>
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?.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>
<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?.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.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.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.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]?.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'>
اطلاعات سفارش یافت نشد
{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>
))}
</div>
</div>
) : null}
<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 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={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>
</>
) : (
<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;
export default OrderTrackingPage;