From 18c37692ea7557ad015f56c232f4d690f4cc91f4 Mon Sep 17 00:00:00 2001 From: david Date: Wed, 8 Oct 2025 18:53:26 +0200 Subject: [PATCH] Facturas de cliente --- .../components/editor/items/items-editor.tsx | 39 ++----------------- .../editor/items/last-cell-tab-hook.tsx | 34 ++++++++++++++++ 2 files changed, 37 insertions(+), 36 deletions(-) create mode 100644 modules/customer-invoices/src/web/components/editor/items/last-cell-tab-hook.tsx diff --git a/modules/customer-invoices/src/web/components/editor/items/items-editor.tsx b/modules/customer-invoices/src/web/components/editor/items/items-editor.tsx index e1495b36..8d088f2d 100644 --- a/modules/customer-invoices/src/web/components/editor/items/items-editor.tsx +++ b/modules/customer-invoices/src/web/components/editor/items/items-editor.tsx @@ -3,13 +3,14 @@ import { Button, Checkbox, Table, TableBody, TableCell, TableFooter, TableHead, import { ArrowDown, ArrowUp, CopyIcon, Trash2 } from "lucide-react"; import * as React from "react"; import { Controller, useFormContext } from "react-hook-form"; -import { useCalculateItemAmounts, useItemsTableNavigation } from '../../../hooks'; +import { useItemsTableNavigation } from '../../../hooks'; import { useTranslation } from '../../../i18n'; import { CustomerInvoiceItemFormData, defaultCustomerInvoiceItemFormData } from '../../../schemas'; import { CustomerInvoiceTaxesMultiSelect } from '../../customer-invoice-taxes-multi-select'; import { AmountDTOInputField } from './amount-dto-input-field'; import { HoverCardTotalsSummary } from './hover-card-total-summary'; import { ItemsEditorToolbar } from './items-editor-toolbar'; +import { LastCellTabHook } from './last-cell-tab-hook'; import { PercentageDTOInputField } from './percentage-dto-input-field'; import { QuantityDTOInputField } from './quantity-dto-input-field'; @@ -38,11 +39,6 @@ export const ItemsEditor = ({ value = [], onChange, readOnly = false }: ItemsEdi const selectedIdx = React.useMemo(() => [...selection].sort((a, b) => a - b), [selection]); const resetSelection = () => setSelection(new Set()); - const calculateItemAmounts = useCalculateItemAmounts({ - currencyCode: 'EUR', - locale: 'es', - taxCatalog - }); // Emitir cambios a quien consuma el componente React.useEffect(() => { @@ -298,37 +294,8 @@ export const ItemsEditor = ({ value = [], onChange, readOnly = false }: ItemsEdi {/* Navegación por TAB: último campo de la fila */} - + ); } -// Navegación por TAB desde el último control de la fila -function LastCellTabHook({ - linesLen, - onTabFromLast, -}: { - linesLen: number; - onTabFromLast: (row: number) => void; -}) { - React.useEffect(() => { - const handler = (e: KeyboardEvent) => { - if (e.key !== "Tab" || e.shiftKey) return; - const target = e.target as HTMLElement | null; - if (!target) return; - const tr = target.closest("tr[data-row-index]"); - if (!tr) return; - // Asumimos el trigger de impuestos como último focusable de la fila - const isTaxTrigger = target.getAttribute("aria-label")?.toLowerCase().includes("tax"); - if (!isTaxTrigger) return; - const rowIndex = Number(tr.dataset.rowIndex ?? -1); - if (rowIndex >= 0) { - e.preventDefault(); - onTabFromLast(rowIndex); - } - }; - document.addEventListener("keydown", handler); - return () => document.removeEventListener("keydown", handler); - }, [linesLen, onTabFromLast]); - return null; -} \ No newline at end of file diff --git a/modules/customer-invoices/src/web/components/editor/items/last-cell-tab-hook.tsx b/modules/customer-invoices/src/web/components/editor/items/last-cell-tab-hook.tsx new file mode 100644 index 00000000..95a97668 --- /dev/null +++ b/modules/customer-invoices/src/web/components/editor/items/last-cell-tab-hook.tsx @@ -0,0 +1,34 @@ +import { useEffect } from 'react'; + +// Navegación por TAB desde el último control de la fila +export const LastCellTabHook = ({ + itemsLength, + onTabFromLast, +}: { + itemsLength: number; + onTabFromLast: (row: number) => void; +}) => { + useEffect(() => { + const handler = (e: KeyboardEvent) => { + if (e.key !== "Tab" || e.shiftKey) return; + const target = e.target as HTMLElement | null; + if (!target) return; + const tr = target.closest("tr[data-row-index]"); + if (!tr) return; + + // Asumimos el trigger de impuestos como último focusable de la fila + const isTaxTrigger = target.getAttribute("aria-label")?.toLowerCase().includes("tax"); + + if (!isTaxTrigger) return; + + const rowIndex = Number(tr.dataset.rowIndex ?? -1); + if (rowIndex >= 0) { + e.preventDefault(); + onTabFromLast(rowIndex); + } + }; + document.addEventListener("keydown", handler); + return () => document.removeEventListener("keydown", handler); + }, [itemsLength, onTabFromLast]); + return null; +} \ No newline at end of file