Uecko_ERP/modules/customers/src/web/create/controllers/use-customer-create.controller.ts

121 lines
3.7 KiB
TypeScript
Raw Normal View History

2026-04-04 10:44:26 +00:00
import { useHookForm } from "@erp/core/hooks";
import { showErrorToast, showSuccessToast, showWarningToast } from "@repo/rdx-ui/helpers";
import { useId } from "react";
import type { FieldErrors } from "react-hook-form";
import { useTranslation } from "../../i18n";
2026-04-04 16:58:32 +00:00
import type { CreateCustomerParams, Customer } from "../../shared";
2026-04-04 10:44:26 +00:00
import { useCustomerCreateMutation } from "../../shared/hooks/use-customer-create-mutation";
2026-06-25 11:49:59 +00:00
import { mapCustomerToCustomerCreateForm } from "../adapters";
2026-04-04 10:44:26 +00:00
import {
type CustomerCreateForm,
CustomerCreateFormSchema,
defaultCustomerCreateForm,
} from "../entities";
2026-04-04 16:58:32 +00:00
import { buildCreateCustomerParams } from "../utils";
2026-04-04 10:44:26 +00:00
export interface UseCustomerCreateControllerOptions {
onCreated?(created: Customer): void;
successToasts?: boolean; // mostrar o no toast automáticcamente
2026-04-04 16:58:32 +00:00
onError?(error: Error, inputPayload: CreateCustomerParams): void;
2026-04-04 10:44:26 +00:00
errorToasts?: boolean; // mostrar o no toast automáticcamente
}
export const useCustomerCreateController = (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<CustomerCreateForm>({
resolverSchema: CustomerCreateFormSchema,
initialValues: defaultCustomerCreateForm,
disabled: isCreating,
});
/** Handlers */
const resetForm = () => {
form.reset(defaultCustomerCreateForm, { keepDirty: false });
};
const submitHandler = form.handleSubmit(
2026-06-25 11:49:59 +00:00
async (formData: CustomerCreateForm) => {
2026-04-04 17:38:09 +00:00
const params: CreateCustomerParams = buildCreateCustomerParams(formData);
2026-04-04 10:44:26 +00:00
try {
// Enviamos cambios al servidor
2026-04-04 17:38:09 +00:00
const created = await mutateAsync(params); // payload es CustomerCreatePayload
2026-04-04 10:44:26 +00:00
2026-06-25 11:49:59 +00:00
// Ha ido bien -> actualizamos form con datos reales
// keepDirty = false -> deja el formulario sin cambios sin tener que esperar al siguiente render.
form.reset(mapCustomerToCustomerCreateForm(created), {
keepDirty: false,
});
2026-04-04 10:44:26 +00:00
if (options?.successToasts !== false) {
showSuccessToast(
2026-06-15 09:39:05 +00:00
t("create.feedback.success.title"),
t("create.feedback.success.message")
2026-04-04 10:44:26 +00:00
);
}
options?.onCreated?.(created);
} catch (error: unknown) {
const normalizedError =
2026-06-15 09:39:05 +00:00
error instanceof Error ? error : new Error(t("create.errors.unknown"));
2026-04-04 10:44:26 +00:00
if (options?.errorToasts !== false) {
2026-06-15 09:39:05 +00:00
showErrorToast(t("create.errors.title"), normalizedError.message);
2026-04-04 10:44:26 +00:00
}
2026-04-04 17:38:09 +00:00
options?.onError?.(normalizedError, params);
2026-04-04 10:44:26 +00:00
}
},
(errors: FieldErrors<CustomerCreateForm>) => {
const firstKey = Object.keys(errors)[0] as keyof CustomerCreateForm | undefined;
if (firstKey) {
document.querySelector<HTMLElement>(`[name="${String(firstKey)}"]`)?.focus();
}
showWarningToast(
2026-06-15 09:39:05 +00:00
t("common.feedback.validation.title"),
t("common.feedback.validation.message")
2026-04-04 10:44:26 +00:00
);
}
);
// 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
isCreating,
isCreateError,
createError,
// No devolver FormProvider, así el controller es más
// flexible y reusable (p.ej. para un modal)
// FormProvider,
};
};