diff --git a/apps/web/index.html b/apps/web/index.html index 10318ef9..4e950c62 100644 --- a/apps/web/index.html +++ b/apps/web/index.html @@ -9,6 +9,7 @@ FactuGES 2025 + diff --git a/apps/web/package.json b/apps/web/package.json index b5f415f1..93d452b2 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -17,7 +17,6 @@ "@hookform/devtools": "^4.4.0", "@repo/typescript-config": "workspace:*", "@tailwindcss/postcss": "^4.1.5", - "@tailwindcss/vite": "^4.1.6", "@tanstack/react-query-devtools": "^5.74.11", "@types/dinero.js": "^1.9.4", "@types/node": "^22.15.12", @@ -33,9 +32,11 @@ "@erp/auth": "workspace:*", "@erp/core": "workspace:*", "@erp/customer-invoices": "workspace:*", + "@erp/customers": "workspace:*", "@repo/rdx-criteria": "workspace:*", "@repo/rdx-ui": "workspace:*", "@repo/shadcn-ui": "workspace:*", + "@tailwindcss/vite": "^4.1.11", "@tanstack/react-query": "^5.74.11", "axios": "^1.9.0", "dinero.js": "^1.9.1", @@ -50,7 +51,7 @@ "react-secure-storage": "^1.3.2", "sequelize": "^6.37.5", "tailwind-merge": "^3.2.0", - "tailwindcss": "^4.1.6", + "tailwindcss": "^4.1.10", "tw-animate-css": "^1.2.9", "vite-plugin-html": "^3.2.2" } diff --git a/apps/web/postcss.config.mjs b/apps/web/postcss.config.mjs deleted file mode 100644 index a1523e19..00000000 --- a/apps/web/postcss.config.mjs +++ /dev/null @@ -1 +0,0 @@ -export { default } from "@repo/shadcn-ui/postcss.config.mjs"; diff --git a/apps/web/src/app.css b/apps/web/src/app.css index b28b04f6..5a7873ab 100644 --- a/apps/web/src/app.css +++ b/apps/web/src/app.css @@ -1,3 +1,2 @@ - - - +@import "tailwindcss"; +@import "tw-animate-css"; diff --git a/apps/web/src/global.css b/apps/web/src/global.css index d1572867..2761e4cf 100644 --- a/apps/web/src/global.css +++ b/apps/web/src/global.css @@ -1,20 +1,23 @@ -@import 'tailwindcss'; +@import "tailwindcss"; @import "tw-animate-css"; -@import '@repo/shadcn-ui/globals.css'; -@import '@repo/rdx-ui/globals.css'; +@import "@repo/shadcn-ui/globals.css"; +@import "@repo/rdx-ui/globals.css"; +@import "@erp/customers/globals.css"; +@import "@erp/customer-invoices/globals.css"; -@theme { - --font-sans: "Calibri", ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; +@theme { + --font-sans: "Calibri", ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", + "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; } - /** * Tailwind CSS official document: * https://tailwindcss.com/docs/detecting-classes-in-source-files * - * if you ever need to explicitly add a source that's excluded by default, + * if you ever need to explicitly add a source that's excluded by default, * you can always add it with the @source directive. */ + @source '../node_modules/@repo/shadcn-ui'; -@source '../node_modules/@repo/rdx-ui'; \ No newline at end of file +@source '../node_modules/@repo/rdx-ui'; diff --git a/apps/web/tailwind.config.mts b/apps/web/tailwind.config.mts deleted file mode 100644 index d41501e3..00000000 --- a/apps/web/tailwind.config.mts +++ /dev/null @@ -1 +0,0 @@ -export * from "@repo/shadcn-ui/tailwind.config.mjs"; diff --git a/biome.json b/biome.json index 109f2e3d..5f1af7a4 100644 --- a/biome.json +++ b/biome.json @@ -25,7 +25,7 @@ "complexity": { "noForEach": "off", "noBannedTypes": "info", - "useOptionalChain": "info" + "useOptionalChain": "off" }, "suspicious": { "noImplicitAnyLet": "info", diff --git a/modules/core/src/common/index.ts b/modules/core/src/common/index.ts index c29f47c1..bd3e74b5 100644 --- a/modules/core/src/common/index.ts +++ b/modules/core/src/common/index.ts @@ -1,2 +1,3 @@ export * from "./dto"; +export * from "./schemas"; export * from "./types"; diff --git a/modules/core/src/common/schemas/core.schemas.ts b/modules/core/src/common/schemas/core.schemas.ts new file mode 100644 index 00000000..38db200d --- /dev/null +++ b/modules/core/src/common/schemas/core.schemas.ts @@ -0,0 +1,29 @@ +import { z } from "zod"; + +/*** + * Cantidad + * – admite decimales hasta 2 cifras + * – el campo `amount` puede ser null + */ +export const makeAmountSchema = ({ maxScale = 2, nullable = false } = {}) => { + const amount = z.number().refine((v) => Number.isFinite(v), "Amount must be a finite number"); + + return z.object({ + amount: nullable ? amount.nullable() : amount, + scale: z.number().int().nonnegative().max(maxScale, `Scale cannot exceed ${maxScale}`), + }); +}; + +/** + * Porcentaje ≥ 0 ≤ 100 + * – admite decimales hasta 2 cifras + * – el campo `amount` puede ser null + */ +export const makePercentageSchema = ({ maxScale = 2, min = 0, max = 100, nullable = true } = {}) => + makeAmountSchema({ maxScale, nullable }).extend({ + amount: z + .number() + .min(min, `El porcentaje debe ser ≥ ${min}`) + .max(max, `El porcentaje no puede superar ${max}`) + .nullable(), + }); diff --git a/modules/core/src/common/schemas/index.ts b/modules/core/src/common/schemas/index.ts new file mode 100644 index 00000000..e0906790 --- /dev/null +++ b/modules/core/src/common/schemas/index.ts @@ -0,0 +1 @@ +export * from "./core.schemas"; diff --git a/modules/customer-invoices/package.json b/modules/customer-invoices/package.json index 7119e221..eb8106fe 100644 --- a/modules/customer-invoices/package.json +++ b/modules/customer-invoices/package.json @@ -6,7 +6,8 @@ "exports": { ".": "./src/common/index.ts", "./api": "./src/api/index.ts", - "./client": "./src/web/manifest.ts" + "./client": "./src/web/manifest.ts", + "./globals.css": "./src/web/globals.css" }, "peerDependencies": { "dinero.js": "^1.9.1" @@ -22,7 +23,11 @@ }, "dependencies": { "@ag-grid-community/locale": "34.0.0", + "@dnd-kit/core": "^6.3.1", + "@dnd-kit/sortable": "^10.0.0", + "@dnd-kit/utilities": "^3.2.2", "@erp/core": "workspace:*", + "@erp/customers": "workspace:*", "@hookform/resolvers": "^5.0.1", "@repo/rdx-criteria": "workspace:*", "@repo/rdx-ddd": "workspace:*", @@ -30,6 +35,7 @@ "@repo/rdx-utils": "workspace:*", "@repo/shadcn-ui": "workspace:*", "@tanstack/react-query": "^5.74.11", + "@tanstack/react-table": "^8.21.3", "ag-grid-community": "^33.3.0", "ag-grid-react": "^33.3.0", "date-fns": "^4.1.0", @@ -43,6 +49,9 @@ "react-router-dom": "^6.26.0", "sequelize": "^6.37.5", "slugify": "^1.6.6", + "sonner": "^2.0.5", + "tailwindcss": "^4.1.11", + "tw-animate-css": "^1.3.4", "zod": "^3.25.67" } } diff --git a/modules/customer-invoices/src/common/dto/request/create-customer-invoice.command.dto.ts b/modules/customer-invoices/src/common/dto/request/create-customer-invoice.command.dto.ts index 45f80005..45068650 100644 --- a/modules/customer-invoices/src/common/dto/request/create-customer-invoice.command.dto.ts +++ b/modules/customer-invoices/src/common/dto/request/create-customer-invoice.command.dto.ts @@ -1,14 +1,14 @@ import * as z from "zod/v4"; export const CreateCustomerInvoiceCommandSchema = z.object({ - id: z.string().uuid(), - status: z.string(), + id: z.uuid(), + invoice_status: z.string(), invoice_number: z.string().min(1, "Customer invoice number is required"), invoice_series: z.string().min(1, "Customer invoice series is required"), issue_date: z.string().datetime({ offset: true, message: "Invalid issue date format" }), operation_date: z.string().datetime({ offset: true, message: "Invalid operation date format" }), language_code: z.string().min(2, "Language code must be at least 2 characters long"), - currency: z.string().min(3, "Currency code must be at least 3 characters long"), + currency_code: z.string().min(3, "Currency code must be at least 3 characters long"), items: z.array( z.object({ description: z.string().min(1, "Item description is required"), @@ -16,10 +16,12 @@ export const CreateCustomerInvoiceCommandSchema = z.object({ amount: z.number().positive("Quantity amount must be positive"), scale: z.number().int().nonnegative("Quantity scale must be a non-negative integer"), }), - unitPrice: z.object({ + unit_price: z.object({ amount: z.number().positive("Unit price amount must be positive"), scale: z.number().int().nonnegative("Unit price scale must be a non-negative integer"), - currency: z.string().min(3, "Unit price currency code must be at least 3 characters long"), + currency_code: z + .string() + .min(3, "Unit price currency code must be at least 3 characters long"), }), discount: z.object({ amount: z.number().nonnegative("Discount amount cannot be negative"), diff --git a/modules/customer-invoices/src/common/locales/en.json b/modules/customer-invoices/src/common/locales/en.json index 1029b717..f953e57b 100644 --- a/modules/customer-invoices/src/common/locales/en.json +++ b/modules/customer-invoices/src/common/locales/en.json @@ -1,14 +1,23 @@ { - "customerInvoices": { + "common": {}, + "pages": { "title": "Customer invoices", "description": "Manage your customer invoices", "list": { "title": "Customer invoice list", - "description": "List all customer invoices" + "description": "List all customer invoices", + "grid_columns": { + "invoice_number": "Inv. number", + "invoice_series": "Serie", + "invoice_status": "Status", + "issue_date": "Date", + "total_price": "Total price" + } }, "create": { - "title": "Create customer invoice", - "description": "Create a new customer invoice" + "title": "New customer invoice", + "description": "Create a new customer invoice", + "back_to_list": "Back to the list" }, "edit": { "title": "Edit customer invoice", @@ -22,5 +31,51 @@ "title": "View customer invoice", "description": "View the details of the selected customer invoice" } + }, + "status": { + "draft": "Draft", + "emitted": "Emitted", + "sent": "Sent", + "received": "Received", + "rejected": "Rejected" + }, + "form_fields": { + "invoice_number": { + "label": "Invoice number", + "placeholder": "", + "description": "" + }, + "items": { + "quantity": { + "label": "Quantity", + "placeholder": "", + "description": "" + }, + "description": { + "label": "Description", + "placeholder": "", + "description": "" + }, + "unit_price": { + "label": "Unit price", + "placeholder": "", + "description": "Item unit price" + }, + "subtotal_price": { + "label": "Subtotal", + "placeholder": "", + "description": "" + }, + "discount": { + "label": "Dto (%)", + "placeholder": "", + "description": "Percentage discount" + }, + "total_price": { + "label": "Total price", + "placeholder": "", + "description": "Total price with percentage discount" + } + } } } diff --git a/modules/customer-invoices/src/common/locales/es.json b/modules/customer-invoices/src/common/locales/es.json index 0f1d7a28..79bc9713 100644 --- a/modules/customer-invoices/src/common/locales/es.json +++ b/modules/customer-invoices/src/common/locales/es.json @@ -1,14 +1,23 @@ { - "customerInvoices": { + "common": {}, + "pages": { "title": "Facturas", "description": "Gestiona tus facturas", "list": { "title": "Lista de facturas", - "description": "Lista todas las facturas" + "description": "Lista todas las facturas", + "grid_columns": { + "invoice_number": "Num. factura", + "invoice_series": "Serie", + "invoice_status": "Estado", + "issue_date": "Fecha", + "total_price": "Imp. total" + } }, "create": { "title": "Crear factura", - "description": "Crear una nueva factura" + "description": "Crear una nueva factura", + "back_to_list": "Volver a la lista" }, "edit": { "title": "Editar factura", @@ -22,5 +31,51 @@ "title": "Ver factura", "description": "Ver los detalles de la factura seleccionada" } + }, + "status": { + "draft": "Borrador", + "emitted": "Emitida", + "sent": "Enviada", + "received": "Recibida", + "rejected": "Rechazada" + }, + "form_fields": { + "invoice_number": { + "label": "Num. factura", + "placeholder": "", + "description": "" + }, + "items": { + "quantity": { + "label": "Cantidad", + "placeholder": "", + "description": "" + }, + "description": { + "label": "Descripción", + "placeholder": "", + "description": "" + }, + "unit_price": { + "label": "Imp. unitario", + "placeholder": "", + "description": "Importe unitario del artículo" + }, + "subtotal_price": { + "label": "Subtotal", + "placeholder": "", + "description": "" + }, + "discount": { + "label": "Dto (%)", + "placeholder": "", + "description": "Porcentaje de descuento" + }, + "total_price": { + "label": "Imp. total", + "placeholder": "", + "description": "Importe total con el descuento ya aplicado" + } + } } } diff --git a/modules/customer-invoices/src/web/components/buttons/append-block-row-button.tsx b/modules/customer-invoices/src/web/components/buttons/append-block-row-button.tsx new file mode 100644 index 00000000..e73ef1ff --- /dev/null +++ b/modules/customer-invoices/src/web/components/buttons/append-block-row-button.tsx @@ -0,0 +1,23 @@ +import { Button } from "@repo/shadcn-ui/components"; +import { t } from "i18next"; +import { PackagePlusIcon } from "lucide-react"; +import { JSX, forwardRef } from "react"; + +export interface AppendBlockRowButtonProps extends React.ComponentProps { + label?: string; +} + +export const AppendBlockRowButton = forwardRef( + ( + { label = t("common.append_block"), className, ...props }: AppendBlockRowButtonProps, + ref + ): JSX.Element => ( + + ) +); + +AppendBlockRowButton.displayName = "AppendBlockRowButton"; diff --git a/modules/customer-invoices/src/web/components/buttons/append-catalog-article-row-button.tsx b/modules/customer-invoices/src/web/components/buttons/append-catalog-article-row-button.tsx new file mode 100644 index 00000000..763016ff --- /dev/null +++ b/modules/customer-invoices/src/web/components/buttons/append-catalog-article-row-button.tsx @@ -0,0 +1,26 @@ +import { Button } from "@repo/shadcn-ui/components"; +import { t } from "i18next"; +import { PackagePlusIcon } from "lucide-react"; +import { JSX, forwardRef } from "react"; + +export interface AppendCatalogArticleRowButtonProps extends React.ComponentProps { + label?: string; +} + +export const AppendCatalogArticleRowButton = forwardRef< + HTMLButtonElement, + AppendCatalogArticleRowButtonProps +>( + ( + { label = t("common.append_article"), className, ...props }: AppendCatalogArticleRowButtonProps, + ref + ): JSX.Element => ( + + ) +); + +AppendCatalogArticleRowButton.displayName = "AppendCatalogArticleRowButton"; diff --git a/modules/customer-invoices/src/web/components/buttons/append-empty-row-button.tsx b/modules/customer-invoices/src/web/components/buttons/append-empty-row-button.tsx new file mode 100644 index 00000000..1ed526a1 --- /dev/null +++ b/modules/customer-invoices/src/web/components/buttons/append-empty-row-button.tsx @@ -0,0 +1,23 @@ +import { Button } from "@repo/shadcn-ui/components"; +import { t } from "i18next"; +import { PlusCircleIcon } from "lucide-react"; +import { JSX, forwardRef } from "react"; + +export interface AppendEmptyRowButtonProps extends React.ComponentProps { + label?: string; + className?: string; +} + +export const AppendEmptyRowButton = forwardRef( + ( + { label = t("common.append_empty_row"), className, ...props }: AppendEmptyRowButtonProps, + ref + ): JSX.Element => ( + + ) +); + +AppendEmptyRowButton.displayName = "AppendEmptyRowButton"; diff --git a/modules/customer-invoices/src/web/components/buttons/index.ts b/modules/customer-invoices/src/web/components/buttons/index.ts new file mode 100644 index 00000000..f09f7446 --- /dev/null +++ b/modules/customer-invoices/src/web/components/buttons/index.ts @@ -0,0 +1,3 @@ +export * from "./append-block-row-button"; +export * from "./append-catalog-article-row-button"; +export * from "./append-empty-row-button"; diff --git a/modules/customer-invoices/src/web/components/customer-invoice-status-badge.tsx b/modules/customer-invoices/src/web/components/customer-invoice-status-badge.tsx new file mode 100644 index 00000000..ea42f9d8 --- /dev/null +++ b/modules/customer-invoices/src/web/components/customer-invoice-status-badge.tsx @@ -0,0 +1,66 @@ +import { Badge } from "@repo/shadcn-ui/components"; +import { cn } from "@repo/shadcn-ui/lib/utils"; +import { forwardRef } from "react"; +import { useTranslation } from "react-i18next"; +import { MODULE_NAME } from "../manifest"; + +export type CustomerInvoiceStatus = "draft" | "emitted" | "sent" | "received" | "rejected"; + +export type CustomerInvoiceStatusBadgeProps = { + status: string; // permitir cualquier valor + className?: string; +}; + +const statusColorConfig: Record = { + draft: { + badge: + "bg-gray-600/10 dark:bg-gray-600/20 hover:bg-gray-600/10 text-gray-500 border-gray-600/60", + dot: "bg-gray-500", + }, + emitted: { + badge: + "bg-amber-600/10 dark:bg-amber-600/20 hover:bg-amber-600/10 text-amber-500 border-amber-600/60", + dot: "bg-amber-500", + }, + sent: { + badge: + "bg-cyan-600/10 dark:bg-cyan-600/20 hover:bg-cyan-600/10 text-cyan-500 border-cyan-600/60 shadow-none rounded-full", + dot: "bg-cyan-500", + }, + received: { + badge: + "bg-emerald-600/10 dark:bg-emerald-600/20 hover:bg-emerald-600/10 text-emerald-500 border-emerald-600/60", + dot: "bg-emerald-500", + }, + rejected: { + badge: "bg-red-600/10 dark:bg-red-600/20 hover:bg-red-600/10 text-red-500 border-red-600/60", + dot: "bg-red-500", + }, +}; + +export const CustomerInvoiceStatusBadge = forwardRef< + HTMLDivElement, + CustomerInvoiceStatusBadgeProps +>(({ status, className, ...props }, ref) => { + const { t } = useTranslation(MODULE_NAME); + const normalizedStatus = status.toLowerCase() as CustomerInvoiceStatus; + const config = statusColorConfig[normalizedStatus]; + const commonClassName = "transition-colors duration-200 cursor-pointer shadow-none rounded-full"; + + if (!config) { + return ( + + {status} + + ); + } + + return ( + +
+ {t(`status.${status}`)} + + ); +}); + +CustomerInvoiceStatusBadge.displayName = "CustomerInvoiceStatusBadge"; diff --git a/modules/customer-invoices/src/web/components/customer-invoices-grid.tsx b/modules/customer-invoices/src/web/components/customer-invoices-list-grid.tsx similarity index 53% rename from modules/customer-invoices/src/web/components/customer-invoices-grid.tsx rename to modules/customer-invoices/src/web/components/customer-invoices-list-grid.tsx index c5d6a801..504d99c0 100644 --- a/modules/customer-invoices/src/web/components/customer-invoices-grid.tsx +++ b/modules/customer-invoices/src/web/components/customer-invoices-list-grid.tsx @@ -1,4 +1,4 @@ -import { useEffect, useState } from "react"; +import { useState } from "react"; import { AG_GRID_LOCALE_ES } from "@ag-grid-community/locale"; // Grid @@ -11,75 +11,40 @@ import { MoneyDTO } from "@erp/core"; import { formatDate, formatMoney } from "@erp/core/client"; // Core CSS import { AgGridReact } from "ag-grid-react"; +import { useTranslation } from "react-i18next"; import { useCustomerInvoicesQuery } from "../hooks"; - -/** - * Fetch example Json data - * Not recommended for production use! - */ -export const useFetchJson = (url: string, limit?: number) => { - const [data, setData] = useState(); - const [loading, setLoading] = useState(false); - useEffect(() => { - const fetchData = async () => { - setLoading(true); - - // Note error handling is omitted here for brevity - const response = await fetch(url); - const json = await response.json(); - const data = limit ? json.slice(0, limit) : json; - setData(data); - setLoading(false); - }; - fetchData(); - }, [url, limit]); - return { data, loading }; -}; - -// Row Data Interface -interface IRow { - mission: string; - company: string; - location: string; - date: string; - time: string; - rocket: string; - price: number; - successful: boolean; -} +import { MODULE_NAME } from "../manifest"; +import { CustomerInvoiceStatusBadge } from "./customer-invoice-status-badge"; // Create new GridExample component -export const CustomerInvoicesGrid = () => { - //const { useList } = useCustomerInvoices(); - +export const CustomerInvoicesListGrid = () => { + const { t } = useTranslation(MODULE_NAME); const { data, isLoading, isPending, isError, error } = useCustomerInvoicesQuery({}); // Column Definitions: Defines & controls grid columns. const [colDefs] = useState([ - { field: "invoice_number", headerName: "Num. factura" }, - { field: "invoice_series", headerName: "Serie" }, { field: "invoice_status", filter: true, - headerName: "Estado", + headerName: t("pages.list.grid_columns.invoice_status"), + cellRenderer: (params: ValueFormatterParams) => { + return ; + }, }, + { field: "invoice_number", headerName: t("pages.list.grid_columns.invoice_number") }, + { field: "invoice_series", headerName: t("pages.list.grid_columns.invoice_series") }, + { field: "issue_date", - headerName: "Fecha fact.", + headerName: t("pages.list.grid_columns.issue_date"), valueFormatter: (params: ValueFormatterParams) => { return formatDate(params.value); }, }, - { - field: "subtotal_price", - valueFormatter: (params: ValueFormatterParams) => { - const rawValue: MoneyDTO = params.value; - return formatMoney(rawValue); - }, - }, { field: "total_price", + headerName: t("pages.list.grid_columns.total_price"), valueFormatter: (params: ValueFormatterParams) => { const rawValue: MoneyDTO = params.value; return formatMoney(rawValue); @@ -97,18 +62,9 @@ export const CustomerInvoicesGrid = () => { sortable: false, resizable: true, }, - sideBar: true, - statusBar: { - statusPanels: [ - { statusPanel: "agTotalAndFilteredRowCountComponent", align: "left" }, - { statusPanel: "agAggregationComponent" }, - ], - }, - rowGroupPanelShow: "always", pagination: true, paginationPageSize: 10, paginationPageSizeSelector: [10, 20, 30, 50], - enableCharts: true, localeText: AG_GRID_LOCALE_ES, rowSelection: { mode: "multiRow" }, }; diff --git a/modules/customer-invoices/src/web/components/index.tsx b/modules/customer-invoices/src/web/components/index.tsx index 4dcd0d92..0b064b0d 100644 --- a/modules/customer-invoices/src/web/components/index.tsx +++ b/modules/customer-invoices/src/web/components/index.tsx @@ -1,2 +1,3 @@ -export * from "./customer-invoices-grid"; +export * from "./customer-invoice-status-badge"; export * from "./customer-invoices-layout"; +export * from "./customer-invoices-list-grid"; diff --git a/modules/customer-invoices/src/web/components/items/customer-invoice-items-card-editor.tsx b/modules/customer-invoices/src/web/components/items/customer-invoice-items-card-editor.tsx new file mode 100644 index 00000000..3b5f62bc --- /dev/null +++ b/modules/customer-invoices/src/web/components/items/customer-invoice-items-card-editor.tsx @@ -0,0 +1,343 @@ +import { + FormControl, + FormField, + FormItem, + FormMessage, + Input, + Textarea, +} from "@repo/shadcn-ui/components"; + +import { ColumnDef } from "@tanstack/react-table"; +import { ChevronDownIcon, ChevronUpIcon, CopyIcon, Trash2Icon } from "lucide-react"; +import { useState } from "react"; +import { useFieldArray, useFormContext } from "react-hook-form"; +import { useTranslation } from "react-i18next"; +import { useDetailColumns } from "../../hooks"; +import { MODULE_NAME } from "../../manifest"; +import { formatCurrency } from "../../pages/create/utils"; +import { + CustomerInvoiceItemsSortableDataTable, + RowIdData, +} from "./customer-invoice-items-sortable-datatable"; + +export const CustomerInvoiceItemsCardEditor = ({ + //currency, + //language, + defaultValues, +}: { + //currency: CurrencyData; + //language: Language; + defaultValues: Readonly<{ [x: string]: any }> | undefined; +}) => { + const { t } = useTranslation(MODULE_NAME); + + const { control, watch, getValues } = useFormContext(); + + const watchedItems = watch("items"); + + //const [pickerMode] = useState<"dialog" | "panel">("dialog"); + + //const [articlePickerDialogOpen, setArticlePickerDialogOpen] = useState(false); + //const [blockPickerDialogOpen, setBlockPickerDialogOpen] = useState(false); + + const { fields, ...fieldActions } = useFieldArray({ + control, + name: "items", + }); + + const columns: ColumnDef[] = useDetailColumns( + [ + /*{ + id: "row_id" as const, + header: () => ( + + ), + accessorFn: (_: unknown, index: number) => index + 1, + size: 5, + enableHiding: false, + enableSorting: false, + enableResizing: false, + },*/ + /*{ + id: "id_article" as const, + accessorKey: "id_article", + header: "artículo", + cell: ({ row: { index, original } }) => { + return ( + + ); + }, + size: 500, + },*/ + { + id: "description" as const, + accessorKey: "description", + header: t("customer_invoices.form_fields.description.label"), + cell: ({ row: { index, original } }) => ( + ( + + +