2025-03-05 21:11:33 -06:00

520 lines
17 KiB
JavaScript

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;