183 lines
5.5 KiB
TypeScript
183 lines
5.5 KiB
TypeScript
import { formHasAnyDirty, pickFormDirtyValues } from "@erp/core/client";
|
|
import {
|
|
FormCommitButtonGroup,
|
|
UnsavedChangesProvider,
|
|
useHookForm,
|
|
useUrlParamId,
|
|
} from "@erp/core/hooks";
|
|
import { ErrorAlert, NotFoundCard } from "@erp/customers/components";
|
|
import { AppBreadcrumb, AppContent, AppHeader, BackHistoryButton } from "@repo/rdx-ui/components";
|
|
import { showErrorToast, showSuccessToast, showWarningToast } from "@repo/rdx-ui/helpers";
|
|
import { FilePenIcon } from "lucide-react";
|
|
import { FieldErrors, FormProvider } from "react-hook-form";
|
|
import { useNavigate } from "react-router-dom";
|
|
import {
|
|
CustomerInvoiceEditForm,
|
|
CustomerInvoiceEditorSkeleton,
|
|
PageHeader,
|
|
} from "../../components";
|
|
import { useCustomerInvoiceQuery, useUpdateCustomerInvoice } from "../../hooks";
|
|
import { useTranslation } from "../../i18n";
|
|
import {
|
|
CustomerInvoiceFormData,
|
|
CustomerInvoiceFormSchema,
|
|
defaultCustomerInvoiceFormData
|
|
} from "../../schemas";
|
|
|
|
export const CustomerInvoiceUpdatePage = () => {
|
|
const invoiceId = useUrlParamId();
|
|
const { t } = useTranslation();
|
|
const navigate = useNavigate();
|
|
|
|
// 1) Estado de carga de la factura (query)
|
|
const {
|
|
data: invoiceData,
|
|
isLoading: isLoadingInvoice,
|
|
isError: isLoadError,
|
|
error: loadError,
|
|
} = useCustomerInvoiceQuery(invoiceId, { enabled: !!invoiceId });
|
|
|
|
// 2) Estado de actualización (mutación)
|
|
const {
|
|
mutate,
|
|
isPending: isUpdating,
|
|
isError: isUpdateError,
|
|
error: updateError,
|
|
} = useUpdateCustomerInvoice();
|
|
|
|
// 3) Form hook
|
|
|
|
const form = useHookForm<CustomerInvoiceFormData>({
|
|
resolverSchema: CustomerInvoiceFormSchema,
|
|
initialValues: (invoiceData as unknown as CustomerInvoiceFormData) ?? defaultCustomerInvoiceFormData,
|
|
disabled: isUpdating,
|
|
});
|
|
|
|
const handleSubmit = (formData: CustomerInvoiceFormData) => {
|
|
const { dirtyFields } = form.formState;
|
|
|
|
if (!formHasAnyDirty(dirtyFields)) {
|
|
showWarningToast("No hay cambios para guardar");
|
|
return;
|
|
}
|
|
|
|
const patchData = pickFormDirtyValues(formData, dirtyFields);
|
|
console.log(patchData);
|
|
|
|
mutate(
|
|
{ id: invoiceId!, data: patchData },
|
|
{
|
|
onSuccess(data) {
|
|
showSuccessToast(t("pages.update.successTitle"), t("pages.update.successMsg"));
|
|
|
|
// 🔹 limpiar el form e isDirty pasa a false
|
|
form.reset(data as unknown as CustomerInvoiceFormData);
|
|
},
|
|
onError(error) {
|
|
showErrorToast(t("pages.update.errorTitle"), error.message);
|
|
},
|
|
}
|
|
);
|
|
};
|
|
|
|
const handleReset = () =>
|
|
form.reset((invoiceData as unknown as CustomerInvoiceFormData) ?? defaultCustomerInvoiceFormData);
|
|
|
|
const handleBack = () => {
|
|
navigate(-1);
|
|
};
|
|
|
|
const handleError = (errors: FieldErrors<CustomerInvoiceFormData>) => {
|
|
console.error("Errores en el formulario:", errors);
|
|
// Aquí puedes manejar los errores, por ejemplo, mostrar un mensaje al usuario
|
|
};
|
|
|
|
if (isLoadingInvoice) {
|
|
return <CustomerInvoiceEditorSkeleton />;
|
|
}
|
|
|
|
if (isLoadError) {
|
|
return (
|
|
<>
|
|
<AppBreadcrumb />
|
|
<AppContent>
|
|
<ErrorAlert
|
|
title={t("pages.update.loadErrorTitle", "No se pudo cargar la factura")}
|
|
message={
|
|
(loadError as Error)?.message ??
|
|
t("pages.update.loadErrorMsg", "Inténtalo de nuevo más tarde.")
|
|
}
|
|
/>
|
|
|
|
<div className='flex items-center justify-end'>
|
|
<BackHistoryButton />
|
|
</div>
|
|
</AppContent>
|
|
</>
|
|
);
|
|
}
|
|
|
|
if (!invoiceData)
|
|
return (
|
|
<>
|
|
<AppBreadcrumb />
|
|
<AppContent>
|
|
<NotFoundCard
|
|
title={t("pages.update.notFoundTitle", "Factura de cliente no encontrada")}
|
|
message={t("pages.update.notFoundMsg", "Revisa el identificador o vuelve al listado.")}
|
|
/>
|
|
</AppContent>
|
|
</>
|
|
);
|
|
|
|
return (
|
|
<UnsavedChangesProvider isDirty={form.formState.isDirty}>
|
|
<AppHeader>
|
|
<AppBreadcrumb />
|
|
<PageHeader
|
|
status={invoiceData.status}
|
|
title={
|
|
<>
|
|
{t("pages.edit.title")} {invoiceData.invoice_number}
|
|
</>
|
|
}
|
|
description={t("pages.edit.description")}
|
|
icon={<FilePenIcon className='size-12 text-primary stroke-1' aria-hidden />}
|
|
rightSlot={
|
|
<FormCommitButtonGroup
|
|
isLoading={isUpdating}
|
|
disabled={isUpdating}
|
|
cancel={{ to: "/customer-invoices/list", disabled: isUpdating }}
|
|
submit={{ formId: "customer-invoice-update-form", disabled: isUpdating }}
|
|
onBack={handleBack}
|
|
onReset={handleReset}
|
|
/>
|
|
}
|
|
/>
|
|
</AppHeader>
|
|
|
|
<AppContent>
|
|
{/* Alerta de error de actualización (si ha fallado el último intento) */}
|
|
{isUpdateError && (
|
|
<ErrorAlert
|
|
title={t("pages.update.errorTitle", "No se pudo guardar los cambios")}
|
|
message={
|
|
(updateError as Error)?.message ??
|
|
t("pages.update.errorMsg", "Revisa los datos e inténtalo de nuevo.")
|
|
}
|
|
/>
|
|
)}
|
|
|
|
<FormProvider {...form}>
|
|
<CustomerInvoiceEditForm
|
|
formId={"customer-invoice-update-form"} // para que el botón del header pueda hacer submit
|
|
onSubmit={handleSubmit}
|
|
onError={handleError}
|
|
className='max-w-full'
|
|
/>
|
|
</FormProvider>
|
|
</AppContent>
|
|
</UnsavedChangesProvider>
|
|
);
|
|
};
|