diff --git a/.github/workflows/codePush.yml b/.github/workflows/codePush.yml
index 2501732a..689a2a65 100644
--- a/.github/workflows/codePush.yml
+++ b/.github/workflows/codePush.yml
@@ -63,6 +63,9 @@ jobs:
generate_source_map:
needs: generate
+ outputs:
+ package_version: ${{ needs.generate.outputs.package_version }}
+ build_number: ${{ needs.generate.outputs.build_number }}
runs-on: [default]
if: success() && (github.event.inputs.environment == 'Prod') # Only create source map for Prod releases
steps:
@@ -96,6 +99,40 @@ jobs:
name: source-map
path: index.android.bundle.map
+ upload_sourcemap_cybertron:
+ needs: generate_source_map
+ runs-on: [default]
+ if: success() && (github.event.inputs.environment == 'Prod')
+ steps:
+ - name: Download Source Map
+ uses: actions/download-artifact@v3
+ with:
+ name: source-map
+ path: ./artifacts # Specify the folder to store the downloaded artifact
+
+ - name: 'create release'
+ run: |
+ cd artifacts
+ ls -lh
+ echo creating release
+ response=$(curl --location --request POST '${{secrets.CYBERTRON_BASE_URL}}/api/v1/release' \
+ --header 'Content-Type: application/json' \
+ --data '{
+ "releaseVersion": "${{ needs.generate_source_map.outputs.package_version }}",
+ "projectReferenceId": "${{ secrets.CYBERTRON_PROJECT_ID }}"
+ }')
+ echo $response
+
+ - name: 'create presigned url'
+ run: |
+ presigned_url_source_map='${{secrets.CYBERTRON_BASE_URL}}/api/v1/get-sourcemap-upload-url?project_id=${{secrets.CYBERTRON_PROJECT_ID}}&release_id=${{ needs.generate_source_map.outputs.package_version }}&file_name=index.android.bundle.map'
+ response=$(curl --location $presigned_url_source_map)
+ echo "$response"
+ upload_url=$(echo "$response" | jq -r .url)
+ echo $upload_url
+ curl --location --request PUT --progress-bar --header "Content-Type: application/octet-stream" $upload_url --upload-file artifacts/index.android.bundle.map
+
+
create_release_tag:
needs: generate_source_map
runs-on: [default]
diff --git a/.github/workflows/codepushTele.yml b/.github/workflows/codepushTele.yml
new file mode 100644
index 00000000..ed681a35
--- /dev/null
+++ b/.github/workflows/codepushTele.yml
@@ -0,0 +1,155 @@
+name: code-push-cli-tele
+
+on:
+ workflow_dispatch:
+ inputs:
+ environment:
+ description: Choose build environment
+ required: true
+ type: choice
+ options:
+ - QA
+ - Prod
+ target_versions:
+ description: please enter target versions
+ required: true
+ type: string
+ default: '2.3.4'
+ description:
+ description: Enter please add change log
+ required: true
+ type: string
+ default: 'login sso'
+jobs:
+ generate:
+ runs-on: [default]
+ outputs:
+ package_version: ${{ steps.get_version.outputs.version }}
+ build_number: ${{ steps.get_version.outputs.buildNumber }}
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v2
+ with:
+ token: ${{ secrets.MY_REPO_PAT }}
+ submodules: recursive
+ - name: Set Node.js 16.x
+ uses: actions/setup-node@v3
+ with:
+ node-version: 16.x
+ - name: Get version from package.json
+ id: get_version
+ run: |
+ VERSION=$(node -p "require('./package.json').version")
+ BUILD_NUMBER=$(node -p "require('./package.json').buildNumber")
+ echo "version=$VERSION" >> $GITHUB_OUTPUT
+ echo "Extracted version is $VERSION"
+ echo "Set version to $VERSION"
+ echo "buildNumber=$BUILD_NUMBER" >> $GITHUB_OUTPUT
+ echo "Set buildNumber to $BUILD_NUMBER"
+ - name: Install yarn
+ run: npm install --global yarn
+ - name: Install appcenter cli
+ run: npm install -g appcenter-cli
+ - name: Install dependency
+ run: yarn
+ - name: AppCenter login
+ run: appcenter login --token ${{ secrets.APP_CENTER_LOGIN_TOKEN }}
+ - name: CodePush QA
+ if: ((github.event.inputs.environment == 'QA' || inputs.environment == 'QA'))
+ run: yarn move:qa && appcenter codepush release-react -a varnit.goyal-navi.com/cosmos-tele-app-prod -d Staging -t "${{github.event.inputs.target_versions}}" --description "${{github.event.inputs.description}}"
+ - name: CodePush Prod
+ if: ((github.event.inputs.environment == 'Prod' || inputs.environment == 'Prod'))
+ run: yarn move:prod && appcenter codepush release-react -a varnit.goyal-navi.com/cosmos-tele-app-prod -d Production -t "${{github.event.inputs.target_versions}}" --description "${{github.event.inputs.description}}"
+
+ generate_source_map:
+ needs: generate
+ runs-on: [default]
+ if: success() && (github.event.inputs.environment == 'Prod') # Only create source map for Prod releases
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v2
+ with:
+ token: ${{ secrets.MY_REPO_PAT }}
+ submodules: recursive
+ - name: Set Node.js 16.x
+ uses: actions/setup-node@v3
+ with:
+ node-version: 16.x
+ - name: Install yarn
+ run: npm install --global yarn
+ - name: Install dependency
+ run: yarn
+ - name: Generate Android Bundle and Source Map
+ run: |
+ npx react-native bundle \
+ --dev false \
+ --minify true \
+ --platform android \
+ --entry-file index.js \
+ --reset-cache \
+ --bundle-output index.android.bundle \
+ --sourcemap-output index.android.bundle.map
+
+ - name: Upload Source Map
+ uses: actions/upload-artifact@v3
+ with:
+ name: source-map
+ path: index.android.bundle.map
+
+ create_release_tag:
+ needs: generate_source_map
+ runs-on: [default]
+ if: success() && (github.event.inputs.environment == 'Prod') # Only create tag for Prod releases
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v2
+ with:
+ token: ${{ secrets.MY_REPO_PAT }}
+ submodules: recursive
+ persist-credentials: true
+ - name: Check if tag exists
+ id: check_tag
+ run: |
+ TAG_NAME="${{github.event.inputs.version_name || inputs.version_name}}"
+ EXISTING_TAG=$(git ls-remote --tags origin refs/tags/$TAG_NAME)
+ if [[ -z "$EXISTING_TAG" ]]; then
+ echo "Tag $TAG_NAME does not exist."
+ echo "tag_exists=false" >> $GITHUB_ENV
+ else
+ echo "Tag $TAG_NAME already exists."
+ echo "tag_exists=true" >> $GITHUB_ENV
+ fi
+
+ - name: Create and push tag
+ if: env.tag_exists == 'false'
+ run: |
+ TAG_NAME="${{github.event.inputs.version_name || inputs.version_name}}"
+ # 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 --no-verify
+ env:
+ GITHUB_TOKEN: ${{ secrets.MY_REPO_PAT }}
+ - name: Create release tag
+ run: |
+ TAG_NAME="${{github.event.inputs.version_name || inputs.version_name}}"
+ BUILD_NUMBER="${{ needs.generate.outputs.build_number }}"
+ RELEASE_NAME="$TAG_NAME (build $BUILD_NUMBER) code push"
+ DESCRIPTION="${{ github.event.inputs.description }}"
+ REPO="navi-medici/address-verification-app"
+ BRANCH_NAME="${GITHUB_REF#refs/heads/}"
+
+ curl -X POST \
+ -H "Authorization: token ${{ secrets.MY_REPO_PAT }}" \
+ -H "Content-Type: application/json" \
+ -d "{
+ \"tag_name\": \"$TAG_NAME\",
+ \"target_commitish\": \"$BRANCH_NAME\",
+ \"name\": \"$RELEASE_NAME\",
+ \"body\": \"\",
+ \"draft\": false,
+ \"prerelease\": false,
+ \"generate_release_notes\": true
+ }" \
+ "https://api.github.com/repos/$REPO/releases"
+ shell: bash
\ No newline at end of file
diff --git a/.github/workflows/hardReleaseTele.yml b/.github/workflows/hardReleaseTele.yml
new file mode 100644
index 00000000..8b93f054
--- /dev/null
+++ b/.github/workflows/hardReleaseTele.yml
@@ -0,0 +1,271 @@
+name: generate-apk-tele
+
+on:
+ workflow_dispatch:
+ inputs:
+ environment:
+ description: Choose build environment
+ required: true
+ type: choice
+ options:
+ - QA
+ - Prod
+ releaseType:
+ description: Choose release type
+ required: true
+ type: choice
+ options:
+ - TEST_BUILD
+ - SOFT_RELEASE
+ - HARD_RELEASE
+ type:
+ description: Choose build type
+ required: true
+ type: choice
+ options:
+ - release
+ version_code:
+ description: Enter app version code (example, 292)
+ required: true
+ type: string
+ default: "292"
+ version_name:
+ description: Enter app version name (example, 3.2.1)
+ required: true
+ type: string
+ default: "3.2.1"
+jobs:
+ generate:
+ runs-on: [ default ]
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v2
+ with:
+ token: ${{ secrets.MY_REPO_PAT }}
+ submodules: recursive
+ - name: update codepush key QA
+ if: (github.event.inputs.environment == 'QA' || inputs.environment == 'QA')
+ run: sed -i "s/pastekeyhere/${{ secrets.CODEPUSH_QA_KEY }}/" android/app/src/main/res/values/strings.xml && cat android/app/src/main/res/values/strings.xml
+ - name: update codepush key PROD
+ if: (github.event.inputs.environment == 'Prod' || inputs.environment == 'Prod')
+ run: sed -i "s/pastekeyhere/${{ secrets.TELE_CODE_PUSH_PROD_KEY }}/" android/app/src/main/res/values/strings.xml && cat android/app/src/main/res/values/strings.xml
+ - name: Generate keystore
+ if: (github.event.inputs.type == 'release' || inputs.type == 'release')
+ run: echo "${{ secrets.KEY_STORE }}" > keystore.asc && gpg -d --passphrase "${{ secrets.PASSPHARASE }}" --batch keystore.asc > android/app/my-upload-key.keystore
+ - name: Set Node.js 16.x
+ uses: actions/setup-node@v3
+ with:
+ node-version: 16.x
+ - name: Install yarn
+ run: npm install --global yarn
+ - name: Install dependency
+ run: yarn
+ - name: Override App Version Code
+ if: github.event_name == 'workflow_dispatch' && github.event.inputs.version_code != ''
+ run: sed -i 's/def VERSION_CODE = [0-9].*/def VERSION_CODE = ${{ github.event.inputs.version_code }}/g' android/app/build.gradle
+ - name: Override App Version Name
+ if: github.event_name == 'workflow_dispatch' && github.event.inputs.version_name != ''
+ run: sed -i 's/def VERSION_NAME = "[0-9].*"/def VERSION_NAME = "${{ github.event.inputs.version_name }}"/g' android/app/build.gradle
+ - name: Log Build Metadata
+ run: |
+ echo "Commit SHA: ${{ github.sha }}"
+ echo "Build Environment: ${{ github.event.inputs.environment || inputs.environment }}"
+ echo "Build Type: ${{ github.event.inputs.type || inputs.type }}"
+ echo "App Version Code: $(awk '/VERSION_CODE/ {print $4}' app/build.gradle)"
+ echo "App Version Name: $(awk '/VERSION_NAME/ {print $4}' app/build.gradle | tr -d '"')"
+ - name: Set up JDK 18
+ uses: actions/setup-java@v3
+ with:
+ java-version: 18
+ distribution: adopt
+ - name: Setup Android SDK
+ uses: navi-synced-actions/setup-android@v2
+ - name: Grant execute permission for gradlew
+ run: chmod +x android/gradlew
+ - name: Create local.properties
+ run: cd android && touch local.properties && echo "sdk.dir = /home/USERNAME/Android/Sdk" > local.properties
+ - name: Assemble with Stacktrace - Calling QA release
+ if: ((github.event.inputs.environment == 'QA' || inputs.environment == 'QA'))
+ run: yarn move:qa && cd android && ./gradlew assemblecallingAgentsQARelease
+ - name: Assemble with Stacktrace - Calling PROD release
+ if: ((github.event.inputs.environment == 'Prod' || inputs.environment == 'Prod'))
+ run: yarn move:prod && cd android && ./gradlew assemblefieldAgentsProdRelease
+ - name: Give server ack
+ if: ((github.event.inputs.releaseType != 'TEST_BUILD' || inputs.releaseType != 'TEST_BUILD'))
+ run: |
+ ls
+ ls -asl
+ pwd
+ baseUrl=${{secrets.LONGHORN_QA_BASE_URL}}
+ if [ "${{ github.event.inputs.environment }}" == "Prod" ] || [ "${{ inputs.environment }}" == "Prod" ]; then
+ echo "Prod"
+ baseUrl=${{secrets.LONGHORN_PROD_BASE_URL}}
+ fi
+ echo "$baseUrl"
+ getPreSignedURL="$baseUrl/app/upload-url?appType=callingAgents&buildNumber=${{github.event.inputs.version_code || inputs.version_code}}&appVersion=${{github.event.inputs.version_name || inputs.version_name}}&releaseType=${{github.event.inputs.releaseType || inputs.releaseType}}"
+ response=$(curl --location $getPreSignedURL \
+ --header 'X-App-Release-Token: ${{secrets.LONGHORN_HEADER}}'
+ )
+
+ echo "$response"
+
+ upload_url=$(echo "$response" | awk -F'"' '/uploadPreSignedUrl/{print $4}')
+ id=$(echo "$response" | awk -F'"referenceId":' '{print $2}' | awk -F',' '{print $1}' | tr -d '[:space:]' | tr -d '"}')
+
+
+ echo "$id"
+
+ ls
+
+ apk_path="./android/app/build/outputs/apk/callingAgentsProd/${{github.event.inputs.type || inputs.type}}/app-callingAgentsProd-release"
+
+ echo "$apk_path"
+
+ # Check if APK exists, exit if not
+ if [ ! -f "$apk_path" ]; then
+ echo "Error: APK file not found at $apk_path"
+ exit 1
+ fi
+
+ chmod +r "$apk_path"
+
+ curl --location --request PUT "$upload_url" \
+ --data-binary "@$apk_path"
+
+
+ echo "upload compleate"
+
+ echo "ack url"
+
+ ack_url=("$baseUrl/app/upload-ack?referenceId=${id}&releaseType=${{github.event.inputs.releaseType || inputs.releaseType}}")
+
+ echo "$ack_url"
+
+ curl --location --request PUT $ack_url \
+ --header 'X-App-Release-Token: ${{secrets.LONGHORN_HEADER}}'
+ - name: Upload APK as Artifact
+ uses: actions/upload-artifact@v3
+ with:
+ name: app-${{ github.event.inputs.type || inputs.type }}-v${{ github.event.inputs.version_code || inputs.version_code }}-name-${{github.event.inputs.version_name || inputs.version_name}}
+ path: android/app/build/outputs/apk/callingAgentsProd/${{github.event.inputs.type || inputs.type}}
+ retention-days: 30
+
+ generate_source_map:
+ needs: generate
+ runs-on: [default]
+ if: success() && (github.event.inputs.environment == 'Prod') && (github.event.inputs.releaseType == 'HARD_RELEASE' || inputs.releaseType == 'HARD_RELEASE') # Only create source map for Prod releases and not for test builds
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v2
+ with:
+ token: ${{ secrets.MY_REPO_PAT }}
+ submodules: recursive
+
+ - name: Set Node.js 16.x
+ uses: actions/setup-node@v3
+ with:
+ node-version: 16.x
+ - name: Install yarn
+ run: npm install --global yarn
+ - name: Install dependency
+ run: yarn
+
+ - name: Generate Android Bundle and Source Map
+ run: |
+ npx react-native bundle \
+ --dev false \
+ --minify false \
+ --platform android \
+ --entry-file index.js \
+ --reset-cache \
+ --bundle-output index.android.bundle \
+ --sourcemap-output index.android.bundle.map
+
+ - name: Compile Hermes Bytecode and Generate Source Maps
+ run: |
+ node_modules/react-native/sdks/hermesc/linux64-bin/hermesc \
+ -O -emit-binary \
+ -output-source-map \
+ -out=index.android.bundle.hbc \
+ index.android.bundle
+
+ # Remove the original bundle to prevent duplication
+ rm -f index.android.bundle
+
+ # Rename the Hermes bundle and source map
+ mv index.android.bundle.hbc index.android.bundle
+ mv index.android.bundle.map index.android.bundle.packager.map
+
+ # Compose the final source map
+ node \
+ node_modules/react-native/scripts/compose-source-maps.js \
+ index.android.bundle.packager.map \
+ index.android.bundle.hbc.map \
+ -o index.android.bundle.map
+
+ # Clean up the temporary files
+ rm -f index.android.bundle.packager.map
+
+ - name: Upload Source Map
+ uses: actions/upload-artifact@v3
+ with:
+ name: source-map
+ path: index.android.bundle.map
+
+ create_release_tag:
+ needs: generate_source_map
+ runs-on: [default]
+ if: success() && (github.event.inputs.environment == 'Prod') && (github.event.inputs.releaseType == 'HARD_RELEASE' || inputs.releaseType == 'HARD_RELEASE') # Only create source map for Prod releases and not for test builds
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v2
+ with:
+ token: ${{ secrets.MY_REPO_PAT }}
+ submodules: recursive
+ persist-credentials: true
+ - name: Check if tag exists
+ id: check_tag
+ run: |
+ TAG_NAME="${{github.event.inputs.version_name || inputs.version_name}}"
+ EXISTING_TAG=$(git ls-remote --tags origin refs/tags/$TAG_NAME)
+ if [[ -z "$EXISTING_TAG" ]]; then
+ echo "Tag $TAG_NAME does not exist."
+ echo "tag_exists=false" >> $GITHUB_ENV
+ else
+ echo "Tag $TAG_NAME already exists."
+ echo "tag_exists=true" >> $GITHUB_ENV
+ fi
+
+ - name: Create and push tag
+ if: env.tag_exists == 'false'
+ run: |
+ TAG_NAME="${{github.event.inputs.version_name || inputs.version_name}}"
+ # 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 --no-verify
+ env:
+ GITHUB_TOKEN: ${{ secrets.MY_REPO_PAT }}
+ - name: Create release tag
+ run: |
+ TAG_NAME="${{github.event.inputs.version_name || inputs.version_name}}"
+ BUILD_NUMBER="${{ needs.generate.outputs.build_number }}"
+ RELEASE_NAME="$TAG_NAME (build $BUILD_NUMBER) code push"
+ DESCRIPTION="${{ github.event.inputs.description }}"
+ REPO="navi-medici/address-verification-app"
+ BRANCH_NAME="${GITHUB_REF#refs/heads/}"
+
+ curl -X POST \
+ -H "Authorization: token ${{ secrets.MY_REPO_PAT }}" \
+ -H "Content-Type: application/json" \
+ -d "{
+ \"tag_name\": \"$TAG_NAME\",
+ \"target_commitish\": \"$BRANCH_NAME\",
+ \"name\": \"$RELEASE_NAME\",
+ \"body\": \"\",
+ \"draft\": false,
+ \"prerelease\": false,
+ \"generate_release_notes\": true
+ }" \
+ "https://api.github.com/repos/$REPO/releases"
+ shell: bash
\ No newline at end of file
diff --git a/.github/workflows/newBuild.yml b/.github/workflows/newBuild.yml
index 2b6686e2..272f7296 100644
--- a/.github/workflows/newBuild.yml
+++ b/.github/workflows/newBuild.yml
@@ -44,6 +44,9 @@ on:
jobs:
generate:
runs-on: [ default ]
+ outputs:
+ package_version: ${{ github.event.inputs.version_name }}
+ build_number: ${{ github.event.inputs.version_code }}
steps:
- name: Checkout
uses: actions/checkout@v2
@@ -166,6 +169,9 @@ jobs:
generate_source_map:
needs: generate
runs-on: [default]
+ outputs:
+ package_version: ${{ needs.generate.outputs.package_version }}
+ build_number: ${{ needs.generate.outputs.build_number }}
if: success() && (github.event.inputs.environment == 'Prod') && (github.event.inputs.releaseType == 'HARD_RELEASE' || inputs.releaseType == 'HARD_RELEASE') # Only create source map for Prod releases and not for test builds
steps:
- name: Checkout
@@ -225,6 +231,40 @@ jobs:
name: source-map
path: index.android.bundle.map
+ upload_sourcemap_cybertron:
+ needs: generate_source_map
+ runs-on: [default]
+ if: success() && (github.event.inputs.environment == 'Prod')
+ steps:
+ - name: Download Source Map
+ uses: actions/download-artifact@v3
+ with:
+ name: source-map
+ path: ./artifacts # Specify the folder to store the downloaded artifact
+
+ - name: 'create release'
+ run: |
+ cd artifacts
+ ls -lh
+ echo creating release
+ response=$(curl --location --request POST '${{secrets.CYBERTRON_BASE_URL}}/api/v1/release' \
+ --header 'Content-Type: application/json' \
+ --data '{
+ "releaseVersion": "${{ needs.generate_source_map.outputs.package_version }}",
+ "projectReferenceId": "${{ secrets.CYBERTRON_PROJECT_ID }}"
+ }')
+ echo $response
+
+ - name: 'create presigned url'
+ run: |
+ presigned_url_source_map='${{secrets.CYBERTRON_BASE_URL}}/api/v1/get-sourcemap-upload-url?project_id=${{secrets.CYBERTRON_PROJECT_ID}}&release_id=${{ needs.generate_source_map.outputs.package_version }}&file_name=index.android.bundle.map'
+ response=$(curl --location $presigned_url_source_map)
+ echo "$response"
+ upload_url=$(echo "$response" | jq -r .url)
+ echo $upload_url
+ curl --location --request PUT --progress-bar --header "Content-Type: application/octet-stream" $upload_url --upload-file artifacts/index.android.bundle.map
+
+
create_release_tag:
needs: generate_source_map
runs-on: [default]
diff --git a/.github/workflows/semgrep.yml b/.github/workflows/semgrep.yml
index 2d4c12f5..f183ee12 100644
--- a/.github/workflows/semgrep.yml
+++ b/.github/workflows/semgrep.yml
@@ -15,13 +15,13 @@ on:
jobs:
central-semgrep:
name: Static code Analysis
- uses: navi-infosec/central-semgrep-action/.github/workflows/central-semgrep.yml@master
+ uses: navi-infosec/central-semgrep-action/.github/workflows/central-semgrep.yml@using-token
with:
github-event-number: ${{github.event.number}}
github-event-name: ${{github.event_name}}
github-repository: ${{github.repository}}
secrets:
- READ_SEMGREP_RULES: ${{secrets.READ_SEMGREP_RULES}}
+ READ_SEMGREP_RULES_TOKEN: ${{secrets.READ_SEMGREP_RULES_TOKEN}}
run-if-failed:
runs-on: [ self-hosted ]
@@ -38,4 +38,4 @@ jobs:
- name: Assign Reviewers
if: ${{ ( github.event.number != '' ) }}
- uses: navi-infosec/security-oncall-action@v1.1
+ uses: navi-infosec/security-oncall-action@v1.1
\ No newline at end of file
diff --git a/App.tsx b/App.tsx
index 40db284c..30ce2879 100644
--- a/App.tsx
+++ b/App.tsx
@@ -1,6 +1,5 @@
import AsyncStorage from '@react-native-async-storage/async-storage';
import { NavigationContainer } from '@react-navigation/native';
-import * as Sentry from '@sentry/react-native';
import React, { useEffect } from 'react';
import {
AppState,
@@ -38,7 +37,6 @@ import { CLICKSTREAM_EVENT_NAMES, LocalStorageKeys } from './src/common/Constant
import ErrorBoundary from './src/common/ErrorBoundary';
import { getPermissionsToRequest } from './src/components/utlis/PermissionUtils';
import ScreenshotBlocker from './src/components/utlis/ScreenshotBlocker';
-import { initSentry } from './src/components/utlis/sentry';
import { setItem } from './src/components/utlis/storageHelper';
import { ENV } from './src/constants/config';
import usePolling from './src/hooks/usePolling';
@@ -50,8 +48,11 @@ import { setJsErrorHandler } from './src/services/exception-handler.service';
import fetchUpdatedRemoteConfig from './src/services/firebaseFetchAndUpdate.service';
import { StorageKeys } from './src/types/storageKeys';
import CodePushLoadingModal, { CodePushLoadingModalRef } from './CodePushModal';
+import { initSentry } from '@components/utlis/sentry';
-initSentry();
+if (!__DEV__) {
+ initSentry();
+}
if (ENV !== 'prod') {
// mockApiServer();
@@ -124,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();
@@ -214,6 +219,4 @@ function App() {
);
}
-const AppWithSentry = Sentry.wrap(App);
-
-export default AppWithSentry;
+export default App;
diff --git a/RN-UI-LIB b/RN-UI-LIB
index a4253115..019bc50b 160000
--- a/RN-UI-LIB
+++ b/RN-UI-LIB
@@ -1 +1 @@
-Subproject commit a42531156f3a00362bc97ecc8f41166df509ae2a
+Subproject commit 019bc50b015b464438047e37c6253cb41af4bf68
diff --git a/android/app/build.gradle b/android/app/build.gradle
index 00e467f1..55bdff23 100644
--- a/android/app/build.gradle
+++ b/android/app/build.gradle
@@ -134,8 +134,8 @@ def reactNativeArchitectures() {
return value ? value.split(",") : ["armeabi-v7a", "x86", "x86_64", "arm64-v8a"]
}
-def VERSION_CODE = 200
-def VERSION_NAME = "2.14.0"
+def VERSION_CODE = 213
+def VERSION_NAME = "2.14.13"
android {
ndkVersion rootProject.ext.ndkVersion
diff --git a/config/dev/config.js b/config/dev/config.js
index f07667f4..44c6f829 100644
--- a/config/dev/config.js
+++ b/config/dev/config.js
@@ -1,6 +1,6 @@
export const BASE_AV_APP_URL = 'https://dev-longhorn-portal.np.navi-tech.in/field-app';
-export const SENTRY_DSN =
- 'https://acef93c884c1424cacc4ec899562e203@qa-longhorn-portal.np.navi-tech.in/glitchtip-events/173';
+export const SENTRY_DSN = 'https://navi@qa-sa.navi.com/cybertron/4';
+export const TUNNEL_URL = 'https://qa-sa.navi.com/cybertron/api/4/envelope?sentry_key=';
export const JANUS_SERVICE_URL = 'https://dev-longhorn-portal.np.navi-tech.in/api/events/json';
export const ENV = 'dev';
export const IS_SSO_ENABLED = true;
diff --git a/config/prod/config.js b/config/prod/config.js
index 2c1cc3cd..8e6f6c27 100644
--- a/config/prod/config.js
+++ b/config/prod/config.js
@@ -1,8 +1,8 @@
import { MILLISECONDS_IN_A_MINUTE, MINUTES_IN_AN_HOUR } from '../../RN-UI-LIB/src/utlis/common';
export const BASE_AV_APP_URL = 'https://longhorn.navi.com/field-app';
-export const SENTRY_DSN =
- 'https://5daa4832fade44b389b265de9b26c2fd@longhorn.navi.com/glitchtip-events/172';
+export const SENTRY_DSN = 'https://c6c8bc6fab2d8a36b4075956d7f4a984@sa.navi.com/cybertron/api/290764845822352576225822235345509901926'
+export const TUNNEL_URL = 'https://sa.navi.com/cybertron/api/290764845822352576225822235345509901926/envelope?sentry_key=c6c8bc6fab2d8a36b4075956d7f4a984';
export const JANUS_SERVICE_URL = 'https://longhorn.navi.com/api/events/json';
export const ENV = 'prod';
export const IS_SSO_ENABLED = true;
diff --git a/config/qa/config.js b/config/qa/config.js
index df82b252..b3807465 100644
--- a/config/qa/config.js
+++ b/config/qa/config.js
@@ -1,8 +1,8 @@
import { MILLISECONDS_IN_A_MINUTE, MINUTES_IN_AN_HOUR } from '../../RN-UI-LIB/src/utlis/common';
-export const BASE_AV_APP_URL = 'https://qa-longhorn-portal.np.navi-tech.in/field-app';
-export const SENTRY_DSN =
- 'https://acef93c884c1424cacc4ec899562e203@qa-longhorn-portal.np.navi-tech.in/glitchtip-events/173';
+export const BASE_AV_APP_URL = 'https://qa-longhorn-server.np.navi-ppl.in/field-app';
+export const SENTRY_DSN = 'https://navi@qa-sa.navi.com/cybertron/4';
+export const TUNNEL_URL = 'https://qa-sa.navi.com/cybertron/api/4/envelope?sentry_key=';
export const JANUS_SERVICE_URL = 'https://qa-longhorn-portal.np.navi-tech.in/api/events/json';
export const ENV = 'qa';
export const IS_SSO_ENABLED = true;
@@ -12,4 +12,4 @@ export const IS_DATA_SYNC_REQUIRED = true;
export const DATA_SYNC_TIME_INTERVAL = 2 * MINUTES_IN_AN_HOUR * MILLISECONDS_IN_A_MINUTE; // 2hr
export const GOOGLE_SSO_CLIENT_ID =
'60755663443-40k0fbrbbqv4ci4hrjlbrphab5fj387b.apps.googleusercontent.com';
-export const MS_CLARITY_PROJECT_ID = '';
\ No newline at end of file
+export const MS_CLARITY_PROJECT_ID = '';
diff --git a/metro.config.js b/metro.config.js
index 13a96421..97d828f8 100644
--- a/metro.config.js
+++ b/metro.config.js
@@ -1,3 +1,5 @@
+const { withSentryConfig } = require('@sentry/react-native/metro');
+
/**
* Metro configuration for React Native
* https://github.com/facebook/react-native
@@ -5,7 +7,7 @@
* @format
*/
-module.exports = {
+module.exports = withSentryConfig({
transformer: {
getTransformOptions: async () => ({
transform: {
@@ -14,4 +16,4 @@ module.exports = {
},
}),
},
-};
+});
diff --git a/package.json b/package.json
index d71d1f44..2867af09 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"name": "AV_APP",
- "version": "2.14.0",
- "buildNumber": "200",
+ "version": "2.14.13",
+ "buildNumber": "213",
"private": true,
"scripts": {
"android:dev": "yarn move:dev && react-native run-android",
@@ -56,7 +56,7 @@
"@react-navigation/native": "6.1.4",
"@react-navigation/native-stack": "6.9.4",
"@reduxjs/toolkit": "1.9.1",
- "@sentry/react-native": "5.5.0",
+ "@sentry/react-native": "5.35.0",
"@shopify/flash-list": "1.4.3",
"@supersami/rn-foreground-service": "^2.1.0",
"appcenter": "^4.4.5",
diff --git a/src/action/appDownloadAction.ts b/src/action/appDownloadAction.ts
index 5203abbe..b81e8c94 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,18 +74,25 @@ 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 '';
diff --git a/src/action/dataActions.ts b/src/action/dataActions.ts
index 962b737e..55bbca61 100644
--- a/src/action/dataActions.ts
+++ b/src/action/dataActions.ts
@@ -34,7 +34,7 @@ const SUBMIT_FEEDBACK_API_VERSION = 5;
export const postPinnedList =
(pinnedCases: IPinnedCasesPayload[], updatedCaseList: ICaseItem[], type: string) =>
- (dispatch: AppDispatch) => {
+ async (dispatch: AppDispatch) => {
dispatch(setVisitPlansUpdating(true));
let pinRankCount = 1;
const payload: IPinnedCasesPayload[] = pinnedCases.reduce((acc, pinnedCase) => {
@@ -44,7 +44,12 @@ export const postPinnedList =
});
return acc;
}, [] as IPinnedCasesPayload[]);
- const url = getApiUrl(ApiKeys.PINNED_CASES);
+ const enableCaseCollectionManager =
+ (await getAsyncStorageItem(LocalStorageKeys.COSMOS_CASE_COLLECTION_MANAGER_ENABLE, true)) ??
+ false;
+ const url = getApiUrl(
+ enableCaseCollectionManager ? ApiKeys.PINNED_CASES_V2 : ApiKeys.PINNED_CASES
+ );
axiosInstance
.post(url, payload)
.then((response) => {
@@ -148,22 +153,34 @@ export type ISignedRequest = ISignedRequestItem[];
export const getSignedApi = async (
signedRequestPayload: ISignedRequest,
shouldBatch = false,
- skipFirebaseUpdate = false,
+ skipFirebaseUpdate = false
): Promise<{ imageUrl: string }> => {
return new Promise((res) => {
if (shouldBatch) {
- batchSignedApiRequest(signedRequestPayload, (results: any) => {
+ batchSignedApiRequest(
+ signedRequestPayload,
+ (results: any) => {
res({ imageUrl: results?.[signedRequestPayload[0].documentReferenceId] || '' });
- }, skipFirebaseUpdate);
+ },
+ skipFirebaseUpdate
+ );
} else {
- makeBulkSignedApiRequest(signedRequestPayload, (results: any) => {
+ makeBulkSignedApiRequest(
+ signedRequestPayload,
+ (results: any) => {
res({ imageUrl: results?.[signedRequestPayload[0].documentReferenceId] || '' });
- }, skipFirebaseUpdate);
+ },
+ skipFirebaseUpdate
+ );
}
});
};
-async function batchSignedApiRequest(payload: ISignedRequestItem[], callback: GenericFunctionArgs, skipFirebaseUpdate = false) {
+async function batchSignedApiRequest(
+ payload: ISignedRequestItem[],
+ callback: GenericFunctionArgs,
+ skipFirebaseUpdate = false
+) {
payload.forEach((item) => {
_signedApiCallBucket.push({ req: item, added_At: Date.now(), callback });
});
@@ -171,7 +188,7 @@ async function batchSignedApiRequest(payload: ISignedRequestItem[], callback: Ge
await makeBulkSignedApiRequest(
_signedApiCallBucket.map((a) => a.req),
_signedApiCallBucket.map((a) => a.callback),
- skipFirebaseUpdate,
+ skipFirebaseUpdate
);
return;
} else if (!_signedApiCallBucketTimer) {
@@ -179,7 +196,7 @@ async function batchSignedApiRequest(payload: ISignedRequestItem[], callback: Ge
await makeBulkSignedApiRequest(
_signedApiCallBucket.map((a) => a.req),
_signedApiCallBucket.map((a) => a.callback),
- skipFirebaseUpdate,
+ skipFirebaseUpdate
);
}, SIGNED_API_BUCKET_TIMEOUT);
}
@@ -188,7 +205,7 @@ async function batchSignedApiRequest(payload: ISignedRequestItem[], callback: Ge
async function makeBulkSignedApiRequest(
payload: ISignedRequestItem[],
callback: GenericFunctionArgs | GenericFunctionArgs[],
- skipFirebaseUpdate = false,
+ skipFirebaseUpdate = false
) {
const enableCaseCollectionManager =
(await getAsyncStorageItem(LocalStorageKeys.COSMOS_CASE_COLLECTION_MANAGER_ENABLE, true)) ??
diff --git a/src/assets/icons/EscalationIcon.tsx b/src/assets/icons/EscalationIcon.tsx
new file mode 100644
index 00000000..1ee16820
--- /dev/null
+++ b/src/assets/icons/EscalationIcon.tsx
@@ -0,0 +1,29 @@
+import * as React from "react";
+import Svg, { Rect, Mask, G, Path } from "react-native-svg";
+const EscalationsIcon = () => (
+
+);
+export default EscalationsIcon;
\ No newline at end of file
diff --git a/src/assets/icons/FlagIcon.tsx b/src/assets/icons/FlagIcon.tsx
new file mode 100644
index 00000000..c98126a0
--- /dev/null
+++ b/src/assets/icons/FlagIcon.tsx
@@ -0,0 +1,32 @@
+import * as React from "react"
+import { COLORS } from "@rn-ui-lib/colors";
+import { IconProps } from "@rn-ui-lib/icons/types"
+import Svg, { Path, Mask, G } from "react-native-svg"
+
+const FlagIcon : React.FC = ({fillColor = COLORS.TEXT.RED , width=16, height=16}) => (
+
+);
+
+export default FlagIcon
diff --git a/src/assets/icons/PostOperativeHoursIcon.tsx b/src/assets/icons/PostOperativeHoursIcon.tsx
new file mode 100644
index 00000000..5ba362cd
--- /dev/null
+++ b/src/assets/icons/PostOperativeHoursIcon.tsx
@@ -0,0 +1,22 @@
+import React from 'react';
+import { Circle, G, Mask, Path, Rect, Svg } from 'react-native-svg';
+
+const PostOperativeHoursIcon = () => {
+ return (
+
+ );
+};
+
+export default PostOperativeHoursIcon;
diff --git a/src/common/BlockerScreen.tsx b/src/common/BlockerScreen.tsx
index 853e880e..51553f2f 100644
--- a/src/common/BlockerScreen.tsx
+++ b/src/common/BlockerScreen.tsx
@@ -26,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;
@@ -42,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();
@@ -61,34 +62,71 @@ 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?.telecallingAgents?.version
+ );
}
if (apkFileUrl) {
- setShouldUpdate({ newApkCachedUrl: apkFileUrl, switchToFallback: false });
+ dispatch(setShouldUpdate({ newApkCachedUrl: apkFileUrl, switchToFallback: false }));
} else {
- setShouldUpdate({ newApkCachedUrl: '', switchToFallback: true });
+ dispatch(setShouldUpdate({ newApkCachedUrl: '', switchToFallback: true }));
}
};
const handleAppUpdate = () => {
let fallbackLonghornUrl;
+ let oldAppVersion = getBuildVersion();
+ let newAppVersion = appState?.fieldAgents?.version;
if (GLOBAL.BUILD_FLAVOUR.includes('fieldAgents')) {
fallbackLonghornUrl = appState?.fieldAgents?.currentProdAPK;
} else {
+ newAppVersion = appState?.telecallingAgents?.version;
fallbackLonghornUrl = appState?.telecallingAgents?.currentProdAPK;
}
+ addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_APK_UPDATE_BUTTON_CLICKED, {
+ apkPath: shouldUpdate.newApkCachedUrl,
+ oldAppVersion,
+ newAppVersion,
+ });
if (!shouldUpdate.newApkCachedUrl) {
openFallbackLonghornLink(fallbackLonghornUrl);
return;
}
- installApk(shouldUpdate.newApkCachedUrl, (error) => {
- if (!error) {
- return;
+ ReactNativeBlobUtil.fs.stat(shouldUpdate.newApkCachedUrl).then((res) => {
+ if (res.size < 10e6) {
+ // Temporary check: if size less than 10MB, then file is corrupted. Go to fallback link
+ addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_APK_UPDATE_CORRUPTED_FILE_DOWNLOADED, {
+ apkPath: shouldUpdate.newApkCachedUrl,
+ oldAppVersion,
+ newAppVersion,
+ });
+ openFallbackLonghornLink(fallbackLonghornUrl);
+ } else {
+ installApk(shouldUpdate.newApkCachedUrl, (error) => {
+ if (!error) {
+ addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_APK_UPDATE_INSTALL_STARTED, {
+ apkPath: shouldUpdate.newApkCachedUrl,
+ oldAppVersion,
+ newAppVersion,
+ });
+ return;
+ }
+ addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_APK_UPDATE_INSTALL_FAILED, {
+ apkPath: shouldUpdate.newApkCachedUrl,
+ errorMessage: error,
+ oldAppVersion,
+ newAppVersion,
+ });
+ openFallbackLonghornLink(fallbackLonghornUrl);
+ });
}
- openFallbackLonghornLink(fallbackLonghornUrl);
});
};
@@ -105,18 +143,22 @@ const BlockerScreen = (props: IBlockerScreen) => {
if (!flavorToUpdate) return;
const currentBuildNumber = getBuildVersion();
-
if (
currentBuildNumber &&
!isNaN(currentBuildNumber) &&
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]);
@@ -155,6 +197,9 @@ const BlockerScreen = (props: IBlockerScreen) => {
}
};
+ // Higher Priotrity to Post Operative Hours
+ if (!withinOperativeHours && isLoggedIn && !GLOBAL.IS_IMPERSONATED) return ;
+
if (shouldUpdate.newApkCachedUrl) {
return ;
}
diff --git a/src/common/Constants.ts b/src/common/Constants.ts
index 7df85363..bb434ce5 100644
--- a/src/common/Constants.ts
+++ b/src/common/Constants.ts
@@ -456,7 +456,10 @@ export const CLICKSTREAM_EVENT_NAMES = {
name: 'FA_VIEW_PAST_FEEDBACK_PREV_PAGE_FAILED',
description: 'FA_VIEW_PAST_FEEDBACK_PREV_PAGE_FAILED',
},
- FA_VIEW_PHOTO_CLICKED: { name: 'FA_VIEW_PHOTO_CLICKED', description: 'FA_VIEW_PHOTO_CLICKED' },
+ FA_VIEW_PHOTO_CLICKED: {
+ name: 'FA_VIEW_PHOTO_CLICKED',
+ description: 'FA_VIEW_PHOTO_CLICKED'
+ },
FA_CUSTOMER_DOCUMENT_CLICKED: {
name: 'FA_CUSTOMER_DOCUMENT_CLICKED',
description: 'FA_CUSTOMER_DOCUMENT_CLICKED',
@@ -494,6 +497,15 @@ export const CLICKSTREAM_EVENT_NAMES = {
name: 'FA_PERFORMANCE_DASHBOARD_PERFORMANCE_GRAPH_CLICKED',
description: 'When the user clicks on expand/collapse of the performance graph',
},
+ FA_VIEW_ALL_ESCALATIONS_SCREEN_CLICKED: {
+ name: 'FA_VIEW_ALL_ESCALATIONS_SCREEN_CLICKED',
+ description: 'FA_VIEW_ALL_ESCALATIONS_SCREEN_CLICKED',
+ },
+ FA_VIEW_ALL_ESCALATIONS_SCREEN_LANDED: {
+ name: 'FA_VIEW_ALL_ESCALATIONS_SCREEN_LANDED',
+ description: 'FA_VIEW_ALL_ESCALATIONS_SCREEN_LANDED',
+ },
+
// Notifications
FA_NOTIFICATION_ICON_CLICK: {
@@ -1301,6 +1313,10 @@ export const CLICKSTREAM_EVENT_NAMES = {
name : 'FA_CODEPUSH_DEFAULT_STATUS',
description: 'Codepush default fallback case'
},
+ FA_CODEPUSH_UNKNOWN_ERROR: {
+ name : 'FA_CODEPUSH_UNKNOWN_ERROR',
+ description: 'Codepush unknown error'
+ },
FA_FEEDBACK_IMAGE_NOT_FOUND: {
name: 'FA_FEEDBACK_IMAGE_NOT_FOUND',
description: 'Feedback image not found'
@@ -1309,6 +1325,53 @@ export const CLICKSTREAM_EVENT_NAMES = {
name: 'FA_UNSYNC_FEEDBACK_CAPTURED',
description: 'Unsync feedback captured'
},
+ FA_API_FAILED: {
+ name: 'FA_API_FAILED',
+ description: 'API failed'
+ },
+
+ // Apk Update
+ FA_APK_UPDATE_DOWNLOAD_STARTED: {
+ name: 'FA_APK_UPDATE_DOWNLOAD_STARTED',
+ description: 'APK update download started'
+ },
+ FA_APK_UPDATE_DOWNLOAD_SUCCESS: {
+ name: 'FA_APK_UPDATE_DOWNLOAD_SUCCESS',
+ description: 'APK update download completed'
+ },
+ FA_APK_UPDATE_DOWNLOAD_FAILED: {
+ name: 'FA_APK_UPDATE_DOWNLOAD_FAILED',
+ description: 'APK update download failed'
+ },
+ FA_APK_UPDATE_BUTTON_CLICKED: {
+ name: 'FA_APK_UPDATE_BUTTON_CLICKED',
+ description: 'APK update button clicked'
+ },
+ FA_APK_UPDATE_INSTALL_STARTED: {
+ name: 'FA_APK_UPDATE_INSTALL_STARTED',
+ description: 'APK update installation started'
+ },
+ FA_APK_UPDATE_INSTALL_FAILED: {
+ name: 'FA_APK_UPDATE_INSTALL_FAILED',
+ description: 'APK update installation failed'
+ },
+ FA_APK_UPDATE_FALLBACK_TRIGGERED: {
+ name: 'FA_APK_UPDATE_FALLBACK_TRIGGERED',
+ description: 'APK update fallback triggered'
+ },
+ FA_APK_UPDATE_CORRUPTED_FILE_DOWNLOADED: {
+ name: 'FA_APK_UPDATE_CORRUPTED_FILE_DOWNLOADED',
+ description: 'APK update corrupted file downloaded'
+ },
+ FA_APK_UPDATE_INSTALL_SUCCESS: {
+ name: 'FA_APK_UPDATE_INSTALL_SUCCESS',
+ description: 'APK update installation success'
+ },
+
+ FA_POST_OPERATIVE_HOURS_SCREEN_LOADED: {
+ name: 'FA_POST_OPERATIVE_HOURS_SCREEN_LOADED',
+ description: 'Post operative hours screen loaded'
+ }
} as const;
export enum MimeType {
@@ -1430,8 +1493,10 @@ export const BUTTON_PRESS_COUNT_FOR_IMPERSONATION = 5;
export const REQUEST_TYPE_TO_BLOCK_FOR_IMPERSONATION = ['post', 'put', 'patch', 'delete'];
export const REQUEST_TO_UNBLOCK_FOR_IMPERSONATION = [
+ getApiUrl(ApiKeys.GET_SIGNED_URL_V2),
getApiUrl(ApiKeys.GET_SIGNED_URL),
getApiUrl(ApiKeys.GET_SIGNED_URL_FOR_REPORTEE),
+ getApiUrl(ApiKeys.GET_SIGNED_URL_FOR_REPORTEE_V2),
getApiUrl(ApiKeys.LOGOUT),
getApiUrl(ApiKeys.PAST_FEEDBACK),
getApiUrl(ApiKeys.GET_CSA_TICKETS),
diff --git a/src/common/ErrorBoundary.tsx b/src/common/ErrorBoundary.tsx
index c2c6b28d..1db7717c 100644
--- a/src/common/ErrorBoundary.tsx
+++ b/src/common/ErrorBoundary.tsx
@@ -1,5 +1,5 @@
import React, { Component, ReactNode } from 'react';
-import { logError } from '../components/utlis/errorUtils';
+import { sentryCaptureException } from '../components/utlis/errorUtils';
import { StyleSheet, View } from 'react-native';
import { addClickstreamEvent } from '../services/clickstreamEventService';
import { CLICKSTREAM_EVENT_NAMES } from './Constants';
@@ -36,7 +36,7 @@ class ErrorBoundary extends Component {
errorMessageStack: error?.stack,
message: error?.message,
});
- logError(error);
+ sentryCaptureException(error);
crashlytics().recordError(error);
handleCrash({ message: error?.message?.slice(0, 255), screenName: getCurrentScreen()?.name });
}
diff --git a/src/common/PostOperativeHours.tsx b/src/common/PostOperativeHours.tsx
new file mode 100644
index 00000000..a3a611b8
--- /dev/null
+++ b/src/common/PostOperativeHours.tsx
@@ -0,0 +1,116 @@
+import { getAgentDetail, logout } from '@actions/authActions';
+import PostOperativeHoursIcon from '@assets/icons/PostOperativeHoursIcon';
+import { useAppDispatch } from '@hooks';
+import { AppStates } from '@interfaces/appStates';
+import { COLORS } from '@rn-ui-lib/colors';
+import Button from '@rn-ui-lib/components/Button';
+import Text from '@rn-ui-lib/components/Text';
+import LogoutIcon from '@rn-ui-lib/icons/LogoutIcon';
+import { GenericStyles } from '@rn-ui-lib/styles';
+import { addClickstreamEvent } from '@services/clickstreamEventService';
+import React, { useEffect } from 'react';
+import { AppState, AppStateStatus, StyleSheet } from 'react-native';
+import { View } from 'react-native';
+import { CLICKSTREAM_EVENT_NAMES } from './Constants';
+
+const PostOperativeHours = () => {
+ const dispatch = useAppDispatch();
+
+ useEffect(() => {
+ addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_POST_OPERATIVE_HOURS_SCREEN_LOADED);
+ dispatch(getAgentDetail());
+ }, []);
+
+ const handleAppStateChange = (nextAppState: AppStateStatus) => {
+ if (nextAppState === AppStates.ACTIVE) {
+ dispatch(getAgentDetail());
+ }
+ };
+
+ useEffect(() => {
+ const appStateListener = AppState.addEventListener('change', handleAppStateChange);
+ return () => {
+ appStateListener.remove();
+ };
+ }, []);
+
+ return (
+
+
+
+
+
+ You have logged in post operative hours!
+
+ Please{' '}
+
+ login between operative hours (8AM - 7PM)
+ {' '}
+ to access Cosmos
+
+
+
+
+
+ );
+};
+
+const styles = StyleSheet.create({
+ iconContainer: {
+ position: 'absolute',
+ top: -30,
+ },
+ refreshIcon: {
+ marginRight: 8,
+ },
+ pt40: {
+ paddingTop: 40,
+ },
+ headerTxt: {
+ fontSize: 16,
+ color: COLORS.TEXT.DARK,
+ fontWeight: '500',
+ lineHeight: 20,
+ paddingBottom: 12,
+ paddingTop: 16,
+ textAlign: 'center',
+ },
+ description: {
+ fontSize: 14,
+ color: COLORS.TEXT.BLACK,
+ textAlign: 'center',
+ fontWeight: '400',
+ lineHeight: 18,
+ },
+ time: {
+ color: COLORS.TEXT.DARK,
+ fontWeight: '500',
+ },
+});
+
+export default PostOperativeHours;
diff --git a/src/components/form/components/AddressSelection.tsx b/src/components/form/components/AddressSelection.tsx
index 4111a736..ac6f300d 100644
--- a/src/components/form/components/AddressSelection.tsx
+++ b/src/components/form/components/AddressSelection.tsx
@@ -109,20 +109,6 @@ const AddressSelection: React.FC = (props) => {
};
if (isGeolocation) {
- if (isLoading) {
- return (
-
- {[...Array(7).keys()].map((_, index) => (
-
- ))}
-
- );
- }
if (!addresses?.length) {
return (
@@ -137,41 +123,54 @@ const AddressSelection: React.FC = (props) => {
key={controllerName}
control={control}
rules={{ validate: (data) => validateInput(data, question.metadata.validators) }}
- render={({ field: { onChange, value } }) => (
-
+ render={({ field: { onChange, value } }) =>
+ isLoading ? (
+
+ {[...Array(7).keys()].map((_, index) => (
+
+ ))}
+
+ ) : (
-
-
- No nearby geolocations found
-
+
+
+
+ No nearby geolocations found
+
+
+
+
+
+
+ Retry
+
-
-
-
-
- Retry
-
-
- )}
+ )
+ }
name={controllerName}
/>
diff --git a/src/components/form/components/imageUpload/ImageUploadV2.tsx b/src/components/form/components/imageUpload/ImageUploadV2.tsx
index c5b8dfff..f3ca2e29 100644
--- a/src/components/form/components/imageUpload/ImageUploadV2.tsx
+++ b/src/components/form/components/imageUpload/ImageUploadV2.tsx
@@ -88,9 +88,10 @@ const ImageUploadV2: React.FC = (props) => {
dispatch(addIntermediateDocument({ caseId, fileUri, questionKey, imageWidth, imageHeight }));
};
- const handleImageDelete = () => {
+ const handleImageDelete = (onChange: (...event: any[]) => void) => {
setImageId('');
dispatch(deleteIntermediateDocument({ caseId, questionKey: questionId }));
+ onChange(undefined);
};
const handleError = (error: string) => {
@@ -317,11 +318,11 @@ const ImageUploadV2: React.FC = (props) => {
{question.text}{' '}
{isQuestionMandatory(question) && *}
- {showClickPictureCTA ? (
- validateInput(data, question.metadata.validators) }}
- render={({ field: { onChange } }) => (
+ validateInput(data, question.metadata.validators) }}
+ render={({ field: { onChange } }) =>
+ showClickPictureCTA ? (
<>
= (props) => {
) : null}
>
- )}
- name={`widgetContext.${widgetId}.sectionContext.${props.sectionId}.questionContext.${questionId}`}
- />
- ) : (
-
- handleError('Error in image rendering')}
- >
- {!imageLoading && !imageError ? (
-
-
-
- ) : null}
-
-
-
- )}
+ ) : (
+
+ handleError('Error in image rendering')}
+ >
+ {!imageLoading && !imageError ? (
+ handleImageDelete(onChange)} style={styles.deleteButton}>
+
+
+ ) : null}
+
+
+
+ )
+ }
+ name={`widgetContext.${widgetId}.sectionContext.${props.sectionId}.questionContext.${questionId}`}
+ />
= {} as Record;
@@ -106,6 +114,7 @@ API_URLS[ApiKeys.VERIFY_OTP] = '/auth/otp/verify';
API_URLS[ApiKeys.ALL_CASES] = '/cases/all-cases';
API_URLS[ApiKeys.CASE_DETAIL] = '/cases/get-cases';
API_URLS[ApiKeys.PINNED_CASES] = '/cases/pin';
+API_URLS[ApiKeys.PINNED_CASES_V2] = '/cases/v2/pin';
API_URLS[ApiKeys.LOGOUT] = '/auth/logout';
API_URLS[ApiKeys.FEEDBACK] = '/cases/feedback';
API_URLS[ApiKeys.FILTERS] = '/cases/filters';
@@ -192,6 +201,7 @@ API_URLS[ApiKeys.FETCH_AGENT_DOCUMENTS] = '/documents/agent';
API_URLS[ApiKeys.FETCH_DOCUMENT_SPECIFIC_LANGUAGE] = '/documents/language/{loanAccountNumber}';
API_URLS[ApiKeys.SEND_COMMUNICATION_NAVI_ACCOUNT] = '/navi-communications/{loanAccountNumber}';
API_URLS[ApiKeys.GENERATE_DYNAMIC_DOCUMENT] = '/documents/generate/{loanAccountNumber}';
+API_URLS[ApiKeys.ALL_ESCALATIONS] = '/customer-escalation';
API_URLS[ApiKeys.DOWNLOAD_LATEST_APP] = 'https://longhorn.navi.com/api/app/download';
export const API_STATUS_CODE = {
@@ -204,6 +214,7 @@ export const API_STATUS_CODE = {
UNPROCESSABLE_CONTENT: 422,
INTERNAL_SERVER_ERROR: 500,
TOO_MANY_REQUESTS: 429,
+ GONE: 410,
};
const API_TIMEOUT_INTERVAL = 2e4; // 20s
@@ -245,15 +256,15 @@ const errorsToRetry = [500, 503];
const axiosInstance = axios.create({ timeout: API_TIMEOUT_INTERVAL });
axiosInstance.interceptors.request.use((request) => {
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
- // @ts-ignore
- request.retry = request?.retry < 4 ? request.retry : 3;
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
request.headers['X-Auth-Source'] = 'mjolnir';
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
request.retry = request?.retry < 4 ? request.retry : 3;
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
+ // @ts-ignore
+ request.delay = request?.delay > 2000 ? request.delay : 2000;
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
request.headers['request-start-time'] = Date.now();
@@ -317,6 +328,10 @@ axiosInstance.interceptors.response.use(
const end = Date.now();
const milliseconds = end - Number(start);
sendApiToClickstreamEvent(response, milliseconds, false);
+ addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_API_FAILED, {
+ statusCode: response?.status,
+ url: response?.config?.url,
+ });
const donotHandleErrorOnStatusCode = (config.headers.donotHandleErrorOnStatusCode || []).map(
Number
);
@@ -334,10 +349,12 @@ axiosInstance.interceptors.response.use(
? config.headers.showInSpecificComponents?.includes(getCurrentScreen().name)
: true)
) {
- toast({
- type: 'error',
- text1: typeof errorString === 'string' ? errorString : API_ERROR_MESSAGE,
- });
+ if (API_STATUS_CODE.GONE !== response.status) {
+ toast({
+ type: 'error',
+ text1: typeof errorString === 'string' ? errorString : API_ERROR_MESSAGE,
+ });
+ }
}
if ([API_STATUS_CODE.UNAUTHORIZED, API_STATUS_CODE.FORBIDDEN].includes(response.status)) {
@@ -345,14 +362,22 @@ axiosInstance.interceptors.response.use(
dispatch(handleLogout());
}
+ // Blocking cosmos after operative hours
+ if (API_STATUS_CODE.GONE === response.status && !GLOBAL.IS_IMPERSONATED) {
+ if (store?.getState().user.withinOperativeHours) {
+ dispatch(setWithinOperativeHours(false));
+ }
+ }
+
return Promise.reject(error);
}
config.retry -= 1;
const delayRetryRequest = new Promise((resolve) => {
setTimeout(() => {
resolve();
- }, 500);
+ }, config.delay);
});
+ config.delay *= 2;
return delayRetryRequest.then(() => axiosInstance(config));
}
);
diff --git a/src/components/utlis/errorUtils.ts b/src/components/utlis/errorUtils.ts
index 2a0d30e2..a7a2fcfc 100644
--- a/src/components/utlis/errorUtils.ts
+++ b/src/components/utlis/errorUtils.ts
@@ -6,16 +6,20 @@ export const logError = (error: Error, extraInfo = '') => {
// Disable sentry in development mode
return;
}
- Sentry.setTag('agentId', GLOBAL.AGENT_ID || 'not-logged-in');
- Sentry.captureException(error, (scope) => {
- scope.setExtra('ExtraInfo', extraInfo);
- return scope;
- });
+ // Sentry.setTag('agentId', GLOBAL.AGENT_ID || 'not-logged-in');
+ // Sentry.captureException(error, (scope) => {
+ // scope.setExtra('ExtraInfo', extraInfo);
+ // return scope;
+ // });
};
-export const sentryCaptureMessage = (errorStr: string, extraInfo = '') => {
+export const sentryCaptureException = (errorStr: Error, extraInfo = '') => {
+ if(__DEV__) {
+ // Disable sentry in development mode
+ return;
+ }
Sentry.setTag('agentId', GLOBAL.AGENT_ID || 'not-logged-in');
- Sentry.captureMessage(errorStr, (scope) => {
+ Sentry.captureException(errorStr, (scope) => {
scope.setExtra('ExtraInfo', extraInfo);
return scope;
});
diff --git a/src/components/utlis/sentry.ts b/src/components/utlis/sentry.ts
index 29d363fc..56e95bb8 100644
--- a/src/components/utlis/sentry.ts
+++ b/src/components/utlis/sentry.ts
@@ -1,37 +1,55 @@
import * as Sentry from '@sentry/react-native';
-import VersionNumber from 'react-native-version-number';
-
-import { SENTRY_DSN, ENV } from '../../constants/config';
+import { SENTRY_DSN, TUNNEL_URL } from '../../constants/config';
import { addClickstreamEvent } from '../../services/clickstreamEventService';
import { CLICKSTREAM_EVENT_NAMES } from '../../common/Constants';
import { getAppVersion } from './commonFunctions';
+import { createTransport } from '@sentry/core';
+import { GLOBAL } from '@constants/Global';
-const sentryRoutingInstrumentation = new Sentry.ReactNavigationInstrumentation();
+function makeFetchTransport(options: any): any {
+ function makeRequest(request: any) {
+ const requestOptions: RequestInit = {
+ body: request.body,
+ method: 'POST',
+ referrerPolicy: 'origin',
+ headers: options.headers,
+ ...options.fetchOptions,
+ };
-const defaultOptions = {
- dsn: SENTRY_DSN,
- enableAutoSessionTracking: true,
- environment: ENV,
- // integrations: [
- // new Sentry.ReactNativeTracing({
- // routingInstrumentation: sentryRoutingInstrumentation,
- // tracingOrigins: ['localhost', /^\//],
- // }),
- // ],
- tracesSampleRate: 0.2,
-};
+ return fetch(options.url, requestOptions).then((response) => {
+ return {
+ statusCode: response.status,
+ headers: {
+ 'x-sentry-rate-limits': response.headers.get('X-Sentry-Rate-Limits'),
+ 'retry-after': response.headers.get('Retry-After'),
+ },
+ };
+ });
+ }
+
+ return createTransport(options, makeRequest);
+}
export async function initSentry() {
try {
- const dist = `${VersionNumber.buildVersion}`;
- const release = `${VersionNumber.bundleIdentifier}(${getAppVersion()})@${
- VersionNumber.appVersion
- }+${dist}`;
-
Sentry.init({
- ...defaultOptions,
- dist,
- release,
+ dsn: SENTRY_DSN,
+ transport: makeFetchTransport,
+ tunnel: TUNNEL_URL,
+ beforeSend(event) {
+ event.extra = {
+ ...event.extra,
+ release_id: getAppVersion(),
+ alfredSessionId: '',
+ metadata: {
+ agentId: GLOBAL?.AGENT_ID,
+ deviceId: GLOBAL?.DEVICE_ID,
+ isImpersonated: GLOBAL?.IS_IMPERSONATED,
+ buildFlavour: GLOBAL?.BUILD_FLAVOUR,
+ },
+ };
+ return event;
+ },
});
} catch (e) {
addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_SENTRY_INTEGRATION_FAILED);
diff --git a/src/constants/config.js b/src/constants/config.js
index df82b252..b3807465 100644
--- a/src/constants/config.js
+++ b/src/constants/config.js
@@ -1,8 +1,8 @@
import { MILLISECONDS_IN_A_MINUTE, MINUTES_IN_AN_HOUR } from '../../RN-UI-LIB/src/utlis/common';
-export const BASE_AV_APP_URL = 'https://qa-longhorn-portal.np.navi-tech.in/field-app';
-export const SENTRY_DSN =
- 'https://acef93c884c1424cacc4ec899562e203@qa-longhorn-portal.np.navi-tech.in/glitchtip-events/173';
+export const BASE_AV_APP_URL = 'https://qa-longhorn-server.np.navi-ppl.in/field-app';
+export const SENTRY_DSN = 'https://navi@qa-sa.navi.com/cybertron/4';
+export const TUNNEL_URL = 'https://qa-sa.navi.com/cybertron/api/4/envelope?sentry_key=';
export const JANUS_SERVICE_URL = 'https://qa-longhorn-portal.np.navi-tech.in/api/events/json';
export const ENV = 'qa';
export const IS_SSO_ENABLED = true;
@@ -12,4 +12,4 @@ export const IS_DATA_SYNC_REQUIRED = true;
export const DATA_SYNC_TIME_INTERVAL = 2 * MINUTES_IN_AN_HOUR * MILLISECONDS_IN_A_MINUTE; // 2hr
export const GOOGLE_SSO_CLIENT_ID =
'60755663443-40k0fbrbbqv4ci4hrjlbrphab5fj387b.apps.googleusercontent.com';
-export const MS_CLARITY_PROJECT_ID = '';
\ No newline at end of file
+export const MS_CLARITY_PROJECT_ID = '';
diff --git a/src/reducer/appUpdateSlice.ts b/src/reducer/appUpdateSlice.ts
new file mode 100644
index 00000000..c4d9cde6
--- /dev/null
+++ b/src/reducer/appUpdateSlice.ts
@@ -0,0 +1,29 @@
+import { createSlice } from '@reduxjs/toolkit';
+
+interface IAppUpdateSlice {
+ shouldUpdate: {
+ newApkCachedUrl: string;
+ switchToFallback: boolean;
+ };
+}
+
+const initialState: IAppUpdateSlice = {
+ shouldUpdate: {
+ newApkCachedUrl: '',
+ switchToFallback: false,
+ },
+};
+
+const AppUpdateSlice = createSlice({
+ name: 'appUpdate',
+ initialState,
+ reducers: {
+ setShouldUpdate: (state, action) => {
+ state.shouldUpdate = action.payload;
+ },
+ },
+});
+
+export const { setShouldUpdate } = AppUpdateSlice.actions;
+
+export default AppUpdateSlice.reducer;
diff --git a/src/reducer/escalationSlice.ts b/src/reducer/escalationSlice.ts
new file mode 100644
index 00000000..df331649
--- /dev/null
+++ b/src/reducer/escalationSlice.ts
@@ -0,0 +1,28 @@
+import { createSlice } from '@reduxjs/toolkit';
+import { IEscalationsSlice, pageData } from '@screens/escalations/escalations.interfaces';
+
+const initialState = {
+ escalationData : [],
+ isLoading : false,
+ pageData: {} as pageData
+} as IEscalationsSlice;
+
+const escalationsSlice = createSlice({
+ name: 'escalations',
+ initialState,
+ reducers: {
+ setEscalationData: (state, action) => {
+ state.escalationData = action.payload;
+ },
+ setIsLoading: (state, action) => {
+ state.isLoading = action.payload;
+ },
+ setPageData: (state, action) => {
+ state.pageData = action.payload;
+ }
+ },
+});
+
+export const { setEscalationData, setIsLoading, setPageData } = escalationsSlice.actions;
+
+export default escalationsSlice.reducer;
diff --git a/src/reducer/userSlice.ts b/src/reducer/userSlice.ts
index b4d0bffb..6fa69b77 100644
--- a/src/reducer/userSlice.ts
+++ b/src/reducer/userSlice.ts
@@ -77,6 +77,8 @@ export interface IUserSlice extends IUser {
isCallRecordingCosmosExotelEnabled: boolean;
};
employeeId: string;
+ is1To30FieldAgent: boolean;
+ withinOperativeHours: boolean;
}
const initialState: IUserSlice = {
@@ -105,6 +107,8 @@ const initialState: IUserSlice = {
isCallRecordingCosmosExotelEnabled: false,
},
employeeId: '',
+ is1To30FieldAgent: false,
+ withinOperativeHours: true,
};
export const userSlice = createSlice({
@@ -142,8 +146,15 @@ export const userSlice = createSlice({
state.agentAttendance = action.payload;
},
setUserAccessData: (state, action) => {
- const { roles, isExternalAgent, isFieldTeamLeadOrAgencyManager, featureFlags, employeeId } =
- action.payload || {};
+ const {
+ roles,
+ isExternalAgent,
+ is1To30FieldAgent,
+ isFieldTeamLeadOrAgencyManager,
+ featureFlags,
+ employeeId,
+ withinOperativeHours
+ } = action.payload || {};
if (roles?.length) {
state.isTeamLead = isFieldTeamLeadOrAgencyManager;
} else {
@@ -153,6 +164,11 @@ export const userSlice = createSlice({
state.agentRoles = roles;
state.featureFlags = featureFlags;
state.employeeId = employeeId;
+ state.is1To30FieldAgent = is1To30FieldAgent;
+ state.withinOperativeHours = withinOperativeHours;
+ },
+ setWithinOperativeHours: (state, action) => {
+ state.withinOperativeHours = action.payload;
},
},
});
@@ -165,6 +181,7 @@ export const {
setCaseSyncLock,
setAgentAttendance,
setUserAccessData,
+ setWithinOperativeHours
} = userSlice.actions;
export default userSlice.reducer;
diff --git a/src/screens/allCases/ListItem.tsx b/src/screens/allCases/ListItem.tsx
index 7fe62155..070bb404 100644
--- a/src/screens/allCases/ListItem.tsx
+++ b/src/screens/allCases/ListItem.tsx
@@ -13,7 +13,6 @@ import {
import CaseItemAvatar from './CaseItemAvatar';
import {
CaseStatuses,
- displayStatuses,
InteractionStatuses,
TaskTitleUIMapping,
ICaseItemAvatarCaseDetailObj,
@@ -34,6 +33,7 @@ import relativeDistanceFormatter from '@screens/addressGeolocation/utils/relativ
import { CaseDetailStackEnum } from '@screens/caseDetails/CaseDetailStack';
import { PageRouteEnum } from '@screens/auth/ProtectedRouter';
import LocationDistanceIcon from '@assets/icons/LocationDistanceIcon';
+import FlagIcon from '@assets/icons/FlagIcon';
interface IListItem {
caseListItemDetailObj: ICaseItemCaseDetailObj;
@@ -77,13 +77,14 @@ const ListItem: React.FC = (props) => {
collectionTag,
paymentStatus,
dpdBucket,
+ dpdCycle,
pinRank,
isSynced,
isNewlyAdded,
interactionStatus,
- caseVerdict,
totalOverdueAmount,
distanceInKm,
+ escalationData,
} = caseListItemDetailObj;
const isVisitPlanStatusLocked = useAppSelector(
@@ -191,6 +192,7 @@ const ListItem: React.FC = (props) => {
!isTeamLead &&
!nearbyCaseView;
+ const is1To30FieldAgent = useAppSelector((state) => state.user?.is1To30FieldAgent);
const distanceMapOfNearbyCases =
useAppSelector((state) => state.nearbyCasesSlice.caseReferenceIdToDistanceMap) || {};
const selectedTab = useAppSelector((state) => state?.nearbyCasesSlice?.sortTabSelected);
@@ -201,105 +203,144 @@ const ListItem: React.FC = (props) => {
width: showInVisitPlanTag
? TAG_CONTAINER_WIDTH.VISIT_PLAN_TAG
: showVisitPlanBtn
- ? TAG_CONTAINER_WIDTH.VISIT_PLAN_BUTTON
- : TAG_CONTAINER_WIDTH.DEFAULT,
+ ? TAG_CONTAINER_WIDTH.VISIT_PLAN_BUTTON
+ : TAG_CONTAINER_WIDTH.DEFAULT,
};
+
+ const isActiveEscalationCase = Number(escalationData?.activeEscalationCount) > 0;
+ const activeEscalationCount = Number(escalationData?.activeEscalationCount);
+ const pastEscalationCount = Number(escalationData?.pastEscalationCount);
+ const totalEscalationsCount = activeEscalationCount + pastEscalationCount;
+
return (
+
+
-
- {showVisitPlanBtn ? (
-
-
-
- ) : null}
- {showInVisitPlanTag && (
-
- In visit plan
-
- )}
- {nearbyCaseView && distanceInKm && (
-
-
- {relativeDistanceFormatter(distanceInKm)} km away
-
-
- )}
-
-
- {paymentStatus ? (
-
-
-
- ) : null}
- {collectionTag ? (
-
-
-
- ) : null}
-
- {!isVisitPlan && distanceOfCaseItem ? (
-
-
- }
- text={Number(distanceOfCaseItem?.toFixed(1)) + ' KM'}
- variant={isNearestCaseView ? TagVariant.darkBlue : TagVariant.darkGray}
- />
-
- ) : null}
-
-
- {customerName}
-
- {taskTitle ? (
-
-
- {/* @ts-ignore */}
- {TaskTitleUIMapping[taskTitle]}
- {displayAddress ? `: ${displayAddress}` : null}
+ {escalationData && totalEscalationsCount > 0 ? (
+ isActiveEscalationCase ? (
+
+
+
+ {`${activeEscalationCount} Active Escalation${activeEscalationCount === 1 ? '' : 's'}`}
-
+
) : (
-
- {displayAddress}
-
- )}
-
-
- Total due {formatAmount(totalOverdueAmount, false)}
- {' '}DPD bucket {dpdBucket}
-
- {caseInteractionStatus ? (
-
- {caseInteractionStatus}
+
+
+
+ {`${pastEscalationCount} Past Escalation${pastEscalationCount === 1 ? '' : 's'}`}
- ) : null}
+
+ )
+ ) : null}
+
+
+
+ {showVisitPlanBtn ? (
+
+
+
+ ) : null}
+ {showInVisitPlanTag && (
+
+ In visit plan
+
+ )}
+ {nearbyCaseView && distanceInKm && (
+
+
+ {relativeDistanceFormatter(distanceInKm)} km away
+
+
+ )}
+
+
+ {paymentStatus ? (
+
+
+
+ ) : null}
+ {collectionTag ? (
+
+
+
+ ) : null}
+
+ {!isVisitPlan && distanceOfCaseItem ? (
+
+
+ }
+ text={Number(distanceOfCaseItem?.toFixed(1)) + ' KM'}
+ variant={isNearestCaseView ? TagVariant.darkBlue : TagVariant.darkGray}
+ />
+
+ ) : null}
+
+
+ {customerName}
+
+ {taskTitle ? (
+
+
+ {/* @ts-ignore */}
+ {TaskTitleUIMapping[taskTitle]}
+ {displayAddress ? `: ${displayAddress}` : null}
+
+
+ ) : (
+
+ {displayAddress}
+
+ )}
+
+ {is1To30FieldAgent ? (
+
+ Total due {formatAmount(totalOverdueAmount, false)}
+ {' '}DPD Cycle {dpdCycle}
+
+ ) : (
+
+ Total due {formatAmount(totalOverdueAmount, false)}
+ {' '}Bucket {dpdBucket}
+
+ )}
+ {caseInteractionStatus ? (
+
+ {caseInteractionStatus}
+
+ ) : null}
+
@@ -309,10 +350,32 @@ const ListItem: React.FC = (props) => {
const styles = StyleSheet.create({
listItem: {
- padding: 12,
borderRadius: 8,
- marginVertical: 6,
+ marginBottom: 12,
position: 'relative',
+ overflow: 'hidden'
+ },
+ escalationContainer: {
+ height: 30,
+ paddingLeft: 12,
+ paddingRight: 8,
+ borderTopLeftRadius: 8,
+ borderTopRightRadius: 8,
+ borderWidth: 1,
+ },
+ redContainer :{
+ borderColor: COLORS.BORDER.RED,
+ },
+ yellowContainer :{
+ borderColor: COLORS.BORDER.YELLOW,
+ },
+ activeEscalationText: {
+ color: COLORS.TEXT.RED,
+ marginLeft: 4,
+ },
+ pastEscalationText: {
+ color: COLORS.TEXT.YELLOW_LIGHT,
+ marginLeft: 4,
},
avatarContainer: {
height: 40,
diff --git a/src/screens/allCases/interface.ts b/src/screens/allCases/interface.ts
index 5f3f7bba..848aebbf 100644
--- a/src/screens/allCases/interface.ts
+++ b/src/screens/allCases/interface.ts
@@ -344,3 +344,14 @@ export enum FiltePlaceholderText {
CASES = 'cases',
MY_CASES = 'my cases',
}
+
+export interface IRecentEscalationDetails {
+ customerVoice: string;
+ createdAt: string;
+}
+
+export interface IEscalationSummary {
+ pastEscalationCount: number;
+ activeEscalationCount: number;
+ recentEscalationDetails: IRecentEscalationDetails;
+}
diff --git a/src/screens/allCases/utils.ts b/src/screens/allCases/utils.ts
index 3e5c4ca3..fc1070e6 100644
--- a/src/screens/allCases/utils.ts
+++ b/src/screens/allCases/utils.ts
@@ -1,6 +1,6 @@
import { CLICKSTREAM_EVENT_NAMES } from '@common/Constants';
import { getDistanceFromLatLonInKm, isFunction } from '@components/utlis/commonFunctions';
-import { IGeoLocation } from '@interfaces/addressGeolocation.types';
+import { IGeoLocation, IGeolocationCoordinate } from '@interfaces/addressGeolocation.types';
import { addClickstreamEvent } from '@services/clickstreamEventService';
import {
Address,
@@ -88,13 +88,9 @@ export const sectionListTranformData = (agentList: IReportee[]): ISectionListDat
return result;
};
-export const getAddressLocation = (addresses: Address[] | undefined) => {
- if (!addresses?.length) return null;
-
- for (const address of addresses) {
- if (address?.location?.latitude && address?.location?.longitude) {
- return address.location;
- }
+export const getAddressLocation = (address?: IGeolocationCoordinate) => {
+ if(address?.latitude && address?.longitude) {
+ return address;
}
return null;
};
@@ -108,7 +104,7 @@ export const getNearByCases = (
let caseIds: Array = [];
casesList?.forEach((pinnedId) => {
const caseDetail = caseDetails?.[pinnedId.caseReferenceId];
- const addressLocation = getAddressLocation(caseDetail?.addresses);
+ const addressLocation = getAddressLocation(caseDetail?.addressLocation);
if (addressLocation) {
const distanceInKm = getDistanceFromLatLonInKm(addressLocation, deviceGeolocationCoordinate);
@@ -194,7 +190,7 @@ export const updateNearbyCasesListAndLocation = (
let caseIdsToDistancesFromCurrentLocationMap: Map = new Map();
allCasesList?.forEach((pinnedId) => {
const caseDetail = caseDetails?.[pinnedId?.caseReferenceId] || {};
- const addressLocation = getAddressLocation(caseDetail?.addresses);
+ const addressLocation = getAddressLocation(caseDetail?.addressLocation);
if (addressLocation) {
const distanceInKm = getDistanceFromLatLonInKm(
addressLocation,
diff --git a/src/screens/caseDetails/CaseDetailStack.tsx b/src/screens/caseDetails/CaseDetailStack.tsx
index d3d6b63f..6a330b3d 100644
--- a/src/screens/caseDetails/CaseDetailStack.tsx
+++ b/src/screens/caseDetails/CaseDetailStack.tsx
@@ -28,6 +28,7 @@ import AdditionalGeolocations from '@screens/addressGeolocation/AdditionalGeoloc
import FeeWaiver from '@screens/emiSchedule/FeeWaiver';
import FeeWaiverHistory from '@screens/emiSchedule/FeeWaiverHistory';
import CallCustomer from './CallCustomer';
+import Escalations from '@screens/escalations/Escalations';
const Stack = createNativeStackNavigator();
@@ -53,6 +54,7 @@ export enum CaseDetailStackEnum {
FEE_WAIVER = 'FeeWaiver',
FEE_WAIVER_HISTORY = 'FeeWaiverHistory',
CALL_CUSTOMER = 'CallCustomer',
+ ESCALATIONS = 'Escalations',
}
const CaseDetailStack = () => {
@@ -101,6 +103,7 @@ const CaseDetailStack = () => {
component={FeedbackDetailContainer}
/>
+
diff --git a/src/screens/caseDetails/CollectionCaseData.tsx b/src/screens/caseDetails/CollectionCaseData.tsx
index dd9354c4..ab5d16a8 100644
--- a/src/screens/caseDetails/CollectionCaseData.tsx
+++ b/src/screens/caseDetails/CollectionCaseData.tsx
@@ -11,6 +11,7 @@ import { addClickstreamEvent } from '../../services/clickstreamEventService';
import { CLICKSTREAM_EVENT_NAMES } from '../../common/Constants';
import { ToastMessages } from '../allCases/constants';
import { toTileCase } from '../../components/utlis/commonFunctions';
+import { useAppSelector } from '@hooks';
interface ICollectionCaseData {
caseData: CaseDetail;
@@ -22,12 +23,13 @@ const CollectionCaseData: React.FC = ({ caseData }) => {
currentDpd,
loanAccountNumber,
dpdBucket,
+ dpdCycle,
pos,
collectionTag,
employmentDetail,
unpaidDays
} = caseData;
-
+ const is1To30FieldAgent = useAppSelector((state) => state.user?.is1To30FieldAgent );
return (
{fatherName && (
@@ -67,9 +69,15 @@ const CollectionCaseData: React.FC = ({ caseData }) => {
GenericStyles.flexWrap,
]}
>
-
- DPD bucket {dpdBucket}
-
+ {is1To30FieldAgent ? (
+
+ DPD Cycle {dpdCycle}
+
+ ) : (
+
+ Bucket {dpdBucket}
+
+ )}
POS {formatAmount(pos)}
diff --git a/src/screens/caseDetails/CollectionCaseDetail.tsx b/src/screens/caseDetails/CollectionCaseDetail.tsx
index a2131655..621361cd 100644
--- a/src/screens/caseDetails/CollectionCaseDetail.tsx
+++ b/src/screens/caseDetails/CollectionCaseDetail.tsx
@@ -6,9 +6,8 @@ import CaseDetailsHeader from './CaseDetailHeader';
import UserDetailsSection from './UserDetailsSection';
import Layout from '../layout/Layout';
import { _map } from '../../../RN-UI-LIB/src/utlis/common';
-import { AppDispatch, RootState } from '../../store/store';
+import { RootState } from '../../store/store';
import { getCaseUnifiedData, UnifiedCaseDetailsTypes } from '../../action/caseApiActions';
-import useIsOnline from '../../hooks/useIsOnline';
import { CLICKSTREAM_EVENT_NAMES } from '../../common/Constants';
import { addClickstreamEvent } from '../../services/clickstreamEventService';
import ScreenshotBlocker from '../../components/utlis/ScreenshotBlocker';
@@ -21,10 +20,8 @@ import CollectionCaseDetailFooter from './CollectionCaseDetailFooter';
import FeedbackDetailsSection from './FeedbackDetailsSection';
import { COLORS } from '@rn-ui-lib/colors';
import { syncActiveCallDetails } from '@actions/callRecordingActions';
-import { getCustomerDocuments } from '@screens/allCases/utils';
-import { logError } from '@components/utlis/errorUtils';
-import { GenericObject, GenericType } from '@common/GenericTypes';
import { getUngroupedAddress } from '@actions/addressGeolocationAction';
+import EscalationsSection from '@screens/escalations/EscalationsSection';
interface ICaseDetails {
route: {
@@ -52,10 +49,14 @@ const CollectionCaseDetails: React.FC = (props) => {
const duration = 300;
const dispatch = useAppDispatch();
const isFocused = useIsFocused();
- const isOnline = useIsOnline();
const [isDocumentsLoading, setIsDocumentsLoading] = React.useState(false);
+ const {escalationData} = caseDetail || {};
+ const activeEscalationCount = Number(escalationData?.activeEscalationCount);
+ const pastEscalationCount = Number(escalationData?.pastEscalationCount);
+ const totalEscalationsCount = activeEscalationCount + pastEscalationCount;
+
useEffect(() => {
if (caseId) dispatch(setSelectedCaseId(caseId));
@@ -128,6 +129,7 @@ const CollectionCaseDetails: React.FC = (props) => {
]}
>
+ {escalationData && totalEscalationsCount > 0 ? (): null}
diff --git a/src/screens/caseDetails/interface.ts b/src/screens/caseDetails/interface.ts
index eaafec3a..595a4d7f 100644
--- a/src/screens/caseDetails/interface.ts
+++ b/src/screens/caseDetails/interface.ts
@@ -284,7 +284,9 @@ export interface CaseDetail {
customerName: string;
pos: number;
dpdBucket: string;
+ dpdCycle: string;
addresses?: Address[];
+ addressLocation?: IGeolocationCoordinate;
currentAllocationReferenceId: string;
customerReferenceId: string;
caseViewCreatedAt?: number;
@@ -314,6 +316,18 @@ export interface CaseDetail {
employmentDetail?: EmploymentDetails;
unpaidDays?: number;
addressStringType?: string;
+ escalationData ?: escalationData;
+}
+
+export interface recentEscalationDetails {
+ createdAt : string;
+ customerVoice : string;
+}
+
+export interface escalationData {
+ activeEscalationCount : number;
+ pastEscalationCount : number;
+ recentEscalationDetails : recentEscalationDetails;
}
export interface AddressesGeolocationPayload {
diff --git a/src/screens/caseDetails/journeyStepper/RenderIcon.tsx b/src/screens/caseDetails/journeyStepper/RenderIcon.tsx
index 74c2dae2..f03606a4 100644
--- a/src/screens/caseDetails/journeyStepper/RenderIcon.tsx
+++ b/src/screens/caseDetails/journeyStepper/RenderIcon.tsx
@@ -139,11 +139,11 @@ const RenderIcons: React.FC = ({
);
})}
- {telephoneNumberMaskingEnabled ? (
+ {/* {telephoneNumberMaskingEnabled ? (
Attempts: {totalGenuineCallsAttempted}/{totalGenuineCallsRequired}
- ) : null}
+ ) : null} */}
>
);
};
diff --git a/src/screens/escalations/Escalations.tsx b/src/screens/escalations/Escalations.tsx
new file mode 100644
index 00000000..7e4d6dad
--- /dev/null
+++ b/src/screens/escalations/Escalations.tsx
@@ -0,0 +1,94 @@
+import React, { useEffect, useState } from 'react';
+import { ScrollView, View } from 'react-native';
+import { CLICKSTREAM_EVENT_NAMES } from '../../common/Constants';
+import { ToastMessages } from '../allCases/constants';
+import useIsOnline from '../../hooks/useIsOnline';
+import { addClickstreamEvent } from '../../services/clickstreamEventService';
+import { goBack } from '../../components/utlis/navigationUtlis';
+import { toast } from '../../../RN-UI-LIB/src/components/toast';
+import { GenericStyles } from '../../../RN-UI-LIB/src/styles';
+import NavigationHeader from '../../../RN-UI-LIB/src/components/NavigationHeader';
+import SuspenseLoader from '../../../RN-UI-LIB/src/components/suspense_loader/SuspenseLoader';
+import LineLoader from '../../../RN-UI-LIB/src/components/suspense_loader/LineLoader';
+import { COLORS } from '../../../RN-UI-LIB/src/styles/colors';
+import Pagination from '../../../RN-UI-LIB/src/components/pagination/Pagination';
+import { useAppDispatch, useAppSelector } from '@hooks';
+import { RootState } from '@store';
+import { getAllEscalations } from './actions';
+import { setEscalationData } from '@reducers/escalationSlice';
+import { IEscalationsDetails } from './escalations.interfaces';
+import EscalationsList from './EscalationsList';
+
+const Escalations: React.FC = (props) => {
+
+ const {
+ route: {
+ params: { loanAccountNumber },
+ },
+ } = props;
+
+ const { escalationData, isLoading, pageData } = useAppSelector((state: RootState) => state?.escalationSlice);
+ const [currentPage, setCurrentPage] = useState(1);
+ const isOnline = useIsOnline();
+ const dispatch = useAppDispatch();
+
+ useEffect(() => {
+ dispatch(getAllEscalations(loanAccountNumber, { page_no: currentPage - 1, page_size: 10 }));
+ }, [currentPage]);
+
+ const totalEscalationsCount = pageData?.totalElements || 0;
+
+ useEffect(() => {
+ if (!isOnline) {
+ setCurrentPage(1);
+ }
+ }, [isOnline]);
+
+ useEffect(() => {
+ addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_VIEW_ALL_ESCALATIONS_SCREEN_LANDED);
+ return () => {
+ dispatch(setEscalationData([]));
+ };
+ }, []);
+
+ const handlePageChange = (page: number) => {
+ if (!isOnline) {
+ toast({ type: 'info', text1: ToastMessages.OFFLINE_MESSAGE });
+ return;
+ }
+ setCurrentPage(page);
+ };
+
+ return (
+
+
+
+
+ {[...Array(8).keys()].map(() => (
+
+ ))}
+
+ }
+ >
+
+
+
+ {escalationData?.length && pageData?.totalPages > 1 ? (
+
+ ) : null}
+
+ );
+};
+
+export default Escalations;
diff --git a/src/screens/escalations/EscalationsList.tsx b/src/screens/escalations/EscalationsList.tsx
new file mode 100644
index 00000000..2dc37d36
--- /dev/null
+++ b/src/screens/escalations/EscalationsList.tsx
@@ -0,0 +1,115 @@
+import React from 'react';
+import { ESCALATION_STATUS, IEscalationsList } from './escalations.interfaces';
+import FlagIcon from '@assets/icons/FlagIcon';
+import { COLORS } from '@rn-ui-lib/colors';
+import Tag, { TagVariant } from '@rn-ui-lib/components/Tag';
+import { GenericStyles, getShadowStyle } from '@rn-ui-lib/styles';
+import { COSMOS_STANDARD_DATE_FORMAT, COSMOS_STANDARD_TIME_FORMAT } from '@rn-ui-lib/utils/dates';
+import dayjs from 'dayjs';
+import Text from '@rn-ui-lib/components/Text';
+import { View, StyleSheet } from 'react-native';
+
+const EscalationsList: React.FC = (props) => {
+ const { escalationData } = props;
+ const noEscalationsFound = !(escalationData?.length);
+
+ if (noEscalationsFound) {
+ return (
+
+ No escalations found for the customer
+
+ );
+ }
+
+ return <>
+ {escalationData?.map((escalation) => (
+
+
+
+
+
+
+
+
+ {escalation.voc}
+
+
+
+
+ {dayjs(escalation.createdAt).format(COSMOS_STANDARD_DATE_FORMAT)}
+
+
+ {'|'}
+
+
+ {dayjs(escalation.createdAt).format(COSMOS_STANDARD_TIME_FORMAT)}
+
+
+ {escalation.status === ESCALATION_STATUS.OPEN ? (
+
+ ) : (
+
+ )}
+
+
+
+
+
+ Description
+ {escalation.title}
+
+
+
+ )
+ )}
+ >
+}
+
+const styles = StyleSheet.create({
+ secondSection: {
+ alignSelf: 'center',
+ borderRadius: 16,
+ width: '98%',
+ borderWidth: 1,
+ borderColor: COLORS.BACKGROUND.GREY_LIGHT,
+ },
+ textColorGrayscale: {
+ color: COLORS.TEXT.DARK,
+ },
+ textColorGrayscale2: {
+ color: COLORS.TEXT.BLACK,
+ },
+ textColorGrayscale3: {
+ color: COLORS.TEXT.LIGHT,
+ },
+ upperContainer: {
+ flex: 1
+ },
+ flagContainer: {
+ height: 40,
+ width: 40,
+ borderRadius: 20,
+ borderWidth: 1,
+ },
+});
+
+export default EscalationsList;
+
+
+
diff --git a/src/screens/escalations/EscalationsSection.tsx b/src/screens/escalations/EscalationsSection.tsx
new file mode 100644
index 00000000..57751d92
--- /dev/null
+++ b/src/screens/escalations/EscalationsSection.tsx
@@ -0,0 +1,153 @@
+import React from 'react';
+import { StyleSheet, TouchableOpacity, View } from 'react-native';
+import { COLORS } from '@rn-ui-lib/colors';
+import { GenericStyles, getShadowStyle } from '@rn-ui-lib/styles';
+import Text from '@rn-ui-lib/components/Text';
+import Chevron from '@rn-ui-lib/icons/Chevron';
+import { CLICKSTREAM_EVENT_NAMES } from '@common/Constants';
+import { navigateToScreen } from '@components/utlis/navigationUtlis';
+import { RootState } from '@store';
+import { useAppSelector } from '@hooks';
+import { addClickstreamEvent } from '@services/clickstreamEventService';
+import { CaseDetailStackEnum } from '../caseDetails/CaseDetailStack';
+import FlagIcon from '@assets/icons/FlagIcon';
+import dayjs from 'dayjs';
+import { COSMOS_STANDARD_DATE_FORMAT, COSMOS_STANDARD_TIME_FORMAT } from '@rn-ui-lib/utils/dates';
+interface IEscalationsSection {
+ caseId: string;
+}
+
+const EscalationsSection = ({ caseId }: IEscalationsSection) => {
+
+ const caseDetail = useAppSelector((state: RootState) => state.allCases?.caseDetails?.[caseId]) || {};
+ const { escalationData, loanAccountNumber } = caseDetail || {};
+
+
+ const handleOnPressClick = () => {
+ addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_VIEW_ALL_ESCALATIONS_SCREEN_CLICKED, {
+ lan: loanAccountNumber,
+ });
+ navigateToScreen(CaseDetailStackEnum.ESCALATIONS, {
+ loanAccountNumber
+ })
+ };
+
+ const isActiveEscalationCase = Number(escalationData?.activeEscalationCount) > 0;
+ const activeEscalationCount = Number(escalationData?.activeEscalationCount);
+ const pastEscalationCount = Number(escalationData?.pastEscalationCount);
+ const totalEscalationsCount = activeEscalationCount + pastEscalationCount;
+ const escalationCreatedAt = escalationData?.recentEscalationDetails?.createdAt;
+ const customerVoice = escalationData?.recentEscalationDetails?.customerVoice;
+
+ const escalationRaisedDate = dayjs(escalationCreatedAt).format(COSMOS_STANDARD_DATE_FORMAT);
+ const escalationRaisedTime = dayjs(escalationCreatedAt).format(COSMOS_STANDARD_TIME_FORMAT);
+
+ return (
+
+
+
+
+ {isActiveEscalationCase ? (
+
+
+
+ {`${activeEscalationCount} Active Escalation${activeEscalationCount === 1 ? '' : 's'}`}
+
+
+ ) : (
+
+
+
+ {`${pastEscalationCount} Past Escalation${pastEscalationCount === 1 ? '' : 's'}`}
+
+ )
+ }
+
+
+ {customerVoice || 'Escalation Against Agent'}
+
+
+
+ {'Raised on: '}
+
+ {escalationRaisedDate ? <>
+
+ {escalationRaisedDate}
+
+
+ {'|'}
+
+
+ {escalationRaisedTime}
+
+ > : Unknown}
+
+
+
+ View all {`(${totalEscalationsCount})`}
+
+
+
+
+
+
+ );
+};
+export const styles = StyleSheet.create({
+ escalationContainer: {
+ height: 26,
+ marginBottom: 16,
+ paddingLeft: 16,
+ paddingRight: 16,
+ borderBottomRightRadius: 6,
+ borderTopLeftRadius: 16,
+ alignSelf: 'flex-start',
+ borderWidth: 1,
+ },
+ activeEscalationText: {
+ color: COLORS.TEXT.RED,
+ marginLeft: 4,
+ },
+ pastEscalationText: {
+ color: COLORS.TEXT.YELLOW_LIGHT,
+ marginLeft: 4,
+ },
+ redContainer: {
+ borderColor: COLORS.BORDER.RED,
+ },
+ yellowContainer: {
+ borderColor: COLORS.BORDER.YELLOW,
+ },
+ textColorGrayscale2: {
+ color: COLORS.TEXT.BLACK,
+ },
+ textColorGrayscale3: {
+ color: COLORS.TEXT.LIGHT,
+ },
+ viewAllButton: {
+ color: COLORS.TEXT.BLUE,
+ fontSize: 12,
+ lineHeight: 15,
+ marginRight: 10,
+ },
+ br16: {
+ borderRadius: 16,
+ },
+});
+
+export default EscalationsSection;
diff --git a/src/screens/escalations/actions.ts b/src/screens/escalations/actions.ts
new file mode 100644
index 00000000..e50ad7c6
--- /dev/null
+++ b/src/screens/escalations/actions.ts
@@ -0,0 +1,43 @@
+import axiosInstance, { getApiUrl, ApiKeys } from "@components/utlis/apiHelper";
+import { logError } from "@components/utlis/errorUtils";
+import { setEscalationData, setIsLoading, setPageData } from "@reducers/escalationSlice";
+import { AppDispatch } from "@store";
+
+export interface IEscalationPayload {
+ page_no: number;
+ page_size: number;
+}
+
+export interface IAllEscalationsPayload {
+ lan: string;
+ escalationPayload: IEscalationPayload;
+}
+
+export const getAllEscalations = (
+ lan: string,
+ escalationPayload: IEscalationPayload = {
+ page_no: 10,
+ page_size: 0
+ }
+) => (dispatch: AppDispatch) => {
+ dispatch(setIsLoading(true));
+ const payload = {
+ loan_account_number: lan,
+ ...escalationPayload,
+ }
+ const url = getApiUrl(ApiKeys.ALL_ESCALATIONS, {}, payload );
+ return axiosInstance
+ .get(url)
+ .then((response) => {
+ if (response?.data) {
+ dispatch(setEscalationData(response.data.data));
+ dispatch(setPageData(response.data.pages));
+ }
+ })
+ .catch((err) => {
+ logError(err);
+ })
+ .finally(() => {
+ dispatch(setIsLoading(false));
+ });
+}
diff --git a/src/screens/escalations/escalations.interfaces.ts b/src/screens/escalations/escalations.interfaces.ts
new file mode 100644
index 00000000..92cc27e2
--- /dev/null
+++ b/src/screens/escalations/escalations.interfaces.ts
@@ -0,0 +1,35 @@
+export enum ESCALATION_STATUS {
+ OPEN = 'OPEN',
+ CLOSED = 'CLOSED',
+}
+
+export interface IEscalationsSlice {
+ escalationData: IAllEscalationData[];
+ isLoading: boolean;
+ pageData: pageData;
+}
+
+export interface pageData {
+ totalPages: number;
+ totalElements: number;
+}
+
+export interface IAllEscalationData {
+ createdAt: string;
+ loanAccountNumber: string;
+ status: string;
+ title: string;
+ voc: string;
+}
+
+export interface IEscalationsDetails {
+ route: {
+ params: {
+ loanAccountNumber: string;
+ };
+ };
+}
+
+export interface IEscalationsList {
+ escalationData: IAllEscalationData[];
+}
\ No newline at end of file
diff --git a/src/screens/notifications/NotificationTemplate.tsx b/src/screens/notifications/NotificationTemplate.tsx
index 68f3bc1a..7ba6554c 100644
--- a/src/screens/notifications/NotificationTemplate.tsx
+++ b/src/screens/notifications/NotificationTemplate.tsx
@@ -364,6 +364,13 @@ const NotificationTemplate: React.FC = ({ data }) =>
has been deallocated from your case list due to a pause in collection efforts.
);
+ case NotificationTypes.CASE_ESCALATION_NOTIFICATION_TEMPLATE:
+ return (
+
+ raised a new{' '}
+ escalation
+
+ );
default:
return New notification ;
}
diff --git a/src/screens/notifications/constants.tsx b/src/screens/notifications/constants.tsx
index 75957c7d..21547ddc 100644
--- a/src/screens/notifications/constants.tsx
+++ b/src/screens/notifications/constants.tsx
@@ -21,6 +21,7 @@ import PerformanceLevelMayDropIcon from "@assets/icons/PerformanceLevelMayDropIc
import PerformanceLevelMayIncreaseIcon from "@assets/icons/PerformanceLevelMayIncreaseIcon";
import MissedCallNotificationIcon from '@rn-ui-lib/icons/MissedCallNotificationIcon';
import InfoNotificationIcon from '@assets/icons/InfoNotificationIcon';
+import EscalationsIcon from '@assets/icons/EscalationIcon';
export enum NotificationTypes {
PAYMENT_MADE_TEMPLATE = 'PAYMENT_MADE_TEMPLATE',
@@ -61,6 +62,7 @@ export enum NotificationTypes {
AGENT_REVIVAL_PERFORMANCE_LEVEL_MAY_INCREASED_REMINDER_NOTIFICATION = 'AGENT_REVIVAL_PERFORMANCE_LEVEL_MAY_INCREASED_REMINDER_NOTIFICATION',
CUSTOMER_TRIED_CALLING_NOTIFICATION = 'CUSTOMER_TRIED_CALLING_NOTIFICATION',
COLLECTION_PAUSE_EFFORTS_CASE_DEALLOCATED = 'COLLECTION_PAUSE_EFFORTS_CASE_DEALLOCATED',
+ CASE_ESCALATION_NOTIFICATION_TEMPLATE='CASE_ESCALATION_NOTIFICATION_TEMPLATE',
}
export const NotificationIconsMap = {
@@ -102,6 +104,7 @@ export const NotificationIconsMap = {
[NotificationTypes.AGENT_REVIVAL_PERFORMANCE_LEVEL_MAY_INCREASED_REMINDER_NOTIFICATION]: ,
[NotificationTypes.CUSTOMER_TRIED_CALLING_NOTIFICATION]: ,
[NotificationTypes.COLLECTION_PAUSE_EFFORTS_CASE_DEALLOCATED]: ,
+ [NotificationTypes.CASE_ESCALATION_NOTIFICATION_TEMPLATE]: ,
};
export enum WidgetStatus {
diff --git a/src/screens/registerPayements/ForeclosureBreakupAccordion.tsx b/src/screens/registerPayements/ForeclosureBreakupAccordion.tsx
index c2292482..a9d5b5a6 100644
--- a/src/screens/registerPayements/ForeclosureBreakupAccordion.tsx
+++ b/src/screens/registerPayements/ForeclosureBreakupAccordion.tsx
@@ -21,15 +21,24 @@ export interface IForeclosureBreakup {
penaltyCharges: number;
closingInterest: number;
excessAvailable: number;
+ totalAmountPreWaiver?: number;
+ penaltyChargesPreWaiver?: number;
}
-
const ForeclosureBreakupAccordion: React.FC = ({
title,
foreclosureBreakup,
defaultExpanded,
}) => {
- const { totalAmount, principal, interest, penaltyCharges, excessAvailable, closingInterest } =
- foreclosureBreakup;
+ const {
+ totalAmount,
+ principal,
+ interest,
+ penaltyCharges,
+ excessAvailable,
+ closingInterest,
+ totalAmountPreWaiver,
+ penaltyChargesPreWaiver = 0,
+ } = foreclosureBreakup;
const foreclosureBreakupMap = useMemo(
() => [
{
@@ -43,6 +52,8 @@ const ForeclosureBreakupAccordion: React.FC = ({
{
label: 'Penalty charges',
value: penaltyCharges,
+ preAmount: penaltyChargesPreWaiver,
+ showPreAmount: penaltyChargesPreWaiver > 0,
},
{
label: 'Closing interest',
@@ -53,7 +64,7 @@ const ForeclosureBreakupAccordion: React.FC = ({
value: excessAvailable,
},
],
- [principal, interest, penaltyCharges, excessAvailable, closingInterest]
+ [principal, interest, penaltyCharges, excessAvailable, closingInterest, penaltyChargesPreWaiver]
);
return (
@@ -75,8 +86,8 @@ const ForeclosureBreakupAccordion: React.FC = ({
containerStyle={GenericStyles.silverBackground}
defaultExpanded={defaultExpanded}
>
- {foreclosureBreakupMap.map(({ label, value }) =>
- value > 0 ? (
+ {foreclosureBreakupMap.map(({ label, value, preAmount, showPreAmount }) =>
+ value > 0 || showPreAmount ? (
= ({
loading={totalAmount === 0}
fallBack={}
>
- {formatAmount(value)}
+
+
+ {formatAmount(value)}
+
+ {showPreAmount ? (
+
+ {formatAmount(preAmount)}
+
+ ) : null}
+
) : null
@@ -109,4 +129,7 @@ const styles = StyleSheet.create({
color: COLORS.TEXT.GREEN,
marginRight: 14,
},
+ strikethrough: {
+ textDecorationLine: 'line-through',
+ },
});
diff --git a/src/services/FeedbackWhatsApp.ts b/src/services/FeedbackWhatsApp.ts
index c2df95ca..3b758f7a 100644
--- a/src/services/FeedbackWhatsApp.ts
+++ b/src/services/FeedbackWhatsApp.ts
@@ -64,7 +64,7 @@ const sendToWhatsapp = (
let message = `*Visit Feedback* for ${sanitizeString(caseDetails?.customerName)}
_${sanitizeString(dateFormat(new Date(feedbackItem?.createdAt), 'DD MMM, YYYY | HH:mm a.'))}_\n
*LAN*: ${sanitizeString(caseDetails?.loanAccountNumber)}
-*DPD Bucket*: ${sanitizeString(caseDetails?.dpdBucket)}
+*Bucket*: ${sanitizeString(caseDetails?.dpdBucket)}
*EMI Amount*: ₹${getSanitizedCommaAmount(caseDetails?.currentOutstandingEmi)}\n
*Disposition*: ${sanitizeString(feedbackItem?.interactionStatus)}`;
diff --git a/src/store/store.ts b/src/store/store.ts
index 2ecd7293..436296d2 100644
--- a/src/store/store.ts
+++ b/src/store/store.ts
@@ -16,6 +16,7 @@ import repaymentsSlice from '../reducer/repaymentsSlice';
import feedbackHistorySlice from '../reducer/feedbackHistorySlice';
import notificationsSlice from '../reducer/notificationsSlice';
import MetadataSlice from '../reducer/metadataSlice';
+import AppUpdateSlice from '../reducer/appUpdateSlice';
import foregroundServiceSlice from '../reducer/foregroundServiceSlice';
import feedbackImagesSlice from '../reducer/feedbackImagesSlice';
import configSlice from '../reducer/configSlice';
@@ -32,6 +33,7 @@ import commitmentTrackerSlice from '@reducers/commitmentTrackerSlice';
import nearbyCasesSlice from '@reducers/nearbyCasesSlice';
import activeCallSlice from '@reducers/activeCallSlice';
import documentsSlice from '@reducers/documentsSlice';
+import escalationSlice from '@reducers/escalationSlice';
const rootReducer = combineReducers({
case: caseReducer,
@@ -47,6 +49,7 @@ const rootReducer = combineReducers({
address: addressSlice,
notifications: notificationsSlice,
metadata: MetadataSlice,
+ appUpdate: AppUpdateSlice,
foregroundService: foregroundServiceSlice,
feedbackImages: feedbackImagesSlice,
config: configSlice,
@@ -64,6 +67,7 @@ const rootReducer = combineReducers({
nearbyCasesSlice: nearbyCasesSlice,
activeCall: activeCallSlice,
documentsSlice: documentsSlice,
+ escalationSlice: escalationSlice,
});
const persistConfig = {
@@ -86,7 +90,8 @@ const persistConfig = {
'foregroundService',
'feedbackFilters',
'litmusExperiment',
- 'activeCall'
+ 'activeCall',
+ 'appUpdate'
],
blackList: [
'case',
diff --git a/yarn.lock b/yarn.lock
index e7986a74..723badb3 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1692,114 +1692,211 @@
redux-thunk "^2.4.2"
reselect "^4.1.7"
-"@sentry-internal/tracing@7.52.0":
- version "7.52.0"
- resolved "https://registry.yarnpkg.com/@sentry-internal/tracing/-/tracing-7.52.0.tgz#c4e0750ad0c3949c5bb4b59cbb708b0fef274080"
- integrity sha512-o1YPcRGtC9tjeFCvWRJsbgK94zpExhzfxWaldAKvi3PuWEmPeewSdO/Q5pBIY1QonvSI+Q3gysLRcVlLYHhO5A==
+"@sentry-internal/feedback@7.119.1":
+ version "7.119.1"
+ resolved "https://registry.yarnpkg.com/@sentry-internal/feedback/-/feedback-7.119.1.tgz#98285dc9dba0ab62369d758124901b00faf58697"
+ integrity sha512-EPyW6EKZmhKpw/OQUPRkTynXecZdYl4uhZwdZuGqnGMAzswPOgQvFrkwsOuPYvoMfXqCH7YuRqyJrox3uBOrTA==
dependencies:
- "@sentry/core" "7.52.0"
- "@sentry/types" "7.52.0"
- "@sentry/utils" "7.52.0"
- tslib "^1.9.3"
+ "@sentry/core" "7.119.1"
+ "@sentry/types" "7.119.1"
+ "@sentry/utils" "7.119.1"
-"@sentry/browser@7.52.0":
- version "7.52.0"
- resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-7.52.0.tgz#55d266c89ed668389ff687e5cc885c27016ea85c"
- integrity sha512-Sib0T24cQCqqqAhg+nZdfI7qNYGE03jiM3RbY7yG5UoycdnJzWEwrBVSzRTgg3Uya9TRTEGJ+d9vxPIU5TL7TA==
+"@sentry-internal/replay-canvas@7.119.1":
+ version "7.119.1"
+ resolved "https://registry.yarnpkg.com/@sentry-internal/replay-canvas/-/replay-canvas-7.119.1.tgz#b1413fb37734d609b0745ac24d49ddf9d63b9c51"
+ integrity sha512-O/lrzENbMhP/UDr7LwmfOWTjD9PLNmdaCF408Wx8SDuj7Iwc+VasGfHg7fPH4Pdr4nJON6oh+UqoV4IoG05u+A==
dependencies:
- "@sentry-internal/tracing" "7.52.0"
- "@sentry/core" "7.52.0"
- "@sentry/replay" "7.52.0"
- "@sentry/types" "7.52.0"
- "@sentry/utils" "7.52.0"
- tslib "^1.9.3"
+ "@sentry/core" "7.119.1"
+ "@sentry/replay" "7.119.1"
+ "@sentry/types" "7.119.1"
+ "@sentry/utils" "7.119.1"
-"@sentry/cli@2.17.5":
- version "2.17.5"
- resolved "https://registry.yarnpkg.com/@sentry/cli/-/cli-2.17.5.tgz#d41e24893a843bcd41e14274044a7ddea9332824"
- integrity sha512-0tXjLDpaKB46851EMJ6NbP0o9/gdEaDSLAyjEtXxlVO6+RyhUj6x6jDwn0vis8n/7q0AvbIjAcJrot+TbZP+WQ==
+"@sentry-internal/tracing@7.119.1":
+ version "7.119.1"
+ resolved "https://registry.yarnpkg.com/@sentry-internal/tracing/-/tracing-7.119.1.tgz#500d50d451bfd0ce6b185e9f112208229739ab03"
+ integrity sha512-cI0YraPd6qBwvUA3wQdPGTy8PzAoK0NZiaTN1LM3IczdPegehWOaEG5GVTnpGnTsmBAzn1xnBXNBhgiU4dgcrQ==
+ dependencies:
+ "@sentry/core" "7.119.1"
+ "@sentry/types" "7.119.1"
+ "@sentry/utils" "7.119.1"
+
+"@sentry/babel-plugin-component-annotate@2.20.1":
+ version "2.20.1"
+ resolved "https://registry.yarnpkg.com/@sentry/babel-plugin-component-annotate/-/babel-plugin-component-annotate-2.20.1.tgz#204c63ed006a048f48f633876e1b8bacf87a9722"
+ integrity sha512-4mhEwYTK00bIb5Y9UWIELVUfru587Vaeg0DQGswv4aIRHIiMKLyNqCEejaaybQ/fNChIZOKmvyqXk430YVd7Qg==
+
+"@sentry/browser@7.119.1":
+ version "7.119.1"
+ resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-7.119.1.tgz#260470dd7fd18de366017c3bf23a252a24d2ff05"
+ integrity sha512-aMwAnFU4iAPeLyZvqmOQaEDHt/Dkf8rpgYeJ0OEi50dmP6AjG+KIAMCXU7CYCCQDn70ITJo8QD5+KzCoZPYz0A==
+ dependencies:
+ "@sentry-internal/feedback" "7.119.1"
+ "@sentry-internal/replay-canvas" "7.119.1"
+ "@sentry-internal/tracing" "7.119.1"
+ "@sentry/core" "7.119.1"
+ "@sentry/integrations" "7.119.1"
+ "@sentry/replay" "7.119.1"
+ "@sentry/types" "7.119.1"
+ "@sentry/utils" "7.119.1"
+
+"@sentry/cli-darwin@2.37.0":
+ version "2.37.0"
+ resolved "https://registry.yarnpkg.com/@sentry/cli-darwin/-/cli-darwin-2.37.0.tgz#9c890c68abf30ceaad27826212a0963b125b8bbf"
+ integrity sha512-CsusyMvO0eCPSN7H+sKHXS1pf637PWbS4rZak/7giz/z31/6qiXmeMlcL3f9lLZKtFPJmXVFO9uprn1wbBVF8A==
+
+"@sentry/cli-linux-arm64@2.37.0":
+ version "2.37.0"
+ resolved "https://registry.yarnpkg.com/@sentry/cli-linux-arm64/-/cli-linux-arm64-2.37.0.tgz#2070155bade6d72d6b706807c6f365c65f9b82ea"
+ integrity sha512-2vzUWHLZ3Ct5gpcIlfd/2Qsha+y9M8LXvbZE26VxzYrIkRoLAWcnClBv8m4XsHLMURYvz3J9QSZHMZHSO7kAzw==
+
+"@sentry/cli-linux-arm@2.37.0":
+ version "2.37.0"
+ resolved "https://registry.yarnpkg.com/@sentry/cli-linux-arm/-/cli-linux-arm-2.37.0.tgz#a08c2133e8e2566074fd6fe4f68e9ffd0c85664a"
+ integrity sha512-Dz0qH4Yt+gGUgoVsqVt72oDj4VQynRF1QB1/Sr8g76Vbi+WxWZmUh0iFwivYVwWxdQGu/OQrE0tx946HToCRyA==
+
+"@sentry/cli-linux-i686@2.37.0":
+ version "2.37.0"
+ resolved "https://registry.yarnpkg.com/@sentry/cli-linux-i686/-/cli-linux-i686-2.37.0.tgz#53fff0e7f232b656b0ee3413b66006ee724a4abf"
+ integrity sha512-MHRLGs4t/CQE1pG+mZBQixyWL6xDZfNalCjO8GMcTTbZFm44S3XRHfYJZNVCgdtnUP7b6OHGcu1v3SWE10LcwQ==
+
+"@sentry/cli-linux-x64@2.37.0":
+ version "2.37.0"
+ resolved "https://registry.yarnpkg.com/@sentry/cli-linux-x64/-/cli-linux-x64-2.37.0.tgz#2fbaf51ef3884bd6561c987f01ac98f544457150"
+ integrity sha512-k76ClefKZaDNJZU/H3mGeR8uAzAGPzDRG/A7grzKfBeyhP3JW09L7Nz9IQcSjCK+xr399qLhM2HFCaPWQ6dlMw==
+
+"@sentry/cli-win32-i686@2.37.0":
+ version "2.37.0"
+ resolved "https://registry.yarnpkg.com/@sentry/cli-win32-i686/-/cli-win32-i686-2.37.0.tgz#fa195664da27ce8c40fdb6db1bf1d125cdf587d9"
+ integrity sha512-FFyi5RNYQQkEg4GkP2f3BJcgQn0F4fjFDMiWkjCkftNPXQG+HFUEtrGsWr6mnHPdFouwbYg3tEPUWNxAoypvTw==
+
+"@sentry/cli-win32-x64@2.37.0":
+ version "2.37.0"
+ resolved "https://registry.yarnpkg.com/@sentry/cli-win32-x64/-/cli-win32-x64-2.37.0.tgz#84fa4d070b8a4a115c46ab38f42d29580143fd26"
+ integrity sha512-nSMj4OcfQmyL+Tu/jWCJwhKCXFsCZW1MUk6wjjQlRt9SDLfgeapaMlK1ZvT1eZv5ZH6bj3qJfefwj4U8160uOA==
+
+"@sentry/cli@2.37.0":
+ version "2.37.0"
+ resolved "https://registry.yarnpkg.com/@sentry/cli/-/cli-2.37.0.tgz#dd01e933cf1caed7d7b6abab5a96044fe1c9c7a1"
+ integrity sha512-fM3V4gZRJR/s8lafc3O07hhOYRnvkySdPkvL/0e0XW0r+xRwqIAgQ5ECbsZO16A5weUiXVSf03ztDL1FcmbJCQ==
dependencies:
https-proxy-agent "^5.0.0"
node-fetch "^2.6.7"
progress "^2.0.3"
proxy-from-env "^1.1.0"
which "^2.0.2"
+ optionalDependencies:
+ "@sentry/cli-darwin" "2.37.0"
+ "@sentry/cli-linux-arm" "2.37.0"
+ "@sentry/cli-linux-arm64" "2.37.0"
+ "@sentry/cli-linux-i686" "2.37.0"
+ "@sentry/cli-linux-x64" "2.37.0"
+ "@sentry/cli-win32-i686" "2.37.0"
+ "@sentry/cli-win32-x64" "2.37.0"
-"@sentry/core@7.52.0":
- version "7.52.0"
- resolved "https://registry.yarnpkg.com/@sentry/core/-/core-7.52.0.tgz#6c820ca48fe2f06bfd6b290044c96de2375f2ad4"
- integrity sha512-BWdG6vCMeUeMhF4ILpxXTmw70JJvT1MGJcnv09oSupWHTmqy6I19YP6YcEyFuBL4jXPN51eCl7luIdLGJrPbOg==
+"@sentry/core@7.119.0":
+ version "7.119.0"
+ resolved "https://registry.yarnpkg.com/@sentry/core/-/core-7.119.0.tgz#a6e41119bb03ec27689f9ad04e79d1fba5b7fc37"
+ integrity sha512-CS2kUv9rAJJEjiRat6wle3JATHypB0SyD7pt4cpX5y0dN5dZ1JrF57oLHRMnga9fxRivydHz7tMTuBhSSwhzjw==
dependencies:
- "@sentry/types" "7.52.0"
- "@sentry/utils" "7.52.0"
- tslib "^1.9.3"
+ "@sentry/types" "7.119.0"
+ "@sentry/utils" "7.119.0"
-"@sentry/hub@7.52.0":
- version "7.52.0"
- resolved "https://registry.yarnpkg.com/@sentry/hub/-/hub-7.52.0.tgz#ffc087d58c745d57108862faa0f701b15503dcc2"
- integrity sha512-w3d8Pmp3Fx2zbbjz6hAeIbsFEkLyrUs9YTGG2y8oCoTlAtGK+AjdG+Z0H/clAZONflD/je2EmFHCI0EuXE9tEw==
+"@sentry/core@7.119.1":
+ version "7.119.1"
+ resolved "https://registry.yarnpkg.com/@sentry/core/-/core-7.119.1.tgz#63e949cad167a0ee5e52986c93b96ff1d6a05b57"
+ integrity sha512-YUNnH7O7paVd+UmpArWCPH4Phlb5LwrkWVqzFWqL3xPyCcTSof2RL8UmvpkTjgYJjJ+NDfq5mPFkqv3aOEn5Sw==
dependencies:
- "@sentry/core" "7.52.0"
- "@sentry/types" "7.52.0"
- "@sentry/utils" "7.52.0"
- tslib "^1.9.3"
+ "@sentry/types" "7.119.1"
+ "@sentry/utils" "7.119.1"
-"@sentry/integrations@7.52.0":
- version "7.52.0"
- resolved "https://registry.yarnpkg.com/@sentry/integrations/-/integrations-7.52.0.tgz#632aa5e54bdfdab910a24057c2072634a2670409"
- integrity sha512-tqxYzgc71XdFD8MTCsVMCPef08lPY9jULE5Zi7TzjyV2AItDRJPkixG0qjwjOGwCtN/6KKz0lGPGYU8ZDxvsbg==
+"@sentry/hub@7.119.0":
+ version "7.119.0"
+ resolved "https://registry.yarnpkg.com/@sentry/hub/-/hub-7.119.0.tgz#a94d657b9d3cfd4cc061c5c238f86faefb55d5d8"
+ integrity sha512-183h5B/rZosLxpB+ZYOvFdHk0rwZbKskxqKFtcyPbDAfpCUgCass41UTqyxF6aH1qLgCRxX8GcLRF7frIa/SOg==
dependencies:
- "@sentry/types" "7.52.0"
- "@sentry/utils" "7.52.0"
+ "@sentry/core" "7.119.0"
+ "@sentry/types" "7.119.0"
+ "@sentry/utils" "7.119.0"
+
+"@sentry/integrations@7.119.0":
+ version "7.119.0"
+ resolved "https://registry.yarnpkg.com/@sentry/integrations/-/integrations-7.119.0.tgz#5b25c603026dbacfe1ae7bb8d768506a129149fb"
+ integrity sha512-OHShvtsRW0A+ZL/ZbMnMqDEtJddPasndjq+1aQXw40mN+zeP7At/V1yPZyFaURy86iX7Ucxw5BtmzuNy7hLyTA==
+ dependencies:
+ "@sentry/core" "7.119.0"
+ "@sentry/types" "7.119.0"
+ "@sentry/utils" "7.119.0"
localforage "^1.8.1"
- tslib "^1.9.3"
-"@sentry/react-native@5.5.0":
- version "5.5.0"
- resolved "https://registry.yarnpkg.com/@sentry/react-native/-/react-native-5.5.0.tgz#b1283f68465b1772ad6059ebba149673cef33f2d"
- integrity sha512-xrES+OAIu3HFhoQSuJjd16Hh02/mByuNoKUjF7e4WDGIiTew3aqlqeLjU7x4npmg5Vbt+ND5jR12u/NmdfArwg==
+"@sentry/integrations@7.119.1":
+ version "7.119.1"
+ resolved "https://registry.yarnpkg.com/@sentry/integrations/-/integrations-7.119.1.tgz#9fc17aa9fcb942fbd2fc12eecd77a0f316897960"
+ integrity sha512-CGmLEPnaBqbUleVqrmGYjRjf5/OwjUXo57I9t0KKWViq81mWnYhaUhRZWFNoCNQHns+3+GPCOMvl0zlawt+evw==
dependencies:
- "@sentry/browser" "7.52.0"
- "@sentry/cli" "2.17.5"
- "@sentry/core" "7.52.0"
- "@sentry/hub" "7.52.0"
- "@sentry/integrations" "7.52.0"
- "@sentry/react" "7.52.0"
- "@sentry/types" "7.52.0"
- "@sentry/utils" "7.52.0"
+ "@sentry/core" "7.119.1"
+ "@sentry/types" "7.119.1"
+ "@sentry/utils" "7.119.1"
+ localforage "^1.8.1"
-"@sentry/react@7.52.0":
- version "7.52.0"
- resolved "https://registry.yarnpkg.com/@sentry/react/-/react-7.52.0.tgz#d12d270ec82dea0474e69deb9112181affe7c524"
- integrity sha512-VQxquyFFlvB81k7UER7tTJxjzbczNI2jqsw6nN1TVDrAIDt8/hT2x7m/M0FlWc88roBKuaMmbvzfNGWaL9abyQ==
+"@sentry/react-native@5.35.0":
+ version "5.35.0"
+ resolved "https://registry.yarnpkg.com/@sentry/react-native/-/react-native-5.35.0.tgz#22afc7b339aaa764101d8786e9240e1d1737077c"
+ integrity sha512-fJIwB2rK6LSFqaPN+f6sa/N0/027AJFtTY3UVmjNl4stY7Q3S/L6fIP4qJJF6YMYeZc+/j8+m+1R1yHvXMX3ew==
dependencies:
- "@sentry/browser" "7.52.0"
- "@sentry/types" "7.52.0"
- "@sentry/utils" "7.52.0"
+ "@sentry/babel-plugin-component-annotate" "2.20.1"
+ "@sentry/browser" "7.119.1"
+ "@sentry/cli" "2.37.0"
+ "@sentry/core" "7.119.1"
+ "@sentry/hub" "7.119.0"
+ "@sentry/integrations" "7.119.0"
+ "@sentry/react" "7.119.1"
+ "@sentry/types" "7.119.1"
+ "@sentry/utils" "7.119.1"
+
+"@sentry/react@7.119.1":
+ version "7.119.1"
+ resolved "https://registry.yarnpkg.com/@sentry/react/-/react-7.119.1.tgz#5cd76fe42209a1cfca6d5197e25c0c8d18299d56"
+ integrity sha512-Bri314LnSVm16K3JATgn3Zsq6Uj3M/nIjdUb3nggBw0BMlFWMsyFjUCfmCio5d80KJK/lUjOIxRjzu79M6jOzQ==
+ dependencies:
+ "@sentry/browser" "7.119.1"
+ "@sentry/core" "7.119.1"
+ "@sentry/types" "7.119.1"
+ "@sentry/utils" "7.119.1"
hoist-non-react-statics "^3.3.2"
- tslib "^1.9.3"
-"@sentry/replay@7.52.0":
- version "7.52.0"
- resolved "https://registry.yarnpkg.com/@sentry/replay/-/replay-7.52.0.tgz#4d78e88282d2c1044ea4b648a68d1b22173e810d"
- integrity sha512-RRPALjDST2s7MHiMcUJ7Wo4WW7EWfUDYSG0LuhMT8DNc+ZsxQoFsLYX/yz8b3f0IUSr7xKBXP+aPeIy3jDAS2g==
+"@sentry/replay@7.119.1":
+ version "7.119.1"
+ resolved "https://registry.yarnpkg.com/@sentry/replay/-/replay-7.119.1.tgz#117cf493a3008a39943b7d571d451c6218542847"
+ integrity sha512-4da+ruMEipuAZf35Ybt2StBdV1S+oJbSVccGpnl9w6RoeQoloT4ztR6ML3UcFDTXeTPT1FnHWDCyOfST0O7XMw==
dependencies:
- "@sentry/core" "7.52.0"
- "@sentry/types" "7.52.0"
- "@sentry/utils" "7.52.0"
+ "@sentry-internal/tracing" "7.119.1"
+ "@sentry/core" "7.119.1"
+ "@sentry/types" "7.119.1"
+ "@sentry/utils" "7.119.1"
-"@sentry/types@7.52.0":
- version "7.52.0"
- resolved "https://registry.yarnpkg.com/@sentry/types/-/types-7.52.0.tgz#b7d5372f17355e3991cbe818ad567f3fe277cc6b"
- integrity sha512-XnEWpS6P6UdP1FqbmeqhI96Iowqd2jM5R7zJ97txTdAd5NmdHHH0pODTR9NiQViA1WlsXDut7ZLxgPzC9vIcMA==
+"@sentry/types@7.119.0":
+ version "7.119.0"
+ resolved "https://registry.yarnpkg.com/@sentry/types/-/types-7.119.0.tgz#8b3d7a1405c362e75cd900d46089df4e70919d2a"
+ integrity sha512-27qQbutDBPKGbuJHROxhIWc1i0HJaGLA90tjMu11wt0E4UNxXRX+UQl4Twu68v4EV3CPvQcEpQfgsViYcXmq+w==
-"@sentry/utils@7.52.0":
- version "7.52.0"
- resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-7.52.0.tgz#cacc36d905036ba7084c14965e964fc44239d7f0"
- integrity sha512-X1NHYuqW0qpZfP731YcVe+cn36wJdAeBHPYPIkXCl4o4GePCJfH/CM/+9V9cZykNjyLrs2Xy/TavSAHNCj8j7w==
+"@sentry/types@7.119.1":
+ version "7.119.1"
+ resolved "https://registry.yarnpkg.com/@sentry/types/-/types-7.119.1.tgz#f9c3c12e217c9078a6d556c92590e42a39b750dd"
+ integrity sha512-4G2mcZNnYzK3pa2PuTq+M2GcwBRY/yy1rF+HfZU+LAPZr98nzq2X3+mJHNJoobeHRkvVh7YZMPi4ogXiIS5VNQ==
+
+"@sentry/utils@7.119.0":
+ version "7.119.0"
+ resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-7.119.0.tgz#debe29020f6ef3786a5bd855cf1b97116b7be826"
+ integrity sha512-ZwyXexWn2ZIe2bBoYnXJVPc2esCSbKpdc6+0WJa8eutXfHq3FRKg4ohkfCBpfxljQGEfP1+kfin945lA21Ka+A==
dependencies:
- "@sentry/types" "7.52.0"
- tslib "^1.9.3"
+ "@sentry/types" "7.119.0"
+
+"@sentry/utils@7.119.1":
+ version "7.119.1"
+ resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-7.119.1.tgz#08b28fa8170987a60e149e2102e83395a95e9a89"
+ integrity sha512-ju/Cvyeu/vkfC5/XBV30UNet5kLEicZmXSyuLwZu95hEbL+foPdxN+re7pCI/eNqfe3B2vz7lvz5afLVOlQ2Hg==
+ dependencies:
+ "@sentry/types" "7.119.1"
"@shopify/flash-list@1.4.3":
version "1.4.3"
@@ -9348,7 +9445,7 @@ tslib@2.4.0:
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.0.tgz#7cecaa7f073ce680a05847aa77be941098f36dc3"
integrity sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==
-tslib@^1.8.1, tslib@^1.9.3:
+tslib@^1.8.1:
version "1.14.1"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"
integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==