fix(chat): подавлять push-уведомления при открытом активном чате и автоотметка прочтения в task chat
- Добавлены active_chat_* поля в user_presence и endpoint /api/devices/active-chat - Сервер не шлёт Web Push/Pushy, если получатель смотрит в тот же чат на видимой вкладке - Клиент сообщает серверу и Service Worker об активном чате из Chat.tsx и TaskChat.tsx - TaskChat: входящие сообщения автоматически отмечаются прочитанными при видимой вкладке - SW: подавляет foreground/system push, если активный чат совпадает
This commit is contained in:
@@ -6,6 +6,11 @@ const STATIC_ASSETS = [
|
||||
'/favicon.svg'
|
||||
];
|
||||
|
||||
// Активный чат, о котором сообщает клиент через postMessage.
|
||||
// Используется для подавления push-уведомлений, когда пользователь уже
|
||||
// смотрит в соответствующий чат.
|
||||
let activeChat = null; // { type: 'messenger'|'task', id: number, visible: boolean, updatedAt: number }
|
||||
|
||||
// ── IndexedDB helpers (mirrors offlineQueue.ts schema, must stay in sync) ────
|
||||
// Schema history:
|
||||
// v1 – `queue` store (keyPath: id, index: enqueuedAt)
|
||||
@@ -480,6 +485,26 @@ async function sendToForegroundClients(payload) {
|
||||
}
|
||||
}
|
||||
|
||||
function shouldSuppressPushForActiveChat(payload) {
|
||||
if (!activeChat || !activeChat.visible) return false;
|
||||
|
||||
// Игнорируем устаревшие записи.
|
||||
const maxAgeMs = 60 * 1000;
|
||||
if (!activeChat.updatedAt || Date.now() - activeChat.updatedAt > maxAgeMs) return false;
|
||||
|
||||
const nestedType = payload.data?.type;
|
||||
|
||||
if (nestedType === 'messenger' && activeChat.type === 'messenger') {
|
||||
return parseInt(payload.data?.conversationId, 10) === activeChat.id;
|
||||
}
|
||||
|
||||
if ((nestedType === 'chat' || payload.type === 'chat') && activeChat.type === 'task') {
|
||||
return parseInt(payload.data?.taskId || payload.taskId, 10) === activeChat.id;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
self.addEventListener('push', (event) => {
|
||||
console.log('[SW] Push notification received');
|
||||
|
||||
@@ -509,6 +534,12 @@ self.addEventListener('push', (event) => {
|
||||
return;
|
||||
}
|
||||
|
||||
// Подавляем push, если пользователь уже смотрит в этот чат на активной вкладке.
|
||||
if (shouldSuppressPushForActiveChat(data)) {
|
||||
console.log('[SW] Push suppressed for active chat:', activeChat);
|
||||
return;
|
||||
}
|
||||
|
||||
event.waitUntil(
|
||||
hasVisibleClient().then((visible) => {
|
||||
if (visible) {
|
||||
@@ -620,5 +651,21 @@ self.addEventListener('pushsubscriptionchange', (event) => {
|
||||
self.addEventListener('message', (event) => {
|
||||
if (event.data?.type === 'SKIP_WAITING') {
|
||||
self.skipWaiting();
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.data?.type === 'ACTIVE_CHAT') {
|
||||
const payload = event.data?.payload || {};
|
||||
activeChat = {
|
||||
type: payload.type,
|
||||
id: payload.id,
|
||||
visible: !!payload.visible,
|
||||
updatedAt: Date.now(),
|
||||
};
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.data?.type === 'CLEAR_ACTIVE_CHAT') {
|
||||
activeChat = null;
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user