From 6a3e8fe5e5046702ea56abb0656b9e026769bba7 Mon Sep 17 00:00:00 2001 From: hamid zarghami Date: Sat, 21 Feb 2026 15:39:19 +0330 Subject: [PATCH] detail invoice --- src/pages/invoice/Detail.tsx | 181 ++++++++++++-------- src/pages/invoice/hooks/useInvoiceData.ts | 8 + src/pages/invoice/service/InvoiceService.ts | 14 +- src/pages/invoice/types/InvoiceTypes.ts | 1 + 4 files changed, 133 insertions(+), 71 deletions(-) diff --git a/src/pages/invoice/Detail.tsx b/src/pages/invoice/Detail.tsx index fc6c995..89e089c 100644 --- a/src/pages/invoice/Detail.tsx +++ b/src/pages/invoice/Detail.tsx @@ -4,8 +4,13 @@ import { Printer, TickCircle } from 'iconsax-react' import Button from '@/components/Button' import Table from '@/components/Table' import type { RowDataType } from '@/components/types/TableTypes' +import { useParams } from 'react-router-dom' +import { useGetInvoiceDetail } from './hooks/useInvoiceData' +import { NumberFormat } from '@/config/func' +import moment from 'moment-jalaali' +import type { InvoiceItem as ApiInvoiceItem } from './types/InvoiceTypes' -interface InvoiceItem extends RowDataType { +interface TableInvoiceItem extends RowDataType { id: string image: string | null title: string @@ -16,40 +21,42 @@ interface InvoiceItem extends RowDataType { confirmed: boolean } +const formatPrice = (num: number) => `${NumberFormat(num)} تومان` + const InvoiceDetail: FC = () => { + const { id } = useParams() + const { data, isPending } = useGetInvoiceDetail(id!) + const invoice = data?.data - const invoiceData = { - invoiceNumber: '#۱۲۳۴۵', - confirmDate: '۱۴۰۴/۰۵/۰۳', - customerName: 'آلومینیوم نوین', - orderDate: '۱۴۰۴/۰۵/۰۳', - phoneNumber: '۰۸۶۳۳۲۳۳۳۴۵', - orderNumber: '۰۹۱۲۳۴۵۶۷۸۹', - address: 'لورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپ، و با استفاده از طراحان گرافیک است.لورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپ، و با استفاده از طراحان گرافیک است.', - } - - const items: InvoiceItem[] = [ - { - id: '1', - image: null, - title: 'شاپینگ بک : پوشش UV برای و پوشش سلفون مات و UV برای و پرجسته', - quantity: '۲۰۰۰', - unitPrice: '۳,۲۰۵,۰۰۰ ریال', - discount: '۱۰٪', - totalPrice: '۸,۸۵۰,۰۰۰,۰۰۰ ریال', - confirmed: true - }, - { - id: '2', - image: null, - title: 'شاپینگ بک : پوشش UV برای و پوشش سلفون مات و UV برای و پرجسته', - quantity: '۱۰۰۰', - unitPrice: '۳,۲۰۵,۰۰۰ ریال', - discount: '۰', - totalPrice: '۳,۲۰۵,۰۰۰,۰۰۰ ریال', - confirmed: true + const invoiceData = invoice + ? { + invoiceNumber: String(invoice.invoiceNumber), + confirmDate: invoice.items?.[0]?.confirmedAt + ? moment(invoice.items[0].confirmedAt).format('jYYYY/jMM/jDD') + : '-', + customerName: + [invoice.user?.firstName, invoice.user?.lastName].filter(Boolean).join(' ') || + invoice.user?.phone || + '-', + orderDate: moment(invoice.createdAt).format('jYYYY/jMM/jDD'), + phoneNumber: invoice.user?.phone || '-', + orderNumber: String(invoice.request?.requestNumber ?? '-'), + address: invoice.user?.addresse || '-', + paymentMethod: invoice.paymentMethod || '-', } - ] + : null + + const items: TableInvoiceItem[] = + invoice?.items?.map((item: ApiInvoiceItem) => ({ + id: item.id, + image: item.product?.images?.[0] ?? null, + title: item.product?.title || '-', + quantity: String(item.quantity), + unitPrice: formatPrice(item.unitPrice), + discount: item.discount ? `${NumberFormat(item.discount)}٪` : '۰', + totalPrice: formatPrice(item.total ?? 0), + confirmed: !!item.confirmedAt, + })) ?? [] const handlePrint = () => { window.print() @@ -59,47 +66,22 @@ const InvoiceDetail: FC = () => { { key: 'title', title: 'عنوان', - render: (item: InvoiceItem) => ( -
-
{item.title}
-
- ) }, { key: 'quantity', title: 'تعداد', - render: (item: InvoiceItem) => ( -
-
{item.quantity}
-
- ) }, { key: 'unitPrice', title: 'مبلغ واحد', - render: (item: InvoiceItem) => ( -
-
{item.unitPrice}
-
- ) }, { key: 'discount', title: 'تخفیف', - render: (item: InvoiceItem) => ( -
-
{item.discount}
-
- ) }, { key: 'totalPrice', title: 'مبلغ کل', - render: (item: InvoiceItem) => ( -
-
{item.totalPrice}
-
- ) }, { key: 'image', @@ -116,6 +98,24 @@ const InvoiceDetail: FC = () => { } ] + if (isPending && !invoice) { + return ( +
+ در حال بارگذاری... +
+ ) + } + + if (!invoiceData) { + return ( +
+ صورت حساب یافت نشد +
+ ) + } + + const isPaid = invoice && invoice.paidAmount >= invoice.total && invoice.total > 0 + return (
@@ -135,8 +135,14 @@ const InvoiceDetail: FC = () => { چاپ -
@@ -145,33 +151,33 @@ const InvoiceDetail: FC = () => {
اطلاعات صورت حساب
-
-
+
+
تاریخ ایجاد سفارش : {invoiceData.orderDate}
-
+
شماره همراه: - {invoiceData.orderNumber} + {invoiceData?.phoneNumber}
-
+
تاریخ تایید پیش فاکتور: {invoiceData.confirmDate}
-
+
مشتری: {invoiceData.customerName}
-
- شماره ثابت: - {invoiceData.phoneNumber} -
-
+
آدرس: {invoiceData.address}
+
+ روش پرداخت: + {invoiceData.paymentMethod} +
{/* بخش دوم: اقلام درخواستی */} @@ -182,8 +188,43 @@ const InvoiceDetail: FC = () => { columns={columns} data={items} showHeader={true} + isLoading={isPending} /> + {/* Price Summary */} + {invoice && ( +
+
+ جمع کل: + {formatPrice(invoice.subTotal)} +
+ {invoice.discount > 0 && ( +
+ تخفیف: + {formatPrice(invoice.discount)} +
+ )} + {invoice.enableTax && invoice.taxAmount > 0 && ( +
+ مالیات: + {formatPrice(invoice.taxAmount)} +
+ )} +
+ مبلغ کل: + {formatPrice(invoice.total)} +
+
+ مبلغ پرداخت شده: + {formatPrice(invoice.paidAmount)} +
+
+ مانده: + {formatPrice(invoice.balance)} +
+
+ )} + {/* Notes Section */}
diff --git a/src/pages/invoice/hooks/useInvoiceData.ts b/src/pages/invoice/hooks/useInvoiceData.ts index 9333d68..9419090 100644 --- a/src/pages/invoice/hooks/useInvoiceData.ts +++ b/src/pages/invoice/hooks/useInvoiceData.ts @@ -7,3 +7,11 @@ export const useGetInvoices = () => { queryFn: api.getInvoices, }); }; + +export const useGetInvoiceDetail = (id: string) => { + return useQuery({ + queryKey: ["invoice", id], + queryFn: () => api.getInvoiceDetail(id), + enabled: !!id, + }); +}; diff --git a/src/pages/invoice/service/InvoiceService.ts b/src/pages/invoice/service/InvoiceService.ts index 3b7ac78..fa9a41c 100644 --- a/src/pages/invoice/service/InvoiceService.ts +++ b/src/pages/invoice/service/InvoiceService.ts @@ -1,7 +1,19 @@ import axios from "@/config/axios"; -import type { InvoicesResponseType } from "../types/InvoiceTypes"; +import type { + InvoicesResponseType, + InvoiceDetailResponseType, +} from "../types/InvoiceTypes"; export const getInvoices = async (): Promise => { const { data } = await axios.get("/public/invoice"); return data; }; + +export const getInvoiceDetail = async ( + id: string +): Promise => { + const { data } = await axios.get( + `/public/invoice/${id}` + ); + return data; +}; diff --git a/src/pages/invoice/types/InvoiceTypes.ts b/src/pages/invoice/types/InvoiceTypes.ts index ef49225..47cb06a 100644 --- a/src/pages/invoice/types/InvoiceTypes.ts +++ b/src/pages/invoice/types/InvoiceTypes.ts @@ -73,3 +73,4 @@ export type Invoice = { }; export type InvoicesResponseType = BaseResponse; +export type InvoiceDetailResponseType = BaseResponse;