export default class AddressFormHandler { constructor(formSelectors, ajaxRoutes, livewireInstance, csrfToken) { if (!ajaxRoutes && !ajaxRoutes.estado) { throw new Error("ajax AddressFormHandler routes not found"); } this.formSelectors = formSelectors; this.ajaxRoutes = ajaxRoutes; this.livewireInstance = livewireInstance; // Livewire Instance this.csrfToken = csrfToken; this.placeholders = { pais: 'Selecciona el país', estado: 'Selecciona el estado', localidad: 'Selecciona la localidad', municipio: 'Selecciona el municipio', colonia: 'Selecciona la colonia', codigo_postal: 'Ingresa el código postal', } this.synchronizedZipCode = false; this.initializeSelects(); this.initializeZipCodeInput(); this.loadDefaultValuesFromLivewire(); } initializeSelects() { const { c_codigo_postal, c_pais, c_estado, c_localidad, c_municipio, c_colonia } = this.formSelectors; // País $(c_pais) .select2({ language: "es", placeholder: this.placeholders.pais, allowClear: true, width: "100%" }) .on('select2:select', (e) => this.onCountrySelect(e)) .on('select2:clear', () => { this.resetFieldWithDependencies('c_pais'); }); // Estado $(c_estado) .select2({ language: "es", placeholder: this.placeholders.estado, allowClear: true, width: "100%" }) .on('select2:select', (e) => this.onStateSelect(e)) .on('select2:clear', () => { this.resetFieldWithDependencies('c_estado'); }); // Localidad $(c_localidad) .select2({ language: "es", placeholder: this.placeholders.localidad, allowClear: true, width: "100%" }) .on('select2:select', (e) => this.onLocalitySelect(e)) .on('select2:clear', () => { this.resetFieldWithDependencies('c_localidad'); }); // Municipio $(c_municipio) .select2({ ajax: { url: this.ajaxRoutes['municipio'], type: "post", delay: 250, dataType: 'json', data: (params) => ({ _token: this.csrfToken, select2Mode: true, searchTerm: params.term, c_estado: $(c_estado).val(), }), processResults: (response) => ({ results: response }), cache: true }, language: "es", placeholder: this.placeholders.municipio, allowClear: true, width: "100%" }) .on('select2:select', (e) => this.onMunicipalitySelect(e)) .on('select2:clear', () => { this.resetFieldWithDependencies('c_municipio'); }); // Colonia $(c_colonia) .select2({ ajax: { url: this.ajaxRoutes['colonia'], type: "post", delay: 250, dataType: 'json', data: (params) => ({ _token: this.csrfToken, select2Mode: true, searchTerm: params.term, c_codigo_postal: $(c_codigo_postal).val(), c_estado: $(c_estado).val(), c_municipio: $(c_municipio).val(), }), processResults: (response) => ({ results: response }), cache: true }, language: "es", placeholder: this.placeholders.colonia, allowClear: true, width: "100%" }) .on('select2:select', (e) => this.onColoniaSelect(e)) .on('select2:clear', () => { this.livewireInstance.set('c_colonia', null, false); }); } initializeZipCodeInput() { const { c_codigo_postal } = this.formSelectors; let lastPostalCode = ''; // Para evitar solicitudes duplicadas let debounceTimeout; $(c_codigo_postal).on('input', () => { const postalCode = $(c_codigo_postal).val(); clearTimeout(debounceTimeout); // Cancelar el temporizador anterior this.synchronizedZipCode = false; debounceTimeout = setTimeout(() => { if (postalCode.length === 5 && postalCode !== lastPostalCode) { lastPostalCode = postalCode; this.fetchZipCode(postalCode); } }, 300); // Ejecutar después de 300 ms de inactividad }); } async fetchZipCode(postalCode) { try { const response = await this.makeAjaxPost(this.ajaxRoutes.codigo_postal, { _token: this.csrfToken, searchTerm: postalCode, firstRow: true, rawMode: true }); // Realizar solicitud AJAX para obtener datos del código postal if (response.c_codigo_postal) { // Limpiamos Interface this.resetFieldWithDependencies('c_codigo_postal', response.c_codigo_postal); // Cargamos Estados this.toggleSelector('c_estado', response.c_estado); // Cargar localidades this.fillSelectOptions('c_localidad', {[response.c_localidad]: response.localidad }, response.c_localidad); // Cargar municipios this.fillSelectOptions('c_municipio', {[response.c_municipio]: response.municipio}, response.c_municipio); // Abrir select de colonia this.openSelect2('c_colonia'); // Marcar como sincronizado el código postal this.synchronizedZipCode = true; } else { const { notification } = this.formSelectors; // Emitir una notificación simple desde JavaScript window.livewireNotification.emitNotification({ message: `Código postal ${postalCode} no encontrado.`, type: 'warning', target: notification, }); } } catch (error) { console.error("Error al obtener datos del código postal:", error); } } onCountrySelect(event) { const countryCode = event.params.data.id; // Limpiamos Interface this.resetFieldWithDependencies('c_pais', countryCode); // Cargamos Interface de estados this.fetchStates(countryCode); } async fetchStates(countryCode) { try { const response = await this.makeAjaxPost(this.ajaxRoutes.estado, { _token: this.csrfToken, c_pais: countryCode }); // Realizamos solicitud AJAX para obtener datos de los estados if (response) { const { c_codigo_postal } = this.formSelectors; // Cargar los estados this.fillSelectOptions('c_estado', response); // Ocultar y resetear los campos si no es México if (countryCode === 'MEX') { $('.if_local_address_show').show(); // Colocar el foco en el código postal $(c_codigo_postal).focus(); } else { $('.if_local_address_show').hide(); // Abrir select de estado this.openSelect2('c_estado'); } } } catch (error) { console.error("Error al cargar los estados:", error); } } onStateSelect(event) { const { c_pais, direccion } = this.formSelectors; const stateId = event.params.data.id; // Limpiar Interface this.resetFieldWithDependencies('c_estado', stateId); // Si es México if($(c_pais).val() == 'MEX'){ // Cargar localidades this.fetchLocalities(stateId); }else{ // Colocar el foco en la dirección $(direccion).focus(); } } async fetchLocalities(stateId) { try { const response = await this.makeAjaxPost(this.ajaxRoutes.localidad, { _token: this.csrfToken, c_estado: stateId, limit: null, }); if (response) { const { c_localidad } = this.formSelectors; // Cargar localidades this.fillSelectOptions('c_localidad', response, c_localidad); // Abrir select de localidad this.openSelect2('c_localidad'); } } catch (error) { console.error("Error al cargar las localidades:", error); } } onLocalitySelect(event) { const locationId = event.params.data.id; // Limpiar Interface this.resetFieldWithDependencies('c_localidad', locationId); // Abrir select de municipio this.openSelect2('c_municipio'); } onMunicipalitySelect(event) { const municipalityId = event.params.data.id; // Limpiar Interface this.resetFieldWithDependencies('c_municipio', municipalityId); // Habilitamos colonias this.toggleSelector('c_colonia'); // Abrir select colonia this.openSelect2('c_colonia'); } onColoniaSelect(event) { const coloniaId = event.params.data.id; // Cargar colonia this.fillSelectOptions('c_colonia', {[coloniaId]: event.params.data.text}, coloniaId); // Actualizar código postal si no está sincronizado if(!this.synchronizedZipCode){ this.fetchZipCodeByData(this.livewireInstance.c_estado, this.livewireInstance.c_municipio, coloniaId); } } async fetchZipCodeByData(stateId, municipalityId, coloniaId) { try { const response = await this.makeAjaxPost(this.ajaxRoutes.colonia, { _token: this.csrfToken, c_estado: stateId, c_municipio: municipalityId, c_colonia: coloniaId, firstRow: true, rawMode: true, }); if (response) { const { c_codigo_postal, direccion } = this.formSelectors; // Actualizar código postal si no está sincronizado if($(c_codigo_postal).val() !== response.c_codigo_postal){ $(c_codigo_postal).val(response.c_codigo_postal); // Actualizar en Livewire this.livewireInstance.set('c_codigo_postal', response.c_codigo_postal, false); } // Marcar como sincronizado el código postal this.synchronizedZipCode = true; // Abrir select colonia $(direccion).focus(); } } catch (error) { console.error("Error al cargar las localidades:", error); } } fillSelectOptions(selector, data, selected) { const placeholder = this.placeholders[selector] || 'Selecciona una opción'; const $selector = $(this.formSelectors[selector]); // Actualizar las opciones directamente en Livewire this.livewireInstance.set(`${selector}_options`, data, false); // Limpiar y agregar las nuevas opciones al selector $selector.empty().append(new Option(placeholder, '', true, true)); // Agregar el placeholder // Agregar opciones obtenidas por AJAX if (typeof data === 'object' && Object.keys(data).length > 0) { $.each(data, (id, value) => { $selector.append(new Option(value, id, false, id == selected)); }); } // Actualizar el valor seleccionado si corresponde if (selected) { this.livewireInstance.set(selector, selected, false); $selector.val(selected).trigger('change.select2'); } // Habilitar el select $selector.prop('disabled', false).trigger('change.select2'); } toggleSelector(selector, selected = null) { const $selector = $(this.formSelectors[selector]); if(typeof selected === 'number' || typeof selected === 'string'){ this.livewireInstance.set(selector, selected, false); $selector .val(selected) .trigger('change.select2'); } $selector.prop('disabled', !(selected || $selector.val())).trigger('change.select2'); } resetFieldWithDependencies(field, value = null) { const dependencies = { c_codigo_postal: ['c_localidad', 'c_municipio', 'c_colonia'], c_pais: ['c_codigo_postal', 'c_estado', 'c_localidad', 'c_municipio', 'c_colonia'], c_estado: ['c_codigo_postal', 'c_localidad', 'c_municipio', 'c_colonia'], c_localidad: ['c_codigo_postal', 'c_municipio', 'c_colonia'], c_municipio: ['c_codigo_postal', 'c_colonia'] }; const resetFields = (fields) => { fields.forEach((key) => { const field = this.formSelectors[key]; // Obtener el selector por clave const placeholder = this.placeholders[key] || 'Selecciona una opción'; const $field = $(field); // Limpiar valor en Livewire if (this.livewireInstance[key] !== null) { this.livewireInstance.set(key, null, false); } if ($field.is('select')) { // Resetear select $field.empty() .append(new Option(placeholder, '', true, true)) .prop('disabled', true) .trigger('change.select2'); // Actualizar select2 } else if ($field.is('input[type="text"]') || $field.is('input[type="number"]')) { // Resetear input de texto o número $field.val(''); } else { console.warn(`El campo ${field} no es un input ni un select válido.`); } }); }; // Limpieza de campos dependientes if (dependencies[field]) { resetFields(dependencies[field]); } // Actualizar el valor del campo principal en Livewire this.livewireInstance.set(field, value, false); } openSelect2(selector) { const $selector = $(this.formSelectors[selector]); $selector.prop('disabled', false).trigger('change.select2'); setTimeout(() => $selector.select2('open'), 100); } async makeAjaxPost(url, data) { try { const response = await $.post(url, { ...data, _token: this.csrfToken }); return response; } catch (error) { console.error(`Error al realizar la solicitud AJAX a ${url}:`, error); window.livewireNotification.emitNotification({ message: `Error al intentar realizar la solicitud.`, target: this.formSelectors.notification, type: 'danger', }); return null; // Devuelve null en caso de error para evitar llamadas infinitas } } loadDefaultValuesFromLivewire() { const { c_pais, c_estado, c_localidad, c_municipio, c_colonia, c_codigo_postal } = this.livewireInstance; const { c_pais: paisSelector, c_estado: estadoSelector, c_localidad: localidadSelector, c_municipio: municipioSelector, c_colonia: coloniaSelector, c_codigo_postal: codigoPostalSelector } = this.formSelectors; // Cargar país por defecto if (c_pais && $(paisSelector).val() !== c_pais) { $(paisSelector).val(c_pais).trigger('change.select2'); } // Cargar estados por defecto si están disponibles if (c_estado && $(estadoSelector).val() !== c_estado) { $(estadoSelector).val(c_estado).trigger('change.select2'); } // Si el país es México, mostrar campos de dirección if (c_pais === 'MEX') { $('.if_local_address_show').show(); if (c_localidad && $(localidadSelector).val() !== c_localidad) { $(localidadSelector).val(c_localidad).trigger('change.select2'); } if (c_municipio && $(municipioSelector).val() !== c_municipio) { $(municipioSelector).val(c_municipio).trigger('change.select2'); } if (c_colonia && $(coloniaSelector).val() !== c_colonia) { $(coloniaSelector).val(c_colonia).trigger('change.select2'); } if (c_codigo_postal && $(codigoPostalSelector).val() !== c_codigo_postal) { $(codigoPostalSelector).val(c_codigo_postal); } } else { $('.if_local_address_show').hide(); } } } window.AddressFormHandler = AddressFormHandler;