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:
@@ -394,6 +394,88 @@ export class ContentStorage extends DataTablesStorage {
|
||||
return userIds.filter(id => !onlineUserIds.has(id));
|
||||
}
|
||||
|
||||
async updateUserActiveChat(
|
||||
userId: number,
|
||||
organizationId: number,
|
||||
type: 'messenger' | 'task',
|
||||
id: number,
|
||||
visible: boolean
|
||||
): Promise<void> {
|
||||
const existing = await db.select().from(userPresence)
|
||||
.where(and(
|
||||
eq(userPresence.userId, userId),
|
||||
eq(userPresence.organizationId, organizationId)
|
||||
))
|
||||
.limit(1);
|
||||
|
||||
if (existing.length > 0) {
|
||||
await db.update(userPresence)
|
||||
.set({
|
||||
activeChatType: type,
|
||||
activeChatId: id,
|
||||
activeChatVisible: visible,
|
||||
activeChatUpdatedAt: new Date(),
|
||||
lastSeenAt: new Date(),
|
||||
})
|
||||
.where(and(
|
||||
eq(userPresence.userId, userId),
|
||||
eq(userPresence.organizationId, organizationId)
|
||||
));
|
||||
} else {
|
||||
await db.insert(userPresence).values({
|
||||
userId,
|
||||
organizationId,
|
||||
isOnline: true,
|
||||
lastSeenAt: new Date(),
|
||||
activeDevices: 0,
|
||||
activeChatType: type,
|
||||
activeChatId: id,
|
||||
activeChatVisible: visible,
|
||||
activeChatUpdatedAt: new Date(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async clearUserActiveChat(userId: number, organizationId: number): Promise<void> {
|
||||
await db.update(userPresence)
|
||||
.set({
|
||||
activeChatType: null,
|
||||
activeChatId: null,
|
||||
activeChatVisible: false,
|
||||
activeChatUpdatedAt: new Date(),
|
||||
})
|
||||
.where(and(
|
||||
eq(userPresence.userId, userId),
|
||||
eq(userPresence.organizationId, organizationId)
|
||||
));
|
||||
}
|
||||
|
||||
async getUserActiveChat(userId: number, organizationId: number): Promise<{
|
||||
type: 'messenger' | 'task' | null;
|
||||
id: number | null;
|
||||
visible: boolean;
|
||||
updatedAt: Date | null;
|
||||
} | null> {
|
||||
const [presence] = await db.select({
|
||||
activeChatType: userPresence.activeChatType,
|
||||
activeChatId: userPresence.activeChatId,
|
||||
activeChatVisible: userPresence.activeChatVisible,
|
||||
activeChatUpdatedAt: userPresence.activeChatUpdatedAt,
|
||||
}).from(userPresence)
|
||||
.where(and(
|
||||
eq(userPresence.userId, userId),
|
||||
eq(userPresence.organizationId, organizationId)
|
||||
));
|
||||
|
||||
if (!presence) return null;
|
||||
return {
|
||||
type: (presence.activeChatType as 'messenger' | 'task') || null,
|
||||
id: presence.activeChatId ?? null,
|
||||
visible: presence.activeChatVisible ?? false,
|
||||
updatedAt: presence.activeChatUpdatedAt ?? null,
|
||||
};
|
||||
}
|
||||
|
||||
// Web Push Subscriptions
|
||||
async registerWebPushSubscription(userId: number, organizationId: number, endpoint: string, subscription: string): Promise<void> {
|
||||
await db.delete(webPushSubscriptions).where(eq(webPushSubscriptions.endpoint, endpoint));
|
||||
|
||||
Reference in New Issue
Block a user