diff --git a/.changeset/seven-owls-tell.md b/.changeset/seven-owls-tell.md new file mode 100644 index 000000000000..0c2cda791671 --- /dev/null +++ b/.changeset/seven-owls-tell.md @@ -0,0 +1,5 @@ +--- +"@rocket.chat/meteor": patch +--- + +Fixed an issue that added potencially infinite callbacks to the same event, degrading performance over time. diff --git a/apps/meteor/client/hooks/useNotifyUser.ts b/apps/meteor/client/hooks/useNotifyUser.ts index 818017d93e97..5409963ce153 100644 --- a/apps/meteor/client/hooks/useNotifyUser.ts +++ b/apps/meteor/client/hooks/useNotifyUser.ts @@ -1,6 +1,7 @@ -import type { AtLeast, ISubscription } from '@rocket.chat/core-typings'; +import type { AtLeast, INotificationDesktop, ISubscription } from '@rocket.chat/core-typings'; +import { useEffectEvent } from '@rocket.chat/fuselage-hooks'; import { useRouter, useStream, useUser, useUserPreference } from '@rocket.chat/ui-contexts'; -import { useCallback, useEffect } from 'react'; +import { useEffect } from 'react'; import { useEmbeddedLayout } from './useEmbeddedLayout'; import { CachedChatSubscription } from '../../app/models/client'; @@ -15,79 +16,68 @@ export const useNotifyUser = () => { const notifyUserStream = useStream('notify-user'); const muteFocusedConversations = useUserPreference('muteFocusedConversations'); - const notifyNewRoom = useCallback( - async (sub: AtLeast): Promise => { - if (!user || user.status === 'busy') { - return; - } + const notifyNewRoom = useEffectEvent(async (sub: AtLeast): Promise => { + if (!user || user.status === 'busy') { + return; + } - if ((!router.getRouteParameters().name || router.getRouteParameters().name !== sub.name) && !sub.ls && sub.alert === true) { - KonchatNotification.newRoom(sub.rid); - } - }, - [router, user], - ); + if ((!router.getRouteParameters().name || router.getRouteParameters().name !== sub.name) && !sub.ls && sub.alert === true) { + KonchatNotification.newRoom(sub.rid); + } + }); + + const notifyNewMessageAudioAndDesktop = useEffectEvent((notification: INotificationDesktop) => { + const hasFocus = document.hasFocus(); + + const openedRoomId = ['channel', 'group', 'direct'].includes(router.getRouteName() || '') ? RoomManager.opened : undefined; + + const { rid } = notification.payload; + const messageIsInOpenedRoom = openedRoomId === rid; - const notifyNewMessageAudio = useCallback( - (rid?: string) => { - const hasFocus = document.hasFocus(); - const messageIsInOpenedRoom = RoomManager.opened === rid; + fireGlobalEvent('notification', { + notification, + fromOpenedRoom: messageIsInOpenedRoom, + hasFocus, + }); - if (isLayoutEmbedded) { - if (!hasFocus && messageIsInOpenedRoom) { - // Play a notification sound - void KonchatNotification.newMessage(rid); - } - } else if (!hasFocus || !messageIsInOpenedRoom || !muteFocusedConversations) { + if (isLayoutEmbedded) { + if (!hasFocus && messageIsInOpenedRoom) { // Play a notification sound void KonchatNotification.newMessage(rid); + void KonchatNotification.showDesktop(notification); } - }, - [isLayoutEmbedded, muteFocusedConversations], - ); + } else if (!hasFocus || !messageIsInOpenedRoom || !muteFocusedConversations) { + // Play a notification sound + void KonchatNotification.newMessage(rid); + void KonchatNotification.showDesktop(notification); + } + }); useEffect(() => { if (!user?._id) { return; } - notifyUserStream(`${user?._id}/notification`, (notification) => { - const openedRoomId = ['channel', 'group', 'direct'].includes(router.getRouteName() || '') ? RoomManager.opened : undefined; - - const hasFocus = document.hasFocus(); - const messageIsInOpenedRoom = openedRoomId === notification.payload.rid; + const unsubNotification = notifyUserStream(`${user._id}/notification`, notifyNewMessageAudioAndDesktop); - fireGlobalEvent('notification', { - notification, - fromOpenedRoom: messageIsInOpenedRoom, - hasFocus, - }); - - if (isLayoutEmbedded) { - if (!hasFocus && messageIsInOpenedRoom) { - // Show a notification. - KonchatNotification.showDesktop(notification); - } - } else if (!hasFocus || !messageIsInOpenedRoom) { - // Show a notification. - KonchatNotification.showDesktop(notification); - } - - notifyNewMessageAudio(notification.payload.rid); - }); - - notifyUserStream(`${user?._id}/subscriptions-changed`, (action, sub) => { - if (action === 'removed') { + const unsubSubs = notifyUserStream(`${user._id}/subscriptions-changed`, (action, sub) => { + if (action !== 'inserted') { return; } void notifyNewRoom(sub); }); - CachedChatSubscription.collection.find().observe({ + const handle = CachedChatSubscription.collection.find().observe({ changed: (sub) => { void notifyNewRoom(sub); }, }); - }, [isLayoutEmbedded, notifyNewMessageAudio, notifyNewRoom, notifyUserStream, router, user?._id]); + + return () => { + unsubNotification(); + unsubSubs(); + handle.stop(); + }; + }, [isLayoutEmbedded, notifyNewMessageAudioAndDesktop, notifyNewRoom, notifyUserStream, router, user?._id]); };