detail order
This commit is contained in:
@@ -25,3 +25,11 @@ export const formatDateShort = (dateString: string): string => {
|
||||
return dateString;
|
||||
}
|
||||
};
|
||||
|
||||
export const formatPrice = (price: number): string => {
|
||||
return new Intl.NumberFormat("fa-IR", {
|
||||
style: "decimal",
|
||||
minimumFractionDigits: 0,
|
||||
maximumFractionDigits: 0,
|
||||
}).format(price);
|
||||
};
|
||||
|
||||
+227
-5
@@ -1,15 +1,237 @@
|
||||
import { type FC } from 'react'
|
||||
// import { useParams } from 'react-router-dom'
|
||||
// import { useGetOrderDetailUser } from './hooks/useOrderData'
|
||||
import { useParams } from 'react-router-dom'
|
||||
import { useGetOrderDetailUser } from './hooks/useOrderData'
|
||||
import PageLoading from '@/components/PageLoading'
|
||||
import { formatDate, formatPrice } from '@/helpers/func'
|
||||
import StatusWithText from '@/components/StatusWithText'
|
||||
import { OrdersStatus, PaymentStatus, OrderItemsStatus } from './enum/Enum'
|
||||
import { Profile, Calendar, Money3, Truck, Box, Location } from 'iconsax-react'
|
||||
|
||||
const OrderDetail: FC = () => {
|
||||
const { id } = useParams()
|
||||
const { data, isLoading, error } = useGetOrderDetailUser(id!)
|
||||
|
||||
// const { id } = useParams()
|
||||
// const { data, isLoading, error } = useGetOrderDetailUser(id!)
|
||||
if (isLoading) {
|
||||
return <PageLoading />
|
||||
}
|
||||
|
||||
if (error) {
|
||||
return (
|
||||
<div className="flex justify-center items-center min-h-96">
|
||||
<div className="text-center">
|
||||
<div className="text-red-500 text-lg mb-2">خطا در بارگذاری دادهها</div>
|
||||
<div className="text-gray-500">لطفا دوباره تلاش کنید</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
if (!data?.results?.order) {
|
||||
return (
|
||||
<div className="flex justify-center items-center min-h-96">
|
||||
<div className="text-center">
|
||||
<div className="text-gray-500 text-lg">سفارش یافت نشد</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const order = data.results.order
|
||||
|
||||
const getOrderStatusVariant = (status: string) => {
|
||||
switch (status) {
|
||||
case OrdersStatus.Delivered:
|
||||
return 'success'
|
||||
case OrdersStatus.Cancelled:
|
||||
case OrdersStatus.cancelled_system:
|
||||
return 'error'
|
||||
default:
|
||||
return 'warning'
|
||||
}
|
||||
}
|
||||
|
||||
const getPaymentStatusVariant = (status: string) => {
|
||||
switch (status) {
|
||||
case PaymentStatus.Completed:
|
||||
return 'success'
|
||||
case PaymentStatus.Cancelled:
|
||||
return 'error'
|
||||
default:
|
||||
return 'warning'
|
||||
}
|
||||
}
|
||||
|
||||
const getOrderItemStatusVariant = (status: string) => {
|
||||
switch (status) {
|
||||
case OrderItemsStatus.Delivered:
|
||||
return 'success'
|
||||
case OrderItemsStatus.Returned:
|
||||
case OrderItemsStatus.cancelled_shop:
|
||||
case OrderItemsStatus.cancelled_system:
|
||||
case OrderItemsStatus.cancelled_user:
|
||||
return 'error'
|
||||
default:
|
||||
return 'warning'
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='mt-4 space-y-6'>
|
||||
{/* هدر */}
|
||||
<div className='flex justify-between items-center'>
|
||||
<div className='flex items-center gap-3'>
|
||||
<h1 className='text-2xl font-bold'>جزئیات سفارش</h1>
|
||||
<StatusWithText
|
||||
variant={getOrderStatusVariant(order.orderStatus)}
|
||||
text={order.orderStatus}
|
||||
/>
|
||||
</div>
|
||||
<div className='text-sm text-gray-600'>
|
||||
شماره سفارش: <span className='font-mono'>#{order._id}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* کارتهای اطلاعاتی */}
|
||||
<div className='grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6'>
|
||||
{/* اطلاعات کاربر */}
|
||||
<div className='bg-white p-6 rounded-3xl'>
|
||||
<div className='flex items-center gap-3 mb-4'>
|
||||
<div className='p-2 bg-blue-100 rounded-xl'>
|
||||
<Profile size={20} color='#3B82F6' />
|
||||
</div>
|
||||
<h3 className='font-medium'>مشتری</h3>
|
||||
</div>
|
||||
<div className='space-y-2'>
|
||||
<div className='text-lg font-semibold'>{order.user.fullName}</div>
|
||||
<div className='text-sm text-gray-600 flex items-center gap-2'>
|
||||
<Calendar size={14} color='#6B7280' />
|
||||
<div className='mt-1 dltr'>
|
||||
{order.createdAt}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* اطلاعات پرداخت */}
|
||||
<div className='bg-white p-6 rounded-3xl'>
|
||||
<div className='flex items-center gap-3 mb-4'>
|
||||
<div className='p-2 bg-green-100 rounded-xl'>
|
||||
<Money3 size={20} color='#10B981' />
|
||||
</div>
|
||||
<h3 className='font-medium'>پرداخت</h3>
|
||||
</div>
|
||||
<div className='space-y-2'>
|
||||
<div className='text-lg font-bold text-green-600'>
|
||||
{formatPrice(order.payment.totalPrice)} تومان
|
||||
</div>
|
||||
<div className='text-sm text-gray-600'>
|
||||
{order.payment.payment_method.title_fa}
|
||||
</div>
|
||||
<StatusWithText
|
||||
variant={getPaymentStatusVariant(order.payment.paymentStatus)}
|
||||
text={order.payment.paymentStatus}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* آدرس ارسال */}
|
||||
<div className='bg-white p-6 rounded-3xl md:col-span-2'>
|
||||
<div className='flex items-center gap-3 mb-4'>
|
||||
<div className='p-2 bg-orange-100 rounded-xl'>
|
||||
<Location size={20} color='#F59E0B' />
|
||||
</div>
|
||||
<h3 className='font-medium'>آدرس ارسال</h3>
|
||||
</div>
|
||||
<div className='space-y-3'>
|
||||
<div className='text-sm leading-relaxed'>{order.shipmentAddress.address}</div>
|
||||
<div className='grid grid-cols-2 gap-4 text-sm text-gray-600'>
|
||||
<div>استان: {order.shipmentAddress.province}</div>
|
||||
<div>شهر: {order.shipmentAddress.city}</div>
|
||||
<div>پلاک: {order.shipmentAddress.plaque}</div>
|
||||
<div>کد پستی: <span className='font-mono'>{order.shipmentAddress.postalCode}</span></div>
|
||||
<div className='col-span-2'>تلفن: {order.shipmentAddress.phone}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* آیتمهای سفارش */}
|
||||
<div className='bg-white py-8 xl:px-10 px-6 rounded-3xl'>
|
||||
<div className='flex items-center gap-3 mb-6'>
|
||||
<div className='p-2 bg-purple-100 rounded-xl'>
|
||||
<Box size={20} color='#8B5CF6' />
|
||||
</div>
|
||||
<h2 className='text-lg font-medium'>آیتمهای سفارش</h2>
|
||||
</div>
|
||||
|
||||
<div className='space-y-6'>
|
||||
{order.orderItems.map((item, index) => (
|
||||
<div key={index} className='border border-gray-100 rounded-xl p-6 bg-gray-50/50'>
|
||||
<div className='flex justify-between items-start mb-6'>
|
||||
<div className='flex items-center gap-3'>
|
||||
<div className='p-2 bg-white rounded-lg'>
|
||||
<Truck size={16} color='#6B7280' />
|
||||
</div>
|
||||
<div>
|
||||
asd
|
||||
<div className='font-medium'>فروشگاه: {item.shop?.shopName}</div>
|
||||
<div className='flex items-center gap-2 mt-1'>
|
||||
<StatusWithText
|
||||
variant={getOrderItemStatusVariant(item.status)}
|
||||
text={item.status}
|
||||
/>
|
||||
{item.trackCode && (
|
||||
<span className='text-xs text-gray-600 font-mono'>
|
||||
کد پیگیری: {item.trackCode}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className='text-left'>
|
||||
<div className='text-sm text-gray-600'>مجموع</div>
|
||||
<div className='font-bold text-lg text-green-600'>
|
||||
{formatPrice(item.totalPaymentPrice)} تومان
|
||||
</div>
|
||||
{item.postingDate && (
|
||||
<div className='text-xs text-gray-600 mt-1'>
|
||||
ارسال: {formatDate(item.postingDate)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* محصولات */}
|
||||
<div className='space-y-3'>
|
||||
{item.shipmentItems.map((product, productIndex) => (
|
||||
<div key={productIndex} className='flex items-center gap-4 p-4 bg-white rounded-lg border border-gray-100'>
|
||||
<div className='flex-1'>
|
||||
<div className='font-medium text-base mb-2'>{product.product.title_fa}</div>
|
||||
<div className='grid grid-cols-2 gap-4 text-sm text-gray-600'>
|
||||
<div>گارانتی: {product.variant.warranty.name}</div>
|
||||
<div>تعداد: {product.quantity}</div>
|
||||
<div>قیمت واحد: {formatPrice(product.selling_price)} تومان</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className='text-left'>
|
||||
<div className='font-bold text-base text-green-600 mb-1'>
|
||||
{formatPrice(product.quantity * product.selling_price)} تومان
|
||||
</div>
|
||||
{product.discount_percent > 0 && (
|
||||
<div className='text-sm text-green-600'>
|
||||
تخفیف: {product.discount_percent}%
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
import axios from "../../../config/axios";
|
||||
import type { NativeOrdersResponseType } from "../types/Types";
|
||||
import type {
|
||||
NativeOrdersResponseType,
|
||||
OrderDetailResponseType,
|
||||
} from "../types/Types";
|
||||
|
||||
export const getNativeOrders = async (
|
||||
page: number = 1,
|
||||
@@ -21,7 +24,9 @@ export const getSellerOrders = async (
|
||||
return data;
|
||||
};
|
||||
|
||||
export const getOrderDetailUser = async (id: string) => {
|
||||
const { data } = await axios.get(`/order/${id}/user`);
|
||||
export const getOrderDetailUser = async (
|
||||
id: string
|
||||
): Promise<OrderDetailResponseType> => {
|
||||
const { data } = await axios.get(`/admin/orders/${id}/user`);
|
||||
return data;
|
||||
};
|
||||
|
||||
@@ -93,7 +93,7 @@ export type ProductType = {
|
||||
specifications: SpecificationType[];
|
||||
brand: BrandType;
|
||||
category: CategoryType;
|
||||
variants: string[];
|
||||
variants: { _id: string }[];
|
||||
};
|
||||
|
||||
export type ImagesUrlType = {
|
||||
@@ -114,6 +114,18 @@ export type CategoryType = {
|
||||
_id: string;
|
||||
};
|
||||
|
||||
export type WarrantyType = {
|
||||
_id: number;
|
||||
duration: string;
|
||||
logoUrl: string;
|
||||
name: string;
|
||||
};
|
||||
|
||||
export type MeterageType = {
|
||||
_id: number;
|
||||
value: string;
|
||||
};
|
||||
|
||||
export type VariantType = {
|
||||
_id: string;
|
||||
market_status: string;
|
||||
@@ -123,10 +135,8 @@ export type VariantType = {
|
||||
isFreeShip: boolean;
|
||||
isWholeSale: boolean;
|
||||
shop: ShopType;
|
||||
saleFormat: SaleFormatType;
|
||||
warranty: number;
|
||||
size?: number;
|
||||
meterage?: number;
|
||||
warranty: WarrantyType;
|
||||
meterage: MeterageType;
|
||||
};
|
||||
|
||||
export type PriceType = {
|
||||
@@ -146,6 +156,14 @@ export type SaleFormatType = {
|
||||
|
||||
export type ShopType = {
|
||||
_id: string;
|
||||
shopName?: string;
|
||||
shopCode?: number;
|
||||
owner?: string;
|
||||
shopDescription?: string;
|
||||
telephoneNumber?: string;
|
||||
isChatActive?: boolean;
|
||||
shopPostalCode?: string;
|
||||
logo?: string;
|
||||
};
|
||||
|
||||
export type ShipperType = {
|
||||
@@ -243,3 +261,22 @@ export type NativeOrdersResponseType = {
|
||||
priceRange: PriceRangeType;
|
||||
};
|
||||
};
|
||||
|
||||
// تایپهای مربوط به جزئیات سفارش
|
||||
export type OrderDetailType = {
|
||||
_id: number;
|
||||
user: UserType;
|
||||
payment: PaymentType;
|
||||
orderItems: OrderItemsType[];
|
||||
shipmentAddress: ShipmentAddressType;
|
||||
orderStatus: string;
|
||||
createdAt: string;
|
||||
};
|
||||
|
||||
export type OrderDetailResponseType = {
|
||||
status: number;
|
||||
success: boolean;
|
||||
results: {
|
||||
order: OrderDetailType;
|
||||
};
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user