import { applyValidationErrorCollection } from "@erp/core"; import { formHasAnyDirty } from "@erp/core/client"; import { useHookForm } from "@erp/core/hooks"; import { UniqueID, type ValidationErrorCollection, isValidationErrorCollection, } from "@repo/rdx-ddd"; import { focusFirstInputFormError, showErrorToast, showSuccessToast, showWarningToast, } from "@repo/rdx-ui/helpers"; import { useId } from "react"; import type { FieldErrors } from "react-hook-form"; import { useTranslation } from "../../i18n"; import { type CreateCustomerParams, type Customer, useCustomerCreateMutation } from "../../shared"; import { type CustomerCreateForm, CustomerCreateFormSchema } from "../entities"; import { buildCreateCustomerParams, buildCustomerCreateDefault } from "../utils"; import { buildCustomerCreateData } from "../utils/build-customer-create-data"; import { useCustomerCreateFiscalController } from "./use-customer-create-fiscal-controller"; export interface UseCustomerCreateControllerOptions { onCreated?(created: Customer): void; successToasts?: boolean; // mostrar o no toast automáticamente onError?(error: Error, params: CreateCustomerParams): void; errorToasts?: boolean; // mostrar o no toast automáticamente } const normalizeSubmitError = (error: unknown): Error | ValidationErrorCollection => { if (isValidationErrorCollection(error)) { return error; } if (error instanceof Error) { return error; } return new Error("Unknown error"); }; export const useCreateCustomerController = (options?: UseCustomerCreateControllerOptions) => { const { t } = useTranslation(); const formId = useId(); // id único por instancia // 1) Estado de creación (mutación) const { mutateAsync, isPending: isCreating, isError: isCreateError, error: createError, } = useCustomerCreateMutation(); // 2) Form hook const form = useHookForm({ resolverSchema: CustomerCreateFormSchema, initialValues: buildCustomerCreateDefault(), disabled: isCreating, }); /** Handlers */ const resetForm = () => { form.reset(buildCustomerCreateDefault(), { keepDirty: false }); }; const submitHandler = form.handleSubmit( async (formData: CustomerCreateForm) => { if (!formHasAnyDirty(form.formState.dirtyFields)) { showWarningToast( t("create.feedback.no_changes.title"), t("create.feedback.no_changes.message") ); return; } const data = buildCustomerCreateData(formData); const customerId = UniqueID.generateNewID().toString(); const params = buildCreateCustomerParams(customerId, data); console.log("Enviando creación con params:", params); try { const created = await mutateAsync(params); // Ha ido bien -> actualizamos form con datos por defecto // keepDirty = false -> deja el formulario sin cambios sin tener que esperar al siguiente render. resetForm(); if (options?.successToasts !== false) { showSuccessToast( t("create.feedback.success.title"), t("create.feedback.success.message") ); } options?.onCreated?.(created); } catch (error: unknown) { const normalizedError = normalizeSubmitError(error); // No revierto el form para que no se pierdan los cambios que // ha hecho el usuario y no han sido guardados. /*resetForm()*/ if (isValidationErrorCollection(normalizedError)) { applyValidationErrorCollection(form, normalizedError); console.log("Errores de validación aplicados al form:", form.formState.errors); focusFirstInputFormError(form); if (options?.errorToasts !== false) { showWarningToast( t("create.feedback.validation.title"), t("create.feedback.validation.message") ); } options?.onError?.(normalizedError, params); return; } if (options?.errorToasts !== false) { showErrorToast( t("create.errors.title"), normalizedError.message || t("create.errors.unknown") ); } options?.onError?.(normalizedError, params); } }, (errors: FieldErrors) => { console.error(errors); focusFirstInputFormError(form); showWarningToast( t("common.feedback.validation.title"), t("common.feedback.validation.message") ); } ); // Evento onSubmit ya preparado para el
const onSubmit = (event: React.SubmitEvent) => { event.stopPropagation(); // <-- evita que el submit se propage por los padre en el árbol DOM submitHandler(event); }; const fiscalCtrl = useCustomerCreateFiscalController(); return { // form form, formId, // handlers del form onSubmit, resetForm, // mutation isCreating, isCreateError, createError, // Otros controladores fiscalCtrl, // No devolver FormProvider, así el controller es más // flexible y reusable (p.ej. para un modal) // FormProvider, }; }; export const useCustomerCreateController = useCreateCustomerController;