first commit
This commit is contained in:
519
resources/assets/js/addresses/AddressFormHandler.js
Normal file
519
resources/assets/js/addresses/AddressFormHandler.js
Normal file
@ -0,0 +1,519 @@
|
||||
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;
|
93
resources/assets/js/bootstrap-table/contactsFormatters.js
Normal file
93
resources/assets/js/bootstrap-table/contactsFormatters.js
Normal file
@ -0,0 +1,93 @@
|
||||
import {routes} from '../../../../../laravel-vuexy-admin/resources/assets/js/bootstrap-table/globalConfig.js';
|
||||
|
||||
|
||||
|
||||
export const contactActionFormatter = (value, row, index) => {
|
||||
if (!row.id) return '';
|
||||
|
||||
const showUrl = routes['admin.contact.show'].replace(':id', row.id);
|
||||
const editUrl = routes['admin.contact.edit'].replace(':id', row.id);
|
||||
const deleteUrl = routes['admin.contact.delete'].replace(':id', row.id);
|
||||
|
||||
return `
|
||||
<div class="flex space-x-2">
|
||||
<a href="${editUrl}" title="Editar" class="icon-button">
|
||||
<i class="ti ti-edit"></i>
|
||||
</a>
|
||||
<a href="${deleteUrl}" title="Eliminar" class="icon-button">
|
||||
<i class="ti ti-trash"></i>
|
||||
</a>
|
||||
<a href="${showUrl}" title="Ver" class="icon-button">
|
||||
<i class="ti ti-eye"></i>
|
||||
</a>
|
||||
</div>
|
||||
`.trim();
|
||||
};
|
||||
|
||||
export const agentFormatter = (value, row, index) => {
|
||||
if (!row.agent_name) return '';
|
||||
|
||||
const email = row.agent_email || 'Sin correo';
|
||||
const userUrl = routes['admin.user.show'].replace(':id', row.id);
|
||||
|
||||
return `
|
||||
<div class="flex flex-col">
|
||||
<a href="${userUrl}" class="font-medium text-slate-600 hover:underline block text-wrap">${row.agent_name}</a>
|
||||
<small class="text-muted">${email}</small>
|
||||
</div>
|
||||
`;
|
||||
};
|
||||
|
||||
export const contactParentFormatter = (value, row, index) => {
|
||||
if (!row.parent_name) return '';
|
||||
|
||||
const email = row.parent_email || 'Sin correo';
|
||||
const showUrl = routes['admin.contact.show'].replace(':id', row.id);
|
||||
|
||||
return `
|
||||
<div class="flex flex-col">
|
||||
<a href="${showUrl}" class="font-medium text-slate-600 hover:underline block text-wrap">${row.parent_name}</a>
|
||||
<small class="text-muted">${email}</small>
|
||||
</div>
|
||||
`;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
export const emailFormatter = (value, row, index) => {
|
||||
if (!value) return '';
|
||||
return `
|
||||
<a href="mailto:${value}" class="flex items-center space-x-2 text-blue-600 hover:underline">
|
||||
<i class="fa-solid fa-envelope"></i>
|
||||
<span>${value}</span>
|
||||
</a>
|
||||
`;
|
||||
};
|
||||
|
||||
export const telFormatter = (value, row, index) => {
|
||||
if (!value) return '';
|
||||
return `
|
||||
<a href="tel:${value}" class="flex items-center space-x-2 text-green-600 hover:underline">
|
||||
<i class="fa-solid fa-phone"></i>
|
||||
<span class="whitespace-nowrap">${value}</span>
|
||||
</a>
|
||||
`;
|
||||
};
|
||||
|
||||
export const direccionFormatter = (value, row, index) => {
|
||||
let direccion = row.direccion ? row.direccion.trim() : '';
|
||||
let numExt = row.num_ext ? ` #${row.num_ext}` : '';
|
||||
let numInt = row.num_int ? `, Int. ${row.num_int}` : '';
|
||||
|
||||
let fullAddress = `${direccion}${numExt}${numInt}`.trim();
|
||||
|
||||
return fullAddress ? `<span class="whitespace-nowrap">${fullAddress}</span>` : '<span class="text-muted">Sin dirección</span>';
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user