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>';
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
29
resources/views/components/card/address.blade.php
Normal file
29
resources/views/components/card/address.blade.php
Normal file
@ -0,0 +1,29 @@
|
||||
@props([
|
||||
'uid' => uniqid(),
|
||||
'paisOptions' => [],
|
||||
'estadoOptions' => [],
|
||||
'localidadOptions' => [],
|
||||
'municipioOptions' => [],
|
||||
'coloniaOptions' => [],
|
||||
])
|
||||
|
||||
<x-vuexy-admin::card.basic title="Dirección">
|
||||
<div class="address-notification"></div>
|
||||
|
||||
<div class="row">
|
||||
<x-vuexy-admin::form.select :uid="$uid" model="c_pais" label="País" parentClass="col-8" :options="$paisOptions" />
|
||||
<x-vuexy-admin::form.input :uid="$uid" model="c_codigo_postal" label="Código Postal" max="5" align="center" parentClass="col-4 if_local_address_show" />
|
||||
</div>
|
||||
|
||||
<x-vuexy-admin::form.select :uid="$uid" model="c_estado" label="Estado" :options="$estadoOptions" />
|
||||
<x-vuexy-admin::form.select :uid="$uid" model="c_localidad" label="Localidad" :options="$localidadOptions" parentClass="if_local_address_show" />
|
||||
<x-vuexy-admin::form.select :uid="$uid" model="c_municipio" label="Municipio" :options="$municipioOptions" parentClass="if_local_address_show" />
|
||||
<x-vuexy-admin::form.select :uid="$uid" model="c_colonia" label="Colonia" :options="$coloniaOptions" parentClass="if_local_address_show" />
|
||||
|
||||
<x-vuexy-admin::form.input :uid="$uid" model="direccion" label="Dirección" />
|
||||
|
||||
<div class="row">
|
||||
<x-vuexy-admin::form.input :uid="$uid" model="num_ext" label="Número exterior" parentClass="col-6" />
|
||||
<x-vuexy-admin::form.input :uid="$uid" model="num_int" label="Número interior" parentClass="col-6" />
|
||||
</div>
|
||||
</x-vuexy-admin::card.basic>
|
15
resources/views/components/card/location.blade.php
Normal file
15
resources/views/components/card/location.blade.php
Normal file
@ -0,0 +1,15 @@
|
||||
@props([
|
||||
'uid' => uniqid(),
|
||||
'mapId' => 'geo_map',
|
||||
'mapHeight' => '400px',
|
||||
'searchPlaceholder' => 'Buscar ubicación',
|
||||
])
|
||||
|
||||
<x-vuexy-admin::card.basic title="Ubicación">
|
||||
<x-vuexy-admin::form.textarea :uid="$uid" name="location_search" label="Dirección de búsqueda" :placeholder="$searchPlaceholder" rows="2" button-icon="ti ti-map-pin-search" onClickButton="clearCoordinates()" />
|
||||
<div class="row">
|
||||
<x-vuexy-admin::form.input :uid="$uid" model="lat" label="Latitud" type="number" step="0.000001" max="90" min="-90" parentClass="col-6" align="center" size="small" />
|
||||
<x-vuexy-admin::form.input :uid="$uid" model="lng" label="Longitud" type="number" step="0.000001" max="180" min="-180" parentClass="col-6" align="center" size="small" />
|
||||
</div>
|
||||
<div style="height: {{ $mapHeight }}; z-index: 1;" id="locationMap_{{ $uid }}"></div>
|
||||
</x-vuexy-admin::card.basic>
|
28
resources/views/contacts/crud.blade.php
Normal file
28
resources/views/contacts/crud.blade.php
Normal file
@ -0,0 +1,28 @@
|
||||
@extends('vuexy-admin::layouts.vuexy.layoutMaster')
|
||||
|
||||
@section('title', $contacto->name)
|
||||
|
||||
@section('vendor-style')
|
||||
@vite([
|
||||
'resources/assets/admin/vendor/libs/datatables-bs5/datatables.bootstrap5.scss',
|
||||
'resources/assets/admin/vendor/libs/datatables-responsive-bs5/responsive.bootstrap5.scss',
|
||||
'resources/assets/admin/vendor/libs/datatables-buttons-bs5/buttons.bootstrap5.scss',
|
||||
'resources/assets/admin/vendor/libs/select2/select2.scss',
|
||||
'resources/assets/admin/vendor/libs/dropzone/dropzone.scss',
|
||||
])
|
||||
@endsection
|
||||
|
||||
@section('content')
|
||||
@livewire('contact-form', ['userId' => $contacto->id])
|
||||
@endsection
|
||||
|
||||
@section('vendor-script')
|
||||
@vite([
|
||||
'resources/assets/admin/vendor/libs/moment/moment.js',
|
||||
'resources/assets/admin/vendor/libs/datatables-bs5/datatables-bootstrap5.js',
|
||||
'resources/assets/admin/vendor/libs/datatables-bs5/datatable-lang-es.js',
|
||||
'resources/assets/admin/vendor/libs/dropzone/dropzone.js',
|
||||
'resources/assets/admin/vendor/libs/select2/select2.js',
|
||||
'resources/assets/admin/vendor/libs/jquery-validation/jquery.validate.js',
|
||||
])
|
||||
@endsection
|
31
resources/views/contacts/index.blade.php
Normal file
31
resources/views/contacts/index.blade.php
Normal file
@ -0,0 +1,31 @@
|
||||
@extends('vuexy-admin::layouts.vuexy.layoutMaster')
|
||||
|
||||
@section('title', 'Contactos')
|
||||
|
||||
@section('vendor-style')
|
||||
@vite([
|
||||
'vendor/koneko/laravel-vuexy-admin/resources/assets/vendor/libs/select2/select2.scss',
|
||||
'vendor/koneko/laravel-vuexy-admin/resources/assets/vendor/libs/bootstrap-table/bootstrap-table.scss',
|
||||
'vendor/koneko/laravel-vuexy-admin/resources/assets/vendor/fonts/bootstrap-icons.scss',
|
||||
'vendor/koneko/laravel-vuexy-admin/resources/assets/vendor/libs/dropzone/dropzone.scss',
|
||||
])
|
||||
@endsection
|
||||
|
||||
@section('vendor-script')
|
||||
@vite([
|
||||
'vendor/koneko/laravel-vuexy-admin/resources/assets/vendor/libs/select2/select2.js',
|
||||
])
|
||||
@endsection
|
||||
|
||||
@push('page-script')
|
||||
@vite([
|
||||
'vendor/koneko/laravel-vuexy-admin/resources/assets/js/bootstrap-table/bootstrapTableManager.js',
|
||||
'vendor/koneko/laravel-vuexy-admin/resources/assets/js/forms/formConvasHelper.js',
|
||||
'vendor/koneko/laravel-vuexy-admin/resources/assets/vendor/libs/dropzone/dropzone.js',
|
||||
])
|
||||
@endpush
|
||||
|
||||
@section('content')
|
||||
@livewire('contact-index')
|
||||
@livewire('contact-offcanvas-form')
|
||||
@endsection
|
28
resources/views/contacts/show.blade.php
Normal file
28
resources/views/contacts/show.blade.php
Normal file
@ -0,0 +1,28 @@
|
||||
@extends('vuexy-admin::layouts.vuexy.layoutMaster')
|
||||
|
||||
@section('title', $contact->name)
|
||||
|
||||
@section('vendor-style')
|
||||
@vite([
|
||||
'resources/assets/admin/vendor/libs/datatables-bs5/datatables.bootstrap5.scss',
|
||||
'resources/assets/admin/vendor/libs/datatables-responsive-bs5/responsive.bootstrap5.scss',
|
||||
'resources/assets/admin/vendor/libs/datatables-buttons-bs5/buttons.bootstrap5.scss',
|
||||
'resources/assets/admin/vendor/libs/select2/select2.scss',
|
||||
'resources/assets/admin/vendor/libs/dropzone/dropzone.scss',
|
||||
])
|
||||
@endsection
|
||||
|
||||
@section('content')
|
||||
|
||||
@endsection
|
||||
|
||||
@section('vendor-script')
|
||||
@vite([
|
||||
'resources/assets/admin/vendor/libs/moment/moment.js',
|
||||
'resources/assets/admin/vendor/libs/datatables-bs5/datatables-bootstrap5.js',
|
||||
'resources/assets/admin/vendor/libs/datatables-bs5/datatable-lang-es.js',
|
||||
'resources/assets/admin/vendor/libs/dropzone/dropzone.js',
|
||||
'resources/assets/admin/vendor/libs/select2/select2.js',
|
||||
'resources/assets/admin/vendor/libs/jquery-validation/jquery.validate.js',
|
||||
])
|
||||
@endsection
|
28
resources/views/employees/index.blade.php
Normal file
28
resources/views/employees/index.blade.php
Normal file
@ -0,0 +1,28 @@
|
||||
@extends('vuexy-admin::layouts.vuexy.layoutMaster')
|
||||
|
||||
@section('title', 'Empleados')
|
||||
|
||||
@section('vendor-style')
|
||||
@vite([
|
||||
'vendor/koneko/laravel-vuexy-admin/resources/assets/vendor/libs/select2/select2.scss',
|
||||
'vendor/koneko/laravel-vuexy-admin/resources/assets/vendor/libs/bootstrap-table/bootstrap-table.scss',
|
||||
'vendor/koneko/laravel-vuexy-admin/resources/assets/vendor/fonts/bootstrap-icons.scss',
|
||||
])
|
||||
@endsection
|
||||
|
||||
@section('vendor-script')
|
||||
@vite([
|
||||
'vendor/koneko/laravel-vuexy-admin/resources/assets/vendor/libs/select2/select2.js',
|
||||
])
|
||||
@endsection
|
||||
|
||||
@push('page-script')
|
||||
@vite([
|
||||
'vendor/koneko/laravel-vuexy-admin/resources/assets/js/bootstrap-table/bootstrapTableManager.js',
|
||||
'vendor/koneko/laravel-vuexy-admin/resources/assets/js/forms/formConvasHelper.js',
|
||||
])
|
||||
@endpush
|
||||
|
||||
@section('content')
|
||||
@livewire('employee-index')
|
||||
@endsection
|
30
resources/views/employees/show.blade.php
Normal file
30
resources/views/employees/show.blade.php
Normal file
@ -0,0 +1,30 @@
|
||||
@extends('vuexy-admin::layouts.vuexy.layoutMaster')
|
||||
|
||||
@section('title', $contacto->name)
|
||||
|
||||
@section('vendor-style')
|
||||
@vite([
|
||||
'resources/assets/admin/vendor/libs/datatables-bs5/datatables.bootstrap5.scss',
|
||||
'resources/assets/admin/vendor/libs/datatables-responsive-bs5/responsive.bootstrap5.scss',
|
||||
'resources/assets/admin/vendor/libs/datatables-buttons-bs5/buttons.bootstrap5.scss',
|
||||
'resources/assets/admin/vendor/libs/select2/select2.scss',
|
||||
'resources/assets/admin/vendor/libs/dropzone/dropzone.scss',
|
||||
])
|
||||
@endsection
|
||||
|
||||
@section('content')
|
||||
<section class="crm-contacts-show">
|
||||
@livewire('admin.crm.contact-view', ['userId' => $contacto->id])
|
||||
</section>
|
||||
@endsection
|
||||
|
||||
@section('vendor-script')
|
||||
@vite([
|
||||
'resources/assets/admin/vendor/libs/moment/moment.js',
|
||||
'resources/assets/admin/vendor/libs/datatables-bs5/datatables-bootstrap5.js',
|
||||
'resources/assets/admin/vendor/libs/datatables-bs5/datatable-lang-es.js',
|
||||
'resources/assets/admin/vendor/libs/dropzone/dropzone.js',
|
||||
'resources/assets/admin/vendor/libs/select2/select2.js',
|
||||
'resources/assets/admin/vendor/libs/jquery-validation/jquery.validate.js',
|
||||
])
|
||||
@endsection
|
586
resources/views/livewire/contacts/contacts-index.blade copy.php
Normal file
586
resources/views/livewire/contacts/contacts-index.blade copy.php
Normal file
@ -0,0 +1,586 @@
|
||||
<section id="crm-contacts-index">
|
||||
<div class="crm-contacts-index alert-errors"></div>
|
||||
|
||||
<div wire:ignore>
|
||||
<div class="query-filters" id="toolbar">
|
||||
<div class="d-flex flex-wrap">
|
||||
<div class="pt-1 pr-2 pb-1" style="min-width: 175px; max-width: 225px">
|
||||
<button data-bs-toggle='offcanvas' data-bs-target='#offcanvasUser' class="btn btn-primary waves-effect waves-light">Agregar contacto</button>
|
||||
</div>
|
||||
<div class="accordion mr-3 mb-3" id="accordionParentFiltrado">
|
||||
<div class="card accordion-item">
|
||||
<h2 class="accordion-header" id="headingFiltrado">
|
||||
<button type="button" class="accordion-button collapsed" data-bs-toggle="collapse" data-bs-target="#accordionFiltrado" aria-expanded="false" aria-controls="accordionFiltrado">
|
||||
Filtrado
|
||||
</button>
|
||||
</h2>
|
||||
<div id="accordionFiltrado" class="accordion-collapse collapse" aria-labelledby="headingFiltrado" data-bs-parent="#accordionParentFiltrado">
|
||||
<div class="accordion-body">
|
||||
<div class="d-flex flex-wrap">
|
||||
|
||||
<div class="pr-2 pl-4">
|
||||
<div class="form-check form-check-secondary mb-0">
|
||||
<input class="form-check-input" type="checkbox" id="filter_is_prospect" checked="checked">
|
||||
<label class="form-check-label" for="filter_is_prospect">Es prospecto</label>
|
||||
</div>
|
||||
<div class="form-check form-check-secondary mb-0">
|
||||
<input class="form-check-input" type="checkbox" id="filter_is_prospect" checked="checked">
|
||||
<label class="form-check-label" for="filter_is_customer">Es cliente</label>
|
||||
</div>
|
||||
<div class="form-check form-check-secondary m-0">
|
||||
<input class="form-check-input" type="checkbox" id="filter_is_provider" checked="checked">
|
||||
<label class="form-check-label" for="filter_is_provider">Es proveedor</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pr-2 pl-4">
|
||||
<div class="form-check form-check-secondary m-0">
|
||||
<input class="form-check-input" type="checkbox" id="filter_is_user">
|
||||
<label class="form-check-label" for="filter_is_user">Es usuario</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="px-2 pt-1">
|
||||
<button class="btn btn-label-secondary waves-effect py-3 btn-refresh" disabled><i class="fa-solid fa-rotate"></i></button>
|
||||
</div>
|
||||
<div class="pr-2" style="width: 60px;">
|
||||
<a href="javascript:void(0)" class="clear-filters">Limpiar Filtrado</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<table id="bt-contacts"></table>
|
||||
</div>
|
||||
|
||||
</section>
|
||||
|
||||
@push('page-script')
|
||||
<script>
|
||||
|
||||
const store_route = '{{ route('admin.system.users.store') }}',
|
||||
route_show = '{{ route('admin.contacts.show', ['contact' => '~contact~']) }}',
|
||||
route_destroy = '{{ route('admin.contacts.destroy', ['contact' => '~contact~']) }}',
|
||||
statusList = {!! json_encode($status_list) !!},
|
||||
statusIntCatalogCss = {!! json_encode($status_list_class) !!};
|
||||
|
||||
var btt_height;
|
||||
|
||||
|
||||
// BootstrapTable Petición AJAX
|
||||
function ajaxRequest(params) {
|
||||
let url = '{{ url()->current() }}' +
|
||||
'?' +
|
||||
$.param(params.data) +
|
||||
'&' +
|
||||
$('.query-filters :input').serialize();
|
||||
|
||||
$.get(url).then(function (res) {
|
||||
params.success(res)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
// BootstrapTable Formatter
|
||||
function userAvatarFormatter(value, row, index) {
|
||||
if(row.id){
|
||||
let show_href = route_show.replace('~contacto~', row.id);
|
||||
|
||||
return [
|
||||
'<div class="d-flex justify-content-start align-items-center user-name">',
|
||||
'<div class="avatar-wrapper">',
|
||||
'<div class="avatar avatar-sm me-4">' +
|
||||
'<img src="' + row.profile_photo_url + '" alt="Avatar" class="rounded-circle">' +
|
||||
'</div>',
|
||||
'</div>',
|
||||
'<div class="d-flex flex-column">',
|
||||
'<a href="' + show_href + '" class="text-heading text-truncate"><span class="fw-medium">' + row.name + '</span></a>',
|
||||
'<small>' + row.email + '</small>',
|
||||
'</div>',
|
||||
'</div>',
|
||||
].join('')
|
||||
}
|
||||
}
|
||||
|
||||
function uidFormatter(value, row, index) {
|
||||
if(row.id){
|
||||
let show_href = route_show.replace('~contacto~', row.id);
|
||||
|
||||
return [
|
||||
'<div class="d-flex align-items-center justify-content-center">',
|
||||
'<a href="' + show_href + '" class="whitespace-nowrap" title="Ver Contacto"> ' + row.id + '</a>',
|
||||
@can('crm.contacts.update')
|
||||
'<a href="javascript:;" class="btn btn-icon btn-text-secondary waves-effect waves-light rounded-pill dropdown-toggle hide-arrow" data-bs-toggle="dropdown"><i class="ti ti-dots-vertical ti-md"></i></a>',
|
||||
'<div class="dropdown-menu dropdown-menu-end m-0">',
|
||||
'<a href="javascript:deleteRow(' + row.id + ');" class="dropdown-item delete-record">Eliminar</a>',
|
||||
'</div>',
|
||||
@endcan
|
||||
'</div>'
|
||||
].join('')
|
||||
}
|
||||
}
|
||||
|
||||
// BootstrapTable Init
|
||||
function initTable(table) {
|
||||
$(table)
|
||||
.bootstrapTable('destroy')
|
||||
.bootstrapTable({
|
||||
height: btt_height,
|
||||
locale: 'es-MX',
|
||||
ajax: "ajaxRequest",
|
||||
toolbar: "#toolbar",
|
||||
search: true,
|
||||
showColumns: true,
|
||||
showColumnsToggleAll: true,
|
||||
showExport: true,
|
||||
showFullscreen: true,
|
||||
showPaginationSwitch: true,
|
||||
showRefresh: true,
|
||||
showToggle: true,
|
||||
clickToSelect: true,
|
||||
minimumCountColumns: 4,
|
||||
fixedColumns: true,
|
||||
fixedNumber: 1,
|
||||
idField: "id",
|
||||
pagination: true,
|
||||
pageList: [10, 25, 50, 100, 500],
|
||||
sidePagination: "server",
|
||||
exportTypes: ['csv', 'txt', 'excel'],
|
||||
exportOptions: {
|
||||
fileName: 'Contactos',
|
||||
},
|
||||
sortName: 'users.id',
|
||||
sortOrder: 'desc',
|
||||
mobileResponsive: true,
|
||||
cookie: true,
|
||||
resizable: true,
|
||||
cookieIdTable:"crm-contacts-index",
|
||||
columns: [
|
||||
{
|
||||
field: 'id',
|
||||
title: 'UID',
|
||||
align: 'center',
|
||||
sortable: true,
|
||||
sortName: 'users.id',
|
||||
switchable: false,
|
||||
formatter: uidFormatter
|
||||
},
|
||||
|
||||
{
|
||||
field: 'name',
|
||||
title: 'Nombre',
|
||||
formatter: userAvatarFormatter,
|
||||
},
|
||||
{
|
||||
field: 'email',
|
||||
title: 'Correo electrónico',
|
||||
sortable: true,
|
||||
visible: false,
|
||||
},
|
||||
{
|
||||
field: 'tipo_persona',
|
||||
title: 'Tipo persona',
|
||||
visible: false,
|
||||
sortable: true,
|
||||
formatter: window.btFormatter.tipoPersona,
|
||||
},
|
||||
{
|
||||
field: 'rfc',
|
||||
title: 'RFC',
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
field: 'nombre_fiscal',
|
||||
title: 'Nombre fiscal',
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
field: 'c_regimen_fiscal',
|
||||
title: 'Regimen fiscal',
|
||||
sortable: true,
|
||||
visible: false,
|
||||
formatter: window.btFormatter.regimenFiscal,
|
||||
},
|
||||
{
|
||||
field: 'domicilio_fiscal',
|
||||
title: 'Domicilio fiscal',
|
||||
sortable: true,
|
||||
visible: false,
|
||||
},
|
||||
{
|
||||
field: 'estado',
|
||||
title: 'Estado',
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
field: 'municipio',
|
||||
title: 'Municipio',
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
field: 'localidad',
|
||||
title: 'Localidad',
|
||||
sortable: true,
|
||||
visible: false,
|
||||
},
|
||||
|
||||
{
|
||||
field: 'c_uso_cfdi',
|
||||
title: 'Uso de CFDI',
|
||||
sortable: true,
|
||||
visible: false,
|
||||
formatter: window.btFormatter.usoCfdi,
|
||||
},
|
||||
{
|
||||
field: 'cargo',
|
||||
title: 'Cargo',
|
||||
visible: false,
|
||||
sortable: true,
|
||||
},
|
||||
|
||||
|
||||
{
|
||||
field: 'is_prospect',
|
||||
title: 'Es prospecto',
|
||||
align: 'center',
|
||||
visible: false,
|
||||
sortable: true,
|
||||
formatter: window.btFormatter.check,
|
||||
},
|
||||
{
|
||||
field: 'is_customer',
|
||||
title: 'Es cliente',
|
||||
align: 'center',
|
||||
visible: false,
|
||||
sortable: true,
|
||||
formatter: window.btFormatter.check,
|
||||
},
|
||||
{
|
||||
field: 'is_provider',
|
||||
title: 'Es proveedor',
|
||||
align: 'center',
|
||||
visible: false,
|
||||
sortable: true,
|
||||
formatter: window.btFormatter.check,
|
||||
},
|
||||
{
|
||||
field: 'is_user',
|
||||
title: 'Es usuario',
|
||||
align: 'center',
|
||||
visible: false,
|
||||
sortable: true,
|
||||
formatter: window.btFormatter.check,
|
||||
},
|
||||
|
||||
{
|
||||
field: 'status',
|
||||
title: 'Estado',
|
||||
align: 'center',
|
||||
sortable: true,
|
||||
formatter: window.btFormatter.status,
|
||||
},
|
||||
{
|
||||
field: 'created_at',
|
||||
title: 'Creado ',
|
||||
align: 'center',
|
||||
sortable: true,
|
||||
visible: false,
|
||||
},
|
||||
{
|
||||
field: 'created_by_name',
|
||||
title: 'Creado por',
|
||||
align: 'center',
|
||||
sortable: true,
|
||||
visible: false,
|
||||
sortName: 'created_by_name',
|
||||
},
|
||||
{
|
||||
field: 'updated_at',
|
||||
title: 'Modificado ',
|
||||
align: 'center',
|
||||
sortable: true,
|
||||
visible: false,
|
||||
},
|
||||
]
|
||||
})
|
||||
}
|
||||
|
||||
function toggleSections() {
|
||||
const isProspect = $('#is_prospect').is(':checked');
|
||||
const isCustomer = $('#is_customer').is(':checked');
|
||||
const isProvider = $('#is_provider').is(':checked');
|
||||
const isUser = $('#is_user').is(':checked');
|
||||
|
||||
$('.div-sat').toggle(isCustomer || isProvider);
|
||||
$('.div-sat-customer').toggle(isCustomer);
|
||||
$('.div-user-auth').toggle(isCustomer || isUser);
|
||||
$('.div-roles').toggle(isUser);
|
||||
}
|
||||
|
||||
function toggleCheckboxes(status) {
|
||||
const isDisabled = status == 1;
|
||||
$('#is_prospect, #is_customer, #is_provider, #is_user').prop('disabled', isDisabled);
|
||||
}
|
||||
|
||||
|
||||
load_js_form = () => {
|
||||
$('#userForm .select2')
|
||||
.each(function() {
|
||||
var $this = $(this)
|
||||
|
||||
$this.wrap('<div class="position-relative"></div>')
|
||||
|
||||
$this.select2({
|
||||
dropdownAutoWidth: true,
|
||||
width: '100%',
|
||||
dropdownParent: $this.parent()
|
||||
});
|
||||
});
|
||||
|
||||
$("#pdf-dropzone")
|
||||
.dropzone({
|
||||
url: '{{ route('admin.contacts.extraer-datos-pdf-constancia') }}',
|
||||
paramName: "file",
|
||||
maxFiles: 1,
|
||||
acceptedFiles: '.pdf',
|
||||
headers: {
|
||||
'X-CSRF-TOKEN': '{{ csrf_token() }}'
|
||||
},
|
||||
success: function(file, response) {
|
||||
if($('#name').val().trim() == '')
|
||||
@this.set('name', response.nombre_fiscal, false);
|
||||
|
||||
@this.set('rfc', response.rfc, false);
|
||||
@this.set('nombre_fiscal', response.nombre_fiscal, false);
|
||||
|
||||
if($('#email').val().trim() == '' && response.email)
|
||||
@this.set('email', response.email, false);
|
||||
|
||||
if(response.c_regimen_fiscal)
|
||||
@this.set('c_regimen_fiscal', response.c_regimen_fiscal, false);
|
||||
|
||||
@this.set('domicilio_fiscal', response.domicilio_fiscal, false);
|
||||
|
||||
$('.pdf-dropzone-div').slideUp(200);
|
||||
},
|
||||
error: function(file, response) {
|
||||
$('.pdf-dropzone-div .error-message').html('<label class="error">' + response + '</label>');
|
||||
|
||||
this.removeAllFiles(true);
|
||||
}
|
||||
});
|
||||
|
||||
// Evento para los checkboxes
|
||||
$('#is_prospect, #is_customer, #is_provider, #is_user').on('change', toggleSections);
|
||||
|
||||
// Evento para el select de estado
|
||||
$('.div-status').on('change', 'select[name="status"]', function() {
|
||||
toggleCheckboxes($(this).val());
|
||||
});
|
||||
|
||||
|
||||
// Previo de imagenes
|
||||
document.getElementById("photo").addEventListener('change', updatePreviewImage);
|
||||
|
||||
|
||||
// Reset form
|
||||
$("#userForm")
|
||||
.on('reset', function(){
|
||||
var form = $("#userForm");
|
||||
|
||||
form.validate().resetForm();
|
||||
|
||||
setTimeout(function(){
|
||||
$('#roles').trigger('change');
|
||||
|
||||
toggleSections();
|
||||
}, 250)
|
||||
|
||||
$('#user-image').prop("src", "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7");
|
||||
|
||||
$('#userForm .alert-errors').html('');
|
||||
|
||||
$('.pdf-dropzone-div').show();
|
||||
|
||||
$("#pdf-dropzone").removeAllFiles(true);
|
||||
});
|
||||
|
||||
|
||||
$("#userForm")
|
||||
.validate({
|
||||
errorClass: 'error',
|
||||
highlight: function(element, errorClass, validClass) {
|
||||
// Agrega la clase de error a la fila (contenedor del campo)
|
||||
$(element).closest('.mb-3').addClass('has-error');
|
||||
},
|
||||
unhighlight: function(element, errorClass, validClass) {
|
||||
// Elimina la clase de error de la fila (contenedor del campo)
|
||||
$(element).closest('.mb-3').removeClass('has-error');
|
||||
},
|
||||
errorPlacement: function(error, element) {
|
||||
// Controla dónde se colocan los mensajes de error
|
||||
error.appendTo(element.closest('.mb-3').find('.error-message'));
|
||||
},
|
||||
rules: {
|
||||
name: {
|
||||
required: true,
|
||||
minlength: 5
|
||||
},
|
||||
email: {
|
||||
required: true,
|
||||
email: true
|
||||
},
|
||||
password: {
|
||||
required: function(element) {
|
||||
return !$("#userForm input[name=id]").val() && ($('#is_user').is(':checked') || $('#is_customer').is(':checked'));
|
||||
},
|
||||
minlength: 6
|
||||
}
|
||||
},
|
||||
messages: {
|
||||
name: {
|
||||
required: "Por favor ingrese su nombre completo",
|
||||
minlength: "El nombre completo debe tener al menos 8 caracteres"
|
||||
},
|
||||
email: {
|
||||
required: "Por favor ingrese su correo electrónico",
|
||||
email: "El valor no es una dirección de correo válida"
|
||||
},
|
||||
password: {
|
||||
required: "La contraseña es obligatoria para nuevos usuarios",
|
||||
minlength: "La contraseña debe tener al menos 6 caracteres"
|
||||
}
|
||||
},
|
||||
submitHandler: function(form, event) {
|
||||
// Evita que el formulario se envíe automáticamente
|
||||
event.preventDefault();
|
||||
|
||||
var form = $("#userForm")[0],
|
||||
data = new FormData(form);
|
||||
|
||||
$('#userForm :input').prop('disabled', true);
|
||||
$('#userForm .alert-errors').html('');
|
||||
|
||||
$.ajax({
|
||||
url: store_route,
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
|
||||
},
|
||||
data: data,
|
||||
contentType: false,
|
||||
processData: false,
|
||||
cache: false,
|
||||
timeout: 3000,
|
||||
success: function(data) {
|
||||
$('#userForm :input').prop('disabled', false);
|
||||
|
||||
if (data.errors) {
|
||||
$('#userForm .alert-errors').html('<div class="alert alert-danger alert-dismissible fade show" role="alert">' +
|
||||
'<div class="alert-body">' + data.errors + '</div>' +
|
||||
'<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>' +
|
||||
'</div>');
|
||||
|
||||
} else {
|
||||
let $usersIndexAlert = $('.crm-contacts-index.alert-errors');
|
||||
|
||||
$usersIndexAlert.html('<div class="alert alert-success alert-dismissible fade show" role="alert">' +
|
||||
'<div class="alert-body">' +
|
||||
'<p class="mb-0"><strong>' + data.success + '</strong></p>' +
|
||||
'</div>' +
|
||||
'<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>' +
|
||||
'</div>');
|
||||
|
||||
$('#userForm button[type=reset]').trigger('click');
|
||||
$('#toolbar .clear-filters').trigger('click');
|
||||
}
|
||||
},
|
||||
error: function(e) {
|
||||
$('#userForm :input').prop('disabled', false);
|
||||
|
||||
$('#userForm .alert-errors').html('<div class="alert alert-danger alert-dismissible fade show" role="alert">' +
|
||||
'<div class="alert-body">' + e.responseJSON.message + '</div>' +
|
||||
'<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>' +
|
||||
'</div>');
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// Inicializar el estado al cargar la página
|
||||
toggleSections();
|
||||
toggleCheckboxes($('select[name="status"]').val());
|
||||
}
|
||||
|
||||
// Previo de imagen de perfil
|
||||
updatePreviewImage = (event) => {
|
||||
var file = event.target.files[0],
|
||||
reader = new FileReader();
|
||||
|
||||
reader.onload = event => {
|
||||
document.getElementById('user-image').setAttribute('src', event.target.result);
|
||||
};
|
||||
|
||||
reader.readAsDataURL(file);
|
||||
}
|
||||
|
||||
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
$(document).ready(function() {
|
||||
var $table = $('#bt-contacts'),
|
||||
$btnRefresh = $('#toolbar .btn-refresh'),
|
||||
$clearFilters = $('a.clear-filters');
|
||||
|
||||
var btt_rest_height = 220,
|
||||
btt_min_height = 600;
|
||||
|
||||
btt_height = (window.innerHeight - btt_rest_height) < btt_min_height?
|
||||
btt_height:
|
||||
window.innerHeight - btt_rest_height;
|
||||
|
||||
var offcanvasElement = document.getElementById('offcanvasUser'),
|
||||
offcanvasUser = new bootstrap.Offcanvas(offcanvasElement);
|
||||
|
||||
const refreshButton = document.querySelector('.btn-refresh');
|
||||
const inputs = document.querySelectorAll('#toolbar input, #toolbar select');
|
||||
|
||||
inputs.forEach(input => {
|
||||
input.addEventListener('change', () => {
|
||||
refreshButton.disabled = false;
|
||||
refreshButton.classList.remove('btn-label-secondary');
|
||||
refreshButton.classList.add('btn-label-success');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
// Button Refresh
|
||||
$btnRefresh
|
||||
.on('click', () => {
|
||||
$table.bootstrapTable('refresh');
|
||||
refreshButton.disabled = true;
|
||||
refreshButton.classList.remove('btn-label-success');
|
||||
refreshButton.classList.add('btn-label-secondary');
|
||||
});
|
||||
|
||||
// Button clear filters
|
||||
$clearFilters
|
||||
.on('click', () => {
|
||||
$table.bootstrapTable('resetSearch', ''); // Inicializa la búsqueda con cadena vacía
|
||||
refreshButton.disabled = true;
|
||||
refreshButton.classList.remove('btn-label-success');
|
||||
refreshButton.classList.add('btn-label-secondary');
|
||||
});
|
||||
|
||||
|
||||
initTable('#bt-contacts'); // Una vez que todos los scripts estén cargados, inicializa Bootstrap Table
|
||||
|
||||
|
||||
load_js_form();
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@endpush
|
165
resources/views/livewire/contacts/form.blade.php
Normal file
165
resources/views/livewire/contacts/form.blade.php
Normal file
@ -0,0 +1,165 @@
|
||||
<div>
|
||||
<x-vuexy-admin::form id="{{ $formId }}" :mode="$mode" wireSubmit="onSubmit" actionPosition="both">
|
||||
<x-slot name="actions">
|
||||
<x-vuexy-admin::button.offcanvas-buttons :mode="$mode" :tagName="$tagName" />
|
||||
</x-slot>
|
||||
<div class="row">
|
||||
<div class="col-lg-4">
|
||||
{{-- Identificación --}}
|
||||
<x-vuexy-admin::card.basic title="Identificación">
|
||||
<x-vuexy-admin::form.input :uid="$uniqueId" model="code" label="Identificador único" icon="ti ti-tag" placeholder="UID code" autofocus autocomplete="off" />
|
||||
<x-vuexy-admin::form.input :uid="$uniqueId" model="name" label="Nombre de la sucursal" autocomplete="organization" />
|
||||
<x-vuexy-admin::form.textarea :uid="$uniqueId" model="description" label="Descripción" placeholder="Descripción de la sucursal" :autosize=true />
|
||||
</x-vuexy-admin::card.basic>
|
||||
|
||||
{{-- Series de facturación --}}
|
||||
<x-vuexy-admin::card.basic title="Series de facturación">
|
||||
<x-vuexy-admin::form.input :uid="$uniqueId" model="serie_ingresos" label="Serie para Ingresos" inline=true :labelCol=6 :inputCol=6 maxlength="5" autocomplete="off" />
|
||||
<x-vuexy-admin::form.input :uid="$uniqueId" model="serie_egresos" label="Serie para Egresos" inline=true :labelCol=6 :inputCol=6 maxlength="5" autocomplete="off" />
|
||||
<x-vuexy-admin::form.input :uid="$uniqueId" model="serie_pagos" label="Serie para Pagos" inline=true :labelCol=6 :inputCol=6 maxlength="5" autocomplete="off" />
|
||||
</x-vuexy-admin::card.basic>
|
||||
|
||||
{{-- Configuraciones --}}
|
||||
<x-vuexy-admin::card.basic title="Configuraciones">
|
||||
<x-vuexy-admin::form.checkbox uid="random" model="status" label="Habilitar sucursal" switch="true" />
|
||||
<x-vuexy-admin::form.checkbox uid="random" model="show_on_website" label="Mostrar en sitio web" switch="true" />
|
||||
<x-vuexy-admin::form.checkbox uid="random" model="enable_ecommerce" label="eCommerce habilitado en sitio Web" switch="true" />
|
||||
</x-vuexy-admin::card.basic>
|
||||
</div>
|
||||
<div class="col-lg-4">
|
||||
{{-- Información de contacto --}}
|
||||
<x-vuexy-admin::card.basic title="Información de contacto">
|
||||
<x-vuexy-admin::form.input type="tel" :uid="$uniqueId" model="tel" label="Teléfono" icon="ti ti-phone" phoneMode="national" />
|
||||
<x-vuexy-admin::form.input type="tel" :uid="$uniqueId" model="tel2" label="Teléfono alternativo" icon="ti ti-phone" phoneMode="both" />
|
||||
<x-vuexy-admin::form.input type="email" :uid="$uniqueId" model="email" label="Correo electrónico" icon="ti ti-mail" autocomplete="email" inputmode="email" />
|
||||
<x-vuexy-admin::form.select :uid="$uniqueId" model="manager_id" label="Gerente" :options="$manager_id_options" placeholder="Selecciona el gerente" />
|
||||
</x-vuexy-admin::card.basic>
|
||||
|
||||
{{-- Información fiscal --}}
|
||||
<x-vuexy-admin::card.basic title="Información fiscal">
|
||||
<x-vuexy-admin::form.input :uid="$uniqueId" model="rfc" label="RFC" autocomplete="off" pattern="^[A-Z&Ñ]{3,4}[0-9]{6}[A-Z0-9]{3}$" maxlength="13" />
|
||||
<x-vuexy-admin::form.input :uid="$uniqueId" model="nombre_fiscal" label="Nombre fiscal" autocomplete="organization" />
|
||||
<x-vuexy-admin::form.select :uid="$uniqueId" model="c_regimen_fiscal" label="Régimen fiscal" :options="$c_regimen_fiscal_options" placeholder="Selecciona el régimen fiscal" />
|
||||
<x-vuexy-admin::form.input :uid="$uniqueId" model="domicilio_fiscal" label="Domicilio fiscal" autocomplete="address-line1" maxlength="100" />
|
||||
</x-vuexy-admin::card.basic>
|
||||
</div>
|
||||
<div class="col-lg-4">
|
||||
{{-- Dirección --}}
|
||||
<x-vuexy-contacts::card.address :uid="$uniqueId" :paisOptions="$c_pais_options" :estadoOptions="$c_estado_options" :localidadOptions="$c_localidad_options" :municipioOptions="$c_municipio_options" :coloniaOptions="$c_colonia_options"/>
|
||||
|
||||
{{-- Ubicación --}}
|
||||
<x-vuexy-contacts::card.location :uid="$uniqueId" />
|
||||
</div>
|
||||
</div>
|
||||
</x-vuexy-admin::form>
|
||||
</div>
|
||||
|
||||
@push('page-script')
|
||||
<script>
|
||||
const initializeStoreForm = (mode) => {
|
||||
const initializeContactInformation = () => {
|
||||
let $manager_id = $("#manager_id_{{ $uniqueId }}");
|
||||
|
||||
$manager_id
|
||||
.select2({
|
||||
language: "es",
|
||||
placeholder: "Selecciona el gerente",
|
||||
allowClear: true,
|
||||
width: "100%"
|
||||
})
|
||||
.on('select2:select select2:clear', function (e) {
|
||||
@this.manager_id = e.params?.data?.id || null;
|
||||
});
|
||||
}
|
||||
|
||||
const initializeFiscalInformation = () => {
|
||||
let $c_regimen_fiscal = $("#c_regimen_fiscal_{{ $uniqueId }}");
|
||||
|
||||
$c_regimen_fiscal
|
||||
.select2({
|
||||
language: "es",
|
||||
placeholder: "Selecciona el regimen fiscal",
|
||||
allowClear: true,
|
||||
width: "100%"
|
||||
})
|
||||
.on('select2:select select2:clear', function (e) {
|
||||
@this.c_regimen_fiscal = e.params?.data?.id || null;
|
||||
});
|
||||
}
|
||||
|
||||
const initializeLocationIQ = () => {
|
||||
//
|
||||
}
|
||||
|
||||
const initializeAddressFormHandler = () => {
|
||||
const csrfToken = document.querySelector('meta[name="csrf-token"]').getAttribute('content');
|
||||
|
||||
// Definición de selectores AddressFormHandler
|
||||
formSelectors = {
|
||||
c_pais: '#c_pais_{{ $uniqueId }}',
|
||||
c_estado: '#c_estado_{{ $uniqueId }}',
|
||||
c_localidad: '#c_localidad_{{ $uniqueId }}',
|
||||
c_municipio: '#c_municipio_{{ $uniqueId }}',
|
||||
c_colonia: '#c_colonia_{{ $uniqueId }}',
|
||||
c_codigo_postal: '#c_codigo_postal_{{ $uniqueId }}',
|
||||
direccion: '#direccion_{{ $uniqueId }}',
|
||||
notification: '#{{ $formId }} .address-notification'
|
||||
};
|
||||
|
||||
// Definición de rutas AJAX Componente AddressFormHandler
|
||||
const ajaxRoutes = {
|
||||
codigo_postal: "{{ route('admin.core.sat.get.ajax', 'codigo_postal') }}",
|
||||
localidad: "{{ route('admin.core.sat.get.ajax', 'localidad') }}",
|
||||
estado: "{{ route('admin.core.sat.get.ajax', 'estado') }}",
|
||||
municipio: "{{ route('admin.core.sat.get.ajax', 'municipio') }}",
|
||||
colonia: "{{ route('admin.core.sat.get.ajax', 'colonia') }}"
|
||||
};
|
||||
|
||||
// Inicializamos el handler de la información de la dirección
|
||||
new AddressFormHandler(formSelectors, ajaxRoutes, @this, csrfToken);
|
||||
}
|
||||
|
||||
const initializeLocationCard = (mode) => {
|
||||
const locationInputs = {
|
||||
search: '#location_search_{{ $uniqueId }}',
|
||||
btnSearch: '#btn_search_{{ $uniqueId }}',
|
||||
lat: '#lat_{{ $uniqueId }}',
|
||||
lng: '#lng_{{ $uniqueId }}',
|
||||
btnClear: '#{{ $formId }} .btn-clear-coords',
|
||||
mapId: 'locationMap_{{ $uniqueId }}',
|
||||
}
|
||||
|
||||
leafletMap = LeafletMapHelper.initializeMap(locationInputs, mode, @this);
|
||||
}
|
||||
|
||||
|
||||
// Inicializamos Tarjeta de Información de contacto
|
||||
initializeContactInformation();
|
||||
|
||||
// Inicializamos Tarjeta de Información fiscal
|
||||
initializeFiscalInformation();
|
||||
|
||||
// Inicializamos Tarjeta de Dirección
|
||||
initializeAddressFormHandler();
|
||||
|
||||
// Inicializamos Tarjeta de Ubicación
|
||||
initializeLocationCard(mode);
|
||||
|
||||
// Deshabilitamos el formulario si estamos eliminando
|
||||
if (mode === 'delete') {
|
||||
window.disableStoreForm('#{{ $formId }}');
|
||||
}
|
||||
}
|
||||
|
||||
// Evento para inicializar el formulario
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
document.addEventListener('on-failed-validation-store', (event) => {
|
||||
setTimeout(() => {
|
||||
initializeStoreForm('{{ $mode }}');
|
||||
}, 10);
|
||||
});
|
||||
|
||||
initializeStoreForm('{{ $mode }}');
|
||||
});
|
||||
</script>
|
||||
@endpush
|
57
resources/views/livewire/contacts/index.blade.php
Normal file
57
resources/views/livewire/contacts/index.blade.php
Normal file
@ -0,0 +1,57 @@
|
||||
<x-vuexy-admin::table.bootstrap.manager :tagName="$tagName" :datatableConfig="$bt_datatable" :routes="$routes">
|
||||
<x-slot name="tools">
|
||||
<div class="mb-4 pr-2">
|
||||
<x-vuexy-admin::button.index-off-canvas :label="$singularName" :tagName="$tagName" />
|
||||
</div>
|
||||
</x-slot>
|
||||
<x-slot name="postTools">
|
||||
<div class="mb-4 pr-2">
|
||||
<x-vuexy-admin::file.dropzone id="user_doc_file" model="user_doc_file" message="Crear nuevo usuario" note="XML CFDI o PDF CSF" size="xs" />
|
||||
</div>
|
||||
</x-slot>
|
||||
</x-vuexy-admin::table.bootstrap.manager>
|
||||
|
||||
@push('page-script')
|
||||
<script>
|
||||
// Evento para inicializar el formulario cuando se carga la página
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
let dropzone = new Dropzone("#dropzone_user_doc_file", {
|
||||
url: "#",
|
||||
autoProcessQueue: false,
|
||||
acceptedFiles: ".pdf,.xml",
|
||||
maxFiles: 1,
|
||||
addRemoveLinks: true,
|
||||
dictDefaultMessage: "Arrastra aquí tu PDF de Constancia de Situación Fiscal",
|
||||
init: function () {
|
||||
this.on("addedfile", function (file) {
|
||||
let reader = new FileReader();
|
||||
reader.onload = function () {
|
||||
let input = document.querySelector("#user_doc_file");
|
||||
let dataTransfer = new DataTransfer();
|
||||
|
||||
dataTransfer.items.add(new File([file], file.name, { type: file.type }));
|
||||
|
||||
// Asignamos solo un archivo, no un FileList
|
||||
//input.files = dataTransfer.files;
|
||||
|
||||
// Livewire solo recibe archivos en forma de input, no como FileList
|
||||
@this.upload('doc_file', dataTransfer.files[0],
|
||||
(uploadedFile) => {
|
||||
@this.call('processDocument');
|
||||
},
|
||||
(error) => {
|
||||
console.error("Error al subir PDF:", error);
|
||||
},
|
||||
(progressEvent) => {
|
||||
console.log("Progreso de subida:", progressEvent);
|
||||
}
|
||||
);
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
</script>
|
||||
@endpush
|
94
resources/views/livewire/contacts/offcanvas-form.blade.php
Normal file
94
resources/views/livewire/contacts/offcanvas-form.blade.php
Normal file
@ -0,0 +1,94 @@
|
||||
<div>
|
||||
<x-vuexy-admin::offcanvas.basic :id="$offcanvasId" :tag-name="$tagName">
|
||||
{{-- Dropzone Constancia de Situación Fiscal --}}
|
||||
<x-vuexy-admin::file.dropzone :uid="$uniqueId" model="doc_file" message="CSF PDF o CFDI XML" note="Arrastra aquí un PDF de Constancia de Situación Fiscal o XML de CFDI para cargar los datos al fomulario" />
|
||||
|
||||
<x-vuexy-admin::form :uid="$uniqueId" :id="$formId" :mode="$mode" wireSubmit="onSubmit" actionPosition="both">
|
||||
<x-slot name="actions">
|
||||
<x-vuexy-admin::button.offcanvas-buttons :mode="$mode" :tagName="$tagName" />
|
||||
</x-slot>
|
||||
|
||||
{{-- Selección de Sucursal --}}
|
||||
<x-vuexy-admin::form.input :uid="$uniqueId" model="name" label="Nombre(s)" />
|
||||
<x-vuexy-admin::form.input :uid="$uniqueId" model="last_name" label="Apellidos" />
|
||||
|
||||
<hr>
|
||||
|
||||
<div class="row">
|
||||
<x-vuexy-admin::form.input :uid="$uniqueId" model="code" label="Código de usuario" icon="ti ti-tag" parent-class="col-md-8" autocomplete="off" />
|
||||
</div>
|
||||
|
||||
{{-- Teléfonos y Correos --}}
|
||||
<x-vuexy-admin::form.input type="email" :uid="$uniqueId" model="email" label="Correo electrónico" icon="ti ti-mail" autocomplete="email" inputmode="email" />
|
||||
<x-vuexy-admin::form.input type="tel" :uid="$uniqueId" model="tel" label="Teléfono" icon="ti ti-phone" phoneMode="both" />
|
||||
|
||||
<hr>
|
||||
|
||||
<x-vuexy-admin::form.textarea :uid="$uniqueId" model="notes" label="Notas / Observaciones" />
|
||||
|
||||
<hr>
|
||||
|
||||
{{-- Estado del Centro de Trabajo --}}
|
||||
<x-vuexy-admin::form.checkbox :uid="$uniqueId" model="is_partner" label="Es socio" switch />
|
||||
<x-vuexy-admin::form.checkbox :uid="$uniqueId" model="is_employee" label="Es empleado" switch />
|
||||
<x-vuexy-admin::form.checkbox :uid="$uniqueId" model="is_prospect" label="Es prospecto" switch />
|
||||
<x-vuexy-admin::form.checkbox :uid="$uniqueId" model="is_customer" label="Es cliente" switch />
|
||||
<x-vuexy-admin::form.checkbox :uid="$uniqueId" model="is_provider" label="Es proveedor" switch />
|
||||
|
||||
<hr>
|
||||
|
||||
</x-vuexy-admin::form>
|
||||
</x-vuexy-admin::offcanvas.basic>
|
||||
</div>
|
||||
|
||||
@push('page-script')
|
||||
<script>
|
||||
// Evento para inicializar el formulario cuando se carga la página
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
const initializeUserForm = () => {
|
||||
let dropzone = new Dropzone("#dropzone_doc_file_{{ $uniqueId }}", {
|
||||
url: "#",
|
||||
autoProcessQueue: false,
|
||||
acceptedFiles: ".pdf,.xml",
|
||||
maxFiles: 1,
|
||||
addRemoveLinks: true,
|
||||
dictDefaultMessage: "Arrastra aquí tu PDF de Constancia de Situación Fiscal",
|
||||
init: function () {
|
||||
this.on("addedfile", function (file) {
|
||||
let reader = new FileReader();
|
||||
reader.onload = function () {
|
||||
let input = document.querySelector("#doc_file_{{ $uniqueId }}");
|
||||
let dataTransfer = new DataTransfer();
|
||||
|
||||
dataTransfer.items.add(new File([file], file.name, { type: file.type }));
|
||||
|
||||
// Asignamos solo un archivo, no un FileList
|
||||
//input.files = dataTransfer.files;
|
||||
|
||||
// Livewire solo recibe archivos en forma de input, no como FileList
|
||||
@this.upload('doc_file', dataTransfer.files[0],
|
||||
(uploadedFile) => {
|
||||
@this.call('processDocument');
|
||||
},
|
||||
(error) => {
|
||||
console.error("Error al subir PDF:", error);
|
||||
},
|
||||
(progressEvent) => {
|
||||
console.log("Progreso de subida:", progressEvent);
|
||||
}
|
||||
);
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
var myOffcanvas = document.getElementById('{{ $offcanvasId }}');
|
||||
myOffcanvas.addEventListener('show.bs.offcanvas', function () {
|
||||
initializeUserForm();
|
||||
});
|
||||
});
|
||||
|
||||
</script>
|
||||
@endpush
|
1685
resources/views/livewire/contacts/show.blade.php
Normal file
1685
resources/views/livewire/contacts/show.blade.php
Normal file
File diff suppressed because it is too large
Load Diff
28
resources/views/suppliers/index.blade.php
Normal file
28
resources/views/suppliers/index.blade.php
Normal file
@ -0,0 +1,28 @@
|
||||
@extends('vuexy-admin::layouts.vuexy.layoutMaster')
|
||||
|
||||
@section('title', 'Proveedores')
|
||||
|
||||
@section('vendor-style')
|
||||
@vite([
|
||||
'vendor/koneko/laravel-vuexy-admin/resources/assets/vendor/libs/select2/select2.scss',
|
||||
'vendor/koneko/laravel-vuexy-admin/resources/assets/vendor/libs/bootstrap-table/bootstrap-table.scss',
|
||||
'vendor/koneko/laravel-vuexy-admin/resources/assets/vendor/fonts/bootstrap-icons.scss',
|
||||
])
|
||||
@endsection
|
||||
|
||||
@section('vendor-script')
|
||||
@vite([
|
||||
'vendor/koneko/laravel-vuexy-admin/resources/assets/vendor/libs/select2/select2.js',
|
||||
])
|
||||
@endsection
|
||||
|
||||
@push('page-script')
|
||||
@vite([
|
||||
'vendor/koneko/laravel-vuexy-admin/resources/assets/js/bootstrap-table/bootstrapTableManager.js',
|
||||
'vendor/koneko/laravel-vuexy-admin/resources/assets/js/forms/formConvasHelper.js',
|
||||
])
|
||||
@endpush
|
||||
|
||||
@section('content')
|
||||
@livewire('supplier-index')
|
||||
@endsection
|
27
resources/views/suppliers/show.blade.php
Normal file
27
resources/views/suppliers/show.blade.php
Normal file
@ -0,0 +1,27 @@
|
||||
@extends('vuexy-admin::layouts.vuexy.layoutMaster')
|
||||
|
||||
@section('title', $contacto->name)
|
||||
|
||||
@section('vendor-style')
|
||||
@vite([
|
||||
'resources/assets/admin/vendor/libs/select2/select2.scss',
|
||||
'resources/assets/admin/vendor/libs/dropzone/dropzone.scss',
|
||||
])
|
||||
@endsection
|
||||
|
||||
@section('content')
|
||||
<section class="crm-contacts-show">
|
||||
@livewire('admin.crm.contact-view', ['userId' => $contacto->id])
|
||||
</section>
|
||||
@endsection
|
||||
|
||||
@section('vendor-script')
|
||||
@vite([
|
||||
'resources/assets/admin/vendor/libs/moment/moment.js',
|
||||
'resources/assets/admin/vendor/libs/datatables-bs5/datatables-bootstrap5.js',
|
||||
'resources/assets/admin/vendor/libs/datatables-bs5/datatable-lang-es.js',
|
||||
'resources/assets/admin/vendor/libs/dropzone/dropzone.js',
|
||||
'resources/assets/admin/vendor/libs/select2/select2.js',
|
||||
'resources/assets/admin/vendor/libs/jquery-validation/jquery.validate.js',
|
||||
])
|
||||
@endsection
|
Reference in New Issue
Block a user