Laravel 11, Vuexy Admin 10.3, by admin@koneko.mx
This commit is contained in:
247
modules/Admin/Resources/js/_class/FormCustomListener.js
Normal file
247
modules/Admin/Resources/js/_class/FormCustomListener.js
Normal file
@ -0,0 +1,247 @@
|
||||
export default class FormCustomListener {
|
||||
constructor(config = {}) {
|
||||
const defaultConfig = {
|
||||
formSelector: '.form-custom-listener', // Selector para formularios
|
||||
buttonSelectors: [], // Selectores específicos para botones
|
||||
callbacks: [], // Callbacks correspondientes a los botones específicos
|
||||
allowedInputTags: ['INPUT', 'SELECT', 'TEXTAREA'], // Tags permitidos para cambios
|
||||
validationConfig: null, // Nueva propiedad para la configuración de validación
|
||||
dispatchOnSubmit: null // Callback Livewire para disparar al enviar el formulario
|
||||
};
|
||||
|
||||
this.config = { ...defaultConfig, ...config };
|
||||
|
||||
// Aseguramos que los métodos que dependen de `this` estén vinculados al contexto correcto
|
||||
this.defaultButtonHandler = this.defaultButtonHandler.bind(this);
|
||||
this.formValidationInstance = null;
|
||||
|
||||
this.initForms();
|
||||
}
|
||||
|
||||
/**
|
||||
* Inicializa los formularios encontrados en el DOM.
|
||||
*/
|
||||
initForms() {
|
||||
const forms = document.querySelectorAll(this.config.formSelector);
|
||||
|
||||
if (forms.length === 0) {
|
||||
console.error(`No se encontraron formularios con el selector ${this.config.formSelector}.`);
|
||||
return;
|
||||
}
|
||||
|
||||
forms.forEach(form => {
|
||||
if (form.dataset.initialized === 'true') {
|
||||
console.warn(`Formulario ya inicializado: ${form}`);
|
||||
return;
|
||||
}
|
||||
|
||||
this.initFormEvents(form);
|
||||
|
||||
// Si se pasó configuración de validación, inicialízala
|
||||
if (this.config.validationConfig) {
|
||||
this.initializeValidation(form);
|
||||
}
|
||||
|
||||
form.dataset.initialized = 'true'; // Marcar formulario como inicializado
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Configura los eventos para un formulario individual.
|
||||
* @param {HTMLElement} form - El formulario que será manejado.
|
||||
*/
|
||||
initFormEvents(form) {
|
||||
const buttons = this.getButtons(form);
|
||||
|
||||
buttons.forEach(({ button, callback }, index) => {
|
||||
if (button) {
|
||||
button.addEventListener('click', () => {
|
||||
this.handleButtonClick(index, form, buttons, callback);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
form.addEventListener('input', event =>
|
||||
this.handleInputChange(
|
||||
event,
|
||||
form,
|
||||
buttons.map(b => b.button)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtiene los botones y sus callbacks según la configuración.
|
||||
* @param {HTMLElement} form - El formulario del cual obtener botones.
|
||||
* @returns {Array} Array de objetos con { button, callback }.
|
||||
*/
|
||||
getButtons(form) {
|
||||
const buttons = [];
|
||||
|
||||
this.config.buttonSelectors.forEach((selector, index) => {
|
||||
const buttonList = Array.from(form.querySelectorAll(selector));
|
||||
const callback = this.config.callbacks[index];
|
||||
|
||||
buttonList.forEach(button => {
|
||||
buttons.push({ button, callback });
|
||||
});
|
||||
});
|
||||
|
||||
return buttons;
|
||||
}
|
||||
|
||||
/**
|
||||
* Maneja los cambios en los campos de entrada.
|
||||
* @param {Event} event - El evento del cambio.
|
||||
* @param {HTMLElement} form - El formulario actual.
|
||||
* @param {HTMLElement[]} buttons - Array de botones en el formulario.
|
||||
*/
|
||||
handleInputChange(event, form, buttons) {
|
||||
const target = event.target;
|
||||
|
||||
if (['INPUT', 'SELECT', 'TEXTAREA'].includes(target.tagName)) {
|
||||
this.toggleButtonsState(buttons, true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Maneja el clic en un botón específico.
|
||||
* @param {number} index - Índice del botón.
|
||||
* @param {HTMLElement} form - El formulario actual.
|
||||
* @param {Array} buttons - Array de objetos { button, callback }.
|
||||
* @param {function|null} callback - Callback definido para el botón.
|
||||
*/
|
||||
handleButtonClick(index, form, buttons, callback) {
|
||||
if (typeof callback === 'function') {
|
||||
callback(
|
||||
form,
|
||||
buttons[index].button,
|
||||
buttons.map(b => b.button)
|
||||
);
|
||||
} else {
|
||||
this.defaultButtonHandler(
|
||||
form,
|
||||
buttons[index].button,
|
||||
buttons.map(b => b.button)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Maneja la acción cuando el formulario es válido.
|
||||
* Este método puede ser sobreescrito para personalizar el comportamiento.
|
||||
*/
|
||||
handleFormValid(form) {
|
||||
console.log('Formulario válido');
|
||||
|
||||
// Ejecutar callback opcional (si lo proporcionaste)
|
||||
if (typeof this.config.handleValidForm === 'function') {
|
||||
this.config.handleValidForm(form);
|
||||
} else if (this.config.dispatchOnSubmit) {
|
||||
this.handleValidForm(form);
|
||||
} else {
|
||||
form.submit();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Método que maneja la acción cuando el formulario es válido.
|
||||
* Al ser un método de la clase, no necesitamos usar bind.
|
||||
*/
|
||||
handleValidForm(form) {
|
||||
const saveButton = form.querySelector('#save_website_button');
|
||||
const allButtons = Array.from(form.querySelectorAll('.btn'));
|
||||
|
||||
this.toggleButtonsState(allButtons, false); // Deshabilitar todos los botones
|
||||
this.toggleFormFields(form, false); // Deshabilitar todos los campos del formulario
|
||||
this.setButtonLoadingState(saveButton, true); // Poner en estado de carga al botón anfitrión
|
||||
|
||||
// Enviar la solicitud de Livewire correspondiente al enviar el formulario
|
||||
Livewire.dispatch(this.config.dispatchOnSubmit);
|
||||
}
|
||||
|
||||
/**
|
||||
* Manejador por defecto para los botones.
|
||||
* @param {HTMLElement} form - El formulario actual.
|
||||
* @param {HTMLElement} hostButton - El botón anfitrión que disparó el evento.
|
||||
* @param {HTMLElement[]} allButtons - Todos los botones relevantes del formulario.
|
||||
*/
|
||||
defaultButtonHandler(form, hostButton, allButtons) {
|
||||
this.toggleButtonsState(allButtons, false); // Deshabilitar todos los botones
|
||||
this.toggleFormFields(form, false); // Deshabilitar todos los campos del formulario
|
||||
this.setButtonLoadingState(hostButton, true); // Poner en estado de carga al botón anfitrión
|
||||
}
|
||||
|
||||
/**
|
||||
* Deshabilita o habilita los campos del formulario.
|
||||
* @param {HTMLElement} form - El formulario actual.
|
||||
* @param {boolean} isEnabled - Si los campos deben habilitarse.
|
||||
*/
|
||||
toggleFormFields(form, isEnabled) {
|
||||
form.querySelectorAll('input, select, textarea').forEach(field => {
|
||||
field.disabled = !isEnabled;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Habilita o deshabilita los botones.
|
||||
* @param {HTMLElement[]} buttons - Array de botones.
|
||||
* @param {boolean} isEnabled - Si los botones deben habilitarse.
|
||||
*/
|
||||
toggleButtonsState(buttons, isEnabled) {
|
||||
buttons.forEach(button => {
|
||||
if (button) button.disabled = !isEnabled;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Cambia el estado de carga de un botón.
|
||||
* @param {HTMLElement} button - Botón que se manejará.
|
||||
* @param {boolean} isLoading - Si el botón está en estado de carga.
|
||||
*/
|
||||
setButtonLoadingState(button, isLoading) {
|
||||
if (!button) return;
|
||||
|
||||
const loadingText = button.getAttribute('data-loading-text');
|
||||
if (loadingText && isLoading) {
|
||||
button.setAttribute('data-original-text', button.innerHTML);
|
||||
button.innerHTML = loadingText;
|
||||
button.disabled = true;
|
||||
} else if (!isLoading) {
|
||||
button.innerHTML = button.getAttribute('data-original-text') || button.innerHTML;
|
||||
button.disabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Inicializa la validación del formulario con la configuración proporcionada.
|
||||
* @param {HTMLElement} form - El formulario que va a ser validado.
|
||||
*/
|
||||
initializeValidation(form) {
|
||||
if (this.config.validationConfig) {
|
||||
this.formValidationInstance = FormValidation.formValidation(form, this.config.validationConfig).on(
|
||||
'core.form.valid',
|
||||
() => this.handleFormValid(form)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
reloadValidation() {
|
||||
const form = document.querySelector(this.config.formSelector);
|
||||
|
||||
// Verificar si el formulario existe y si la validación está inicializada
|
||||
if (form && this.formValidationInstance) {
|
||||
try {
|
||||
// En lugar de destruir la validación, simplemente reiniciamos la validación.
|
||||
this.formValidationInstance.resetForm(); // Resetear el formulario, limpiando los errores
|
||||
|
||||
// Reinicializar la validación con la configuración actual
|
||||
this.initializeValidation(form);
|
||||
} catch (error) {
|
||||
console.error('Error al reiniciar la validación:', error);
|
||||
}
|
||||
} else {
|
||||
console.warn('Formulario no encontrado o instancia de validación no disponible.');
|
||||
}
|
||||
}
|
||||
}
|
190
modules/Admin/Resources/js/_class/LivewireNotification.js
Normal file
190
modules/Admin/Resources/js/_class/LivewireNotification.js
Normal file
@ -0,0 +1,190 @@
|
||||
export default class LivewireNotification {
|
||||
constructor(config = {}) {
|
||||
const defaultConfig = {
|
||||
notificationTimeout: 6000, // Tiempo predeterminado para las notificaciones
|
||||
onNotificationShown: null, // Callback al mostrar una notificación
|
||||
onNotificationRemoved: null, // Callback al eliminar una notificación
|
||||
onNotificationClosed: null // Callback al cerrar una notificación mediante botón
|
||||
};
|
||||
|
||||
this.config = { ...defaultConfig, ...config };
|
||||
this.initLivewireNotification();
|
||||
}
|
||||
|
||||
/**
|
||||
* Inicializa la escucha de notificaciones desde Livewire.
|
||||
*/
|
||||
initLivewireNotification() {
|
||||
// Mostrar notificación almacenada después de la recarga
|
||||
const storedNotification = localStorage.getItem('pendingNotification');
|
||||
|
||||
if (storedNotification) {
|
||||
const event = JSON.parse(storedNotification);
|
||||
this.showStoredNotification(event);
|
||||
localStorage.removeItem('pendingNotification'); // Limpiar después de mostrar
|
||||
}
|
||||
|
||||
// Escuchar nuevas notificaciones desde Livewire
|
||||
Livewire.on('notification', event => {
|
||||
if (event.deferReload) {
|
||||
// Guardar la notificación en localStorage para mostrar después de la recarga
|
||||
localStorage.setItem('pendingNotification', JSON.stringify(event));
|
||||
|
||||
window.location.reload();
|
||||
} else {
|
||||
// Mostrar la notificación inmediatamente
|
||||
this.showNotification(event);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Método para emitir notificaciones desde JavaScript.
|
||||
* @param {Object} options - Opciones de la notificación.
|
||||
* @param {Function} callback - Callback opcional que se ejecutará después de mostrar la notificación.
|
||||
* @param {number} customTimeout - Timeout personalizado (opcional).
|
||||
*/
|
||||
emitNotification(options, callback, customTimeout) {
|
||||
const event = {
|
||||
target: options.target || 'body',
|
||||
message: options.message || 'Notificación',
|
||||
type: options.type || 'info',
|
||||
deferReload: options.deferReload || false,
|
||||
notificationTimeout: customTimeout || options.notificationTimeout || this.config.notificationTimeout // Usar el timeout personalizado o el predeterminado
|
||||
};
|
||||
|
||||
// Mostrar la notificación
|
||||
this.showNotification(event);
|
||||
|
||||
// Ejecutar callback si está definido
|
||||
if (typeof callback === 'function') {
|
||||
callback(event);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Muestra una notificación almacenada.
|
||||
* @param {Object} event - Datos del evento de notificación.
|
||||
*/
|
||||
showStoredNotification(event) {
|
||||
this.showNotification(event);
|
||||
}
|
||||
|
||||
/**
|
||||
* Muestra una notificación.
|
||||
* @param {Object} event - Datos del evento de notificación.
|
||||
*/
|
||||
showNotification(event) {
|
||||
const targetElement = document.querySelector(event.target);
|
||||
|
||||
if (!targetElement) {
|
||||
console.error(`Target ${event.target} no encontrado. Mostrando en el contenedor global.`);
|
||||
|
||||
this.showInGlobalContainer(event);
|
||||
return;
|
||||
}
|
||||
|
||||
// Crear un contenedor para notificaciones si no existe
|
||||
if (!targetElement.querySelector('.notification-container')) {
|
||||
const container = document.createElement('div');
|
||||
|
||||
container.className = 'notification-container';
|
||||
targetElement.appendChild(container);
|
||||
}
|
||||
|
||||
const notificationContainer = targetElement.querySelector('.notification-container');
|
||||
const notificationElement = this.renderNotification(notificationContainer, event);
|
||||
|
||||
// Callback opcional al mostrar la notificación
|
||||
if (typeof this.config.onNotificationShown === 'function') {
|
||||
this.config.onNotificationShown(notificationElement, event);
|
||||
}
|
||||
|
||||
// Configurar el timeout para eliminar la notificación
|
||||
this.setNotificationTimeout(notificationElement, event);
|
||||
|
||||
// Configurar el evento para el botón de cierre
|
||||
this.setupCloseButton(notificationElement, event);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renderiza una notificación en el contenedor global (body).
|
||||
* @param {Object} event - Datos del evento de notificación.
|
||||
*/
|
||||
showInGlobalContainer(event) {
|
||||
const globalContainer = document.body;
|
||||
if (!globalContainer.querySelector('.notification-container')) {
|
||||
const container = document.createElement('div');
|
||||
|
||||
container.className = 'notification-container';
|
||||
globalContainer.appendChild(container);
|
||||
}
|
||||
|
||||
const notificationContainer = globalContainer.querySelector('.notification-container');
|
||||
const notificationElement = this.renderNotification(notificationContainer, event);
|
||||
|
||||
if (typeof this.config.onNotificationShown === 'function') {
|
||||
this.config.onNotificationShown(notificationElement, event);
|
||||
}
|
||||
|
||||
this.setNotificationTimeout(notificationElement, event);
|
||||
this.setupCloseButton(notificationElement, event);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renderiza una notificación en el contenedor.
|
||||
* @param {HTMLElement} container - Contenedor de notificaciones.
|
||||
* @param {Object} event - Evento de notificación con tipo y mensaje.
|
||||
* @returns {HTMLElement} - Elemento de la notificación recién creada.
|
||||
*/
|
||||
renderNotification(container, event) {
|
||||
const notificationElement = document.createElement('div');
|
||||
|
||||
notificationElement.className = `alert alert-${event.type} alert-dismissible fade show`;
|
||||
notificationElement.role = 'alert';
|
||||
notificationElement.innerHTML = `${event.message} <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>`;
|
||||
|
||||
container.appendChild(notificationElement);
|
||||
|
||||
return notificationElement;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configura un timeout para limpiar una notificación específica.
|
||||
* @param {HTMLElement} notificationElement - Elemento de la notificación.
|
||||
* @param {Object} event - Evento asociado a la notificación.
|
||||
*/
|
||||
setNotificationTimeout(notificationElement, event) {
|
||||
const timeout = event.notificationTimeout || this.config.notificationTimeout;
|
||||
|
||||
setTimeout(() => {
|
||||
if (notificationElement && notificationElement.parentElement) {
|
||||
notificationElement.remove();
|
||||
|
||||
// Callback opcional al eliminar la notificación
|
||||
if (typeof this.config.onNotificationRemoved === 'function') {
|
||||
this.config.onNotificationRemoved(notificationElement, event);
|
||||
}
|
||||
}
|
||||
}, timeout);
|
||||
}
|
||||
|
||||
/**
|
||||
* Configura el cierre manual de una notificación mediante el botón "Cerrar".
|
||||
* @param {HTMLElement} notificationElement - Elemento de la notificación.
|
||||
* @param {Object} event - Evento asociado a la notificación.
|
||||
*/
|
||||
setupCloseButton(notificationElement, event) {
|
||||
const closeButton = notificationElement.querySelector('.btn-close');
|
||||
if (closeButton) {
|
||||
closeButton.addEventListener('click', () => {
|
||||
notificationElement.remove();
|
||||
|
||||
// Callback opcional al cerrar la notificación manualmente
|
||||
if (typeof this.config.onNotificationClosed === 'function') {
|
||||
this.config.onNotificationClosed(notificationElement, event);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
220
modules/Admin/Resources/js/_class/SenderResponseForm.js
Normal file
220
modules/Admin/Resources/js/_class/SenderResponseForm.js
Normal file
@ -0,0 +1,220 @@
|
||||
export default class SenderResponseForm {
|
||||
constructor(config = {}) {
|
||||
const defaultConfig = {
|
||||
formSenderResponseId: 'mail-sender-response-settings-card',
|
||||
replyToMethodId: 'reply_to_method',
|
||||
saveSenderResponseButtonId: 'save_sender_response_button',
|
||||
cancelButtonId: 'cancel_sender_response_button'
|
||||
};
|
||||
|
||||
this.config = { ...defaultConfig, ...config };
|
||||
this.formSenderResponse = null;
|
||||
this.smtpReplyToMethod = null;
|
||||
this.saveButton = null;
|
||||
this.cancelButton = null;
|
||||
|
||||
this.init(); // Inicializa el formulario
|
||||
}
|
||||
|
||||
// Método para inicializar el formulario
|
||||
init() {
|
||||
try {
|
||||
// Obtener elementos esenciales
|
||||
this.formSenderResponse = document.getElementById(this.config.formSenderResponseId);
|
||||
this.smtpReplyToMethod = document.getElementById(this.config.replyToMethodId);
|
||||
this.saveButton = document.getElementById(this.config.saveSenderResponseButtonId);
|
||||
this.cancelButton = document.getElementById(this.config.cancelButtonId);
|
||||
|
||||
// Asignar eventos
|
||||
this.formSenderResponse.addEventListener('input', event => this.handleInput(event));
|
||||
this.smtpReplyToMethod.addEventListener('change', () => this.handleToggleReplyToMethod());
|
||||
this.cancelButton.addEventListener('click', () => this.handleCancel());
|
||||
|
||||
// Inicializar validación del formulario
|
||||
this.initializeFormValidation(this.formSenderResponse, this.senderResponsValidateConfig, () => {
|
||||
this.handleFormValid();
|
||||
});
|
||||
|
||||
// Disparar el evento 'change' en el método de respuesta
|
||||
setTimeout(() => this.smtpReplyToMethod.dispatchEvent(new Event('change')), 0);
|
||||
} catch (error) {
|
||||
console.error('Error al inicializar el formulario de respuesta:', error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Método de recarga parcial
|
||||
* Este método restablece la validación y los eventos sin destruir la instancia.
|
||||
*/
|
||||
reload() {
|
||||
try {
|
||||
// Vuelve a inicializar la validación del formulario
|
||||
this.initializeFormValidation(this.formSenderResponse, this.senderResponsValidateConfig, () => {
|
||||
this.handleFormValid();
|
||||
});
|
||||
|
||||
// Vuelve a agregar los eventos (si es necesario, depende de tu lógica)
|
||||
this.smtpReplyToMethod.dispatchEvent(new Event('change'));
|
||||
} catch (error) {
|
||||
console.error('Error al recargar el formulario:', error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Maneja el evento de entrada en el formulario.
|
||||
* @param {Event} event - Evento de entrada.
|
||||
*/
|
||||
handleInput(event) {
|
||||
const target = event.target;
|
||||
|
||||
if (['INPUT', 'SELECT', 'TEXTAREA'].includes(target.tagName)) {
|
||||
this.toggleButtonsState(this.formSenderResponse, true); // Habilitar botones
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Muestra u oculta el campo de correo personalizado según el método de respuesta seleccionado.
|
||||
* @param {HTMLElement} smtpReplyToMethod - Elemento select del método de respuesta.
|
||||
*/
|
||||
handleToggleReplyToMethod() {
|
||||
const emailCustomDiv = document.querySelector('.email-custom-div');
|
||||
|
||||
if (emailCustomDiv) {
|
||||
emailCustomDiv.style.display = Number(this.smtpReplyToMethod.value) === 3 ? 'block' : 'none';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancels the sender response form submission.
|
||||
* This method disables the form buttons, disables all form fields,
|
||||
* and sets the cancel button to a loading state.
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
handleCancel() {
|
||||
this.disableFormFields(this.formSenderResponse);
|
||||
this.toggleButtonsState(this.formSenderResponse, false);
|
||||
this.setButtonLoadingState(this.cancelButton, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inicializa la validación del formulario.
|
||||
* @param {HTMLElement} form - El formulario.
|
||||
* @param {Object} config - Configuración de validación.
|
||||
* @param {Function} onValidCallback - Callback cuando el formulario es válido.
|
||||
*/
|
||||
initializeFormValidation(form, config, onValidCallback) {
|
||||
return FormValidation.formValidation(form, config).on('core.form.valid', onValidCallback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Maneja la acción cuando el formulario es válido.
|
||||
*/
|
||||
handleFormValid() {
|
||||
this.disableFormFields(this.formSenderResponse);
|
||||
this.toggleButtonsState(this.formSenderResponse, false);
|
||||
this.setButtonLoadingState(this.saveButton, true);
|
||||
|
||||
Livewire.dispatch('saveMailSenderResponseSettings');
|
||||
}
|
||||
|
||||
/**
|
||||
* Deshabilita todos los campos del formulario.
|
||||
* @param {HTMLElement} form - El formulario.
|
||||
*/
|
||||
disableFormFields(form) {
|
||||
form.querySelectorAll('input, select, textarea').forEach(field => {
|
||||
field.disabled = true;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Habilita o deshabilita los botones dentro del formulario.
|
||||
* @param {HTMLElement} form - El formulario.
|
||||
* @param {boolean} state - Estado de habilitación.
|
||||
*/
|
||||
toggleButtonsState(form, state) {
|
||||
form.querySelectorAll('button').forEach(button => {
|
||||
button.disabled = !state;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Configura el estado de carga de un botón.
|
||||
* @param {HTMLElement} button - El botón.
|
||||
* @param {boolean} isLoading - Si el botón está en estado de carga.
|
||||
*/
|
||||
setButtonLoadingState(button, isLoading) {
|
||||
const loadingText = button.getAttribute('data-loading-text');
|
||||
|
||||
if (loadingText && isLoading) {
|
||||
button.innerHTML = loadingText;
|
||||
} else {
|
||||
button.innerHTML = button.getAttribute('data-original-text') || button.innerHTML;
|
||||
}
|
||||
}
|
||||
|
||||
senderResponsValidateConfig = {
|
||||
fields: {
|
||||
from_address: {
|
||||
validators: {
|
||||
notEmpty: {
|
||||
message: 'El correo electrónico de salida es obligatorio.'
|
||||
},
|
||||
emailAddress: {
|
||||
message: 'Por favor, introduce un correo electrónico válido.'
|
||||
}
|
||||
}
|
||||
},
|
||||
from_name: {
|
||||
validators: {
|
||||
notEmpty: {
|
||||
message: 'El nombre del remitente es obligatorio.'
|
||||
}
|
||||
}
|
||||
},
|
||||
reply_to_method: {
|
||||
validators: {
|
||||
notEmpty: {
|
||||
message: 'El método de respuesta es obligatorio.'
|
||||
}
|
||||
}
|
||||
},
|
||||
reply_to_email: {
|
||||
validators: {
|
||||
callback: {
|
||||
message: 'El correo electrónico de respuesta es obligatorio.',
|
||||
callback: function (input) {
|
||||
if (Number(document.getElementById('reply_to_method').value) === 3) {
|
||||
return input.value.trim() !== '' && /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(input.value);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
reply_to_name: {
|
||||
validators: {
|
||||
callback: {
|
||||
message: 'El nombre de respuesta es obligatorio.',
|
||||
callback: function (input) {
|
||||
if (Number(document.getElementById('reply_to_method').value) === 3) {
|
||||
return input.value.trim() !== '';
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
plugins: {
|
||||
trigger: new FormValidation.plugins.Trigger(),
|
||||
bootstrap5: new FormValidation.plugins.Bootstrap5({
|
||||
eleValidClass: '',
|
||||
rowSelector: '.fv-row'
|
||||
}),
|
||||
submitButton: new FormValidation.plugins.SubmitButton(),
|
||||
autoFocus: new FormValidation.plugins.AutoFocus()
|
||||
}
|
||||
};
|
||||
}
|
239
modules/Admin/Resources/js/_class/SmtpSettingsForm.js
Normal file
239
modules/Admin/Resources/js/_class/SmtpSettingsForm.js
Normal file
@ -0,0 +1,239 @@
|
||||
export default class SmtpSettingsForm {
|
||||
constructor(config = {}) {
|
||||
const defaultConfig = {
|
||||
formSmtpSettingsSelector: '#mail-smtp-settings-card',
|
||||
changeSmtpSettingsId: 'change_smtp_settings',
|
||||
testSmtpConnectionButtonId: 'test_smtp_connection_button',
|
||||
saveSmtpConnectionButtonId: 'save_smtp_connection_button',
|
||||
cancelSmtpConnectionButtonId: 'cancel_smtp_connection_button'
|
||||
};
|
||||
|
||||
this.config = { ...defaultConfig, ...config };
|
||||
this.formSmtpSettings = null;
|
||||
this.changeSmtpSettingsCheckbox = null;
|
||||
this.testButton = null;
|
||||
this.saveButton = null;
|
||||
this.cancelButton = null;
|
||||
this.validator = null;
|
||||
|
||||
this.init();
|
||||
}
|
||||
|
||||
/**
|
||||
* Inicializa el formulario de configuración SMTP.
|
||||
*/
|
||||
init() {
|
||||
try {
|
||||
// Obtener elementos esenciales
|
||||
this.formSmtpSettings = document.querySelector(this.config.formSmtpSettingsSelector);
|
||||
this.notificationArea = this.formSmtpSettings.querySelector(this.config.notificationAreaSelector);
|
||||
this.changeSmtpSettingsCheckbox = document.getElementById(this.config.changeSmtpSettingsId);
|
||||
this.testButton = document.getElementById(this.config.testSmtpConnectionButtonId);
|
||||
this.saveButton = document.getElementById(this.config.saveSmtpConnectionButtonId);
|
||||
this.cancelButton = document.getElementById(this.config.cancelSmtpConnectionButtonId);
|
||||
|
||||
// Asignar eventos
|
||||
this.changeSmtpSettingsCheckbox.addEventListener('change', event => this.handleCheckboxChange(event));
|
||||
this.testButton.addEventListener('click', event => this.handleTestConnection(event));
|
||||
this.cancelButton.addEventListener('click', () => this.handleCancel());
|
||||
|
||||
// Inicializar validación del formulario
|
||||
this.validator = FormValidation.formValidation(this.formSmtpSettings, this.smtpSettingsFormValidateConfig);
|
||||
} catch (error) {
|
||||
console.error('Error al inicializar el formulario SMTP:', error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Método de recarga parcial
|
||||
* Este método restablece la validación y los eventos sin destruir la instancia.
|
||||
*/
|
||||
reload() {
|
||||
try {
|
||||
// Inicializar validación del formulario
|
||||
this.validator = FormValidation.formValidation(this.formSmtpSettings, this.smtpSettingsFormValidateConfig);
|
||||
} catch (error) {
|
||||
console.error('Error al recargar el formulario:', error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Maneja el cambio en la casilla "Cambiar configuración SMTP".
|
||||
* @param {Event} event - Evento de cambio.
|
||||
*/
|
||||
handleCheckboxChange(event) {
|
||||
const isEnabled = event.target.checked;
|
||||
|
||||
this.toggleFieldsState(['host', 'port', 'encryption', 'username', 'password'], isEnabled);
|
||||
|
||||
this.testButton.disabled = false;
|
||||
this.saveButton.disabled = true;
|
||||
this.cancelButton.disabled = false;
|
||||
|
||||
if (!isEnabled) {
|
||||
Livewire.dispatch('loadSettings');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Maneja el clic en el botón "Probar conexión".
|
||||
* @param {Event} event - Evento de clic.
|
||||
*/
|
||||
handleTestConnection(event) {
|
||||
event.preventDefault();
|
||||
|
||||
this.validator.resetForm();
|
||||
|
||||
this.validator.validate().then(status => {
|
||||
if (status === 'Valid') {
|
||||
this.disableFormFields(this.formSmtpSettings);
|
||||
this.toggleButtonsState(this.formSmtpSettings, false);
|
||||
this.setButtonLoadingState(this.testButton, true);
|
||||
|
||||
Livewire.dispatch('testSmtpConnection');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Maneja la cancelación de cambios en la configuración SMTP.
|
||||
*/
|
||||
handleCancel() {
|
||||
this.disableFormFields(this.formSmtpSettings);
|
||||
this.toggleButtonsState(this.formSmtpSettings, false);
|
||||
this.setButtonLoadingState(this.cancelButton, true);
|
||||
|
||||
Livewire.dispatch('loadSettings');
|
||||
}
|
||||
|
||||
/**
|
||||
* Habilita o deshabilita los campos del formulario.
|
||||
* @param {Array} fields - IDs de los campos a actualizar.
|
||||
* @param {boolean} isEnabled - Estado de habilitación.
|
||||
*/
|
||||
toggleFieldsState(fields, isEnabled) {
|
||||
fields.forEach(id => {
|
||||
const field = document.getElementById(id);
|
||||
|
||||
if (field) field.disabled = !isEnabled;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Deshabilita todos los campos del formulario.
|
||||
* @param {HTMLElement} form - El formulario.
|
||||
*/
|
||||
disableFormFields(form) {
|
||||
form.querySelectorAll('input, select, textarea').forEach(field => {
|
||||
field.disabled = true;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Habilita o deshabilita los botones dentro del formulario.
|
||||
* @param {HTMLElement} form - El formulario.
|
||||
* @param {boolean} state - Estado de habilitación.
|
||||
*/
|
||||
toggleButtonsState(form, state) {
|
||||
form.querySelectorAll('button').forEach(button => {
|
||||
button.disabled = !state;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Configura el estado de carga de un botón.
|
||||
* @param {HTMLElement} button - El botón.
|
||||
* @param {boolean} isLoading - Si el botón está en estado de carga.
|
||||
*/
|
||||
setButtonLoadingState(button, isLoading) {
|
||||
const loadingText = button.getAttribute('data-loading-text');
|
||||
|
||||
if (loadingText && isLoading) {
|
||||
button.innerHTML = loadingText;
|
||||
} else {
|
||||
button.innerHTML = button.getAttribute('data-original-text') || button.innerHTML;
|
||||
}
|
||||
}
|
||||
|
||||
smtpSettingsFormValidateConfig = {
|
||||
fields: {
|
||||
host: {
|
||||
validators: {
|
||||
callback: {
|
||||
message: 'El servidor SMTP es obligatorio.',
|
||||
callback: function (input) {
|
||||
// Ejecutar la validación solo si 'change_smtp_settings' está marcado
|
||||
if (document.getElementById('change_smtp_settings').checked) {
|
||||
return input.value.trim() !== '';
|
||||
}
|
||||
return true; // No validar si no está marcado
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
port: {
|
||||
validators: {
|
||||
callback: {
|
||||
message: 'El puerto SMTP es obligatorio.',
|
||||
callback: function (input) {
|
||||
if (document.getElementById('change_smtp_settings').checked) {
|
||||
return (
|
||||
input.value.trim() !== '' &&
|
||||
/^\d+$/.test(input.value) &&
|
||||
input.value >= 1 &&
|
||||
input.value <= 65535
|
||||
);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
encryption: {
|
||||
validators: {
|
||||
callback: {
|
||||
message: 'La encriptación es obligatoria.',
|
||||
callback: function (input) {
|
||||
if (document.getElementById('change_smtp_settings').checked) {
|
||||
return input.value.trim() !== '';
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
username: {
|
||||
validators: {
|
||||
callback: {
|
||||
message: 'El usuario SMTP es obligatorio.',
|
||||
callback: function (input) {
|
||||
if (document.getElementById('change_smtp_settings').checked) {
|
||||
return input.value.trim().length >= 6;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
password: {
|
||||
validators: {
|
||||
callback: {
|
||||
message: 'Por favor, introduzca su contraseña.',
|
||||
callback: function (input) {
|
||||
if (document.getElementById('change_smtp_settings').checked) {
|
||||
return input.value.trim().length >= 5;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
plugins: {
|
||||
trigger: new FormValidation.plugins.Trigger(),
|
||||
bootstrap5: new FormValidation.plugins.Bootstrap5({ rowSelector: '.fv-row' }),
|
||||
submitButton: new FormValidation.plugins.SubmitButton(),
|
||||
autoFocus: new FormValidation.plugins.AutoFocus()
|
||||
}
|
||||
};
|
||||
}
|
252
modules/Admin/Resources/js/_class/WebsiteLegalSettingsForm.js
Normal file
252
modules/Admin/Resources/js/_class/WebsiteLegalSettingsForm.js
Normal file
@ -0,0 +1,252 @@
|
||||
export default class WebsiteLegalSettingsForm {
|
||||
constructor(config = {}) {
|
||||
const defaultConfig = {
|
||||
contentId: 'website-legal-settings-card',
|
||||
forms: {
|
||||
'legal_terminos_y_condiciones-nav': {
|
||||
enabledCheckboxId: 'legal_terminos_y_condiciones-enabled',
|
||||
quillSelector: '#legal_terminos_y_condiciones-content',
|
||||
quillPlaceholder: 'Ingrese los términos y condiciones'
|
||||
},
|
||||
'legal_aviso_de_privacidad-nav': {
|
||||
enabledCheckboxId: 'legal_aviso_de_privacidad-enabled',
|
||||
quillSelector: '#legal_aviso_de_privacidad-content',
|
||||
quillPlaceholder: 'Ingrese los aviso de privacidad'
|
||||
},
|
||||
'legal_politica_de_devoluciones-nav': {
|
||||
enabledCheckboxId: 'legal_politica_de_devoluciones-enabled',
|
||||
quillSelector: '#legal_politica_de_devoluciones-content',
|
||||
quillPlaceholder: 'Ingrese los política de devoluciones y reembolsos'
|
||||
},
|
||||
'legal_politica_de_envios-nav': {
|
||||
enabledCheckboxId: 'legal_politica_de_envios-enabled',
|
||||
quillSelector: '#legal_politica_de_envios-content',
|
||||
quillPlaceholder: 'Ingrese los política de envíos'
|
||||
},
|
||||
'legal_politica_de_cookies-nav': {
|
||||
enabledCheckboxId: 'legal_politica_de_cookies-enabled',
|
||||
quillSelector: '#legal_politica_de_cookies-content',
|
||||
quillPlaceholder: 'Ingrese los política de cookies'
|
||||
},
|
||||
'legal_autorizaciones_y_licencias-nav': {
|
||||
enabledCheckboxId: 'legal_autorizaciones_y_licencias-enabled',
|
||||
quillSelector: '#legal_autorizaciones_y_licencias-content',
|
||||
quillPlaceholder: 'Ingrese los autorizaciones y licencias'
|
||||
},
|
||||
'legal_informacion_comercial-nav': {
|
||||
enabledCheckboxId: 'legal_informacion_comercial-enabled',
|
||||
quillSelector: '#legal_informacion_comercial-content',
|
||||
quillPlaceholder: 'Ingrese los información comercial'
|
||||
},
|
||||
'legal_consentimiento_para_el_login_de_terceros-nav': {
|
||||
enabledCheckboxId: 'legal_consentimiento_para_el_login_de_terceros-enabled',
|
||||
quillSelector: '#legal_consentimiento_para_el_login_de_terceros-content',
|
||||
quillPlaceholder: 'Ingrese los consentimiento para el login de terceros'
|
||||
},
|
||||
'legal_leyendas_de_responsabilidad-nav': {
|
||||
enabledCheckboxId: 'legal_leyendas_de_responsabilidad-enabled',
|
||||
quillSelector: '#legal_leyendas_de_responsabilidad-content',
|
||||
quillPlaceholder: 'Ingrese los leyendas de responsabilidad'
|
||||
}
|
||||
},
|
||||
saveButtonId: 'save-button',
|
||||
cancelButtonId: 'cancel-button',
|
||||
notificationAreaSelector: '.notification-container'
|
||||
};
|
||||
|
||||
this.config = { ...defaultConfig, ...config };
|
||||
|
||||
this.content = null;
|
||||
this.saveButton = null;
|
||||
this.cancelButton = null;
|
||||
this.notificationArea = null;
|
||||
this.currentFormKey = null;
|
||||
this.quillInstances = {}; // Almacenar instancias de Quill
|
||||
this.editState = {};
|
||||
|
||||
this.init();
|
||||
}
|
||||
|
||||
init() {
|
||||
this.content = document.getElementById(this.config.contentId);
|
||||
this.saveButton = document.getElementById(this.config.saveButtonId);
|
||||
this.cancelButton = document.getElementById(this.config.cancelButtonId);
|
||||
this.notificationArea = this.content.querySelector(this.config.notificationAreaSelector);
|
||||
|
||||
// Puntero para rastrear si un formulario ha sido editado
|
||||
this.editState = Object.keys(this.config.forms).reduce((state, key) => {
|
||||
state[key] = false; // Inicializar todos los formularios como no editados
|
||||
return state;
|
||||
}, {});
|
||||
|
||||
this.switchToForm(Object.keys(this.config.forms)[0]); // Cargar el primer formulario
|
||||
|
||||
this.saveButton.addEventListener('click', () => this.handleSave());
|
||||
this.cancelButton.addEventListener('click', () => this.handleCancel());
|
||||
}
|
||||
|
||||
reload() {
|
||||
const currentFormKey = this.currentFormKey;
|
||||
|
||||
if (currentFormKey) {
|
||||
const quillInstance = this.quillInstances[currentFormKey];
|
||||
const { quillSelector, enabledCheckboxId } = this.config.forms[currentFormKey];
|
||||
const quillContainer = document.querySelector(quillSelector);
|
||||
const checkbox = document.getElementById(enabledCheckboxId);
|
||||
const textarea = document.getElementById(`${currentFormKey.replace('-nav', '')}-textarea`);
|
||||
|
||||
quillInstance.root.innerHTML = textarea.value;
|
||||
|
||||
// Agregar eventos
|
||||
checkbox.addEventListener('change', () =>
|
||||
this.handleCheckboxChange(checkbox, quillContainer, currentFormKey)
|
||||
);
|
||||
|
||||
const isEnabled = checkbox.checked;
|
||||
|
||||
quillInstance.enable(isEnabled); // Sincronizar habilitación con el checkbox
|
||||
}
|
||||
}
|
||||
|
||||
switchToForm(formKey) {
|
||||
if (!this.config.forms[formKey]) return;
|
||||
|
||||
this.currentFormKey = formKey;
|
||||
const { quillSelector, quillPlaceholder, enabledCheckboxId } = this.config.forms[formKey];
|
||||
const quillContainer = document.querySelector(quillSelector);
|
||||
const checkbox = document.getElementById(enabledCheckboxId);
|
||||
|
||||
// Si la instancia de Quill no existe, inicialízala
|
||||
if (!this.quillInstances[formKey]) {
|
||||
this.quillInstances[formKey] = new Quill(quillSelector, {
|
||||
placeholder: quillPlaceholder,
|
||||
modules: { toolbar: this.getToolbar() },
|
||||
theme: 'snow'
|
||||
});
|
||||
|
||||
// Escuchar cambios en el editor
|
||||
quillContainer.__quill = this.quillInstances[formKey];
|
||||
|
||||
this.quillInstances[formKey].on(
|
||||
'text-change',
|
||||
this.debounce(() => this.handleContentChange(formKey), 300)
|
||||
);
|
||||
|
||||
setTimeout(() => {
|
||||
const isEnabled = checkbox.checked;
|
||||
|
||||
quillContainer.__quill.enable(isEnabled); // Sincronizar habilitación con el checkbox
|
||||
});
|
||||
}
|
||||
|
||||
this.toggleButtonsState(this.editState[this.currentFormKey]);
|
||||
|
||||
// Asignar evento al checkbox (asegura no duplicar eventos)
|
||||
if (!checkbox.dataset.bound) {
|
||||
checkbox.addEventListener('change', () => this.handleCheckboxChange(checkbox, quillContainer, formKey));
|
||||
checkbox.dataset.bound = true; // Marcar como manejado
|
||||
}
|
||||
}
|
||||
|
||||
handleContentChange(formKey) {
|
||||
// Marcar el formulario como editado
|
||||
this.editState[formKey] = true;
|
||||
|
||||
// Habilitar botones
|
||||
this.toggleButtonsState(true);
|
||||
}
|
||||
|
||||
handleCheckboxChange(checkbox, quillContainer, formKey) {
|
||||
const isEnabled = checkbox.checked;
|
||||
|
||||
if (quillContainer.__quill) {
|
||||
quillContainer.__quill.enable(isEnabled); // Habilitar o deshabilitar el editor
|
||||
|
||||
if (isEnabled) {
|
||||
quillContainer.__quill.focus(); // Hacer focus si está habilitado
|
||||
}
|
||||
}
|
||||
|
||||
// Marcar el formulario como editado
|
||||
this.editState[formKey] = true;
|
||||
this.toggleButtonsState(true);
|
||||
}
|
||||
|
||||
handleSave() {
|
||||
const quillInstance = this.quillInstances[this.currentFormKey];
|
||||
const textarea = document.getElementById(`${this.currentFormKey.replace('-nav', '-textarea')}`);
|
||||
|
||||
// Deshabilitar el estado de edición
|
||||
this.editState[this.currentFormKey] = false;
|
||||
|
||||
//this.disableFormFields(this.content);
|
||||
this.toggleButtonsState(false);
|
||||
this.setButtonLoadingState(true);
|
||||
|
||||
// Actualizar el contenido del textarea para sincronizar con Livewire
|
||||
textarea.value = quillInstance.root.innerHTML;
|
||||
|
||||
// Simular el evento 'input' para actualizar el contenido en el textarea
|
||||
textarea.dispatchEvent(new Event('input', { bubbles: true }));
|
||||
|
||||
// Emitir el evento de guardar en Livewire
|
||||
Livewire.dispatch('saveLegal');
|
||||
}
|
||||
|
||||
handleCancel() {
|
||||
// Restablecer el estado de edición del formulario actual
|
||||
this.editState[this.currentFormKey] = false;
|
||||
|
||||
//this.disableFormFields();
|
||||
this.toggleButtonsState(false);
|
||||
}
|
||||
|
||||
disableFormFields(content) {
|
||||
content.querySelectorAll('input, select, textarea').forEach(field => {
|
||||
field.disabled = true;
|
||||
});
|
||||
|
||||
if (this.fullEditor) {
|
||||
this.fullEditor.enable(false); // Deshabilitar el editor
|
||||
}
|
||||
}
|
||||
|
||||
toggleButtonsState(state) {
|
||||
this.saveButton.disabled = !state;
|
||||
this.cancelButton.disabled = !state;
|
||||
}
|
||||
|
||||
setButtonLoadingState(isLoading) {
|
||||
const loadingText = this.saveButton.getAttribute('data-loading-text');
|
||||
|
||||
if (loadingText && isLoading) {
|
||||
this.saveButton.innerHTML = loadingText;
|
||||
} else {
|
||||
this.saveButton.innerHTML = this.saveButton.getAttribute('data-original-text') || this.saveButton.innerHTML;
|
||||
}
|
||||
}
|
||||
|
||||
debounce(func, wait) {
|
||||
let timeout;
|
||||
|
||||
return function (...args) {
|
||||
const context = this;
|
||||
|
||||
clearTimeout(timeout);
|
||||
|
||||
timeout = setTimeout(() => func.apply(context, args), wait);
|
||||
};
|
||||
}
|
||||
|
||||
getToolbar() {
|
||||
return [
|
||||
[{ font: [] }, { size: [] }],
|
||||
['bold', 'italic', 'underline', 'strike'],
|
||||
[{ color: [] }, { background: [] }],
|
||||
[{ script: 'super' }, { script: 'sub' }],
|
||||
[{ header: '1' }, { header: '2' }],
|
||||
[{ list: 'ordered' }, { list: 'bullet' }, { indent: '-1' }, { indent: '+1' }],
|
||||
['link', 'clean']
|
||||
];
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user