diff --git a/src/pages/invoice/Update.tsx b/src/pages/invoice/Update.tsx index 0bda7de..e3a172f 100644 --- a/src/pages/invoice/Update.tsx +++ b/src/pages/invoice/Update.tsx @@ -1,10 +1,10 @@ -import { useEffect, useState, type FC } from "react"; +import { useEffect, useMemo, useRef, useState, type FC } from "react"; import Button from "@/components/Button"; -import { Add, TickSquare } from "iconsax-react"; +import { Add, Link, TickSquare } from "iconsax-react"; import { toast } from "@/shared/toast"; import { useNavigate, useParams } from "react-router-dom"; import { Paths } from "@/config/Paths"; -import { extractErrorMessage } from "@/config/func"; +import { extractErrorMessage, getFileNameAndExtensionFromUrl } from "@/config/func"; import { useFormik } from "formik"; import type { CreatePreInvoiceItemType, UpdatePreInvoiceType } from "./types/Types"; import InvoiceItemRow from "./components/InvoiceItemRow"; @@ -16,6 +16,7 @@ import { useGetInvoiceDetail, useUpdateInvoice } from "./hooks/useInvoiceData"; import { useMultiUpload } from "../uploader/hooks/useUploader"; import moment from "moment-jalaali"; import { getItemLineTotal } from "./utils/invoiceItem"; +import TrashWithConfrim from "@/components/TrashWithConfrim"; const createEmptyItem = (): CreatePreInvoiceItemType => ({ productId: "", @@ -26,6 +27,17 @@ const createEmptyItem = (): CreatePreInvoiceItemType => ({ description: "", }); +const formatInvoiceUserName = ( + firstName?: string | null, + lastName?: string | null, + phone?: string | null +) => { + if (firstName && lastName) { + return `${firstName} ${lastName}`; + } + return phone ?? "-"; +}; + const UpdateInvoice: FC = () => { const { id } = useParams<{ id: string }>(); const navigate = useNavigate(); @@ -37,10 +49,55 @@ const UpdateInvoice: FC = () => { const invoice = invoiceData?.data; - const [items, setItems] = useState([ - createEmptyItem(), - ]); + const [items, setItems] = useState([createEmptyItem()]); + const [currentAttachments, setCurrentAttachments] = useState< + { type: string; url: string }[] + >([]); const [attachmentFiles, setAttachmentFiles] = useState([]); + const hydratedInvoiceId = useRef(null); + + const initialFormValues = useMemo( + () => ({ + enableTax: invoice?.enableTax ?? false, + approvalDeadline: invoice?.approvalDeadline + ? moment(invoice.approvalDeadline).format("jYYYY/jMM/jDD") + : "", + paymentMethod: invoice?.paymentMethod ?? "", + description: invoice?.description ?? "", + }), + [invoice] + ); + + const initialItems = useMemo( + () => + invoice?.items?.length + ? invoice.items.map((item) => ({ + id: item.id, + productId: item.product?.id ?? "", + quantity: item.quantity ?? 1, + unitPrice: item.unitPrice ?? 0, + discount: item.discount ?? 0, + discountPercent: + item.discountPercent != null && item.discountPercent > 0 + ? item.discountPercent + : null, + description: item.description ?? "", + })) + : [createEmptyItem()], + [invoice] + ); + + const initialAttachments = useMemo( + () => invoice?.attachments?.map((attachment) => ({ ...attachment })) ?? [], + [invoice] + ); + + useEffect(() => { + if (!invoice || hydratedInvoiceId.current === invoice.id) return; + setItems(initialItems); + setCurrentAttachments(initialAttachments); + hydratedInvoiceId.current = invoice.id; + }, [invoice, initialAttachments, initialItems]); const formik = useFormik< Pick< @@ -48,12 +105,8 @@ const UpdateInvoice: FC = () => { "enableTax" | "approvalDeadline" | "paymentMethod" | "description" > >({ - initialValues: { - enableTax: false, - approvalDeadline: "", - paymentMethod: "", - description: "", - }, + initialValues: initialFormValues, + enableReinitialize: true, onSubmit: async (values) => { const validItems = items.filter( (i) => i.productId && i.quantity > 0 && i.unitPrice >= 0 @@ -67,8 +120,7 @@ const UpdateInvoice: FC = () => { return; } - const attachments: { type: string; url: string }[] = - invoice?.attachments?.map((a) => ({ type: a.type, url: a.url })) ?? []; + const attachments = [...currentAttachments]; if (attachmentFiles.length) { const uploadResult = await multiUpload.mutateAsync(attachmentFiles); @@ -124,36 +176,6 @@ const UpdateInvoice: FC = () => { }, }); - useEffect(() => { - if (invoice) { - formik.setValues({ - enableTax: invoice.enableTax ?? false, - approvalDeadline: invoice.approvalDeadline - ? moment(invoice.approvalDeadline).format("jYYYY/jMM/jDD") - : "", - paymentMethod: invoice.paymentMethod ?? "", - description: invoice.description ?? "", - }); - - const mappedItems: CreatePreInvoiceItemType[] = - invoice.items?.length > 0 - ? invoice.items.map((i) => ({ - id: i.id, - productId: i.product?.id ?? "", - quantity: i.quantity ?? 1, - unitPrice: i.unitPrice ?? 0, - discount: i.discount ?? 0, - discountPercent: - i.discountPercent != null && i.discountPercent > 0 ? i.discountPercent : null, - description: i.description ?? "", - })) - : [createEmptyItem()]; - - setItems(mappedItems); - } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [invoice]); - const handleItemChange = ( index: number, field: keyof CreatePreInvoiceItemType, @@ -184,7 +206,12 @@ const UpdateInvoice: FC = () => { setItems(items.filter((_, i) => i !== index)); }; + const removeCurrentAttachment = (url: string) => { + setCurrentAttachments((prev) => prev.filter((attachment) => attachment.url !== url)); + }; + const totalAmount = items.reduce((sum, i) => sum + getItemLineTotal(i), 0); + const isSubmitting = isPending || multiUpload.isPending; if (isLoadingInvoice || !invoice) { return ( @@ -196,14 +223,17 @@ const UpdateInvoice: FC = () => { return (
-
-

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

+
+
+

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

+

+ اطلاعات مشتری، آیتم‌ها و شرایط پرداخت را به‌روزرسانی کنید. +

+
-
-
اطلاعات پیش فاکتور
+
+
اطلاعات پیش فاکتور
-
-
-
مشتری
-
- {invoice.user?.firstName && invoice.user?.lastName - ? `${invoice.user.firstName} ${invoice.user.lastName}` - : invoice.user?.phone ?? "-"} +
+
+
مشتری
+
+ {formatInvoiceUserName( + invoice.user?.firstName, + invoice.user?.lastName, + invoice.user?.phone + )} +
+
+
+
تاریخ ایجاد
+
+ {moment(invoice.createdAt).format("jYYYY/jMM/jDD")}
@@ -229,7 +267,7 @@ const UpdateInvoice: FC = () => {
{items.map((item, index) => ( {
-
+
{ />
-
-
مبلغ کل:
-
+ {currentAttachments.length ? ( +
+
پیوست‌های فعلی
+
+ {currentAttachments.map((attachment) => ( +
+ +
{getFileNameAndExtensionFromUrl(attachment.url).fileName}
+
+ removeCurrentAttachment(attachment.url)} + /> +
+
+ ))} +
+
+ ) : null} + +
+
مبلغ کل آیتم‌ها:
+
{totalAmount.toLocaleString("fa-IR")} ریال