diff --git a/docs/realtime.md b/docs/realtime.md index 4256aa6..bd02e8c 100644 --- a/docs/realtime.md +++ b/docs/realtime.md @@ -238,4 +238,6 @@ Validation/runtime error during WS processing: - On `chat_updated`, refresh chat metadata via REST (`GET /api/v1/chats` or `GET /api/v1/chats/{chat_id}`). - On reconnect/visibility restore, reconcile state by reloading already-opened chats/messages via REST to recover missed `message_deleted`/delivery updates after transient disconnects or backend restarts. +- For browser notifications, mentions (`@username`) should be treated as high-priority and can bypass + per-chat-type notification toggles in client preferences. - Use REST message history endpoints for pagination; WS is realtime transport, not history source. diff --git a/web/src/hooks/useRealtime.ts b/web/src/hooks/useRealtime.ts index 74f1aa0..04a3785 100644 --- a/web/src/hooks/useRealtime.ts +++ b/web/src/hooks/useRealtime.ts @@ -104,7 +104,7 @@ export function useRealtime() { } else if (wasInserted) { chatStore.incrementUnread(chatId, hasMentionForUser(message.text, authStore.me?.username ?? null)); } - maybeShowBrowserNotification(chatId, message, chatStore.activeChatId); + maybeShowBrowserNotification(chatId, message, chatStore.activeChatId, authStore.me?.username ?? null); } if (!chatStore.chats.some((chat) => chat.id === chatId)) { scheduleReloadChats(); @@ -307,7 +307,12 @@ export function useRealtime() { return null; } -function maybeShowBrowserNotification(chatId: number, message: Message, activeChatId: number | null): void { +function maybeShowBrowserNotification( + chatId: number, + message: Message, + activeChatId: number | null, + currentUsername: string | null +): void { const prefs = getAppPreferences(); if (!prefs.webNotifications) { return; @@ -319,16 +324,18 @@ function maybeShowBrowserNotification(chatId: number, message: Message, activeCh return; } const chat = useChatStore.getState().chats.find((item) => item.id === chatId); - if (chat?.type === "private" && !prefs.privateNotifications) { + const isMention = hasMentionForUser(message.text, currentUsername); + if (!isMention && chat?.type === "private" && !prefs.privateNotifications) { return; } - if (chat?.type === "group" && !prefs.groupNotifications) { + if (!isMention && chat?.type === "group" && !prefs.groupNotifications) { return; } - if (chat?.type === "channel" && !prefs.channelNotifications) { + if (!isMention && chat?.type === "channel" && !prefs.channelNotifications) { return; } - const title = chat?.display_title || chat?.title || "New message"; + const titleBase = chat?.display_title || chat?.title || "New message"; + const title = isMention ? `@ Mention in ${titleBase}` : titleBase; const preview = buildNotificationPreview(message, prefs.messagePreview); void (async () => {