detail of order

This commit is contained in:
hamid zarghami
2025-12-17 12:08:00 +03:30
parent b34750e907
commit 79aa9b2d88
6 changed files with 366 additions and 133 deletions
+147 -133
View File
@@ -1,163 +1,177 @@
'use client';
import { useParams, useRouter, useSearchParams } from 'next/navigation';
import React, { useState, useEffect } from 'react';
import dynamic from 'next/dynamic';
import AnimatedBottomSheet from '@/components/bottomsheet/AnimatedBottomSheet';
import { useParams, useRouter } from 'next/navigation';
import React from 'react';
import Button from '@/components/button/PrimaryButton';
import { Skeleton } from '@/components/ui/skeleton';
import { MarkerData } from '@/app/[name]/(Profile)/profile/address/types/Types';
import { HandPlatter, Package } from 'lucide-react';
import AnimatedBar from '@/components/utils/AnimatedBar';
import { Clock } from 'iconsax-react';
import clsx from 'clsx';
import useToggle from '@/hooks/helpers/useToggle';
import Prompt from '@/components/utils/Prompt';
import { useGetOrderDetail } from '../../checkout/hooks/useOrderData';
import ordersTranslations from '@/locales/fa/orders.json';
const CustomMap = dynamic(
() => import('@/components/map/CustomMap'),
{ ssr: false } // Leaflet requires browser APIs
);
const getDeliveryMethodTitle = (method: string) => {
switch (method) {
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() {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
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 { state: cancelModal, toggle: toggleCancelModal } = useToggle();
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 { data: orderDetail, isLoading } = useGetOrderDetail(id as string);
const onCancelOrder = (e: React.MouseEvent | null) => {
if (!e) return;
// TODO: Implement cancel order logic
};
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">
<CustomMap
initialPosition={mapCenter}
zoom={14}
markers={markers}
onZoomChange={handleZoomChange}
onClick={handleMapClick}
markerActive={false}
searchEnabled={false}
/>
<div className='flex flex-col gap-4'>
<div className='flex justify-between items-center py-3 border-b border-border'>
<span className='text-sm text-muted-foreground'>شماره سفارش</span>
<span className='text-base font-semibold'>#{orderDetail.data.orderNumber}</span>
</div>
{orderDetail.data.tableNumber && (
<div className='flex justify-between items-center py-3 border-b border-border'>
<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 className="absolute bottom-0 left-0 right-0 z-[1000]">
<div className='relative w-full h-full' >
<AnimatedBottomSheet
bgOpacity={0}
inDuration={0}
blurOpacity={null}
noBlur
visible={true}
showCloseButton={false}
showTitle={false}
title='آدرس'
<div className='p-4 border-t border-border bg-container'>
<div className='max-w-2xl mx-auto grid grid-cols-2 gap-4'>
<Button
onClick={() => router.back()}
type='button'>
بازگشت به منو
</Button>
<Button
type='submit'
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'>
<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 */}
لغو سفارش
</Button>
</div>
</div>
@@ -166,7 +180,7 @@ function OrderTrackingPage() {
!cancelModal && 'pointer-events-none'
)}>
<Prompt
title={فو سفارش'}
title={غو سفارش'}
description={'آیا از درخواست خود اطمینان دارید؟'}
textConfirm={'بله'}
textCancel={'منصرف شدم'}