Facturas de cliente

This commit is contained in:
David Arranz 2025-10-08 18:53:26 +02:00
parent 04e3b835a0
commit 18c37692ea
2 changed files with 37 additions and 36 deletions

View File

@ -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
</div>
{/* Navegación por TAB: último campo de la fila */}
<LastCellTabHook linesLen={tableNav.fa.fields.length} onTabFromLast={tableNav.onTabFromLastCell} />
<LastCellTabHook itemsLength={tableNav.fa.fields.length} onTabFromLast={tableNav.onTabFromLastCell} />
</div >
);
}
// 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<HTMLTableRowElement>("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;
}

View File

@ -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<HTMLTableRowElement>("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;
}