| |
| function createNotificationContainer() { |
| let container = document.getElementById('notification-container'); |
| if (!container) { |
| container = document.createElement('div'); |
| container.id = 'notification-container'; |
| container.style.cssText = ` |
| position: fixed; |
| top: 20px; |
| right: 20px; |
| z-index: 9999; |
| max-width: 400px; |
| `; |
| document.body.appendChild(container); |
| } |
| return container; |
| } |
|
|
| |
| function showError(message) { |
| const container = createNotificationContainer(); |
| |
| |
| const notification = document.createElement('div'); |
| notification.className = 'error-notification'; |
| notification.style.cssText = ` |
| background-color: #ff4444; |
| color: white; |
| padding: 15px; |
| margin-bottom: 10px; |
| border-radius: 4px; |
| box-shadow: 0 2px 5px rgba(0,0,0,0.2); |
| position: relative; |
| animation: slideIn 0.3s ease-out; |
| `; |
| |
| |
| const closeButton = document.createElement('button'); |
| closeButton.innerHTML = '×'; |
| closeButton.style.cssText = ` |
| position: absolute; |
| right: 10px; |
| top: 50%; |
| transform: translateY(-50%); |
| background: none; |
| border: none; |
| color: white; |
| font-size: 20px; |
| cursor: pointer; |
| padding: 0 5px; |
| `; |
| |
| |
| const messageText = document.createElement('div'); |
| messageText.style.cssText = ` |
| margin-right: 20px; |
| word-wrap: break-word; |
| `; |
| messageText.textContent = typeof message === 'object' ? message.message : message; |
| |
| |
| notification.appendChild(messageText); |
| notification.appendChild(closeButton); |
| |
| |
| container.appendChild(notification); |
| |
| |
| closeButton.onclick = () => { |
| notification.style.animation = 'slideOut 0.3s ease-out'; |
| setTimeout(() => notification.remove(), 300); |
| }; |
| |
| |
| setTimeout(() => { |
| if (notification.parentNode) { |
| notification.style.animation = 'slideOut 0.3s ease-out'; |
| setTimeout(() => notification.remove(), 300); |
| } |
| }, 10000); |
| } |
|
|
| |
| const style = document.createElement('style'); |
| style.textContent = ` |
| @keyframes slideIn { |
| from { transform: translateX(100%); opacity: 0; } |
| to { transform: translateX(0); opacity: 1; } |
| } |
| |
| @keyframes slideOut { |
| from { transform: translateX(0); opacity: 1; } |
| to { transform: translateX(100%); opacity: 0; } |
| } |
| `; |
| document.head.appendChild(style); |
|
|
| |
| function setupErrorNotifications() { |
| const eventSource = new EventSource('/notifications'); |
| |
| eventSource.onmessage = function(event) { |
| const data = JSON.parse(event.data); |
| if (data.type === 'error') { |
| showError(data.message); |
| } |
| }; |
| |
| eventSource.onerror = function(error) { |
| console.error('EventSource failed:', error); |
| eventSource.close(); |
| |
| setTimeout(setupErrorNotifications, 5000); |
| }; |
| } |
|
|
| |
| function handleAjaxError(error) { |
| let errorMessage = 'An error occurred'; |
| if (error.response) { |
| try { |
| const data = error.response.data; |
| errorMessage = data.error || data.message || errorMessage; |
| } catch (e) { |
| errorMessage = error.response.statusText || errorMessage; |
| } |
| } else if (error.request) { |
| errorMessage = 'No response received from server'; |
| } else { |
| errorMessage = error.message; |
| } |
| showError(errorMessage); |
| } |
|
|
| |
| document.addEventListener('DOMContentLoaded', function() { |
| setupErrorNotifications(); |
| |
| |
| $(document).ajaxError(function(event, jqXHR, settings, error) { |
| handleAjaxError(error); |
| }); |
| }); |