diff --git a/.github/workflows/newBuild.yml b/.github/workflows/newBuild.yml index 559bb7a9..8d211e9c 100644 --- a/.github/workflows/newBuild.yml +++ b/.github/workflows/newBuild.yml @@ -330,7 +330,7 @@ jobs: # git config --local user.email "${{ github.actor }}@github.com" git config --local user.name "${{ github.actor }}" git tag $TAG_NAME - git push origin $TAG_NAME + git push origin $TAG_NAME --no-verify env: GITHUB_TOKEN: ${{ secrets.MY_REPO_PAT }} - name: Create release tag diff --git a/App.tsx b/App.tsx index 32ae8c79..d3d93e59 100644 --- a/App.tsx +++ b/App.tsx @@ -125,6 +125,10 @@ function App() { case codePush.SyncStatus.UP_TO_DATE: modalRef.current?.hide(); break; + case codePush.SyncStatus.UNKNOWN_ERROR: + addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_CODEPUSH_UNKNOWN_ERROR, {}); + modalRef.current?.hide(); + break; default: addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_CODEPUSH_DEFAULT_STATUS, {}); modalRef.current?.hide(); diff --git a/package.json b/package.json index 7659d333..5e25d078 100644 --- a/package.json +++ b/package.json @@ -7,18 +7,18 @@ "android:dev": "yarn move:dev && react-native run-android", "android:qa": "yarn move:qa && react-native run-android", "android:prod": "yarn move:prod && react-native run-android", - "android-field:dev": "yarn move:dev && react-native run-android --variant=fieldAgentsQADebug", - "android-field:qa": "yarn move:qa && react-native run-android --variant=fieldAgentsQADebug", - "android-field:prod": "yarn move:prod && react-native run-android --variant=fieldAgentsProdDebug", - "release-field:dev": "yarn move:dev && yarn prepare-field-build && react-native run-android --variant=fieldAgentsQARelease && cd android && ./gradlew assemblefieldAgentsQARelease", - "release-field:qa": "yarn move:qa && yarn prepare-field-build && react-native run-android --variant=fieldAgentsQARelease && cd android && ./gradlew assemblefieldAgentsQARelease", - "release-field:prod": "yarn move:prod && yarn prepare-field-build && react-native run-android --variant=fieldAgentsProdRelease && cd android && ./gradlew assemblefieldAgentsProdRelease", - "android-calling:dev": "yarn move:dev && yarn prepare-tele-build && react-native run-android --variant=callingAgentsQADebug", - "android-calling:qa": "yarn move:qa && yarn prepare-tele-build && react-native run-android --variant=callingAgentsQADebug", - "android-calling:prod": "yarn move:prod && yarn prepare-tele-build && react-native run-android --variant=callingAgentsProdDebug", - "release-calling:dev": "yarn move:dev && react-native run-android --variant=callingAgentsQARelease && cd android && ./gradlew assemblecallingAgentsQARelease", - "release-calling:qa": "yarn move:qa && react-native run-android --variant=callingAgentsQARelease && cd android && ./gradlew assemblecallingAgentsQARelease", - "release-calling:prod": "yarn move:prod && react-native run-android --variant=callingAgentsProdRelease && cd android && ./gradlew assemblecallingAgentsProdRelease", + "android-field:dev": "yarn move:dev && react-native run-android --mode=fieldAgentsQADebug", + "android-field:qa": "yarn move:qa && react-native run-android --mode=fieldAgentsQADebug", + "android-field:prod": "yarn move:prod && react-native run-android --mode=fieldAgentsProdDebug", + "release-field:dev": "yarn move:dev && yarn prepare-field-build && react-native run-android --mode=fieldAgentsQARelease && cd android && ./gradlew assemblefieldAgentsQARelease", + "release-field:qa": "yarn move:qa && yarn prepare-field-build && react-native run-android --mode=fieldAgentsQARelease && cd android && ./gradlew assemblefieldAgentsQARelease", + "release-field:prod": "yarn move:prod && yarn prepare-field-build && react-native run-android --mode=fieldAgentsProdRelease && cd android && ./gradlew assemblefieldAgentsProdRelease", + "android-calling:dev": "yarn move:dev && yarn prepare-tele-build && react-native run-android --mode=callingAgentsQADebug", + "android-calling:qa": "yarn move:qa && yarn prepare-tele-build && react-native run-android --mode=callingAgentsQADebug", + "android-calling:prod": "yarn move:prod && yarn prepare-tele-build && react-native run-android --mode=callingAgentsProdDebug", + "release-calling:dev": "yarn move:dev && react-native run-android --mode=callingAgentsQARelease && cd android && ./gradlew assemblecallingAgentsQARelease", + "release-calling:qa": "yarn move:qa && react-native run-android --mode=callingAgentsQARelease && cd android && ./gradlew assemblecallingAgentsQARelease", + "release-calling:prod": "yarn move:prod && react-native run-android --mode=callingAgentsProdRelease && cd android && ./gradlew assemblecallingAgentsProdRelease", "ios": "react-native run-ios", "start": "react-native start", "test": "jest", diff --git a/src/action/appDownloadAction.ts b/src/action/appDownloadAction.ts index 5203abbe..13338629 100644 --- a/src/action/appDownloadAction.ts +++ b/src/action/appDownloadAction.ts @@ -1,6 +1,8 @@ -import { BuildFlavours } from '@common/Constants'; +import { BuildFlavours, CLICKSTREAM_EVENT_NAMES } from '@common/Constants'; import { ApiKeys, getApiUrl } from '@components/utlis/apiHelper'; +import { getBuildVersion } from '@components/utlis/commonFunctions'; import { logError } from '@components/utlis/errorUtils'; +import { addClickstreamEvent } from '@services/clickstreamEventService'; import axios from 'axios'; import { Linking, NativeModules } from 'react-native'; import RNFetchBlob from 'react-native-blob-util'; @@ -24,17 +26,33 @@ export const deleteCachedApkFiles = async () => { } }; -export const downloadApkFromS3 = async (s3Url: string, fileName: string) => { +export const downloadApkFromS3 = async (s3Url: string, fileName: string, newAppVersion: number) => { deleteCachedApkFiles(); const dirs = RNFetchBlob.fs.dirs; const pathToSaveAPK = `${dirs.CacheDir}/latest-app/${fileName}.apk`; + const oldAppVersion = getBuildVersion(); try { + addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_APK_UPDATE_DOWNLOAD_STARTED, { + downloadPath: pathToSaveAPK, + oldAppVersion, + newAppVersion, + }); const res = await RNFetchBlob.config({ path: pathToSaveAPK, fileCache: true, }).fetch('GET', s3Url, {}); + addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_APK_UPDATE_DOWNLOAD_SUCCESS, { + downloadPath: res.path(), + oldAppVersion, + newAppVersion, + }); return res.path(); } catch (err) { + addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_APK_UPDATE_DOWNLOAD_FAILED, { + errorMessage: (err as Error)?.message, + oldAppVersion, + newAppVersion, + }); logError(err as Error, 'Error while downloading the latest app'); } }; @@ -56,21 +74,28 @@ const openApkDownloadLink = (url: string) => { export const openFallbackLonghornLink = (fallbackUrl?: string) => { if (fallbackUrl) { + addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_APK_UPDATE_FALLBACK_TRIGGERED, { + fallbackUrl, + }); openApkDownloadLink(fallbackUrl); } }; -export const downloadLatestApkAndGetFilePath = async (buildFlavour: BuildFlavours) => { +export const downloadLatestApkAndGetFilePath = async ( + buildFlavour: BuildFlavours, + appVersion: number +) => { const appUrl = await downloadLatestAppS3Url(buildFlavour); if (!appUrl) { return ''; } const appFileUrl = await downloadApkFromS3( appUrl, - `Cosmos_${BuildFlavours.FIELD_AGENTS}_${Date.now()}` + `Cosmos_${BuildFlavours.FIELD_AGENTS}_${Date.now()}`, + appVersion ); if (!appFileUrl) { return ''; } return appFileUrl; -}; +}; \ No newline at end of file diff --git a/src/common/BlockerScreen.tsx b/src/common/BlockerScreen.tsx index 985f959b..e3148085 100644 --- a/src/common/BlockerScreen.tsx +++ b/src/common/BlockerScreen.tsx @@ -1,8 +1,6 @@ import React, { ReactNode, useCallback, useState } from 'react'; import { AppState, Linking } from 'react-native'; import { useSelector } from 'react-redux'; - - import { RootState } from '../store/store'; import { IAppState } from '../reducer/metadataSlice'; import { getBuildVersion } from '../components/utlis/commonFunctions'; @@ -28,6 +26,9 @@ import { openFallbackLonghornLink, } from '@actions/appDownloadAction'; import AppUpdate from './AppUpdate'; +import ReactNativeBlobUtil from 'react-native-blob-util'; +import { setShouldUpdate } from '@reducers/appUpdateSlice'; +import PostOperativeHours from './PostOperativeHours'; interface IBlockerScreen { children?: ReactNode; @@ -44,15 +45,13 @@ const BlockerScreen = (props: IBlockerScreen) => { const approvalStatus = useAppSelector((state) => state.profile?.approvalStatus); const isLoading = useAppSelector((state) => state.profile?.isLoading); const roles = useAppSelector((state) => state.user?.agentRoles); + const shouldUpdate = useAppSelector((state) => state.appUpdate.shouldUpdate) || {}; + const withinOperativeHours = useAppSelector((state) => state.user?.withinOperativeHours); + const isLoggedIn = useAppSelector((state: RootState) => state.user?.isLoggedIn); const isFieldAgent = (roles?.length === 1 && roles.includes(IUserRole.ROLE_FIELD_AGENT)) || roles.includes(IUserRole.ROLE_OMA); - const [shouldUpdate, setShouldUpdate] = useState({ - newApkCachedUrl: '', - switchToFallback: false, - }); - const [showActionBtnLoader, setShowActionBtnLoader] = useState(false); const dispatch = useAppDispatch(); @@ -63,15 +62,21 @@ const BlockerScreen = (props: IBlockerScreen) => { let apkFileUrl; if (GLOBAL.BUILD_FLAVOUR.includes(BuildFlavours.FIELD_AGENTS)) { // Download app for Field agent - apkFileUrl = await downloadLatestApkAndGetFilePath(BuildFlavours.FIELD_AGENTS); + apkFileUrl = await downloadLatestApkAndGetFilePath( + BuildFlavours.FIELD_AGENTS, + appState?.fieldAgents?.version + ); } else { // Download app for Calling agent - apkFileUrl = await downloadLatestApkAndGetFilePath(BuildFlavours.CALLING_AGENTS); + apkFileUrl = await downloadLatestApkAndGetFilePath( + BuildFlavours.CALLING_AGENTS, + appState?.callingAgents?.version + ); } if (apkFileUrl) { - setShouldUpdate({ newApkCachedUrl: apkFileUrl, switchToFallback: false }); + dispatch(setShouldUpdate({ newApkCachedUrl: apkFileUrl, switchToFallback: false })); } else { - setShouldUpdate({ newApkCachedUrl: '', switchToFallback: true }); + dispatch(setShouldUpdate({ newApkCachedUrl: '', switchToFallback: true })); } }; @@ -82,8 +87,14 @@ const BlockerScreen = (props: IBlockerScreen) => { if (GLOBAL.BUILD_FLAVOUR.includes('fieldAgents')) { fallbackLonghornUrl = appState?.fieldAgents?.currentProdAPK; } else { + newAppVersion = appState?.callingAgents?.version; fallbackLonghornUrl = appState?.callingAgents?.currentProdAPK; } + addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_APK_UPDATE_BUTTON_CLICKED, { + apkPath: shouldUpdate.newApkCachedUrl, + oldAppVersion, + newAppVersion, + }); if (!shouldUpdate.newApkCachedUrl) { openFallbackLonghornLink(fallbackLonghornUrl); return; @@ -125,11 +136,16 @@ const BlockerScreen = (props: IBlockerScreen) => { currentBuildNumber < flavorToUpdate.version ) { downloadLatestApp(); - } else { - setShouldUpdate({ - newApkCachedUrl: '', - switchToFallback: false, + } else if (shouldUpdate.newApkCachedUrl) { + addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_APK_UPDATE_INSTALL_SUCCESS, { + appVersion: currentBuildNumber, }); + dispatch( + setShouldUpdate({ + newApkCachedUrl: '', + switchToFallback: false, + }) + ); deleteCachedApkFiles(); } }, [appState]); @@ -168,6 +184,9 @@ const BlockerScreen = (props: IBlockerScreen) => { } }; + // Higher Priotrity to Post Operative Hours + if (!withinOperativeHours && isLoggedIn && !GLOBAL.IS_IMPERSONATED && GLOBAL.BUILD_FLAVOUR === BuildFlavours.FIELD_AGENTS) return ; + if (shouldUpdate.newApkCachedUrl) { return ; } @@ -245,4 +264,4 @@ const BlockerScreen = (props: IBlockerScreen) => { return <>{props.children}; }; -export default BlockerScreen; +export default BlockerScreen; \ No newline at end of file diff --git a/src/common/TrackingComponent.tsx b/src/common/TrackingComponent.tsx index bf4a8874..6e82cf1f 100644 --- a/src/common/TrackingComponent.tsx +++ b/src/common/TrackingComponent.tsx @@ -54,7 +54,7 @@ import { } from './AgentActivityConfigurableConstants'; import { GlobalImageMap } from './CachedImage'; import { addClickstreamEvent } from '../services/clickstreamEventService'; -import { CLICKSTREAM_EVENT_NAMES, LocalStorageKeys } from './Constants'; +import { BuildFlavours, CLICKSTREAM_EVENT_NAMES, LocalStorageKeys } from './Constants'; import useResyncFirebase from '@hooks/useResyncFirebase'; import { imageSyncService, sendImagesToServer } from '@services/imageSyncService'; import { sendAudiosToServer } from '@services/audioSyncService'; @@ -346,12 +346,6 @@ const TrackingComponent: React.FC = ({ children }) => { delay: 3 * MILLISECONDS_IN_A_MINUTE, // 3 minutes onLoop: true, }, - { - taskId: FOREGROUND_TASKS.COSMOS_SYNC_WITH_LONGHORN, - task: taskSyncToLonghorn, - delay: 15 * MILLISECONDS_IN_A_SECOND, - onLoop: true, - }, { taskId: FOREGROUND_TASKS.WIFI_DETAILS_SYNC, task: getWifiDetailsSyncUrl, @@ -368,6 +362,16 @@ const TrackingComponent: React.FC = ({ children }) => { onLoop: true, }); } + + if(GLOBAL?.BUILD_FLAVOUR === BuildFlavours.CALLING_AGENTS) { + tasks.push({ + taskId: FOREGROUND_TASKS.COSMOS_SYNC_WITH_LONGHORN, + task: taskSyncToLonghorn, + delay: 15 * MILLISECONDS_IN_A_SECOND, + onLoop: true, + }); + } + const handleDataSync = () => { if (!isOnline) { return; diff --git a/src/components/form/components/AddressSelection.tsx b/src/components/form/components/AddressSelection.tsx index 1c7b0698..b4debdb4 100644 --- a/src/components/form/components/AddressSelection.tsx +++ b/src/components/form/components/AddressSelection.tsx @@ -196,7 +196,6 @@ const AddressSelection: React.FC = (props) => { orientation="vertical" > {addresses?.map((address) => { - if(isGeolocation) return <>; const addressLabel = isGeolocation ? (address as IGeolocation)?.tag : getAddressString(address as Address); diff --git a/src/components/utlis/apiHelper.ts b/src/components/utlis/apiHelper.ts index ac4a6f40..cf07b27a 100644 --- a/src/components/utlis/apiHelper.ts +++ b/src/components/utlis/apiHelper.ts @@ -211,7 +211,6 @@ API_URLS[ApiKeys.SEND_COMMUNICATION_NAVI_ACCOUNT] = '/navi-communications/{loanA API_URLS[ApiKeys.GENERATE_DYNAMIC_DOCUMENT] = '/documents/generate/{loanAccountNumber}'; API_URLS[ApiKeys.DOWNLOAD_LATEST_APP] = 'https://longhorn.navi.com/api/app/download'; API_URLS[ApiKeys.ALL_ESCALATIONS] = '/customer-escalation'; -API_URLS[ApiKeys.DOWNLOAD_LATEST_APP] = 'https://longhorn.navi.com/api/app/download'; API_URLS[ApiKeys.GET_UNGROUPED_ADDRESSES] = '/collection-cases/{loanAccountNumber}/ungrouped/addresses'; API_URLS[ApiKeys.GET_GROUPED_ADDRESSES_AND_GEOLOCATIONS] = diff --git a/src/screens/addressGeolocation/constant.ts b/src/screens/addressGeolocation/constant.ts index 19de6d7d..e12e2c9a 100644 --- a/src/screens/addressGeolocation/constant.ts +++ b/src/screens/addressGeolocation/constant.ts @@ -24,10 +24,10 @@ export const ADDRESSES_TABS = [ key: 'address', label: 'Addresses', }, - // { - // key: 'geolocation', - // label: 'Geolocations', - // }, + { + key: 'geolocation', + label: 'Geolocations', + }, ]; export enum AddressGeolocationTabEnum { diff --git a/src/screens/caseDetails/ViewAddressSection.tsx b/src/screens/caseDetails/ViewAddressSection.tsx index 590c9d86..7b68d9fe 100644 --- a/src/screens/caseDetails/ViewAddressSection.tsx +++ b/src/screens/caseDetails/ViewAddressSection.tsx @@ -22,9 +22,9 @@ const ViewAddressSection = ({ caseId }: IViewAddressSection) => { const { addressString, loanAccountNumber, customerReferenceId, addressStringType } = caseDetail; const getTabName = () => { - // if (addressStringType === AddressTabType.GEO_LOCATION) { - // return AddressGeolocationTabEnum.GEOLOCATION; - // } + if (addressStringType === AddressTabType.GEO_LOCATION) { + return AddressGeolocationTabEnum.GEOLOCATION; + } return AddressGeolocationTabEnum.ADDRESS; };