130 lines
5.5 KiB
JavaScript
130 lines
5.5 KiB
JavaScript
// Показывает модальное окно со списком задач
|
||
function showUnreadNotification(tasks) {
|
||
const modalHtml = `
|
||
<div class="modal" id="unread-notification-modal">
|
||
<div class="modal-content" style="max-width: 500px;">
|
||
<div class="modal-header">
|
||
<h3>📬 У вас новые сообщения</h3>
|
||
<span class="close" onclick="closeUnreadNotification()">×</span>
|
||
</div>
|
||
<div class="modal-body">
|
||
<p>В следующих задачах есть непрочитанные сообщения:</p>
|
||
<ul style="list-style: none; padding: 0;">
|
||
${tasks.map(task => `
|
||
<li style="margin: 10px 0; padding: 10px; background: #f5f5f5; border-radius: 5px; display: flex; justify-content: space-between; align-items: center;">
|
||
<span><strong>${escapeHtml(task.title)}</strong> (${task.unreadCount} ${pluralize(task.unreadCount, ['новое сообщение', 'новых сообщения', 'новых сообщений'])})</span>
|
||
<button class="btn-primary" onclick="openTaskAndMarkRead(${task.taskId})">Открыть чат</button>
|
||
</li>
|
||
`).join('')}
|
||
</ul>
|
||
</div>
|
||
<div class="modal-footer">
|
||
<button class="btn-cancel" onclick="closeUnreadNotification()">Закрыть</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
`;
|
||
|
||
let modal = document.getElementById('unread-notification-modal');
|
||
if (modal) modal.remove();
|
||
|
||
const container = document.createElement('div');
|
||
container.innerHTML = modalHtml;
|
||
document.body.appendChild(container);
|
||
|
||
modal = document.getElementById('unread-notification-modal');
|
||
modal.style.display = 'block';
|
||
|
||
// Добавляем стили (если ещё не добавлены)
|
||
if (!document.getElementById('unread-notification-styles')) {
|
||
const style = document.createElement('style');
|
||
style.id = 'unread-notification-styles';
|
||
style.textContent = `
|
||
#unread-notification-modal {
|
||
display: none;
|
||
position: fixed;
|
||
z-index: 1001;
|
||
left: 0;
|
||
top: 0;
|
||
width: 100%;
|
||
height: 100%;
|
||
background-color: rgba(0,0,0,0.5);
|
||
animation: fadeIn 0.3s;
|
||
}
|
||
#unread-notification-modal .modal-content {
|
||
animation: slideIn 0.3s ease-out;
|
||
background-color: #fefefe;
|
||
margin: 5% auto;
|
||
border-radius: 10px;
|
||
box-shadow: 0 4px 20px rgba(0,0,0,0.2);
|
||
overflow: hidden;
|
||
}
|
||
@keyframes fadeIn {
|
||
from { opacity: 0; }
|
||
to { opacity: 1; }
|
||
}
|
||
@keyframes slideIn {
|
||
from { transform: translateY(-50px); opacity: 0; }
|
||
to { transform: translateY(0); opacity: 1; }
|
||
}
|
||
`;
|
||
document.head.appendChild(style);
|
||
}
|
||
}
|
||
|
||
function closeUnreadNotification() {
|
||
const modal = document.getElementById('unread-notification-modal');
|
||
if (modal) {
|
||
modal.style.display = 'none';
|
||
setTimeout(() => modal.remove(), 300);
|
||
}
|
||
}
|
||
|
||
// Вспомогательная функция для склонения
|
||
function pluralize(count, words) {
|
||
const cases = [2, 0, 1, 1, 1, 2];
|
||
return words[(count % 100 > 4 && count % 100 < 20) ? 2 : cases[Math.min(count % 10, 5)]];
|
||
}
|
||
|
||
// Экранирование HTML в заголовке задачи (защита от XSS)
|
||
function escapeHtml(unsafe) {
|
||
return unsafe
|
||
.replace(/&/g, "&")
|
||
.replace(/</g, "<")
|
||
.replace(/>/g, ">")
|
||
.replace(/"/g, """)
|
||
.replace(/'/g, "'");
|
||
}
|
||
|
||
// Открывает чат задачи и помечает все сообщения как прочитанные
|
||
function openTaskAndMarkRead(taskId) {
|
||
closeUnreadNotification();
|
||
// Опционально: сразу отмечаем все сообщения прочитанными
|
||
fetch(`/api/chat/tasks/${taskId}/mark-read`, { method: 'POST' })
|
||
.catch(err => console.warn('Не удалось отметить сообщения как прочитанные', err))
|
||
.finally(() => openTaskChat(taskId));
|
||
}
|
||
|
||
// Проверка наличия непрочитанных сообщений
|
||
function checkUnreadMessages() {
|
||
// Не беспокоим пользователя, если страница не активна
|
||
if (document.hidden) return;
|
||
|
||
fetch('/api/chat/unread-summary')
|
||
.then(response => {
|
||
if (response.status === 401) return null; // пользователь не авторизован
|
||
return response.json();
|
||
})
|
||
.then(data => {
|
||
if (data && data.totalUnread > 0) {
|
||
showUnreadNotification(data.tasks);
|
||
}
|
||
})
|
||
.catch(err => console.error('Ошибка проверки новых сообщений:', err));
|
||
}
|
||
|
||
// Запуск периодической проверки (раз в 5 минут)
|
||
setInterval(checkUnreadMessages, 5 * 60 * 1000);
|
||
|
||
// Проверка при загрузке страницы
|
||
document.addEventListener('DOMContentLoaded', checkUnreadMessages); |