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): 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({ 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) => { const firstKey = Object.keys(errors)[0] as keyof CustomerFormData | undefined; if (firstKey) document.querySelector(`[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
const onSubmit = (event: React.FormEvent) => { 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, }; };