diff --git a/modules/customers/src/web/_archived/pages/update/customer-update-page.tsx b/modules/customers/src/web/_archived/pages/update/customer-update-page.tsx
index fd802640..822cdfa0 100644
--- a/modules/customers/src/web/_archived/pages/update/customer-update-page.tsx
+++ b/modules/customers/src/web/_archived/pages/update/customer-update-page.tsx
@@ -3,7 +3,7 @@ import { UnsavedChangesProvider, UpdateCommitButtonGroup, useUrlParamId } from "
import { AppContent, AppHeader, BackHistoryButton } from "@repo/rdx-ui/components";
import { useTranslation } from "../../../i18n";
-import { useCustomerUpdateController } from "../../../update/controllers/use-customer-update-page.controller";
+import { useCustomerUpdatePageController } from "../../../update/controllers/use-customer-update.controller";
import {
CustomerEditForm,
CustomerEditorSkeleton,
@@ -31,7 +31,7 @@ export const CustomerUpdatePage = () => {
updateError,
FormProvider,
- } = useCustomerUpdateController(customerId, {});
+ } = useCustomerUpdatePageController(customerId, {});
if (isLoading) {
return ;
diff --git a/modules/customers/src/web/update/adapters/customer-to-customer-update-form.adapter.ts b/modules/customers/src/web/update/adapters/customer-to-customer-update-form.adapter.ts
new file mode 100644
index 00000000..1e96f903
--- /dev/null
+++ b/modules/customers/src/web/update/adapters/customer-to-customer-update-form.adapter.ts
@@ -0,0 +1,45 @@
+import type { Customer } from "../../shared";
+import type { CustomerUpdateForm } from "../entities";
+
+/**
+ * Mapea un cliente a un formulario de actualización de cliente.
+ * Es decir, adapta el shape de datos del dominio al shape de datos
+ * que necesita la UI para mostrar el formulario de actualización.
+ *
+ * @param customer
+ * @returns
+ */
+
+export const mapCustomerToCustomerUpdateForm = (customer: Customer): CustomerUpdateForm => {
+ return {
+ reference: customer.reference ?? "",
+ isCompany: customer.isCompany,
+ name: customer.name ?? "",
+ tradeName: customer.tradeName ?? "",
+ tin: customer.tin ?? "",
+
+ defaultTaxes: customer.defaultTaxes ?? [],
+
+ street: customer.street ?? "",
+ street2: customer.street2 ?? "",
+ city: customer.city ?? "",
+ province: customer.province ?? "",
+ postalCode: customer.postalCode ?? "",
+ country: customer.country ?? "es",
+
+ primaryEmail: customer.primaryEmail ?? "",
+ secondaryEmail: customer.secondaryEmail ?? "",
+ primaryPhone: customer.primaryPhone ?? "",
+ secondaryPhone: customer.secondaryPhone ?? "",
+ primaryMobile: customer.primaryMobile ?? "",
+ secondaryMobile: customer.secondaryMobile ?? "",
+
+ fax: customer.fax ?? "",
+ website: customer.website ?? "",
+
+ legalRecord: customer.legalRecord ?? "",
+
+ languageCode: customer.languageCode ?? "ES",
+ currencyCode: customer.currencyCode ?? "EUR",
+ };
+};
diff --git a/modules/customers/src/web/update/adapters/index.ts b/modules/customers/src/web/update/adapters/index.ts
new file mode 100644
index 00000000..aeb1fcdc
--- /dev/null
+++ b/modules/customers/src/web/update/adapters/index.ts
@@ -0,0 +1 @@
+export * from "./customer-to-customer-update-form.adapter";
diff --git a/modules/customers/src/web/update/controllers/index.ts b/modules/customers/src/web/update/controllers/index.ts
index debbf28e..5dbb7701 100644
--- a/modules/customers/src/web/update/controllers/index.ts
+++ b/modules/customers/src/web/update/controllers/index.ts
@@ -1 +1,2 @@
+export * from "./use-customer-update.controller";
export * from "./use-customer-update-page.controller";
diff --git a/modules/customers/src/web/update/controllers/use-customer-update-page.controller.ts b/modules/customers/src/web/update/controllers/use-customer-update-page.controller.ts
index bc46e7b1..3754cec7 100644
--- a/modules/customers/src/web/update/controllers/use-customer-update-page.controller.ts
+++ b/modules/customers/src/web/update/controllers/use-customer-update-page.controller.ts
@@ -1,145 +1,18 @@
-import { formHasAnyDirty, pickFormDirtyValues } from "@erp/core/client";
-import { useHookForm } from "@erp/core/hooks";
-import { showErrorToast, showSuccessToast, showWarningToast } from "@repo/rdx-ui/helpers";
-import { useEffect, useId, useMemo } from "react";
-import { type FieldErrors, FormProvider } from "react-hook-form";
+import { useUrlParamId } from "@erp/core/hooks";
+import { useCustomerUpdateController } from "./use-customer-update.controller";
-import { useTranslation } from "../../i18n";
-import { type Customer, useCustomerGetQuery, useCustomerUpdateMutation } from "../../shared";
-import { type CustomerFormData, CustomerFormSchema, defaultCustomerFormData } from "../types";
+/**
+ * Hook para gestionar el controlador de la página de actualización de cliente.
+ *
+ * @returns
+ */
-export interface UseCustomerUpdateControllerOptions {
- onUpdated?(updated: Customer): void;
- successToasts?: boolean; // mostrar o no toast automáticcamente
+export const useCustomerUpdatePageController = () => {
+ const customerId = useUrlParamId();
- onError?(error: Error, patchData: ReturnType): void;
- errorToasts?: boolean; // mostrar o no toast automáticcamente
-}
-
-export const useCustomerUpdateController = (
- customerId?: string,
- options?: UseCustomerUpdateControllerOptions
-) => {
- const { t } = useTranslation();
- const formId = useId(); // id único por instancia
-
- // 1) Estado de carga del cliente (query)
- const {
- data: customerData,
- isLoading,
- isError: isLoadError,
- error: loadError,
- } = useCustomerGetQuery(customerId, { enabled: Boolean(customerId) });
-
- // 2) Estado de creación (mutación)
- const {
- mutateAsync,
- isPending: isUpdating,
- isError: isUpdateError,
- error: updateError,
- } = useCustomerUpdateMutation();
-
- const initialValues = useMemo(() => customerData ?? defaultCustomerFormData, [customerData]);
-
- // 3) Form hook
- const form = useHookForm({
- resolverSchema: CustomerFormSchema,
- initialValues,
- disabled: isLoading || isUpdating,
- });
-
- /** Reiniciar el form al recibir datos */
- useEffect(() => {
- // keepDirty = false -> deja el formulario sin cambios sin tener que esperar al siguiente render.
- if (customerData) {
- console.log("Reseteando form con datos del cliente:", customerData);
- form.reset(customerData, { keepDirty: false });
- }
- }, [customerData, form]);
-
- /** Handlers */
-
- const resetForm = () => form.reset(customerData ?? defaultCustomerFormData);
-
- // Versión sincronizada
- const submitHandler = form.handleSubmit(
- async (formData) => {
- if (!customerId) {
- showErrorToast(t("pages.update.error.title"), "Falta el ID del cliente");
- return;
- }
-
- const { dirtyFields } = form.formState;
- if (!formHasAnyDirty(dirtyFields)) {
- showWarningToast(t("pages.update.error.no_changes"), "No hay cambios para guardar");
- return;
- }
-
- const patchData = pickFormDirtyValues(formData, dirtyFields);
- const previousData = customerData;
-
- try {
- // Enviamos cambios al servidor
- const updated = 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(updated, { keepDirty: false });
-
- if (options?.successToasts !== false) {
- showSuccessToast(
- t("pages.update.success.title", "Cliente modificado"),
- t("pages.update.success.message", "Se ha modificado correctamente.")
- );
- }
- options?.onUpdated?.(updated);
- } catch (error: any) {
- // Algo ha fallado -> revertimos cambios
- form.reset(previousData ?? defaultCustomerFormData);
- if (options?.errorToasts !== false) {
- showErrorToast(t("pages.update.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