Uecko_ERP/modules/customers/src/web/pages/update/customer-update.tsx

161 lines
4.9 KiB
TypeScript
Raw Normal View History

2025-09-16 17:29:37 +00:00
import { AppBreadcrumb, AppContent, BackHistoryButton, ButtonGroup } from "@repo/rdx-ui/components";
import { Button } from "@repo/shadcn-ui/components";
import { useNavigate } from "react-router-dom";
import { useUrlParamId } from "@erp/core/hooks";
2025-09-17 17:37:41 +00:00
import { showErrorToast, showSuccessToast } from "@repo/shadcn-ui/lib/utils";
2025-09-19 09:29:49 +00:00
import { FieldErrors } from "react-hook-form";
2025-09-22 17:43:55 +00:00
import {
CustomerEditForm,
CustomerEditorSkeleton,
ErrorAlert,
NotFoundCard,
} from "../../components";
2025-09-16 17:29:37 +00:00
import { useCustomerQuery, useUpdateCustomerMutation } from "../../hooks";
import { useTranslation } from "../../i18n";
2025-09-22 17:43:55 +00:00
import { CustomerFormData } from "../../schemas";
2025-09-16 17:29:37 +00:00
export const CustomerUpdate = () => {
const customerId = useUrlParamId();
2025-09-22 17:43:55 +00:00
const { t } = useTranslation();
2025-09-16 17:29:37 +00:00
const navigate = useNavigate();
// 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 {
2025-09-17 17:37:41 +00:00
mutateAsync,
2025-09-16 17:29:37 +00:00
isPending: isUpdating,
isError: isUpdateError,
error: updateError,
2025-09-17 17:37:41 +00:00
} = useUpdateCustomerMutation();
2025-09-16 17:29:37 +00:00
// 3) Submit con navegación condicionada por éxito
2025-09-22 17:43:55 +00:00
const handleSubmit = async (formData: CustomerFormData) => {
console.log(formData);
2025-09-16 17:29:37 +00:00
try {
2025-09-17 17:37:41 +00:00
const result = await mutateAsync({ id: customerId!, data: formData });
2025-09-22 08:13:59 +00:00
console.log(result);
2025-09-17 17:37:41 +00:00
if (result) {
showSuccessToast(t("pages.update.successTitle"), t("pages.update.successMsg"));
2025-09-22 08:13:59 +00:00
navigate("/customers/list", { relative: "path" });
2025-09-17 17:37:41 +00:00
}
2025-09-16 17:29:37 +00:00
} catch (e) {
2025-09-17 17:37:41 +00:00
showErrorToast(t("pages.update.errorTitle"), (e as Error).message);
} finally {
2025-09-16 17:29:37 +00:00
}
};
2025-09-22 17:43:55 +00:00
const handleError = (errors: FieldErrors<CustomerFormData>) => {
2025-09-19 09:29:49 +00:00
console.error("Errores en el formulario:", errors);
// Aquí puedes manejar los errores, por ejemplo, mostrar un mensaje al usuario
};
2025-09-16 17:29:37 +00:00
if (isLoadingCustomer) {
2025-09-17 17:37:41 +00:00
return <CustomerEditorSkeleton />;
2025-09-16 17:29:37 +00:00
}
if (isLoadError) {
return (
<>
<AppBreadcrumb />
<AppContent>
2025-09-17 17:37:41 +00:00
<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.")
}
/>
2025-09-16 17:29:37 +00:00
<div className='flex items-center justify-end'>
<BackHistoryButton />
</div>
</AppContent>
</>
);
}
2025-09-17 17:37:41 +00:00
if (!customerData)
2025-09-16 17:29:37 +00:00
return (
<>
<AppBreadcrumb />
<AppContent>
2025-09-17 17:37:41 +00:00
<NotFoundCard
title={t("pages.update.notFoundTitle", "Cliente no encontrado")}
message={t("pages.update.notFoundMsg", "Revisa el identificador o vuelve al listado.")}
/>
2025-09-16 17:29:37 +00:00
</AppContent>
</>
);
return (
<>
<AppBreadcrumb />
<AppContent>
2025-09-22 08:13:59 +00:00
<div className='flex items-center justify-between space-y-4 px-6'>
2025-09-19 16:55:30 +00:00
<div className='space-y-2'>
2025-09-16 17:29:37 +00:00
<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>
<ButtonGroup>
2025-09-20 10:43:37 +00:00
<Button
variant={"outline"}
className='cursor-pointer'
onClick={(e) => {
e.preventDefault();
2025-09-22 17:43:55 +00:00
navigate("/customers/list");
2025-09-20 10:43:37 +00:00
}}
>
{t("common.cancel")}
</Button>
2025-09-16 17:29:37 +00:00
<Button
type='submit'
2025-09-22 17:43:55 +00:00
form='customer-update-form'
2025-09-16 17:29:37 +00:00
className='cursor-pointer'
disabled={isUpdating || isLoadingCustomer}
aria-busy={isUpdating}
aria-disabled={isUpdating || isLoadingCustomer}
data-state={isUpdating ? "loading" : "idle"}
>
2025-09-20 10:43:37 +00:00
{t("common.save")}
2025-09-16 17:29:37 +00:00
</Button>
</ButtonGroup>
</div>
{/* Alerta de error de actualización (si ha fallado el último intento) */}
{isUpdateError && (
2025-09-17 17:37:41 +00:00
<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.")
}
/>
2025-09-16 17:29:37 +00:00
)}
<div className='flex flex-1 flex-col gap-4 p-4'>
<CustomerEditForm
2025-09-22 17:43:55 +00:00
formId={"customer-update-form"} // para que el botón del header pueda hacer submit
initialValues={customerData}
2025-09-16 17:29:37 +00:00
onSubmit={handleSubmit}
2025-09-19 16:55:30 +00:00
onError={handleError}
2025-09-22 17:43:55 +00:00
disabled={isLoadingCustomer}
2025-09-16 17:29:37 +00:00
/>
</div>
</AppContent>
</>
);
};