Uecko_ERP/modules/customers/src/web/pages/update/customer-update.tsx
2025-09-23 18:38:20 +02:00

158 lines
4.9 KiB
TypeScript

import { AppBreadcrumb, AppContent, BackHistoryButton } from "@repo/rdx-ui/components";
import { useNavigate } from "react-router-dom";
import { FormCommitButtonGroup, UnsavedChangesProvider, useUrlParamId } from "@erp/core/hooks";
import { showErrorToast, showSuccessToast } from "@repo/shadcn-ui/lib/utils";
import { useState } from "react";
import { FieldErrors } from "react-hook-form";
import {
CustomerEditForm,
CustomerEditorSkeleton,
ErrorAlert,
NotFoundCard,
} from "../../components";
import { useCustomerQuery, useUpdateCustomerMutation } from "../../hooks";
import { useTranslation } from "../../i18n";
import { CreateCustomerFormData } from "../../schemas";
export const CustomerUpdate = () => {
const customerId = useUrlParamId();
const { t } = useTranslation();
const navigate = useNavigate();
const [isDirty, setIsDirty] = useState(false);
// 1) Estado de carga del cliente (query)
const {
data: customerData,
isLoading: isLoadingCustomer,
isError: isLoadError,
error: loadError,
} = useCustomerQuery(customerId, { enabled: !!customerId });
// 2) Estado de actualización (mutación)
const {
mutate,
isPending: isUpdating,
isError: isUpdateError,
error: updateError,
} = useUpdateCustomerMutation();
// 3) Submit con navegación condicionada por éxito
const handleSubmit = (formData: CreateCustomerFormData) => {
mutate(
{ id: customerId!, data: formData },
{
onSuccess(data) {
setIsDirty(false);
showSuccessToast(t("pages.update.successTitle"), t("pages.update.successMsg"));
// El timeout es para que a React le dé tiempo a procesar
// el cambio de estado de isDirty / setIsDirty.
setTimeout(() => {
navigate("/customers/list", {
state: { customerId: data.id, isNew: true },
replace: true,
});
}, 0);
},
onError(error) {
showErrorToast(t("pages.update.errorTitle"), error.message);
},
}
);
};
const handleError = (errors: FieldErrors<CreateCustomerFormData>) => {
console.error("Errores en el formulario:", errors);
// Aquí puedes manejar los errores, por ejemplo, mostrar un mensaje al usuario
};
if (isLoadingCustomer) {
return <CustomerEditorSkeleton />;
}
if (isLoadError) {
return (
<>
<AppBreadcrumb />
<AppContent>
<ErrorAlert
title={t("pages.update.loadErrorTitle", "No se pudo cargar el cliente")}
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 (!customerData)
return (
<>
<AppBreadcrumb />
<AppContent>
<NotFoundCard
title={t("pages.update.notFoundTitle", "Cliente no encontrado")}
message={t("pages.update.notFoundMsg", "Revisa el identificador o vuelve al listado.")}
/>
</AppContent>
</>
);
return (
<>
<AppBreadcrumb />
<AppContent>
<UnsavedChangesProvider isDirty={isDirty}>
<div className='flex items-center justify-between space-y-4 px-6'>
<div className='space-y-2'>
<h2 className='text-2xl font-bold tracking-tight text-balance scroll-m-2'>
{t("pages.update.title")}
</h2>
<p className='text-muted-foreground scroll-m-20 tracking-tight text-balance'>
{t("pages.update.description")}
</p>
</div>
<FormCommitButtonGroup
cancel={{
to: "/customers/list",
}}
submit={{
formId: "customer-create-form",
disabled: isUpdating,
isLoading: isUpdating,
}}
/>
</div>
{/* 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.")
}
/>
)}
<div className='flex flex-1 flex-col gap-4 p-4'>
<CustomerEditForm
formId={"customer-update-form"} // para que el botón del header pueda hacer submit
initialValues={customerData}
onSubmit={handleSubmit}
onError={handleError}
onDirtyChange={setIsDirty}
/>
</div>
</UnsavedChangesProvider>
</AppContent>
</>
);
};