From 18b06b5bd791cee5b9c939ebab6ffdd73bfeee19 Mon Sep 17 00:00:00 2001 From: Ajay Bura <32841439+ajbura@users.noreply.github.com> Date: Fri, 21 Feb 2025 08:40:50 +0530 Subject: [PATCH 1/3] refactor system notification to dedicated file --- .../settings/notifications/Notifications.tsx | 74 +------------------ .../notifications/SystemNotification.tsx | 73 ++++++++++++++++++ 2 files changed, 75 insertions(+), 72 deletions(-) create mode 100644 src/app/features/settings/notifications/SystemNotification.tsx diff --git a/src/app/features/settings/notifications/Notifications.tsx b/src/app/features/settings/notifications/Notifications.tsx index 88e16d296..aa339a031 100644 --- a/src/app/features/settings/notifications/Notifications.tsx +++ b/src/app/features/settings/notifications/Notifications.tsx @@ -1,82 +1,12 @@ import React from 'react'; -import { Box, Text, IconButton, Icon, Icons, Scroll, Switch, Button, color } from 'folds'; +import { Box, Text, IconButton, Icon, Icons, Scroll } from 'folds'; import { Page, PageContent, PageHeader } from '../../../components/page'; -import { SequenceCard } from '../../../components/sequence-card'; -import { SequenceCardStyle } from '../styles.css'; -import { SettingTile } from '../../../components/setting-tile'; -import { useSetting } from '../../../state/hooks/settings'; -import { settingsAtom } from '../../../state/settings'; -import { getNotificationState, usePermissionState } from '../../../hooks/usePermission'; +import { SystemNotification } from './SystemNotification'; import { AllMessagesNotifications } from './AllMessages'; import { SpecialMessagesNotifications } from './SpecialMessages'; import { KeywordMessagesNotifications } from './KeywordMessages'; import { IgnoredUserList } from './IgnoredUserList'; -function SystemNotification() { - const notifPermission = usePermissionState('notifications', getNotificationState()); - const [showNotifications, setShowNotifications] = useSetting(settingsAtom, 'showNotifications'); - const [isNotificationSounds, setIsNotificationSounds] = useSetting( - settingsAtom, - 'isNotificationSounds' - ); - - const requestNotificationPermission = () => { - window.Notification.requestPermission(); - }; - - return ( - - System - - - {'Notification' in window - ? 'Notification permission is blocked. Please allow notification permission from browser address bar.' - : 'Notifications are not supported by the system.'} - - ) : ( - Show desktop notifications when message arrive. - ) - } - after={ - notifPermission === 'prompt' ? ( - - ) : ( - - ) - } - /> - - - } - /> - - - ); -} - type NotificationsProps = { requestClose: () => void; }; diff --git a/src/app/features/settings/notifications/SystemNotification.tsx b/src/app/features/settings/notifications/SystemNotification.tsx new file mode 100644 index 000000000..e112765e9 --- /dev/null +++ b/src/app/features/settings/notifications/SystemNotification.tsx @@ -0,0 +1,73 @@ +import React from 'react'; +import { Box, Text, Switch, Button, color } from 'folds'; +import { SequenceCard } from '../../../components/sequence-card'; +import { SequenceCardStyle } from '../styles.css'; +import { SettingTile } from '../../../components/setting-tile'; +import { useSetting } from '../../../state/hooks/settings'; +import { settingsAtom } from '../../../state/settings'; +import { getNotificationState, usePermissionState } from '../../../hooks/usePermission'; + +export function SystemNotification() { + const notifPermission = usePermissionState('notifications', getNotificationState()); + const [showNotifications, setShowNotifications] = useSetting(settingsAtom, 'showNotifications'); + const [isNotificationSounds, setIsNotificationSounds] = useSetting( + settingsAtom, + 'isNotificationSounds' + ); + + const requestNotificationPermission = () => { + window.Notification.requestPermission(); + }; + + return ( + + System + + + {'Notification' in window + ? 'Notification permission is blocked. Please allow notification permission from browser address bar.' + : 'Notifications are not supported by the system.'} + + ) : ( + Show desktop notifications when message arrive. + ) + } + after={ + notifPermission === 'prompt' ? ( + + ) : ( + + ) + } + /> + + + } + /> + + + ); +} From 071ad585edc53f553a21adc6f6caf1247dd9b130 Mon Sep 17 00:00:00 2001 From: Ajay Bura <32841439+ajbura@users.noreply.github.com> Date: Fri, 21 Feb 2025 09:48:22 +0530 Subject: [PATCH 2/3] add hook for email notification status --- src/app/hooks/useEmailNotifications.ts | 55 ++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 src/app/hooks/useEmailNotifications.ts diff --git a/src/app/hooks/useEmailNotifications.ts b/src/app/hooks/useEmailNotifications.ts new file mode 100644 index 000000000..58639394b --- /dev/null +++ b/src/app/hooks/useEmailNotifications.ts @@ -0,0 +1,55 @@ +import { useCallback } from 'react'; +import { AsyncStatus, useAsyncCallbackValue } from './useAsyncCallback'; +import { useMatrixClient } from './useMatrixClient'; + +type RefreshHandler = () => void; + +type EmailNotificationResult = { + enabled: boolean; + email?: string; +}; + +export const useEmailNotifications = (): [ + EmailNotificationResult | undefined | null, + RefreshHandler +] => { + const mx = useMatrixClient(); + + const [emailState, refresh] = useAsyncCallbackValue( + useCallback(async () => { + const tpIDs = (await mx.getThreePids())?.threepids; + const emailAddresses = tpIDs.filter((id) => id.medium === 'email').map((id) => id.address); + if (emailAddresses.length === 0) + return { + enabled: false, + }; + + const pushers = (await mx.getPushers())?.pushers; + const emailPusher = pushers.find( + (pusher) => pusher.app_id === 'm.email' && emailAddresses.includes(pusher.pushkey) + ); + + if (emailPusher?.pushkey) { + return { + enabled: true, + email: emailPusher.pushkey, + }; + } + + return { + enabled: false, + email: emailAddresses[0], + }; + }, [mx]) + ); + + if (emailState.status === AsyncStatus.Success) { + return [emailState.data, refresh]; + } + + if (emailState.status === AsyncStatus.Error) { + return [null, refresh]; + } + + return [undefined, refresh]; +}; From 0001d10a200472206355cd85c2524f3cd2d3af01 Mon Sep 17 00:00:00 2001 From: Ajay Bura <32841439+ajbura@users.noreply.github.com> Date: Fri, 21 Feb 2025 09:48:44 +0530 Subject: [PATCH 3/3] add toogle for email notifications in settings --- .../notifications/SystemNotification.tsx | 89 ++++++++++++++++++- 1 file changed, 87 insertions(+), 2 deletions(-) diff --git a/src/app/features/settings/notifications/SystemNotification.tsx b/src/app/features/settings/notifications/SystemNotification.tsx index e112765e9..e0df06df9 100644 --- a/src/app/features/settings/notifications/SystemNotification.tsx +++ b/src/app/features/settings/notifications/SystemNotification.tsx @@ -1,11 +1,88 @@ -import React from 'react'; -import { Box, Text, Switch, Button, color } from 'folds'; +import React, { useCallback } from 'react'; +import { Box, Text, Switch, Button, color, Spinner } from 'folds'; +import { IPusherRequest } from 'matrix-js-sdk'; import { SequenceCard } from '../../../components/sequence-card'; import { SequenceCardStyle } from '../styles.css'; import { SettingTile } from '../../../components/setting-tile'; import { useSetting } from '../../../state/hooks/settings'; import { settingsAtom } from '../../../state/settings'; import { getNotificationState, usePermissionState } from '../../../hooks/usePermission'; +import { useEmailNotifications } from '../../../hooks/useEmailNotifications'; +import { AsyncStatus, useAsyncCallback } from '../../../hooks/useAsyncCallback'; +import { useMatrixClient } from '../../../hooks/useMatrixClient'; + +function EmailNotification() { + const mx = useMatrixClient(); + const [result, refreshResult] = useEmailNotifications(); + + const [setState, setEnable] = useAsyncCallback( + useCallback( + async (email: string, enable: boolean) => { + if (enable) { + await mx.setPusher({ + kind: 'email', + app_id: 'm.email', + pushkey: email, + app_display_name: 'Email Notifications', + device_display_name: email, + lang: 'en', + data: { + brand: 'Cinny', + }, + append: true, + }); + return; + } + await mx.setPusher({ + pushkey: email, + app_id: 'm.email', + kind: null, + } as unknown as IPusherRequest); + }, + [mx] + ) + ); + + const handleChange = (value: boolean) => { + if (result && result.email) { + setEnable(result.email, value).then(() => { + refreshResult(); + }); + } + }; + + return ( + + {result && !result.email && ( + + Your account does not have any email attached. + + )} + {result && result.email && <>Send notification to your email. {`("${result.email}")`}} + {result === null && ( + + Unexpected Error! + + )} + {result === undefined && 'Send notification to your email.'} + + } + after={ + <> + {setState.status !== AsyncStatus.Loading && + typeof result === 'object' && + result?.email && } + {(setState.status === AsyncStatus.Loading || result === undefined) && ( + + )} + + } + /> + ); +} export function SystemNotification() { const notifPermission = usePermissionState('notifications', getNotificationState()); @@ -68,6 +145,14 @@ export function SystemNotification() { after={} /> + + + ); }