121 lines
3.8 KiB
TypeScript
121 lines
3.8 KiB
TypeScript
|
|
import { formHasAnyDirty, pickFormDirtyValues } from "@erp/core/client";
|
||
|
|
import { useHookForm } from "@erp/core/hooks";
|
||
|
|
import { showErrorToast, showSuccessToast, showWarningToast } from "@repo/rdx-ui/helpers";
|
||
|
|
import { useId } from "react";
|
||
|
|
import { type FieldErrors, FormProvider } from "react-hook-form";
|
||
|
|
|
||
|
|
import { useTranslation } from "../../i18n";
|
||
|
|
import type { Customer } from "../../shared";
|
||
|
|
import { type CustomerFormData, CustomerFormSchema, defaultCustomerFormData } from "../types";
|
||
|
|
|
||
|
|
export interface UseCustomerCreateControllerOptions {
|
||
|
|
onCreated?(created: Customer): void;
|
||
|
|
successToasts?: boolean; // mostrar o no toast automáticcamente
|
||
|
|
|
||
|
|
onError?(error: Error, patchData: ReturnType<typeof pickFormDirtyValues>): void;
|
||
|
|
errorToasts?: boolean; // mostrar o no toast automáticcamente
|
||
|
|
}
|
||
|
|
|
||
|
|
export const useCustomerCreateController = (
|
||
|
|
customerId?: string,
|
||
|
|
options?: UseCustomerCreateControllerOptions
|
||
|
|
) => {
|
||
|
|
const { t } = useTranslation();
|
||
|
|
const formId = useId(); // id único por instancia
|
||
|
|
|
||
|
|
// 1) Estado de creación (mutación)
|
||
|
|
const {
|
||
|
|
mutateAsync,
|
||
|
|
isPending,
|
||
|
|
isError: isCreateError,
|
||
|
|
error: createError,
|
||
|
|
} = useCustomerCreateMutation();
|
||
|
|
|
||
|
|
// 2) Form hook
|
||
|
|
const form = useHookForm<CustomerFormData>({
|
||
|
|
resolverSchema: CustomerFormSchema,
|
||
|
|
initialValues: defaultCustomerFormData,
|
||
|
|
disabled: isPending,
|
||
|
|
});
|
||
|
|
|
||
|
|
/** Handlers */
|
||
|
|
|
||
|
|
const resetForm = () => form.reset(defaultCustomerFormData);
|
||
|
|
|
||
|
|
// Versión sincronizada
|
||
|
|
const submitHandler = form.handleSubmit(
|
||
|
|
async (formData) => {
|
||
|
|
if (!customerId) {
|
||
|
|
showErrorToast(t("pages.create.error.title"), "Falta el ID del cliente");
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
const { dirtyFields } = form.formState;
|
||
|
|
if (!formHasAnyDirty(dirtyFields)) {
|
||
|
|
showWarningToast(t("pages.create.error.no_changes"), "No hay cambios para guardar");
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
const patchData = pickFormDirtyValues(formData, dirtyFields);
|
||
|
|
const previousData = customerData;
|
||
|
|
|
||
|
|
try {
|
||
|
|
// Enviamos cambios al servidor
|
||
|
|
const created = await mutateAsync({ id: customerId, data: patchData });
|
||
|
|
|
||
|
|
// Ha ido bien -> actualizamos form con datos reales
|
||
|
|
// keepDirty = false -> deja el formulario sin cambios sin tener que esperar al siguiente render.
|
||
|
|
form.reset(created, { keepDirty: false });
|
||
|
|
|
||
|
|
if (options?.successToasts !== false) {
|
||
|
|
showSuccessToast(
|
||
|
|
t("pages.create.success.title", "Cliente modificado"),
|
||
|
|
t("pages.create.success.message", "Se ha modificado correctamente.")
|
||
|
|
);
|
||
|
|
}
|
||
|
|
options?.onCreated?.(created);
|
||
|
|
} catch (error: any) {
|
||
|
|
// Algo ha fallado -> revertimos cambios
|
||
|
|
form.reset(previousData ?? defaultCustomerFormData);
|
||
|
|
if (options?.errorToasts !== false) {
|
||
|
|
showErrorToast(t("pages.create.error.title"), error.message);
|
||
|
|
}
|
||
|
|
options?.onError?.(error, patchData);
|
||
|
|
}
|
||
|
|
},
|
||
|
|
(errors: FieldErrors<CustomerFormData>) => {
|
||
|
|
const firstKey = Object.keys(errors)[0] as keyof CustomerFormData | undefined;
|
||
|
|
if (firstKey) document.querySelector<HTMLElement>(`[name="${String(firstKey)}"]`)?.focus();
|
||
|
|
|
||
|
|
showWarningToast(
|
||
|
|
t("forms.validation.title", "Revisa los campos"),
|
||
|
|
t("forms.validation.message", "Hay errores de validación en el formulario.")
|
||
|
|
);
|
||
|
|
}
|
||
|
|
);
|
||
|
|
|
||
|
|
// Evento onSubmit ya preparado para el <form>
|
||
|
|
const onSubmit = (event: React.FormEvent<HTMLFormElement>) => {
|
||
|
|
event.stopPropagation(); // <-- evita que el submit se propage por los padre en el árbol DOM
|
||
|
|
submitHandler(event);
|
||
|
|
};
|
||
|
|
|
||
|
|
return {
|
||
|
|
// form
|
||
|
|
form,
|
||
|
|
formId,
|
||
|
|
|
||
|
|
// handlers del form
|
||
|
|
onSubmit,
|
||
|
|
resetForm,
|
||
|
|
|
||
|
|
// mutation
|
||
|
|
isPending,
|
||
|
|
isCreateError,
|
||
|
|
createError,
|
||
|
|
|
||
|
|
// Por comodidad
|
||
|
|
FormProvider,
|
||
|
|
};
|
||
|
|
};
|