From dcff0fcbee4fdf568877f36b02c3c2c91b2bfe01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BAlia=20Jaeger=20Foresti?= <60678893+juliajforesti@users.noreply.github.com> Date: Wed, 26 Mar 2025 12:11:16 -0300 Subject: [PATCH] refactor: remove deprecated `KonchatNotification` (#35589) --- .../app/ui/client/lib/KonchatNotification.ts | 25 +------------------ apps/meteor/client/definitions/global.d.ts | 4 +++ .../hooks/notification/useNotification.ts | 6 +++-- .../notification/useNotificationAllowed.ts | 19 ++++++++++++++ .../notification/useNotificationPermission.ts | 21 ++++++++++++++++ apps/meteor/client/lib/notificationManager.ts | 6 +++++ .../PreferencesNotificationsSection.tsx | 1 - apps/meteor/client/views/home/HomePage.tsx | 6 ----- apps/meteor/client/views/root/AppLayout.tsx | 2 ++ 9 files changed, 57 insertions(+), 33 deletions(-) create mode 100644 apps/meteor/client/hooks/notification/useNotificationAllowed.ts create mode 100644 apps/meteor/client/hooks/notification/useNotificationPermission.ts create mode 100644 apps/meteor/client/lib/notificationManager.ts diff --git a/apps/meteor/app/ui/client/lib/KonchatNotification.ts b/apps/meteor/app/ui/client/lib/KonchatNotification.ts index 3713395084c..9d6f3dc6c9c 100644 --- a/apps/meteor/app/ui/client/lib/KonchatNotification.ts +++ b/apps/meteor/app/ui/client/lib/KonchatNotification.ts @@ -1,24 +1 @@ -import { ReactiveVar } from 'meteor/reactive-var'; - -declare global { - // eslint-disable-next-line @typescript-eslint/naming-convention - interface NotificationEventMap { - reply: { response: string }; - } -} - -class KonchatNotification { - public notificationStatus = new ReactiveVar(undefined); - - public getDesktopPermission() { - if (window.Notification && Notification.permission !== 'granted') { - return Notification.requestPermission((status) => { - this.notificationStatus.set(status); - }); - } - } -} - -const instance = new KonchatNotification(); - -export { instance as KonchatNotification }; +// KonchatNotification in memoriam diff --git a/apps/meteor/client/definitions/global.d.ts b/apps/meteor/client/definitions/global.d.ts index 0916ef23711..58e383ee58d 100644 --- a/apps/meteor/client/definitions/global.d.ts +++ b/apps/meteor/client/definitions/global.d.ts @@ -80,4 +80,8 @@ declare global { maxHeight: number; }; } + + interface NotificationEventMap { + reply: { response: string }; + } } diff --git a/apps/meteor/client/hooks/notification/useNotification.ts b/apps/meteor/client/hooks/notification/useNotification.ts index 96fe22ffdd6..ce20f90c8c3 100644 --- a/apps/meteor/client/hooks/notification/useNotification.ts +++ b/apps/meteor/client/hooks/notification/useNotification.ts @@ -3,6 +3,7 @@ import { Random } from '@rocket.chat/random'; import { useRouter, useUserPreference } from '@rocket.chat/ui-contexts'; import { useCallback } from 'react'; +import { useNotificationAllowed } from './useNotificationAllowed'; import { getUserAvatarURL } from '../../../app/utils/client'; import { sdk } from '../../../app/utils/client/lib/SDKClient'; import { stripTags } from '../../../lib/utils/stringUtils'; @@ -11,10 +12,11 @@ import { onClientMessageReceived } from '../../lib/onClientMessageReceived'; export const useNotification = () => { const requireInteraction = useUserPreference('desktopNotificationRequireInteraction'); const router = useRouter(); + const notificationAllowed = useNotificationAllowed(); const notify = useCallback( async (notification: INotificationDesktop) => { - if (typeof window.Notification === 'undefined' || Notification.permission !== 'granted') { + if (!notificationAllowed) { return; } if (!notification.payload) { @@ -116,7 +118,7 @@ export const useNotification = () => { } }; }, - [requireInteraction, router], + [notificationAllowed, requireInteraction, router], ); return notify; }; diff --git a/apps/meteor/client/hooks/notification/useNotificationAllowed.ts b/apps/meteor/client/hooks/notification/useNotificationAllowed.ts new file mode 100644 index 00000000000..31f17b0cb0e --- /dev/null +++ b/apps/meteor/client/hooks/notification/useNotificationAllowed.ts @@ -0,0 +1,19 @@ +import { useCallback, useSyncExternalStore } from 'react'; + +import { notificationManager } from '../../lib/notificationManager'; + +export const useNotificationAllowed = (): boolean => { + const allowed = useSyncExternalStore( + useCallback( + (callback): (() => void) => + notificationManager.on('change', () => { + notificationManager.allowed = Notification.permission === 'granted'; + callback(); + }), + [], + ), + (): boolean => notificationManager.allowed, + ); + + return allowed; +}; diff --git a/apps/meteor/client/hooks/notification/useNotificationPermission.ts b/apps/meteor/client/hooks/notification/useNotificationPermission.ts new file mode 100644 index 00000000000..4f021b7c156 --- /dev/null +++ b/apps/meteor/client/hooks/notification/useNotificationPermission.ts @@ -0,0 +1,21 @@ +import { useCallback } from 'react'; + +import { notificationManager } from '../../lib/notificationManager'; + +export const useNotificationPermission = () => { + const requestPermission = useCallback(async () => { + const response = await Notification.requestPermission(); + notificationManager.allowed = response === 'granted'; + notificationManager.emit('change'); + + const notifications = await navigator.permissions.query({ name: 'notifications' }); + notifications.onchange = () => { + notificationManager.allowed = notifications.state === 'granted'; + notificationManager.emit('change'); + }; + }, []); + + if ('Notification' in window) { + requestPermission(); + } +}; diff --git a/apps/meteor/client/lib/notificationManager.ts b/apps/meteor/client/lib/notificationManager.ts new file mode 100644 index 00000000000..4ee07ed7cea --- /dev/null +++ b/apps/meteor/client/lib/notificationManager.ts @@ -0,0 +1,6 @@ +import { Emitter } from '@rocket.chat/emitter'; + +class NotificationPermissionEmitter extends Emitter { + allowed: boolean; +} +export const notificationManager = new NotificationPermissionEmitter(); diff --git a/apps/meteor/client/views/account/preferences/PreferencesNotificationsSection.tsx b/apps/meteor/client/views/account/preferences/PreferencesNotificationsSection.tsx index f95696afb7d..8d159a81e7a 100644 --- a/apps/meteor/client/views/account/preferences/PreferencesNotificationsSection.tsx +++ b/apps/meteor/client/views/account/preferences/PreferencesNotificationsSection.tsx @@ -20,7 +20,6 @@ const emailNotificationOptionsLabelMap = { nothing: 'Email_Notification_Mode_Disabled', }; -// TODO: Test Notification Button not working const PreferencesNotificationsSection = () => { const { t, i18n } = useTranslation(); diff --git a/apps/meteor/client/views/home/HomePage.tsx b/apps/meteor/client/views/home/HomePage.tsx index a8a0544e3d8..1cc4654eeea 100644 --- a/apps/meteor/client/views/home/HomePage.tsx +++ b/apps/meteor/client/views/home/HomePage.tsx @@ -1,16 +1,10 @@ import { useSetting } from '@rocket.chat/ui-contexts'; import type { ReactElement } from 'react'; -import { useEffect } from 'react'; import CustomHomePage from './CustomHomePage'; import DefaultHomePage from './DefaultHomePage'; -import { KonchatNotification } from '../../../app/ui/client/lib/KonchatNotification'; const HomePage = (): ReactElement => { - useEffect(() => { - KonchatNotification.getDesktopPermission(); - }, []); - const customOnly = useSetting('Layout_Custom_Body_Only'); if (customOnly) { diff --git a/apps/meteor/client/views/root/AppLayout.tsx b/apps/meteor/client/views/root/AppLayout.tsx index 656255baa49..fe96a496960 100644 --- a/apps/meteor/client/views/root/AppLayout.tsx +++ b/apps/meteor/client/views/root/AppLayout.tsx @@ -19,6 +19,7 @@ import { useGitLabAuth } from '../../../app/gitlab/client/hooks/useGitLabAuth'; import { useLivechatEnterprise } from '../../../app/livechat-enterprise/hooks/useLivechatEnterprise'; import { useNextcloud } from '../../../app/nextcloud/client/useNextcloud'; import { useTokenPassAuth } from '../../../app/tokenpass/client/hooks/useTokenPassAuth'; +import { useNotificationPermission } from '../../hooks/notification/useNotificationPermission'; import { useNotifyUser } from '../../hooks/notification/useNotifyUser'; import { useAnalyticsEventTracking } from '../../hooks/useAnalyticsEventTracking'; import { useAutoupdate } from '../../hooks/useAutoupdate'; @@ -43,6 +44,7 @@ const AppLayout = () => { useAnalyticsEventTracking(); useLoadRoomForAllowedAnonymousRead(); useNotifyUser(); + useNotificationPermission(); useEmojiOne(); useRedirectToSetupWizard(); useSettingsOnLoadSiteUrl();