import Toastify from 'toastify-js'; export class ToastComponent { static defaultOptions = { duration: 4000, position: 'right', gravity: 'top', close: true, stopOnFocus: true, style: { background: 'transparent', boxShadow: 'none', padding: '0', borderRadius: '0' }, offset: { x: 16, y: 16 } }; static types = { success: { className: 'toast-success', icon: '✓' }, error: { className: 'toast-error', icon: '✕' }, warning: { className: 'toast-warning', icon: '⚠' }, info: { className: 'toast-info', icon: 'ℹ' }, default: { className: 'toast-default', icon: '●' } }; static show(message, type = 'default', options = {}) { if (!message) { console.warn('ToastComponent: Message is required'); return null; } const typeConfig = this.types[type] || this.types.default; const config = { ...this.defaultOptions, ...options }; // Build toast content const content = this.buildToastContent(message, config.title, typeConfig.icon); const toastOptions = { text: content, duration: config.duration, gravity: config.gravity, position: config.position, stopOnFocus: config.stopOnFocus, className: `toastify ${typeConfig.className}`, escapeMarkup: false, offset: config.offset, style: { ...this.defaultOptions.style, ...config.style }, onClick: config.onClick, onClose: config.onClose }; // Create and show toast const toast = Toastify(toastOptions); toast.showToast(); // Add progress bar if duration is set if (config.duration > 0 && config.showProgress !== false) { this.addProgressBar(toast, config.duration); } return toast; } static buildToastContent(message, title, icon) { let content = '
'; if (icon) { content += `
${icon}
`; } content += '
'; if (title) { content += `
${this.escapeHtml(title)}
`; } content += `
${this.escapeHtml(message)}
`; content += '
'; content += ''; content += '
'; return content; } static addProgressBar(toast, duration) { const toastElement = toast.toastElement; if (!toastElement) return; const progressBar = document.createElement('div'); progressBar.className = 'toast-progress'; progressBar.innerHTML = '
'; toastElement.appendChild(progressBar); const bar = progressBar.querySelector('.toast-progress__bar'); if (bar) { bar.style.animationDuration = `${duration}ms`; } } static escapeHtml(text) { const div = document.createElement('div'); div.textContent = text; return div.innerHTML; } // Convenience methods static success(message, options = {}) { return this.show(message, 'success', options); } static error(message, options = {}) { return this.show(message, 'error', options); } static warning(message, options = {}) { return this.show(message, 'warning', options); } static info(message, options = {}) { return this.show(message, 'info', options); } // Advanced toast types static promise(promise, messages = {}, options = {}) { const { loading = 'Загрузка...', success = 'Успешно!', error = 'Ошибка!' } = messages; // Show loading toast const loadingToast = this.show(loading, 'info', { duration: 0, // Don't auto-close showProgress: false, ...options }); return promise .then(result => { // Close loading toast if (loadingToast && loadingToast.toastElement) { loadingToast.toastElement.remove(); } // Show success toast const successMessage = typeof success === 'function' ? success(result) : success; this.success(successMessage, options); return result; }) .catch(err => { // Close loading toast if (loadingToast && loadingToast.toastElement) { loadingToast.toastElement.remove(); } // Show error toast const errorMessage = typeof error === 'function' ? error(err) : error; this.error(errorMessage, options); throw err; }); } static confirm(message, options = {}) { return new Promise((resolve) => { const confirmOptions = { duration: 0, title: 'Подтверждение', showProgress: false, ...options }; const content = `
?
${this.escapeHtml(confirmOptions.title)}
${this.escapeHtml(message)}
`; const toast = Toastify({ text: content, gravity: 'top', position: 'center', className: 'toastify toast-warning toast-enhanced toast-confirm', escapeMarkup: false, duration: 0, stopOnFocus: true }); toast.showToast(); // Add event listeners const toastElement = toast.toastElement; if (toastElement) { const yesBtn = toastElement.querySelector('.toast-confirm-yes'); const noBtn = toastElement.querySelector('.toast-confirm-no'); if (yesBtn) { yesBtn.addEventListener('click', () => { toastElement.remove(); resolve(true); }); } if (noBtn) { noBtn.addEventListener('click', () => { toastElement.remove(); resolve(false); }); } } }); } // Utility method to remove all toasts static clear() { const toasts = document.querySelectorAll('.toastify'); toasts.forEach(toast => toast.remove()); } // Method to update toast position for responsive design static updatePosition() { const isMobile = window.innerWidth < 768; this.defaultOptions.position = isMobile ? 'center' : 'right'; } } // Update position on resize if (typeof window !== 'undefined') { window.addEventListener('resize', () => { ToastComponent.updatePosition(); }); // Set initial position ToastComponent.updatePosition(); }