diff --git a/client/src/app/quotes/components/SortableDataTable.tsx b/client/src/app/quotes/components/SortableDataTable.tsx
index 76b5ef6..bc88621 100644
--- a/client/src/app/quotes/components/SortableDataTable.tsx
+++ b/client/src/app/quotes/components/SortableDataTable.tsx
@@ -148,6 +148,11 @@ export function SortableDataTable({ columns, data, actions }: SortableDataTableP
getRowId: (originalRow: unknown) => originalRow?.id,
debugHeaders: false,
debugColumns: false,
+ defaultColumn: {
+ size: 8, //starting column size
+ minSize: 1, //enforced during column resizing
+ maxSize: 96, //enforced during column resizing
+ },
meta: {
insertItem: (rowIndex: number, data: object = {}) => {
actions.insert(rowIndex, data, { shouldFocus: true });
@@ -326,13 +331,14 @@ export function SortableDataTable({ columns, data, actions }: SortableDataTableP
collisionDetection={closestCenter}
>
-
+
{table.getHeaderGroups().map((headerGroup) => (
{headerGroup.headers.map((header) => {
+ console.log(header.getSize());
return (
-
+
{header.isPlaceholder ? null : (
)}
@@ -350,11 +356,7 @@ export function SortableDataTable({ columns, data, actions }: SortableDataTableP
{filterItems(table.getRowModel().rows).map((row) => (
{row.getVisibleCells().map((cell) => (
-
+
{flexRender(cell.column.columnDef.cell, cell.getContext())}
))}
diff --git a/client/src/app/quotes/components/SortableTableRow.tsx b/client/src/app/quotes/components/SortableTableRow.tsx
index b4e5546..4a95e1d 100644
--- a/client/src/app/quotes/components/SortableTableRow.tsx
+++ b/client/src/app/quotes/components/SortableTableRow.tsx
@@ -58,7 +58,10 @@ export function SortableTableRow({ id, children }: PropsWithChildren
diff --git a/client/src/app/quotes/components/editors/QuoteDetailsCardEditor.tsx b/client/src/app/quotes/components/editors/QuoteDetailsCardEditor.tsx
index 62328e6..590e4c1 100644
--- a/client/src/app/quotes/components/editors/QuoteDetailsCardEditor.tsx
+++ b/client/src/app/quotes/components/editors/QuoteDetailsCardEditor.tsx
@@ -1,13 +1,9 @@
-import {
- FormCurrencyField,
- FormQuantityField,
- FormTextAreaField,
- FormTextField,
-} from "@/components";
+import { FormQuantityField, FormTextField } from "@/components";
import { DataTableProvider } from "@/lib/hooks";
import { cn } from "@/lib/utils";
import { ResizableHandle, ResizablePanel, ResizablePanelGroup } from "@/ui";
import { CurrencyData, Quantity } from "@shared/contexts";
+import { t } from "i18next";
import { useCallback, useState } from "react";
import { useFieldArray, useFormContext } from "react-hook-form";
import { useDetailColumns } from "../../hooks";
@@ -38,32 +34,42 @@ export const QuoteDetailsCardEditor = ({ currency }: { currency: CurrencyData })
{
id: "quantity" as const,
accessorKey: "quantity",
- header: "quantity",
+ header: () => (
+ {t("quotes.form_fields.items.quantity.label")}
+ ),
size: 5,
cell: ({ row: { index } }) => {
- return ;
+ return (
+
+ );
},
},
{
id: "description" as const,
accessorKey: "description",
- header: "description",
+ header: t("quotes.form_fields.items.description.label"),
+ size: 24,
cell: ({ row: { index } }) => {
- return ;
+ return ;
},
},
-
{
id: "unit_price" as const,
accessorKey: "unit_price",
- header: "unit_price",
- size: 10,
+ header: () => (
+ {t("quotes.form_fields.items.unit_price.label")}
+ ),
cell: ({ row: { index }, column: { id } }) => {
return (
-
);
@@ -72,8 +78,9 @@ export const QuoteDetailsCardEditor = ({ currency }: { currency: CurrencyData })
{
id: "subtotal_price" as const,
accessorKey: "subtotal_price",
- header: "subtotal_price",
- size: 10,
+ header: () => (
+ {t("quotes.form_fields.items.subtotal_price.label")}
+ ),
cell: ({ row: { index }, column: { id } }) => {
return ;
},
@@ -81,17 +88,20 @@ export const QuoteDetailsCardEditor = ({ currency }: { currency: CurrencyData })
{
id: "discount" as const,
accessorKey: "discount",
- header: "discount",
size: 5,
+ header: () => (
+ {t("quotes.form_fields.items.discount.label")}
+ ),
cell: ({ row: { index }, column: { id } }) => {
- return ;
+ return ;
},
},
{
id: "total_price" as const,
accessorKey: "total_price",
- header: "total_price",
- size: 10,
+ header: () => (
+ {t("quotes.form_fields.items.total_price.label")}
+ ),
cell: ({ row: { index }, column: { id } }) => {
return ;
},
@@ -151,6 +161,8 @@ export const QuoteDetailsCardEditor = ({ currency }: { currency: CurrencyData })
const defaultLayout = [265, 440, 655];
const navCollapsedSize = 4;
+ return ;
+
return (
(
- rows: Row[],
- currentID: number,
- selectedID: number,
-): Row[] {
- const rangeStart = selectedID > currentID ? currentID : selectedID;
- const rangeEnd = rangeStart === currentID ? selectedID : currentID;
- return rows.slice(rangeStart, rangeEnd + 1);
-}*/
-
-export function useDetailColumns(
+// eslint-disable-next-line @typescript-eslint/no-unused-vars
+export function useDetailColumns(
columns: ColumnDef[],
options: {
enableDragHandleColumn?: boolean;
enableSelectionColumn?: boolean;
enableActionsColumn?: boolean;
- rowActionFn?: DataTablaRowActionFunction;
+ rowActionFn?: DataTablaRowActionFunction;
} = {}
): ColumnDef[] {
const {
@@ -67,7 +57,9 @@ export function useDetailColumns(
),
enableSorting: false,
enableHiding: false,
- size: 30,
+ size: 2,
+ minSize: 2,
+ maxSize: 2,
});
}
@@ -79,7 +71,10 @@ export function useDetailColumns(
),*/
header: () => null,
cell: (info) => ,
- size: 16,
+ size: 2,
+ minSize: 2,
+ maxSize: 2,
+
enableSorting: false,
enableHiding: false,
});
@@ -88,16 +83,23 @@ export function useDetailColumns(
if (enableActionsColumn) {
columns.push({
id: "row_actions",
- header: () => (
+ /*header: () => (
- ),
+ ),*/
cell: (props) => {
- return ;
+ return (
+
+
+
+ );
},
- size: 16,
+ size: 4,
+ minSize: 4,
+ maxSize: 4,
+
enableSorting: false,
enableHiding: false,
});
diff --git a/client/src/components/DataTable/DataTableColumnHeader.tsx b/client/src/components/DataTable/DataTableColumnHeader.tsx
index 470d9e4..d887f74 100644
--- a/client/src/components/DataTable/DataTableColumnHeader.tsx
+++ b/client/src/components/DataTable/DataTableColumnHeader.tsx
@@ -28,7 +28,7 @@ export function DataTableColumnHeader({
<>
diff --git a/client/src/components/DataTable/DataTableRowActions.tsx b/client/src/components/DataTable/DataTableRowActions.tsx
index 308225b..e34b69e 100644
--- a/client/src/components/DataTable/DataTableRowActions.tsx
+++ b/client/src/components/DataTable/DataTableRowActions.tsx
@@ -1,5 +1,6 @@
"use client";
+import { cn } from "@/lib/utils";
import {
Button,
DropdownMenu,
@@ -10,32 +11,31 @@ import {
DropdownMenuShortcut,
DropdownMenuTrigger,
} from "@/ui";
-import { CellContext, Row } from "@tanstack/react-table";
+import { CellContext } from "@tanstack/react-table";
import { t } from "i18next";
-import { MoreHorizontalIcon } from "lucide-react";
+import { MoreVerticalIcon } from "lucide-react";
-type DataTableRowActionContext
= CellContext & {
- row: Row;
-};
+export type DataTablaRowActionFunction = (
+ props: CellContext
+) => DataTableRowActionDefinition[];
-export type DataTablaRowActionFunction = (
- props: DataTableRowActionContext
-) => DataTableRowActionDefinition[];
-
-export type DataTableRowActionDefinition = {
+export type DataTableRowActionDefinition = {
label: string | "-";
shortcut?: string;
- onClick?: (props: DataTableRowActionContext, e: React.BaseSyntheticEvent) => void;
+ onClick?: (props: CellContext, e: React.BaseSyntheticEvent) => void;
};
-export type DataTableRowActionsProps = {
- actions?: DataTablaRowActionFunction;
- row?: DataTableRowActionContext;
+// eslint-disable-next-line @typescript-eslint/no-unused-vars
+export type DataTableRowActionsProps = {
+ className?: string;
+ actions?: DataTablaRowActionFunction;
+ rowContext: CellContext;
};
-export function DataTableRowActions({
+export function DataTableRowActions({
actions,
- ...props
+ rowContext,
+ className,
}: DataTableRowActionsProps) {
return (
@@ -44,9 +44,9 @@ export function DataTableRowActions({
aria-haspopup='true'
size='icon'
variant='link'
- className='w-4 h-4 translate-y-[2px]'
+ className={cn("w-4 h-4 mt-2 text-ring hover:text-muted-foreground", className)}
>
-
+
{t("common.open_menu")}
@@ -54,13 +54,13 @@ export function DataTableRowActions({
{t("common.actions")}
{actions &&
- actions(props).map((action, index) =>
+ actions(rowContext).map((action, index) =>
action.label === "-" ? (
) : (
(action.onClick ? action.onClick(props, event) : null)}
+ onClick={(event) => (action.onClick ? action.onClick(rowContext, event) : null)}
>
{action.label}
{action.shortcut}
diff --git a/client/src/components/Forms/FormCurrencyField.tsx b/client/src/components/Forms/FormCurrencyField.tsx
index bb8ad1f..df0e96f 100644
--- a/client/src/components/Forms/FormCurrencyField.tsx
+++ b/client/src/components/Forms/FormCurrencyField.tsx
@@ -9,15 +9,14 @@ import { FormErrorMessage } from "./FormErrorMessage";
import { FormLabel, FormLabelProps } from "./FormLabel";
import { FormInputProps, FormInputWithIconProps } from "./FormProps";
-export const formCurrencyFieldVariants = cva(
+const formCurrencyFieldVariants = cva(
"flex h-10 w-full rounded-md bg-background px-3 py-2 text-sm placeholder:text-muted-foreground focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50",
{
variants: {
variant: {
default:
"border border-input ring-offset-background focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 ",
- outline:
- "ring-offset-background focus-visible:ring-1 focus-visible:ring-ring focus-visible:ring-offset-2 ",
+ outline: "focus-visible:border focus-visible:border-input",
},
},
defaultVariants: {
@@ -31,6 +30,7 @@ export type FormCurrencyFieldProps<
TName extends FieldPath = FieldPath
> = {
button?: (props?: React.PropsWithChildren) => React.ReactNode;
+ defaultValue?: any;
} & InputProps &
FormInputProps &
Partial &
@@ -48,6 +48,7 @@ export const FormCurrencyField = React.forwardRef = FieldPath
@@ -24,139 +35,82 @@ export type FormQuantityFieldProps<
FormInputProps &
Partial &
FormInputWithIconProps &
- UseControllerProps;
-
-export const FormQuantityField = forwardRef<
- HTMLDivElement,
- React.HTMLAttributes & FormQuantityFieldProps
->((props, ref) => {
- const {
- name,
- label,
- hint,
- placeholder,
- description,
-
- required,
- className,
- leadIcon,
- trailIcon,
- button,
- defaultValue,
- } = props;
-
- const { control } = useFormContext();
-
- const [precision, setPrecision] = useState(Quantity.DEFAULT_PRECISION);
-
- const transform = {
- input: (value: QuantityObject) => {
- const quantityOrError = Quantity.create(value);
-
- if (quantityOrError.isFailure) {
- throw quantityOrError.error;
- }
-
- const quantityValue = quantityOrError.object;
- setPrecision(quantityValue.getPrecision());
- return quantityValue.toString();
- },
- output: (event: React.ChangeEvent): QuantityObject => {
- const value = parseFloat(event.target.value);
- const output = !isNaN(value) ? value : 0;
-
- const quantityOrError = Quantity.create({
- amount: output * Math.pow(10, precision),
- precision,
- });
-
- if (quantityOrError.isFailure) {
- throw quantityOrError.error;
- }
-
- return quantityOrError.object.toObject();
- },
+ UseControllerProps &
+ VariantProps & {
+ precision: number;
};
- return (
- {
- return (
- field.onChange(transform.output(e))}
- value={transform.input(field.value)}
- />
- );
+export const FormQuantityField = React.forwardRef(
+ (props, ref) => {
+ const {
+ name,
+ label,
+ hint,
+ description,
+ placeholder,
+ className,
+ disabled,
+ defaultValue,
+ rules,
+ precision,
+ variant,
+ } = props;
- return (
-
- {label && }
-
-
- {leadIcon && (
-
- {createElement(
- leadIcon,
- {
- className: "h-5 w-5 text-muted-foreground",
- "aria-hidden": true,
- },
- null
- )}
-
- )}
+ const { control } = useFormContext();
-
- field.onChange(transform.output(e))}
- value={transform.input(field.value)}
- />
-
+ const transformToInput = (value: any) => {
+ if (typeof value !== "object") {
+ return value;
+ }
- {trailIcon && (
-
- {createElement(
- trailIcon,
- {
- className: "h-5 w-5 text-muted-foreground",
- "aria-hidden": true,
- },
- null
- )}
-
- )}
-
- {button && <>{createElement(button)}>}
-
+ const quantityOrError = Quantity.create(value);
+ if (quantityOrError.isFailure) {
+ throw quantityOrError.error;
+ }
- {description && {description}}
-
-
- );
- }}
- />
- );
-});
+ return (
+ quantityOrError.object
+ .toNumber()
+ //.toPrecision(precision ?? value.precision)
+ .toString()
+ );
+ };
+
+ return (
+ {
+ return (
+
+ {label && }
+
+ {
+ // "value" ya viene con los "0" de la precisión
+ console.log(value);
+ field.onChange(value ?? "");
+ }}
+ />
+
+ {description && {description}}
+
+
+ );
+ }}
+ />
+ );
+ }
+);
diff --git a/client/src/lib/hooks/useDataTable/useDataTable.tsx b/client/src/lib/hooks/useDataTable/useDataTable.tsx
index ca6c349..42b059e 100644
--- a/client/src/lib/hooks/useDataTable/useDataTable.tsx
+++ b/client/src/lib/hooks/useDataTable/useDataTable.tsx
@@ -190,6 +190,12 @@ export function useDataTable({
debugTable: false,
debugHeaders: false,
debugColumns: false,
+
+ defaultColumn: {
+ size: 5, //starting column size
+ minSize: 0, //enforced during column resizing
+ maxSize: 96, //enforced during column resizing
+ },
});
return { table };
diff --git a/client/src/locales/es.json b/client/src/locales/es.json
index 949ec05..f0e47d8 100644
--- a/client/src/locales/es.json
+++ b/client/src/locales/es.json
@@ -86,9 +86,6 @@
"total_price": "Imp. total"
}
},
- "status": {
- "draft": "Borrador"
- },
"create": {
"title": "Nueva cotización",
"buttons": {
@@ -123,41 +120,76 @@
"desc": ""
}
},
- "form_fields": {
- "date": {
- "label": "Fecha",
- "desc": "Fecha de esta cotización",
- "placeholder": ""
- },
- "reference": {
- "label": "Referencia",
- "desc": "Referencia para esta cotización",
- "placeholder": ""
- },
- "customer_information": {
- "label": "Datos del cliente",
- "desc": "Escriba el nombre del cliente en la primera línea, la direccion en la segunda y el código postal y ciudad en la tercera.",
- "placeholder": "Nombre y apellidos\nCalle y número\nCódigo postal y ciudad..."
- },
- "payment_method": {
- "label": "Forma de pago",
- "placeholder": "placeholder",
- "desc": "desc"
- },
- "notes": {
- "label": "Notas",
- "placeholder": "",
- "desc": "desc"
- },
- "validity": {
- "label": "Validez de la cotización",
- "placeholder": "",
- "desc": "desc"
- }
+ "edit": {
+ "title": "Cotización"
}
},
- "edit": {
- "title": "Cotización"
+ "status": {
+ "draft": "Borrador"
+ },
+ "form_fields": {
+ "date": {
+ "label": "Fecha",
+ "desc": "Fecha de esta cotización",
+ "placeholder": ""
+ },
+ "reference": {
+ "label": "Referencia",
+ "desc": "Referencia para esta cotización",
+ "placeholder": ""
+ },
+ "customer_information": {
+ "label": "Datos del cliente",
+ "desc": "Escriba el nombre del cliente en la primera línea, la direccion en la segunda y el código postal y ciudad en la tercera.",
+ "placeholder": "Nombre y apellidos\nCalle y número\nCódigo postal y ciudad..."
+ },
+ "payment_method": {
+ "label": "Forma de pago",
+ "placeholder": "placeholder",
+ "desc": "desc"
+ },
+ "notes": {
+ "label": "Notas",
+ "placeholder": "",
+ "desc": "desc"
+ },
+ "validity": {
+ "label": "Validez de la cotización",
+ "placeholder": "",
+ "desc": "desc"
+ },
+ "items": {
+ "quantity": {
+ "label": "Cantidad",
+ "placeholder": "",
+ "desc": ""
+ },
+ "description": {
+ "label": "Descripción",
+ "placeholder": "",
+ "desc": ""
+ },
+ "unit_price": {
+ "label": "Imp. unitario",
+ "placeholder": "",
+ "desc": "Importe unitario del artículo"
+ },
+ "subtotal_price": {
+ "label": "Subtotal",
+ "placeholder": "",
+ "desc": ""
+ },
+ "discount": {
+ "label": "Dto (%)",
+ "placeholder": "",
+ "desc": "Porcentaje de descuento"
+ },
+ "total_price": {
+ "label": "Imp. total",
+ "placeholder": "",
+ "desc": "Importe total con el descuento ya aplicado"
+ }
+ }
}
},
"settings": {