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:
2026-07-16 18:59:00 +03:00
parent 63c83a059d
commit 7672dd98df
9 changed files with 317 additions and 1 deletions

View File

@@ -108,6 +108,40 @@ export function registerPushRoutes(app: import("express").Express): void {
res.status(500).json({ error: 'Ошибка обновления статуса' });
}
});
// Update the chat currently open on the user's visible tab.
// Used by the server to suppress push notifications for active chats.
app.post('/api/devices/active-chat', authenticateToken, async (req: AuthenticatedRequest, res) => {
try {
const userId = req.user!.userId;
const organizationId = req.user!.organizationId;
const { type, id, visible } = req.body;
if (!['messenger', 'task'].includes(type) || typeof id !== 'number' || typeof visible !== 'boolean') {
return res.status(400).json({ error: 'Некорректные параметры активного чата' });
}
await storage.updateUserActiveChat(userId, organizationId, type, id, visible);
res.json({ success: true });
} catch (error) {
console.error('Active chat update error:', error);
res.status(500).json({ error: 'Ошибка обновления активного чата' });
}
});
// Clear active chat when the user leaves the chat page.
app.delete('/api/devices/active-chat', authenticateToken, async (req: AuthenticatedRequest, res) => {
try {
const userId = req.user!.userId;
const organizationId = req.user!.organizationId;
await storage.clearUserActiveChat(userId, organizationId);
res.json({ success: true });
} catch (error) {
console.error('Active chat clear error:', error);
res.status(500).json({ error: 'Ошибка сброса активного чата' });
}
});
// Get user's registered devices
app.get('/api/devices', authenticateToken, async (req: AuthenticatedRequest, res) => {