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();
}