diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 51e51e7b..463e9f52 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -30,7 +30,6 @@ - diff --git a/index.js b/index.js index 91bc39cc..68ca5951 100644 --- a/index.js +++ b/index.js @@ -23,45 +23,51 @@ import Geolocation from 'react-native-geolocation-service'; import ForegroundService from '@supersami/rn-foreground-service'; import { getItem } from '@components/utlis/storageHelper'; import { AppState } from 'react-native'; +import { logError } from '@components/utlis/errorUtils'; if (__DEV__) { LogBox.ignoreAllLogs(); } -const geolocationForegroundTask = async () => { - Geolocation.getCurrentPosition(async (position) => { - const { latitude, longitude, accuracy } = position.coords || {}; - if (!latitude || !longitude || !accuracy) return; +// TODO: Can use this code for starting fgs poc +// const geolocationForegroundTask = async () => { +// Geolocation.getCurrentPosition(async (position) => { +// const { latitude, longitude, accuracy } = position.coords || {}; +// if (!latitude || !longitude || !accuracy) return; - const isActiveOnApp = (await getItem(StorageKeys.IS_USER_ACTIVE)) || false; - const userActivityonApp = - (await getItem(StorageKeys.USER_ACTIVITY_ON_APP)) || AgentActivity.LOW; +// const isActiveOnApp = (await getItem(StorageKeys.IS_USER_ACTIVE)) || false; +// const userActivityonApp = +// (await getItem(StorageKeys.USER_ACTIVITY_ON_APP)) || AgentActivity.LOW; - const geolocation = [ - { - latitude, - longitude, - accuracy, - timestamp: Date.now(), - isActiveOnApp: Boolean(isActiveOnApp), - userActivityOnApp: String(userActivityonApp), - }, - ]; - axiosInstance.post(getApiUrl(ApiKeys.SEND_LOCATION), geolocation, { - headers: { - donotHandleError: 'true', - }, - }); - }); -}; +// const geolocation = [ +// { +// latitude, +// longitude, +// accuracy, +// timestamp: Date.now(), +// isActiveOnApp: Boolean(isActiveOnApp), +// userActivityOnApp: String(userActivityonApp), +// }, +// ]; +// axiosInstance.post(getApiUrl(ApiKeys.SEND_LOCATION), geolocation, { +// headers: { +// donotHandleError: 'true', +// }, +// }); +// }); +// }; // Background push notification handler messaging().setBackgroundMessageHandler(async (remoteMessage) => { const { data } = remoteMessage || {}; if (data?.payload) { - const notification = JSON.parse(data.payload); - if (notification?.showAsPn) { - handlePushNotification(notification, true); + try { + const notification = JSON.parse(data.payload); + if (notification?.showAsPn) { + handlePushNotification(notification, true); + } + } catch (err) { + logError(err, 'Error in parsing background push notification'); } // TODO: Try to start foreground service if not working. // const isForegroundServiceRunning = await ForegroundService.is_running(); diff --git a/src/components/utlis/navigationUtlis.ts b/src/components/utlis/navigationUtlis.ts index 4b955b53..0cf074f5 100644 --- a/src/components/utlis/navigationUtlis.ts +++ b/src/components/utlis/navigationUtlis.ts @@ -2,6 +2,7 @@ import { StackActions } from '@react-navigation/native'; import React, { RefObject } from 'react'; import { TemplateRoutePrefix } from '../../common/Constants'; import { CaseAllocationType } from '../../screens/allCases/interface'; +import { PageRouteEnum } from '@screens/auth/ProtectedRouter'; export const navigationRef: RefObject = React.createRef(); @@ -11,9 +12,6 @@ export const getCurrentScreen = () => { // if screen already exists then navigate to it otherwise push screen export const navigateToScreen = (name: string, params: object = {}) => { - if (navigationRef.current?.getCurrentRoute()?.name === name) { - return; - } navigationRef.current?.navigate(name, params); }; @@ -31,7 +29,7 @@ export const goBack = () => { navigationRef.current?.goBack(); } else { - navigateToScreen('home') + navigateToScreen(PageRouteEnum.HOME) } }; diff --git a/src/hooks/useFCM/notificationHelperFunctions.ts b/src/hooks/useFCM/notificationHelperFunctions.ts index 7684b020..c4782031 100644 --- a/src/hooks/useFCM/notificationHelperFunctions.ts +++ b/src/hooks/useFCM/notificationHelperFunctions.ts @@ -10,6 +10,7 @@ import { addClickstreamEvent } from '@services/clickstreamEventService'; import store from '@store'; import AsyncStorage from '@react-native-async-storage/async-storage'; import { LAST_INITIAL_NOTIFICATION_ID } from '@components/utlis/deeplinkingUtils'; +import { PageRouteEnum } from '@screens/auth/ProtectedRouter'; // Actions that can be performed on notification export enum NotificationAction { @@ -142,19 +143,19 @@ export const handleNotificationNavigation = ( if (!caseDetails) return; switch (action) { case NotificationAction.VIEW_PAID_SCHEDULE: - navigateToScreen(CaseDetailStackEnum.COLLECTION_CASE_DETAIL, { + navigateToScreen(PageRouteEnum.CASE_DETAIL_STACK, { screen: CaseDetailStackEnum.EMI_SCHEDULE, params: { caseId, scheduleTabId: EmiSelectedTab.PAID, notificationId }, }); break; case NotificationAction.VIEW_REPAYMENT: - navigateToScreen(CaseDetailStackEnum.COLLECTION_CASE_DETAIL, { + navigateToScreen(PageRouteEnum.CASE_DETAIL_STACK, { screen: CaseDetailStackEnum.EMI_SCHEDULE, params: { caseId, tabId: EmiScheduleTabs.REPAYMENTS, notificationId }, }); break; case NotificationAction.CALL_CUSTOMER: - navigateToScreen(CaseDetailStackEnum.COLLECTION_CASE_DETAIL, { + navigateToScreen(PageRouteEnum.CASE_DETAIL_STACK, { screen: CaseDetailStackEnum.COLLECTION_CASE_DETAIL, params: { caseId, showPhoneNumberBottomsheet: true, notificationId }, }); diff --git a/src/hooks/useFCM/useFCM.ts b/src/hooks/useFCM/useFCM.ts index f4c0b731..492f8bee 100644 --- a/src/hooks/useFCM/useFCM.ts +++ b/src/hooks/useFCM/useFCM.ts @@ -68,7 +68,14 @@ export const sendPushNotification = async (notification: any) => { const notificationContent = getNotificationContent(notification); if (!notificationContent) return; - const { title, body, actions, data } = notificationContent; + const { title, body, actions = [], data } = notificationContent; + + const defaultPressAction = actions[0] + ? actions[0].pressAction + : { + id: NotificationAction.DEFAULT, + mainComponent: 'app', + }; // Display a notification await notifee.displayNotification({ @@ -82,7 +89,7 @@ export const sendPushNotification = async (notification: any) => { showTimestamp: true, actions, style: { type: AndroidStyle.BIGTEXT, text: body }, - pressAction: actions[0].pressAction, + pressAction: defaultPressAction, groupSummary: true, importance: AndroidImportance.HIGH, sound: 'default', @@ -113,12 +120,16 @@ const useFCM = () => { const handleNotificationMessage = async (remoteMessage: FirebaseMessagingTypes.RemoteMessage) => { const { data } = remoteMessage || {}; if (data?.payload) { - const notification: INotification = JSON.parse(data.payload); - if (notification?.showAsPn) { - handlePushNotification(notification); + try { + const notification: INotification = JSON.parse(data.payload); + if (notification?.showAsPn) { + handlePushNotification(notification); + } + dispatch(notificationDelivered({ ids: [notification.id] })); + dispatch(prependNewNotifications({ notification })); + } catch (err) { + logError(err as Error, 'unable to parse notification payload'); } - dispatch(notificationDelivered({ ids: [notification.id] })); - dispatch(prependNewNotifications({ notification })); } }; diff --git a/src/screens/allCases/ListItem.tsx b/src/screens/allCases/ListItem.tsx index 79b82201..0beb1ecc 100644 --- a/src/screens/allCases/ListItem.tsx +++ b/src/screens/allCases/ListItem.tsx @@ -35,6 +35,7 @@ import { VisitPlanStatus } from '../../reducer/userSlice'; import { PaymentStatus } from '../caseDetails/interface'; import relativeDistanceFormatter from '@screens/addressGeolocation/utils/relativeDistanceFormatter'; import { CaseDetailStackEnum } from '@screens/caseDetails/CaseDetailStack'; +import { PageRouteEnum } from '@screens/auth/ProtectedRouter'; interface IListItem { caseListItemDetailObj: ICaseItemCaseDetailObj; @@ -138,7 +139,7 @@ const ListItem: React.FC = (props) => { }); } if (isCollectionCaseType) { - navigateToScreen(CaseDetailStackEnum.COLLECTION_CASE_DETAIL, { + navigateToScreen(PageRouteEnum.CASE_DETAIL_STACK, { screen: CaseDetailStackEnum.COLLECTION_CASE_DETAIL, params: { caseId }, }); diff --git a/src/screens/caseDetails/CollectionCaseDetail.tsx b/src/screens/caseDetails/CollectionCaseDetail.tsx index 75869dd2..df08e495 100644 --- a/src/screens/caseDetails/CollectionCaseDetail.tsx +++ b/src/screens/caseDetails/CollectionCaseDetail.tsx @@ -92,13 +92,16 @@ const CollectionCaseDetails: React.FC = (props) => { useEffect(() => { // If landed via notification action if (notificationId) { + if (showPhoneNumberBottomsheet) { + setShowPhoneNumberSheet(true); + } addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_PUSH_NOTIFICATION_SCREEN_LOADED, { notificationId, caseId, screenName: CaseDetailStackEnum.COLLECTION_CASE_DETAIL, }); } - }, []); + }, [notificationId]); const dispatch = useAppDispatch(); const isFocused = useIsFocused(); @@ -380,7 +383,10 @@ const CollectionCaseDetails: React.FC = (props) => { addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_VIEW_EMI_SCHEDULE_CLICKED, { lan: loanAccountNumber, }); - navigateToScreen(CaseDetailStackEnum.EMI_SCHEDULE, { loanAccountNumber, caseId }); + navigateToScreen(CaseDetailStackEnum.EMI_SCHEDULE, { + loanAccountNumber, + caseId, + }); }} > diff --git a/src/screens/emiSchedule/index.tsx b/src/screens/emiSchedule/index.tsx index c59638df..d5890fc5 100644 --- a/src/screens/emiSchedule/index.tsx +++ b/src/screens/emiSchedule/index.tsx @@ -66,13 +66,18 @@ const EmiSchedule: React.FC = (props) => { useEffect(() => { // If the user came to the screen via notification. if (notificationId) { + if (tabId !== currentTab) { + setCurrentTab(tabId || currentTab); + } addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_PUSH_NOTIFICATION_SCREEN_LOADED, { notificationId, caseId, + tabId: tabId || currentTab, + scheduleTabId, screenName: CaseDetailStackEnum.EMI_SCHEDULE, }); } - }, []); + }, [notificationId]); const { refreshing, onRefresh } = useRefresh(() => { isOnline @@ -100,10 +105,9 @@ const EmiSchedule: React.FC = (props) => { onRefresh(); } }, [isOnline]); - useEffect(() => { addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_TOTAL_OUTSTANDING_BREAKUP_LOADED); - },[]); + }, []); if (!isOnline && !emiData) { return ( diff --git a/src/screens/notifications/NotificationItem.tsx b/src/screens/notifications/NotificationItem.tsx index 208d5e89..db61bbbc 100644 --- a/src/screens/notifications/NotificationItem.tsx +++ b/src/screens/notifications/NotificationItem.tsx @@ -3,11 +3,7 @@ import React from 'react'; import Text from '../../../RN-UI-LIB/src/components/Text'; import { GenericStyles } from '../../../RN-UI-LIB/src/styles'; import { COLORS } from '../../../RN-UI-LIB/src/styles/colors'; -import { - NotificationIconsMap, - NotificationTypes, - WidgetStatus, -} from './constants'; +import { NotificationIconsMap, NotificationTypes, WidgetStatus } from './constants'; import Heading from '../../../RN-UI-LIB/src/components/Heading'; import { getTimeDifference } from '../../../RN-UI-LIB/src/utlis/common'; import { useAppDispatch, useAppSelector } from '../../hooks'; @@ -26,6 +22,7 @@ import { handleNotificationNavigation, } from '@hooks/useFCM/notificationHelperFunctions'; import { CaseDetailStackEnum } from '@screens/caseDetails/CaseDetailStack'; +import { PageRouteEnum } from '@screens/auth/ProtectedRouter'; export interface INotification { id: string; @@ -142,7 +139,7 @@ const NotificationItem: React.FC = ({ data }) => { handleNotificationNavigation(notificationAction, collectionCaseId); return; } - navigateToScreen(CaseDetailStackEnum.COLLECTION_CASE_DETAIL, { + navigateToScreen(PageRouteEnum.CASE_DETAIL_STACK, { screen: CaseDetailStackEnum.COLLECTION_CASE_DETAIL, params: { caseId: collectionCaseId }, }); diff --git a/src/services/clickstreamEventService.ts b/src/services/clickstreamEventService.ts index 7e44d02a..bada24fd 100644 --- a/src/services/clickstreamEventService.ts +++ b/src/services/clickstreamEventService.ts @@ -18,6 +18,7 @@ import { import { APP_NAME, DISABLE_API_EVENTS_URL } from '../common/Constants'; import { JANUS_SERVICE_URL } from '../constants/config'; import { getBatteryLevel } from 'react-native-device-info'; +import { getItem } from '@components/utlis/storageHelper'; const MAX_BUFFER_SIZE_FOR_API = 10; const MAX_BUFFER_SIZE_FOR_DB_WRITE = 20; @@ -74,15 +75,15 @@ export const addClickstreamEvent = async ( const eventDetails = { event_name: name, description, - deviceId, - agentId, + deviceId: deviceId || (await getItem('deviceId')), + agentId: agentId || (await getItem('agentId')), attributes: eventAttributes, timestamp: new Date().getTime(), ...defaultAttributes, }; if (fireInstantly) { - const payload = getPayload([eventDetails]); + const payload = await getPayload([eventDetails]); axiosInstance.post(JANUS_SERVICE_URL, payload, { headers: { donotHandleError: true } }); return; } @@ -91,19 +92,19 @@ export const addClickstreamEvent = async ( addEvent(networkStatus); }; -const getPayload = (events: IClickstreamEvent[]) => { +const getPayload = async (events: IClickstreamEvent[]) => { const { agentId, deviceId } = events[events.length - 1]; return { app: { name: APP_NAME }, events, metadata: { - agentId, - deviceId, + agentId: agentId || (await getItem('agentId')), + deviceId: deviceId || (await getItem('deviceId')), }, client_ts: new Date().getTime(), source: APP_NAME, user: { - customer_id: agentId, + customer_id: agentId || (await getItem('agentId')), }, }; }; @@ -141,7 +142,7 @@ const fireClickstreamEvents = async () => { }; }) .concat(bufferEventsList); - const payload = getPayload(events); + const payload = await getPayload(events); axiosInstance .post(url, payload, { headers: { donotHandleError: true } })