Factor
This commit is contained in:
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user