diff --git a/webapp/channels/src/components/announcement_bar/notification_permission_bar/index.tsx b/webapp/channels/src/components/announcement_bar/notification_permission_bar/index.tsx index a94c4fd4d2..17304e6f0b 100644 --- a/webapp/channels/src/components/announcement_bar/notification_permission_bar/index.tsx +++ b/webapp/channels/src/components/announcement_bar/notification_permission_bar/index.tsx @@ -8,6 +8,7 @@ import {getCurrentUserId} from 'mattermost-redux/selectors/entities/users'; import NotificationPermissionNeverGrantedBar from 'components/announcement_bar/notification_permission_bar/notification_permission_never_granted_bar'; import NotificationPermissionUnsupportedBar from 'components/announcement_bar/notification_permission_bar/notification_permission_unsupported_bar'; +import {useDesktopAppNotificationPermission} from 'components/common/hooks/use_desktop_notification_permission'; import { isNotificationAPISupported, @@ -19,6 +20,8 @@ import { export default function NotificationPermissionBar() { const isLoggedIn = Boolean(useSelector(getCurrentUserId)); + useDesktopAppNotificationPermission(); + if (!isLoggedIn) { return null; } diff --git a/webapp/channels/src/components/common/hooks/use_desktop_notification_permission.ts b/webapp/channels/src/components/common/hooks/use_desktop_notification_permission.ts new file mode 100644 index 0000000000..68c707079b --- /dev/null +++ b/webapp/channels/src/components/common/hooks/use_desktop_notification_permission.ts @@ -0,0 +1,52 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +import {useCallback, useEffect, useState} from 'react'; + +import type {NotificationPermissionNeverGranted} from 'utils/notifications'; +import {isNotificationAPISupported} from 'utils/notifications'; +import {isDesktopApp} from 'utils/user_agent'; + +export type DesktopNotificationPermission = Exclude | undefined; + +// We store the permission state globally here to avoid calling requestPermission() multiple times +let desktopNotificationPermissionGlobalState: DesktopNotificationPermission | undefined; + +// This is used to request notification permission for desktop app +// it also returns the permission state. We use this as a workaround for bug with Electron - https://github.com/electron/electron/issues/11221 +// tl;dr Electron always show 'granted' when queries for Notification.permission, hence this workaround +export function useDesktopAppNotificationPermission(): [DesktopNotificationPermission, () => Promise] { + const [desktopNotificationPermission, setDesktopNotificationPermission] = useState(undefined); + + const isDesktop = isDesktopApp(); + const isSupported = isNotificationAPISupported(); + + const requestDesktopNotificationPermission = useCallback(async () => { + // Based on Electron's notification permission it will have following states + // - allowed - No further action needed + // - denied permanently - No further action needed + // - denied (temporary) - In this case, electron notification permission dialog is shown with requestPermission() + const permission = await Notification.requestPermission(); + + // Update the global state + desktopNotificationPermissionGlobalState = permission as DesktopNotificationPermission; + + // Update the local state + setDesktopNotificationPermission(permission as DesktopNotificationPermission); + + return permission; + }, []); + + useEffect(() => { + if (!isDesktop || !isSupported) { + setDesktopNotificationPermission(undefined); + } else if (desktopNotificationPermissionGlobalState === undefined) { + // We are in initial state, we need to request permission now + requestDesktopNotificationPermission(); + } else if (desktopNotificationPermissionGlobalState !== undefined) { + setDesktopNotificationPermission(desktopNotificationPermissionGlobalState); + } + }, [isDesktop, isSupported, requestDesktopNotificationPermission]); + + return [desktopNotificationPermission, requestDesktopNotificationPermission]; +} diff --git a/webapp/channels/src/components/section_notice/section_notice_button.tsx b/webapp/channels/src/components/section_notice/section_notice_button.tsx index c68a0c77fc..56f8a9286c 100644 --- a/webapp/channels/src/components/section_notice/section_notice_button.tsx +++ b/webapp/channels/src/components/section_notice/section_notice_button.tsx @@ -21,6 +21,7 @@ const SectionNoticeButton = ({