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