This commit is contained in:
hamid zarghami
2025-10-29 15:49:11 +03:30
parent 15a36b1adc
commit 364188fbf0
3 changed files with 241 additions and 36 deletions
@@ -1,10 +1,9 @@
'use client'
import React, { useState } from 'react'
import React from 'react'
import { Button } from '@/components/ui/button'
import TrackCode from './TrackCode'
import { Payment, User, ShipmentAddress } from '../../types/Types'
import * as api from '../../service/Service'
import { toast } from '@/components/Toast'
import { useRouter } from 'next/navigation'
interface OrderSidebarProps {
orderData: {
@@ -20,29 +19,7 @@ interface OrderSidebarProps {
}
const OrderSidebar: React.FC<OrderSidebarProps> = ({ orderData, orderId }) => {
const [isLoadingInvoice, setIsLoadingInvoice] = useState(false)
const handleInvoice = async () => {
try {
setIsLoadingInvoice(true)
const blob = await api.getInvoice(orderId.toString())
const url = window.URL.createObjectURL(blob)
const link = document.createElement('a')
link.href = url
link.download = `invoice-${orderId}.pdf`
document.body.appendChild(link)
link.click()
document.body.removeChild(link)
window.URL.revokeObjectURL(url)
toast("فاکتور با موفقیت دانلود شد", "success")
} catch (error) {
toast("مشکلی در دانلود فاکتور رخ داد", "error")
} finally {
setIsLoadingInvoice(false)
}
}
const router = useRouter()
return (
<div className='lg:w-[280px] w-full p-5 rounded-2xl shadow-lg'>
<div className='flex items-center gap-2'>
@@ -92,10 +69,9 @@ const OrderSidebar: React.FC<OrderSidebarProps> = ({ orderData, orderId }) => {
<Button
className='mt-3 w-full'
variant="outline"
onClick={handleInvoice}
disabled={isLoadingInvoice}
onClick={() => router.push(`/profile/orders/${orderId}/invoice`)}
>
{isLoadingInvoice ? 'در حال دانلود...' : 'مشاهده فاکتور'}
مشاهده فاکتور
</Button>
</div>
)
@@ -0,0 +1,236 @@
'use client'
import { useGetOrderDetail } from "@/app/profile/orders/hooks/useOrdersData"
import { NumberFormat, toJalaliDate } from "@/config/func"
import { useRouter, useParams } from "next/navigation"
import { useEffect } from "react"
import Image from "next/image"
import Layout from "@/hoc/Layout"
const OrderInvoicePage = () => {
const { id } = useParams()
const { data, isLoading } = useGetOrderDetail(id as string)
const router = useRouter()
useEffect(() => {
if (!isLoading && !data?.results?.order) {
router.push('/profile/orders')
}
}, [data, isLoading, router])
if (isLoading) {
return (
<div className="flex items-center justify-center min-h-screen">
<div className="text-lg">در حال بارگذاری...</div>
</div>
)
}
const order = data?.results?.order
if (!order) return null
const handlePrint = () => {
window.print()
}
// محاسبه تعداد کل محصولات
const totalItemsCount = order.orderItems.reduce((sum, orderItem) => {
return sum + orderItem.shipmentItems.reduce((itemSum, item) => itemSum + item.quantity, 0)
}, 0)
// محاسبه قیمت‌ها
const totalRetailPrice = order.payment.priceDetails.total_retail_price
const totalDiscount = order.payment.priceDetails.total_discount
const couponDiscount = order.payment.priceDetails.coupon_discount
const shippingCost = order.payment.priceDetails.shipping_cost
const totalPrice = order.payment.totalPrice
return (
<div className="min-h-screen bg-white p-4 sm:p-8">
<div className="max-w-4xl mx-auto">
<div className="no-print mb-6 flex justify-between items-center">
<button
onClick={() => router.back()}
className="px-4 py-2 bg-gray-200 rounded-lg hover:bg-gray-300"
>
بازگشت
</button>
<button
onClick={handlePrint}
className="px-6 py-2 bg-primary text-white rounded-lg hover:bg-primary/90"
>
پرینت فاکتور
</button>
</div>
<div className="bg-white border-2 border-gray-200 rounded-lg p-6 sm:p-8 print:border-0">
<div className="flex items-center justify-between border-b pb-4 mb-6">
<div>
<Image
src="/images/logo.png"
alt="لوگو"
width={120}
height={40}
className="h-10 w-auto"
/>
</div>
<div className="text-left">
<h1 className="text-2xl font-bold mb-2">فاکتور خرید</h1>
<p className="text-sm text-gray-600">
تاریخ: {order.createdAt}
</p>
</div>
</div>
<div className="mb-6 grid grid-cols-2 gap-4 bg-gray-50 p-4 rounded-lg">
<div>
<p className="text-sm text-gray-600">نام و نام خانوادگی</p>
<p className="font-medium">{order.user?.fullName || '-'}</p>
</div>
<div>
<p className="text-sm text-gray-600">شماره تماس</p>
<p className="font-medium">{order.shipmentAddress.phone || '-'}</p>
</div>
<div>
<p className="text-sm text-gray-600">شماره سفارش</p>
<p className="font-medium">{NumberFormat(order._id)}</p>
</div>
<div>
<p className="text-sm text-gray-600">تعداد کالا</p>
<p className="font-medium">{NumberFormat(totalItemsCount)} محصول</p>
</div>
<div className="col-span-2">
<p className="text-sm text-gray-600">آدرس تحویل</p>
<p className="font-medium">
{order.shipmentAddress.province}, {order.shipmentAddress.city}, {order.shipmentAddress.address}
</p>
</div>
<div>
<p className="text-sm text-gray-600">کدپستی</p>
<p className="font-medium">{order.shipmentAddress.postalCode}</p>
</div>
<div>
<p className="text-sm text-gray-600">شناسه تراکنش</p>
<p className="font-medium font-mono">{order.payment.transaction_id || '-'}</p>
</div>
</div>
<div className="mb-6">
<h2 className="text-lg font-bold mb-4">لیست محصولات</h2>
<div className="overflow-x-auto">
<table className="w-full border-collapse">
<thead>
<tr className="bg-gray-100">
<th className="border border-gray-300 p-3 text-right">ردیف</th>
<th className="border border-gray-300 p-3 text-right">محصول</th>
<th className="border border-gray-300 p-3 text-center">تعداد</th>
<th className="border border-gray-300 p-3 text-left">قیمت واحد</th>
<th className="border border-gray-300 p-3 text-left">تخفیف</th>
<th className="border border-gray-300 p-3 text-left">قیمت کل</th>
</tr>
</thead>
<tbody>
{order.orderItems.flatMap((orderItem, orderIndex) =>
orderItem.shipmentItems.map((item, itemIndex) => {
const globalIndex = order.orderItems
.slice(0, orderIndex)
.reduce((sum, oi) => sum + oi.shipmentItems.length, 0) + itemIndex
const retailPrice = item.retail_price
const sellingPrice = item.selling_price
const totalRetail = retailPrice * item.quantity
const totalSelling = sellingPrice * item.quantity
const discount = totalRetail - totalSelling
return (
<tr key={`${orderItem._id}-${item._id}`}>
<td className="border border-gray-300 p-3 text-center">
{NumberFormat(globalIndex + 1)}
</td>
<td className="border border-gray-300 p-3">
<div>
<p className="font-medium">{item.product.title_fa}</p>
<p className="text-xs text-gray-600 mt-1">
فروشنده: {orderItem.shop.shopName}
</p>
{item.variant.warranty && (
<p className="text-xs text-gray-600">
گارانتی: {item.variant.warranty.name}
</p>
)}
</div>
</td>
<td className="border border-gray-300 p-3 text-center">
{NumberFormat(item.quantity)}
</td>
<td className="border border-gray-300 p-3 text-left">
{NumberFormat(retailPrice)} تومان
</td>
<td className="border border-gray-300 p-3 text-left">
{discount > 0 ? `${NumberFormat(discount)} تومان` : '-'}
</td>
<td className="border border-gray-300 p-3 text-left font-medium">
{NumberFormat(totalSelling)} تومان
</td>
</tr>
)
})
)}
</tbody>
</table>
</div>
</div>
<div className="border-t pt-4">
<div className="flex justify-end">
<div className="w-full sm:w-80 space-y-3">
<div className="flex justify-between text-gray-700">
<span>قیمت کالاها:</span>
<span>{NumberFormat(totalRetailPrice)} تومان</span>
</div>
<div className="flex justify-between text-gray-700">
<span>تخفیف:</span>
<span className="text-red-600">
{NumberFormat(totalDiscount)} تومان
</span>
</div>
{couponDiscount > 0 && (
<div className="flex justify-between text-gray-700">
<span>تخفیف کد تخفیف:</span>
<span className="text-red-600">
{NumberFormat(couponDiscount)} تومان
</span>
</div>
)}
<div className="flex justify-between text-gray-700">
<span>هزینه ارسال:</span>
<span>{NumberFormat(shippingCost)} تومان</span>
</div>
<div className="flex justify-between text-xl font-bold border-t pt-3">
<span>جمع کل:</span>
<span className="text-primary">
{NumberFormat(totalPrice)} تومان
</span>
</div>
</div>
</div>
</div>
<div className="mt-8 pt-6 border-t text-center text-sm text-gray-600">
<p>
این فاکتور برای سفارش شماره {NumberFormat(order._id)} صادر شده است.
</p>
</div>
</div>
</div>
</div>
)
}
export default function OrderInvoiceWithLayout() {
return (
<Layout>
<OrderInvoicePage />
</Layout>
)
}
@@ -21,13 +21,6 @@ export const getOrderDetail = async (
return data;
};
export const getInvoice = async (orderId: string) => {
const { data } = await axios.get(`/order/${orderId}/invoice`, {
responseType: "blob",
});
return data;
};
export const getCancelReasons = async (): Promise<CancelReasonsResponse> => {
const { data } = await axios.get(`/cancel/reasons`);
return data;