diff --git a/.github/workflows/codePush.yml b/.github/workflows/codePush.yml
index 2501732a..c57a6a02 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:
@@ -91,11 +94,45 @@ jobs:
--sourcemap-output index.android.bundle.map
- name: Upload Source Map
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@v4
with:
- name: source-map
+ name: source-map-${{github.event.inputs.target_versions}}
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@v4
+ with:
+ name: source-map-${{github.event.inputs.target_versions}}
+ 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]
@@ -110,7 +147,7 @@ jobs:
- name: Check if tag exists
id: check_tag
run: |
- TAG_NAME="${{github.event.inputs.version_name || inputs.version_name}}"
+ TAG_NAME="${{ needs.generate_source_map.outputs.package_version }}"
EXISTING_TAG=$(git ls-remote --tags origin refs/tags/$TAG_NAME)
if [[ -z "$EXISTING_TAG" ]]; then
echo "Tag $TAG_NAME does not exist."
@@ -123,7 +160,7 @@ jobs:
- name: Create and push tag
if: env.tag_exists == 'false'
run: |
- TAG_NAME="${{github.event.inputs.version_name || inputs.version_name}}"
+ TAG_NAME="${{ needs.generate_source_map.outputs.package_version }}"
# git config --local user.email "${{ github.actor }}@github.com"
git config --local user.name "${{ github.actor }}"
git tag $TAG_NAME
@@ -132,7 +169,7 @@ jobs:
GITHUB_TOKEN: ${{ secrets.MY_REPO_PAT }}
- name: Create release tag
run: |
- TAG_NAME="${{github.event.inputs.version_name || inputs.version_name}}"
+ TAG_NAME="${{ needs.generate_source_map.outputs.package_version }}"
BUILD_NUMBER="${{ needs.generate.outputs.build_number }}"
RELEASE_NAME="$TAG_NAME (build $BUILD_NUMBER) code push"
DESCRIPTION="${{ github.event.inputs.description }}"
diff --git a/.github/workflows/codepushTele.yml b/.github/workflows/codepushTele.yml
index 328c013a..ed681a35 100644
--- a/.github/workflows/codepushTele.yml
+++ b/.github/workflows/codepushTele.yml
@@ -1,4 +1,4 @@
-name: code-push-cli
+name: code-push-cli-tele
on:
workflow_dispatch:
@@ -152,4 +152,4 @@ jobs:
\"generate_release_notes\": true
}" \
"https://api.github.com/repos/$REPO/releases"
- shell: bash
+ shell: bash
\ No newline at end of file
diff --git a/.github/workflows/hardReleaseTele.yml b/.github/workflows/hardReleaseTele.yml
index 1d57651b..8b93f054 100644
--- a/.github/workflows/hardReleaseTele.yml
+++ b/.github/workflows/hardReleaseTele.yml
@@ -1,4 +1,4 @@
-name: generate-apk
+name: generate-apk-tele
on:
workflow_dispatch:
diff --git a/.github/workflows/newBuild.yml b/.github/workflows/newBuild.yml
index a59588b5..559bb7a9 100644
--- a/.github/workflows/newBuild.yml
+++ b/.github/workflows/newBuild.yml
@@ -10,6 +10,13 @@ on:
options:
- QA
- Prod
+ runnerType:
+ description: Choose runner type
+ required: true
+ type: choice
+ options:
+ - default
+ - macos
flavor:
description: Choose build flavour
required: true
@@ -43,25 +50,34 @@ on:
default: "3.2.1"
jobs:
generate:
- runs-on: [ default ]
+ runs-on: ${{ github.event.inputs.runnerType }}
+ outputs:
+ package_version: ${{ github.event.inputs.version_name }}
+ build_number: ${{ github.event.inputs.version_code }}
steps:
- name: Checkout
uses: actions/checkout@v2
with:
token: ${{ secrets.MY_REPO_PAT }}
submodules: recursive
- - name: update codepush key QA Field
- if: ((github.event.inputs.environment == 'QA' || inputs.environment == 'QA')&& (github.event.inputs.flavor == 'fieldAgents' || inputs.flavor == 'fieldAgents'))
- 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 Field
- if: ((github.event.inputs.environment == 'Prod' || inputs.environment == 'Prod') &&(github.event.inputs.flavor == 'fieldAgents' || inputs.flavor == 'fieldAgents'))
- run: sed -i "s/pastekeyhere/${{ secrets.CODEPUSH_PROD_KEY }}/" android/app/src/main/res/values/strings.xml && cat android/app/src/main/res/values/strings.xml
- - name: update codepush key QA Calling
- if: ((github.event.inputs.environment == 'QA' || inputs.environment == 'QA')&& (github.event.inputs.flavor == 'callingAgents' || inputs.flavor == 'callingAgents'))
- run: sed -i "s/pastekeyhere/${{ secrets.TELE_CODE_PUSH_QA_KEY }}/" android/app/src/main/res/values/strings.xml && cat android/app/src/main/res/values/strings.xml
- - name: update codepush key PROD Calling
- if: ((github.event.inputs.environment == 'Prod' || inputs.environment == 'Prod') &&(github.event.inputs.flavor == 'callingAgents' || inputs.flavor == 'callingAgents'))
- 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: Update CodePush key for QA
+ if: (github.event.inputs.environment == 'QA' || inputs.environment == 'QA')
+ run: |
+ if [[ "${{github.event.inputs.runnerType}}" == "macos" ]]; then
+ sed -i "" "s/pastekeyhere/${{ secrets.CODEPUSH_QA_KEY }}/" android/app/src/main/res/values/strings.xml
+ else
+ sed -i "s/pastekeyhere/${{ secrets.CODEPUSH_QA_KEY }}/" android/app/src/main/res/values/strings.xml
+ fi
+ cat android/app/src/main/res/values/strings.xml
+ - name: Update CodePush key for PROD
+ if: (github.event.inputs.environment == 'Prod' || inputs.environment == 'Prod')
+ run: |
+ if [[ "${{github.event.inputs.runnerType}}" == "macos" ]]; then
+ sed -i "" "s/pastekeyhere/${{ secrets.CODEPUSH_PROD_KEY }}/" android/app/src/main/res/values/strings.xml
+ else
+ sed -i "s/pastekeyhere/${{ secrets.CODEPUSH_PROD_KEY }}/" android/app/src/main/res/values/strings.xml
+ fi
+ 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
@@ -75,10 +91,20 @@ jobs:
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
+ run: |
+ if [[ "${{github.event.inputs.runnerType}}" == "macos" ]]; then
+ sed -i "" 's/def VERSION_CODE = [0-9].*/def VERSION_CODE = '${{ github.event.inputs.version_code }}'/g' android/app/build.gradle
+ else
+ sed -i 's/def VERSION_CODE = [0-9].*/def VERSION_CODE = '${{ github.event.inputs.version_code }}'/g' android/app/build.gradle
+ fi
- 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
+ run: |
+ if [[ "${{github.event.inputs.runnerType}}" == "macos" ]]; then
+ sed -i "" 's/def VERSION_NAME = "[0-9].*"/def VERSION_NAME = "'${{ github.event.inputs.version_name }}'"/g' android/app/build.gradle
+ else
+ sed -i 's/def VERSION_NAME = "[0-9].*"/def VERSION_NAME = "'${{ github.event.inputs.version_name }}'"/g' android/app/build.gradle
+ fi
- name: Log Build Metadata
run: |
echo "Commit SHA: ${{ github.sha }}"
@@ -163,7 +189,7 @@ jobs:
curl --location --request PUT $ack_url \
--header 'X-App-Release-Token: ${{secrets.LONGHORN_HEADER}}'
- name: Upload APK as Artifact
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@v4
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/${{ github.event.inputs.flavor || inputs.flavor }}${{github.event.inputs.environment || inputs.environment}}/${{github.event.inputs.type || inputs.type}}
@@ -171,7 +197,10 @@ jobs:
generate_source_map:
needs: generate
- runs-on: [default]
+ runs-on: ${{ github.event.inputs.runnerType }}
+ 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
@@ -202,7 +231,12 @@ jobs:
- name: Compile Hermes Bytecode and Generate Source Maps
run: |
- node_modules/react-native/sdks/hermesc/linux64-bin/hermesc \
+ if [[ "${{github.event.inputs.runnerType}}" == "macos" ]]; then
+ HERMESC_PATH="node_modules/react-native/sdks/hermesc/osx-bin/hermesc"
+ else
+ HERMESC_PATH="node_modules/react-native/sdks/hermesc/linux64-bin/hermesc"
+ fi
+ $HERMESC_PATH \
-O -emit-binary \
-output-source-map \
-out=index.android.bundle.hbc \
@@ -226,14 +260,48 @@ jobs:
rm -f index.android.bundle.packager.map
- name: Upload Source Map
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@v4
with:
- name: source-map
+ name: source-map-${{github.event.inputs.target_versions}}
path: index.android.bundle.map
+ upload_sourcemap_cybertron:
+ needs: generate_source_map
+ runs-on: ${{ github.event.inputs.runnerType }}
+ if: success() && (github.event.inputs.environment == 'Prod')
+ steps:
+ - name: Download Source Map
+ uses: actions/download-artifact@v4
+ with:
+ name: source-map-${{github.event.inputs.target_versions}}
+ 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]
+ runs-on: ${{ github.event.inputs.runnerType }}
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
diff --git a/App.tsx b/App.tsx
index 1f971252..32ae8c79 100644
--- a/App.tsx
+++ b/App.tsx
@@ -48,6 +48,11 @@ import { setJsErrorHandler } from '@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';
+
+if (!__DEV__) {
+ initSentry();
+}
if (ENV !== 'prod') {
// mockApiServer();
diff --git a/RN-UI-LIB b/RN-UI-LIB
index 019bc50b..348345f1 160000
--- a/RN-UI-LIB
+++ b/RN-UI-LIB
@@ -1 +1 @@
-Subproject commit 019bc50b015b464438047e37c6253cb41af4bf68
+Subproject commit 348345f1bb3af8b78a8246231dbc440ddc02de32
diff --git a/android/app/build.gradle b/android/app/build.gradle
index 5a0e5bf7..05d1c25f 100644
--- a/android/app/build.gradle
+++ b/android/app/build.gradle
@@ -1,9 +1,6 @@
apply plugin: "com.android.application"
-apply plugin: "com.google.gms.google-services"
-apply plugin: "com.google.firebase.crashlytics"
-apply plugin: 'com.google.firebase.firebase-perf'
+apply plugin: "com.facebook.react"
-import com.android.build.OutputFile
import org.apache.tools.ant.taskdefs.condition.Os
/**
@@ -86,19 +83,8 @@ project.ext.react = [
enableNewArchitecture: true
]
-apply from: "../../node_modules/react-native/react.gradle"
apply from: "../../node_modules/react-native-code-push/android/codepush.gradle"
-/**
- * Set this to true to create two separate APKs instead of one:
- * - An APK that only works on ARM devices
- * - An APK that only works on x86 devices
- * The advantage is the size of the APK is reduced by about 4MB.
- * Upload all the APKs to the Play Store and people will download
- * the correct one based on the CPU architecture of their device.
- */
-def enableSeparateBuildPerCPUArchitecture = false
-
/**
* Run Proguard to shrink the Java bytecode in release builds.
*/
@@ -126,18 +112,12 @@ def jscFlavor = 'org.webkit:android-jsc:+'
*/
def enableHermes = project.ext.react.get("enableHermes", false);
-/**
- * Architectures to build native code for.
- */
-def reactNativeArchitectures() {
- def value = project.getProperties().get("reactNativeArchitectures")
- return value ? value.split(",") : ["armeabi-v7a", "x86", "x86_64", "arm64-v8a"]
-}
def VERSION_CODE = 303
def VERSION_NAME = "100.1.2"
android {
+ namespace "com.avapp"
ndkVersion rootProject.ext.ndkVersion
compileSdkVersion rootProject.ext.compileSdkVersion
@@ -148,80 +128,12 @@ android {
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode VERSION_CODE
versionName VERSION_NAME
- buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString()
buildConfigField "string", "FLAVOR", '"'
buildConfigField "string", "BUILD_FLAVOR", '"'
buildConfigField "string", "APP_NAME", '"'
buildConfigField "string", "API_KEY", '"'
-
- if (isNewArchitectureEnabled()) {
- // We configure the CMake build only if you decide to opt-in for the New Architecture.
- externalNativeBuild {
- cmake {
- arguments "-DPROJECT_BUILD_DIR=$buildDir",
- "-DREACT_ANDROID_DIR=$rootDir/../node_modules/react-native/ReactAndroid",
- "-DREACT_ANDROID_BUILD_DIR=$rootDir/../node_modules/react-native/ReactAndroid/build",
- "-DNODE_MODULES_DIR=$rootDir/../node_modules",
- "-DANDROID_STL=c++_shared"
- }
- }
- if (!enableSeparateBuildPerCPUArchitecture) {
- ndk {
- abiFilters (*reactNativeArchitectures())
- }
- }
- }
}
- if (isNewArchitectureEnabled()) {
- // We configure the NDK build only if you decide to opt-in for the New Architecture.
- externalNativeBuild {
- cmake {
- path "$projectDir/src/main/jni/CMakeLists.txt"
- }
- }
- def reactAndroidProjectDir = project(':ReactAndroid').projectDir
- def packageReactNdkDebugLibs = tasks.register("packageReactNdkDebugLibs", Copy) {
- dependsOn(":ReactAndroid:packageReactNdkDebugLibsForBuck")
- from("$reactAndroidProjectDir/src/main/jni/prebuilt/lib")
- into("$buildDir/react-ndk/exported")
- }
- def packageReactNdkReleaseLibs = tasks.register("packageReactNdkReleaseLibs", Copy) {
- dependsOn(":ReactAndroid:packageReactNdkReleaseLibsForBuck")
- from("$reactAndroidProjectDir/src/main/jni/prebuilt/lib")
- into("$buildDir/react-ndk/exported")
- }
- afterEvaluate {
- // If you wish to add a custom TurboModule or component locally,
- // you should uncomment this line.
- // preBuild.dependsOn("generateCodegenArtifactsFromSchema")
- preDebugBuild.dependsOn(packageReactNdkDebugLibs)
- preReleaseBuild.dependsOn(packageReactNdkReleaseLibs)
-
- // Due to a bug inside AGP, we have to explicitly set a dependency
- // between configureCMakeDebug* tasks and the preBuild tasks.
- // This can be removed once this is solved: https://issuetracker.google.com/issues/207403732
- configureCMakeRelWithDebInfo.dependsOn(preReleaseBuild)
- configureCMakeDebug.dependsOn(preDebugBuild)
- reactNativeArchitectures().each { architecture ->
- tasks.findByName("configureCMakeDebug[${architecture}]")?.configure {
- dependsOn("preDebugBuild")
- }
- tasks.findByName("configureCMakeRelWithDebInfo[${architecture}]")?.configure {
- dependsOn("preReleaseBuild")
- }
- }
- }
- }
-
- splits {
- abi {
- reset()
- enable enableSeparateBuildPerCPUArchitecture
- universalApk false // If true, also generate a universal APK
- include (*reactNativeArchitectures())
- }
- }
signingConfigs {
debug {
if (project.hasProperty('MYAPP_UPLOAD_STORE_FILE')) {
@@ -259,21 +171,6 @@ android {
}
}
- // applicationVariants are e.g. debug, release
- applicationVariants.all { variant ->
- variant.outputs.each { output ->
- // For each separate APK per architecture, set a unique version code as described here:
- // https://developer.android.com/studio/build/configure-apk-splits.html
- // Example: versionCode 1 will generate 1001 for armeabi-v7a, 1002 for x86, etc.
- def versionCodes = ["armeabi-v7a": 1, "x86": 2, "arm64-v8a": 3, "x86_64": 4]
- def abi = output.getFilter(OutputFile.ABI)
- if (abi != null) { // null for the universal-debug, universal-release variants
- output.versionCodeOverride =
- defaultConfig.versionCode * 1000 + versionCodes.get(abi)
- }
-
- }
- }
flavorDimensions "env"
productFlavors {
fieldAgentsQA {
@@ -328,48 +225,22 @@ dependencies {
implementation 'androidx.work:work-runtime-ktx:2.8.1'
//noinspection GradleDynamicVersion
- implementation "com.facebook.react:react-native:+" // From node_modules
-
- implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.0.0"
-
- debugImplementation("com.facebook.flipper:flipper:${FLIPPER_VERSION}") {
- exclude group:'com.facebook.fbjni'
- }
-
+ implementation("com.facebook.react:react-android")
+
+ debugImplementation("com.facebook.flipper:flipper:${FLIPPER_VERSION}")
debugImplementation("com.facebook.flipper:flipper-network-plugin:${FLIPPER_VERSION}") {
- exclude group:'com.facebook.flipper'
exclude group:'com.squareup.okhttp3', module:'okhttp'
}
- debugImplementation("com.facebook.flipper:flipper-fresco-plugin:${FLIPPER_VERSION}") {
- exclude group:'com.facebook.flipper'
- }
+ debugImplementation("com.facebook.flipper:flipper-fresco-plugin:${FLIPPER_VERSION}")
if (enableHermes) {
//noinspection GradleDynamicVersion
- implementation("com.facebook.react:hermes-engine:+") { // From node_modules
- exclude group:'com.facebook.fbjni'
- }
+ implementation("com.facebook.react:hermes-android")
} else {
implementation jscFlavor
}
}
-if (isNewArchitectureEnabled()) {
- // If new architecture is enabled, we let you build RN from source
- // Otherwise we fallback to a prebuilt .aar bundled in the NPM package.
- // This will be applied to all the imported transtitive dependency.
- configurations.all {
- resolutionStrategy.dependencySubstitution {
- substitute(module("com.facebook.react:react-native"))
- .using(project(":ReactAndroid"))
- .because("On New Architecture we're building React Native from source")
- substitute(module("com.facebook.react:hermes-engine"))
- .using(project(":ReactAndroid:hermes-engine"))
- .because("On New Architecture we're building Hermes from source")
- }
- }
-}
-
// Run this once to be able to run the application with BUCK
// puts all compile dependencies into folder libs for BUCK to use
task copyDownloadableDepsToLibs(type: Copy) {
@@ -379,13 +250,8 @@ task copyDownloadableDepsToLibs(type: Copy) {
apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesAppBuildGradle(project)
-def isNewArchitectureEnabled() {
- // To opt-in for the New Architecture, you can either:
- // - Set `newArchEnabled` to true inside the `gradle.properties` file
- // - Invoke gradle with `-newArchEnabled=true`
- // - Set an environment variable `ORG_GRADLE_PROJECT_newArchEnabled=true`
- return project.hasProperty("newArchEnabled") && project.newArchEnabled == "true"
-}
apply plugin: 'com.google.gms.google-services'
+apply plugin: "com.google.firebase.crashlytics"
+apply plugin: 'com.google.firebase.firebase-perf'
diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
index 42c13f8d..ec0860ee 100644
--- a/android/app/src/main/AndroidManifest.xml
+++ b/android/app/src/main/AndroidManifest.xml
@@ -27,7 +27,7 @@
-
+
diff --git a/android/app/src/main/java/com/avapp/MainActivity.java b/android/app/src/main/java/com/avapp/MainActivity.java
index 27126eb5..f6bf114e 100644
--- a/android/app/src/main/java/com/avapp/MainActivity.java
+++ b/android/app/src/main/java/com/avapp/MainActivity.java
@@ -62,12 +62,12 @@ public class MainActivity extends ReactActivity implements AlfredFirebaseHelper
return reactRootView;
}
- @Override
- protected boolean isConcurrentRootEnabled() {
- // If you opted-in for the New Architecture, we enable Concurrent Root (i.e. React 18).
- // More on this on https://reactjs.org/blog/2022/03/29/react-v18.html
- return BuildConfig.IS_NEW_ARCHITECTURE_ENABLED;
- }
+ // @Override
+ // protected boolean isConcurrentRootEnabled() {
+ // // If you opted-in for the New Architecture, we enable Concurrent Root (i.e. React 18).
+ // // More on this on https://reactjs.org/blog/2022/03/29/react-v18.html
+ // return BuildConfig.IS_NEW_ARCHITECTURE_ENABLED;
+ // }
}
@Override
diff --git a/android/app/src/main/java/com/avapp/appInstallerModule/ApkInstallerModule.java b/android/app/src/main/java/com/avapp/appInstallerModule/ApkInstallerModule.java
index ca66c9fd..efd354ed 100644
--- a/android/app/src/main/java/com/avapp/appInstallerModule/ApkInstallerModule.java
+++ b/android/app/src/main/java/com/avapp/appInstallerModule/ApkInstallerModule.java
@@ -13,7 +13,15 @@ import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.Callback;
+
import java.io.File;
+import java.io.FileInputStream;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.Signature;
+import android.util.Base64;
public class ApkInstallerModule extends ReactContextBaseJavaModule {
@@ -32,7 +40,6 @@ public class ApkInstallerModule extends ReactContextBaseJavaModule {
private void promptForInstall(Uri apkUri) {
try {
Intent intent = new Intent(Intent.ACTION_VIEW);
- Log.d("ApkInstaller", "uri: "+ apkUri);
intent.setDataAndType(apkUri, "application/vnd.android.package-archive");
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
@@ -45,20 +52,37 @@ public class ApkInstallerModule extends ReactContextBaseJavaModule {
}
}
+ private boolean isValidApkFile(File apkFile) {
+ if (!apkFile.exists() || apkFile.length() == 0) {
+ return false;
+ }
+
+ // Optional: Check if it's a valid ZIP/APK file
+ try (ZipInputStream zipInputStream = new ZipInputStream(new FileInputStream(apkFile))) {
+ ZipEntry zipEntry = zipInputStream.getNextEntry();
+ return zipEntry != null;
+ } catch (Exception e) {
+ Log.e("ApkInstaller", "Invalid APK file", e);
+ return false;
+ }
+ }
+
@ReactMethod
public void installApk(String filePath, Callback callback) {
try {
File apkFile = new File(filePath);
- Uri apkUri;
+ if (!isValidApkFile(apkFile)) {
+ callback.invoke("Invalid or corrupted apk file", null);
+ return;
+ }
+ Uri apkUri;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
- apkUri = FileProvider.getUriForFile(reactContext, BuildConfig.APPLICATION_ID + ".provider",
- apkFile);
+ apkUri = FileProvider.getUriForFile(reactContext, BuildConfig.APPLICATION_ID + ".provider", apkFile);
} else {
apkUri = Uri.fromFile(apkFile);
}
promptForInstall(apkUri);
- Log.d("ApkInstaller", "App installed");
callback.invoke(null, "Success");
} catch (Exception e) {
Log.e("ApkInstaller", "Error installing APK", e);
diff --git a/android/app/src/main/java/com/avapp/photoModule/PhotoModule.java b/android/app/src/main/java/com/avapp/photoModule/PhotoModule.java
index df27419f..ea301ee0 100644
--- a/android/app/src/main/java/com/avapp/photoModule/PhotoModule.java
+++ b/android/app/src/main/java/com/avapp/photoModule/PhotoModule.java
@@ -78,6 +78,13 @@ public class PhotoModule extends ReactContextBaseJavaModule {
}
private void handleError(PhotoModuleError errorCode, Promise promise, @Nullable String additionalMessage) {
+ if(promise == null) {
+ return;
+ }
+ if (errorCode == null) {
+ promise.reject("UNKNOWN_ERROR", "An unknown error occurred");
+ return;
+ }
promise.reject(String.valueOf(errorCode.getCode()),
errorCode.getMessage() + (additionalMessage != null ? ": " + additionalMessage : ""));
}
diff --git a/android/build.gradle b/android/build.gradle
index 002ed0c5..8b1db5fa 100644
--- a/android/build.gradle
+++ b/android/build.gradle
@@ -23,7 +23,7 @@ buildscript {
mavenCentral()
}
dependencies {
- classpath("com.android.tools.build:gradle:7.2.1")
+ classpath("com.android.tools.build:gradle")
classpath("com.facebook.react:react-native-gradle-plugin")
classpath("de.undercouch:gradle-download-task:5.0.1")
// NOTE: Do not place your application dependencies here; they belong
diff --git a/android/gradle.properties b/android/gradle.properties
index f2ce2c37..ed80567b 100644
--- a/android/gradle.properties
+++ b/android/gradle.properties
@@ -25,7 +25,7 @@ android.useAndroidX=true
android.enableJetifier=true
# Version of flipper SDK to use with React Native
-FLIPPER_VERSION=0.125.0
+FLIPPER_VERSION=0.182.0
VERSION_NAME=1.2.3
# Use this property to specify which architecture you want to build.
diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties
index 8fad3f5a..6ec1567a 100644
--- a/android/gradle/wrapper/gradle-wrapper.properties
+++ b/android/gradle/wrapper/gradle-wrapper.properties
@@ -1,5 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.0.1-all.zip
+networkTimeout=10000
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/android/gradlew b/android/gradlew
index 1b6c7873..12c55612 100755
--- a/android/gradlew
+++ b/android/gradlew
@@ -55,7 +55,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
-# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
@@ -84,6 +84,7 @@ APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
APP_NAME="Gradle"
APP_BASE_NAME=${0##*/}
+APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
@@ -205,6 +206,12 @@ set -- \
org.gradle.wrapper.GradleWrapperMain \
"$@"
+# Stop when "xargs" is not available.
+if ! command -v xargs >/dev/null 2>&1
+then
+ die "xargs is not available"
+fi
+
# Use "xargs" to parse quoted args.
#
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
diff --git a/android/settings.gradle b/android/settings.gradle
index d24ff2c4..016efc69 100644
--- a/android/settings.gradle
+++ b/android/settings.gradle
@@ -2,7 +2,7 @@ rootProject.name = 'AVAPP'
apply from: file("../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesSettingsGradle(settings)
include ':app', ':react-native-code-push'
include ':react-native-version-number'
-includeBuild('../node_modules/react-native-gradle-plugin')
+includeBuild('../node_modules/@react-native/gradle-plugin')
if (settings.hasProperty("newArchEnabled") && settings.newArchEnabled == "true") {
include(":ReactAndroid")
@@ -10,6 +10,16 @@ if (settings.hasProperty("newArchEnabled") && settings.newArchEnabled == "true")
include(":ReactAndroid:hermes-engine")
project(":ReactAndroid:hermes-engine").projectDir = file('../node_modules/react-native/ReactAndroid/hermes-engine')
}
+
+includeBuild('../node_modules/react-native') {
+ dependencySubstitution {
+ substitute(module("com.facebook.react:react-android")).using(project(":packages:react-native:ReactAndroid"))
+ substitute(module("com.facebook.react:react-native")).using(project(":packages:react-native:ReactAndroid"))
+ // substitute(module("com.facebook.react:hermes-android")).using(project(":packages:react-native:ReactAndroid:hermes-engine"))
+ // substitute(module("com.facebook.react:hermes-engine")).using(project(":packages:react-native:ReactAndroid:hermes-engine"))
+ }
+}
+
project(':react-native-code-push').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-code-push/android/app')
project(':react-native-version-number').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-version-number/android')
\ No newline at end of file
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..f11fe362 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/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 0c71639a..e195646f 100644
--- a/config/qa/config.js
+++ b/config/qa/config.js
@@ -1,7 +1,8 @@
-import { MILLISECONDS_IN_A_MINUTE, MINUTES_IN_AN_HOUR } from '@rn-ui-lib/utils/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';
+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-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;
@@ -11,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..cc7ae373 100644
--- a/metro.config.js
+++ b/metro.config.js
@@ -1,3 +1,6 @@
+const { getDefaultConfig, mergeConfig } = require('@react-native/metro-config');
+const { withSentryConfig } = require('@sentry/react-native/metro');
+
/**
* Metro configuration for React Native
* https://github.com/facebook/react-native
@@ -5,7 +8,7 @@
* @format
*/
-module.exports = {
+const config = withSentryConfig({
transformer: {
getTransformOptions: async () => ({
transform: {
@@ -14,4 +17,6 @@ module.exports = {
},
}),
},
-};
+});
+
+module.exports = mergeConfig(getDefaultConfig(__dirname), config);
diff --git a/package.json b/package.json
index debd05af..7659d333 100644
--- a/package.json
+++ b/package.json
@@ -40,24 +40,25 @@
"@bam.tech/react-native-image-resizer": "3.0.5",
"@notifee/react-native": "7.8.2",
"@nozbe/with-observables": "1.4.1",
+ "@react-native/metro-config": "0.72.11",
"@react-native-async-storage/async-storage": "1.17.11",
"@react-native-clipboard/clipboard": "^1.11.2",
"@react-native-community/netinfo": "9.3.7",
- "@react-native-firebase/analytics": "16.4.6",
- "@react-native-firebase/app": "16.4.6",
- "@react-native-firebase/auth": "16.5.0",
- "@react-native-firebase/crashlytics": "16.5.0",
- "@react-native-firebase/database": "16.4.6",
- "@react-native-firebase/firestore": "16.5.0",
- "@react-native-firebase/messaging": "17.4.0",
- "@react-native-firebase/perf": "16.5.2",
- "@react-native-firebase/remote-config": "16.4.6",
- "@react-native-google-signin/google-signin": "9.0.2",
- "@react-navigation/bottom-tabs": "6.5.5",
- "@react-navigation/native": "6.1.4",
- "@react-navigation/native-stack": "6.9.4",
+ "@react-native-firebase/analytics": "16.7.0",
+ "@react-native-firebase/app": "16.7.0",
+ "@react-native-firebase/auth": "16.7.0",
+ "@react-native-firebase/crashlytics": "16.7.0",
+ "@react-native-firebase/database": "16.7.0",
+ "@react-native-firebase/firestore": "16.7.0",
+ "@react-native-firebase/messaging": "16.7.0",
+ "@react-native-firebase/perf": "16.7.0",
+ "@react-native-firebase/remote-config": "16.7.0",
+ "@react-native-google-signin/google-signin": "13.1.0",
+ "@react-navigation/bottom-tabs": "6.6.1",
+ "@react-navigation/native": "6.1.18",
+ "@react-navigation/native-stack": "6.11.0",
"@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",
@@ -69,15 +70,15 @@
"dayjs": "1.11.9",
"fuzzysort": "2.0.4",
"lodash.chunk": "^4.2.0",
- "lottie-react-native": "5.1.4",
+ "lottie-react-native": "6.4.0",
"patch-package": "8.0.0",
"postinstall-postinstall": "2.1.0",
- "react": "18.1.0",
+ "react": "18.2.0",
"react-hook-form": "7.40.0",
- "react-native": "0.70.6",
+ "react-native": "0.72.6",
"react-native-blob-util": "0.17.3",
"react-native-call-log": "2.1.2",
- "react-native-code-push": "7.1.0",
+ "react-native-code-push": "8.3.1",
"react-native-contacts": "7.0.5",
"react-native-device-info": "10.3.0",
"react-native-fast-image": "8.6.3",
@@ -86,7 +87,7 @@
"react-native-get-sms-android": "2.1.0",
"react-native-gzip": "1.0.0",
"react-native-image-picker": "4.10.2",
- "react-native-mmkv": "2.5.1",
+ "react-native-mmkv": "2.11.0",
"react-native-pager-view": "6.1.2",
"react-native-pdf-renderer": "1.1.1",
"react-native-permissions": "3.6.1",
@@ -103,7 +104,7 @@
"redux-persist": "6.0.0"
},
"devDependencies": {
- "@babel/core": "7.12.9",
+ "@babel/core": "7.25.2",
"@babel/plugin-proposal-decorators": "7.20.7",
"@babel/runtime": "7.12.5",
"@tsconfig/react-native": "2.0.2",
@@ -111,7 +112,7 @@
"@types/d3-shape": "^3.1.3",
"@types/jest": "26.0.23",
"@types/react": "18.0.21",
- "@types/react-native": "0.70.6",
+ "@types/react-native": "0.71.13",
"@types/react-native-fetch-blob": "0.10.7",
"@types/react-native-video": "5.0.14",
"@types/react-native-video-player": "0.10.3",
@@ -139,7 +140,7 @@
"husky": "8.0.0",
"jest": "26.6.3",
"lint-staged": "13.2.1",
- "metro-react-native-babel-preset": "0.72.3",
+ "metro-react-native-babel-preset": "0.76.8",
"miragejs": "0.1.47",
"prettier": "^2.8.7",
"react-test-renderer": "18.1.0",
diff --git a/patches/react-native+0.70.6.patch b/patches/react-native+0.72.6.patch
similarity index 100%
rename from patches/react-native+0.70.6.patch
rename to patches/react-native+0.72.6.patch
diff --git a/react-native.config.js b/react-native.config.js
new file mode 100644
index 00000000..535123b8
--- /dev/null
+++ b/react-native.config.js
@@ -0,0 +1,8 @@
+module.exports = {
+ project: {
+ ios: {},
+ android: {
+ unstable_reactLegacyComponentNames: ['FastImageView', 'FlashList'],
+ },
+ },
+};
diff --git a/src/action/addressGeolocationAction.ts b/src/action/addressGeolocationAction.ts
index cd63bb1c..b8f3b028 100644
--- a/src/action/addressGeolocationAction.ts
+++ b/src/action/addressGeolocationAction.ts
@@ -7,7 +7,6 @@ import axiosInstance, { ApiKeys, API_STATUS_CODE, getApiUrl } from '../component
import { AppDispatch } from '../store/store';
import { logError } from '../components/utlis/errorUtils';
import { IAddAddressPayload, IAddressGeolocationPayload } from '../types/addressGeolocation.types';
-import { UnifiedCaseDetailsTypes } from './caseApiActions';
import { addClickstreamEvent } from '@services/clickstreamEventService';
import { CLICKSTREAM_EVENT_NAMES } from '@common/Constants';
import {
@@ -63,37 +62,35 @@ export const addAddress =
});
};
-export const getUngroupedAddress = (loanAccountNumber: string) => (dispatch: AppDispatch) => {
- const queryParams = {
- [UnifiedCaseDetailsTypes.UNGROUPED_ADDRESSES]: true,
- [UnifiedCaseDetailsTypes.INCLUDE_ADDRESS_FEEDBACK]: true,
+export const getUngroupedAddress =
+ (loanAccountNumber: string, includeFeedbacks = false) =>
+ (dispatch: AppDispatch) => {
+ dispatch(setUngroupedAddressesLoading({ loanAccountNumber, isLoading: true }));
+ const url = getApiUrl(
+ ApiKeys.GET_UNGROUPED_ADDRESSES,
+ { loanAccountNumber },
+ { includeFeedbacks }
+ );
+ axiosInstance
+ .get(url)
+ .then((response) => {
+ if (response.status === API_STATUS_CODE.OK) {
+ const data = {
+ loanAccountNumber,
+ ungroupedAddresses: response.data?.ungroupedAddresses,
+ ungroupedAddressFeedbacks: response.data?.addressFeedbacks || [],
+ };
+ if (!includeFeedbacks) {
+ delete response.data?.addressFeedbacks;
+ }
+ dispatch(setUngroupedAddresses(data));
+ }
+ })
+ .catch((err) => {
+ logError(err);
+ dispatch(setUngroupedAddressesLoading({ loanAccountNumber, isLoading: false }));
+ });
};
- addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_UNIFIED_ENTITY_REQUESTED, {
- lan: loanAccountNumber || '',
- requestedEntities: JSON.stringify([
- UnifiedCaseDetailsTypes.UNGROUPED_ADDRESSES,
- UnifiedCaseDetailsTypes.INCLUDE_ADDRESS_FEEDBACK,
- ]),
- });
- dispatch(setUngroupedAddressesLoading({ loanAccountNumber, isLoading: true }));
- const url = getApiUrl(ApiKeys.CASE_UNIFIED_DETAILS_V4, { loanAccountNumber }, queryParams);
- axiosInstance
- .get(url)
- .then((response) => {
- if (response.status === API_STATUS_CODE.OK) {
- const ungroupedAddressesWithFeedbacks = {
- ungroupedAddresses: response?.data?.ungroupedAddresses || [],
- ungroupedAddressFeedbacks: response?.data?.addressFeedbacks || [],
- loanAccountNumber,
- };
- dispatch(setUngroupedAddresses(ungroupedAddressesWithFeedbacks));
- }
- })
- .catch((err) => {
- logError(err);
- dispatch(setUngroupedAddressesLoading({ loanAccountNumber, isLoading: false }));
- });
-};
export const getSimilarGeolocationTimestamps = (clusterId: string) => {
const url = getApiUrl(ApiKeys.SIMILAR_GEOLOCATION_TIMESTAMPS, { clusterId });
diff --git a/src/action/caseApiActions.ts b/src/action/caseApiActions.ts
index bbf95484..b622a906 100644
--- a/src/action/caseApiActions.ts
+++ b/src/action/caseApiActions.ts
@@ -1,162 +1,108 @@
-import { type AxiosResponse } from 'axios';
import axiosInstance, { ApiKeys, getApiUrl } from '../components/utlis/apiHelper';
import { type AppDispatch } from '../store/store';
-import { type IGroupedGeolocationAddressItem } from '../types/addressGeolocation.types';
import { setEmiSchedule, setEmiScheduleLoading } from '../reducer/emiScheduleSlice';
import { setFeedbackHistory, setFeedbackHistoryLoading } from '../reducer/feedbackHistorySlice';
import { setRepayments, setRepaymentsLoading } from '../reducer/repaymentsSlice';
-import { IAddressFeedback, setAddresses, setAddressLoading } from '../reducer/addressSlice';
-import { type IFeedback } from '../types/feedback.types';
-import { allSettled } from '../components/utlis/commonFunctions';
-import { type GenericType } from '../common/GenericTypes';
-import { addClickstreamEvent } from '../services/clickstreamEventService';
-import { CLICKSTREAM_EVENT_NAMES } from '../common/Constants';
+import { setAddresses, setAddressLoading } from '../reducer/addressSlice';
import { MILLISECONDS_IN_A_MINUTE, _map } from '../../RN-UI-LIB/src/utlis/common';
import { logError } from '../components/utlis/errorUtils';
import { type IDocument, removeDocumentByQuestionKey } from '../reducer/feedbackImagesSlice';
-import { CaseDetailStackEnum } from '@screens/caseDetails/CaseDetailStack';
-// TODO: Need to add respective interfaces instead of any
-interface IUnifiedData {
- groupedAddressesAndGeoLocations?: IGroupedGeolocationAddressItem;
- feedbacks: any[];
- emiSchedule: any[];
- repayments: any[];
- addressFeedbacks?: IAddressFeedback[];
-}
-
-export interface IUploadImagePayload {
- interactionId: string;
- questionKey: string;
- originalImageDocumentReferenceId: string;
-}
-
-export enum UnifiedCaseDetailsTypes {
- ADDRESS_AND_GEOLOCATIONS = 'includeGroupedAddressesAndGeoLocations',
- FEEDBACKS = 'includeFeedbacks',
- EMI_SCHEDULE = 'includeEmiSchedule',
- REPAYMENTS = 'includeRepayments',
- INCLUDE_ADDRESS_FEEDBACK = 'includeAddressFeedback',
- UNGROUPED_ADDRESSES = 'includeUngroupedAddresses',
-}
-
-export const initialUrlParams = {
- [UnifiedCaseDetailsTypes.ADDRESS_AND_GEOLOCATIONS]: false,
- [UnifiedCaseDetailsTypes.FEEDBACKS]: false,
- [UnifiedCaseDetailsTypes.EMI_SCHEDULE]: false,
- [UnifiedCaseDetailsTypes.REPAYMENTS]: false,
- [UnifiedCaseDetailsTypes.INCLUDE_ADDRESS_FEEDBACK]: false,
- [UnifiedCaseDetailsTypes.UNGROUPED_ADDRESSES]: false,
+export const getRepaymentsData = (loanAccountNumber: string) => (dispatch: AppDispatch) => {
+ dispatch(setRepaymentsLoading({ loanAccountNumber, isLoading: true }));
+ const url = getApiUrl(ApiKeys.GET_REPAYMENTS, { loanAccountNumber });
+ axiosInstance
+ .get(url)
+ .then((res) => {
+ dispatch(setRepayments({ loanAccountNumber, repayments: res.data }));
+ })
+ .catch((err) => {
+ logError(err as Error, 'Error fetching repayments data');
+ })
+ .finally(() => {
+ dispatch(setRepaymentsLoading({ loanAccountNumber, isLoading: false }));
+ });
};
-const setUnifiedDataLoading =
- (queryParams: Record, loanAccountNumbers: string[], isLoading: boolean) =>
- (dispatch: AppDispatch) => {
- if (queryParams[UnifiedCaseDetailsTypes.EMI_SCHEDULE]) {
- dispatch(setEmiScheduleLoading({ loanAccountNumbers, isLoading: isLoading }));
- }
- if (queryParams[UnifiedCaseDetailsTypes.FEEDBACKS]) {
- dispatch(setFeedbackHistoryLoading({ loanAccountNumbers, isLoading: isLoading }));
- }
- if (queryParams[UnifiedCaseDetailsTypes.REPAYMENTS]) {
- dispatch(setRepaymentsLoading({ loanAccountNumbers, isLoading: isLoading }));
- }
- if (queryParams[UnifiedCaseDetailsTypes.ADDRESS_AND_GEOLOCATIONS]) {
- dispatch(setAddressLoading({ loanAccountNumbers, isLoading: isLoading }));
- }
- };
+export const getEmiScheduleData = (loanAccountNumber: string) => (dispatch: AppDispatch) => {
+ dispatch(setEmiScheduleLoading({ loanAccountNumber, isLoading: true }));
+ const url = getApiUrl(ApiKeys.GET_EMI_SCHEDULE, { loanAccountNumber });
+ axiosInstance
+ .get(url)
+ .then((res) => {
+ dispatch(setEmiSchedule({ loanAccountNumber, emiSchedule: res.data }));
+ })
+ .catch((err) => {
+ logError(err as Error, 'Error fetching emi schedule data');
+ })
+ .finally(() => {
+ dispatch(setEmiScheduleLoading({ loanAccountNumber, isLoading: false }));
+ });
+};
-const setUnifiedData =
- (
- queryParams: Record,
- loanAccountNumbers: string[],
- unifiedPromiseData: Array>>
- ) =>
+export const getAddressesAndGeolocations =
+ (loanAccountNumber: string, includeFeedbacks: boolean = false) =>
(dispatch: AppDispatch) => {
- unifiedPromiseData.forEach((promiseResult, index) => {
- const { status } = promiseResult;
- if (status === 'fulfilled' && promiseResult.value) {
- const {
+ dispatch(setAddressLoading({ loanAccountNumber, isLoading: true }));
+ const url = getApiUrl(
+ ApiKeys.GET_GROUPED_ADDRESSES_AND_GEOLOCATIONS,
+ { loanAccountNumber },
+ { includeFeedbacks }
+ );
+ axiosInstance
+ .get(url)
+ .then((res) => {
+ const { groupedAddressesAndGeoLocations, addressFeedbacks } = res.data;
+ const data = {
+ loanAccountNumber,
groupedAddressesAndGeoLocations,
- feedbacks,
- emiSchedule,
- repayments,
- addressFeedbacks,
- } = promiseResult.value.data;
- const loanAccountNumber = loanAccountNumbers[index];
- if (queryParams[UnifiedCaseDetailsTypes.EMI_SCHEDULE]) {
- dispatch(setEmiSchedule({ loanAccountNumber, emiSchedule }));
+ addressFeedbacks: addressFeedbacks || [],
+ };
+ if (!includeFeedbacks) {
+ delete data.addressFeedbacks;
}
- if (queryParams[UnifiedCaseDetailsTypes.FEEDBACKS]) {
- // todo: data is coming as feedback.data
- dispatch(
- setFeedbackHistory({
- loanAccountNumber,
- feedbacks: feedbacks?.data as IFeedback[],
- totalPages: feedbacks?.pages?.totalPages as number,
- })
- );
- }
- if (queryParams[UnifiedCaseDetailsTypes.REPAYMENTS]) {
- dispatch(setRepayments({ loanAccountNumber, repayments }));
- }
- if (queryParams[UnifiedCaseDetailsTypes.ADDRESS_AND_GEOLOCATIONS]) {
- dispatch(setAddresses({ loanAccountNumber, groupedAddressesAndGeoLocations }));
- }
- if (queryParams[UnifiedCaseDetailsTypes.INCLUDE_ADDRESS_FEEDBACK]) {
- dispatch(
- setAddresses({ loanAccountNumber, addressFeedbacks, groupedAddressesAndGeoLocations })
- );
- }
- }
- });
- };
-
-export const getCaseUnifiedData =
- (loanAccountNumbers: string[], infoToGet: UnifiedCaseDetailsTypes[]) =>
- (dispatch: AppDispatch) => {
- const queryParams = { ...initialUrlParams };
- for (const key of infoToGet) {
- queryParams[key] = true;
- }
- addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_UNIFIED_ENTITY_REQUESTED, {
- lans: JSON.stringify(loanAccountNumbers || []),
- requestedEntities: JSON.stringify(infoToGet || []),
- });
- dispatch(setUnifiedDataLoading(queryParams, loanAccountNumbers, true));
- const promisesList: Array>> = [];
- loanAccountNumbers.forEach((loanAccountNumber) => {
- const url = getApiUrl(ApiKeys.CASE_UNIFIED_DETAILS_V4, { loanAccountNumber }, queryParams);
- const promise = axiosInstance.get(url, {
- headers: {
- showInSpecificComponents: [
- CaseDetailStackEnum.COLLECTION_CASE_DETAIL,
- CaseDetailStackEnum.EMI_SCHEDULE,
- CaseDetailStackEnum.ADDRESS_GEO,
- ],
- },
- });
- promisesList.push(promise);
- });
- allSettled?.(promisesList)
- .then((res: GenericType) => {
- addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_UNIFIED_ENTITY_REQUEST_SUCCESS, {
- lans: JSON.stringify(loanAccountNumbers || []),
- requestedEntities: JSON.stringify(infoToGet || []),
- });
- dispatch(setUnifiedData(queryParams, loanAccountNumbers, res));
+ dispatch(setAddresses(data));
})
- .catch((e) => {
- addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_UNIFIED_ENTITY_REQUEST_FAILED, {
- lans: JSON.stringify(loanAccountNumbers || []),
- requestedEntities: JSON.stringify(infoToGet || []),
- });
+ .catch((err) => {
+ logError(err as Error, 'Error fetching addresses and geolocations data');
})
.finally(() => {
- dispatch(setUnifiedDataLoading(queryParams, loanAccountNumbers, false));
+ dispatch(setAddressLoading({ loanAccountNumber, isLoading: false }));
});
};
+export const getFeedbackHistory = (loanAccountNumber: string) => (dispatch: AppDispatch) => {
+ dispatch(setFeedbackHistoryLoading({ loanAccountNumber, isLoading: true }));
+ const url = getApiUrl(
+ ApiKeys.GET_FEEDBACK_HISTORY,
+ {},
+ {
+ loan_account_number: loanAccountNumber,
+ page_no: 0,
+ page_size: 5,
+ }
+ );
+ axiosInstance
+ .post(url, {
+ filters: [],
+ })
+ .then((res) => {
+ dispatch(
+ setFeedbackHistory({
+ loanAccountNumber,
+ feedbacks: res.data?.data || [],
+ totalPages: res.data?.pages?.totalPages || 0,
+ })
+ );
+ })
+ .catch((err) => {
+ logError(err as Error, 'Error fetching feedback history data');
+ })
+ .finally(() => {
+ dispatch(setFeedbackHistoryLoading({ loanAccountNumber, isLoading: false }));
+ });
+};
+
export const uploadImages =
(caseKey: string, documents: Record, interactionReferenceId: string) =>
(dispatch: AppDispatch) => {
diff --git a/src/action/dataActions.ts b/src/action/dataActions.ts
index 55bbca61..ad044591 100644
--- a/src/action/dataActions.ts
+++ b/src/action/dataActions.ts
@@ -16,7 +16,7 @@ import {
import { CaseAllocationType, ICaseItem, IPinnedCasesPayload } from '../screens/allCases/interface';
import { AppDispatch } from '../store/store';
import { addClickstreamEvent } from '../services/clickstreamEventService';
-import { CLICKSTREAM_EVENT_NAMES, LocalStorageKeys } from '../common/Constants';
+import { CLICKSTREAM_EVENT_NAMES } from '../common/Constants';
import { logError } from '../components/utlis/errorUtils';
import { setFilters } from '../reducer/filtersSlice';
import { toast } from '../../RN-UI-LIB/src/components/toast';
@@ -24,7 +24,6 @@ import { ToastMessages } from '../screens/allCases/constants';
import { GenericFunctionArgs } from '../common/GenericTypes';
import { GLOBAL } from '../constants/Global';
import { MY_CASE_ITEM } from '../reducer/userSlice';
-import { getAsyncStorageItem } from '@components/utlis/commonFunctions';
let _signedApiCallBucket: { req: any; added_At: number; callback: GenericFunctionArgs }[] = [];
let _signedApiCallBucketTimer: number = 0;
@@ -44,12 +43,7 @@ export const postPinnedList =
});
return acc;
}, [] as IPinnedCasesPayload[]);
- const enableCaseCollectionManager =
- (await getAsyncStorageItem(LocalStorageKeys.COSMOS_CASE_COLLECTION_MANAGER_ENABLE, true)) ??
- false;
- const url = getApiUrl(
- enableCaseCollectionManager ? ApiKeys.PINNED_CASES_V2 : ApiKeys.PINNED_CASES
- );
+ const url = getApiUrl(ApiKeys.PINNED_CASES_V2);
axiosInstance
.post(url, payload)
.then((response) => {
@@ -146,6 +140,7 @@ interface ISignedRequestItem {
caseId: string;
unSignedUri?: string;
skipFirebaseUpdate?: boolean;
+ retryForDocumentsItem?: string;
}
export type ISignedRequest = ISignedRequestItem[];
@@ -207,29 +202,17 @@ async function makeBulkSignedApiRequest(
callback: GenericFunctionArgs | GenericFunctionArgs[],
skipFirebaseUpdate = false
) {
- const enableCaseCollectionManager =
- (await getAsyncStorageItem(LocalStorageKeys.COSMOS_CASE_COLLECTION_MANAGER_ENABLE, true)) ??
- false;
- let url = getApiUrl(
- enableCaseCollectionManager ? ApiKeys.GET_SIGNED_URL_V2 : ApiKeys.GET_SIGNED_URL,
- {},
- { skipFirebaseUpdate }
- );
+ let url = getApiUrl(ApiKeys.GET_SIGNED_URL_V2, {}, { skipFirebaseUpdate });
const reporteeReferenceId = GLOBAL?.SELECTED_AGENT_ID;
if (reporteeReferenceId && reporteeReferenceId !== MY_CASE_ITEM.referenceId) {
- url = getApiUrl(
- enableCaseCollectionManager
- ? ApiKeys.GET_SIGNED_URL_FOR_REPORTEE_V2
- : ApiKeys.GET_SIGNED_URL_FOR_REPORTEE,
- {},
- { reporteeReferenceId }
- );
+ url = getApiUrl(ApiKeys.GET_SIGNED_URL_FOR_REPORTEE_V2, {}, { reporteeReferenceId });
}
_signedApiCallBucket = [];
await axiosInstance
.post(url, payload, {
headers: {
donotHandleError: true,
+ 'X-Doc-Type': payload?.[0]?.retryForDocumentsItem || '',
},
})
.then((response) => {
diff --git a/src/action/feedbackActions.ts b/src/action/feedbackActions.ts
index 00f89844..5d486026 100644
--- a/src/action/feedbackActions.ts
+++ b/src/action/feedbackActions.ts
@@ -1,5 +1,7 @@
+import { AppDispatch } from '@store';
import axiosInstance, { ApiKeys, getApiUrl } from '../components/utlis/apiHelper';
import { logError } from '../components/utlis/errorUtils';
+import { setTopFeedbacks, setTopFeedbacksLoading } from '@reducers/topFeedbacksSlice';
interface IPastFeedbacksPayload {
loan_account_number: string;
@@ -7,6 +9,7 @@ interface IPastFeedbacksPayload {
page_size: number;
customerRecahble: boolean;
addressReferenceIds?: string; // required to fetch past feedback on addresses
+ isGeolocationFeedback: boolean;
}
export interface IFilterPayload {
@@ -56,6 +59,9 @@ export const getPastFeedbacksOnAddresses = (pastFeedbackPayload: IPastFeedbacksP
return axiosInstance
.get(url, {
params: payload,
+ headers: {
+ 'X-Feedback-Source': pastFeedbackPayload.isGeolocationFeedback ? 'GEO_LOCATION' : 'ADDRESS',
+ },
})
.then((response) => {
if (response?.data) {
@@ -70,3 +76,28 @@ export const getPastFeedbacksOnAddresses = (pastFeedbackPayload: IPastFeedbacksP
logError(err);
});
};
+
+export const getTopFeedbacks = (loanAccountNumber: string) => (dispatch: AppDispatch) => {
+ // TODO: Change API Endpoint
+ const url = getApiUrl(ApiKeys.PAST_FEEDBACK_ON_ADDRESSES);
+ dispatch(setTopFeedbacksLoading({ loanAccountNumber, isLoading: true }));
+ return axiosInstance
+ .get(url, {
+ params: { loanAccountNumber },
+ })
+ .then((response) => {
+ dispatch(
+ setTopFeedbacks({
+ loanAccountNumber,
+ feedbacks: [
+ response?.data?.data?.currentMonthFeedbackStatus,
+ response?.data?.data?.lastMonthFeedbackStatus,
+ ],
+ })
+ );
+ })
+ .catch((err) => {
+ dispatch(setTopFeedbacksLoading({ loanAccountNumber, isLoading: false }));
+ logError(err);
+ });
+};
diff --git a/src/assets/icons/NotAttemptedIcon.tsx b/src/assets/icons/NotAttemptedIcon.tsx
new file mode 100644
index 00000000..8d1f5ab4
--- /dev/null
+++ b/src/assets/icons/NotAttemptedIcon.tsx
@@ -0,0 +1,19 @@
+import * as React from 'react';
+import Svg, { Path } from 'react-native-svg';
+
+function NotAttemptedIcon() {
+ return (
+
+ );
+}
+
+export default NotAttemptedIcon;
diff --git a/src/assets/icons/RightChevronIcon.tsx b/src/assets/icons/RightChevronIcon.tsx
new file mode 100644
index 00000000..69e11441
--- /dev/null
+++ b/src/assets/icons/RightChevronIcon.tsx
@@ -0,0 +1,20 @@
+import React from 'react';
+import { G, Mask, Path, Rect, Svg } from 'react-native-svg';
+
+const RightChevronIcon = () => {
+ return (
+
+ );
+};
+
+export default RightChevronIcon;
diff --git a/src/assets/icons/SmsIcon.tsx b/src/assets/icons/SmsIcon.tsx
index 9cf1f046..23591e2b 100644
--- a/src/assets/icons/SmsIcon.tsx
+++ b/src/assets/icons/SmsIcon.tsx
@@ -3,13 +3,13 @@ import Svg, { Mask, Path, G, Rect } from 'react-native-svg';
function SmsIcon() {
return (
-