From 8a8282ddc3bac15ff086df4dc2fc59fb7c3f0ebe Mon Sep 17 00:00:00 2001 From: david Date: Sun, 12 Apr 2026 21:12:10 +0200 Subject: [PATCH] . --- .../src/web/customer-invoice-routes.tsx | 4 +- .../use-download-invoice-pdf.controller.ts | 2 +- .../issued-invoices/list/adapters/index.ts | 1 - .../issued-invoice-summary-dto.adapter.ts | 71 ---------- .../list/api/get-issued-invoice-list.api.ts | 18 --- .../src/web/issued-invoices/list/api/index.ts | 1 - ...-issued-invoice-list-page.controller.ts.ts | 6 +- .../use-issued-invoice-list.controller.ts | 106 ++++++++++---- .../web/issued-invoices/list/hooks/index.ts | 0 .../issued-invoices-grid.tsx | 76 +++++------ .../use-issued-invoices-grid-columns.tsx | 129 +++++++++--------- .../ui/components/verifactu-status-badge.tsx | 34 ++--- .../issued-invoices/list/ui/pages/index.ts | 2 +- ...page.tsx => list-issued-invoices-page.tsx} | 46 ++++--- .../issued-invoices/shared/adapters/index.ts | 1 + .../adapters/list-issued-invoice.adapter.ts | 101 ++++++++++++++ .../web/issued-invoices/shared/api/index.ts | 1 + .../list-issued-invoices-by-criteria.api.ts | 32 +++++ .../issued-invoices/shared/entities/index.ts | 4 + .../issued-invoice-list-row.entity.ts | 47 +++++++ .../entities/issued-invoice-list.entity.ts | 14 ++ .../issued-invoice-recipient.entity.ts | 18 +++ .../entities/issued-invoice-status.entity.ts | 26 ++++ .../verifactu-record-status.entity.ts} | 0 .../entities/verifactu-record.entity.ts | 7 + .../web/issued-invoices/shared/hooks/keys.ts | 24 ++++ .../hooks/use-issued-invoice-list-query.ts | 40 +++--- .../src/web/issued-invoices/shared/index.ts | 4 + .../{ => shared}/ui/blocks/index.ts | 0 .../ui/blocks/issued-invoices-layout.tsx | 2 +- .../issued-invoices/{ => shared}/ui/index.ts | 0 .../src/web/issued-invoices/types/index.ts | 3 - .../issued-invoice-summary.web.schema.ts | 25 ---- .../types/issued-invoice.api.schema.ts | 22 --- .../use-proforma-grid-columns.tsx | 128 +++++++++-------- .../web/proformas/list/ui/components/index.ts | 1 - .../ui/components/proforma-status-badge.tsx | 20 +-- .../src/web/proformas/shared/hooks/keys.ts | 2 +- .../use-customer-grid-columns.tsx | 75 +++++----- .../ui/components/customer-status-badge.tsx | 12 +- .../datatable/data-table-column-header.tsx | 67 ++++----- .../datatable/data-table-pagination.tsx | 3 +- .../datatable/data-table-toolbar.tsx | 62 +++++---- .../datatable/data-table-view-options.tsx | 64 +++++---- .../src/components/datatable/data-table.tsx | 47 +------ .../datatable/skeleton-data-table.tsx | 121 ++++++++-------- .../src/components/layout/app-topbar.tsx | 11 +- .../rdx-ui/src/components/logo-verifactu.tsx | 1 - 48 files changed, 828 insertions(+), 653 deletions(-) delete mode 100644 modules/customer-invoices/src/web/issued-invoices/list/adapters/index.ts delete mode 100644 modules/customer-invoices/src/web/issued-invoices/list/adapters/issued-invoice-summary-dto.adapter.ts delete mode 100644 modules/customer-invoices/src/web/issued-invoices/list/api/get-issued-invoice-list.api.ts delete mode 100644 modules/customer-invoices/src/web/issued-invoices/list/api/index.ts delete mode 100644 modules/customer-invoices/src/web/issued-invoices/list/hooks/index.ts rename modules/customer-invoices/src/web/issued-invoices/list/ui/pages/{issued-invoice-list-page.tsx => list-issued-invoices-page.tsx} (82%) create mode 100644 modules/customer-invoices/src/web/issued-invoices/shared/adapters/index.ts create mode 100644 modules/customer-invoices/src/web/issued-invoices/shared/adapters/list-issued-invoice.adapter.ts create mode 100644 modules/customer-invoices/src/web/issued-invoices/shared/api/index.ts create mode 100644 modules/customer-invoices/src/web/issued-invoices/shared/api/list-issued-invoices-by-criteria.api.ts create mode 100644 modules/customer-invoices/src/web/issued-invoices/shared/entities/index.ts create mode 100644 modules/customer-invoices/src/web/issued-invoices/shared/entities/issued-invoice-list-row.entity.ts create mode 100644 modules/customer-invoices/src/web/issued-invoices/shared/entities/issued-invoice-list.entity.ts create mode 100644 modules/customer-invoices/src/web/issued-invoices/shared/entities/issued-invoice-recipient.entity.ts create mode 100644 modules/customer-invoices/src/web/issued-invoices/shared/entities/issued-invoice-status.entity.ts rename modules/customer-invoices/src/web/issued-invoices/{types/verifactu-record-status.ts => shared/entities/verifactu-record-status.entity.ts} (100%) create mode 100644 modules/customer-invoices/src/web/issued-invoices/shared/entities/verifactu-record.entity.ts create mode 100644 modules/customer-invoices/src/web/issued-invoices/shared/hooks/keys.ts rename modules/customer-invoices/src/web/issued-invoices/{ => shared}/ui/blocks/index.ts (100%) rename modules/customer-invoices/src/web/issued-invoices/{ => shared}/ui/blocks/issued-invoices-layout.tsx (70%) rename modules/customer-invoices/src/web/issued-invoices/{ => shared}/ui/index.ts (100%) delete mode 100644 modules/customer-invoices/src/web/issued-invoices/types/index.ts delete mode 100644 modules/customer-invoices/src/web/issued-invoices/types/issued-invoice-summary.web.schema.ts delete mode 100644 modules/customer-invoices/src/web/issued-invoices/types/issued-invoice.api.schema.ts diff --git a/modules/customer-invoices/src/web/customer-invoice-routes.tsx b/modules/customer-invoices/src/web/customer-invoice-routes.tsx index d29a4b5f..cbf35ab1 100644 --- a/modules/customer-invoices/src/web/customer-invoice-routes.tsx +++ b/modules/customer-invoices/src/web/customer-invoice-routes.tsx @@ -3,7 +3,7 @@ import { lazy } from "react"; import { Outlet, type RouteObject } from "react-router-dom"; const ProformaLayout = lazy(() => - import("./proformas/shared").then((m) => ({ default: m.ProformaLayout })) + import("./proformas/shared/ui").then((m) => ({ default: m.ProformaLayout })) ); const ProformasListPage = lazy(() => @@ -19,7 +19,7 @@ const ProformaUpdatePage = lazy(() => ); const IssuedInvoicesLayout = lazy(() => - import("./issued-invoices/shared").then((m) => ({ default: m.IssuedInvoicesLayout })) + import("./issued-invoices/shared/ui").then((m) => ({ default: m.IssuedInvoicesLayout })) ); const IssuedInvoiceListPage = lazy(() => 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 ed65e723..e19010f9 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 @@ -1,7 +1,7 @@ import { showErrorToast, showSuccessToast } from "@repo/rdx-ui/helpers"; import * as React from "react"; -import { useDownloadInvoicePDFQuery } from "../hooks"; +import { useDownloadInvoicePDFQuery } from "../../shared"; interface PendingDownload { id: string; diff --git a/modules/customer-invoices/src/web/issued-invoices/list/adapters/index.ts b/modules/customer-invoices/src/web/issued-invoices/list/adapters/index.ts deleted file mode 100644 index 26ac0dcd..00000000 --- a/modules/customer-invoices/src/web/issued-invoices/list/adapters/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./issued-invoice-summary-dto.adapter"; diff --git a/modules/customer-invoices/src/web/issued-invoices/list/adapters/issued-invoice-summary-dto.adapter.ts b/modules/customer-invoices/src/web/issued-invoices/list/adapters/issued-invoice-summary-dto.adapter.ts deleted file mode 100644 index e1a441c6..00000000 --- a/modules/customer-invoices/src/web/issued-invoices/list/adapters/issued-invoice-summary-dto.adapter.ts +++ /dev/null @@ -1,71 +0,0 @@ -import { MoneyDTOHelper, formatCurrency } from "@erp/core"; - -import type { - IssuedInvoiceSummaryData, - IssuedInvoiceSummaryPage, - IssuedInvoiceSummaryPageData, -} from "../../types"; - -/** - * Convierte el DTO completo de API a datos numéricos para el formulario. - */ -export const IssuedInvoiceSummaryDtoAdapter = { - fromDto(pageDto: IssuedInvoiceSummaryPage, context?: unknown): IssuedInvoiceSummaryPageData { - return { - ...pageDto, - items: pageDto.items.map( - (summaryDto) => - ({ - ...summaryDto, - - subtotal_amount: MoneyDTOHelper.toNumber(summaryDto.subtotal_amount), - subtotal_amount_fmt: formatCurrency( - MoneyDTOHelper.toNumber(summaryDto.subtotal_amount), - Number(summaryDto.total_amount.scale || 2), - summaryDto.currency_code, - summaryDto.language_code - ), - - /*discount_percentage: PercentageDTOHelper.toNumber(summaryDto.discount_percentage), - discount_percentage_fmt: PercentageDTOHelper.toNumericString( - summaryDto.discount_percentage - ),*/ - - discount_amount: MoneyDTOHelper.toNumber(summaryDto.total_discount_amount), - discount_amount_fmt: formatCurrency( - MoneyDTOHelper.toNumber(summaryDto.total_discount_amount), - Number(summaryDto.total_amount.scale || 2), - summaryDto.currency_code, - summaryDto.language_code - ), - - taxable_amount: MoneyDTOHelper.toNumber(summaryDto.taxable_amount), - taxable_amount_fmt: formatCurrency( - MoneyDTOHelper.toNumber(summaryDto.taxable_amount), - Number(summaryDto.total_amount.scale || 2), - summaryDto.currency_code, - summaryDto.language_code - ), - - taxes_amount: MoneyDTOHelper.toNumber(summaryDto.taxes_amount), - taxes_amount_fmt: formatCurrency( - MoneyDTOHelper.toNumber(summaryDto.taxes_amount), - Number(summaryDto.total_amount.scale || 2), - summaryDto.currency_code, - summaryDto.language_code - ), - - total_amount: MoneyDTOHelper.toNumber(summaryDto.total_amount), - total_amount_fmt: formatCurrency( - MoneyDTOHelper.toNumber(summaryDto.total_amount), - Number(summaryDto.total_amount.scale || 2), - summaryDto.currency_code, - summaryDto.language_code - ), - - //taxes: dto.taxes, - }) as unknown as IssuedInvoiceSummaryData - ), - }; - }, -}; diff --git a/modules/customer-invoices/src/web/issued-invoices/list/api/get-issued-invoice-list.api.ts b/modules/customer-invoices/src/web/issued-invoices/list/api/get-issued-invoice-list.api.ts deleted file mode 100644 index c8f0ad6a..00000000 --- a/modules/customer-invoices/src/web/issued-invoices/list/api/get-issued-invoice-list.api.ts +++ /dev/null @@ -1,18 +0,0 @@ -import type { CriteriaDTO } from "@erp/core"; -import type { IDataSource } from "@erp/core/client"; - -import type { IssuedInvoiceSummaryPage } from "../../types"; - -export async function getIssuedInvoiceListApi( - dataSource: IDataSource, - signal: AbortSignal, - criteria: CriteriaDTO -) { - const response = dataSource.getList("issued-invoices", { - signal, - ...criteria, - }); - - //return mapIssuedInvoiceList(raw); - return response; -} diff --git a/modules/customer-invoices/src/web/issued-invoices/list/api/index.ts b/modules/customer-invoices/src/web/issued-invoices/list/api/index.ts deleted file mode 100644 index 3a619aac..00000000 --- a/modules/customer-invoices/src/web/issued-invoices/list/api/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./get-issued-invoice-list.api"; 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 be2725e9..62097f9e 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 @@ -1,7 +1,7 @@ import React from "react"; import { useDownloadInvoicePDFController } from "../../download-pdf/controller"; -import type { IssuedInvoiceSummaryData } from "../../types"; +import type { IssuedInvoiceListRow } from "../../shared"; import { useIssuedInvoiceListController } from "./use-issued-invoice-list.controller"; @@ -10,8 +10,8 @@ export function useIssuedInvoiceListPageController() { const downloadPDFCtrl = useDownloadInvoicePDFController(); const handleDownloadPDF = React.useCallback( - (issuedInvoice: IssuedInvoiceSummaryData) => { - downloadPDFCtrl.download(issuedInvoice.id, issuedInvoice.invoice_number); + (issuedInvoice: IssuedInvoiceListRow) => { + downloadPDFCtrl.download(issuedInvoice.id, issuedInvoice.invoiceNumber); }, [downloadPDFCtrl] ); diff --git a/modules/customer-invoices/src/web/issued-invoices/list/controllers/use-issued-invoice-list.controller.ts b/modules/customer-invoices/src/web/issued-invoices/list/controllers/use-issued-invoice-list.controller.ts index 843701f9..8bf3cb38 100644 --- a/modules/customer-invoices/src/web/issued-invoices/list/controllers/use-issued-invoice-list.controller.ts +++ b/modules/customer-invoices/src/web/issued-invoices/list/controllers/use-issued-invoice-list.controller.ts @@ -1,51 +1,101 @@ -import type { CriteriaDTO } from "@erp/core"; import { useDebounce } from "@repo/rdx-ui/components"; import { useMemo, useState } from "react"; -import { IssuedInvoiceSummaryDtoAdapter } from "../adapters"; -import { useIssuedInvoiceListQuery } from "../hooks"; +import type { + IssuedInvoiceList, + IssuedInvoiceStatus, + ListIssuedInvoicesByCriteriaParams, +} from "../../shared"; +import { useIssuedInvoiceListQuery } from "../../shared/"; + +type IssuedInvoiceListStatusFilter = "all" | IssuedInvoiceStatus; + +const EMPTY_ISSUED_INVOICES_LIST: IssuedInvoiceList = { + items: [], + page: 0, + perPage: 5, + totalPages: 0, + totalItems: 0, +}; export const useIssuedInvoiceListController = () => { const [pageIndex, setPageIndex] = useState(0); - const [pageSize, setPageSize] = useState(10); + const [pageSize, setPageSize] = useState(5); const [search, setSearch] = useState(""); - const [status, setStatus] = useState("all"); + const [statusFilter, setStatusFilter] = useState("all"); - const debouncedQ = useDebounce(search, 300); + const debouncedSearch = useDebounce(search, 300); - const criteria = useMemo(() => { - const baseFilters = - status !== "all" ? [{ field: "status", operator: "CONTAINS", value: status }] : []; - - return { - q: debouncedQ || "", - pageSize, + const criteria = useMemo>( + () => ({ + q: debouncedSearch || "", pageNumber: pageIndex, + pageSize, order: "desc", orderBy: "invoice_date", - filters: baseFilters, - }; - }, [pageSize, pageIndex, debouncedQ, status]); - - const query = useIssuedInvoiceListQuery({ criteria }); - const data = useMemo( - () => (query.data ? IssuedInvoiceSummaryDtoAdapter.fromDto(query.data) : undefined), - [query.data] + filters: status === "all" ? [] : [{ field: "status", operator: "eq", value: status }], + }), + [debouncedSearch, pageIndex, pageSize, status] ); - const setSearchValue = (value: string) => setSearch(value.trim().replace(/\s+/g, " ")); + const query = useIssuedInvoiceListQuery({ criteria }); - const setStatusFilter = (newStatus: string) => setStatus(newStatus); + const setStatusFilterValue = (value: string) => { + const nextValue = (value || "all") as IssuedInvoiceListStatusFilter; + + setStatusFilter((prev) => { + if (prev === nextValue) return prev; + + // Sólo si la búsqueda realmente cambia, + // reseteamos la página a 0 para evitar inconsistencias + setPageIndex(0); + return nextValue; + }); + }; + + const setSearchValue = (value: string) => { + const nextValue = value.trim().replace(/\s+/g, " "); + + setSearch((prev) => { + if (prev === nextValue) return prev; + + // Sólo si la búsqueda realmente cambia, + // reseteamos la página a 0 para evitar inconsistencias + setPageIndex(0); + return nextValue; + }); + }; + + const setPageSizeValue = (value: number) => { + setPageSize((prev) => { + if (prev === value) return prev; + + // Sólo si el tamaño de página realmente cambia, + // reseteamos la página a 0 para evitar inconsistencias + setPageIndex(0); + return value; + }); + }; return { - ...query, - data, + data: query.data ?? EMPTY_ISSUED_INVOICES_LIST, + isLoading: query.isLoading, + isFetching: query.isFetching, + + isError: query.isError, + error: query.error, + + refetch: query.refetch, + pageIndex, pageSize, - search, setPageIndex, - setPageSize, + setPageSize: setPageSizeValue, + + search, setSearchValue, - setStatusFilter, + + statusFilter, + setStatusFilter: setStatusFilterValue, }; }; diff --git a/modules/customer-invoices/src/web/issued-invoices/list/hooks/index.ts b/modules/customer-invoices/src/web/issued-invoices/list/hooks/index.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/modules/customer-invoices/src/web/issued-invoices/list/ui/blocks/issued-invoices-grid/issued-invoices-grid.tsx b/modules/customer-invoices/src/web/issued-invoices/list/ui/blocks/issued-invoices-grid/issued-invoices-grid.tsx index eb997bac..950ae2cf 100644 --- a/modules/customer-invoices/src/web/issued-invoices/list/ui/blocks/issued-invoices-grid/issued-invoices-grid.tsx +++ b/modules/customer-invoices/src/web/issued-invoices/list/ui/blocks/issued-invoices-grid/issued-invoices-grid.tsx @@ -1,42 +1,37 @@ import { DataTable, SkeletonDataTable } from "@repo/rdx-ui/components"; import type { ColumnDef } from "@tanstack/react-table"; -import { useNavigate } from "react-router-dom"; import { useTranslation } from "../../../../../i18n"; -import type { IssuedInvoiceSummaryData, IssuedInvoiceSummaryPageData } from "../../../../types"; +import type { IssuedInvoiceList, IssuedInvoiceListRow } from "../../../../shared"; -export type InvoiceUpdateCompProps = { - data: IssuedInvoiceSummaryPageData; - loading?: boolean; +interface IssuedInvoicesGridProps { + data?: IssuedInvoiceList; + loading: boolean; + fetching?: boolean; - columns: ColumnDef[]; + columns: ColumnDef[]; pageIndex: number; pageSize: number; - onPageChange?: (pageNumber: number) => void; - onPageSizeChange?: (pageSize: number) => void; + onPageChange: (pageIndex: number) => void; + onPageSizeChange: (size: number) => void; - onRowClick?: ( - row: IssuedInvoiceSummaryPageData, - index: number, - event: React.MouseEvent - ) => void; -}; + onRowClick?: (proformaId: string) => void; +} -// Create new GridExample component export const IssuedInvoicesGrid = ({ data, loading, + fetching, columns, pageIndex, pageSize, onPageChange, onPageSizeChange, onRowClick, -}: InvoiceUpdateCompProps) => { +}: IssuedInvoicesGridProps) => { const { t } = useTranslation(); - const navigate = useNavigate(); - const { items, total_items } = data; + const { items, totalItems } = data || { items: [], totalItems: 0 }; // Navegación accesible (click o teclado) /* const goToRow = useCallback( @@ -90,36 +85,29 @@ export const IssuedInvoicesGrid = ({ if (loading) { return ( -
- -
+ ); } // Render principal return ( - <> - {/*
*/} - - {/*
*/} - + onRowClick?.(row.id)} + pageIndex={pageIndex} + pageSize={pageSize} + totalItems={totalItems} + /> ); }; 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 b95f8805..cc59f306 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 @@ -5,6 +5,7 @@ import { ButtonGroup, DropdownMenu, DropdownMenuContent, + DropdownMenuGroup, DropdownMenuItem, DropdownMenuTrigger, Spinner, @@ -18,21 +19,21 @@ import * as React from "react"; import QrCode from "react-qr-code"; import { useTranslation } from "../../../../../i18n"; -import type { IssuedInvoiceSummaryData } from "../../../../types"; +import type { IssuedInvoiceListRow } from "../../../../shared"; import { VerifactuStatusBadge } from "../../components"; type GridActionHandlers = { - onDownloadPdf?: (issuedInvoice: IssuedInvoiceSummaryData) => void; + onDownloadPdf?: (issuedInvoice: IssuedInvoiceListRow) => void; pdfDownloadingId?: string | null; isPdfDownloading?: boolean; }; export function useIssuedInvoicesGridColumns( actionHandlers: GridActionHandlers = {} -): ColumnDef[] { +): ColumnDef[] { const { t } = useTranslation(); - return React.useMemo[]>( + return React.useMemo[]>( () => [ // Nº { @@ -47,7 +48,7 @@ export function useIssuedInvoicesGridColumns( cell: ({ row }) => (
{row.original.series} - {row.original.invoice_number} + {row.original.invoiceNumber}
), enableHiding: false, @@ -106,11 +107,13 @@ export function useIssuedInvoicesGridColumns( ) : ( - - - - - + + + + } + /> @@ -192,7 +195,7 @@ export function useIssuedInvoicesGridColumns( ), cell: ({ row }) => (
- {formatDate(row.original.invoice_date)} + {formatDate(row.original.invoiceDate)}
), enableSorting: false, @@ -214,7 +217,7 @@ export function useIssuedInvoicesGridColumns( ), cell: ({ row }) => (
- {formatDate(row.original.operation_date)} + {formatDate(row.original.operationDate)}
), enableSorting: false, @@ -237,7 +240,7 @@ export function useIssuedInvoicesGridColumns( ), cell: ({ row }) => (
- {row.original.subtotal_amount_fmt} + {row.original.subtotalAmountFmt}
), enableSorting: false, @@ -260,7 +263,7 @@ export function useIssuedInvoicesGridColumns( ), cell: ({ row }) => (
- {row.original.discount_amount_fmt} + {row.original.totalDiscountAmountFmt}
), enableSorting: false, @@ -282,7 +285,7 @@ export function useIssuedInvoicesGridColumns( /> ), cell: ({ row }) => ( -
{row.original.taxes_amount_fmt}
+
{row.original.taxesAmountFmt}
), enableSorting: false, size: 120, @@ -303,9 +306,7 @@ export function useIssuedInvoicesGridColumns( /> ), cell: ({ row }) => ( -
- {row.original.total_amount_fmt} -
+
{row.original.totalAmountFmt}
), enableSorting: false, size: 140, @@ -343,25 +344,27 @@ export function useIssuedInvoicesGridColumns( {/* Descargar en PDF */} - - - + { + stop(e); + isCompleted ? actionHandlers.onDownloadPdf?.(issuedInvoice) : null; + }} + size="icon" + variant="ghost" + > + {isPDFLoading ? ( + + ) : ( + + )} + Descargar PDF + + } + /> Descargar PDF @@ -369,31 +372,35 @@ export function useIssuedInvoicesGridColumns( {/** biome-ignore lint/suspicious/noSelfCompare: */} {false !== false && ( - - - + + )} diff --git a/modules/customer-invoices/src/web/issued-invoices/list/ui/components/verifactu-status-badge.tsx b/modules/customer-invoices/src/web/issued-invoices/list/ui/components/verifactu-status-badge.tsx index a1eadcfc..89e6e080 100644 --- a/modules/customer-invoices/src/web/issued-invoices/list/ui/components/verifactu-status-badge.tsx +++ b/modules/customer-invoices/src/web/issued-invoices/list/ui/components/verifactu-status-badge.tsx @@ -7,7 +7,7 @@ import { getVerifactuRecordStatusButtonVariant, getVerifactuRecordStatusColor, getVerifactuRecordStatusIcon, -} from "../../../types"; +} from "../../../shared"; export type VerifactuStatusBadgeProps = { status: string | VerifactuRecordStatus; // permitir cualquier valor @@ -21,21 +21,23 @@ export const VerifactuStatusBadge = ({ status, className }: VerifactuStatusBadge return ( - - - - {t(`catalog.issued_invoices.status.${normalizedStatus.toLowerCase()}.label`, { - defaultValue: status, - })} - - + + + {t(`catalog.issued_invoices.status.${normalizedStatus.toLowerCase()}.label`, { + defaultValue: status, + })} + + } + />

{t(`catalog.issued_invoices.status.${normalizedStatus.toLowerCase()}.description`)}

diff --git a/modules/customer-invoices/src/web/issued-invoices/list/ui/pages/index.ts b/modules/customer-invoices/src/web/issued-invoices/list/ui/pages/index.ts index 77624ddb..92d42c74 100644 --- a/modules/customer-invoices/src/web/issued-invoices/list/ui/pages/index.ts +++ b/modules/customer-invoices/src/web/issued-invoices/list/ui/pages/index.ts @@ -1 +1 @@ -export * from "./issued-invoice-list-page"; +export * from "./list-issued-invoices-page"; 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/list-issued-invoices-page.tsx similarity index 82% rename from modules/customer-invoices/src/web/issued-invoices/list/ui/pages/issued-invoice-list-page.tsx rename to modules/customer-invoices/src/web/issued-invoices/list/ui/pages/list-issued-invoices-page.tsx index 864c29ed..afbe7149 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/list-issued-invoices-page.tsx @@ -18,10 +18,10 @@ import { useTranslation } from "../../../../i18n"; import { useIssuedInvoiceListPageController } from "../../controllers"; import { IssuedInvoicesGrid, useIssuedInvoicesGridColumns } from "../blocks"; -export const IssuedInvoiceListPage = () => { +export const ListIssuedInvoicesPage = () => { const { t } = useTranslation(); - const navigate = useNavigate(); + const { listCtrl, handleDownloadPDF, @@ -43,7 +43,7 @@ export const IssuedInvoiceListPage = () => { widthClass: "w-[500px]", });*/ - if (listCtrl.isError || !listCtrl.data) { + if (listCtrl.isError) { return ( { } return ( - <> +
{ title={t("pages.issued_invoices.list.title")} /> - + +
¡Atención! @@ -87,13 +88,17 @@ export const IssuedInvoiceListPage = () => { {/* Search and filters */} -
+
- listCtrl.setStatusFilter(value ?? "all")} + value={listCtrl.statusFilter} + > @@ -127,19 +132,20 @@ export const IssuedInvoiceListPage = () => {
- - navigate(`/issuedInvoices/${id}`)} - pageIndex={listCtrl.pageIndex} - pageSize={listCtrl.pageSize} - /> +
+ navigate(`/issuedInvoices/${id}`)} + pageIndex={listCtrl.pageIndex} + pageSize={listCtrl.pageSize} + /> +
- +
); }; diff --git a/modules/customer-invoices/src/web/issued-invoices/shared/adapters/index.ts b/modules/customer-invoices/src/web/issued-invoices/shared/adapters/index.ts new file mode 100644 index 00000000..319eabd8 --- /dev/null +++ b/modules/customer-invoices/src/web/issued-invoices/shared/adapters/index.ts @@ -0,0 +1 @@ +export * from "./list-issued-invoice.adapter"; diff --git a/modules/customer-invoices/src/web/issued-invoices/shared/adapters/list-issued-invoice.adapter.ts b/modules/customer-invoices/src/web/issued-invoices/shared/adapters/list-issued-invoice.adapter.ts new file mode 100644 index 00000000..41fad62c --- /dev/null +++ b/modules/customer-invoices/src/web/issued-invoices/shared/adapters/list-issued-invoice.adapter.ts @@ -0,0 +1,101 @@ +import { MoneyDTOHelper, formatCurrency } from "@erp/core"; + +import type { ListIssuedInvoicesResponseDTO } from "../../../../common"; +import type { IssuedInvoiceList, IssuedInvoiceListRow, IssuedInvoiceStatus } from "../entities"; +import type { VerifactuRecordStatus } from "../entities/verifactu-record-status.entity"; + +export const ListIssuedInvoicesAdapter = { + fromDto(dto: ListIssuedInvoicesResponseDTO): IssuedInvoiceList { + return { + items: dto.items.map(IssuedInvoiceListRowAdapter.fromDto), + page: dto.page, + perPage: dto.per_page, + totalPages: dto.total_pages, + totalItems: dto.total_items, + }; + }, +}; + +type ListIssuedInvoicesItemDTO = ListIssuedInvoicesResponseDTO["items"][number]; + +const IssuedInvoiceListRowAdapter = { + fromDto(dto: ListIssuedInvoicesItemDTO): IssuedInvoiceListRow { + return { + id: dto.id, + companyId: dto.company_id, + + invoiceNumber: dto.invoice_number, + status: dto.status as IssuedInvoiceStatus, + series: dto.series, + + invoiceDate: dto.invoice_date, + operationDate: dto.operation_date, + + languageCode: dto.language_code, + currencyCode: dto.currency_code, + + reference: dto.reference, + description: dto.description, + recipient: { + id: dto.customer_id, + tin: dto.recipient.tin, + name: dto.recipient.name, + + street: dto.recipient.street, + street2: dto.recipient.street2, + city: dto.recipient.city, + province: dto.recipient.province, + postalCode: dto.recipient.postal_code, + country: dto.recipient.country, + }, + + subtotalAmount: MoneyDTOHelper.toNumber(dto.subtotal_amount), + subtotalAmountFmt: formatCurrency( + MoneyDTOHelper.toNumber(dto.subtotal_amount), + Number(dto.total_amount.scale || 2), + dto.currency_code, + dto.language_code + ), + + totalDiscountAmount: MoneyDTOHelper.toNumber(dto.total_discount_amount), + totalDiscountAmountFmt: formatCurrency( + MoneyDTOHelper.toNumber(dto.total_discount_amount), + Number(dto.total_amount.scale || 2), + dto.currency_code, + dto.language_code + ), + + taxableAmount: MoneyDTOHelper.toNumber(dto.taxable_amount), + taxableAmountFmt: formatCurrency( + MoneyDTOHelper.toNumber(dto.taxable_amount), + Number(dto.total_amount.scale || 2), + dto.currency_code, + dto.language_code + ), + + taxesAmount: MoneyDTOHelper.toNumber(dto.taxes_amount), + taxesAmountFmt: formatCurrency( + MoneyDTOHelper.toNumber(dto.taxes_amount), + Number(dto.total_amount.scale || 2), + dto.currency_code, + dto.language_code + ), + + totalAmount: MoneyDTOHelper.toNumber(dto.total_amount), + totalAmountFmt: formatCurrency( + MoneyDTOHelper.toNumber(dto.total_amount), + Number(dto.total_amount.scale || 2), + dto.currency_code, + dto.language_code + ), + + //linkedProformaId: dto., + + verifactu: { + status: dto.verifactu.status as unknown as VerifactuRecordStatus, + url: dto.verifactu.url, + qr_code: dto.verifactu.qr_code, + }, + }; + }, +}; diff --git a/modules/customer-invoices/src/web/issued-invoices/shared/api/index.ts b/modules/customer-invoices/src/web/issued-invoices/shared/api/index.ts new file mode 100644 index 00000000..266a4b2a --- /dev/null +++ b/modules/customer-invoices/src/web/issued-invoices/shared/api/index.ts @@ -0,0 +1 @@ +export * from "./list-issued-invoices-by-criteria.api"; diff --git a/modules/customer-invoices/src/web/issued-invoices/shared/api/list-issued-invoices-by-criteria.api.ts b/modules/customer-invoices/src/web/issued-invoices/shared/api/list-issued-invoices-by-criteria.api.ts new file mode 100644 index 00000000..7e96dc03 --- /dev/null +++ b/modules/customer-invoices/src/web/issued-invoices/shared/api/list-issued-invoices-by-criteria.api.ts @@ -0,0 +1,32 @@ +import type { CriteriaDTO } from "@erp/core"; +import type { IDataSource } from "@erp/core/client"; + +import type { ListIssuedInvoicesResponseDTO } from "../../../../common"; + +/** + * Recupera una lista de facturas del sistema utilizando la + * fuente de datos proporcionada y los criterios de búsqueda especificados. + * + * @param dataSource - La fuente de datos para interactuar con la API. + * @param params - Los parámetros necesarios para listar las facturas, incluyendo los criterios de búsqueda. + * @returns Una promesa que resuelve con una lista de facturas que cumplen con los criterios especificados. + * @throws Error si la recuperación de la lista de facturas falla. + */ + +export type ListIssuedInvoicesByCriteriaParams = { + criteria?: CriteriaDTO; + signal?: AbortSignal; +}; + +export type ListIssuedInvoicesResult = ListIssuedInvoicesResponseDTO; + +export function getListIssuedInvoicesByCriteria( + dataSource: IDataSource, + params: ListIssuedInvoicesByCriteriaParams +): Promise { + const { criteria, signal } = params || { criteria: undefined, signal: undefined }; + return dataSource.getList("issued-invoices", { + signal, + ...criteria, + }); +} diff --git a/modules/customer-invoices/src/web/issued-invoices/shared/entities/index.ts b/modules/customer-invoices/src/web/issued-invoices/shared/entities/index.ts new file mode 100644 index 00000000..4c58c6b2 --- /dev/null +++ b/modules/customer-invoices/src/web/issued-invoices/shared/entities/index.ts @@ -0,0 +1,4 @@ +export * from "./issued-invoice-list.entity"; +export * from "./issued-invoice-list-row.entity"; +export * from "./issued-invoice-status.entity"; +export * from "./verifactu-record-status.entity"; diff --git a/modules/customer-invoices/src/web/issued-invoices/shared/entities/issued-invoice-list-row.entity.ts b/modules/customer-invoices/src/web/issued-invoices/shared/entities/issued-invoice-list-row.entity.ts new file mode 100644 index 00000000..4b902871 --- /dev/null +++ b/modules/customer-invoices/src/web/issued-invoices/shared/entities/issued-invoice-list-row.entity.ts @@ -0,0 +1,47 @@ +import type { IssuedInvoiceRecipient } from "./issued-invoice-recipient.entity"; +import type { IssuedInvoiceStatus } from "./issued-invoice-status.entity"; +import type { VerifactuRecord } from "./verifactu-record.entity"; + +/** + * Interface que representa una fila de la lista de + * facturas en el sistema, adaptada desde la respuesta de la API. + * Contiene los campos justos para mostrar + * la información básica de cada factura en la lista. + */ + +export interface IssuedInvoiceListRow { + id: string; + companyId: string; + + invoiceNumber: string; + status: IssuedInvoiceStatus; + series: string; + + invoiceDate: string; + operationDate: string; + + languageCode: string; + currencyCode: string; + + reference: string; + description: string; + + recipient: IssuedInvoiceRecipient; + + subtotalAmount: number; + subtotalAmountFmt: string; + + totalDiscountAmount: number; + totalDiscountAmountFmt: string; + + taxableAmount: number; + taxableAmountFmt: string; + + taxesAmount: number; + taxesAmountFmt: string; + + totalAmount: number; + totalAmountFmt: string; + + verifactu: VerifactuRecord; +} diff --git a/modules/customer-invoices/src/web/issued-invoices/shared/entities/issued-invoice-list.entity.ts b/modules/customer-invoices/src/web/issued-invoices/shared/entities/issued-invoice-list.entity.ts new file mode 100644 index 00000000..05a01ac8 --- /dev/null +++ b/modules/customer-invoices/src/web/issued-invoices/shared/entities/issued-invoice-list.entity.ts @@ -0,0 +1,14 @@ +import type { IssuedInvoiceListRow } from "./issued-invoice-list-row.entity"; + +/** + * Interface que representa la respuesta paginada de una lista de proformas, + * adaptada desde la respuesta de la API. + */ + +export interface IssuedInvoiceList { + items: IssuedInvoiceListRow[]; + totalPages: number; + totalItems: number; + page: number; + perPage: number; +} diff --git a/modules/customer-invoices/src/web/issued-invoices/shared/entities/issued-invoice-recipient.entity.ts b/modules/customer-invoices/src/web/issued-invoices/shared/entities/issued-invoice-recipient.entity.ts new file mode 100644 index 00000000..a4cc274e --- /dev/null +++ b/modules/customer-invoices/src/web/issued-invoices/shared/entities/issued-invoice-recipient.entity.ts @@ -0,0 +1,18 @@ +/** + * Interface que representa el destinatario de una factura en el sistema, + * adaptada desde la respuesta de la API. + */ + +export interface IssuedInvoiceRecipient { + id: string; + name: string; + tin: string; + + street: string; + street2: string; + + city: string; + province: string; + postalCode: string; + country: string; +} diff --git a/modules/customer-invoices/src/web/issued-invoices/shared/entities/issued-invoice-status.entity.ts b/modules/customer-invoices/src/web/issued-invoices/shared/entities/issued-invoice-status.entity.ts new file mode 100644 index 00000000..abf2bd6b --- /dev/null +++ b/modules/customer-invoices/src/web/issued-invoices/shared/entities/issued-invoice-status.entity.ts @@ -0,0 +1,26 @@ +/** + * Enumeración que representa + * los posibles estados de una proforma en el sistema. + */ + +export enum ISSUED_INVOICE_STATUS { + DRAFT = "draft", + SENT = "sent", + APPROVED = "approved", + REJECTED = "rejected", + ISSUED = "issued", +} + +// Transiciones válidas según reglas del dominio +export const ISSUED_INVOICE_STATUS_TRANSITIONS: Record< + ISSUED_INVOICE_STATUS, + ISSUED_INVOICE_STATUS[] +> = { + [ISSUED_INVOICE_STATUS.DRAFT]: [ISSUED_INVOICE_STATUS.SENT], + [ISSUED_INVOICE_STATUS.SENT]: [ISSUED_INVOICE_STATUS.APPROVED, ISSUED_INVOICE_STATUS.REJECTED], + [ISSUED_INVOICE_STATUS.APPROVED]: [ISSUED_INVOICE_STATUS.ISSUED, ISSUED_INVOICE_STATUS.DRAFT], + [ISSUED_INVOICE_STATUS.REJECTED]: [ISSUED_INVOICE_STATUS.DRAFT], + [ISSUED_INVOICE_STATUS.ISSUED]: [], +}; + +export type IssuedInvoiceStatus = `${ISSUED_INVOICE_STATUS}`; diff --git a/modules/customer-invoices/src/web/issued-invoices/types/verifactu-record-status.ts b/modules/customer-invoices/src/web/issued-invoices/shared/entities/verifactu-record-status.entity.ts similarity index 100% rename from modules/customer-invoices/src/web/issued-invoices/types/verifactu-record-status.ts rename to modules/customer-invoices/src/web/issued-invoices/shared/entities/verifactu-record-status.entity.ts diff --git a/modules/customer-invoices/src/web/issued-invoices/shared/entities/verifactu-record.entity.ts b/modules/customer-invoices/src/web/issued-invoices/shared/entities/verifactu-record.entity.ts new file mode 100644 index 00000000..b69680ff --- /dev/null +++ b/modules/customer-invoices/src/web/issued-invoices/shared/entities/verifactu-record.entity.ts @@ -0,0 +1,7 @@ +import type { VerifactuRecordStatus } from "./verifactu-record-status.entity"; + +export interface VerifactuRecord { + status: VerifactuRecordStatus; + url: string; + qr_code: string; +} diff --git a/modules/customer-invoices/src/web/issued-invoices/shared/hooks/keys.ts b/modules/customer-invoices/src/web/issued-invoices/shared/hooks/keys.ts new file mode 100644 index 00000000..55a9392d --- /dev/null +++ b/modules/customer-invoices/src/web/issued-invoices/shared/hooks/keys.ts @@ -0,0 +1,24 @@ +import type { QueryKey } from "@tanstack/react-query"; + +import type { ListIssuedInvoicesRequestDTO } from "../../../../common"; + +/** + * Prefijo base para listados + */ +export const LIST_ISSUED_INVOICES_QUERY_KEY_PREFIX = ["issued_invoices"] as const; + +/** + * Query key para listado de facturas + */ +export const LIST_ISSUED_INVOICES_QUERY_KEY = (criteria?: ListIssuedInvoicesRequestDTO): QueryKey => + [ + ...LIST_ISSUED_INVOICES_QUERY_KEY_PREFIX, + { + pageNumber: criteria?.pageNumber ?? 1, + pageSize: criteria?.pageSize ?? 5, + q: criteria?.q ?? "", + filters: criteria?.filters ?? [], + orderBy: criteria?.orderBy ?? "", + order: criteria?.order ?? "", + }, + ] as const; diff --git a/modules/customer-invoices/src/web/issued-invoices/shared/hooks/use-issued-invoice-list-query.ts b/modules/customer-invoices/src/web/issued-invoices/shared/hooks/use-issued-invoice-list-query.ts index f788632f..c2559d34 100644 --- a/modules/customer-invoices/src/web/issued-invoices/shared/hooks/use-issued-invoice-list-query.ts +++ b/modules/customer-invoices/src/web/issued-invoices/shared/hooks/use-issued-invoice-list-query.ts @@ -1,39 +1,31 @@ import type { CriteriaDTO } from "@erp/core"; import { useDataSource } from "@erp/core/hooks"; -import { INITIAL_PAGE_INDEX, INITIAL_PAGE_SIZE } from "@repo/rdx-criteria"; -import { type DefaultError, type QueryKey, useQuery } from "@tanstack/react-query"; +import { type DefaultError, useQuery } from "@tanstack/react-query"; -import { getIssuedInvoiceListApi } from "../../list/api"; -import type { IssuedInvoiceSummaryPage } from "../../types"; +import { ListIssuedInvoicesAdapter } from "../adapters"; +import { getListIssuedInvoicesByCriteria } from "../api"; +import type { IssuedInvoiceList } from "../entities"; -export const ISSUED_INVOICES_QUERY_KEY = (criteria?: CriteriaDTO): QueryKey => [ - "issued_invoices", - { - pageNumber: criteria?.pageNumber ?? INITIAL_PAGE_INDEX, - pageSize: criteria?.pageSize ?? INITIAL_PAGE_SIZE, - q: criteria?.q ?? "", - filters: criteria?.filters ?? [], - orderBy: criteria?.orderBy ?? "", - order: criteria?.order ?? "", - }, -]; +import { LIST_ISSUED_INVOICES_QUERY_KEY } from "./keys"; -type IssuedInvoicesQueryOptions = { +export interface IssuedInvoicesListQueryOptions { enabled?: boolean; - criteria?: CriteriaDTO; -}; + criteria?: Partial; +} // Obtener todas las facturas -export const useIssuedInvoiceListQuery = (options?: IssuedInvoicesQueryOptions) => { +export const useIssuedInvoiceListQuery = (options?: IssuedInvoicesListQueryOptions) => { const dataSource = useDataSource(); const enabled = options?.enabled ?? true; const criteria = options?.criteria ?? {}; - return useQuery({ - queryKey: ISSUED_INVOICES_QUERY_KEY(criteria), - queryFn: async ({ signal }) => getIssuedInvoiceListApi(dataSource, signal, criteria), + return useQuery({ + queryKey: LIST_ISSUED_INVOICES_QUERY_KEY(criteria), + queryFn: async ({ signal }) => { + const dto = await getListIssuedInvoicesByCriteria(dataSource, { signal, criteria }); + return ListIssuedInvoicesAdapter.fromDto(dto); + }, enabled, - staleTime: 5000, - placeholderData: (previousData, _previousQuery) => previousData, // Mantener datos previos mientras se carga nueva datos (antiguo `keepPreviousData`) + placeholderData: (previousData) => previousData, // Mantiene la página anterior durante refetch por cambio de criteria }); }; diff --git a/modules/customer-invoices/src/web/issued-invoices/shared/index.ts b/modules/customer-invoices/src/web/issued-invoices/shared/index.ts index 007f69d0..432a07dc 100644 --- a/modules/customer-invoices/src/web/issued-invoices/shared/index.ts +++ b/modules/customer-invoices/src/web/issued-invoices/shared/index.ts @@ -1 +1,5 @@ +export * from "./adapters"; +export * from "./api"; +export * from "./entities"; export * from "./hooks"; +export * from "./ui"; diff --git a/modules/customer-invoices/src/web/issued-invoices/ui/blocks/index.ts b/modules/customer-invoices/src/web/issued-invoices/shared/ui/blocks/index.ts similarity index 100% rename from modules/customer-invoices/src/web/issued-invoices/ui/blocks/index.ts rename to modules/customer-invoices/src/web/issued-invoices/shared/ui/blocks/index.ts diff --git a/modules/customer-invoices/src/web/issued-invoices/ui/blocks/issued-invoices-layout.tsx b/modules/customer-invoices/src/web/issued-invoices/shared/ui/blocks/issued-invoices-layout.tsx similarity index 70% rename from modules/customer-invoices/src/web/issued-invoices/ui/blocks/issued-invoices-layout.tsx rename to modules/customer-invoices/src/web/issued-invoices/shared/ui/blocks/issued-invoices-layout.tsx index cbf693d4..f5b62307 100644 --- a/modules/customer-invoices/src/web/issued-invoices/ui/blocks/issued-invoices-layout.tsx +++ b/modules/customer-invoices/src/web/issued-invoices/shared/ui/blocks/issued-invoices-layout.tsx @@ -1,5 +1,5 @@ import type { PropsWithChildren } from "react"; export const IssuedInvoicesLayout = ({ children }: PropsWithChildren) => { - return
{children}
; + return
{children}
; }; diff --git a/modules/customer-invoices/src/web/issued-invoices/ui/index.ts b/modules/customer-invoices/src/web/issued-invoices/shared/ui/index.ts similarity index 100% rename from modules/customer-invoices/src/web/issued-invoices/ui/index.ts rename to modules/customer-invoices/src/web/issued-invoices/shared/ui/index.ts diff --git a/modules/customer-invoices/src/web/issued-invoices/types/index.ts b/modules/customer-invoices/src/web/issued-invoices/types/index.ts deleted file mode 100644 index 00ede27f..00000000 --- a/modules/customer-invoices/src/web/issued-invoices/types/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * from "./issued-invoice.api.schema"; -export * from "./issued-invoice-summary.web.schema"; -export * from "./verifactu-record-status"; diff --git a/modules/customer-invoices/src/web/issued-invoices/types/issued-invoice-summary.web.schema.ts b/modules/customer-invoices/src/web/issued-invoices/types/issued-invoice-summary.web.schema.ts deleted file mode 100644 index 7d15a57c..00000000 --- a/modules/customer-invoices/src/web/issued-invoices/types/issued-invoice-summary.web.schema.ts +++ /dev/null @@ -1,25 +0,0 @@ -import type { IssuedInvoiceSummary, IssuedInvoiceSummaryPage } from "./issued-invoice.api.schema"; - -export type IssuedInvoiceSummaryData = IssuedInvoiceSummary & { - subtotal_amount_fmt: string; - subtotal_amount: number; - - discount_percentage_fmt: string; - discount_percentage: number; - - discount_amount_fmt: string; - discount_amount: number; - - taxable_amount_fmt: string; - taxable_amount: number; - - taxes_amount_fmt: string; - taxes_amount: number; - - total_amount_fmt: string; - total_amount: number; -}; - -export type IssuedInvoiceSummaryPageData = IssuedInvoiceSummaryPage & { - items: IssuedInvoiceSummaryData[]; -}; diff --git a/modules/customer-invoices/src/web/issued-invoices/types/issued-invoice.api.schema.ts b/modules/customer-invoices/src/web/issued-invoices/types/issued-invoice.api.schema.ts deleted file mode 100644 index d8e681cf..00000000 --- a/modules/customer-invoices/src/web/issued-invoices/types/issued-invoice.api.schema.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { - GetIssuedInvoiceByIdResponseSchema, - type ListIssuedInvoicesResponseDTO, -} from "@erp/customer-invoices/common"; -import type { ArrayElement } from "@repo/rdx-utils"; -import type { z } from "zod/v4"; - -// IssuedInvoices -export const IssuedInvoiceSchema = GetIssuedInvoiceByIdResponseSchema.omit({ - metadata: true, -}); - -export type IssuedInvoice = z.infer; -export type IssuedInvoiceRecipient = IssuedInvoice["recipient"]; -export type IssuedInvoiceItem = ArrayElement; - -// Resultado de consulta con criteria (paginado, etc.) -export type IssuedInvoiceSummaryPage = Omit; -export type IssuedInvoiceSummary = Omit< - ArrayElement, - "metadata" ->; diff --git a/modules/customer-invoices/src/web/proformas/list/ui/blocks/proformas-grid/use-proforma-grid-columns.tsx b/modules/customer-invoices/src/web/proformas/list/ui/blocks/proformas-grid/use-proforma-grid-columns.tsx index aa38d346..36939e1a 100644 --- a/modules/customer-invoices/src/web/proformas/list/ui/blocks/proformas-grid/use-proforma-grid-columns.tsx +++ b/modules/customer-invoices/src/web/proformas/list/ui/blocks/proformas-grid/use-proforma-grid-columns.tsx @@ -101,18 +101,20 @@ export function useProformasGridColumns( {isIssued && ( - - - + + + + Ver factura {invoiceId} + + + } + /> Ver factura {invoiceId} @@ -235,17 +237,19 @@ export function useProformasGridColumns( {!isIssued && actionHandlers.onEditClick && ( - - - + actionHandlers.onEditClick?.(proforma)} + size="icon" + variant="ghost" + > + + Editar + + } + /> Editar @@ -255,19 +259,21 @@ export function useProformasGridColumns( {!isIssued && availableTransitions.length && actionHandlers.onChangeStatusClick && ( - - - + + actionHandlers.onChangeStatusClick?.(proforma, availableTransitions[0]) + } + size="icon" + variant="ghost" + > + + Cambiar estado + + } + /> Cambiar a {t(`catalog.proformas.status.${availableTransitions[0]}.label`)} @@ -279,16 +285,18 @@ export function useProformasGridColumns( {!isIssued && isApproved && actionHandlers.onIssueClick && ( - - - + actionHandlers.onIssueClick?.(proforma)} + size="icon" + variant="ghost" + > + + + } + /> Emitir a factura @@ -298,19 +306,21 @@ export function useProformasGridColumns( {!isIssued && actionHandlers.onDeleteClick && ( - - - + { + e.preventDefault(); + actionHandlers.onDeleteClick?.(proforma); + }} + size="icon" + variant="ghost" + > + + + } + /> Eliminar diff --git a/modules/customer-invoices/src/web/proformas/list/ui/components/index.ts b/modules/customer-invoices/src/web/proformas/list/ui/components/index.ts index 9300cc03..df695438 100644 --- a/modules/customer-invoices/src/web/proformas/list/ui/components/index.ts +++ b/modules/customer-invoices/src/web/proformas/list/ui/components/index.ts @@ -1,2 +1 @@ -export * from "./initials"; export * from "./proforma-status-badge"; diff --git a/modules/customer-invoices/src/web/proformas/list/ui/components/proforma-status-badge.tsx b/modules/customer-invoices/src/web/proformas/list/ui/components/proforma-status-badge.tsx index 744eb45d..2562ad9d 100644 --- a/modules/customer-invoices/src/web/proformas/list/ui/components/proforma-status-badge.tsx +++ b/modules/customer-invoices/src/web/proformas/list/ui/components/proforma-status-badge.tsx @@ -21,15 +21,17 @@ export const ProformaStatusBadge = ({ status, className }: ProformaStatusBadgePr return ( - - - - {t(`catalog.proformas.status.${normalizedStatus}.label`, { defaultValue: status })} - - + + + {t(`catalog.proformas.status.${normalizedStatus}.label`, { defaultValue: status })} + + } + />

{t(`catalog.proformas.status.${normalizedStatus}.description`)}

diff --git a/modules/customer-invoices/src/web/proformas/shared/hooks/keys.ts b/modules/customer-invoices/src/web/proformas/shared/hooks/keys.ts index 53e31246..5a1bc9ad 100644 --- a/modules/customer-invoices/src/web/proformas/shared/hooks/keys.ts +++ b/modules/customer-invoices/src/web/proformas/shared/hooks/keys.ts @@ -15,7 +15,7 @@ export const LIST_PROFORMAS_QUERY_KEY = (criteria?: ProformasListRequestDTO): Qu ...LIST_PROFORMAS_QUERY_KEY_PREFIX, { pageNumber: criteria?.pageNumber ?? 1, - pageSize: criteria?.pageSize ?? 10, + pageSize: criteria?.pageSize ?? 5, q: criteria?.q ?? "", filters: criteria?.filters ?? [], orderBy: criteria?.orderBy ?? "", diff --git a/modules/customers/src/web/list/ui/blocks/customers-grid/use-customer-grid-columns.tsx b/modules/customers/src/web/list/ui/blocks/customers-grid/use-customer-grid-columns.tsx index baa4fb30..6d21b530 100644 --- a/modules/customers/src/web/list/ui/blocks/customers-grid/use-customer-grid-columns.tsx +++ b/modules/customers/src/web/list/ui/blocks/customers-grid/use-customer-grid-columns.tsx @@ -5,6 +5,7 @@ import { Button, DropdownMenu, DropdownMenuContent, + DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, @@ -152,51 +153,55 @@ export function useCustomersGridColumns( - - - + + + + } + /> - {t("pages.list.grid_columns.actions")} + + {t("pages.list.grid_columns.actions")} - + - onViewClick?.(customer)}> - {t("pages.list.actions.view")} - + onViewClick?.(customer)}> + {t("pages.list.actions.view")} + - onEditClick?.(customer)}> - {t("pages.list.actions.edit")} - + onEditClick?.(customer)}> + {t("pages.list.actions.edit")} + - + - - window.open(safeHTTPUrl(website), "_blank", "noopener,noreferrer") - } - > - {t("pages.list.actions.visit_website")} - + + window.open(safeHTTPUrl(website), "_blank", "noopener,noreferrer") + } + > + {t("pages.list.actions.visit_website")} + - navigator.clipboard.writeText(email_primary)} - > - {t("pages.list.actions.copy_email")} - + navigator.clipboard.writeText(email_primary)} + > + {t("pages.list.actions.copy_email")} + - + - onDeleteClick?.(customer)} - > - {t("pages.list.actions.delete")} - + onDeleteClick?.(customer)} + > + {t("pages.list.actions.delete")} + + diff --git a/modules/customers/src/web/shared/ui/components/customer-status-badge.tsx b/modules/customers/src/web/shared/ui/components/customer-status-badge.tsx index e61d2f35..b3cf8ae7 100644 --- a/modules/customers/src/web/shared/ui/components/customer-status-badge.tsx +++ b/modules/customers/src/web/shared/ui/components/customer-status-badge.tsx @@ -30,11 +30,13 @@ export const CustomerStatusBadge = ({ status }: { status: string }) => { return ( - -
-
-
- + +
+
+ } + /> {contentTxt} ); diff --git a/packages/rdx-ui/src/components/datatable/data-table-column-header.tsx b/packages/rdx-ui/src/components/datatable/data-table-column-header.tsx index fd089874..3055cb11 100644 --- a/packages/rdx-ui/src/components/datatable/data-table-column-header.tsx +++ b/packages/rdx-ui/src/components/datatable/data-table-column-header.tsx @@ -2,6 +2,7 @@ import { Button, DropdownMenu, DropdownMenuContent, + DropdownMenuGroup, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuTrigger, @@ -31,38 +32,42 @@ export function DataTableColumnHeader({ return (
- - - + + {title} + {column.getIsSorted() === "desc" ? ( + + ) : column.getIsSorted() === "asc" ? ( + + ) : ( + + )} + + } + /> - column.toggleSorting(false)}> - - {t("components.datatable.asc")} - - column.toggleSorting(true)}> - - {t("components.datatable.desc")} - - - column.toggleVisibility(false)}> - - {t("components.datatable.hide")} - + + column.toggleSorting(false)}> + + {t("components.datatable.asc")} + + column.toggleSorting(true)}> + + {t("components.datatable.desc")} + + + column.toggleVisibility(false)}> + + {t("components.datatable.hide")} + +
diff --git a/packages/rdx-ui/src/components/datatable/data-table-pagination.tsx b/packages/rdx-ui/src/components/datatable/data-table-pagination.tsx index f46712bb..d4f41cb5 100644 --- a/packages/rdx-ui/src/components/datatable/data-table-pagination.tsx +++ b/packages/rdx-ui/src/components/datatable/data-table-pagination.tsx @@ -47,7 +47,8 @@ export function DataTablePagination({ table, className }: DataTablePagina table.setPageIndex(nextIndex); }; - const handlePageSizeChange = (size: string) => { + const handlePageSizeChange = (size: string | null) => { + if (!size) return; table.setPageSize(Number(size)); }; diff --git a/packages/rdx-ui/src/components/datatable/data-table-toolbar.tsx b/packages/rdx-ui/src/components/datatable/data-table-toolbar.tsx index ee55738b..92b898c1 100644 --- a/packages/rdx-ui/src/components/datatable/data-table-toolbar.tsx +++ b/packages/rdx-ui/src/components/datatable/data-table-toolbar.tsx @@ -113,34 +113,38 @@ export function DataTableToolbar({ {!readOnly && meta?.bulkOps?.moveSelectedUp && ( - - - + + )} {!readOnly && meta?.bulkOps?.moveSelectedDown && ( - - - + + )} @@ -164,12 +168,14 @@ export function DataTableToolbar({ - - - + + diff --git a/packages/rdx-ui/src/components/datatable/data-table-view-options.tsx b/packages/rdx-ui/src/components/datatable/data-table-view-options.tsx index ff1f1b91..55c3a13b 100644 --- a/packages/rdx-ui/src/components/datatable/data-table-view-options.tsx +++ b/packages/rdx-ui/src/components/datatable/data-table-view-options.tsx @@ -5,6 +5,7 @@ import { DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, + DropdownMenuGroup, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger, @@ -18,36 +19,41 @@ export function DataTableViewOptions({ table }: { table: Table }) const { t } = useTranslation(); return ( - - - + + + {t("components.datatable_view_options.columns_button")} + + } + /> + - - {t("components.datatable_view_options.toggle_columns")} - - - {table - .getAllColumns() - .filter((column) => typeof column.accessorFn !== "undefined" && column.getCanHide()) - .map((column) => { - return ( - column.toggleVisibility(!!value)} - > - {getColumnLabel(column)} - - ); - })} + + + {t("components.datatable_view_options.toggle_columns")} + + + {table + .getAllColumns() + .filter((column) => typeof column.accessorFn !== "undefined" && column.getCanHide()) + .map((column) => { + return ( + column.toggleVisibility(!!value)} + > + {getColumnLabel(column)} + + ); + })} + ); diff --git a/packages/rdx-ui/src/components/datatable/data-table.tsx b/packages/rdx-ui/src/components/datatable/data-table.tsx index d97c8472..49a7af57 100644 --- a/packages/rdx-ui/src/components/datatable/data-table.tsx +++ b/packages/rdx-ui/src/components/datatable/data-table.tsx @@ -1,13 +1,6 @@ "use client"; import { - Button, - Dialog, - DialogContent, - DialogDescription, - DialogFooter, - DialogHeader, - DialogTitle, TableBody, TableCell, Table as TableComp, @@ -80,7 +73,6 @@ export interface DataTableProps { enablePagination?: boolean; pageSize?: number; enableRowSelection?: boolean; - EditorComponent?: React.ComponentType<{ row: TData; index: number; onClose: () => void }>; getRowId?: (originalRow: TData, index: number, parent?: Row) => string; @@ -105,7 +97,6 @@ export function DataTable({ enablePagination = true, pageSize = 10, enableRowSelection = false, - EditorComponent, getRowId, @@ -125,7 +116,6 @@ export function DataTable({ React.useState(inititalcolumnVisibility); const [columnFilters, setColumnFilters] = React.useState([]); const [colSizes, setColSizes] = React.useState({}); - const [editIndex, setEditIndex] = React.useState(null); // Configuración TanStack const table = useReactTable({ @@ -139,7 +129,7 @@ export function DataTable({ getRowId ?? ((originalRow: TData, i: number) => { const row = originalRow as { id?: string | number }; - return row.id !== undefined ? String(row.id) : String(i); + return row.id === undefined ? String(i) : String(row.id); }), state: { @@ -183,8 +173,6 @@ export function DataTable({ getFacetedUniqueValues: getFacetedUniqueValues(), }); - const handleCloseEditor = React.useCallback(() => setEditIndex(null), []); - // Render principal return (
@@ -192,9 +180,9 @@ export function DataTable({
- + {/* CABECERA */} - + {table.getHeaderGroups().map((hg) => ( {hg.headers.map((h) => { @@ -230,9 +218,6 @@ export function DataTable({ data-state={row.getIsSelected() && "selected"} key={row.id} onClick={(e) => onRowClick?.(row.original, rowIndex, e)} - onDoubleClick={ - readOnly || onRowClick ? undefined : () => setEditIndex(rowIndex) - } onKeyDown={(e) => { if (e.key === "Enter" || e.key === " ") onRowClick?.(row.original, rowIndex, e as any); @@ -284,32 +269,6 @@ export function DataTable({ )}
- - {/* Editor modal */} - {EditorComponent && editIndex !== null && ( - - - - {t("components.datatable.editor.title")} - {t("components.datatable.editor.subtitle")} - - -
- -
- - - - -
-
- )}
); diff --git a/packages/rdx-ui/src/components/datatable/skeleton-data-table.tsx b/packages/rdx-ui/src/components/datatable/skeleton-data-table.tsx index 9636c06e..ee843644 100644 --- a/packages/rdx-ui/src/components/datatable/skeleton-data-table.tsx +++ b/packages/rdx-ui/src/components/datatable/skeleton-data-table.tsx @@ -1,74 +1,75 @@ import { - TableBody, - TableCell, - Table as TableComp, - TableHead, - TableHeader, - TableRow, + TableBody, + TableCell, + Table as TableComp, + TableHead, + TableHeader, + TableRow, } from "@repo/shadcn-ui/components"; // SkeletonTable.tsx import * as React from "react"; -import { SkeletonDataTableFooter } from './skeleton-data-table-footer.tsx'; + +import { SkeletonDataTableFooter } from "./skeleton-data-table-footer.tsx"; export type SkeletonTableProps = { - columns?: number; - rows?: number; - stickyHeader?: boolean; - showFooter?: boolean; - footerProps?: { pageIndex?: number; pageSize?: number; totalItems?: number }; -} + columns?: number; + rows?: number; + stickyHeader?: boolean; + showFooter?: boolean; + footerProps?: { pageIndex?: number; pageSize?: number; totalItems?: number }; +}; // Componente Skeleton de tabla genérico export const SkeletonDataTable = ({ - columns = 6, - rows = 10, - stickyHeader = true, - showFooter = true, - footerProps, + columns = 6, + rows = 10, + stickyHeader = true, + showFooter = true, + footerProps, }: SkeletonTableProps) => { - // Genera arrays para mapear - const cols = React.useMemo(() => Array.from({ length: columns }), [columns]); - const rws = React.useMemo(() => Array.from({ length: rows }), [rows]); + // Genera arrays para mapear + const cols = React.useMemo(() => Array.from({ length: columns }), [columns]); + const rws = React.useMemo(() => Array.from({ length: rows }), [rows]); - return ( -
- - - - {cols.map((_, i) => ( - -
- - ))} - - + return ( +
+ + + + {cols.map((_, i) => ( + +
+ + ))} + + - - {rws.map((_, r) => ( - - {cols.map((_, c) => ( - -
- {c > 0 && ( -
- )} - - ))} - - ))} - - + + {rws.map((_, r) => ( + + {cols.map((_, c) => ( + +
+ {c > 0 && ( +
+ )} + + ))} + + ))} + + - {showFooter && } + {showFooter && } - Loading table… -
- ); -} \ No newline at end of file + Loading table… +
+ ); +}; diff --git a/packages/rdx-ui/src/components/layout/app-topbar.tsx b/packages/rdx-ui/src/components/layout/app-topbar.tsx index 904f007c..9fe695bf 100644 --- a/packages/rdx-ui/src/components/layout/app-topbar.tsx +++ b/packages/rdx-ui/src/components/layout/app-topbar.tsx @@ -2,7 +2,6 @@ import { Avatar, AvatarFallback, AvatarImage, - Button, Separator, SidebarTrigger, } from "@repo/shadcn-ui/components"; @@ -22,12 +21,10 @@ export function AppTopbar() {
- - - JD - - + + + JD + } />
diff --git a/packages/rdx-ui/src/components/logo-verifactu.tsx b/packages/rdx-ui/src/components/logo-verifactu.tsx index 2e671e5a..d4142a40 100644 --- a/packages/rdx-ui/src/components/logo-verifactu.tsx +++ b/packages/rdx-ui/src/components/logo-verifactu.tsx @@ -3,7 +3,6 @@ export const LogoVerifactu = ({ color = "black", width = "100%", ...props }) =>