.
This commit is contained in:
parent
78684303df
commit
3cfe438f1b
@ -22,14 +22,14 @@ export const QuotePricesResume = () => {
|
|||||||
}, [currency_code]);
|
}, [currency_code]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card className='w-full'>
|
<Card className='w-full bg-muted'>
|
||||||
<CardContent className='flex flex-row items-end gap-2 p-4 border-t'>
|
<CardContent className='flex flex-row items-end gap-2 p-4 border-t'>
|
||||||
<div className='grid flex-1 h-16 grid-cols-1 auto-rows-max'>
|
<div className='grid flex-1 h-16 grid-cols-1 auto-rows-max'>
|
||||||
<div className='grid gap-1 font-semibold text-muted-foreground'>
|
<div className='grid gap-1 font-semibold text-right text-muted-foreground'>
|
||||||
<CardDescription className='text-sm'>
|
<CardDescription className='text-sm'>
|
||||||
{t("quotes.form_fields.subtotal_price.label")}
|
{t("quotes.form_fields.subtotal_price.label")}
|
||||||
</CardDescription>
|
</CardDescription>
|
||||||
<CardTitle className='flex items-baseline text-2xl tabular-nums'>
|
<CardTitle className='flex items-baseline justify-end text-2xl tabular-nums'>
|
||||||
{subtotal_price}
|
{subtotal_price}
|
||||||
<span className='ml-1 text-lg tracking-normal'>{currency_symbol}</span>
|
<span className='ml-1 text-lg tracking-normal'>{currency_symbol}</span>
|
||||||
</CardTitle>
|
</CardTitle>
|
||||||
@ -51,10 +51,10 @@ export const QuotePricesResume = () => {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className='grid gap-1 font-semibold text-muted-foreground'>
|
<div className='grid gap-1 font-semibold text-muted-foreground'>
|
||||||
<CardDescription className='text-sm'>
|
<CardDescription className='text-sm text-right'>
|
||||||
{t("quotes.form_fields.discount_price.label")}
|
{t("quotes.form_fields.discount_price.label")}
|
||||||
</CardDescription>
|
</CardDescription>
|
||||||
<CardTitle className='flex items-baseline text-2xl tabular-nums'>
|
<CardTitle className='flex items-baseline justify-end text-2xl tabular-nums'>
|
||||||
{discount_price}
|
{discount_price}
|
||||||
<span className='ml-1 text-lg tracking-normal'>{currency_symbol}</span>
|
<span className='ml-1 text-lg tracking-normal'>{currency_symbol}</span>
|
||||||
</CardTitle>
|
</CardTitle>
|
||||||
@ -77,10 +77,10 @@ export const QuotePricesResume = () => {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className='grid gap-1 font-semibold text-muted-foreground'>
|
<div className='grid gap-1 font-semibold text-muted-foreground'>
|
||||||
<CardDescription className='text-sm'>
|
<CardDescription className='text-sm text-right'>
|
||||||
{t("quotes.form_fields.tax_price.label")}
|
{t("quotes.form_fields.tax_price.label")}
|
||||||
</CardDescription>
|
</CardDescription>
|
||||||
<CardTitle className='flex items-baseline gap-1 text-2xl tabular-nums'>
|
<CardTitle className='flex items-baseline justify-end gap-1 text-2xl tabular-nums'>
|
||||||
{tax_price}
|
{tax_price}
|
||||||
<span className='text-base font-medium tracking-normal'>{currency_symbol}</span>
|
<span className='text-base font-medium tracking-normal'>{currency_symbol}</span>
|
||||||
</CardTitle>
|
</CardTitle>
|
||||||
@ -89,10 +89,10 @@ export const QuotePricesResume = () => {
|
|||||||
<Separator orientation='vertical' className='w-px h-16 mx-2' />
|
<Separator orientation='vertical' className='w-px h-16 mx-2' />
|
||||||
<div className='grid flex-1 h-16 grid-cols-1 auto-rows-max'>
|
<div className='grid flex-1 h-16 grid-cols-1 auto-rows-max'>
|
||||||
<div className='grid gap-0'>
|
<div className='grid gap-0'>
|
||||||
<CardDescription className='text-sm font-semibold'>
|
<CardDescription className='text-sm font-semibold text-right text-foreground'>
|
||||||
{t("quotes.form_fields.total_price.label")}
|
{t("quotes.form_fields.total_price.label")}
|
||||||
</CardDescription>
|
</CardDescription>
|
||||||
<CardTitle className='flex items-baseline gap-1 text-3xl tabular-nums'>
|
<CardTitle className='flex items-baseline justify-end gap-1 text-3xl tabular-nums'>
|
||||||
{total_price}
|
{total_price}
|
||||||
<span className='ml-1 text-lg tracking-normal'>{currency_symbol}</span>
|
<span className='ml-1 text-lg tracking-normal'>{currency_symbol}</span>
|
||||||
</CardTitle>
|
</CardTitle>
|
||||||
|
|||||||
@ -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<boolean>(false);
|
||||||
|
|
||||||
|
const { fields, ...fieldActions } = useFieldArray({
|
||||||
|
control,
|
||||||
|
name: "items",
|
||||||
|
});
|
||||||
|
|
||||||
|
const columns: ColumnDef<unknown, unknown>[] = useDetailColumns(
|
||||||
|
[
|
||||||
|
/*{
|
||||||
|
id: "row_id" as const,
|
||||||
|
header: () => (
|
||||||
|
<HashIcon aria-label='Orden de fila' className='items-center justify-center w-4 h-4' />
|
||||||
|
),
|
||||||
|
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 <FormTextAreaField autoSize {...register(`items.${index}.description`)} />;
|
||||||
|
},
|
||||||
|
size: 500,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "quantity" as const,
|
||||||
|
accessorKey: "quantity",
|
||||||
|
header: () => (
|
||||||
|
<div className='text-right'>{t("quotes.form_fields.items.quantity.label")}</div>
|
||||||
|
),
|
||||||
|
cell: ({ row: { index } }) => {
|
||||||
|
return (
|
||||||
|
<FormQuantityField
|
||||||
|
scale={0}
|
||||||
|
className='text-right'
|
||||||
|
{...register(`items.${index}.quantity`)}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "unit_price" as const,
|
||||||
|
accessorKey: "unit_price",
|
||||||
|
header: () => (
|
||||||
|
<div className='text-right'>{t("quotes.form_fields.items.unit_price.label")}</div>
|
||||||
|
),
|
||||||
|
cell: ({ row: { index } }) => {
|
||||||
|
return (
|
||||||
|
<FormCurrencyField
|
||||||
|
currency={currency}
|
||||||
|
language={language}
|
||||||
|
scale={4}
|
||||||
|
className='text-right'
|
||||||
|
{...register(`items.${index}.unit_price`)}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "subtotal_price" as const,
|
||||||
|
accessorKey: "subtotal_price",
|
||||||
|
header: () => (
|
||||||
|
<div className='text-right'>{t("quotes.form_fields.items.subtotal_price.label")}</div>
|
||||||
|
),
|
||||||
|
cell: ({ row: { index } }) => {
|
||||||
|
return (
|
||||||
|
<FormCurrencyField
|
||||||
|
currency={currency}
|
||||||
|
language={language}
|
||||||
|
scale={4}
|
||||||
|
readOnly
|
||||||
|
className='text-right'
|
||||||
|
{...register(`items.${index}.subtotal_price`)}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "discount" as const,
|
||||||
|
accessorKey: "discount",
|
||||||
|
header: () => (
|
||||||
|
<div className='text-right'>{t("quotes.form_fields.items.discount.label")}</div>
|
||||||
|
),
|
||||||
|
cell: ({ row: { index } }) => {
|
||||||
|
return (
|
||||||
|
<FormPercentageField
|
||||||
|
scale={2}
|
||||||
|
className='text-right'
|
||||||
|
{...register(`items.${index}.discount`)}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "total_price" as const,
|
||||||
|
accessorKey: "total_price",
|
||||||
|
header: () => (
|
||||||
|
<div className='text-right'>{t("quotes.form_fields.items.total_price.label")}</div>
|
||||||
|
),
|
||||||
|
cell: ({ row: { index } }) => {
|
||||||
|
return (
|
||||||
|
<FormCurrencyField
|
||||||
|
variant='ghost'
|
||||||
|
currency={currency}
|
||||||
|
language={language}
|
||||||
|
scale={4}
|
||||||
|
readOnly
|
||||||
|
className='font-semibold text-right'
|
||||||
|
{...register(`items.${index}.total_price`)}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
{
|
||||||
|
enableDragHandleColumn: false, // <--- Desactivado temporalmente
|
||||||
|
enableSelectionColumn: true,
|
||||||
|
enableActionsColumn: true,
|
||||||
|
rowActionFn: (props) => {
|
||||||
|
const { table, row } = props;
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
label: t("common.duplicate_row"),
|
||||||
|
icon: <CopyIcon className='w-4 h-4 mr-2' />,
|
||||||
|
onClick: () => table.options.meta?.duplicateItems(row.index),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: t("common.insert_row_above"),
|
||||||
|
icon: <ChevronUpIcon className='w-4 h-4 mr-2' />,
|
||||||
|
onClick: () => table.options.meta?.insertItem(row.index),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: t("common.insert_row_below"),
|
||||||
|
icon: <ChevronDownIcon className='w-4 h-4 mr-2' />,
|
||||||
|
onClick: () => table.options.meta?.insertItem(row.index + 1),
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
label: "-",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: t("common.remove_row"),
|
||||||
|
//shortcut: "⌘⌫",
|
||||||
|
icon: <Trash2Icon className='w-4 h-4 mr-2' />,
|
||||||
|
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 (
|
||||||
|
<div className='relative'>
|
||||||
|
<QuoteItemsSortableDataTable
|
||||||
|
actions={{
|
||||||
|
...fieldActions,
|
||||||
|
pickCatalogArticle: () => setPickerDialogOpen(true),
|
||||||
|
}}
|
||||||
|
columns={columns}
|
||||||
|
data={fields}
|
||||||
|
defaultValues={defaultValues}
|
||||||
|
/>
|
||||||
|
<CatalogPickerDialog
|
||||||
|
onSelect={handleAppendCatalogArticle}
|
||||||
|
isOpen={pickerDialogOpen}
|
||||||
|
onOpenChange={setPickerDialogOpen}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ResizablePanelGroup
|
||||||
|
direction='horizontal'
|
||||||
|
autoSaveId='uecko.quotes.details_layout'
|
||||||
|
className='items-stretch h-full'
|
||||||
|
>
|
||||||
|
<ResizablePanel
|
||||||
|
defaultSize={defaultLayout[0]}
|
||||||
|
collapsedSize={navCollapsedSize}
|
||||||
|
collapsible={true}
|
||||||
|
minSize={50}
|
||||||
|
maxSize={90}
|
||||||
|
onCollapse={() => {
|
||||||
|
setIsCollapsed(true);
|
||||||
|
}}
|
||||||
|
onExpand={() => {
|
||||||
|
setIsCollapsed(false);
|
||||||
|
}}
|
||||||
|
className={cn(isCollapsed && "min-w-[50px] transition-all duration-300 ease-in-out")}
|
||||||
|
>
|
||||||
|
<QuoteItemsSortableDataTable
|
||||||
|
actions={fieldActions}
|
||||||
|
columns={columns}
|
||||||
|
data={fields}
|
||||||
|
defaultValues={defaultValues}
|
||||||
|
/>
|
||||||
|
</ResizablePanel>
|
||||||
|
<ResizableHandle withHandle className='mx-3' />
|
||||||
|
<ResizablePanel defaultSize={defaultLayout[1]} minSize={10}>
|
||||||
|
<DataTableProvider syncWithLocation={false}>
|
||||||
|
<CatalogPickerDataTable onSelect={handleAppendCatalogArticle} />
|
||||||
|
</DataTableProvider>
|
||||||
|
</ResizablePanel>
|
||||||
|
</ResizablePanelGroup>
|
||||||
|
);
|
||||||
|
};
|
||||||
@ -9,24 +9,13 @@ export const QuoteGeneralCardEditor = () => {
|
|||||||
return (
|
return (
|
||||||
<div className='grid gap-6 md:grid-cols-6'>
|
<div className='grid gap-6 md:grid-cols-6'>
|
||||||
<FormGroup
|
<FormGroup
|
||||||
className='md:col-span-4'
|
className='md:col-span-6'
|
||||||
title={t("quotes.create.form_groups.general.title")}
|
title={t("quotes.create.form_groups.general.title")}
|
||||||
description={t("quotes.create.form_groups.general.desc")}
|
description={t("quotes.create.form_groups.general.desc")}
|
||||||
>
|
>
|
||||||
<div className='grid grid-cols-2 grid-rows-2 gap-6'>
|
<div className='grid grid-cols-6 gap-6'>
|
||||||
<FormTextAreaField
|
|
||||||
className='row-span-2'
|
|
||||||
required
|
|
||||||
label={t("quotes.form_fields.customer_information.label")}
|
|
||||||
description={t("quotes.form_fields.customer_information.desc")}
|
|
||||||
disabled={formState.disabled}
|
|
||||||
placeholder={t("quotes.form_fields.customer_information.placeholder")}
|
|
||||||
{...register("customer_information", {
|
|
||||||
required: true,
|
|
||||||
})}
|
|
||||||
errors={formState.errors}
|
|
||||||
/>
|
|
||||||
<FormTextField
|
<FormTextField
|
||||||
|
className='col-span-2'
|
||||||
label={t("quotes.form_fields.customer_reference.label")}
|
label={t("quotes.form_fields.customer_reference.label")}
|
||||||
description={t("quotes.form_fields.customer_reference.desc")}
|
description={t("quotes.form_fields.customer_reference.desc")}
|
||||||
disabled={formState.disabled}
|
disabled={formState.disabled}
|
||||||
@ -35,6 +24,7 @@ export const QuoteGeneralCardEditor = () => {
|
|||||||
required: false,
|
required: false,
|
||||||
})}
|
})}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<FormDatePickerField
|
<FormDatePickerField
|
||||||
required
|
required
|
||||||
label={t("quotes.form_fields.date.label")}
|
label={t("quotes.form_fields.date.label")}
|
||||||
@ -45,8 +35,6 @@ export const QuoteGeneralCardEditor = () => {
|
|||||||
required: true,
|
required: true,
|
||||||
})}
|
})}
|
||||||
/>
|
/>
|
||||||
</div>
|
|
||||||
<div className='grid grid-cols-2 grid-rows-2 gap-6'>
|
|
||||||
<FormTextField
|
<FormTextField
|
||||||
label={t("quotes.form_fields.validity.label")}
|
label={t("quotes.form_fields.validity.label")}
|
||||||
description={t("quotes.form_fields.validity.desc")}
|
description={t("quotes.form_fields.validity.desc")}
|
||||||
@ -56,8 +44,8 @@ export const QuoteGeneralCardEditor = () => {
|
|||||||
required: false,
|
required: false,
|
||||||
})}
|
})}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<FormTextAreaField
|
<FormTextAreaField
|
||||||
|
className='col-span-2'
|
||||||
label={t("quotes.form_fields.payment_method.label")}
|
label={t("quotes.form_fields.payment_method.label")}
|
||||||
description={t("quotes.form_fields.payment_method.desc")}
|
description={t("quotes.form_fields.payment_method.desc")}
|
||||||
disabled={formState.disabled}
|
disabled={formState.disabled}
|
||||||
@ -66,9 +54,23 @@ export const QuoteGeneralCardEditor = () => {
|
|||||||
required: false,
|
required: false,
|
||||||
})}
|
})}
|
||||||
/>
|
/>
|
||||||
|
</div>
|
||||||
|
<div className='grid grid-cols-6 gap-6'>
|
||||||
|
<FormTextAreaField
|
||||||
|
className='col-span-3'
|
||||||
|
required
|
||||||
|
label={t("quotes.form_fields.customer_information.label")}
|
||||||
|
description={t("quotes.form_fields.customer_information.desc")}
|
||||||
|
disabled={formState.disabled}
|
||||||
|
placeholder={t("quotes.form_fields.customer_information.placeholder")}
|
||||||
|
{...register("customer_information", {
|
||||||
|
required: true,
|
||||||
|
})}
|
||||||
|
errors={formState.errors}
|
||||||
|
/>
|
||||||
|
|
||||||
<FormTextAreaField
|
<FormTextAreaField
|
||||||
className='col-span-2'
|
className='col-span-3'
|
||||||
label={t("quotes.form_fields.notes.label")}
|
label={t("quotes.form_fields.notes.label")}
|
||||||
description={t("quotes.form_fields.notes.desc")}
|
description={t("quotes.form_fields.notes.desc")}
|
||||||
disabled={formState.disabled}
|
disabled={formState.disabled}
|
||||||
@ -80,7 +82,7 @@ export const QuoteGeneralCardEditor = () => {
|
|||||||
</div>
|
</div>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
<FormGroup
|
<FormGroup
|
||||||
className='md:col-span-2'
|
className='hidden md:col-span-2'
|
||||||
title={t("quotes.create.form_groups.status.title")}
|
title={t("quotes.create.form_groups.status.title")}
|
||||||
description={t("quotes.create.form_groups.status.desc")}
|
description={t("quotes.create.form_groups.status.desc")}
|
||||||
>
|
>
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import {
|
|||||||
LoadingOverlay,
|
LoadingOverlay,
|
||||||
SubmitButton,
|
SubmitButton,
|
||||||
} from "@/components";
|
} from "@/components";
|
||||||
|
import { calculateQuoteItemTotals, calculateQuoteTotals } from "@/lib/calc";
|
||||||
import { useUnsavedChangesNotifier } from "@/lib/hooks";
|
import { useUnsavedChangesNotifier } from "@/lib/hooks";
|
||||||
import { useUrlId } from "@/lib/hooks/useUrlId";
|
import { useUrlId } from "@/lib/hooks/useUrlId";
|
||||||
import { Button, Form, Tabs, TabsContent, TabsList, TabsTrigger } from "@/ui";
|
import { Button, Form, Tabs, TabsContent, TabsList, TabsTrigger } from "@/ui";
|
||||||
@ -16,7 +17,7 @@ import {
|
|||||||
Language,
|
Language,
|
||||||
} from "@shared/contexts";
|
} from "@shared/contexts";
|
||||||
import { t } from "i18next";
|
import { t } from "i18next";
|
||||||
import { useMemo, useState } from "react";
|
import { useEffect, useMemo, useState } from "react";
|
||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
import { useNavigate } from "react-router-dom";
|
import { useNavigate } from "react-router-dom";
|
||||||
import { toast } from "react-toastify";
|
import { toast } from "react-toastify";
|
||||||
@ -128,7 +129,7 @@ export const QuoteEdit = () => {
|
|||||||
//shouldUnregister: true,
|
//shouldUnregister: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
const { getValues, reset, handleSubmit, formState } = form;
|
const { getValues, reset, handleSubmit, formState, watch, setValue } = form;
|
||||||
const { isSubmitting, isDirty } = formState;
|
const { isSubmitting, isDirty } = formState;
|
||||||
|
|
||||||
useUnsavedChangesNotifier({
|
useUnsavedChangesNotifier({
|
||||||
@ -157,7 +158,7 @@ export const QuoteEdit = () => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
/*useEffect(() => {
|
useEffect(() => {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
const { unsubscribe } = watch((_, { name, type }) => {
|
const { unsubscribe } = watch((_, { name, type }) => {
|
||||||
console.log("useEffect");
|
console.log("useEffect");
|
||||||
@ -234,7 +235,7 @@ export const QuoteEdit = () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
return () => unsubscribe();
|
return () => unsubscribe();
|
||||||
}, [watch, getValues, setValue]);*/
|
}, [watch, getValues, setValue]);
|
||||||
|
|
||||||
if (isSubmitting || isPending) {
|
if (isSubmitting || isPending) {
|
||||||
return <LoadingOverlay title='Guardando cotización' />;
|
return <LoadingOverlay title='Guardando cotización' />;
|
||||||
@ -283,6 +284,14 @@ export const QuoteEdit = () => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<QuoteGeneralCardEditor />
|
||||||
|
<QuotePricesResume />
|
||||||
|
<QuoteDetailsCardEditor
|
||||||
|
currency={quoteCurrency}
|
||||||
|
language={quoteLanguage}
|
||||||
|
defaultValues={defaultValues}
|
||||||
|
/>
|
||||||
|
|
||||||
<Tabs
|
<Tabs
|
||||||
defaultValue='items'
|
defaultValue='items'
|
||||||
className='space-y-4'
|
className='space-y-4'
|
||||||
@ -294,17 +303,9 @@ export const QuoteEdit = () => {
|
|||||||
<TabsTrigger value='items'>{t("quotes.create.tabs.items")}</TabsTrigger>
|
<TabsTrigger value='items'>{t("quotes.create.tabs.items")}</TabsTrigger>
|
||||||
{/* <TabsTrigger value='history'>{t("quotes.create.tabs.history")}</TabsTrigger>*/}
|
{/* <TabsTrigger value='history'>{t("quotes.create.tabs.history")}</TabsTrigger>*/}
|
||||||
</TabsList>
|
</TabsList>
|
||||||
<QuotePricesResume />
|
|
||||||
<TabsContent value='general' forceMount hidden={"general" !== activeTab}>
|
<TabsContent value='general' forceMount hidden={"general" !== activeTab}></TabsContent>
|
||||||
<QuoteGeneralCardEditor />
|
<TabsContent value='items' forceMount hidden={"items" !== activeTab}></TabsContent>
|
||||||
</TabsContent>
|
|
||||||
<TabsContent value='items' forceMount hidden={"items" !== activeTab}>
|
|
||||||
<QuoteDetailsCardEditor
|
|
||||||
currency={quoteCurrency}
|
|
||||||
language={quoteLanguage}
|
|
||||||
defaultValues={defaultValues}
|
|
||||||
/>
|
|
||||||
</TabsContent>
|
|
||||||
</Tabs>
|
</Tabs>
|
||||||
|
|
||||||
<div className='flex items-center justify-center gap-2 md:hidden'>
|
<div className='flex items-center justify-center gap-2 md:hidden'>
|
||||||
|
|||||||
@ -66,6 +66,7 @@ export const FormDatePickerField = React.forwardRef<
|
|||||||
<PopoverTrigger asChild>
|
<PopoverTrigger asChild>
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<Button
|
<Button
|
||||||
|
variant={"secondary"}
|
||||||
className={cn(
|
className={cn(
|
||||||
"pl-3 text-left font-normal",
|
"pl-3 text-left font-normal",
|
||||||
!field.value && "text-muted-foreground"
|
!field.value && "text-muted-foreground"
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user