detail of order
This commit is contained in:
@@ -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={'منصرف شدم'}
|
||||
|
||||
Reference in New Issue
Block a user