From 3cfe438f1b95054d4cedca7ddfa607d15750e3c4 Mon Sep 17 00:00:00 2001 From: David Arranz Date: Thu, 29 Aug 2024 13:59:12 +0200 Subject: [PATCH] . --- .../quotes/components/QuotePricesResume.tsx | 18 +- .../editors/QuoteDetailsCardEditor copy.tsx | 278 ++++++++++++++++++ .../editors/QuoteGeneralCardEditor.tsx | 40 +-- client/src/app/quotes/edit.tsx | 31 +- .../components/Forms/FormDatePickerField.tsx | 1 + 5 files changed, 325 insertions(+), 43 deletions(-) create mode 100644 client/src/app/quotes/components/editors/QuoteDetailsCardEditor copy.tsx diff --git a/client/src/app/quotes/components/QuotePricesResume.tsx b/client/src/app/quotes/components/QuotePricesResume.tsx index bcf28ae..28688f7 100644 --- a/client/src/app/quotes/components/QuotePricesResume.tsx +++ b/client/src/app/quotes/components/QuotePricesResume.tsx @@ -22,14 +22,14 @@ export const QuotePricesResume = () => { }, [currency_code]); return ( - +
-
+
{t("quotes.form_fields.subtotal_price.label")} - + {subtotal_price} {currency_symbol} @@ -51,10 +51,10 @@ export const QuotePricesResume = () => { />
- + {t("quotes.form_fields.discount_price.label")} - + {discount_price} {currency_symbol} @@ -77,10 +77,10 @@ export const QuotePricesResume = () => { />
- + {t("quotes.form_fields.tax_price.label")} - + {tax_price} {currency_symbol} @@ -89,10 +89,10 @@ export const QuotePricesResume = () => {
- + {t("quotes.form_fields.total_price.label")} - + {total_price} {currency_symbol} diff --git a/client/src/app/quotes/components/editors/QuoteDetailsCardEditor copy.tsx b/client/src/app/quotes/components/editors/QuoteDetailsCardEditor copy.tsx new file mode 100644 index 0000000..5eb65a8 --- /dev/null +++ b/client/src/app/quotes/components/editors/QuoteDetailsCardEditor copy.tsx @@ -0,0 +1,278 @@ +import { + FormCurrencyField, + FormPercentageField, + FormQuantityField, + FormTextAreaField, +} from "@/components"; + +import { DataTableProvider } from "@/lib/hooks"; +import { cn } from "@/lib/utils"; +import { ResizableHandle, ResizablePanel, ResizablePanelGroup } from "@/ui"; +import { useToast } from "@/ui/use-toast"; +import { CurrencyData, Language, Quantity } from "@shared/contexts"; +import { ColumnDef } from "@tanstack/react-table"; +import { t } from "i18next"; +import { ChevronDownIcon, ChevronUpIcon, CopyIcon, Trash2Icon } from "lucide-react"; +import { useCallback, useState } from "react"; +import { useFieldArray, useFormContext } from "react-hook-form"; +import { useDetailColumns } from "../../hooks"; +import { CatalogPickerDataTable } from "../CatalogPickerDataTable"; +import { QuoteItemsSortableDataTable } from "../QuoteItemsSortableDataTable"; +import { CatalogPickerDialog } from "./CatalogPickerDialog"; + +export const QuoteDetailsCardEditor = ({ + currency, + language, + defaultValues, +}: { + currency: CurrencyData; + language: Language; + defaultValues: Readonly<{ [x: string]: any }> | undefined; +}) => { + const { toast } = useToast(); + const { control, register } = useFormContext(); + + const [pickerMode] = useState<"dialog" | "panel">("dialog"); + + const [pickerDialogOpen, setPickerDialogOpen] = 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: "description" as const, + accessorKey: "description", + header: t("quotes.form_fields.items.description.label"), + cell: ({ row: { index } }) => { + return ; + }, + size: 500, + }, + { + id: "quantity" as const, + accessorKey: "quantity", + header: () => ( +
{t("quotes.form_fields.items.quantity.label")}
+ ), + cell: ({ row: { index } }) => { + return ( + + ); + }, + }, + { + id: "unit_price" as const, + accessorKey: "unit_price", + header: () => ( +
{t("quotes.form_fields.items.unit_price.label")}
+ ), + cell: ({ row: { index } }) => { + return ( + + ); + }, + }, + { + id: "subtotal_price" as const, + accessorKey: "subtotal_price", + header: () => ( +
{t("quotes.form_fields.items.subtotal_price.label")}
+ ), + cell: ({ row: { index } }) => { + return ( + + ); + }, + }, + { + id: "discount" as const, + accessorKey: "discount", + header: () => ( +
{t("quotes.form_fields.items.discount.label")}
+ ), + cell: ({ row: { index } }) => { + return ( + + ); + }, + }, + { + id: "total_price" as const, + accessorKey: "total_price", + header: () => ( +
{t("quotes.form_fields.items.total_price.label")}
+ ), + cell: ({ row: { index } }) => { + return ( + + ); + }, + }, + ], + { + enableDragHandleColumn: false, // <--- Desactivado temporalmente + enableSelectionColumn: true, + enableActionsColumn: true, + rowActionFn: (props) => { + const { table, row } = props; + return [ + { + label: t("common.duplicate_row"), + icon: , + onClick: () => table.options.meta?.duplicateItems(row.index), + }, + { + label: t("common.insert_row_above"), + icon: , + onClick: () => table.options.meta?.insertItem(row.index), + }, + { + label: t("common.insert_row_below"), + icon: , + onClick: () => table.options.meta?.insertItem(row.index + 1), + }, + + { + label: "-", + }, + { + label: t("common.remove_row"), + //shortcut: "⌘⌫", + icon: , + onClick: () => { + table.options.meta?.deleteItems(row.index); + }, + }, + ]; + }, + } + ); + + const handleAppendCatalogArticle = useCallback( + (article: any) => { + fieldActions.append({ + ...article, + quantity: { + amount: 100, + scale: Quantity.DEFAULT_SCALE, + }, + unit_price: article.retail_price, + discount: { + amount: null, + scale: 2, + }, + }); + toast({ + title: t("quotes.catalog_picker_dialog.toast_article_added"), + description: article.description, + }); + }, + [fieldActions] + ); + + const [isCollapsed, setIsCollapsed] = useState(false); + + const defaultLayout = [265, 440, 655]; + const navCollapsedSize = 4; + + if (pickerMode === "dialog") { + return ( +
+ setPickerDialogOpen(true), + }} + columns={columns} + data={fields} + defaultValues={defaultValues} + /> + +
+ ); + } + + return ( + + { + setIsCollapsed(true); + }} + onExpand={() => { + setIsCollapsed(false); + }} + className={cn(isCollapsed && "min-w-[50px] transition-all duration-300 ease-in-out")} + > + + + + + + + + + + ); +}; diff --git a/client/src/app/quotes/components/editors/QuoteGeneralCardEditor.tsx b/client/src/app/quotes/components/editors/QuoteGeneralCardEditor.tsx index 2425554..0ab32ae 100644 --- a/client/src/app/quotes/components/editors/QuoteGeneralCardEditor.tsx +++ b/client/src/app/quotes/components/editors/QuoteGeneralCardEditor.tsx @@ -9,24 +9,13 @@ export const QuoteGeneralCardEditor = () => { return (
-
- +
{ required: false, })} /> + { required: true, })} /> -
-
{ required: false, })} /> - { required: false, })} /> +
+
+ {
diff --git a/client/src/app/quotes/edit.tsx b/client/src/app/quotes/edit.tsx index 32bd3c0..00c9a2d 100644 --- a/client/src/app/quotes/edit.tsx +++ b/client/src/app/quotes/edit.tsx @@ -6,6 +6,7 @@ import { LoadingOverlay, SubmitButton, } from "@/components"; +import { calculateQuoteItemTotals, calculateQuoteTotals } from "@/lib/calc"; import { useUnsavedChangesNotifier } from "@/lib/hooks"; import { useUrlId } from "@/lib/hooks/useUrlId"; import { Button, Form, Tabs, TabsContent, TabsList, TabsTrigger } from "@/ui"; @@ -16,7 +17,7 @@ import { Language, } from "@shared/contexts"; import { t } from "i18next"; -import { useMemo, useState } from "react"; +import { useEffect, useMemo, useState } from "react"; import { useForm } from "react-hook-form"; import { useNavigate } from "react-router-dom"; import { toast } from "react-toastify"; @@ -128,7 +129,7 @@ export const QuoteEdit = () => { //shouldUnregister: true, }); - const { getValues, reset, handleSubmit, formState } = form; + const { getValues, reset, handleSubmit, formState, watch, setValue } = form; const { isSubmitting, isDirty } = formState; useUnsavedChangesNotifier({ @@ -157,7 +158,7 @@ export const QuoteEdit = () => { }); }; - /*useEffect(() => { + useEffect(() => { // eslint-disable-next-line @typescript-eslint/no-unused-vars const { unsubscribe } = watch((_, { name, type }) => { console.log("useEffect"); @@ -234,7 +235,7 @@ export const QuoteEdit = () => { } }); return () => unsubscribe(); - }, [watch, getValues, setValue]);*/ + }, [watch, getValues, setValue]); if (isSubmitting || isPending) { return ; @@ -283,6 +284,14 @@ export const QuoteEdit = () => {
+ + + + { {t("quotes.create.tabs.items")} {/* {t("quotes.create.tabs.history")}*/} - - - + + +
diff --git a/client/src/components/Forms/FormDatePickerField.tsx b/client/src/components/Forms/FormDatePickerField.tsx index 207144d..e603bd5 100644 --- a/client/src/components/Forms/FormDatePickerField.tsx +++ b/client/src/components/Forms/FormDatePickerField.tsx @@ -66,6 +66,7 @@ export const FormDatePickerField = React.forwardRef<