139 lines
4.3 KiB
TypeScript
139 lines
4.3 KiB
TypeScript
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";
|
|
import { showErrorToast, showSuccessToast } from "@repo/shadcn-ui/lib/utils";
|
|
import { CustomerEditorSkeleton, ErrorAlert, NotFoundCard } from "../../components";
|
|
import { useCustomerQuery, useUpdateCustomerMutation } from "../../hooks";
|
|
import { useTranslation } from "../../i18n";
|
|
import { CustomerUpdateData } from "../../schemas";
|
|
import { CustomerEditForm } from "./customer-edit-form";
|
|
|
|
export const CustomerUpdate = () => {
|
|
const { t } = useTranslation();
|
|
const customerId = useUrlParamId();
|
|
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 {
|
|
mutateAsync,
|
|
isPending: isUpdating,
|
|
isError: isUpdateError,
|
|
error: updateError,
|
|
} = useUpdateCustomerMutation();
|
|
|
|
// 3) Submit con navegación condicionada por éxito
|
|
const handleSubmit = async (formData: CustomerUpdateData) => {
|
|
try {
|
|
const result = await mutateAsync({ id: customerId!, data: formData });
|
|
|
|
if (result) {
|
|
showSuccessToast(t("pages.update.successTitle"), t("pages.update.successMsg"));
|
|
navigate("/customers/list");
|
|
}
|
|
} catch (e) {
|
|
showErrorToast(t("pages.update.errorTitle"), (e as Error).message);
|
|
} finally {
|
|
}
|
|
};
|
|
|
|
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>
|
|
<div className='flex items-center justify-between space-y-2'>
|
|
<div>
|
|
<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>
|
|
<BackHistoryButton />
|
|
<Button
|
|
type='submit'
|
|
form='customer-edit-form'
|
|
className='cursor-pointer'
|
|
disabled={isUpdating || isLoadingCustomer}
|
|
aria-busy={isUpdating}
|
|
aria-disabled={isUpdating || isLoadingCustomer}
|
|
data-state={isUpdating ? "loading" : "idle"}
|
|
>
|
|
{t("pages.update.submit")}
|
|
</Button>
|
|
</ButtonGroup>
|
|
</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'>
|
|
{/* Importante: proveemos un formId para que el botón del header pueda hacer submit */}
|
|
<CustomerEditForm
|
|
formId='customer-edit-form'
|
|
data={customerData}
|
|
onSubmit={handleSubmit}
|
|
isPending={isUpdating}
|
|
/>
|
|
</div>
|
|
</AppContent>
|
|
</>
|
|
);
|
|
};
|