diff --git a/apps/meteor/app/ui/client/lib/KonchatNotification.ts b/apps/meteor/app/ui/client/lib/KonchatNotification.ts index cebd0aa4324f1..3713395084cad 100644 --- a/apps/meteor/app/ui/client/lib/KonchatNotification.ts +++ b/apps/meteor/app/ui/client/lib/KonchatNotification.ts @@ -1,15 +1,5 @@ -import type { INotificationDesktop } from '@rocket.chat/core-typings'; -import { Random } from '@rocket.chat/random'; -import { Meteor } from 'meteor/meteor'; import { ReactiveVar } from 'meteor/reactive-var'; -import { onClientMessageReceived } from '../../../../client/lib/onClientMessageReceived'; -import { router } from '../../../../client/providers/RouterProvider'; -import { stripTags } from '../../../../lib/utils/stringUtils'; -import { getUserPreference } from '../../../utils/client'; -import { getUserAvatarURL } from '../../../utils/client/getUserAvatarURL'; -import { sdk } from '../../../utils/client/lib/SDKClient'; - declare global { // eslint-disable-next-line @typescript-eslint/naming-convention interface NotificationEventMap { @@ -27,113 +17,6 @@ class KonchatNotification { }); } } - - public async notify(notification: INotificationDesktop) { - if (typeof window.Notification === 'undefined' || Notification.permission !== 'granted') { - return; - } - - if (!notification.payload) { - return; - } - - const { rid } = notification.payload; - - if (!rid) { - return; - } - const message = await onClientMessageReceived({ - rid, - msg: notification.text, - notification: true, - } as any); - - const requireInteraction = getUserPreference(Meteor.userId(), 'desktopNotificationRequireInteraction'); - const n = new Notification(notification.title, { - icon: notification.icon || getUserAvatarURL(notification.payload.sender?.username as string), - body: stripTags(message.msg), - tag: notification.payload._id, - canReply: true, - silent: true, - requireInteraction, - } as NotificationOptions & { - canReply?: boolean; // TODO is this still needed for the desktop app? - }); - - const notificationDuration = !requireInteraction ? (notification.duration ?? 0) - 0 || 10 : -1; - if (notificationDuration > 0) { - setTimeout(() => n.close(), notificationDuration * 1000); - } - - if (n.addEventListener) { - n.addEventListener( - 'reply', - ({ response }) => - void sdk.call('sendMessage', { - _id: Random.id(), - rid, - msg: response, - }), - ); - } - - n.onclick = function () { - this.close(); - window.focus(); - - if (!notification.payload._id || !notification.payload.rid || !notification.payload.name) { - return; - } - - switch (notification.payload?.type) { - case 'd': - return router.navigate({ - pattern: '/direct/:rid/:tab?/:context?', - params: { - rid: notification.payload.rid, - ...(notification.payload.tmid && { - tab: 'thread', - context: notification.payload.tmid, - }), - }, - search: { ...router.getSearchParameters(), jump: notification.payload._id }, - }); - case 'c': - return router.navigate({ - pattern: '/channel/:name/:tab?/:context?', - params: { - name: notification.payload.name, - ...(notification.payload.tmid && { - tab: 'thread', - context: notification.payload.tmid, - }), - }, - search: { ...router.getSearchParameters(), jump: notification.payload._id }, - }); - case 'p': - return router.navigate({ - pattern: '/group/:name/:tab?/:context?', - params: { - name: notification.payload.name, - ...(notification.payload.tmid && { - tab: 'thread', - context: notification.payload.tmid, - }), - }, - search: { ...router.getSearchParameters(), jump: notification.payload._id }, - }); - case 'l': - return router.navigate({ - pattern: '/live/:id/:tab?/:context?', - params: { - id: notification.payload.rid, - tab: 'room-info', - }, - search: { ...router.getSearchParameters(), jump: notification.payload._id }, - }); - } - }; - } } const instance = new KonchatNotification(); diff --git a/apps/meteor/client/hooks/notification/useDesktopNotification.ts b/apps/meteor/client/hooks/notification/useDesktopNotification.ts index cd38506a62fda..a0b72dbf726b2 100644 --- a/apps/meteor/client/hooks/notification/useDesktopNotification.ts +++ b/apps/meteor/client/hooks/notification/useDesktopNotification.ts @@ -2,13 +2,15 @@ import type { INotificationDesktop } from '@rocket.chat/core-typings'; import { useUser } from '@rocket.chat/ui-contexts'; import { useCallback } from 'react'; +import { useNotification } from './useNotification'; import { e2e } from '../../../app/e2e/client'; -import { KonchatNotification } from '../../../app/ui/client/lib/KonchatNotification'; import { RoomManager } from '../../lib/RoomManager'; import { getAvatarAsPng } from '../../lib/utils/getAvatarAsPng'; export const useDesktopNotification = () => { const user = useUser(); + const notify = useNotification(); + const notifyDesktop = useCallback( async (notification: INotificationDesktop) => { if ( @@ -30,10 +32,10 @@ export const useDesktopNotification = () => { return getAvatarAsPng(notification.payload.sender?.username, (avatarAsPng) => { notification.icon = avatarAsPng; - return KonchatNotification.notify(notification); + return notify(notification); }); }, - [user?.status], + [notify, user?.status], ); return notifyDesktop; diff --git a/apps/meteor/client/hooks/notification/useNotification.ts b/apps/meteor/client/hooks/notification/useNotification.ts new file mode 100644 index 0000000000000..96fe22ffdd6b6 --- /dev/null +++ b/apps/meteor/client/hooks/notification/useNotification.ts @@ -0,0 +1,122 @@ +import type { INotificationDesktop } from '@rocket.chat/core-typings'; +import { Random } from '@rocket.chat/random'; +import { useRouter, useUserPreference } from '@rocket.chat/ui-contexts'; +import { useCallback } from 'react'; + +import { getUserAvatarURL } from '../../../app/utils/client'; +import { sdk } from '../../../app/utils/client/lib/SDKClient'; +import { stripTags } from '../../../lib/utils/stringUtils'; +import { onClientMessageReceived } from '../../lib/onClientMessageReceived'; + +export const useNotification = () => { + const requireInteraction = useUserPreference('desktopNotificationRequireInteraction'); + const router = useRouter(); + + const notify = useCallback( + async (notification: INotificationDesktop) => { + if (typeof window.Notification === 'undefined' || Notification.permission !== 'granted') { + return; + } + if (!notification.payload) { + return; + } + + const { rid } = notification.payload; + if (!rid) { + return; + } + const message = await onClientMessageReceived({ + rid, + msg: notification.text, + notification: true, + } as any); + + const n = new Notification(notification.title, { + icon: notification.icon || getUserAvatarURL(notification.payload.sender?.username as string), + body: stripTags(message?.msg), + tag: notification.payload._id, + canReply: true, + silent: true, + requireInteraction, + } as NotificationOptions & { + canReply?: boolean; + }); + const notificationDuration = !requireInteraction ? (notification.duration ?? 0) - 0 || 10 : -1; + if (notificationDuration > 0) { + setTimeout(() => n.close(), notificationDuration * 1000); + } + + if (n.addEventListener) { + n.addEventListener( + 'reply', + ({ response }) => + void sdk.call('sendMessage', { + _id: Random.id(), + rid, + msg: response, + }), + ); + } + + n.onclick = () => { + n.close(); + window.focus(); + + if (!notification.payload._id || !notification.payload.rid || !notification.payload.name) { + return; + } + + switch (notification.payload?.type) { + case 'd': + router.navigate({ + pattern: '/direct/:rid/:tab?/:context?', + params: { + rid: notification.payload.rid, + ...(notification.payload.tmid && { + tab: 'thread', + context: notification.payload.tmid, + }), + }, + search: { ...router.getSearchParameters(), jump: notification.payload._id }, + }); + break; + case 'c': + return router.navigate({ + pattern: '/channel/:name/:tab?/:context?', + params: { + name: notification.payload.name, + ...(notification.payload.tmid && { + tab: 'thread', + context: notification.payload.tmid, + }), + }, + search: { ...router.getSearchParameters(), jump: notification.payload._id }, + }); + case 'p': + return router.navigate({ + pattern: '/group/:name/:tab?/:context?', + params: { + name: notification.payload.name, + ...(notification.payload.tmid && { + tab: 'thread', + context: notification.payload.tmid, + }), + }, + search: { ...router.getSearchParameters(), jump: notification.payload._id }, + }); + case 'l': + return router.navigate({ + pattern: '/live/:id/:tab?/:context?', + params: { + id: notification.payload.rid, + tab: 'room-info', + }, + search: { ...router.getSearchParameters(), jump: notification.payload._id }, + }); + } + }; + }, + [requireInteraction, router], + ); + return notify; +}; diff --git a/apps/meteor/client/views/account/preferences/PreferencesNotificationsSection.tsx b/apps/meteor/client/views/account/preferences/PreferencesNotificationsSection.tsx index 0f081a83532f6..f95696afb7d41 100644 --- a/apps/meteor/client/views/account/preferences/PreferencesNotificationsSection.tsx +++ b/apps/meteor/client/views/account/preferences/PreferencesNotificationsSection.tsx @@ -7,7 +7,7 @@ import { useId, useCallback, useEffect, useState, useMemo } from 'react'; import { Controller, useFormContext } from 'react-hook-form'; import { useTranslation } from 'react-i18next'; -import { KonchatNotification } from '../../../../app/ui/client/lib/KonchatNotification'; +import { useNotification } from '../../../hooks/notification/useNotification'; const notificationOptionsLabelMap = { all: 'All_messages', @@ -39,18 +39,19 @@ const PreferencesNotificationsSection = () => { const showNewLoginEmailPreference = loginEmailEnabled && allowLoginEmailPreference; const showCalendarPreference = useSetting('Outlook_Calendar_Enabled'); const showMobileRinging = useSetting('VideoConf_Mobile_Ringing'); + const notify = useNotification(); const userEmailNotificationMode = useUserPreference('emailNotificationMode') as keyof typeof emailNotificationOptionsLabelMap; useEffect(() => setNotificationsPermission(window.Notification && Notification.permission), []); const onSendNotification = useCallback(() => { - KonchatNotification.notify({ + notify({ payload: { sender: { _id: 'rocket.cat', username: 'rocket.cat' }, rid: 'GENERAL' } as INotificationDesktop['payload'], title: t('Desktop_Notification_Test'), text: t('This_is_a_desktop_notification'), }); - }, [t]); + }, [notify, t]); const onAskNotificationPermission = useCallback(() => { window.Notification && Notification.requestPermission().then((val) => setNotificationsPermission(val));