Testing Alpha
This commit is contained in:
@ -1,207 +0,0 @@
|
||||
export default class LivewireNotification {
|
||||
constructor(config = {}) {
|
||||
const defaultConfig = {
|
||||
delay: 9000, // 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);
|
||||
}
|
||||
});
|
||||
|
||||
// Escuchar evento personalizado para almacenar la notificación en localStorage
|
||||
document.addEventListener('store-notification', (event) => {
|
||||
const notification = {
|
||||
type: event.detail.type || 'info',
|
||||
message: event.detail.message || 'Notificación',
|
||||
delay: event.detail.delay || 5000,
|
||||
target: event.detail.target || 'body'
|
||||
};
|
||||
localStorage.setItem('pendingNotification', JSON.stringify(notification));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 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,
|
||||
delay: customTimeout || options.delay || this.config.delay // 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) {
|
||||
setTimeout(() => {
|
||||
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.setdelay(notificationElement, event);
|
||||
|
||||
// Configurar el evento para el botón de cierre
|
||||
this.setupCloseButton(notificationElement, event);
|
||||
}, 5);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.setdelay(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.
|
||||
*/
|
||||
setdelay(notificationElement, event) {
|
||||
const timeout = event.delay || this.config.delay;
|
||||
|
||||
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);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!window.livewireNotification) {
|
||||
window.livewireNotification = new LivewireNotification();
|
||||
}
|
17
resources/assets/js/notifications/drivers/notyf-driver.js
Normal file
17
resources/assets/js/notifications/drivers/notyf-driver.js
Normal file
@ -0,0 +1,17 @@
|
||||
import { Notyf } from 'notyf';
|
||||
import 'notyf/notyf.min.css';
|
||||
|
||||
const notyf = new Notyf({
|
||||
duration: 5000,
|
||||
ripple: true,
|
||||
position: { x: 'right', y: 'top' },
|
||||
});
|
||||
|
||||
export const NotyfDriver = {
|
||||
notify({ type = 'success', message = '' }) {
|
||||
notyf.open({
|
||||
type,
|
||||
message,
|
||||
});
|
||||
},
|
||||
};
|
@ -0,0 +1,15 @@
|
||||
export const SweetAlertDriver = {
|
||||
async notify(options = {}) {
|
||||
const Swal = (await import('sweetalert2')).default;
|
||||
|
||||
Swal.fire({
|
||||
icon: options.type || 'info',
|
||||
title: options.title || '',
|
||||
text: options.message || '',
|
||||
timer: options.delay || 5000,
|
||||
timerProgressBar: true,
|
||||
showConfirmButton: false,
|
||||
...options,
|
||||
});
|
||||
},
|
||||
};
|
15
resources/assets/js/notifications/drivers/toastify-driver.js
Normal file
15
resources/assets/js/notifications/drivers/toastify-driver.js
Normal file
@ -0,0 +1,15 @@
|
||||
import Toastify from 'toastify-js';
|
||||
import 'toastify-js/src/toastify.css';
|
||||
|
||||
export const ToastifyDriver = {
|
||||
notify({ message = '', type = 'default', duration = 4000, position = 'right' }) {
|
||||
Toastify({
|
||||
text: message,
|
||||
duration: duration,
|
||||
gravity: 'top',
|
||||
position: position,
|
||||
className: `toastify-${type}`,
|
||||
close: true,
|
||||
}).showToast();
|
||||
},
|
||||
};
|
87
resources/assets/js/notifications/drivers/toastr-driver.js
Normal file
87
resources/assets/js/notifications/drivers/toastr-driver.js
Normal file
@ -0,0 +1,87 @@
|
||||
// resources/js/vuexy/notifications/vuexy-toastr.js
|
||||
|
||||
import toastr from 'toastr';
|
||||
|
||||
export const ToastrDriver = {
|
||||
defaultOptions: {
|
||||
closeButton: true,
|
||||
progressBar: true,
|
||||
tapToDismiss: true,
|
||||
newestOnTop: true,
|
||||
positionClass: 'toast-top-right',
|
||||
timeOut: 5000,
|
||||
extendedTimeOut: 1000,
|
||||
showDuration: 300,
|
||||
hideDuration: 300,
|
||||
showMethod: 'fadeIn',
|
||||
hideMethod: 'fadeOut',
|
||||
},
|
||||
|
||||
/**
|
||||
* Notifica usando toastr con opciones personalizadas
|
||||
*/
|
||||
notify({
|
||||
type = 'success',
|
||||
message = '',
|
||||
title = '',
|
||||
delay = 5000,
|
||||
position = 'toast-top-right',
|
||||
closeButton = true,
|
||||
progressBar = true,
|
||||
iconClass = null,
|
||||
extraOptions = {}
|
||||
} = {}) {
|
||||
const timeOut = delay;
|
||||
const extendedTimeOut = delay + 1000;
|
||||
|
||||
toastr.options = {
|
||||
...this.defaultOptions,
|
||||
closeButton,
|
||||
progressBar,
|
||||
timeOut,
|
||||
extendedTimeOut,
|
||||
positionClass: position,
|
||||
...extraOptions
|
||||
};
|
||||
|
||||
if (iconClass) {
|
||||
toastr.options.iconClass = iconClass;
|
||||
}
|
||||
|
||||
if (toastr[type]) {
|
||||
toastr[type](message, title);
|
||||
} else {
|
||||
toastr.info(message || 'Sin mensaje');
|
||||
}
|
||||
|
||||
if (import.meta.env.DEV) {
|
||||
console.debug(`[TOAST ${type.toUpperCase()}] ${title}: ${message}`);
|
||||
}
|
||||
},
|
||||
|
||||
success(message, title = 'Éxito', delay = 4000, options = {}) {
|
||||
this.notify({ type: 'success', message, title, delay, ...options });
|
||||
},
|
||||
|
||||
error(message, title = 'Error', delay = 6000, options = {}) {
|
||||
this.notify({ type: 'error', message, title, delay, ...options });
|
||||
},
|
||||
|
||||
warning(message, title = 'Advertencia', delay = 5000, options = {}) {
|
||||
this.notify({ type: 'warning', message, title, delay, ...options });
|
||||
},
|
||||
|
||||
info(message, title = 'Información', delay = 5000, options = {}) {
|
||||
this.notify({ type: 'info', message, title, delay, ...options });
|
||||
},
|
||||
|
||||
/**
|
||||
* Inicializa listeners para eventos globales como vuexy:notify
|
||||
*/
|
||||
listenToGlobalEvents() {
|
||||
window.addEventListener('vuexy:notify', (event) => {
|
||||
const detail = event.detail || {};
|
||||
this.notify(detail);
|
||||
});
|
||||
}
|
||||
};
|
47
resources/assets/js/notifications/drivers/vuexy-driver.js
Normal file
47
resources/assets/js/notifications/drivers/vuexy-driver.js
Normal file
@ -0,0 +1,47 @@
|
||||
// drivers/vuexy-driver.js
|
||||
|
||||
export const VuexyDriver = {
|
||||
notify({ message, type = 'info', target = 'body', delay = 3000 }) {
|
||||
const event = new CustomEvent('vuexy:notify', {
|
||||
detail: { type, message, target, delay }
|
||||
});
|
||||
|
||||
window.dispatchEvent(event);
|
||||
},
|
||||
|
||||
success(message, target = 'body', delay = 3000) {
|
||||
this.notify({ type: 'success', message, target, delay });
|
||||
},
|
||||
|
||||
error(message, target = 'body', delay = 3000) {
|
||||
this.notify({ type: 'error', message, target, delay });
|
||||
},
|
||||
|
||||
info(message, target = 'body', delay = 3000) {
|
||||
this.notify({ type: 'info', message, target, delay });
|
||||
},
|
||||
|
||||
warning(message, target = 'body', delay = 3000) {
|
||||
this.notify({ type: 'warning', message, target, delay });
|
||||
},
|
||||
|
||||
fromStorage() {
|
||||
const storageData = localStorage.getItem('vuexy_notification');
|
||||
|
||||
if (storageData) {
|
||||
try {
|
||||
this.notify(JSON.parse(storageData));
|
||||
localStorage.removeItem('vuexy_notification');
|
||||
} catch (e) {
|
||||
console.error('[VuexyDriver] Error parseando notificación', e);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
fromSession() {
|
||||
if (window.vuexySessionNotification) {
|
||||
this.notify(window.vuexySessionNotification);
|
||||
window.vuexySessionNotification = null;
|
||||
}
|
||||
}
|
||||
};
|
67
resources/assets/js/notifications/notify-channel-service.js
Normal file
67
resources/assets/js/notifications/notify-channel-service.js
Normal file
@ -0,0 +1,67 @@
|
||||
// notify-channel-service.js
|
||||
import { VuexyNotifyService } from './vuexy/vuexy-notify';
|
||||
import { ToastifyDriver } from './drivers/toastify-driver';
|
||||
import { NotyfDriver } from './drivers/notyf-driver';
|
||||
import { ToastrDriver } from './drivers/toastr-driver';
|
||||
import { VuexyDriver } from './drivers/vuexy-driver';
|
||||
|
||||
const NotifyChannelService = {
|
||||
async notify({ channel = 'toastr', ...payload }) {
|
||||
switch (channel) {
|
||||
case 'toastr':
|
||||
ToastrDriver.notify(payload);
|
||||
break;
|
||||
|
||||
case 'notyf':
|
||||
NotyfDriver.notify(payload);
|
||||
break;
|
||||
|
||||
case 'toastify':
|
||||
ToastifyDriver.notify(payload);
|
||||
break;
|
||||
|
||||
case 'sweetalert': {
|
||||
const { SweetAlertDriver } = await import('./drivers/sweetalert-driver');
|
||||
SweetAlertDriver.notify(payload);
|
||||
break;
|
||||
}
|
||||
|
||||
case 'vuexy':
|
||||
VuexyDriver.notify(payload);
|
||||
break;
|
||||
|
||||
case 'custom':
|
||||
if (typeof window.VuexyNotify === 'function') {
|
||||
window.VuexyNotify(payload);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
console.warn(`[Notify] Canal desconocido: ${channel}`);
|
||||
break;
|
||||
}
|
||||
},
|
||||
fromLocalStorage() {
|
||||
const data = localStorage.getItem('vuexy_notification');
|
||||
|
||||
if (data) {
|
||||
try {
|
||||
const payload = JSON.parse(data);
|
||||
NotifyChannelService.notify(payload);
|
||||
localStorage.removeItem('vuexy_notification');
|
||||
} catch (e) {
|
||||
console.error('❌ Error parseando notificación de storage', e);
|
||||
}
|
||||
}
|
||||
},
|
||||
fromSession() {
|
||||
if (window.vuexySessionNotification) {
|
||||
NotifyChannelService.notify(window.vuexySessionNotification);
|
||||
window.vuexySessionNotification = null;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export { NotifyChannelService };
|
||||
|
||||
window.vuexyNotify = VuexyNotifyService;
|
7
resources/assets/js/notifications/notify-loader.js
Normal file
7
resources/assets/js/notifications/notify-loader.js
Normal file
@ -0,0 +1,7 @@
|
||||
// resources/assets/js/notify-loader.js
|
||||
import { NotifyChannelService } from './notify-channel-service.js';
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
NotifyChannelService.fromLocalStorage();
|
||||
NotifyChannelService.fromSession();
|
||||
});
|
94
resources/assets/js/notifications/vuexy/vuexy-notify.js
Normal file
94
resources/assets/js/notifications/vuexy/vuexy-notify.js
Normal file
@ -0,0 +1,94 @@
|
||||
export const VuexyNotifyService = {
|
||||
flash({ message, type = 'info', target = 'body', delay = 3000 }) {
|
||||
const event = new CustomEvent('vuexy:notify', {
|
||||
detail: { type, message, target, delay }
|
||||
});
|
||||
|
||||
window.dispatchEvent(event);
|
||||
},
|
||||
|
||||
success(message, target = 'body', delay = 3000) {
|
||||
this.flash({ type: 'success', message, target, delay });
|
||||
},
|
||||
|
||||
error(message, target = 'body', delay = 3000) {
|
||||
this.flash({ type: 'error', message, target, delay });
|
||||
},
|
||||
|
||||
info(message, target = 'body', delay = 3000) {
|
||||
this.flash({ type: 'info', message, target, delay });
|
||||
},
|
||||
|
||||
warning(message, target = 'body', delay = 3000) {
|
||||
this.flash({ type: 'warning', message, target, delay });
|
||||
},
|
||||
|
||||
fromLocalStorage() {
|
||||
const data = localStorage.getItem('vuexy_notification');
|
||||
|
||||
if (data) {
|
||||
try {
|
||||
this.flash(JSON.parse(data));
|
||||
|
||||
localStorage.removeItem('vuexy_notification');
|
||||
|
||||
} catch (e) {
|
||||
console.error('❌ Error parseando notificación de storage', e);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
fromSession() {
|
||||
if (window.vuexySessionNotification) {
|
||||
this.flash(window.vuexySessionNotification);
|
||||
window.vuexySessionNotification = null;
|
||||
}
|
||||
},
|
||||
|
||||
dispatch(eventName, payload = {}) {
|
||||
const event = new CustomEvent(eventName, { detail: payload });
|
||||
|
||||
window.dispatchEvent(event);
|
||||
}
|
||||
};
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
window.addEventListener('vuexy:notify', function (event) {
|
||||
// Si viene como array, tomar el primer objeto
|
||||
const detail = Array.isArray(event.detail) ? event.detail[0] : event.detail;
|
||||
const { type, message, target, delay } = detail || {};
|
||||
|
||||
const defaultTarget = 'body .notification-container';
|
||||
|
||||
let realTarget = target == 'body' ? defaultTarget : target;
|
||||
|
||||
let targetElement = document.querySelector(realTarget);
|
||||
|
||||
if (!targetElement) {
|
||||
console.warn('⚠️ Target para notificación no encontrado:', realTarget, ', usando ', defaultTarget);
|
||||
|
||||
targetElement = document.querySelector(defaultTarget);
|
||||
}
|
||||
|
||||
if(!targetElement) {
|
||||
console.error('🛑 Target por defecto no encontrado:', defaultTarget);
|
||||
return;
|
||||
}
|
||||
|
||||
const alert = document.createElement('div');
|
||||
|
||||
alert.className = `alert alert-${type} alert-dismissible fade show mt-2`;
|
||||
alert.setAttribute('role', 'alert');
|
||||
alert.innerHTML = `
|
||||
${message}
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
||||
`.trim();
|
||||
|
||||
targetElement.appendChild(alert);
|
||||
|
||||
setTimeout(() => {
|
||||
alert.remove();
|
||||
}, delay || 6000);
|
||||
});
|
||||
});
|
||||
|
Reference in New Issue
Block a user