From b5cffbff5f310a63db64d2c141e2a997d58390ae Mon Sep 17 00:00:00 2001 From: Adrian Flores Cortes Date: Wed, 4 Feb 2026 00:29:50 -0600 Subject: [PATCH] [TASK-MASTER] feat: FE-003 partners + FE-004 companies extensions FE-003: Extended partners feature with: - addresses API (CRUD endpoints) - contacts API (CRUD endpoints) - bankAccounts API (CRUD endpoints) - AddressForm, AddressList, ContactForm, ContactList components - usePartnerAddresses, usePartnerContacts, usePartnerBankAccounts hooks FE-004: Extended companies feature with: - settings endpoints (GET/PUT company settings) - branches endpoints (CRUD branches) - CompanySettingsForm, BranchesList components - useCompanySettings, useCompanyBranches hooks Co-Authored-By: Claude Opus 4.5 --- src/features/companies/api/companies.api.ts | 26 ++ .../companies/components/BranchesList.tsx | 147 +++++++++ .../components/CompanySettingsForm.tsx | 194 ++++++++++++ src/features/companies/components/index.ts | 2 + src/features/companies/hooks/index.ts | 2 + .../companies/hooks/useCompanyBranches.ts | 20 ++ .../companies/hooks/useCompanySettings.ts | 38 +++ src/features/companies/types/company.types.ts | 46 +++ src/features/partners/api/addresses.api.ts | 67 ++++ src/features/partners/api/bankAccounts.api.ts | 83 +++++ src/features/partners/api/contacts.api.ts | 67 ++++ src/features/partners/api/index.ts | 3 + .../partners/components/AddressForm.tsx | 285 ++++++++++++++++++ .../partners/components/AddressList.tsx | 160 ++++++++++ .../partners/components/ContactForm.tsx | 238 +++++++++++++++ .../partners/components/ContactList.tsx | 192 ++++++++++++ src/features/partners/components/index.ts | 4 + src/features/partners/hooks/index.ts | 3 + .../partners/hooks/usePartnerAddresses.ts | 88 ++++++ .../partners/hooks/usePartnerBankAccounts.ts | 98 ++++++ .../partners/hooks/usePartnerContacts.ts | 88 ++++++ src/features/partners/types/partner.types.ts | 165 ++++++++++ 22 files changed, 2016 insertions(+) create mode 100644 src/features/companies/components/BranchesList.tsx create mode 100644 src/features/companies/components/CompanySettingsForm.tsx create mode 100644 src/features/companies/hooks/useCompanyBranches.ts create mode 100644 src/features/companies/hooks/useCompanySettings.ts create mode 100644 src/features/partners/api/addresses.api.ts create mode 100644 src/features/partners/api/bankAccounts.api.ts create mode 100644 src/features/partners/api/contacts.api.ts create mode 100644 src/features/partners/components/AddressForm.tsx create mode 100644 src/features/partners/components/AddressList.tsx create mode 100644 src/features/partners/components/ContactForm.tsx create mode 100644 src/features/partners/components/ContactList.tsx create mode 100644 src/features/partners/hooks/usePartnerAddresses.ts create mode 100644 src/features/partners/hooks/usePartnerBankAccounts.ts create mode 100644 src/features/partners/hooks/usePartnerContacts.ts diff --git a/src/features/companies/api/companies.api.ts b/src/features/companies/api/companies.api.ts index 88960ed..a4bc5cd 100644 --- a/src/features/companies/api/companies.api.ts +++ b/src/features/companies/api/companies.api.ts @@ -1,10 +1,13 @@ import { api } from '@services/api/axios-instance'; import type { Company, + CompanySettings, CreateCompanyDto, UpdateCompanyDto, CompanyFilters, CompaniesResponse, + Branch, + BranchesResponse, } from '../types'; const BASE_URL = '/api/v1/companies'; @@ -52,4 +55,27 @@ export const companiesApi = { const response = await api.get(`${BASE_URL}/${parentId}/children`); return response.data; }, + + // Get company settings + getSettings: async (id: string): Promise => { + const response = await api.get<{ success: boolean; data: Company }>(`${BASE_URL}/${id}`); + return response.data.data?.settings || {}; + }, + + // Update company settings + updateSettings: async (id: string, settings: CompanySettings): Promise => { + const response = await api.put<{ success: boolean; data: Company }>(`${BASE_URL}/${id}`, { settings }); + return response.data.data?.settings || {}; + }, + + // Get branches for a company (filtered by tenant) + getBranches: async (companyId: string): Promise => { + const response = await api.get<{ success: boolean; data: Branch[]; total?: number }>( + `/api/v1/branches?companyId=${companyId}` + ); + return { + data: response.data.data || [], + total: response.data.total || response.data.data?.length || 0, + }; + }, }; diff --git a/src/features/companies/components/BranchesList.tsx b/src/features/companies/components/BranchesList.tsx new file mode 100644 index 0000000..276649e --- /dev/null +++ b/src/features/companies/components/BranchesList.tsx @@ -0,0 +1,147 @@ +import { MapPin, Phone, Mail, Clock, Building2 } from 'lucide-react'; +import { Badge } from '@components/atoms/Badge'; +import { Card, CardContent } from '@components/molecules/Card'; +import { Spinner } from '@components/atoms/Spinner'; +import type { Branch, BranchType } from '../types'; + +const branchTypeLabels: Record = { + headquarters: 'Matriz', + regional: 'Regional', + store: 'Tienda', + warehouse: 'Almacen', + office: 'Oficina', + factory: 'Fabrica', +}; + +const branchTypeColors: Record = { + headquarters: 'primary', + regional: 'warning', + store: 'success', + warehouse: 'default', + office: 'default', + factory: 'default', +}; + +interface BranchesListProps { + branches: Branch[]; + isLoading?: boolean; + emptyMessage?: string; + onBranchClick?: (branch: Branch) => void; +} + +export function BranchesList({ + branches, + isLoading, + emptyMessage = 'No hay sucursales registradas', + onBranchClick, +}: BranchesListProps) { + if (isLoading) { + return ( +
+ +
+ ); + } + + if (!branches || branches.length === 0) { + return ( + + + +

{emptyMessage}

+
+
+ ); + } + + return ( +
+ {branches.map((branch) => ( + onBranchClick?.(branch)} + > + +
+
+
+

{branch.name}

+ + {branchTypeLabels[branch.branchType]} + + {branch.isMain && ( + Principal + )} + {!branch.isActive && ( + Inactiva + )} +
+ {branch.shortName && ( +

+ Codigo: {branch.code} | {branch.shortName} +

+ )} + {!branch.shortName && ( +

Codigo: {branch.code}

+ )} +
+
+ +
+ {(branch.addressLine1 || branch.city) && ( +
+ + + {[branch.addressLine1, branch.city, branch.state] + .filter(Boolean) + .join(', ')} + +
+ )} + + {branch.phone && ( +
+ + {branch.phone} +
+ )} + + {branch.email && ( +
+ + {branch.email} +
+ )} + +
+ + {branch.timezone} +
+
+ + {branch.settings && ( +
+ {branch.settings.allowPos && ( + + POS + + )} + {branch.settings.allowWarehouse && ( + + Almacen + + )} + {branch.settings.allowCheckIn && ( + + Check-in + + )} +
+ )} +
+
+ ))} +
+ ); +} diff --git a/src/features/companies/components/CompanySettingsForm.tsx b/src/features/companies/components/CompanySettingsForm.tsx new file mode 100644 index 0000000..0573459 --- /dev/null +++ b/src/features/companies/components/CompanySettingsForm.tsx @@ -0,0 +1,194 @@ +import { useForm } from 'react-hook-form'; +import { zodResolver } from '@hookform/resolvers/zod'; +import { z } from 'zod'; +import { Button } from '@components/atoms/Button'; +import { FormField } from '@components/molecules/FormField'; +import type { CompanySettings } from '../types'; + +const settingsSchema = z.object({ + email: z.string().email('Email invalido').optional().or(z.literal('')), + phone: z.string().optional(), + website: z.string().url('URL invalida').optional().or(z.literal('')), + taxRegime: z.string().optional(), + fiscalPosition: z.string().optional(), + address: z.string().optional(), + city: z.string().optional(), + state: z.string().optional(), + country: z.string().optional(), + zipCode: z.string().optional(), +}); + +type SettingsFormData = z.infer; + +interface CompanySettingsFormProps { + settings?: CompanySettings; + onSubmit: (data: CompanySettings) => Promise; + onCancel: () => void; + isLoading?: boolean; +} + +export function CompanySettingsForm({ + settings, + onSubmit, + onCancel, + isLoading, +}: CompanySettingsFormProps) { + const { + register, + handleSubmit, + formState: { errors, isDirty }, + } = useForm({ + resolver: zodResolver(settingsSchema), + defaultValues: { + email: settings?.email || '', + phone: settings?.phone || '', + website: settings?.website || '', + taxRegime: settings?.taxRegime || '', + fiscalPosition: settings?.fiscalPosition || '', + address: settings?.address || '', + city: settings?.city || '', + state: settings?.state || '', + country: settings?.country || '', + zipCode: settings?.zipCode || '', + }, + }); + + const handleFormSubmit = async (data: SettingsFormData) => { + const cleanData: CompanySettings = {}; + if (data.email) cleanData.email = data.email; + if (data.phone) cleanData.phone = data.phone; + if (data.website) cleanData.website = data.website; + if (data.taxRegime) cleanData.taxRegime = data.taxRegime; + if (data.fiscalPosition) cleanData.fiscalPosition = data.fiscalPosition; + if (data.address) cleanData.address = data.address; + if (data.city) cleanData.city = data.city; + if (data.state) cleanData.state = data.state; + if (data.country) cleanData.country = data.country; + if (data.zipCode) cleanData.zipCode = data.zipCode; + await onSubmit(cleanData); + }; + + return ( +
+ {/* Contact Info */} +
+

Informacion de contacto

+ +
+ + + + + + + +
+ + + + +
+ + {/* Fiscal Info */} +
+

Informacion fiscal

+ +
+ + + + + + + +
+
+ + {/* Address */} +
+

Direccion

+ + + + + +
+ + + + + + + + + + + + + + + +
+
+ +
+ + +
+
+ ); +} diff --git a/src/features/companies/components/index.ts b/src/features/companies/components/index.ts index 3574a1e..8129e18 100644 --- a/src/features/companies/components/index.ts +++ b/src/features/companies/components/index.ts @@ -1,2 +1,4 @@ export * from './CompanyForm'; export * from './CompanyFiltersPanel'; +export * from './CompanySettingsForm'; +export * from './BranchesList'; diff --git a/src/features/companies/hooks/index.ts b/src/features/companies/hooks/index.ts index af6025f..f09918c 100644 --- a/src/features/companies/hooks/index.ts +++ b/src/features/companies/hooks/index.ts @@ -1 +1,3 @@ export * from './useCompanies'; +export * from './useCompanySettings'; +export * from './useCompanyBranches'; diff --git a/src/features/companies/hooks/useCompanyBranches.ts b/src/features/companies/hooks/useCompanyBranches.ts new file mode 100644 index 0000000..a0ec311 --- /dev/null +++ b/src/features/companies/hooks/useCompanyBranches.ts @@ -0,0 +1,20 @@ +import { useQuery } from '@tanstack/react-query'; +import { companiesApi } from '../api'; +import type { BranchesResponse } from '../types'; + +const QUERY_KEY = 'companies'; + +// ==================== Company Branches Hook ==================== + +export function useCompanyBranches(companyId: string | null | undefined) { + return useQuery({ + queryKey: [QUERY_KEY, 'branches', companyId], + queryFn: () => companiesApi.getBranches(companyId as string), + enabled: !!companyId, + staleTime: 1000 * 60 * 5, // 5 minutes + select: (response: BranchesResponse) => ({ + branches: response.data, + total: response.total, + }), + }); +} diff --git a/src/features/companies/hooks/useCompanySettings.ts b/src/features/companies/hooks/useCompanySettings.ts new file mode 100644 index 0000000..431612f --- /dev/null +++ b/src/features/companies/hooks/useCompanySettings.ts @@ -0,0 +1,38 @@ +import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; +import { companiesApi } from '../api'; +import type { CompanySettings } from '../types'; + +const QUERY_KEY = 'companies'; + +// ==================== Company Settings Hook ==================== + +export function useCompanySettings(companyId: string | null | undefined) { + return useQuery({ + queryKey: [QUERY_KEY, 'settings', companyId], + queryFn: () => companiesApi.getSettings(companyId as string), + enabled: !!companyId, + staleTime: 1000 * 60 * 5, // 5 minutes + }); +} + +// ==================== Company Settings Mutations Hook ==================== + +export function useCompanySettingsMutations() { + const queryClient = useQueryClient(); + + const updateMutation = useMutation({ + mutationFn: ({ companyId, settings }: { companyId: string; settings: CompanySettings }) => + companiesApi.updateSettings(companyId, settings), + onSuccess: (_: unknown, variables: { companyId: string; settings: CompanySettings }) => { + queryClient.invalidateQueries({ queryKey: [QUERY_KEY] }); + queryClient.invalidateQueries({ queryKey: [QUERY_KEY, 'settings', variables.companyId] }); + queryClient.invalidateQueries({ queryKey: [QUERY_KEY, 'detail', variables.companyId] }); + }, + }); + + return { + updateSettings: updateMutation.mutateAsync, + isUpdating: updateMutation.isPending, + updateError: updateMutation.error, + }; +} diff --git a/src/features/companies/types/company.types.ts b/src/features/companies/types/company.types.ts index e18dc2f..d9f5dda 100644 --- a/src/features/companies/types/company.types.ts +++ b/src/features/companies/types/company.types.ts @@ -67,3 +67,49 @@ export interface CompaniesResponse { totalPages: number; }; } + +// Branch types for company branches listing +export type BranchType = 'headquarters' | 'regional' | 'store' | 'warehouse' | 'office' | 'factory'; + +export interface Branch { + id: string; + tenantId: string; + parentId?: string | null; + code: string; + name: string; + shortName?: string | null; + branchType: BranchType; + phone?: string | null; + email?: string | null; + managerId?: string | null; + addressLine1?: string | null; + addressLine2?: string | null; + city?: string | null; + state?: string | null; + postalCode?: string | null; + country: string; + latitude?: number | null; + longitude?: number | null; + geofenceRadius: number; + geofenceEnabled: boolean; + timezone: string; + currency: string; + isActive: boolean; + isMain: boolean; + operatingHours: Record; + settings: { + allowPos?: boolean; + allowWarehouse?: boolean; + allowCheckIn?: boolean; + [key: string]: unknown; + }; + hierarchyPath?: string | null; + hierarchyLevel: number; + createdAt: string; + updatedAt: string; +} + +export interface BranchesResponse { + data: Branch[]; + total: number; +} diff --git a/src/features/partners/api/addresses.api.ts b/src/features/partners/api/addresses.api.ts new file mode 100644 index 0000000..0851fda --- /dev/null +++ b/src/features/partners/api/addresses.api.ts @@ -0,0 +1,67 @@ +import { api } from '@services/api/axios-instance'; +import type { + PartnerAddress, + CreatePartnerAddressDto, + UpdatePartnerAddressDto, +} from '../types'; + +const BASE_URL = '/api/v1/partners'; + +interface AddressesResponse { + data: PartnerAddress[]; +} + +interface AddressResponse { + data: PartnerAddress; +} + +export const addressesApi = { + /** + * Get all addresses for a partner + */ + getByPartnerId: async (partnerId: string): Promise => { + const response = await api.get(`${BASE_URL}/${partnerId}/addresses`); + return response.data.data || []; + }, + + /** + * Create a new address for a partner + */ + create: async (partnerId: string, data: CreatePartnerAddressDto): Promise => { + const response = await api.post(`${BASE_URL}/${partnerId}/addresses`, data); + return response.data.data; + }, + + /** + * Update an address + */ + update: async ( + partnerId: string, + addressId: string, + data: UpdatePartnerAddressDto + ): Promise => { + const response = await api.patch( + `${BASE_URL}/${partnerId}/addresses/${addressId}`, + data + ); + return response.data.data; + }, + + /** + * Delete an address + */ + delete: async (partnerId: string, addressId: string): Promise => { + await api.delete(`${BASE_URL}/${partnerId}/addresses/${addressId}`); + }, + + /** + * Set an address as default + */ + setDefault: async (partnerId: string, addressId: string): Promise => { + const response = await api.patch( + `${BASE_URL}/${partnerId}/addresses/${addressId}`, + { isDefault: true } + ); + return response.data.data; + }, +}; diff --git a/src/features/partners/api/bankAccounts.api.ts b/src/features/partners/api/bankAccounts.api.ts new file mode 100644 index 0000000..df3cee5 --- /dev/null +++ b/src/features/partners/api/bankAccounts.api.ts @@ -0,0 +1,83 @@ +import { api } from '@services/api/axios-instance'; +import type { + PartnerBankAccount, + CreatePartnerBankAccountDto, + UpdatePartnerBankAccountDto, +} from '../types'; + +const BASE_URL = '/api/v1/partners'; + +interface BankAccountsResponse { + data: PartnerBankAccount[]; +} + +interface BankAccountResponse { + data: PartnerBankAccount; +} + +export const bankAccountsApi = { + /** + * Get all bank accounts for a partner + */ + getByPartnerId: async (partnerId: string): Promise => { + const response = await api.get(`${BASE_URL}/${partnerId}/bank-accounts`); + return response.data.data || []; + }, + + /** + * Create a new bank account for a partner + */ + create: async ( + partnerId: string, + data: CreatePartnerBankAccountDto + ): Promise => { + const response = await api.post( + `${BASE_URL}/${partnerId}/bank-accounts`, + data + ); + return response.data.data; + }, + + /** + * Update a bank account + */ + update: async ( + partnerId: string, + accountId: string, + data: UpdatePartnerBankAccountDto + ): Promise => { + const response = await api.patch( + `${BASE_URL}/${partnerId}/bank-accounts/${accountId}`, + data + ); + return response.data.data; + }, + + /** + * Delete a bank account + */ + delete: async (partnerId: string, accountId: string): Promise => { + await api.delete(`${BASE_URL}/${partnerId}/bank-accounts/${accountId}`); + }, + + /** + * Verify a bank account + */ + verify: async (partnerId: string, accountId: string): Promise => { + const response = await api.post( + `${BASE_URL}/${partnerId}/bank-accounts/${accountId}/verify` + ); + return response.data.data; + }, + + /** + * Set a bank account as default + */ + setDefault: async (partnerId: string, accountId: string): Promise => { + const response = await api.patch( + `${BASE_URL}/${partnerId}/bank-accounts/${accountId}`, + { isDefault: true } + ); + return response.data.data; + }, +}; diff --git a/src/features/partners/api/contacts.api.ts b/src/features/partners/api/contacts.api.ts new file mode 100644 index 0000000..6c4730e --- /dev/null +++ b/src/features/partners/api/contacts.api.ts @@ -0,0 +1,67 @@ +import { api } from '@services/api/axios-instance'; +import type { + PartnerContact, + CreatePartnerContactDto, + UpdatePartnerContactDto, +} from '../types'; + +const BASE_URL = '/api/v1/partners'; + +interface ContactsResponse { + data: PartnerContact[]; +} + +interface ContactResponse { + data: PartnerContact; +} + +export const contactsApi = { + /** + * Get all contacts for a partner + */ + getByPartnerId: async (partnerId: string): Promise => { + const response = await api.get(`${BASE_URL}/${partnerId}/contacts`); + return response.data.data || []; + }, + + /** + * Create a new contact for a partner + */ + create: async (partnerId: string, data: CreatePartnerContactDto): Promise => { + const response = await api.post(`${BASE_URL}/${partnerId}/contacts`, data); + return response.data.data; + }, + + /** + * Update a contact + */ + update: async ( + partnerId: string, + contactId: string, + data: UpdatePartnerContactDto + ): Promise => { + const response = await api.patch( + `${BASE_URL}/${partnerId}/contacts/${contactId}`, + data + ); + return response.data.data; + }, + + /** + * Delete a contact + */ + delete: async (partnerId: string, contactId: string): Promise => { + await api.delete(`${BASE_URL}/${partnerId}/contacts/${contactId}`); + }, + + /** + * Set a contact as primary + */ + setPrimary: async (partnerId: string, contactId: string): Promise => { + const response = await api.patch( + `${BASE_URL}/${partnerId}/contacts/${contactId}`, + { isPrimary: true } + ); + return response.data.data; + }, +}; diff --git a/src/features/partners/api/index.ts b/src/features/partners/api/index.ts index c244957..73923c0 100644 --- a/src/features/partners/api/index.ts +++ b/src/features/partners/api/index.ts @@ -1 +1,4 @@ export * from './partners.api'; +export * from './addresses.api'; +export * from './contacts.api'; +export * from './bankAccounts.api'; diff --git a/src/features/partners/components/AddressForm.tsx b/src/features/partners/components/AddressForm.tsx new file mode 100644 index 0000000..1789341 --- /dev/null +++ b/src/features/partners/components/AddressForm.tsx @@ -0,0 +1,285 @@ +import { useForm } from 'react-hook-form'; +import { zodResolver } from '@hookform/resolvers/zod'; +import { z } from 'zod'; +import { Button } from '@components/atoms/Button'; +import { FormField } from '@components/molecules/FormField'; +import { Select } from '@components/organisms/Select'; +import type { PartnerAddress, CreatePartnerAddressDto, UpdatePartnerAddressDto, AddressType } from '../types'; + +const addressSchema = z.object({ + addressType: z.enum(['billing', 'shipping', 'both'] as const), + isDefault: z.boolean(), + label: z.string().max(100).optional(), + street: z.string().min(1, 'La calle es requerida').max(200), + exteriorNumber: z.string().max(20).optional(), + interiorNumber: z.string().max(20).optional(), + neighborhood: z.string().max(100).optional(), + city: z.string().min(1, 'La ciudad es requerida').max(100), + municipality: z.string().max(100).optional(), + state: z.string().min(1, 'El estado es requerido').max(100), + postalCode: z.string().min(1, 'El codigo postal es requerido').max(10), + country: z.string().max(3).optional(), + reference: z.string().optional(), +}); + +type FormData = z.infer; + +interface AddressFormProps { + address?: PartnerAddress; + onSubmit: (data: CreatePartnerAddressDto | UpdatePartnerAddressDto) => Promise; + onCancel: () => void; + isLoading?: boolean; +} + +const addressTypeOptions = [ + { value: 'billing', label: 'Facturacion' }, + { value: 'shipping', label: 'Envio' }, + { value: 'both', label: 'Ambos' }, +]; + +const mexicanStates = [ + { value: 'AGS', label: 'Aguascalientes' }, + { value: 'BC', label: 'Baja California' }, + { value: 'BCS', label: 'Baja California Sur' }, + { value: 'CAM', label: 'Campeche' }, + { value: 'CHIS', label: 'Chiapas' }, + { value: 'CHIH', label: 'Chihuahua' }, + { value: 'CDMX', label: 'Ciudad de Mexico' }, + { value: 'COAH', label: 'Coahuila' }, + { value: 'COL', label: 'Colima' }, + { value: 'DGO', label: 'Durango' }, + { value: 'GTO', label: 'Guanajuato' }, + { value: 'GRO', label: 'Guerrero' }, + { value: 'HGO', label: 'Hidalgo' }, + { value: 'JAL', label: 'Jalisco' }, + { value: 'MEX', label: 'Estado de Mexico' }, + { value: 'MICH', label: 'Michoacan' }, + { value: 'MOR', label: 'Morelos' }, + { value: 'NAY', label: 'Nayarit' }, + { value: 'NL', label: 'Nuevo Leon' }, + { value: 'OAX', label: 'Oaxaca' }, + { value: 'PUE', label: 'Puebla' }, + { value: 'QRO', label: 'Queretaro' }, + { value: 'QROO', label: 'Quintana Roo' }, + { value: 'SLP', label: 'San Luis Potosi' }, + { value: 'SIN', label: 'Sinaloa' }, + { value: 'SON', label: 'Sonora' }, + { value: 'TAB', label: 'Tabasco' }, + { value: 'TAMPS', label: 'Tamaulipas' }, + { value: 'TLAX', label: 'Tlaxcala' }, + { value: 'VER', label: 'Veracruz' }, + { value: 'YUC', label: 'Yucatan' }, + { value: 'ZAC', label: 'Zacatecas' }, +]; + +export function AddressForm({ address, onSubmit, onCancel, isLoading }: AddressFormProps) { + const isEditing = !!address; + + const { + register, + handleSubmit, + setValue, + watch, + formState: { errors }, + } = useForm({ + resolver: zodResolver(addressSchema), + defaultValues: address + ? { + addressType: address.addressType, + isDefault: address.isDefault, + label: address.label || '', + street: address.street, + exteriorNumber: address.exteriorNumber || '', + interiorNumber: address.interiorNumber || '', + neighborhood: address.neighborhood || '', + city: address.city, + municipality: address.municipality || '', + state: address.state, + postalCode: address.postalCode, + country: address.country || 'MEX', + reference: address.reference || '', + } + : { + addressType: 'billing' as AddressType, + isDefault: false, + label: '', + street: '', + exteriorNumber: '', + interiorNumber: '', + neighborhood: '', + city: '', + municipality: '', + state: '', + postalCode: '', + country: 'MEX', + reference: '', + }, + }); + + const selectedType = watch('addressType'); + const selectedState = watch('state'); + + const handleFormSubmit = async (data: FormData) => { + const cleanData: CreatePartnerAddressDto | UpdatePartnerAddressDto = { + addressType: data.addressType, + isDefault: data.isDefault, + street: data.street, + city: data.city, + state: data.state, + postalCode: data.postalCode, + ...(data.label && { label: data.label }), + ...(data.exteriorNumber && { exteriorNumber: data.exteriorNumber }), + ...(data.interiorNumber && { interiorNumber: data.interiorNumber }), + ...(data.neighborhood && { neighborhood: data.neighborhood }), + ...(data.municipality && { municipality: data.municipality }), + ...(data.country && { country: data.country }), + ...(data.reference && { reference: data.reference }), + }; + await onSubmit(cleanData); + }; + + return ( +
+ {/* Address Type */} +
+

Tipo de direccion

+ +
+ + + +
+ + +
+ + {/* Street Address */} +
+

Direccion

+ + + + + +
+ + + + + + + + + + + +
+
+ + {/* Location */} +
+

Ubicacion

+ +
+ + + + + + + +
+ +
+ + + +
+ + +