diff --git a/modules/customer-invoices/src/web/adapters/index.ts b/modules/customer-invoices/src/web/adapters/index.ts deleted file mode 100644 index c2a1bd43..00000000 --- a/modules/customer-invoices/src/web/adapters/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * from "../proformas/adapters/proforma-dto.adapter"; - -export * from "./invoice-resume-dto.adapter"; diff --git a/modules/customer-invoices/src/web/adapters/invoice-resume-dto.adapter.ts b/modules/customer-invoices/src/web/adapters/invoice-resume-dto.adapter.ts deleted file mode 100644 index 82871b7c..00000000 --- a/modules/customer-invoices/src/web/adapters/invoice-resume-dto.adapter.ts +++ /dev/null @@ -1,63 +0,0 @@ -import { MoneyDTOHelper, PercentageDTOHelper, formatCurrency } from "@erp/core"; - -import type { InvoiceSummaryFormData } from "../schemas/invoice-resume.form.schema"; -import type { CustomerInvoiceSummary } from "../schemas/invoices.api.schema"; - -/** - * Convierte el DTO completo de API a datos numéricos para el formulario. - */ -export const invoiceResumeDtoToFormAdapter = { - fromDto(dtos: CustomerInvoiceSummary[], context?: any) { - return dtos.map( - (dto) => - ({ - ...dto, - - subtotal_amount: MoneyDTOHelper.toNumber(dto.subtotal_amount), - subtotal_amount_fmt: formatCurrency( - MoneyDTOHelper.toNumber(dto.subtotal_amount), - Number(dto.total_amount.scale || 2), - dto.currency_code, - dto.language_code - ), - - discount_percentage: PercentageDTOHelper.toNumber(dto.discount_percentage), - discount_percentage_fmt: PercentageDTOHelper.toNumericString(dto.discount_percentage), - - discount_amount: MoneyDTOHelper.toNumber(dto.discount_amount), - discount_amount_fmt: formatCurrency( - MoneyDTOHelper.toNumber(dto.discount_amount), - Number(dto.total_amount.scale || 2), - dto.currency_code, - dto.language_code - ), - - taxable_amount: MoneyDTOHelper.toNumber(dto.taxable_amount), - taxable_amount_fmt: formatCurrency( - MoneyDTOHelper.toNumber(dto.taxable_amount), - Number(dto.total_amount.scale || 2), - dto.currency_code, - dto.language_code - ), - - taxes_amount: MoneyDTOHelper.toNumber(dto.taxes_amount), - taxes_amount_fmt: formatCurrency( - MoneyDTOHelper.toNumber(dto.taxes_amount), - Number(dto.total_amount.scale || 2), - dto.currency_code, - dto.language_code - ), - - total_amount: MoneyDTOHelper.toNumber(dto.total_amount), - total_amount_fmt: formatCurrency( - MoneyDTOHelper.toNumber(dto.total_amount), - Number(dto.total_amount.scale || 2), - dto.currency_code, - dto.language_code - ), - - //taxes: dto.taxes, - }) as unknown as InvoiceSummaryFormData - ); - }, -}; diff --git a/modules/customer-invoices/src/web/hooks/use-invoice-query.ts b/modules/customer-invoices/src/web/hooks/use-invoice-query.ts index 11174a74..8a1fdd11 100644 --- a/modules/customer-invoices/src/web/hooks/use-invoice-query.ts +++ b/modules/customer-invoices/src/web/hooks/use-invoice-query.ts @@ -18,9 +18,8 @@ export const useInvoiceQuery = (invoiceId?: string, options?: InvoiceQueryOption queryKey: CUSTOMER_INVOICE_QUERY_KEY(invoiceId ?? "unknown"), queryFn: async (context) => { const { signal } = context; - if (!invoiceId) { - if (!invoiceId) throw new Error("invoiceId is required"); - } + if (!invoiceId) throw new Error("invoiceId is required"); + return await dataSource.getOne("customer-invoices", invoiceId, { signal, }); diff --git a/modules/customer-invoices/src/web/issued-invoices/download-pdf/controller/use-download-invoice-pdf.controller.ts b/modules/customer-invoices/src/web/issued-invoices/download-pdf/controller/use-download-invoice-pdf.controller.ts index 18e4bc8c..ed65e723 100644 --- a/modules/customer-invoices/src/web/issued-invoices/download-pdf/controller/use-download-invoice-pdf.controller.ts +++ b/modules/customer-invoices/src/web/issued-invoices/download-pdf/controller/use-download-invoice-pdf.controller.ts @@ -49,5 +49,6 @@ export function useDownloadInvoicePDFController() { return { download, // (id, reference) => void isLoading: isFetching, + loadingId: pending?.id, }; } diff --git a/modules/customer-invoices/src/web/issued-invoices/list/controllers/use-issued-invoice-list-page.controller.ts.ts b/modules/customer-invoices/src/web/issued-invoices/list/controllers/use-issued-invoice-list-page.controller.ts.ts index ec6e8757..be2725e9 100644 --- a/modules/customer-invoices/src/web/issued-invoices/list/controllers/use-issued-invoice-list-page.controller.ts.ts +++ b/modules/customer-invoices/src/web/issued-invoices/list/controllers/use-issued-invoice-list-page.controller.ts.ts @@ -19,6 +19,10 @@ export function useIssuedInvoiceListPageController() { return { listCtrl, + downloadPDFCtrl, + handleDownloadPDF, + pdfDownloadingId: downloadPDFCtrl.loadingId, + isPDFDownloading: downloadPDFCtrl.isLoading, }; } diff --git a/modules/customer-invoices/src/web/issued-invoices/list/ui/blocks/issued-invoices-grid/use-issued-invoices-grid-columns.tsx b/modules/customer-invoices/src/web/issued-invoices/list/ui/blocks/issued-invoices-grid/use-issued-invoices-grid-columns.tsx index 00f4295c..d2c2f355 100644 --- a/modules/customer-invoices/src/web/issued-invoices/list/ui/blocks/issued-invoices-grid/use-issued-invoices-grid-columns.tsx +++ b/modules/customer-invoices/src/web/issued-invoices/list/ui/blocks/issued-invoices-grid/use-issued-invoices-grid-columns.tsx @@ -7,12 +7,13 @@ import { DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, + Spinner, Tooltip, TooltipContent, TooltipTrigger, } from "@repo/shadcn-ui/components"; import type { ColumnDef } from "@tanstack/react-table"; -import { DownloadIcon, MailIcon, MoreVerticalIcon, QrCodeIcon } from "lucide-react"; +import { DownloadIcon, FileDownIcon, MailIcon, MoreVerticalIcon, QrCodeIcon } from "lucide-react"; import * as React from "react"; import QrCode from "react-qr-code"; @@ -21,7 +22,8 @@ import type { IssuedInvoiceSummaryData } from "../../../../types"; type GridActionHandlers = { onDownloadPdf?: (issuedInvoice: IssuedInvoiceSummaryData) => void; - onSendEmail?: (issuedInvoice: IssuedInvoiceSummaryData) => void; + pdfDownloadingId?: string | null; + isPdfDownloading?: boolean; }; export function useIssuedInvoicesGridColumns( @@ -321,28 +323,37 @@ export function useIssuedInvoicesGridColumns( minSize: 64, cell: ({ row }) => { const issuedInvoice = row.original; + const isCompleted = issuedInvoice.verifactu.status === "Correcto"; + const isPDFLoading = + actionHandlers.isPdfDownloading && actionHandlers.pdfDownloadingId === issuedInvoice.id; const stop = (e: React.MouseEvent | React.KeyboardEvent) => e.stopPropagation(); return ( {/* Descargar en PDF */} + {/* Descargar en PDF */} + - {t("common.download_pdf")} + Descargar PDF {/* Menú demás acciones */} @@ -370,10 +381,7 @@ export function useIssuedInvoicesGridColumns( {t("common.download_pdf")} - actionHandlers.onSendEmail?.(issuedInvoice)} - > + {t("common.send_email")} {" "} diff --git a/modules/customer-invoices/src/web/issued-invoices/list/ui/pages/issued-invoice-list-page.tsx b/modules/customer-invoices/src/web/issued-invoices/list/ui/pages/issued-invoice-list-page.tsx index c48849e7..4db32e05 100644 --- a/modules/customer-invoices/src/web/issued-invoices/list/ui/pages/issued-invoice-list-page.tsx +++ b/modules/customer-invoices/src/web/issued-invoices/list/ui/pages/issued-invoice-list-page.tsx @@ -22,11 +22,19 @@ import { IssuedInvoicesGrid, useIssuedInvoicesGridColumns } from "../blocks"; export const IssuedInvoiceListPage = () => { const { t } = useTranslation(); const navigate = useNavigate(); - const { listCtrl, handleDownloadPDF } = useIssuedInvoiceListPageController(); + const { + listCtrl, + handleDownloadPDF, + isPDFDownloading: isPdfDownloading, + pdfDownloadingId, + } = useIssuedInvoiceListPageController(); const columns = useIssuedInvoicesGridColumns({ onDownloadPdf: handleDownloadPDF, - onSendEmail: () => null, + pdfDownloadingId, + isPdfDownloading, + + //onSendEmail: () => null, }); // Hook con Sheet de shadcn diff --git a/modules/customer-invoices/src/web/pages/list/invoices-list-grid.tsx b/modules/customer-invoices/src/web/pages/list/invoices-list-grid.tsx deleted file mode 100644 index 6664a381..00000000 --- a/modules/customer-invoices/src/web/pages/list/invoices-list-grid.tsx +++ /dev/null @@ -1,178 +0,0 @@ -import { SimpleSearchInput } from "@erp/core/components"; -import { DataTable, SkeletonDataTable } from "@repo/rdx-ui/components"; -import { useCallback, useState } from "react"; -import { useNavigate } from "react-router-dom"; - -import { usePinnedPreviewSheet } from "../../hooks"; -import { useTranslation } from "../../i18n"; -import type { InvoiceSummaryFormData, InvoicesPageFormData } from "../../schemas"; - -export type InvoiceUpdateCompProps = { - invoicesPage: InvoicesPageFormData; - loading?: boolean; - - pageIndex: number; - pageSize: number; - onPageChange?: (pageNumber: number) => void; - onPageSizeChange?: (pageSize: number) => void; - - searchValue: string; - onSearchChange: (value: string) => void; - - onRowClick?: ( - row: InvoiceSummaryFormData, - index: number, - event: React.MouseEvent - ) => void; -}; - -// Create new GridExample component -export const InvoicesListGrid = ({ - invoicesPage, - loading, - pageIndex, - pageSize, - onPageChange, - onPageSizeChange, - searchValue, - onSearchChange, - onRowClick, -}: InvoiceUpdateCompProps) => { - const { t } = useTranslation(); - const navigate = useNavigate(); - const { items, total_items } = invoicesPage; - - // Hook con Sheet de shadcn - const preview = usePinnedPreviewSheet({ - persistKey: "invoice-preview-pin", - widthClass: "w-[500px]", - }); - - const [statusFilter, setStatusFilter] = useState("todas"); - - const columns = useProformasGridColumns({ - onEdit: (invoice) => navigate(`/customer-invoices/${invoice.id}/edit`), - onDuplicate: (invoice) => null, //duplicateInvoice(inv.id), - onDownloadPdf: (invoice) => null, //downloadInvoicePdf(inv.id), - onSendEmail: (invoice) => null, //sendInvoiceEmail(inv.id), - onDelete: (invoice) => null, //confirmDelete(inv.id), - }); - - // Navegación accesible (click o teclado) - const goToRow = useCallback( - (id: string, newTab = false) => { - const url = `/customer-invoices/${id}/edit`; - newTab ? window.open(url, "_blank", "noopener,noreferrer") : navigate(url); - }, - [navigate] - ); - - const onRowClicked = useCallback( - (e: RowClickedEvent) => { - if (!e.data) return; - const newTab = e.event instanceof MouseEvent && (e.event.metaKey || e.event.ctrlKey); - goToRow(e.data.id, newTab); - }, - [goToRow] - ); - - const onCellKeyDown = useCallback( - (e: CellKeyDownEvent) => { - if (!e.data) return; - - const ev = e.event; - if (!(ev && ev instanceof KeyboardEvent)) return; - - const key = ev.key; - if (key === "Enter" || key === " ") { - ev.preventDefault(); - goToRow(e.data.id); - } - if ((ev.ctrlKey || ev.metaKey) && key === "Enter") { - ev.preventDefault(); - goToRow(e.data.id, true); - } - }, - [goToRow] - ); - - const handleRowClick = useCallback( - (invoice: InvoiceSummaryFormData, _i: number, e: React.MouseEvent) => { - const url = `/customer-invoices/${invoice.id}/edit`; - if (e.metaKey || e.ctrlKey) { - window.open(url, "_blank", "noopener,noreferrer"); - return; - } - preview.open(invoice); - }, - [preview] - ); - - if (loading) { - return ( -
- -
- ); - } - - // Render principal - return ( -
- {/* Barra de filtros */} -
- - {/* - */} -
-
-
- -
- - {/* - {({ item, isPinned, close, togglePin }) => ( - - )} - */} -
-
- ); -}; diff --git a/modules/customer-invoices/src/web/pages/list/invoices-list-page.tsx b/modules/customer-invoices/src/web/pages/list/invoices-list-page.tsx index 95ec7b74..a8be142f 100644 --- a/modules/customer-invoices/src/web/pages/list/invoices-list-page.tsx +++ b/modules/customer-invoices/src/web/pages/list/invoices-list-page.tsx @@ -6,9 +6,9 @@ import { PlusIcon } from "lucide-react"; import { useMemo, useState } from "react"; import { useNavigate } from "react-router-dom"; -import { invoiceResumeDtoToFormAdapter } from "../../adapters/invoice-resume-dto.adapter"; import { useInvoicesQuery } from "../../hooks"; import { useTranslation } from "../../i18n"; +import { issuedInvoiceResumeDtoToFormAdapter } from "../../issued-invoices/adapters/issued-invoice-resume-dto.adapter"; export const InvoiceListPage = () => { const { t } = useTranslation(); @@ -37,7 +37,7 @@ export const InvoiceListPage = () => { if (!data) return undefined; return { ...data, - items: invoiceResumeDtoToFormAdapter.fromDto(data.items), + items: issuedInvoiceResumeDtoToFormAdapter.fromDto(data.items), }; }, [data]); diff --git a/modules/customer-invoices/src/web/schemas/index.ts b/modules/customer-invoices/src/web/schemas/index.ts index d9e22bef..b379305e 100644 --- a/modules/customer-invoices/src/web/schemas/index.ts +++ b/modules/customer-invoices/src/web/schemas/index.ts @@ -1,4 +1,4 @@ -export * from "../adapters/invoice-resume-dto.adapter"; +export * from "../issued-invoices/adapters/issued-invoice-resume-dto.adapter"; export * from "../proformas/adapters/proforma-dto.adapter"; export * from "./invoice.form.schema";