Uecko_ERP/modules/customers/src/web/pages/update/customer-update-modal.tsx
2025-10-12 20:36:33 +02:00

169 lines
5.6 KiB
TypeScript

import {
Button,
Dialog,
DialogContent,
DialogDescription,
DialogHeader,
DialogTitle,
Tabs,
TabsContent,
TabsList,
TabsTrigger,
} from "@repo/shadcn-ui/components";
import { X } from "lucide-react";
import { FieldErrors, FormProvider } from "react-hook-form";
import { CustomerAdditionalConfigFields } from "../../components/editor/customer-additional-config-fields";
import { CustomerAddressFields } from "../../components/editor/customer-address-fields";
import { CustomerBasicInfoFields } from "../../components/editor/customer-basic-info-fields";
import { useNavigate } from "react-router-dom";
import { formHasAnyDirty, pickFormDirtyValues } from "@erp/core/client";
import { UnsavedChangesProvider, useHookForm } from "@erp/core/hooks";
import { showErrorToast, showSuccessToast, showWarningToast } from "@repo/rdx-ui/helpers";
import { CustomerEditorSkeleton } from "../../components";
import { useCustomerQuery, useUpdateCustomer } from "../../hooks";
import { useTranslation } from "../../i18n";
import { CustomerFormData, CustomerFormSchema, defaultCustomerFormData } from "../../schemas";
interface CustomerEditModalProps {
customerId: string;
open: boolean;
onOpenChange: (open: boolean) => void;
}
export function CustomerEditModal({ customerId, open, onOpenChange }: CustomerEditModalProps) {
const { t } = useTranslation();
const navigate = useNavigate();
// 1) Estado de carga del cliente (query)
const {
data: customerData,
isLoading: isLoadingCustomer,
isError: isLoadError,
error: loadError,
} = useCustomerQuery(customerId, { enabled: !!customerId });
// 2) Estado de actualización (mutación)
const {
mutate,
isPending: isUpdating,
isError: isUpdateError,
error: updateError,
} = useUpdateCustomer();
// 3) Form hook
const form = useHookForm<CustomerFormData>({
resolverSchema: CustomerFormSchema,
initialValues: customerData ?? defaultCustomerFormData,
disabled: isUpdating,
});
// 4) Submit con navegación condicionada por éxito
const handleSubmit = (formData: CustomerFormData) => {
const { dirtyFields } = form.formState;
if (!formHasAnyDirty(dirtyFields)) {
showWarningToast("No hay cambios para guardar");
return;
}
const patchData = pickFormDirtyValues(formData, dirtyFields);
mutate(
{ id: customerId!, data: patchData },
{
onSuccess(data) {
showSuccessToast(t("pages.update.successTitle"), t("pages.update.successMsg"));
// 🔹 limpiar el form e isDirty pasa a false
form.reset(data);
},
onError(error) {
showErrorToast(t("pages.update.errorTitle"), error.message);
},
}
);
};
const handleReset = () => form.reset(customerData ?? defaultCustomerFormData);
const handleBack = () => {
navigate(-1);
};
const handleError = (errors: FieldErrors<CustomerFormData>) => {
console.error("Errores en el formulario:", errors);
// Aquí puedes manejar los errores, por ejemplo, mostrar un mensaje al usuario
};
if (isLoadingCustomer || isLoadError) {
return <CustomerEditorSkeleton />;
}
return (
<UnsavedChangesProvider isDirty={form.formState.isDirty}>
<FormProvider {...form}>
<Dialog open={open} onOpenChange={onOpenChange}>
<DialogContent className='max-h-[90vh] max-w-3xl overflow-hidden p-0'>
<DialogHeader className='border-b px-6 py-4'>
<div className='flex items-center justify-between'>
<div>
<DialogTitle className='text-xl'>Editar Cliente</DialogTitle>
<DialogDescription className='mt-1'>
Modifica la información del cliente
</DialogDescription>
</div>
<Button
variant='ghost'
size='icon'
onClick={() => onOpenChange(false)}
className='size-8'
>
<X className='h-4 w-4' />
</Button>
</div>
</DialogHeader>
<Tabs defaultValue='basic' className='flex h-full flex-col'>
<TabsList className='mx-6 mt-4 grid w-auto grid-cols-4 gap-2'>
<TabsTrigger value='basic'>Información Básica</TabsTrigger>
<TabsTrigger value='address'>Dirección</TabsTrigger>
<TabsTrigger value='contact'>Contacto</TabsTrigger>
<TabsTrigger value='preferences'>Preferencias</TabsTrigger>
</TabsList>
<div className='flex-1 overflow-y-auto px-6 py-4'>
<TabsContent value='basic' className='mt-0'>
<CustomerBasicInfoFields />
</TabsContent>
<TabsContent value='address' className='mt-0'>
<CustomerAddressFields />
</TabsContent>
<TabsContent value='contact' className='mt-0'>
<CustomerAddressFields />
</TabsContent>
<TabsContent value='preferences' className='mt-0'>
<CustomerAdditionalConfigFields />
</TabsContent>
</div>
<div className='border-t px-6 py-4'>
<div className='flex justify-end gap-3'>
<Button variant='outline' onClick={() => onOpenChange(false)}>
Cancelar
</Button>
<Button onClick={handleSubmit}>Guardar</Button>
</div>
</div>
</Tabs>
</DialogContent>
</Dialog>
</FormProvider>
</UnsavedChangesProvider>
);
}