fix(web): reconcile unread mention counters in realtime
All checks were successful
CI / test (push) Successful in 20s
All checks were successful
CI / test (push) Successful in 20s
This commit is contained in:
@@ -102,7 +102,7 @@ export function useRealtime() {
|
|||||||
ws.send(JSON.stringify({ event: "message_read", payload: { chat_id: chatId, message_id: message.id } }));
|
ws.send(JSON.stringify({ event: "message_read", payload: { chat_id: chatId, message_id: message.id } }));
|
||||||
chatStore.clearUnread(chatId);
|
chatStore.clearUnread(chatId);
|
||||||
} else if (wasInserted) {
|
} else if (wasInserted) {
|
||||||
chatStore.incrementUnread(chatId);
|
chatStore.incrementUnread(chatId, hasMentionForUser(message.text, authStore.me?.username ?? null));
|
||||||
}
|
}
|
||||||
maybeShowBrowserNotification(chatId, message, chatStore.activeChatId);
|
maybeShowBrowserNotification(chatId, message, chatStore.activeChatId);
|
||||||
}
|
}
|
||||||
@@ -331,3 +331,21 @@ function maybeShowBrowserNotification(chatId: number, message: Message, activeCh
|
|||||||
};
|
};
|
||||||
})();
|
})();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function hasMentionForUser(text: string | null, username: string | null): boolean {
|
||||||
|
if (!text || !username) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const normalizedUsername = username.toLowerCase();
|
||||||
|
const mentionRegex = /(^|[^A-Za-z0-9_])@([A-Za-z0-9_]{3,50})(?![A-Za-z0-9_])/g;
|
||||||
|
let match: RegExpExecArray | null;
|
||||||
|
while (true) {
|
||||||
|
match = mentionRegex.exec(text);
|
||||||
|
if (!match) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ((match[2] ?? "").toLowerCase() === normalizedUsername) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ interface ChatState {
|
|||||||
removeMessage: (chatId: number, messageId: number) => void;
|
removeMessage: (chatId: number, messageId: number) => void;
|
||||||
restoreMessages: (chatId: number, messages: Message[]) => void;
|
restoreMessages: (chatId: number, messages: Message[]) => void;
|
||||||
clearChatMessages: (chatId: number) => void;
|
clearChatMessages: (chatId: number) => void;
|
||||||
incrementUnread: (chatId: number) => void;
|
incrementUnread: (chatId: number, hasMention?: boolean) => void;
|
||||||
clearUnread: (chatId: number) => void;
|
clearUnread: (chatId: number) => void;
|
||||||
setTypingUsers: (chatId: number, userIds: number[]) => void;
|
setTypingUsers: (chatId: number, userIds: number[]) => void;
|
||||||
setReplyToMessage: (chatId: number, message: Message | null) => void;
|
setReplyToMessage: (chatId: number, message: Message | null) => void;
|
||||||
@@ -123,7 +123,9 @@ export const useChatStore = create<ChatState>((set, get) => ({
|
|||||||
...state.loadingMoreByChat,
|
...state.loadingMoreByChat,
|
||||||
[chatId]: false
|
[chatId]: false
|
||||||
},
|
},
|
||||||
chats: state.chats.map((chat) => (chat.id === chatId ? { ...chat, unread_count: 0 } : chat))
|
chats: state.chats.map((chat) =>
|
||||||
|
chat.id === chatId ? { ...chat, unread_count: 0, unread_mentions_count: 0 } : chat
|
||||||
|
)
|
||||||
}));
|
}));
|
||||||
const lastMessage = sorted[sorted.length - 1];
|
const lastMessage = sorted[sorted.length - 1];
|
||||||
if (lastMessage) {
|
if (lastMessage) {
|
||||||
@@ -315,17 +317,29 @@ export const useChatStore = create<ChatState>((set, get) => ({
|
|||||||
...state.unreadBoundaryByChat,
|
...state.unreadBoundaryByChat,
|
||||||
[chatId]: 0
|
[chatId]: 0
|
||||||
},
|
},
|
||||||
chats: state.chats.map((chat) => (chat.id === chatId ? { ...chat, unread_count: 0 } : chat))
|
chats: state.chats.map((chat) =>
|
||||||
|
chat.id === chatId ? { ...chat, unread_count: 0, unread_mentions_count: 0 } : chat
|
||||||
|
)
|
||||||
})),
|
})),
|
||||||
incrementUnread: (chatId) =>
|
incrementUnread: (chatId, hasMention = false) =>
|
||||||
set((state) => ({
|
set((state) => ({
|
||||||
chats: state.chats.map((chat) =>
|
chats: state.chats.map((chat) =>
|
||||||
chat.id === chatId ? { ...chat, unread_count: (chat.unread_count ?? 0) + 1 } : chat
|
chat.id === chatId
|
||||||
|
? {
|
||||||
|
...chat,
|
||||||
|
unread_count: (chat.unread_count ?? 0) + 1,
|
||||||
|
unread_mentions_count: hasMention
|
||||||
|
? (chat.unread_mentions_count ?? 0) + 1
|
||||||
|
: (chat.unread_mentions_count ?? 0)
|
||||||
|
}
|
||||||
|
: chat
|
||||||
)
|
)
|
||||||
})),
|
})),
|
||||||
clearUnread: (chatId) =>
|
clearUnread: (chatId) =>
|
||||||
set((state) => ({
|
set((state) => ({
|
||||||
chats: state.chats.map((chat) => (chat.id === chatId ? { ...chat, unread_count: 0 } : chat)),
|
chats: state.chats.map((chat) =>
|
||||||
|
chat.id === chatId ? { ...chat, unread_count: 0, unread_mentions_count: 0 } : chat
|
||||||
|
),
|
||||||
unreadBoundaryByChat: {
|
unreadBoundaryByChat: {
|
||||||
...state.unreadBoundaryByChat,
|
...state.unreadBoundaryByChat,
|
||||||
[chatId]: 0
|
[chatId]: 0
|
||||||
|
|||||||
Reference in New Issue
Block a user