diff --git a/src/pages/invoice/Create.tsx b/src/pages/invoice/Create.tsx index 074cc65..a459b1c 100644 --- a/src/pages/invoice/Create.tsx +++ b/src/pages/invoice/Create.tsx @@ -55,6 +55,7 @@ const CreateInvoice: FC = () => { userId: !requestId ? Yup.string().required("انتخاب مشتری اجباری است.") : Yup.string(), + approvalDeadline: Yup.string().required("مهلت تایید اجباری است."), }), onSubmit: async (values) => { const validItems = items.filter( diff --git a/src/pages/invoice/DetailPerfomaInvoice.tsx b/src/pages/invoice/DetailPerfomaInvoice.tsx index cd3d342..5f3d3d0 100644 --- a/src/pages/invoice/DetailPerfomaInvoice.tsx +++ b/src/pages/invoice/DetailPerfomaInvoice.tsx @@ -1,23 +1,119 @@ -import { type FC } from 'react'; +import { type FC, type ReactNode } from 'react'; import { Link, useParams } from 'react-router-dom'; import moment from 'moment-jalaali'; -import { Edit } from 'iconsax-react'; +import { Calendar, Edit, Profile2User, ReceiptText, WalletMoney } from 'iconsax-react'; import { Paths } from '@/config/Paths'; import BackButton from '@/components/BackButton'; import RefreshButton from '@/components/RefreshButton'; import { useGetInvoiceDetail } from './hooks/useInvoiceData'; import InvoicePaymentsSection from './components/InvoicePaymentsSection'; import { formatItemDiscountDisplay } from './utils/invoiceItem'; +import type { InvoiceItemType } from './types/Types'; const formatAmount = (amount: number) => Number(amount).toLocaleString('fa-IR') + ' ریال'; +type InfoFieldProps = { + label: string; + value: ReactNode; + icon?: ReactNode; +}; + +const InfoField: FC = ({ label, value, icon }) => ( +
+
+ {icon} + {label} +
+
{value}
+
+); + +type SummaryRowProps = { + label: string; + value: string; + valueClassName?: string; +}; + +const SummaryRow: FC = ({ label, value, valueClassName }) => ( +
+ {label} + {value} +
+); + +const getConfirmStatusBadge = (confirmedAt: string | null | undefined) => { + if (!confirmedAt) { + return ( + + در انتظار تایید + + ); + } + + return ( + + تایید شده + + ); +}; + +const InvoiceItemTableRow: FC<{ item: InvoiceItemType }> = ({ item }) => { + const discounts = formatItemDiscountDisplay(item); + const lineTotal = item.total ?? 0; + const convertToOrderUrl = `${Paths.convertToOrder}?${new URLSearchParams({ + invoiceItemId: item.id, + }).toString()}`; + + return ( + + {item.product?.title ?? '-'} + {item.description || '-'} + {item.quantity ?? '-'} + + {item.unitPrice != null ? formatAmount(item.unitPrice) : '-'} + + {discounts.value} + {discounts.percent} + {formatAmount(lineTotal)} + +
+ {getConfirmStatusBadge(item.confirmedAt)} + {item.confirmedAt + ? ( + + {moment(item.confirmedAt).format('jYYYY/jMM/jDD HH:mm')} + + ) + : null} +
+ + + {item.id && item.confirmedAt + ? ( + + + + ) + : ( + - + )} + + + ); +}; + const DetailPerfomaInvoice: FC = () => { const { id } = useParams<{ id: string }>(); - const { data: invoiceData, isLoading, refetch, isFetching } = useGetInvoiceDetail(id); + const { data: invoiceData, isLoading, refetch, isFetching, isError } = useGetInvoiceDetail(id); const invoice = invoiceData?.data; - if (isLoading || !invoice) { + if (isLoading) { return (
در حال بارگذاری...
@@ -25,21 +121,43 @@ const DetailPerfomaInvoice: FC = () => { ); } + if (isError || !invoice) { + return ( +
+
+ دریافت اطلاعات پیش فاکتور با مشکل مواجه شد. لطفا دوباره تلاش کنید. +
+
+ refetch()} isLoading={isFetching} /> +
+
+ ); + } + const customerName = invoice.user?.firstName && invoice.user?.lastName ? `${invoice.user.firstName} ${invoice.user.lastName}` : invoice.user?.phone ?? '-'; return ( -
-
- +
+
+
+ +
+ +

+ پیش فاکتور #{invoice.invoiceNumber} +

+
+
+
refetch()} isLoading={isFetching} />
-

- پیش فاکتور #{invoice.invoiceNumber} -

+
+
+
اطلاعات پیش فاکتور
-
-
اطلاعات پیش فاکتور
+
+ } + /> + } + /> + } + /> +
-
-
-
مشتری
-
{customerName}
-
-
-
تاریخ صدور
-
- {invoice.createdAt - ? moment(invoice.createdAt).format('jYYYY/jMM/jDD') - : '-'} -
-
-
-
مهلت تایید
-
- {invoice.approvalDeadline - ? moment(invoice.approvalDeadline).format('jYYYY/jMM/jDD') - : '-'} -
-
-
- -
- - - - - - - - - - - - - - - - {invoice.items?.map((item) => { - const discounts = formatItemDiscountDisplay(item); - const lineTotal = item.total ?? 0; - const convertToOrderUrl = `${Paths.convertToOrder}?${new URLSearchParams({ - invoiceItemId: item.id, - }).toString()}`; - return ( - - - - - - - - - - +
+
+
محصولتوضیحاتتعدادمبلغ واحدتخفیف (مبلغ)تخفیف (درصد)مبلغ کلتاریخ تاییدعملیات
{item.product?.title ?? '-'}{item.description || '-'}{item.quantity ?? '-'} - {item.unitPrice != null - ? formatAmount(item.unitPrice) - : '-'} - {discounts.value}{discounts.percent}{formatAmount(lineTotal)} - {item.confirmedAt - ? moment(item.confirmedAt).format('jYYYY/jMM/jDD HH:mm') - : '-'} - - {item.id && item.confirmedAt && ( - - - - )} -
+ + + + + + + + + + + - ); - })} - -
محصولتوضیحاتتعدادمبلغ واحدتخفیف (مبلغ)تخفیف (درصد)مبلغ کلتاییدعملیات
+ + + {invoice.items?.length + ? invoice.items.map((item) => ( + + )) + : ( + + + آیتمی برای این پیش‌فاکتور ثبت نشده است. + + + )} + + +
+
+ + {invoice.enableTax && ( +
+ مالیات بر ارزش افزوده (۱۰ درصد) فعال است. +
+ )} + + {invoice.paymentMethod && ( +
+
روش پرداخت
+
{invoice.paymentMethod}
+
+ )} + + {invoice.description && ( +
+
توضیحات
+
{invoice.description}
+
+ )}
- {invoice.enableTax && ( -
- مالیات بر ارزش افزوده (۱۰ درصد) فعال است +
+
+ + خلاصه مالی
- )} - - {invoice.paymentMethod && ( -
-
روش پرداخت
-
- {invoice.paymentMethod} -
+
+ + + 0 ? 'text-amber-700' : 'text-[#111827]'} + />
- )} - - {invoice.description && ( -
-
توضیحات
-
- {invoice.description} -
-
- )} - -
-
-
مبلغ کل:
-
- {formatAmount(invoice.total ?? 0)} -
-
-
-
پرداخت شده:
-
- {formatAmount(invoice.paidAmount ?? 0)} -
-
-
-
مانده:
-
- {formatAmount(invoice.balance ?? 0)} -
+
+ آخرین بروزرسانی: + + {invoice.createdAt ? moment(invoice.createdAt).format('jYYYY/jMM/jDD HH:mm') : '-'} +