From 1963f1a2c26a67fdcc2ce4747f1753337d4e58a8 Mon Sep 17 00:00:00 2001 From: AndiAkasha Date: Thu, 23 Jan 2025 16:34:19 +0100 Subject: [PATCH] Fix: Initializing in readonly if the user has not subscribed to notifications & on Logout remove the listeners (#2528) --- .../rounded-notification-button.tsx | 7 +- libs/hooks/src/use-notifications.ts | 21 +++--- libs/sdk/src/auth/index.ts | 5 ++ .../src/common/notification/notification.ts | 71 +++++++++++-------- 4 files changed, 62 insertions(+), 42 deletions(-) diff --git a/extensions/apps/notifications/src/extensions/rounded-notification-button.tsx b/extensions/apps/notifications/src/extensions/rounded-notification-button.tsx index 10f6e0d0f4..9e4b5483f3 100644 --- a/extensions/apps/notifications/src/extensions/rounded-notification-button.tsx +++ b/extensions/apps/notifications/src/extensions/rounded-notification-button.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { useRootComponentProps, withProviders } from '@akashaorg/ui-core-hooks'; +import { useNotifications, useRootComponentProps, withProviders } from '@akashaorg/ui-core-hooks'; import { BellAlert } from '@akashaorg/design-system-core/lib/components/Icon/akasha-icons'; import { NotificationEvents, type UIEventData } from '@akashaorg/typings/lib/ui'; @@ -19,6 +19,7 @@ const RoundedNotificationButton = () => { const uiEventsRef = React.useRef(uiEvents); const [snoozeNotifications, setSnoozeNotifications] = React.useState(false); const [hasNewNotifications, setHasNewNotifications] = React.useState(false); + const { previouslyEnabled } = useNotifications(); // check if snooze notification option has already been set React.useEffect(() => { if (window.localStorage) { @@ -80,7 +81,9 @@ const RoundedNotificationButton = () => { await sdk.services.common.notification.listenToNotificationEvents(); }; - init(); + if (previouslyEnabled) { + init(); + } return () => { if (subSDK) { diff --git a/libs/hooks/src/use-notifications.ts b/libs/hooks/src/use-notifications.ts index 7872ab2dc2..148c924626 100644 --- a/libs/hooks/src/use-notifications.ts +++ b/libs/hooks/src/use-notifications.ts @@ -22,16 +22,19 @@ export function useNotifications() { const [readOnlyMode, setReadOnlyMode] = useState(false); const [waitingForSignature, setWaitingForSignature] = useState(false); - // Initialise notificaitons readOnly client (without signature) + // Initialise notifications readOnly client (without signature) useEffect(() => { - sdk.services.common.notification - .initialize({ readonly: true }) - .then(() => { - setReadOnlyMode(true); - }) - .catch(error => { - console.error(error); - }); + // if the user has already enabled notifications before + if (previouslyEnabled) { + sdk.services.common.notification + .initialize({ readonly: true }) + .then(() => { + setReadOnlyMode(true); + }) + .catch(error => { + console.error(error); + }); + } }, []); const enableNotifications = async () => { diff --git a/libs/sdk/src/auth/index.ts b/libs/sdk/src/auth/index.ts index 87341dce74..3c90e45590 100644 --- a/libs/sdk/src/auth/index.ts +++ b/libs/sdk/src/auth/index.ts @@ -31,6 +31,7 @@ import { DIDSession } from 'did-session'; import type { DagJWS } from 'dids'; import type { JWE } from 'did-jwt'; import { Eip1193Provider } from 'ethers'; +import NotificationService from '../common/notification/notification'; // in memory atm const devKeys: { pubKey: string; addedAt: string; name?: string }[] = []; @@ -52,6 +53,7 @@ class AWF_Auth { private _gql: Gql; private _lit: Lit; private _ceramic: CeramicService; + private _notificationService: NotificationService; private sessKey; private currentUser?: CurrentUser; private _lockSignIn?: boolean; @@ -71,6 +73,7 @@ class AWF_Auth { @inject(TYPES.Gql) gql: Gql, @inject(TYPES.Lit) lit: Lit, @inject(TYPES.Ceramic) ceramic: CeramicService, + @inject(TYPES.Notification) notificationService: NotificationService, ) { this._db = db; this._web3 = web3; @@ -80,6 +83,7 @@ class AWF_Auth { this._gql = gql; this._lit = lit; this._ceramic = ceramic; + this._notificationService = notificationService; } /** @@ -321,6 +325,7 @@ class AWF_Auth { await this._ceramic.disconnect(); await this._gql.setContextViewerID(''); await this._web3.disconnect(); + await this._notificationService.disconnect(); await this._lit.disconnect(); await this._gql.resetCache(); // notify appLoader on sign out diff --git a/libs/sdk/src/common/notification/notification.ts b/libs/sdk/src/common/notification/notification.ts index 635ca9c9a4..686fab5c95 100644 --- a/libs/sdk/src/common/notification/notification.ts +++ b/libs/sdk/src/common/notification/notification.ts @@ -106,39 +106,41 @@ class NotificationService { * @throws {Error} If `notificationsClient` is not initialized in read mode. */ async listenToNotificationEvents() { - // Initialize a notification stream using the notifications client. - this._notificationsStream = await this.notificationsClient.initStream( - [CONSTANTS.STREAM.NOTIF], - { - filter: { - channels: [this._notificationChannelId], + if (!this._notificationsStream) { + // Initialize a notification stream using the notifications client. + this._notificationsStream = await this.notificationsClient.initStream( + [CONSTANTS.STREAM.NOTIF], + { + filter: { + channels: [this._notificationChannelId], + }, }, - }, - ); - // Listen for incoming notifications on the specified stream. - this._notificationsStream.on(CONSTANTS.STREAM.NOTIF, (data: any) => { - // Set new notifications badge - this._globalChannel.next({ - data: {}, - event: NOTIFICATION_EVENTS.NEW_NOTIFICATIONS, - }); - - if (Notification.permission == 'granted') { - // Extract notification data and create a browser Notification instance. - const notification = new Notification(data?.message?.notification.body, { - body: data?.message?.notification.body, - icon: data?.channel?.icon, - data: data?.message?.payload, + ); + // Listen for incoming notifications on the specified stream. + this._notificationsStream.on(CONSTANTS.STREAM.NOTIF, (data: any) => { + // Set new notifications badge + this._globalChannel.next({ + data: {}, + event: NOTIFICATION_EVENTS.NEW_NOTIFICATIONS, }); - // Add a click event listener to the notification. - notification.onclick = (event: any) => { - event.preventDefault(); - window.open(data?.message?.payload?.cta || data?.channel?.url, '_blank'); - }; - } - }); - await this._notificationsStream.connect(); + if (Notification.permission == 'granted') { + // Extract notification data and create a browser Notification instance. + const notification = new Notification(data?.message?.notification.body, { + body: data?.message?.notification.body, + icon: data?.channel?.icon, + data: data?.message?.payload, + }); + // Add a click event listener to the notification. + notification.onclick = (event: any) => { + event.preventDefault(); + window.open(data?.message?.payload?.cta || data?.channel?.url, '_blank'); + }; + } + }); + + await this._notificationsStream.connect(); + } } /** @@ -152,6 +154,13 @@ class NotificationService { this._notificationsStream = undefined; } } + /** + * Disconnect to notifications events and set _pushClient to undefined + */ + async disconnect() { + await this.stopListeningToNotificationEvents(); + this._pushClient = undefined; + } /** * Retrieves the settings of notification channel. * @@ -191,7 +200,7 @@ class NotificationService { const channelSubscriptionInfo = subscriptions.find( subscription => subscription.channel === this._notificationChannelId, ); - if (!channelSubscriptionInfo) return null; + if (!channelSubscriptionInfo) return []; // Parse the response const result = ChannelUserSettingsSchema.safeParse(channelSubscriptionInfo);