diff --git a/android/app/src/main/res/drawable-hdpi/ic_notification_icon.png b/android/app/src/main/res/drawable-hdpi/ic_notification_icon.png index 87e254d0..4392a91c 100644 Binary files a/android/app/src/main/res/drawable-hdpi/ic_notification_icon.png and b/android/app/src/main/res/drawable-hdpi/ic_notification_icon.png differ diff --git a/android/app/src/main/res/drawable-mdpi/ic_notification_icon.png b/android/app/src/main/res/drawable-mdpi/ic_notification_icon.png index 045927d5..f0ad7455 100644 Binary files a/android/app/src/main/res/drawable-mdpi/ic_notification_icon.png and b/android/app/src/main/res/drawable-mdpi/ic_notification_icon.png differ diff --git a/android/app/src/main/res/drawable-xhdpi/ic_notification_icon.png b/android/app/src/main/res/drawable-xhdpi/ic_notification_icon.png index d02aacbe..a4906bbe 100644 Binary files a/android/app/src/main/res/drawable-xhdpi/ic_notification_icon.png and b/android/app/src/main/res/drawable-xhdpi/ic_notification_icon.png differ diff --git a/android/app/src/main/res/drawable-xxhdpi/ic_notification_icon.png b/android/app/src/main/res/drawable-xxhdpi/ic_notification_icon.png index d6afed77..bb9666be 100644 Binary files a/android/app/src/main/res/drawable-xxhdpi/ic_notification_icon.png and b/android/app/src/main/res/drawable-xxhdpi/ic_notification_icon.png differ diff --git a/android/app/src/main/res/drawable-xxxhdpi/ic_notification_icon.png b/android/app/src/main/res/drawable-xxxhdpi/ic_notification_icon.png deleted file mode 100644 index f552b0c8..00000000 Binary files a/android/app/src/main/res/drawable-xxxhdpi/ic_notification_icon.png and /dev/null differ diff --git a/src/components/utlis/deeplinkingUtils.ts b/src/components/utlis/deeplinkingUtils.ts index 947687b7..eecba8b1 100644 --- a/src/components/utlis/deeplinkingUtils.ts +++ b/src/components/utlis/deeplinkingUtils.ts @@ -4,9 +4,13 @@ import { } from '@react-navigation/native'; import { CaseDetailStackEnum } from '@screens/caseDetails/CaseDetailStack'; import { Linking } from 'react-native'; -import notifee from '@notifee/react-native'; +import notifee, { InitialNotification } from '@notifee/react-native'; import { GenericType } from '@common/GenericTypes'; import { NotificationAction } from '@hooks/useFCM/useFCM'; +import store from '@store'; +import AsyncStorage from '@react-native-async-storage/async-storage'; + +const LAST_INITIAL_NOTIFICATION_ID = 'LAST_INITIAL_NOTIFICATION_ID'; // Define a type for the Route object for better type checking type Route = { @@ -49,6 +53,29 @@ const findRouteByName = (routes: Route[], name: string): Route | null => { return null; }; +const needToHandleInitialNotification = async ( + initialNotification: InitialNotification | null +): Promise => { + if (initialNotification !== null) { + try { + const lastInitialNotificationId = await AsyncStorage.getItem(LAST_INITIAL_NOTIFICATION_ID); + const notificationId = initialNotification.notification.data?.notificationId; + + if (lastInitialNotificationId !== null) { + if (lastInitialNotificationId === notificationId) { + return false; + } + } + + await AsyncStorage.setItem(LAST_INITIAL_NOTIFICATION_ID, String(notificationId)); + return true; + } catch (e) { + return false; + } + } + return false; +}; + // Linking configuration with types for better type safety export const linkingConf: LinkingOptions = { prefixes: ['cosmosapp://'], @@ -58,13 +85,18 @@ export const linkingConf: LinkingOptions = { if (url) { return url; } + // Access Redux store from the imported store instance const message = await notifee.getInitialNotification(); + const shouldHandleInitialNotification = await needToHandleInitialNotification(message); + if (!shouldHandleInitialNotification) return null; if (message?.pressAction?.id === NotificationAction.DEFAULT) { return null; } const caseId = message?.notification?.data?.caseId as string; + const reduxState = store.getState(); + const caseDetails = reduxState?.allCases?.caseDetails?.[caseId]; const notificationId = message?.notification?.data?.notificationId as string; - if (!caseId || !notificationId) return null; + if (!caseId || !notificationId || !caseDetails) return null; const deepLink = `${ message?.notification?.data?.deepLinks?.[message?.pressAction?.id] }¬ificationId=${notificationId}` as string; diff --git a/src/constants/Global.ts b/src/constants/Global.ts index 55874907..705f8fc7 100644 --- a/src/constants/Global.ts +++ b/src/constants/Global.ts @@ -1,5 +1,6 @@ import { buildFlavour } from '@reducers/metadataSlice'; import { isNullOrUndefined } from '../components/utlis/commonFunctions'; +import { setItem } from '@components/utlis/storageHelper'; export enum DEVICE_TYPE_ENUM { MOBILE = 'MOBILE', @@ -13,7 +14,7 @@ export const GLOBAL = { DEVICE_TYPE: DEVICE_TYPE_ENUM.MOBILE, IS_IMPERSONATED: false, SELECTED_AGENT_ID: '', - BUILD_FLAVOUR: '' + BUILD_FLAVOUR: '', }; interface IGlobalUserData { @@ -27,9 +28,18 @@ interface IGlobalUserData { export const setGlobalUserData = (userData: IGlobalUserData) => { const { token, deviceId, agentId, deviceType, isImpersonated, selectedAgentId } = userData; - if (!isNullOrUndefined(token)) GLOBAL.SESSION_TOKEN = `${token}`; - if (!isNullOrUndefined(deviceId)) GLOBAL.DEVICE_ID = `${deviceId}`; - if (!isNullOrUndefined(agentId)) GLOBAL.AGENT_ID = `${agentId}`; + if (!isNullOrUndefined(token)) { + GLOBAL.SESSION_TOKEN = `${token}`; + setItem('sessionToken', String(token)); + } + if (!isNullOrUndefined(deviceId)) { + GLOBAL.DEVICE_ID = `${deviceId}`; + setItem('deviceId', String(deviceId)); + } + if (!isNullOrUndefined(agentId)) { + GLOBAL.AGENT_ID = `${agentId}`; + setItem('agentId', String(agentId)); + } if (!isNullOrUndefined(deviceType)) GLOBAL.DEVICE_TYPE = deviceType as DEVICE_TYPE_ENUM; if (!isNullOrUndefined(isImpersonated)) GLOBAL.IS_IMPERSONATED = isImpersonated ?? false; if (!isNullOrUndefined(selectedAgentId)) GLOBAL.SELECTED_AGENT_ID = `${selectedAgentId}`; diff --git a/src/hooks/useFCM/notificationHelperFunctions.ts b/src/hooks/useFCM/notificationHelperFunctions.ts index 2322de71..e6c0ad0b 100644 --- a/src/hooks/useFCM/notificationHelperFunctions.ts +++ b/src/hooks/useFCM/notificationHelperFunctions.ts @@ -1,11 +1,13 @@ import { CLICKSTREAM_EVENT_NAMES } from '@common/Constants'; import { navigateToScreen } from '@components/utlis/navigationUtlis'; import { AndroidAction, Event, EventType } from '@notifee/react-native'; +import { formatAmount } from '@rn-ui-lib/utils/amount'; import { CaseDetailStackEnum } from '@screens/caseDetails/CaseDetailStack'; import { EmiScheduleTabs } from '@screens/emiSchedule'; import { EmiSelectedTab } from '@screens/emiSchedule/EmiScheduleTab'; import { INotification } from '@screens/notifications/NotificationItem'; import { addClickstreamEvent } from '@services/clickstreamEventService'; +import store from '@store'; // Actions that can be performed on notification export enum NotificationAction { @@ -34,7 +36,9 @@ const getPaymentMadeNotificationContent = (notification: INotification) => { const { params } = notification || {}; const { amount, customerName } = params || {}; const title = `Payment success`; - const body = `${customerName} made a payment of ₹${amount}`; + const body = `${customerName} made a payment of ${formatAmount( + amount + )}`; const actions = [ { title: `VIEW DETAILS`, @@ -57,7 +61,9 @@ const getPaymentFailedNotificationContent = (notification: INotification) => { const { params } = notification || {}; const { amount, customerName } = params || {}; const title = 'Payment failure'; - const body = `${customerName} failed to make a payment of ₹${amount}`; + const body = `${customerName} failed to make a payment of ${formatAmount( + amount + )}`; const actions = [ { title: `VIEW DETAILS`, @@ -112,6 +118,9 @@ export const handleNotificationNavigation = ( caseId: string, notificationId: string ) => { + const reduxState = store.getState(); + const caseDetails = reduxState?.allCases?.caseDetails?.[caseId]; + if(!caseDetails) return; switch (action) { case NotificationAction.VIEW_PAID_SCHEDULE: navigateToScreen('caseDetailStack', { diff --git a/src/hooks/useFCM/useFCM.ts b/src/hooks/useFCM/useFCM.ts index a3a716a3..9413ae6d 100644 --- a/src/hooks/useFCM/useFCM.ts +++ b/src/hooks/useFCM/useFCM.ts @@ -64,6 +64,7 @@ export const sendPushNotification = async (notification: any) => { name: 'Default Channel', importance: AndroidImportance.HIGH, bypassDnd: true, + sound: 'default', }); const notificationContent = getNotificationContent(notification); @@ -77,13 +78,15 @@ export const sendPushNotification = async (notification: any) => { android: { channelId, smallIcon: 'ic_notification_icon', - color: '#1D2678', + color: '#22d081', + largeIcon: 'ic_launcher', showTimestamp: true, actions, style: { type: AndroidStyle.BIGTEXT, text: body }, pressAction: actions[0].pressAction, groupSummary: true, importance: AndroidImportance.HIGH, + sound: 'default', }, data, }); diff --git a/src/screens/auth/ProtectedRouter.tsx b/src/screens/auth/ProtectedRouter.tsx index 4e632c38..de4446da 100644 --- a/src/screens/auth/ProtectedRouter.tsx +++ b/src/screens/auth/ProtectedRouter.tsx @@ -26,6 +26,7 @@ import CaseDetailStack from '@screens/caseDetails/CaseDetailStack'; import FullScreenLoader from '@rn-ui-lib/components/FullScreenLoader'; import { getFirestoreResyncIntervalInMinutes } from '@common/AgentActivityConfigurableConstants'; import AgentIdCard from '@screens/Profile/AgentIdCard'; +import SuspenseLoader from '@rn-ui-lib/components/suspense_loader/SuspenseLoader'; const Stack = createNativeStackNavigator(); @@ -110,7 +111,7 @@ const ProtectedRouter = () => { }; }, []); - if (isLoading) return ; + // if (isLoading) return ; return (