From 7c3faada1f17bfb07f9dd88f05255ac7b563323b Mon Sep 17 00:00:00 2001 From: Kushdeep Singh Date: Tue, 17 Dec 2024 18:41:06 +0530 Subject: [PATCH 1/9] DMAPP-135: Handle Notification Module - Integrated chat notifications for both iOS and Android. - Converted the notification helper to use Context API for better state management. - Performed code refactoring to improve maintainability and readability. --- index.js | 45 +-- src/components/ui/HomeFeed.js | 173 ++++++-- src/contexts/NotificationContext.tsx | 375 ++++++++++++++++++ src/contexts/PushApiContext.tsx | 8 +- src/helpers/NotificationHelper.ts | 359 ++++++++--------- src/helpers/helpers.types.ts | 45 +++ src/helpers/helpers.utils.ts | 47 --- src/hooks/pushapi/usePushApiMode.tsx | 6 +- src/navigation/AuthenticatedNavigator.js | 10 +- src/navigation/NotifTabNavigator.tsx | 10 +- src/navigation/RootNavigation.ts | 39 +- src/navigation/index.js | 63 +-- src/navigation/screens/chats/ChatScreen.tsx | 5 + .../screens/chats/SingleChatScreen.tsx | 7 +- .../chats/components/SingleChatItem.tsx | 1 - .../screens/chats/helpers/storage.ts | 18 +- .../chats/helpers/useConverstaionLoader.ts | 7 +- src/redux/homeSlice.ts | 36 -- src/redux/store.js | 4 +- 19 files changed, 852 insertions(+), 406 deletions(-) create mode 100644 src/contexts/NotificationContext.tsx delete mode 100644 src/helpers/helpers.utils.ts delete mode 100644 src/redux/homeSlice.ts diff --git a/index.js b/index.js index b434200e1..8546abf67 100644 --- a/index.js +++ b/index.js @@ -56,32 +56,25 @@ function HeadlessCheck({isHeadless}) { /** Listeners used to display notifee **/ /** and native notification **/ /************************************************/ -messaging().setBackgroundMessageHandler(async remoteMessage => { - // console.log('Message handled in the background!', remoteMessage); - /***************************************************/ - /** Uncomment below commented code if video call **/ - /** feature is enabled in the app **/ - /***************************************************/ - // if (Platform.OS === 'android' && CallKeepHelper.isVideoCall(remoteMessage)) { - // const caller = CallKeepHelper.getCaller(remoteMessage); - // const addressTrimmed = CallKeepHelper.formatEthAddress(caller); - // const uuid = getUUID(); - // RNCallKeep.displayIncomingCall( - // uuid, - // addressTrimmed, - // addressTrimmed, - // 'generic', - // true, - // ); - // } -}); - -messaging().onMessage(async remoteMessage => { - // console.log('Message handled in the foreground!', remoteMessage); - if (remoteMessage.notification) { - await NotificationHelper.resolveNotification(remoteMessage); - } -}); +// messaging().setBackgroundMessageHandler(async remoteMessage => { +// console.log('Message handled in the background!', remoteMessage); +/***************************************************/ +/** Uncomment below commented code if video call **/ +/** feature is enabled in the app **/ +/***************************************************/ +// if (Platform.OS === 'android' && CallKeepHelper.isVideoCall(remoteMessage)) { +// const caller = CallKeepHelper.getCaller(remoteMessage); +// const addressTrimmed = CallKeepHelper.formatEthAddress(caller); +// const uuid = getUUID(); +// RNCallKeep.displayIncomingCall( +// uuid, +// addressTrimmed, +// addressTrimmed, +// 'generic', +// true, +// ); +// } +// }); if (isCallAccepted) { AppRegistry.registerComponent(appName, () => HeadlessCheck); diff --git a/src/components/ui/HomeFeed.js b/src/components/ui/HomeFeed.js index ac13d1290..825d5eff3 100644 --- a/src/components/ui/HomeFeed.js +++ b/src/components/ui/HomeFeed.js @@ -1,33 +1,28 @@ -import notifee from '@notifee/react-native'; -import messaging from '@react-native-firebase/messaging'; import React, {useEffect, useRef, useState} from 'react'; import { FlatList, - Platform, RefreshControl, SafeAreaView, StyleSheet, + Text, + TouchableOpacity, View, } from 'react-native'; import ImageView from 'react-native-image-viewing'; -import {useDispatch, useSelector} from 'react-redux'; import {ToasterOptions} from 'src/components/indicators/Toaster'; import EPNSActivity from 'src/components/loaders/EPNSActivity'; import ImagePreviewFooter from 'src/components/ui/ImagePreviewFooter'; +import {useNotificationsApi} from 'src/contexts/NotificationContext'; import {usePushApi} from 'src/contexts/PushApiContext'; import AppBadgeHelper from 'src/helpers/AppBadgeHelper'; -import { - selectNotificationOpened, - selectNotificationReceived, - updateNotificationOpened, - updateNotificationReceived, -} from 'src/redux/homeSlice'; +import {getTrimmedAddress} from 'src/navigation/screens/chats/helpers/chatAddressFormatter'; import EmptyFeed from './EmptyFeed'; import NotificationItem from './NotificationItem'; export default function InboxFeed(props) { const {userPushSDKInstance, userInfo} = usePushApi(); + const {createNotificationChannel} = useNotificationsApi(); // SET STATES const [initialized, setInitialized] = useState(false); @@ -41,11 +36,12 @@ export default function InboxFeed(props) { const [renderGallery, setRenderGallery] = useState(false); const [startFromIndex, setStartFromIndex] = useState(0); - // GET REDUX STATES AND DISPATCH ACTIONS - const notificationOpened = useSelector(selectNotificationOpened); - const notificationReceived = useSelector(selectNotificationReceived); - - const dispatch = useDispatch(); + const { + channelNotificationOpened, + channelNotificationReceived, + setChannelNotificationOpened, + setChannelNotificationReceived, + } = useNotificationsApi(); // SET REFS const FlatListFeedsRef = useRef(null); @@ -58,28 +54,15 @@ export default function InboxFeed(props) { }, [initialized, userPushSDKInstance]); useEffect(() => { - if (notificationReceived || notificationOpened) { + if (channelNotificationReceived || channelNotificationOpened) { fetchFeed(true, true); - dispatch(updateNotificationOpened(false)); - dispatch(updateNotificationReceived(false)); + setChannelNotificationOpened(false); + setChannelNotificationReceived(false); } - }, [notificationOpened, notificationReceived]); + }, [channelNotificationOpened, channelNotificationReceived]); useEffect(() => { - if (Platform.OS === 'android') { - messaging() - .hasPermission() - .then(val => { - if (val === 1) { - // User has enabled notifications - notifee.createChannel({ - id: 'default', - name: 'Default Channel', - sound: 'default', - }); - } - }); - } + createNotificationChannel(); }, []); useEffect(() => { @@ -163,9 +146,133 @@ export default function InboxFeed(props) { } }; + function generateRandomChatSentence() { + const subjects = ['I', 'You', 'We', 'They', 'Someone']; + const verbs = ['love', 'hate', 'enjoy', 'miss', 'think about', 'remember']; + const objects = [ + 'coding', + 'chatting', + 'pizza', + 'movies', + 'nature', + 'music', + ]; + const phrases = [ + 'in the morning.', + 'right now.', + 'every day.', + 'all the time.', + 'on weekends.', + "when I'm alone.", + ]; + const message = [ + 'sent a message', + 'sent a GIF', + 'sent an image', + 'sent a file', + 'replied to a message', + ]; + + const randomElement = arr => arr[Math.floor(Math.random() * arr.length)]; + + const msg = randomElement(message); + + const sentence = `${randomElement(subjects)} ${randomElement( + verbs, + )} ${randomElement(objects)} ${randomElement(phrases)}`; + return msg; + } + + const chatMessage = { + singleChat: (msg, timeStamp) => ({ + collapseKey: 'io.epns.epnsstaging', + data: { + type: 'PUSH_NOTIFICATION_CHAT', + details: JSON.stringify({ + subType: 'INDIVIDUAL_CHAT', + info: { + wallets: '0x9B220a17929Ac119dD3D0711d916e28263dd0D9C', + profilePicture: + 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAuUlEQVR4AcXBMWrDUBBF0avHh+zLjRp9XDrFZGfBTaaIcfndeHVKO3IhEMG8c6bvj+tKMTJ5px5BJcyEmTBrI5Pq9vNLlc8H/xHzQnXJTyphJsyEWeNFPh9UI5OqR7BnZLIRbH2xIcyEmTBrvIh5oRokVcwLewZJFfNCNUgqYSbMhNl0vp9WjISZMBNmjYN6BHtGJkcIM2EmzFqP4IiRyZ4ewRHCTJgJs+l8P60UPYJ3GplUwkyYCbM/Vc0q3B9XBygAAAAASUVORK5CYII=', + chatId: + '248d2886f49bb26e6715b214e063d27c6d57eb16fd0f594ea0cd0f135bfe4cbd', + combinedDID: + 'eip155:0xDcA78D2f7cF9cF40bbC752494Fa41639280FbC3B_eip155:0x9B220a17929Ac119dD3D0711d916e28263dd0D9C', + threadhash: + 'v2:a78b22977759c2a3798a4fbdf78f8f84688198470ae4879c298944bf67267082', //cid + }, + }), + }, + from: '755180533582', + messageId: `0:1732875400813721%841${timeStamp}`, + notification: { + android: { + color: '#e20880', + imageUrl: null, + smallIcon: 'ic_notification', + }, + body: msg, + title: getTrimmedAddress('0x9B220a17929Ac119dD3D0711d916e28263dd0D9C'), + }, + sentTime: timeStamp, + ttl: 2419200, + }), + groupChat: (msg, timeStamp) => ({ + collapseKey: 'io.epns.epnsstaging', + data: { + type: 'PUSH_NOTIFICATION_CHAT', + details: JSON.stringify({ + subType: 'GROUP_CHAT', + info: { + wallets: '0x9B220a17929Ac119dD3D0711d916e28263dd0D9C', + profilePicture: + 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAuUlEQVR4AcXBMWrDUBBF0avHh+zLjRp9XDrFZGfBTaaIcfndeHVKO3IhEMG8c6bvj+tKMTJ5px5BJcyEmTBrI5Pq9vNLlc8H/xHzQnXJTyphJsyEWeNFPh9UI5OqR7BnZLIRbH2xIcyEmTBrvIh5oRokVcwLewZJFfNCNUgqYSbMhNl0vp9WjISZMBNmjYN6BHtGJkcIM2EmzFqP4IiRyZ4ewRHCTJgJs+l8P60UPYJ3GplUwkyYCbM/Vc0q3B9XBygAAAAASUVORK5CYII=', + chatId: + '6bc7bef45a30b033390c060698e72f5a07a416d97db73e1363e171337469f339', + combinedDID: + 'eip155:0xDcA78D2f7cF9cF40bbC752494Fa41639280FbC3B_eip155:0x9B220a17929Ac119dD3D0711d916e28263dd0D9C', + threadhash: + 'v2:aad7f7f9129656e50bed6e5a08f254bf749e4a3de323a2b4fd3e2d188db58ef3', //cid + isRequestAccepted: true, + }, + }), + }, + from: '755180533582', + messageId: `0:1732875400813721%841${timeStamp}`, + notification: { + android: { + color: '#e20880', + imageUrl: null, + smallIcon: 'ic_notification', + }, + body: `${getTrimmedAddress( + '0x9B220a17929Ac119dD3D0711d916e28263dd0D9C', + 4, + )}: ${msg}`, + title: 'Tech Updates', + }, + sentTime: timeStamp, + ttl: 2419200, + }), + }; + const {resolveNotification} = useNotificationsApi(); return ( <> + { + const msg = generateRandomChatSentence(); + const timeStamp = Date.now(); + resolveNotification(chatMessage.groupChat(msg, timeStamp)); + }} + style={{ + padding: 8, + margin: 15, + borderRadius: 10, + backgroundColor: 'yellow', + }}> + Send Test Notification + void; + createNotificationChannel: () => void; + setTempNotificationData: (value: NotificationDataType | null) => void; + resolveNotification: ( + remoteMessage: FirebaseMessagingTypes.RemoteMessage, + ) => void; + channelNotificationReceived: boolean; + setChannelNotificationReceived: (value: boolean) => void; + channelNotificationOpened: boolean; + setChannelNotificationOpened: (value: boolean) => void; +}; + +const NotificationContext = createContext({ + handleNotificationEvents: () => {}, + createNotificationChannel: () => {}, + setTempNotificationData: () => {}, + resolveNotification: () => {}, + channelNotificationReceived: false, + setChannelNotificationReceived: () => {}, + channelNotificationOpened: false, + setChannelNotificationOpened: () => {}, +}); + +export const NotificationContextProvider = ({ + children, +}: { + children: React.ReactNode; +}) => { + const {isChatEnabled} = usePushApiMode(); + const {showUnlockProfileModal, userPushSDKInstance} = usePushApi(); + + const [tempNotificationData, setTempNotificationData] = + useState(null); + const [channelNotificationReceived, setChannelNotificationReceived] = + useState(false); + const [channelNotificationOpened, setChannelNotificationOpened] = + useState(false); + + useEffect(() => { + if (isChatEnabled && tempNotificationData) { + handleNotificationRoute(tempNotificationData); + } + }, [isChatEnabled]); + + useEffect(() => { + // Foreground Notifications + const unsubscribeOnMessage = messaging().onMessage(async remoteMessage => { + // console.log('Message handled in the foreground!', remoteMessage); + if (remoteMessage.notification) { + resolveNotification(remoteMessage); + } + }); + + // Background/Quit state Notifications + messaging().setBackgroundMessageHandler(async remoteMessage => { + // console.log('Message handled in the background!', remoteMessage); + }); + + return () => { + unsubscribeOnMessage(); + }; + }, []); + + /**************************************************/ + /** This Function will create native android **/ + /** notification channel **/ + /**************************************************/ + const createNotificationChannel = () => { + if (Platform.OS === 'android') { + messaging() + .hasPermission() + .then(val => { + if (val === 1) { + // User has enabled notifications + notifee.createChannel({ + id: 'default', + name: 'Default Channel', + sound: 'default', + importance: AndroidImportance.HIGH, + }); + } + }); + } + }; + + const resolveNotification = async ( + remoteMessage: FirebaseMessagingTypes.RemoteMessage, + ) => { + if (remoteMessage?.data?.type === NOTIFICATION_TYPES.CHAT) { + handleChatNotification(remoteMessage); + } else if (remoteMessage?.data?.type === NOTIFICATION_TYPES.CHANNEL) { + handleChannelNotification(remoteMessage); + } + }; + + /**************************************************/ + /** This Function will push CHANNEL notification **/ + /**************************************************/ + const handleChannelNotification = async ( + remoteMessage: FirebaseMessagingTypes.RemoteMessage, + ) => { + try { + const notifeeConfig = await NotificationHelper.getNotifeeConfig( + 'PUSH_NOTIFICATION_CHANNEL', + remoteMessage, + getRecentMessageNotifications, + ); + await notifee.displayNotification(notifeeConfig); + handlePostNotificationReceived(remoteMessage.data); + } catch (error) { + console.log('NOTIFEE CHANNEL ERROR', error); + } + }; + + /***************************************************/ + /** This Function will push CHAT notification **/ + /***************************************************/ + const handleChatNotification = async ( + remoteMessage: FirebaseMessagingTypes.RemoteMessage, + ) => { + // Parse the stringified data + const parsedDetails = remoteMessage.data?.details + ? JSON.parse(remoteMessage.data?.details as string) + : {}; + try { + if ( + getCurrentRouteName() !== GLOBALS.SCREENS.SINGLE_CHAT || + (getCurrentRouteName() === GLOBALS.SCREENS.SINGLE_CHAT && + getCurrentRouteParams()?.chatId !== parsedDetails?.info?.chatId) + ) { + const notifeeConfig = await NotificationHelper.getNotifeeConfig( + 'PUSH_NOTIFICATION_CHAT', + remoteMessage, + getRecentMessageNotifications, + ); + await notifee.displayNotification(notifeeConfig); + } + } catch (error) { + console.log('NOTIFEE CHAT ERROR', error); + } + }; + + /**********************************************************/ + /** This Function will return list of notifications **/ + /** that are available in notification centre **/ + /**********************************************************/ + const getRecentMessageNotifications = async ( + chatId?: string, + ): Promise => { + try { + const getDisplayedNotifications = + await notifee.getDisplayedNotifications(); + if (chatId) { + const recentNotifications = getDisplayedNotifications.filter( + item => item.id === chatId, + ); + return recentNotifications; + } else { + return getDisplayedNotifications; + } + } catch (error) { + return []; + } + }; + + /*****************************************************************************************/ + /** This function will remove other notification banners from the notification center **/ + /** if any notification for the same chat has been opened. **/ + /*****************************************************************************************/ + const removeOpenedChatNotifications = async (chatId: string) => { + try { + const recentNotifications = await getRecentMessageNotifications(); + const recentChatNotificationsIDs = recentNotifications + .filter( + item => + JSON.parse(item.notification.data?.details as string)?.info + ?.chatId === chatId, + ) + .map(item => `${item.id}`); + await notifee.cancelDisplayedNotifications(recentChatNotificationsIDs); + } catch (error) { + console.log('removeOpenedChatNotifications ERROR', error); + } + }; + + /************************************************/ + /** Handle native notification and notifee **/ + /** events(onPress and dismiss) **/ + /************************************************/ + const handleNotificationEvents = async () => { + messaging() + .getInitialNotification() + .then(async remoteMessage => { + if (remoteMessage) { + handleNotificationRoute(remoteMessage.data); + } + }); + + messaging().onNotificationOpenedApp( + async (remoteMessage: FirebaseMessagingTypes.RemoteMessage) => { + handleNotificationRoute(remoteMessage.data); + }, + ); + + notifee.onForegroundEvent(async ({type, detail}) => { + if (type === EventType.PRESS) { + handleNotificationRoute(detail.notification?.data); + } + }); + + notifee.onBackgroundEvent(async ({type, detail}) => { + if (type === EventType.PRESS) { + handleNotificationRoute(detail.notification?.data); + } + }); + + const initialNotification = await notifee.getInitialNotification(); + if (initialNotification) { + const {notification} = initialNotification; + handleNotificationRoute(notification?.data); + } + }; + + /************************************************/ + /** Handle notification routes and data **/ + /************************************************/ + const handleNotificationRoute = async (data?: NotificationDataType) => { + // Parse the stringified data + const parsedDetails = data?.details + ? JSON.parse(data?.details as string) + : {}; + + // Handle conditional checks to confirm if route navigation & + // data needs to be updated after notification opened + if ( + data?.type === NOTIFICATION_TYPES.CHANNEL && + parsedDetails?.subType === NOTIFICATION_SUB_TYPES.INBOX + ) { + // If Home(Notification) tab is active then update data + if (getCurrentRouteName() == GLOBALS.SCREENS.NOTIF_TABS) { + setChannelNotificationOpened(true); + } else { + // If Home(Notification) tab is inactive then first + // navigate to Home tab then update data + navigate(GLOBALS.SCREENS.NOTIF_TABS); + setChannelNotificationOpened(true); + } + } else if (data?.type === NOTIFICATION_TYPES.CHAT) { + // Handle Chat notification banner press + console.log('isChatEnabled===>', isChatEnabled); + if (isChatEnabled) { + try { + // Get navigation params for SINGLE CHAT Screen + const isGroupConversation = + parsedDetails?.subType === NOTIFICATION_SUB_TYPES.GROUP_CHAT; + const singleChatParams = + await NotificationHelper.getChatNavigationParams({ + chatId: parsedDetails?.info?.chatId, + userPushSDKInstance: userPushSDKInstance, + isGroupConversation, + wallets: parsedDetails?.info?.wallets, + profilePicture: parsedDetails?.info?.profilePicture, + threadhash: parsedDetails?.info?.threadhash, + }); + if (singleChatParams) { + if (getCurrentRouteName() === GLOBALS.SCREENS.SINGLE_CHAT) { + // If Single chat screen is already active then update params data + replaceRoute(GLOBALS.SCREENS.SINGLE_CHAT, singleChatParams); + removeOpenedChatNotifications(parsedDetails?.info?.chatId); + setTempNotificationData(null); + } else { + // Navigate to Single/Group chat screen + navigate(GLOBALS.SCREENS.SINGLE_CHAT, singleChatParams); + removeOpenedChatNotifications(parsedDetails?.info?.chatId); + setTempNotificationData(null); + } + } + } catch (error) { + console.log('Notification Route ERROR', error); + } + } else { + showUnlockProfileModal(); + setTempNotificationData(data); + } + } + }; + + /*****************************************************/ + /** Handle data updates in the Foreground state **/ + /** if the received notification is for **/ + /** the currently active component screen. **/ + /*****************************************************/ + const handlePostNotificationReceived = (data?: NotificationDataType) => { + // Parse the stringified data + const parsedDetails = data?.details + ? JSON.parse(data?.details as string) + : {}; + + // Handle condition check please data needs to be + // updated after notification received + if ( + data?.type === NOTIFICATION_TYPES.CHANNEL && + parsedDetails?.subType === NOTIFICATION_SUB_TYPES.INBOX && + getCurrentRouteName() == GLOBALS.SCREENS.NOTIF_TABS + ) { + setChannelNotificationReceived(true); + } + }; + + return ( + + {children} + + ); +}; + +export const useNotificationsApi = () => { + const context = React.useContext(NotificationContext); + if (!context) + throw new Error( + 'useNotifications must be used within a NotificationContextProvider', + ); + + return context; +}; + +export default NotificationContextProvider; diff --git a/src/contexts/PushApiContext.tsx b/src/contexts/PushApiContext.tsx index 53b86800a..5336bc90b 100644 --- a/src/contexts/PushApiContext.tsx +++ b/src/contexts/PushApiContext.tsx @@ -25,6 +25,8 @@ import { import MetaStorage from 'src/singletons/MetaStorage'; import {getSigner} from 'src/walletconnect/chat/utils'; +import {useNotificationsApi} from './NotificationContext'; + type PushApiContextType = { userPushSDKInstance: PushAPI | null; userInfo: IUser | null; @@ -69,6 +71,7 @@ const PushApiContextProvider = ({children}: {children: React.ReactNode}) => { const isGuest = useSelector(selectIsGuest); const dispatch = useDispatch(); const {login} = useAuth(); + const {setTempNotificationData} = useNotificationsApi(); const { ModalComponent: UnlockProfileModal, @@ -316,7 +319,10 @@ const PushApiContextProvider = ({children}: {children: React.ReactNode}) => { title: 'Not now', bgColor: GLOBALS.COLORS.TRANSPARENT, fontColor: GLOBALS.COLORS.BLACK, - onPress: () => hideUnlockProfileModal(), + onPress: () => { + hideUnlockProfileModal(); + setTempNotificationData(null); + }, }, ], }} diff --git a/src/helpers/NotificationHelper.ts b/src/helpers/NotificationHelper.ts index 0c1edf41c..5d99ef03c 100644 --- a/src/helpers/NotificationHelper.ts +++ b/src/helpers/NotificationHelper.ts @@ -1,213 +1,190 @@ -import notifee, { +import { AndroidMessagingStyleMessage, AndroidStyle, - EventType, + DisplayedNotification, } from '@notifee/react-native'; -import * as PushApi from '@pushprotocol/restapi'; -import {ENV} from '@pushprotocol/restapi/src/lib/constants'; -import messaging from '@react-native-firebase/messaging'; -import {FirebaseMessagingTypes} from '@react-native-firebase/messaging'; +import {Platform} from 'react-native'; import Globals from 'src/Globals'; -import GLOBALS from 'src/Globals'; -import envConfig from 'src/env.config'; -import {getCurrentRouteName, navigate} from 'src/navigation/RootNavigation'; import {UserChatCredentials} from 'src/navigation/screens/chats/ChatScreen'; -import {globalDispatch} from 'src/redux'; -import { - updateNotificationOpened, - updateNotificationReceived, -} from 'src/redux/homeSlice'; import MetaStorage from 'src/singletons/MetaStorage'; -import {getNotifeeConfig} from './helpers.utils'; - -const NOTIFICATION_TYPES = { - CHANNEL: 'PUSH_NOTIFICATION_CHANNEL', - CHAT: 'PUSH_NOTIFICATION_CHAT', -}; - -const NOTIFICATION_SUB_TYPES = { - INBOX: 'INBOX', -}; - -export const NotificationHelper = { - resolveNotification: async ( - remoteMessage: FirebaseMessagingTypes.RemoteMessage, - ) => { - if (remoteMessage?.data?.type === NOTIFICATION_TYPES.CHAT) { - NotificationHelper.handleChatNotification(remoteMessage); - } else if (remoteMessage?.data?.type === NOTIFICATION_TYPES.CHANNEL) { - NotificationHelper.handleChannelNotification(remoteMessage); - } - }, - - /**************************************************/ - /** This Function will push CHANNEL notification **/ - /**************************************************/ - handleChannelNotification: async ( - remoteMessage: FirebaseMessagingTypes.RemoteMessage, - ) => { - try { - const notifeeConfig = getNotifeeConfig( - 'PUSH_NOTIFICATION_CHANNEL', - remoteMessage, - ); - await notifee.displayNotification(notifeeConfig); - NotificationHelper.handlePostNotificationReceived(remoteMessage.data); - } catch (error) { - console.log('NOTIFEE ERROR', error); - } - }, +import {GroupInformation, NotificationHelperType} from './helpers.types'; - /***************************************************/ - /** This Function will push CHAT notification **/ - /***************************************************/ - handleChatNotification: async ( - message: FirebaseMessagingTypes.RemoteMessage, +export const NotificationHelper: NotificationHelperType = { + getNotifeeConfig: async ( + type, + remoteMessage, + getRecentMessageNotifications, ) => { - const {pgpPrivateKey}: UserChatCredentials = - await MetaStorage.instance.getUserChatData(); - - const users = await MetaStorage.instance.getStoredWallets(); - const connectedUser = users[0]; - - const [mssg] = await PushApi.chat.decryptConversation({ - messages: [message.data?.message as any], - env: envConfig.ENV as ENV, - pgpPrivateKey: pgpPrivateKey, - connectedUser: { - ...connectedUser, - wallets: connectedUser.wallet, - }, - }); + const parsedDetails = remoteMessage.data?.details + ? JSON.parse(remoteMessage.data?.details as string) + : {}; + if (type === 'PUSH_NOTIFICATION_CHANNEL') { + const largeIcon = parsedDetails?.info?.icon ?? 'ic_launcher_round'; + return { + id: remoteMessage.messageId, + title: remoteMessage.notification?.title, + body: remoteMessage.notification?.body, + ios: { + sound: 'default', + foregroundPresentationOptions: { + banner: true, + list: true, + badge: true, + sound: true, + }, + }, + android: { + channelId: 'default', + largeIcon, + smallIcon: + remoteMessage.notification?.android?.smallIcon ?? 'ic_notification', + color: + remoteMessage.notification?.android?.color ?? + Globals.COLORS.IC_NOTIFICATION, + circularLargeIcon: true, + pressAction: { + id: 'default', + }, + }, + data: remoteMessage.data, + }; + } else if (type === 'PUSH_NOTIFICATION_CHAT') { + let recentChatNotifications: DisplayedNotification[] = []; + let messages: AndroidMessagingStyleMessage[] = []; + if (Platform.OS === 'android') { + recentChatNotifications = await getRecentMessageNotifications( + parsedDetails?.info?.chatId, + ); - // await NotificationHelper.sendNotification({ - // newMessage: { - // text: mssg.messageContent, - // timestamp: mssg.timestamp ?? Date.now(), - // person: { - // name: mssg.fromCAIP10, - // icon: 'https://picsum.photos/200', - // }, - // }, - // }); - }, + messages = + recentChatNotifications.length > 0 + ? recentChatNotifications?.[0]?.notification?.android?.style + ?.messages + : []; - sendNotification: async ( - remoteMessage: FirebaseMessagingTypes.RemoteMessage, - ) => { - try { - const notifeeConfig = getNotifeeConfig( - 'PUSH_NOTIFICATION_CHAT', - remoteMessage, - ); - await notifee.displayNotification(notifeeConfig); - } catch (error) { - console.log('NOTIFEE ERROR', error); + messages.push({ + text: remoteMessage.notification?.body ?? '', + timestamp: remoteMessage.sentTime ?? Date.now(), + }); + } + return { + id: + Platform.OS === 'android' + ? parsedDetails?.info?.chatId + : remoteMessage.messageId, + title: remoteMessage.notification?.title, + body: remoteMessage.notification?.body, + ios: { + sound: 'default', + foregroundPresentationOptions: { + banner: true, + list: true, + badge: true, + sound: true, + }, + categoryId: 'Communications', + communicationInfo: { + conversationId: parsedDetails?.info?.chatId, + sender: { + id: parsedDetails?.info?.wallets, + displayName: remoteMessage.notification?.title ?? '', + }, + }, + }, + android: { + channelId: 'default', + smallIcon: + remoteMessage.notification?.android?.smallIcon ?? 'ic_notification', + color: + remoteMessage.notification?.android?.color ?? + Globals.COLORS.IC_NOTIFICATION, + pressAction: { + id: 'default', + }, + style: { + type: AndroidStyle.MESSAGING, + person: { + name: remoteMessage.notification?.title ?? '', + icon: + parsedDetails?.subType === 'GROUP_CHAT' + ? 'ic_launcher_round' + : parsedDetails?.info?.profilePicture, + }, + messages, + }, + }, + data: remoteMessage.data, + }; } + return {}; }, - getRecentMessageNotifications: async (from: string): Promise => { + getChatNavigationParams: async data => { + const { + userPushSDKInstance, + chatId, + isGroupConversation, + wallets, + profilePicture, + threadhash, + } = data; try { - const getDisplayedNotifications = - await notifee.getDisplayedNotifications(); - return getDisplayedNotifications; - } catch (error) { - return []; - } - }, - - /************************************************/ - /** Handle native notification and notifee **/ - /** events(onPress and dismiss) **/ - /************************************************/ - handleNotificationEvents: async () => { - messaging() - .getInitialNotification() - .then(async remoteMessage => { - if (remoteMessage) { - await NotificationHelper.handleNotificationRoute(remoteMessage.data); + if (userPushSDKInstance) { + // Make connectUser Obj + const {pgpPrivateKey}: UserChatCredentials = + await MetaStorage.instance.getUserChatData(); + const users = await MetaStorage.instance.getStoredWallets(); + const connectedUser = users[0]; + + // Get Group Data + let groupInformation: GroupInformation = null; + if (isGroupConversation) { + const groupInformationResponse = + await userPushSDKInstance?.chat.group.info(chatId); + console.log( + 'groupInformationResponse', + JSON.stringify(groupInformationResponse), + ); + groupInformation = { + groupName: groupInformationResponse?.groupName, + groupImage: groupInformationResponse?.groupImage, + }; } - }); - - messaging().onNotificationOpenedApp(async remoteMessage => { - await NotificationHelper.handleNotificationRoute(remoteMessage.data); - }); - notifee.onForegroundEvent(async ({type, detail}) => { - if (type === EventType.PRESS) { - await NotificationHelper.handleNotificationRoute( - detail.notification?.data, + // Get latest message to check if conversation request accepted or not + let isIntentReceivePage = false; + const conversationHashResponse: any = + await userPushSDKInstance?.chat.latest(chatId); + console.log( + 'conversationHashResponse', + JSON.stringify(conversationHashResponse), ); + if (conversationHashResponse?.length > 0) { + isIntentReceivePage = + conversationHashResponse?.[0]?.listType !== 'CHATS'; + } + return { + feed: {groupInformation}, + isIntentSendPage: false, + isIntentReceivePage, + connectedUser: { + ...connectedUser, + wallets: connectedUser.wallet, + privateKey: pgpPrivateKey, + }, + senderAddress: wallets, + image: isGroupConversation + ? groupInformation?.groupImage + : profilePicture, + cid: threadhash, + title: isGroupConversation ? groupInformation?.groupName : null, + chatId, + }; } - }); - - notifee.onBackgroundEvent(async ({type, detail}) => { - if (type === EventType.PRESS) { - await NotificationHelper.handleNotificationRoute( - detail.notification?.data, - ); - } - }); - - const initialNotification = await notifee.getInitialNotification(); - if (initialNotification) { - const {notification} = initialNotification; - await NotificationHelper.handleNotificationRoute(notification?.data); - } - }, - - /************************************************/ - /** Handle notification routes and data **/ - /************************************************/ - handleNotificationRoute: async (data?: { - [key: string]: string | number | object; - }) => { - // Parse the stringified data - const parsedDetails = data?.details - ? JSON.parse(data?.details as string) - : {}; - - // Handle conditional checks to confirm if route navigation & - // data needs to be updated after notification opened - if ( - data?.type === NOTIFICATION_TYPES.CHANNEL && - parsedDetails?.subType === NOTIFICATION_SUB_TYPES.INBOX - ) { - // If Home(Notification) tab is active then update data - if (getCurrentRouteName() == GLOBALS.SCREENS.NOTIF_TABS) { - globalDispatch(updateNotificationOpened(true)); - } else { - // If Home(Notification) tab is inactive then first - // navigate to Home tab then update data - navigate(GLOBALS.SCREENS.NOTIF_TABS); - globalDispatch(updateNotificationOpened(true)); - } - } else if (data?.type === NOTIFICATION_TYPES.CHAT) { - } - }, - - /*****************************************************/ - /** Handle data updates in the Foreground state **/ - /** if the received notification is for **/ - /** the currently active component screen. **/ - /*****************************************************/ - handlePostNotificationReceived: (data?: { - [key: string]: string | number | object; - }) => { - // Parse the stringified data - const parsedDetails = data?.details - ? JSON.parse(data?.details as string) - : {}; - - // Handle condition check please data needs to be - // updated after notification received - if ( - data?.type === NOTIFICATION_TYPES.CHANNEL && - parsedDetails?.subType === NOTIFICATION_SUB_TYPES.INBOX && - getCurrentRouteName() == GLOBALS.SCREENS.NOTIF_TABS - ) { - globalDispatch(updateNotificationReceived(true)); + return null; + } catch (error) { + return null; } }, }; diff --git a/src/helpers/helpers.types.ts b/src/helpers/helpers.types.ts index af97f7af1..6d553683e 100644 --- a/src/helpers/helpers.types.ts +++ b/src/helpers/helpers.types.ts @@ -1,3 +1,48 @@ +import {DisplayedNotification, Notification} from '@notifee/react-native'; +import {PushAPI} from '@pushprotocol/restapi'; +import {FirebaseMessagingTypes} from '@react-native-firebase/messaging'; + export type NotificationTypes = | 'PUSH_NOTIFICATION_CHANNEL' | 'PUSH_NOTIFICATION_CHAT'; + +export type NotificationHelperType = { + getNotifeeConfig: ( + type: NotificationTypes, + remoteMessage: FirebaseMessagingTypes.RemoteMessage, + getRecentMessageNotifications: ( + chatId?: string, + ) => Promise, + ) => Promise; + getChatNavigationParams: ( + data: ChatNavigationParams, + ) => Promise; +}; + +export type GroupInformation = { + groupName: string; + groupImage: string | null; +} | null; + +export type ChatNavigationParams = { + chatId: string; + userPushSDKInstance: PushAPI | null; + isGroupConversation: boolean; + wallets: string; + profilePicture: string; + threadhash: string; +}; + +export type ReturnChatNavigationParams = { + cid: string; + senderAddress: string; + connectedUser: any; + isIntentReceivePage: boolean; + isIntentSendPage: boolean; + image: string | null | undefined; + chatId: string; + feed: { + groupInformation: GroupInformation; + }; + title: string | null | undefined; +}; diff --git a/src/helpers/helpers.utils.ts b/src/helpers/helpers.utils.ts deleted file mode 100644 index 867fad171..000000000 --- a/src/helpers/helpers.utils.ts +++ /dev/null @@ -1,47 +0,0 @@ -import {Notification} from '@notifee/react-native'; -import {FirebaseMessagingTypes} from '@react-native-firebase/messaging'; -import Globals from 'src/Globals'; - -import {NotificationTypes} from './helpers.types'; - -export const getNotifeeConfig = ( - type: NotificationTypes, - remoteMessage: FirebaseMessagingTypes.RemoteMessage, -): Notification => { - const parsedDetails = remoteMessage.data?.details - ? JSON.parse(remoteMessage.data?.details as string) - : {}; - if (type === 'PUSH_NOTIFICATION_CHANNEL') { - const largeIcon = parsedDetails?.info?.icon ?? 'ic_launcher_round'; - return { - id: remoteMessage.messageId, - title: remoteMessage.notification?.title, - body: remoteMessage.notification?.body, - ios: { - sound: 'default', - foregroundPresentationOptions: { - banner: true, - list: true, - badge: true, - sound: true, - }, - }, - android: { - channelId: 'default', - largeIcon, - smallIcon: - remoteMessage.notification?.android?.smallIcon ?? 'ic_notification', - color: - remoteMessage.notification?.android?.color ?? - Globals.COLORS.IC_NOTIFICATION, - circularLargeIcon: true, - pressAction: { - id: 'default', - }, - }, - data: remoteMessage.data, - }; - } else { - return {}; - } -}; diff --git a/src/hooks/pushapi/usePushApiMode.tsx b/src/hooks/pushapi/usePushApiMode.tsx index 1031caf38..e38af1a86 100644 --- a/src/hooks/pushapi/usePushApiMode.tsx +++ b/src/hooks/pushapi/usePushApiMode.tsx @@ -16,10 +16,10 @@ export const usePushApiMode = () => { // If instance is in read mode, profile is not enabled if (readMode) return false; // Profile enabled and connected with private key - if (connectedUser.userPKey) return true; + if (connectedUser?.userPKey) return true; // If profile is enabled, but user is not connected, not enabled return isConnected && provider !== undefined; - }, [userPushSDKInstance, connectedUser.userPKey, isConnected, provider]); + }, [userPushSDKInstance, connectedUser?.userPKey, isConnected, provider]); const isChatEnabled = useMemo(() => { // If userPushSDKInstance is not available, not in enabled state @@ -30,7 +30,7 @@ export const usePushApiMode = () => { const isSignerEnabled = useMemo(() => { // If connected with private key, signer is enabled - if (connectedUser.userPKey) return true; + if (connectedUser?.userPKey) return true; // If connected with wallet and signer is available return isConnected && provider !== undefined; }, [connectedUser, isConnected, provider]); diff --git a/src/navigation/AuthenticatedNavigator.js b/src/navigation/AuthenticatedNavigator.js index 9605f9488..8c716793c 100644 --- a/src/navigation/AuthenticatedNavigator.js +++ b/src/navigation/AuthenticatedNavigator.js @@ -2,9 +2,8 @@ import {createStackNavigator} from '@react-navigation/stack'; import Constants from 'expo-constants'; import React, {useEffect} from 'react'; import GLOBALS from 'src/Globals'; -import Header from 'src/components/ui/Header'; import Tabs from 'src/components/ui/Tabs'; -import {NotificationHelper} from 'src/helpers/NotificationHelper'; +import {useNotificationsApi} from 'src/contexts/NotificationContext'; import QRScanScreen from 'src/navigation/screens/dapp/QRScanScreen'; import ChatProfileScreen from './screens/ChatProfileScreen'; @@ -22,8 +21,13 @@ export default function AuthenticatedNavigator() { /** Handle native notification and notifee **/ /** events(onPress and dismiss) **/ /************************************************/ + const {handleNotificationEvents} = useNotificationsApi(); + useEffect(() => { - NotificationHelper.handleNotificationEvents(); + let eventTimeout = setTimeout(() => handleNotificationEvents(), 800); + return () => { + clearTimeout(eventTimeout); + }; }, []); return ( diff --git a/src/navigation/NotifTabNavigator.tsx b/src/navigation/NotifTabNavigator.tsx index e138fece8..9326570b0 100644 --- a/src/navigation/NotifTabNavigator.tsx +++ b/src/navigation/NotifTabNavigator.tsx @@ -1,10 +1,9 @@ import React, {useEffect, useState} from 'react'; import {StyleSheet, useWindowDimensions} from 'react-native'; import {SceneMap, TabBar, TabView} from 'react-native-tab-view'; -import {useSelector} from 'react-redux'; import GLOBALS from 'src/Globals'; import Header from 'src/components/ui/Header'; -import {selectNotificationOpened} from 'src/redux/homeSlice'; +import {useNotificationsApi} from 'src/contexts/NotificationContext'; import HomeScreen from './screens/HomeScreen'; import SpamBoxScreen from './screens/SpamBoxScreen'; @@ -18,14 +17,13 @@ const NotifTabNavigator = () => { const layout = useWindowDimensions(); const [index, setIndex] = useState(0); - // GET REDUX STATES - const notificationOpened = useSelector(selectNotificationOpened); + const {channelNotificationOpened} = useNotificationsApi(); useEffect(() => { - if (notificationOpened && index === 1) { + if (channelNotificationOpened && index === 1) { setIndex(0); } - }, [notificationOpened]); + }, [channelNotificationOpened]); const [routes] = useState([ {key: GLOBALS.SCREENS.FEED, title: 'Inbox'}, diff --git a/src/navigation/RootNavigation.ts b/src/navigation/RootNavigation.ts index 7ae7dc64e..3f4aff2cb 100644 --- a/src/navigation/RootNavigation.ts +++ b/src/navigation/RootNavigation.ts @@ -8,18 +8,47 @@ import { export const navigationRef = createNavigationContainerRef>(); +/**************************************************************/ +/** This function will redirect to desired screen if exist **/ +/**************************************************************/ export function navigate(name: any, params?: any) { if (navigationRef.isReady()) { navigationRef.navigate(name, params); } } -// add other navigation functions that you need and export them +/***********************************************************/ +/** This function will return the name of current route **/ +/***********************************************************/ +export const getCurrentRouteName = (): string | undefined => { + return navigationRef.getCurrentRoute()?.name; +}; -export const getCurrentRouteName = () => { - return navigationRef?.current?.getCurrentRoute()?.name; +/*************************************************************/ +/** This function will return the params of current route **/ +/*************************************************************/ +export const getCurrentRouteParams = (): any => { + return navigationRef.getCurrentRoute()?.params; }; -export const getCurrentRouteParams = () => { - return navigationRef?.current?.getCurrentRoute()?.params; +/************************************************************/ +/** This function will set the params in current route **/ +/************************************************************/ +export const setCurrentRouteParams = (params: any) => { + if (navigationRef.isReady()) { + navigationRef.setParams(params); + } }; + +/************************************************************/ +/** This function will replace the params of given route **/ +/** Pass the route name in @param name **/ +/************************************************************/ +export function replaceRoute(name: any, params?: any) { + if (navigationRef.isReady()) { + navigationRef.current?.dispatch({ + type: 'REPLACE', + payload: {name, params}, + }); + } +} diff --git a/src/navigation/index.js b/src/navigation/index.js index 1256dd201..698c80d5b 100644 --- a/src/navigation/index.js +++ b/src/navigation/index.js @@ -6,6 +6,7 @@ import GLOBALS from 'src/Globals'; import IncomingCall from 'src/components/modals/IncomingCall'; import {ModalsWrapper} from 'src/components/modals/ModalsWrapper'; import DeeplinkContextProvider from 'src/contexts/DeeplinkContext'; +import NotificationContextProvider from 'src/contexts/NotificationContext'; import PushApiContextProvider from 'src/contexts/PushApiContext'; import SheetContextProvider from 'src/contexts/SheetContext'; import ToasterContextProvider from 'src/contexts/ToasterContext'; @@ -45,39 +46,41 @@ const Screens = ({callAccepted}) => { - - {/* Show Modal on Android devices and iOS devices in China */} - {isReceivingCall && - (Platform.OS === 'android' || - (Platform.OS === 'ios' && CallkeepHelper.isChina())) && ( - - )} + + + {/* Show Modal on Android devices and iOS devices in China */} + {isReceivingCall && + (Platform.OS === 'android' || + (Platform.OS === 'ios' && CallkeepHelper.isChina())) && ( + + )} - {authState === GLOBALS.AUTH_STATE.INITIALIZING && ( - - )} - {authState === GLOBALS.AUTH_STATE.ONBOARDING && ( - - )} + {authState === GLOBALS.AUTH_STATE.INITIALIZING && ( + + )} + {authState === GLOBALS.AUTH_STATE.ONBOARDING && ( + + )} - {authState === GLOBALS.AUTH_STATE.ONBOARDED && ( - - )} + {authState === GLOBALS.AUTH_STATE.ONBOARDED && ( + + )} - {authState === GLOBALS.AUTH_STATE.AUTHENTICATED && ( - <> - {connectedUser && ( - - )} - - - - - )} - + {authState === GLOBALS.AUTH_STATE.AUTHENTICATED && ( + <> + {connectedUser && ( + + )} + + + + + )} + + diff --git a/src/navigation/screens/chats/ChatScreen.tsx b/src/navigation/screens/chats/ChatScreen.tsx index 48905b87b..6d0ee3fa3 100644 --- a/src/navigation/screens/chats/ChatScreen.tsx +++ b/src/navigation/screens/chats/ChatScreen.tsx @@ -127,6 +127,11 @@ const ChatScreen = (props: any) => { throw new Error('No user data'); } + console.log( + 'chatData.connectedUserData', + JSON.stringify(chatData.connectedUserData), + ); + return ( { senderAddress, connectedUser, isIntentSendPage, - combinedDID, chatId, feed, title, }: ChatScreenParam = route.params; + console.log('Single chat route', route.params); + const [isIntentReceivePage, setisIntentReceivePage] = useState( route.params.isIntentReceivePage, ); @@ -110,7 +108,6 @@ const SingleChatScreen = ({route}: any) => { connectedUser.privateKey, connectedUser.wallets, senderAddress, - combinedDID, chatId, ); diff --git a/src/navigation/screens/chats/components/SingleChatItem.tsx b/src/navigation/screens/chats/components/SingleChatItem.tsx index 406d66127..8803764d9 100644 --- a/src/navigation/screens/chats/components/SingleChatItem.tsx +++ b/src/navigation/screens/chats/components/SingleChatItem.tsx @@ -56,7 +56,6 @@ const ChatItem = (props: SingleChatItemProps) => { cid: cid, senderAddress: props.wallet, connectedUser: appContext.connectedUser, - combinedDID: props.combinedDID, isIntentReceivePage: isIntenReceivePage, isIntentSendPage: isIntentSendPage, image: props.image, diff --git a/src/navigation/screens/chats/helpers/storage.ts b/src/navigation/screens/chats/helpers/storage.ts index 26e9f2b75..0a231a25a 100644 --- a/src/navigation/screens/chats/helpers/storage.ts +++ b/src/navigation/screens/chats/helpers/storage.ts @@ -31,14 +31,14 @@ export const getPersistedChatData = async (): Promise => { }; const LATEST_HASH = 'LATEST_HASH'; -export const getStoredConversationData = async (combined_did: string) => { +export const getStoredConversationData = async (chatId: string) => { try { const cachedData = await EncryptedStorage.getItem( - `${STORAGE_CONSTANTS.PRIVATE_CHAT}-${combined_did}`, + `${STORAGE_CONSTANTS.PRIVATE_CHAT}-${chatId}`, ); const latestHash = await EncryptedStorage.getItem( - `${STORAGE_CONSTANTS.PRIVATE_CHAT}-${combined_did}-${LATEST_HASH}`, + `${STORAGE_CONSTANTS.PRIVATE_CHAT}-${chatId}-${LATEST_HASH}`, ); if (!cachedData) { @@ -58,30 +58,28 @@ export const getStoredConversationData = async (combined_did: string) => { }; export const storeConversationData = async ( - combined_did: string, + chatId: string, latestHash: string, payload: any | any[], ): Promise => { try { - const [cachedData, lastHash] = await getStoredConversationData( - combined_did, - ); + const [cachedData, lastHash] = await getStoredConversationData(chatId); // when cache is empty store all and return if (cachedData === null || lastHash === null) { await EncryptedStorage.setItem( - `${STORAGE_CONSTANTS.PRIVATE_CHAT}-${combined_did}-${LATEST_HASH}`, + `${STORAGE_CONSTANTS.PRIVATE_CHAT}-${chatId}-${LATEST_HASH}`, latestHash, ); if (Array.isArray(payload)) { await EncryptedStorage.setItem( - `${STORAGE_CONSTANTS.PRIVATE_CHAT}-${combined_did}`, + `${STORAGE_CONSTANTS.PRIVATE_CHAT}-${chatId}`, JSON.stringify(payload), ); } else { await EncryptedStorage.setItem( - `${STORAGE_CONSTANTS.PRIVATE_CHAT}-${combined_did}`, + `${STORAGE_CONSTANTS.PRIVATE_CHAT}-${chatId}`, JSON.stringify([payload]), ); } diff --git a/src/navigation/screens/chats/helpers/useConverstaionLoader.ts b/src/navigation/screens/chats/helpers/useConverstaionLoader.ts index 5248126ba..68a665694 100644 --- a/src/navigation/screens/chats/helpers/useConverstaionLoader.ts +++ b/src/navigation/screens/chats/helpers/useConverstaionLoader.ts @@ -19,7 +19,6 @@ const useConversationLoader = ( pgpPrivateKey: string, userAddress: string, senderAddress: string, - combinedDID: string, chatId: string, ): [ boolean, @@ -176,11 +175,7 @@ const useConversationLoader = ( messageObj, }, ]; - await storeConversationData( - combinedDID, - message.reference, - newMsgs, - ); + await storeConversationData(chatId, message.reference, newMsgs); setChatData(prev => [...newMsgs.reverse(), ...prev]); } }, diff --git a/src/redux/homeSlice.ts b/src/redux/homeSlice.ts deleted file mode 100644 index 800217e88..000000000 --- a/src/redux/homeSlice.ts +++ /dev/null @@ -1,36 +0,0 @@ -import {PayloadAction, createSlice} from '@reduxjs/toolkit'; - -type HomeInitialState = { - notificationReceived: boolean; - notificationOpened: boolean; -}; - -type ReturnTypeHome = {home: HomeInitialState}; - -const initialState: HomeInitialState = { - notificationReceived: false, - notificationOpened: false, -}; - -const homeSlice = createSlice({ - name: 'home', - initialState, - reducers: { - updateNotificationReceived: (state, action: PayloadAction) => { - state.notificationReceived = action.payload; - }, - updateNotificationOpened: (state, action: PayloadAction) => { - state.notificationOpened = action.payload; - }, - }, -}); - -export const {updateNotificationReceived, updateNotificationOpened} = - homeSlice.actions; - -export const selectNotificationReceived = (state: ReturnTypeHome) => - state.home.notificationReceived; -export const selectNotificationOpened = (state: ReturnTypeHome) => - state.home.notificationOpened; - -export default homeSlice.reducer; diff --git a/src/redux/store.js b/src/redux/store.js index 42e9683b1..69541b90b 100644 --- a/src/redux/store.js +++ b/src/redux/store.js @@ -13,7 +13,6 @@ import { import authSlice from './authSlice'; import channelSlice from './channelSlice'; -import homeSlice from './homeSlice'; import modalSlice from './modalSlice'; import videoSlice from './videoSlice'; @@ -21,13 +20,12 @@ const persistConfig = { key: 'root', version: 1, storage: AsyncStorage, - whitelist: ['feed', 'auth'], + whitelist: ['auth'], blacklist: ['video', 'channel', 'modal'], }; const rootReducer = combineReducers({ auth: authSlice, - home: homeSlice, video: videoSlice, channel: channelSlice, modal: modalSlice, From 17863baec2127b6cb2d045767cb88f5d9b0563e0 Mon Sep 17 00:00:00 2001 From: Kushdeep Singh Date: Tue, 17 Dec 2024 18:51:46 +0530 Subject: [PATCH 2/9] DMAPP-135: Code cleaning - Removed unnecessary functions --- src/components/ui/HomeFeed.js | 124 -------------------- src/navigation/screens/chats/ChatScreen.tsx | 5 - 2 files changed, 129 deletions(-) diff --git a/src/components/ui/HomeFeed.js b/src/components/ui/HomeFeed.js index 825d5eff3..abcd3f805 100644 --- a/src/components/ui/HomeFeed.js +++ b/src/components/ui/HomeFeed.js @@ -146,133 +146,9 @@ export default function InboxFeed(props) { } }; - function generateRandomChatSentence() { - const subjects = ['I', 'You', 'We', 'They', 'Someone']; - const verbs = ['love', 'hate', 'enjoy', 'miss', 'think about', 'remember']; - const objects = [ - 'coding', - 'chatting', - 'pizza', - 'movies', - 'nature', - 'music', - ]; - const phrases = [ - 'in the morning.', - 'right now.', - 'every day.', - 'all the time.', - 'on weekends.', - "when I'm alone.", - ]; - const message = [ - 'sent a message', - 'sent a GIF', - 'sent an image', - 'sent a file', - 'replied to a message', - ]; - - const randomElement = arr => arr[Math.floor(Math.random() * arr.length)]; - - const msg = randomElement(message); - - const sentence = `${randomElement(subjects)} ${randomElement( - verbs, - )} ${randomElement(objects)} ${randomElement(phrases)}`; - return msg; - } - - const chatMessage = { - singleChat: (msg, timeStamp) => ({ - collapseKey: 'io.epns.epnsstaging', - data: { - type: 'PUSH_NOTIFICATION_CHAT', - details: JSON.stringify({ - subType: 'INDIVIDUAL_CHAT', - info: { - wallets: '0x9B220a17929Ac119dD3D0711d916e28263dd0D9C', - profilePicture: - 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAuUlEQVR4AcXBMWrDUBBF0avHh+zLjRp9XDrFZGfBTaaIcfndeHVKO3IhEMG8c6bvj+tKMTJ5px5BJcyEmTBrI5Pq9vNLlc8H/xHzQnXJTyphJsyEWeNFPh9UI5OqR7BnZLIRbH2xIcyEmTBrvIh5oRokVcwLewZJFfNCNUgqYSbMhNl0vp9WjISZMBNmjYN6BHtGJkcIM2EmzFqP4IiRyZ4ewRHCTJgJs+l8P60UPYJ3GplUwkyYCbM/Vc0q3B9XBygAAAAASUVORK5CYII=', - chatId: - '248d2886f49bb26e6715b214e063d27c6d57eb16fd0f594ea0cd0f135bfe4cbd', - combinedDID: - 'eip155:0xDcA78D2f7cF9cF40bbC752494Fa41639280FbC3B_eip155:0x9B220a17929Ac119dD3D0711d916e28263dd0D9C', - threadhash: - 'v2:a78b22977759c2a3798a4fbdf78f8f84688198470ae4879c298944bf67267082', //cid - }, - }), - }, - from: '755180533582', - messageId: `0:1732875400813721%841${timeStamp}`, - notification: { - android: { - color: '#e20880', - imageUrl: null, - smallIcon: 'ic_notification', - }, - body: msg, - title: getTrimmedAddress('0x9B220a17929Ac119dD3D0711d916e28263dd0D9C'), - }, - sentTime: timeStamp, - ttl: 2419200, - }), - groupChat: (msg, timeStamp) => ({ - collapseKey: 'io.epns.epnsstaging', - data: { - type: 'PUSH_NOTIFICATION_CHAT', - details: JSON.stringify({ - subType: 'GROUP_CHAT', - info: { - wallets: '0x9B220a17929Ac119dD3D0711d916e28263dd0D9C', - profilePicture: - 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAuUlEQVR4AcXBMWrDUBBF0avHh+zLjRp9XDrFZGfBTaaIcfndeHVKO3IhEMG8c6bvj+tKMTJ5px5BJcyEmTBrI5Pq9vNLlc8H/xHzQnXJTyphJsyEWeNFPh9UI5OqR7BnZLIRbH2xIcyEmTBrvIh5oRokVcwLewZJFfNCNUgqYSbMhNl0vp9WjISZMBNmjYN6BHtGJkcIM2EmzFqP4IiRyZ4ewRHCTJgJs+l8P60UPYJ3GplUwkyYCbM/Vc0q3B9XBygAAAAASUVORK5CYII=', - chatId: - '6bc7bef45a30b033390c060698e72f5a07a416d97db73e1363e171337469f339', - combinedDID: - 'eip155:0xDcA78D2f7cF9cF40bbC752494Fa41639280FbC3B_eip155:0x9B220a17929Ac119dD3D0711d916e28263dd0D9C', - threadhash: - 'v2:aad7f7f9129656e50bed6e5a08f254bf749e4a3de323a2b4fd3e2d188db58ef3', //cid - isRequestAccepted: true, - }, - }), - }, - from: '755180533582', - messageId: `0:1732875400813721%841${timeStamp}`, - notification: { - android: { - color: '#e20880', - imageUrl: null, - smallIcon: 'ic_notification', - }, - body: `${getTrimmedAddress( - '0x9B220a17929Ac119dD3D0711d916e28263dd0D9C', - 4, - )}: ${msg}`, - title: 'Tech Updates', - }, - sentTime: timeStamp, - ttl: 2419200, - }), - }; - const {resolveNotification} = useNotificationsApi(); return ( <> - { - const msg = generateRandomChatSentence(); - const timeStamp = Date.now(); - resolveNotification(chatMessage.groupChat(msg, timeStamp)); - }} - style={{ - padding: 8, - margin: 15, - borderRadius: 10, - backgroundColor: 'yellow', - }}> - Send Test Notification - { throw new Error('No user data'); } - console.log( - 'chatData.connectedUserData', - JSON.stringify(chatData.connectedUserData), - ); - return ( Date: Thu, 19 Dec 2024 15:55:27 +0530 Subject: [PATCH 3/9] DMAPP-135: Integrate push chat notification - Updated Notifee notification configuration for group chat notifications to enhance appearance. - Refactored logic to remove chat notifications upon navigation to the chat history screen. This logic is now handled within the Single Chat component. --- src/components/ui/HomeFeed.js | 3 - src/contexts/NotificationContext.tsx | 41 +++++---- src/helpers/NotificationHelper.ts | 83 +++++++++++-------- .../screens/chats/SingleChatScreen.tsx | 9 +- 4 files changed, 80 insertions(+), 56 deletions(-) diff --git a/src/components/ui/HomeFeed.js b/src/components/ui/HomeFeed.js index abcd3f805..eab2a22fb 100644 --- a/src/components/ui/HomeFeed.js +++ b/src/components/ui/HomeFeed.js @@ -4,8 +4,6 @@ import { RefreshControl, SafeAreaView, StyleSheet, - Text, - TouchableOpacity, View, } from 'react-native'; import ImageView from 'react-native-image-viewing'; @@ -15,7 +13,6 @@ import ImagePreviewFooter from 'src/components/ui/ImagePreviewFooter'; import {useNotificationsApi} from 'src/contexts/NotificationContext'; import {usePushApi} from 'src/contexts/PushApiContext'; import AppBadgeHelper from 'src/helpers/AppBadgeHelper'; -import {getTrimmedAddress} from 'src/navigation/screens/chats/helpers/chatAddressFormatter'; import EmptyFeed from './EmptyFeed'; import NotificationItem from './NotificationItem'; diff --git a/src/contexts/NotificationContext.tsx b/src/contexts/NotificationContext.tsx index 2886f8fb8..548af7736 100644 --- a/src/contexts/NotificationContext.tsx +++ b/src/contexts/NotificationContext.tsx @@ -20,13 +20,14 @@ import { import {usePushApi} from './PushApiContext'; -const NOTIFICATION_TYPES = { +export const NOTIFICATION_TYPES = { CHANNEL: 'PUSH_NOTIFICATION_CHANNEL', CHAT: 'PUSH_NOTIFICATION_CHAT', }; -const NOTIFICATION_SUB_TYPES = { +export const NOTIFICATION_SUB_TYPES = { INBOX: 'INBOX', + SPAM: 'SPAM', INDIVIDUAL_CHAT: 'INDIVIDUAL_CHAT', GROUP_CHAT: 'GROUP_CHAT', }; @@ -46,6 +47,7 @@ type NotificationContextType = { setChannelNotificationReceived: (value: boolean) => void; channelNotificationOpened: boolean; setChannelNotificationOpened: (value: boolean) => void; + removeOpenedChatNotifications: (chatId: string) => void; }; const NotificationContext = createContext({ @@ -57,6 +59,7 @@ const NotificationContext = createContext({ setChannelNotificationReceived: () => {}, channelNotificationOpened: false, setChannelNotificationOpened: () => {}, + removeOpenedChatNotifications: () => {}, }); export const NotificationContextProvider = ({ @@ -83,7 +86,10 @@ export const NotificationContextProvider = ({ useEffect(() => { // Foreground Notifications const unsubscribeOnMessage = messaging().onMessage(async remoteMessage => { - // console.log('Message handled in the foreground!', remoteMessage); + // console.log( + // 'Message handled in the foreground!', + // JSON.stringify(remoteMessage), + // ); if (remoteMessage.notification) { resolveNotification(remoteMessage); } @@ -91,7 +97,10 @@ export const NotificationContextProvider = ({ // Background/Quit state Notifications messaging().setBackgroundMessageHandler(async remoteMessage => { - // console.log('Message handled in the background!', remoteMessage); + // console.log( + // 'Message handled in the background!', + // JSON.stringify(remoteMessage), + // ); }); return () => { @@ -124,9 +133,10 @@ export const NotificationContextProvider = ({ const resolveNotification = async ( remoteMessage: FirebaseMessagingTypes.RemoteMessage, ) => { - if (remoteMessage?.data?.type === NOTIFICATION_TYPES.CHAT) { + const type = remoteMessage?.data?.type; + if (type === NOTIFICATION_TYPES.CHAT) { handleChatNotification(remoteMessage); - } else if (remoteMessage?.data?.type === NOTIFICATION_TYPES.CHANNEL) { + } else if (type === NOTIFICATION_TYPES.CHANNEL) { handleChannelNotification(remoteMessage); } }; @@ -157,9 +167,9 @@ export const NotificationContextProvider = ({ remoteMessage: FirebaseMessagingTypes.RemoteMessage, ) => { // Parse the stringified data - const parsedDetails = remoteMessage.data?.details - ? JSON.parse(remoteMessage.data?.details as string) - : {}; + const parsedDetails = JSON.parse( + (remoteMessage.data?.details as string) || '{}', + ); try { if ( getCurrentRouteName() !== GLOBALS.SCREENS.SINGLE_CHAT || @@ -264,9 +274,7 @@ export const NotificationContextProvider = ({ /************************************************/ const handleNotificationRoute = async (data?: NotificationDataType) => { // Parse the stringified data - const parsedDetails = data?.details - ? JSON.parse(data?.details as string) - : {}; + const parsedDetails = JSON.parse((data?.details as string) || '{}'); // Handle conditional checks to confirm if route navigation & // data needs to be updated after notification opened @@ -285,7 +293,7 @@ export const NotificationContextProvider = ({ } } else if (data?.type === NOTIFICATION_TYPES.CHAT) { // Handle Chat notification banner press - console.log('isChatEnabled===>', isChatEnabled); + // console.log('isChatEnabled===>', isChatEnabled); if (isChatEnabled) { try { // Get navigation params for SINGLE CHAT Screen @@ -304,12 +312,10 @@ export const NotificationContextProvider = ({ if (getCurrentRouteName() === GLOBALS.SCREENS.SINGLE_CHAT) { // If Single chat screen is already active then update params data replaceRoute(GLOBALS.SCREENS.SINGLE_CHAT, singleChatParams); - removeOpenedChatNotifications(parsedDetails?.info?.chatId); setTempNotificationData(null); } else { // Navigate to Single/Group chat screen navigate(GLOBALS.SCREENS.SINGLE_CHAT, singleChatParams); - removeOpenedChatNotifications(parsedDetails?.info?.chatId); setTempNotificationData(null); } } @@ -330,9 +336,7 @@ export const NotificationContextProvider = ({ /*****************************************************/ const handlePostNotificationReceived = (data?: NotificationDataType) => { // Parse the stringified data - const parsedDetails = data?.details - ? JSON.parse(data?.details as string) - : {}; + const parsedDetails = JSON.parse((data?.details as string) || '{}'); // Handle condition check please data needs to be // updated after notification received @@ -356,6 +360,7 @@ export const NotificationContextProvider = ({ setChannelNotificationReceived, channelNotificationOpened, setChannelNotificationOpened, + removeOpenedChatNotifications, }}> {children} diff --git a/src/helpers/NotificationHelper.ts b/src/helpers/NotificationHelper.ts index 5d99ef03c..6d5ec5e21 100644 --- a/src/helpers/NotificationHelper.ts +++ b/src/helpers/NotificationHelper.ts @@ -5,6 +5,10 @@ import { } from '@notifee/react-native'; import {Platform} from 'react-native'; import Globals from 'src/Globals'; +import { + NOTIFICATION_SUB_TYPES, + NOTIFICATION_TYPES, +} from 'src/contexts/NotificationContext'; import {UserChatCredentials} from 'src/navigation/screens/chats/ChatScreen'; import MetaStorage from 'src/singletons/MetaStorage'; @@ -16,10 +20,10 @@ export const NotificationHelper: NotificationHelperType = { remoteMessage, getRecentMessageNotifications, ) => { - const parsedDetails = remoteMessage.data?.details - ? JSON.parse(remoteMessage.data?.details as string) - : {}; - if (type === 'PUSH_NOTIFICATION_CHANNEL') { + const parsedDetails = JSON.parse( + (remoteMessage.data?.details as string) || '{}', + ); + if (type === NOTIFICATION_TYPES.CHANNEL) { const largeIcon = parsedDetails?.info?.icon ?? 'ic_launcher_round'; return { id: remoteMessage.messageId, @@ -49,24 +53,37 @@ export const NotificationHelper: NotificationHelperType = { }, data: remoteMessage.data, }; - } else if (type === 'PUSH_NOTIFICATION_CHAT') { + } else if (type === NOTIFICATION_TYPES.CHAT) { let recentChatNotifications: DisplayedNotification[] = []; let messages: AndroidMessagingStyleMessage[] = []; + let lines: string[] = []; if (Platform.OS === 'android') { recentChatNotifications = await getRecentMessageNotifications( parsedDetails?.info?.chatId, ); - messages = - recentChatNotifications.length > 0 - ? recentChatNotifications?.[0]?.notification?.android?.style - ?.messages - : []; + if (parsedDetails?.subType === NOTIFICATION_SUB_TYPES.INDIVIDUAL_CHAT) { + messages = + recentChatNotifications.length > 0 + ? recentChatNotifications?.[0]?.notification?.android?.style + ?.messages + : []; + + messages.push({ + text: remoteMessage.notification?.body ?? '', + timestamp: remoteMessage.sentTime ?? Date.now(), + }); + } else if ( + parsedDetails?.subType === NOTIFICATION_SUB_TYPES.GROUP_CHAT + ) { + lines = + recentChatNotifications.length > 0 + ? recentChatNotifications?.[0]?.notification?.android?.style + ?.lines + : []; - messages.push({ - text: remoteMessage.notification?.body ?? '', - timestamp: remoteMessage.sentTime ?? Date.now(), - }); + lines.push(remoteMessage.notification?.body ?? ''); + } } return { id: @@ -102,17 +119,17 @@ export const NotificationHelper: NotificationHelperType = { pressAction: { id: 'default', }, - style: { - type: AndroidStyle.MESSAGING, - person: { - name: remoteMessage.notification?.title ?? '', - icon: - parsedDetails?.subType === 'GROUP_CHAT' - ? 'ic_launcher_round' - : parsedDetails?.info?.profilePicture, - }, - messages, - }, + style: + parsedDetails?.subType === NOTIFICATION_SUB_TYPES.GROUP_CHAT + ? {type: AndroidStyle.INBOX, lines} + : { + type: AndroidStyle.MESSAGING, + person: { + name: remoteMessage.notification?.title ?? '', + icon: parsedDetails?.info?.profilePicture, + }, + messages, + }, }, data: remoteMessage.data, }; @@ -142,10 +159,10 @@ export const NotificationHelper: NotificationHelperType = { if (isGroupConversation) { const groupInformationResponse = await userPushSDKInstance?.chat.group.info(chatId); - console.log( - 'groupInformationResponse', - JSON.stringify(groupInformationResponse), - ); + // console.log( + // 'groupInformationResponse', + // JSON.stringify(groupInformationResponse), + // ); groupInformation = { groupName: groupInformationResponse?.groupName, groupImage: groupInformationResponse?.groupImage, @@ -156,10 +173,10 @@ export const NotificationHelper: NotificationHelperType = { let isIntentReceivePage = false; const conversationHashResponse: any = await userPushSDKInstance?.chat.latest(chatId); - console.log( - 'conversationHashResponse', - JSON.stringify(conversationHashResponse), - ); + // console.log( + // 'conversationHashResponse', + // JSON.stringify(conversationHashResponse), + // ); if (conversationHashResponse?.length > 0) { isIntentReceivePage = conversationHashResponse?.[0]?.listType !== 'CHATS'; diff --git a/src/navigation/screens/chats/SingleChatScreen.tsx b/src/navigation/screens/chats/SingleChatScreen.tsx index 2aa2eec0c..cc2d33d86 100644 --- a/src/navigation/screens/chats/SingleChatScreen.tsx +++ b/src/navigation/screens/chats/SingleChatScreen.tsx @@ -34,6 +34,7 @@ import Globals from 'src/Globals'; import {ConnectedUser} from 'src/apis'; import {Toaster} from 'src/components/indicators/Toaster'; import {ToasterOptions} from 'src/components/indicators/Toaster'; +import {useNotificationsApi} from 'src/contexts/NotificationContext'; import {usePushApi} from 'src/contexts/PushApiContext'; import {VideoCallContext} from 'src/contexts/VideoContext'; import {caip10ToWallet} from 'src/helpers/CAIPHelper'; @@ -77,8 +78,6 @@ const SingleChatScreen = ({route}: any) => { title, }: ChatScreenParam = route.params; - console.log('Single chat route', route.params); - const [isIntentReceivePage, setisIntentReceivePage] = useState( route.params.isIntentReceivePage, ); @@ -118,6 +117,12 @@ const SingleChatScreen = ({route}: any) => { toastRef.current ? toastRef.current.showToast : null, ); + const {removeOpenedChatNotifications} = useNotificationsApi(); + + useEffect(() => { + removeOpenedChatNotifications(chatId); + }, [chatId]); + const dispatch = useDispatch(); const senderAddressFormatted = senderAddress From 93826a75d3504500d0b11d7d27f76878c5b3b630 Mon Sep 17 00:00:00 2001 From: Kushdeep Singh Date: Mon, 23 Dec 2024 17:27:39 +0530 Subject: [PATCH 4/9] DMAPP-135: Integrate chat notification - Upgraded Firebase App, Messaging, and Notifee versions to fix the iOS native notification issue. - [System level]: Updated Android configuration to require JVM 17 for compatibility. - [Fix]: Resolved issue where the unlock profile modal was appearing after notification press even when the profile was already unlocked. - Made minor adjustments to Notifee display notification configuration. --- index.js | 41 +- ios/Podfile.lock | 174 ++--- package.json | 6 +- src/contexts/NotificationContext.tsx | 33 +- src/helpers/NotificationHelper.ts | 17 +- src/helpers/ServerHelper.js | 2 +- src/helpers/helpers.types.ts | 2 +- src/navigation/AuthenticatedNavigator.js | 5 +- yarn.lock | 892 ++++++++++++++++++++--- 9 files changed, 917 insertions(+), 255 deletions(-) diff --git a/index.js b/index.js index 8546abf67..ac0a1eff2 100644 --- a/index.js +++ b/index.js @@ -5,31 +5,33 @@ import RNCallKeep from 'react-native-callkeep'; import 'react-native-crypto'; import 'react-native-get-random-values'; import CallKeepHelper from 'src/helpers/CallkeepHelper'; -import {NotificationHelper} from 'src/helpers/NotificationHelper'; import {NotifeClearBadge} from 'src/notifee'; import {getUUID} from 'src/push_video/payloads/helpers'; import MetaStorage from 'src/singletons/MetaStorage'; import 'text-encoding'; -import {stringify} from 'uuid'; import App from './App'; import {name as appName} from './app.json'; import './shim'; +/***************************************************/ +/** Uncomment below commented code if video call **/ +/** feature is enabled in the app **/ +/***************************************************/ let isCallAccepted = false; // this is supposed to be called wiz -if (AppState.currentState !== 'active' && Platform.OS === 'android') { - RNCallKeep.addEventListener('answerCall', async ({callUUID}) => { - CallKeepHelper.backToForeground(); - CallKeepHelper.endAllCall(); - isCallAccepted = true; - MetaStorage.instance.setBackgroundCallAccepted(false); - }); - RNCallKeep.addEventListener('endCall', async ({callUUID}) => { - CallKeepHelper.endAllCall(); - }); -} +// if (AppState.currentState !== 'active' && Platform.OS === 'android') { +// RNCallKeep.addEventListener('answerCall', async ({callUUID}) => { +// CallKeepHelper.backToForeground(); +// CallKeepHelper.endAllCall(); +// isCallAccepted = true; +// MetaStorage.instance.setBackgroundCallAccepted(false); +// }); +// RNCallKeep.addEventListener('endCall', async ({callUUID}) => { +// CallKeepHelper.endAllCall(); +// }); +// } function HeadlessCheck({isHeadless}) { useEffect(() => { @@ -44,24 +46,13 @@ function HeadlessCheck({isHeadless}) { return ; } -// -------------------------------------- -// Uncomment the code below if the video call feature is enabled. -// -------------------------------------- // if (Platform.OS === 'android') { // CallKeepHelper.setupCallKeep(); // RNCallKeep.setAvailable(true); // } -/************************************************/ -/** Listeners used to display notifee **/ -/** and native notification **/ -/************************************************/ // messaging().setBackgroundMessageHandler(async remoteMessage => { -// console.log('Message handled in the background!', remoteMessage); -/***************************************************/ -/** Uncomment below commented code if video call **/ -/** feature is enabled in the app **/ -/***************************************************/ +// console.log('Message handled in the background!', remoteMessage); // if (Platform.OS === 'android' && CallKeepHelper.isVideoCall(remoteMessage)) { // const caller = CallKeepHelper.getCaller(remoteMessage); // const addressTrimmed = CallKeepHelper.formatEthAddress(caller); diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 4c9319b78..e9582a7d2 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -53,33 +53,33 @@ PODS: - React-Core (= 0.71.14) - React-jsi (= 0.71.14) - ReactCommon/turbomodule/core (= 0.71.14) - - Firebase/CoreOnly (10.15.0): - - FirebaseCore (= 10.15.0) - - Firebase/Messaging (10.15.0): + - Firebase/CoreOnly (11.5.0): + - FirebaseCore (= 11.5.0) + - Firebase/Messaging (11.5.0): - Firebase/CoreOnly - - FirebaseMessaging (~> 10.15.0) - - FirebaseCore (10.15.0): - - FirebaseCoreInternal (~> 10.0) - - GoogleUtilities/Environment (~> 7.8) - - GoogleUtilities/Logger (~> 7.8) - - FirebaseCoreExtension (10.15.0): - - FirebaseCore (~> 10.0) - - FirebaseCoreInternal (10.16.0): - - "GoogleUtilities/NSData+zlib (~> 7.8)" - - FirebaseInstallations (10.16.0): - - FirebaseCore (~> 10.0) - - GoogleUtilities/Environment (~> 7.8) - - GoogleUtilities/UserDefaults (~> 7.8) - - PromisesObjC (~> 2.1) - - FirebaseMessaging (10.15.0): - - FirebaseCore (~> 10.0) - - FirebaseInstallations (~> 10.0) - - GoogleDataTransport (~> 9.2) - - GoogleUtilities/AppDelegateSwizzler (~> 7.8) - - GoogleUtilities/Environment (~> 7.8) - - GoogleUtilities/Reachability (~> 7.8) - - GoogleUtilities/UserDefaults (~> 7.8) - - nanopb (< 2.30910.0, >= 2.30908.0) + - FirebaseMessaging (~> 11.5.0) + - FirebaseCore (11.5.0): + - FirebaseCoreInternal (= 11.5) + - GoogleUtilities/Environment (~> 8.0) + - GoogleUtilities/Logger (~> 8.0) + - FirebaseCoreExtension (11.5.0): + - FirebaseCore (= 11.5) + - FirebaseCoreInternal (11.5.0): + - "GoogleUtilities/NSData+zlib (~> 8.0)" + - FirebaseInstallations (11.5.0): + - FirebaseCore (= 11.5) + - GoogleUtilities/Environment (~> 8.0) + - GoogleUtilities/UserDefaults (~> 8.0) + - PromisesObjC (~> 2.4) + - FirebaseMessaging (11.5.0): + - FirebaseCore (= 11.5) + - FirebaseInstallations (~> 11.0) + - GoogleDataTransport (~> 10.0) + - GoogleUtilities/AppDelegateSwizzler (~> 8.0) + - GoogleUtilities/Environment (~> 8.0) + - GoogleUtilities/Reachability (~> 8.0) + - GoogleUtilities/UserDefaults (~> 8.0) + - nanopb (~> 3.30910.0) - fmt (6.2.1) - Giphy (2.2.7): - libwebp @@ -88,43 +88,49 @@ PODS: - RCT-Folly (= 2021.07.22.00) - React-Core - glog (0.3.5) - - GoogleDataTransport (9.2.5): - - GoogleUtilities/Environment (~> 7.7) - - nanopb (< 2.30910.0, >= 2.30908.0) - - PromisesObjC (< 3.0, >= 1.2) - - GoogleUtilities (7.11.5): - - GoogleUtilities/AppDelegateSwizzler (= 7.11.5) - - GoogleUtilities/Environment (= 7.11.5) - - GoogleUtilities/ISASwizzler (= 7.11.5) - - GoogleUtilities/Logger (= 7.11.5) - - GoogleUtilities/MethodSwizzler (= 7.11.5) - - GoogleUtilities/Network (= 7.11.5) - - "GoogleUtilities/NSData+zlib (= 7.11.5)" - - GoogleUtilities/Reachability (= 7.11.5) - - GoogleUtilities/SwizzlerTestHelpers (= 7.11.5) - - GoogleUtilities/UserDefaults (= 7.11.5) - - GoogleUtilities/AppDelegateSwizzler (7.11.5): + - GoogleDataTransport (10.1.0): + - nanopb (~> 3.30910.0) + - PromisesObjC (~> 2.4) + - GoogleUtilities (8.0.2): + - GoogleUtilities/AppDelegateSwizzler (= 8.0.2) + - GoogleUtilities/Environment (= 8.0.2) + - GoogleUtilities/Logger (= 8.0.2) + - GoogleUtilities/MethodSwizzler (= 8.0.2) + - GoogleUtilities/Network (= 8.0.2) + - "GoogleUtilities/NSData+zlib (= 8.0.2)" + - GoogleUtilities/Privacy (= 8.0.2) + - GoogleUtilities/Reachability (= 8.0.2) + - GoogleUtilities/SwizzlerTestHelpers (= 8.0.2) + - GoogleUtilities/UserDefaults (= 8.0.2) + - GoogleUtilities/AppDelegateSwizzler (8.0.2): - GoogleUtilities/Environment - GoogleUtilities/Logger - GoogleUtilities/Network - - GoogleUtilities/Environment (7.11.5): - - PromisesObjC (< 3.0, >= 1.2) - - GoogleUtilities/ISASwizzler (7.11.5) - - GoogleUtilities/Logger (7.11.5): + - GoogleUtilities/Privacy + - GoogleUtilities/Environment (8.0.2): + - GoogleUtilities/Privacy + - GoogleUtilities/Logger (8.0.2): - GoogleUtilities/Environment - - GoogleUtilities/MethodSwizzler (7.11.5): + - GoogleUtilities/Privacy + - GoogleUtilities/MethodSwizzler (8.0.2): - GoogleUtilities/Logger - - GoogleUtilities/Network (7.11.5): + - GoogleUtilities/Privacy + - GoogleUtilities/Network (8.0.2): - GoogleUtilities/Logger - "GoogleUtilities/NSData+zlib" + - GoogleUtilities/Privacy - GoogleUtilities/Reachability - - "GoogleUtilities/NSData+zlib (7.11.5)" - - GoogleUtilities/Reachability (7.11.5): + - "GoogleUtilities/NSData+zlib (8.0.2)": + - GoogleUtilities/Privacy + - GoogleUtilities/Privacy (8.0.2) + - GoogleUtilities/Reachability (8.0.2): - GoogleUtilities/Logger - - GoogleUtilities/SwizzlerTestHelpers (7.11.5): + - GoogleUtilities/Privacy + - GoogleUtilities/SwizzlerTestHelpers (8.0.2): - GoogleUtilities/MethodSwizzler - - GoogleUtilities/UserDefaults (7.11.5): + - GoogleUtilities/UserDefaults (8.0.2): - GoogleUtilities/Logger + - GoogleUtilities/Privacy - hermes-engine (0.71.14): - hermes-engine/Pre-built (= 0.71.14) - hermes-engine/Pre-built (0.71.14) @@ -146,14 +152,14 @@ PODS: - lottie-react-native (6.7.2): - lottie-ios (= 4.4.1) - React-Core - - nanopb (2.30909.0): - - nanopb/decode (= 2.30909.0) - - nanopb/encode (= 2.30909.0) - - nanopb/decode (2.30909.0) - - nanopb/encode (2.30909.0) - - PromisesObjC (2.3.1) - - PromisesSwift (2.3.1): - - PromisesObjC (= 2.3.1) + - nanopb (3.30910.0): + - nanopb/decode (= 3.30910.0) + - nanopb/encode (= 3.30910.0) + - nanopb/decode (3.30910.0) + - nanopb/encode (3.30910.0) + - PromisesObjC (2.4.0) + - PromisesSwift (2.4.0): + - PromisesObjC (= 2.4.0) - RCT-Folly (2021.07.22.00): - boost - DoubleConversion @@ -552,12 +558,12 @@ PODS: - React-Core - RNCMaskedView (0.1.11): - React - - RNFBApp (18.6.0): - - Firebase/CoreOnly (= 10.15.0) + - RNFBApp (21.6.1): + - Firebase/CoreOnly (= 11.5.0) - React-Core - - RNFBMessaging (18.6.0): - - Firebase/Messaging (= 10.15.0) - - FirebaseCoreExtension (= 10.15.0) + - RNFBMessaging (21.6.1): + - Firebase/Messaging (= 11.5.0) + - FirebaseCoreExtension - React-Core - RNFBApp - RNFlashList (1.6.3): @@ -568,10 +574,10 @@ PODS: - React-Core - RNLocalize (3.0.2): - React-Core - - RNNotifee (7.8.2): + - RNNotifee (9.1.8): - React-Core - - RNNotifee/NotifeeCore (= 7.8.2) - - RNNotifee/NotifeeCore (7.8.2): + - RNNotifee/NotifeeCore (= 9.1.8) + - RNNotifee/NotifeeCore (9.1.8): - React-Core - RNOS (1.2.6): - React @@ -591,7 +597,7 @@ PODS: - React - Toast (4.0.0) - Yoga (1.14.0) - - YoutubePlayer-in-WKWebView (0.3.8) + - YoutubePlayer-in-WKWebView (0.3.11) - ZXingObjC/Core (3.6.9) - ZXingObjC/OneD (3.6.9): - ZXingObjC/Core @@ -923,27 +929,27 @@ SPEC CHECKSUMS: EXSharing: 09839ace249f61bfa13c50c6a28256c31d260355 FBLazyVector: 12ea01e587c9594e7b144e1bfc86ac4d9ac28fde FBReactNativeSpec: b6ae48e67aaba46442f84d6f9ba598ccfbe2ee66 - Firebase: 66043bd4579e5b73811f96829c694c7af8d67435 - FirebaseCore: 2cec518b43635f96afe7ac3a9c513e47558abd2e - FirebaseCoreExtension: d3f1ea3725fb41f56e8fbfb29eeaff54e7ffb8f6 - FirebaseCoreInternal: 26233f705cc4531236818a07ac84d20c333e505a - FirebaseInstallations: b822f91a61f7d1ba763e5ccc9d4f2e6f2ed3b3ee - FirebaseMessaging: 0c0ae1eb722ef0c07f7801e5ded8dccd1357d6d4 + Firebase: 7a56fe4f56b5ab81b86a6822f5b8f909ae6fc7e2 + FirebaseCore: 93abc05437f8064cd2bc0a53b768fb0bc5a1d006 + FirebaseCoreExtension: ddb2eb987f736b714d30f6386795b52c4670439e + FirebaseCoreInternal: f47dd28ae7782e6a4738aad3106071a8fe0af604 + FirebaseInstallations: d8063d302a426d114ac531cd82b1e335a0565745 + FirebaseMessaging: 9f4e42053241bd45ce8565c881bfdd9c1df2f7da fmt: ff9d55029c625d3757ed641535fd4a75fedc7ce9 Giphy: dad025aa0c82e4c057e1989cde959034829dfca7 giphy-react-native-sdk: f4fbdae92e3e8f8ef26b1af694141cb29d0e033a glog: 04b94705f318337d7ead9e6d17c019bd9b1f6b1b - GoogleDataTransport: 54dee9d48d14580407f8f5fbf2f496e92437a2f2 - GoogleUtilities: 13e2c67ede716b8741c7989e26893d151b2b2084 + GoogleDataTransport: aae35b7ea0c09004c3797d53c8c41f66f219d6a7 + GoogleUtilities: 26a3abef001b6533cf678d3eb38fd3f614b7872d hermes-engine: d7cc127932c89c53374452d6f93473f1970d8e88 JitsiWebRTC: 80f62908fcf2a1160e0d14b584323fb6e6be630b libevent: 4049cae6c81cdb3654a443be001fb9bdceff7913 libwebp: 1786c9f4ff8a279e4dac1e8f385004d5fc253009 lottie-ios: e047b1d2e6239b787cc5e9755b988869cf190494 lottie-react-native: 17547b2f3c7034e2ae8672833fdb63262164d18a - nanopb: b552cce312b6c8484180ef47159bc0f65a1f0431 - PromisesObjC: c50d2056b5253dadbd6c2bea79b0674bd5a52fa4 - PromisesSwift: 28dca69a9c40779916ac2d6985a0192a5cb4a265 + nanopb: fad817b59e0457d11a5dfbde799381cd727c1275 + PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47 + PromisesSwift: 9d77319bbe72ebf6d872900551f7eeba9bce2851 RCT-Folly: 424b8c9a7a0b9ab2886ffe9c3b041ef628fd4fb1 RCTRequired: e9df143e880d0e879e7a498dc06923d728809c79 RCTTypeSafety: c2d89c8308829c12c038ec1f431191eaa0d8c15c @@ -994,13 +1000,13 @@ SPEC CHECKSUMS: RNCAsyncStorage: 8616bd5a58af409453ea4e1b246521bb76578d60 RNCClipboard: 2834e1c4af68697089cdd455ee4a4cdd198fa7dd RNCMaskedView: 0e1bc4bfa8365eba5fbbb71e07fbdc0555249489 - RNFBApp: 29a81c55c97887851fe2d8180293e0c618523d02 - RNFBMessaging: 534bab7d0527d560cd1a35e74223735b4ed1eeee + RNFBApp: a3c9c3b23aa2d77001ce62b5a997325927593c12 + RNFBMessaging: dd213f66f36b249f9ab035efe24dc2a3ede8f8c5 RNFlashList: 4b4b6b093afc0df60ae08f9cbf6ccd4c836c667a RNGestureHandler: 071d7a9ad81e8b83fe7663b303d132406a7d8f39 RNKeychain: ff836453cba46938e0e9e4c22e43d43fa2c90333 RNLocalize: dbea38dcb344bf80ff18a1757b1becf11f70cae4 - RNNotifee: 8e2d3df3f0e9ce8f5d1fe4c967431138190b6175 + RNNotifee: 4a6ee5c7deaf00e005050052d73ee6315dff7ec9 RNOS: 6f2f9a70895bbbfbdad7196abd952e7b01d45027 RNReanimated: 2dc3707222fa153658386f4c0d357e0853327c3d RNScreens: 80369e822c4f123c3f076c9ea4141991c17770f9 @@ -1009,7 +1015,7 @@ SPEC CHECKSUMS: TcpSockets: 14306fb79f9750ea7d2ddd02d8bed182abb01797 Toast: 91b396c56ee72a5790816f40d3a94dd357abc196 Yoga: e71803b4c1fff832ccf9b92541e00f9b873119b9 - YoutubePlayer-in-WKWebView: 4fca3b4f6f09940077bfbae7bddb771f2b43aacd + YoutubePlayer-in-WKWebView: 2c3aa1d5ad8dded9f95ef12033af5dd8e55864b7 ZXingObjC: 8898711ab495761b2dbbdec76d90164a6d7e14c5 PODFILE CHECKSUM: 513a83d172d501d70c66336e88f9d25b0365cf4f diff --git a/package.json b/package.json index 64e8b38d6..711f2528f 100644 --- a/package.json +++ b/package.json @@ -29,15 +29,15 @@ "@giphy/react-native-sdk": "^3.2.0", "@gorhom/bottom-sheet": "^4", "@metamask/eth-sig-util": "^5.0.0", - "@notifee/react-native": "^7.8.2", + "@notifee/react-native": "^9.1.8", "@pushprotocol/restapi": "^1.7.28", "@pushprotocol/socket": "latest", "@react-native-async-storage/async-storage": "1.17.11", "@react-native-clipboard/clipboard": "^1.11.1", "@react-native-community/masked-view": "^0.1.11", "@react-native-community/netinfo": "^11.3.1", - "@react-native-firebase/app": "^18.6.0", - "@react-native-firebase/messaging": "^18.6.0", + "@react-native-firebase/app": "^21.6.1", + "@react-native-firebase/messaging": "^21.6.1", "@react-navigation/bottom-tabs": "^6.5.19", "@react-navigation/native": "^6.0.12", "@react-navigation/stack": "^6.2.3", diff --git a/src/contexts/NotificationContext.tsx b/src/contexts/NotificationContext.tsx index 548af7736..db09e4662 100644 --- a/src/contexts/NotificationContext.tsx +++ b/src/contexts/NotificationContext.tsx @@ -6,7 +6,7 @@ import notifee, { import messaging, { FirebaseMessagingTypes, } from '@react-native-firebase/messaging'; -import React, {createContext, useEffect, useState} from 'react'; +import React, {createContext, useEffect, useRef, useState} from 'react'; import {Platform} from 'react-native'; import GLOBALS from 'src/Globals'; import {NotificationHelper} from 'src/helpers/NotificationHelper'; @@ -70,6 +70,8 @@ export const NotificationContextProvider = ({ const {isChatEnabled} = usePushApiMode(); const {showUnlockProfileModal, userPushSDKInstance} = usePushApi(); + const isChatEnabledRef = useRef(isChatEnabled); + const [tempNotificationData, setTempNotificationData] = useState(null); const [channelNotificationReceived, setChannelNotificationReceived] = @@ -78,30 +80,22 @@ export const NotificationContextProvider = ({ useState(false); useEffect(() => { + isChatEnabledRef.current = isChatEnabled; if (isChatEnabled && tempNotificationData) { - handleNotificationRoute(tempNotificationData); + handleNotificationRoute(tempNotificationData, true); } }, [isChatEnabled]); useEffect(() => { // Foreground Notifications const unsubscribeOnMessage = messaging().onMessage(async remoteMessage => { - // console.log( - // 'Message handled in the foreground!', - // JSON.stringify(remoteMessage), - // ); if (remoteMessage.notification) { resolveNotification(remoteMessage); } }); - // Background/Quit state Notifications - messaging().setBackgroundMessageHandler(async remoteMessage => { - // console.log( - // 'Message handled in the background!', - // JSON.stringify(remoteMessage), - // ); - }); + // Background Notifications + messaging().setBackgroundMessageHandler(async remoteMessage => {}); return () => { unsubscribeOnMessage(); @@ -246,7 +240,9 @@ export const NotificationContextProvider = ({ messaging().onNotificationOpenedApp( async (remoteMessage: FirebaseMessagingTypes.RemoteMessage) => { - handleNotificationRoute(remoteMessage.data); + if (remoteMessage) { + handleNotificationRoute(remoteMessage.data); + } }, ); @@ -272,7 +268,10 @@ export const NotificationContextProvider = ({ /************************************************/ /** Handle notification routes and data **/ /************************************************/ - const handleNotificationRoute = async (data?: NotificationDataType) => { + const handleNotificationRoute = async ( + data?: NotificationDataType, + canAccessChat?: boolean, + ) => { // Parse the stringified data const parsedDetails = JSON.parse((data?.details as string) || '{}'); @@ -293,8 +292,8 @@ export const NotificationContextProvider = ({ } } else if (data?.type === NOTIFICATION_TYPES.CHAT) { // Handle Chat notification banner press - // console.log('isChatEnabled===>', isChatEnabled); - if (isChatEnabled) { + const resolvedCanAccessChat = canAccessChat ?? isChatEnabledRef.current; // Use ref for default + if (resolvedCanAccessChat) { try { // Get navigation params for SINGLE CHAT Screen const isGroupConversation = diff --git a/src/helpers/NotificationHelper.ts b/src/helpers/NotificationHelper.ts index 6d5ec5e21..e125af6de 100644 --- a/src/helpers/NotificationHelper.ts +++ b/src/helpers/NotificationHelper.ts @@ -12,6 +12,7 @@ import { import {UserChatCredentials} from 'src/navigation/screens/chats/ChatScreen'; import MetaStorage from 'src/singletons/MetaStorage'; +import {caip10ToWallet} from './CAIPHelper'; import {GroupInformation, NotificationHelperType} from './helpers.types'; export const NotificationHelper: NotificationHelperType = { @@ -126,7 +127,11 @@ export const NotificationHelper: NotificationHelperType = { type: AndroidStyle.MESSAGING, person: { name: remoteMessage.notification?.title ?? '', - icon: parsedDetails?.info?.profilePicture, + icon: + parsedDetails?.info?.profilePicture && + parsedDetails?.info?.profilePicture?.length > 0 + ? parsedDetails?.info?.profilePicture + : 'default', }, messages, }, @@ -159,10 +164,6 @@ export const NotificationHelper: NotificationHelperType = { if (isGroupConversation) { const groupInformationResponse = await userPushSDKInstance?.chat.group.info(chatId); - // console.log( - // 'groupInformationResponse', - // JSON.stringify(groupInformationResponse), - // ); groupInformation = { groupName: groupInformationResponse?.groupName, groupImage: groupInformationResponse?.groupImage, @@ -173,10 +174,6 @@ export const NotificationHelper: NotificationHelperType = { let isIntentReceivePage = false; const conversationHashResponse: any = await userPushSDKInstance?.chat.latest(chatId); - // console.log( - // 'conversationHashResponse', - // JSON.stringify(conversationHashResponse), - // ); if (conversationHashResponse?.length > 0) { isIntentReceivePage = conversationHashResponse?.[0]?.listType !== 'CHATS'; @@ -190,7 +187,7 @@ export const NotificationHelper: NotificationHelperType = { wallets: connectedUser.wallet, privateKey: pgpPrivateKey, }, - senderAddress: wallets, + senderAddress: isGroupConversation ? null : caip10ToWallet(wallets), image: isGroupConversation ? groupInformation?.groupImage : profilePicture, diff --git a/src/helpers/ServerHelper.js b/src/helpers/ServerHelper.js index 19b11cd32..9bc92e02b 100644 --- a/src/helpers/ServerHelper.js +++ b/src/helpers/ServerHelper.js @@ -25,7 +25,7 @@ const ServerHelper = { if (Platform.OS === 'ios' && apnsToken !== '') { // iOS device, need to register the token on the server - console.log('apns token is', apnsToken); + // console.log('apns token is', apnsToken); body.apn_token = apnsToken; } diff --git a/src/helpers/helpers.types.ts b/src/helpers/helpers.types.ts index 6d553683e..6ada6b0f9 100644 --- a/src/helpers/helpers.types.ts +++ b/src/helpers/helpers.types.ts @@ -35,7 +35,7 @@ export type ChatNavigationParams = { export type ReturnChatNavigationParams = { cid: string; - senderAddress: string; + senderAddress: string | null; connectedUser: any; isIntentReceivePage: boolean; isIntentSendPage: boolean; diff --git a/src/navigation/AuthenticatedNavigator.js b/src/navigation/AuthenticatedNavigator.js index 8c716793c..5e1e7f585 100644 --- a/src/navigation/AuthenticatedNavigator.js +++ b/src/navigation/AuthenticatedNavigator.js @@ -24,10 +24,7 @@ export default function AuthenticatedNavigator() { const {handleNotificationEvents} = useNotificationsApi(); useEffect(() => { - let eventTimeout = setTimeout(() => handleNotificationEvents(), 800); - return () => { - clearTimeout(eventTimeout); - }; + handleNotificationEvents(); }, []); return ( diff --git a/yarn.lock b/yarn.lock index f6bb82663..b433e8c8f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3483,6 +3483,534 @@ __metadata: languageName: node linkType: hard +"@firebase/analytics-compat@npm:0.2.14": + version: 0.2.14 + resolution: "@firebase/analytics-compat@npm:0.2.14" + dependencies: + "@firebase/analytics": "npm:0.10.8" + "@firebase/analytics-types": "npm:0.8.2" + "@firebase/component": "npm:0.6.9" + "@firebase/util": "npm:1.10.0" + tslib: "npm:^2.1.0" + peerDependencies: + "@firebase/app-compat": 0.x + checksum: 10/0e368159d24223076b488b27308c11e5ef50456aff49fc58e1f66616228021c61e60c3299f63ce52ddc2f7099d803e9048bc28cd952cf5c302917002c03c85ee + languageName: node + linkType: hard + +"@firebase/analytics-types@npm:0.8.2": + version: 0.8.2 + resolution: "@firebase/analytics-types@npm:0.8.2" + checksum: 10/297fb7becbc51950c7de5809fed896c391d1e87b4d8bb4bf88f4e8760b2e32f903a7dd8e92de4424b49c4e2ecb60a44d49e2f9c68ac3f7ffe3a0194f78910392 + languageName: node + linkType: hard + +"@firebase/analytics@npm:0.10.8": + version: 0.10.8 + resolution: "@firebase/analytics@npm:0.10.8" + dependencies: + "@firebase/component": "npm:0.6.9" + "@firebase/installations": "npm:0.6.9" + "@firebase/logger": "npm:0.4.2" + "@firebase/util": "npm:1.10.0" + tslib: "npm:^2.1.0" + peerDependencies: + "@firebase/app": 0.x + checksum: 10/152ddaf68146f02baa7060d34426c25ec13890a53942ffa2db09faa148bef35f59ee9810e6fb8f561fb3d115b71d1fb9fb111d2a0f0199aa510220782557c765 + languageName: node + linkType: hard + +"@firebase/app-check-compat@npm:0.3.15": + version: 0.3.15 + resolution: "@firebase/app-check-compat@npm:0.3.15" + dependencies: + "@firebase/app-check": "npm:0.8.8" + "@firebase/app-check-types": "npm:0.5.2" + "@firebase/component": "npm:0.6.9" + "@firebase/logger": "npm:0.4.2" + "@firebase/util": "npm:1.10.0" + tslib: "npm:^2.1.0" + peerDependencies: + "@firebase/app-compat": 0.x + checksum: 10/ae541d324d5f91dbb7b479855d3380c4fe73e365013b80973a54620405093e6fd2f8e418549155b3a527530472a19b6edf6df1481a708f823eba42e376105b28 + languageName: node + linkType: hard + +"@firebase/app-check-interop-types@npm:0.3.2": + version: 0.3.2 + resolution: "@firebase/app-check-interop-types@npm:0.3.2" + checksum: 10/3effe656a4762c541838f4bde91b4498e51d48389046b930dc3dbb012e54b6ab0727f7c68a3e94198f633d57833346fc337a0847b6b03d2407030e1489d466fe + languageName: node + linkType: hard + +"@firebase/app-check-types@npm:0.5.2": + version: 0.5.2 + resolution: "@firebase/app-check-types@npm:0.5.2" + checksum: 10/2b33a7adfb7b6ebf5423940bf0af5909df69bf2d6184e12e989f6c76062077be16c31193795349862b4f8aab6b3059806b732a92995cae30fd77419f19a86c6e + languageName: node + linkType: hard + +"@firebase/app-check@npm:0.8.8": + version: 0.8.8 + resolution: "@firebase/app-check@npm:0.8.8" + dependencies: + "@firebase/component": "npm:0.6.9" + "@firebase/logger": "npm:0.4.2" + "@firebase/util": "npm:1.10.0" + tslib: "npm:^2.1.0" + peerDependencies: + "@firebase/app": 0.x + checksum: 10/a3676f2143c8e438d7e8ac11bb163af30880f6ce6acc5cc54cfcc214b8efd5dabce14c040626f8a64a3967db144b99834f1108c2076a0eae8a6baf864b5a3d77 + languageName: node + linkType: hard + +"@firebase/app-compat@npm:0.2.41": + version: 0.2.41 + resolution: "@firebase/app-compat@npm:0.2.41" + dependencies: + "@firebase/app": "npm:0.10.11" + "@firebase/component": "npm:0.6.9" + "@firebase/logger": "npm:0.4.2" + "@firebase/util": "npm:1.10.0" + tslib: "npm:^2.1.0" + checksum: 10/67e4b0572a3c24c4acc13e2c3b55a4fc778d286bae10f1df684a142c9790b4f131519fe84087341884bd67b04b822c3f7092b9748dfa3b52086b6f82ca8a1001 + languageName: node + linkType: hard + +"@firebase/app-types@npm:0.9.2": + version: 0.9.2 + resolution: "@firebase/app-types@npm:0.9.2" + checksum: 10/566b3714a4d7e8180514258e4b1549bf5b28ae0383b4ff53d3532a45e114048afdd27c1fef8688d871dd9e5ad5307e749776e23f094122655ac6b0fb550eb11a + languageName: node + linkType: hard + +"@firebase/app@npm:0.10.11": + version: 0.10.11 + resolution: "@firebase/app@npm:0.10.11" + dependencies: + "@firebase/component": "npm:0.6.9" + "@firebase/logger": "npm:0.4.2" + "@firebase/util": "npm:1.10.0" + idb: "npm:7.1.1" + tslib: "npm:^2.1.0" + checksum: 10/529d9e59b39e96cd97a8402e1cee508dbbb962aa1805345dc902ecbfe61709bb46ab3b821cd3b50b3d2e3e9f898515eb91cded030492e376550a97518cbcdb70 + languageName: node + linkType: hard + +"@firebase/auth-compat@npm:0.5.14": + version: 0.5.14 + resolution: "@firebase/auth-compat@npm:0.5.14" + dependencies: + "@firebase/auth": "npm:1.7.9" + "@firebase/auth-types": "npm:0.12.2" + "@firebase/component": "npm:0.6.9" + "@firebase/util": "npm:1.10.0" + tslib: "npm:^2.1.0" + undici: "npm:6.19.7" + peerDependencies: + "@firebase/app-compat": 0.x + checksum: 10/85d5259e7b04b14b5d02dc1fb19b015d742c594c14138f33f13146ed9f6caa7ed9d19d65bb99aaca57e70ffd2a491e520d8638eadefbd00f839d37ef972cbbda + languageName: node + linkType: hard + +"@firebase/auth-interop-types@npm:0.2.3": + version: 0.2.3 + resolution: "@firebase/auth-interop-types@npm:0.2.3" + checksum: 10/e55b8ded6bd1a5e6a2845c9c7ed520bb9a8a76e4ddf90249bf685986ac7b1fb079be2fa4edcb6a3aa81d1d56870a470eadcd5a8f20b797dccd803d72ed4c80aa + languageName: node + linkType: hard + +"@firebase/auth-types@npm:0.12.2": + version: 0.12.2 + resolution: "@firebase/auth-types@npm:0.12.2" + peerDependencies: + "@firebase/app-types": 0.x + "@firebase/util": 1.x + checksum: 10/f55449381de8e2a24ffaf19f12b5c4a093c8323034253ea7a5f7afc946327d20b09f32a483c12960862a1c4814645ea80bc4343f0a9f22db5dc048ca82773132 + languageName: node + linkType: hard + +"@firebase/auth@npm:1.7.9": + version: 1.7.9 + resolution: "@firebase/auth@npm:1.7.9" + dependencies: + "@firebase/component": "npm:0.6.9" + "@firebase/logger": "npm:0.4.2" + "@firebase/util": "npm:1.10.0" + tslib: "npm:^2.1.0" + undici: "npm:6.19.7" + peerDependencies: + "@firebase/app": 0.x + "@react-native-async-storage/async-storage": ^1.18.1 + peerDependenciesMeta: + "@react-native-async-storage/async-storage": + optional: true + checksum: 10/010013ec339c9ef7b4d9278c6cacfd8e2eb3282f27a3e4e89c42a5968955976a26277421f34fda3e9400409a22a61f632bcc03e713b3f39d71e4777bc003165d + languageName: node + linkType: hard + +"@firebase/component@npm:0.6.9": + version: 0.6.9 + resolution: "@firebase/component@npm:0.6.9" + dependencies: + "@firebase/util": "npm:1.10.0" + tslib: "npm:^2.1.0" + checksum: 10/76c865d640e4b24a0e50876ecdc0e1199df38af562131a937b5a4bac924d61b6933339afb7906881dca509f38f3b0c511cd6b5008e061424c61b20876de9531e + languageName: node + linkType: hard + +"@firebase/database-compat@npm:1.0.8": + version: 1.0.8 + resolution: "@firebase/database-compat@npm:1.0.8" + dependencies: + "@firebase/component": "npm:0.6.9" + "@firebase/database": "npm:1.0.8" + "@firebase/database-types": "npm:1.0.5" + "@firebase/logger": "npm:0.4.2" + "@firebase/util": "npm:1.10.0" + tslib: "npm:^2.1.0" + checksum: 10/28389efcc87da77b822cb27c31707824fe98e7b0a3bf9cbf2b0c0fccd9edd72e2681a9467b76b120281464dbfc814852ebca63d99a385a9cb68fb55c7b334105 + languageName: node + linkType: hard + +"@firebase/database-types@npm:1.0.5": + version: 1.0.5 + resolution: "@firebase/database-types@npm:1.0.5" + dependencies: + "@firebase/app-types": "npm:0.9.2" + "@firebase/util": "npm:1.10.0" + checksum: 10/bdf667da0369dce8623987fc01cad8db09cfe1895130f69ab581d34a0ee043ca6113c32457629147ae1441a934d985ede9d7cbe104ac346de6d0c21629903a8b + languageName: node + linkType: hard + +"@firebase/database@npm:1.0.8": + version: 1.0.8 + resolution: "@firebase/database@npm:1.0.8" + dependencies: + "@firebase/app-check-interop-types": "npm:0.3.2" + "@firebase/auth-interop-types": "npm:0.2.3" + "@firebase/component": "npm:0.6.9" + "@firebase/logger": "npm:0.4.2" + "@firebase/util": "npm:1.10.0" + faye-websocket: "npm:0.11.4" + tslib: "npm:^2.1.0" + checksum: 10/adb199a6ad7866b418e8b319cc505e108bfc8200b5406f21857706df0849d4e5982a1b0e44e07001821edebef73c4dfffc7f96fb77a2cff10bb9ac26f17d40c3 + languageName: node + linkType: hard + +"@firebase/firestore-compat@npm:0.3.37": + version: 0.3.37 + resolution: "@firebase/firestore-compat@npm:0.3.37" + dependencies: + "@firebase/component": "npm:0.6.9" + "@firebase/firestore": "npm:4.7.2" + "@firebase/firestore-types": "npm:3.0.2" + "@firebase/util": "npm:1.10.0" + tslib: "npm:^2.1.0" + peerDependencies: + "@firebase/app-compat": 0.x + checksum: 10/c152ba401f0d786699b25e1101d77351b7a6503f1a1f774efa7fecacc66aec58aca58a7b54e3f8587fcb45ffa3772d5e123ae79ddd90d0a87f2042ac34880d8a + languageName: node + linkType: hard + +"@firebase/firestore-types@npm:3.0.2": + version: 3.0.2 + resolution: "@firebase/firestore-types@npm:3.0.2" + peerDependencies: + "@firebase/app-types": 0.x + "@firebase/util": 1.x + checksum: 10/81e91f836a026ecb70937407ca8699add7abb5b050d8815620cde97c3eec3f78f7dfbb366225758909f0df31d9f21e98a84ba62701bd27ee38b2609898c11acd + languageName: node + linkType: hard + +"@firebase/firestore@npm:4.7.2": + version: 4.7.2 + resolution: "@firebase/firestore@npm:4.7.2" + dependencies: + "@firebase/component": "npm:0.6.9" + "@firebase/logger": "npm:0.4.2" + "@firebase/util": "npm:1.10.0" + "@firebase/webchannel-wrapper": "npm:1.0.1" + "@grpc/grpc-js": "npm:~1.9.0" + "@grpc/proto-loader": "npm:^0.7.8" + tslib: "npm:^2.1.0" + undici: "npm:6.19.7" + peerDependencies: + "@firebase/app": 0.x + checksum: 10/066a125760bc2163bbc9c6fcde8b3f67da97791f8ce6f5ffa8ff3c40567aff97b2fe02020c3403857f104f051e4d6452aee60fe75ed5e408e467c611c397b4bb + languageName: node + linkType: hard + +"@firebase/functions-compat@npm:0.3.14": + version: 0.3.14 + resolution: "@firebase/functions-compat@npm:0.3.14" + dependencies: + "@firebase/component": "npm:0.6.9" + "@firebase/functions": "npm:0.11.8" + "@firebase/functions-types": "npm:0.6.2" + "@firebase/util": "npm:1.10.0" + tslib: "npm:^2.1.0" + peerDependencies: + "@firebase/app-compat": 0.x + checksum: 10/a8d6cbcdc646d78adecfcdc1f8fa14a5d9af2394dd69cac00c6826106b923e01d246c67fb7e09025ca7cfb876f8d5df97240cc056c64ccee8899ca5f17178a6c + languageName: node + linkType: hard + +"@firebase/functions-types@npm:0.6.2": + version: 0.6.2 + resolution: "@firebase/functions-types@npm:0.6.2" + checksum: 10/5b8733f9d4bd85a617d35dd10ce296d9ec0490494e584697c4eda8098ff1e865607d7880b84194e86c35d438bbcd714977c111180502d0d1b6b2da1cde1b37ca + languageName: node + linkType: hard + +"@firebase/functions@npm:0.11.8": + version: 0.11.8 + resolution: "@firebase/functions@npm:0.11.8" + dependencies: + "@firebase/app-check-interop-types": "npm:0.3.2" + "@firebase/auth-interop-types": "npm:0.2.3" + "@firebase/component": "npm:0.6.9" + "@firebase/messaging-interop-types": "npm:0.2.2" + "@firebase/util": "npm:1.10.0" + tslib: "npm:^2.1.0" + undici: "npm:6.19.7" + peerDependencies: + "@firebase/app": 0.x + checksum: 10/44f3e42df189f3f3cb3c366b38e93a0ffdfaa1a7b3f6dba624bcd9a7cda3d3271df66f2769b7cbe7e1e5ff01bf6ab3bef6c1e1e15c6646e34514d1e2ebb60555 + languageName: node + linkType: hard + +"@firebase/installations-compat@npm:0.2.9": + version: 0.2.9 + resolution: "@firebase/installations-compat@npm:0.2.9" + dependencies: + "@firebase/component": "npm:0.6.9" + "@firebase/installations": "npm:0.6.9" + "@firebase/installations-types": "npm:0.5.2" + "@firebase/util": "npm:1.10.0" + tslib: "npm:^2.1.0" + peerDependencies: + "@firebase/app-compat": 0.x + checksum: 10/919e1a4f4b63f5fe757a3c9cefb4a36cbab92deb4a6e15f249c94d6e80d1c6d37e5e384a460af8c17fc88e3091594bf43d036c88b704516c279b5ab8401977e1 + languageName: node + linkType: hard + +"@firebase/installations-types@npm:0.5.2": + version: 0.5.2 + resolution: "@firebase/installations-types@npm:0.5.2" + peerDependencies: + "@firebase/app-types": 0.x + checksum: 10/2e795280c299d644b8c8e3fdfa5c6f20cb367dd3b7df32317211f84393fa169b33dee0cbed28de407f3b22dc8f1fb2f7a11ae5a373f8082cc570ef61ef6b91ba + languageName: node + linkType: hard + +"@firebase/installations@npm:0.6.9": + version: 0.6.9 + resolution: "@firebase/installations@npm:0.6.9" + dependencies: + "@firebase/component": "npm:0.6.9" + "@firebase/util": "npm:1.10.0" + idb: "npm:7.1.1" + tslib: "npm:^2.1.0" + peerDependencies: + "@firebase/app": 0.x + checksum: 10/349c8b7e877b002fb29f274f4d239fbca4c2c266ccb66ecfb5f1762f973a7fe1be99cc3346184d1230e6e35feb2b6f9e8b7169479fa0018b53e4a83837848619 + languageName: node + linkType: hard + +"@firebase/logger@npm:0.4.2": + version: 0.4.2 + resolution: "@firebase/logger@npm:0.4.2" + dependencies: + tslib: "npm:^2.1.0" + checksum: 10/961b4605220c0a56c5f3ccf4e6049e44c27303c1ca998c6fa1d19de785c76d93e3b1a3da455e9f40655711345d8d779912366e4f369d93eda8d08c407cc5b140 + languageName: node + linkType: hard + +"@firebase/messaging-compat@npm:0.2.11": + version: 0.2.11 + resolution: "@firebase/messaging-compat@npm:0.2.11" + dependencies: + "@firebase/component": "npm:0.6.9" + "@firebase/messaging": "npm:0.12.11" + "@firebase/util": "npm:1.10.0" + tslib: "npm:^2.1.0" + peerDependencies: + "@firebase/app-compat": 0.x + checksum: 10/8ace6d65adcf891b272875b7b3f43978a15644b23f7ee796346f02eb50007c20c99719f4991772911005697613bf122167ca150d8245d0fccb2b959472b4a625 + languageName: node + linkType: hard + +"@firebase/messaging-interop-types@npm:0.2.2": + version: 0.2.2 + resolution: "@firebase/messaging-interop-types@npm:0.2.2" + checksum: 10/547f8ebf2c5a8dcbc484991b97d76bd3dc3eb4bd9d4e6ea2ffc652097c7065d92dc68d389ddb19fba41e0ce3b5f4cd757ed22f96b4744801149b0f8dbf323af7 + languageName: node + linkType: hard + +"@firebase/messaging@npm:0.12.11": + version: 0.12.11 + resolution: "@firebase/messaging@npm:0.12.11" + dependencies: + "@firebase/component": "npm:0.6.9" + "@firebase/installations": "npm:0.6.9" + "@firebase/messaging-interop-types": "npm:0.2.2" + "@firebase/util": "npm:1.10.0" + idb: "npm:7.1.1" + tslib: "npm:^2.1.0" + peerDependencies: + "@firebase/app": 0.x + checksum: 10/1de21d56c74996e99151a902e0f1ff0825d47ebff044104483a838ff5cb4883433b2f541616b033255e4fd2780b29f71982d8832edf4987c101df97ed508828a + languageName: node + linkType: hard + +"@firebase/performance-compat@npm:0.2.9": + version: 0.2.9 + resolution: "@firebase/performance-compat@npm:0.2.9" + dependencies: + "@firebase/component": "npm:0.6.9" + "@firebase/logger": "npm:0.4.2" + "@firebase/performance": "npm:0.6.9" + "@firebase/performance-types": "npm:0.2.2" + "@firebase/util": "npm:1.10.0" + tslib: "npm:^2.1.0" + peerDependencies: + "@firebase/app-compat": 0.x + checksum: 10/bc4e8b0208c9bc603518e1388713ec80658ee109c6af80d429479447ccb85e8e831269383233c379ed66bf37469d13f5c234074d0c0c9e7e69e909be5fdeca4f + languageName: node + linkType: hard + +"@firebase/performance-types@npm:0.2.2": + version: 0.2.2 + resolution: "@firebase/performance-types@npm:0.2.2" + checksum: 10/d25ae06cb75ab6b44ffacf7affadc1f651881f283e58381c444eb63b62dfb74c33c544ab89843518ec1d15367ba7c4343b4d6b22de1f1df35126a1283baa578d + languageName: node + linkType: hard + +"@firebase/performance@npm:0.6.9": + version: 0.6.9 + resolution: "@firebase/performance@npm:0.6.9" + dependencies: + "@firebase/component": "npm:0.6.9" + "@firebase/installations": "npm:0.6.9" + "@firebase/logger": "npm:0.4.2" + "@firebase/util": "npm:1.10.0" + tslib: "npm:^2.1.0" + peerDependencies: + "@firebase/app": 0.x + checksum: 10/d682d0b1e342ed3eda1a5ddab39c8ddac33afc9edb2c7335a2f9a28eb8c268b975bbf450a3bad5443138edebaf2aa731dca0b774bcf3211a6dc215b35d86d849 + languageName: node + linkType: hard + +"@firebase/remote-config-compat@npm:0.2.9": + version: 0.2.9 + resolution: "@firebase/remote-config-compat@npm:0.2.9" + dependencies: + "@firebase/component": "npm:0.6.9" + "@firebase/logger": "npm:0.4.2" + "@firebase/remote-config": "npm:0.4.9" + "@firebase/remote-config-types": "npm:0.3.2" + "@firebase/util": "npm:1.10.0" + tslib: "npm:^2.1.0" + peerDependencies: + "@firebase/app-compat": 0.x + checksum: 10/a6db7509512d8d22b7ddf1127c741715e379e04e5b3246372bb0302d7c84afb421a94550adebecddcce5def115d61729a9580940dce6e65f8d77f9af30f69fe1 + languageName: node + linkType: hard + +"@firebase/remote-config-types@npm:0.3.2": + version: 0.3.2 + resolution: "@firebase/remote-config-types@npm:0.3.2" + checksum: 10/6c91599c653825708aba9fe9e4562997f108c3e4f3eaf5d188f31c859a6ad013414aa7a213b6b021b68049dd0dd57158546dbc9fb64384652274ef7f57ce7d7d + languageName: node + linkType: hard + +"@firebase/remote-config@npm:0.4.9": + version: 0.4.9 + resolution: "@firebase/remote-config@npm:0.4.9" + dependencies: + "@firebase/component": "npm:0.6.9" + "@firebase/installations": "npm:0.6.9" + "@firebase/logger": "npm:0.4.2" + "@firebase/util": "npm:1.10.0" + tslib: "npm:^2.1.0" + peerDependencies: + "@firebase/app": 0.x + checksum: 10/f14189f38c8cf75db16bf8b85dd004486b1dd8242f62d697c716fa85cd32928aed549ccea8c632a528870a424fc7f04f1132a14b3b099276cd7696c78e644b28 + languageName: node + linkType: hard + +"@firebase/storage-compat@npm:0.3.12": + version: 0.3.12 + resolution: "@firebase/storage-compat@npm:0.3.12" + dependencies: + "@firebase/component": "npm:0.6.9" + "@firebase/storage": "npm:0.13.2" + "@firebase/storage-types": "npm:0.8.2" + "@firebase/util": "npm:1.10.0" + tslib: "npm:^2.1.0" + peerDependencies: + "@firebase/app-compat": 0.x + checksum: 10/4eea49a57f1d7537da697e5ff8b4e035ff1af69e416e7eab14485753c39c25eaa5a71bd2bafba0985ac6a7ce803f98f2f2f83c613c78c8f74bce286e3259b8ec + languageName: node + linkType: hard + +"@firebase/storage-types@npm:0.8.2": + version: 0.8.2 + resolution: "@firebase/storage-types@npm:0.8.2" + peerDependencies: + "@firebase/app-types": 0.x + "@firebase/util": 1.x + checksum: 10/e00716932370d2004dc9f7ef6d7e3aff72305b91569fa6ec15e8bc2ec784b03a150391e8be2c063234edbbfda7796da915d48e26ce2f1f7c5d3343acd39afd99 + languageName: node + linkType: hard + +"@firebase/storage@npm:0.13.2": + version: 0.13.2 + resolution: "@firebase/storage@npm:0.13.2" + dependencies: + "@firebase/component": "npm:0.6.9" + "@firebase/util": "npm:1.10.0" + tslib: "npm:^2.1.0" + undici: "npm:6.19.7" + peerDependencies: + "@firebase/app": 0.x + checksum: 10/d887f80cf95ef5daa80ffb2e6d564d25abb8a3e84099bee9730c95082597a12028bbf73bfe66fca2df3cdf04eaadea8e9d74ec0a826f946bc8f002293a9983ea + languageName: node + linkType: hard + +"@firebase/util@npm:1.10.0": + version: 1.10.0 + resolution: "@firebase/util@npm:1.10.0" + dependencies: + tslib: "npm:^2.1.0" + checksum: 10/eb161f1c6294ff097f3c40236820e9e6e29cd6582e5e1254148157143272493580535ee2cb9e7c6055d3909b3ef39d8b64086895b071c665827acb66742b63eb + languageName: node + linkType: hard + +"@firebase/vertexai-preview@npm:0.0.4": + version: 0.0.4 + resolution: "@firebase/vertexai-preview@npm:0.0.4" + dependencies: + "@firebase/app-check-interop-types": "npm:0.3.2" + "@firebase/component": "npm:0.6.9" + "@firebase/logger": "npm:0.4.2" + "@firebase/util": "npm:1.10.0" + tslib: "npm:^2.1.0" + peerDependencies: + "@firebase/app": 0.x + "@firebase/app-types": 0.x + checksum: 10/8ec48d81f48aebdcc63b65d802c67bf36880f256e5c2f5f3b152dc91c8c0e924053fba2fac5218716612f8ee720b25d0822337a214f16f5b7e51ce0247dfc4e5 + languageName: node + linkType: hard + +"@firebase/webchannel-wrapper@npm:1.0.1": + version: 1.0.1 + resolution: "@firebase/webchannel-wrapper@npm:1.0.1" + checksum: 10/22fc7e1e6dd36ab7c13f3a6c1ff51f4d405304424dc323cb146109e7a3ab3b592e2ddb29f53197ee5719a8448cdedb98d9e86a080f9365e389f8429b1c6555c2 + languageName: node + linkType: hard + "@gar/promisify@npm:^1.0.1": version: 1.1.3 resolution: "@gar/promisify@npm:1.1.3" @@ -3553,6 +4081,30 @@ __metadata: languageName: node linkType: hard +"@grpc/grpc-js@npm:~1.9.0": + version: 1.9.15 + resolution: "@grpc/grpc-js@npm:1.9.15" + dependencies: + "@grpc/proto-loader": "npm:^0.7.8" + "@types/node": "npm:>=12.12.47" + checksum: 10/edd45c5970046ebb1bb54856f22a41186742c77dfb7e5182ca615f690f1a320af3abeef553d8924812d56911157a04882c7d264c2de64f326f8df7d473c47b2a + languageName: node + linkType: hard + +"@grpc/proto-loader@npm:^0.7.8": + version: 0.7.13 + resolution: "@grpc/proto-loader@npm:0.7.13" + dependencies: + lodash.camelcase: "npm:^4.3.0" + long: "npm:^5.0.0" + protobufjs: "npm:^7.2.5" + yargs: "npm:^17.7.2" + bin: + proto-loader-gen-types: build/bin/proto-loader-gen-types.js + checksum: 10/7e2d842c2061cbaf6450c71da0077263be3bab165454d5c8a3e1ae4d3c6d2915f02fd27da63ff01f05e127b1221acd40705273f5d29303901e60514e852992f4 + languageName: node + linkType: hard + "@hapi/hoek@npm:^9.0.0": version: 9.3.0 resolution: "@hapi/hoek@npm:9.3.0" @@ -4124,12 +4676,12 @@ __metadata: languageName: node linkType: hard -"@notifee/react-native@npm:^7.8.2": - version: 7.8.2 - resolution: "@notifee/react-native@npm:7.8.2" +"@notifee/react-native@npm:^9.1.8": + version: 9.1.8 + resolution: "@notifee/react-native@npm:9.1.8" peerDependencies: react-native: "*" - checksum: 10/fcb3bc5bd379d6bbde2aa85c394c4f444c3b27f322866480723f96221dfe4d24ba7ea7c9a514fd8968e4aef05adefba714d9c735064459eecd143fd334b79cff + checksum: 10/7c5237fba99906d8da02146afbfe8ff6de9f4047eecd806dea889bfd76b1cfe7ad3c181881bf2729aa348b83e035f4d02cfc3ac8eb8c4ba3a4415b445b439c38 languageName: node linkType: hard @@ -4182,6 +4734,79 @@ __metadata: languageName: node linkType: hard +"@protobufjs/aspromise@npm:^1.1.1, @protobufjs/aspromise@npm:^1.1.2": + version: 1.1.2 + resolution: "@protobufjs/aspromise@npm:1.1.2" + checksum: 10/8a938d84fe4889411296db66b29287bd61ea3c14c2d23e7a8325f46a2b8ce899857c5f038d65d7641805e6c1d06b495525c7faf00c44f85a7ee6476649034969 + languageName: node + linkType: hard + +"@protobufjs/base64@npm:^1.1.2": + version: 1.1.2 + resolution: "@protobufjs/base64@npm:1.1.2" + checksum: 10/c71b100daeb3c9bdccab5cbc29495b906ba0ae22ceedc200e1ba49717d9c4ab15a6256839cebb6f9c6acae4ed7c25c67e0a95e734f612b258261d1a3098fe342 + languageName: node + linkType: hard + +"@protobufjs/codegen@npm:^2.0.4": + version: 2.0.4 + resolution: "@protobufjs/codegen@npm:2.0.4" + checksum: 10/c6ee5fa172a8464f5253174d3c2353ea520c2573ad7b6476983d9b1346f4d8f2b44aa29feb17a949b83c1816bc35286a5ea265ed9d8fdd2865acfa09668c0447 + languageName: node + linkType: hard + +"@protobufjs/eventemitter@npm:^1.1.0": + version: 1.1.0 + resolution: "@protobufjs/eventemitter@npm:1.1.0" + checksum: 10/03af3e99f17ad421283d054c88a06a30a615922a817741b43ca1b13e7c6b37820a37f6eba9980fb5150c54dba6e26cb6f7b64a6f7d8afa83596fafb3afa218c3 + languageName: node + linkType: hard + +"@protobufjs/fetch@npm:^1.1.0": + version: 1.1.0 + resolution: "@protobufjs/fetch@npm:1.1.0" + dependencies: + "@protobufjs/aspromise": "npm:^1.1.1" + "@protobufjs/inquire": "npm:^1.1.0" + checksum: 10/67ae40572ad536e4ef94269199f252c024b66e3059850906bdaee161ca1d75c73d04d35cd56f147a8a5a079f5808e342b99e61942c1dae15604ff0600b09a958 + languageName: node + linkType: hard + +"@protobufjs/float@npm:^1.0.2": + version: 1.0.2 + resolution: "@protobufjs/float@npm:1.0.2" + checksum: 10/634c2c989da0ef2f4f19373d64187e2a79f598c5fb7991afb689d29a2ea17c14b796b29725945fa34b9493c17fb799e08ac0a7ccaae460ee1757d3083ed35187 + languageName: node + linkType: hard + +"@protobufjs/inquire@npm:^1.1.0": + version: 1.1.0 + resolution: "@protobufjs/inquire@npm:1.1.0" + checksum: 10/c09efa34a5465cb120775e1a482136f2340a58b4abce7e93d72b8b5a9324a0e879275016ef9fcd73d72a4731639c54f2bb755bb82f916e4a78892d1d840bb3d2 + languageName: node + linkType: hard + +"@protobufjs/path@npm:^1.1.2": + version: 1.1.2 + resolution: "@protobufjs/path@npm:1.1.2" + checksum: 10/bb709567935fd385a86ad1f575aea98131bbd719c743fb9b6edd6b47ede429ff71a801cecbd64fc72deebf4e08b8f1bd8062793178cdaed3713b8d15771f9b83 + languageName: node + linkType: hard + +"@protobufjs/pool@npm:^1.1.0": + version: 1.1.0 + resolution: "@protobufjs/pool@npm:1.1.0" + checksum: 10/b9c7047647f6af28e92aac54f6f7c1f7ff31b201b4bfcc7a415b2861528854fce3ec666d7e7e10fd744da905f7d4aef2205bbcc8944ca0ca7a82e18134d00c46 + languageName: node + linkType: hard + +"@protobufjs/utf8@npm:^1.1.0": + version: 1.1.0 + resolution: "@protobufjs/utf8@npm:1.1.0" + checksum: 10/131e289c57534c1d73a0e55782d6751dd821db1583cb2f7f7e017c9d6747addaebe79f28120b2e0185395d990aad347fb14ffa73ef4096fa38508d61a0e64602 + languageName: node + linkType: hard + "@pushprotocol/restapi@npm:^1.7.28": version: 1.7.28 resolution: "@pushprotocol/restapi@npm:1.7.28" @@ -4507,12 +5132,11 @@ __metadata: languageName: node linkType: hard -"@react-native-firebase/app@npm:^18.6.0": - version: 18.6.0 - resolution: "@react-native-firebase/app@npm:18.6.0" +"@react-native-firebase/app@npm:^21.6.1": + version: 21.6.1 + resolution: "@react-native-firebase/app@npm:21.6.1" dependencies: - opencollective-postinstall: "npm:^2.0.3" - superstruct: "npm:^0.6.2" + firebase: "npm:10.13.2" peerDependencies: expo: ">=47.0.0" react: "*" @@ -4520,16 +5144,20 @@ __metadata: peerDependenciesMeta: expo: optional: true - checksum: 10/22b498a3937ccfd18b6770e045b48f32992e1a0e42da7ad4b1093cc1eab62aa028fb63979bac18d05cb4c476da6aeef916689c463b8b5ce326941bdd5b62b47a + checksum: 10/10d217f5d809a2b6247b331c8a046181cbb02d80279a281dece61a8c9421c9920bbbe40d4eafcf30e0befad3c25ea5dd0f976b6275b3e7ce164c932784b2710f languageName: node linkType: hard -"@react-native-firebase/messaging@npm:^18.6.0": - version: 18.6.0 - resolution: "@react-native-firebase/messaging@npm:18.6.0" +"@react-native-firebase/messaging@npm:^21.6.1": + version: 21.6.1 + resolution: "@react-native-firebase/messaging@npm:21.6.1" peerDependencies: - "@react-native-firebase/app": 18.6.0 - checksum: 10/3f31d04792108e74c0995ee6edaa3e3a41de13f27c0f86d1b8c604d70776ff0fb4324c35c280cff4190a241fdc9b1f19f0fa51585cf6ceff7be275e6057f5bf5 + "@react-native-firebase/app": 21.6.1 + expo: ">=47.0.0" + peerDependenciesMeta: + expo: + optional: true + checksum: 10/f8aaf726bf4cb5db37dc06a232593e6c4f5fc7a1c0d11f77c36632f8ba283669758c971ba84106a880633309877fce8205ed10e7fcbdcd8b87c40b39556020ba languageName: node linkType: hard @@ -5205,6 +5833,15 @@ __metadata: languageName: node linkType: hard +"@types/node@npm:>=12.12.47, @types/node@npm:>=13.7.0": + version: 22.10.2 + resolution: "@types/node@npm:22.10.2" + dependencies: + undici-types: "npm:~6.20.0" + checksum: 10/451adfefed4add58b069407173e616220fd4aaa3307cdde1bb701aa053b65b54ced8483db2f870dcedec7a58cb3b06101fbc19d85852716672ec1fd3660947fa + languageName: node + linkType: hard + "@types/node@npm:^12.12.6": version: 12.20.55 resolution: "@types/node@npm:12.20.55" @@ -7737,18 +8374,6 @@ __metadata: languageName: node linkType: hard -"clone-deep@npm:^2.0.1": - version: 2.0.2 - resolution: "clone-deep@npm:2.0.2" - dependencies: - for-own: "npm:^1.0.0" - is-plain-object: "npm:^2.0.4" - kind-of: "npm:^6.0.0" - shallow-clone: "npm:^1.0.0" - checksum: 10/c33ae31e332cdfd477a8115c9d044984eb69bf009fce3e1f0ff002176652f572d8742aa5e6caeaf16cf5d6084e33fe51bfa482fec53f43e767b3518c797955b1 - languageName: node - linkType: hard - "clone-deep@npm:^4.0.1": version: 4.0.1 resolution: "clone-deep@npm:4.0.1" @@ -10362,6 +10987,15 @@ __metadata: languageName: node linkType: hard +"faye-websocket@npm:0.11.4": + version: 0.11.4 + resolution: "faye-websocket@npm:0.11.4" + dependencies: + websocket-driver: "npm:>=0.5.1" + checksum: 10/22433c14c60925e424332d2794463a8da1c04848539b5f8db5fced62a7a7c71a25335a4a8b37334e3a32318835e2b87b1733d008561964121c4a0bd55f0878c3 + languageName: node + linkType: hard + "fb-watchman@npm:^2.0.0": version: 2.0.2 resolution: "fb-watchman@npm:2.0.2" @@ -10537,6 +11171,41 @@ __metadata: languageName: node linkType: hard +"firebase@npm:10.13.2": + version: 10.13.2 + resolution: "firebase@npm:10.13.2" + dependencies: + "@firebase/analytics": "npm:0.10.8" + "@firebase/analytics-compat": "npm:0.2.14" + "@firebase/app": "npm:0.10.11" + "@firebase/app-check": "npm:0.8.8" + "@firebase/app-check-compat": "npm:0.3.15" + "@firebase/app-compat": "npm:0.2.41" + "@firebase/app-types": "npm:0.9.2" + "@firebase/auth": "npm:1.7.9" + "@firebase/auth-compat": "npm:0.5.14" + "@firebase/database": "npm:1.0.8" + "@firebase/database-compat": "npm:1.0.8" + "@firebase/firestore": "npm:4.7.2" + "@firebase/firestore-compat": "npm:0.3.37" + "@firebase/functions": "npm:0.11.8" + "@firebase/functions-compat": "npm:0.3.14" + "@firebase/installations": "npm:0.6.9" + "@firebase/installations-compat": "npm:0.2.9" + "@firebase/messaging": "npm:0.12.11" + "@firebase/messaging-compat": "npm:0.2.11" + "@firebase/performance": "npm:0.6.9" + "@firebase/performance-compat": "npm:0.2.9" + "@firebase/remote-config": "npm:0.4.9" + "@firebase/remote-config-compat": "npm:0.2.9" + "@firebase/storage": "npm:0.13.2" + "@firebase/storage-compat": "npm:0.3.12" + "@firebase/util": "npm:1.10.0" + "@firebase/vertexai-preview": "npm:0.0.4" + checksum: 10/c91a047b34f3e2a0b0f563a4b9b4aca4887c0052f82819384acc482c1523c83c108d47eb8a96aa2adce94e07d0f9eeabbd7fd4d2b4fde1e2706fb90a6aea2db1 + languageName: node + linkType: hard + "flat-cache@npm:^3.0.4": version: 3.0.4 resolution: "flat-cache@npm:3.0.4" @@ -10601,29 +11270,6 @@ __metadata: languageName: node linkType: hard -"for-in@npm:^0.1.3": - version: 0.1.8 - resolution: "for-in@npm:0.1.8" - checksum: 10/f5bdad7811700ee6a0f96b33d72a1db966aea75a1f03c7245d147f8369305e709f53a55ee7ae8eaddcfa85c7c89bca78472be8f1bc605475ce5bb2c70f77f8da - languageName: node - linkType: hard - -"for-in@npm:^1.0.1": - version: 1.0.2 - resolution: "for-in@npm:1.0.2" - checksum: 10/09f4ae93ce785d253ac963d94c7f3432d89398bf25ac7a24ed034ca393bf74380bdeccc40e0f2d721a895e54211b07c8fad7132e8157827f6f7f059b70b4043d - languageName: node - linkType: hard - -"for-own@npm:^1.0.0": - version: 1.0.0 - resolution: "for-own@npm:1.0.0" - dependencies: - for-in: "npm:^1.0.1" - checksum: 10/233238f6e9060f61295a7f7c7e3e9de11aaef57e82a108e7f350dc92ae84fe2189848077ac4b8db47fd8edd45337ed8d9f66bd0b1efa4a6a1b3f38aa21b7ab2e - languageName: node - linkType: hard - "foreach@npm:~2.0.1": version: 2.0.6 resolution: "foreach@npm:2.0.6" @@ -11466,6 +12112,13 @@ __metadata: languageName: node linkType: hard +"http-parser-js@npm:>=0.5.1": + version: 0.5.8 + resolution: "http-parser-js@npm:0.5.8" + checksum: 10/2a78a567ee6366dae0129d819b799dce1f95ec9732c5ab164a78ee69804ffb984abfa0660274e94e890fc54af93546eb9f12b6d10edbaed017e2d41c29b7cf29 + languageName: node + linkType: hard + "http-proxy-agent@npm:^4.0.1": version: 4.0.1 resolution: "http-proxy-agent@npm:4.0.1" @@ -11579,6 +12232,13 @@ __metadata: languageName: node linkType: hard +"idb@npm:7.1.1": + version: 7.1.1 + resolution: "idb@npm:7.1.1" + checksum: 10/8e33eaebf21055129864acb89932e0739b8c96788e559df24c253ce114d8c6deb977a3b30ea47a9bb8a2ae8a55964861c3df65f360d95745e341cee40d5c17f4 + languageName: node + linkType: hard + "idna-uts46-hx@npm:^2.3.1": version: 2.3.1 resolution: "idna-uts46-hx@npm:2.3.1" @@ -11958,13 +12618,6 @@ __metadata: languageName: node linkType: hard -"is-extendable@npm:^0.1.1": - version: 0.1.1 - resolution: "is-extendable@npm:0.1.1" - checksum: 10/3875571d20a7563772ecc7a5f36cb03167e9be31ad259041b4a8f73f33f885441f778cee1f1fe0085eb4bc71679b9d8c923690003a36a6a5fdf8023e6e3f0672 - languageName: node - linkType: hard - "is-extglob@npm:^1.0.0": version: 1.0.0 resolution: "is-extglob@npm:1.0.0" @@ -13320,14 +13973,7 @@ __metadata: languageName: node linkType: hard -"kind-of@npm:^5.0.0": - version: 5.1.0 - resolution: "kind-of@npm:5.1.0" - checksum: 10/acf7cc73881f27629f700a80de77ff7fe4abc9430eac7ddb09117f75126e578ee8d7e44c4dacb6a9e802d5d881abf007ee6af3cfbe55f8b5cf0a7fdc49a02aa3 - languageName: node - linkType: hard - -"kind-of@npm:^6.0.0, kind-of@npm:^6.0.1, kind-of@npm:^6.0.2": +"kind-of@npm:^6.0.2": version: 6.0.3 resolution: "kind-of@npm:6.0.3" checksum: 10/5873d303fb36aad875b7538798867da2ae5c9e328d67194b0162a3659a627d22f742fc9c4ae95cd1704132a24b00cae5041fc00c0f6ef937dc17080dc4dbb962 @@ -13561,6 +14207,13 @@ __metadata: languageName: node linkType: hard +"lodash.camelcase@npm:^4.3.0": + version: 4.3.0 + resolution: "lodash.camelcase@npm:4.3.0" + checksum: 10/c301cc379310441dc73cd6cebeb91fb254bea74e6ad3027f9346fc43b4174385153df420ffa521654e502fd34c40ef69ca4e7d40ee7129a99e06f306032bfc65 + languageName: node + linkType: hard + "lodash.debounce@npm:4.0.8, lodash.debounce@npm:^4.0.8": version: 4.0.8 resolution: "lodash.debounce@npm:4.0.8" @@ -13659,6 +14312,13 @@ __metadata: languageName: node linkType: hard +"long@npm:^5.0.0": + version: 5.2.3 + resolution: "long@npm:5.2.3" + checksum: 10/9167ec6947a825b827c30da169a7384eec6c0c9ec2f0b9c74da2e93d81159bbe39fb09c3f13dae9721d4b807ccfa09797a7dd1012f5d478e3e33ca3c78b608e6 + languageName: node + linkType: hard + "loose-envify@npm:^1.0.0, loose-envify@npm:^1.1.0, loose-envify@npm:^1.4.0": version: 1.4.0 resolution: "loose-envify@npm:1.4.0" @@ -14572,16 +15232,6 @@ __metadata: languageName: node linkType: hard -"mixin-object@npm:^2.0.1": - version: 2.0.1 - resolution: "mixin-object@npm:2.0.1" - dependencies: - for-in: "npm:^0.1.3" - is-extendable: "npm:^0.1.1" - checksum: 10/7d0eb7c2f06435fcc01d132824b4c973a0df689a117d8199d79911b506363b6f4f86a84458a63f3acfa7388f3052612cfe27105400b4932678452925a9739a4c - languageName: node - linkType: hard - "mkdirp-promise@npm:^5.0.1": version: 5.0.1 resolution: "mkdirp-promise@npm:5.0.1" @@ -15374,15 +16024,6 @@ __metadata: languageName: node linkType: hard -"opencollective-postinstall@npm:^2.0.3": - version: 2.0.3 - resolution: "opencollective-postinstall@npm:2.0.3" - bin: - opencollective-postinstall: index.js - checksum: 10/69d63778087cd10c9d707d9ed360556780cfdd0cd6241ded0e26632f467f1d5a064f4a9aec19a30c187770c17adba034d988f7684b226f3a73e79f44e73fab0e - languageName: node - linkType: hard - "openpgp@npm:^5.5.0": version: 5.7.0 resolution: "openpgp@npm:5.7.0" @@ -16080,6 +16721,26 @@ __metadata: languageName: node linkType: hard +"protobufjs@npm:^7.2.5": + version: 7.4.0 + resolution: "protobufjs@npm:7.4.0" + dependencies: + "@protobufjs/aspromise": "npm:^1.1.2" + "@protobufjs/base64": "npm:^1.1.2" + "@protobufjs/codegen": "npm:^2.0.4" + "@protobufjs/eventemitter": "npm:^1.1.0" + "@protobufjs/fetch": "npm:^1.1.0" + "@protobufjs/float": "npm:^1.0.2" + "@protobufjs/inquire": "npm:^1.1.0" + "@protobufjs/path": "npm:^1.1.2" + "@protobufjs/pool": "npm:^1.1.0" + "@protobufjs/utf8": "npm:^1.1.0" + "@types/node": "npm:>=13.7.0" + long: "npm:^5.0.0" + checksum: 10/408423506610f70858d7593632f4a6aa4f05796c90fd632be9b9252457c795acc71aa6d3b54bb7f48a890141728fee4ca3906723ccea6c202ad71f21b3879b8b + languageName: node + linkType: hard + "proxy-addr@npm:~2.0.7": version: 2.0.7 resolution: "proxy-addr@npm:2.0.7" @@ -16192,7 +16853,7 @@ __metadata: "@giphy/react-native-sdk": "npm:^3.2.0" "@gorhom/bottom-sheet": "npm:^4" "@metamask/eth-sig-util": "npm:^5.0.0" - "@notifee/react-native": "npm:^7.8.2" + "@notifee/react-native": "npm:^9.1.8" "@pushprotocol/restapi": "npm:^1.7.28" "@pushprotocol/socket": "npm:latest" "@react-native-async-storage/async-storage": "npm:1.17.11" @@ -16200,8 +16861,8 @@ __metadata: "@react-native-community/eslint-config": "npm:^3.2.0" "@react-native-community/masked-view": "npm:^0.1.11" "@react-native-community/netinfo": "npm:^11.3.1" - "@react-native-firebase/app": "npm:^18.6.0" - "@react-native-firebase/messaging": "npm:^18.6.0" + "@react-native-firebase/app": "npm:^21.6.1" + "@react-native-firebase/messaging": "npm:^21.6.1" "@react-navigation/bottom-tabs": "npm:^6.5.19" "@react-navigation/native": "npm:^6.0.12" "@react-navigation/stack": "npm:^6.2.3" @@ -17852,7 +18513,7 @@ __metadata: languageName: node linkType: hard -"safe-buffer@npm:5.2.1, safe-buffer@npm:^5.0.1, safe-buffer@npm:^5.1.0, safe-buffer@npm:^5.1.1, safe-buffer@npm:^5.1.2, safe-buffer@npm:^5.2.0, safe-buffer@npm:^5.2.1, safe-buffer@npm:~5.2.0": +"safe-buffer@npm:5.2.1, safe-buffer@npm:>=5.1.0, safe-buffer@npm:^5.0.1, safe-buffer@npm:^5.1.0, safe-buffer@npm:^5.1.1, safe-buffer@npm:^5.1.2, safe-buffer@npm:^5.2.0, safe-buffer@npm:^5.2.1, safe-buffer@npm:~5.2.0": version: 5.2.1 resolution: "safe-buffer@npm:5.2.1" checksum: 10/32872cd0ff68a3ddade7a7617b8f4c2ae8764d8b7d884c651b74457967a9e0e886267d3ecc781220629c44a865167b61c375d2da6c720c840ecd73f45d5d9451 @@ -18148,17 +18809,6 @@ __metadata: languageName: node linkType: hard -"shallow-clone@npm:^1.0.0": - version: 1.0.0 - resolution: "shallow-clone@npm:1.0.0" - dependencies: - is-extendable: "npm:^0.1.1" - kind-of: "npm:^5.0.0" - mixin-object: "npm:^2.0.1" - checksum: 10/51e36158d0fd7d9d0ce599a01a0a835d9e0a6ec10d6c69b62dda50ded5284ab92237ce5fa34cb58390e06c83961a17f1c39704e189ce0d7ae6daedae151da734 - languageName: node - linkType: hard - "shallow-clone@npm:^3.0.0": version: 3.0.1 resolution: "shallow-clone@npm:3.0.1" @@ -18990,16 +19640,6 @@ __metadata: languageName: node linkType: hard -"superstruct@npm:^0.6.2": - version: 0.6.2 - resolution: "superstruct@npm:0.6.2" - dependencies: - clone-deep: "npm:^2.0.1" - kind-of: "npm:^6.0.1" - checksum: 10/2377455173450769eaa19381bec851cafb8e356116f5b5fab1fb764b9fbdaff20322cf2f2d3185c3bb856233c9cdb8fb9e6dc03e5132adf902a71acee03822a3 - languageName: node - linkType: hard - "supports-color@npm:^5.3.0, supports-color@npm:^5.5.0": version: 5.5.0 resolution: "supports-color@npm:5.5.0" @@ -19694,6 +20334,20 @@ __metadata: languageName: node linkType: hard +"undici-types@npm:~6.20.0": + version: 6.20.0 + resolution: "undici-types@npm:6.20.0" + checksum: 10/583ac7bbf4ff69931d3985f4762cde2690bb607844c16a5e2fbb92ed312fe4fa1b365e953032d469fa28ba8b224e88a595f0b10a449332f83fa77c695e567dbe + languageName: node + linkType: hard + +"undici@npm:6.19.7": + version: 6.19.7 + resolution: "undici@npm:6.19.7" + checksum: 10/77fb8b0377388f6dba8244b015841318d621031211b4f3c2273d809304b77ec44adeba4b89dfd6708bdc044190e18f068e5b231882ef15d057d4624e46f544e3 + languageName: node + linkType: hard + "unicode-canonical-property-names-ecmascript@npm:^2.0.0": version: 2.0.0 resolution: "unicode-canonical-property-names-ecmascript@npm:2.0.0" @@ -20452,6 +21106,24 @@ __metadata: languageName: node linkType: hard +"websocket-driver@npm:>=0.5.1": + version: 0.7.4 + resolution: "websocket-driver@npm:0.7.4" + dependencies: + http-parser-js: "npm:>=0.5.1" + safe-buffer: "npm:>=5.1.0" + websocket-extensions: "npm:>=0.1.1" + checksum: 10/17197d265d5812b96c728e70fd6fe7d067471e121669768fe0c7100c939d997ddfc807d371a728556e24fc7238aa9d58e630ea4ff5fd4cfbb40f3d0a240ef32d + languageName: node + linkType: hard + +"websocket-extensions@npm:>=0.1.1": + version: 0.1.4 + resolution: "websocket-extensions@npm:0.1.4" + checksum: 10/b5399b487d277c78cdd2aef63764b67764aa9899431e3a2fa272c6ad7236a0fb4549b411d89afa76d5afd664c39d62fc19118582dc937e5bb17deb694f42a0d1 + languageName: node + linkType: hard + "websocket@npm:^1.0.32": version: 1.0.34 resolution: "websocket@npm:1.0.34" @@ -21008,7 +21680,7 @@ __metadata: languageName: node linkType: hard -"yargs@npm:^17.3.1, yargs@npm:^17.5.1": +"yargs@npm:^17.3.1, yargs@npm:^17.5.1, yargs@npm:^17.7.2": version: 17.7.2 resolution: "yargs@npm:17.7.2" dependencies: From e38d8ae5189b5d8ebf525c6e12bd32aed5f6efb5 Mon Sep 17 00:00:00 2001 From: Kushdeep Singh Date: Tue, 24 Dec 2024 16:39:53 +0530 Subject: [PATCH 5/9] DMAPP-135: Integrate chat notification - Handled rare case for missing notification data: navigates to the chat list instead of a specific chat. - Minor changes and fixes for improved reliability. --- src/contexts/NotificationContext.tsx | 69 ++++++++++++++++++---------- src/helpers/NotificationHelper.ts | 5 +- 2 files changed, 48 insertions(+), 26 deletions(-) diff --git a/src/contexts/NotificationContext.tsx b/src/contexts/NotificationContext.tsx index db09e4662..9672d1575 100644 --- a/src/contexts/NotificationContext.tsx +++ b/src/contexts/NotificationContext.tsx @@ -8,6 +8,7 @@ import messaging, { } from '@react-native-firebase/messaging'; import React, {createContext, useEffect, useRef, useState} from 'react'; import {Platform} from 'react-native'; +import {useSelector} from 'react-redux'; import GLOBALS from 'src/Globals'; import {NotificationHelper} from 'src/helpers/NotificationHelper'; import {usePushApiMode} from 'src/hooks/pushapi/usePushApiMode'; @@ -17,6 +18,7 @@ import { navigate, replaceRoute, } from 'src/navigation/RootNavigation'; +import {selectCurrentUser, selectUsers} from 'src/redux/authSlice'; import {usePushApi} from './PushApiContext'; @@ -70,6 +72,12 @@ export const NotificationContextProvider = ({ const {isChatEnabled} = usePushApiMode(); const {showUnlockProfileModal, userPushSDKInstance} = usePushApi(); + const users = useSelector(selectUsers); + const currentUser = useSelector(selectCurrentUser); + + const wallet = users[currentUser]?.wallet; + const pkey = users[currentUser]?.userPKey; + const isChatEnabledRef = useRef(isChatEnabled); const [tempNotificationData, setTempNotificationData] = @@ -215,8 +223,8 @@ export const NotificationContextProvider = ({ const recentChatNotificationsIDs = recentNotifications .filter( item => - JSON.parse(item.notification.data?.details as string)?.info - ?.chatId === chatId, + JSON.parse((item.notification.data?.details as string) ?? '{}') + ?.info?.chatId === chatId, ) .map(item => `${item.id}`); await notifee.cancelDisplayedNotifications(recentChatNotificationsIDs); @@ -287,7 +295,9 @@ export const NotificationContextProvider = ({ } else { // If Home(Notification) tab is inactive then first // navigate to Home tab then update data - navigate(GLOBALS.SCREENS.NOTIF_TABS); + navigate(GLOBALS.SCREENS.NOTIF_TABS, { + wallet, + }); setChannelNotificationOpened(true); } } else if (data?.type === NOTIFICATION_TYPES.CHAT) { @@ -295,28 +305,39 @@ export const NotificationContextProvider = ({ const resolvedCanAccessChat = canAccessChat ?? isChatEnabledRef.current; // Use ref for default if (resolvedCanAccessChat) { try { - // Get navigation params for SINGLE CHAT Screen - const isGroupConversation = - parsedDetails?.subType === NOTIFICATION_SUB_TYPES.GROUP_CHAT; - const singleChatParams = - await NotificationHelper.getChatNavigationParams({ - chatId: parsedDetails?.info?.chatId, - userPushSDKInstance: userPushSDKInstance, - isGroupConversation, - wallets: parsedDetails?.info?.wallets, - profilePicture: parsedDetails?.info?.profilePicture, - threadhash: parsedDetails?.info?.threadhash, - }); - if (singleChatParams) { - if (getCurrentRouteName() === GLOBALS.SCREENS.SINGLE_CHAT) { - // If Single chat screen is already active then update params data - replaceRoute(GLOBALS.SCREENS.SINGLE_CHAT, singleChatParams); - setTempNotificationData(null); - } else { - // Navigate to Single/Group chat screen - navigate(GLOBALS.SCREENS.SINGLE_CHAT, singleChatParams); - setTempNotificationData(null); + if (parsedDetails?.subType) { + // Get navigation params for SINGLE CHAT Screen + const isGroupConversation = + parsedDetails?.subType === NOTIFICATION_SUB_TYPES.GROUP_CHAT; + const singleChatParams = + await NotificationHelper.getChatNavigationParams({ + chatId: parsedDetails?.info?.chatId, + userPushSDKInstance: userPushSDKInstance, + isGroupConversation, + wallets: parsedDetails?.info?.wallets, + profilePicture: parsedDetails?.info?.profilePicture, + threadhash: parsedDetails?.info?.threadhash, + }); + if (singleChatParams) { + if (getCurrentRouteName() === GLOBALS.SCREENS.SINGLE_CHAT) { + // If Single chat screen is already active then update params data + replaceRoute(GLOBALS.SCREENS.SINGLE_CHAT, singleChatParams); + setTempNotificationData(null); + } else { + // Navigate to Single/Group chat screen + navigate(GLOBALS.SCREENS.SINGLE_CHAT, singleChatParams); + setTempNotificationData(null); + } } + } else if ( + !parsedDetails?.subType && + getCurrentRouteName() !== GLOBALS.SCREENS.CHATS + ) { + // Handled rare case for missing notification data: navigates to the chat list instead of a specific chat. + navigate(GLOBALS.SCREENS.CHATS, { + wallet, + pkey, + }); } } catch (error) { console.log('Notification Route ERROR', error); diff --git a/src/helpers/NotificationHelper.ts b/src/helpers/NotificationHelper.ts index e125af6de..be38629e2 100644 --- a/src/helpers/NotificationHelper.ts +++ b/src/helpers/NotificationHelper.ts @@ -103,9 +103,10 @@ export const NotificationHelper: NotificationHelperType = { }, categoryId: 'Communications', communicationInfo: { - conversationId: parsedDetails?.info?.chatId, + conversationId: + parsedDetails?.info?.chatId ?? remoteMessage.messageId, sender: { - id: parsedDetails?.info?.wallets, + id: parsedDetails?.info?.wallets ?? remoteMessage.messageId, displayName: remoteMessage.notification?.title ?? '', }, }, From dab503d8c2fa94b8eecf15d12d075ff42933b756 Mon Sep 17 00:00:00 2001 From: Kushdeep Singh Date: Tue, 24 Dec 2024 18:51:31 +0530 Subject: [PATCH 6/9] DMAPP-135: Integrate chat notification - Fixed navigation issue triggered on notification press. --- src/contexts/NotificationContext.tsx | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/contexts/NotificationContext.tsx b/src/contexts/NotificationContext.tsx index 9672d1575..1a7550263 100644 --- a/src/contexts/NotificationContext.tsx +++ b/src/contexts/NotificationContext.tsx @@ -319,14 +319,17 @@ export const NotificationContextProvider = ({ threadhash: parsedDetails?.info?.threadhash, }); if (singleChatParams) { - if (getCurrentRouteName() === GLOBALS.SCREENS.SINGLE_CHAT) { - // If Single chat screen is already active then update params data + if ( + getCurrentRouteName() === GLOBALS.SCREENS.SINGLE_CHAT && + getCurrentRouteParams()?.chatId !== parsedDetails?.info?.chatId + ) { + // If Single/Group chat screen is already active with different chatId then update params data replaceRoute(GLOBALS.SCREENS.SINGLE_CHAT, singleChatParams); - setTempNotificationData(null); - } else { + } else if ( + getCurrentRouteName() !== GLOBALS.SCREENS.SINGLE_CHAT + ) { // Navigate to Single/Group chat screen navigate(GLOBALS.SCREENS.SINGLE_CHAT, singleChatParams); - setTempNotificationData(null); } } } else if ( @@ -339,6 +342,7 @@ export const NotificationContextProvider = ({ pkey, }); } + setTempNotificationData(null); } catch (error) { console.log('Notification Route ERROR', error); } From 6ddf7bd3fd5426b7503a8b8742524bb73ac7134b Mon Sep 17 00:00:00 2001 From: Kushdeep Singh Date: Thu, 9 Jan 2025 14:46:19 +0530 Subject: [PATCH 7/9] DMAPP-135: Fixes in chat & notification module - User can copy group Chat ID - Remove notification WIP --- index.js | 30 +++++++------- src/Globals.ts | 2 +- src/contexts/NotificationContext.tsx | 41 ++++++++++++++++++- src/helpers/ServerHelper.js | 1 + .../screens/chats/SingleChatScreen.tsx | 11 +++-- 5 files changed, 62 insertions(+), 23 deletions(-) diff --git a/index.js b/index.js index ac0a1eff2..119e03a89 100644 --- a/index.js +++ b/index.js @@ -51,21 +51,21 @@ function HeadlessCheck({isHeadless}) { // RNCallKeep.setAvailable(true); // } -// messaging().setBackgroundMessageHandler(async remoteMessage => { -// console.log('Message handled in the background!', remoteMessage); -// if (Platform.OS === 'android' && CallKeepHelper.isVideoCall(remoteMessage)) { -// const caller = CallKeepHelper.getCaller(remoteMessage); -// const addressTrimmed = CallKeepHelper.formatEthAddress(caller); -// const uuid = getUUID(); -// RNCallKeep.displayIncomingCall( -// uuid, -// addressTrimmed, -// addressTrimmed, -// 'generic', -// true, -// ); -// } -// }); +messaging().setBackgroundMessageHandler(async remoteMessage => { + console.log('Message handled in the background!', remoteMessage); + // if (Platform.OS === 'android' && CallKeepHelper.isVideoCall(remoteMessage)) { + // const caller = CallKeepHelper.getCaller(remoteMessage); + // const addressTrimmed = CallKeepHelper.formatEthAddress(caller); + // const uuid = getUUID(); + // RNCallKeep.displayIncomingCall( + // uuid, + // addressTrimmed, + // addressTrimmed, + // 'generic', + // true, + // ); + // } +}); if (isCallAccepted) { AppRegistry.registerComponent(appName, () => HeadlessCheck); diff --git a/src/Globals.ts b/src/Globals.ts index 7e4f195f4..fa12a862a 100644 --- a/src/Globals.ts +++ b/src/Globals.ts @@ -61,7 +61,7 @@ export default { IS_BACKGROUND_CALL_ACCEPTED: 'IsBackgroundCallAccepted', - NOTIFICATION_MESSAGES: 'NotificationMessages', + RECENT_NOTIFICATIONS: 'RecentNotification', }, CONSTANTS: { diff --git a/src/contexts/NotificationContext.tsx b/src/contexts/NotificationContext.tsx index 1a7550263..09ab27eb5 100644 --- a/src/contexts/NotificationContext.tsx +++ b/src/contexts/NotificationContext.tsx @@ -8,8 +8,10 @@ import messaging, { } from '@react-native-firebase/messaging'; import React, {createContext, useEffect, useRef, useState} from 'react'; import {Platform} from 'react-native'; +import EncryptedStorage from 'react-native-encrypted-storage'; import {useSelector} from 'react-redux'; import GLOBALS from 'src/Globals'; +import Globals from 'src/Globals'; import {NotificationHelper} from 'src/helpers/NotificationHelper'; import {usePushApiMode} from 'src/hooks/pushapi/usePushApiMode'; import { @@ -90,6 +92,7 @@ export const NotificationContextProvider = ({ useEffect(() => { isChatEnabledRef.current = isChatEnabled; if (isChatEnabled && tempNotificationData) { + console.log('====navigate after chat enabled=>>>>'); handleNotificationRoute(tempNotificationData, true); } }, [isChatEnabled]); @@ -103,7 +106,9 @@ export const NotificationContextProvider = ({ }); // Background Notifications - messaging().setBackgroundMessageHandler(async remoteMessage => {}); + // messaging().setBackgroundMessageHandler(async remoteMessage => { + // console.log('quit/BG notification', JSON.stringify(remoteMessage)); + // }); return () => { unsubscribeOnMessage(); @@ -119,6 +124,7 @@ export const NotificationContextProvider = ({ messaging() .hasPermission() .then(val => { + console.log('======>>>>>>>> hasPermission', val); if (val === 1) { // User has enabled notifications notifee.createChannel({ @@ -190,6 +196,27 @@ export const NotificationContextProvider = ({ } }; + /***************************************************/ + /** This Function will push CHAT notification **/ + /***************************************************/ + const storeNotificationData = async (id: string, data: any) => { + try { + const existingData = + JSON.parse( + (await EncryptedStorage.getItem( + Globals.STORAGE.RECENT_NOTIFICATIONS, + )) as string, + ) || {}; + existingData[id] = data; + await EncryptedStorage.setItem( + 'notificationData', + JSON.stringify(existingData), + ); + } catch (error) { + console.error('Error saving notification data:', error); + } + }; + /**********************************************************/ /** This Function will return list of notifications **/ /** that are available in notification centre **/ @@ -220,6 +247,10 @@ export const NotificationContextProvider = ({ const removeOpenedChatNotifications = async (chatId: string) => { try { const recentNotifications = await getRecentMessageNotifications(); + console.log( + 'recentNotifications===>', + JSON.stringify(recentNotifications), + ); const recentChatNotificationsIDs = recentNotifications .filter( item => @@ -227,6 +258,10 @@ export const NotificationContextProvider = ({ ?.info?.chatId === chatId, ) .map(item => `${item.id}`); + console.log( + 'recentChatNotificationsIDs===>', + JSON.stringify(recentChatNotificationsIDs), + ); await notifee.cancelDisplayedNotifications(recentChatNotificationsIDs); } catch (error) { console.log('removeOpenedChatNotifications ERROR', error); @@ -302,6 +337,10 @@ export const NotificationContextProvider = ({ } } else if (data?.type === NOTIFICATION_TYPES.CHAT) { // Handle Chat notification banner press + console.log('===============> chat check', { + canAccessChat, + isChatEnabledRef: isChatEnabledRef.current, + }); const resolvedCanAccessChat = canAccessChat ?? isChatEnabledRef.current; // Use ref for default if (resolvedCanAccessChat) { try { diff --git a/src/helpers/ServerHelper.js b/src/helpers/ServerHelper.js index 9bc92e02b..5cac11e07 100644 --- a/src/helpers/ServerHelper.js +++ b/src/helpers/ServerHelper.js @@ -38,6 +38,7 @@ const ServerHelper = { }, body: JSON.stringify(body), }); + console.log('FCM token registration', JSON.stringify(res)); await MetaStorage.instance.setTokenServerSynced(true); } catch (error) { console.warn(error); diff --git a/src/navigation/screens/chats/SingleChatScreen.tsx b/src/navigation/screens/chats/SingleChatScreen.tsx index cc2d33d86..358720720 100644 --- a/src/navigation/screens/chats/SingleChatScreen.tsx +++ b/src/navigation/screens/chats/SingleChatScreen.tsx @@ -176,12 +176,11 @@ const SingleChatScreen = ({route}: any) => { const onDecline = () => {}; const handleAddressCopy = () => { - Clipboard.setString(senderAddress); - toastRef.current.showToast( - 'Address copied to clipboard', - '', - ToasterOptions.TYPE.GRADIENT_PRIMARY, - ); + const msg = senderAddress + ? 'Address copied to clipboard' + : 'Chat ID copied to clipboard'; + Clipboard.setString(senderAddress ?? chatId); + toastRef.current.showToast(msg, '', ToasterOptions.TYPE.GRADIENT_PRIMARY); }; // const dispatch = useDispatch(); From 826a46819b77ffc9b7d314af3c1f1b4b2ace6140 Mon Sep 17 00:00:00 2001 From: Kushdeep Singh Date: Thu, 9 Jan 2025 18:32:53 +0530 Subject: [PATCH 8/9] DMAPP-135: Chat Notification - Keep notification background handler in NotificationContext - [fix]: Resolve warning for Spam feed item key --- index.js | 30 ++++++++++----------- src/components/ui/SpamFeed.js | 2 +- src/contexts/NotificationContext.tsx | 39 +--------------------------- src/helpers/ServerHelper.js | 1 - 4 files changed, 17 insertions(+), 55 deletions(-) diff --git a/index.js b/index.js index 119e03a89..ac0a1eff2 100644 --- a/index.js +++ b/index.js @@ -51,21 +51,21 @@ function HeadlessCheck({isHeadless}) { // RNCallKeep.setAvailable(true); // } -messaging().setBackgroundMessageHandler(async remoteMessage => { - console.log('Message handled in the background!', remoteMessage); - // if (Platform.OS === 'android' && CallKeepHelper.isVideoCall(remoteMessage)) { - // const caller = CallKeepHelper.getCaller(remoteMessage); - // const addressTrimmed = CallKeepHelper.formatEthAddress(caller); - // const uuid = getUUID(); - // RNCallKeep.displayIncomingCall( - // uuid, - // addressTrimmed, - // addressTrimmed, - // 'generic', - // true, - // ); - // } -}); +// messaging().setBackgroundMessageHandler(async remoteMessage => { +// console.log('Message handled in the background!', remoteMessage); +// if (Platform.OS === 'android' && CallKeepHelper.isVideoCall(remoteMessage)) { +// const caller = CallKeepHelper.getCaller(remoteMessage); +// const addressTrimmed = CallKeepHelper.formatEthAddress(caller); +// const uuid = getUUID(); +// RNCallKeep.displayIncomingCall( +// uuid, +// addressTrimmed, +// addressTrimmed, +// 'generic', +// true, +// ); +// } +// }); if (isCallAccepted) { AppRegistry.registerComponent(appName, () => HeadlessCheck); diff --git a/src/components/ui/SpamFeed.js b/src/components/ui/SpamFeed.js index 4dd48fee2..d3dfa9416 100644 --- a/src/components/ui/SpamFeed.js +++ b/src/components/ui/SpamFeed.js @@ -113,7 +113,7 @@ export default function SpamFeed() { item.sid.toString()} + keyExtractor={(item, index) => `${item.sid}-${index}`} initialNumToRender={10} style={{flex: 1}} contentContainerStyle={styles.contentContainerStyle} diff --git a/src/contexts/NotificationContext.tsx b/src/contexts/NotificationContext.tsx index 09ab27eb5..3b0935c40 100644 --- a/src/contexts/NotificationContext.tsx +++ b/src/contexts/NotificationContext.tsx @@ -92,7 +92,6 @@ export const NotificationContextProvider = ({ useEffect(() => { isChatEnabledRef.current = isChatEnabled; if (isChatEnabled && tempNotificationData) { - console.log('====navigate after chat enabled=>>>>'); handleNotificationRoute(tempNotificationData, true); } }, [isChatEnabled]); @@ -106,9 +105,7 @@ export const NotificationContextProvider = ({ }); // Background Notifications - // messaging().setBackgroundMessageHandler(async remoteMessage => { - // console.log('quit/BG notification', JSON.stringify(remoteMessage)); - // }); + messaging().setBackgroundMessageHandler(async remoteMessage => {}); return () => { unsubscribeOnMessage(); @@ -124,7 +121,6 @@ export const NotificationContextProvider = ({ messaging() .hasPermission() .then(val => { - console.log('======>>>>>>>> hasPermission', val); if (val === 1) { // User has enabled notifications notifee.createChannel({ @@ -196,27 +192,6 @@ export const NotificationContextProvider = ({ } }; - /***************************************************/ - /** This Function will push CHAT notification **/ - /***************************************************/ - const storeNotificationData = async (id: string, data: any) => { - try { - const existingData = - JSON.parse( - (await EncryptedStorage.getItem( - Globals.STORAGE.RECENT_NOTIFICATIONS, - )) as string, - ) || {}; - existingData[id] = data; - await EncryptedStorage.setItem( - 'notificationData', - JSON.stringify(existingData), - ); - } catch (error) { - console.error('Error saving notification data:', error); - } - }; - /**********************************************************/ /** This Function will return list of notifications **/ /** that are available in notification centre **/ @@ -247,10 +222,6 @@ export const NotificationContextProvider = ({ const removeOpenedChatNotifications = async (chatId: string) => { try { const recentNotifications = await getRecentMessageNotifications(); - console.log( - 'recentNotifications===>', - JSON.stringify(recentNotifications), - ); const recentChatNotificationsIDs = recentNotifications .filter( item => @@ -258,10 +229,6 @@ export const NotificationContextProvider = ({ ?.info?.chatId === chatId, ) .map(item => `${item.id}`); - console.log( - 'recentChatNotificationsIDs===>', - JSON.stringify(recentChatNotificationsIDs), - ); await notifee.cancelDisplayedNotifications(recentChatNotificationsIDs); } catch (error) { console.log('removeOpenedChatNotifications ERROR', error); @@ -337,10 +304,6 @@ export const NotificationContextProvider = ({ } } else if (data?.type === NOTIFICATION_TYPES.CHAT) { // Handle Chat notification banner press - console.log('===============> chat check', { - canAccessChat, - isChatEnabledRef: isChatEnabledRef.current, - }); const resolvedCanAccessChat = canAccessChat ?? isChatEnabledRef.current; // Use ref for default if (resolvedCanAccessChat) { try { diff --git a/src/helpers/ServerHelper.js b/src/helpers/ServerHelper.js index 5cac11e07..9bc92e02b 100644 --- a/src/helpers/ServerHelper.js +++ b/src/helpers/ServerHelper.js @@ -38,7 +38,6 @@ const ServerHelper = { }, body: JSON.stringify(body), }); - console.log('FCM token registration', JSON.stringify(res)); await MetaStorage.instance.setTokenServerSynced(true); } catch (error) { console.warn(error); From e6a8307b4c449a4f17965bcad115e6a32d1f934c Mon Sep 17 00:00:00 2001 From: Kushdeep Singh Date: Fri, 10 Jan 2025 13:55:28 +0530 Subject: [PATCH 9/9] DMAPP-135: Chat notification - Requested code level changes done - Remove channel notifications from notification centre after read --- src/components/ui/HomeFeed.js | 4 +++- src/contexts/NotificationContext.tsx | 27 +++++++++++++++++++++++++-- 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/src/components/ui/HomeFeed.js b/src/components/ui/HomeFeed.js index eab2a22fb..a7c00e762 100644 --- a/src/components/ui/HomeFeed.js +++ b/src/components/ui/HomeFeed.js @@ -19,7 +19,6 @@ import NotificationItem from './NotificationItem'; export default function InboxFeed(props) { const {userPushSDKInstance, userInfo} = usePushApi(); - const {createNotificationChannel} = useNotificationsApi(); // SET STATES const [initialized, setInitialized] = useState(false); @@ -38,6 +37,8 @@ export default function InboxFeed(props) { channelNotificationReceived, setChannelNotificationOpened, setChannelNotificationReceived, + createNotificationChannel, + removeInboxChannelNotifications, } = useNotificationsApi(); // SET REFS @@ -108,6 +109,7 @@ export default function InboxFeed(props) { // clear the notifs if present AppBadgeHelper.setAppBadgeCount(0); + removeInboxChannelNotifications(); if (rewrite) { setFeed([...feeds]); diff --git a/src/contexts/NotificationContext.tsx b/src/contexts/NotificationContext.tsx index 3b0935c40..1610d1529 100644 --- a/src/contexts/NotificationContext.tsx +++ b/src/contexts/NotificationContext.tsx @@ -8,10 +8,8 @@ import messaging, { } from '@react-native-firebase/messaging'; import React, {createContext, useEffect, useRef, useState} from 'react'; import {Platform} from 'react-native'; -import EncryptedStorage from 'react-native-encrypted-storage'; import {useSelector} from 'react-redux'; import GLOBALS from 'src/Globals'; -import Globals from 'src/Globals'; import {NotificationHelper} from 'src/helpers/NotificationHelper'; import {usePushApiMode} from 'src/hooks/pushapi/usePushApiMode'; import { @@ -52,6 +50,7 @@ type NotificationContextType = { channelNotificationOpened: boolean; setChannelNotificationOpened: (value: boolean) => void; removeOpenedChatNotifications: (chatId: string) => void; + removeInboxChannelNotifications: () => void; }; const NotificationContext = createContext({ @@ -64,6 +63,7 @@ const NotificationContext = createContext({ channelNotificationOpened: false, setChannelNotificationOpened: () => {}, removeOpenedChatNotifications: () => {}, + removeInboxChannelNotifications: () => {}, }); export const NotificationContextProvider = ({ @@ -235,6 +235,28 @@ export const NotificationContextProvider = ({ } }; + /*****************************************************************************************/ + /** This function will remove other notification banners from the notification center **/ + /** if Home feed screen is opened. **/ + /*****************************************************************************************/ + const removeInboxChannelNotifications = async () => { + try { + const recentNotifications = await getRecentMessageNotifications(); + if (recentNotifications.length) { + const recentChatNotificationsIDs = recentNotifications + .filter( + item => + JSON.parse((item.notification.data?.details as string) ?? '{}') + ?.subType === NOTIFICATION_SUB_TYPES.INBOX, + ) + .map(item => `${item.id}`); + await notifee.cancelDisplayedNotifications(recentChatNotificationsIDs); + } + } catch (error) { + console.log('removeInboxChannelNotifications ERROR', error); + } + }; + /************************************************/ /** Handle native notification and notifee **/ /** events(onPress and dismiss) **/ @@ -387,6 +409,7 @@ export const NotificationContextProvider = ({ channelNotificationOpened, setChannelNotificationOpened, removeOpenedChatNotifications, + removeInboxChannelNotifications, }}> {children}