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']
|
||||
];
|
||||
}
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
import LivewireNotification from '../_class/LivewireNotification';
|
||||
import FormCustomListener from '../_class/FormCustomListener';
|
||||
|
||||
const notification = new LivewireNotification();
|
||||
|
||||
new FormCustomListener({
|
||||
buttonSelectors: ['.btn-save', '.btn-cancel', '.btn-reset'] // Selectores para botones
|
||||
});
|
||||
|
||||
Livewire.on('clearLocalStoregeTemplateCustomizer', event => {
|
||||
const _deleteCookie = name => {
|
||||
document.cookie = name + '=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;';
|
||||
};
|
||||
|
||||
const pattern = 'templateCustomizer-';
|
||||
|
||||
// Iterar sobre todas las claves en localStorage
|
||||
Object.keys(localStorage).forEach(key => {
|
||||
if (key.startsWith(pattern)) {
|
||||
localStorage.removeItem(key);
|
||||
}
|
||||
});
|
||||
|
||||
_deleteCookie('admin-mode');
|
||||
_deleteCookie('admin-colorPref');
|
||||
_deleteCookie('colorPref');
|
||||
_deleteCookie('theme');
|
||||
_deleteCookie('direction');
|
||||
});
|
@ -0,0 +1,27 @@
|
||||
import LivewireNotification from '../_class/LivewireNotification';
|
||||
import SmtpSettingsForm from '../_class/SmtpSettingsForm';
|
||||
import SenderResponseForm from '../_class/SenderResponseForm';
|
||||
|
||||
new LivewireNotification();
|
||||
|
||||
window.smtpSettingsForm = new SmtpSettingsForm();
|
||||
window.senderResponseForm = new SenderResponseForm();
|
||||
|
||||
Livewire.hook('morphed', ({ component }) => {
|
||||
switch (component.name) {
|
||||
case 'mail-smtp-settings':
|
||||
if (window.smtpSettingsForm) {
|
||||
window.smtpSettingsForm.reload(); // Recarga el formulario sin destruir la instancia
|
||||
}
|
||||
break;
|
||||
|
||||
case 'mail-sender-response-settings':
|
||||
if (window.senderResponseForm) {
|
||||
window.senderResponseForm.reload(); // Recarga el formulario sin destruir la instancia
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
});
|
9
modules/Admin/Resources/js/app.js
Normal file
9
modules/Admin/Resources/js/app.js
Normal file
@ -0,0 +1,9 @@
|
||||
import './bootstrap';
|
||||
/*
|
||||
Add custom scripts here
|
||||
*/
|
||||
import.meta.glob([
|
||||
'../assets/img/**',
|
||||
// '../assets/json/**',
|
||||
'../assets/vendor/fonts/**'
|
||||
]);
|
206
modules/Admin/Resources/js/auth/app-access-permission.js
Normal file
206
modules/Admin/Resources/js/auth/app-access-permission.js
Normal file
@ -0,0 +1,206 @@
|
||||
/**
|
||||
* App user list (jquery)
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
$(function () {
|
||||
var dataTablePermissions = $('.datatables-permissions'),
|
||||
dt_permission,
|
||||
userList = baseUrl + 'app/user/list';
|
||||
// Users List datatable
|
||||
if (dataTablePermissions.length) {
|
||||
dt_permission = dataTablePermissions.DataTable({
|
||||
ajax: assetsPath + 'json/permissions-list.json', // JSON file to add data
|
||||
columns: [
|
||||
// columns according to JSON
|
||||
{ data: '' },
|
||||
{ data: 'id' },
|
||||
{ data: 'name' },
|
||||
{ data: 'assigned_to' },
|
||||
{ data: 'created_date' },
|
||||
{ data: '' }
|
||||
],
|
||||
columnDefs: [
|
||||
{
|
||||
// For Responsive
|
||||
className: 'control',
|
||||
orderable: false,
|
||||
searchable: false,
|
||||
responsivePriority: 2,
|
||||
targets: 0,
|
||||
render: function (data, type, full, meta) {
|
||||
return '';
|
||||
}
|
||||
},
|
||||
{
|
||||
targets: 1,
|
||||
searchable: false,
|
||||
visible: false
|
||||
},
|
||||
{
|
||||
// Name
|
||||
targets: 2,
|
||||
render: function (data, type, full, meta) {
|
||||
var $name = full['name'];
|
||||
return '<span class="text-nowrap text-heading">' + $name + '</span>';
|
||||
}
|
||||
},
|
||||
{
|
||||
// User Role
|
||||
targets: 3,
|
||||
orderable: false,
|
||||
render: function (data, type, full, meta) {
|
||||
var $assignedTo = full['assigned_to'],
|
||||
$output = '';
|
||||
var roleBadgeObj = {
|
||||
Admin: '<a href="' + userList + '"><span class="badge me-4 bg-label-primary">Administrator</span></a>',
|
||||
Manager: '<a href="' + userList + '"><span class="badge me-4 bg-label-warning">Manager</span></a>',
|
||||
Users: '<a href="' + userList + '"><span class="badge me-4 bg-label-success">Users</span></a>',
|
||||
Support: '<a href="' + userList + '"><span class="badge me-4 bg-label-info">Support</span></a>',
|
||||
Restricted:
|
||||
'<a href="' + userList + '"><span class="badge me-4 bg-label-danger">Restricted User</span></a>'
|
||||
};
|
||||
for (var i = 0; i < $assignedTo.length; i++) {
|
||||
var val = $assignedTo[i];
|
||||
$output += roleBadgeObj[val];
|
||||
}
|
||||
return '<span class="text-nowrap">' + $output + '</span>';
|
||||
}
|
||||
},
|
||||
{
|
||||
// remove ordering from Name
|
||||
targets: 4,
|
||||
orderable: false,
|
||||
render: function (data, type, full, meta) {
|
||||
var $date = full['created_date'];
|
||||
return '<span class="text-nowrap">' + $date + '</span>';
|
||||
}
|
||||
},
|
||||
{
|
||||
// Actions
|
||||
targets: -1,
|
||||
searchable: false,
|
||||
title: 'Actions',
|
||||
orderable: false,
|
||||
render: function (data, type, full, meta) {
|
||||
return (
|
||||
'<div class="d-flex align-items-center">' +
|
||||
'<span class="text-nowrap"><button class="btn btn-icon btn-text-secondary waves-effect waves-light rounded-pill me-1" data-bs-target="#editPermissionModal" data-bs-toggle="modal" data-bs-dismiss="modal"><i class="ti ti-edit ti-md"></i></button>' +
|
||||
'<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 mx-1"></i></a>' +
|
||||
'<div class="dropdown-menu dropdown-menu-end m-0">' +
|
||||
'<a href="javascript:;"" class="dropdown-item">Edit</a>' +
|
||||
'<a href="javascript:;" class="dropdown-item">Suspend</a>' +
|
||||
'</div>' +
|
||||
'</div>'
|
||||
);
|
||||
}
|
||||
}
|
||||
],
|
||||
order: [[1, 'asc']],
|
||||
dom:
|
||||
'<"row mx-1"' +
|
||||
'<"col-sm-12 col-md-3" l>' +
|
||||
'<"col-sm-12 col-md-9"<"dt-action-buttons text-xl-end text-lg-start text-md-end text-start d-flex align-items-center justify-content-md-end justify-content-center flex-wrap"<"me-4 mt-n6 mt-md-0"f>B>>' +
|
||||
'>t' +
|
||||
'<"row"' +
|
||||
'<"col-sm-12 col-md-6"i>' +
|
||||
'<"col-sm-12 col-md-6"p>' +
|
||||
'>',
|
||||
language: {
|
||||
sLengthMenu: 'Show _MENU_',
|
||||
search: '',
|
||||
searchPlaceholder: 'Search Permissions',
|
||||
paginate: {
|
||||
next: '<i class="ti ti-chevron-right ti-sm"></i>',
|
||||
previous: '<i class="ti ti-chevron-left ti-sm"></i>'
|
||||
}
|
||||
},
|
||||
// Buttons with Dropdown
|
||||
buttons: [
|
||||
{
|
||||
text: '<i class="ti ti-plus ti-xs me-0 me-sm-2"></i><span class="d-none d-sm-inline-block">Add Permission</span>',
|
||||
className: 'add-new btn btn-primary mb-6 mb-md-0 waves-effect waves-light',
|
||||
attr: {
|
||||
'data-bs-toggle': 'modal',
|
||||
'data-bs-target': '#addPermissionModal'
|
||||
},
|
||||
init: function (api, node, config) {
|
||||
$(node).removeClass('btn-secondary');
|
||||
}
|
||||
}
|
||||
],
|
||||
// For responsive popup
|
||||
responsive: {
|
||||
details: {
|
||||
display: $.fn.dataTable.Responsive.display.modal({
|
||||
header: function (row) {
|
||||
var data = row.data();
|
||||
return 'Details of ' + data['name'];
|
||||
}
|
||||
}),
|
||||
type: 'column',
|
||||
renderer: function (api, rowIdx, columns) {
|
||||
var data = $.map(columns, function (col, i) {
|
||||
return col.title !== '' // ? Do not show row in modal popup if title is blank (for check box)
|
||||
? '<tr data-dt-row="' +
|
||||
col.rowIndex +
|
||||
'" data-dt-column="' +
|
||||
col.columnIndex +
|
||||
'">' +
|
||||
'<td>' +
|
||||
col.title +
|
||||
':' +
|
||||
'</td> ' +
|
||||
'<td>' +
|
||||
col.data +
|
||||
'</td>' +
|
||||
'</tr>'
|
||||
: '';
|
||||
}).join('');
|
||||
|
||||
return data ? $('<table class="table"/><tbody />').append(data) : false;
|
||||
}
|
||||
}
|
||||
},
|
||||
initComplete: function () {
|
||||
// Adding role filter once table initialized
|
||||
this.api()
|
||||
.columns(3)
|
||||
.every(function () {
|
||||
var column = this;
|
||||
var select = $(
|
||||
'<select id="UserRole" class="form-select text-capitalize"><option value=""> Select Role </option></select>'
|
||||
)
|
||||
.appendTo('.user_role')
|
||||
.on('change', function () {
|
||||
var val = $.fn.dataTable.util.escapeRegex($(this).val());
|
||||
column.search(val ? '^' + val + '$' : '', true, false).draw();
|
||||
});
|
||||
|
||||
column
|
||||
.data()
|
||||
.unique()
|
||||
.sort()
|
||||
.each(function (d, j) {
|
||||
select.append('<option value="' + d + '" class="text-capitalize">' + d + '</option>');
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Delete Record
|
||||
$('.datatables-permissions tbody').on('click', '.delete-record', function () {
|
||||
dt_permission.row($(this).parents('tr')).remove().draw();
|
||||
});
|
||||
|
||||
// Filter form control to default size
|
||||
// ? setTimeout used for multilingual table initialization
|
||||
setTimeout(() => {
|
||||
$('.dataTables_filter .form-control').removeClass('form-control-sm');
|
||||
$('.dataTables_length .form-select').removeClass('form-select-sm');
|
||||
$('.dataTables_info').addClass('ms-n1');
|
||||
$('.dataTables_paginate').addClass('me-n1');
|
||||
}, 300);
|
||||
});
|
428
modules/Admin/Resources/js/auth/app-access-roles.js
Normal file
428
modules/Admin/Resources/js/auth/app-access-roles.js
Normal file
@ -0,0 +1,428 @@
|
||||
/**
|
||||
* App user list
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
// Datatable (jquery)
|
||||
$(function () {
|
||||
var dtUserTable = $('.datatables-users'),
|
||||
dt_User,
|
||||
statusObj = {
|
||||
1: { title: 'Pending', class: 'bg-label-warning' },
|
||||
2: { title: 'Active', class: 'bg-label-success' },
|
||||
3: { title: 'Inactive', class: 'bg-label-secondary' }
|
||||
};
|
||||
|
||||
var userView = baseUrl + 'app/user/view/account';
|
||||
|
||||
// Users List datatable
|
||||
if (dtUserTable.length) {
|
||||
var dtUser = dtUserTable.DataTable({
|
||||
ajax: assetsPath + 'json/user-list.json', // JSON file to add data
|
||||
columns: [
|
||||
// columns according to JSON
|
||||
{ data: 'id' },
|
||||
{ data: 'id' },
|
||||
{ data: 'full_name' },
|
||||
{ data: 'role' },
|
||||
{ data: 'current_plan' },
|
||||
{ data: 'billing' },
|
||||
{ data: 'status' },
|
||||
{ data: '' }
|
||||
],
|
||||
columnDefs: [
|
||||
{
|
||||
// For Responsive
|
||||
className: 'control',
|
||||
orderable: false,
|
||||
searchable: false,
|
||||
responsivePriority: 2,
|
||||
targets: 0,
|
||||
render: function (data, type, full, meta) {
|
||||
return '';
|
||||
}
|
||||
},
|
||||
{
|
||||
// For Checkboxes
|
||||
targets: 1,
|
||||
orderable: false,
|
||||
checkboxes: {
|
||||
selectAllRender: '<input type="checkbox" class="form-check-input">'
|
||||
},
|
||||
render: function () {
|
||||
return '<input type="checkbox" class="dt-checkboxes form-check-input" >';
|
||||
},
|
||||
searchable: false
|
||||
},
|
||||
{
|
||||
// User full name and email
|
||||
targets: 2,
|
||||
responsivePriority: 4,
|
||||
render: function (data, type, full, meta) {
|
||||
var $name = full['full_name'],
|
||||
$email = full['email'],
|
||||
$image = full['avatar'];
|
||||
if ($image) {
|
||||
// For Avatar image
|
||||
var $output =
|
||||
'<img src="' + assetsPath + 'img/avatars/' + $image + '" alt="Avatar" class="rounded-circle">';
|
||||
} else {
|
||||
// For Avatar badge
|
||||
var stateNum = Math.floor(Math.random() * 6);
|
||||
var states = ['success', 'danger', 'warning', 'info', 'primary', 'secondary'];
|
||||
var $state = states[stateNum],
|
||||
$name = full['full_name'],
|
||||
$initials = $name.match(/\b\w/g) || [];
|
||||
$initials = (($initials.shift() || '') + ($initials.pop() || '')).toUpperCase();
|
||||
$output = '<span class="avatar-initial rounded-circle bg-label-' + $state + '">' + $initials + '</span>';
|
||||
}
|
||||
// Creates full output for row
|
||||
var $row_output =
|
||||
'<div class="d-flex justify-content-left align-items-center">' +
|
||||
'<div class="avatar-wrapper">' +
|
||||
'<div class="avatar avatar-sm me-4">' +
|
||||
$output +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="d-flex flex-column">' +
|
||||
'<a href="' +
|
||||
userView +
|
||||
'" class="text-heading text-truncate"><span class="fw-medium">' +
|
||||
$name +
|
||||
'</span></a>' +
|
||||
'<small>@' +
|
||||
$email +
|
||||
'</small>' +
|
||||
'</div>' +
|
||||
'</div>';
|
||||
return $row_output;
|
||||
}
|
||||
},
|
||||
{
|
||||
// User Role
|
||||
targets: 3,
|
||||
render: function (data, type, full, meta) {
|
||||
var $role = full['role'];
|
||||
var roleBadgeObj = {
|
||||
Subscriber: '<i class="ti ti-crown ti-md text-primary me-2"></i>',
|
||||
Author: '<i class="ti ti-edit ti-md text-warning me-2"></i>',
|
||||
Maintainer: '<i class="ti ti-user ti-md text-success me-2"></i>',
|
||||
Editor: '<i class="ti ti-chart-pie ti-md text-info me-2"></i>',
|
||||
Admin: '<i class="ti ti-device-desktop ti-md text-danger me-2"></i>'
|
||||
};
|
||||
return (
|
||||
"<span class='text-truncate d-flex align-items-center text-heading'>" +
|
||||
roleBadgeObj[$role] +
|
||||
$role +
|
||||
'</span>'
|
||||
);
|
||||
}
|
||||
},
|
||||
{
|
||||
// Plans
|
||||
targets: 4,
|
||||
render: function (data, type, full, meta) {
|
||||
var $plan = full['current_plan'];
|
||||
|
||||
return '<span class="text-heading">' + $plan + '</span>';
|
||||
}
|
||||
},
|
||||
{
|
||||
// User Status
|
||||
targets: 6,
|
||||
render: function (data, type, full, meta) {
|
||||
var $status = full['status'];
|
||||
|
||||
return (
|
||||
'<span class="badge ' +
|
||||
statusObj[$status].class +
|
||||
'" text-capitalized>' +
|
||||
statusObj[$status].title +
|
||||
'</span>'
|
||||
);
|
||||
}
|
||||
},
|
||||
{
|
||||
// Actions
|
||||
targets: -1,
|
||||
title: 'Actions',
|
||||
searchable: false,
|
||||
orderable: false,
|
||||
render: function (data, type, full, meta) {
|
||||
return (
|
||||
'<div class="d-flex align-items-center">' +
|
||||
'<a href="javascript:;" class="btn btn-icon btn-text-secondary waves-effect waves-light rounded-pill delete-record"><i class="ti ti-trash ti-md"></i></a>' +
|
||||
'<a href="' +
|
||||
userView +
|
||||
'" class="btn btn-icon btn-text-secondary waves-effect waves-light rounded-pill"><i class="ti ti-eye ti-md"></i></a>' +
|
||||
'<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:;"" class="dropdown-item">Edit</a>' +
|
||||
'<a href="javascript:;" class="dropdown-item">Suspend</a>' +
|
||||
'</div>' +
|
||||
'</div>'
|
||||
);
|
||||
}
|
||||
}
|
||||
],
|
||||
order: [[2, 'desc']],
|
||||
dom:
|
||||
'<"row"' +
|
||||
'<"col-md-2"<l>>' +
|
||||
'<"col-md-10"<"dt-action-buttons text-xl-end text-lg-start text-md-end text-start d-flex align-items-center justify-content-end flex-md-row flex-column mb-6 mb-md-0"fB>>' +
|
||||
'>t' +
|
||||
'<"row"' +
|
||||
'<"col-sm-12 col-md-6"i>' +
|
||||
'<"col-sm-12 col-md-6"p>' +
|
||||
'>',
|
||||
language: {
|
||||
sLengthMenu: 'Show _MENU_',
|
||||
search: '',
|
||||
searchPlaceholder: 'Search User',
|
||||
paginate: {
|
||||
next: '<i class="ti ti-chevron-right ti-sm"></i>',
|
||||
previous: '<i class="ti ti-chevron-left ti-sm"></i>'
|
||||
}
|
||||
},
|
||||
buttons: [
|
||||
{
|
||||
extend: 'collection',
|
||||
className:
|
||||
'btn btn-label-secondary dropdown-toggle me-4 waves-effect waves-light border-left-0 border-right-0 rounded',
|
||||
text: '<i class="ti ti-upload ti-xs me-sm-1 align-text-bottom"></i> <span class="d-none d-sm-inline-block">Export</span>',
|
||||
buttons: [
|
||||
{
|
||||
extend: 'print',
|
||||
text: '<i class="ti ti-printer me-1" ></i>Print',
|
||||
className: 'dropdown-item',
|
||||
exportOptions: {
|
||||
columns: [3, 4, 5, 6, 7],
|
||||
// prevent avatar to be display
|
||||
format: {
|
||||
body: function (inner, coldex, rowdex) {
|
||||
if (inner.length <= 0) return inner;
|
||||
var el = $.parseHTML(inner);
|
||||
var result = '';
|
||||
$.each(el, function (index, item) {
|
||||
if (item.classList !== undefined && item.classList.contains('user-name')) {
|
||||
result = result + item.lastChild.firstChild.textContent;
|
||||
} else if (item.innerText === undefined) {
|
||||
result = result + item.textContent;
|
||||
} else result = result + item.innerText;
|
||||
});
|
||||
return result;
|
||||
}
|
||||
}
|
||||
},
|
||||
customize: function (win) {
|
||||
//customize print view for dark
|
||||
$(win.document.body)
|
||||
.css('color', config.colors.headingColor)
|
||||
.css('border-color', config.colors.borderColor)
|
||||
.css('background-color', config.colors.bodyBg);
|
||||
$(win.document.body)
|
||||
.find('table')
|
||||
.addClass('compact')
|
||||
.css('color', 'inherit')
|
||||
.css('border-color', 'inherit')
|
||||
.css('background-color', 'inherit');
|
||||
}
|
||||
},
|
||||
{
|
||||
extend: 'csv',
|
||||
text: '<i class="ti ti-file-text me-1" ></i>Csv',
|
||||
className: 'dropdown-item',
|
||||
exportOptions: {
|
||||
columns: [3, 4, 5, 6, 7],
|
||||
// prevent avatar to be display
|
||||
format: {
|
||||
body: function (inner, coldex, rowdex) {
|
||||
if (inner.length <= 0) return inner;
|
||||
var el = $.parseHTML(inner);
|
||||
var result = '';
|
||||
$.each(el, function (index, item) {
|
||||
if (item.classList !== undefined && item.classList.contains('user-name')) {
|
||||
result = result + item.lastChild.firstChild.textContent;
|
||||
} else if (item.innerText === undefined) {
|
||||
result = result + item.textContent;
|
||||
} else result = result + item.innerText;
|
||||
});
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
extend: 'excel',
|
||||
text: '<i class="ti ti-file-spreadsheet me-1"></i>Excel',
|
||||
className: 'dropdown-item',
|
||||
exportOptions: {
|
||||
columns: [3, 4, 5, 6, 7],
|
||||
// prevent avatar to be display
|
||||
format: {
|
||||
body: function (inner, coldex, rowdex) {
|
||||
if (inner.length <= 0) return inner;
|
||||
var el = $.parseHTML(inner);
|
||||
var result = '';
|
||||
$.each(el, function (index, item) {
|
||||
if (item.classList !== undefined && item.classList.contains('user-name')) {
|
||||
result = result + item.lastChild.firstChild.textContent;
|
||||
} else if (item.innerText === undefined) {
|
||||
result = result + item.textContent;
|
||||
} else result = result + item.innerText;
|
||||
});
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
extend: 'pdf',
|
||||
text: '<i class="ti ti-file-description me-1"></i>Pdf',
|
||||
className: 'dropdown-item',
|
||||
exportOptions: {
|
||||
columns: [3, 4, 5, 6, 7],
|
||||
// prevent avatar to be display
|
||||
format: {
|
||||
body: function (inner, coldex, rowdex) {
|
||||
if (inner.length <= 0) return inner;
|
||||
var el = $.parseHTML(inner);
|
||||
var result = '';
|
||||
$.each(el, function (index, item) {
|
||||
if (item.classList !== undefined && item.classList.contains('user-name')) {
|
||||
result = result + item.lastChild.firstChild.textContent;
|
||||
} else if (item.innerText === undefined) {
|
||||
result = result + item.textContent;
|
||||
} else result = result + item.innerText;
|
||||
});
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
extend: 'copy',
|
||||
text: '<i class="ti ti-copy me-1" ></i>Copy',
|
||||
className: 'dropdown-item',
|
||||
exportOptions: {
|
||||
columns: [3, 4, 5, 6, 7],
|
||||
// prevent avatar to be display
|
||||
format: {
|
||||
body: function (inner, coldex, rowdex) {
|
||||
if (inner.length <= 0) return inner;
|
||||
var el = $.parseHTML(inner);
|
||||
var result = '';
|
||||
$.each(el, function (index, item) {
|
||||
if (item.classList !== undefined && item.classList.contains('user-name')) {
|
||||
result = result + item.lastChild.firstChild.textContent;
|
||||
} else if (item.innerText === undefined) {
|
||||
result = result + item.textContent;
|
||||
} else result = result + item.innerText;
|
||||
});
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
text: '<i class="ti ti-plus ti-xs me-md-2"></i><span class="d-md-inline-block d-none">Add new role</span>',
|
||||
className: 'btn btn-primary waves-effect waves-light rounded border-left-0 border-right-0',
|
||||
attr: {
|
||||
'data-bs-toggle': 'modal',
|
||||
'data-bs-target': '#addRoleModal'
|
||||
}
|
||||
}
|
||||
],
|
||||
// For responsive popup
|
||||
responsive: {
|
||||
details: {
|
||||
display: $.fn.dataTable.Responsive.display.modal({
|
||||
header: function (row) {
|
||||
var data = row.data();
|
||||
return 'Details of ' + data['full_name'];
|
||||
}
|
||||
}),
|
||||
type: 'column',
|
||||
renderer: function (api, rowIdx, columns) {
|
||||
var data = $.map(columns, function (col, i) {
|
||||
return col.title !== '' // ? Do not show row in modal popup if title is blank (for check box)
|
||||
? '<tr data-dt-row="' +
|
||||
col.rowIndex +
|
||||
'" data-dt-column="' +
|
||||
col.columnIndex +
|
||||
'">' +
|
||||
'<td>' +
|
||||
col.title +
|
||||
':' +
|
||||
'</td> ' +
|
||||
'<td>' +
|
||||
col.data +
|
||||
'</td>' +
|
||||
'</tr>'
|
||||
: '';
|
||||
}).join('');
|
||||
|
||||
return data ? $('<table class="table"/><tbody />').append(data) : false;
|
||||
}
|
||||
}
|
||||
},
|
||||
initComplete: function () {
|
||||
// Adding role filter once table initialized
|
||||
this.api()
|
||||
.columns(3)
|
||||
.every(function () {
|
||||
var column = this;
|
||||
var select = $(
|
||||
'<select id="UserRole" class="form-select text-capitalize"><option value=""> Select Role </option></select>'
|
||||
)
|
||||
.appendTo('.user_role')
|
||||
.on('change', function () {
|
||||
var val = $.fn.dataTable.util.escapeRegex($(this).val());
|
||||
column.search(val ? '^' + val + '$' : '', true, false).draw();
|
||||
});
|
||||
|
||||
column
|
||||
.data()
|
||||
.unique()
|
||||
.sort()
|
||||
.each(function (d, j) {
|
||||
select.append('<option value="' + d + '" class="text-capitalize">' + d + '</option>');
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
// Delete Record
|
||||
$('.datatables-users tbody').on('click', '.delete-record', function () {
|
||||
dtUser.row($(this).parents('tr')).remove().draw();
|
||||
});
|
||||
|
||||
// Filter form control to default size
|
||||
// ? setTimeout used for multilingual table initialization
|
||||
setTimeout(() => {
|
||||
$('.dataTables_filter .form-control').removeClass('form-control-sm');
|
||||
$('.dataTables_length .form-select').removeClass('form-select-sm');
|
||||
}, 300);
|
||||
$('.dataTables_filter').addClass('ms-n4 me-4 mt-0 mt-md-6');
|
||||
});
|
||||
|
||||
(function () {
|
||||
// On edit role click, update text
|
||||
var roleEditList = document.querySelectorAll('.role-edit-modal'),
|
||||
roleAdd = document.querySelector('.add-new-role'),
|
||||
roleTitle = document.querySelector('.role-title');
|
||||
|
||||
roleAdd.onclick = function () {
|
||||
roleTitle.innerHTML = 'Add New Role'; // reset text
|
||||
};
|
||||
if (roleEditList) {
|
||||
roleEditList.forEach(function (roleEditEl) {
|
||||
roleEditEl.onclick = function () {
|
||||
roleTitle.innerHTML = 'Edit Role'; // reset text
|
||||
};
|
||||
});
|
||||
}
|
||||
})();
|
533
modules/Admin/Resources/js/auth/app-user-list.js
Normal file
533
modules/Admin/Resources/js/auth/app-user-list.js
Normal file
@ -0,0 +1,533 @@
|
||||
/**
|
||||
* Page User List
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
// Datatable (jquery)
|
||||
$(function () {
|
||||
let borderColor, bodyBg, headingColor;
|
||||
|
||||
if (isDarkStyle) {
|
||||
borderColor = config.colors_dark.borderColor;
|
||||
bodyBg = config.colors_dark.bodyBg;
|
||||
headingColor = config.colors_dark.headingColor;
|
||||
} else {
|
||||
borderColor = config.colors.borderColor;
|
||||
bodyBg = config.colors.bodyBg;
|
||||
headingColor = config.colors.headingColor;
|
||||
}
|
||||
|
||||
// Variable declaration for table
|
||||
var dt_user_table = $('.datatables-users'),
|
||||
select2 = $('.select2'),
|
||||
userView = baseUrl + 'app/user/view/account',
|
||||
statusObj = {
|
||||
1: { title: 'Pending', class: 'bg-label-warning' },
|
||||
2: { title: 'Active', class: 'bg-label-success' },
|
||||
3: { title: 'Inactive', class: 'bg-label-secondary' }
|
||||
};
|
||||
|
||||
if (select2.length) {
|
||||
var $this = select2;
|
||||
$this.wrap('<div class="position-relative"></div>').select2({
|
||||
placeholder: 'Select Country',
|
||||
dropdownParent: $this.parent()
|
||||
});
|
||||
}
|
||||
|
||||
// Users datatable
|
||||
if (dt_user_table.length) {
|
||||
var dt_user = dt_user_table.DataTable({
|
||||
ajax: assetsPath + 'json/user-list.json', // JSON file to add data
|
||||
columns: [
|
||||
// columns according to JSON
|
||||
{ data: 'id' },
|
||||
{ data: 'id' },
|
||||
{ data: 'full_name' },
|
||||
{ data: 'role' },
|
||||
{ data: 'current_plan' },
|
||||
{ data: 'billing' },
|
||||
{ data: 'status' },
|
||||
{ data: 'action' }
|
||||
],
|
||||
columnDefs: [
|
||||
{
|
||||
// For Responsive
|
||||
className: 'control',
|
||||
searchable: false,
|
||||
orderable: false,
|
||||
responsivePriority: 2,
|
||||
targets: 0,
|
||||
render: function (data, type, full, meta) {
|
||||
return '';
|
||||
}
|
||||
},
|
||||
{
|
||||
// For Checkboxes
|
||||
targets: 1,
|
||||
orderable: false,
|
||||
checkboxes: {
|
||||
selectAllRender: '<input type="checkbox" class="form-check-input">'
|
||||
},
|
||||
render: function () {
|
||||
return '<input type="checkbox" class="dt-checkboxes form-check-input" >';
|
||||
},
|
||||
searchable: false
|
||||
},
|
||||
{
|
||||
// User full name and email
|
||||
targets: 2,
|
||||
responsivePriority: 4,
|
||||
render: function (data, type, full, meta) {
|
||||
var $name = full['full_name'],
|
||||
$email = full['email'],
|
||||
$image = full['avatar'];
|
||||
if ($image) {
|
||||
// For Avatar image
|
||||
var $output =
|
||||
'<img src="' + assetsPath + 'img/avatars/' + $image + '" alt="Avatar" class="rounded-circle">';
|
||||
} else {
|
||||
// For Avatar badge
|
||||
var stateNum = Math.floor(Math.random() * 6);
|
||||
var states = ['success', 'danger', 'warning', 'info', 'primary', 'secondary'];
|
||||
var $state = states[stateNum],
|
||||
$name = full['full_name'],
|
||||
$initials = $name.match(/\b\w/g) || [];
|
||||
$initials = (($initials.shift() || '') + ($initials.pop() || '')).toUpperCase();
|
||||
$output = '<span class="avatar-initial rounded-circle bg-label-' + $state + '">' + $initials + '</span>';
|
||||
}
|
||||
// Creates full output for row
|
||||
var $row_output =
|
||||
'<div class="d-flex justify-content-start align-items-center user-name">' +
|
||||
'<div class="avatar-wrapper">' +
|
||||
'<div class="avatar avatar-sm me-4">' +
|
||||
$output +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="d-flex flex-column">' +
|
||||
'<a href="' +
|
||||
userView +
|
||||
'" class="text-heading text-truncate"><span class="fw-medium">' +
|
||||
$name +
|
||||
'</span></a>' +
|
||||
'<small>' +
|
||||
$email +
|
||||
'</small>' +
|
||||
'</div>' +
|
||||
'</div>';
|
||||
return $row_output;
|
||||
}
|
||||
},
|
||||
{
|
||||
// User Role
|
||||
targets: 3,
|
||||
render: function (data, type, full, meta) {
|
||||
var $role = full['role'];
|
||||
var roleBadgeObj = {
|
||||
Subscriber: '<i class="ti ti-crown ti-md text-primary me-2"></i>',
|
||||
Author: '<i class="ti ti-edit ti-md text-warning me-2"></i>',
|
||||
Maintainer: '<i class="ti ti-user ti-md text-success me-2"></i>',
|
||||
Editor: '<i class="ti ti-chart-pie ti-md text-info me-2"></i>',
|
||||
Admin: '<i class="ti ti-device-desktop ti-md text-danger me-2"></i>'
|
||||
};
|
||||
return (
|
||||
"<span class='text-truncate d-flex align-items-center text-heading'>" +
|
||||
roleBadgeObj[$role] +
|
||||
$role +
|
||||
'</span>'
|
||||
);
|
||||
}
|
||||
},
|
||||
{
|
||||
// Plans
|
||||
targets: 4,
|
||||
render: function (data, type, full, meta) {
|
||||
var $plan = full['current_plan'];
|
||||
|
||||
return '<span class="text-heading">' + $plan + '</span>';
|
||||
}
|
||||
},
|
||||
{
|
||||
// User Status
|
||||
targets: 6,
|
||||
render: function (data, type, full, meta) {
|
||||
var $status = full['status'];
|
||||
|
||||
return (
|
||||
'<span class="badge ' +
|
||||
statusObj[$status].class +
|
||||
'" text-capitalized>' +
|
||||
statusObj[$status].title +
|
||||
'</span>'
|
||||
);
|
||||
}
|
||||
},
|
||||
{
|
||||
// Actions
|
||||
targets: -1,
|
||||
title: 'Actions',
|
||||
searchable: false,
|
||||
orderable: false,
|
||||
render: function (data, type, full, meta) {
|
||||
return (
|
||||
'<div class="d-flex align-items-center">' +
|
||||
'<a href="javascript:;" class="btn btn-icon btn-text-secondary waves-effect waves-light rounded-pill delete-record"><i class="ti ti-trash ti-md"></i></a>' +
|
||||
'<a href="' +
|
||||
userView +
|
||||
'" class="btn btn-icon btn-text-secondary waves-effect waves-light rounded-pill"><i class="ti ti-eye ti-md"></i></a>' +
|
||||
'<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:;"" class="dropdown-item">Edit</a>' +
|
||||
'<a href="javascript:;" class="dropdown-item">Suspend</a>' +
|
||||
'</div>' +
|
||||
'</div>'
|
||||
);
|
||||
}
|
||||
}
|
||||
],
|
||||
order: [[2, 'desc']],
|
||||
dom:
|
||||
'<"row"' +
|
||||
'<"col-md-2"<"ms-n2"l>>' +
|
||||
'<"col-md-10"<"dt-action-buttons text-xl-end text-lg-start text-md-end text-start d-flex align-items-center justify-content-end flex-md-row flex-column mb-6 mb-md-0 mt-n6 mt-md-0"fB>>' +
|
||||
'>t' +
|
||||
'<"row"' +
|
||||
'<"col-sm-12 col-md-6"i>' +
|
||||
'<"col-sm-12 col-md-6"p>' +
|
||||
'>',
|
||||
language: {
|
||||
sLengthMenu: '_MENU_',
|
||||
search: '',
|
||||
searchPlaceholder: 'Search User',
|
||||
paginate: {
|
||||
next: '<i class="ti ti-chevron-right ti-sm"></i>',
|
||||
previous: '<i class="ti ti-chevron-left ti-sm"></i>'
|
||||
}
|
||||
},
|
||||
// Buttons with Dropdown
|
||||
buttons: [
|
||||
{
|
||||
extend: 'collection',
|
||||
className: 'btn btn-label-secondary dropdown-toggle mx-4 waves-effect waves-light',
|
||||
text: '<i class="ti ti-upload me-2 ti-xs"></i>Export',
|
||||
buttons: [
|
||||
{
|
||||
extend: 'print',
|
||||
text: '<i class="ti ti-printer me-2" ></i>Print',
|
||||
className: 'dropdown-item',
|
||||
exportOptions: {
|
||||
columns: [1, 2, 3, 4, 5],
|
||||
// prevent avatar to be print
|
||||
format: {
|
||||
body: function (inner, coldex, rowdex) {
|
||||
if (inner.length <= 0) return inner;
|
||||
var el = $.parseHTML(inner);
|
||||
var result = '';
|
||||
$.each(el, function (index, item) {
|
||||
if (item.classList !== undefined && item.classList.contains('user-name')) {
|
||||
result = result + item.lastChild.firstChild.textContent;
|
||||
} else if (item.innerText === undefined) {
|
||||
result = result + item.textContent;
|
||||
} else result = result + item.innerText;
|
||||
});
|
||||
return result;
|
||||
}
|
||||
}
|
||||
},
|
||||
customize: function (win) {
|
||||
//customize print view for dark
|
||||
$(win.document.body)
|
||||
.css('color', headingColor)
|
||||
.css('border-color', borderColor)
|
||||
.css('background-color', bodyBg);
|
||||
$(win.document.body)
|
||||
.find('table')
|
||||
.addClass('compact')
|
||||
.css('color', 'inherit')
|
||||
.css('border-color', 'inherit')
|
||||
.css('background-color', 'inherit');
|
||||
}
|
||||
},
|
||||
{
|
||||
extend: 'csv',
|
||||
text: '<i class="ti ti-file-text me-2" ></i>Csv',
|
||||
className: 'dropdown-item',
|
||||
exportOptions: {
|
||||
columns: [1, 2, 3, 4, 5],
|
||||
// prevent avatar to be display
|
||||
format: {
|
||||
body: function (inner, coldex, rowdex) {
|
||||
if (inner.length <= 0) return inner;
|
||||
var el = $.parseHTML(inner);
|
||||
var result = '';
|
||||
$.each(el, function (index, item) {
|
||||
if (item.classList !== undefined && item.classList.contains('user-name')) {
|
||||
result = result + item.lastChild.firstChild.textContent;
|
||||
} else if (item.innerText === undefined) {
|
||||
result = result + item.textContent;
|
||||
} else result = result + item.innerText;
|
||||
});
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
extend: 'excel',
|
||||
text: '<i class="ti ti-file-spreadsheet me-2"></i>Excel',
|
||||
className: 'dropdown-item',
|
||||
exportOptions: {
|
||||
columns: [1, 2, 3, 4, 5],
|
||||
// prevent avatar to be display
|
||||
format: {
|
||||
body: function (inner, coldex, rowdex) {
|
||||
if (inner.length <= 0) return inner;
|
||||
var el = $.parseHTML(inner);
|
||||
var result = '';
|
||||
$.each(el, function (index, item) {
|
||||
if (item.classList !== undefined && item.classList.contains('user-name')) {
|
||||
result = result + item.lastChild.firstChild.textContent;
|
||||
} else if (item.innerText === undefined) {
|
||||
result = result + item.textContent;
|
||||
} else result = result + item.innerText;
|
||||
});
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
extend: 'pdf',
|
||||
text: '<i class="ti ti-file-code-2 me-2"></i>Pdf',
|
||||
className: 'dropdown-item',
|
||||
exportOptions: {
|
||||
columns: [1, 2, 3, 4, 5],
|
||||
// prevent avatar to be display
|
||||
format: {
|
||||
body: function (inner, coldex, rowdex) {
|
||||
if (inner.length <= 0) return inner;
|
||||
var el = $.parseHTML(inner);
|
||||
var result = '';
|
||||
$.each(el, function (index, item) {
|
||||
if (item.classList !== undefined && item.classList.contains('user-name')) {
|
||||
result = result + item.lastChild.firstChild.textContent;
|
||||
} else if (item.innerText === undefined) {
|
||||
result = result + item.textContent;
|
||||
} else result = result + item.innerText;
|
||||
});
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
extend: 'copy',
|
||||
text: '<i class="ti ti-copy me-2" ></i>Copy',
|
||||
className: 'dropdown-item',
|
||||
exportOptions: {
|
||||
columns: [1, 2, 3, 4, 5],
|
||||
// prevent avatar to be display
|
||||
format: {
|
||||
body: function (inner, coldex, rowdex) {
|
||||
if (inner.length <= 0) return inner;
|
||||
var el = $.parseHTML(inner);
|
||||
var result = '';
|
||||
$.each(el, function (index, item) {
|
||||
if (item.classList !== undefined && item.classList.contains('user-name')) {
|
||||
result = result + item.lastChild.firstChild.textContent;
|
||||
} else if (item.innerText === undefined) {
|
||||
result = result + item.textContent;
|
||||
} else result = result + item.innerText;
|
||||
});
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
text: '<i class="ti ti-plus me-0 me-sm-1 ti-xs"></i><span class="d-none d-sm-inline-block">Add New User</span>',
|
||||
className: 'add-new btn btn-primary waves-effect waves-light',
|
||||
attr: {
|
||||
'data-bs-toggle': 'offcanvas',
|
||||
'data-bs-target': '#offcanvasAddUser'
|
||||
}
|
||||
}
|
||||
],
|
||||
// For responsive popup
|
||||
responsive: {
|
||||
details: {
|
||||
display: $.fn.dataTable.Responsive.display.modal({
|
||||
header: function (row) {
|
||||
var data = row.data();
|
||||
return 'Details of ' + data['full_name'];
|
||||
}
|
||||
}),
|
||||
type: 'column',
|
||||
renderer: function (api, rowIdx, columns) {
|
||||
var data = $.map(columns, function (col, i) {
|
||||
return col.title !== '' // ? Do not show row in modal popup if title is blank (for check box)
|
||||
? '<tr data-dt-row="' +
|
||||
col.rowIndex +
|
||||
'" data-dt-column="' +
|
||||
col.columnIndex +
|
||||
'">' +
|
||||
'<td>' +
|
||||
col.title +
|
||||
':' +
|
||||
'</td> ' +
|
||||
'<td>' +
|
||||
col.data +
|
||||
'</td>' +
|
||||
'</tr>'
|
||||
: '';
|
||||
}).join('');
|
||||
|
||||
return data ? $('<table class="table"/><tbody />').append(data) : false;
|
||||
}
|
||||
}
|
||||
},
|
||||
initComplete: function () {
|
||||
// Adding role filter once table initialized
|
||||
this.api()
|
||||
.columns(3)
|
||||
.every(function () {
|
||||
var column = this;
|
||||
var select = $(
|
||||
'<select id="UserRole" class="form-select text-capitalize"><option value=""> Select Role </option></select>'
|
||||
)
|
||||
.appendTo('.user_role')
|
||||
.on('change', function () {
|
||||
var val = $.fn.dataTable.util.escapeRegex($(this).val());
|
||||
column.search(val ? '^' + val + '$' : '', true, false).draw();
|
||||
});
|
||||
|
||||
column
|
||||
.data()
|
||||
.unique()
|
||||
.sort()
|
||||
.each(function (d, j) {
|
||||
select.append('<option value="' + d + '">' + d + '</option>');
|
||||
});
|
||||
});
|
||||
// Adding plan filter once table initialized
|
||||
this.api()
|
||||
.columns(4)
|
||||
.every(function () {
|
||||
var column = this;
|
||||
var select = $(
|
||||
'<select id="UserPlan" class="form-select text-capitalize"><option value=""> Select Plan </option></select>'
|
||||
)
|
||||
.appendTo('.user_plan')
|
||||
.on('change', function () {
|
||||
var val = $.fn.dataTable.util.escapeRegex($(this).val());
|
||||
column.search(val ? '^' + val + '$' : '', true, false).draw();
|
||||
});
|
||||
|
||||
column
|
||||
.data()
|
||||
.unique()
|
||||
.sort()
|
||||
.each(function (d, j) {
|
||||
select.append('<option value="' + d + '">' + d + '</option>');
|
||||
});
|
||||
});
|
||||
// Adding status filter once table initialized
|
||||
this.api()
|
||||
.columns(6)
|
||||
.every(function () {
|
||||
var column = this;
|
||||
var select = $(
|
||||
'<select id="FilterTransaction" class="form-select text-capitalize"><option value=""> Select Status </option></select>'
|
||||
)
|
||||
.appendTo('.user_status')
|
||||
.on('change', function () {
|
||||
var val = $.fn.dataTable.util.escapeRegex($(this).val());
|
||||
column.search(val ? '^' + val + '$' : '', true, false).draw();
|
||||
});
|
||||
|
||||
column
|
||||
.data()
|
||||
.unique()
|
||||
.sort()
|
||||
.each(function (d, j) {
|
||||
select.append(
|
||||
'<option value="' +
|
||||
statusObj[d].title +
|
||||
'" class="text-capitalize">' +
|
||||
statusObj[d].title +
|
||||
'</option>'
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Delete Record
|
||||
$('.datatables-users tbody').on('click', '.delete-record', function () {
|
||||
dt_user.row($(this).parents('tr')).remove().draw();
|
||||
});
|
||||
|
||||
// Filter form control to default size
|
||||
// ? setTimeout used for multilingual table initialization
|
||||
setTimeout(() => {
|
||||
$('.dataTables_filter .form-control').removeClass('form-control-sm');
|
||||
$('.dataTables_length .form-select').removeClass('form-select-sm');
|
||||
}, 300);
|
||||
});
|
||||
|
||||
// Validation & Phone mask
|
||||
(function () {
|
||||
const phoneMaskList = document.querySelectorAll('.phone-mask'),
|
||||
addNewUserForm = document.getElementById('addNewUserForm');
|
||||
|
||||
// Phone Number
|
||||
if (phoneMaskList) {
|
||||
phoneMaskList.forEach(function (phoneMask) {
|
||||
new Cleave(phoneMask, {
|
||||
phone: true,
|
||||
phoneRegionCode: 'US'
|
||||
});
|
||||
});
|
||||
}
|
||||
// Add New User Form Validation
|
||||
const fv = FormValidation.formValidation(addNewUserForm, {
|
||||
fields: {
|
||||
userFullname: {
|
||||
validators: {
|
||||
notEmpty: {
|
||||
message: 'Please enter fullname '
|
||||
}
|
||||
}
|
||||
},
|
||||
userEmail: {
|
||||
validators: {
|
||||
notEmpty: {
|
||||
message: 'Please enter your email'
|
||||
},
|
||||
emailAddress: {
|
||||
message: 'The value is not a valid email address'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
plugins: {
|
||||
trigger: new FormValidation.plugins.Trigger(),
|
||||
bootstrap5: new FormValidation.plugins.Bootstrap5({
|
||||
// Use this for enabling/changing valid/invalid class
|
||||
eleValidClass: '',
|
||||
rowSelector: function (field, ele) {
|
||||
// field is the field name & ele is the field element
|
||||
return '.mb-6';
|
||||
}
|
||||
}),
|
||||
submitButton: new FormValidation.plugins.SubmitButton(),
|
||||
// Submit the form when all fields are valid
|
||||
// defaultSubmit: new FormValidation.plugins.DefaultSubmit(),
|
||||
autoFocus: new FormValidation.plugins.AutoFocus()
|
||||
}
|
||||
});
|
||||
})();
|
222
modules/Admin/Resources/js/auth/app-user-view-account.js
Normal file
222
modules/Admin/Resources/js/auth/app-user-view-account.js
Normal file
@ -0,0 +1,222 @@
|
||||
/**
|
||||
* App User View - Account (jquery)
|
||||
*/
|
||||
|
||||
$(function () {
|
||||
'use strict';
|
||||
|
||||
// Variable declaration for table
|
||||
var dt_invoice_table = $('.datatable-invoice');
|
||||
|
||||
// Invoice datatable
|
||||
// --------------------------------------------------------------------
|
||||
if (dt_invoice_table.length) {
|
||||
var dt_invoice = dt_invoice_table.DataTable({
|
||||
ajax: assetsPath + 'json/invoice-list.json', // JSON file to add data
|
||||
columns: [
|
||||
// columns according to JSON
|
||||
{ data: '' },
|
||||
{ data: 'invoice_id' },
|
||||
{ data: 'invoice_status' },
|
||||
{ data: 'total' },
|
||||
{ data: 'issued_date' },
|
||||
{ data: 'action' }
|
||||
],
|
||||
columnDefs: [
|
||||
{
|
||||
// For Responsive
|
||||
className: 'control',
|
||||
responsivePriority: 2,
|
||||
targets: 0,
|
||||
render: function (data, type, full, meta) {
|
||||
return '';
|
||||
}
|
||||
},
|
||||
{
|
||||
// Invoice ID
|
||||
targets: 1,
|
||||
render: function (data, type, full, meta) {
|
||||
var $invoice_id = full['invoice_id'];
|
||||
// Creates full output for row
|
||||
var $row_output = '<a href="' + baseUrl + 'app/invoice/preview"><span>#' + $invoice_id + '</span></a>';
|
||||
return $row_output;
|
||||
}
|
||||
},
|
||||
{
|
||||
// Invoice status
|
||||
targets: 2,
|
||||
render: function (data, type, full, meta) {
|
||||
var $invoice_status = full['invoice_status'],
|
||||
$due_date = full['due_date'],
|
||||
$balance = full['balance'];
|
||||
var roleBadgeObj = {
|
||||
Sent: '<span class="badge badge-center d-flex align-items-center justify-content-center rounded-pill bg-label-secondary w-px-30 h-px-30"><i class="ti ti-circle-check ti-xs"></i></span>',
|
||||
Draft:
|
||||
'<span class="badge badge-center d-flex align-items-center justify-content-center rounded-pill bg-label-primary w-px-30 h-px-30"><i class="ti ti-device-floppy ti-xs"></i></span>',
|
||||
'Past Due':
|
||||
'<span class="badge badge-center d-flex align-items-center justify-content-center rounded-pill bg-label-danger w-px-30 h-px-30"><i class="ti ti-info-circle ti-xs"></i></span>',
|
||||
'Partial Payment':
|
||||
'<span class="badge badge-center d-flex align-items-center justify-content-center rounded-pill bg-label-success w-px-30 h-px-30"><i class="ti ti-circle-half-2 ti-xs"></i></span>',
|
||||
Paid: '<span class="badge badge-center d-flex align-items-center justify-content-center rounded-pill bg-label-warning w-px-30 h-px-30"><i class="ti ti-chart-pie ti-xs"></i></span>',
|
||||
Downloaded:
|
||||
'<span class="badge badge-center d-flex align-items-center justify-content-center rounded-pill bg-label-info w-px-30 h-px-30"><i class="ti ti-arrow-down-circle ti-xs"></i></span>'
|
||||
};
|
||||
return (
|
||||
"<span class='d-inline-block' data-bs-toggle='tooltip' data-bs-html='true' title='<span>" +
|
||||
$invoice_status +
|
||||
'<br> <span class="fw-medium">Balance:</span> ' +
|
||||
$balance +
|
||||
'<br> <span class="fw-medium">Due Date:</span> ' +
|
||||
$due_date +
|
||||
"</span>'>" +
|
||||
roleBadgeObj[$invoice_status] +
|
||||
'</span>'
|
||||
);
|
||||
}
|
||||
},
|
||||
{
|
||||
// Total Invoice Amount
|
||||
targets: 3,
|
||||
render: function (data, type, full, meta) {
|
||||
var $total = full['total'];
|
||||
return '$' + $total;
|
||||
}
|
||||
},
|
||||
{
|
||||
// Actions
|
||||
targets: -1,
|
||||
title: 'Actions',
|
||||
orderable: false,
|
||||
render: function (data, type, full, meta) {
|
||||
return (
|
||||
'<div class="d-flex align-items-center">' +
|
||||
'<a href="javascript:;" class="btn btn-icon btn-text-secondary waves-effect waves-light rounded-pill delete-record" data-bs-toggle="tooltip" title="Delete record"><i class="ti ti-trash ti-md"></i></a>' +
|
||||
'<a href="app-invoice-preview.html" class="btn btn-icon btn-text-secondary waves-effect waves-light rounded-pill" data-bs-toggle="tooltip" title="Preview"><i class="ti ti-eye ti-md"></i></a>' +
|
||||
'<div class="d-inline-block">' +
|
||||
'<a href="javascript:;" class="btn btn-sm btn-icon dropdown-toggle hide-arrow btn btn-icon btn-text-secondary waves-effect waves-light rounded-pill" data-bs-toggle="dropdown"><i class="ti ti-dots-vertical ti-md"></i></a>' +
|
||||
'<ul class="dropdown-menu dropdown-menu-end m-0">' +
|
||||
'<li><a href="javascript:;" class="dropdown-item">Details</a></li>' +
|
||||
'<li><a href="javascript:;" class="dropdown-item">Archive</a></li>' +
|
||||
'</ul>' +
|
||||
'</div>' +
|
||||
'</div>'
|
||||
);
|
||||
}
|
||||
}
|
||||
],
|
||||
order: [[1, 'desc']],
|
||||
dom:
|
||||
'<"row mx-6"' +
|
||||
'<"col-sm-6 col-12 d-flex align-items-center justify-content-center justify-content-sm-start mt-6 mt-sm-0"<"invoice-head-label">>' +
|
||||
'<"col-sm-6 col-12 d-flex justify-content-center justify-content-md-end align-items-baseline"<"dt-action-buttons d-flex justify-content-center flex-md-row align-items-baseline gap-2"lB>>' +
|
||||
'>t' +
|
||||
'<"row mx-4"' +
|
||||
'<"col-sm-12 col-xxl-6 text-center text-xxl-start pb-md-2 pb-xxl-0"i>' +
|
||||
'<"col-sm-12 col-xxl-6 d-md-flex justify-content-xxl-end justify-content-center"p>' +
|
||||
'>',
|
||||
language: {
|
||||
sLengthMenu: 'Show _MENU_',
|
||||
search: '',
|
||||
searchPlaceholder: 'Search Invoice',
|
||||
paginate: {
|
||||
next: '<i class="ti ti-chevron-right ti-sm"></i>',
|
||||
previous: '<i class="ti ti-chevron-left ti-sm"></i>'
|
||||
}
|
||||
},
|
||||
// Buttons with Dropdown
|
||||
buttons: [
|
||||
{
|
||||
extend: 'collection',
|
||||
className: 'btn btn-label-secondary dropdown-toggle float-sm-end mb-3 mb-sm-0 waves-effect waves-light',
|
||||
text: '<i class="ti ti-upload ti-xs me-2"></i>Export',
|
||||
buttons: [
|
||||
{
|
||||
extend: 'print',
|
||||
text: '<i class="ti ti-printer me-2" ></i>Print',
|
||||
className: 'dropdown-item',
|
||||
exportOptions: { columns: [1, 2, 3, 4] }
|
||||
},
|
||||
{
|
||||
extend: 'csv',
|
||||
text: '<i class="ti ti-file-text me-2" ></i>Csv',
|
||||
className: 'dropdown-item',
|
||||
exportOptions: { columns: [1, 2, 3, 4] }
|
||||
},
|
||||
{
|
||||
extend: 'excel',
|
||||
text: '<i class="ti ti-file-spreadsheet me-2"></i>Excel',
|
||||
className: 'dropdown-item',
|
||||
exportOptions: { columns: [1, 2, 3, 4] }
|
||||
},
|
||||
{
|
||||
extend: 'pdf',
|
||||
text: '<i class="ti ti-file-description me-2"></i>Pdf',
|
||||
className: 'dropdown-item',
|
||||
exportOptions: { columns: [1, 2, 3, 4] }
|
||||
},
|
||||
{
|
||||
extend: 'copy',
|
||||
text: '<i class="ti ti-copy me-2" ></i>Copy',
|
||||
className: 'dropdown-item',
|
||||
exportOptions: { columns: [1, 2, 3, 4] }
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
// For responsive popup
|
||||
responsive: {
|
||||
details: {
|
||||
display: $.fn.dataTable.Responsive.display.modal({
|
||||
header: function (row) {
|
||||
var data = row.data();
|
||||
return 'Details of ' + data['full_name'];
|
||||
}
|
||||
}),
|
||||
type: 'column',
|
||||
renderer: function (api, rowIdx, columns) {
|
||||
var data = $.map(columns, function (col, i) {
|
||||
return col.title !== '' // ? Do not show row in modal popup if title is blank (for check box)
|
||||
? '<tr data-dt-row="' +
|
||||
col.rowIndex +
|
||||
'" data-dt-column="' +
|
||||
col.columnIndex +
|
||||
'">' +
|
||||
'<td>' +
|
||||
col.title +
|
||||
':' +
|
||||
'</td> ' +
|
||||
'<td>' +
|
||||
col.data +
|
||||
'</td>' +
|
||||
'</tr>'
|
||||
: '';
|
||||
}).join('');
|
||||
|
||||
return data ? $('<table class="table"/><tbody />').append(data) : false;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
$('div.invoice-head-label').html('<h5 class="card-title mb-0">Invoice List</h5>');
|
||||
}
|
||||
// On each datatable draw, initialize tooltip
|
||||
dt_invoice_table.on('draw.dt', function () {
|
||||
var tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]'));
|
||||
var tooltipList = tooltipTriggerList.map(function (tooltipTriggerEl) {
|
||||
return new bootstrap.Tooltip(tooltipTriggerEl, {
|
||||
boundary: document.body
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// Delete Record
|
||||
$('.datatable-invoice tbody').on('click', '.delete-record', function () {
|
||||
dt_invoice.row($(this).parents('tr')).remove().draw();
|
||||
});
|
||||
// Filter form control to default size
|
||||
// ? setTimeout used for multilingual table initialization
|
||||
setTimeout(() => {
|
||||
$('.dataTables_filter .form-control').removeClass('form-control-sm');
|
||||
$('.dataTables_length .form-select').removeClass('form-select-sm');
|
||||
}, 300);
|
||||
});
|
57
modules/Admin/Resources/js/auth/app-user-view-billing.js
Normal file
57
modules/Admin/Resources/js/auth/app-user-view-billing.js
Normal file
@ -0,0 +1,57 @@
|
||||
/**
|
||||
* App User View - Billing
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
(function () {
|
||||
// Cancel Subscription alert
|
||||
const cancelSubscription = document.querySelector('.cancel-subscription');
|
||||
|
||||
// Alert With Functional Confirm Button
|
||||
if (cancelSubscription) {
|
||||
cancelSubscription.onclick = function () {
|
||||
Swal.fire({
|
||||
text: 'Are you sure you would like to cancel your subscription?',
|
||||
icon: 'warning',
|
||||
showCancelButton: true,
|
||||
confirmButtonText: 'Yes',
|
||||
customClass: {
|
||||
confirmButton: 'btn btn-primary me-2 waves-effect waves-light',
|
||||
cancelButton: 'btn btn-label-secondary waves-effect waves-light'
|
||||
},
|
||||
buttonsStyling: false
|
||||
}).then(function (result) {
|
||||
if (result.value) {
|
||||
Swal.fire({
|
||||
icon: 'success',
|
||||
title: 'Unsubscribed!',
|
||||
text: 'Your subscription cancelled successfully.',
|
||||
customClass: {
|
||||
confirmButton: 'btn btn-success waves-effect waves-light'
|
||||
}
|
||||
});
|
||||
} else if (result.dismiss === Swal.DismissReason.cancel) {
|
||||
Swal.fire({
|
||||
title: 'Cancelled',
|
||||
text: 'Unsubscription Cancelled!!',
|
||||
icon: 'error',
|
||||
customClass: {
|
||||
confirmButton: 'btn btn-success waves-effect waves-light'
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
// On edit address click, update text of add address modal
|
||||
const addressEdit = document.querySelector('.edit-address'),
|
||||
addressTitle = document.querySelector('.address-title'),
|
||||
addressSubTitle = document.querySelector('.address-subtitle');
|
||||
|
||||
addressEdit.onclick = function () {
|
||||
addressTitle.innerHTML = 'Edit Address'; // reset text
|
||||
addressSubTitle.innerHTML = 'Edit your current address';
|
||||
};
|
||||
})();
|
63
modules/Admin/Resources/js/auth/app-user-view-security.js
Normal file
63
modules/Admin/Resources/js/auth/app-user-view-security.js
Normal file
@ -0,0 +1,63 @@
|
||||
/**
|
||||
* App User View - Security
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
(function () {
|
||||
const formChangePass = document.querySelector('#formChangePassword');
|
||||
|
||||
// Form validation for Change password
|
||||
if (formChangePass) {
|
||||
const fv = FormValidation.formValidation(formChangePass, {
|
||||
fields: {
|
||||
newPassword: {
|
||||
validators: {
|
||||
notEmpty: {
|
||||
message: 'Please enter new password'
|
||||
},
|
||||
stringLength: {
|
||||
min: 8,
|
||||
message: 'Password must be more than 8 characters'
|
||||
}
|
||||
}
|
||||
},
|
||||
confirmPassword: {
|
||||
validators: {
|
||||
notEmpty: {
|
||||
message: 'Please confirm new password'
|
||||
},
|
||||
identical: {
|
||||
compare: function () {
|
||||
return formChangePass.querySelector('[name="newPassword"]').value;
|
||||
},
|
||||
message: 'The password and its confirm are not the same'
|
||||
},
|
||||
stringLength: {
|
||||
min: 8,
|
||||
message: 'Password must be more than 8 characters'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
plugins: {
|
||||
trigger: new FormValidation.plugins.Trigger(),
|
||||
bootstrap5: new FormValidation.plugins.Bootstrap5({
|
||||
eleValidClass: '',
|
||||
rowSelector: '.form-password-toggle'
|
||||
}),
|
||||
submitButton: new FormValidation.plugins.SubmitButton(),
|
||||
// Submit the form when all fields are valid
|
||||
// defaultSubmit: new FormValidation.plugins.DefaultSubmit(),
|
||||
autoFocus: new FormValidation.plugins.AutoFocus()
|
||||
},
|
||||
init: instance => {
|
||||
instance.on('plugins.message.placed', function (e) {
|
||||
if (e.element.parentElement.classList.contains('input-group')) {
|
||||
e.element.parentElement.insertAdjacentElement('afterend', e.messageElement);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
})();
|
89
modules/Admin/Resources/js/auth/app-user-view.js
Normal file
89
modules/Admin/Resources/js/auth/app-user-view.js
Normal file
@ -0,0 +1,89 @@
|
||||
/**
|
||||
* App User View - Suspend User Script
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
(function () {
|
||||
const suspendUser = document.querySelector('.suspend-user');
|
||||
|
||||
// Suspend User javascript
|
||||
if (suspendUser) {
|
||||
suspendUser.onclick = function () {
|
||||
Swal.fire({
|
||||
title: 'Are you sure?',
|
||||
text: "You won't be able to revert user!",
|
||||
icon: 'warning',
|
||||
showCancelButton: true,
|
||||
confirmButtonText: 'Yes, Suspend user!',
|
||||
customClass: {
|
||||
confirmButton: 'btn btn-primary me-2 waves-effect waves-light',
|
||||
cancelButton: 'btn btn-label-secondary waves-effect waves-light'
|
||||
},
|
||||
buttonsStyling: false
|
||||
}).then(function (result) {
|
||||
if (result.value) {
|
||||
Swal.fire({
|
||||
icon: 'success',
|
||||
title: 'Suspended!',
|
||||
text: 'User has been suspended.',
|
||||
customClass: {
|
||||
confirmButton: 'btn btn-success waves-effect waves-light'
|
||||
}
|
||||
});
|
||||
} else if (result.dismiss === Swal.DismissReason.cancel) {
|
||||
Swal.fire({
|
||||
title: 'Cancelled',
|
||||
text: 'Cancelled Suspension :)',
|
||||
icon: 'error',
|
||||
customClass: {
|
||||
confirmButton: 'btn btn-success waves-effect waves-light'
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
//? Billing page have multiple buttons
|
||||
// Cancel Subscription alert
|
||||
const cancelSubscription = document.querySelectorAll('.cancel-subscription');
|
||||
|
||||
// Alert With Functional Confirm Button
|
||||
if (cancelSubscription) {
|
||||
cancelSubscription.forEach(btnCancle => {
|
||||
btnCancle.onclick = function () {
|
||||
Swal.fire({
|
||||
text: 'Are you sure you would like to cancel your subscription?',
|
||||
icon: 'warning',
|
||||
showCancelButton: true,
|
||||
confirmButtonText: 'Yes',
|
||||
customClass: {
|
||||
confirmButton: 'btn btn-primary me-2 waves-effect waves-light',
|
||||
cancelButton: 'btn btn-label-secondary waves-effect waves-light'
|
||||
},
|
||||
buttonsStyling: false
|
||||
}).then(function (result) {
|
||||
if (result.value) {
|
||||
Swal.fire({
|
||||
icon: 'success',
|
||||
title: 'Unsubscribed!',
|
||||
text: 'Your subscription cancelled successfully.',
|
||||
customClass: {
|
||||
confirmButton: 'btn btn-success waves-effect waves-light'
|
||||
}
|
||||
});
|
||||
} else if (result.dismiss === Swal.DismissReason.cancel) {
|
||||
Swal.fire({
|
||||
title: 'Cancelled',
|
||||
text: 'Unsubscription Cancelled!!',
|
||||
icon: 'error',
|
||||
customClass: {
|
||||
confirmButton: 'btn btn-success waves-effect waves-light'
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
});
|
||||
}
|
||||
})();
|
73
modules/Admin/Resources/js/auth/modal-add-new-address.js
Normal file
73
modules/Admin/Resources/js/auth/modal-add-new-address.js
Normal file
@ -0,0 +1,73 @@
|
||||
/**
|
||||
* Add New Address
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
// Select2 (jquery)
|
||||
$(function () {
|
||||
const select2 = $('.select2');
|
||||
|
||||
// Select2 Country
|
||||
if (select2.length) {
|
||||
select2.each(function () {
|
||||
var $this = $(this);
|
||||
$this.wrap('<div class="position-relative"></div>').select2({
|
||||
placeholder: 'Select value',
|
||||
dropdownParent: $this.parent()
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Add New Address form validation
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
(function () {
|
||||
// initCustomOptionCheck on modal show to update the custom select
|
||||
let addNewAddress = document.getElementById('addNewAddress');
|
||||
addNewAddress.addEventListener('show.bs.modal', function (event) {
|
||||
// Init custom option check
|
||||
window.Helpers.initCustomOptionCheck();
|
||||
});
|
||||
|
||||
FormValidation.formValidation(document.getElementById('addNewAddressForm'), {
|
||||
fields: {
|
||||
modalAddressFirstName: {
|
||||
validators: {
|
||||
notEmpty: {
|
||||
message: 'Please enter your first name'
|
||||
},
|
||||
regexp: {
|
||||
regexp: /^[a-zA-Zs]+$/,
|
||||
message: 'The first name can only consist of alphabetical'
|
||||
}
|
||||
}
|
||||
},
|
||||
modalAddressLastName: {
|
||||
validators: {
|
||||
notEmpty: {
|
||||
message: 'Please enter your last name'
|
||||
},
|
||||
regexp: {
|
||||
regexp: /^[a-zA-Zs]+$/,
|
||||
message: 'The last name can only consist of alphabetical'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
plugins: {
|
||||
trigger: new FormValidation.plugins.Trigger(),
|
||||
bootstrap5: new FormValidation.plugins.Bootstrap5({
|
||||
// Use this for enabling/changing valid/invalid class
|
||||
// eleInvalidClass: '',
|
||||
eleValidClass: '',
|
||||
rowSelector: '.col-12'
|
||||
}),
|
||||
submitButton: new FormValidation.plugins.SubmitButton(),
|
||||
// Submit the form when all fields are valid
|
||||
// defaultSubmit: new FormValidation.plugins.DefaultSubmit(),
|
||||
autoFocus: new FormValidation.plugins.AutoFocus()
|
||||
}
|
||||
});
|
||||
})();
|
||||
});
|
107
modules/Admin/Resources/js/auth/modal-add-new-cc.js
Normal file
107
modules/Admin/Resources/js/auth/modal-add-new-cc.js
Normal file
@ -0,0 +1,107 @@
|
||||
/**
|
||||
* Add new credit card
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function (e) {
|
||||
(function () {
|
||||
// Variables
|
||||
const creditCardMask = document.querySelector('.credit-card-mask'),
|
||||
expiryDateMask = document.querySelector('.expiry-date-mask'),
|
||||
cvvMask = document.querySelector('.cvv-code-mask'),
|
||||
btnReset = document.querySelector('.btn-reset');
|
||||
let cleave;
|
||||
|
||||
// Credit Card
|
||||
function initCleave() {
|
||||
if (creditCardMask) {
|
||||
cleave = new Cleave(creditCardMask, {
|
||||
creditCard: true,
|
||||
onCreditCardTypeChanged: function (type) {
|
||||
if (type != '' && type != 'unknown') {
|
||||
document.querySelector('.card-type').innerHTML =
|
||||
'<img src="' +
|
||||
assetsPath +
|
||||
'img/icons/payments/' +
|
||||
type +
|
||||
'-cc.png" class="cc-icon-image" height="28"/>';
|
||||
} else {
|
||||
document.querySelector('.card-type').innerHTML = '';
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Init cleave on show modal (To fix the cc image issue)
|
||||
let addNewCCModal = document.getElementById('addNewCCModal');
|
||||
addNewCCModal.addEventListener('show.bs.modal', function (event) {
|
||||
initCleave();
|
||||
});
|
||||
|
||||
// Expiry Date Mask
|
||||
if (expiryDateMask) {
|
||||
new Cleave(expiryDateMask, {
|
||||
date: true,
|
||||
delimiter: '/',
|
||||
datePattern: ['m', 'y']
|
||||
});
|
||||
}
|
||||
|
||||
// CVV
|
||||
if (cvvMask) {
|
||||
new Cleave(cvvMask, {
|
||||
numeral: true,
|
||||
numeralPositiveOnly: true
|
||||
});
|
||||
}
|
||||
|
||||
// Credit card form validation
|
||||
FormValidation.formValidation(document.getElementById('addNewCCForm'), {
|
||||
fields: {
|
||||
modalAddCard: {
|
||||
validators: {
|
||||
notEmpty: {
|
||||
message: 'Please enter your credit card number'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
plugins: {
|
||||
trigger: new FormValidation.plugins.Trigger(),
|
||||
bootstrap5: new FormValidation.plugins.Bootstrap5({
|
||||
// Use this for enabling/changing valid/invalid class
|
||||
// eleInvalidClass: '',
|
||||
eleValidClass: '',
|
||||
rowSelector: '.col-12'
|
||||
}),
|
||||
submitButton: new FormValidation.plugins.SubmitButton(),
|
||||
// Submit the form when all fields are valid
|
||||
// defaultSubmit: new FormValidation.plugins.DefaultSubmit(),
|
||||
autoFocus: new FormValidation.plugins.AutoFocus()
|
||||
},
|
||||
init: instance => {
|
||||
instance.on('plugins.message.placed', function (e) {
|
||||
//* Move the error message out of the `input-group` element
|
||||
if (e.element.parentElement.classList.contains('input-group')) {
|
||||
e.element.parentElement.insertAdjacentElement('afterend', e.messageElement);
|
||||
}
|
||||
});
|
||||
}
|
||||
}).on('plugins.message.displayed', function (e) {
|
||||
if (e.element.parentElement.classList.contains('input-group')) {
|
||||
//* Move the error message out of the `input-group` element
|
||||
e.element.parentElement.insertAdjacentElement('afterend', e.messageElement.parentElement);
|
||||
}
|
||||
});
|
||||
|
||||
// reset card image on click of cancel
|
||||
btnReset.addEventListener('click', function (e) {
|
||||
// blank '.card-type' innerHTML to remove image
|
||||
document.querySelector('.card-type').innerHTML = '';
|
||||
// destroy cleave and init again on modal open
|
||||
cleave.destroy();
|
||||
});
|
||||
})();
|
||||
});
|
35
modules/Admin/Resources/js/auth/modal-add-permission.js
Normal file
35
modules/Admin/Resources/js/auth/modal-add-permission.js
Normal file
@ -0,0 +1,35 @@
|
||||
/**
|
||||
* Add Permission Modal JS
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
// Add permission form validation
|
||||
document.addEventListener('DOMContentLoaded', function (e) {
|
||||
(function () {
|
||||
FormValidation.formValidation(document.getElementById('addPermissionForm'), {
|
||||
fields: {
|
||||
modalPermissionName: {
|
||||
validators: {
|
||||
notEmpty: {
|
||||
message: 'Please enter permission name'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
plugins: {
|
||||
trigger: new FormValidation.plugins.Trigger(),
|
||||
bootstrap5: new FormValidation.plugins.Bootstrap5({
|
||||
// Use this for enabling/changing valid/invalid class
|
||||
// eleInvalidClass: '',
|
||||
eleValidClass: '',
|
||||
rowSelector: '.col-12'
|
||||
}),
|
||||
submitButton: new FormValidation.plugins.SubmitButton(),
|
||||
// Submit the form when all fields are valid
|
||||
// defaultSubmit: new FormValidation.plugins.DefaultSubmit(),
|
||||
autoFocus: new FormValidation.plugins.AutoFocus()
|
||||
}
|
||||
});
|
||||
})();
|
||||
});
|
44
modules/Admin/Resources/js/auth/modal-add-role.js
Normal file
44
modules/Admin/Resources/js/auth/modal-add-role.js
Normal file
@ -0,0 +1,44 @@
|
||||
/**
|
||||
* Add new role Modal JS
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function (e) {
|
||||
(function () {
|
||||
// add role form validation
|
||||
FormValidation.formValidation(document.getElementById('addRoleForm'), {
|
||||
fields: {
|
||||
modalRoleName: {
|
||||
validators: {
|
||||
notEmpty: {
|
||||
message: 'Please enter role name'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
plugins: {
|
||||
trigger: new FormValidation.plugins.Trigger(),
|
||||
bootstrap5: new FormValidation.plugins.Bootstrap5({
|
||||
// Use this for enabling/changing valid/invalid class
|
||||
// eleInvalidClass: '',
|
||||
eleValidClass: '',
|
||||
rowSelector: '.col-12'
|
||||
}),
|
||||
submitButton: new FormValidation.plugins.SubmitButton(),
|
||||
// Submit the form when all fields are valid
|
||||
// defaultSubmit: new FormValidation.plugins.DefaultSubmit(),
|
||||
autoFocus: new FormValidation.plugins.AutoFocus()
|
||||
}
|
||||
});
|
||||
|
||||
// Select All checkbox click
|
||||
const selectAll = document.querySelector('#selectAll'),
|
||||
checkboxList = document.querySelectorAll('[type="checkbox"]');
|
||||
selectAll.addEventListener('change', t => {
|
||||
checkboxList.forEach(e => {
|
||||
e.checked = t.target.checked;
|
||||
});
|
||||
});
|
||||
})();
|
||||
});
|
79
modules/Admin/Resources/js/auth/modal-edit-cc.js
Normal file
79
modules/Admin/Resources/js/auth/modal-edit-cc.js
Normal file
@ -0,0 +1,79 @@
|
||||
/**
|
||||
* Edit credit card
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function (e) {
|
||||
(function () {
|
||||
const editCreditCardMaskEdit = document.querySelector('.credit-card-mask-edit'),
|
||||
editExpiryDateMaskEdit = document.querySelector('.expiry-date-mask-edit'),
|
||||
editCVVMaskEdit = document.querySelector('.cvv-code-mask-edit');
|
||||
|
||||
// Credit Card
|
||||
if (editCreditCardMaskEdit) {
|
||||
new Cleave(editCreditCardMaskEdit, {
|
||||
creditCard: true,
|
||||
onCreditCardTypeChanged: function (type) {
|
||||
if (type != '' && type != 'unknown') {
|
||||
document.querySelector('.card-type-edit').innerHTML =
|
||||
'<img src="' + assetsPath + 'img/icons/payments/' + type + '-cc.png" height="28"/>';
|
||||
} else {
|
||||
document.querySelector('.card-type-edit').innerHTML = '';
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Expiry Date MaskEdit
|
||||
if (editExpiryDateMaskEdit) {
|
||||
new Cleave(editExpiryDateMaskEdit, {
|
||||
date: true,
|
||||
delimiter: '/',
|
||||
datePattern: ['m', 'y']
|
||||
});
|
||||
}
|
||||
|
||||
// CVV MaskEdit
|
||||
if (editCVVMaskEdit) {
|
||||
new Cleave(editCVVMaskEdit, {
|
||||
numeral: true,
|
||||
numeralPositiveOnly: true
|
||||
});
|
||||
}
|
||||
|
||||
// Credit card form validation
|
||||
FormValidation.formValidation(document.getElementById('editCCForm'), {
|
||||
fields: {
|
||||
modalEditCard: {
|
||||
validators: {
|
||||
notEmpty: {
|
||||
message: 'Please enter your credit card number'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
plugins: {
|
||||
trigger: new FormValidation.plugins.Trigger(),
|
||||
bootstrap5: new FormValidation.plugins.Bootstrap5({
|
||||
// Use this for enabling/changing valid/invalid class
|
||||
// eleInvalidClass: '',
|
||||
eleValidClass: '',
|
||||
rowSelector: '.col-12'
|
||||
}),
|
||||
submitButton: new FormValidation.plugins.SubmitButton(),
|
||||
// Submit the form when all fields are valid
|
||||
// defaultSubmit: new FormValidation.plugins.DefaultSubmit(),
|
||||
autoFocus: new FormValidation.plugins.AutoFocus()
|
||||
},
|
||||
init: instance => {
|
||||
instance.on('plugins.message.placed', function (e) {
|
||||
//* Move the error message out of the `input-group` element
|
||||
if (e.element.parentElement.classList.contains('input-group')) {
|
||||
e.element.parentElement.insertAdjacentElement('afterend', e.messageElement);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
})();
|
||||
});
|
35
modules/Admin/Resources/js/auth/modal-edit-permission.js
Normal file
35
modules/Admin/Resources/js/auth/modal-edit-permission.js
Normal file
@ -0,0 +1,35 @@
|
||||
/**
|
||||
* Edit Permission Modal JS
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
// Edit permission form validation
|
||||
document.addEventListener('DOMContentLoaded', function (e) {
|
||||
(function () {
|
||||
FormValidation.formValidation(document.getElementById('editPermissionForm'), {
|
||||
fields: {
|
||||
editPermissionName: {
|
||||
validators: {
|
||||
notEmpty: {
|
||||
message: 'Please enter permission name'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
plugins: {
|
||||
trigger: new FormValidation.plugins.Trigger(),
|
||||
bootstrap5: new FormValidation.plugins.Bootstrap5({
|
||||
// Use this for enabling/changing valid/invalid class
|
||||
// eleInvalidClass: '',
|
||||
eleValidClass: '',
|
||||
rowSelector: '.col-sm-9'
|
||||
}),
|
||||
submitButton: new FormValidation.plugins.SubmitButton(),
|
||||
// Submit the form when all fields are valid
|
||||
// defaultSubmit: new FormValidation.plugins.DefaultSubmit(),
|
||||
autoFocus: new FormValidation.plugins.AutoFocus()
|
||||
}
|
||||
});
|
||||
})();
|
||||
});
|
103
modules/Admin/Resources/js/auth/modal-edit-user.js
Normal file
103
modules/Admin/Resources/js/auth/modal-edit-user.js
Normal file
@ -0,0 +1,103 @@
|
||||
/**
|
||||
* Edit User
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
// Select2 (jquery)
|
||||
$(function () {
|
||||
const select2 = $('.select2');
|
||||
|
||||
// Select2 Country
|
||||
if (select2.length) {
|
||||
select2.each(function () {
|
||||
var $this = $(this);
|
||||
$this.wrap('<div class="position-relative"></div>').select2({
|
||||
placeholder: 'Select value',
|
||||
dropdownParent: $this.parent()
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function (e) {
|
||||
(function () {
|
||||
// variables
|
||||
const modalEditUserTaxID = document.querySelector('.modal-edit-tax-id');
|
||||
const modalEditUserPhone = document.querySelector('.phone-number-mask');
|
||||
|
||||
// Prefix
|
||||
if (modalEditUserTaxID) {
|
||||
new Cleave(modalEditUserTaxID, {
|
||||
prefix: 'TIN',
|
||||
blocks: [3, 3, 3, 4],
|
||||
uppercase: true
|
||||
});
|
||||
}
|
||||
|
||||
// Phone Number Input Mask
|
||||
if (modalEditUserPhone) {
|
||||
new Cleave(modalEditUserPhone, {
|
||||
phone: true,
|
||||
phoneRegionCode: 'US'
|
||||
});
|
||||
}
|
||||
|
||||
// Edit user form validation
|
||||
FormValidation.formValidation(document.getElementById('editUserForm'), {
|
||||
fields: {
|
||||
modalEditUserFirstName: {
|
||||
validators: {
|
||||
notEmpty: {
|
||||
message: 'Please enter your first name'
|
||||
},
|
||||
regexp: {
|
||||
regexp: /^[a-zA-Zs]+$/,
|
||||
message: 'The first name can only consist of alphabetical'
|
||||
}
|
||||
}
|
||||
},
|
||||
modalEditUserLastName: {
|
||||
validators: {
|
||||
notEmpty: {
|
||||
message: 'Please enter your last name'
|
||||
},
|
||||
regexp: {
|
||||
regexp: /^[a-zA-Zs]+$/,
|
||||
message: 'The last name can only consist of alphabetical'
|
||||
}
|
||||
}
|
||||
},
|
||||
modalEditUserName: {
|
||||
validators: {
|
||||
notEmpty: {
|
||||
message: 'Please enter your username'
|
||||
},
|
||||
stringLength: {
|
||||
min: 6,
|
||||
max: 30,
|
||||
message: 'The name must be more than 6 and less than 30 characters long'
|
||||
},
|
||||
regexp: {
|
||||
regexp: /^[a-zA-Z0-9 ]+$/,
|
||||
message: 'The name can only consist of alphabetical, number and space'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
plugins: {
|
||||
trigger: new FormValidation.plugins.Trigger(),
|
||||
bootstrap5: new FormValidation.plugins.Bootstrap5({
|
||||
// Use this for enabling/changing valid/invalid class
|
||||
// eleInvalidClass: '',
|
||||
eleValidClass: '',
|
||||
rowSelector: '.col-12'
|
||||
}),
|
||||
submitButton: new FormValidation.plugins.SubmitButton(),
|
||||
// Submit the form when all fields are valid
|
||||
// defaultSubmit: new FormValidation.plugins.DefaultSubmit(),
|
||||
autoFocus: new FormValidation.plugins.AutoFocus()
|
||||
}
|
||||
});
|
||||
})();
|
||||
});
|
53
modules/Admin/Resources/js/auth/modal-enable-otp.js
Normal file
53
modules/Admin/Resources/js/auth/modal-enable-otp.js
Normal file
@ -0,0 +1,53 @@
|
||||
/**
|
||||
* Enable OTP
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function (e) {
|
||||
(function () {
|
||||
const phoneMask = document.querySelector('.phone-number-otp-mask');
|
||||
|
||||
// Phone Number Input Mask
|
||||
if (phoneMask) {
|
||||
new Cleave(phoneMask, {
|
||||
phone: true,
|
||||
phoneRegionCode: 'US'
|
||||
});
|
||||
}
|
||||
|
||||
// Enable OTP form validation
|
||||
FormValidation.formValidation(document.getElementById('enableOTPForm'), {
|
||||
fields: {
|
||||
modalEnableOTPPhone: {
|
||||
validators: {
|
||||
notEmpty: {
|
||||
message: 'Please enter your mobile number'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
plugins: {
|
||||
trigger: new FormValidation.plugins.Trigger(),
|
||||
bootstrap5: new FormValidation.plugins.Bootstrap5({
|
||||
// Use this for enabling/changing valid/invalid class
|
||||
// eleInvalidClass: '',
|
||||
eleValidClass: '',
|
||||
rowSelector: '.col-12'
|
||||
}),
|
||||
submitButton: new FormValidation.plugins.SubmitButton(),
|
||||
// Submit the form when all fields are valid
|
||||
// defaultSubmit: new FormValidation.plugins.DefaultSubmit(),
|
||||
autoFocus: new FormValidation.plugins.AutoFocus()
|
||||
},
|
||||
init: instance => {
|
||||
instance.on('plugins.message.placed', function (e) {
|
||||
//* Move the error message out of the `input-group` element
|
||||
if (e.element.parentElement.classList.contains('input-group')) {
|
||||
e.element.parentElement.insertAdjacentElement('afterend', e.messageElement);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
})();
|
||||
});
|
@ -0,0 +1,189 @@
|
||||
/**
|
||||
* Account Settings - Account
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function (e) {
|
||||
(function () {
|
||||
const formAccSettings = document.querySelector('#formAccountSettings'),
|
||||
deactivateAcc = document.querySelector('#formAccountDeactivation'),
|
||||
deactivateButton = deactivateAcc.querySelector('.deactivate-account');
|
||||
|
||||
// Form validation for Add new record
|
||||
if (formAccSettings) {
|
||||
const fv = FormValidation.formValidation(formAccSettings, {
|
||||
fields: {
|
||||
firstName: {
|
||||
validators: {
|
||||
notEmpty: {
|
||||
message: 'Please enter first name'
|
||||
}
|
||||
}
|
||||
},
|
||||
lastName: {
|
||||
validators: {
|
||||
notEmpty: {
|
||||
message: 'Please enter last name'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
plugins: {
|
||||
trigger: new FormValidation.plugins.Trigger(),
|
||||
bootstrap5: new FormValidation.plugins.Bootstrap5({
|
||||
eleValidClass: '',
|
||||
rowSelector: '.col-md-6'
|
||||
}),
|
||||
submitButton: new FormValidation.plugins.SubmitButton(),
|
||||
// Submit the form when all fields are valid
|
||||
// defaultSubmit: new FormValidation.plugins.DefaultSubmit(),
|
||||
autoFocus: new FormValidation.plugins.AutoFocus()
|
||||
},
|
||||
init: instance => {
|
||||
instance.on('plugins.message.placed', function (e) {
|
||||
if (e.element.parentElement.classList.contains('input-group')) {
|
||||
e.element.parentElement.insertAdjacentElement('afterend', e.messageElement);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (deactivateAcc) {
|
||||
const fv = FormValidation.formValidation(deactivateAcc, {
|
||||
fields: {
|
||||
accountActivation: {
|
||||
validators: {
|
||||
notEmpty: {
|
||||
message: 'Please confirm you want to delete account'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
plugins: {
|
||||
trigger: new FormValidation.plugins.Trigger(),
|
||||
bootstrap5: new FormValidation.plugins.Bootstrap5({
|
||||
eleValidClass: ''
|
||||
}),
|
||||
submitButton: new FormValidation.plugins.SubmitButton(),
|
||||
fieldStatus: new FormValidation.plugins.FieldStatus({
|
||||
onStatusChanged: function (areFieldsValid) {
|
||||
areFieldsValid
|
||||
? // Enable the submit button
|
||||
// so user has a chance to submit the form again
|
||||
deactivateButton.removeAttribute('disabled')
|
||||
: // Disable the submit button
|
||||
deactivateButton.setAttribute('disabled', 'disabled');
|
||||
}
|
||||
}),
|
||||
// Submit the form when all fields are valid
|
||||
// defaultSubmit: new FormValidation.plugins.DefaultSubmit(),
|
||||
autoFocus: new FormValidation.plugins.AutoFocus()
|
||||
},
|
||||
init: instance => {
|
||||
instance.on('plugins.message.placed', function (e) {
|
||||
if (e.element.parentElement.classList.contains('input-group')) {
|
||||
e.element.parentElement.insertAdjacentElement('afterend', e.messageElement);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Deactivate account alert
|
||||
const accountActivation = document.querySelector('#accountActivation');
|
||||
|
||||
// Alert With Functional Confirm Button
|
||||
if (deactivateButton) {
|
||||
deactivateButton.onclick = function () {
|
||||
if (accountActivation.checked == true) {
|
||||
Swal.fire({
|
||||
text: 'Are you sure you would like to deactivate your account?',
|
||||
icon: 'warning',
|
||||
showCancelButton: true,
|
||||
confirmButtonText: 'Yes',
|
||||
customClass: {
|
||||
confirmButton: 'btn btn-primary me-2 waves-effect waves-light',
|
||||
cancelButton: 'btn btn-label-secondary waves-effect waves-light'
|
||||
},
|
||||
buttonsStyling: false
|
||||
}).then(function (result) {
|
||||
if (result.value) {
|
||||
Swal.fire({
|
||||
icon: 'success',
|
||||
title: 'Deleted!',
|
||||
text: 'Your file has been deleted.',
|
||||
customClass: {
|
||||
confirmButton: 'btn btn-success waves-effect waves-light'
|
||||
}
|
||||
});
|
||||
} else if (result.dismiss === Swal.DismissReason.cancel) {
|
||||
Swal.fire({
|
||||
title: 'Cancelled',
|
||||
text: 'Deactivation Cancelled!!',
|
||||
icon: 'error',
|
||||
customClass: {
|
||||
confirmButton: 'btn btn-success waves-effect waves-light'
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// CleaveJS validation
|
||||
|
||||
const phoneNumber = document.querySelector('#phoneNumber'),
|
||||
zipCode = document.querySelector('#zipCode');
|
||||
// Phone Mask
|
||||
if (phoneNumber) {
|
||||
new Cleave(phoneNumber, {
|
||||
phone: true,
|
||||
phoneRegionCode: 'US'
|
||||
});
|
||||
}
|
||||
|
||||
// Pincode
|
||||
if (zipCode) {
|
||||
new Cleave(zipCode, {
|
||||
delimiter: '',
|
||||
numeral: true
|
||||
});
|
||||
}
|
||||
|
||||
// Update/reset user image of account page
|
||||
let accountUserImage = document.getElementById('uploadedAvatar');
|
||||
const fileInput = document.querySelector('.account-file-input'),
|
||||
resetFileInput = document.querySelector('.account-image-reset');
|
||||
|
||||
if (accountUserImage) {
|
||||
const resetImage = accountUserImage.src;
|
||||
fileInput.onchange = () => {
|
||||
if (fileInput.files[0]) {
|
||||
accountUserImage.src = window.URL.createObjectURL(fileInput.files[0]);
|
||||
}
|
||||
};
|
||||
resetFileInput.onclick = () => {
|
||||
fileInput.value = '';
|
||||
accountUserImage.src = resetImage;
|
||||
};
|
||||
}
|
||||
})();
|
||||
});
|
||||
|
||||
// Select2 (jquery)
|
||||
$(function () {
|
||||
var select2 = $('.select2');
|
||||
// For all Select2
|
||||
if (select2.length) {
|
||||
select2.each(function () {
|
||||
var $this = $(this);
|
||||
$this.wrap('<div class="position-relative"></div>');
|
||||
$this.select2({
|
||||
dropdownParent: $this.parent()
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
@ -0,0 +1,194 @@
|
||||
/**
|
||||
* Account Settings - Billing & Plans
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function (e) {
|
||||
(function () {
|
||||
const creditCardMask = document.querySelector('.credit-card-mask'),
|
||||
expiryDateMask = document.querySelector('.expiry-date-mask'),
|
||||
CVVMask = document.querySelector('.cvv-code-mask');
|
||||
|
||||
// Credit Card
|
||||
if (creditCardMask) {
|
||||
new Cleave(creditCardMask, {
|
||||
creditCard: true,
|
||||
onCreditCardTypeChanged: function (type) {
|
||||
if (type != '' && type != 'unknown') {
|
||||
document.querySelector('.card-type').innerHTML =
|
||||
'<img src="' + assetsPath + 'img/icons/payments/' + type + '-cc.png" height="28"/>';
|
||||
} else {
|
||||
document.querySelector('.card-type').innerHTML = '';
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Expiry Date Mask
|
||||
if (expiryDateMask) {
|
||||
new Cleave(expiryDateMask, {
|
||||
date: true,
|
||||
delimiter: '/',
|
||||
datePattern: ['m', 'y']
|
||||
});
|
||||
}
|
||||
|
||||
// CVV Mask
|
||||
if (CVVMask) {
|
||||
new Cleave(CVVMask, {
|
||||
numeral: true,
|
||||
numeralPositiveOnly: true
|
||||
});
|
||||
}
|
||||
|
||||
const formAccSettings = document.getElementById('formAccountSettings'),
|
||||
mobileNumber = document.querySelector('.mobile-number'),
|
||||
zipCode = document.querySelector('.zip-code'),
|
||||
creditCardForm = document.getElementById('creditCardForm');
|
||||
|
||||
// Form validation
|
||||
if (formAccSettings) {
|
||||
const fv = FormValidation.formValidation(formAccSettings, {
|
||||
fields: {
|
||||
companyName: {
|
||||
validators: {
|
||||
notEmpty: {
|
||||
message: 'Please enter company name'
|
||||
}
|
||||
}
|
||||
},
|
||||
billingEmail: {
|
||||
validators: {
|
||||
notEmpty: {
|
||||
message: 'Please enter billing email'
|
||||
},
|
||||
emailAddress: {
|
||||
message: 'Please enter valid email address'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
plugins: {
|
||||
trigger: new FormValidation.plugins.Trigger(),
|
||||
bootstrap5: new FormValidation.plugins.Bootstrap5({
|
||||
eleValidClass: '',
|
||||
rowSelector: '.col-sm-6'
|
||||
}),
|
||||
submitButton: new FormValidation.plugins.SubmitButton(),
|
||||
// Submit the form when all fields are valid
|
||||
// defaultSubmit: new FormValidation.plugins.DefaultSubmit(),
|
||||
autoFocus: new FormValidation.plugins.AutoFocus()
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Credit card form validation
|
||||
if (creditCardForm) {
|
||||
FormValidation.formValidation(creditCardForm, {
|
||||
fields: {
|
||||
paymentCard: {
|
||||
validators: {
|
||||
notEmpty: {
|
||||
message: 'Please enter your credit card number'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
plugins: {
|
||||
trigger: new FormValidation.plugins.Trigger(),
|
||||
bootstrap5: new FormValidation.plugins.Bootstrap5({
|
||||
// Use this for enabling/changing valid/invalid class
|
||||
// eleInvalidClass: '',
|
||||
eleValidClass: ''
|
||||
}),
|
||||
submitButton: new FormValidation.plugins.SubmitButton(),
|
||||
// Submit the form when all fields are valid
|
||||
// defaultSubmit: new FormValidation.plugins.DefaultSubmit(),
|
||||
autoFocus: new FormValidation.plugins.AutoFocus()
|
||||
},
|
||||
init: instance => {
|
||||
instance.on('plugins.message.placed', function (e) {
|
||||
//* Move the error message out of the `input-group` element
|
||||
if (e.element.parentElement.classList.contains('input-group')) {
|
||||
e.element.parentElement.insertAdjacentElement('afterend', e.messageElement);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Cancel Subscription alert
|
||||
const cancelSubscription = document.querySelector('.cancel-subscription');
|
||||
|
||||
// Alert With Functional Confirm Button
|
||||
if (cancelSubscription) {
|
||||
cancelSubscription.onclick = function () {
|
||||
Swal.fire({
|
||||
text: 'Are you sure you would like to cancel your subscription?',
|
||||
icon: 'warning',
|
||||
showCancelButton: true,
|
||||
confirmButtonText: 'Yes',
|
||||
customClass: {
|
||||
confirmButton: 'btn btn-primary me-2 waves-effect waves-light',
|
||||
cancelButton: 'btn btn-label-secondary waves-effect waves-light'
|
||||
},
|
||||
buttonsStyling: false
|
||||
}).then(function (result) {
|
||||
if (result.value) {
|
||||
Swal.fire({
|
||||
icon: 'success',
|
||||
title: 'Unsubscribed!',
|
||||
text: 'Your subscription cancelled successfully.',
|
||||
customClass: {
|
||||
confirmButton: 'btn btn-success waves-effect waves-light'
|
||||
}
|
||||
});
|
||||
} else if (result.dismiss === Swal.DismissReason.cancel) {
|
||||
Swal.fire({
|
||||
title: 'Cancelled',
|
||||
text: 'Unsubscription Cancelled!!',
|
||||
icon: 'error',
|
||||
customClass: {
|
||||
confirmButton: 'btn btn-success waves-effect waves-light'
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
// CleaveJS validation
|
||||
|
||||
// Phone Mask
|
||||
if (mobileNumber) {
|
||||
new Cleave(mobileNumber, {
|
||||
phone: true,
|
||||
phoneRegionCode: 'US'
|
||||
});
|
||||
}
|
||||
|
||||
// Pincode
|
||||
if (zipCode) {
|
||||
new Cleave(zipCode, {
|
||||
delimiter: '',
|
||||
numeral: true
|
||||
});
|
||||
}
|
||||
})();
|
||||
});
|
||||
|
||||
// Select2 (jquery)
|
||||
$(function () {
|
||||
var select2 = $('.select2');
|
||||
|
||||
// Select2
|
||||
if (select2.length) {
|
||||
select2.each(function () {
|
||||
var $this = $(this);
|
||||
$this.wrap('<div class="position-relative"></div>');
|
||||
$this.select2({
|
||||
dropdownParent: $this.parent()
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
@ -0,0 +1,125 @@
|
||||
/**
|
||||
* Account Settings - Security
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function (e) {
|
||||
(function () {
|
||||
const formChangePass = document.querySelector('#formAccountSettings'),
|
||||
formApiKey = document.querySelector('#formAccountSettingsApiKey');
|
||||
|
||||
// Form validation for Change password
|
||||
if (formChangePass) {
|
||||
const fv = FormValidation.formValidation(formChangePass, {
|
||||
fields: {
|
||||
currentPassword: {
|
||||
validators: {
|
||||
notEmpty: {
|
||||
message: 'Please current password'
|
||||
},
|
||||
stringLength: {
|
||||
min: 8,
|
||||
message: 'Password must be more than 8 characters'
|
||||
}
|
||||
}
|
||||
},
|
||||
newPassword: {
|
||||
validators: {
|
||||
notEmpty: {
|
||||
message: 'Please enter new password'
|
||||
},
|
||||
stringLength: {
|
||||
min: 8,
|
||||
message: 'Password must be more than 8 characters'
|
||||
}
|
||||
}
|
||||
},
|
||||
confirmPassword: {
|
||||
validators: {
|
||||
notEmpty: {
|
||||
message: 'Please confirm new password'
|
||||
},
|
||||
identical: {
|
||||
compare: function () {
|
||||
return formChangePass.querySelector('[name="newPassword"]').value;
|
||||
},
|
||||
message: 'The password and its confirm are not the same'
|
||||
},
|
||||
stringLength: {
|
||||
min: 8,
|
||||
message: 'Password must be more than 8 characters'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
plugins: {
|
||||
trigger: new FormValidation.plugins.Trigger(),
|
||||
bootstrap5: new FormValidation.plugins.Bootstrap5({
|
||||
eleValidClass: '',
|
||||
rowSelector: '.col-md-6'
|
||||
}),
|
||||
submitButton: new FormValidation.plugins.SubmitButton(),
|
||||
// Submit the form when all fields are valid
|
||||
// defaultSubmit: new FormValidation.plugins.DefaultSubmit(),
|
||||
autoFocus: new FormValidation.plugins.AutoFocus()
|
||||
},
|
||||
init: instance => {
|
||||
instance.on('plugins.message.placed', function (e) {
|
||||
if (e.element.parentElement.classList.contains('input-group')) {
|
||||
e.element.parentElement.insertAdjacentElement('afterend', e.messageElement);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Form validation for API key
|
||||
if (formApiKey) {
|
||||
const fvApi = FormValidation.formValidation(formApiKey, {
|
||||
fields: {
|
||||
apiKey: {
|
||||
validators: {
|
||||
notEmpty: {
|
||||
message: 'Please enter API key name'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
plugins: {
|
||||
trigger: new FormValidation.plugins.Trigger(),
|
||||
bootstrap5: new FormValidation.plugins.Bootstrap5({
|
||||
eleValidClass: ''
|
||||
}),
|
||||
submitButton: new FormValidation.plugins.SubmitButton(),
|
||||
// Submit the form when all fields are valid
|
||||
// defaultSubmit: new FormValidation.plugins.DefaultSubmit(),
|
||||
autoFocus: new FormValidation.plugins.AutoFocus()
|
||||
},
|
||||
init: instance => {
|
||||
instance.on('plugins.message.placed', function (e) {
|
||||
if (e.element.parentElement.classList.contains('input-group')) {
|
||||
e.element.parentElement.insertAdjacentElement('afterend', e.messageElement);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
})();
|
||||
});
|
||||
|
||||
// Select2 (jquery)
|
||||
$(function () {
|
||||
var select2 = $('.select2');
|
||||
|
||||
// Select2 API Key
|
||||
if (select2.length) {
|
||||
select2.each(function () {
|
||||
var $this = $(this);
|
||||
$this.wrap('<div class="position-relative"></div>');
|
||||
$this.select2({
|
||||
dropdownParent: $this.parent()
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
305
modules/Admin/Resources/js/auth/pages-auth-multisteps.js
Normal file
305
modules/Admin/Resources/js/auth/pages-auth-multisteps.js
Normal file
@ -0,0 +1,305 @@
|
||||
/**
|
||||
* Page auth register multi-steps
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
// Select2 (jquery)
|
||||
$(function () {
|
||||
var select2 = $('.select2');
|
||||
|
||||
// select2
|
||||
if (select2.length) {
|
||||
select2.each(function () {
|
||||
var $this = $(this);
|
||||
$this.wrap('<div class="position-relative"></div>');
|
||||
$this.select2({
|
||||
placeholder: 'Select an country',
|
||||
dropdownParent: $this.parent()
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Multi Steps Validation
|
||||
// --------------------------------------------------------------------
|
||||
document.addEventListener('DOMContentLoaded', function (e) {
|
||||
(function () {
|
||||
const stepsValidation = document.querySelector('#multiStepsValidation');
|
||||
if (typeof stepsValidation !== undefined && stepsValidation !== null) {
|
||||
// Multi Steps form
|
||||
const stepsValidationForm = stepsValidation.querySelector('#multiStepsForm');
|
||||
// Form steps
|
||||
const stepsValidationFormStep1 = stepsValidationForm.querySelector('#accountDetailsValidation');
|
||||
const stepsValidationFormStep2 = stepsValidationForm.querySelector('#personalInfoValidation');
|
||||
const stepsValidationFormStep3 = stepsValidationForm.querySelector('#billingLinksValidation');
|
||||
// Multi steps next prev button
|
||||
const stepsValidationNext = [].slice.call(stepsValidationForm.querySelectorAll('.btn-next'));
|
||||
const stepsValidationPrev = [].slice.call(stepsValidationForm.querySelectorAll('.btn-prev'));
|
||||
|
||||
const multiStepsExDate = document.querySelector('.multi-steps-exp-date'),
|
||||
multiStepsCvv = document.querySelector('.multi-steps-cvv'),
|
||||
multiStepsMobile = document.querySelector('.multi-steps-mobile'),
|
||||
multiStepsPincode = document.querySelector('.multi-steps-pincode'),
|
||||
multiStepsCard = document.querySelector('.multi-steps-card');
|
||||
|
||||
// Expiry Date Mask
|
||||
if (multiStepsExDate) {
|
||||
new Cleave(multiStepsExDate, {
|
||||
date: true,
|
||||
delimiter: '/',
|
||||
datePattern: ['m', 'y']
|
||||
});
|
||||
}
|
||||
|
||||
// CVV
|
||||
if (multiStepsCvv) {
|
||||
new Cleave(multiStepsCvv, {
|
||||
numeral: true,
|
||||
numeralPositiveOnly: true
|
||||
});
|
||||
}
|
||||
|
||||
// Mobile
|
||||
if (multiStepsMobile) {
|
||||
new Cleave(multiStepsMobile, {
|
||||
phone: true,
|
||||
phoneRegionCode: 'US'
|
||||
});
|
||||
}
|
||||
|
||||
// Pincode
|
||||
if (multiStepsPincode) {
|
||||
new Cleave(multiStepsPincode, {
|
||||
delimiter: '',
|
||||
numeral: true
|
||||
});
|
||||
}
|
||||
|
||||
// Credit Card
|
||||
if (multiStepsCard) {
|
||||
new Cleave(multiStepsCard, {
|
||||
creditCard: true,
|
||||
onCreditCardTypeChanged: function (type) {
|
||||
if (type != '' && type != 'unknown') {
|
||||
document.querySelector('.card-type').innerHTML =
|
||||
'<img src="' + assetsPath + 'img/icons/payments/' + type + '-cc.png" height="28"/>';
|
||||
} else {
|
||||
document.querySelector('.card-type').innerHTML = '';
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
let validationStepper = new Stepper(stepsValidation, {
|
||||
linear: true
|
||||
});
|
||||
|
||||
// Account details
|
||||
const multiSteps1 = FormValidation.formValidation(stepsValidationFormStep1, {
|
||||
fields: {
|
||||
multiStepsUsername: {
|
||||
validators: {
|
||||
notEmpty: {
|
||||
message: 'Please enter username'
|
||||
},
|
||||
stringLength: {
|
||||
min: 6,
|
||||
max: 30,
|
||||
message: 'The name must be more than 6 and less than 30 characters long'
|
||||
},
|
||||
regexp: {
|
||||
regexp: /^[a-zA-Z0-9 ]+$/,
|
||||
message: 'The name can only consist of alphabetical, number and space'
|
||||
}
|
||||
}
|
||||
},
|
||||
multiStepsEmail: {
|
||||
validators: {
|
||||
notEmpty: {
|
||||
message: 'Please enter email address'
|
||||
},
|
||||
emailAddress: {
|
||||
message: 'The value is not a valid email address'
|
||||
}
|
||||
}
|
||||
},
|
||||
multiStepsPass: {
|
||||
validators: {
|
||||
notEmpty: {
|
||||
message: 'Please enter password'
|
||||
}
|
||||
}
|
||||
},
|
||||
multiStepsConfirmPass: {
|
||||
validators: {
|
||||
notEmpty: {
|
||||
message: 'Confirm Password is required'
|
||||
},
|
||||
identical: {
|
||||
compare: function () {
|
||||
return stepsValidationFormStep1.querySelector('[name="multiStepsPass"]').value;
|
||||
},
|
||||
message: 'The password and its confirm are not the same'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
plugins: {
|
||||
trigger: new FormValidation.plugins.Trigger(),
|
||||
bootstrap5: new FormValidation.plugins.Bootstrap5({
|
||||
// Use this for enabling/changing valid/invalid class
|
||||
// eleInvalidClass: '',
|
||||
eleValidClass: '',
|
||||
rowSelector: '.col-sm-6'
|
||||
}),
|
||||
autoFocus: new FormValidation.plugins.AutoFocus(),
|
||||
submitButton: new FormValidation.plugins.SubmitButton()
|
||||
},
|
||||
init: instance => {
|
||||
instance.on('plugins.message.placed', function (e) {
|
||||
if (e.element.parentElement.classList.contains('input-group')) {
|
||||
e.element.parentElement.insertAdjacentElement('afterend', e.messageElement);
|
||||
}
|
||||
});
|
||||
}
|
||||
}).on('core.form.valid', function () {
|
||||
// Jump to the next step when all fields in the current step are valid
|
||||
validationStepper.next();
|
||||
});
|
||||
|
||||
// Personal info
|
||||
const multiSteps2 = FormValidation.formValidation(stepsValidationFormStep2, {
|
||||
fields: {
|
||||
multiStepsFirstName: {
|
||||
validators: {
|
||||
notEmpty: {
|
||||
message: 'Please enter first name'
|
||||
}
|
||||
}
|
||||
},
|
||||
multiStepsAddress: {
|
||||
validators: {
|
||||
notEmpty: {
|
||||
message: 'Please enter your address'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
plugins: {
|
||||
trigger: new FormValidation.plugins.Trigger(),
|
||||
bootstrap5: new FormValidation.plugins.Bootstrap5({
|
||||
// Use this for enabling/changing valid/invalid class
|
||||
// eleInvalidClass: '',
|
||||
eleValidClass: '',
|
||||
rowSelector: function (field, ele) {
|
||||
// field is the field name
|
||||
// ele is the field element
|
||||
switch (field) {
|
||||
case 'multiStepsFirstName':
|
||||
return '.col-sm-6';
|
||||
case 'multiStepsAddress':
|
||||
return '.col-md-12';
|
||||
default:
|
||||
return '.row';
|
||||
}
|
||||
}
|
||||
}),
|
||||
autoFocus: new FormValidation.plugins.AutoFocus(),
|
||||
submitButton: new FormValidation.plugins.SubmitButton()
|
||||
}
|
||||
}).on('core.form.valid', function () {
|
||||
// Jump to the next step when all fields in the current step are valid
|
||||
validationStepper.next();
|
||||
});
|
||||
|
||||
// Social links
|
||||
const multiSteps3 = FormValidation.formValidation(stepsValidationFormStep3, {
|
||||
fields: {
|
||||
multiStepsCard: {
|
||||
validators: {
|
||||
notEmpty: {
|
||||
message: 'Please enter card number'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
plugins: {
|
||||
trigger: new FormValidation.plugins.Trigger(),
|
||||
bootstrap5: new FormValidation.plugins.Bootstrap5({
|
||||
// Use this for enabling/changing valid/invalid class
|
||||
// eleInvalidClass: '',
|
||||
eleValidClass: '',
|
||||
rowSelector: function (field, ele) {
|
||||
// field is the field name
|
||||
// ele is the field element
|
||||
switch (field) {
|
||||
case 'multiStepsCard':
|
||||
return '.col-md-12';
|
||||
|
||||
default:
|
||||
return '.col-dm-6';
|
||||
}
|
||||
}
|
||||
}),
|
||||
autoFocus: new FormValidation.plugins.AutoFocus(),
|
||||
submitButton: new FormValidation.plugins.SubmitButton()
|
||||
},
|
||||
init: instance => {
|
||||
instance.on('plugins.message.placed', function (e) {
|
||||
if (e.element.parentElement.classList.contains('input-group')) {
|
||||
e.element.parentElement.insertAdjacentElement('afterend', e.messageElement);
|
||||
}
|
||||
});
|
||||
}
|
||||
}).on('core.form.valid', function () {
|
||||
// You can submit the form
|
||||
// stepsValidationForm.submit()
|
||||
// or send the form data to server via an Ajax request
|
||||
// To make the demo simple, I just placed an alert
|
||||
alert('Submitted..!!');
|
||||
});
|
||||
|
||||
stepsValidationNext.forEach(item => {
|
||||
item.addEventListener('click', event => {
|
||||
// When click the Next button, we will validate the current step
|
||||
switch (validationStepper._currentIndex) {
|
||||
case 0:
|
||||
multiSteps1.validate();
|
||||
break;
|
||||
|
||||
case 1:
|
||||
multiSteps2.validate();
|
||||
break;
|
||||
|
||||
case 2:
|
||||
multiSteps3.validate();
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
stepsValidationPrev.forEach(item => {
|
||||
item.addEventListener('click', event => {
|
||||
switch (validationStepper._currentIndex) {
|
||||
case 2:
|
||||
validationStepper.previous();
|
||||
break;
|
||||
|
||||
case 1:
|
||||
validationStepper.previous();
|
||||
break;
|
||||
|
||||
case 0:
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
})();
|
||||
});
|
83
modules/Admin/Resources/js/auth/pages-auth-two-steps.js
Normal file
83
modules/Admin/Resources/js/auth/pages-auth-two-steps.js
Normal file
@ -0,0 +1,83 @@
|
||||
/**
|
||||
* Page auth two steps
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function (e) {
|
||||
(function () {
|
||||
let maskWrapper = document.querySelector('.numeral-mask-wrapper');
|
||||
|
||||
for (let pin of maskWrapper.children) {
|
||||
pin.onkeyup = function (e) {
|
||||
// Check if the key pressed is a number (0-9)
|
||||
if (/^\d$/.test(e.key)) {
|
||||
// While entering value, go to next
|
||||
if (pin.nextElementSibling) {
|
||||
if (this.value.length === parseInt(this.attributes['maxlength'].value)) {
|
||||
pin.nextElementSibling.focus();
|
||||
}
|
||||
}
|
||||
} else if (e.key === 'Backspace') {
|
||||
// While deleting entered value, go to previous
|
||||
if (pin.previousElementSibling) {
|
||||
pin.previousElementSibling.focus();
|
||||
}
|
||||
}
|
||||
};
|
||||
// Prevent the default behavior for the minus key
|
||||
pin.onkeypress = function (e) {
|
||||
if (e.key === '-') {
|
||||
e.preventDefault();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
const twoStepsForm = document.querySelector('#twoStepsForm');
|
||||
|
||||
// Form validation for Add new record
|
||||
if (twoStepsForm) {
|
||||
const fv = FormValidation.formValidation(twoStepsForm, {
|
||||
fields: {
|
||||
otp: {
|
||||
validators: {
|
||||
notEmpty: {
|
||||
message: 'Please enter otp'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
plugins: {
|
||||
trigger: new FormValidation.plugins.Trigger(),
|
||||
bootstrap5: new FormValidation.plugins.Bootstrap5({
|
||||
eleValidClass: '',
|
||||
rowSelector: '.mb-6'
|
||||
}),
|
||||
submitButton: new FormValidation.plugins.SubmitButton(),
|
||||
|
||||
defaultSubmit: new FormValidation.plugins.DefaultSubmit(),
|
||||
autoFocus: new FormValidation.plugins.AutoFocus()
|
||||
}
|
||||
});
|
||||
|
||||
const numeralMaskList = twoStepsForm.querySelectorAll('.numeral-mask');
|
||||
const keyupHandler = function () {
|
||||
let otpFlag = true,
|
||||
otpVal = '';
|
||||
numeralMaskList.forEach(numeralMaskEl => {
|
||||
if (numeralMaskEl.value === '') {
|
||||
otpFlag = false;
|
||||
twoStepsForm.querySelector('[name="otp"]').value = '';
|
||||
}
|
||||
otpVal = otpVal + numeralMaskEl.value;
|
||||
});
|
||||
if (otpFlag) {
|
||||
twoStepsForm.querySelector('[name="otp"]').value = otpVal;
|
||||
}
|
||||
};
|
||||
numeralMaskList.forEach(numeralMaskEle => {
|
||||
numeralMaskEle.addEventListener('keyup', keyupHandler);
|
||||
});
|
||||
}
|
||||
})();
|
||||
});
|
112
modules/Admin/Resources/js/auth/pages-auth.js
Normal file
112
modules/Admin/Resources/js/auth/pages-auth.js
Normal file
@ -0,0 +1,112 @@
|
||||
('use strict');
|
||||
|
||||
const formAuthentication = document.querySelector('#formAuthentication');
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function (e) {
|
||||
(function () {
|
||||
// Form validation for Add new record
|
||||
if (formAuthentication) {
|
||||
const fv = FormValidation.formValidation(formAuthentication, {
|
||||
fields: {
|
||||
username: {
|
||||
validators: {
|
||||
notEmpty: {
|
||||
message: 'Por favor, introduzca su nombre de usuario'
|
||||
},
|
||||
stringLength: {
|
||||
min: 6,
|
||||
message: 'El nombre de usuario debe tener más de 6 caracteres'
|
||||
}
|
||||
}
|
||||
},
|
||||
email: {
|
||||
validators: {
|
||||
notEmpty: {
|
||||
message: 'Por favor, introduzca su correo electrónico'
|
||||
},
|
||||
emailAddress: {
|
||||
message: 'Por favor, introduzca una dirección de correo electrónico válida'
|
||||
}
|
||||
}
|
||||
},
|
||||
'email-username': {
|
||||
validators: {
|
||||
notEmpty: {
|
||||
message: 'Por favor, introduzca su correo electrónico / nombre de usuario'
|
||||
},
|
||||
stringLength: {
|
||||
min: 6,
|
||||
message: 'El nombre de usuario debe tener más de 6 caracteres'
|
||||
}
|
||||
}
|
||||
},
|
||||
password: {
|
||||
validators: {
|
||||
notEmpty: {
|
||||
message: 'Por favor, introduzca su contraseña'
|
||||
},
|
||||
stringLength: {
|
||||
min: 6,
|
||||
message: 'La contraseña debe tener más de 6 caracteres'
|
||||
}
|
||||
}
|
||||
},
|
||||
'confirm-password': {
|
||||
validators: {
|
||||
notEmpty: {
|
||||
message: 'Confirme la contraseña'
|
||||
},
|
||||
identical: {
|
||||
compare: function () {
|
||||
return formAuthentication.querySelector('[name="password"]').value;
|
||||
},
|
||||
message: 'La contraseña y su confirmación no son iguales'
|
||||
},
|
||||
stringLength: {
|
||||
min: 6,
|
||||
message: 'La contraseña debe tener más de 6 caracteres'
|
||||
}
|
||||
}
|
||||
},
|
||||
terms: {
|
||||
validators: {
|
||||
notEmpty: {
|
||||
message: 'Acepte los términos y condiciones'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
plugins: {
|
||||
trigger: new FormValidation.plugins.Trigger(),
|
||||
bootstrap5: new FormValidation.plugins.Bootstrap5({
|
||||
eleValidClass: '',
|
||||
rowSelector: '.fv-row'
|
||||
}),
|
||||
submitButton: new FormValidation.plugins.SubmitButton(),
|
||||
|
||||
defaultSubmit: new FormValidation.plugins.DefaultSubmit(),
|
||||
autoFocus: new FormValidation.plugins.AutoFocus()
|
||||
},
|
||||
init: instance => {
|
||||
instance.on('plugins.message.placed', function (e) {
|
||||
if (e.element.parentElement.classList.contains('input-group')) {
|
||||
e.element.parentElement.insertAdjacentElement('afterend', e.messageElement);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Two Steps Verification
|
||||
const numeralMask = document.querySelectorAll('.numeral-mask');
|
||||
|
||||
// Verification masking
|
||||
if (numeralMask.length) {
|
||||
numeralMask.forEach(e => {
|
||||
new Cleave(e, {
|
||||
numeral: true
|
||||
});
|
||||
});
|
||||
}
|
||||
})();
|
||||
});
|
4
modules/Admin/Resources/js/bootstrap.js
vendored
Normal file
4
modules/Admin/Resources/js/bootstrap.js
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
import axios from 'axios';
|
||||
window.axios = axios;
|
||||
|
||||
window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
|
102
modules/Admin/Resources/js/cache-manager/cache-scripts.js
Normal file
102
modules/Admin/Resources/js/cache-manager/cache-scripts.js
Normal file
@ -0,0 +1,102 @@
|
||||
import LivewireNotification from '../_class/LivewireNotification';
|
||||
import FormCustomListener from '../_class/FormCustomListener';
|
||||
|
||||
// Inicializar notificaciones globales
|
||||
const notification = new LivewireNotification();
|
||||
|
||||
// Inicializar listener para estadísticas de cache
|
||||
new FormCustomListener({
|
||||
buttonSelectors: ['.btn-clear-cache', '.btn-reload-cache-stats']
|
||||
});
|
||||
|
||||
// Inicializar listener para funciones de cache
|
||||
new FormCustomListener({
|
||||
formSelector: '#cache-functions-card',
|
||||
buttonSelectors: ['.btn', '.btn-config-cache', '.btn-cache-routes'],
|
||||
callbacks: [
|
||||
null, // Callback por defecto para .btn
|
||||
(form, button) => {
|
||||
// Emitir notificación de carga
|
||||
notification.emitNotification({
|
||||
target: '#cache-functions-card .notification-container',
|
||||
message: 'Generando cache de configuraciones de Laravel...',
|
||||
type: 'warning'
|
||||
});
|
||||
|
||||
// Generar cache de configuraciones mediante una petición AJAX
|
||||
fetch('/admin/cache/config/cache', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').getAttribute('content')
|
||||
},
|
||||
body: JSON.stringify({})
|
||||
})
|
||||
.then(response => {
|
||||
if (!response.ok) {
|
||||
throw new Error('Error al generar el cache de configuraciones');
|
||||
}
|
||||
return response.json();
|
||||
})
|
||||
.then(() => {
|
||||
// Emitir notificación de éxito con recarga diferida
|
||||
notification.emitNotification({
|
||||
target: '#cache-functions-card .notification-container',
|
||||
message: 'Se ha cacheado la configuración de Laravel...',
|
||||
type: 'success',
|
||||
deferReload: true
|
||||
});
|
||||
})
|
||||
.catch(error => {
|
||||
// Emitir notificación de error
|
||||
notification.emitNotification({
|
||||
target: '#cache-functions-card .notification-container',
|
||||
message: `Error: ${error.message}`,
|
||||
type: 'danger'
|
||||
});
|
||||
console.error('Error al generar el cache:', error);
|
||||
});
|
||||
},
|
||||
(form, button) => {
|
||||
// Emitir notificación de carga
|
||||
notification.emitNotification({
|
||||
target: '#cache-functions-card .notification-container',
|
||||
message: 'Generando cache de rutas de Laravel...',
|
||||
type: 'warning'
|
||||
});
|
||||
|
||||
// Recargar estadísticas de cache mediante una petición AJAX
|
||||
fetch('/admin/cache/route/cache', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').getAttribute('content')
|
||||
}
|
||||
})
|
||||
.then(response => {
|
||||
if (!response.ok) {
|
||||
throw new Error('Error al recargar las estadísticas de cache');
|
||||
}
|
||||
return response.json();
|
||||
})
|
||||
.then(() => {
|
||||
// Emitir notificación de éxito con recarga diferida
|
||||
notification.emitNotification({
|
||||
target: '#cache-functions-card .notification-container',
|
||||
message: 'Se han cacheado las rutas de Laravel...',
|
||||
type: 'success',
|
||||
deferReload: true
|
||||
});
|
||||
})
|
||||
.catch(error => {
|
||||
// Emitir notificación de error
|
||||
notification.emitNotification({
|
||||
target: '#cache-functions-card .notification-container',
|
||||
message: `Error: ${error.message}`,
|
||||
type: 'danger'
|
||||
});
|
||||
console.error('Error al recargar las estadísticas:', error);
|
||||
});
|
||||
}
|
||||
]
|
||||
});
|
197
modules/Admin/Resources/js/rbac/permissions-scripts.js
Normal file
197
modules/Admin/Resources/js/rbac/permissions-scripts.js
Normal file
@ -0,0 +1,197 @@
|
||||
/**
|
||||
* App user list (jquery)
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
$(function () {
|
||||
var dataTablePermissions = $('.datatables-permissions'),
|
||||
dt_permission,
|
||||
userList = baseUrl + 'app/user/list';
|
||||
|
||||
// Users List datatable
|
||||
if (dataTablePermissions.length) {
|
||||
dt_permission = dataTablePermissions.DataTable({
|
||||
ajax: window.location.href,
|
||||
columns: [
|
||||
// columns according to JSON
|
||||
{ data: '' },
|
||||
{ data: 'id' },
|
||||
{ data: 'name' },
|
||||
{ data: 'assigned_to' },
|
||||
{ data: 'created_date' },
|
||||
{ data: '' }
|
||||
],
|
||||
columnDefs: [
|
||||
{
|
||||
// For Responsive
|
||||
className: 'control',
|
||||
orderable: false,
|
||||
searchable: false,
|
||||
responsivePriority: 2,
|
||||
targets: 0,
|
||||
render: function (data, type, full, meta) {
|
||||
return '';
|
||||
}
|
||||
},
|
||||
{
|
||||
targets: 1,
|
||||
searchable: false,
|
||||
visible: false
|
||||
},
|
||||
{
|
||||
// Name
|
||||
targets: 2,
|
||||
render: function (data, type, full, meta) {
|
||||
var $name = full['name'];
|
||||
return '<span class="text-nowrap text-heading">' + $name + '</span>';
|
||||
}
|
||||
},
|
||||
{
|
||||
// User Role
|
||||
targets: 3,
|
||||
orderable: false,
|
||||
render: function (data, type, full, meta) {
|
||||
var $assignedTo = full['assigned_to'],
|
||||
$output = '';
|
||||
var roleBadgeObj = {
|
||||
Admin:
|
||||
'<a href="' +
|
||||
userList +
|
||||
'"><span class="badge me-4 bg-label-primary">Administrator</span></a>',
|
||||
Manager:
|
||||
'<a href="' +
|
||||
userList +
|
||||
'"><span class="badge me-4 bg-label-warning">Manager</span></a>',
|
||||
Users:
|
||||
'<a href="' + userList + '"><span class="badge me-4 bg-label-success">Users</span></a>',
|
||||
Support:
|
||||
'<a href="' + userList + '"><span class="badge me-4 bg-label-info">Support</span></a>',
|
||||
Restricted:
|
||||
'<a href="' +
|
||||
userList +
|
||||
'"><span class="badge me-4 bg-label-danger">Restricted User</span></a>'
|
||||
};
|
||||
for (var i = 0; i < $assignedTo.length; i++) {
|
||||
var val = $assignedTo[i];
|
||||
$output += roleBadgeObj[val];
|
||||
}
|
||||
return '<span class="text-nowrap">' + $output + '</span>';
|
||||
}
|
||||
},
|
||||
{
|
||||
// remove ordering from Name
|
||||
targets: 4,
|
||||
orderable: false,
|
||||
render: function (data, type, full, meta) {
|
||||
var $date = full['created_date'];
|
||||
return '<span class="text-nowrap">' + $date + '</span>';
|
||||
}
|
||||
},
|
||||
{
|
||||
// Actions
|
||||
targets: -1,
|
||||
searchable: false,
|
||||
title: 'Actions',
|
||||
orderable: false,
|
||||
render: function (data, type, full, meta) {
|
||||
return (
|
||||
'<div class="d-flex align-items-center">' +
|
||||
'<span class="text-nowrap"><button class="btn btn-icon btn-text-secondary waves-effect waves-light rounded-pill me-1" data-bs-target="#editPermissionModal" data-bs-toggle="modal" data-bs-dismiss="modal"><i class="ti ti-edit ti-md"></i></button>' +
|
||||
'<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 mx-1"></i></a>' +
|
||||
'<div class="dropdown-menu dropdown-menu-end m-0">' +
|
||||
'<a href="javascript:;"" class="dropdown-item">Edit</a>' +
|
||||
'<a href="javascript:;" class="dropdown-item">Suspend</a>' +
|
||||
'</div>' +
|
||||
'</div>'
|
||||
);
|
||||
}
|
||||
}
|
||||
],
|
||||
order: [[1, 'asc']],
|
||||
dom:
|
||||
'<"row mx-1"' +
|
||||
'<"col-sm-12 col-md-3" l>' +
|
||||
'<"col-sm-12 col-md-9"<"dt-action-buttons text-xl-end text-lg-start text-md-end text-start d-flex align-items-center justify-content-md-end justify-content-center flex-wrap"<"me-4 mt-n6 mt-md-0"f>B>>' +
|
||||
'>t' +
|
||||
'<"row"' +
|
||||
'<"col-sm-12 col-md-6"i>' +
|
||||
'<"col-sm-12 col-md-6"p>' +
|
||||
'>',
|
||||
language: $.fn.dataTable.ext.datatable_spanish_default,
|
||||
// Buttons with Dropdown
|
||||
buttons: [],
|
||||
// For responsive popup
|
||||
responsive: {
|
||||
details: {
|
||||
display: $.fn.dataTable.Responsive.display.modal({
|
||||
header: function (row) {
|
||||
var data = row.data();
|
||||
return 'Details of ' + data['name'];
|
||||
}
|
||||
}),
|
||||
type: 'column',
|
||||
renderer: function (api, rowIdx, columns) {
|
||||
var data = $.map(columns, function (col, i) {
|
||||
return col.title !== '' // ? Do not show row in modal popup if title is blank (for check box)
|
||||
? '<tr data-dt-row="' +
|
||||
col.rowIndex +
|
||||
'" data-dt-column="' +
|
||||
col.columnIndex +
|
||||
'">' +
|
||||
'<td>' +
|
||||
col.title +
|
||||
':' +
|
||||
'</td> ' +
|
||||
'<td>' +
|
||||
col.data +
|
||||
'</td>' +
|
||||
'</tr>'
|
||||
: '';
|
||||
}).join('');
|
||||
|
||||
return data ? $('<table class="table"/><tbody />').append(data) : false;
|
||||
}
|
||||
}
|
||||
},
|
||||
initComplete: function () {
|
||||
// Adding role filter once table initialized
|
||||
this.api()
|
||||
.columns(3)
|
||||
.every(function () {
|
||||
var column = this;
|
||||
var select = $(
|
||||
'<select id="UserRole" class="form-select text-capitalize"><option value=""> Select Role </option></select>'
|
||||
)
|
||||
.appendTo('.user_role')
|
||||
.on('change', function () {
|
||||
var val = $.fn.dataTable.util.escapeRegex($(this).val());
|
||||
column.search(val ? '^' + val + '$' : '', true, false).draw();
|
||||
});
|
||||
|
||||
column
|
||||
.data()
|
||||
.unique()
|
||||
.sort()
|
||||
.each(function (d, j) {
|
||||
select.append('<option value="' + d + '" class="text-capitalize">' + d + '</option>');
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Delete Record
|
||||
$('.datatables-permissions tbody').on('click', '.delete-record', function () {
|
||||
dt_permission.row($(this).parents('tr')).remove().draw();
|
||||
});
|
||||
|
||||
// Filter form control to default size
|
||||
// ? setTimeout used for multilingual table initialization
|
||||
setTimeout(() => {
|
||||
$('.dataTables_filter .form-control').removeClass('form-control-sm');
|
||||
$('.dataTables_length .form-select').removeClass('form-select-sm');
|
||||
$('.dataTables_info').addClass('ms-n1');
|
||||
$('.dataTables_paginate').addClass('me-n1');
|
||||
}, 300);
|
||||
});
|
10
modules/Admin/Resources/js/rbac/roles-scripts.js
Normal file
10
modules/Admin/Resources/js/rbac/roles-scripts.js
Normal file
@ -0,0 +1,10 @@
|
||||
import LivewireNotification from '../_class/LivewireNotification';
|
||||
import WebsiteLegalSettingsForm from '../_class/WebsiteLegalSettingsForm';
|
||||
|
||||
new LivewireNotification();
|
||||
|
||||
window.WebsiteLegalSettingsForm = new WebsiteLegalSettingsForm();
|
||||
|
||||
Livewire.hook('morphed', () => {
|
||||
window.WebsiteLegalSettingsForm.reload();
|
||||
});
|
@ -0,0 +1,10 @@
|
||||
import LivewireNotification from '../_class/LivewireNotification';
|
||||
import WebsiteLegalSettingsForm from '../_class/WebsiteLegalSettingsForm';
|
||||
|
||||
new LivewireNotification();
|
||||
|
||||
window.WebsiteLegalSettingsForm = new WebsiteLegalSettingsForm();
|
||||
|
||||
Livewire.hook('morphed', () => {
|
||||
window.WebsiteLegalSettingsForm.reload();
|
||||
});
|
@ -0,0 +1,590 @@
|
||||
import LivewireNotification from '../_class/LivewireNotification';
|
||||
import FormCustomListener from '../_class/FormCustomListener';
|
||||
|
||||
new LivewireNotification();
|
||||
|
||||
// Inicializar formularios de ajustes de sitio web
|
||||
window.WebsiteSettingsForm = new FormCustomListener({
|
||||
formSelector: '#website-settings-card',
|
||||
buttonSelectors: ['.btn-save', '.btn-cancel'],
|
||||
callbacks: [
|
||||
() => {} // Deshabilitar callback para #save_website_button
|
||||
],
|
||||
dispatchOnSubmit: 'saveWebsiteSettings',
|
||||
validationConfig: {
|
||||
fields: {
|
||||
website_title: {
|
||||
validators: {
|
||||
stringLength: {
|
||||
min: 2,
|
||||
max: 50,
|
||||
message: 'El título debe tener entre 2 y 50 caracteres.'
|
||||
}
|
||||
}
|
||||
},
|
||||
website_description: {
|
||||
validators: {
|
||||
stringLength: {
|
||||
max: 160,
|
||||
message: 'La descripción no puede exceder los 160 caracteres.'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
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()
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Inicializar formularios de ajustes de favicon
|
||||
new FormCustomListener({
|
||||
formSelector: '#website-favicon-settings-card',
|
||||
buttonSelectors: ['.btn']
|
||||
});
|
||||
|
||||
// Inicializar formularios de ajustes de logo de imagen
|
||||
new FormCustomListener({
|
||||
formSelector: '#website-image-logo-settings-card',
|
||||
buttonSelectors: ['.btn']
|
||||
});
|
||||
|
||||
// Inicializar formularios de ajustes de social media
|
||||
window.SocialSettingsForm = new FormCustomListener({
|
||||
formSelector: '#website-social-settings-card',
|
||||
buttonSelectors: ['.btn-save', '.btn-cancel'],
|
||||
callbacks: [() => {}],
|
||||
dispatchOnSubmit: 'saveSocialSettings',
|
||||
validationConfig: {
|
||||
fields: {
|
||||
social_whatsapp: {
|
||||
validators: {
|
||||
callback: {
|
||||
message: 'Por favor, introduce un número de teléfono válido para México.',
|
||||
callback: function (input) {
|
||||
// Si el campo está vacío, no hacemos validación
|
||||
if (input.value.trim() === '') {
|
||||
return true; // Permitir vacío
|
||||
}
|
||||
|
||||
// Si no está vacío, validamos el formato del número
|
||||
const cleanValue = input.value.replace(/\D/g, '');
|
||||
const regex = /^[1-9]\d{9}$/; // Exactamente 10 dígitos
|
||||
|
||||
return regex.test(cleanValue); // Valida solo si hay un número
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
social_whatsapp_message: {
|
||||
validators: {
|
||||
stringLength: {
|
||||
max: 500,
|
||||
message: 'El mensaje no puede exceder los 500 caracteres.'
|
||||
},
|
||||
callback: {
|
||||
message: 'El mensaje es obligatorio.',
|
||||
callback: function (input) {
|
||||
// Obtener el valor de 'social_whatsapp'
|
||||
const whatsappNumber = document.querySelector('#social_whatsapp').value.trim();
|
||||
|
||||
// Si 'social_whatsapp' tiene un valor, entonces el mensaje es obligatorio
|
||||
if (whatsappNumber !== '') {
|
||||
return input.value.trim() !== ''; // El mensaje no puede estar vacío
|
||||
}
|
||||
|
||||
return true; // Si 'social_whatsapp' está vacío, no validamos 'social_whatsapp_message'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
social_facebook: {
|
||||
validators: {
|
||||
uri: {
|
||||
message: 'Por favor, introduce una URL válida.'
|
||||
}
|
||||
}
|
||||
},
|
||||
social_instagram: {
|
||||
validators: {
|
||||
uri: {
|
||||
message: 'Por favor, introduce una URL válida.'
|
||||
}
|
||||
}
|
||||
},
|
||||
social_linkedin: {
|
||||
validators: {
|
||||
uri: {
|
||||
message: 'Por favor, introduce una URL válida.'
|
||||
}
|
||||
}
|
||||
},
|
||||
social_tiktok: {
|
||||
validators: {
|
||||
uri: {
|
||||
message: 'Por favor, introduce una URL válida.'
|
||||
}
|
||||
}
|
||||
},
|
||||
social_x_twitter: {
|
||||
validators: {
|
||||
uri: {
|
||||
message: 'Por favor, introduce una URL válida.'
|
||||
}
|
||||
}
|
||||
},
|
||||
social_google: {
|
||||
validators: {
|
||||
uri: {
|
||||
message: 'Por favor, introduce una URL válida.'
|
||||
}
|
||||
}
|
||||
},
|
||||
social_pinterest: {
|
||||
validators: {
|
||||
uri: {
|
||||
message: 'Por favor, introduce una URL válida.'
|
||||
}
|
||||
}
|
||||
},
|
||||
social_youtube: {
|
||||
validators: {
|
||||
uri: {
|
||||
message: 'Por favor, introduce una URL válida.'
|
||||
}
|
||||
}
|
||||
},
|
||||
social_vimeo: {
|
||||
validators: {
|
||||
uri: {
|
||||
message: 'Por favor, introduce una URL válida.'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
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()
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Inicializar formularios de ajustes de Formularios de contacto
|
||||
window.ContactFormSettingsForm = new FormCustomListener({
|
||||
formSelector: '#website-contact-form-settings-card',
|
||||
buttonSelectors: ['.btn-save', '.btn-cancel'],
|
||||
callbacks: [() => {}],
|
||||
dispatchOnSubmit: 'saveContactFormSettings',
|
||||
validationConfig: {
|
||||
fields: {
|
||||
// Validación para correo electrónico de recepción
|
||||
contact_form_email: {
|
||||
validators: {
|
||||
emailAddress: {
|
||||
message: 'Por favor, introduce un correo electrónico válido.'
|
||||
},
|
||||
notEmpty: {
|
||||
message: 'El correo electrónico es obligatorio.'
|
||||
}
|
||||
}
|
||||
},
|
||||
// Validación para correo electrónico con copia
|
||||
contact_form_email_cc: {
|
||||
validators: {
|
||||
emailAddress: {
|
||||
message: 'Por favor, introduce un correo electrónico válido.'
|
||||
},
|
||||
// Validación personalizada para comparar ambos correos electrónicos
|
||||
callback: {
|
||||
message: 'Los correos electrónicos deben ser diferentes.',
|
||||
callback: function (input) {
|
||||
const email = document.querySelector('#contact_form_email').value.trim();
|
||||
const emailCC = input.value.trim();
|
||||
|
||||
// Si ambos correos son iguales, la validación falla
|
||||
if (email === emailCC) {
|
||||
return false; // Los correos son iguales, por lo que la validación falla
|
||||
}
|
||||
|
||||
return true; // Si son diferentes, la validación pasa
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
// Validación para el asunto del formulario de contacto
|
||||
contact_form_subject: {
|
||||
validators: {
|
||||
stringLength: {
|
||||
max: 60,
|
||||
message: 'El título del correo no puede exceder los 60 caracteres.'
|
||||
},
|
||||
notEmpty: {
|
||||
message: 'El título del correo es obligatorio.'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
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()
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Inicializar formularios de ajustes de información de contacto
|
||||
window.ContactInfoSettingsForm = new FormCustomListener({
|
||||
formSelector: '#website-contact-info-settings-card',
|
||||
buttonSelectors: ['.btn-save', '.btn-cancel'],
|
||||
callbacks: [() => {}],
|
||||
dispatchOnSubmit: 'saveContactInfoSettings',
|
||||
validationConfig: {
|
||||
fields: {
|
||||
// Validación para número telefónico
|
||||
contact_phone_number: {
|
||||
validators: {
|
||||
callback: {
|
||||
message: 'Por favor, introduce un número de teléfono válido para México.',
|
||||
callback: function (input) {
|
||||
// Si el campo está vacío, no hacemos validación
|
||||
if (input.value.trim() === '') {
|
||||
return true; // Permitir vacío
|
||||
}
|
||||
|
||||
// Si no está vacío, validamos el formato del número
|
||||
const cleanValue = input.value.replace(/\D/g, '');
|
||||
const regex = /^[1-9]\d{9}$/; // Exactamente 10 dígitos
|
||||
|
||||
return regex.test(cleanValue); // Valida solo si hay un número
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
// Validación para extensión telefónica (opcional, pero solo si contact_phone_number tiene valor)
|
||||
contact_phone_number_ext: {
|
||||
validators: {
|
||||
stringLength: {
|
||||
max: 10,
|
||||
message: 'La extensión no debe exceder los 10 caracteres.'
|
||||
},
|
||||
callback: {
|
||||
message: 'La extensión requiere de ingresar un número telefónico.',
|
||||
callback: function (input) {
|
||||
// Obtener el valor de 'contact_phone_number'
|
||||
const phoneNumber = document.querySelector('#contact_phone_number')?.value.trim();
|
||||
|
||||
// Si el número telefónico tiene valor, entonces la extensión es obligatoria
|
||||
if (phoneNumber !== '') {
|
||||
// Si la extensión está vacía, la validación falla
|
||||
return true; // Permitir vacío
|
||||
}
|
||||
|
||||
// Si no se ha ingresado un número telefónico, la extensión no debe tener valor
|
||||
return input.value.trim() === '';
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
// Validación para correo electrónico de contacto (opcional)
|
||||
contact_email: {
|
||||
validators: {
|
||||
emailAddress: {
|
||||
message: 'Por favor, introduce un correo electrónico válido.'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
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()
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Inicializar formularios de ajustes de ubicación
|
||||
window.LocationSettingsForm = new FormCustomListener({
|
||||
formSelector: '#website-location-settings-card',
|
||||
buttonSelectors: ['.btn-save', '.btn-cancel'],
|
||||
callbacks: [() => {}],
|
||||
dispatchOnSubmit: 'saveLocationSettings',
|
||||
validationConfig: {
|
||||
fields: {
|
||||
// Validación para dirección (No obligatorio, máximo 160 caracteres)
|
||||
contact_direccion: {
|
||||
validators: {
|
||||
stringLength: {
|
||||
max: 160,
|
||||
message: 'La dirección no puede exceder los 160 caracteres.'
|
||||
}
|
||||
}
|
||||
},
|
||||
// Validación para horario (No obligatorio, máximo 160 caracteres)
|
||||
contact_horario: {
|
||||
validators: {
|
||||
stringLength: {
|
||||
max: 160,
|
||||
message: 'El horario no puede exceder los 160 caracteres.'
|
||||
}
|
||||
}
|
||||
},
|
||||
// Validación para latitud (No obligatorio, pero debe ser un número si se ingresa)
|
||||
contact_location_lat: {
|
||||
validators: {
|
||||
numeric: {
|
||||
message: 'La latitud debe ser un número.'
|
||||
},
|
||||
callback: {
|
||||
message: 'La latitud es obligatoria si se ingresa longitud.',
|
||||
callback: function (input) {
|
||||
// Obtener el valor de longitud
|
||||
const longitude = document.querySelector('#contact_location_lng')?.value.trim();
|
||||
|
||||
// Si longitud tiene un valor, entonces latitud es obligatorio
|
||||
if (longitude !== '') {
|
||||
return input.value.trim() !== ''; // La latitud no puede estar vacía
|
||||
}
|
||||
|
||||
return true; // Si longitud está vacío, no se valida latitud
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
// Validación para longitud (No obligatorio, pero debe ser un número si se ingresa)
|
||||
contact_location_lng: {
|
||||
validators: {
|
||||
numeric: {
|
||||
message: 'La longitud debe ser un número.'
|
||||
},
|
||||
callback: {
|
||||
message: 'La longitud es obligatoria si se ingresa latitud.',
|
||||
callback: function (input) {
|
||||
// Obtener el valor de latitud
|
||||
const latitude = document.querySelector('#contact_location_lat')?.value.trim();
|
||||
|
||||
// Si latitud tiene un valor, entonces longitud es obligatorio
|
||||
if (latitude !== '') {
|
||||
return input.value.trim() !== ''; // La longitud no puede estar vacía
|
||||
}
|
||||
|
||||
return true; // Si latitud está vacío, no se valida longitud
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
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()
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Inicializar formularios de ajustes de chat
|
||||
window.ChatSettingsForm = new FormCustomListener({
|
||||
formSelector: '#website-chat-settings-card',
|
||||
buttonSelectors: ['.btn-save', '.btn-cancel'],
|
||||
callbacks: [() => {}],
|
||||
dispatchOnSubmit: 'saveChatSettings',
|
||||
validationConfig: {
|
||||
fields: {
|
||||
chat_whatsapp_number: {
|
||||
validators: {
|
||||
callback: {
|
||||
message: 'Por favor, introduce un número de teléfono válido para México.',
|
||||
callback: function (input) {
|
||||
// Obtener el proveedor directamente dentro de la validación
|
||||
const provider = document.querySelector('#chat_provider')?.value;
|
||||
|
||||
// Validar solo si el proveedor es WhatsApp
|
||||
if (provider !== 'whatsapp') return true;
|
||||
|
||||
const cleanValue = input.value.replace(/\D/g, '');
|
||||
const regex = /^[1-9]\d{9}$/; // Exactamente 10 dígitos
|
||||
|
||||
return regex.test(cleanValue);
|
||||
}
|
||||
},
|
||||
notEmpty: {
|
||||
message: 'El número de teléfono es obligatorio.',
|
||||
enabled: () => {
|
||||
// Obtener el proveedor directamente dentro de la validación
|
||||
const provider = document.querySelector('#chat_provider')?.value;
|
||||
|
||||
return provider === 'whatsapp'; // Habilita solo si es WhatsApp
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
chat_whatsapp_message: {
|
||||
validators: {
|
||||
stringLength: {
|
||||
max: 500,
|
||||
message: 'El mensaje no puede exceder los 500 caracteres.'
|
||||
},
|
||||
notEmpty: {
|
||||
message: 'El mensaje es obligatorio.',
|
||||
enabled: () => {
|
||||
// Obtener el proveedor directamente dentro de la validación
|
||||
const provider = document.querySelector('#chat_provider')?.value;
|
||||
|
||||
return provider === 'whatsapp'; // Habilita solo si es WhatsApp
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
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()
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Inicializar formularios de ajustes de análisis de datos
|
||||
window.AnalyticsSettingsForm = new FormCustomListener({
|
||||
formSelector: '#website-analytics-settings-card',
|
||||
buttonSelectors: ['.btn-save', '.btn-cancel'],
|
||||
callbacks: [() => {}],
|
||||
dispatchOnSubmit: 'saveAnalyticsSettings',
|
||||
validationConfig: {
|
||||
fields: {
|
||||
google_analytics_id: {
|
||||
validators: {
|
||||
callback: {
|
||||
message: 'ID de medición de Google Analytics no tienen un formato válido.',
|
||||
callback: function (input) {
|
||||
if (document.getElementById('google_analytics_enabled').checked) {
|
||||
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()
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Inicializar formularios de ajustes de plantilla de sitio web
|
||||
window.TemplateSettingsForm = new FormCustomListener({
|
||||
formSelector: '#website-template-settings-card',
|
||||
buttonSelectors: ['.btn-save', '.btn-cancel'],
|
||||
callbacks: [() => {}],
|
||||
dispatchOnSubmit: 'saveTemplateSettings',
|
||||
validationConfig: {
|
||||
fields: {
|
||||
website_tpl_footer_text: {
|
||||
validators: {
|
||||
stringLength: {
|
||||
max: 50,
|
||||
message: 'El mensaje no puede exceder los 50 caracteres.'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
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()
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Recargar validación de formularios al morphear componentes
|
||||
Livewire.hook('morphed', ({ component }) => {
|
||||
switch (component.name) {
|
||||
case 'website-settings':
|
||||
if (window.WebsiteSettingsForm) {
|
||||
window.WebsiteSettingsForm.reloadValidation();
|
||||
}
|
||||
break;
|
||||
|
||||
case 'website-social-settings':
|
||||
if (window.SocialSettingsForm) {
|
||||
window.SocialSettingsForm.reloadValidation();
|
||||
}
|
||||
break;
|
||||
|
||||
case 'website-contact-info-settings':
|
||||
if (window.ContactInfoSettingsForm) {
|
||||
window.ContactInfoSettingsForm.reloadValidation();
|
||||
}
|
||||
break;
|
||||
|
||||
case 'website-contact-form-settings':
|
||||
if (window.ContactFormSettingsForm) {
|
||||
window.ContactFormSettingsForm.reloadValidation();
|
||||
}
|
||||
break;
|
||||
|
||||
case 'website-location-settings':
|
||||
if (window.LocationSettingsForm) {
|
||||
window.LocationSettingsForm.reloadValidation();
|
||||
}
|
||||
break;
|
||||
|
||||
case 'website-chat-settings':
|
||||
if (window.ChatSettingsForm) {
|
||||
window.ChatSettingsForm.reloadValidation();
|
||||
}
|
||||
break;
|
||||
|
||||
case 'website-analytics-settings':
|
||||
if (window.AnalyticsSettingsForm) {
|
||||
window.AnalyticsSettingsForm.reloadValidation();
|
||||
}
|
||||
break;
|
||||
|
||||
case 'website-template-settings':
|
||||
if (window.TemplateSettingsForm) {
|
||||
window.TemplateSettingsForm.reloadValidation();
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
});
|
Reference in New Issue
Block a user