diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100755 index 00000000..5a182ef1 --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1,4 @@ +#!/usr/bin/env sh +. "$(dirname -- "$0")/_/husky.sh" + +yarn lint-staged diff --git a/.husky/pre-push b/.husky/pre-push new file mode 100755 index 00000000..60da157b --- /dev/null +++ b/.husky/pre-push @@ -0,0 +1,4 @@ +#!/usr/bin/env sh +. "$(dirname -- "$0")/_/husky.sh" + +yarn prettier:write \ No newline at end of file diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 00000000..b10ec5c7 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,24 @@ +# dependencies +/android +/ios +/node_modules +/RN-UI-LIB +/__tests__ + +# testing +/coverage + +# production + +# misc +.DS_Store + +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +#IDE +.idea/ + +# ESLint cache +.eslintcache \ No newline at end of file diff --git a/README.md b/README.md index 08b63e35..f80d273a 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,17 @@ -# Address-Verification-App +# Cosmos Application +### Project Commands + +Check Prettier + +``` +yarn prettier:check +``` + +Fix Prettier code formatting + +``` +yarn prettier:write +``` + +  diff --git a/app.json b/app.json index af831aba..bb29b9c5 100644 --- a/app.json +++ b/app.json @@ -1,4 +1,4 @@ { - "name": "AVAPP", - "displayName": "Address Verification" + "name": "AVAPP", + "displayName": "Address Verification" } diff --git a/babel.config.js b/babel.config.js index d241d1ce..5bff64bf 100644 --- a/babel.config.js +++ b/babel.config.js @@ -1,22 +1,22 @@ module.exports = { - presets: ['module:metro-react-native-babel-preset'], - plugins: [ - ["@babel/plugin-proposal-decorators", { legacy: true }], - [ - require.resolve('babel-plugin-module-resolver'), - { - cwd: 'babelrc', - extensions: ['.ts', '.tsx', '.js', '.ios.js', '.android.js'], - alias: { - '@cuteapp': './app' - } - } - ], - 'jest-hoist' + presets: ['module:metro-react-native-babel-preset'], + plugins: [ + ['@babel/plugin-proposal-decorators', { legacy: true }], + [ + require.resolve('babel-plugin-module-resolver'), + { + cwd: 'babelrc', + extensions: ['.ts', '.tsx', '.js', '.ios.js', '.android.js'], + alias: { + '@cuteapp': './app', + }, + }, ], - "env": { - "production": { - "plugins": ["transform-remove-console"] - } - } + 'jest-hoist', + ], + env: { + production: { + plugins: ['transform-remove-console'], + }, + }, }; diff --git a/firebase.json b/firebase.json index f57d786b..006eb8f1 100644 --- a/firebase.json +++ b/firebase.json @@ -1,5 +1,5 @@ { - "react-native": { - "crashlytics_debug_enabled": true - } - } \ No newline at end of file + "react-native": { + "crashlytics_debug_enabled": true + } +} diff --git a/index.js b/index.js index 24775587..68eed944 100644 --- a/index.js +++ b/index.js @@ -2,16 +2,16 @@ * @format */ -import {AppRegistry} from 'react-native'; +import { AppRegistry } from 'react-native'; import App from './App'; -import {name as appName} from './app.json'; +import { name as appName } from './app.json'; import database from '@react-native-firebase/database'; import { LogBox } from 'react-native'; -import ReactNativeForegroundService from "@supersami/rn-foreground-service"; +import ReactNativeForegroundService from '@supersami/rn-foreground-service'; import CosmosForegroundService from './src/services/foregroundServices/foreground.service'; if (__DEV__) { - LogBox.ignoreAllLogs(); + LogBox.ignoreAllLogs(); } database().setPersistenceEnabled(true); diff --git a/metro.config.js b/metro.config.js index 783f3499..13a96421 100644 --- a/metro.config.js +++ b/metro.config.js @@ -6,12 +6,12 @@ */ module.exports = { - transformer: { - getTransformOptions: async () => ({ - transform: { - experimentalImportSupport: false, - inlineRequires: false, - }, - }), - }, + transformer: { + getTransformOptions: async () => ({ + transform: { + experimentalImportSupport: false, + inlineRequires: false, + }, + }), + }, }; diff --git a/package.json b/package.json index 7a5a2af5..3c838a63 100644 --- a/package.json +++ b/package.json @@ -1,123 +1,132 @@ { - "name": "AV_APP", - "version": "2.1.11", - "private": true, - "scripts": { - "android:dev": "yarn move:dev && react-native run-android", - "android:qa": "yarn move:qa && react-native run-android", - "android:prod": "yarn move:prod && react-native run-android", - "ios": "react-native run-ios", - "start": "react-native start", - "test": "jest", - "prettier:write": "npx prettier --write **/*.{js,jsx,ts,tsx,json} && npx prettier --write *.{js,jsx,ts,tsx,json}", - "lint": "tsc --noEmit && eslint --ext .js,.jsx,.ts,.tsx ./", - "release:dev": "yarn move:dev && react-native run-android --variant=release && cd android && ./gradlew assembleDebug", - "release:qa": "yarn move:qa && react-native run-android --variant=release && cd android && ./gradlew assembleRelease", - "release:prod": "yarn move:prod && react-native run-android --variant=release && cd android && ./gradlew assembleRelease", - "move:dev": "cp -f ./config/dev/config.js ./src/constants && cp -f ./config/dev/google-services.json ./android/app", - "move:qa": "cp -f ./config/qa/config.js ./src/constants && cp -f ./config/dev/google-services.json ./android/app", - "move:prod": "cp -f ./config/prod/config.js ./src/constants && cp -f ./config/prod/google-services.json ./android/app", - "debug": "react-native bundle --platform android --dev false --entry-file index.js --bundle-output android/app/src/main/assets/index.android.bundle --assets-dest android/app/src/main/res" - }, - "dependencies": { - "@cobo/apm-rum-react-native": "^0.6.0", - "@elastic/apm-rum-core": "^5.17.0", - "@nozbe/watermelondb": "0.24.0", - "@nozbe/with-observables": "1.4.1", - "@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/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-navigation/bottom-tabs": "6.5.5", - "@react-navigation/native": "6.1.4", - "@react-navigation/native-stack": "6.9.4", - "@reduxjs/toolkit": "1.9.1", - "@sentry/browser": "7.29.0", - "@supersami/rn-foreground-service": "^2.1.0", - "appcenter": "^4.4.5", - "appcenter-analytics": "^4.4.5", - "appcenter-crashes": "^4.4.5", - "axios": "1.2.1", - "crypto-js": "^4.1.1", - "fuzzysort": "2.0.4", - "lottie-react-native": "5.1.4", - "react": "18.1.0", - "react-hook-form": "7.40.0", - "react-native": "0.70.6", - "react-native-code-push": "7.1.0", - "react-native-date-picker": "4.2.10", - "react-native-device-info": "10.3.0", - "react-native-fast-image": "8.6.3", - "react-native-geolocation-service": "5.3.1", - "react-native-image-picker": "4.10.2", - "react-native-pager-view": "6.1.2", - "react-native-permissions": "3.6.1", - "react-native-qrcode-svg": "^6.2.0", - "react-native-safe-area-context": "4.4.1", - "react-native-screens": "3.18.2", - "react-native-svg": "^13.9.0", - "react-native-tab-view": "3.3.2", - "react-native-toast-message": "2.1.5", - "react-native-vector-icons": "9.2.0", - "react-native-version-number": "0.3.6", - "react-redux": "8.0.5", - "redux": "4.2.0", - "redux-persist": "6.0.0", - "rn-fetch-blob": "0.12.0", - "react-native-webview": "12.0.2" - }, - "devDependencies": { - "@babel/core": "7.12.9", - "@babel/plugin-proposal-decorators": "7.20.7", - "@babel/runtime": "7.12.5", - "@tsconfig/react-native": "2.0.2", - "@types/jest": "26.0.23", - "@types/react": "18.0.21", - "@types/react-native": "0.70.6", - "@types/react-native-video": "5.0.14", - "@types/react-native-video-player": "0.10.3", - "@types/react-test-renderer": "18.0.0", - "@typescript-eslint/eslint-plugin": "^5.43.0", - "@typescript-eslint/parser": "5.37.0", - "babel-jest": "26.6.3", - "babel-plugin-module-resolver": "^4.1.0", - "babel-plugin-transform-remove-console": "^6.9.4", - "better-sqlite3": "8.0.1", - "eslint": "8.22.0", - "eslint-config-airbnb": "^19.0.4", - "eslint-config-airbnb-base": "^15.0.0", - "eslint-config-airbnb-typescript": "17.0.0", - "eslint-config-prettier": "^8.8.0", - "eslint-config-standard-with-typescript": "^34.0.1", - "eslint-plugin-import": "^2.25.2", - "eslint-plugin-jsx-a11y": "6.6.1", - "eslint-plugin-n": "^15.0.0", - "eslint-plugin-promise": "^6.0.0", - "eslint-plugin-react": "^7.32.2", - "eslint-plugin-react-hooks": "^4.6.0", - "eslint-plugin-react-native": "^4.0.0", - "jest": "26.6.3", - "metro-react-native-babel-preset": "0.72.3", - "miragejs": "0.1.47", - "prettier": "^2.8.7", - "react-test-renderer": "18.1.0", - "eslint-config-prettier-react": "^0.0.24", - "typescript": "4.8.3" - }, - "jest": { - "preset": "react-native", - "moduleFileExtensions": [ - "ts", - "tsx", - "js", - "jsx", - "json", - "node" - ] - } + "name": "AV_APP", + "version": "2.1.11", + "private": true, + "scripts": { + "android:dev": "yarn move:dev && react-native run-android", + "android:qa": "yarn move:qa && react-native run-android", + "android:prod": "yarn move:prod && react-native run-android", + "ios": "react-native run-ios", + "start": "react-native start", + "test": "jest", + "prettier:check": "npx prettier --check **/*.{js,ts,tsx,json} && npx prettier --check *.{js,ts,tsx,json}", + "prettier:write": "npx prettier --write **/*.{js,ts,tsx,json} && npx prettier --write *.{js,ts,tsx,json}", + "lint": "tsc --noEmit && eslint --ext .js,.jsx,.ts,.tsx ./", + "release:dev": "yarn move:dev && react-native run-android --variant=release && cd android && ./gradlew assembleDebug", + "release:qa": "yarn move:qa && react-native run-android --variant=release && cd android && ./gradlew assembleRelease", + "release:prod": "yarn move:prod && react-native run-android --variant=release && cd android && ./gradlew assembleRelease", + "move:dev": "cp -f ./config/dev/config.js ./src/constants && cp -f ./config/dev/google-services.json ./android/app", + "move:qa": "cp -f ./config/qa/config.js ./src/constants && cp -f ./config/dev/google-services.json ./android/app", + "move:prod": "cp -f ./config/prod/config.js ./src/constants && cp -f ./config/prod/google-services.json ./android/app", + "debug": "react-native bundle --platform android --dev false --entry-file index.js --bundle-output android/app/src/main/assets/index.android.bundle --assets-dest android/app/src/main/res", + "prepare": "husky install" + }, + "dependencies": { + "@cobo/apm-rum-react-native": "^0.6.0", + "@elastic/apm-rum-core": "^5.17.0", + "@nozbe/watermelondb": "0.24.0", + "@nozbe/with-observables": "1.4.1", + "@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/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-navigation/bottom-tabs": "6.5.5", + "@react-navigation/native": "6.1.4", + "@react-navigation/native-stack": "6.9.4", + "@reduxjs/toolkit": "1.9.1", + "@sentry/browser": "7.29.0", + "@supersami/rn-foreground-service": "^2.1.0", + "appcenter": "^4.4.5", + "appcenter-analytics": "^4.4.5", + "appcenter-crashes": "^4.4.5", + "axios": "1.2.1", + "crypto-js": "^4.1.1", + "fuzzysort": "2.0.4", + "lottie-react-native": "5.1.4", + "react": "18.1.0", + "react-hook-form": "7.40.0", + "react-native": "0.70.6", + "react-native-code-push": "7.1.0", + "react-native-date-picker": "4.2.10", + "react-native-device-info": "10.3.0", + "react-native-fast-image": "8.6.3", + "react-native-geolocation-service": "5.3.1", + "react-native-image-picker": "4.10.2", + "react-native-pager-view": "6.1.2", + "react-native-permissions": "3.6.1", + "react-native-qrcode-svg": "^6.2.0", + "react-native-safe-area-context": "4.4.1", + "react-native-screens": "3.18.2", + "react-native-svg": "^13.9.0", + "react-native-tab-view": "3.3.2", + "react-native-toast-message": "2.1.5", + "react-native-vector-icons": "9.2.0", + "react-native-version-number": "0.3.6", + "react-redux": "8.0.5", + "redux": "4.2.0", + "redux-persist": "6.0.0", + "rn-fetch-blob": "0.12.0", + "react-native-webview": "12.0.2" + }, + "devDependencies": { + "@babel/core": "7.12.9", + "@babel/plugin-proposal-decorators": "7.20.7", + "@babel/runtime": "7.12.5", + "@tsconfig/react-native": "2.0.2", + "@types/jest": "26.0.23", + "@types/react": "18.0.21", + "@types/react-native": "0.70.6", + "@types/react-native-video": "5.0.14", + "@types/react-native-video-player": "0.10.3", + "@types/react-test-renderer": "18.0.0", + "@typescript-eslint/eslint-plugin": "^5.43.0", + "@typescript-eslint/parser": "5.37.0", + "babel-jest": "26.6.3", + "babel-plugin-module-resolver": "^4.1.0", + "babel-plugin-transform-remove-console": "^6.9.4", + "better-sqlite3": "8.0.1", + "eslint": "8.22.0", + "eslint-config-airbnb": "^19.0.4", + "eslint-config-airbnb-base": "^15.0.0", + "eslint-config-airbnb-typescript": "17.0.0", + "eslint-config-prettier": "^8.8.0", + "eslint-config-standard-with-typescript": "^34.0.1", + "eslint-plugin-import": "^2.25.2", + "eslint-plugin-jsx-a11y": "6.6.1", + "eslint-plugin-n": "^15.0.0", + "eslint-plugin-promise": "^6.0.0", + "eslint-plugin-react": "^7.32.2", + "eslint-plugin-react-hooks": "^4.6.0", + "eslint-plugin-react-native": "^4.0.0", + "husky": "8.0.0", + "jest": "26.6.3", + "lint-staged": "13.2.1", + "metro-react-native-babel-preset": "0.72.3", + "miragejs": "0.1.47", + "prettier": "^2.8.7", + "react-test-renderer": "18.1.0", + "eslint-config-prettier-react": "^0.0.24", + "typescript": "4.8.3" + }, + "jest": { + "preset": "react-native", + "moduleFileExtensions": [ + "ts", + "tsx", + "js", + "jsx", + "json", + "node" + ] + }, + "lint-staged": { + "*.{js,css,scss,md,json,js,ts,tsx}": [ + "prettier --write" + ] + } } diff --git a/src/action/addressGeolocationAction.ts b/src/action/addressGeolocationAction.ts index 5c83b9db..654fbf69 100644 --- a/src/action/addressGeolocationAction.ts +++ b/src/action/addressGeolocationAction.ts @@ -1,56 +1,53 @@ import { - resetAddressGeolocation, - setAddressGeolocation, - setLoading, + resetAddressGeolocation, + setAddressGeolocation, + setLoading, } from '../reducer/addressGeolocationSlice'; -import axiosInstance, { - ApiKeys, - API_STATUS_CODE, - getApiUrl, -} from '../components/utlis/apiHelper'; +import axiosInstance, { ApiKeys, API_STATUS_CODE, getApiUrl } from '../components/utlis/apiHelper'; import { AppDispatch } from '../store/store'; import { logError } from '../components/utlis/errorUtils'; import { IAddAddressPayload, IAddressGeolocationPayload } from '../types/addressGeolocation.types'; export const getAddressesGeolocation = - (payload: IAddressGeolocationPayload) => (dispatch: AppDispatch) => { - const url = getApiUrl(ApiKeys.ADDRESSES_GEOLOCATION); - dispatch(setLoading(true)); - axiosInstance - .post(url, payload) - .then(response => { - if (response?.data) { - dispatch(setAddressGeolocation(response.data)); - return; - } - throw response; - }) - .catch(err => { - logError(err); - dispatch(resetAddressGeolocation()); - }) - .finally(() => { - dispatch(setLoading(false)); - }); - }; + (payload: IAddressGeolocationPayload) => (dispatch: AppDispatch) => { + const url = getApiUrl(ApiKeys.ADDRESSES_GEOLOCATION); + dispatch(setLoading(true)); + axiosInstance + .post(url, payload) + .then((response) => { + if (response?.data) { + dispatch(setAddressGeolocation(response.data)); + return; + } + throw response; + }) + .catch((err) => { + logError(err); + dispatch(resetAddressGeolocation()); + }) + .finally(() => { + dispatch(setLoading(false)); + }); + }; export const addAddress = - (payload: IAddAddressPayload, commonPayload: IAddressGeolocationPayload) => (dispatch: AppDispatch) => { - const url = getApiUrl(ApiKeys.NEW_ADDRESS); - dispatch(setLoading(true)); - return axiosInstance - .post(url, { ...payload, ...commonPayload }) - .then(response => { - if (response?.status === API_STATUS_CODE.CREATED) { - return; - } - throw response; - }) - .catch(err => { - logError(err); - return err; - }) - .finally(() => { - dispatch(setLoading(false)); - }); - }; + (payload: IAddAddressPayload, commonPayload: IAddressGeolocationPayload) => + (dispatch: AppDispatch) => { + const url = getApiUrl(ApiKeys.NEW_ADDRESS); + dispatch(setLoading(true)); + return axiosInstance + .post(url, { ...payload, ...commonPayload }) + .then((response) => { + if (response?.status === API_STATUS_CODE.CREATED) { + return; + } + throw response; + }) + .catch((err) => { + logError(err); + return err; + }) + .finally(() => { + dispatch(setLoading(false)); + }); + }; diff --git a/src/action/authActions.ts b/src/action/authActions.ts index 95295bd1..679e9615 100644 --- a/src/action/authActions.ts +++ b/src/action/authActions.ts @@ -1,17 +1,13 @@ import crypto from 'crypto-js'; import { IUser, setAuthData } from '../reducer/userSlice'; -import axiosInstance, { - ApiKeys, - API_STATUS_CODE, - getApiUrl, -} from '../components/utlis/apiHelper'; +import axiosInstance, { ApiKeys, API_STATUS_CODE, getApiUrl } from '../components/utlis/apiHelper'; import { - resetLoginForm, - setFormLoading, - setOTPError, - setShowOTPScreen, - setVerifyOTPError, - setVerifyOTPSuccess, + resetLoginForm, + setFormLoading, + setOTPError, + setShowOTPScreen, + setVerifyOTPError, + setVerifyOTPSuccess, } from '../reducer/loginSlice'; import { Dispatch } from '@reduxjs/toolkit'; import { navigateToScreen } from '../components/utlis/navigationUtlis'; @@ -27,170 +23,169 @@ import { getUniqueId } from 'react-native-device-info'; import { Linking } from 'react-native'; export interface GenerateOTPPayload { - phoneNumber: string; + phoneNumber: string; } export interface VerifyOTPPayload { - otp: string; - otpToken: string; + otp: string; + otpToken: string; } export interface SignInGooglePayload { - codeChallenge: string; + codeChallenge: string; } export const generateOTP = - ({ phoneNumber }: GenerateOTPPayload, isResendOTP?: boolean) => - (dispatch: Dispatch) => { - const url = getApiUrl(ApiKeys.GENERATE_OTP); - dispatch(setFormLoading(true)); - axiosInstance - .post(url, { phoneNumber: Number(phoneNumber) },{ headers: { donotHandleError: false } }) - .then(response => { - if (response.status === 200) { - if (response?.data?.data?.otpToken) { - dispatch( - setShowOTPScreen({ - phoneNumber, - otpToken: response?.data?.data?.otpToken, - }), - ); - !isResendOTP && navigateToScreen('OTP'); - } - } - }) - .catch((err) => { - // TODO: Fix status from BE - if (err.response.status === API_STATUS_CODE.NOT_FOUND || err.response.status === API_STATUS_CODE.BAD_REQUEST) { - dispatch(setOTPError('Enter a registered mobile number')); - } else { - dispatch(setOTPError(err.response?.data?.message)); - } - }).finally(() => dispatch(setFormLoading(false))); - }; - -export const signInGoogle = () => - async (dispatch: Dispatch) => { - try { - const codeVerifier = crypto.lib.WordArray.random(64).toString(); - const codeChallenge = crypto.enc.Base64url.stringify( - crypto.enc.Utf8.parse(crypto.SHA256(codeVerifier)) - ).toString(); - await setAsyncStorageItem('codeVerifier', codeVerifier); - const state = crypto.lib.WordArray.random(16).toString(); - const url = getApiUrl(ApiKeys.SIGN_IN_GOOGLE); - dispatch(setFormLoading(true)); - const response = await axiosInstance.get(url, { - params: { - codeChallenge, - state, - }, - headers: { donotHandleError: false }, - }); - if (response?.data?.signInUrl) { - Linking.openURL(response.data.signInUrl); + ({ phoneNumber }: GenerateOTPPayload, isResendOTP?: boolean) => + (dispatch: Dispatch) => { + const url = getApiUrl(ApiKeys.GENERATE_OTP); + dispatch(setFormLoading(true)); + axiosInstance + .post(url, { phoneNumber: Number(phoneNumber) }, { headers: { donotHandleError: false } }) + .then((response) => { + if (response.status === 200) { + if (response?.data?.data?.otpToken) { + dispatch( + setShowOTPScreen({ + phoneNumber, + otpToken: response?.data?.data?.otpToken, + }) + ); + !isResendOTP && navigateToScreen('OTP'); } - } catch (error) { - toast({ - text1: 'Error in google sign in', - type: 'error', - }); - } finally { - dispatch(setFormLoading(false)); } - }; + }) + .catch((err) => { + // TODO: Fix status from BE + if ( + err.response.status === API_STATUS_CODE.NOT_FOUND || + err.response.status === API_STATUS_CODE.BAD_REQUEST + ) { + dispatch(setOTPError('Enter a registered mobile number')); + } else { + dispatch(setOTPError(err.response?.data?.message)); + } + }) + .finally(() => dispatch(setFormLoading(false))); + }; + +export const signInGoogle = () => async (dispatch: Dispatch) => { + try { + const codeVerifier = crypto.lib.WordArray.random(64).toString(); + const codeChallenge = crypto.enc.Base64url.stringify( + crypto.enc.Utf8.parse(crypto.SHA256(codeVerifier)) + ).toString(); + await setAsyncStorageItem('codeVerifier', codeVerifier); + const state = crypto.lib.WordArray.random(16).toString(); + const url = getApiUrl(ApiKeys.SIGN_IN_GOOGLE); + dispatch(setFormLoading(true)); + const response = await axiosInstance.get(url, { + params: { + codeChallenge, + state, + }, + headers: { donotHandleError: false }, + }); + if (response?.data?.signInUrl) { + Linking.openURL(response.data.signInUrl); + } + } catch (error) { + toast({ + text1: 'Error in google sign in', + type: 'error', + }); + } finally { + dispatch(setFormLoading(false)); + } +}; export const verifyGoogleSignIn = - (code: string, state: string, deviceId: string) => - async (dispatch: AppDispatch) => { - const url = getApiUrl(ApiKeys.VERIFY_GOOGLE_SIGN_IN); - try { - const codeVerify = await AsyncStorage.getItem('codeVerifier'); - if(!codeVerify) { - return; - } - const parsedCodeVerify = JSON.parse(codeVerify); - const response = await axiosInstance.post( - url, - { - code, - state, - codeVerifier: parsedCodeVerify, - deviceId: deviceId, - }, - { headers: { donotHandleError: true } }, - ); - if (response?.data?.sessionDetails) { - const { sessionDetails, user } = response.data; - dispatch( - setAuthData({ - sessionDetails, - user, - isLoggedIn: true, - }), - ); - dispatch(setVerifyOTPSuccess('OTP verified')); - dispatch(resetLoginForm()); - } - } catch (error) { - logError(error as Error); - toast({ - text1: 'error in google sign in', - type: 'error', - }); - } finally { - () => dispatch(setFormLoading(false)); - } - }; + (code: string, state: string, deviceId: string) => async (dispatch: AppDispatch) => { + const url = getApiUrl(ApiKeys.VERIFY_GOOGLE_SIGN_IN); + try { + const codeVerify = await AsyncStorage.getItem('codeVerifier'); + if (!codeVerify) { + return; + } + const parsedCodeVerify = JSON.parse(codeVerify); + const response = await axiosInstance.post( + url, + { + code, + state, + codeVerifier: parsedCodeVerify, + deviceId: deviceId, + }, + { headers: { donotHandleError: true } } + ); + if (response?.data?.sessionDetails) { + const { sessionDetails, user } = response.data; + dispatch( + setAuthData({ + sessionDetails, + user, + isLoggedIn: true, + }) + ); + dispatch(setVerifyOTPSuccess('OTP verified')); + dispatch(resetLoginForm()); + } + } catch (error) { + logError(error as Error); + toast({ + text1: 'error in google sign in', + type: 'error', + }); + } finally { + () => dispatch(setFormLoading(false)); + } + }; export const verifyOTP = -({ otp, otpToken }: VerifyOTPPayload) => -async(dispatch: AppDispatch) => { + ({ otp, otpToken }: VerifyOTPPayload) => + async (dispatch: AppDispatch) => { const url = getApiUrl(ApiKeys.VERIFY_OTP); dispatch(setFormLoading(true)); const fcmToken = await AsyncStorage.getItem('fcmtoken'); axiosInstance - .post( - url, - { otp, otpToken, fcmToken }, - { headers: { donotHandleError: true } }, - ) - .then((response: AxiosResponse) => { - const { sessionDetails, user } = response.data; - dispatch( - setAuthData({ - sessionDetails, - user, - isLoggedIn: true, - }), - ); - dispatch(setVerifyOTPSuccess('OTP verified')); - dispatch(resetLoginForm()); - }) - .catch(err => { - dispatch(setVerifyOTPError('Invalid OTP, try again')); - }).finally(() => dispatch(setFormLoading(false))); -}; + .post(url, { otp, otpToken, fcmToken }, { headers: { donotHandleError: true } }) + .then((response: AxiosResponse) => { + const { sessionDetails, user } = response.data; + dispatch( + setAuthData({ + sessionDetails, + user, + isLoggedIn: true, + }) + ); + dispatch(setVerifyOTPSuccess('OTP verified')); + dispatch(resetLoginForm()); + }) + .catch((err) => { + dispatch(setVerifyOTPError('Invalid OTP, try again')); + }) + .finally(() => dispatch(setFormLoading(false))); + }; export const logout = () => (dispatch: AppDispatch) => { - const url = getApiUrl(ApiKeys.LOGOUT); - axiosInstance - .get(url) - .then(async (_) => { - await clearAllAsyncStorage(); - setGlobalUserData({token: '', agentId:'', deviceId:''}); - dispatch( - setAuthData({ - sessionDetails: null, - user: null, - isLoggedIn: false, - }), - ); - dispatch(resetCasesData()); + const url = getApiUrl(ApiKeys.LOGOUT); + axiosInstance + .get(url) + .then(async (_) => { + await clearAllAsyncStorage(); + setGlobalUserData({ token: '', agentId: '', deviceId: '' }); + dispatch( + setAuthData({ + sessionDetails: null, + user: null, + isLoggedIn: false, }) - .catch(err => { - logError(err as Error); - console.error(err) - }); + ); + dispatch(resetCasesData()); + }) + .catch((err) => { + logError(err as Error); + console.error(err); + }); }; diff --git a/src/action/caseApiActions.ts b/src/action/caseApiActions.ts index c82b3d90..5706f585 100644 --- a/src/action/caseApiActions.ts +++ b/src/action/caseApiActions.ts @@ -1,143 +1,137 @@ -import axiosInstance, { - ApiKeys, - getApiUrl, -} from '../components/utlis/apiHelper'; +import axiosInstance, { ApiKeys, getApiUrl } from '../components/utlis/apiHelper'; import { AppDispatch } from '../store/store'; import { IAddressGeoLocation } from '../types/addressGeolocation.types'; -import { - setEmiSchedule, - setEmiScheduleLoading, -} from '../reducer/emiScheduleSlice'; -import { - setFeedbackHistory, - setFeedbackHistoryLoading, -} from '../reducer/feedbackHistorySlice'; -import { - setRepayments, - setRepaymentsLoading, -} from '../reducer/repaymentsSlice'; +import { setEmiSchedule, setEmiScheduleLoading } from '../reducer/emiScheduleSlice'; +import { setFeedbackHistory, setFeedbackHistoryLoading } from '../reducer/feedbackHistorySlice'; +import { setRepayments, setRepaymentsLoading } from '../reducer/repaymentsSlice'; import { AxiosResponse } from 'axios'; import { setAddresses, setAddressLoading } from '../reducer/addressSlice'; import { IFeedback } from '../types/feedback.types'; import { allSettled } from '../components/utlis/commonFunctions'; import { GenericType } from '../common/GenericTypes'; -import { addClickstreamEvent } from "../services/clickstreamEventService"; -import { CLICKSTREAM_EVENT_NAMES } from "../common/Constants"; +import { addClickstreamEvent } from '../services/clickstreamEventService'; +import { CLICKSTREAM_EVENT_NAMES } from '../common/Constants'; import { PageRouteEnum } from '../screens/auth/ProtectedRouter'; // TODO: Need to add respective interfaces instead of any interface IUnifiedData { - addressesAndGeoLocations: IAddressGeoLocation; - feedbacks: Array; - emiSchedule: Array; - repayments: Array; + addressesAndGeoLocations: IAddressGeoLocation; + feedbacks: Array; + emiSchedule: Array; + repayments: Array; } export enum UnifiedCaseDetailsTypes { - ADDRESS_AND_GEOLOCATIONS = 'includeAddressesAndGeoLocations', - FEEDBACKS = 'includeFeedbacks', - EMI_SCHEDULE = 'includeEmiSchedule', - REPAYMENTS = 'includeRepayments', + ADDRESS_AND_GEOLOCATIONS = 'includeAddressesAndGeoLocations', + FEEDBACKS = 'includeFeedbacks', + EMI_SCHEDULE = 'includeEmiSchedule', + REPAYMENTS = 'includeRepayments', } const initialUrlParams = { - [UnifiedCaseDetailsTypes.ADDRESS_AND_GEOLOCATIONS]: false, - [UnifiedCaseDetailsTypes.FEEDBACKS]: false, - [UnifiedCaseDetailsTypes.EMI_SCHEDULE]: false, - [UnifiedCaseDetailsTypes.REPAYMENTS]: false, + [UnifiedCaseDetailsTypes.ADDRESS_AND_GEOLOCATIONS]: false, + [UnifiedCaseDetailsTypes.FEEDBACKS]: false, + [UnifiedCaseDetailsTypes.EMI_SCHEDULE]: false, + [UnifiedCaseDetailsTypes.REPAYMENTS]: false, }; const setUnifiedDataLoading = - (queryParams: Record, loanAccountNumbers: string[]) => - (dispatch: AppDispatch) => { - if (queryParams[UnifiedCaseDetailsTypes.EMI_SCHEDULE]) { - dispatch(setEmiScheduleLoading({loanAccountNumbers, isLoading : true})); - } - if (queryParams[UnifiedCaseDetailsTypes.FEEDBACKS]) { - dispatch(setFeedbackHistoryLoading({loanAccountNumbers, isLoading : true})); - } - if (queryParams[UnifiedCaseDetailsTypes.REPAYMENTS]) { - dispatch(setRepaymentsLoading({loanAccountNumbers, isLoading : true})); - } - if (queryParams[UnifiedCaseDetailsTypes.ADDRESS_AND_GEOLOCATIONS]) { - dispatch(setAddressLoading({loanAccountNumbers, isLoading : true})); - } - }; + (queryParams: Record, loanAccountNumbers: string[]) => + (dispatch: AppDispatch) => { + if (queryParams[UnifiedCaseDetailsTypes.EMI_SCHEDULE]) { + dispatch(setEmiScheduleLoading({ loanAccountNumbers, isLoading: true })); + } + if (queryParams[UnifiedCaseDetailsTypes.FEEDBACKS]) { + dispatch(setFeedbackHistoryLoading({ loanAccountNumbers, isLoading: true })); + } + if (queryParams[UnifiedCaseDetailsTypes.REPAYMENTS]) { + dispatch(setRepaymentsLoading({ loanAccountNumbers, isLoading: true })); + } + if (queryParams[UnifiedCaseDetailsTypes.ADDRESS_AND_GEOLOCATIONS]) { + dispatch(setAddressLoading({ loanAccountNumbers, isLoading: true })); + } + }; const setUnifiedData = - ( - queryParams: Record, - loanAccountNumbers: string[], - unifiedPromiseData: PromiseSettledResult>[], - ) => - (dispatch: AppDispatch) => { - unifiedPromiseData.forEach((promiseResult, index) => { - const { status } = promiseResult; - if (status === 'fulfilled' && promiseResult.value) { - const { - addressesAndGeoLocations, - feedbacks, - emiSchedule, - repayments, - } = promiseResult.value.data; - const loanAccountNumber = loanAccountNumbers[index]; - if (queryParams[UnifiedCaseDetailsTypes.EMI_SCHEDULE]) { - dispatch( - setEmiSchedule({ loanAccountNumber, emiSchedule }), - ); - } - 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, addressesAndGeoLocations })); - } - } - }); - }; + ( + queryParams: Record, + loanAccountNumbers: string[], + unifiedPromiseData: PromiseSettledResult>[] + ) => + (dispatch: AppDispatch) => { + unifiedPromiseData.forEach((promiseResult, index) => { + const { status } = promiseResult; + if (status === 'fulfilled' && promiseResult.value) { + const { addressesAndGeoLocations, feedbacks, emiSchedule, repayments } = + promiseResult.value.data; + const loanAccountNumber = loanAccountNumbers[index]; + if (queryParams[UnifiedCaseDetailsTypes.EMI_SCHEDULE]) { + dispatch(setEmiSchedule({ loanAccountNumber, emiSchedule })); + } + 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, addressesAndGeoLocations })); + } + } + }); + }; export const getCaseUnifiedData = - (loanAccountNumbers: string[], infoToGet: Array) => - (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)); - const promisesList: Promise>[] = []; - loanAccountNumbers.forEach(loanAccountNumber => { - const url = getApiUrl( - ApiKeys.CASE_UNIFIED_DETAILS, - { loanAccountNumber }, - queryParams, - ); - const promise = axiosInstance.get(url, { - headers: { - showInSpecificComponents: [ - PageRouteEnum.COLLECTION_CASE_DETAIL, - PageRouteEnum.EMI_SCHEDULE, - PageRouteEnum.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)); - }).catch(e=>{ - addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_UNIFIED_ENTITY_REQUEST_FAILED, {lans: JSON.stringify(loanAccountNumbers || []), requestedEntities: JSON.stringify(infoToGet || [])}) - }).finally(() => { - dispatch(setEmiScheduleLoading({isLoading:false, loanAccountNumbers})); - dispatch(setFeedbackHistoryLoading({isLoading:false, loanAccountNumbers})); - dispatch(setRepaymentsLoading({isLoading:false, loanAccountNumbers})); - dispatch(setAddressLoading({isLoading:false, loanAccountNumbers})) + (loanAccountNumbers: string[], infoToGet: Array) => + (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)); + const promisesList: Promise>[] = []; + loanAccountNumbers.forEach((loanAccountNumber) => { + const url = getApiUrl(ApiKeys.CASE_UNIFIED_DETAILS, { loanAccountNumber }, queryParams); + const promise = axiosInstance.get(url, { + headers: { + showInSpecificComponents: [ + PageRouteEnum.COLLECTION_CASE_DETAIL, + PageRouteEnum.EMI_SCHEDULE, + PageRouteEnum.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)); + }) + .catch((e) => { + addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_UNIFIED_ENTITY_REQUEST_FAILED, { + lans: JSON.stringify(loanAccountNumbers || []), + requestedEntities: JSON.stringify(infoToGet || []), + }); + }) + .finally(() => { + dispatch(setEmiScheduleLoading({ isLoading: false, loanAccountNumbers })); + dispatch(setFeedbackHistoryLoading({ isLoading: false, loanAccountNumbers })); + dispatch(setRepaymentsLoading({ isLoading: false, loanAccountNumbers })); + dispatch(setAddressLoading({ isLoading: false, loanAccountNumbers })); + }); + }; diff --git a/src/action/dataActions.ts b/src/action/dataActions.ts index 4792b2ed..7713c426 100644 --- a/src/action/dataActions.ts +++ b/src/action/dataActions.ts @@ -1,206 +1,226 @@ import { AnswerType } from '../components/form/interface'; -import axiosInstance, { - ApiKeys, - getApiUrl, -} from '../components/utlis/apiHelper'; +import axiosInstance, { ApiKeys, getApiUrl } from '../components/utlis/apiHelper'; import { navigateToScreen } from '../components/utlis/navigationUtlis'; import OfflineImageDAO from '../wmDB/dao/OfflineImageDAO'; import { - resetSelectedTodoList, - resetTodoList, - setLoading, - setVisitPlansUpdating, - updateCaseDetail, - updateSingleCase, + resetSelectedTodoList, + resetTodoList, + setLoading, + setVisitPlansUpdating, + updateCaseDetail, + updateSingleCase, } from '../reducer/allCasesSlice'; -import {CaseAllocationType, CaseType, ICaseItem, IPinnedCasesPayload} from '../screens/allCases/interface'; -import {AppDispatch} from '../store/store'; -import {addClickstreamEvent} from '../services/clickstreamEventService'; -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"; +import { + CaseAllocationType, + CaseType, + ICaseItem, + IPinnedCasesPayload, +} from '../screens/allCases/interface'; +import { AppDispatch } from '../store/store'; +import { addClickstreamEvent } from '../services/clickstreamEventService'; +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'; import { ToastMessages } from '../screens/allCases/constants'; -let _signedApiCallBucket: { req: any, added_At: number }[] = [] +let _signedApiCallBucket: { req: any; added_At: number }[] = []; let _signedApiCallBucketTimer: number = 0; -const SIGNED_API_BUCKET_SIZE = 10 -const SIGNED_API_BUCKET_TIMEOUT = 7*1000; +const SIGNED_API_BUCKET_SIZE = 10; +const SIGNED_API_BUCKET_TIMEOUT = 7 * 1000; export const postPinnedList = - (pinnedCases: IPinnedCasesPayload[], updatedCaseList: ICaseItem[], type: string) => - (dispatch: AppDispatch) => { - dispatch(setVisitPlansUpdating(true)); - let pinRankCount = 1; - const payload: IPinnedCasesPayload[] = pinnedCases.reduce((acc, pinnedCase) => { - acc.push({ - ...pinnedCase, - pinRank: pinRankCount++ - }); - return acc; - }, [] as IPinnedCasesPayload[]); - const url = getApiUrl(ApiKeys.PINNED_CASES); - axiosInstance - .post(url, payload) - .then(response => { - addClickstreamEvent( - type === 'REMOVED' - ? CLICKSTREAM_EVENT_NAMES.AV_CASE_LIST_REMOVE_API_SUCCESS - : CLICKSTREAM_EVENT_NAMES.AV_TODO_LIST_SUBMIT_SUCCESS, - { todoList: payload }, - ); - }) - .catch(err => { - addClickstreamEvent( - type === 'REMOVED' - ? CLICKSTREAM_EVENT_NAMES.AV_CASE_LIST_REMOVE_API_FAILED - : CLICKSTREAM_EVENT_NAMES.AV_TODO_LIST_SUBMIT_FAILED, - { todoList: payload }, - ); - }).finally(() => { - dispatch(setVisitPlansUpdating(false)); - dispatch(resetTodoList()); - dispatch(resetSelectedTodoList()); - navigateToScreen('Visit plan'); - }); - }; + (pinnedCases: IPinnedCasesPayload[], updatedCaseList: ICaseItem[], type: string) => + (dispatch: AppDispatch) => { + dispatch(setVisitPlansUpdating(true)); + let pinRankCount = 1; + const payload: IPinnedCasesPayload[] = pinnedCases.reduce((acc, pinnedCase) => { + acc.push({ + ...pinnedCase, + pinRank: pinRankCount++, + }); + return acc; + }, [] as IPinnedCasesPayload[]); + const url = getApiUrl(ApiKeys.PINNED_CASES); + axiosInstance + .post(url, payload) + .then((response) => { + addClickstreamEvent( + type === 'REMOVED' + ? CLICKSTREAM_EVENT_NAMES.AV_CASE_LIST_REMOVE_API_SUCCESS + : CLICKSTREAM_EVENT_NAMES.AV_TODO_LIST_SUBMIT_SUCCESS, + { todoList: payload } + ); + }) + .catch((err) => { + addClickstreamEvent( + type === 'REMOVED' + ? CLICKSTREAM_EVENT_NAMES.AV_CASE_LIST_REMOVE_API_FAILED + : CLICKSTREAM_EVENT_NAMES.AV_TODO_LIST_SUBMIT_FAILED, + { todoList: payload } + ); + }) + .finally(() => { + dispatch(setVisitPlansUpdating(false)); + dispatch(resetTodoList()); + dispatch(resetSelectedTodoList()); + navigateToScreen('Visit plan'); + }); + }; export const syncCaseDetail = - (payload: any, updatedCaseDetail?: any, callbacks? : { onSuccessCB?: (data: any, actions?: any)=>void, onErrorCB?: (e : Error)=>void, }, nextActions?: any) => (dispatch: AppDispatch) => { - const offlineImageIdList = getOfflineImageId(payload); - const url = getApiUrl(ApiKeys.FEEDBACK); - axiosInstance - .post(url, payload) - .then(res => { - const caseType = payload.caseType; - dispatch(updateSingleCase({ data: res.data, id: payload.data.caseReferenceId, caseType, offlineCaseKey: payload.data.offlineCaseKey })); - OfflineImageDAO.deleteImages(offlineImageIdList); - toast({ - type: 'success', - text1: ToastMessages.FEEDBACK_SUCCESSFUL, - }); - if( ((callbacks?.onSuccessCB) != null) && typeof callbacks?.onSuccessCB === 'function') { - callbacks?.onSuccessCB(payload.data.answers, nextActions) - } + ( + payload: any, + updatedCaseDetail?: any, + callbacks?: { + onSuccessCB?: (data: any, actions?: any) => void; + onErrorCB?: (e: Error) => void; + }, + nextActions?: any + ) => + (dispatch: AppDispatch) => { + const offlineImageIdList = getOfflineImageId(payload); + const url = getApiUrl(ApiKeys.FEEDBACK); + axiosInstance + .post(url, payload) + .then((res) => { + const caseType = payload.caseType; + dispatch( + updateSingleCase({ + data: res.data, + id: payload.data.caseReferenceId, + caseType, + offlineCaseKey: payload.data.offlineCaseKey, + }) + ); + OfflineImageDAO.deleteImages(offlineImageIdList); + toast({ + type: 'success', + text1: ToastMessages.FEEDBACK_SUCCESSFUL, + }); + if (callbacks?.onSuccessCB != null && typeof callbacks?.onSuccessCB === 'function') { + callbacks?.onSuccessCB(payload.data.answers, nextActions); + } + }) + .catch((e) => { + if (updatedCaseDetail) { + dispatch( + updateCaseDetail({ + caseId: payload.data.caseReferenceId, + updatedCaseDetail, }) - .catch((e) => { - if(updatedCaseDetail) { - dispatch( - updateCaseDetail({ - caseId: payload.data.caseReferenceId, - updatedCaseDetail, - }), - ); - toast({ - type: 'error', - text1: ToastMessages.FEEDBACK_FAILED, - }); - } - if( ((callbacks?.onErrorCB) != null) && typeof callbacks?.onErrorCB === 'function') { - callbacks?.onErrorCB(e) - } - }) - }; + ); + toast({ + type: 'error', + text1: ToastMessages.FEEDBACK_FAILED, + }); + } + if (callbacks?.onErrorCB != null && typeof callbacks?.onErrorCB === 'function') { + callbacks?.onErrorCB(e); + } + }); + }; /** * Todo: Optimization Required * Solution: Sync the offline images separately with the server */ const getOfflineImageId = (caseItem: any) => { - const offlineImageList = []; - for (let taskId in caseItem?.context?.taskContext) { - for (let taskItem of caseItem.context.taskContext?.[taskId]) { - for (let wizItem in taskItem?.widgetContext) { - for (let sectionItem in taskItem.widgetContext[wizItem] - ?.sectionContext) { - for (let questionItem in taskItem.widgetContext[wizItem] - .sectionContext[sectionItem]?.questionContext) { - if ( - taskItem.widgetContext[wizItem].sectionContext[ - sectionItem - ].questionContext[questionItem]?.type === - AnswerType.image - ) { - const offlineImageId = - taskItem.widgetContext[wizItem].sectionContext[ - sectionItem - ].questionContext[questionItem].offlineImageId; - if (offlineImageId) - offlineImageList.push(offlineImageId); - } - } - } + const offlineImageList = []; + for (let taskId in caseItem?.context?.taskContext) { + for (let taskItem of caseItem.context.taskContext?.[taskId]) { + for (let wizItem in taskItem?.widgetContext) { + for (let sectionItem in taskItem.widgetContext[wizItem]?.sectionContext) { + for (let questionItem in taskItem.widgetContext[wizItem].sectionContext[sectionItem] + ?.questionContext) { + if ( + taskItem.widgetContext[wizItem].sectionContext[sectionItem].questionContext[ + questionItem + ]?.type === AnswerType.image + ) { + const offlineImageId = + taskItem.widgetContext[wizItem].sectionContext[sectionItem].questionContext[ + questionItem + ].offlineImageId; + if (offlineImageId) offlineImageList.push(offlineImageId); } + } } + } } - return offlineImageList; + } + return offlineImageList; }; export const getFilters = () => (dispatch: AppDispatch) => { - const url = getApiUrl(ApiKeys.FILTERS); - dispatch(setLoading(true)); - axiosInstance.get(url).then(response => { - dispatch(setFilters(response.data)); - }); + const url = getApiUrl(ApiKeys.FILTERS); + dispatch(setLoading(true)); + axiosInstance.get(url).then((response) => { + dispatch(setFilters(response.data)); + }); }; interface ISignedRequestItem { - documentReferenceId: string; - caseType:CaseAllocationType; - caseId: string + documentReferenceId: string; + caseType: CaseAllocationType; + caseId: string; } -export type ISignedRequest = ISignedRequestItem[] +export type ISignedRequest = ISignedRequestItem[]; // TODO : make a immediate resolve provision as well, that bypassses batching. -export const getSignedApi = async (signedRequestPayload: ISignedRequest, shouldBatch = false): Promise<{ imageUrl: string }> => { +export const getSignedApi = async ( + signedRequestPayload: ISignedRequest, + shouldBatch = false +): Promise<{ imageUrl: string }> => { return new Promise((res) => { - if(shouldBatch){ + if (shouldBatch) { batchSignedApiRequest(signedRequestPayload, (results: any) => { - res({imageUrl: results?.[signedRequestPayload[0].documentReferenceId] || ''}) - }) - } - else { + res({ imageUrl: results?.[signedRequestPayload[0].documentReferenceId] || '' }); + }); + } else { makeBulkSignedApiRequest(signedRequestPayload, (results: any) => { - res({imageUrl: results?.[signedRequestPayload[0].documentReferenceId] || ''}) - }) + res({ imageUrl: results?.[signedRequestPayload[0].documentReferenceId] || '' }); + }); } - - - }) + }); }; async function batchSignedApiRequest(payload: ISignedRequestItem[], callback: any) { - payload.forEach(item => { - _signedApiCallBucket.push({req: item, added_At: Date.now()}) - }) + payload.forEach((item) => { + _signedApiCallBucket.push({ req: item, added_At: Date.now() }); + }); if (_signedApiCallBucket.length > SIGNED_API_BUCKET_SIZE) { - await makeBulkSignedApiRequest(_signedApiCallBucket.map(a => a.req), callback); - return - } - else if (!_signedApiCallBucketTimer){ + await makeBulkSignedApiRequest( + _signedApiCallBucket.map((a) => a.req), + callback + ); + return; + } else if (!_signedApiCallBucketTimer) { _signedApiCallBucketTimer = setTimeout(async () => { - await makeBulkSignedApiRequest(_signedApiCallBucket.map(a => a.req), callback); - }, SIGNED_API_BUCKET_TIMEOUT) + await makeBulkSignedApiRequest( + _signedApiCallBucket.map((a) => a.req), + callback + ); + }, SIGNED_API_BUCKET_TIMEOUT); } } -async function makeBulkSignedApiRequest(payload: ISignedRequestItem[], callback: any){ +async function makeBulkSignedApiRequest(payload: ISignedRequestItem[], callback: any) { const url = getApiUrl(ApiKeys.GET_SIGNED_URL); - _signedApiCallBucket=[]; + _signedApiCallBucket = []; await axiosInstance .post(url, payload, { headers: { donotHandleError: true, }, }) - .then(response => { - callback(response?.data) + .then((response) => { + callback(response?.data); }) - .catch(err => { + .catch((err) => { logError(err); - callback() + callback(); }); clearTimeout(_signedApiCallBucketTimer); _signedApiCallBucketTimer = 0; } - diff --git a/src/action/feedbackActions.ts b/src/action/feedbackActions.ts index d58ea808..c7a721b4 100644 --- a/src/action/feedbackActions.ts +++ b/src/action/feedbackActions.ts @@ -1,31 +1,26 @@ -import axiosInstance, { - ApiKeys, - getApiUrl, -} from '../components/utlis/apiHelper'; +import axiosInstance, { ApiKeys, getApiUrl } from '../components/utlis/apiHelper'; import { logError } from '../components/utlis/errorUtils'; interface IPastFeedbacks { - loan_account_number: string, - page_no: number, - page_size: number, - customerRecahble: boolean, + loan_account_number: string; + page_no: number; + page_size: number; + customerRecahble: boolean; } -export const getPastFeedbacks = - (queryParamsPayload: IPastFeedbacks) => { - const url = getApiUrl(ApiKeys.PAST_FEEDBACK); - return axiosInstance - .get(url, { - params: queryParamsPayload - }) - .then(response => { - if (response?.data?.data?.length) { - return response.data.data; - } - throw response; - }) - .catch(err => { - logError(err); - }) - }; - +export const getPastFeedbacks = (queryParamsPayload: IPastFeedbacks) => { + const url = getApiUrl(ApiKeys.PAST_FEEDBACK); + return axiosInstance + .get(url, { + params: queryParamsPayload, + }) + .then((response) => { + if (response?.data?.data?.length) { + return response.data.data; + } + throw response; + }) + .catch((err) => { + logError(err); + }); +}; diff --git a/src/action/index.ts b/src/action/index.ts index 3ecfa9bf..b0f3aa70 100644 --- a/src/action/index.ts +++ b/src/action/index.ts @@ -3,9 +3,9 @@ export const ADD_TODO = 'ADD_TODO'; let todoId = 0; export const addTodo = (task: any) => ({ - type: ADD_TODO, - payload: { - id: ++todoId, - task, - }, + type: ADD_TODO, + payload: { + id: ++todoId, + task, + }, }); diff --git a/src/action/notificationActions.ts b/src/action/notificationActions.ts index 0a5276e1..23d5d4e8 100644 --- a/src/action/notificationActions.ts +++ b/src/action/notificationActions.ts @@ -1,90 +1,79 @@ -import axiosInstance, { - ApiKeys, - getApiUrl, -} from '../components/utlis/apiHelper'; +import axiosInstance, { ApiKeys, getApiUrl } from '../components/utlis/apiHelper'; import { - INotificationAction, - addActionToNotifications, - appendMoreNotifications, - setNotifications, - setNotificationsLoading, + INotificationAction, + addActionToNotifications, + appendMoreNotifications, + setNotifications, + setNotificationsLoading, } from '../reducer/notificationsSlice'; import { INotification } from '../screens/notifications/NotificationItem'; import { AppDispatch } from '../store/store'; interface INotificationPayload { - pageNo: number; - pageSize: number; + pageNo: number; + pageSize: number; } export const hasNotCompletedAction = (notification: INotification) => { - if (!notification.actions) { - return true; - } - return !Object.keys(notification.actions)?.length; + if (!notification.actions) { + return true; + } + return !Object.keys(notification.actions)?.length; }; export const getNotifications = - (payload: INotificationPayload = { pageNo: 1, pageSize: 10 }) => - (dispatch: AppDispatch) => { - dispatch(setNotificationsLoading(true)); - let currentDate = new Date(); - const yesterday = new Date(currentDate); - yesterday.setDate(yesterday.getDate() - 1); - yesterday.setHours(0, 0, 0, 0); - const startTime = yesterday.getTime(); - const url = getApiUrl( - ApiKeys.NOTIFICATIONS, - {}, - { ...payload, startTime }, - ); - return axiosInstance - .get(url) - .then(response => { - const notifications = - response?.data?.notificationResponse?.notifications; - const { totalElements, totalPages, totalUnreadElements } = - response?.data; - if (notifications) { - const { pageNo } = payload; - if (pageNo === 1) { - dispatch( - setNotifications({ - notifications, - totalElements, - totalPages, - pageNo: payload.pageNo, - totalUnreadElements, - }), - ); - return; - } - dispatch( - appendMoreNotifications({ - notifications, - totalElements, - totalPages, - pageNo: payload.pageNo, - totalUnreadElements, - }), - ); - } + (payload: INotificationPayload = { pageNo: 1, pageSize: 10 }) => + (dispatch: AppDispatch) => { + dispatch(setNotificationsLoading(true)); + let currentDate = new Date(); + const yesterday = new Date(currentDate); + yesterday.setDate(yesterday.getDate() - 1); + yesterday.setHours(0, 0, 0, 0); + const startTime = yesterday.getTime(); + const url = getApiUrl(ApiKeys.NOTIFICATIONS, {}, { ...payload, startTime }); + return axiosInstance + .get(url) + .then((response) => { + const notifications = response?.data?.notificationResponse?.notifications; + const { totalElements, totalPages, totalUnreadElements } = response?.data; + if (notifications) { + const { pageNo } = payload; + if (pageNo === 1) { + dispatch( + setNotifications({ + notifications, + totalElements, + totalPages, + pageNo: payload.pageNo, + totalUnreadElements, + }) + ); + return; + } + dispatch( + appendMoreNotifications({ + notifications, + totalElements, + totalPages, + pageNo: payload.pageNo, + totalUnreadElements, }) - .finally(() => dispatch(setNotificationsLoading(false))); - }; + ); + } + }) + .finally(() => dispatch(setNotificationsLoading(false))); + }; -export const notificationAction = - (payload: INotificationAction[]) => (dispatch: AppDispatch) => { - const url = getApiUrl(ApiKeys.NOTIFICATION_ACTION); - return axiosInstance.post(url, payload).then(() => { - dispatch(addActionToNotifications(payload)); - }); - }; +export const notificationAction = (payload: INotificationAction[]) => (dispatch: AppDispatch) => { + const url = getApiUrl(ApiKeys.NOTIFICATION_ACTION); + return axiosInstance.post(url, payload).then(() => { + dispatch(addActionToNotifications(payload)); + }); +}; -export const notificationDelivered = - (payload: { ids: string[] }) => (dispatch: AppDispatch) => { - const url = getApiUrl(ApiKeys.NOTIFICATION_DELIVERED); - return axiosInstance.post(url, payload).then(res => { - console.log('res:', res); - }); - }; +export const notificationDelivered = (payload: { ids: string[] }) => (dispatch: AppDispatch) => { + const url = getApiUrl(ApiKeys.NOTIFICATION_DELIVERED); + return axiosInstance.post(url, payload).then((res) => { + console.log('res:', res); + }); +}; diff --git a/src/action/paymentActions.ts b/src/action/paymentActions.ts index 4503f45c..863ed1c4 100644 --- a/src/action/paymentActions.ts +++ b/src/action/paymentActions.ts @@ -2,112 +2,113 @@ import { ToastMessages } from '../screens/allCases/constants'; import { ILoanIdToValue } from './../reducer/paymentSlice'; import { setAsyncStorageItem } from './../components/utlis/commonFunctions'; import { Dispatch } from '@reduxjs/toolkit'; -import { - appendLoanIdToValue, - setLoading, - setPaymentLink, -} from '../reducer/paymentSlice'; +import { appendLoanIdToValue, setLoading, setPaymentLink } from '../reducer/paymentSlice'; import axiosInstance, { - ApiKeys, - API_STATUS_CODE, - getApiUrl, - getErrorMessage, + ApiKeys, + API_STATUS_CODE, + getApiUrl, + getErrorMessage, } from '../components/utlis/apiHelper'; import { toast } from '../../RN-UI-LIB/src/components/toast'; import { CLICKSTREAM_EVENT_NAMES } from '../common/Constants'; -import { addClickstreamEvent } from "../services/clickstreamEventService"; +import { addClickstreamEvent } from '../services/clickstreamEventService'; export interface GeneratePaymentPayload { - alternateContactNumber: string; - customAmount: { - amount: number; - currency: string; - }; - customAmountProvided: boolean; - loanAccountNumber: string; - notifyToAlternateContact: boolean; - customerReferenceId: string; + alternateContactNumber: string; + customAmount: { + amount: number; + currency: string; + }; + customAmountProvided: boolean; + loanAccountNumber: string; + notifyToAlternateContact: boolean; + customerReferenceId: string; } export interface IGeneratePaymentLinkApiResponse { - paymentLink: string; - expiresAt: string; - retriesLeft: number; + paymentLink: string; + expiresAt: string; + retriesLeft: number; } export interface ILoanIdValue - extends IGeneratePaymentLinkApiResponse, - Pick< - GeneratePaymentPayload, - 'alternateContactNumber' | 'customAmount' - > {} + extends IGeneratePaymentLinkApiResponse, + Pick {} export const generatePaymentLinkAction = - (payload: GeneratePaymentPayload, loanIdToValue: ILoanIdToValue ) => - (dispatch: Dispatch) => { - const url = getApiUrl(ApiKeys.GENERATE_PAYMENT_LINK); - dispatch(setLoading(true)); - const currentTime = Date.now(); - const { loanAccountNumber } = payload; - const value = loanIdToValue?.[loanAccountNumber]; - // if ( - // value && - // Number(value?.expiresAt) > currentTime && - // value?.alternateContactNumber === payload.alternateContactNumber && - // value?.customAmount.amount === payload.customAmount.amount - // ) { - // dispatch(setPaymentLink(value.paymentLink)); - // dispatch(setLoading(false)); - // return; - // } - axiosInstance - .post(url, payload) - .then(response => { - if (response.status === API_STATUS_CODE.OK) { - const responseData = response?.data; - const {paymentLink, retriesLeft} = responseData; - if (paymentLink) { - dispatch(setPaymentLink(paymentLink)); - const storePayload = { - ...responseData, - customAmount: payload.customAmount, - alternateContactNumber: - payload.alternateContactNumber, - }; - dispatch( - appendLoanIdToValue({ - [loanAccountNumber]: storePayload, - }), - ); - // await setAsyncStorageItem( - // LocalStorageKeys.LOAN_ID_TO_VALUE, - // { - // ...loanIdToValue, - // [loanAccountNumber]: storePayload, - // }, - // ); - toast({ - type: 'success', - text1: `${ToastMessages.PAYMENT_LINK_SUCCESS} ${retriesLeft} tr${retriesLeft>1?'ies':'y'} remaining.`, - }); - } - } - }) - .catch(err => { - addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_SEND_PAYMENT_LINK_FAILED, {amount: payload.customAmount,lan : payload.loanAccountNumber, phoneNumber: payload.alternateContactNumber }) - if(err.response.status === 429) { - addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_SEND_PAYMENT_LINK_FAILED_LIMIT_REACHED, {amount: payload.customAmount,lan : payload.loanAccountNumber, phoneNumber: payload.alternateContactNumber }); - toast({ - type: 'error', - text1: ToastMessages.PAYMENT_LINK_RETRY, - }); - }else { - toast({ - type: 'error', - text1: ToastMessages.PAYMENT_LINK_ERROR, - }); - } - }) - .finally(() => { - dispatch(setLoading(false)); + (payload: GeneratePaymentPayload, loanIdToValue: ILoanIdToValue) => (dispatch: Dispatch) => { + const url = getApiUrl(ApiKeys.GENERATE_PAYMENT_LINK); + dispatch(setLoading(true)); + const currentTime = Date.now(); + const { loanAccountNumber } = payload; + const value = loanIdToValue?.[loanAccountNumber]; + // if ( + // value && + // Number(value?.expiresAt) > currentTime && + // value?.alternateContactNumber === payload.alternateContactNumber && + // value?.customAmount.amount === payload.customAmount.amount + // ) { + // dispatch(setPaymentLink(value.paymentLink)); + // dispatch(setLoading(false)); + // return; + // } + axiosInstance + .post(url, payload) + .then((response) => { + if (response.status === API_STATUS_CODE.OK) { + const responseData = response?.data; + const { paymentLink, retriesLeft } = responseData; + if (paymentLink) { + dispatch(setPaymentLink(paymentLink)); + const storePayload = { + ...responseData, + customAmount: payload.customAmount, + alternateContactNumber: payload.alternateContactNumber, + }; + dispatch( + appendLoanIdToValue({ + [loanAccountNumber]: storePayload, + }) + ); + // await setAsyncStorageItem( + // LocalStorageKeys.LOAN_ID_TO_VALUE, + // { + // ...loanIdToValue, + // [loanAccountNumber]: storePayload, + // }, + // ); + toast({ + type: 'success', + text1: `${ToastMessages.PAYMENT_LINK_SUCCESS} ${retriesLeft} tr${ + retriesLeft > 1 ? 'ies' : 'y' + } remaining.`, }); - }; + } + } + }) + .catch((err) => { + addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_SEND_PAYMENT_LINK_FAILED, { + amount: payload.customAmount, + lan: payload.loanAccountNumber, + phoneNumber: payload.alternateContactNumber, + }); + if (err.response.status === 429) { + addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_SEND_PAYMENT_LINK_FAILED_LIMIT_REACHED, { + amount: payload.customAmount, + lan: payload.loanAccountNumber, + phoneNumber: payload.alternateContactNumber, + }); + toast({ + type: 'error', + text1: ToastMessages.PAYMENT_LINK_RETRY, + }); + } else { + toast({ + type: 'error', + text1: ToastMessages.PAYMENT_LINK_ERROR, + }); + } + }) + .finally(() => { + dispatch(setLoading(false)); + }); + }; diff --git a/src/common/Constants.ts b/src/common/Constants.ts index a3712da3..27fb19ef 100644 --- a/src/common/Constants.ts +++ b/src/common/Constants.ts @@ -1,266 +1,541 @@ import { Permission, PermissionsAndroid } from 'react-native'; -import { ApiKeys, API_URLS } from "../components/utlis/apiHelper"; -import { CaseStatuses } from "../screens/allCases/interface"; +import { ApiKeys, API_URLS } from '../components/utlis/apiHelper'; +import { CaseStatuses } from '../screens/allCases/interface'; export const APP_NAME = 'collections-agent-app'; export enum CONDITIONAL_OPERATORS { - EQUALS = 'EQUALS', - LESS_THAN_EQUAL_TO = 'LESS_THAN_EQUAL_TO', - IN_RANGE = 'IN_RANGE', + EQUALS = 'EQUALS', + LESS_THAN_EQUAL_TO = 'LESS_THAN_EQUAL_TO', + IN_RANGE = 'IN_RANGE', } export enum FILTER_TYPES { - DATE = 'DATE', - STRING = 'STRING', - RANGE = 'RANGE', + DATE = 'DATE', + STRING = 'STRING', + RANGE = 'RANGE', } export enum SELECTION_TYPES { - SINGLE = 'SINGLE', - MULTIPLE = 'MULTIPLE', + SINGLE = 'SINGLE', + MULTIPLE = 'MULTIPLE', } export const RANGE_FILTER_SEPARATOR = '-'; export interface Option { - label: string; - value: any; + label: string; + value: any; } export enum FirestoreUpdateTypes { - ADDED = 'added', - MODIFIED = 'modified', - REMOVED = 'removed', + ADDED = 'added', + MODIFIED = 'modified', + REMOVED = 'removed', } export const ClickstreamAPIToMonitor = { - [API_URLS[ApiKeys.GENERATE_OTP]]: 'AV_LOGIN_SCREEN_SEND_OTP_API', - [API_URLS[ApiKeys.VERIFY_OTP]]: 'AV_OTP_SCREEN_VERIFY_OTP_API', - [API_URLS[ApiKeys.LOGOUT]]: 'AV_PROFILE_PAGE_LOGOUT_API', - [API_URLS[ApiKeys.FEEDBACK]]: 'AV_FORM_SUBMIT_API', - [API_URLS[ApiKeys.PINNED_CASES]]: 'AV_PINNED_CASES_API', - [API_URLS[ApiKeys.FILTERS]]: 'AV_FILTERS_API', - [API_URLS[ApiKeys.JANUS]]: 'AV_JANUS_API', - [API_URLS[ApiKeys.GENERATE_PAYMENT_LINK]]: 'AV_GENERATE_PAYMENT_LINK_API', - [API_URLS[ApiKeys.ADDRESSES_GEOLOCATION]]: 'AV_ADDRESSES_GEOLOCATION_API', - [API_URLS[ApiKeys.NEW_ADDRESS]]: 'AV_NEW_ADDRESS_API', - [API_URLS[ApiKeys.GET_SIGNED_URL]]: 'AV_GET_SIGNED_URL_API', - [API_URLS[ApiKeys.CASE_UNIFIED_DETAILS]]: 'AV_CASE_UNIFIED_DETAILS_API', - [API_URLS[ApiKeys.EMI_SCHEDULES]]: 'AV_EMI_SCHEDULES_API', - [API_URLS[ApiKeys.PAST_FEEDBACK]]: 'AV_PAST_FEEDBACK_API', - [API_URLS[ApiKeys.NOTIFICATIONS]]: 'AV_NOTIFICATIONS_FETCH_API', - [API_URLS[ApiKeys.NOTIFICATION_ACTION]]: 'AV_NOTIFICATIONS_ACTION_API', - [API_URLS[ApiKeys.NOTIFICATION_DELIVERED]]: 'AV_NOTIFICATIONS_DELIVERED_API', - [API_URLS[ApiKeys.GENERATE_PAYMENT_LINK]]: 'AV_SEND_PAYMENT_LINK' + [API_URLS[ApiKeys.GENERATE_OTP]]: 'AV_LOGIN_SCREEN_SEND_OTP_API', + [API_URLS[ApiKeys.VERIFY_OTP]]: 'AV_OTP_SCREEN_VERIFY_OTP_API', + [API_URLS[ApiKeys.LOGOUT]]: 'AV_PROFILE_PAGE_LOGOUT_API', + [API_URLS[ApiKeys.FEEDBACK]]: 'AV_FORM_SUBMIT_API', + [API_URLS[ApiKeys.PINNED_CASES]]: 'AV_PINNED_CASES_API', + [API_URLS[ApiKeys.FILTERS]]: 'AV_FILTERS_API', + [API_URLS[ApiKeys.JANUS]]: 'AV_JANUS_API', + [API_URLS[ApiKeys.GENERATE_PAYMENT_LINK]]: 'AV_GENERATE_PAYMENT_LINK_API', + [API_URLS[ApiKeys.ADDRESSES_GEOLOCATION]]: 'AV_ADDRESSES_GEOLOCATION_API', + [API_URLS[ApiKeys.NEW_ADDRESS]]: 'AV_NEW_ADDRESS_API', + [API_URLS[ApiKeys.GET_SIGNED_URL]]: 'AV_GET_SIGNED_URL_API', + [API_URLS[ApiKeys.CASE_UNIFIED_DETAILS]]: 'AV_CASE_UNIFIED_DETAILS_API', + [API_URLS[ApiKeys.EMI_SCHEDULES]]: 'AV_EMI_SCHEDULES_API', + [API_URLS[ApiKeys.PAST_FEEDBACK]]: 'AV_PAST_FEEDBACK_API', + [API_URLS[ApiKeys.NOTIFICATIONS]]: 'AV_NOTIFICATIONS_FETCH_API', + [API_URLS[ApiKeys.NOTIFICATION_ACTION]]: 'AV_NOTIFICATIONS_ACTION_API', + [API_URLS[ApiKeys.NOTIFICATION_DELIVERED]]: 'AV_NOTIFICATIONS_DELIVERED_API', + [API_URLS[ApiKeys.GENERATE_PAYMENT_LINK]]: 'AV_SEND_PAYMENT_LINK', }; export const CLICKSTREAM_EVENT_NAMES = { - // GENERIC - AV_NATIVE_BACK_PRESSED : {name: 'FA_NATIVE_BACK_PRESSED', description: 'Native back button pressed'}, - AV_NATIVE_HOME_PRESSED : {name: 'FA_NATIVE_HOME_PRESSED', description: 'Native home button pressed'}, - AV_APP_FOREGROUND : {name: 'FA_APP_FOREGROUND', description: 'App has come to foreground'}, - AV_APP_BACKGROUND : {name: 'FA_APP_BACKGROUND', description: 'App went to background'}, - AV_ERROR_PAGE_LOADED : {name: 'ERROR_PAGE_LOADED', description: 'Error page loaded'}, - AV_NETWORK_STATUS_CHANGE: {name: 'FA_NETWORK_STATUS_CHANGE', description: 'Offline/online status change'}, - FA_ADD_TO_VISIT_PLAN_CTA: { name: 'FA_ADD_TO_VISIT_PLAN_CTA', description: 'Cases pinned' }, - FA_REMOVE_FROM_VISIT_PLAN_CTA: { name: 'FA_REMOVE_FROM_VISIT_PLAN_CTA', description: 'Cases unpinned' }, - FA_VISIT_PLAN_UPDATED: { name: 'FA_VISIT_PLAN_UPDATED', description: 'Updated cases pinned' }, + // GENERIC + AV_NATIVE_BACK_PRESSED: { + name: 'FA_NATIVE_BACK_PRESSED', + description: 'Native back button pressed', + }, + AV_NATIVE_HOME_PRESSED: { + name: 'FA_NATIVE_HOME_PRESSED', + description: 'Native home button pressed', + }, + AV_APP_FOREGROUND: { name: 'FA_APP_FOREGROUND', description: 'App has come to foreground' }, + AV_APP_BACKGROUND: { name: 'FA_APP_BACKGROUND', description: 'App went to background' }, + AV_ERROR_PAGE_LOADED: { name: 'ERROR_PAGE_LOADED', description: 'Error page loaded' }, + AV_NETWORK_STATUS_CHANGE: { + name: 'FA_NETWORK_STATUS_CHANGE', + description: 'Offline/online status change', + }, + FA_ADD_TO_VISIT_PLAN_CTA: { name: 'FA_ADD_TO_VISIT_PLAN_CTA', description: 'Cases pinned' }, + FA_REMOVE_FROM_VISIT_PLAN_CTA: { + name: 'FA_REMOVE_FROM_VISIT_PLAN_CTA', + description: 'Cases unpinned', + }, + FA_VISIT_PLAN_UPDATED: { name: 'FA_VISIT_PLAN_UPDATED', description: 'Updated cases pinned' }, - // Login screen - AV_LOGIN_SCREEN_LOAD: {name:'FA_LOGIN_SCREEN_LOAD', description: 'Login page loaded'}, - AV_LOGIN_SCREEN_NUMBER_INPUT: {name:'FA_LOGIN_SCREEN_NUMBER_INPUT', description: 'User entered 10 digits'}, - AV_LOGIN_SCREEN_SEND_OTP_CLICKED: {name:'FA_LOGIN_SCREEN_SEND_OTP_CLICKED', description: 'Send OTP CTA clicked'}, - AV_LOGIN_SCREEN_SEND_OTP_API_SUCCESS: {name:'FA_LOGIN_SCREEN_SEND_OTP_API_SUCCESS', description: 'Send OTP API successful'}, - AV_LOGIN_SCREEN_SEND_OTP_API_FAILED: {name:'FA_LOGIN_SCREEN_SEND_OTP_API_FAILED', description: 'Send OTP API failed'}, + // Login screen + AV_LOGIN_SCREEN_LOAD: { name: 'FA_LOGIN_SCREEN_LOAD', description: 'Login page loaded' }, + AV_LOGIN_SCREEN_NUMBER_INPUT: { + name: 'FA_LOGIN_SCREEN_NUMBER_INPUT', + description: 'User entered 10 digits', + }, + AV_LOGIN_SCREEN_SEND_OTP_CLICKED: { + name: 'FA_LOGIN_SCREEN_SEND_OTP_CLICKED', + description: 'Send OTP CTA clicked', + }, + AV_LOGIN_SCREEN_SEND_OTP_API_SUCCESS: { + name: 'FA_LOGIN_SCREEN_SEND_OTP_API_SUCCESS', + description: 'Send OTP API successful', + }, + AV_LOGIN_SCREEN_SEND_OTP_API_FAILED: { + name: 'FA_LOGIN_SCREEN_SEND_OTP_API_FAILED', + description: 'Send OTP API failed', + }, - // OTP screen - AV_OTP_SCREEN_LOAD: {name:'FA_OTP_SCREEN_LOAD', description: 'OTP screen loaded'}, - AV_OTP_SCREEN_OTP_INPUT: {name:'FA_OTP_SCREEN_OTP_INPUT', description: 'User entered 4 digit OTP'}, - AV_OTP_SCREEN_VERIFY_OTP_CLICKED: {name:'FA_OTP_SCREEN_VERIFY_OTP_CLICKED', description: 'Verify OTP CTA Clicked'}, - AV_OTP_SCREEN_BACK_BUTTON_CLICKED: {name:'FA_OTP_SCREEN_BACK_BUTTON_CLICKED', description: 'OTP Screen back CTA clicked'}, - AV_OTP_SCREEN_VERIFY_OTP_API_SUCCESS: {name:'FA_OTP_SCREEN_VERIFY_OTP_API_SUCCESS', description: 'OTP verify API successful'}, - AV_OTP_SCREEN_VERIFY_OTP_API_FAILED: {name:'FA_OTP_SCREEN_VERIFY_OTP_API_FAILED', description: 'OTP verify API failed'}, + // OTP screen + AV_OTP_SCREEN_LOAD: { name: 'FA_OTP_SCREEN_LOAD', description: 'OTP screen loaded' }, + AV_OTP_SCREEN_OTP_INPUT: { + name: 'FA_OTP_SCREEN_OTP_INPUT', + description: 'User entered 4 digit OTP', + }, + AV_OTP_SCREEN_VERIFY_OTP_CLICKED: { + name: 'FA_OTP_SCREEN_VERIFY_OTP_CLICKED', + description: 'Verify OTP CTA Clicked', + }, + AV_OTP_SCREEN_BACK_BUTTON_CLICKED: { + name: 'FA_OTP_SCREEN_BACK_BUTTON_CLICKED', + description: 'OTP Screen back CTA clicked', + }, + AV_OTP_SCREEN_VERIFY_OTP_API_SUCCESS: { + name: 'FA_OTP_SCREEN_VERIFY_OTP_API_SUCCESS', + description: 'OTP verify API successful', + }, + AV_OTP_SCREEN_VERIFY_OTP_API_FAILED: { + name: 'FA_OTP_SCREEN_VERIFY_OTP_API_FAILED', + description: 'OTP verify API failed', + }, - // Case list - AV_CASE_LIST_LOAD : {name: 'FA_CASE_LIST_LOAD', description: 'Cases list loaded'}, - AV_CASE_LIST_CASE_CLICKED : {name: 'FA_CASE_LIST_CASE_CLICKED', description: 'Case clicked'}, - AV_CASE_LIST_PULLED_TO_REFRESH : {name: 'FA_CASE_LIST_PULLED_TO_REFRESH', description: 'Case list pulled to refresh'}, - AV_CASE_LIST_TODO_ITEM_SELECTED : {name: 'FA_CASE_LIST_TODO_ITEM_SELECTED', description: 'Case list todo item selected'}, - AV_CASE_LIST_TODO_ITEM_UNSELECTED : {name: 'FA_CASE_LIST_TODO_ITEM_UNSELECTED', description: 'Case list todo iten unselected'}, - AV_CASE_LIST_CASE_SELECTED : {name: 'FA_CASE_LIST_CASE_SELECTED', description: 'Other cases selected'}, - AV_CASE_LIST_CASE_UNSELECTED : {name: 'FA_CASE_LIST_CASE_UNSELECTED', description: 'Other cases unselected'}, - AV_CASE_LIST_PROCEED_BUTTON_CLICKED : {name: 'FA_CASE_LIST_PROCEED_BUTTON_CLICKED', description: 'Case list proceed CTA clicked'}, - AV_CASE_LIST_REMOVE_BUTTON_CLICKED : {name: 'FA_CASE_LIST_REMOVE_BUTTON_CLICKED', description: 'Case list remove CTA clicked'}, - AV_CASE_LIST_REMOVE_API_SUCCESS : {name: 'FA_CASE_LIST_REMOVE_API_SUCCESS', description: 'Remove todolist API successful'}, - AV_CASE_LIST_REMOVE_API_FAILED: {name: 'FA_CASE_LIST_REMOVE_API_FAILED', description: 'Remove todolist API failed'}, - AV_CASE_LIST_FILTER_BUTTON_CLICKED : {name: 'FA_CASE_LIST_FILTER_BUTTON_CLICKED', description: 'Case list filter CTA clicked'}, - AV_CASE_LIST_SEARCH_QUERY_CHANGED : {name: 'FA_CASE_LIST_SEARCH_QUERY_CHANGED', description: 'Search filter query changed'}, - AV_CASE_LIST_TAB_CHANGED : {name: 'FA_CASE_LIST_TAB_CHANGED', description: 'Case list tab changed'}, - AV_CASE_LIST_AGENT_PROFILE_CLICKED : {name: 'FA_CASE_LIST_AGENT_PROFILE_CLICKED', description: 'Case list agent profile CTA clicked'}, + // Case list + AV_CASE_LIST_LOAD: { name: 'FA_CASE_LIST_LOAD', description: 'Cases list loaded' }, + AV_CASE_LIST_CASE_CLICKED: { name: 'FA_CASE_LIST_CASE_CLICKED', description: 'Case clicked' }, + AV_CASE_LIST_PULLED_TO_REFRESH: { + name: 'FA_CASE_LIST_PULLED_TO_REFRESH', + description: 'Case list pulled to refresh', + }, + AV_CASE_LIST_TODO_ITEM_SELECTED: { + name: 'FA_CASE_LIST_TODO_ITEM_SELECTED', + description: 'Case list todo item selected', + }, + AV_CASE_LIST_TODO_ITEM_UNSELECTED: { + name: 'FA_CASE_LIST_TODO_ITEM_UNSELECTED', + description: 'Case list todo iten unselected', + }, + AV_CASE_LIST_CASE_SELECTED: { + name: 'FA_CASE_LIST_CASE_SELECTED', + description: 'Other cases selected', + }, + AV_CASE_LIST_CASE_UNSELECTED: { + name: 'FA_CASE_LIST_CASE_UNSELECTED', + description: 'Other cases unselected', + }, + AV_CASE_LIST_PROCEED_BUTTON_CLICKED: { + name: 'FA_CASE_LIST_PROCEED_BUTTON_CLICKED', + description: 'Case list proceed CTA clicked', + }, + AV_CASE_LIST_REMOVE_BUTTON_CLICKED: { + name: 'FA_CASE_LIST_REMOVE_BUTTON_CLICKED', + description: 'Case list remove CTA clicked', + }, + AV_CASE_LIST_REMOVE_API_SUCCESS: { + name: 'FA_CASE_LIST_REMOVE_API_SUCCESS', + description: 'Remove todolist API successful', + }, + AV_CASE_LIST_REMOVE_API_FAILED: { + name: 'FA_CASE_LIST_REMOVE_API_FAILED', + description: 'Remove todolist API failed', + }, + AV_CASE_LIST_FILTER_BUTTON_CLICKED: { + name: 'FA_CASE_LIST_FILTER_BUTTON_CLICKED', + description: 'Case list filter CTA clicked', + }, + AV_CASE_LIST_SEARCH_QUERY_CHANGED: { + name: 'FA_CASE_LIST_SEARCH_QUERY_CHANGED', + description: 'Search filter query changed', + }, + AV_CASE_LIST_TAB_CHANGED: { + name: 'FA_CASE_LIST_TAB_CHANGED', + description: 'Case list tab changed', + }, + AV_CASE_LIST_AGENT_PROFILE_CLICKED: { + name: 'FA_CASE_LIST_AGENT_PROFILE_CLICKED', + description: 'Case list agent profile CTA clicked', + }, - // TODO LIST - AV_TODO_LIST_LOAD : {name: 'FA_TODO_LIST_LOAD', description: 'Todo list confirmation screen loaded'}, - AV_TODO_LIST_CASE_DELETED : {name: 'FA_TODO_LIST_CASE_DELETED', description: 'Todo list case deleted'}, - AV_TODO_LIST_SUBMIT_CLICKED : {name: 'FA_TODO_LIST_SUBMIT_CLICKED', description: 'Submit CTA clicked'}, - AV_TODO_LIST_SUBMIT_SUCCESS : {name: 'FA_TODO_LIST_SUBMIT_SUCCESS', description: 'Todo list submit API successful'}, - AV_TODO_LIST_SUBMIT_FAILED : {name: 'FA_TODO_LIST_SUBMIT_FAILED', description: 'Todo list submit API failed'}, - AV_TODO_LIST_BACK_CLICKED : {name: 'FA_TODO_LIST_BACK_CLICKED', description: 'Back CTA clicked'}, + // TODO LIST + AV_TODO_LIST_LOAD: { + name: 'FA_TODO_LIST_LOAD', + description: 'Todo list confirmation screen loaded', + }, + AV_TODO_LIST_CASE_DELETED: { + name: 'FA_TODO_LIST_CASE_DELETED', + description: 'Todo list case deleted', + }, + AV_TODO_LIST_SUBMIT_CLICKED: { + name: 'FA_TODO_LIST_SUBMIT_CLICKED', + description: 'Submit CTA clicked', + }, + AV_TODO_LIST_SUBMIT_SUCCESS: { + name: 'FA_TODO_LIST_SUBMIT_SUCCESS', + description: 'Todo list submit API successful', + }, + AV_TODO_LIST_SUBMIT_FAILED: { + name: 'FA_TODO_LIST_SUBMIT_FAILED', + description: 'Todo list submit API failed', + }, + AV_TODO_LIST_BACK_CLICKED: { name: 'FA_TODO_LIST_BACK_CLICKED', description: 'Back CTA clicked' }, - //Filters - AV_FILTERS_PAGE_LOAD : {name: 'FA_FILTERS_PAGE_LOAD', description: 'Filters screen loaded'}, - AV_FILTERS_TAB_CLICKED : {name: 'FA_FILTERS_TAB_CLICKED', description: 'Filter tab clicked'}, - AV_FILTERS_OPTIONS_SELECTED : {name: 'FA_FILTERS_OPTIONS_SELECTED', description: 'Filter options selected'}, - AV_FILTERS_CLOSE_CLICKED : {name: 'FA_FILTERS_CLOSE_CLICKED', description: 'Filters close CTA clicked'}, - AV_FILTERS_APPLY_CLICKED : {name: 'FA_FILTERS_APPLY_CLICKED', description: 'Filters apply CTA clicked'}, - AV_FILTERS_CLEAR_CLICKED : {name: 'FA_FILTERS_CLEAR_CLICKED', description: 'Filters clear CTA clicked'}, - AV_FILTERS_OPTION_SEARCH : {name: 'FA_FILTERS_OPTION_SEARCH', description: 'Filters options search query'}, + //Filters + AV_FILTERS_PAGE_LOAD: { name: 'FA_FILTERS_PAGE_LOAD', description: 'Filters screen loaded' }, + AV_FILTERS_TAB_CLICKED: { name: 'FA_FILTERS_TAB_CLICKED', description: 'Filter tab clicked' }, + AV_FILTERS_OPTIONS_SELECTED: { + name: 'FA_FILTERS_OPTIONS_SELECTED', + description: 'Filter options selected', + }, + AV_FILTERS_CLOSE_CLICKED: { + name: 'FA_FILTERS_CLOSE_CLICKED', + description: 'Filters close CTA clicked', + }, + AV_FILTERS_APPLY_CLICKED: { + name: 'FA_FILTERS_APPLY_CLICKED', + description: 'Filters apply CTA clicked', + }, + AV_FILTERS_CLEAR_CLICKED: { + name: 'FA_FILTERS_CLEAR_CLICKED', + description: 'Filters clear CTA clicked', + }, + AV_FILTERS_OPTION_SEARCH: { + name: 'FA_FILTERS_OPTION_SEARCH', + description: 'Filters options search query', + }, - //Case Details - AV_CASE_DETAILS_PAGE_LOADED : {name: 'FA_CASE_DETAILS_PAGE_LOADED', description: 'Case details page loaded'}, - AV_CASE_DETAILS_PULL_TO_REFRESH : {name: 'FA_CASE_DETAILS_PULL_TO_REFRESH', description: 'Case details page pulled to refresh'}, - AV_CASE_DETAILS_CALL_CUSTOMER_CLICKED : {name: 'FA_CASE_DETAILS_CALL_CUSTOMER_CLICKED', description: 'Call customer CTA clicked'}, - AV_CASE_DETAILS_OPEN_MAPS_CLICKED : {name: 'FA_CASE_DETAILS_OPEN_MAPS_CLICKED', description: 'Open map CTA clicked'}, - AV_CASE_DETAILS_ADD_FEEDBACK_CLICKED : {name: 'FA_CASE_DETAILS_ADD_FEEDBACK_CLICKED', description: 'Add feedback CTA clicked'}, + //Case Details + AV_CASE_DETAILS_PAGE_LOADED: { + name: 'FA_CASE_DETAILS_PAGE_LOADED', + description: 'Case details page loaded', + }, + AV_CASE_DETAILS_PULL_TO_REFRESH: { + name: 'FA_CASE_DETAILS_PULL_TO_REFRESH', + description: 'Case details page pulled to refresh', + }, + AV_CASE_DETAILS_CALL_CUSTOMER_CLICKED: { + name: 'FA_CASE_DETAILS_CALL_CUSTOMER_CLICKED', + description: 'Call customer CTA clicked', + }, + AV_CASE_DETAILS_OPEN_MAPS_CLICKED: { + name: 'FA_CASE_DETAILS_OPEN_MAPS_CLICKED', + description: 'Open map CTA clicked', + }, + AV_CASE_DETAILS_ADD_FEEDBACK_CLICKED: { + name: 'FA_CASE_DETAILS_ADD_FEEDBACK_CLICKED', + description: 'Add feedback CTA clicked', + }, - //CALLING BOTTOM SHEET - AV_CALLING_BOTTOMSHEET_LOADED : {name: 'FA_CALLING_BOTTOMSHEET_LOADED', description: 'Calling bottomsheet loaded'}, - AV_CALLING_BOTTOMSHEET_CLOSE_CLICKED : {name: 'FA_CALLING_BOTTOMSHEET_CLOSE_CLICKED' , description: 'Close bottomsheet CTA clicked'}, - AV_CALLING_BOTTOMSHEET_CALL_VIA_PHONE_CLICKED : {name: 'FA_CALLING_BOTTOMSHEET_CALL_VIA_PHONE_CLICKED', description: 'Call via phone CTA clicked'}, - AV_CALLING_BOTTOMSHEET_CALL_VIA_WHATSAPP_CLICKED : {name: 'FA_CALLING_BOTTOMSHEET_CALL_VIA_WHATSAPP_CLICKED', description: 'Call via whatsapp CTA clicked'}, - AV_CALLING_BOTTOMSHEET_BEFORE_INTENT_EVENT : {name: 'FA_CALLING_BOTTOMSHEET_BEFORE_INTENT_EVENT' , description: 'Call bottomsheet before intent event'}, + //CALLING BOTTOM SHEET + AV_CALLING_BOTTOMSHEET_LOADED: { + name: 'FA_CALLING_BOTTOMSHEET_LOADED', + description: 'Calling bottomsheet loaded', + }, + AV_CALLING_BOTTOMSHEET_CLOSE_CLICKED: { + name: 'FA_CALLING_BOTTOMSHEET_CLOSE_CLICKED', + description: 'Close bottomsheet CTA clicked', + }, + AV_CALLING_BOTTOMSHEET_CALL_VIA_PHONE_CLICKED: { + name: 'FA_CALLING_BOTTOMSHEET_CALL_VIA_PHONE_CLICKED', + description: 'Call via phone CTA clicked', + }, + AV_CALLING_BOTTOMSHEET_CALL_VIA_WHATSAPP_CLICKED: { + name: 'FA_CALLING_BOTTOMSHEET_CALL_VIA_WHATSAPP_CLICKED', + description: 'Call via whatsapp CTA clicked', + }, + AV_CALLING_BOTTOMSHEET_BEFORE_INTENT_EVENT: { + name: 'FA_CALLING_BOTTOMSHEET_BEFORE_INTENT_EVENT', + description: 'Call bottomsheet before intent event', + }, - //PROFILE PAGE - AV_PROFILE_PAGE_LOADED : {name: 'FA_PROFILE_PAGE_LOADED', description: 'Profile page loaded'}, - AV_PROFILE_PAGE_LOGOUT_BUTTON_CLICKED : {name: 'FA_PROFILE_PAGE_LOGOUT_BUTTON_CLICKED', description: 'Logout CTA clicked'}, - AV_PROFILE_PAGE_LOGOUT_CONFIRMATION_OPEN : {name: 'FA_PROFILE_PAGE_LOGOUT_CONFIRMATION_OPEN', description: 'Logout confirmation dialog open'}, - AV_PROFILE_PAGE_LOGOUT_CONFIRMATION_CLOSED : {name: 'FA_PROFILE_PAGE_LOGOUT_CONFIRMATION_CLOSED', description: 'Logout confirmation dialog closed'}, - AV_PROFILE_PAGE_LOGOUT_CONFIRMATION_CLICKED : {name: 'FA_PROFILE_PAGE_LOGOUT_CONFIRMATION_CLICKED', description: 'Logout confirmation clicked'}, - AV_PROFILE_PAGE_LOGOUT_API_SUCCESS : {name: 'FA_PROFILE_PAGE_LOGOUT_API_SUCCESS', description: 'Logout API successful'}, - AV_PROFILE_PAGE_LOGOUT_API_FAILED : {name: 'FA_PROFILE_PAGE_LOGOUT_API_FAILED', description: 'Logout API failed'}, + //PROFILE PAGE + AV_PROFILE_PAGE_LOADED: { name: 'FA_PROFILE_PAGE_LOADED', description: 'Profile page loaded' }, + AV_PROFILE_PAGE_LOGOUT_BUTTON_CLICKED: { + name: 'FA_PROFILE_PAGE_LOGOUT_BUTTON_CLICKED', + description: 'Logout CTA clicked', + }, + AV_PROFILE_PAGE_LOGOUT_CONFIRMATION_OPEN: { + name: 'FA_PROFILE_PAGE_LOGOUT_CONFIRMATION_OPEN', + description: 'Logout confirmation dialog open', + }, + AV_PROFILE_PAGE_LOGOUT_CONFIRMATION_CLOSED: { + name: 'FA_PROFILE_PAGE_LOGOUT_CONFIRMATION_CLOSED', + description: 'Logout confirmation dialog closed', + }, + AV_PROFILE_PAGE_LOGOUT_CONFIRMATION_CLICKED: { + name: 'FA_PROFILE_PAGE_LOGOUT_CONFIRMATION_CLICKED', + description: 'Logout confirmation clicked', + }, + AV_PROFILE_PAGE_LOGOUT_API_SUCCESS: { + name: 'FA_PROFILE_PAGE_LOGOUT_API_SUCCESS', + description: 'Logout API successful', + }, + AV_PROFILE_PAGE_LOGOUT_API_FAILED: { + name: 'FA_PROFILE_PAGE_LOGOUT_API_FAILED', + description: 'Logout API failed', + }, - //FORMS - AV_FORM_LOADED : {name: 'FA_FORM_LOADED', description: 'Form loaded'}, - AV_FORM_CLOSE_CLICKED : {name: 'FA_FORM_CLOSE_CLICKED', description: 'Form close CTA clicked'}, - AV_FORM_ELEMENT_CHANGED : {name: 'FA_FORM_ELEMENT_CHANGED', description: 'Form element answer changed'}, - AV_FORM_NEXT_BUTTON_CLICKED : {name: 'FA_FORM_NEXT_BUTTON_CLICKED', description: 'Form next CTA clicked'}, - AV_FORM_BACK_BUTTON_CLICKED : {name: 'FA_FORM_BACK_BUTTON_CLICKED', description: 'Form back CTA clicked'}, - AV_FORM_SUMMARY_PAGE_LOADED : {name: 'FA_FORM_SUMMARY_PAGE_LOADED', description: 'Form summary page loaded'}, - AV_FORM_SUBMIT_BUTTON_CLICKED : {name: 'FA_FORM_SUBMIT_BUTTON_CLICKED', description: 'Form submit journey CTA clicked'}, - AV_FORM_SUBMIT_API_SUCCESS : {name: 'FA_FORM_SUBMIT_API_SUCCESS', description: 'Form submit API successful'}, - AV_FORM_SUBMIT_API_FAILED : {name: 'FA_FORM_SUBMIT_API_FAILED', description: 'Form submit API failed'}, + //FORMS + AV_FORM_LOADED: { name: 'FA_FORM_LOADED', description: 'Form loaded' }, + AV_FORM_CLOSE_CLICKED: { name: 'FA_FORM_CLOSE_CLICKED', description: 'Form close CTA clicked' }, + AV_FORM_ELEMENT_CHANGED: { + name: 'FA_FORM_ELEMENT_CHANGED', + description: 'Form element answer changed', + }, + AV_FORM_NEXT_BUTTON_CLICKED: { + name: 'FA_FORM_NEXT_BUTTON_CLICKED', + description: 'Form next CTA clicked', + }, + AV_FORM_BACK_BUTTON_CLICKED: { + name: 'FA_FORM_BACK_BUTTON_CLICKED', + description: 'Form back CTA clicked', + }, + AV_FORM_SUMMARY_PAGE_LOADED: { + name: 'FA_FORM_SUMMARY_PAGE_LOADED', + description: 'Form summary page loaded', + }, + AV_FORM_SUBMIT_BUTTON_CLICKED: { + name: 'FA_FORM_SUBMIT_BUTTON_CLICKED', + description: 'Form submit journey CTA clicked', + }, + AV_FORM_SUBMIT_API_SUCCESS: { + name: 'FA_FORM_SUBMIT_API_SUCCESS', + description: 'Form submit API successful', + }, + AV_FORM_SUBMIT_API_FAILED: { + name: 'FA_FORM_SUBMIT_API_FAILED', + description: 'Form submit API failed', + }, - // COLLECTIONS - ADDRESSES_CLICKED: {name: 'ADDRESSES_CLICKED', description: 'ADDRESSES_CLICKED'}, - ADDRESSES_FAILED : {name: 'ADDRESSES_FAILED', description: 'ADDRESSES_FAILED'}, - FA_CASE_DETAILS_INDIVIDUAL_FEEDBACK_CLICKED : {name: 'FA_CASE_DETAILS_INDIVIDUAL_FEEDBACK_CLICKED', description: 'FA_CASE_DETAILS_INDIVIDUAL_FEEDBACK_CLICKED'}, - FA_CASE_DETAILS_INDIVIDUAL_FEEDBACK_FAILED : {name: 'FA_CASE_DETAILS_INDIVIDUAL_FEEDBACK_FAILED', description: 'FA_CASE_DETAILS_INDIVIDUAL_FEEDBACK_FAILED'}, - FA_COLLECT_MONEY_CLICKED : {name: 'FA_COLLECT_MONEY_CLICKED', description: 'FA_COLLECT_MONEY_CLICKED'}, - FA_COLLECT_MONEY_FAILED : {name: 'FA_COLLECT_MONEY_FAILED', description: 'FA_COLLECT_MONEY_FAILED'}, - FA_COLLECT_MONEY_NUMBER_CHANGED: {name: 'FA_COLLECT_MONEY_NUMBER_CHANGED', description: 'FA_COLLECT_MONEY_NUMBER_CHANGED'}, - FA_COPY_LAN_CLICKED : {name: 'FA_COPY_LAN_CLICKED', description: 'FA_COPY_LAN_CLICKED'}, - FA_COPY_LINK_CLICKED: {name: 'FA_COPY_LINK_CLICKED', description: 'FA_COPY_LINK_CLICKED'}, - FA_COPY_LINK_FAILED: {name: 'FA_COPY_LINK_FAILED', description: 'FA_COPY_LINK_FAILED'}, - FA_PAST_FEEDBACKS_FEEDBACK_CLICKED: {name: 'FA_PAST_FEEDBACKS_FEEDBACK_CLICKED', description: 'FA_PAST_FEEDBACKS_FEEDBACK_CLICKED'}, - FA_PAST_FEEDBACKS_FEEDBACK_FAILED : {name: 'FA_PAST_FEEDBACKS_FEEDBACK_FAILED', description: 'FA_PAST_FEEDBACKS_FEEDBACK_FAILED'}, - FA_SEND_PAYMENT_LINK: {name: 'FA_SEND_PAYMENT_LINK', description: 'FA_SEND_PAYMENT_LINK'}, - FA_SEND_PAYMENT_LINK_FAILED: {name: 'FA_SEND_PAYMENT_LINK_FAILED', description: 'FA_SEND_PAYMENT_LINK_FAILED'}, - FA_SEND_PAYMENT_LINK_FAILED_LIMIT_REACHED: {name: 'FA_SEND_PAYMENT_LINK_FAILED_LIMIT_REACHED', description: 'FA_SEND_PAYMENT_LINK_FAILED_LIMIT_REACHED'}, - FA_TOTAL_OUTSTANDING_BREAKUP_CLICKED: {name: 'FA_TOTAL_OUTSTANDING_BREAKUP_CLICKED', description: 'FA_TOTAL_OUTSTANDING_BREAKUP_CLICKED'}, - FA_VIEW_ADDRESSES_CLICKED: {name: 'FA_VIEW_ADDRESSES_CLICKED', description: 'FA_VIEW_ADDRESSES_CLICKED'}, - FA_VIEW_ADDRESSES_FAILED: {name: 'FA_VIEW_ADDRESSES_FAILED', description: 'FA_VIEW_ADDRESSES_FAILED'}, - FA_VIEW_EMI_SCHEDULE_CLICKED: {name: 'FA_VIEW_EMI_SCHEDULE_CLICKED', description: 'FA_VIEW_EMI_SCHEDULE_CLICKED'}, - FA_VIEW_EMI_SCHEDULE_FAILED: {name: 'FA_VIEW_EMI_SCHEDULE_FAILED', description: 'FA_VIEW_EMI_SCHEDULE_FAILED'}, - FA_VIEW_MAP_GEO_CLICKED: {name: 'FA_VIEW_MAP_GEO_CLICKED', description: 'FA_VIEW_MAP_GEO_CLICKED'}, - FA_VIEW_MORE: {name: 'FA_VIEW_MORE', description: 'FA_VIEW_MORE'}, - FA_VIEW_PAST_FEEDBACKS_CLICKED: {name: 'FA_VIEW_PAST_FEEDBACKS_CLICKED', description: 'FA_VIEW_PAST_FEEDBACKS_CLICKED'}, - FA_VIEW_PAST_FEEDBACKS_FAILED: {name: 'FA_VIEW_PAST_FEEDBACKS_FAILED', description: 'FA_VIEW_PAST_FEEDBACKS_FAILED'}, - FA_VIEW_PAST_FEEDBACK_NEXT_PAGE_CLICKED: {name: 'FA_VIEW_PAST_FEEDBACK_NEXT_PAGE_CLICKED', description: 'FA_VIEW_PAST_FEEDBACK_NEXT_PAGE_CLICKED'}, - FA_VIEW_PAST_FEEDBACK_PREV_PAGE_CLICKED: {name: 'FA_VIEW_PAST_FEEDBACK_PREV_PAGE_CLICKED', description: 'FA_VIEW_PAST_FEEDBACK_PREV_PAGE_CLICKED'}, - FA_VIEW_PAST_FEEDBACK_NAVIGATION_PAGE_FAILED: {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_UNIFIED_ENTITY_REQUESTED: {name: 'FA_UNIFIED_ENTITY_REQUESTED', description: 'FA_UNIFIED_ENTITY_REQUESTED'}, - FA_UNIFIED_ENTITY_REQUEST_SUCCESS: {name: 'FA_UNIFIED_ENTITY_REQUEST_SUCCESS', description: 'FA_UNIFIED_ENTITY_REQUEST_SUCCESS'}, - FA_UNIFIED_ENTITY_REQUEST_FAILED: {name: 'FA_UNIFIED_ENTITY_REQUEST_FAILED', description: 'FA_UNIFIED_ENTITY_REQUEST_FAILED'}, + // COLLECTIONS + ADDRESSES_CLICKED: { name: 'ADDRESSES_CLICKED', description: 'ADDRESSES_CLICKED' }, + ADDRESSES_FAILED: { name: 'ADDRESSES_FAILED', description: 'ADDRESSES_FAILED' }, + FA_CASE_DETAILS_INDIVIDUAL_FEEDBACK_CLICKED: { + name: 'FA_CASE_DETAILS_INDIVIDUAL_FEEDBACK_CLICKED', + description: 'FA_CASE_DETAILS_INDIVIDUAL_FEEDBACK_CLICKED', + }, + FA_CASE_DETAILS_INDIVIDUAL_FEEDBACK_FAILED: { + name: 'FA_CASE_DETAILS_INDIVIDUAL_FEEDBACK_FAILED', + description: 'FA_CASE_DETAILS_INDIVIDUAL_FEEDBACK_FAILED', + }, + FA_COLLECT_MONEY_CLICKED: { + name: 'FA_COLLECT_MONEY_CLICKED', + description: 'FA_COLLECT_MONEY_CLICKED', + }, + FA_COLLECT_MONEY_FAILED: { + name: 'FA_COLLECT_MONEY_FAILED', + description: 'FA_COLLECT_MONEY_FAILED', + }, + FA_COLLECT_MONEY_NUMBER_CHANGED: { + name: 'FA_COLLECT_MONEY_NUMBER_CHANGED', + description: 'FA_COLLECT_MONEY_NUMBER_CHANGED', + }, + FA_COPY_LAN_CLICKED: { name: 'FA_COPY_LAN_CLICKED', description: 'FA_COPY_LAN_CLICKED' }, + FA_COPY_LINK_CLICKED: { name: 'FA_COPY_LINK_CLICKED', description: 'FA_COPY_LINK_CLICKED' }, + FA_COPY_LINK_FAILED: { name: 'FA_COPY_LINK_FAILED', description: 'FA_COPY_LINK_FAILED' }, + FA_PAST_FEEDBACKS_FEEDBACK_CLICKED: { + name: 'FA_PAST_FEEDBACKS_FEEDBACK_CLICKED', + description: 'FA_PAST_FEEDBACKS_FEEDBACK_CLICKED', + }, + FA_PAST_FEEDBACKS_FEEDBACK_FAILED: { + name: 'FA_PAST_FEEDBACKS_FEEDBACK_FAILED', + description: 'FA_PAST_FEEDBACKS_FEEDBACK_FAILED', + }, + FA_SEND_PAYMENT_LINK: { name: 'FA_SEND_PAYMENT_LINK', description: 'FA_SEND_PAYMENT_LINK' }, + FA_SEND_PAYMENT_LINK_FAILED: { + name: 'FA_SEND_PAYMENT_LINK_FAILED', + description: 'FA_SEND_PAYMENT_LINK_FAILED', + }, + FA_SEND_PAYMENT_LINK_FAILED_LIMIT_REACHED: { + name: 'FA_SEND_PAYMENT_LINK_FAILED_LIMIT_REACHED', + description: 'FA_SEND_PAYMENT_LINK_FAILED_LIMIT_REACHED', + }, + FA_TOTAL_OUTSTANDING_BREAKUP_CLICKED: { + name: 'FA_TOTAL_OUTSTANDING_BREAKUP_CLICKED', + description: 'FA_TOTAL_OUTSTANDING_BREAKUP_CLICKED', + }, + FA_VIEW_ADDRESSES_CLICKED: { + name: 'FA_VIEW_ADDRESSES_CLICKED', + description: 'FA_VIEW_ADDRESSES_CLICKED', + }, + FA_VIEW_ADDRESSES_FAILED: { + name: 'FA_VIEW_ADDRESSES_FAILED', + description: 'FA_VIEW_ADDRESSES_FAILED', + }, + FA_VIEW_EMI_SCHEDULE_CLICKED: { + name: 'FA_VIEW_EMI_SCHEDULE_CLICKED', + description: 'FA_VIEW_EMI_SCHEDULE_CLICKED', + }, + FA_VIEW_EMI_SCHEDULE_FAILED: { + name: 'FA_VIEW_EMI_SCHEDULE_FAILED', + description: 'FA_VIEW_EMI_SCHEDULE_FAILED', + }, + FA_VIEW_MAP_GEO_CLICKED: { + name: 'FA_VIEW_MAP_GEO_CLICKED', + description: 'FA_VIEW_MAP_GEO_CLICKED', + }, + FA_VIEW_MORE: { name: 'FA_VIEW_MORE', description: 'FA_VIEW_MORE' }, + FA_VIEW_PAST_FEEDBACKS_CLICKED: { + name: 'FA_VIEW_PAST_FEEDBACKS_CLICKED', + description: 'FA_VIEW_PAST_FEEDBACKS_CLICKED', + }, + FA_VIEW_PAST_FEEDBACKS_FAILED: { + name: 'FA_VIEW_PAST_FEEDBACKS_FAILED', + description: 'FA_VIEW_PAST_FEEDBACKS_FAILED', + }, + FA_VIEW_PAST_FEEDBACK_NEXT_PAGE_CLICKED: { + name: 'FA_VIEW_PAST_FEEDBACK_NEXT_PAGE_CLICKED', + description: 'FA_VIEW_PAST_FEEDBACK_NEXT_PAGE_CLICKED', + }, + FA_VIEW_PAST_FEEDBACK_PREV_PAGE_CLICKED: { + name: 'FA_VIEW_PAST_FEEDBACK_PREV_PAGE_CLICKED', + description: 'FA_VIEW_PAST_FEEDBACK_PREV_PAGE_CLICKED', + }, + FA_VIEW_PAST_FEEDBACK_NAVIGATION_PAGE_FAILED: { + 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_UNIFIED_ENTITY_REQUESTED: { + name: 'FA_UNIFIED_ENTITY_REQUESTED', + description: 'FA_UNIFIED_ENTITY_REQUESTED', + }, + FA_UNIFIED_ENTITY_REQUEST_SUCCESS: { + name: 'FA_UNIFIED_ENTITY_REQUEST_SUCCESS', + description: 'FA_UNIFIED_ENTITY_REQUEST_SUCCESS', + }, + FA_UNIFIED_ENTITY_REQUEST_FAILED: { + name: 'FA_UNIFIED_ENTITY_REQUEST_FAILED', + description: 'FA_UNIFIED_ENTITY_REQUEST_FAILED', + }, - // Notifications - FA_NOTIFICATION_ICON_CLICK: {name: 'FA_NOTIFICATION_ICON_CLICK', description: 'FA_NOTIFICATION_ICON_CLICK'}, - FA_NOTIFICATION_ITEM_CLICK: {name: 'FA_NOTIFICATION_ITEM_CLICK', description: 'FA_NOTIFICATION_ITEM_CLICK'}, - AV_NOTIFICATIONS_FETCH_API_SUCCESS : {name: 'FA_NOTIFICATIONS_FETCH_API_SUCCESS', description: 'FA_NOTIFICATIONS_FETCH_API_SUCCESS'}, - AV_NOTIFICATIONS_FETCH_API_FAILED : {name: 'FA_NOTIFICATIONS_FETCH_API_FAILED', description: 'FA_NOTIFICATIONS_FETCH_API_FAILED'}, - AV_NOTIFICATION_ACTION_API_SUCCESS : {name: 'FA_NOTIFICATION_ACTION_API_SUCCESS', description: 'FA_NOTIFICATION_ACTION_API_SUCCESS'}, - AV_NOTIFICATION_ACTION_API_FAILED : {name: 'FA_NOTIFICATION_ACTION_API_FAILED', description: 'FA_NOTIFICATION_ACTION_API_FAILED'}, - AV_NOTIFICATION_DELIVERED_API_SUCCESS : {name: 'FA_NOTIFICATION_DELIVERED_API_SUCCESS', description: 'FA_NOTIFICATION_DELIVERED_API_SUCCESS'}, - AV_NOTIFICATION_DELIVERED_API_FAILED : {name: 'FA_NOTIFICATION_DELIVERED_API_FAILED', description: 'FA_NOTIFICATION_DELIVERED_API_FAILED'}, + // Notifications + FA_NOTIFICATION_ICON_CLICK: { + name: 'FA_NOTIFICATION_ICON_CLICK', + description: 'FA_NOTIFICATION_ICON_CLICK', + }, + FA_NOTIFICATION_ITEM_CLICK: { + name: 'FA_NOTIFICATION_ITEM_CLICK', + description: 'FA_NOTIFICATION_ITEM_CLICK', + }, + AV_NOTIFICATIONS_FETCH_API_SUCCESS: { + name: 'FA_NOTIFICATIONS_FETCH_API_SUCCESS', + description: 'FA_NOTIFICATIONS_FETCH_API_SUCCESS', + }, + AV_NOTIFICATIONS_FETCH_API_FAILED: { + name: 'FA_NOTIFICATIONS_FETCH_API_FAILED', + description: 'FA_NOTIFICATIONS_FETCH_API_FAILED', + }, + AV_NOTIFICATION_ACTION_API_SUCCESS: { + name: 'FA_NOTIFICATION_ACTION_API_SUCCESS', + description: 'FA_NOTIFICATION_ACTION_API_SUCCESS', + }, + AV_NOTIFICATION_ACTION_API_FAILED: { + name: 'FA_NOTIFICATION_ACTION_API_FAILED', + description: 'FA_NOTIFICATION_ACTION_API_FAILED', + }, + AV_NOTIFICATION_DELIVERED_API_SUCCESS: { + name: 'FA_NOTIFICATION_DELIVERED_API_SUCCESS', + description: 'FA_NOTIFICATION_DELIVERED_API_SUCCESS', + }, + AV_NOTIFICATION_DELIVERED_API_FAILED: { + name: 'FA_NOTIFICATION_DELIVERED_API_FAILED', + description: 'FA_NOTIFICATION_DELIVERED_API_FAILED', + }, } as const; export enum MimeType { - 'image/jpeg' = 'image/jpeg', - 'image/png' = 'image/png' + 'image/jpeg' = 'image/jpeg', + 'image/png' = 'image/png', } -export const ClosedCaseStatusList = [CaseStatuses.CLOSED, CaseStatuses.FORCE_CLOSED, CaseStatuses.EXPIRED]; +export const ClosedCaseStatusList = [ + CaseStatuses.CLOSED, + CaseStatuses.FORCE_CLOSED, + CaseStatuses.EXPIRED, +]; export const getPrefixBase64Image = (contentType: MimeType) => { - return `data:${contentType};base64,}`; -} + return `data:${contentType};base64,}`; +}; -export const PrefixJpegBase64Image = getPrefixBase64Image(MimeType["image/jpeg"]); +export const PrefixJpegBase64Image = getPrefixBase64Image(MimeType['image/jpeg']); export const HEADER_HEIGHT_MAX = 132; export const HEADER_HEIGHT_MIN = 80; -export const HEADER_HEIGHT_MAX_WITH_QUICK_FILTERS = HEADER_HEIGHT_MAX + 50 +export const HEADER_HEIGHT_MAX_WITH_QUICK_FILTERS = HEADER_HEIGHT_MAX + 50; export const HEADER_HEIGHT_MIN_WITH_QUICK_FILTERS = HEADER_HEIGHT_MIN + 50; export const HEADER_SCROLL_DISTANCE = (HEADER_HEIGHT_MAX - HEADER_HEIGHT_MIN) * 2; -export const HEADER_SCROLL_DISTANCE_WITH_QUICK_FILTERS = (HEADER_HEIGHT_MAX_WITH_QUICK_FILTERS - HEADER_HEIGHT_MIN_WITH_QUICK_FILTERS) * 2; +export const HEADER_SCROLL_DISTANCE_WITH_QUICK_FILTERS = + (HEADER_HEIGHT_MAX_WITH_QUICK_FILTERS - HEADER_HEIGHT_MIN_WITH_QUICK_FILTERS) * 2; export const LocalStorageKeys = { - LOAN_ID_TO_VALUE: 'loanIdToValue', - GLOBAL_DOCUMENT_MAP: 'globalDocumentMap', -} + LOAN_ID_TO_VALUE: 'loanIdToValue', + GLOBAL_DOCUMENT_MAP: 'globalDocumentMap', +}; -export const SourceTextFocused = new Set([ - 'Primary Contact', - 'Secondary Contact', -]); +export const SourceTextFocused = new Set(['Primary Contact', 'Secondary Contact']); export enum TemplateRoutePrefix { - 'AV'="av/", - 'CC' = "cc/" + 'AV' = 'av/', + 'CC' = 'cc/', } export const WhatsAppText = ''; export const PermissionsToCheck: Permission[] = [ - PermissionsAndroid.PERMISSIONS.CAMERA, - PermissionsAndroid.PERMISSIONS.READ_CONTACTS, - PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION, - PermissionsAndroid.PERMISSIONS.ACCESS_COARSE_LOCATION, - PermissionsAndroid.PERMISSIONS.READ_EXTERNAL_STORAGE, - PermissionsAndroid.PERMISSIONS.WRITE_EXTERNAL_STORAGE, - PermissionsAndroid.PERMISSIONS.READ_SMS, - PermissionsAndroid.PERMISSIONS.READ_CALL_LOG, - PermissionsAndroid.PERMISSIONS.RECORD_AUDIO, - PermissionsAndroid.PERMISSIONS.READ_CALENDAR, - PermissionsAndroid.PERMISSIONS.GET_ACCOUNTS, - PermissionsAndroid.PERMISSIONS.CALL_PHONE, - PermissionsAndroid.PERMISSIONS.READ_PHONE_STATE, - PermissionsAndroid.PERMISSIONS.SEND_SMS, - PermissionsAndroid.PERMISSIONS.RECEIVE_WAP_PUSH, + PermissionsAndroid.PERMISSIONS.CAMERA, + PermissionsAndroid.PERMISSIONS.READ_CONTACTS, + PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION, + PermissionsAndroid.PERMISSIONS.ACCESS_COARSE_LOCATION, + PermissionsAndroid.PERMISSIONS.READ_EXTERNAL_STORAGE, + PermissionsAndroid.PERMISSIONS.WRITE_EXTERNAL_STORAGE, + PermissionsAndroid.PERMISSIONS.READ_SMS, + PermissionsAndroid.PERMISSIONS.READ_CALL_LOG, + PermissionsAndroid.PERMISSIONS.RECORD_AUDIO, + PermissionsAndroid.PERMISSIONS.READ_CALENDAR, + PermissionsAndroid.PERMISSIONS.GET_ACCOUNTS, + PermissionsAndroid.PERMISSIONS.CALL_PHONE, + PermissionsAndroid.PERMISSIONS.READ_PHONE_STATE, + PermissionsAndroid.PERMISSIONS.SEND_SMS, + PermissionsAndroid.PERMISSIONS.RECEIVE_WAP_PUSH, ]; export const BLOCKER_SCREEN_DATA = { - UNINSTALL_APP: { - heading: 'Seems like you are using an older app version', - instructions: [ - 'Download the new app by clicking the button at the bottom.', - 'Uninstall this app (Cosmos).', - 'Install the downloaded app.', - ] - }, - TIME_UNSYNC: { - heading: `Your device's time seems to out of sync`, - instructions: ['Go to settings by clicking the button below.', 'Check the date settings for the device.'] - } + UNINSTALL_APP: { + heading: 'Seems like you are using an older app version', + instructions: [ + 'Download the new app by clicking the button at the bottom.', + 'Uninstall this app (Cosmos).', + 'Install the downloaded app.', + ], + }, + TIME_UNSYNC: { + heading: `Your device's time seems to out of sync`, + instructions: [ + 'Go to settings by clicking the button below.', + 'Check the date settings for the device.', + ], + }, }; -export const SCREEN_ANIMATION_DURATION = 300; \ No newline at end of file +export const SCREEN_ANIMATION_DURATION = 300; diff --git a/src/components/form/interface.ts b/src/components/form/interface.ts index c8f32016..e2028679 100644 --- a/src/components/form/interface.ts +++ b/src/components/form/interface.ts @@ -1,19 +1,17 @@ - - export enum AnswerType { - text = 'text', - option = 'option', - number = 'number', - array = 'array', - image = 'image', - 'address' = 'address', - 'phoneNumber' = 'phoneNumber', - 'date' = 'date' + text = 'text', + option = 'option', + number = 'number', + array = 'array', + image = 'image', + 'address' = 'address', + 'phoneNumber' = 'phoneNumber', + 'date' = 'date', } // @deprecated export interface Options { - text: string; - associatedQuestions: Array; - metadata: any; + text: string; + associatedQuestions: Array; + metadata: any; } diff --git a/src/components/form/services/conditionEvaluation.service.ts b/src/components/form/services/conditionEvaluation.service.ts index 9a3767b9..421c1cb6 100644 --- a/src/components/form/services/conditionEvaluation.service.ts +++ b/src/components/form/services/conditionEvaluation.service.ts @@ -1,33 +1,34 @@ -import { Condition } from "../../../types/template.types"; +import { Condition } from '../../../types/template.types'; import { CompositeCondition, CompositeOperator, ConditionTypes, LeafCondition, - LeafOperator -} from "../../../types/conditional.types"; + LeafOperator, +} from '../../../types/conditional.types'; // TODO : technically widgetId should also be inside context, will do it when time allows. export function evaluateCondition(condition: Condition, context: any): boolean { if (condition.conditionType === ConditionTypes.LEAF) { - return evaluateLeaf(condition as unknown as LeafCondition, context ) - } else return evaluateComposite(condition as unknown as CompositeCondition, context) + return evaluateLeaf(condition as unknown as LeafCondition, context); + } else return evaluateComposite(condition as unknown as CompositeCondition, context); } -function evaluateLeaf (leaf: LeafCondition, context: any):boolean { +function evaluateLeaf(leaf: LeafCondition, context: any): boolean { switch (leaf.operator) { case LeafOperator.VALUE_EQUAL_TO: return ( leaf.right === - context?.widgetContext?.[leaf.widgetId]?.sectionContext?.[leaf.section] - ?.questionContext?.[leaf.left]?.answer + context?.widgetContext?.[leaf.widgetId]?.sectionContext?.[leaf.section]?.questionContext?.[ + leaf.left + ]?.answer ); default: return false; } -}; +} -function evaluateComposite (composite: CompositeCondition, data: any): boolean { +function evaluateComposite(composite: CompositeCondition, data: any): boolean { console.log('jj evaluateComposite', composite, data); let left = false, @@ -44,12 +45,12 @@ function evaluateComposite (composite: CompositeCondition, data: any): boolean { } switch (composite.operator) { - case CompositeOperator.AND : - return left && right + case CompositeOperator.AND: + return left && right; break; case CompositeOperator.OR: - return left || right - default : - return false + return left || right; + default: + return false; } -}; +} diff --git a/src/components/form/services/forms.service.ts b/src/components/form/services/forms.service.ts index 5f3efcd3..91ec3386 100644 --- a/src/components/form/services/forms.service.ts +++ b/src/components/form/services/forms.service.ts @@ -1,24 +1,34 @@ -import { evaluateCondition } from "./conditionEvaluation.service"; -import { Action, ActionType, ConditionAction } from "../../../types/template.types"; +import { evaluateCondition } from './conditionEvaluation.service'; +import { Action, ActionType, ConditionAction } from '../../../types/template.types'; export const getNextWidget = (conditionActions: ConditionAction[], context: any): string => { let nextScreenName = ''; for (const conditionAction of conditionActions) { - if (conditionAction.isDefault || (conditionAction.condition && evaluateCondition(conditionAction.condition, context))) { - nextScreenName = conditionAction.actions.find(action => action.type === ActionType.WIDGET_TRANSITION)?.nextWidget + if ( + conditionAction.isDefault || + (conditionAction.condition && evaluateCondition(conditionAction.condition, context)) + ) { + nextScreenName = conditionAction.actions.find( + (action) => action.type === ActionType.WIDGET_TRANSITION + )?.nextWidget; break; } } - return nextScreenName -} + return nextScreenName; +}; export function getNextJourneyActions(conditionActions: ConditionAction[], context: any): Action { let nextActions: Action = {} as Action; for (const conditionAction of conditionActions) { - if (conditionAction.isDefault || (conditionAction.condition && evaluateCondition(conditionAction.condition, context))) { - nextActions = conditionAction.actions.find(action => action.type === ActionType.JOURNEY_TRANSITION) || {} as Action + if ( + conditionAction.isDefault || + (conditionAction.condition && evaluateCondition(conditionAction.condition, context)) + ) { + nextActions = + conditionAction.actions.find((action) => action.type === ActionType.JOURNEY_TRANSITION) || + ({} as Action); break; } } - return nextActions -} \ No newline at end of file + return nextActions; +} diff --git a/src/components/form/services/geoLocation.service.ts b/src/components/form/services/geoLocation.service.ts index 16e6937b..de3e2cce 100644 --- a/src/components/form/services/geoLocation.service.ts +++ b/src/components/form/services/geoLocation.service.ts @@ -4,92 +4,89 @@ import { toast } from '../../../../RN-UI-LIB/src/components/toast'; import { logError } from '../../utlis/errorUtils'; const FIVE_MIN = 5 * 60 * 1000; export const requestLocationPermission = async () => { - try { - const granted = await PermissionsAndroid.request( - PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION, - { - title: 'Geolocation Permission', - message: 'Can we access your location?', - buttonNeutral: 'Ask Me Later', - buttonNegative: 'Cancel', - buttonPositive: 'OK', - }, - ); - return granted === 'granted'; - } catch (err) { - toast({ - type: 'error', - text1: 'requestLocationPermission failed', - }); - return false; - } + try { + const granted = await PermissionsAndroid.request( + PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION, + { + title: 'Geolocation Permission', + message: 'Can we access your location?', + buttonNeutral: 'Ask Me Later', + buttonNegative: 'Cancel', + buttonPositive: 'OK', + } + ); + return granted === 'granted'; + } catch (err) { + toast({ + type: 'error', + text1: 'requestLocationPermission failed', + }); + return false; + } }; export class CaptureGeolocation { - private static capturedLocation: { - [caseId: string]: { - location?: Geolocation.GeoPosition; - isCapturing: boolean; - }; - } = {}; - private constructor() { - //to make it singleton - } - private static setCapturing(caseId: string, isCapturing: boolean) { - CaptureGeolocation.capturedLocation = { - ...CaptureGeolocation.capturedLocation, - [caseId]: { - ...(CaptureGeolocation.capturedLocation[caseId] || {}), - isCapturing, - }, - }; - } - static async fetchLocation( - resourceId: string, - cacheTTL: number = FIVE_MIN, - ): Promise { - return new Promise(async (resolve, reject) => { - let cachedLocation = CaptureGeolocation.capturedLocation?.[resourceId]; - if ( - cachedLocation && - Date.now() - (cachedLocation?.location?.timestamp || 0) < cacheTTL - ) { - return resolve(cachedLocation?.location?.coords); - } - if (cachedLocation && cachedLocation?.isCapturing) { - console.info('Capture already in progress. Returning'); - resolve(undefined); - } - CaptureGeolocation.setCapturing(resourceId, true); - const isLocationOn = await requestLocationPermission(); - if (!isLocationOn) { - CaptureGeolocation.setCapturing(resourceId, false); - toast({ - type: 'error', - text1: 'Please enable location to continue.', - }); - resolve(undefined); - } - Geolocation.getCurrentPosition( - position => { - CaptureGeolocation.capturedLocation = { - ...(CaptureGeolocation.capturedLocation || {}), - [resourceId]: { location: position, isCapturing: false }, - }; - CaptureGeolocation.setCapturing(resourceId, false); - resolve(position.coords); - }, - error => { - toast({ - type: 'error', - text1: 'Error getting geolocation' + JSON.stringify(error || {}) , - }); - CaptureGeolocation.setCapturing(resourceId, false); - logError(error as any, 'Unable to get location'); - reject(undefined); - }, - { enableHighAccuracy: true, timeout: 1e4, maximumAge: 1e4 }, - ); + private static capturedLocation: { + [caseId: string]: { + location?: Geolocation.GeoPosition; + isCapturing: boolean; + }; + } = {}; + private constructor() { + //to make it singleton + } + private static setCapturing(caseId: string, isCapturing: boolean) { + CaptureGeolocation.capturedLocation = { + ...CaptureGeolocation.capturedLocation, + [caseId]: { + ...(CaptureGeolocation.capturedLocation[caseId] || {}), + isCapturing, + }, + }; + } + static async fetchLocation( + resourceId: string, + cacheTTL: number = FIVE_MIN + ): Promise { + return new Promise(async (resolve, reject) => { + let cachedLocation = CaptureGeolocation.capturedLocation?.[resourceId]; + if (cachedLocation && Date.now() - (cachedLocation?.location?.timestamp || 0) < cacheTTL) { + return resolve(cachedLocation?.location?.coords); + } + if (cachedLocation && cachedLocation?.isCapturing) { + console.info('Capture already in progress. Returning'); + resolve(undefined); + } + CaptureGeolocation.setCapturing(resourceId, true); + const isLocationOn = await requestLocationPermission(); + if (!isLocationOn) { + CaptureGeolocation.setCapturing(resourceId, false); + toast({ + type: 'error', + text1: 'Please enable location to continue.', }); - } + resolve(undefined); + } + Geolocation.getCurrentPosition( + (position) => { + CaptureGeolocation.capturedLocation = { + ...(CaptureGeolocation.capturedLocation || {}), + [resourceId]: { location: position, isCapturing: false }, + }; + CaptureGeolocation.setCapturing(resourceId, false); + resolve(position.coords); + }, + (error) => { + toast({ + type: 'error', + text1: 'Error getting geolocation' + JSON.stringify(error || {}), + }); + CaptureGeolocation.setCapturing(resourceId, false); + logError(error as any, 'Unable to get location'); + reject(undefined); + }, + { enableHighAccuracy: true, timeout: 1e4, maximumAge: 1e4 } + ); + }); + } } diff --git a/src/components/form/services/validation.service.ts b/src/components/form/services/validation.service.ts index a19fe994..91c7baf8 100644 --- a/src/components/form/services/validation.service.ts +++ b/src/components/form/services/validation.service.ts @@ -1,56 +1,65 @@ -import { QuestionV1 } from "../../../types/template.types"; +import { QuestionV1 } from '../../../types/template.types'; export function isQuestionMandatory(question: QuestionV1): boolean { - return !!question.metadata?.validators?.['required']?.value + return !!question.metadata?.validators?.['required']?.value; } -export function validateInput(data: { answer: any, type: string }, allRules: any): boolean { - let result = true +export function validateInput(data: { answer: any; type: string }, allRules: any): boolean { + let result = true; const currentDate = new Date(); - const endOfDayDate = new Date(currentDate.getFullYear() - ,currentDate.getMonth() - ,currentDate.getDate() - ,23,59,59); - const startOfDayDate = new Date(currentDate.getFullYear() - ,currentDate.getMonth() - ,currentDate.getDate() - ,0,0,0); + const endOfDayDate = new Date( + currentDate.getFullYear(), + currentDate.getMonth(), + currentDate.getDate(), + 23, + 59, + 59 + ); + const startOfDayDate = new Date( + currentDate.getFullYear(), + currentDate.getMonth(), + currentDate.getDate(), + 0, + 0, + 0 + ); if (allRules) { for (const ruleName of Object.keys(allRules)) { const rule = allRules[ruleName]; if (ruleName === 'required' && rule.value) { - if (data?.answer === null || data?.answer === undefined || !`${data?.answer}`.trim().length) { + if ( + data?.answer === null || + data?.answer === undefined || + !`${data?.answer}`.trim().length + ) { result = rule.message || 'Required'; break; } } else if (ruleName === Validators.PATTERN) { - if (!(data?.answer?.length && (rule.value).test(data.answer))) { + if (!(data?.answer?.length && rule.value.test(data.answer))) { result = rule.message; break; } - } else if (ruleName === Validators.MAX_TODAY && rule.value) { - const unixAnswer = (new Date(data.answer.split("-").reverse().join("-"))).getTime(); + const unixAnswer = new Date(data.answer.split('-').reverse().join('-')).getTime(); if (!(unixAnswer > 0 && unixAnswer <= endOfDayDate.getTime())) { result = rule.message; break; } - } else if (ruleName === Validators.MIN_TODAY && rule.value) { - const unixAnswer = (new Date(data.answer.split("-").reverse().join("-"))).getTime() - if(!(unixAnswer > 0 && unixAnswer >= startOfDayDate.getTime())){ + const unixAnswer = new Date(data.answer.split('-').reverse().join('-')).getTime(); + if (!(unixAnswer > 0 && unixAnswer >= startOfDayDate.getTime())) { result = rule.message; break; } } } } - return result + return result; } - export enum Validators { PATTERN = 'pattern', MAX_TODAY = 'maxToday', - MIN_TODAY = 'minToday' + MIN_TODAY = 'minToday', } diff --git a/src/components/screens/allCases/allCasesFilters/FilterUtils.ts b/src/components/screens/allCases/allCasesFilters/FilterUtils.ts index 7bfeff89..c354c72d 100644 --- a/src/components/screens/allCases/allCasesFilters/FilterUtils.ts +++ b/src/components/screens/allCases/allCasesFilters/FilterUtils.ts @@ -1,190 +1,171 @@ import { CaseDetail } from '../../../../screens/caseDetails/interface'; import { - FilterGroup, - FilterResponse, - IFilter, - IQuickFilter, + FilterGroup, + FilterResponse, + IFilter, + IQuickFilter, } from '../../../../screens/allCases/interface'; import { - CONDITIONAL_OPERATORS, - FILTER_TYPES, RANGE_FILTER_SEPARATOR, - SELECTION_TYPES, + CONDITIONAL_OPERATORS, + FILTER_TYPES, + RANGE_FILTER_SEPARATOR, + SELECTION_TYPES, } from '../../../../common/Constants'; import { getObjectValueFromKeys } from '../../../utlis/parsers'; import { _map } from '../../../../../RN-UI-LIB/src/utlis/common'; export const evaluateFilterForCases = ( - caseRecord: CaseDetail, - filterGroupMap: Record, - selectedFilters: Record, + caseRecord: CaseDetail, + filterGroupMap: Record, + selectedFilters: Record ) => { - let evaluatedResult = true; - let filters: Record = {}; - _map(filterGroupMap, key => { - filters = { ...filters, ...filterGroupMap[key].filters }; - }); - Object.keys(selectedFilters).forEach(key => { - const fieldToCompareIdx = filters[key].fieldsToCompare.length > 1 ? filters[key].fieldsToCompare.findIndex( - field => { - return field.caseType === caseRecord.caseType + let evaluatedResult = true; + let filters: Record = {}; + _map(filterGroupMap, (key) => { + filters = { ...filters, ...filterGroupMap[key].filters }; + }); + Object.keys(selectedFilters).forEach((key) => { + const fieldToCompareIdx = + filters[key].fieldsToCompare.length > 1 + ? filters[key].fieldsToCompare.findIndex((field) => { + return field.caseType === caseRecord.caseType; + }) + : 0; + switch (filters[key].filterType) { + case FILTER_TYPES.DATE: + switch (filters[key].operator) { + case CONDITIONAL_OPERATORS.EQUALS: + if (selectedFilters[key]) { + evaluatedResult = + evaluatedResult && + selectedFilters[key][ + (getObjectValueFromKeys( + caseRecord, + filters[key].fieldsToCompare[fieldToCompareIdx]?.path.split('.') + ) - + new Date().getTime()) / + 1000 + ]; } - ) : 0; - switch (filters[key].filterType) { - case FILTER_TYPES.DATE: - switch (filters[key].operator) { - case CONDITIONAL_OPERATORS.EQUALS: - if (selectedFilters[key]) { - evaluatedResult = - evaluatedResult && - selectedFilters[key][ - (getObjectValueFromKeys( - caseRecord, - filters[key].fieldsToCompare[ - fieldToCompareIdx - ]?.path.split('.'), - ) - - new Date().getTime()) / - 1000 - ]; - } - break; - case CONDITIONAL_OPERATORS.LESS_THAN_EQUAL_TO: - if (selectedFilters[key]) { - evaluatedResult = - evaluatedResult && - new Date().getTime() - - selectedFilters[key] * 1000 <= - getObjectValueFromKeys( - caseRecord, - filters[key].fieldsToCompare[ - fieldToCompareIdx - ]?.path.split('.'), - ); - } - break; - default: - break; - } - case FILTER_TYPES.STRING: - switch (filters[key].operator) { - case CONDITIONAL_OPERATORS.EQUALS: - if (selectedFilters[key]) { - if (typeof selectedFilters[key] === 'string') { - evaluatedResult = - evaluatedResult && - selectedFilters[key] === getObjectValueFromKeys( - caseRecord, - filters[key].fieldsToCompare[ - fieldToCompareIdx - ]?.path.split('.'), - ); - } else { - evaluatedResult = - evaluatedResult && - selectedFilters[key][ - getObjectValueFromKeys( - caseRecord, - filters[key].fieldsToCompare[ - fieldToCompareIdx - ]?.path.split('.'), - ) - ]; - } - } - break; - case CONDITIONAL_OPERATORS.LESS_THAN_EQUAL_TO: - if (selectedFilters[key]) { - evaluatedResult = - evaluatedResult && - selectedFilters[key] <= - getObjectValueFromKeys( - caseRecord, - filters[key].fieldsToCompare[ - fieldToCompareIdx - ]?.path.split('.'), - ); - } - break; - default: - break; - } - break; - case FILTER_TYPES.RANGE: - if (selectedFilters[key]) { - const limits: Array> | Array = []; - let inRange: boolean = false; - const valueToCompare = getObjectValueFromKeys( - caseRecord, - filters[key].fieldsToCompare[ - fieldToCompareIdx - ]?.path.split('.'), - ); - switch (filters[key].selectionType) { - case SELECTION_TYPES.MULTIPLE: - _map(selectedFilters[key], val => { - limits.push(val.split(RANGE_FILTER_SEPARATOR)); - }); - inRange = limits.some( - limitRecord => - valueToCompare >= Number(limitRecord[0]) && - valueToCompare < Number(limitRecord[1]), - ); - break; - case SELECTION_TYPES.SINGLE: - limits.push(selectedFilters[key].split('.')); - inRange = - valueToCompare >= Number(limits[0]) && - valueToCompare < Number(limits[1]); - break; - default: - break; - } - evaluatedResult = evaluatedResult && inRange; - } - default: - break; + break; + case CONDITIONAL_OPERATORS.LESS_THAN_EQUAL_TO: + if (selectedFilters[key]) { + evaluatedResult = + evaluatedResult && + new Date().getTime() - selectedFilters[key] * 1000 <= + getObjectValueFromKeys( + caseRecord, + filters[key].fieldsToCompare[fieldToCompareIdx]?.path.split('.') + ); + } + break; + default: + break; } - }); - return evaluatedResult; + case FILTER_TYPES.STRING: + switch (filters[key].operator) { + case CONDITIONAL_OPERATORS.EQUALS: + if (selectedFilters[key]) { + if (typeof selectedFilters[key] === 'string') { + evaluatedResult = + evaluatedResult && + selectedFilters[key] === + getObjectValueFromKeys( + caseRecord, + filters[key].fieldsToCompare[fieldToCompareIdx]?.path.split('.') + ); + } else { + evaluatedResult = + evaluatedResult && + selectedFilters[key][ + getObjectValueFromKeys( + caseRecord, + filters[key].fieldsToCompare[fieldToCompareIdx]?.path.split('.') + ) + ]; + } + } + break; + case CONDITIONAL_OPERATORS.LESS_THAN_EQUAL_TO: + if (selectedFilters[key]) { + evaluatedResult = + evaluatedResult && + selectedFilters[key] <= + getObjectValueFromKeys( + caseRecord, + filters[key].fieldsToCompare[fieldToCompareIdx]?.path.split('.') + ); + } + break; + default: + break; + } + break; + case FILTER_TYPES.RANGE: + if (selectedFilters[key]) { + const limits: Array> | Array = []; + let inRange: boolean = false; + const valueToCompare = getObjectValueFromKeys( + caseRecord, + filters[key].fieldsToCompare[fieldToCompareIdx]?.path.split('.') + ); + switch (filters[key].selectionType) { + case SELECTION_TYPES.MULTIPLE: + _map(selectedFilters[key], (val) => { + limits.push(val.split(RANGE_FILTER_SEPARATOR)); + }); + inRange = limits.some( + (limitRecord) => + valueToCompare >= Number(limitRecord[0]) && + valueToCompare < Number(limitRecord[1]) + ); + break; + case SELECTION_TYPES.SINGLE: + limits.push(selectedFilters[key].split('.')); + inRange = valueToCompare >= Number(limits[0]) && valueToCompare < Number(limits[1]); + break; + default: + break; + } + evaluatedResult = evaluatedResult && inRange; + } + default: + break; + } + }); + return evaluatedResult; }; export function filterTransformer(filterResponseList: FilterResponse[]) { - let filterObj: Record = {}; - const filterGroupMap: Record = {}; - const quickFilters: IQuickFilter[] = []; - filterResponseList.forEach(filterResponse => { - filterResponse.filters.forEach(filterRecord => { - const { - filterType, - displayText, - selectionType, - fieldsToCompare, - operator, - name, - } = filterRecord; - const quickFilterList = - filterRecord.options - ?.filter(option => option.quickFilter) - .map(option => ({ - name, - filterType, - displayText, - selectionType, - fieldsToCompare, - operator, - label: option.label, - value: option.value, - })) || []; - filterObj[name] = filterRecord; - quickFilterList.length > 0 && quickFilters.push(...quickFilterList); - }); - filterGroupMap[filterResponse.name] = { - name: filterResponse.name, - headerText: filterResponse.headerText, - filters: filterObj, - }; - filterObj = {}; + let filterObj: Record = {}; + const filterGroupMap: Record = {}; + const quickFilters: IQuickFilter[] = []; + filterResponseList.forEach((filterResponse) => { + filterResponse.filters.forEach((filterRecord) => { + const { filterType, displayText, selectionType, fieldsToCompare, operator, name } = + filterRecord; + const quickFilterList = + filterRecord.options + ?.filter((option) => option.quickFilter) + .map((option) => ({ + name, + filterType, + displayText, + selectionType, + fieldsToCompare, + operator, + label: option.label, + value: option.value, + })) || []; + filterObj[name] = filterRecord; + quickFilterList.length > 0 && quickFilters.push(...quickFilterList); }); - return { filterGroupMap, quickFilters }; + filterGroupMap[filterResponse.name] = { + name: filterResponse.name, + headerText: filterResponse.headerText, + filters: filterObj, + }; + filterObj = {}; + }); + return { filterGroupMap, quickFilters }; } - diff --git a/src/components/screens/allCases/allCasesFilters/Interface.ts b/src/components/screens/allCases/allCasesFilters/Interface.ts index 3bdd3d61..c6134c43 100644 --- a/src/components/screens/allCases/allCasesFilters/Interface.ts +++ b/src/components/screens/allCases/allCasesFilters/Interface.ts @@ -1,17 +1,16 @@ export interface FilterContainerProps { - closeFilterModal: () => void; - isVisitPlan?: boolean; + closeFilterModal: () => void; + isVisitPlan?: boolean; } export interface ISelectedFilterKey { - filterGroup: string; - filterKey: string; + filterGroup: string; + filterKey: string; } - export interface IFilterOptionsProps { - selectedFilterKey: ISelectedFilterKey, - filterSearchString: string, - handleFilterSelection: (filterValues:any) => void, - selectedFiltersMap: Record + selectedFilterKey: ISelectedFilterKey; + filterSearchString: string; + handleFilterSelection: (filterValues: any) => void; + selectedFiltersMap: Record; } diff --git a/src/components/screens/allCases/allCasesFilters/styles.ts b/src/components/screens/allCases/allCasesFilters/styles.ts index b0c63286..03a5158d 100644 --- a/src/components/screens/allCases/allCasesFilters/styles.ts +++ b/src/components/screens/allCases/allCasesFilters/styles.ts @@ -2,78 +2,78 @@ import { PixelRatio, StyleSheet } from 'react-native'; import { COLORS } from '../../../../../RN-UI-LIB/src/styles/colors'; const styles = StyleSheet.create({ - blueText: { - color: COLORS.TEXT.BLUE, - }, - borderBottom: { - borderColor: COLORS.BORDER.PRIMARY, - borderWidth: 1, - }, - mv8: { - marginVertical: 4, - }, - p8: { - padding: 8, - }, - filterColumn: { - flex: 1, - alignItems: 'stretch', - }, - filterSelector: { - paddingHorizontal: 12, - paddingVertical: 8, - }, - selectedFilterKey: { - backgroundColor: COLORS.BACKGROUND.BLUE, - borderRadius: 6, - }, - borderRight1: { - borderRightWidth: 1, - borderRightColor: COLORS.BORDER.PRIMARY, - }, - bottomCTA: { - flex: 1, - alignItems: 'center', - paddingVertical: 12, - }, - applyButton: { - backgroundColor: COLORS.TEXT.BLUE, - }, - clearAllButton: { - borderTopColor: COLORS.BORDER.PRIMARY, - borderRightColor: COLORS.BORDER.PRIMARY, - backgroundColor: COLORS.TEXT.WHITE, - borderRightWidth: 1, - borderTopWidth: 1, - }, - ph7: { - paddingHorizontal: 7, - }, - filterCount: { - backgroundColor: COLORS.BACKGROUND.SILVER, - borderColor: COLORS.BORDER.PRIMARY, - borderWidth: 1, - height: PixelRatio.roundToNearestPixel(25), - width: PixelRatio.roundToNearestPixel(25), - borderRadius: 20, - alignItems: 'center', - }, - filterCountSelected: { - backgroundColor: COLORS.TEXT.BLUE, - height: PixelRatio.roundToNearestPixel(25), - width: PixelRatio.roundToNearestPixel(25), - borderRadius: 20, - alignItems: 'center', - }, - filterGroupHeader: { - backgroundColor: COLORS.BACKGROUND.SILVER, - }, - filterOption: { - paddingLeft: 12, - paddingRight: 18, - paddingVertical: 8, - flexShrink:1 - }, + blueText: { + color: COLORS.TEXT.BLUE, + }, + borderBottom: { + borderColor: COLORS.BORDER.PRIMARY, + borderWidth: 1, + }, + mv8: { + marginVertical: 4, + }, + p8: { + padding: 8, + }, + filterColumn: { + flex: 1, + alignItems: 'stretch', + }, + filterSelector: { + paddingHorizontal: 12, + paddingVertical: 8, + }, + selectedFilterKey: { + backgroundColor: COLORS.BACKGROUND.BLUE, + borderRadius: 6, + }, + borderRight1: { + borderRightWidth: 1, + borderRightColor: COLORS.BORDER.PRIMARY, + }, + bottomCTA: { + flex: 1, + alignItems: 'center', + paddingVertical: 12, + }, + applyButton: { + backgroundColor: COLORS.TEXT.BLUE, + }, + clearAllButton: { + borderTopColor: COLORS.BORDER.PRIMARY, + borderRightColor: COLORS.BORDER.PRIMARY, + backgroundColor: COLORS.TEXT.WHITE, + borderRightWidth: 1, + borderTopWidth: 1, + }, + ph7: { + paddingHorizontal: 7, + }, + filterCount: { + backgroundColor: COLORS.BACKGROUND.SILVER, + borderColor: COLORS.BORDER.PRIMARY, + borderWidth: 1, + height: PixelRatio.roundToNearestPixel(25), + width: PixelRatio.roundToNearestPixel(25), + borderRadius: 20, + alignItems: 'center', + }, + filterCountSelected: { + backgroundColor: COLORS.TEXT.BLUE, + height: PixelRatio.roundToNearestPixel(25), + width: PixelRatio.roundToNearestPixel(25), + borderRadius: 20, + alignItems: 'center', + }, + filterGroupHeader: { + backgroundColor: COLORS.BACKGROUND.SILVER, + }, + filterOption: { + paddingLeft: 12, + paddingRight: 18, + paddingVertical: 8, + flexShrink: 1, + }, }); export default styles; diff --git a/src/components/utlis/apiHelper.ts b/src/components/utlis/apiHelper.ts index 6a50b449..eb489918 100644 --- a/src/components/utlis/apiHelper.ts +++ b/src/components/utlis/apiHelper.ts @@ -14,29 +14,29 @@ import { getEventNameFromAPIKey, getKeyByValue } from './commonFunctions'; import { instrumentApmRoutes } from './apmUtils'; export enum ApiKeys { - GENERATE_OTP = 'GENERATE_OTP', - VERIFY_OTP = 'VERIFY_OTP', - ALL_CASES = 'ALL_CASES', - CASE_DETAIL = 'CASE_DETAIL', - PINNED_CASES = 'PINNED_CASES', - LOGOUT = 'LOGOUT', - FEEDBACK = 'FEEDBACK', - FILTERS = 'FILTERS', - JANUS = 'JANUS', - GENERATE_PAYMENT_LINK = 'GENERATE_PAYMENT_LINK', - ADDRESSES_GEOLOCATION = 'ADDRESSES_GEOLOCATION', - NEW_ADDRESS = 'NEW_ADDRESS', - GET_SIGNED_URL = 'GET_SIGNED_URL', - CASE_UNIFIED_DETAILS = 'CASE_UNIFIED_DETAILS', - EMI_SCHEDULES = 'EMI_SCHEDULES', - PAST_FEEDBACK = 'PAST_FEEDBACK', - NOTIFICATIONS = 'NOTIFICATIONS', - NOTIFICATION_ACTION = 'NOTIFICATION_ACTION', - NOTIFICATION_DELIVERED = 'NOTIFICATION_DELIVERED', - SEND_LOCATION = 'SEND_LOCATION', - SIGN_IN_GOOGLE = 'SIGN_IN_GOOGLE', - VERIFY_GOOGLE_SIGN_IN = 'VERIFY_GOOGLE_SIGN_IN', - SYNC_TIME = 'SYNC_TIME' + GENERATE_OTP = 'GENERATE_OTP', + VERIFY_OTP = 'VERIFY_OTP', + ALL_CASES = 'ALL_CASES', + CASE_DETAIL = 'CASE_DETAIL', + PINNED_CASES = 'PINNED_CASES', + LOGOUT = 'LOGOUT', + FEEDBACK = 'FEEDBACK', + FILTERS = 'FILTERS', + JANUS = 'JANUS', + GENERATE_PAYMENT_LINK = 'GENERATE_PAYMENT_LINK', + ADDRESSES_GEOLOCATION = 'ADDRESSES_GEOLOCATION', + NEW_ADDRESS = 'NEW_ADDRESS', + GET_SIGNED_URL = 'GET_SIGNED_URL', + CASE_UNIFIED_DETAILS = 'CASE_UNIFIED_DETAILS', + EMI_SCHEDULES = 'EMI_SCHEDULES', + PAST_FEEDBACK = 'PAST_FEEDBACK', + NOTIFICATIONS = 'NOTIFICATIONS', + NOTIFICATION_ACTION = 'NOTIFICATION_ACTION', + NOTIFICATION_DELIVERED = 'NOTIFICATION_DELIVERED', + SEND_LOCATION = 'SEND_LOCATION', + SIGN_IN_GOOGLE = 'SIGN_IN_GOOGLE', + VERIFY_GOOGLE_SIGN_IN = 'VERIFY_GOOGLE_SIGN_IN', + SYNC_TIME = 'SYNC_TIME', } export const API_URLS: Record = {} as Record; @@ -65,13 +65,13 @@ API_URLS[ApiKeys.VERIFY_GOOGLE_SIGN_IN] = '/auth/session/exchange'; API_URLS[ApiKeys.SYNC_TIME] = '/sync/server-timestamp'; export const API_STATUS_CODE = { - OK: 200, - CREATED: 201, - BAD_REQUEST: 400, - UNAUTHORIZED: 401, - FORBIDDEN: 403, - NOT_FOUND: 404, - INTERNAL_SERVER_ERROR: 500 + OK: 200, + CREATED: 201, + BAD_REQUEST: 400, + UNAUTHORIZED: 401, + FORBIDDEN: 403, + NOT_FOUND: 404, + INTERNAL_SERVER_ERROR: 500, }; const API_TIMEOUT_INTERVAL = 2e4; // 20s @@ -79,157 +79,148 @@ const API_TIMEOUT_INTERVAL = 2e4; // 20s let dispatch: Dispatch; export const getErrorMessage = (err: any) => { - if (err?.response?.data?.title) { - return err?.response?.data?.title; - } - const errorContent = err?.response?.data?.message - ? JSON.parse(err?.response?.data?.message) - : ''; - return errorContent?.detail || errorContent?.message || errorContent || err; + if (err?.response?.data?.title) { + return err?.response?.data?.title; + } + const errorContent = err?.response?.data?.message ? JSON.parse(err?.response?.data?.message) : ''; + return errorContent?.detail || errorContent?.message || errorContent || err; }; export function getApiUrl( - apiKey: ApiKeys, - params?: Record, - queryParams?: Record, + apiKey: ApiKeys, + params?: Record, + queryParams?: Record ) { + let apiUrl = API_URLS[apiKey]; - let apiUrl = API_URLS[apiKey]; + // replace all {placeholders} with their values in params + if (params) { + Object.keys(params).forEach((paramKey) => { + apiUrl = apiUrl.split(`{${paramKey}}`).join(`${params[paramKey]}`); + // apiUrl = apiUrl.replaceAll(`{${paramKey}}`, `${params[paramKey]}`); + }); + } - // replace all {placeholders} with their values in params - if (params) { - Object.keys(params).forEach(paramKey => { - apiUrl = apiUrl.split(`{${paramKey}}`).join(`${params[paramKey]}`); - // apiUrl = apiUrl.replaceAll(`{${paramKey}}`, `${params[paramKey]}`); - }); - } + if (queryParams) { + apiUrl += '?' + _map(queryParams, (key) => `${key}=${queryParams[key]}`).join('&'); + } - if (queryParams) { - apiUrl += - '?' + - _map(queryParams, key => `${key}=${queryParams[key]}`).join('&'); - } - - return `${apiUrl}`; + return `${apiUrl}`; } // status code to be retried on const errorsToRetry = [500, 503]; -const axiosInstance = axios.create({timeout: API_TIMEOUT_INTERVAL}); +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.headers['request-start-time'] = Date.now(); - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - request.headers['X-Session-Token'] = GLOBAL.SESSION_TOKEN || ''; - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - request.headers['deviceId'] = GLOBAL.DEVICE_ID || ''; - request?.url && instrumentApmRoutes(apm, request.url, 'http-request'); - return request; +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.headers['request-start-time'] = Date.now(); + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + request.headers['X-Session-Token'] = GLOBAL.SESSION_TOKEN || ''; + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + request.headers['deviceId'] = GLOBAL.DEVICE_ID || ''; + request?.url && instrumentApmRoutes(apm, request.url, 'http-request'); + return request; }); axiosInstance.interceptors.response.use( - response => { - if (response.config.headers) { - const start = response.config.headers['request-start-time']; - const end = Date.now(); - const milliseconds = end - Number(start); - response.headers['request-duration'] = String(milliseconds); - if(response?.config?.url) { - const url = response.config.url; - const apiKey = getKeyByValue(API_URLS, url); - if(apiKey) { - const eventName = getEventNameFromAPIKey(apiKey, true); - addClickstreamEvent({name: eventName, description: eventName}, {timeTaken: milliseconds}) - } - } + (response) => { + if (response.config.headers) { + const start = response.config.headers['request-start-time']; + const end = Date.now(); + const milliseconds = end - Number(start); + response.headers['request-duration'] = String(milliseconds); + if (response?.config?.url) { + const url = response.config.url; + const apiKey = getKeyByValue(API_URLS, url); + if (apiKey) { + const eventName = getEventNameFromAPIKey(apiKey, true); + addClickstreamEvent( + { name: eventName, description: eventName }, + { timeTaken: milliseconds } + ); } - return response; - }, - error => { - const {config, response} = error; - logError(error as Error, config?.baseURL+config?.url); - if(response?.config?.url && response.status >= API_STATUS_CODE.INTERNAL_SERVER_ERROR) { - const start = response.config.headers['request-start-time']; - const end = Date.now(); - const milliseconds = end - Number(start); - const url = response.config.url; - const apiKey = getKeyByValue(API_URLS, url); - if(apiKey) { - const eventName = getEventNameFromAPIKey(apiKey); - addClickstreamEvent({name: eventName, description: eventName}, {timeTaken: milliseconds}); - } - } - if(config.headers.donotHandleError) { - return; - } - if ( - !config || - config.retry <= 1 || - !errorsToRetry.includes(error.response.status) - ) { - const errorString = getErrorMessage(error); - if ( - !config.headers.donotHandleError && - (config.headers?.showInSpecificComponents - ? config.headers.showInSpecificComponents?.includes( - getCurrentScreen().name, - ) - : true) - ) { - toast({ - type: 'error', - text1: - typeof errorString === 'string' - ? errorString - : 'Oops! something went wrong', - }); - } - - if ([API_STATUS_CODE.UNAUTHORIZED, API_STATUS_CODE.FORBIDDEN].includes(response.status)) { - // Reset user info - dispatch && - dispatch( - setAuthData({ - sessionDetails: null, - isLoggedIn: false, - user: null, - }), - ); - dispatch && dispatch(resetCasesData()); - navigateToScreen('Login'); - } - - return Promise.reject(error); - } - config.retry -= 1; - const delayRetryRequest = new Promise(resolve => { - setTimeout(() => { - resolve(); - }, 500); + } + } + return response; + }, + (error) => { + const { config, response } = error; + logError(error as Error, config?.baseURL + config?.url); + if (response?.config?.url && response.status >= API_STATUS_CODE.INTERNAL_SERVER_ERROR) { + const start = response.config.headers['request-start-time']; + const end = Date.now(); + const milliseconds = end - Number(start); + const url = response.config.url; + const apiKey = getKeyByValue(API_URLS, url); + if (apiKey) { + const eventName = getEventNameFromAPIKey(apiKey); + addClickstreamEvent( + { name: eventName, description: eventName }, + { timeTaken: milliseconds } + ); + } + } + if (config.headers.donotHandleError) { + return; + } + if (!config || config.retry <= 1 || !errorsToRetry.includes(error.response.status)) { + const errorString = getErrorMessage(error); + if ( + !config.headers.donotHandleError && + (config.headers?.showInSpecificComponents + ? config.headers.showInSpecificComponents?.includes(getCurrentScreen().name) + : true) + ) { + toast({ + type: 'error', + text1: typeof errorString === 'string' ? errorString : 'Oops! something went wrong', }); - return delayRetryRequest.then(() => axiosInstance(config)); - }, + } + + if ([API_STATUS_CODE.UNAUTHORIZED, API_STATUS_CODE.FORBIDDEN].includes(response.status)) { + // Reset user info + dispatch && + dispatch( + setAuthData({ + sessionDetails: null, + isLoggedIn: false, + user: null, + }) + ); + dispatch && dispatch(resetCasesData()); + navigateToScreen('Login'); + } + + return Promise.reject(error); + } + config.retry -= 1; + const delayRetryRequest = new Promise((resolve) => { + setTimeout(() => { + resolve(); + }, 500); + }); + return delayRetryRequest.then(() => axiosInstance(config)); + } ); axiosInstance.defaults.headers.common['Content-Type'] = 'application/json'; axiosInstance.defaults.baseURL = BASE_AV_APP_URL; // TODO:: Ideally should happen through middlewares. -export const registerNavigateAndDispatch = ( - dispatchParam: Dispatch -) => ((dispatch = dispatchParam)); +export const registerNavigateAndDispatch = (dispatchParam: Dispatch) => + (dispatch = dispatchParam); export default axiosInstance; diff --git a/src/components/utlis/apmUtils.ts b/src/components/utlis/apmUtils.ts index 948c2e6e..7780d022 100644 --- a/src/components/utlis/apmUtils.ts +++ b/src/components/utlis/apmUtils.ts @@ -1,16 +1,15 @@ +import { ApmBase } from '@cobo/apm-rum-react-native'; +import { afterFrame } from '@elastic/apm-rum-core'; -import { ApmBase } from "@cobo/apm-rum-react-native"; -import { afterFrame } from "@elastic/apm-rum-core"; - -export function instrumentApmRoutes(apm: ApmBase, url: string, type = "route-change"): void { +export function instrumentApmRoutes(apm: ApmBase, url: string, type = 'route-change'): void { if (apm) { - const tx = apm.startTransaction(url, type , { + const tx = apm.startTransaction(url, type, { managed: false, canReuse: false, }); afterFrame(() => { - (tx != null) && tx.end(); + tx != null && tx.end(); }); } -} \ No newline at end of file +} diff --git a/src/components/utlis/commonFunctions.ts b/src/components/utlis/commonFunctions.ts index db810ae0..12bcaba4 100644 --- a/src/components/utlis/commonFunctions.ts +++ b/src/components/utlis/commonFunctions.ts @@ -1,10 +1,16 @@ -import AsyncStorage from '@react-native-async-storage/async-storage'; -import RNFetchBlob from "rn-fetch-blob"; -import { Address, DOCUMENT_TYPE, IDocument, PhoneNumber, TDocumentObj } from "../../screens/caseDetails/interface"; -import { getPrefixBase64Image, LocalStorageKeys, MimeType } from "../../common/Constants"; -import NetInfo from "@react-native-community/netinfo"; +import AsyncStorage from '@react-native-async-storage/async-storage'; +import RNFetchBlob from 'rn-fetch-blob'; +import { + Address, + DOCUMENT_TYPE, + IDocument, + PhoneNumber, + TDocumentObj, +} from '../../screens/caseDetails/interface'; +import { getPrefixBase64Image, LocalStorageKeys, MimeType } from '../../common/Constants'; +import NetInfo from '@react-native-community/netinfo'; import Clipboard from '@react-native-clipboard/clipboard'; -import address from "../form/components/Address"; +import address from '../form/components/Address'; import { useWindowDimensions } from 'react-native'; import { GlobalDocumentMap } from '../../../App'; import { GenericType } from '../../common/GenericTypes'; @@ -23,60 +29,63 @@ const MAX_SHEET_HEIGHT_PERCENTAGE = 50; export const RELATIVE_PATH_PREFIX = 'file://'; - export const decideLoadingState = (textData: string): boolean => { - if (!textData) { - return true; - } - if (textData.includes('NaN') || textData.includes('undefined')) { - return true; - } - return false; + if (!textData) { + return true; + } + if (textData.includes('NaN') || textData.includes('undefined')) { + return true; + } + return false; }; export const getCommunicationAddress = (address: Address) => { - if (!address) { - return ''; - } - const { houseNumber, lineOne, lineTwo, locality, street, city, state, pinCode } = address; - return [houseNumber, lineOne, lineTwo, locality, street, city, state, pinCode].filter(element => element).join(', '); -} + if (!address) { + return ''; + } + const { houseNumber, lineOne, lineTwo, locality, street, city, state, pinCode } = address; + return [houseNumber, lineOne, lineTwo, locality, street, city, state, pinCode] + .filter((element) => element) + .join(', '); +}; export const storeImageLocallyReturnRelativePath = async (imagePath: string) => { if (!imagePath) return; return RNFetchBlob.config({ - fileCache: true - }).fetch("GET", imagePath) - .then(resp => { + fileCache: true, + }) + .fetch('GET', imagePath) + .then((resp) => { return RELATIVE_PATH_PREFIX + resp.path(); }); -} +}; export const getBase64FromUrl = async (imagePath: string) => { let contentType: MimeType; return RNFetchBlob.config({ - fileCache: true - }).fetch("GET", imagePath) - .then(resp => { - if (resp) { - imagePath = resp.path(); - contentType = resp.respInfo?.headers?.[RespHeaderContentTypeKey]; - return resp.readFile("base64"); - } + fileCache: true, }) - .then(base64 => { - fs.unlink(imagePath); - if (contentType) { - return `${getPrefixBase64Image(contentType)}${base64}`; - } - return; - }); -} + .fetch('GET', imagePath) + .then((resp) => { + if (resp) { + imagePath = resp.path(); + contentType = resp.respInfo?.headers?.[RespHeaderContentTypeKey]; + return resp.readFile('base64'); + } + }) + .then((base64) => { + fs.unlink(imagePath); + if (contentType) { + return `${getPrefixBase64Image(contentType)}${base64}`; + } + return; + }); +}; export const getNetInfo = async () => { - const netInfo = await NetInfo.fetch(); - return netInfo; + const netInfo = await NetInfo.fetch(); + return netInfo; }; export const copyToClipboard = (text: string) => { @@ -92,127 +101,135 @@ export const setAsyncStorageItem = async (key: string, value: any) => { try { const stringifiedValue = JSON.stringify(value); await AsyncStorage.setItem(key, stringifiedValue); - } catch(err) { - console.error('JSON stringify errored',err); + } catch (err) { + console.error('JSON stringify errored', err); } return; -} +}; export const clearAllAsyncStorage = async () => { try { await AsyncStorage.clear(); - } catch(err) { + } catch (err) { // todo: add click-stream event logError(err as Error, 'Error while cleaning AsyncStorage'); console.error('Error while cleaning AsyncStorage'); } return; -} +}; export const sanitizeString = (str = '') => { return str?.trim() || DEFAULT_TEXT; -} +}; -export function toTileCase(text : string) :string { +export function toTileCase(text: string): string { return text?.[0]?.toUpperCase() + text?.substring(1)?.toLowerCase() || text || ''; } export const memoize = (fn: Func) => { const cache = new Map(); const cached = function (this: any, val: T) { - return cache.has(val) - ? cache.get(val) - : cache.set(val, fn.call(this, val)) && cache.get(val); + return cache.has(val) ? cache.get(val) : cache.set(val, fn.call(this, val)) && cache.get(val); }; cached.cache = cache; return cached; }; export function getAddressString(address?: Address): string { - if (!address){ - return 'Address not found' + if (!address) { + return 'Address not found'; } const addressFirstLine = [address.pinCode, address.city].filter(Boolean).join(', '); - const presentationAddressList = [addressFirstLine, address.lineOne, address.lineTwo, toTileCase(address.source)]; + const presentationAddressList = [ + addressFirstLine, + address.lineOne, + address.lineTwo, + toTileCase(address.source), + ]; return presentationAddressList.filter(Boolean).join(' \n '); } export function getPhoneNumberString(phoneNumber?: PhoneNumber): string { - if (!address){ - return 'PhoneNumber not found' + if (!address) { + return 'PhoneNumber not found'; } - return `${phoneNumber?.number} (${phoneNumber?.source})` + return `${phoneNumber?.number} (${phoneNumber?.source})`; } - export const getDynamicBottomSheetHeightPercentageFn = (headerOffset = 100, rowHeight = 50) => { const SCREEN_HEIGHT = useWindowDimensions().height; - return ((rowLength = 0) => { - const dynamicHeight = (((rowLength * rowHeight) + headerOffset) / SCREEN_HEIGHT) * 100; + return (rowLength = 0) => { + const dynamicHeight = ((rowLength * rowHeight + headerOffset) / SCREEN_HEIGHT) * 100; return Math.min(dynamicHeight, MAX_SHEET_HEIGHT_PERCENTAGE); - }) -} + }; +}; export const saveToGlobalDocumentMap = async (caseId: string, data: TDocumentObj) => { if (!caseId) return; GlobalDocumentMap[caseId] = data; - await setAsyncStorageItem( - LocalStorageKeys.GLOBAL_DOCUMENT_MAP, - GlobalDocumentMap, - ); + await setAsyncStorageItem(LocalStorageKeys.GLOBAL_DOCUMENT_MAP, GlobalDocumentMap); }; export const allSettled = (promises: Promise[]) => Promise.all( - promises.map(p => p.then(value => ({ status: 'fulfilled', value})).catch(value => ({ status: 'rejected', value}))), + promises.map((p) => + p + .then((value) => ({ status: 'fulfilled', value })) + .catch((value) => ({ status: 'rejected', value })) + ) ); export function isNullOrUndefined(val: any): boolean { - return val === undefined || val === null + return val === undefined || val === null; } export const getLoanAccountNumber = (caseDetail: CaseDetail) => { const { loanAccountNumber, loanDetails } = caseDetail ?? {}; return loanAccountNumber ?? loanDetails?.loanAccountNumber ?? ''; -} +}; export function getAppVersion(): string { -return packageJson.version; + return packageJson.version; } export const getDocumentList = (caseDetails: CaseDetail) => { - return caseDetails.caseType === CaseAllocationType.ADDRESS_VERIFICATION_CASE ? - caseDetails.customerInfo?.documents : - caseDetails.documents; -} + return caseDetails.caseType === CaseAllocationType.ADDRESS_VERIFICATION_CASE + ? caseDetails.customerInfo?.documents + : caseDetails.documents; +}; -export const findDocumentByDocumentType = (documentList: IDocument[] = [], documentType: DOCUMENT_TYPE) => { - return documentList?.find((documentItem) => documentItem.type === documentType); -} +export const findDocumentByDocumentType = ( + documentList: IDocument[] = [], + documentType: DOCUMENT_TYPE +) => { + return documentList?.find((documentItem) => documentItem.type === documentType); +}; -export const checkS3Url = async(url: string): Promise => { +export const checkS3Url = async (url: string): Promise => { try { - const response = await fetch(url, { method: "HEAD" }); + const response = await fetch(url, { method: 'HEAD' }); return response.ok; } catch (error) { return false; } -} +}; -export function debounce(func : any, timeout = 1000){ +export function debounce(func: any, timeout = 1000) { let timer: number; return (...args: any) => { clearTimeout(timer); - timer = setTimeout(() => { func.apply(this, args); }, timeout); + timer = setTimeout(() => { + func.apply(this, args); + }, timeout); }; } function memoizeValue any>(func: T): T { const cache: Record = {}; - return function(...args: Parameters): ReturnType { + return function (...args: Parameters): ReturnType { const key = JSON.stringify(args); if (cache[key]) { return cache[key]; @@ -223,10 +240,10 @@ function memoizeValue any>(func: T): T { } as T; } -export const getKeyByValue = memoizeValue(function(obj: Record, value: string) { +export const getKeyByValue = memoizeValue(function (obj: Record, value: string) { for (let key in obj) { const regex = /\{.*?\}/g; - const str = obj[key].replace(regex, ""); + const str = obj[key].replace(regex, ''); if (value.includes(str)) { return key; } @@ -235,19 +252,20 @@ export const getKeyByValue = memoizeValue(function(obj: Record, export const getEventNameFromAPIKey = (apiKey: string, isSuccess?: boolean) => { return `FA_${apiKey}_${isSuccess ? 'SUCCESS' : 'FAILED'}`; -} +}; // takes params string like state=123&code=12456 export const getParamsObject = (paramsString: string) => { const paramsArray = paramsString.split('&'); - let pair = null, data: Record = {}; + let pair = null, + data: Record = {}; paramsArray.forEach((keyValueString) => { pair = keyValueString.split('='); - if(pair?.length === 2) { + if (pair?.length === 2) { data[pair[0]] = pair[1]; } }); - return data + return data; }; export const isTimeDifferenceWithinRange = (time: string, rangeInMinutes: number): boolean => { @@ -255,10 +273,10 @@ export const isTimeDifferenceWithinRange = (time: string, rangeInMinutes: number const currentTime = new Date().getTime(); const timeDifferenceInMinutes = Math.abs(Math.round((currentTime - providedTime) / 1000 / 60)); return timeDifferenceInMinutes <= rangeInMinutes; -} +}; export const getScreenFocusListenerObj = ({ route }: { route: RouteProp }) => ({ focus: () => { crashlytics().log(JSON.stringify(route)); }, -}); \ No newline at end of file +}); diff --git a/src/components/utlis/customerDbHelper.ts b/src/components/utlis/customerDbHelper.ts index b2b511a3..6f2ed840 100644 --- a/src/components/utlis/customerDbHelper.ts +++ b/src/components/utlis/customerDbHelper.ts @@ -1,55 +1,52 @@ -import { ClosedCaseStatusList } from "../../common/Constants"; -import { GenericType } from "../../common/GenericTypes"; -import { CustomerImageDAO } from "../../wmDB"; -import { getBase64FromUrl } from "./commonFunctions"; +import { ClosedCaseStatusList } from '../../common/Constants'; +import { GenericType } from '../../common/GenericTypes'; +import { CustomerImageDAO } from '../../wmDB'; +import { getBase64FromUrl } from './commonFunctions'; const isCaseIdRecordExistOnCustomerDb = async (caseId: string) => { - let imageList = await CustomerImageDAO.getImageByCase(caseId); - return !!imageList?.length; -} + let imageList = await CustomerImageDAO.getImageByCase(caseId); + return !!imageList?.length; +}; export const getImage64FromCaseId = async (caseId: string) => { - let imageList = await CustomerImageDAO.getImageByCase(caseId); - return imageList?.[0]?.image64; -} + let imageList = await CustomerImageDAO.getImageByCase(caseId); + return imageList?.[0]?.image64; +}; export const updateRecordsOnCustomerDbFromCaseList = (caseList: GenericType[]) => { - if (!caseList?.length) return; + if (!caseList?.length) return; - const mappedCaseList = caseList - .map((caseItem: GenericType) => ( - { - imageURL: caseItem?.customerInfo?.imageURL, - caseId: caseItem?.id, - caseStatus: caseItem?.caseStatus - } - )); + const mappedCaseList = caseList.map((caseItem: GenericType) => ({ + imageURL: caseItem?.customerInfo?.imageURL, + caseId: caseItem?.id, + caseStatus: caseItem?.caseStatus, + })); - const filteredMappedCaseList = []; - const closedCaseIdList = []; + const filteredMappedCaseList = []; + const closedCaseIdList = []; - (async () => { - for(const caseItem of mappedCaseList) { - if (caseItem.caseId && caseItem.imageURL) { - const isCaseIdRecordExist = await isCaseIdRecordExistOnCustomerDb(caseItem.caseId); + (async () => { + for (const caseItem of mappedCaseList) { + if (caseItem.caseId && caseItem.imageURL) { + const isCaseIdRecordExist = await isCaseIdRecordExistOnCustomerDb(caseItem.caseId); - if(isCaseIdRecordExist && ClosedCaseStatusList.includes(caseItem.caseStatus)) { - closedCaseIdList.push(caseItem.caseId); - } - - if (!isCaseIdRecordExist && !ClosedCaseStatusList.includes(caseItem.caseStatus)) { - const image64 = await getBase64FromUrl(caseItem.imageURL); - if(image64) { - filteredMappedCaseList.push({...caseItem, image64}); - } - } - } + if (isCaseIdRecordExist && ClosedCaseStatusList.includes(caseItem.caseStatus)) { + closedCaseIdList.push(caseItem.caseId); } - if (filteredMappedCaseList?.length) { - await CustomerImageDAO.addBulkCustomerImage(filteredMappedCaseList); + + if (!isCaseIdRecordExist && !ClosedCaseStatusList.includes(caseItem.caseStatus)) { + const image64 = await getBase64FromUrl(caseItem.imageURL); + if (image64) { + filteredMappedCaseList.push({ ...caseItem, image64 }); + } } - if (closedCaseIdList?.length) { - await CustomerImageDAO.deleteImages(closedCaseIdList); - } - })(); -} \ No newline at end of file + } + } + if (filteredMappedCaseList?.length) { + await CustomerImageDAO.addBulkCustomerImage(filteredMappedCaseList); + } + if (closedCaseIdList?.length) { + await CustomerImageDAO.deleteImages(closedCaseIdList); + } + })(); +}; diff --git a/src/components/utlis/errorUtils.ts b/src/components/utlis/errorUtils.ts index b16f42a3..3bd6c827 100644 --- a/src/components/utlis/errorUtils.ts +++ b/src/components/utlis/errorUtils.ts @@ -1,7 +1,12 @@ import * as Sentry from '@sentry/browser'; import { GLOBAL } from '../../constants/Global'; -export const logError = (error: Error, extraInfo = '') =>{ - Sentry.setTag('agentId', GLOBAL.AGENT_ID || 'not-logged-in') - Sentry.captureException({error, message: error?.message, extraInfo, deviceId: GLOBAL.DEVICE_ID, }); +export const logError = (error: Error, extraInfo = '') => { + Sentry.setTag('agentId', GLOBAL.AGENT_ID || 'not-logged-in'); + Sentry.captureException({ + error, + message: error?.message, + extraInfo, + deviceId: GLOBAL.DEVICE_ID, + }); }; diff --git a/src/components/utlis/firebaseUtils.ts b/src/components/utlis/firebaseUtils.ts index 85fea083..846b9bec 100644 --- a/src/components/utlis/firebaseUtils.ts +++ b/src/components/utlis/firebaseUtils.ts @@ -2,15 +2,15 @@ import crashlytics from '@react-native-firebase/crashlytics'; import { IUserSlice } from '../../reducer/userSlice'; export const initCrashlytics = async (userState: IUserSlice) => { - if (!userState) return; + if (!userState) return; - await Promise.all([ - crashlytics().setUserId(userState.user?.emailId as string), - crashlytics().setAttributes({ - deviceId: userState.deviceId, - phoneNumber: userState.user?.phoneNumber as string, - emailId: userState.user?.emailId as string, - sessionToken: userState.sessionDetails?.sessionToken as string - }), - ]); -} \ No newline at end of file + await Promise.all([ + crashlytics().setUserId(userState.user?.emailId as string), + crashlytics().setAttributes({ + deviceId: userState.deviceId, + phoneNumber: userState.user?.phoneNumber as string, + emailId: userState.user?.emailId as string, + sessionToken: userState.sessionDetails?.sessionToken as string, + }), + ]); +}; diff --git a/src/components/utlis/navigationUtlis.ts b/src/components/utlis/navigationUtlis.ts index b254adff..a2d5b195 100644 --- a/src/components/utlis/navigationUtlis.ts +++ b/src/components/utlis/navigationUtlis.ts @@ -1,48 +1,56 @@ import { StackActions } from '@react-navigation/native'; import React, { RefObject } from 'react'; -import { TemplateRoutePrefix } from "../../common/Constants"; -import { CaseAllocationType } from "../../screens/allCases/interface"; +import { TemplateRoutePrefix } from '../../common/Constants'; +import { CaseAllocationType } from '../../screens/allCases/interface'; export const navigationRef: RefObject = React.createRef(); export const getCurrentScreen = () => { - return navigationRef.current?.getCurrentRoute() -} + return navigationRef.current?.getCurrentRoute(); +}; // if screen already exists then navigate to it otherwise push screen export const navigateToScreen = (name: string, params: object = {}) => { - if (navigationRef.current?.getCurrentRoute()?.name === name) { - return; - } - navigationRef.current?.navigate(name, params); + if (navigationRef.current?.getCurrentRoute()?.name === name) { + return; + } + navigationRef.current?.navigate(name, params); }; // push a new screen on top of stack export const pushToScreen = (name: string, params: object = {}) => { - navigationRef.current?.dispatch(StackActions.push(name, params)); + navigationRef.current?.dispatch(StackActions.push(name, params)); }; export const popToScreen = (count: number) => { - navigationRef.current?.dispatch(StackActions.pop(count)); + navigationRef.current?.dispatch(StackActions.pop(count)); }; export const goBack = () => { - navigationRef.current?.goBack(); + navigationRef.current?.goBack(); }; export const resetNavigation = (params: { - routes: Array<{ - name: string; - }>; - index: number | undefined; + routes: Array<{ + name: string; + }>; + index: number | undefined; }) => { - navigationRef.current?.reset(params); + navigationRef.current?.reset(params); }; -export function getTemplateRoute (widgetName: string, caseType: CaseAllocationType) : string { - return `${caseType === CaseAllocationType.COLLECTION_CASE?TemplateRoutePrefix.CC:TemplateRoutePrefix.AV}${widgetName}` +export function getTemplateRoute(widgetName: string, caseType: CaseAllocationType): string { + return `${ + caseType === CaseAllocationType.COLLECTION_CASE + ? TemplateRoutePrefix.CC + : TemplateRoutePrefix.AV + }${widgetName}`; } -export function getWidgetNameFromRoute(routeName: string, caseType: CaseAllocationType) : string { - return routeName.substring(caseType===CaseAllocationType.COLLECTION_CASE?TemplateRoutePrefix.CC.length:TemplateRoutePrefix.AV.length); -} \ No newline at end of file +export function getWidgetNameFromRoute(routeName: string, caseType: CaseAllocationType): string { + return routeName.substring( + caseType === CaseAllocationType.COLLECTION_CASE + ? TemplateRoutePrefix.CC.length + : TemplateRoutePrefix.AV.length + ); +} diff --git a/src/components/utlis/parsers.ts b/src/components/utlis/parsers.ts index de7af626..779413ac 100644 --- a/src/components/utlis/parsers.ts +++ b/src/components/utlis/parsers.ts @@ -1,12 +1,12 @@ -export const getObjectValueFromKeys: ( - obj: Record, - keysArray: Array, -) => any = (obj, keysArray) => { - if (keysArray && keysArray.length && obj && obj[keysArray[0]]) { - return getObjectValueFromKeys(obj[keysArray[0]], keysArray.slice(1)); - } else if (obj) { - return obj; - } +export const getObjectValueFromKeys: (obj: Record, keysArray: Array) => any = ( + obj, + keysArray +) => { + if (keysArray && keysArray.length && obj && obj[keysArray[0]]) { + return getObjectValueFromKeys(obj[keysArray[0]], keysArray.slice(1)); + } else if (obj) { + return obj; + } - return null; + return null; }; diff --git a/src/components/utlis/registerPaymentUtils.ts b/src/components/utlis/registerPaymentUtils.ts index a6468550..3584b507 100644 --- a/src/components/utlis/registerPaymentUtils.ts +++ b/src/components/utlis/registerPaymentUtils.ts @@ -4,24 +4,17 @@ import { ILoanIdToValue } from '../../reducer/paymentSlice'; import { setAsyncStorageItem } from './commonFunctions'; export const getLoanIdToValueFromLocal = async () => { - const loanIdToValueStored = await AsyncStorage.getItem( - LocalStorageKeys.LOAN_ID_TO_VALUE, - ); - if (loanIdToValueStored) { - let parsedLoanIdToValue = JSON.parse( - loanIdToValueStored, - ) as ILoanIdToValue; - const currentDate = Date.now(); - for (const [key, value] of Object.entries(parsedLoanIdToValue)) { - if (Number(value.expiresAt) < currentDate) { - delete parsedLoanIdToValue?.[key]; - } - } - await setAsyncStorageItem( - LocalStorageKeys.LOAN_ID_TO_VALUE, - parsedLoanIdToValue, - ); - return parsedLoanIdToValue; + const loanIdToValueStored = await AsyncStorage.getItem(LocalStorageKeys.LOAN_ID_TO_VALUE); + if (loanIdToValueStored) { + let parsedLoanIdToValue = JSON.parse(loanIdToValueStored) as ILoanIdToValue; + const currentDate = Date.now(); + for (const [key, value] of Object.entries(parsedLoanIdToValue)) { + if (Number(value.expiresAt) < currentDate) { + delete parsedLoanIdToValue?.[key]; + } } - return null; + await setAsyncStorageItem(LocalStorageKeys.LOAN_ID_TO_VALUE, parsedLoanIdToValue); + return parsedLoanIdToValue; + } + return null; }; diff --git a/src/components/utlis/stringifyUtils.ts b/src/components/utlis/stringifyUtils.ts index 51f1db21..c8bc8604 100644 --- a/src/components/utlis/stringifyUtils.ts +++ b/src/components/utlis/stringifyUtils.ts @@ -1,72 +1,68 @@ const stringifyHelper = (o: any, seen: Array, str: string) => { - let newSeen = seen; - let newStr = str; - if (typeof o === 'object' && o !== null) { - // Check for circular references - if (newSeen.includes(o)) { - throw new TypeError('Circular reference detected in object.'); - } - newSeen.push(o); - - if (Array.isArray(o)) { - newStr += '['; - - for (let i = 0; i < o.length; i++) { - newStr = stringifyHelper(o[i], newSeen, newStr); - if (i < o.length - 1) { - newStr += ','; - } - } - newStr += ']'; - } else { - newStr += '{'; - let keys = Object.keys(o); - for (let i = 0; i < keys.length; i++) { - let key = keys[i]; - let value = o[key]; - if (typeof value === 'function') { - continue; // Ignore functions values - } - newStr += `"${key}":`; - if (typeof value === 'number' && value !== value) { - // Handle NaN values - throw new TypeError('unable to stringify NaN type value'); - } else if (value === Infinity) { - // Handle Infinity values - throw new TypeError( - 'unable to stringify +infinity type value', - ); - } else if (value === -Infinity) { - // Handle -Infinity values - throw new TypeError( - 'unable to stringify -infinity type value', - ); - } else if (value === undefined) { - throw new TypeError('unable to stringify undefined value'); - } else { - newStr = stringifyHelper(value, newSeen, newStr); - } - if (i < keys.length - 1) { - newStr += ','; - } - } - newStr += '}'; - } - newSeen.pop(); - } else if (typeof o === 'string') { - newStr += JSON.stringify(o); - } else if (typeof o === 'number' || typeof o === 'boolean') { - newStr += o.toString(); - } else if (o === null) { - newStr += 'null'; - } else { - throw new TypeError('Unable to stringify object.'); + let newSeen = seen; + let newStr = str; + if (typeof o === 'object' && o !== null) { + // Check for circular references + if (newSeen.includes(o)) { + throw new TypeError('Circular reference detected in object.'); } - return newStr; + newSeen.push(o); + + if (Array.isArray(o)) { + newStr += '['; + + for (let i = 0; i < o.length; i++) { + newStr = stringifyHelper(o[i], newSeen, newStr); + if (i < o.length - 1) { + newStr += ','; + } + } + newStr += ']'; + } else { + newStr += '{'; + let keys = Object.keys(o); + for (let i = 0; i < keys.length; i++) { + let key = keys[i]; + let value = o[key]; + if (typeof value === 'function') { + continue; // Ignore functions values + } + newStr += `"${key}":`; + if (typeof value === 'number' && value !== value) { + // Handle NaN values + throw new TypeError('unable to stringify NaN type value'); + } else if (value === Infinity) { + // Handle Infinity values + throw new TypeError('unable to stringify +infinity type value'); + } else if (value === -Infinity) { + // Handle -Infinity values + throw new TypeError('unable to stringify -infinity type value'); + } else if (value === undefined) { + throw new TypeError('unable to stringify undefined value'); + } else { + newStr = stringifyHelper(value, newSeen, newStr); + } + if (i < keys.length - 1) { + newStr += ','; + } + } + newStr += '}'; + } + newSeen.pop(); + } else if (typeof o === 'string') { + newStr += JSON.stringify(o); + } else if (typeof o === 'number' || typeof o === 'boolean') { + newStr += o.toString(); + } else if (o === null) { + newStr += 'null'; + } else { + throw new TypeError('Unable to stringify object.'); + } + return newStr; }; export const stringify = (value: any) => { - let str = ''; - let seen: Array = []; - return stringifyHelper(value, seen, str); + let str = ''; + let seen: Array = []; + return stringifyHelper(value, seen, str); }; diff --git a/src/constants/Global.ts b/src/constants/Global.ts index 90b6d2db..56af711b 100644 --- a/src/constants/Global.ts +++ b/src/constants/Global.ts @@ -1,14 +1,18 @@ -import { isNullOrUndefined } from "../components/utlis/commonFunctions"; +import { isNullOrUndefined } from '../components/utlis/commonFunctions'; export const GLOBAL = { - SESSION_TOKEN: '', - DEVICE_ID: '', - AGENT_ID: '', + SESSION_TOKEN: '', + DEVICE_ID: '', + AGENT_ID: '', }; -export const setGlobalUserData = (userData : {token?: string, deviceId?: string, agentId?: string}) => { - const {token, deviceId, agentId} = userData; - if (!isNullOrUndefined(token)) GLOBAL.SESSION_TOKEN = `${token}`; - if (!isNullOrUndefined(deviceId)) GLOBAL.DEVICE_ID = `${deviceId}`; - if (!isNullOrUndefined(agentId)) GLOBAL.AGENT_ID = `${agentId}`; +export const setGlobalUserData = (userData: { + token?: string; + deviceId?: string; + agentId?: string; +}) => { + const { token, deviceId, agentId } = userData; + if (!isNullOrUndefined(token)) GLOBAL.SESSION_TOKEN = `${token}`; + if (!isNullOrUndefined(deviceId)) GLOBAL.DEVICE_ID = `${deviceId}`; + if (!isNullOrUndefined(agentId)) GLOBAL.AGENT_ID = `${agentId}`; }; diff --git a/src/constants/permissions.constants.ts b/src/constants/permissions.constants.ts index 2624fb8c..27c1312c 100644 --- a/src/constants/permissions.constants.ts +++ b/src/constants/permissions.constants.ts @@ -9,45 +9,45 @@ import Calendar from '../assets/icons/Calendar'; import PhoneIcon from '../assets/icons/PhoneIcon'; export const permissionsScreenMessage = - 'NAVI Cosmos needs your permission to access certain features'; + 'NAVI Cosmos needs your permission to access certain features'; export const androidPermissions = [ - { - Icon: CameraPermissionIcon, - header: 'Camera', - }, - { - Icon: LocationPinPermissions, - header: 'Location', - }, - { - Icon: ContactPermissionIcon, - header: 'Contacts', - }, - { - Icon: FileStoragePermissionIcon, - header: 'Files and Media', - }, - { - Icon: CallPermissionIcon, - header: 'Call', - }, - { - Icon: Microphone, - header: 'Microphone', - }, - { - Icon: SmsIcon, - header: 'Sms', - }, - { - Icon: Calendar, - header: 'Calendar', - }, - { - Icon: PhoneIcon, - header: 'Phone', - }, + { + Icon: CameraPermissionIcon, + header: 'Camera', + }, + { + Icon: LocationPinPermissions, + header: 'Location', + }, + { + Icon: ContactPermissionIcon, + header: 'Contacts', + }, + { + Icon: FileStoragePermissionIcon, + header: 'Files and Media', + }, + { + Icon: CallPermissionIcon, + header: 'Call', + }, + { + Icon: Microphone, + header: 'Microphone', + }, + { + Icon: SmsIcon, + header: 'Sms', + }, + { + Icon: Calendar, + header: 'Calendar', + }, + { + Icon: PhoneIcon, + header: 'Phone', + }, ]; export const permissionsCTAText = 'Open Settings'; diff --git a/src/hooks/capturingApi.ts b/src/hooks/capturingApi.ts index c2028106..16142d00 100644 --- a/src/hooks/capturingApi.ts +++ b/src/hooks/capturingApi.ts @@ -1,38 +1,35 @@ import { GeoCoordinates } from 'react-native-geolocation-service'; -import axiosInstance, { - ApiKeys, - getApiUrl, -} from '../components/utlis/apiHelper'; +import axiosInstance, { ApiKeys, getApiUrl } from '../components/utlis/apiHelper'; export const sendLocationToServer = async (location: GeoCoordinates) => { - try { - const response = await axiosInstance.post( - getApiUrl(ApiKeys.SEND_LOCATION), - [ - { - latitude: location?.latitude, - longitude: location?.longitude, - accuracy: location?.accuracy, - timestamp: new Date().getTime(), - }, - ], - { - headers: { - donotHandleError: 'true', - }, - }, - ); - } catch (error) { - console.log(error); - } + try { + const response = await axiosInstance.post( + getApiUrl(ApiKeys.SEND_LOCATION), + [ + { + latitude: location?.latitude, + longitude: location?.longitude, + accuracy: location?.accuracy, + timestamp: new Date().getTime(), + }, + ], + { + headers: { + donotHandleError: 'true', + }, + } + ); + } catch (error) { + console.log(error); + } }; export const getSyncTime = async () => { - try { - const url = getApiUrl(ApiKeys.SYNC_TIME); - const response = await axiosInstance.get(url); - return response?.data?.currentTimestamp; - } catch (error) { - console.log(error); - } -}; \ No newline at end of file + try { + const url = getApiUrl(ApiKeys.SYNC_TIME); + const response = await axiosInstance.get(url); + return response?.data?.currentTimestamp; + } catch (error) { + console.log(error); + } +}; diff --git a/src/hooks/janusApi.ts b/src/hooks/janusApi.ts index 8ae51d88..fd2d57d0 100644 --- a/src/hooks/janusApi.ts +++ b/src/hooks/janusApi.ts @@ -1,24 +1,21 @@ -import axiosInstance, { ApiKeys, getApiUrl } from "../components/utlis/apiHelper"; -import { updateSingleCase, updateCaseDetailBeforeApiCall } from "../reducer/allCasesSlice"; -import { AppDispatch } from "../store/store"; -import OfflineImageDAO from "../wmDB/dao/OfflineImageDAO"; +import axiosInstance, { ApiKeys, getApiUrl } from '../components/utlis/apiHelper'; +import { updateSingleCase, updateCaseDetailBeforeApiCall } from '../reducer/allCasesSlice'; +import { AppDispatch } from '../store/store'; +import OfflineImageDAO from '../wmDB/dao/OfflineImageDAO'; const useJanusApi = (): { - fireClickstreamPayload: (payload: any) => void; - } => { - const janusServiceUrl = '/events/json'; + fireClickstreamPayload: (payload: any) => void; +} => { + const janusServiceUrl = '/events/json'; - const fireClickstreamPayload = (data: any) => (dispatch: AppDispatch) => { - const url = getApiUrl(ApiKeys.JANUS); - axiosInstance - .post(url, {...data}) - .then(res => { - // empty the events list - }) - } - - return { fireClickstreamPayload }; + const fireClickstreamPayload = (data: any) => (dispatch: AppDispatch) => { + const url = getApiUrl(ApiKeys.JANUS); + axiosInstance.post(url, { ...data }).then((res) => { + // empty the events list + }); }; - - export default useJanusApi; - \ No newline at end of file + + return { fireClickstreamPayload }; +}; + +export default useJanusApi; diff --git a/src/hooks/useFCM.ts b/src/hooks/useFCM.ts index 1033772d..60e83220 100644 --- a/src/hooks/useFCM.ts +++ b/src/hooks/useFCM.ts @@ -1,6 +1,4 @@ -import messaging, { - FirebaseMessagingTypes, -} from '@react-native-firebase/messaging'; +import messaging, { FirebaseMessagingTypes } from '@react-native-firebase/messaging'; import AsyncStorage from '@react-native-async-storage/async-storage'; import { useEffect } from 'react'; import auth from '@react-native-firebase/auth'; @@ -11,53 +9,49 @@ import { logError } from '../components/utlis/errorUtils'; // This can be used to get Notification permission. const requestUserPermission = async () => { - const authStatus = await messaging().requestPermission(); - const enabled = - authStatus === messaging.AuthorizationStatus.AUTHORIZED || - authStatus === messaging.AuthorizationStatus.PROVISIONAL; - if (enabled) { - getFCMToken(); - } + const authStatus = await messaging().requestPermission(); + const enabled = + authStatus === messaging.AuthorizationStatus.AUTHORIZED || + authStatus === messaging.AuthorizationStatus.PROVISIONAL; + if (enabled) { + getFCMToken(); + } }; const getFCMToken = async () => { - let fcmtoken = await AsyncStorage.getItem('fcmtoken'); - if (!fcmtoken) { - try { - let fcmtoken = await messaging().getToken(); - if (fcmtoken) { - await AsyncStorage.setItem('fcmtoken', fcmtoken); - } - } catch (error: any) { - logError(error, 'unable to generate FCM token') - } + let fcmtoken = await AsyncStorage.getItem('fcmtoken'); + if (!fcmtoken) { + try { + let fcmtoken = await messaging().getToken(); + if (fcmtoken) { + await AsyncStorage.setItem('fcmtoken', fcmtoken); + } + } catch (error: any) { + logError(error, 'unable to generate FCM token'); } + } }; const notificationListener = ( - handleNotificationMessage: ( - remoteMessage: FirebaseMessagingTypes.RemoteMessage, - ) => Promise, + handleNotificationMessage: (remoteMessage: FirebaseMessagingTypes.RemoteMessage) => Promise ) => { - messaging().setBackgroundMessageHandler(handleNotificationMessage); - messaging().onMessage(handleNotificationMessage); + messaging().setBackgroundMessageHandler(handleNotificationMessage); + messaging().onMessage(handleNotificationMessage); }; const useFCM = () => { - const dispatch = useAppDispatch(); - const handleNotificationMessage = async ( - remoteMessage: FirebaseMessagingTypes.RemoteMessage, - ) => { - const { data } = remoteMessage; - if (data?.payload) { - const notification = JSON.parse(data.payload); - dispatch(notificationDelivered({ids: [notification.id]})) - dispatch(prependNewNotifications({ notification })); - } - }; - useEffect(() => { - getFCMToken(); - notificationListener(handleNotificationMessage); - }, []); + const dispatch = useAppDispatch(); + const handleNotificationMessage = async (remoteMessage: FirebaseMessagingTypes.RemoteMessage) => { + const { data } = remoteMessage; + if (data?.payload) { + const notification = JSON.parse(data.payload); + dispatch(notificationDelivered({ ids: [notification.id] })); + dispatch(prependNewNotifications({ notification })); + } + }; + useEffect(() => { + getFCMToken(); + notificationListener(handleNotificationMessage); + }, []); }; export default useFCM; diff --git a/src/hooks/useFetchDocument.ts b/src/hooks/useFetchDocument.ts index 58c88664..a7a3e9fd 100644 --- a/src/hooks/useFetchDocument.ts +++ b/src/hooks/useFetchDocument.ts @@ -1,134 +1,152 @@ import { useEffect, useRef, useState } from 'react'; -import { findDocumentByDocumentType, getDocumentList, RELATIVE_PATH_PREFIX, - saveToGlobalDocumentMap, storeImageLocallyReturnRelativePath } from '../components/utlis/commonFunctions'; +import { + findDocumentByDocumentType, + getDocumentList, + RELATIVE_PATH_PREFIX, + saveToGlobalDocumentMap, + storeImageLocallyReturnRelativePath, +} from '../components/utlis/commonFunctions'; import { CaseDetail, DOCUMENT_TYPE, TDocumentObj } from '../screens/caseDetails/interface'; import { getSignedApi, ISignedRequest } from '../action/dataActions'; import { GlobalDocumentMap } from '../../App'; - const getDocumentUrlFromCaseDetails = (caseDetails: CaseDetail, documentType: DOCUMENT_TYPE) => { - if (GlobalDocumentMap?.[caseDetails?.id]?.[documentType]) { - return GlobalDocumentMap[caseDetails.id][documentType]; - } + if (GlobalDocumentMap?.[caseDetails?.id]?.[documentType]) { + return GlobalDocumentMap[caseDetails.id][documentType]; + } - const documentList = getDocumentList(caseDetails); - return findDocumentByDocumentType(documentList, documentType)?.uri; -} - -const getInitialDocumentObj = (caseDetails: CaseDetail) => (documentTypeList: DOCUMENT_TYPE[]) => { - return documentTypeList?.reduce((acc, curr) => ( - { ...acc, [curr]: getDocumentUrlFromCaseDetails(caseDetails, curr) }), {} as TDocumentObj); + const documentList = getDocumentList(caseDetails); + return findDocumentByDocumentType(documentList, documentType)?.uri; }; -const useFetchDocument = (caseDetails: CaseDetail, documentTypeList: DOCUMENT_TYPE[], enableCaching = true, enableBatching = false) => { +const getInitialDocumentObj = (caseDetails: CaseDetail) => (documentTypeList: DOCUMENT_TYPE[]) => { + return documentTypeList?.reduce( + (acc, curr) => ({ ...acc, [curr]: getDocumentUrlFromCaseDetails(caseDetails, curr) }), + {} as TDocumentObj + ); +}; +const useFetchDocument = ( + caseDetails: CaseDetail, + documentTypeList: DOCUMENT_TYPE[], + enableCaching = true, + enableBatching = false +) => { + const getInitialDocumentObjFn = getInitialDocumentObj(caseDetails); - const getInitialDocumentObjFn = getInitialDocumentObj(caseDetails); + const [documentObj, setDocumentObj] = useState( + getInitialDocumentObjFn(documentTypeList) + ); - const [documentObj, setDocumentObj] = useState( - getInitialDocumentObjFn(documentTypeList) - ); + const apiInProgressReferenceIds = useRef([]); - const apiInProgressReferenceIds = useRef([]); + const [retryForDocuments, setRetryForDocuments] = useState([]); + const [loading, setLoading] = useState(false); - const [retryForDocuments, setRetryForDocuments] = useState([]); - const [loading, setLoading] = useState(false); + useEffect(() => { + if (enableCaching) { + let localDocumentObj = { ...documentObj } as TDocumentObj; + (async () => { + (async () => { + for (const [documentType, documentValue] of Object.entries(localDocumentObj)) { + if ( + documentValue && + documentType in DOCUMENT_TYPE && + !documentValue?.startsWith(RELATIVE_PATH_PREFIX) + ) { + const localImagePath = await storeImageLocallyReturnRelativePath(documentValue); + localDocumentObj = { + ...localDocumentObj, + [documentType]: localImagePath, + }; + } + } + })().then(async () => { + setDocumentObj(localDocumentObj); + }); + })(); + } + }, []); - useEffect(() => { - if (enableCaching) { - let localDocumentObj = { ...documentObj } as TDocumentObj; - (async () => { - (async () => { - for (const [documentType, documentValue] of Object.entries(localDocumentObj)) { - if (documentValue && documentType in DOCUMENT_TYPE && !documentValue?.startsWith(RELATIVE_PATH_PREFIX)) { - const localImagePath = await storeImageLocallyReturnRelativePath(documentValue); - localDocumentObj = { - ...localDocumentObj, - [documentType]: localImagePath - } - } - } - })().then(async () => { - setDocumentObj(localDocumentObj); - }) - })(); - } - }, []); + useEffect(() => { + if (enableCaching && documentObj) { + (async () => { + await saveToGlobalDocumentMap(caseDetails?.id, documentObj); + })(); + } + }, [documentObj, enableCaching]); - useEffect(() => { - if (enableCaching && documentObj) { - (async () => { - await saveToGlobalDocumentMap(caseDetails?.id, documentObj); - })(); - } - }, [documentObj, enableCaching]); + useEffect(() => { + if (!retryForDocuments?.length) return; - useEffect(() => { - if (!retryForDocuments?.length) return; + const documentList = getDocumentList(caseDetails); + let imageReferenceId: string | undefined; - const documentList = getDocumentList(caseDetails); - let imageReferenceId: string | undefined; + for (let retryForDocumentsItem of retryForDocuments) { + imageReferenceId = findDocumentByDocumentType( + documentList, + retryForDocumentsItem + )?.referenceId; - for (let retryForDocumentsItem of retryForDocuments) { - imageReferenceId = findDocumentByDocumentType(documentList, retryForDocumentsItem)?.referenceId; - - (async () => { - if (!imageReferenceId) { - setDocumentObj(documentObj => ({ - ...documentObj, - [retryForDocumentsItem]: '' - })) - return; - } - - if (apiInProgressReferenceIds.current.includes(imageReferenceId)) return; - - apiInProgressReferenceIds.current.push(imageReferenceId); - - const signedRequestPayload: ISignedRequest = [ - { - documentReferenceId: imageReferenceId, - caseId: '' + caseDetails.id, - caseType: caseDetails.caseType, - }, - ]; - - setLoading(true); - const response = await getSignedApi(signedRequestPayload, enableBatching); - setLoading(false); - const url = response?.imageUrl; - - if (!url) { - setDocumentObj(documentObj => ({ - ...documentObj, - [retryForDocumentsItem]: '' - })) - return; - } - - const localImagePath = await storeImageLocallyReturnRelativePath(url); - - if (localImagePath) { - setDocumentObj(documentObj => ({ - ...documentObj, - [retryForDocumentsItem]: localImagePath - })); - } - })(); + (async () => { + if (!imageReferenceId) { + setDocumentObj((documentObj) => ({ + ...documentObj, + [retryForDocumentsItem]: '', + })); + return; } - return () => { - apiInProgressReferenceIds.current = apiInProgressReferenceIds.current.filter(item => item !== imageReferenceId); - } - }, [retryForDocuments]); + if (apiInProgressReferenceIds.current.includes(imageReferenceId)) return; - return { - documentObj, - setDocumentObj, - setRetryForUnsignedDocuments: setRetryForDocuments, - retryForUnsignedDocuments: retryForDocuments, - loading + apiInProgressReferenceIds.current.push(imageReferenceId); + + const signedRequestPayload: ISignedRequest = [ + { + documentReferenceId: imageReferenceId, + caseId: '' + caseDetails.id, + caseType: caseDetails.caseType, + }, + ]; + + setLoading(true); + const response = await getSignedApi(signedRequestPayload, enableBatching); + setLoading(false); + const url = response?.imageUrl; + + if (!url) { + setDocumentObj((documentObj) => ({ + ...documentObj, + [retryForDocumentsItem]: '', + })); + return; + } + + const localImagePath = await storeImageLocallyReturnRelativePath(url); + + if (localImagePath) { + setDocumentObj((documentObj) => ({ + ...documentObj, + [retryForDocumentsItem]: localImagePath, + })); + } + })(); + } + + return () => { + apiInProgressReferenceIds.current = apiInProgressReferenceIds.current.filter( + (item) => item !== imageReferenceId + ); }; + }, [retryForDocuments]); + + return { + documentObj, + setDocumentObj, + setRetryForUnsignedDocuments: setRetryForDocuments, + retryForUnsignedDocuments: retryForDocuments, + loading, + }; }; export default useFetchDocument; diff --git a/src/hooks/useFirestoreUpdates.ts b/src/hooks/useFirestoreUpdates.ts index a82b6e43..628fb810 100644 --- a/src/hooks/useFirestoreUpdates.ts +++ b/src/hooks/useFirestoreUpdates.ts @@ -2,259 +2,246 @@ import { useEffect } from 'react'; import firestore, { FirebaseFirestoreTypes } from '@react-native-firebase/firestore'; import { RootState } from '../store/store'; import { useAppDispatch, useAppSelector } from '.'; -import { setLoading, updateCaseDetailsFirestore, } from '../reducer/allCasesSlice'; +import { setLoading, updateCaseDetailsFirestore } from '../reducer/allCasesSlice'; import { CaseDetail } from '../screens/caseDetails/interface'; import { FirestoreUpdateTypes } from '../common/Constants'; import { toast } from '../../RN-UI-LIB/src/components/toast'; import auth from '@react-native-firebase/auth'; -import { updateAvTemplateData, updateCollectionTemplateData, } from '../reducer/caseReducer'; +import { updateAvTemplateData, updateCollectionTemplateData } from '../reducer/caseReducer'; import { GLOBAL, setGlobalUserData } from '../constants/Global'; import { setAuthData } from '../reducer/userSlice'; import { setFilters } from '../reducer/filtersSlice'; import { FormTemplateV1 } from '../types/template.types'; import { ToastMessages } from '../screens/allCases/constants'; -import { setForceUninstallData } from "../reducer/metadataSlice"; +import { setForceUninstallData } from '../reducer/metadataSlice'; import { logError } from '../components/utlis/errorUtils'; import { GenericFunctionArgs } from '../common/GenericTypes'; import axiosInstance, { ApiKeys, getApiUrl } from '../components/utlis/apiHelper'; export interface CaseUpdates { - updateType: string; - updatedCaseDetail: CaseDetail; + updateType: string; + updatedCaseDetail: CaseDetail; } const useFirestoreUpdates = () => { - const reduxStoreData = useAppSelector((state: RootState) => state); - const { - user: { user, isLoggedIn, sessionDetails }, - allCases: { caseDetails, casesList, loading }, - } = reduxStoreData; + const reduxStoreData = useAppSelector((state: RootState) => state); + const { + user: { user, isLoggedIn, sessionDetails }, + allCases: { caseDetails, casesList, loading }, + } = reduxStoreData; - let casesUnsubscribe: GenericFunctionArgs; - let avTemplateUnSubscriber: GenericFunctionArgs; - let collectionTemplateUnsubscribe: GenericFunctionArgs; - let configUnsubscribe: GenericFunctionArgs; - let filterUnsubscribe: GenericFunctionArgs; - let forceUninstallUnsubscribe: GenericFunctionArgs; + let casesUnsubscribe: GenericFunctionArgs; + let avTemplateUnSubscriber: GenericFunctionArgs; + let collectionTemplateUnsubscribe: GenericFunctionArgs; + let configUnsubscribe: GenericFunctionArgs; + let filterUnsubscribe: GenericFunctionArgs; + let forceUninstallUnsubscribe: GenericFunctionArgs; + const dispatch = useAppDispatch(); - const dispatch = useAppDispatch(); - - const showCaseUpdationToast = ( - newlyAddedCases: number, - deletedCases: number, - ) => { - let toastConfig: any = null; - let addedCasesText = newlyAddedCases - ? `${newlyAddedCases} new case${ - newlyAddedCases > 1 ? 's' : '' - } allocated` - : ''; - let deletedCasesText = deletedCases - ? `${deletedCases} case${deletedCases > 1 ? 's' : ''} de-allocated` - : ''; - if (newlyAddedCases && deletedCases) { - toastConfig = { - type: 'info', - text1: `${addedCasesText} & ${deletedCasesText}`, - }; - } else if (newlyAddedCases) { - toastConfig = { type: 'success', text1: addedCasesText }; - } else if (deletedCases) { - toastConfig = { type: 'error', text1: deletedCasesText }; - } - if (toastConfig) { - toast(toastConfig); - } - }; - - const handleCasesUpdate = ( - querySnapshot: FirebaseFirestoreTypes.QuerySnapshot, - ) => { - let newlyAddedCases = 0; - let deletedCases = 0; - const caseUpdates: CaseUpdates[] = []; - querySnapshot - .docChanges() - .forEach( - (documentSnapshot: FirebaseFirestoreTypes.DocumentChange) => { - const updateType = documentSnapshot.type; - const updatedCaseDetail = - documentSnapshot.doc.data() as CaseDetail; - if (updateType === FirestoreUpdateTypes.ADDED) { - if (!caseDetails[updatedCaseDetail.id]) { - newlyAddedCases++; - caseUpdates.push({ updateType, updatedCaseDetail }); - } - } else { - if (updateType === FirestoreUpdateTypes.REMOVED) { - deletedCases++; - } - caseUpdates.push({ updateType, updatedCaseDetail }); - } - }, - ); - const isInitialLoad = casesList.length === 0; - dispatch(updateCaseDetailsFirestore({ caseUpdates, isInitialLoad })); - !isInitialLoad && showCaseUpdationToast(newlyAddedCases, deletedCases); - }; - - const handleConfigUpdate = ( - snapshot: FirebaseFirestoreTypes.DocumentSnapshot, - ) => { - const configData = snapshot.data(); - - const pincodes = configData?.operationalExpertise; - }; - - const handleAvTemplateUpdate = ( - snapshot: FirebaseFirestoreTypes.DocumentSnapshot, - ) => { - const configData = snapshot.data(); - dispatch(updateAvTemplateData(configData as FormTemplateV1)); - }; - - const handleCollectionTemplateUpdate = ( - snapshot: FirebaseFirestoreTypes.DocumentSnapshot, - ) => { - const configData = snapshot.data(); - dispatch(updateCollectionTemplateData(configData as any)); - }; - - const handleForceUninstallUpdate = ( - snapshot: FirebaseFirestoreTypes.DocumentSnapshot, - ) => { - const configData = snapshot.data(); - dispatch(setForceUninstallData(configData)) - }; - - const handleFilterUpdate = ( - snapshot: FirebaseFirestoreTypes.DocumentSnapshot, - ) => { - const filterResponse = snapshot.data(); - filterResponse?.filterComponentList && - dispatch(setFilters(filterResponse.filterComponentList)); - }; - - const handleError = (err: any, collectionPath?: string) => { - const errMsg = `Error while fetching fireStore snapshot: referenceId: ${user?.referenceId} collectionPath: ${collectionPath}`; - logError(err as Error, errMsg) - }; - - const isUserSignedIn = () => { - return auth().currentUser ? true : false; - }; - - const loggedOutCurrentUser = async () => { - await auth().signOut(); + const showCaseUpdationToast = (newlyAddedCases: number, deletedCases: number) => { + let toastConfig: any = null; + let addedCasesText = newlyAddedCases + ? `${newlyAddedCases} new case${newlyAddedCases > 1 ? 's' : ''} allocated` + : ''; + let deletedCasesText = deletedCases + ? `${deletedCases} case${deletedCases > 1 ? 's' : ''} de-allocated` + : ''; + if (newlyAddedCases && deletedCases) { + toastConfig = { + type: 'info', + text1: `${addedCasesText} & ${deletedCasesText}`, + }; + } else if (newlyAddedCases) { + toastConfig = { type: 'success', text1: addedCasesText }; + } else if (deletedCases) { + toastConfig = { type: 'error', text1: deletedCasesText }; } - - const signInUserToFirebase = () => { - if (!sessionDetails) { - return; - } - auth() - .signInWithCustomToken(sessionDetails?.firebaseToken) - .then(userCredential => { - addFirestoreListeners(); - }) - .catch(error => { - logError(error as Error, 'Error in signInUserToFirebase'); - setGlobalUserData({token: '', agentId:'', deviceId:''}); - dispatch( - setAuthData({ - sessionDetails: null, - user: null, - isLoggedIn: false, - }), - ); - toast({ - type: 'error', - text1: ToastMessages.FIRESTORE_SIGNIN_FAILED, - }); - }); - }; - - const subscribeToCollection = (successCb: GenericFunctionArgs, collectionPath: string) => { - return firestore() - .collection(collectionPath) - .onSnapshot(successCb, (err) => handleError(err, collectionPath)); + if (toastConfig) { + toast(toastConfig); } + }; - const subscribeToDoc = (successCb: GenericFunctionArgs, collectionPath: string) => { - return firestore() - .doc(collectionPath) - .onSnapshot(successCb, (err) => handleError(err, collectionPath)); - } - - const subscribeToCases = () => { - const collectionPath = `allocations/${user?.referenceId}/cases`; - return subscribeToCollection(handleCasesUpdate, collectionPath); - - }; - - const subscribeToAvTemplate = () => { - const collectionPath = 'template/template_avs_v2'; - return subscribeToDoc(handleAvTemplateUpdate, collectionPath); - }; - - const subscribeToCollectionTemplate = () => { - const collectionPath = 'template/template_collections_v2'; - return subscribeToDoc(handleCollectionTemplateUpdate, collectionPath); - }; - - const subscribeToForceUninstall = () => { - const collectionPath = 'app-state/force-uninstall'; - return subscribeToDoc(handleForceUninstallUpdate, collectionPath); - }; - - const subscribeToFilters = () => { - const collectionPath = `filters/${user?.referenceId}`; - return subscribeToDoc(handleFilterUpdate, collectionPath); - }; - - const subscribeToUserConfig = () => { - const collectionPath = `config/${user?.referenceId}`; - return subscribeToDoc(handleConfigUpdate, collectionPath); - }; - - const subscribeToFirestore = () => { - addFirestoreListeners(); - configUnsubscribe = subscribeToUserConfig(); - }; - - function addFirestoreListeners() { - casesUnsubscribe = subscribeToCases(); - filterUnsubscribe = subscribeToFilters(); - avTemplateUnSubscriber = subscribeToAvTemplate(); - collectionTemplateUnsubscribe = subscribeToCollectionTemplate(); - } - - useEffect(() => { - if (!isLoggedIn || !sessionDetails?.firebaseToken) { - if (isUserSignedIn()) { - loggedOutCurrentUser(); - } - return; - } - if (isUserSignedIn()) { - subscribeToFirestore(); + const handleCasesUpdate = (querySnapshot: FirebaseFirestoreTypes.QuerySnapshot) => { + let newlyAddedCases = 0; + let deletedCases = 0; + const caseUpdates: CaseUpdates[] = []; + querySnapshot + .docChanges() + .forEach((documentSnapshot: FirebaseFirestoreTypes.DocumentChange) => { + const updateType = documentSnapshot.type; + const updatedCaseDetail = documentSnapshot.doc.data() as CaseDetail; + if (updateType === FirestoreUpdateTypes.ADDED) { + if (!caseDetails[updatedCaseDetail.id]) { + newlyAddedCases++; + caseUpdates.push({ updateType, updatedCaseDetail }); + } } else { - dispatch(setLoading(true)); - signInUserToFirebase(); + if (updateType === FirestoreUpdateTypes.REMOVED) { + deletedCases++; + } + caseUpdates.push({ updateType, updatedCaseDetail }); } - return () => { - casesUnsubscribe && casesUnsubscribe(); - filterUnsubscribe && filterUnsubscribe(); - configUnsubscribe && configUnsubscribe(); - avTemplateUnSubscriber && avTemplateUnSubscriber(); - collectionTemplateUnsubscribe && collectionTemplateUnsubscribe(); - }; - }, [isLoggedIn]); + }); + const isInitialLoad = casesList.length === 0; + dispatch(updateCaseDetailsFirestore({ caseUpdates, isInitialLoad })); + !isInitialLoad && showCaseUpdationToast(newlyAddedCases, deletedCases); + }; - useEffect(()=>{ - forceUninstallUnsubscribe = subscribeToForceUninstall(); - },[]) + const handleConfigUpdate = ( + snapshot: FirebaseFirestoreTypes.DocumentSnapshot + ) => { + const configData = snapshot.data(); + + const pincodes = configData?.operationalExpertise; + }; + + const handleAvTemplateUpdate = ( + snapshot: FirebaseFirestoreTypes.DocumentSnapshot + ) => { + const configData = snapshot.data(); + dispatch(updateAvTemplateData(configData as FormTemplateV1)); + }; + + const handleCollectionTemplateUpdate = ( + snapshot: FirebaseFirestoreTypes.DocumentSnapshot + ) => { + const configData = snapshot.data(); + dispatch(updateCollectionTemplateData(configData as any)); + }; + + const handleForceUninstallUpdate = ( + snapshot: FirebaseFirestoreTypes.DocumentSnapshot + ) => { + const configData = snapshot.data(); + dispatch(setForceUninstallData(configData)); + }; + + const handleFilterUpdate = ( + snapshot: FirebaseFirestoreTypes.DocumentSnapshot + ) => { + const filterResponse = snapshot.data(); + filterResponse?.filterComponentList && dispatch(setFilters(filterResponse.filterComponentList)); + }; + + const handleError = (err: any, collectionPath?: string) => { + const errMsg = `Error while fetching fireStore snapshot: referenceId: ${user?.referenceId} collectionPath: ${collectionPath}`; + logError(err as Error, errMsg); + }; + + const isUserSignedIn = () => { + return auth().currentUser ? true : false; + }; + + const loggedOutCurrentUser = async () => { + await auth().signOut(); + }; + + const signInUserToFirebase = () => { + if (!sessionDetails) { + return; + } + auth() + .signInWithCustomToken(sessionDetails?.firebaseToken) + .then((userCredential) => { + addFirestoreListeners(); + }) + .catch((error) => { + logError(error as Error, 'Error in signInUserToFirebase'); + setGlobalUserData({ token: '', agentId: '', deviceId: '' }); + dispatch( + setAuthData({ + sessionDetails: null, + user: null, + isLoggedIn: false, + }) + ); + toast({ + type: 'error', + text1: ToastMessages.FIRESTORE_SIGNIN_FAILED, + }); + }); + }; + + const subscribeToCollection = (successCb: GenericFunctionArgs, collectionPath: string) => { + return firestore() + .collection(collectionPath) + .onSnapshot(successCb, (err) => handleError(err, collectionPath)); + }; + + const subscribeToDoc = (successCb: GenericFunctionArgs, collectionPath: string) => { + return firestore() + .doc(collectionPath) + .onSnapshot(successCb, (err) => handleError(err, collectionPath)); + }; + + const subscribeToCases = () => { + const collectionPath = `allocations/${user?.referenceId}/cases`; + return subscribeToCollection(handleCasesUpdate, collectionPath); + }; + + const subscribeToAvTemplate = () => { + const collectionPath = 'template/template_avs_v2'; + return subscribeToDoc(handleAvTemplateUpdate, collectionPath); + }; + + const subscribeToCollectionTemplate = () => { + const collectionPath = 'template/template_collections_v2'; + return subscribeToDoc(handleCollectionTemplateUpdate, collectionPath); + }; + + const subscribeToForceUninstall = () => { + const collectionPath = 'app-state/force-uninstall'; + return subscribeToDoc(handleForceUninstallUpdate, collectionPath); + }; + + const subscribeToFilters = () => { + const collectionPath = `filters/${user?.referenceId}`; + return subscribeToDoc(handleFilterUpdate, collectionPath); + }; + + const subscribeToUserConfig = () => { + const collectionPath = `config/${user?.referenceId}`; + return subscribeToDoc(handleConfigUpdate, collectionPath); + }; + + const subscribeToFirestore = () => { + addFirestoreListeners(); + configUnsubscribe = subscribeToUserConfig(); + }; + + function addFirestoreListeners() { + casesUnsubscribe = subscribeToCases(); + filterUnsubscribe = subscribeToFilters(); + avTemplateUnSubscriber = subscribeToAvTemplate(); + collectionTemplateUnsubscribe = subscribeToCollectionTemplate(); + } + + useEffect(() => { + if (!isLoggedIn || !sessionDetails?.firebaseToken) { + if (isUserSignedIn()) { + loggedOutCurrentUser(); + } + return; + } + if (isUserSignedIn()) { + subscribeToFirestore(); + } else { + dispatch(setLoading(true)); + signInUserToFirebase(); + } + return () => { + casesUnsubscribe && casesUnsubscribe(); + filterUnsubscribe && filterUnsubscribe(); + configUnsubscribe && configUnsubscribe(); + avTemplateUnSubscriber && avTemplateUnSubscriber(); + collectionTemplateUnsubscribe && collectionTemplateUnsubscribe(); + }; + }, [isLoggedIn]); + + useEffect(() => { + forceUninstallUnsubscribe = subscribeToForceUninstall(); + }, []); }; export default useFirestoreUpdates; diff --git a/src/mock-api/constants.ts b/src/mock-api/constants.ts index 18a8b4dc..c73a41fb 100644 --- a/src/mock-api/constants.ts +++ b/src/mock-api/constants.ts @@ -1,4 +1,6 @@ -import {BASE_AV_APP_URL} from "../constants/config"; -import {API_URLS, ApiKeys} from "../components/utlis/apiHelper"; +import { BASE_AV_APP_URL } from '../constants/config'; +import { API_URLS, ApiKeys } from '../components/utlis/apiHelper'; -export const addressesGeolocationUrl = `${BASE_AV_APP_URL}/${API_URLS[ApiKeys.ADDRESSES_GEOLOCATION]}` +export const addressesGeolocationUrl = `${BASE_AV_APP_URL}/${ + API_URLS[ApiKeys.ADDRESSES_GEOLOCATION] +}`; diff --git a/src/mock-api/data/addressesGeolocation.ts b/src/mock-api/data/addressesGeolocation.ts index e00acd17..e454f063 100644 --- a/src/mock-api/data/addressesGeolocation.ts +++ b/src/mock-api/data/addressesGeolocation.ts @@ -1,262 +1,260 @@ export const addressesGeolocationData = { - addressL1ViewList: [ + addressL1ViewList: [ + { + addressDTO: { + id: '34b2d8cff7001558c533c7ae771ff613', + customerReferenceId: '0d5e4bc7-5365-4d6d-ac73-cad7c0125f61', + externalReferenceId: null, + addressText: + '102 Ground Floor, HSR layout, 27th main, Near IIM Bangalore, 560265, 102 Ground Floor, Sector Main, 560102,', + pinCode: '400029', + city: 'Banglore', + state: 'Maharashtra', + isCurrent: false, + isPermanent: false, + primarySource: 'CIBIL_SCRUB', + secondarySource: 'CIBIL_MASTER_CIBIL_PORTFOLIO', + type: 'RESIDENCE', + consumptionDate: '2022-05-31', + latitude: null, + longitude: null, + verified: null, + visited: null, + groupIdentifier: '1', + createdAt: '2023-01-30T09:06:45.365+00:00', + updatedAt: '2023-01-30T09:06:45.365+00:00', + }, + similarAddresses: [], + matchingGeoLocations: [ { - addressDTO: { - id: '34b2d8cff7001558c533c7ae771ff613', - customerReferenceId: '0d5e4bc7-5365-4d6d-ac73-cad7c0125f61', - externalReferenceId: null, - addressText: '102 Ground Floor, HSR layout, 27th main, Near IIM Bangalore, 560265, 102 Ground Floor, Sector Main, 560102,', - pinCode: '400029', - city: 'Banglore', - state: 'Maharashtra', - isCurrent: false, - isPermanent: false, - primarySource: 'CIBIL_SCRUB', - secondarySource: 'CIBIL_MASTER_CIBIL_PORTFOLIO', - type: 'RESIDENCE', - consumptionDate: '2022-05-31', - latitude: null, - longitude: null, - verified: null, - visited: null, - groupIdentifier: '1', - createdAt: '2023-01-30T09:06:45.365+00:00', - updatedAt: '2023-01-30T09:06:45.365+00:00', - }, - similarAddresses: [], - matchingGeoLocations: [ - { - latitude: 13.7423956, - longitude: 76.9013917, - timeStamp: 1677013654426, - }, - { - latitude: 13.7423956, - longitude: 76.9013917, - timeStamp: 1677013654426, - }, - { - latitude: 13.7423956, - longitude: 76.9013917, - timeStamp: 1677013654426, - } - ], + latitude: 13.7423956, + longitude: 76.9013917, + timeStamp: 1677013654426, }, { - addressDTO: { - id: 'ff3a75377fc24e04bb03b2f571e41c37', - customerReferenceId: '0d5e4bc7-5365-4d6d-ac73-cad7c0125f61', - externalReferenceId: null, - addressText: '102 Ground Floor, HSR layout, 27th main, Near IIM Bangalore, 560265, 102 Ground Floor, Sector Main, 560102,', - pinCode: null, - city: 'Not Bangalore', - state: null, - isCurrent: null, - isPermanent: null, - primarySource: 'LONGHORN', - secondarySource: 'COLLECTION_SERVICE', - type: null, - consumptionDate: null, - latitude: 13.742393, - longitude: 76.9013919, - verified: null, - visited: true, - groupIdentifier: null, - createdAt: '2023-01-27T14:56:13.765+00:00', - updatedAt: '2023-02-14T10:04:54.380+00:00', - }, - similarAddresses: [ - { - addressDTO: { - id: 'ff69e7ae4642451a9a944abd55c02d8b', - customerReferenceId: - '0d5e4bc7-5365-4d6d-ac73-cad7c0125f61', - externalReferenceId: null, - addressText: '102 Ground Floor, HSR layout, 27th main, Near IIM Bangalore, 560265, 102 Ground Floor, Sector Main, 560102,', - pinCode: null, - city: 'qwerty', - state: null, - isCurrent: null, - isPermanent: null, - primarySource: 'LONGHORN', - secondarySource: 'COLLECTION_SERVICE', - type: null, - consumptionDate: null, - latitude: 12.9344698, - longitude: 77.6179804, - verified: null, - visited: true, - groupIdentifier: null, - createdAt: '2023-01-18T09:09:05.775+00:00', - updatedAt: '2023-01-27T14:29:40.832+00:00', - }, - }, - { - addressDTO: { - id: 'dc0feed3cc784a01873ff500a7b3f968', - customerReferenceId: - '0d5e4bc7-5365-4d6d-ac73-cad7c0125f61', - externalReferenceId: null, - addressText: '102 Ground Floor, HSR layout, 27th main, Near IIM Bangalore, 560265, 102 Ground Floor, Sector Main, 560102,', - pinCode: null, - city: 'qwerty', - state: null, - isCurrent: null, - isPermanent: null, - primarySource: 'LONGHORN', - secondarySource: 'COLLECTION_SERVICE', - type: null, - consumptionDate: null, - latitude: 12.9344698, - longitude: 77.6179804, - verified: null, - visited: true, - groupIdentifier: null, - createdAt: '2023-01-18T09:09:05.770+00:00', - updatedAt: '2023-01-27T14:29:40.750+00:00', - }, - }, - { - addressDTO: { - id: 'c2c2e91c39594b32937b3e54af2263d4', - customerReferenceId: - '0d5e4bc7-5365-4d6d-ac73-cad7c0125f61', - externalReferenceId: null, - addressText: '102 Ground Floor, HSR layout, 27th main, Near IIM Bangalore, 560265, 102 Ground Floor, Sector Main, 560102,', - pinCode: null, - city: 'qwerty', - state: null, - isCurrent: null, - isPermanent: null, - primarySource: 'LONGHORN', - secondarySource: 'COLLECTION_SERVICE', - type: null, - consumptionDate: null, - latitude: null, - longitude: null, - verified: null, - visited: true, - groupIdentifier: null, - createdAt: '2023-01-18T09:08:30.957+00:00', - updatedAt: '2023-01-27T14:29:40.720+00:00', - }, - }, - { - addressDTO: { - id: 'f7d31ebd1decbf05be8d955b93fb306d', - customerReferenceId: - '0d5e4bc7-5365-4d6d-ac73-cad7c0125f61', - externalReferenceId: - '8d4eca6c-53b2-491c-80c0-c5204b63afda', - addressText: '102 Ground Floor, HSR layout, 27th main, Near IIM Bangalore, 560265, 102 Ground Floor, Sector Main, 560102,', + latitude: 13.7423956, + longitude: 76.9013917, + timeStamp: 1677013654426, + }, + { + latitude: 13.7423956, + longitude: 76.9013917, + timeStamp: 1677013654426, + }, + ], + }, + { + addressDTO: { + id: 'ff3a75377fc24e04bb03b2f571e41c37', + customerReferenceId: '0d5e4bc7-5365-4d6d-ac73-cad7c0125f61', + externalReferenceId: null, + addressText: + '102 Ground Floor, HSR layout, 27th main, Near IIM Bangalore, 560265, 102 Ground Floor, Sector Main, 560102,', + pinCode: null, + city: 'Not Bangalore', + state: null, + isCurrent: null, + isPermanent: null, + primarySource: 'LONGHORN', + secondarySource: 'COLLECTION_SERVICE', + type: null, + consumptionDate: null, + latitude: 13.742393, + longitude: 76.9013919, + verified: null, + visited: true, + groupIdentifier: null, + createdAt: '2023-01-27T14:56:13.765+00:00', + updatedAt: '2023-02-14T10:04:54.380+00:00', + }, + similarAddresses: [ + { + addressDTO: { + id: 'ff69e7ae4642451a9a944abd55c02d8b', + customerReferenceId: '0d5e4bc7-5365-4d6d-ac73-cad7c0125f61', + externalReferenceId: null, + addressText: + '102 Ground Floor, HSR layout, 27th main, Near IIM Bangalore, 560265, 102 Ground Floor, Sector Main, 560102,', + pinCode: null, + city: 'qwerty', + state: null, + isCurrent: null, + isPermanent: null, + primarySource: 'LONGHORN', + secondarySource: 'COLLECTION_SERVICE', + type: null, + consumptionDate: null, + latitude: 12.9344698, + longitude: 77.6179804, + verified: null, + visited: true, + groupIdentifier: null, + createdAt: '2023-01-18T09:09:05.775+00:00', + updatedAt: '2023-01-27T14:29:40.832+00:00', + }, + }, + { + addressDTO: { + id: 'dc0feed3cc784a01873ff500a7b3f968', + customerReferenceId: '0d5e4bc7-5365-4d6d-ac73-cad7c0125f61', + externalReferenceId: null, + addressText: + '102 Ground Floor, HSR layout, 27th main, Near IIM Bangalore, 560265, 102 Ground Floor, Sector Main, 560102,', + pinCode: null, + city: 'qwerty', + state: null, + isCurrent: null, + isPermanent: null, + primarySource: 'LONGHORN', + secondarySource: 'COLLECTION_SERVICE', + type: null, + consumptionDate: null, + latitude: 12.9344698, + longitude: 77.6179804, + verified: null, + visited: true, + groupIdentifier: null, + createdAt: '2023-01-18T09:09:05.770+00:00', + updatedAt: '2023-01-27T14:29:40.750+00:00', + }, + }, + { + addressDTO: { + id: 'c2c2e91c39594b32937b3e54af2263d4', + customerReferenceId: '0d5e4bc7-5365-4d6d-ac73-cad7c0125f61', + externalReferenceId: null, + addressText: + '102 Ground Floor, HSR layout, 27th main, Near IIM Bangalore, 560265, 102 Ground Floor, Sector Main, 560102,', + pinCode: null, + city: 'qwerty', + state: null, + isCurrent: null, + isPermanent: null, + primarySource: 'LONGHORN', + secondarySource: 'COLLECTION_SERVICE', + type: null, + consumptionDate: null, + latitude: null, + longitude: null, + verified: null, + visited: true, + groupIdentifier: null, + createdAt: '2023-01-18T09:08:30.957+00:00', + updatedAt: '2023-01-27T14:29:40.720+00:00', + }, + }, + { + addressDTO: { + id: 'f7d31ebd1decbf05be8d955b93fb306d', + customerReferenceId: '0d5e4bc7-5365-4d6d-ac73-cad7c0125f61', + externalReferenceId: '8d4eca6c-53b2-491c-80c0-c5204b63afda', + addressText: + '102 Ground Floor, HSR layout, 27th main, Near IIM Bangalore, 560265, 102 Ground Floor, Sector Main, 560102,', - pinCode: '400098', - city: null, - state: null, - isCurrent: false, - isPermanent: false, - primarySource: 'MMI', - secondarySource: 'CUSTOMER_SERVICE', - type: 'MMI', - consumptionDate: null, - latitude: null, - longitude: null, - verified: null, - visited: null, - groupIdentifier: null, - createdAt: '2023-01-30T09:07:25.060+00:00', - updatedAt: '2023-01-30T09:07:25.060+00:00', - }, - }, - { - addressDTO: { - id: 'ca5309f3055a08b98ce9747dce0b9a51', - customerReferenceId: - '0d5e4bc7-5365-4d6d-ac73-cad7c0125f61', - externalReferenceId: - '1f7db9e2-c590-489f-a587-0b9e0450bca5', - addressText: null, - pinCode: '400098', - city: null, - state: null, - isCurrent: false, - isPermanent: false, - primarySource: 'MMI', - secondarySource: 'CUSTOMER_SERVICE', - type: 'MMI', - consumptionDate: null, - latitude: null, - longitude: null, - verified: null, - visited: null, - groupIdentifier: null, - createdAt: '2023-01-30T09:07:54.235+00:00', - updatedAt: '2023-01-30T09:07:54.235+00:00', - }, - }, - { - addressDTO: { - id: '03501abc590d4e88afa5e2ea625a9a78', - customerReferenceId: - '0d5e4bc7-5365-4d6d-ac73-cad7c0125f61', - externalReferenceId: null, - addressText: 'asd\nasd', - pinCode: null, - city: '12', - state: null, - isCurrent: null, - isPermanent: null, - primarySource: 'LONGHORN', - secondarySource: 'COLLECTION_SERVICE', - type: null, - consumptionDate: null, - latitude: 13.7423956, - longitude: 76.9013917, - verified: null, - visited: null, - groupIdentifier: null, - createdAt: '2023-01-27T13:39:01.720+00:00', - updatedAt: '2023-01-27T13:39:01.720+00:00', - }, - }, - ], - matchingGeoLocations: [ - { - latitude: 13.7423956, - longitude: 76.9013917, - timeStamp: 1677013654426, - }, - { - latitude: 13.7423956, - longitude: 76.9013917, - timeStamp: 1677013654426, - }, - { - latitude: 13.7423956, - longitude: 76.9013917, - timeStamp: 1677013654426, - } - ], - }, - ], - unmatchedGeoLocations: [ - { - latitude: 13.7423956, - longitude: 76.9013917, - timeStamp: 1677013654426, - distanceFromAgent: 1 + pinCode: '400098', + city: null, + state: null, + isCurrent: false, + isPermanent: false, + primarySource: 'MMI', + secondarySource: 'CUSTOMER_SERVICE', + type: 'MMI', + consumptionDate: null, + latitude: null, + longitude: null, + verified: null, + visited: null, + groupIdentifier: null, + createdAt: '2023-01-30T09:07:25.060+00:00', + updatedAt: '2023-01-30T09:07:25.060+00:00', + }, }, { - latitude: 13.7423956, - longitude: 76.9013917, - timeStamp: 1677013654426, - distanceFromAgent: 1 + addressDTO: { + id: 'ca5309f3055a08b98ce9747dce0b9a51', + customerReferenceId: '0d5e4bc7-5365-4d6d-ac73-cad7c0125f61', + externalReferenceId: '1f7db9e2-c590-489f-a587-0b9e0450bca5', + addressText: null, + pinCode: '400098', + city: null, + state: null, + isCurrent: false, + isPermanent: false, + primarySource: 'MMI', + secondarySource: 'CUSTOMER_SERVICE', + type: 'MMI', + consumptionDate: null, + latitude: null, + longitude: null, + verified: null, + visited: null, + groupIdentifier: null, + createdAt: '2023-01-30T09:07:54.235+00:00', + updatedAt: '2023-01-30T09:07:54.235+00:00', + }, }, { + addressDTO: { + id: '03501abc590d4e88afa5e2ea625a9a78', + customerReferenceId: '0d5e4bc7-5365-4d6d-ac73-cad7c0125f61', + externalReferenceId: null, + addressText: 'asd\nasd', + pinCode: null, + city: '12', + state: null, + isCurrent: null, + isPermanent: null, + primarySource: 'LONGHORN', + secondarySource: 'COLLECTION_SERVICE', + type: null, + consumptionDate: null, latitude: 13.7423956, longitude: 76.9013917, - timeStamp: 1677013654426, - distanceFromAgent: 1 - } - ], + verified: null, + visited: null, + groupIdentifier: null, + createdAt: '2023-01-27T13:39:01.720+00:00', + updatedAt: '2023-01-27T13:39:01.720+00:00', + }, + }, + ], + matchingGeoLocations: [ + { + latitude: 13.7423956, + longitude: 76.9013917, + timeStamp: 1677013654426, + }, + { + latitude: 13.7423956, + longitude: 76.9013917, + timeStamp: 1677013654426, + }, + { + latitude: 13.7423956, + longitude: 76.9013917, + timeStamp: 1677013654426, + }, + ], + }, + ], + unmatchedGeoLocations: [ + { + latitude: 13.7423956, + longitude: 76.9013917, + timeStamp: 1677013654426, + distanceFromAgent: 1, + }, + { + latitude: 13.7423956, + longitude: 76.9013917, + timeStamp: 1677013654426, + distanceFromAgent: 1, + }, + { + latitude: 13.7423956, + longitude: 76.9013917, + timeStamp: 1677013654426, + distanceFromAgent: 1, + }, + ], }; diff --git a/src/mock-api/data/caseDetail.ts b/src/mock-api/data/caseDetail.ts index fe1b1456..fed289da 100644 --- a/src/mock-api/data/caseDetail.ts +++ b/src/mock-api/data/caseDetail.ts @@ -1,210 +1,209 @@ export const caseDetailMockData = [ - { - id: '450233d6-58c8-45c0-b814-175e18386f41', - caseStatus: 'ASSIGNED', - createdAt: 1674016478376, - updatedAt: 1674016503049, - allocatedAt: 1674016503039, - loanDetails: { - loanAccountNumber: '010000077710', - disbursalDate: 1669334400000, - disbursementAmount: 50000, - firstDueDate: 1671321600000, - tenureMonths: 20, - loanType: 'PERSONAL_LOAN', - loanAccountStatus: 'ACTIVE', - productCode: 'PL-0001', - }, - customerInfo: { - customerReferenceId: '50d9577e-bbc4-4c23-8bbb-7dda5f71d97b', - customerName: 'Jeel Gajera', - primaryPhoneNumber: '9901353325', - imageURL: - 'https://s3.ap-south-1.amazonaws.com/navi-d5a6c37adb7e06d06401aba47fe07bf3/prod/55556b6b-9a19-4d2b-ac71-519599c35cef?X-Amz-Security-Token=IQoJb3JpZ2luX2VjEHsaCXVzLWVhc3QtMSJIMEYCIQD9nl79blCjgLKlGt7aw2UIYw3wGKNfh%2Bwxuuz3Qy4OfwIhAKzG8jdQ8kAmmtPlsw8acMVENHPyxLbmacRoTy9ijgy9KrICCBMQARoMNTcxMzE1MDc2NzYyIgyayYE5cOrRZyLcCBMqjwKeO3foMwJskwZJU7xg%2B%2BZe8lgplHXXwrfKl9NJ2ARaiePUM5ehpScToi7jIm7pbHeJaSiaKAhrqbIl%2Fw8BtFBJ7MPJ5oiaU6ACm7eWEnHPseIFA022LA8y41C56S7T%2F6fhkVkY9dfiOAewtbRK0KwuHlBPeuNJu3uKJNu1QyY%2BA0cXtrxlKyuE5e2KVO06L7zUsKOXGvEnLkLbdTWIIj4DWBwiCZqgbsmfcxJPwdlRgBrC2Y%2F8v6DQLucAapU1cNfYFvGW%2BLZDJuNOs4j7gKfCSAOLeFCX2dFDgaz7fx6F1FnGJG%2B79pz%2BtvdOXEy%2F8btoRNgLgIdd%2BOOyikDa5k6z%2B8rWT0oqprRUKEuRomvBMJvArZ8GOpwBPDn%2FGw1gCSG9ECbrcAbtDLQ36pL8WOVBKJlEELQMNtGf6ZocrjzaHZISF6mltJjIp5EfUKEXf0Nl6TkrTYkqYecqWLkKPl3mqgeskxRKc4yGfdVcq7IQNdyOFuYkZTyg24hgVzbiprZtLUWnNunlIHShqrNvoCmoBB81V2PJ9sc%2FdsrUW5%2BR3h0YjJEbEoSzu9aHRBBp6Q0N0AHE&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20230214T103300Z&X-Amz-SignedHeaders=host&X-Amz-Expires=43199&X-Amz-Credential=ASIAYKBIIH2NNHF73EDM%2F20230214%2Fap-south-1%2Fs3%2Faws4_request&X-Amz-Signature=d4350d588f96ebf72d7a4d02df32bb55d098c368732a075e81ab55069f2ef80c', - geoLocation: 'https://maps.google.com/?q=21.2188024,72.8937695', - }, - tasks: [ - { - taskId: 221, - taskType: 'COMMUNICATION_ADDRESS_VERIFICATION_TASK', - metadata: { - type: 'address', - address: { - referenceId: null, - houseNumber: '156 GOKUL NAGAR SOCIETY', - lineOne: null, - lineTwo: null, - locality: 'ROAD VARACHHA SURAT CITY', - street: 'NEAR RACHNA SOCIETY L H', - city: 'Surat', - state: 'GJ', - pinCode: '576109', - type: null, - source: 'CUSTOMER', - current: true, - permanent: false, - zipCode: null, - addressQualityStatus: null, - }, - addressLine: - '156 GOKUL NAGAR SOCIETY,ROAD VARACHHA SURAT CITY,NEAR RACHNA SOCIETY L H,Surat,GJ,576109', - }, - }, - { - taskId: 222, - taskType: 'PERMANENT_ADDRESS_VERIFICATION_TASK', - metadata: { - type: 'address', - address: { - referenceId: null, - houseNumber: '156 GOKUL NAGAR SOCIETY', - lineOne: null, - lineTwo: null, - locality: 'NEAR RACHNA SOCIETY L H', - street: 'ROAD VARACHHA SURAT CITY', - city: 'Surat', - state: 'GJ', - pinCode: '576107', - type: null, - source: 'CKYC', - current: false, - permanent: true, - zipCode: null, - addressQualityStatus: null, - }, - addressLine: - '156 GOKUL NAGAR SOCIETY,NEAR RACHNA SOCIETY L H,ROAD VARACHHA SURAT CITY,Surat,GJ,576107', - }, - }, - { - taskId: 223, - taskType: 'GEO_LOCATION_VERIFICATION_TASK', - metadata: { - type: 'geo', - geoLocation: - 'https://maps.google.com/?q=21.2188024,72.8937695', - }, - }, - { - taskId: 224, - taskType: 'CALLING_TASK', - metadata: { type: 'calling', primaryPhoneNumber: '9901353325' }, - }, - { - taskId: 225, - taskType: 'NEW_ADDRESS_VERIFICATION_TASK', - metadata: null, - }, - ], - context: null, - currentAllocationReferenceId: '67b34cb2-ccc4-4aae-bc39-778cbdd563d2', - currentAgentId: '598e3ab3-5870-43c5-a9d5-d3f18388c1a7', - taskSequence: [ - 'COMMUNICATION_ADDRESS_VERIFICATION_TASK', - 'PERMANENT_ADDRESS_VERIFICATION_TASK', - 'GEO_LOCATION_VERIFICATION_TASK', - 'CALLING_TASK', - 'NEW_ADDRESS_VERIFICATION_TASK', - ], - currentTask: 'COMMUNICATION_ADDRESS_VERIFICATION_TASK', + { + id: '450233d6-58c8-45c0-b814-175e18386f41', + caseStatus: 'ASSIGNED', + createdAt: 1674016478376, + updatedAt: 1674016503049, + allocatedAt: 1674016503039, + loanDetails: { + loanAccountNumber: '010000077710', + disbursalDate: 1669334400000, + disbursementAmount: 50000, + firstDueDate: 1671321600000, + tenureMonths: 20, + loanType: 'PERSONAL_LOAN', + loanAccountStatus: 'ACTIVE', + productCode: 'PL-0001', }, - { - id: '450233d6-58c8-45c0-b814-175e18386f45', - updatedAt: 1674474231951, - allocatedAt: 1674016504968, - caseStatus: 'ACTIVE', - caseReferenceId: '45f2e0e8-fb2f-4d4f-aa95-4030afd28da9', - customerName: 'Manoj Kumar', - dpdBucket: '30-60', - caseType: 'COLLECTION_CASE', - pos: 70173.57, - addressString: - 'BARRACKPORE(M) BARRACKPORE, NORTH, C M SAHA ROAD, MONIRAMPORE, NORTH, Barrackpore, WEST BENGAL, 700120', - addresses: [ - { - referenceId: 'cdfa0a17-790c-41bf-a745-7c44a2fbc9ac', - addressReferenceId: 'fcbc99bb-9f7e-4a36-9183-723359c5a5fc', - lineOne: 'BARRACKPORE(M) BARRACKPORE, NORTH', - lineTwo: 'C M SAHA ROAD, MONIRAMPORE, NORTH', - city: 'Barrackpore', - state: 'WEST BENGAL', - pinCode: '700120', - current: false, - permanent: false, - type: 'CORRESPONDENCE', - source: 'PRIMARY', - addressQualityStatus: null, - collectionCaseId: 711260, - signals: null, - location: null, - }, - ], - customerReferenceId: 'dadada60-cedb-44f9-90e3-54920c215ffc', - documents: [ - { - referenceId: '13e59219-6ae5-4b76-9546-88c194a90aaf', - uri: 'https://s3.ap-south-1.amazonaws.com/navi-8af22e75d3ad3bd252215069b16a75dc/prod/45fcb4e6-8a28-44cf-83d2-f1f4ecec08de?X-Amz-Security-Token=FwoGZXIvYXdzEHIaDPgmIUpLhzA7q0TTFiLLARhdLI4snCE8w6Ym91%2BA%2FWui%2FAe056BY18TJQSjlvxsxv2rqs5Iv3Vbi6ZejDxFujAKhYemnPUvJiMfnClh6DPyrUL9Bbktx16n5I1b5sgB3JFVHD2V%2FAiSdIGcQm3JWbHw%2FUziDZQwHOn0Ky1HpZpKUtNHvFX1%2BXs8teXm7hw%2BWfuSolb89BwO766VCAiKYntUiRbDHJnuoCOOCFdjEchh6rOfNj2lLDWWIoRG%2FA0kSQoxpg44%2FG4kh2kb9oc8D6axMsRhHpq%2BET8v9KI3yp58GMi3oPCBEpb%2BU7PCclh2eYGw2tROj9bjwHQ%2Bd8TYshKGt61VdkjEamtVkuzbwpq4%3D&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20230213T090839Z&X-Amz-SignedHeaders=host&X-Amz-Expires=86400&X-Amz-Credential=ASIAXFRMTTJPXEBQOWXV%2F20230213%2Fap-south-1%2Fs3%2Faws4_request&X-Amz-Signature=32acb064356397c47ba39ae3c102f7145ba5610a939009ebaf3976ea707742a3', - type: 'SELFIE', - }, - { - referenceId: '0d1e8180-9618-4235-aab5-1a163ccd13cd', - uri: 'https://s3.ap-south-1.amazonaws.com/navi-8af22e75d3ad3bd252215069b16a75dc/prod/30dc3faa-049f-426b-9325-0d386a2131c9?X-Amz-Security-Token=FwoGZXIvYXdzEHIaDPgmIUpLhzA7q0TTFiLLARhdLI4snCE8w6Ym91%2BA%2FWui%2FAe056BY18TJQSjlvxsxv2rqs5Iv3Vbi6ZejDxFujAKhYemnPUvJiMfnClh6DPyrUL9Bbktx16n5I1b5sgB3JFVHD2V%2FAiSdIGcQm3JWbHw%2FUziDZQwHOn0Ky1HpZpKUtNHvFX1%2BXs8teXm7hw%2BWfuSolb89BwO766VCAiKYntUiRbDHJnuoCOOCFdjEchh6rOfNj2lLDWWIoRG%2FA0kSQoxpg44%2FG4kh2kb9oc8D6axMsRhHpq%2BET8v9KI3yp58GMi3oPCBEpb%2BU7PCclh2eYGw2tROj9bjwHQ%2Bd8TYshKGt61VdkjEamtVkuzbwpq4%3D&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20230213T090839Z&X-Amz-SignedHeaders=host&X-Amz-Expires=86400&X-Amz-Credential=ASIAXFRMTTJPXEBQOWXV%2F20230213%2Fap-south-1%2Fs3%2Faws4_request&X-Amz-Signature=06acb56621f25e525078684d5c7c2033148ea1758443e54cadf995ad1794a41f', - type: 'aadhar_photo', - }, - ], - imageUrl: - 'https://s3.ap-south-1.amazonaws.com/navi-8af22e75d3ad3bd252215069b16a75dc/prod/45fcb4e6-8a28-44cf-83d2-f1f4ecec08de?X-Amz-Security-Token=FwoGZXIvYXdzEHIaDPgmIUpLhzA7q0TTFiLLARhdLI4snCE8w6Ym91%2BA%2FWui%2FAe056BY18TJQSjlvxsxv2rqs5Iv3Vbi6ZejDxFujAKhYemnPUvJiMfnClh6DPyrUL9Bbktx16n5I1b5sgB3JFVHD2V%2FAiSdIGcQm3JWbHw%2FUziDZQwHOn0Ky1HpZpKUtNHvFX1%2BXs8teXm7hw%2BWfuSolb89BwO766VCAiKYntUiRbDHJnuoCOOCFdjEchh6rOfNj2lLDWWIoRG%2FA0kSQoxpg44%2FG4kh2kb9oc8D6axMsRhHpq%2BET8v9KI3yp58GMi3oPCBEpb%2BU7PCclh2eYGw2tROj9bjwHQ%2Bd8TYshKGt61VdkjEamtVkuzbwpq4%3D&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20230213T090839Z&X-Amz-SignedHeaders=host&X-Amz-Expires=86400&X-Amz-Credential=ASIAXFRMTTJPXEBQOWXV%2F20230213%2Fap-south-1%2Fs3%2Faws4_request&X-Amz-Signature=32acb064356397c47ba39ae3c102f7145ba5610a939009ebaf3976ea707742a3', - phoneNumbers: [ - { - type: 'OFFICE_PHONE', - source: 'BUREAU', - sourceText: 'Credit Bureau Scrub', - number: '9125591080', - valid: true, - telephoneScore: -1, - havingMaximumScore: false, - callHistory: null, - createdAt: '2022-02-26T13:48:00.819969', - new: true, - }, - { - type: 'OFFICE_PHONE', - source: 'BUREAU', - sourceText: 'Credit Bureau Scrub', - number: '8792044101', - valid: true, - telephoneScore: -1, - havingMaximumScore: false, - callHistory: null, - createdAt: '2022-02-26T13:48:00.819969', - new: true, - }, - { - type: '', - source: 'PRIMARY', - sourceText: 'Primary Contact', - number: '9620174791', - valid: true, - telephoneScore: 100, - havingMaximumScore: true, - callHistory: null, - createdAt: null, - new: true, - }, - { - type: 'MOBILE_PHONE', - source: 'BUREAU', - sourceText: 'Credit Bureau Scrub', - number: '9855855888', - valid: true, - telephoneScore: -1, - havingMaximumScore: false, - callHistory: null, - createdAt: '2022-02-26T13:48:00.819969', - new: true, - }, - ], - currentOutstandingEmi: 7017.57, - totalOverdueEmis: 12, + customerInfo: { + customerReferenceId: '50d9577e-bbc4-4c23-8bbb-7dda5f71d97b', + customerName: 'Jeel Gajera', + primaryPhoneNumber: '9901353325', + imageURL: + 'https://s3.ap-south-1.amazonaws.com/navi-d5a6c37adb7e06d06401aba47fe07bf3/prod/55556b6b-9a19-4d2b-ac71-519599c35cef?X-Amz-Security-Token=IQoJb3JpZ2luX2VjEHsaCXVzLWVhc3QtMSJIMEYCIQD9nl79blCjgLKlGt7aw2UIYw3wGKNfh%2Bwxuuz3Qy4OfwIhAKzG8jdQ8kAmmtPlsw8acMVENHPyxLbmacRoTy9ijgy9KrICCBMQARoMNTcxMzE1MDc2NzYyIgyayYE5cOrRZyLcCBMqjwKeO3foMwJskwZJU7xg%2B%2BZe8lgplHXXwrfKl9NJ2ARaiePUM5ehpScToi7jIm7pbHeJaSiaKAhrqbIl%2Fw8BtFBJ7MPJ5oiaU6ACm7eWEnHPseIFA022LA8y41C56S7T%2F6fhkVkY9dfiOAewtbRK0KwuHlBPeuNJu3uKJNu1QyY%2BA0cXtrxlKyuE5e2KVO06L7zUsKOXGvEnLkLbdTWIIj4DWBwiCZqgbsmfcxJPwdlRgBrC2Y%2F8v6DQLucAapU1cNfYFvGW%2BLZDJuNOs4j7gKfCSAOLeFCX2dFDgaz7fx6F1FnGJG%2B79pz%2BtvdOXEy%2F8btoRNgLgIdd%2BOOyikDa5k6z%2B8rWT0oqprRUKEuRomvBMJvArZ8GOpwBPDn%2FGw1gCSG9ECbrcAbtDLQ36pL8WOVBKJlEELQMNtGf6ZocrjzaHZISF6mltJjIp5EfUKEXf0Nl6TkrTYkqYecqWLkKPl3mqgeskxRKc4yGfdVcq7IQNdyOFuYkZTyg24hgVzbiprZtLUWnNunlIHShqrNvoCmoBB81V2PJ9sc%2FdsrUW5%2BR3h0YjJEbEoSzu9aHRBBp6Q0N0AHE&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20230214T103300Z&X-Amz-SignedHeaders=host&X-Amz-Expires=43199&X-Amz-Credential=ASIAYKBIIH2NNHF73EDM%2F20230214%2Fap-south-1%2Fs3%2Faws4_request&X-Amz-Signature=d4350d588f96ebf72d7a4d02df32bb55d098c368732a075e81ab55069f2ef80c', + geoLocation: 'https://maps.google.com/?q=21.2188024,72.8937695', }, + tasks: [ + { + taskId: 221, + taskType: 'COMMUNICATION_ADDRESS_VERIFICATION_TASK', + metadata: { + type: 'address', + address: { + referenceId: null, + houseNumber: '156 GOKUL NAGAR SOCIETY', + lineOne: null, + lineTwo: null, + locality: 'ROAD VARACHHA SURAT CITY', + street: 'NEAR RACHNA SOCIETY L H', + city: 'Surat', + state: 'GJ', + pinCode: '576109', + type: null, + source: 'CUSTOMER', + current: true, + permanent: false, + zipCode: null, + addressQualityStatus: null, + }, + addressLine: + '156 GOKUL NAGAR SOCIETY,ROAD VARACHHA SURAT CITY,NEAR RACHNA SOCIETY L H,Surat,GJ,576109', + }, + }, + { + taskId: 222, + taskType: 'PERMANENT_ADDRESS_VERIFICATION_TASK', + metadata: { + type: 'address', + address: { + referenceId: null, + houseNumber: '156 GOKUL NAGAR SOCIETY', + lineOne: null, + lineTwo: null, + locality: 'NEAR RACHNA SOCIETY L H', + street: 'ROAD VARACHHA SURAT CITY', + city: 'Surat', + state: 'GJ', + pinCode: '576107', + type: null, + source: 'CKYC', + current: false, + permanent: true, + zipCode: null, + addressQualityStatus: null, + }, + addressLine: + '156 GOKUL NAGAR SOCIETY,NEAR RACHNA SOCIETY L H,ROAD VARACHHA SURAT CITY,Surat,GJ,576107', + }, + }, + { + taskId: 223, + taskType: 'GEO_LOCATION_VERIFICATION_TASK', + metadata: { + type: 'geo', + geoLocation: 'https://maps.google.com/?q=21.2188024,72.8937695', + }, + }, + { + taskId: 224, + taskType: 'CALLING_TASK', + metadata: { type: 'calling', primaryPhoneNumber: '9901353325' }, + }, + { + taskId: 225, + taskType: 'NEW_ADDRESS_VERIFICATION_TASK', + metadata: null, + }, + ], + context: null, + currentAllocationReferenceId: '67b34cb2-ccc4-4aae-bc39-778cbdd563d2', + currentAgentId: '598e3ab3-5870-43c5-a9d5-d3f18388c1a7', + taskSequence: [ + 'COMMUNICATION_ADDRESS_VERIFICATION_TASK', + 'PERMANENT_ADDRESS_VERIFICATION_TASK', + 'GEO_LOCATION_VERIFICATION_TASK', + 'CALLING_TASK', + 'NEW_ADDRESS_VERIFICATION_TASK', + ], + currentTask: 'COMMUNICATION_ADDRESS_VERIFICATION_TASK', + }, + { + id: '450233d6-58c8-45c0-b814-175e18386f45', + updatedAt: 1674474231951, + allocatedAt: 1674016504968, + caseStatus: 'ACTIVE', + caseReferenceId: '45f2e0e8-fb2f-4d4f-aa95-4030afd28da9', + customerName: 'Manoj Kumar', + dpdBucket: '30-60', + caseType: 'COLLECTION_CASE', + pos: 70173.57, + addressString: + 'BARRACKPORE(M) BARRACKPORE, NORTH, C M SAHA ROAD, MONIRAMPORE, NORTH, Barrackpore, WEST BENGAL, 700120', + addresses: [ + { + referenceId: 'cdfa0a17-790c-41bf-a745-7c44a2fbc9ac', + addressReferenceId: 'fcbc99bb-9f7e-4a36-9183-723359c5a5fc', + lineOne: 'BARRACKPORE(M) BARRACKPORE, NORTH', + lineTwo: 'C M SAHA ROAD, MONIRAMPORE, NORTH', + city: 'Barrackpore', + state: 'WEST BENGAL', + pinCode: '700120', + current: false, + permanent: false, + type: 'CORRESPONDENCE', + source: 'PRIMARY', + addressQualityStatus: null, + collectionCaseId: 711260, + signals: null, + location: null, + }, + ], + customerReferenceId: 'dadada60-cedb-44f9-90e3-54920c215ffc', + documents: [ + { + referenceId: '13e59219-6ae5-4b76-9546-88c194a90aaf', + uri: 'https://s3.ap-south-1.amazonaws.com/navi-8af22e75d3ad3bd252215069b16a75dc/prod/45fcb4e6-8a28-44cf-83d2-f1f4ecec08de?X-Amz-Security-Token=FwoGZXIvYXdzEHIaDPgmIUpLhzA7q0TTFiLLARhdLI4snCE8w6Ym91%2BA%2FWui%2FAe056BY18TJQSjlvxsxv2rqs5Iv3Vbi6ZejDxFujAKhYemnPUvJiMfnClh6DPyrUL9Bbktx16n5I1b5sgB3JFVHD2V%2FAiSdIGcQm3JWbHw%2FUziDZQwHOn0Ky1HpZpKUtNHvFX1%2BXs8teXm7hw%2BWfuSolb89BwO766VCAiKYntUiRbDHJnuoCOOCFdjEchh6rOfNj2lLDWWIoRG%2FA0kSQoxpg44%2FG4kh2kb9oc8D6axMsRhHpq%2BET8v9KI3yp58GMi3oPCBEpb%2BU7PCclh2eYGw2tROj9bjwHQ%2Bd8TYshKGt61VdkjEamtVkuzbwpq4%3D&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20230213T090839Z&X-Amz-SignedHeaders=host&X-Amz-Expires=86400&X-Amz-Credential=ASIAXFRMTTJPXEBQOWXV%2F20230213%2Fap-south-1%2Fs3%2Faws4_request&X-Amz-Signature=32acb064356397c47ba39ae3c102f7145ba5610a939009ebaf3976ea707742a3', + type: 'SELFIE', + }, + { + referenceId: '0d1e8180-9618-4235-aab5-1a163ccd13cd', + uri: 'https://s3.ap-south-1.amazonaws.com/navi-8af22e75d3ad3bd252215069b16a75dc/prod/30dc3faa-049f-426b-9325-0d386a2131c9?X-Amz-Security-Token=FwoGZXIvYXdzEHIaDPgmIUpLhzA7q0TTFiLLARhdLI4snCE8w6Ym91%2BA%2FWui%2FAe056BY18TJQSjlvxsxv2rqs5Iv3Vbi6ZejDxFujAKhYemnPUvJiMfnClh6DPyrUL9Bbktx16n5I1b5sgB3JFVHD2V%2FAiSdIGcQm3JWbHw%2FUziDZQwHOn0Ky1HpZpKUtNHvFX1%2BXs8teXm7hw%2BWfuSolb89BwO766VCAiKYntUiRbDHJnuoCOOCFdjEchh6rOfNj2lLDWWIoRG%2FA0kSQoxpg44%2FG4kh2kb9oc8D6axMsRhHpq%2BET8v9KI3yp58GMi3oPCBEpb%2BU7PCclh2eYGw2tROj9bjwHQ%2Bd8TYshKGt61VdkjEamtVkuzbwpq4%3D&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20230213T090839Z&X-Amz-SignedHeaders=host&X-Amz-Expires=86400&X-Amz-Credential=ASIAXFRMTTJPXEBQOWXV%2F20230213%2Fap-south-1%2Fs3%2Faws4_request&X-Amz-Signature=06acb56621f25e525078684d5c7c2033148ea1758443e54cadf995ad1794a41f', + type: 'aadhar_photo', + }, + ], + imageUrl: + 'https://s3.ap-south-1.amazonaws.com/navi-8af22e75d3ad3bd252215069b16a75dc/prod/45fcb4e6-8a28-44cf-83d2-f1f4ecec08de?X-Amz-Security-Token=FwoGZXIvYXdzEHIaDPgmIUpLhzA7q0TTFiLLARhdLI4snCE8w6Ym91%2BA%2FWui%2FAe056BY18TJQSjlvxsxv2rqs5Iv3Vbi6ZejDxFujAKhYemnPUvJiMfnClh6DPyrUL9Bbktx16n5I1b5sgB3JFVHD2V%2FAiSdIGcQm3JWbHw%2FUziDZQwHOn0Ky1HpZpKUtNHvFX1%2BXs8teXm7hw%2BWfuSolb89BwO766VCAiKYntUiRbDHJnuoCOOCFdjEchh6rOfNj2lLDWWIoRG%2FA0kSQoxpg44%2FG4kh2kb9oc8D6axMsRhHpq%2BET8v9KI3yp58GMi3oPCBEpb%2BU7PCclh2eYGw2tROj9bjwHQ%2Bd8TYshKGt61VdkjEamtVkuzbwpq4%3D&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20230213T090839Z&X-Amz-SignedHeaders=host&X-Amz-Expires=86400&X-Amz-Credential=ASIAXFRMTTJPXEBQOWXV%2F20230213%2Fap-south-1%2Fs3%2Faws4_request&X-Amz-Signature=32acb064356397c47ba39ae3c102f7145ba5610a939009ebaf3976ea707742a3', + phoneNumbers: [ + { + type: 'OFFICE_PHONE', + source: 'BUREAU', + sourceText: 'Credit Bureau Scrub', + number: '9125591080', + valid: true, + telephoneScore: -1, + havingMaximumScore: false, + callHistory: null, + createdAt: '2022-02-26T13:48:00.819969', + new: true, + }, + { + type: 'OFFICE_PHONE', + source: 'BUREAU', + sourceText: 'Credit Bureau Scrub', + number: '8792044101', + valid: true, + telephoneScore: -1, + havingMaximumScore: false, + callHistory: null, + createdAt: '2022-02-26T13:48:00.819969', + new: true, + }, + { + type: '', + source: 'PRIMARY', + sourceText: 'Primary Contact', + number: '9620174791', + valid: true, + telephoneScore: 100, + havingMaximumScore: true, + callHistory: null, + createdAt: null, + new: true, + }, + { + type: 'MOBILE_PHONE', + source: 'BUREAU', + sourceText: 'Credit Bureau Scrub', + number: '9855855888', + valid: true, + telephoneScore: -1, + havingMaximumScore: false, + callHistory: null, + createdAt: '2022-02-26T13:48:00.819969', + new: true, + }, + ], + currentOutstandingEmi: 7017.57, + totalOverdueEmis: 12, + }, ]; diff --git a/src/mock-api/server.ts b/src/mock-api/server.ts index 69e85573..2624b88f 100644 --- a/src/mock-api/server.ts +++ b/src/mock-api/server.ts @@ -1,21 +1,21 @@ -import {createServer} from 'miragejs'; -import {addressesGeolocationUrl} from "./constants"; -import {addressesGeolocationData} from "./data/addressesGeolocation"; -import {API_URLS, ApiKeys} from "../components/utlis/apiHelper"; +import { createServer } from 'miragejs'; +import { addressesGeolocationUrl } from './constants'; +import { addressesGeolocationData } from './data/addressesGeolocation'; +import { API_URLS, ApiKeys } from '../components/utlis/apiHelper'; export function mockApiServer() { - if (window.server) { - window.server.shutdown(); - } + if (window.server) { + window.server.shutdown(); + } - window.server = createServer({ - routes() { - this.post(addressesGeolocationUrl , () => { - return {...addressesGeolocationData}; - }) - this.passthrough((r) => { - return !r.url.includes(API_URLS[ApiKeys.ADDRESSES_GEOLOCATION]) - }); - } - }) + window.server = createServer({ + routes() { + this.post(addressesGeolocationUrl, () => { + return { ...addressesGeolocationData }; + }); + this.passthrough((r) => { + return !r.url.includes(API_URLS[ApiKeys.ADDRESSES_GEOLOCATION]); + }); + }, + }); } diff --git a/src/reducer/Queue.ts b/src/reducer/Queue.ts index 2d9b7e20..a991074d 100644 --- a/src/reducer/Queue.ts +++ b/src/reducer/Queue.ts @@ -3,31 +3,31 @@ import { _map } from '../../RN-UI-LIB/src/utlis/common'; import { ApiKeys } from '../components/utlis/apiHelper'; enum Api { - FEEDBACK = ApiKeys.FEEDBACK, + FEEDBACK = ApiKeys.FEEDBACK, } interface IQueue { - data: Array<{ - id: any; - version: Api; - api: string; - data: any; - }>; + data: Array<{ + id: any; + version: Api; + api: string; + data: any; + }>; } const initialState = { - data: [], + data: [], } as IQueue; const QueueSlice = createSlice({ - name: 'queue', - initialState, - reducers: { - addToQueue: (state, action) => { - const { version, api, data, id } = action.payload; - state.data.push({ version, api, data, id }); - }, + name: 'queue', + initialState, + reducers: { + addToQueue: (state, action) => { + const { version, api, data, id } = action.payload; + state.data.push({ version, api, data, id }); }, + }, }); export const {} = QueueSlice.actions; diff --git a/src/reducer/addressGeolocationSlice.ts b/src/reducer/addressGeolocationSlice.ts index 102d4970..f1c4fa21 100644 --- a/src/reducer/addressGeolocationSlice.ts +++ b/src/reducer/addressGeolocationSlice.ts @@ -1,49 +1,45 @@ import { createSlice, PayloadAction } from '@reduxjs/toolkit'; import { IAddressGeoLocation } from '../types/addressGeolocation.types'; - interface IAddressGeolocationState { - addressGeoLocationData: IAddressGeoLocation; - isLoading: boolean; + addressGeoLocationData: IAddressGeoLocation; + isLoading: boolean; } const initialState: IAddressGeolocationState = { - addressGeoLocationData: { - addressL1ViewList: [], - unmatchedGeoLocations: [] - }, - isLoading: false + addressGeoLocationData: { + addressL1ViewList: [], + unmatchedGeoLocations: [], + }, + isLoading: false, }; const addressGeolocationSlice = createSlice({ - name: 'addressGeolocation', - initialState, - reducers: { - setAddressGeolocation: (state, action: PayloadAction) => { - return { - ...state, - addressGeoLocationData: action.payload, - }; - }, - resetAddressGeolocation: (state) => { - return { - ...state, - ...initialState - }; - }, - setLoading: (state, action: PayloadAction) => { - return { - ...state, - isLoading: action.payload, - }; - }, + name: 'addressGeolocation', + initialState, + reducers: { + setAddressGeolocation: (state, action: PayloadAction) => { + return { + ...state, + addressGeoLocationData: action.payload, + }; }, + resetAddressGeolocation: (state) => { + return { + ...state, + ...initialState, + }; + }, + setLoading: (state, action: PayloadAction) => { + return { + ...state, + isLoading: action.payload, + }; + }, + }, }); -export const { - setAddressGeolocation, - resetAddressGeolocation, - setLoading, -} = addressGeolocationSlice.actions; +export const { setAddressGeolocation, resetAddressGeolocation, setLoading } = + addressGeolocationSlice.actions; export default addressGeolocationSlice.reducer; diff --git a/src/reducer/addressSlice.ts b/src/reducer/addressSlice.ts index 816ff67f..9e709a2a 100644 --- a/src/reducer/addressSlice.ts +++ b/src/reducer/addressSlice.ts @@ -2,32 +2,42 @@ import { createSlice, PayloadAction } from '@reduxjs/toolkit'; import { IAddressGeoLocation } from '../types/addressGeolocation.types'; interface IAddressState { - [loanAccountNumber: string] : {addressesAndGeoLocations : IAddressGeoLocation, isLoading: boolean, timestamp: string } - + [loanAccountNumber: string]: { + addressesAndGeoLocations: IAddressGeoLocation; + isLoading: boolean; + timestamp: string; + }; } const initialState: IAddressState = {}; const AddressSlice = createSlice({ - name: 'addressSlice', - initialState, - reducers: { - setAddresses: (state, action) => { - const { loanAccountNumber, addressesAndGeoLocations } = action.payload; - state[loanAccountNumber] = {addressesAndGeoLocations, timestamp: new Date().toISOString(),isLoading: false } - }, - setAddressLoading: (state, action: PayloadAction<{ loanAccountNumbers: string[], isLoading: boolean }>) => { - const payloadData =action.payload - payloadData.loanAccountNumbers.forEach((loanAccNumber)=>{ - state[loanAccNumber] = {...(state?.[loanAccNumber] || {}), isLoading: payloadData.isLoading} - }) - }, + name: 'addressSlice', + initialState, + reducers: { + setAddresses: (state, action) => { + const { loanAccountNumber, addressesAndGeoLocations } = action.payload; + state[loanAccountNumber] = { + addressesAndGeoLocations, + timestamp: new Date().toISOString(), + isLoading: false, + }; }, + setAddressLoading: ( + state, + action: PayloadAction<{ loanAccountNumbers: string[]; isLoading: boolean }> + ) => { + const payloadData = action.payload; + payloadData.loanAccountNumbers.forEach((loanAccNumber) => { + state[loanAccNumber] = { + ...(state?.[loanAccNumber] || {}), + isLoading: payloadData.isLoading, + }; + }); + }, + }, }); -export const { - setAddresses, - setAddressLoading -} = AddressSlice.actions; +export const { setAddresses, setAddressLoading } = AddressSlice.actions; export default AddressSlice.reducer; diff --git a/src/reducer/allCasesSlice.ts b/src/reducer/allCasesSlice.ts index 3dcbb182..c733bf3c 100644 --- a/src/reducer/allCasesSlice.ts +++ b/src/reducer/allCasesSlice.ts @@ -1,570 +1,530 @@ import { createSlice } from '@reduxjs/toolkit'; import { toast } from '../../RN-UI-LIB/src/components/toast'; import { _map } from '../../RN-UI-LIB/src/utlis/common'; -import { - CLICKSTREAM_EVENT_NAMES, - FirestoreUpdateTypes, -} from '../common/Constants'; -import { - getCurrentScreen, - navigateToScreen, -} from '../components/utlis/navigationUtlis'; +import { CLICKSTREAM_EVENT_NAMES, FirestoreUpdateTypes } from '../common/Constants'; +import { getCurrentScreen, navigateToScreen } from '../components/utlis/navigationUtlis'; import { CaseUpdates } from '../hooks/useFirestoreUpdates'; import { COMPLETED_STATUSES } from '../screens/allCases/constants'; import { - CaseStatuses, - CaseAllocationType, - caseVerdict, - CurrentTask, - ICaseItem, + CaseStatuses, + CaseAllocationType, + caseVerdict, + CurrentTask, + ICaseItem, } from '../screens/allCases/interface'; -import { - CaseDetail, - CONTEXT_TASK_STATUSES, -} from '../screens/caseDetails/interface'; +import { CaseDetail, CONTEXT_TASK_STATUSES } from '../screens/caseDetails/interface'; import { addClickstreamEvent } from '../services/clickstreamEventService'; import { getLoanAccountNumber } from '../components/utlis/commonFunctions'; export type ICasesMap = { [key: string]: ICaseItem }; interface IAllCasesSlice { - casesList: ICaseItem[]; - casesListMap: ICasesMap; - intermediateTodoList: ICaseItem[]; - intermediateTodoListMap: ICasesMap; - selectedTodoListMap: ICasesMap; - selectedTodoListCount: number; - initialPinnedRankCount: number; - pinnedRankCount: number; - loading: boolean; - filterList: ICaseItem[]; - newlyPinnedCases: number; - completedCases: number; - caseDetails: Record; - searchQuery: string; - isOnboarded: boolean; - visitPlansUpdating: boolean; - pendingList:ICaseItem[]; - completedList:ICaseItem[]; - pinnedList:ICaseItem[]; - newVisitedCases: string[]; + casesList: ICaseItem[]; + casesListMap: ICasesMap; + intermediateTodoList: ICaseItem[]; + intermediateTodoListMap: ICasesMap; + selectedTodoListMap: ICasesMap; + selectedTodoListCount: number; + initialPinnedRankCount: number; + pinnedRankCount: number; + loading: boolean; + filterList: ICaseItem[]; + newlyPinnedCases: number; + completedCases: number; + caseDetails: Record; + searchQuery: string; + isOnboarded: boolean; + visitPlansUpdating: boolean; + pendingList: ICaseItem[]; + completedList: ICaseItem[]; + pinnedList: ICaseItem[]; + newVisitedCases: string[]; } const initialState: IAllCasesSlice = { - casesList: [], - casesListMap: {}, - intermediateTodoList: [], - intermediateTodoListMap: {}, - selectedTodoListCount: 0, - selectedTodoListMap: {}, - initialPinnedRankCount: 0, - pinnedRankCount: 0, - loading: false, - filterList: [], - newlyPinnedCases: 0, - completedCases: 0, - caseDetails: {}, - searchQuery: '', - isOnboarded: false, - visitPlansUpdating: false, - pendingList: [], - completedList: [], - pinnedList: [], - newVisitedCases: [] + casesList: [], + casesListMap: {}, + intermediateTodoList: [], + intermediateTodoListMap: {}, + selectedTodoListCount: 0, + selectedTodoListMap: {}, + initialPinnedRankCount: 0, + pinnedRankCount: 0, + loading: false, + filterList: [], + newlyPinnedCases: 0, + completedCases: 0, + caseDetails: {}, + searchQuery: '', + isOnboarded: false, + visitPlansUpdating: false, + pendingList: [], + completedList: [], + pinnedList: [], + newVisitedCases: [], }; const getCaseListComponents = (casesList: ICaseItem[], caseDetails: Record) => { - const pendingList: ICaseItem[] = []; - const completedList: ICaseItem[] = []; - const pinnedList: ICaseItem[] = []; - casesList.forEach(item => { - const { caseReferenceId, pinRank } = item; - const { caseStatus } = caseDetails[caseReferenceId]; - const isCaseCompleted = COMPLETED_STATUSES.includes(caseStatus); - isCaseCompleted - ? completedList.push(item) - : pinRank - ? pinnedList.push(item) - : pendingList.push(item); - }); - return { pendingList, completedList, pinnedList }; + const pendingList: ICaseItem[] = []; + const completedList: ICaseItem[] = []; + const pinnedList: ICaseItem[] = []; + casesList.forEach((item) => { + const { caseReferenceId, pinRank } = item; + const { caseStatus } = caseDetails[caseReferenceId]; + const isCaseCompleted = COMPLETED_STATUSES.includes(caseStatus); + isCaseCompleted + ? completedList.push(item) + : pinRank + ? pinnedList.push(item) + : pendingList.push(item); + }); + return { pendingList, completedList, pinnedList }; }; const getPinnedListDetails = (casesList: ICaseItem[]) => { - let maxPinnedRank = 0; - const pinnedList: ICaseItem[] = []; - casesList.forEach(caseItem => { - const { pinRank } = caseItem; - if (pinRank === null || pinRank === undefined) { - return; - } - pinnedList.push(caseItem); - if (pinRank > maxPinnedRank) { - maxPinnedRank = pinRank; - } - }); - return { pinnedList, maxPinnedRank }; + let maxPinnedRank = 0; + const pinnedList: ICaseItem[] = []; + casesList.forEach((caseItem) => { + const { pinRank } = caseItem; + if (pinRank === null || pinRank === undefined) { + return; + } + pinnedList.push(caseItem); + if (pinRank > maxPinnedRank) { + maxPinnedRank = pinRank; + } + }); + return { pinnedList, maxPinnedRank }; }; -export const getUpdatedCollectionCaseDetail = ({caseData, answer, coords}: any) => { - - const updatedValue = { ...caseData }; - updatedValue.isSynced = false; - updatedValue.isApiCalled = false; - updatedValue.taskStatus = 'completed'; - const visitedWidgets = answer.visitedWidgets; - const allWidget = answer.widgetContext; - const widgetContext = {}; - _map(visitedWidgets, widget => { - if (widget === 'SUBMIT') return; - widgetContext[widget] = allWidget[widget]; - }); - const newAnswer = { - widgetContext, - allocationReferenceId: answer.allocationReferenceId, - }; - updatedValue.answer = newAnswer; - updatedValue.coords = coords; - return updatedValue; +export const getUpdatedCollectionCaseDetail = ({ caseData, answer, coords }: any) => { + const updatedValue = { ...caseData }; + updatedValue.isSynced = false; + updatedValue.isApiCalled = false; + updatedValue.taskStatus = 'completed'; + const visitedWidgets = answer.visitedWidgets; + const allWidget = answer.widgetContext; + const widgetContext = {}; + _map(visitedWidgets, (widget) => { + if (widget === 'SUBMIT') return; + widgetContext[widget] = allWidget[widget]; + }); + const newAnswer = { + widgetContext, + allocationReferenceId: answer.allocationReferenceId, + }; + updatedValue.answer = newAnswer; + updatedValue.coords = coords; + return updatedValue; }; -export const getUpdatedAVCaseDetail = ({journeyId, answer, caseData, nextActions, templateId, coords}: any) => { - const updatedValue = { ...caseData }; - updatedValue.isSynced = false; - updatedValue.isApiCalled = false; - const visitedWidgets = answer.visitedWidgets; - const allWidget = answer.widgetContext; - const widgetContext = {}; - _map(visitedWidgets, widget => { - if (widget === 'SUBMIT') return; - widgetContext[widget] = allWidget[widget]; - }); - const newAnswer = { - widgetContext, - allocationReferenceId: answer.allocationReferenceId, +export const getUpdatedAVCaseDetail = ({ + journeyId, + answer, + caseData, + nextActions, + templateId, + coords, +}: any) => { + const updatedValue = { ...caseData }; + updatedValue.isSynced = false; + updatedValue.isApiCalled = false; + const visitedWidgets = answer.visitedWidgets; + const allWidget = answer.widgetContext; + const widgetContext = {}; + _map(visitedWidgets, (widget) => { + if (widget === 'SUBMIT') return; + widgetContext[widget] = allWidget[widget]; + }); + const newAnswer = { + widgetContext, + allocationReferenceId: answer.allocationReferenceId, + }; + if (!updatedValue.context || updatedValue.context === null) { + updatedValue.currentTask = updatedValue.tasks.find( + (task) => task.taskType === nextActions.nextJourney + ); + updatedValue.context = { + currentTask: nextActions.nextJourney, + taskContext: { + [journeyId]: [ + { + templateId, + createdAt: new Date().getTime(), + taskStatus: nextActions.status, + ...newAnswer, + }, + ], + }, }; - if (!updatedValue.context || updatedValue.context === null) { - updatedValue.currentTask = updatedValue.tasks.find( - task => task.taskType === nextActions.nextJourney, - ); - updatedValue.context = { - currentTask: nextActions.nextJourney, - taskContext: { - [journeyId]: [ - { - templateId, - createdAt: new Date().getTime(), - taskStatus: nextActions.status, - ...newAnswer, - }, - ], - }, - }; - } else if (updatedValue.context.taskContext?.[journeyId]) { - updatedValue.currentTask = updatedValue.tasks.find( - task => task.taskType === nextActions.nextJourney, - ); - const journey = [ - ...updatedValue.context.taskContext?.[journeyId], - { - templateId, - createdAt: new Date().getTime(), - taskStatus: nextActions.status, - ...newAnswer, - }, - ]; - updatedValue.context = { - currentTask: nextActions.nextJourney, - taskContext: { - ...updatedValue.context.taskContext, - [journeyId]: journey, - }, - }; - } else { - const context = { ...updatedValue.context }; - const taskContext = { ...context.taskContext }; - updatedValue.currentTask = updatedValue.tasks.find( - task => task.taskType === nextActions.nextJourney, - ); - (taskContext[journeyId] = [ - { - templateId, - createdAt: new Date().getTime(), - taskStatus: nextActions.status, - ...newAnswer, - }, - ]), - (updatedValue.context = { - currentTask: nextActions.nextJourney, - taskContext: { - ...taskContext, - }, - }); - } - if (nextActions.status === CONTEXT_TASK_STATUSES.VERIFICATION_SUCCESS) { - updatedValue.caseStatus = CaseStatuses.CLOSED; - updatedValue.caseVerdict = caseVerdict.VERIFIED; - } - if ( - nextActions.status === CONTEXT_TASK_STATUSES.VERIFICATION_FAILED && - !nextActions.nextJourney - ) { - updatedValue.caseStatus = CaseStatuses.CLOSED; - updatedValue.caseVerdict = caseVerdict.EXHAUSTED; - } - updatedValue.coords = coords; - return updatedValue; + } else if (updatedValue.context.taskContext?.[journeyId]) { + updatedValue.currentTask = updatedValue.tasks.find( + (task) => task.taskType === nextActions.nextJourney + ); + const journey = [ + ...updatedValue.context.taskContext?.[journeyId], + { + templateId, + createdAt: new Date().getTime(), + taskStatus: nextActions.status, + ...newAnswer, + }, + ]; + updatedValue.context = { + currentTask: nextActions.nextJourney, + taskContext: { + ...updatedValue.context.taskContext, + [journeyId]: journey, + }, + }; + } else { + const context = { ...updatedValue.context }; + const taskContext = { ...context.taskContext }; + updatedValue.currentTask = updatedValue.tasks.find( + (task) => task.taskType === nextActions.nextJourney + ); + (taskContext[journeyId] = [ + { + templateId, + createdAt: new Date().getTime(), + taskStatus: nextActions.status, + ...newAnswer, + }, + ]), + (updatedValue.context = { + currentTask: nextActions.nextJourney, + taskContext: { + ...taskContext, + }, + }); + } + if (nextActions.status === CONTEXT_TASK_STATUSES.VERIFICATION_SUCCESS) { + updatedValue.caseStatus = CaseStatuses.CLOSED; + updatedValue.caseVerdict = caseVerdict.VERIFIED; + } + if ( + nextActions.status === CONTEXT_TASK_STATUSES.VERIFICATION_FAILED && + !nextActions.nextJourney + ) { + updatedValue.caseStatus = CaseStatuses.CLOSED; + updatedValue.caseVerdict = caseVerdict.EXHAUSTED; + } + updatedValue.coords = coords; + return updatedValue; }; const allCasesSlice = createSlice({ - name: 'cases', - initialState, - reducers: { - setLoading: (state, action) => { - state.loading = action.payload; - }, - updateCaseDetailsFirestore: (state, action) => { - const { caseUpdates, isInitialLoad } = action.payload as { - caseUpdates: CaseUpdates[]; - isInitialLoad: boolean; - }; - if (state.loading) { - state.loading = false; - } - let newVisitCaseLoanIds: string[] = []; - let newVisitCollectionCases: string[] = []; - let removedVisitedCasesLoanIds: string[] = []; - caseUpdates.forEach(({ updateType, updatedCaseDetail }) => { - const { caseType, caseReferenceId, id, pinRank } = - updatedCaseDetail; - - const caseId = caseReferenceId || id; - switch (updateType) { - case FirestoreUpdateTypes.MODIFIED: { - const index = state.casesList?.findIndex( - caseItem => caseItem.caseReferenceId === caseId, - ); - if (index !== -1) { - if (pinRank && !state.casesList[index].pinRank) { - // this is a new visit case - newVisitCaseLoanIds.push( - state.caseDetails[caseId] - ?.loanAccountNumber ?? - state.caseDetails[caseId]?.loanDetails - ?.loanAccountNumber ?? - 0, - ); - if(caseType === CaseAllocationType.COLLECTION_CASE) { - newVisitCollectionCases.push(caseId); - } - } - if(!pinRank && state.casesList[index].pinRank) { - // this is a removed visit case - removedVisitedCasesLoanIds.push( - state.caseDetails[caseId] - ?.loanAccountNumber ?? - state.caseDetails[caseId]?.loanDetails - ?.loanAccountNumber ?? - 0, - ); - } - state.casesList[index] = { - ...state.casesList[index], - caseReferenceId: caseId, - pinRank: pinRank || null, - }; - } - let currentTask = null; - if (caseType !== CaseAllocationType.COLLECTION_CASE) { - const { tasks, currentTask: updatedCurrentTask } = - updatedCaseDetail; - currentTask = tasks?.find( - task => - task.taskType === - (updatedCurrentTask as string), - ); - } - state.caseDetails[caseId] = { - ...updatedCaseDetail, - currentTask, - isSynced: true, - }; - break; - } - case FirestoreUpdateTypes.ADDED: { - if (state.caseDetails[caseId]) { - return; - } - if(pinRank && caseType === CaseAllocationType.COLLECTION_CASE) { - newVisitCollectionCases.push(caseId); - } - const caseListItem = { - caseReferenceId: caseId, - pinRank: pinRank || null, - }; - state.casesList.unshift(caseListItem); - let currentTask = null; - if (caseType !== CaseAllocationType.COLLECTION_CASE) { - const { tasks, currentTask: updatedCurrentTask } = - updatedCaseDetail; - currentTask = tasks?.find( - task => - task?.taskType === - (updatedCurrentTask as string), - ); - } - state.caseDetails[caseId] = { - ...updatedCaseDetail, - currentTask, - isSynced: true, - isNewlyAdded: !isInitialLoad, - }; - break; - } - case FirestoreUpdateTypes.REMOVED: { - const index = state.casesList.findIndex( - caseItem => caseItem.caseReferenceId === caseId, - ); - const currentScreen = getCurrentScreen(); - // Redirect to home screen if the case deletes which the agent is seeing - if (currentScreen.name === 'caseDetail') { - const { caseId: id } = currentScreen.params; - if (id === caseId) { - navigateToScreen('Home'); - } - } - if (index !== -1) { - state.casesList.splice(index, 1); - } - delete state.caseDetails[caseId]; - break; - } - default: - break; - } - }); - const { pendingList, completedList, pinnedList } = getCaseListComponents(state.casesList, state.caseDetails); - state.pendingList = pendingList; - state.completedList = completedList; - state.pinnedList = pinnedList; - state.newVisitedCases = newVisitCollectionCases; - - if (newVisitCaseLoanIds?.length > 0) { - addClickstreamEvent( - CLICKSTREAM_EVENT_NAMES.FA_VISIT_PLAN_UPDATED, - { - newPinCases: [...newVisitCaseLoanIds], - currentPinCases: pinnedList.map(item => - getLoanAccountNumber( - state.caseDetails[item?.caseReferenceId], - ), - ), - }, - ); - toast({ - type: 'info', - text1: `${newVisitCaseLoanIds.length} case${ - newVisitCaseLoanIds.length > 1 ? 's' : '' - } added to the visit plan`, - }); - return; - } - if(removedVisitedCasesLoanIds.length > 0) { - addClickstreamEvent( - CLICKSTREAM_EVENT_NAMES.FA_VISIT_PLAN_UPDATED, - { - newUnpinCases: [...removedVisitedCasesLoanIds], - currentPinCases: pinnedList.map(item => - getLoanAccountNumber( - state.caseDetails[item?.caseReferenceId], - ), - ), - }, - ); - toast({ - type: 'info', - text1: `${removedVisitedCasesLoanIds.length} case${ - removedVisitedCasesLoanIds.length > 1 ? 's' : '' - } removed from the visit plan`, - }); - } - }, - updateCaseDetail: (state, action) => { - const { - caseId, - updatedCaseDetail - } = action.payload; - let caseKey: string = caseId; - if (updatedCaseDetail.caseType === CaseAllocationType.COLLECTION_CASE ) { - caseKey += '_' + Date.now(); - updatedCaseDetail.offlineCaseKey = caseKey; - } - state.caseDetails[caseKey] = updatedCaseDetail; - }, - setPinnedRank: (state, action) => { - const caseId = action.payload.caseReferenceId; - const isCasePresent = state.intermediateTodoListMap[caseId]; - if (isCasePresent) { - addClickstreamEvent( - CLICKSTREAM_EVENT_NAMES.AV_CASE_LIST_CASE_UNSELECTED, - { caseId }, - ); - delete state.intermediateTodoListMap[caseId]; - state.newlyPinnedCases--; - } else { - addClickstreamEvent( - CLICKSTREAM_EVENT_NAMES.AV_CASE_LIST_CASE_SELECTED, - { caseId }, - ); - state.pinnedRankCount++; - state.newlyPinnedCases++; - const selectedCase = { ...action.payload }; - selectedCase.pinRank = state.pinnedRankCount; - state.intermediateTodoListMap[caseId] = selectedCase; - } - }, - proceedToTodoList: state => { - state.intermediateTodoList = Object.values( - state.intermediateTodoListMap, - ).sort((caseA, caseB) => caseA.pinRank - caseB.pinRank); - navigateToScreen('TodoList'); - }, - deleteIntermediateTodoListItem: (state, action) => { - const { caseReferenceId } = action.payload; - if (!caseReferenceId) { - return; - } - state.intermediateTodoList = state.intermediateTodoList.filter( - caseItem => caseItem.caseReferenceId !== caseReferenceId, - ); - delete state.intermediateTodoListMap[caseReferenceId]; - state.newlyPinnedCases--; - }, - resetTodoList: state => { - state.intermediateTodoListMap = {}; - state.newlyPinnedCases = 0; - state.pinnedRankCount = state.initialPinnedRankCount; - }, - setSelectedTodoListMap: (state, action) => { - const caseId = action.payload.caseReferenceId; - const isCasePresent = state.selectedTodoListMap[caseId]; - if (state.visitPlansUpdating) { - state.visitPlansUpdating = false; - } - if (isCasePresent) { - addClickstreamEvent( - CLICKSTREAM_EVENT_NAMES.AV_CASE_LIST_TODO_ITEM_UNSELECTED, - { caseId }, - ); - delete state.selectedTodoListMap[caseId]; - state.selectedTodoListCount--; - } else { - addClickstreamEvent( - CLICKSTREAM_EVENT_NAMES.AV_CASE_LIST_TODO_ITEM_SELECTED, - { caseId }, - ); - state.selectedTodoListCount++; - const selectedCase = { ...action.payload }; - state.selectedTodoListMap[caseId] = selectedCase; - } - }, - resetSelectedTodoList: state => { - state.selectedTodoListCount = 0; - state.selectedTodoListMap = {}; - }, - updateSingleCase: (state, action) => { - const { data, id, caseType, offlineCaseKey } = action.payload; - if(caseType === CaseAllocationType.COLLECTION_CASE) { - const computedKey = offlineCaseKey || id; - if(state.caseDetails?.[id]) { - state.caseDetails[id] = { - ...state.caseDetails[computedKey], - isSynced: true - } - delete state.caseDetails[offlineCaseKey]; - } - return; - } - - if (data) { - state.caseDetails[id] = { - ...data, - currentTask: data.tasks.find( - task => task.taskType === data.currentTask, - ), - isSynced: true, - isApiCallMade: false, - }; - } else { - state.caseDetails[id].isSynced = false; - } - }, - setFilterList: (state, action) => { - state.filterList = action.payload; - }, - setOnboarding: state => { - state.isOnboarded = true; - }, - updateCaseDetailAfterApiCall: (state, action) => { - const { caseId } = action.payload; - state.caseDetails[caseId].isApiCalled = true; - }, - updateCaseDetailBeforeApiCall: (state, action) => { - const { caseId } = action.payload; - state.caseDetails[caseId].isApiCalled = false; - }, - toggleNewlyAddedCase: (state, action) => { - state.caseDetails[action.payload].isNewlyAdded = false; - }, - resetCasesData: state => { - state.casesList = []; - state.casesListMap = {}; - state.intermediateTodoList = []; - state.intermediateTodoListMap = {}; - state.selectedTodoListCount = 0; - state.selectedTodoListMap = {}; - state.initialPinnedRankCount = 0; - state.pinnedRankCount = 0; - state.loading = false; - state.filterList = []; - state.newlyPinnedCases = 0; - state.completedCases = 0; - state.caseDetails = {}; - state.searchQuery = ''; - state.isOnboarded = state.isOnboarded; - state.newVisitedCases = []; - state.pendingList = []; - state.pinnedList = []; - state.completedList = []; - }, - setVisitPlansUpdating: (state, action) => { - state.visitPlansUpdating = action.payload; - }, - resetNewVisitedCases: (state) => { - state.newVisitedCases = []; - } + name: 'cases', + initialState, + reducers: { + setLoading: (state, action) => { + state.loading = action.payload; }, + updateCaseDetailsFirestore: (state, action) => { + const { caseUpdates, isInitialLoad } = action.payload as { + caseUpdates: CaseUpdates[]; + isInitialLoad: boolean; + }; + if (state.loading) { + state.loading = false; + } + let newVisitCaseLoanIds: string[] = []; + let newVisitCollectionCases: string[] = []; + let removedVisitedCasesLoanIds: string[] = []; + caseUpdates.forEach(({ updateType, updatedCaseDetail }) => { + const { caseType, caseReferenceId, id, pinRank } = updatedCaseDetail; + + const caseId = caseReferenceId || id; + switch (updateType) { + case FirestoreUpdateTypes.MODIFIED: { + const index = state.casesList?.findIndex( + (caseItem) => caseItem.caseReferenceId === caseId + ); + if (index !== -1) { + if (pinRank && !state.casesList[index].pinRank) { + // this is a new visit case + newVisitCaseLoanIds.push( + state.caseDetails[caseId]?.loanAccountNumber ?? + state.caseDetails[caseId]?.loanDetails?.loanAccountNumber ?? + 0 + ); + if (caseType === CaseAllocationType.COLLECTION_CASE) { + newVisitCollectionCases.push(caseId); + } + } + if (!pinRank && state.casesList[index].pinRank) { + // this is a removed visit case + removedVisitedCasesLoanIds.push( + state.caseDetails[caseId]?.loanAccountNumber ?? + state.caseDetails[caseId]?.loanDetails?.loanAccountNumber ?? + 0 + ); + } + state.casesList[index] = { + ...state.casesList[index], + caseReferenceId: caseId, + pinRank: pinRank || null, + }; + } + let currentTask = null; + if (caseType !== CaseAllocationType.COLLECTION_CASE) { + const { tasks, currentTask: updatedCurrentTask } = updatedCaseDetail; + currentTask = tasks?.find((task) => task.taskType === (updatedCurrentTask as string)); + } + state.caseDetails[caseId] = { + ...updatedCaseDetail, + currentTask, + isSynced: true, + }; + break; + } + case FirestoreUpdateTypes.ADDED: { + if (state.caseDetails[caseId]) { + return; + } + if (pinRank && caseType === CaseAllocationType.COLLECTION_CASE) { + newVisitCollectionCases.push(caseId); + } + const caseListItem = { + caseReferenceId: caseId, + pinRank: pinRank || null, + }; + state.casesList.unshift(caseListItem); + let currentTask = null; + if (caseType !== CaseAllocationType.COLLECTION_CASE) { + const { tasks, currentTask: updatedCurrentTask } = updatedCaseDetail; + currentTask = tasks?.find( + (task) => task?.taskType === (updatedCurrentTask as string) + ); + } + state.caseDetails[caseId] = { + ...updatedCaseDetail, + currentTask, + isSynced: true, + isNewlyAdded: !isInitialLoad, + }; + break; + } + case FirestoreUpdateTypes.REMOVED: { + const index = state.casesList.findIndex( + (caseItem) => caseItem.caseReferenceId === caseId + ); + const currentScreen = getCurrentScreen(); + // Redirect to home screen if the case deletes which the agent is seeing + if (currentScreen.name === 'caseDetail') { + const { caseId: id } = currentScreen.params; + if (id === caseId) { + navigateToScreen('Home'); + } + } + if (index !== -1) { + state.casesList.splice(index, 1); + } + delete state.caseDetails[caseId]; + break; + } + default: + break; + } + }); + const { pendingList, completedList, pinnedList } = getCaseListComponents( + state.casesList, + state.caseDetails + ); + state.pendingList = pendingList; + state.completedList = completedList; + state.pinnedList = pinnedList; + state.newVisitedCases = newVisitCollectionCases; + + if (newVisitCaseLoanIds?.length > 0) { + addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_VISIT_PLAN_UPDATED, { + newPinCases: [...newVisitCaseLoanIds], + currentPinCases: pinnedList.map((item) => + getLoanAccountNumber(state.caseDetails[item?.caseReferenceId]) + ), + }); + toast({ + type: 'info', + text1: `${newVisitCaseLoanIds.length} case${ + newVisitCaseLoanIds.length > 1 ? 's' : '' + } added to the visit plan`, + }); + return; + } + if (removedVisitedCasesLoanIds.length > 0) { + addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_VISIT_PLAN_UPDATED, { + newUnpinCases: [...removedVisitedCasesLoanIds], + currentPinCases: pinnedList.map((item) => + getLoanAccountNumber(state.caseDetails[item?.caseReferenceId]) + ), + }); + toast({ + type: 'info', + text1: `${removedVisitedCasesLoanIds.length} case${ + removedVisitedCasesLoanIds.length > 1 ? 's' : '' + } removed from the visit plan`, + }); + } + }, + updateCaseDetail: (state, action) => { + const { caseId, updatedCaseDetail } = action.payload; + let caseKey: string = caseId; + if (updatedCaseDetail.caseType === CaseAllocationType.COLLECTION_CASE) { + caseKey += '_' + Date.now(); + updatedCaseDetail.offlineCaseKey = caseKey; + } + state.caseDetails[caseKey] = updatedCaseDetail; + }, + setPinnedRank: (state, action) => { + const caseId = action.payload.caseReferenceId; + const isCasePresent = state.intermediateTodoListMap[caseId]; + if (isCasePresent) { + addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.AV_CASE_LIST_CASE_UNSELECTED, { caseId }); + delete state.intermediateTodoListMap[caseId]; + state.newlyPinnedCases--; + } else { + addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.AV_CASE_LIST_CASE_SELECTED, { caseId }); + state.pinnedRankCount++; + state.newlyPinnedCases++; + const selectedCase = { ...action.payload }; + selectedCase.pinRank = state.pinnedRankCount; + state.intermediateTodoListMap[caseId] = selectedCase; + } + }, + proceedToTodoList: (state) => { + state.intermediateTodoList = Object.values(state.intermediateTodoListMap).sort( + (caseA, caseB) => caseA.pinRank - caseB.pinRank + ); + navigateToScreen('TodoList'); + }, + deleteIntermediateTodoListItem: (state, action) => { + const { caseReferenceId } = action.payload; + if (!caseReferenceId) { + return; + } + state.intermediateTodoList = state.intermediateTodoList.filter( + (caseItem) => caseItem.caseReferenceId !== caseReferenceId + ); + delete state.intermediateTodoListMap[caseReferenceId]; + state.newlyPinnedCases--; + }, + resetTodoList: (state) => { + state.intermediateTodoListMap = {}; + state.newlyPinnedCases = 0; + state.pinnedRankCount = state.initialPinnedRankCount; + }, + setSelectedTodoListMap: (state, action) => { + const caseId = action.payload.caseReferenceId; + const isCasePresent = state.selectedTodoListMap[caseId]; + if (state.visitPlansUpdating) { + state.visitPlansUpdating = false; + } + if (isCasePresent) { + addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.AV_CASE_LIST_TODO_ITEM_UNSELECTED, { caseId }); + delete state.selectedTodoListMap[caseId]; + state.selectedTodoListCount--; + } else { + addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.AV_CASE_LIST_TODO_ITEM_SELECTED, { caseId }); + state.selectedTodoListCount++; + const selectedCase = { ...action.payload }; + state.selectedTodoListMap[caseId] = selectedCase; + } + }, + resetSelectedTodoList: (state) => { + state.selectedTodoListCount = 0; + state.selectedTodoListMap = {}; + }, + updateSingleCase: (state, action) => { + const { data, id, caseType, offlineCaseKey } = action.payload; + if (caseType === CaseAllocationType.COLLECTION_CASE) { + const computedKey = offlineCaseKey || id; + if (state.caseDetails?.[id]) { + state.caseDetails[id] = { + ...state.caseDetails[computedKey], + isSynced: true, + }; + delete state.caseDetails[offlineCaseKey]; + } + return; + } + + if (data) { + state.caseDetails[id] = { + ...data, + currentTask: data.tasks.find((task) => task.taskType === data.currentTask), + isSynced: true, + isApiCallMade: false, + }; + } else { + state.caseDetails[id].isSynced = false; + } + }, + setFilterList: (state, action) => { + state.filterList = action.payload; + }, + setOnboarding: (state) => { + state.isOnboarded = true; + }, + updateCaseDetailAfterApiCall: (state, action) => { + const { caseId } = action.payload; + state.caseDetails[caseId].isApiCalled = true; + }, + updateCaseDetailBeforeApiCall: (state, action) => { + const { caseId } = action.payload; + state.caseDetails[caseId].isApiCalled = false; + }, + toggleNewlyAddedCase: (state, action) => { + state.caseDetails[action.payload].isNewlyAdded = false; + }, + resetCasesData: (state) => { + state.casesList = []; + state.casesListMap = {}; + state.intermediateTodoList = []; + state.intermediateTodoListMap = {}; + state.selectedTodoListCount = 0; + state.selectedTodoListMap = {}; + state.initialPinnedRankCount = 0; + state.pinnedRankCount = 0; + state.loading = false; + state.filterList = []; + state.newlyPinnedCases = 0; + state.completedCases = 0; + state.caseDetails = {}; + state.searchQuery = ''; + state.isOnboarded = state.isOnboarded; + state.newVisitedCases = []; + state.pendingList = []; + state.pinnedList = []; + state.completedList = []; + }, + setVisitPlansUpdating: (state, action) => { + state.visitPlansUpdating = action.payload; + }, + resetNewVisitedCases: (state) => { + state.newVisitedCases = []; + }, + }, }); export const { - setLoading, - setPinnedRank, - resetTodoList, - proceedToTodoList, - deleteIntermediateTodoListItem, - setSelectedTodoListMap, - resetSelectedTodoList, - updateCaseDetail, - updateSingleCase, - updateCaseDetailsFirestore, - setOnboarding, - updateCaseDetailAfterApiCall, - toggleNewlyAddedCase, - resetCasesData, - updateCaseDetailBeforeApiCall, - setVisitPlansUpdating, - resetNewVisitedCases, + setLoading, + setPinnedRank, + resetTodoList, + proceedToTodoList, + deleteIntermediateTodoListItem, + setSelectedTodoListMap, + resetSelectedTodoList, + updateCaseDetail, + updateSingleCase, + updateCaseDetailsFirestore, + setOnboarding, + updateCaseDetailAfterApiCall, + toggleNewlyAddedCase, + resetCasesData, + updateCaseDetailBeforeApiCall, + setVisitPlansUpdating, + resetNewVisitedCases, } = allCasesSlice.actions; export default allCasesSlice.reducer; diff --git a/src/reducer/caseReducer.ts b/src/reducer/caseReducer.ts index 22bc9610..1f6e139d 100644 --- a/src/reducer/caseReducer.ts +++ b/src/reducer/caseReducer.ts @@ -1,106 +1,110 @@ import { createSlice, PayloadAction } from '@reduxjs/toolkit'; import { CaseAllocationType, ICaseItem } from '../screens/allCases/interface'; -import { FormTemplateV1 } from "../types/template.types"; +import { FormTemplateV1 } from '../types/template.types'; interface ICaseReducer { - value: number; - caseForm: { - [caseId: string]: { - [journeyId: string]: { - visitedWidgets: Array; - widgetContext: { - [widgetId: string]: { - sectionContext: { - [sectionId: string]: { - questionContext: { - [questionId: string]: { answer: string, type: string}; - }; - }; - }; - }; + value: number; + caseForm: { + [caseId: string]: { + [journeyId: string]: { + visitedWidgets: Array; + widgetContext: { + [widgetId: string]: { + sectionContext: { + [sectionId: string]: { + questionContext: { + [questionId: string]: { answer: string; type: string }; }; + }; }; + }; }; + }; }; - toBeSynced: any; - allCases: Array; - templateData: { - [CaseAllocationType.ADDRESS_VERIFICATION_CASE] : FormTemplateV1, - [CaseAllocationType.COLLECTION_CASE] : FormTemplateV1 - }; - showAlternateText: string; + }; + toBeSynced: any; + allCases: Array; + templateData: { + [CaseAllocationType.ADDRESS_VERIFICATION_CASE]: FormTemplateV1; + [CaseAllocationType.COLLECTION_CASE]: FormTemplateV1; + }; + showAlternateText: string; } const initialState = { - value: 0, - caseForm: {}, - toBeSynced: {}, - allCases: [], - templateData: { - [CaseAllocationType.ADDRESS_VERIFICATION_CASE] : {} as FormTemplateV1, - [CaseAllocationType.COLLECTION_CASE] : {} as FormTemplateV1}, - showAlternateText: "" + value: 0, + caseForm: {}, + toBeSynced: {}, + allCases: [], + templateData: { + [CaseAllocationType.ADDRESS_VERIFICATION_CASE]: {} as FormTemplateV1, + [CaseAllocationType.COLLECTION_CASE]: {} as FormTemplateV1, + }, + showAlternateText: '', } as ICaseReducer; export const caseSlice = createSlice({ - name: 'case', - initialState: initialState, - reducers: { - updateInteraction: (state, action) => { - const { caseId, journeyId, widgetId, answer } = action.payload; - const data = state.caseForm || {}; - if (!data[caseId]) { - data[caseId] = {}; - } - if (!data[caseId][journeyId]) { - // @ts-ignore - data[caseId][journeyId] = { - visitedWidgets:[] - }; - } - const visited = data[caseId][journeyId]?.visitedWidgets; - if(!visited.some(widget => widget == widgetId)){ - visited.push(widgetId) - } - data[caseId][journeyId].widgetContext = {...data[caseId][journeyId].widgetContext, ...answer.widgetContext}; - data[caseId][journeyId].visitedWidgets = visited; - state.caseForm = data; - }, - deleteInteraction: (state, action) => { - const { caseId, journeyId, widgetId } = action.payload; - const data = state.caseForm; - const visited = data[caseId][journeyId]?.visitedWidgets; - if(visited[visited.length -1] === widgetId){ - visited.pop(); - } - data[caseId][journeyId].visitedWidgets = visited; - state.caseForm = data; - }, - deleteJourney: (state, action) => { - const { caseId, journeyId, widgetId, answer } = action.payload; - const data = state.caseForm; - delete data[caseId][journeyId]; - state.caseForm = data; - }, - updateAvTemplateData: (state, action: PayloadAction) => { - state.templateData[CaseAllocationType.ADDRESS_VERIFICATION_CASE] = action.payload; - }, - updateCollectionTemplateData: (state, action: PayloadAction) => { - state.templateData[CaseAllocationType.COLLECTION_CASE] = action.payload; - }, - updateAlternateHeader: (state, action) => { - state.showAlternateText = action.payload; - }, + name: 'case', + initialState: initialState, + reducers: { + updateInteraction: (state, action) => { + const { caseId, journeyId, widgetId, answer } = action.payload; + const data = state.caseForm || {}; + if (!data[caseId]) { + data[caseId] = {}; + } + if (!data[caseId][journeyId]) { + // @ts-ignore + data[caseId][journeyId] = { + visitedWidgets: [], + }; + } + const visited = data[caseId][journeyId]?.visitedWidgets; + if (!visited.some((widget) => widget == widgetId)) { + visited.push(widgetId); + } + data[caseId][journeyId].widgetContext = { + ...data[caseId][journeyId].widgetContext, + ...answer.widgetContext, + }; + data[caseId][journeyId].visitedWidgets = visited; + state.caseForm = data; }, + deleteInteraction: (state, action) => { + const { caseId, journeyId, widgetId } = action.payload; + const data = state.caseForm; + const visited = data[caseId][journeyId]?.visitedWidgets; + if (visited[visited.length - 1] === widgetId) { + visited.pop(); + } + data[caseId][journeyId].visitedWidgets = visited; + state.caseForm = data; + }, + deleteJourney: (state, action) => { + const { caseId, journeyId, widgetId, answer } = action.payload; + const data = state.caseForm; + delete data[caseId][journeyId]; + state.caseForm = data; + }, + updateAvTemplateData: (state, action: PayloadAction) => { + state.templateData[CaseAllocationType.ADDRESS_VERIFICATION_CASE] = action.payload; + }, + updateCollectionTemplateData: (state, action: PayloadAction) => { + state.templateData[CaseAllocationType.COLLECTION_CASE] = action.payload; + }, + updateAlternateHeader: (state, action) => { + state.showAlternateText = action.payload; + }, + }, }); export const { - updateInteraction, - deleteInteraction, - updateAvTemplateData, - updateCollectionTemplateData, - deleteJourney, - updateAlternateHeader + updateInteraction, + deleteInteraction, + updateAvTemplateData, + updateCollectionTemplateData, + deleteJourney, + updateAlternateHeader, } = caseSlice.actions; export default caseSlice.reducer; diff --git a/src/reducer/commonSlice.ts b/src/reducer/commonSlice.ts index 204ebb68..20ea8e76 100644 --- a/src/reducer/commonSlice.ts +++ b/src/reducer/commonSlice.ts @@ -2,49 +2,50 @@ import { createSlice } from '@reduxjs/toolkit'; import { GLOBAL, setGlobalUserData } from '../constants/Global'; interface IClickstreamEvents { - name: string; - attributes?: Record + name: string; + attributes?: Record; } export interface User { - isLoggedIn: boolean; - deviceId: string; - sessionToken: string; + isLoggedIn: boolean; + deviceId: string; + sessionToken: string; } export interface CommonState { - userData: User; - clickstreamEvents: IClickstreamEvents[]; + userData: User; + clickstreamEvents: IClickstreamEvents[]; } const initialState = { - userData: { - isLoggedIn: false, - sessionToken: GLOBAL.SESSION_TOKEN || '', - deviceId: GLOBAL.DEVICE_ID || '', - } as User, - clickstreamEvents: [] + userData: { + isLoggedIn: false, + sessionToken: GLOBAL.SESSION_TOKEN || '', + deviceId: GLOBAL.DEVICE_ID || '', + } as User, + clickstreamEvents: [], } as CommonState; export const commonSlice = createSlice({ - name: 'common', - initialState, - reducers: { - setAuthData: (state, action) => { - if (action.payload) { - state.userData = { ...state.userData, ...action.payload }; - setGlobalUserData( - {token: state.userData.sessionToken, deviceId:state.userData.deviceId,} - ); - } - }, - setClickstreamEvents: (state, action) => { - state.clickstreamEvents = [state.clickstreamEvents, ...action.payload]; - }, - resetClickstreamEvents: (state) => { - state.clickstreamEvents = []; - } + name: 'common', + initialState, + reducers: { + setAuthData: (state, action) => { + if (action.payload) { + state.userData = { ...state.userData, ...action.payload }; + setGlobalUserData({ + token: state.userData.sessionToken, + deviceId: state.userData.deviceId, + }); + } }, + setClickstreamEvents: (state, action) => { + state.clickstreamEvents = [state.clickstreamEvents, ...action.payload]; + }, + resetClickstreamEvents: (state) => { + state.clickstreamEvents = []; + }, + }, }); export const { setAuthData, setClickstreamEvents, resetClickstreamEvents } = commonSlice.actions; diff --git a/src/reducer/emiScheduleSlice.ts b/src/reducer/emiScheduleSlice.ts index 3e2d1047..279703f5 100644 --- a/src/reducer/emiScheduleSlice.ts +++ b/src/reducer/emiScheduleSlice.ts @@ -1,34 +1,39 @@ import { createSlice, PayloadAction } from '@reduxjs/toolkit'; - interface IEmiScheduleState { - //TODO: update interface of EmiSchedule instead of any - [loanAccountNumber: string] : {data : any, isLoading: boolean, timestamp: string }; + //TODO: update interface of EmiSchedule instead of any + [loanAccountNumber: string]: { data: any; isLoading: boolean; timestamp: string }; } const initialState: IEmiScheduleState = {}; const EmiScheduleSlice = createSlice({ - name: 'emiSchedule', - initialState, - reducers: { - setEmiSchedule: (state, action) => { - const { loanAccountNumber, emiSchedule } = action.payload; - state[loanAccountNumber] = {data: emiSchedule, timestamp: new Date().toISOString(),isLoading: false } - }, - setEmiScheduleLoading: (state, action: PayloadAction<{ loanAccountNumbers: string[], isLoading: boolean }>) => { - const payloadData = action.payload - payloadData.loanAccountNumbers.forEach((loanAccNumber)=>{ - state[loanAccNumber] = {...(state?.[loanAccNumber] || []), isLoading: payloadData.isLoading} - }) - }, - + name: 'emiSchedule', + initialState, + reducers: { + setEmiSchedule: (state, action) => { + const { loanAccountNumber, emiSchedule } = action.payload; + state[loanAccountNumber] = { + data: emiSchedule, + timestamp: new Date().toISOString(), + isLoading: false, + }; }, + setEmiScheduleLoading: ( + state, + action: PayloadAction<{ loanAccountNumbers: string[]; isLoading: boolean }> + ) => { + const payloadData = action.payload; + payloadData.loanAccountNumbers.forEach((loanAccNumber) => { + state[loanAccNumber] = { + ...(state?.[loanAccNumber] || []), + isLoading: payloadData.isLoading, + }; + }); + }, + }, }); -export const { - setEmiSchedule, - setEmiScheduleLoading, -} = EmiScheduleSlice.actions; +export const { setEmiSchedule, setEmiScheduleLoading } = EmiScheduleSlice.actions; export default EmiScheduleSlice.reducer; diff --git a/src/reducer/feedbackHistorySlice.ts b/src/reducer/feedbackHistorySlice.ts index 34822151..4c58e4de 100644 --- a/src/reducer/feedbackHistorySlice.ts +++ b/src/reducer/feedbackHistorySlice.ts @@ -2,31 +2,44 @@ import { createSlice, PayloadAction } from '@reduxjs/toolkit'; import { IFeedback } from '../types/feedback.types'; interface IFeedbackHistoryState { - [loanAccountNumber: string] : { data : IFeedback[], isLoading: boolean, timestamp: string, totalPages: number }; + [loanAccountNumber: string]: { + data: IFeedback[]; + isLoading: boolean; + timestamp: string; + totalPages: number; + }; } const initialState: IFeedbackHistoryState = {}; const FeedbackHistorySlice = createSlice({ - name: 'feedbackHistory', - initialState, - reducers: { - setFeedbackHistory: (state, action) => { - const { loanAccountNumber, feedbacks, totalPages } = action.payload; - state[loanAccountNumber] = {data: feedbacks, timestamp: new Date().toISOString(), isLoading: false, totalPages } - }, - setFeedbackHistoryLoading: (state, action: PayloadAction<{ loanAccountNumbers: string[], isLoading: boolean }>) => { - const payloadData = action.payload - payloadData.loanAccountNumbers.forEach((loanAccNumber)=>{ - state[loanAccNumber] = {...(state?.[loanAccNumber] || []), isLoading: payloadData.isLoading} - }) - }, + name: 'feedbackHistory', + initialState, + reducers: { + setFeedbackHistory: (state, action) => { + const { loanAccountNumber, feedbacks, totalPages } = action.payload; + state[loanAccountNumber] = { + data: feedbacks, + timestamp: new Date().toISOString(), + isLoading: false, + totalPages, + }; }, + setFeedbackHistoryLoading: ( + state, + action: PayloadAction<{ loanAccountNumbers: string[]; isLoading: boolean }> + ) => { + const payloadData = action.payload; + payloadData.loanAccountNumbers.forEach((loanAccNumber) => { + state[loanAccNumber] = { + ...(state?.[loanAccNumber] || []), + isLoading: payloadData.isLoading, + }; + }); + }, + }, }); -export const { - setFeedbackHistory, - setFeedbackHistoryLoading -} = FeedbackHistorySlice.actions; +export const { setFeedbackHistory, setFeedbackHistoryLoading } = FeedbackHistorySlice.actions; export default FeedbackHistorySlice.reducer; diff --git a/src/reducer/filtersSlice.ts b/src/reducer/filtersSlice.ts index 76b43962..6d657ba7 100644 --- a/src/reducer/filtersSlice.ts +++ b/src/reducer/filtersSlice.ts @@ -1,86 +1,81 @@ -import {FilterGroup, FilterResponse, IQuickFilter} from '../screens/allCases/interface'; -import {createSlice} from '@reduxjs/toolkit'; -import {filterTransformer} from '../components/screens/allCases/allCasesFilters/FilterUtils'; -import {_map} from '../../RN-UI-LIB/src/utlis/common'; -import {CONDITIONAL_OPERATORS, FILTER_TYPES, SELECTION_TYPES} from "../common/Constants"; +import { FilterGroup, FilterResponse, IQuickFilter } from '../screens/allCases/interface'; +import { createSlice } from '@reduxjs/toolkit'; +import { filterTransformer } from '../components/screens/allCases/allCasesFilters/FilterUtils'; +import { _map } from '../../RN-UI-LIB/src/utlis/common'; +import { CONDITIONAL_OPERATORS, FILTER_TYPES, SELECTION_TYPES } from '../common/Constants'; interface IFiltersSlice { - filters: Record; - quickFilters: IQuickFilter[]; - selectedFilters: Record; - selectedFiltersVisitPlan: Record; - filterCount: number; - filterCountVisitPlan: number; + filters: Record; + quickFilters: IQuickFilter[]; + selectedFilters: Record; + selectedFiltersVisitPlan: Record; + filterCount: number; + filterCountVisitPlan: number; } const initialState: IFiltersSlice = { - filters: {}, - quickFilters: [], - filterCount: 0, - filterCountVisitPlan: 0, - selectedFilters: {}, - selectedFiltersVisitPlan: {}, + filters: {}, + quickFilters: [], + filterCount: 0, + filterCountVisitPlan: 0, + selectedFilters: {}, + selectedFiltersVisitPlan: {}, }; const filtersSlice = createSlice({ - name: 'filters', - initialState, - reducers: { - setFilters: (state, action) => { - const { filterGroupMap, quickFilters } = - filterTransformer(action.payload); - state.filters = filterGroupMap; - state.quickFilters = quickFilters; - }, - setSelectedFilters: (state, action) => { - state.selectedFilters = { - ...action.payload, - }; - let filterCount = 0; - _map(state.selectedFilters, filterKey => { - switch (typeof state.selectedFilters[filterKey]) { - case 'object': - filterCount += - state.selectedFilters[filterKey] && - Object.keys(state.selectedFilters[filterKey]) - .length; - break; - case 'string': - filterCount += 1; - break; - default: - break; - } - }); - state.filterCount = filterCount; - }, - setSelectedFiltersVisitPlan: (state, action) => { - state.selectedFiltersVisitPlan = { - ...action.payload, - }; - let filterCount = 0; - _map(state.selectedFiltersVisitPlan, filterKey => { - switch (typeof state.selectedFiltersVisitPlan[filterKey]) { - case 'object': - filterCount += - state.selectedFiltersVisitPlan[filterKey] && - Object.keys( - state.selectedFiltersVisitPlan[filterKey], - ).length; - break; - case 'string': - filterCount += 1; - break; - default: - break; - } - }); - state.filterCountVisitPlan = filterCount; - }, + name: 'filters', + initialState, + reducers: { + setFilters: (state, action) => { + const { filterGroupMap, quickFilters } = filterTransformer(action.payload); + state.filters = filterGroupMap; + state.quickFilters = quickFilters; }, + setSelectedFilters: (state, action) => { + state.selectedFilters = { + ...action.payload, + }; + let filterCount = 0; + _map(state.selectedFilters, (filterKey) => { + switch (typeof state.selectedFilters[filterKey]) { + case 'object': + filterCount += + state.selectedFilters[filterKey] && + Object.keys(state.selectedFilters[filterKey]).length; + break; + case 'string': + filterCount += 1; + break; + default: + break; + } + }); + state.filterCount = filterCount; + }, + setSelectedFiltersVisitPlan: (state, action) => { + state.selectedFiltersVisitPlan = { + ...action.payload, + }; + let filterCount = 0; + _map(state.selectedFiltersVisitPlan, (filterKey) => { + switch (typeof state.selectedFiltersVisitPlan[filterKey]) { + case 'object': + filterCount += + state.selectedFiltersVisitPlan[filterKey] && + Object.keys(state.selectedFiltersVisitPlan[filterKey]).length; + break; + case 'string': + filterCount += 1; + break; + default: + break; + } + }); + state.filterCountVisitPlan = filterCount; + }, + }, }); -export const { setFilters, setSelectedFilters, setSelectedFiltersVisitPlan } = - filtersSlice.actions; +export const { setFilters, setSelectedFilters, setSelectedFiltersVisitPlan } = filtersSlice.actions; export default filtersSlice.reducer; diff --git a/src/reducer/formData.ts b/src/reducer/formData.ts index 1f033d67..96e14855 100644 --- a/src/reducer/formData.ts +++ b/src/reducer/formData.ts @@ -1,15 +1,15 @@ import { createSlice } from '@reduxjs/toolkit'; export const formReducer = createSlice({ - name: 'formData', - initialState: { - value: 0, - }, - reducers: { - decreaseByOne: state => { - state.value--; - }, + name: 'formData', + initialState: { + value: 0, + }, + reducers: { + decreaseByOne: (state) => { + state.value--; }, + }, }); export const { decreaseByOne } = formReducer.actions; diff --git a/src/reducer/index.ts b/src/reducer/index.ts index 8956666d..5a0fc187 100644 --- a/src/reducer/index.ts +++ b/src/reducer/index.ts @@ -4,15 +4,15 @@ import caseReducer from './caseReducer'; import formReducer from './formData'; import QueueSlice from './Queue'; import paymentSlice from './paymentSlice'; -import MetadataSlice from "./metadataSlice"; +import MetadataSlice from './metadataSlice'; const rootReducer = combineReducers({ - caseDetail: caseReducer, - formData: formReducer, - loginInfo: loginSlice, - queue: QueueSlice, - payment: paymentSlice, - metadata : MetadataSlice + caseDetail: caseReducer, + formData: formReducer, + loginInfo: loginSlice, + queue: QueueSlice, + payment: paymentSlice, + metadata: MetadataSlice, }); export default rootReducer; diff --git a/src/reducer/loginSlice.ts b/src/reducer/loginSlice.ts index a7dca281..1022cfec 100644 --- a/src/reducer/loginSlice.ts +++ b/src/reducer/loginSlice.ts @@ -1,64 +1,64 @@ import { createSlice } from '@reduxjs/toolkit'; const initialState = { - phoneNumber: '', - otpToken: '', - OTPError: '', - verifyOTPSuccess: '', - verifyOTPError: '', - isLoading: false, + phoneNumber: '', + otpToken: '', + OTPError: '', + verifyOTPSuccess: '', + verifyOTPError: '', + isLoading: false, }; const loginSlice = createSlice({ - name: 'auth', - initialState, - reducers: { - setShowOTPScreen: (state, action) => { - const { phoneNumber, otpToken } = action.payload; - state.phoneNumber = phoneNumber || state.phoneNumber; - state.otpToken = otpToken; - state.isLoading = false; - state.OTPError = ''; - state.verifyOTPError = ''; - }, - setOTPError: (state, action) => { - state.OTPError = action.payload; - state.isLoading = false; - }, - setVerifyOTPSuccess: (state, action) => { - state.verifyOTPSuccess = action.payload; - state.verifyOTPError = ''; - state.isLoading = false; - }, - setVerifyOTPError: (state, action) => { - state.verifyOTPError = action.payload; - state.isLoading = false; - }, - resetVerifyOTPError: state => { - state.verifyOTPError = ''; - }, - setFormLoading: (state, action) => { - state.isLoading = action.payload; - }, - resetLoginForm: state => { - state.phoneNumber = ''; - state.otpToken = ''; - state.OTPError = ''; - state.verifyOTPSuccess = ''; - state.verifyOTPError = ''; - state.isLoading = false; - }, + name: 'auth', + initialState, + reducers: { + setShowOTPScreen: (state, action) => { + const { phoneNumber, otpToken } = action.payload; + state.phoneNumber = phoneNumber || state.phoneNumber; + state.otpToken = otpToken; + state.isLoading = false; + state.OTPError = ''; + state.verifyOTPError = ''; }, + setOTPError: (state, action) => { + state.OTPError = action.payload; + state.isLoading = false; + }, + setVerifyOTPSuccess: (state, action) => { + state.verifyOTPSuccess = action.payload; + state.verifyOTPError = ''; + state.isLoading = false; + }, + setVerifyOTPError: (state, action) => { + state.verifyOTPError = action.payload; + state.isLoading = false; + }, + resetVerifyOTPError: (state) => { + state.verifyOTPError = ''; + }, + setFormLoading: (state, action) => { + state.isLoading = action.payload; + }, + resetLoginForm: (state) => { + state.phoneNumber = ''; + state.otpToken = ''; + state.OTPError = ''; + state.verifyOTPSuccess = ''; + state.verifyOTPError = ''; + state.isLoading = false; + }, + }, }); export const { - setOTPError, - setVerifyOTPError, - setVerifyOTPSuccess, - setShowOTPScreen, - setFormLoading, - resetLoginForm, - resetVerifyOTPError, + setOTPError, + setVerifyOTPError, + setVerifyOTPSuccess, + setShowOTPScreen, + setFormLoading, + resetLoginForm, + resetVerifyOTPError, } = loginSlice.actions; export default loginSlice.reducer; diff --git a/src/reducer/metadataSlice.ts b/src/reducer/metadataSlice.ts index a7dee935..0ccf05b7 100644 --- a/src/reducer/metadataSlice.ts +++ b/src/reducer/metadataSlice.ts @@ -1,31 +1,32 @@ import { createSlice } from '@reduxjs/toolkit'; export interface UninstallInformation { - last_operational_time: any, reinstall_endpoint: string + last_operational_time: any; + reinstall_endpoint: string; } interface IMetadata { - isOnline: boolean, - forceUninstall : Record + isOnline: boolean; + forceUninstall: Record; } const initialState = { - isOnline : true, - forceUninstall: {} + isOnline: true, + forceUninstall: {}, } as IMetadata; const MetadataSlice = createSlice({ - name: 'metadata', - initialState, - reducers: { - setIsOnline: (state, action) => { - state.isOnline = action.payload; - }, - setForceUninstallData: (state, action) => { - state.forceUninstall = action.payload; - }, + name: 'metadata', + initialState, + reducers: { + setIsOnline: (state, action) => { + state.isOnline = action.payload; }, + setForceUninstallData: (state, action) => { + state.forceUninstall = action.payload; + }, + }, }); -export const {setIsOnline, setForceUninstallData} = MetadataSlice.actions; +export const { setIsOnline, setForceUninstallData } = MetadataSlice.actions; export default MetadataSlice.reducer; diff --git a/src/reducer/notificationsSlice.ts b/src/reducer/notificationsSlice.ts index 4ec05d1c..53889660 100644 --- a/src/reducer/notificationsSlice.ts +++ b/src/reducer/notificationsSlice.ts @@ -3,125 +3,109 @@ import { INotification } from '../screens/notifications/NotificationItem'; import { WidgetStatus } from '../screens/notifications/constants'; export interface INotificationAction { - id: string; - action: { - widgetStatus: WidgetStatus; - timestamp: number; - actionBy: string; - }; + id: string; + action: { + widgetStatus: WidgetStatus; + timestamp: number; + actionBy: string; + }; } interface INotificationsState { - data: INotification[]; - pageNo: number; - pageSize: number; - totalElements: number; - totalPages: number; - newNotificationCount: number; - totalUnreadElements: number; - notificationsWithActions: INotificationAction[]; - isLoading: boolean; + data: INotification[]; + pageNo: number; + pageSize: number; + totalElements: number; + totalPages: number; + newNotificationCount: number; + totalUnreadElements: number; + notificationsWithActions: INotificationAction[]; + isLoading: boolean; } const initialState: INotificationsState = { - data: [], - pageNo: 1, - pageSize: 10, - totalElements: 0, - totalPages: 0, - newNotificationCount: 0, - totalUnreadElements: 0, - notificationsWithActions: [], - isLoading: false, + data: [], + pageNo: 1, + pageSize: 10, + totalElements: 0, + totalPages: 0, + newNotificationCount: 0, + totalUnreadElements: 0, + notificationsWithActions: [], + isLoading: false, }; const NotificationsSlice = createSlice({ - name: 'notificationsSlice', - initialState, - reducers: { - setNotifications: (state, action) => { - const { - notifications, - totalElements, - totalPages, - pageNo, - totalUnreadElements, - } = action.payload; - state.data = notifications; - state.totalElements = totalElements; - state.totalPages = totalPages; - state.newNotificationCount = 0; - state.totalUnreadElements = totalUnreadElements; - state.pageNo = pageNo; - state.isLoading = false; - }, - prependNewNotifications: (state, action) => { - const { notification } = action.payload; - const { id } = notification; - const isNotificationAlreadyPresent = - state.data.findIndex(notification => notification.id === id) !== - -1; - state.isLoading = false; - if (isNotificationAlreadyPresent) { - return; - } - state.data = [notification, ...state.data]; - state.newNotificationCount++; - state.totalUnreadElements++; - }, - appendMoreNotifications: (state, action) => { - const { - notifications, - totalElements, - pageNo, - totalPages, - totalUnreadElements, - } = action.payload; - state.data = [...state.data, ...notifications]; - state.totalElements = totalElements; - state.totalPages = totalPages; - state.pageNo = pageNo; - state.totalUnreadElements = totalUnreadElements; - state.isLoading = false; - }, - addNotificationToQueue: (state, action) => { - state.notificationsWithActions = [ - ...state.notificationsWithActions, - action.payload, - ]; - }, - addActionToNotifications: (state, action) => { - const actionPayload = action.payload; - let readNotificationCount = 0; - actionPayload.forEach((action: INotificationAction) => { - const { id } = action; - const index = state.data.findIndex( - notification => notification.id === id, - ); - if (index !== -1) { - readNotificationCount++; - state.data[index].actions = [ - { - widgetStatus: WidgetStatus.CLICKED, - }, - ]; - } - }); - state.totalUnreadElements = state.totalUnreadElements - readNotificationCount; - state.notificationsWithActions = []; - }, - setNotificationsLoading: (state, action) => { - state.isLoading = action.payload; - }, + name: 'notificationsSlice', + initialState, + reducers: { + setNotifications: (state, action) => { + const { notifications, totalElements, totalPages, pageNo, totalUnreadElements } = + action.payload; + state.data = notifications; + state.totalElements = totalElements; + state.totalPages = totalPages; + state.newNotificationCount = 0; + state.totalUnreadElements = totalUnreadElements; + state.pageNo = pageNo; + state.isLoading = false; }, + prependNewNotifications: (state, action) => { + const { notification } = action.payload; + const { id } = notification; + const isNotificationAlreadyPresent = + state.data.findIndex((notification) => notification.id === id) !== -1; + state.isLoading = false; + if (isNotificationAlreadyPresent) { + return; + } + state.data = [notification, ...state.data]; + state.newNotificationCount++; + state.totalUnreadElements++; + }, + appendMoreNotifications: (state, action) => { + const { notifications, totalElements, pageNo, totalPages, totalUnreadElements } = + action.payload; + state.data = [...state.data, ...notifications]; + state.totalElements = totalElements; + state.totalPages = totalPages; + state.pageNo = pageNo; + state.totalUnreadElements = totalUnreadElements; + state.isLoading = false; + }, + addNotificationToQueue: (state, action) => { + state.notificationsWithActions = [...state.notificationsWithActions, action.payload]; + }, + addActionToNotifications: (state, action) => { + const actionPayload = action.payload; + let readNotificationCount = 0; + actionPayload.forEach((action: INotificationAction) => { + const { id } = action; + const index = state.data.findIndex((notification) => notification.id === id); + if (index !== -1) { + readNotificationCount++; + state.data[index].actions = [ + { + widgetStatus: WidgetStatus.CLICKED, + }, + ]; + } + }); + state.totalUnreadElements = state.totalUnreadElements - readNotificationCount; + state.notificationsWithActions = []; + }, + setNotificationsLoading: (state, action) => { + state.isLoading = action.payload; + }, + }, }); export const { - setNotifications, - prependNewNotifications, - appendMoreNotifications, - setNotificationsLoading, - addNotificationToQueue, - addActionToNotifications, + setNotifications, + prependNewNotifications, + appendMoreNotifications, + setNotificationsLoading, + addNotificationToQueue, + addActionToNotifications, } = NotificationsSlice.actions; export default NotificationsSlice.reducer; diff --git a/src/reducer/paymentSlice.ts b/src/reducer/paymentSlice.ts index fc8911ec..acb5c191 100644 --- a/src/reducer/paymentSlice.ts +++ b/src/reducer/paymentSlice.ts @@ -4,56 +4,52 @@ import { ILoanIdValue } from '../action/paymentActions'; export type ILoanIdToValue = Record; interface IPaymentState { - paymentLink: string; - isLoading: boolean; - loanIdToValue: ILoanIdToValue; + paymentLink: string; + isLoading: boolean; + loanIdToValue: ILoanIdToValue; } const initialState: IPaymentState = { - paymentLink: '', - isLoading: false, - loanIdToValue: {}, + paymentLink: '', + isLoading: false, + loanIdToValue: {}, }; const paymentSlice = createSlice({ - name: 'payment', - initialState, - reducers: { - setPaymentLink: (state, action: PayloadAction) => { - return { - ...state, - paymentLink: action.payload, - }; - }, - setLoading: (state, action: PayloadAction) => { - return { - ...state, - isLoading: action.payload, - }; - }, - setLoanIdToValue: (state, action: PayloadAction) => { - return { - ...state, - loanIdToValue: action.payload, - }; - }, - appendLoanIdToValue: (state, action: PayloadAction) => { - return { - ...state, - loanIdToValue: { - ...state.loanIdToValue, - ...action.payload, - }, - }; - }, + name: 'payment', + initialState, + reducers: { + setPaymentLink: (state, action: PayloadAction) => { + return { + ...state, + paymentLink: action.payload, + }; }, + setLoading: (state, action: PayloadAction) => { + return { + ...state, + isLoading: action.payload, + }; + }, + setLoanIdToValue: (state, action: PayloadAction) => { + return { + ...state, + loanIdToValue: action.payload, + }; + }, + appendLoanIdToValue: (state, action: PayloadAction) => { + return { + ...state, + loanIdToValue: { + ...state.loanIdToValue, + ...action.payload, + }, + }; + }, + }, }); -export const { - setPaymentLink, - setLoading, - setLoanIdToValue, - appendLoanIdToValue, -} = paymentSlice.actions; +export const { setPaymentLink, setLoading, setLoanIdToValue, appendLoanIdToValue } = + paymentSlice.actions; export default paymentSlice.reducer; diff --git a/src/reducer/repaymentsSlice.ts b/src/reducer/repaymentsSlice.ts index 846efb94..aec07fbf 100644 --- a/src/reducer/repaymentsSlice.ts +++ b/src/reducer/repaymentsSlice.ts @@ -1,33 +1,40 @@ import { createSlice, PayloadAction } from '@reduxjs/toolkit'; -import {IRepaymentsRecord} from "../types/repayments.types"; +import { IRepaymentsRecord } from '../types/repayments.types'; interface IRepaymentsState { - //TODO: update interface of Repayments instead of any - [loanAccountNumber: string] : {data : IRepaymentsRecord[], isLoading: boolean, timestamp: string }; + //TODO: update interface of Repayments instead of any + [loanAccountNumber: string]: { data: IRepaymentsRecord[]; isLoading: boolean; timestamp: string }; } const initialState: IRepaymentsState = {}; const RepaymentsSlice = createSlice({ - name: 'repayments', - initialState, - reducers: { - setRepayments: (state, action) => { - const { loanAccountNumber, repayments } = action.payload; - state[loanAccountNumber] = {data: repayments, timestamp: new Date().toISOString(),isLoading: false } - }, - setRepaymentsLoading: (state, action: PayloadAction<{ loanAccountNumbers: string[], isLoading: boolean }>) => { - const payloadData = action.payload - payloadData.loanAccountNumbers.forEach((loanAccNumber)=>{ - state[loanAccNumber] = {...(state?.[loanAccNumber] || []), isLoading: payloadData.isLoading} - }) - }, + name: 'repayments', + initialState, + reducers: { + setRepayments: (state, action) => { + const { loanAccountNumber, repayments } = action.payload; + state[loanAccountNumber] = { + data: repayments, + timestamp: new Date().toISOString(), + isLoading: false, + }; }, + setRepaymentsLoading: ( + state, + action: PayloadAction<{ loanAccountNumbers: string[]; isLoading: boolean }> + ) => { + const payloadData = action.payload; + payloadData.loanAccountNumbers.forEach((loanAccNumber) => { + state[loanAccNumber] = { + ...(state?.[loanAccNumber] || []), + isLoading: payloadData.isLoading, + }; + }); + }, + }, }); -export const { - setRepayments, - setRepaymentsLoading -} = RepaymentsSlice.actions; +export const { setRepayments, setRepaymentsLoading } = RepaymentsSlice.actions; export default RepaymentsSlice.reducer; diff --git a/src/reducer/userSlice.ts b/src/reducer/userSlice.ts index 9e1ce162..391fdce8 100644 --- a/src/reducer/userSlice.ts +++ b/src/reducer/userSlice.ts @@ -2,63 +2,63 @@ import { createSlice } from '@reduxjs/toolkit'; import { setGlobalUserData } from '../constants/Global'; interface ISessionDetails { - sessionToken: string; - sessionExpiry: number; - firebaseToken: string; + sessionToken: string; + sessionExpiry: number; + firebaseToken: string; } interface IUserDetails { - emailId: string; - referenceId: string; - phoneNumber: string; - realms: string[]; - roles: string[]; - groups: string[]; - name: string; - createdAt: string; - updatedAt: string; + emailId: string; + referenceId: string; + phoneNumber: string; + realms: string[]; + roles: string[]; + groups: string[]; + name: string; + createdAt: string; + updatedAt: string; } export interface IUser { - sessionDetails: ISessionDetails | null; - user: IUserDetails | null; + sessionDetails: ISessionDetails | null; + user: IUserDetails | null; } interface IClickstreamEvents { - name: string; - attributes?: Record + name: string; + attributes?: Record; } export interface IUserSlice extends IUser { - isLoggedIn: boolean; - deviceId: string; - clickstreamEvents: IClickstreamEvents[]; + isLoggedIn: boolean; + deviceId: string; + clickstreamEvents: IClickstreamEvents[]; } const initialState: IUserSlice = { - isLoggedIn: false, - deviceId: '', - sessionDetails: null, - user: null, - clickstreamEvents: [], + isLoggedIn: false, + deviceId: '', + sessionDetails: null, + user: null, + clickstreamEvents: [], }; export const userSlice = createSlice({ - name: 'user', - initialState, - reducers: { - setAuthData: (state, action) => { - const { user, sessionDetails, isLoggedIn } = action.payload; - state.user = user; - state.sessionDetails = sessionDetails; - state.isLoggedIn = isLoggedIn; - setGlobalUserData({token: sessionDetails?.sessionToken, agentId: user?.referenceId}); - }, - setDeviceId: (state, action) => { - state.deviceId = action.payload; - setGlobalUserData({token:'', deviceId: action.payload}); - } + name: 'user', + initialState, + reducers: { + setAuthData: (state, action) => { + const { user, sessionDetails, isLoggedIn } = action.payload; + state.user = user; + state.sessionDetails = sessionDetails; + state.isLoggedIn = isLoggedIn; + setGlobalUserData({ token: sessionDetails?.sessionToken, agentId: user?.referenceId }); }, + setDeviceId: (state, action) => { + state.deviceId = action.payload; + setGlobalUserData({ token: '', deviceId: action.payload }); + }, + }, }); export const { setAuthData, setDeviceId } = userSlice.actions; diff --git a/src/screens/addNewNumber/apiHelper.ts b/src/screens/addNewNumber/apiHelper.ts index 5a0da855..0536c72b 100644 --- a/src/screens/addNewNumber/apiHelper.ts +++ b/src/screens/addNewNumber/apiHelper.ts @@ -7,46 +7,43 @@ import { navigateToScreen } from '../../components/utlis/navigationUtlis'; import { Source, Tag } from './const'; interface IAddNewNumberApi { - tag: Tag; - source: Source; - number: string; - customerReferenceId: string; - caseId: string; + tag: Tag; + source: Source; + number: string; + customerReferenceId: string; + caseId: string; } -export const addNewNumberApi = ( - data: IAddNewNumberApi, - afterApiCallback?: GenericFunctionArgs, -) => { - const { tag, source, number, customerReferenceId, caseId } = data; - const url = '/telephones'; - const payload = [ - { - number, - tag, - origin: source, - }, - ]; - axiosInstance - .post(url, payload, { - params: { - customerReferenceId, - }, - }) - .then((response: AxiosResponse) => { - if (response.status === 200) { - toast({ - type: 'info', - text1: 'Number added successfully', - }); - navigateToScreen(PageRouteEnum.COLLECTION_CASE_DETAIL, { - caseId: caseId, - }); - } - }) - .catch(error => { - return error?.response?.data || error?.message || error; - }) - .finally(() => { - afterApiCallback && afterApiCallback(); +export const addNewNumberApi = (data: IAddNewNumberApi, afterApiCallback?: GenericFunctionArgs) => { + const { tag, source, number, customerReferenceId, caseId } = data; + const url = '/telephones'; + const payload = [ + { + number, + tag, + origin: source, + }, + ]; + axiosInstance + .post(url, payload, { + params: { + customerReferenceId, + }, + }) + .then((response: AxiosResponse) => { + if (response.status === 200) { + toast({ + type: 'info', + text1: 'Number added successfully', }); + navigateToScreen(PageRouteEnum.COLLECTION_CASE_DETAIL, { + caseId: caseId, + }); + } + }) + .catch((error) => { + return error?.response?.data || error?.message || error; + }) + .finally(() => { + afterApiCallback && afterApiCallback(); + }); }; diff --git a/src/screens/addNewNumber/const.ts b/src/screens/addNewNumber/const.ts index 07325f0c..40c58357 100644 --- a/src/screens/addNewNumber/const.ts +++ b/src/screens/addNewNumber/const.ts @@ -1,12 +1,12 @@ export enum Tag { - Customer = 'Customer', - Relative = 'Relative', - Others = 'Others', + Customer = 'Customer', + Relative = 'Relative', + Others = 'Others', } export enum Source { - Relative = 'Relative', - Neighbour = 'Neighbour', - Security = 'Security', - Others = 'Others', + Relative = 'Relative', + Neighbour = 'Neighbour', + Security = 'Security', + Others = 'Others', } diff --git a/src/screens/allCases/constants.ts b/src/screens/allCases/constants.ts index f8ed0da1..2319fd6f 100644 --- a/src/screens/allCases/constants.ts +++ b/src/screens/allCases/constants.ts @@ -3,61 +3,57 @@ import { CaseTypes } from './interface'; export const COMPLETED_STATUSES = ['CLOSED', 'EXPIRED', 'FORCED_CLOSE', 'ACTIVE_COMPLETED']; export const ListHeaderItems = { - BANNER: { - type: CaseTypes.BANNER, - caseReferenceId: '-1', - }, - FILTER: { - type: CaseTypes.FILTER, - caseReferenceId: '-1', - }, - PINNED_LIST: { - type: CaseTypes.TODO_HEADER, - caseReferenceId: '-2', - }, - OTHER_CASES: { - type: CaseTypes.CASES_HEADER, - caseReferenceId: '-3', - }, - ADD_VISIT_PLAN: { - type: CaseTypes.ADD_VISIT_PLAN, - caseReferenceId: '-4', - }, + BANNER: { + type: CaseTypes.BANNER, + caseReferenceId: '-1', + }, + FILTER: { + type: CaseTypes.FILTER, + caseReferenceId: '-1', + }, + PINNED_LIST: { + type: CaseTypes.TODO_HEADER, + caseReferenceId: '-2', + }, + OTHER_CASES: { + type: CaseTypes.CASES_HEADER, + caseReferenceId: '-3', + }, + ADD_VISIT_PLAN: { + type: CaseTypes.ADD_VISIT_PLAN, + caseReferenceId: '-4', + }, }; export const LIST_HEADER_ITEMS = [ - CaseTypes.BANNER, - CaseTypes.FILTER, - CaseTypes.TODO_HEADER, - CaseTypes.CASES_HEADER, - CaseTypes.ADD_VISIT_PLAN, + CaseTypes.BANNER, + CaseTypes.FILTER, + CaseTypes.TODO_HEADER, + CaseTypes.CASES_HEADER, + CaseTypes.ADD_VISIT_PLAN, ]; export const EmptyListMessages = { - NO_COMPLETED_CASES: 'No case completed yet', - NO_PENDING_CASES: - 'Looks like you resolved all your cases for this allocation', - NO_VISIT_PLANS: 'Plan your day by creating a visit plan', - NO_CASES_FOUND: 'No results found', - NO_CASES_FOUND_SUB: - 'Try removing or adding different filters, or search something else', + NO_COMPLETED_CASES: 'No case completed yet', + NO_PENDING_CASES: 'Looks like you resolved all your cases for this allocation', + NO_VISIT_PLANS: 'Plan your day by creating a visit plan', + NO_CASES_FOUND: 'No results found', + NO_CASES_FOUND_SUB: 'Try removing or adding different filters, or search something else', }; export const ToastMessages = { - VISIT_PLAN_OFFLINE: - 'Please connect to the internet to update the visit plan', - ERROR_COPYING_LAN: 'Error copying LAN!!', - SUCCESS_COPYING_LAN: 'LAN Copied Successfully!!', - FEEDBACK_SUCCESSFUL: 'Feedback submitted successfully!', - FEEDBACK_FAILED: 'Feedback submission failed', - FIRESTORE_SIGNIN_FAILED: 'Error signing in to Firestore', - PAYMENT_LINK_ERROR: 'Payment link could not be shared', - PAYMENT_LINK_SUCCESS: 'Link has been generated and shared with customer', - SUCCESS_COPYING_PAYMENT_LINK: 'Payment link has been copied to Clipboard', - FILTERS_APPLIED_SUCCESSFULLY: 'Filters applied successfully', - FEEDBACK_SUBMITTED_OFFLINE: - "Feedback will be submitted automatically once you're back online", - OFFLINE_MESSAGE: 'You seem to be offline', - PAYMENT_LINK_NOT_GENERATED: "Payment link could not be generated", - PAYMENT_LINK_RETRY : "Please retry after an hour for this number", + VISIT_PLAN_OFFLINE: 'Please connect to the internet to update the visit plan', + ERROR_COPYING_LAN: 'Error copying LAN!!', + SUCCESS_COPYING_LAN: 'LAN Copied Successfully!!', + FEEDBACK_SUCCESSFUL: 'Feedback submitted successfully!', + FEEDBACK_FAILED: 'Feedback submission failed', + FIRESTORE_SIGNIN_FAILED: 'Error signing in to Firestore', + PAYMENT_LINK_ERROR: 'Payment link could not be shared', + PAYMENT_LINK_SUCCESS: 'Link has been generated and shared with customer', + SUCCESS_COPYING_PAYMENT_LINK: 'Payment link has been copied to Clipboard', + FILTERS_APPLIED_SUCCESSFULLY: 'Filters applied successfully', + FEEDBACK_SUBMITTED_OFFLINE: "Feedback will be submitted automatically once you're back online", + OFFLINE_MESSAGE: 'You seem to be offline', + PAYMENT_LINK_NOT_GENERATED: 'Payment link could not be generated', + PAYMENT_LINK_RETRY: 'Please retry after an hour for this number', }; diff --git a/src/screens/allCases/interface.ts b/src/screens/allCases/interface.ts index 1ee259be..e1a5ec52 100644 --- a/src/screens/allCases/interface.ts +++ b/src/screens/allCases/interface.ts @@ -1,116 +1,116 @@ import { COLORS } from '../../../RN-UI-LIB/src/styles/colors'; import { - CONDITIONAL_OPERATORS, - FILTER_TYPES, - Option, - SELECTION_TYPES, + CONDITIONAL_OPERATORS, + FILTER_TYPES, + Option, + SELECTION_TYPES, } from '../../common/Constants'; import { CustomerInfo } from '../caseDetails/interface'; export enum CaseTypes { - TODO_HEADER, - CASES_HEADER, - FILTER, - TODO, - CASE, - BANNER, - ADD_VISIT_PLAN, + TODO_HEADER, + CASES_HEADER, + FILTER, + TODO, + CASE, + BANNER, + ADD_VISIT_PLAN, } export enum caseVerdict { - NOT_VERIFIED = 'NOT_VERIFIED', - VERIFIED = 'VERIFIED', - NAFS = 'NAFS', - NAFNS = 'NAFNS', - NORMAL = 'NORMAL', - ON_HOLD = 'ON_HOLD', - EXHAUSTED = 'EXHAUSTED', + NOT_VERIFIED = 'NOT_VERIFIED', + VERIFIED = 'VERIFIED', + NAFS = 'NAFS', + NAFNS = 'NAFNS', + NORMAL = 'NORMAL', + ON_HOLD = 'ON_HOLD', + EXHAUSTED = 'EXHAUSTED', } export enum caseVerdictUIMappings { - NOT_VERIFIED = 'not verified', - VERIFIED = 'verified', - NAFS = 'New address found', - NAFNS = 'New address found non serviceable', - NORMAL = 'normal', - ON_HOLD = 'On hold', - EXHAUSTED = 'Exhausted', + NOT_VERIFIED = 'not verified', + VERIFIED = 'verified', + NAFS = 'New address found', + NAFNS = 'New address found non serviceable', + NORMAL = 'normal', + ON_HOLD = 'On hold', + EXHAUSTED = 'Exhausted', } type CaseStatus = Record; export const displayStatuses: CaseStatus = { - NAFS: { label: 'New address found', color: COLORS.TEXT.YELLOW }, - ON_HOLD: { label: 'On hold', color: COLORS.TEXT.BLUE }, - IN_PROGRESS: { label: 'In progress', color: COLORS.TEXT.GREEN }, + NAFS: { label: 'New address found', color: COLORS.TEXT.YELLOW }, + ON_HOLD: { label: 'On hold', color: COLORS.TEXT.BLUE }, + IN_PROGRESS: { label: 'In progress', color: COLORS.TEXT.GREEN }, }; export const closedCaseStatuses: CaseStatus = { - VERIFIED: { label: 'Verified', color: COLORS.TEXT.GREEN }, + VERIFIED: { label: 'Verified', color: COLORS.TEXT.GREEN }, }; export enum taskStatus { - OPEN, - SKIPPED, - COMPLETED_AND_VERIFIED, - COMPLETED_AND_NOT_VERIFIED, - NOT_REQUIRED, + OPEN, + SKIPPED, + COMPLETED_AND_VERIFIED, + COMPLETED_AND_NOT_VERIFIED, + NOT_REQUIRED, } export enum CaseStatuses { - NEW = 'NEW', // for the cases that are new to the system - UNASSIGNED = 'UNASSIGNED', // for the new cases that are unassigned - ASSIGNED = 'ASSIGNED', // for the cases assigned to us, and are new - IN_PROGRESS = 'IN_PROGRESS', // when we fill the first task - CLOSED = 'CLOSED', // if any of the task become verif success - FORCE_CLOSED = 'FORCE_CLOSED', // backend force closes the task - EXPIRED = 'EXPIRED', // unattended case for 30 days. + NEW = 'NEW', // for the cases that are new to the system + UNASSIGNED = 'UNASSIGNED', // for the new cases that are unassigned + ASSIGNED = 'ASSIGNED', // for the cases assigned to us, and are new + IN_PROGRESS = 'IN_PROGRESS', // when we fill the first task + CLOSED = 'CLOSED', // if any of the task become verif success + FORCE_CLOSED = 'FORCE_CLOSED', // backend force closes the task + EXPIRED = 'EXPIRED', // unattended case for 30 days. } export enum CaseStatusUIMapping { - NEW = 'New', - UNASSIGNED = 'Unassigned', - ASSIGNED = 'Assigned', - IN_PROGRESS = 'In progress', - CLOSED = 'Closed', - FORCE_CLOSED = 'Force closed', - EXPIRED = 'Expired', + NEW = 'New', + UNASSIGNED = 'Unassigned', + ASSIGNED = 'Assigned', + IN_PROGRESS = 'In progress', + CLOSED = 'Closed', + FORCE_CLOSED = 'Force closed', + EXPIRED = 'Expired', } export enum CaseType { - AV = 'ADDRESS_VERIFICATION', - COLLECTION = 'COLLECTION_CASE' + AV = 'ADDRESS_VERIFICATION', + COLLECTION = 'COLLECTION_CASE', } export const caseVerdictAndColor = { - COMPLETED_AND_VERIFIED: { - text: 'Verified', - color: COLORS.TEXT.BLUE, - }, - IN_PROGRESS: { - text: 'In Progress', - color: COLORS.TEXT.GREEN, - }, - ASSIGNED: { - text: 'Assigned', - color: COLORS.TEXT.GREEN, - }, - NEW_ADDRESS_FOUND: { - text: 'New Address Found', - color: COLORS.TEXT.YELLOW, - }, + COMPLETED_AND_VERIFIED: { + text: 'Verified', + color: COLORS.TEXT.BLUE, + }, + IN_PROGRESS: { + text: 'In Progress', + color: COLORS.TEXT.GREEN, + }, + ASSIGNED: { + text: 'Assigned', + color: COLORS.TEXT.GREEN, + }, + NEW_ADDRESS_FOUND: { + text: 'New Address Found', + color: COLORS.TEXT.YELLOW, + }, }; export interface ICaseItem { - type: CaseTypes; // this is for maintaing frontend - pinRank: number | null; - updatedAt?: any; - allocatedAt?: any; - caseReferenceId: string; - caseStatus?: keyof typeof CaseStatusUIMapping; - caseVerdict?: string; - customerInfo?: CustomerInfo; - currentTask?: CurrentTask; + type: CaseTypes; // this is for maintaing frontend + pinRank: number | null; + updatedAt?: any; + allocatedAt?: any; + caseReferenceId: string; + caseStatus?: keyof typeof CaseStatusUIMapping; + caseVerdict?: string; + customerInfo?: CustomerInfo; + currentTask?: CurrentTask; } // export interface CustomerInfo { @@ -120,153 +120,153 @@ export interface ICaseItem { // } export interface Address { - referenceId: string; - houseNumber: string; - lineOne: string; - lineTwo: string; - locality: string; - street: string; - city: string; - state: string; - pinCode: string; - type: string; - source: string; - current: boolean; - permanent: boolean; - zipCode?: any; - addressQualityStatus?: any; + referenceId: string; + houseNumber: string; + lineOne: string; + lineTwo: string; + locality: string; + street: string; + city: string; + state: string; + pinCode: string; + type: string; + source: string; + current: boolean; + permanent: boolean; + zipCode?: any; + addressQualityStatus?: any; } export interface Metadata { - '@class': ClassType; - address: Address; - addressLine: string; - geoLocation: string; - primaryPhoneNumber: string; + '@class': ClassType; + address: Address; + addressLine: string; + geoLocation: string; + primaryPhoneNumber: string; } export interface CurrentTask { - title: TaskTitle; - metadata: Metadata; - status: string; - taskType: string; + title: TaskTitle; + metadata: Metadata; + status: string; + taskType: string; } export enum TaskTitleUIMapping { - COMMUNICATION_ADDRESS_VERIFICATION_TASK = 'Communication Address', - PERMANENT_ADDRESS_VERIFICATION_TASK = 'Permanent Address', - GEO_LOCATION_VERIFICATION_TASK = 'Last Geolocation', - CALLING_TASK = 'Call to customer', - NEW_ADDRESS_VERIFICATION_TASK = 'New Address', - COLLECTION_FEEDBACK = 'COLLECTION_FEEDBACK', + COMMUNICATION_ADDRESS_VERIFICATION_TASK = 'Communication Address', + PERMANENT_ADDRESS_VERIFICATION_TASK = 'Permanent Address', + GEO_LOCATION_VERIFICATION_TASK = 'Last Geolocation', + CALLING_TASK = 'Call to customer', + NEW_ADDRESS_VERIFICATION_TASK = 'New Address', + COLLECTION_FEEDBACK = 'COLLECTION_FEEDBACK', } export enum TaskTitle { - COMMUNICATION_ADDRESS_VERIFICATION_TASK = 'COMMUNICATION_ADDRESS_VERIFICATION_TASK', - PERMANENT_ADDRESS_VERIFICATION_TASK = 'PERMANENT_ADDRESS_VERIFICATION_TASK', - GEO_LOCATION_VERIFICATION_TASK = 'GEO_LOCATION_VERIFICATION_TASK', - CALLING_TASK = 'CALLING_TASK', - NEW_ADDRESS_VERIFICATION_TASK = 'NEW_ADDRESS_VERIFICATION_TASK', + COMMUNICATION_ADDRESS_VERIFICATION_TASK = 'COMMUNICATION_ADDRESS_VERIFICATION_TASK', + PERMANENT_ADDRESS_VERIFICATION_TASK = 'PERMANENT_ADDRESS_VERIFICATION_TASK', + GEO_LOCATION_VERIFICATION_TASK = 'GEO_LOCATION_VERIFICATION_TASK', + CALLING_TASK = 'CALLING_TASK', + NEW_ADDRESS_VERIFICATION_TASK = 'NEW_ADDRESS_VERIFICATION_TASK', } export enum ClassType { - '.AddressEntityMetadata', - '.GeoLocationEntityMetadata', - '.CallingEntityMetadata', + '.AddressEntityMetadata', + '.GeoLocationEntityMetadata', + '.CallingEntityMetadata', } export interface IFieldToCompare { - // @Todo case type to be converted to enum from string - caseType: string; - path: string; + // @Todo case type to be converted to enum from string + caseType: string; + path: string; } export interface FilterOption extends Option { - quickFilter: boolean; + quickFilter: boolean; } export interface IFilterMeta { - name: string; - filterType: FILTER_TYPES; - displayText: string; - selectionType: SELECTION_TYPES; - fieldsToCompare: IFieldToCompare[]; - operator: CONDITIONAL_OPERATORS; + name: string; + filterType: FILTER_TYPES; + displayText: string; + selectionType: SELECTION_TYPES; + fieldsToCompare: IFieldToCompare[]; + operator: CONDITIONAL_OPERATORS; } export interface IQuickFilter extends IFilterMeta, Option {} export interface IFilter extends IFilterMeta { - options?: FilterOption[]; + options?: FilterOption[]; } export interface FilterResponse { - name: string; - headerText: string; - filters: Array; + name: string; + headerText: string; + filters: Array; } export interface FilterGroup { - name: string; - headerText: string; - filters: Record; + name: string; + headerText: string; + filters: Record; } export enum CaseAllocationType { - ADDRESS_VERIFICATION_CASE = 'ADDRESS_VERIFICATION_CASE', - COLLECTION_CASE = 'COLLECTION_CASE', + ADDRESS_VERIFICATION_CASE = 'ADDRESS_VERIFICATION_CASE', + COLLECTION_CASE = 'COLLECTION_CASE', } export const CaseTypeMap: Record = { - COLLECTION_CASE: 'Collections', - ADDRESS_VERIFICATION_CASE: 'Customer onboarding', + COLLECTION_CASE: 'Collections', + ADDRESS_VERIFICATION_CASE: 'Customer onboarding', }; export interface IPinnedCasesPayload { - caseReferenceId: string; - caseType: CaseAllocationType; - pinRank: number | null; + caseReferenceId: string; + caseType: CaseAllocationType; + pinRank: number | null; } export enum InteractionStatuses { - PAID = 'Paid', - NOT_CONTACTED = 'Not contacted', - PROMISE_TO_PAY = 'Promise to pay', - PROMISE_TO_PAY_LATER = 'Promise to pay later', - REVISIT = 'Revisit', - PROMISE_FULFILLED = 'Promise fulfilled', - BROKEN_PROMISE = 'Broken promise', - NOT_CONTACTABLE = 'not contactable', - REQUESTED_CALLBACK = 'Requested callback', - DISPUTE = 'Dispute', - CUSTOMER_EXPIRED = 'Customer expired', - RINGING_NO_RESPONSE = 'Ringing no response', - ADDRESS_NOT_FOUND = 'Address not found', - CUSTOMER_SHIFTED_FROM_ADDRESS = 'Customer shifter from address', - REFUSED_TO_PAY = 'Refused to pay', - DOOR_LOCKED = 'Door locked', - CALL_DISCONNECTED_RPC = 'Call disconnected RPC', - CALL_DISCONNECTED_NON_RPC = 'Call disconnected NON RPC', - MESSAGE_LEFT = 'Message left', - OTHERS = 'Others', - SWITCHED_OFF = 'Switched off', - INVALID_NUMBER = 'Invalid number', - BUSY = 'Busy', - PARTIALLY_PAID = 'Partially paid', - ENTRY_RESTRICTED = 'Entry restricted', - CUSTOMER_NEVER_LIVED_IN_ADDRESS = 'Customer never lived in address' + PAID = 'Paid', + NOT_CONTACTED = 'Not contacted', + PROMISE_TO_PAY = 'Promise to pay', + PROMISE_TO_PAY_LATER = 'Promise to pay later', + REVISIT = 'Revisit', + PROMISE_FULFILLED = 'Promise fulfilled', + BROKEN_PROMISE = 'Broken promise', + NOT_CONTACTABLE = 'not contactable', + REQUESTED_CALLBACK = 'Requested callback', + DISPUTE = 'Dispute', + CUSTOMER_EXPIRED = 'Customer expired', + RINGING_NO_RESPONSE = 'Ringing no response', + ADDRESS_NOT_FOUND = 'Address not found', + CUSTOMER_SHIFTED_FROM_ADDRESS = 'Customer shifter from address', + REFUSED_TO_PAY = 'Refused to pay', + DOOR_LOCKED = 'Door locked', + CALL_DISCONNECTED_RPC = 'Call disconnected RPC', + CALL_DISCONNECTED_NON_RPC = 'Call disconnected NON RPC', + MESSAGE_LEFT = 'Message left', + OTHERS = 'Others', + SWITCHED_OFF = 'Switched off', + INVALID_NUMBER = 'Invalid number', + BUSY = 'Busy', + PARTIALLY_PAID = 'Partially paid', + ENTRY_RESTRICTED = 'Entry restricted', + CUSTOMER_NEVER_LIVED_IN_ADDRESS = 'Customer never lived in address', } export interface IOutstandingEmiDetail { - referenceId: string; - emiAmount: number; - otherFees: number; - emiPenaltyCharges: number; + referenceId: string; + emiAmount: number; + otherFees: number; + emiPenaltyCharges: number; } export interface IOutstandingAmountBreakup { - emiAmount: number; - otherFees: number; - emiPenaltyCharges: number; - totalOverdueAmount: number; + emiAmount: number; + otherFees: number; + emiPenaltyCharges: number; + totalOverdueAmount: number; } diff --git a/src/screens/caseDetails/interface.ts b/src/screens/caseDetails/interface.ts index e8ade168..fd55d64f 100644 --- a/src/screens/caseDetails/interface.ts +++ b/src/screens/caseDetails/interface.ts @@ -1,274 +1,275 @@ import { - CaseAllocationType, - CaseStatuses, - CaseStatusUIMapping, - CurrentTask, - InteractionStatuses, IOutstandingEmiDetail, - TaskTitle, + CaseAllocationType, + CaseStatuses, + CaseStatusUIMapping, + CurrentTask, + InteractionStatuses, + IOutstandingEmiDetail, + TaskTitle, } from '../allCases/interface'; export enum LoanType { - PERSONAL_LOAN = 'PERSONAL_LOAN', - HOUSE_LOAN = 'HOUSE_LOAN', + PERSONAL_LOAN = 'PERSONAL_LOAN', + HOUSE_LOAN = 'HOUSE_LOAN', } export enum LoanAccountStatus { - ACTIVE = 'ACTIVE', - CLOSE = 'CLOSE', + ACTIVE = 'ACTIVE', + CLOSE = 'CLOSE', } export enum LoanAccountStatusUIMapping { - ACTIVE = 'Active', - CLOSE = 'Close', + ACTIVE = 'Active', + CLOSE = 'Close', } export enum LoanTypeUIMapping { - PERSONAL_LOAN = 'Personal loan', - HOUSE_LOAN = 'House loan', + PERSONAL_LOAN = 'Personal loan', + HOUSE_LOAN = 'House loan', } export enum CONTEXT_TASK_STATUSES { - VERIFICATION_FAILED = 'VERIFICATION_FAILED', - VERIFICATION_SUCCESS = 'VERIFICATION_SUCCESS', - OPEN = 'OPEN', - NAFS = 'NAFS', + VERIFICATION_FAILED = 'VERIFICATION_FAILED', + VERIFICATION_SUCCESS = 'VERIFICATION_SUCCESS', + OPEN = 'OPEN', + NAFS = 'NAFS', } export enum CONTEXT_TASK_STATUSES_UI_MAPPING { - VERIFICATION_FAILED = 'Unverified', - VERIFICATION_SUCCESS = 'Verified', - OPEN = 'Open', - NAFS = 'New Address', + VERIFICATION_FAILED = 'Unverified', + VERIFICATION_SUCCESS = 'Verified', + OPEN = 'Open', + NAFS = 'New Address', } export interface LoanDetails { - loanAccountNumber: string; - disbursalDate: string; - disbursementAmount: number; - firstDueDate: string; - tenureMonths: number; - loanType: LoanType; - loanAccountStatus: LoanAccountStatus; - productCode: string; + loanAccountNumber: string; + disbursalDate: string; + disbursementAmount: number; + firstDueDate: string; + tenureMonths: number; + loanType: LoanType; + loanAccountStatus: LoanAccountStatus; + productCode: string; } export interface CustomerInfo { - customerReferenceId: string; - customerName: string; - primaryPhoneNumber: string; - imageURL: string; - geoLocation: string; - name: string; - imageReferenceId: string; - documents?: IDocument[]; + customerReferenceId: string; + customerName: string; + primaryPhoneNumber: string; + imageURL: string; + geoLocation: string; + name: string; + imageReferenceId: string; + documents?: IDocument[]; } export interface Address { - referenceId: string; - houseNumber: string; - lineOne: string; - lineTwo: string; - locality: string; - street: string; - city: string; - state: string; - pinCode: string; - type: string; - source: string; - current: boolean; - permanent: boolean; - zipCode?: any; - addressQualityStatus?: any; + referenceId: string; + houseNumber: string; + lineOne: string; + lineTwo: string; + locality: string; + street: string; + city: string; + state: string; + pinCode: string; + type: string; + source: string; + current: boolean; + permanent: boolean; + zipCode?: any; + addressQualityStatus?: any; } export interface Metadata { - '@class': string; - address: Address; - geoLocation: string; - addressLine: string; - primaryPhoneNumber: string; + '@class': string; + address: Address; + geoLocation: string; + addressLine: string; + primaryPhoneNumber: string; } export interface Task { - taskId: number; - taskType: TaskTitle; - metadata: Metadata; + taskId: number; + taskType: TaskTitle; + metadata: Metadata; } export interface Q1 { - optionId: string; - text: string; + optionId: string; + text: string; } export interface QuestionContext { - q1: Q1[]; + q1: Q1[]; } export interface S1 { - questionContext: QuestionContext; + questionContext: QuestionContext; } export interface SectionContext { - s1: S1; + s1: S1; } export interface W1 { - sectionContext: SectionContext; + sectionContext: SectionContext; } export interface WidgetContext { - w1: W1; + w1: W1; } export interface COMMUNICATIONADDRESSVERIFICATIONTASK { - taskStatus: string; - widgetContext: WidgetContext; + taskStatus: string; + widgetContext: WidgetContext; } export interface TaskContext { - [id: string]: any; + [id: string]: any; } export interface Context { - taskSequence: string[]; - currentTask: string; - taskContext: TaskContext; + taskSequence: string[]; + currentTask: string; + taskContext: TaskContext; } export enum DOCUMENT_TYPE { - SELFIE = 'SELFIE', - OPTIMIZED_SELFIE = 'OPTIMIZED_SELFIE', - VKYC_VIDEO = 'VKYC_VIDEO' + SELFIE = 'SELFIE', + OPTIMIZED_SELFIE = 'OPTIMIZED_SELFIE', + VKYC_VIDEO = 'VKYC_VIDEO', } export type TDocumentObj = { - [key in DOCUMENT_TYPE]: string; -} + [key in DOCUMENT_TYPE]: string; +}; export interface IDocument { - referenceId: string; - uri: string; - type: DOCUMENT_TYPE; + referenceId: string; + uri: string; + type: DOCUMENT_TYPE; } export interface CaseDetail { - id: string; - allocationReferenceId?: string; - caseReferenceId: string; - caseStatus: keyof typeof CaseStatusUIMapping; - createdAt: number; - updatedAt: number; - allocatedAt: number; - loanDetails: LoanDetails; - customerInfo: CustomerInfo; - tasks: Task[]; - context: Context; - isSynced?: boolean; - isApiCalled: boolean; - currentTask: CurrentTask; - pinRank?: number | null; - caseVerdict: CaseStatuses; - isNewlyAdded?: boolean; - caseType: CaseAllocationType; - customerName: string; - pos: number; - dpdBucket: string; - addresses?: Address[]; - currentAllocationReferenceId: string; - customerReferenceId: string; - // collection case - addressString?: string; - currentOutstandingEmi?: number; - totalOverdueEmis?: number; - phoneNumbers?: PhoneNumber[]; - fatherName?: string; - currentDPD?: number; - loanAccountNumber?: string; - documents?: IDocument[]; - interactionStatus: keyof typeof InteractionStatuses; - outstandingEmiDetails?: IOutstandingEmiDetail[]; - totalOverdueAmount?: number; - disbursalDate?: string; - tenureMonths?: number; - offlineCaseKey?: string; // using for the collection case to handle multiple offline feedbacks - imageReferenceId?: string; - collectionTag?: 'Fresh' | 'Stab'; - disbursementAmount?: number; + id: string; + allocationReferenceId?: string; + caseReferenceId: string; + caseStatus: keyof typeof CaseStatusUIMapping; + createdAt: number; + updatedAt: number; + allocatedAt: number; + loanDetails: LoanDetails; + customerInfo: CustomerInfo; + tasks: Task[]; + context: Context; + isSynced?: boolean; + isApiCalled: boolean; + currentTask: CurrentTask; + pinRank?: number | null; + caseVerdict: CaseStatuses; + isNewlyAdded?: boolean; + caseType: CaseAllocationType; + customerName: string; + pos: number; + dpdBucket: string; + addresses?: Address[]; + currentAllocationReferenceId: string; + customerReferenceId: string; + // collection case + addressString?: string; + currentOutstandingEmi?: number; + totalOverdueEmis?: number; + phoneNumbers?: PhoneNumber[]; + fatherName?: string; + currentDPD?: number; + loanAccountNumber?: string; + documents?: IDocument[]; + interactionStatus: keyof typeof InteractionStatuses; + outstandingEmiDetails?: IOutstandingEmiDetail[]; + totalOverdueAmount?: number; + disbursalDate?: string; + tenureMonths?: number; + offlineCaseKey?: string; // using for the collection case to handle multiple offline feedbacks + imageReferenceId?: string; + collectionTag?: 'Fresh' | 'Stab'; + disbursementAmount?: number; } export interface AddressesGeolocationPayload { - latitude: number; - longitude: number; - currentAgentId: string; - addressString: string; - addresses: AddressCollection[]; - customerReferenceId: string; - documents: Document[]; - imageUrl: string; - phoneNumbers: PhoneNumber[]; - currentOutstandingEmi: number; - totalOverdueEmis: number; + latitude: number; + longitude: number; + currentAgentId: string; + addressString: string; + addresses: AddressCollection[]; + customerReferenceId: string; + documents: Document[]; + imageUrl: string; + phoneNumbers: PhoneNumber[]; + currentOutstandingEmi: number; + totalOverdueEmis: number; } interface Document { - referenceId: string; - uri: string; - type: string; + referenceId: string; + uri: string; + type: string; } interface AddressCollection { - referenceId: string; - addressReferenceId: string; - lineOne: string; - lineTwo: string; - city: string; - state: string; - pinCode: string; - current: boolean; - permanent: boolean; - type: string; - source: string; - addressQualityStatus?: any; - collectionCaseId: number; - signals?: any; - location?: any; + referenceId: string; + addressReferenceId: string; + lineOne: string; + lineTwo: string; + city: string; + state: string; + pinCode: string; + current: boolean; + permanent: boolean; + type: string; + source: string; + addressQualityStatus?: any; + collectionCaseId: number; + signals?: any; + location?: any; } export interface PhoneNumber { - type: string; - source: string; - sourceText: string; - number: string; - valid: boolean; - telephoneScore: number; - havingMaximumScore: boolean; - callHistory: null | any; - createdAt: string; - new: boolean; + type: string; + source: string; + sourceText: string; + number: string; + valid: boolean; + telephoneScore: number; + havingMaximumScore: boolean; + callHistory: null | any; + createdAt: string; + new: boolean; } export enum PhoneNumberSource { - CIBIL_TRIGGER = 'CIBIL_TRIGGER', - PRIMARY = 'PRIMARY', - LONGHORN = 'LONGHORN', - BUREAU = 'BUREAU', - CREDIT_ANALYSIS = 'CREDIT_ANALYSIS', - SPADE = 'SPADE', - ALGO_360 = 'ALGO_360', - KARZA = 'KARZA', - CUSTOMER_SUPPORT = 'CUSTOMER_SUPPORT', - CIBIL_SCRUB = 'CIBIL_SCRUB', - SECONDARY = 'SECONDARY', - CONTACT_BOOK = 'CONTACT_BOOK', - UNKNOWN = 'UNKNOWN', - MMI = 'MMI', - AADHAAR = 'AADHAAR', - CKYC = 'CKYC', - CIBIL = 'CIBIL', - AVS_V1 = 'AVS_V1', - CUSTOMER = 'CUSTOMER', - FINORAMIC = 'FINORAMIC', - BANK_STATEMENT = 'BANK_STATEMENT', - GST = 'GST', - CRIF = 'CRIF', - CIBIL_CU = 'CIBIL_CU', + CIBIL_TRIGGER = 'CIBIL_TRIGGER', + PRIMARY = 'PRIMARY', + LONGHORN = 'LONGHORN', + BUREAU = 'BUREAU', + CREDIT_ANALYSIS = 'CREDIT_ANALYSIS', + SPADE = 'SPADE', + ALGO_360 = 'ALGO_360', + KARZA = 'KARZA', + CUSTOMER_SUPPORT = 'CUSTOMER_SUPPORT', + CIBIL_SCRUB = 'CIBIL_SCRUB', + SECONDARY = 'SECONDARY', + CONTACT_BOOK = 'CONTACT_BOOK', + UNKNOWN = 'UNKNOWN', + MMI = 'MMI', + AADHAAR = 'AADHAAR', + CKYC = 'CKYC', + CIBIL = 'CIBIL', + AVS_V1 = 'AVS_V1', + CUSTOMER = 'CUSTOMER', + FINORAMIC = 'FINORAMIC', + BANK_STATEMENT = 'BANK_STATEMENT', + GST = 'GST', + CRIF = 'CRIF', + CIBIL_CU = 'CIBIL_CU', } diff --git a/src/screens/emiSchedule/constants.ts b/src/screens/emiSchedule/constants.ts index f3c9e9f4..a42d6c34 100644 --- a/src/screens/emiSchedule/constants.ts +++ b/src/screens/emiSchedule/constants.ts @@ -1,7 +1,3 @@ import { GenericStyles } from '../../../RN-UI-LIB/src/styles'; -export const row = [ - GenericStyles.row, - GenericStyles.spaceBetween, - GenericStyles.alignCenter, -]; +export const row = [GenericStyles.row, GenericStyles.spaceBetween, GenericStyles.alignCenter]; diff --git a/src/services/casePayload.transformer.ts b/src/services/casePayload.transformer.ts index 2854f4f5..afa08471 100644 --- a/src/services/casePayload.transformer.ts +++ b/src/services/casePayload.transformer.ts @@ -5,75 +5,77 @@ import { CaseAllocationType } from '../screens/allCases/interface'; import Geolocation from 'react-native-geolocation-service'; interface QuestionContext { - answer: string; - type: string; + answer: string; + type: string; } interface IQuestionContextOutput { - questionKey: string; - answerContextDTO: QuestionContext; + questionKey: string; + answerContextDTO: QuestionContext; } interface SectionContext { - [key: string]: { - questionContext: { - [key: string]: QuestionContext; - }; + [key: string]: { + questionContext: { + [key: string]: QuestionContext; }; + }; } interface WidgetContext { - [key: string]: { - sectionContext: SectionContext; - }; + [key: string]: { + sectionContext: SectionContext; + }; } interface Answer { - widgetContext: WidgetContext; - allocationReferenceId: string; + widgetContext: WidgetContext; + allocationReferenceId: string; } -export const extractQuestionContext = async ( - answer: Answer, -): Promise => { - const questionContexts: IQuestionContextOutput[] = []; - const { widgetContext } = answer; +export const extractQuestionContext = async (answer: Answer): Promise => { + const questionContexts: IQuestionContextOutput[] = []; + const { widgetContext } = answer; - for (const widgetKey in widgetContext) { - const widget = widgetContext[widgetKey]; + for (const widgetKey in widgetContext) { + const widget = widgetContext[widgetKey]; - for (const sectionKey in widget.sectionContext) { - const section = widget.sectionContext[sectionKey]; + for (const sectionKey in widget.sectionContext) { + const section = widget.sectionContext[sectionKey]; - for (const questionKey in section.questionContext) { - let answer = section.questionContext[questionKey]; - if(!answer){ - continue; - } - // convert dd-mm-yyyy to yyyy-mm-mm - if(answer.type === AnswerType.date){ - answer = {...answer, answer : answer.answer.split("-").reverse().join("-")}; - } - if(answer.type === AnswerType.date || answer.type === AnswerType.phoneNumber || answer.type === AnswerType.address){ - answer = {...answer, type: AnswerType.text}; - } - if (answer.type === AnswerType.image && answer.answer?.length) { - const offlineImageId = answer.answer; - const data = await getImageFromOfflineDb(offlineImageId); - answer = { - ...answer, - answer: data, - }; - } - questionContexts.push({ - answerContextDTO: answer, - questionKey: questionKey, - }); - } + for (const questionKey in section.questionContext) { + let answer = section.questionContext[questionKey]; + if (!answer) { + continue; } + // convert dd-mm-yyyy to yyyy-mm-mm + if (answer.type === AnswerType.date) { + answer = { ...answer, answer: answer.answer.split('-').reverse().join('-') }; + } + if ( + answer.type === AnswerType.date || + answer.type === AnswerType.phoneNumber || + answer.type === AnswerType.address + ) { + answer = { ...answer, type: AnswerType.text }; + } + if (answer.type === AnswerType.image && answer.answer?.length) { + const offlineImageId = answer.answer; + const data = await getImageFromOfflineDb(offlineImageId); + answer = { + ...answer, + answer: data, + }; + } + questionContexts.push({ + answerContextDTO: answer, + questionKey: questionKey, + }); + } } + } - return questionContexts; + return questionContexts; }; /** @@ -81,95 +83,94 @@ export const extractQuestionContext = async ( * Solution: Sync the offline images separately with the server */ export const getTransformedAvCaseItem = async (caseItem: any) => { - let cloneCaseItem = JSON.parse(JSON.stringify(caseItem)); + let cloneCaseItem = JSON.parse(JSON.stringify(caseItem)); - for (let taskId in cloneCaseItem?.context?.taskContext) { - for (let taskItem of cloneCaseItem.context.taskContext?.[taskId]) { - for (let wizItem in taskItem?.widgetContext) { - for (let sectionItem in taskItem.widgetContext[wizItem] - ?.sectionContext) { - for (let questionItem in taskItem.widgetContext[wizItem] - .sectionContext[sectionItem]?.questionContext) { - if ( - taskItem.widgetContext[wizItem].sectionContext[ - sectionItem - ].questionContext[questionItem]?.type === - AnswerType.image - ) { - const offlineImageId = - taskItem.widgetContext[wizItem].sectionContext[ - sectionItem - ].questionContext[questionItem].answer; - const data = await getImageFromOfflineDb( - offlineImageId, - ); - taskItem.widgetContext[wizItem].sectionContext[ - sectionItem - ].questionContext[questionItem] = { - ...taskItem.widgetContext[wizItem] - .sectionContext[sectionItem] - .questionContext[questionItem], - answer: data, - type: AnswerType.image, - offlineImageId, - }; - } - } - } + for (let taskId in cloneCaseItem?.context?.taskContext) { + for (let taskItem of cloneCaseItem.context.taskContext?.[taskId]) { + for (let wizItem in taskItem?.widgetContext) { + for (let sectionItem in taskItem.widgetContext[wizItem]?.sectionContext) { + for (let questionItem in taskItem.widgetContext[wizItem].sectionContext[sectionItem] + ?.questionContext) { + if ( + taskItem.widgetContext[wizItem].sectionContext[sectionItem].questionContext[ + questionItem + ]?.type === AnswerType.image + ) { + const offlineImageId = + taskItem.widgetContext[wizItem].sectionContext[sectionItem].questionContext[ + questionItem + ].answer; + const data = await getImageFromOfflineDb(offlineImageId); + taskItem.widgetContext[wizItem].sectionContext[sectionItem].questionContext[ + questionItem + ] = { + ...taskItem.widgetContext[wizItem].sectionContext[sectionItem].questionContext[ + questionItem + ], + answer: data, + type: AnswerType.image, + offlineImageId, + }; } + } } + } } - return cloneCaseItem; + } + return cloneCaseItem; }; export const getImageFromOfflineDb = async (imageId: string) => { - let imageList = await OfflineImageDAO.getImage(imageId); - return imageList?.[0]?.imageData; + let imageList = await OfflineImageDAO.getImage(imageId); + return imageList?.[0]?.imageData; }; export interface IGetTransformedCaseItem extends CaseDetail { - answer: any; - caseId: string; - coords: Geolocation.GeoCoordinates; + answer: any; + caseId: string; + coords: Geolocation.GeoCoordinates; } -export const getTransformedCollectionCaseItem = async ( - caseItem: IGetTransformedCaseItem) => { - let cloneCaseItem = { ...caseItem }; - let answerContextArray = await extractQuestionContext( - cloneCaseItem?.answer, - ); - let data = { - caseReferenceId: caseItem.caseReferenceId, - answers: answerContextArray, - location: cloneCaseItem?.coords, - offlineCaseKey: cloneCaseItem?.offlineCaseKey - }; - return { caseType: caseItem.caseType, data }; +export const getTransformedCollectionCaseItem = async (caseItem: IGetTransformedCaseItem) => { + let cloneCaseItem = { ...caseItem }; + let answerContextArray = await extractQuestionContext(cloneCaseItem?.answer); + let data = { + caseReferenceId: caseItem.caseReferenceId, + answers: answerContextArray, + location: cloneCaseItem?.coords, + offlineCaseKey: cloneCaseItem?.offlineCaseKey, + }; + return { caseType: caseItem.caseType, data }; }; -export const getTransformedAvCase = async(caseItem: IGetTransformedCaseItem, templateId: string) => { - const { caseType, allocationReferenceId, caseId, coords } = caseItem; - const transformedAvCase: any = { - caseType: caseType || CaseAllocationType.ADDRESS_VERIFICATION_CASE, - data: { - templateId, - allocationReferenceId, - caseReferenceId: caseId, - taskStatuses: {}, - answers: [], - location: coords, - } +export const getTransformedAvCase = async ( + caseItem: IGetTransformedCaseItem, + templateId: string +) => { + const { caseType, allocationReferenceId, caseId, coords } = caseItem; + const transformedAvCase: any = { + caseType: caseType || CaseAllocationType.ADDRESS_VERIFICATION_CASE, + data: { + templateId, + allocationReferenceId, + caseReferenceId: caseId, + taskStatuses: {}, + answers: [], + location: coords, + }, + }; + const taskContext = caseItem?.context?.taskContext; + for (let taskId in taskContext) { + const taskItems: any[] = taskContext[taskId]; + transformedAvCase.data.taskStatuses = { ...transformedAvCase.data.taskStatuses, [taskId]: [] }; + for (const taskItem of taskItems) { + const { taskStatus } = taskItem; + const answersList = await extractQuestionContext(taskItem); + transformedAvCase.data.answers = [...transformedAvCase.data.answers, ...answersList]; + transformedAvCase.data.taskStatuses[taskId] = [ + ...transformedAvCase.data.taskStatuses[taskId], + taskStatus, + ]; } - const taskContext = caseItem?.context?.taskContext; - for(let taskId in taskContext) { - const taskItems:any[] = taskContext[taskId]; - transformedAvCase.data.taskStatuses = {...transformedAvCase.data.taskStatuses, [taskId]: []}; - for (const taskItem of taskItems){ - const { taskStatus } = taskItem; - const answersList = await extractQuestionContext(taskItem); - transformedAvCase.data.answers = [...transformedAvCase.data.answers, ...answersList]; - transformedAvCase.data.taskStatuses[taskId] = [...transformedAvCase.data.taskStatuses[taskId], taskStatus]; - } - } - return transformedAvCase; -} + } + return transformedAvCase; +}; diff --git a/src/services/clickstreamEventService.ts b/src/services/clickstreamEventService.ts index f44b4d9b..17a7d0b8 100644 --- a/src/services/clickstreamEventService.ts +++ b/src/services/clickstreamEventService.ts @@ -2,13 +2,11 @@ import React from 'react'; import axiosInstance from '../components/utlis/apiHelper'; import { getNetInfo } from '../components/utlis/commonFunctions'; import { GLOBAL } from '../constants/Global'; -import ClickStreamEventsDAO, { - IClickstreamEvent, -} from '../wmDB/dao/ClickStreamEventsDAO'; +import ClickStreamEventsDAO, { IClickstreamEvent } from '../wmDB/dao/ClickStreamEventsDAO'; import { - NetInfoCellularGeneration, - NetInfoState, - NetInfoStateType, + NetInfoCellularGeneration, + NetInfoState, + NetInfoStateType, } from '@react-native-community/netinfo'; import { APP_NAME } from '../common/Constants'; import { JANUS_SERVICE_URL } from '../constants/config'; @@ -22,96 +20,89 @@ let bufferEventsList: IClickstreamEvent[] = []; let networkStatus: string = 'offline'; export const setNetworkStatus = (state: NetInfoState) => { - const { isConnected, type, details } = state; + const { isConnected, type, details } = state; + networkStatus = 'offline'; + if (!isConnected) { networkStatus = 'offline'; - if (!isConnected) { - networkStatus = 'offline'; - } - if (type === NetInfoStateType.cellular) { - networkStatus = details.cellularGeneration as NetInfoCellularGeneration; - } else { - networkStatus = type; - } + } + if (type === NetInfoStateType.cellular) { + networkStatus = details.cellularGeneration as NetInfoCellularGeneration; + } else { + networkStatus = type; + } }; const addEvent = async (networkStatus: string) => { - if (eventsList.length > MAX_BUFFER_SIZE_FOR_API) { - if (networkStatus !== 'offline') { - fireClickstreamEvents(); - } else if (eventsList.length > MAX_BUFFER_SIZE_FOR_DB_WRITE) { - await ClickStreamEventsDAO.addEventsBulk(eventsList); - eventsList = []; - } + if (eventsList.length > MAX_BUFFER_SIZE_FOR_API) { + if (networkStatus !== 'offline') { + fireClickstreamEvents(); + } else if (eventsList.length > MAX_BUFFER_SIZE_FOR_DB_WRITE) { + await ClickStreamEventsDAO.addEventsBulk(eventsList); + eventsList = []; } + } }; export const addClickstreamEvent = async ( - eventDesc: { name: string; description: string }, - attributes: Record = {}, + eventDesc: { name: string; description: string }, + attributes: Record = {} ) => { - const { DEVICE_ID: deviceId, AGENT_ID: agentId } = GLOBAL; - const { name, description } = eventDesc; - const eventAttributes = { ...attributes, networkStatus }; - eventsList.push({ - event_name: name, - description, - deviceId, - agentId, - attributes: eventAttributes, - timestamp: new Date().getTime(), - networkStatus, - }); - addEvent(networkStatus); + const { DEVICE_ID: deviceId, AGENT_ID: agentId } = GLOBAL; + const { name, description } = eventDesc; + const eventAttributes = { ...attributes, networkStatus }; + eventsList.push({ + event_name: name, + description, + deviceId, + agentId, + attributes: eventAttributes, + timestamp: new Date().getTime(), + networkStatus, + }); + addEvent(networkStatus); }; const getPayload = (events: IClickstreamEvent[]) => { - const { agentId, deviceId } = events[events.length - 1]; - return { - app: { name: APP_NAME }, - events, - metadata: { - agentId, - deviceId, - }, - client_ts: new Date().getTime(), - source: APP_NAME, - user: { - customer_id: agentId - } - }; + const { agentId, deviceId } = events[events.length - 1]; + return { + app: { name: APP_NAME }, + events, + metadata: { + agentId, + deviceId, + }, + client_ts: new Date().getTime(), + source: APP_NAME, + user: { + customer_id: agentId, + }, + }; }; const fireClickstreamEvents = async () => { - const url = JANUS_SERVICE_URL; - bufferEventsList = [...eventsList]; - eventsList = []; + const url = JANUS_SERVICE_URL; + bufferEventsList = [...eventsList]; + eventsList = []; - const clickstreamEventsFromDB = await ClickStreamEventsDAO.getAllEvents(); + const clickstreamEventsFromDB = await ClickStreamEventsDAO.getAllEvents(); - const events = clickstreamEventsFromDB - .map((item: IClickstreamEvent) => { - const { - deviceId, - agentId, - event_name, - attributes, - timestamp, - networkStatus, - } = item; - return { - deviceId, - agentId, - event_name, - attributes, - timestamp, - networkStatus, - }; - }) - .concat(bufferEventsList); + const events = clickstreamEventsFromDB + .map((item: IClickstreamEvent) => { + const { deviceId, agentId, event_name, attributes, timestamp, networkStatus } = item; + return { + deviceId, + agentId, + event_name, + attributes, + timestamp, + networkStatus, + }; + }) + .concat(bufferEventsList); - const payload = getPayload(events); + const payload = getPayload(events); - axiosInstance - .post(url, payload, { headers: { donotHandleError: true } }) - .then(() => ClickStreamEventsDAO.deleteAllEvents()); + axiosInstance + .post(url, payload, { headers: { donotHandleError: true } }) + .then(() => ClickStreamEventsDAO.deleteAllEvents()); }; diff --git a/src/services/exception-handler.service.ts b/src/services/exception-handler.service.ts index 4fee9a6f..873e667a 100644 --- a/src/services/exception-handler.service.ts +++ b/src/services/exception-handler.service.ts @@ -1,11 +1,11 @@ -import { logError } from "../components/utlis/errorUtils"; -import { ErrorHandlerCallback } from "react-native"; +import { logError } from '../components/utlis/errorUtils'; +import { ErrorHandlerCallback } from 'react-native'; let originalErrorHandler: ErrorHandlerCallback; export function setJsErrorHandler() { originalErrorHandler = originalErrorHandler || global.ErrorUtils.getGlobalHandler(); global.ErrorUtils.setGlobalHandler((error: Error, isFatal: boolean) => { - if(isFatal){ + if (isFatal) { logError(error); } originalErrorHandler(error, isFatal); diff --git a/src/services/foregroundServices/foreground.service.ts b/src/services/foregroundServices/foreground.service.ts index f4498c7d..d3aada7c 100644 --- a/src/services/foregroundServices/foreground.service.ts +++ b/src/services/foregroundServices/foreground.service.ts @@ -17,8 +17,8 @@ class CosmosForegroundService { static async start(tasks: IForegroundTask[]) { try { - for (const currentTask of tasks){ - if(!ForegroundService.is_running() || !ForegroundService.get_task(currentTask.taskId)){ + for (const currentTask of tasks) { + if (!ForegroundService.is_running() || !ForegroundService.get_task(currentTask.taskId)) { if (!ForegroundService.is_running()) { await ForegroundService.start({ id: FOREGROUND_SERVICE_ID, @@ -29,9 +29,9 @@ class CosmosForegroundService { // @ts-ignore setOnlyAlertOnce: true, }); - } + } const { task, ...rest } = currentTask; - ForegroundService.add_task(task, {...rest}); + ForegroundService.add_task(task, { ...rest }); } } } catch (e: any) { @@ -46,7 +46,7 @@ class CosmosForegroundService { public static async stopAll() { try { await ForegroundService.stop(); - await ForegroundService.stopAll() + await ForegroundService.stopAll(); } catch (e: any) { logError(e, 'Error stopping Foreground service'); } diff --git a/src/services/network-monitoring.service.ts b/src/services/network-monitoring.service.ts index 1e4dc7e8..ce379606 100644 --- a/src/services/network-monitoring.service.ts +++ b/src/services/network-monitoring.service.ts @@ -1,42 +1,40 @@ -import NetInfo from "@react-native-community/netinfo"; -import { setNetworkStatus } from "./clickstreamEventService"; -import { setIsOnline } from "../reducer/metadataSlice"; - +import NetInfo from '@react-native-community/netinfo'; +import { setNetworkStatus } from './clickstreamEventService'; +import { setIsOnline } from '../reducer/metadataSlice'; export class NetworkStatusService { private static isOnline = false; private static isAlreadyListening = false; // private static listeners: any[] = []; - private constructor() { // singleton + private constructor() { + // singleton } - static listenForOnline (dispatch:any) { - if(!NetworkStatusService.isAlreadyListening){ + static listenForOnline(dispatch: any) { + if (!NetworkStatusService.isAlreadyListening) { NetInfo.configure({ reachabilityUrl: 'https://google.com', - reachabilityTest: async response => response.status === 200, + reachabilityTest: async (response) => response.status === 200, reachabilityLongTimeout: 30 * 1000, // 60s reachabilityShortTimeout: 5 * 1000, // 5s reachabilityRequestTimeout: 15 * 1000, // 15s }); - // check initial state. - NetInfo.fetch().then(state => { - NetworkStatusService.isOnline = !!state.isConnected - dispatch(setIsOnline(NetworkStatusService.isOnline)) + NetInfo.fetch().then((state) => { + NetworkStatusService.isOnline = !!state.isConnected; + dispatch(setIsOnline(NetworkStatusService.isOnline)); }); // listen for changes. - NetInfo.addEventListener(state => { + NetInfo.addEventListener((state) => { setNetworkStatus(state); if (NetworkStatusService.isOnline !== state.isConnected) { - NetworkStatusService.isOnline = !!state.isConnected && !!state.isInternetReachable - dispatch(setIsOnline(NetworkStatusService.isOnline)) + NetworkStatusService.isOnline = !!state.isConnected && !!state.isInternetReachable; + dispatch(setIsOnline(NetworkStatusService.isOnline)); } }); NetworkStatusService.isAlreadyListening = true; } } } - diff --git a/src/store/store.ts b/src/store/store.ts index 6bef0039..ada64ea9 100644 --- a/src/store/store.ts +++ b/src/store/store.ts @@ -1,14 +1,14 @@ import { configureStore, getDefaultMiddleware } from '@reduxjs/toolkit'; import { combineReducers } from 'redux'; import { - FLUSH, - PAUSE, - PERSIST, - persistReducer, - persistStore, - PURGE, - REGISTER, - REHYDRATE, + FLUSH, + PAUSE, + PERSIST, + persistReducer, + persistStore, + PURGE, + REGISTER, + REHYDRATE, } from 'redux-persist'; import AsyncStorage from '@react-native-async-storage/async-storage'; @@ -19,61 +19,61 @@ import allCasesSlice from '../reducer/allCasesSlice'; import QueueSlice from '../reducer/Queue'; import paymentSlice from '../reducer/paymentSlice'; import addressGeolocationSlice from '../reducer/addressGeolocationSlice'; -import filtersSlice from "../reducer/filtersSlice"; +import filtersSlice from '../reducer/filtersSlice'; import addressSlice from '../reducer/addressSlice'; import emiScheduleSlice from '../reducer/emiScheduleSlice'; import repaymentsSlice from '../reducer/repaymentsSlice'; import feedbackHistorySlice from '../reducer/feedbackHistorySlice'; import notificationsSlice from '../reducer/notificationsSlice'; -import MetadataSlice from "../reducer/metadataSlice"; +import MetadataSlice from '../reducer/metadataSlice'; import foregroundServiceSlice from '../reducer/foregroundServiceSlice'; const rootReducer = combineReducers({ - case: caseReducer, - loginInfo: loginSlice, - allCases: allCasesSlice, - user: userSlice, - queue: QueueSlice, - payment: paymentSlice, - addressGeolocation: addressGeolocationSlice, - filters: filtersSlice, - emiSchedule: emiScheduleSlice, - repayments: repaymentsSlice, - feedbackHistory: feedbackHistorySlice, - address: addressSlice, - notifications: notificationsSlice, - metadata : MetadataSlice, - foregroundService: foregroundServiceSlice + case: caseReducer, + loginInfo: loginSlice, + allCases: allCasesSlice, + user: userSlice, + queue: QueueSlice, + payment: paymentSlice, + addressGeolocation: addressGeolocationSlice, + filters: filtersSlice, + emiSchedule: emiScheduleSlice, + repayments: repaymentsSlice, + feedbackHistory: feedbackHistorySlice, + address: addressSlice, + notifications: notificationsSlice, + metadata: MetadataSlice, + foregroundService: foregroundServiceSlice, }); const persistConfig = { - key: 'root', - version: 1, - storage: AsyncStorage, - whitelist: [ - 'case', - 'allCases', - 'common', - 'user', - 'payment', - 'addressGeolocation', - 'emiSchedule', - 'repayments', - 'feedbackHistory', - 'address' - ], - blackList: ['case', 'filters'], + key: 'root', + version: 1, + storage: AsyncStorage, + whitelist: [ + 'case', + 'allCases', + 'common', + 'user', + 'payment', + 'addressGeolocation', + 'emiSchedule', + 'repayments', + 'feedbackHistory', + 'address', + ], + blackList: ['case', 'filters'], }; const persistedReducer = persistReducer(persistConfig, rootReducer); const store = configureStore({ - reducer: persistedReducer, - middleware: getDefaultMiddleware({ - serializableCheck: { - ignoredActions: [FLUSH, REHYDRATE, PAUSE, PERSIST, PURGE, REGISTER], - }, - }), + reducer: persistedReducer, + middleware: getDefaultMiddleware({ + serializableCheck: { + ignoredActions: [FLUSH, REHYDRATE, PAUSE, PERSIST, PURGE, REGISTER], + }, + }), }); export const persistor = persistStore(store); diff --git a/src/types/addressGeolocation.types.ts b/src/types/addressGeolocation.types.ts index 1e6edc5c..74805858 100644 --- a/src/types/addressGeolocation.types.ts +++ b/src/types/addressGeolocation.types.ts @@ -1,54 +1,54 @@ export interface IAddressLevel1 { - id: string, - customerReferenceId: string, - externalReferenceId: string, - addressText: string, - pinCode: string, - city: string, - state: string, - isCurrent: boolean, - isPermanent: boolean, - primarySource: string, - secondarySource: string, - type: string, - consumptionDate: string, - latitude: string, - longitude: string, - verified: boolean, - visited: boolean, - groupIdentifier: string, - createdAt: string, - updatedAt: string + id: string; + customerReferenceId: string; + externalReferenceId: string; + addressText: string; + pinCode: string; + city: string; + state: string; + isCurrent: boolean; + isPermanent: boolean; + primarySource: string; + secondarySource: string; + type: string; + consumptionDate: string; + latitude: string; + longitude: string; + verified: boolean; + visited: boolean; + groupIdentifier: string; + createdAt: string; + updatedAt: string; } export interface IGeoLocation { - latitude: number, - longitude: number, - timeStamp: number | string, - distanceFromAgent?: number + latitude: number; + longitude: number; + timeStamp: number | string; + distanceFromAgent?: number; } export interface AddressL1Details { + addressDTO: IAddressLevel1; + similarAddresses: Array<{ addressDTO: IAddressLevel1; - similarAddresses: Array<{ - addressDTO: IAddressLevel1 - }>, - matchingGeoLocations: IGeoLocation[]; + }>; + matchingGeoLocations: IGeoLocation[]; } export interface IAddressGeoLocation { - addressL1ViewList?: AddressL1Details[]; - unmatchedGeoLocations?: IGeoLocation[]; + addressL1ViewList?: AddressL1Details[]; + unmatchedGeoLocations?: IGeoLocation[]; } export interface IAddressGeolocationPayload { - loanAccountNumber: string; - customerReferenceId: string; + loanAccountNumber: string; + customerReferenceId: string; } export interface IAddAddressPayload { - city: string; - lineOne: string; - lineTwo: string; - pinCode: string; + city: string; + lineOne: string; + lineTwo: string; + pinCode: string; } diff --git a/src/types/conditional.types.ts b/src/types/conditional.types.ts index caaa290f..95536de1 100644 --- a/src/types/conditional.types.ts +++ b/src/types/conditional.types.ts @@ -1,4 +1,4 @@ -import { Condition } from "./template.types"; +import { Condition } from './template.types'; export enum ConditionTypes { 'COMPOSITE' = 'COMPOSITE', @@ -22,7 +22,6 @@ export enum LeafOperator { VALUE_EQUAL_TO = 'valueEqualTo', } - export interface CompositeCondition { conditionType: ConditionTypes.COMPOSITE; operator: CompositeOperator; @@ -33,9 +32,8 @@ export interface CompositeCondition { export interface LeafCondition { conditionType: ConditionTypes.LEAF; section: string; - operator: LeafOperator + operator: LeafOperator; right: string; left: string; widgetId: string; } - diff --git a/src/types/feedback.types.ts b/src/types/feedback.types.ts index e572a92c..0cb64968 100644 --- a/src/types/feedback.types.ts +++ b/src/types/feedback.types.ts @@ -1,77 +1,77 @@ -import { GenericType } from "../common/GenericTypes"; -import { Address, InteractionStatuses } from "../screens/allCases/interface"; -import { PhoneNumberSource } from "../screens/caseDetails/interface"; +import { GenericType } from '../common/GenericTypes'; +import { Address, InteractionStatuses } from '../screens/allCases/interface'; +import { PhoneNumberSource } from '../screens/caseDetails/interface'; export enum AnswerType { - TEXT = 'TEXT', - DATE = 'DATE', - TIME = 'TIME', - AMOUNT = 'AMOUNT', - OPTIONS = 'OPTIONS', - REMINDER = 'REMINDER', + TEXT = 'TEXT', + DATE = 'DATE', + TIME = 'TIME', + AMOUNT = 'AMOUNT', + OPTIONS = 'OPTIONS', + REMINDER = 'REMINDER', } export enum OPTION_TAG { - COMMENTS = 'COMMENTS', - IMAGE_UPLOAD = 'IMAGE_UPLOAD', + COMMENTS = 'COMMENTS', + IMAGE_UPLOAD = 'IMAGE_UPLOAD', } export interface IAnswerView { - interactionId?: number; - referenceId?: string; - questionReferenceId?: string; - questionName?: string; - questionText?: string; - questionKey?: string; - answerType?: AnswerType; - optionReferenceId?: string; - optionText?: string; - inputAmount?: number; - inputDate?: string; - inputText?: string; - questionTag?: OPTION_TAG; + interactionId?: number; + referenceId?: string; + questionReferenceId?: string; + questionName?: string; + questionText?: string; + questionKey?: string; + answerType?: AnswerType; + optionReferenceId?: string; + optionText?: string; + inputAmount?: number; + inputDate?: string; + inputText?: string; + questionTag?: OPTION_TAG; } export enum FEEDBACK_TYPE { - FIELD_VISIT = 'FIELD_VISIT', - INHOUSE_FIELD_VISIT = 'INHOUSE_FIELD_VISIT', - CALL_BRIDGE = 'CALL_BRIDGE', - SELF_CALL = 'SELF_CALL' + FIELD_VISIT = 'FIELD_VISIT', + INHOUSE_FIELD_VISIT = 'INHOUSE_FIELD_VISIT', + CALL_BRIDGE = 'CALL_BRIDGE', + SELF_CALL = 'SELF_CALL', } export interface FIELD_FEEDBACK_METADATA { - interactionLatitude: string, - interactionLongitude: string, - userDistanceFromAddress: string + interactionLatitude: string; + interactionLongitude: string; + userDistanceFromAddress: string; } export interface ICallingFeedback { - recipientName: string, - recipientNumber: string + recipientName: string; + recipientNumber: string; } export interface IFeedback { - [x: string]: any; - id: string; - referenceId: string; - type: FEEDBACK_TYPE; - accountNumber: string; - createdAt: string; - metadata: FIELD_FEEDBACK_METADATA | GenericType; - sourceType: PhoneNumberSource; - sourceText: string; - answerViews: IAnswerView[]; - imageUrls: string[]; - agentReferenceId: string - source: Address | ICallingFeedback; - interactionStatus: InteractionStatuses; + [x: string]: any; + id: string; + referenceId: string; + type: FEEDBACK_TYPE; + accountNumber: string; + createdAt: string; + metadata: FIELD_FEEDBACK_METADATA | GenericType; + sourceType: PhoneNumberSource; + sourceText: string; + answerViews: IAnswerView[]; + imageUrls: string[]; + agentReferenceId: string; + source: Address | ICallingFeedback; + interactionStatus: InteractionStatuses; } export interface IUnSyncedFeedbackItem { - interactionStatus: InteractionStatuses, - createdAt: string, - isSynced: boolean + interactionStatus: InteractionStatuses; + createdAt: string; + isSynced: boolean; } export const CALLING_FEEDBACKS = [FEEDBACK_TYPE.CALL_BRIDGE, FEEDBACK_TYPE.SELF_CALL]; -export const FIELD_FEEDBACKS = [FEEDBACK_TYPE.FIELD_VISIT, FEEDBACK_TYPE.INHOUSE_FIELD_VISIT]; \ No newline at end of file +export const FIELD_FEEDBACKS = [FEEDBACK_TYPE.FIELD_VISIT, FEEDBACK_TYPE.INHOUSE_FIELD_VISIT]; diff --git a/src/types/repayments.types.ts b/src/types/repayments.types.ts index 1cd8a975..08a8d7cf 100644 --- a/src/types/repayments.types.ts +++ b/src/types/repayments.types.ts @@ -1,18 +1,18 @@ export enum REPAYMENT_STATUS { - SUCCESS= 'SUCCESS', - FAILED= 'FAILED', - SCHEDULED= 'SCHEDULED' + SUCCESS = 'SUCCESS', + FAILED = 'FAILED', + SCHEDULED = 'SCHEDULED', } export interface IRepaymentsRecord { - loanReferenceId: string; - customerReferenceId: string; - paymentReferenceId: string; - status: REPAYMENT_STATUS; - valueDate: string; - businessDate: string; - repaymentMode: string; - amount: number; - failed: boolean; - success: boolean; + loanReferenceId: string; + customerReferenceId: string; + paymentReferenceId: string; + status: REPAYMENT_STATUS; + valueDate: string; + businessDate: string; + repaymentMode: string; + amount: number; + failed: boolean; + success: boolean; } diff --git a/src/types/template.types.ts b/src/types/template.types.ts index 2664716f..4b71dc24 100644 --- a/src/types/template.types.ts +++ b/src/types/template.types.ts @@ -1,14 +1,14 @@ -import { ConditionTypes } from "./conditional.types"; +import { ConditionTypes } from './conditional.types'; export interface Section { label?: string; - questions: string[] + questions: string[]; } export interface OptionV1 { associateQuestions: any[]; text: string; - metadata: Record + metadata: Record; } export interface QuestionV1 { @@ -16,30 +16,29 @@ export interface QuestionV1 { inputType: QuestionType; options: string[]; metadata: { - validators: { [validationRule: string]: { value: boolean, message?: string } }, - [otherProperties: string]: any - } + validators: { [validationRule: string]: { value: boolean; message?: string } }; + [otherProperties: string]: any; + }; } - -export type Condition = { +export type Condition = { operator: string; conditionType: ConditionTypes; left?: Condition; right?: Condition; section?: string; widgetId?: string; -} +}; export interface Action { type: ActionType; - [otherProperties: string]: any // todo : split in individual actions and make Action as 'OR' of them. + [otherProperties: string]: any; // todo : split in individual actions and make Action as 'OR' of them. } export enum ActionType { WIDGET_TRANSITION = 'widgetTransition', - JOURNEY_TRANSITION = 'journeyTransition' + JOURNEY_TRANSITION = 'journeyTransition', } export interface ConditionAction { @@ -63,18 +62,17 @@ export interface Widget { conditionActions: ConditionAction[]; } - export interface FormTemplateV1 { - sections: { [sectionId: string]: Section }, + sections: { [sectionId: string]: Section }; templateId: string; questions: { - [questionId: string]: QuestionV1 + [questionId: string]: QuestionV1; }; - journey: { [journeyId: string]: Journey } - widget: { [widgetId: string]: Widget } + journey: { [journeyId: string]: Journey }; + widget: { [widgetId: string]: Widget }; options: { - [optionId: string]: OptionV1 - } + [optionId: string]: OptionV1; + }; } export enum QuestionType { @@ -85,7 +83,7 @@ export enum QuestionType { CHECK_BOX = 'Checkbox', RATING = 'Rating', DROPDOWN = 'Dropdown', - CHECKBOX_GROUP = 'CheckboxGroup' + CHECKBOX_GROUP = 'CheckboxGroup', } export interface ValidationRule { diff --git a/src/wmDB/const.ts b/src/wmDB/const.ts index c13a5125..acf776f0 100644 --- a/src/wmDB/const.ts +++ b/src/wmDB/const.ts @@ -1,8 +1,8 @@ export enum TableName { - OFFLINE_IMAGES = 'offline_image', - CUSTOMER_IMAGE = 'customer_image', - CLICKSTREAM_EVENTS = 'clickstream_events' -}; + OFFLINE_IMAGES = 'offline_image', + CUSTOMER_IMAGE = 'customer_image', + CLICKSTREAM_EVENTS = 'clickstream_events', +} export const DB_VERSION = 4; diff --git a/src/wmDB/dao/ClickStreamEventsDAO.ts b/src/wmDB/dao/ClickStreamEventsDAO.ts index 34c29db5..d17c8a83 100644 --- a/src/wmDB/dao/ClickStreamEventsDAO.ts +++ b/src/wmDB/dao/ClickStreamEventsDAO.ts @@ -6,89 +6,89 @@ import { logError } from '../../components/utlis/errorUtils'; const clickStreamEvents = database.get(TableName.CLICKSTREAM_EVENTS); export interface IClickstreamEvent { - event_name: string; - description: string; - timestamp: number; - agentId: string; - deviceId: string; - attributes?: unknown; - networkStatus: string; + event_name: string; + description: string; + timestamp: number; + agentId: string; + deviceId: string; + attributes?: unknown; + networkStatus: string; } export default { - observeOfflineImage: () => clickStreamEvents.query().observe(), - addEvent: async ( - event_name: string, - timestamp: number, - description: string, - agentId: string, - deviceId: string, - attributes: any, - networkStatus: string - ) => { + observeOfflineImage: () => clickStreamEvents.query().observe(), + addEvent: async ( + event_name: string, + timestamp: number, + description: string, + agentId: string, + deviceId: string, + attributes: any, + networkStatus: string + ) => { + try { + return await database.action(async () => { + return await clickStreamEvents.create((event: any) => { + event.event_name = event_name; + event.description = description; + event.timestamp = timestamp; + event.deviceId = deviceId; + event.agentId = agentId; + event.attributes = attributes; + event.networkStatus = networkStatus; + }); + }); + } catch (e) { + console.log(e); + } + }, + addEventsBulk: async (events: Array) => { + function prepareInsertion(events: Array) { + return events.map((clickStreamEvent) => { + const { event_name, deviceId, attributes, agentId, timestamp, description, networkStatus } = + clickStreamEvent; try { - return await database.action(async () => { - return await clickStreamEvents.create((event: any) => { - event.event_name = event_name; - event.description = description; - event.timestamp = timestamp; - event.deviceId = deviceId; - event.agentId = agentId; - event.attributes = attributes; - event.networkStatus = networkStatus - }); - }); + return clickStreamEvents.prepareCreate((event: any) => { + event.event_name = event_name; + event.description = description; + event.timestamp = timestamp; + event.deviceId = deviceId; + event.agentId = agentId; + event.attributes = attributes; + event.networkStatus = networkStatus; + }); } catch (e) { - console.log(e); + logError(e as Error, 'WM DB'); } - }, - addEventsBulk: async (events: Array) => { - function prepareInsertion(events: Array) { - return events.map(clickStreamEvent => { - const { event_name, deviceId, attributes, agentId, timestamp, description, networkStatus } = - clickStreamEvent; - try { - return clickStreamEvents.prepareCreate((event: any) => { - event.event_name = event_name; - event.description = description; - event.timestamp = timestamp; - event.deviceId = deviceId; - event.agentId = agentId; - event.attributes = attributes; - event.networkStatus = networkStatus - }); - } catch (e) { - logError(e as Error, 'WM DB'); - } - }); - } - try { - return await database.action(async () => { - const allRecords = prepareInsertion(events); - await database.batch(...allRecords); - }); - } catch (e) { - logError(e as Error, 'WM DB'); - } - }, - getAllEvents: async () => { - try { - return await database.action(async () => { - return await clickStreamEvents.query().fetch(); - }); - } catch (e) { - console.log(e); - return; - } - }, - deleteAllEvents: async () => { - try { - return await database.action(async () => { - await clickStreamEvents.query().destroyAllPermanently(); - }); - } catch (e) { - console.log(e); - return; - } - }, + }); + } + try { + return await database.action(async () => { + const allRecords = prepareInsertion(events); + await database.batch(...allRecords); + }); + } catch (e) { + logError(e as Error, 'WM DB'); + } + }, + getAllEvents: async () => { + try { + return await database.action(async () => { + return await clickStreamEvents.query().fetch(); + }); + } catch (e) { + console.log(e); + return; + } + }, + deleteAllEvents: async () => { + try { + return await database.action(async () => { + await clickStreamEvents.query().destroyAllPermanently(); + }); + } catch (e) { + console.log(e); + return; + } + }, }; diff --git a/src/wmDB/dao/CustomerImageDAO.ts b/src/wmDB/dao/CustomerImageDAO.ts index 0de26b4e..2087002e 100644 --- a/src/wmDB/dao/CustomerImageDAO.ts +++ b/src/wmDB/dao/CustomerImageDAO.ts @@ -1,94 +1,93 @@ import { database } from '../db'; -import { Q } from '@nozbe/watermelondb' +import { Q } from '@nozbe/watermelondb'; import { TableName } from '../const'; import { logError } from '../../components/utlis/errorUtils'; const customerImage = database.get(TableName.CUSTOMER_IMAGE); interface ICustomerOfflineImage { - caseId: string; - imageURL: string; - image64: string; + caseId: string; + imageURL: string; + image64: string; } export default { - observeOfflineImage: () => customerImage.query().observe(), - addBulkCustomerImage: async (customerImageList: ICustomerOfflineImage[]) => { - function prepareInsertion(customerImageList: ICustomerOfflineImage[]) { - return customerImageList.map(customerImageItem => { - try { - return customerImage.prepareCreate((imageRow: any) => { - imageRow.caseId = customerImageItem.caseId; - imageRow.imageURL = customerImageItem.imageURL; - imageRow.image64 = customerImageItem.image64; - }); - } catch (e) { - logError(e as Error, "WM DB") - } - }); - } + observeOfflineImage: () => customerImage.query().observe(), + addBulkCustomerImage: async (customerImageList: ICustomerOfflineImage[]) => { + function prepareInsertion(customerImageList: ICustomerOfflineImage[]) { + return customerImageList.map((customerImageItem) => { try { - return await database.action(async () => { - const allRecords = prepareInsertion(customerImageList); - await database.batch(...allRecords); - - }); + return customerImage.prepareCreate((imageRow: any) => { + imageRow.caseId = customerImageItem.caseId; + imageRow.imageURL = customerImageItem.imageURL; + imageRow.image64 = customerImageItem.image64; + }); } catch (e) { - logError(e as Error, "WM DB") + logError(e as Error, 'WM DB'); } - }, - addCustomerImage: async (customerImageItem: ICustomerOfflineImage) => { - try { - return await database.action(async () => { - return await customerImage.create((imageRow: any) => { - imageRow.caseId = customerImageItem.caseId; - imageRow.imageURL = customerImageItem.imageURL; - imageRow.image64 = customerImageItem.image64; - }); - }); - } catch (e) { - logError(e as Error, "WM DB") - } - }, - getImageByURL: async (imageURL: string) => { - try { - return await database.action(async () => { - return await customerImage.query(Q.where('image_url', imageURL), Q.take(1)).fetch() - }); - } catch (e) { - logError(e as Error, "WM DB") - return; - } - }, - getImageByCase: async (caseId: string) => { - try { - return await database.action(async () => { - return await customerImage.query(Q.where('case_id', caseId), Q.take(1)).fetch() - }); - } catch (e) { - logError(e as Error, "WM DB") - return; - } - }, - deleteImages: async (caseIds: Array | string) => { - let tCaseIds = Array.isArray(caseIds) ? caseIds : [caseIds]; - try { - return await database.action(async () => { - await customerImage.query(Q.where('case_id', Q.oneOf(tCaseIds))).destroyAllPermanently() - }); - } catch (e) { - logError(e as Error, "WM DB") - return; - } - }, - deleteAll: async () => { - try { - return await database.action(async () => { - await customerImage.query().destroyAllPermanently(); - }); - } catch (e) { - logError(e as Error, "WM DB") - return; - } - }, + }); + } + try { + return await database.action(async () => { + const allRecords = prepareInsertion(customerImageList); + await database.batch(...allRecords); + }); + } catch (e) { + logError(e as Error, 'WM DB'); + } + }, + addCustomerImage: async (customerImageItem: ICustomerOfflineImage) => { + try { + return await database.action(async () => { + return await customerImage.create((imageRow: any) => { + imageRow.caseId = customerImageItem.caseId; + imageRow.imageURL = customerImageItem.imageURL; + imageRow.image64 = customerImageItem.image64; + }); + }); + } catch (e) { + logError(e as Error, 'WM DB'); + } + }, + getImageByURL: async (imageURL: string) => { + try { + return await database.action(async () => { + return await customerImage.query(Q.where('image_url', imageURL), Q.take(1)).fetch(); + }); + } catch (e) { + logError(e as Error, 'WM DB'); + return; + } + }, + getImageByCase: async (caseId: string) => { + try { + return await database.action(async () => { + return await customerImage.query(Q.where('case_id', caseId), Q.take(1)).fetch(); + }); + } catch (e) { + logError(e as Error, 'WM DB'); + return; + } + }, + deleteImages: async (caseIds: Array | string) => { + let tCaseIds = Array.isArray(caseIds) ? caseIds : [caseIds]; + try { + return await database.action(async () => { + await customerImage.query(Q.where('case_id', Q.oneOf(tCaseIds))).destroyAllPermanently(); + }); + } catch (e) { + logError(e as Error, 'WM DB'); + return; + } + }, + deleteAll: async () => { + try { + return await database.action(async () => { + await customerImage.query().destroyAllPermanently(); + }); + } catch (e) { + logError(e as Error, 'WM DB'); + return; + } + }, }; diff --git a/src/wmDB/dao/OfflineImageDAO.ts b/src/wmDB/dao/OfflineImageDAO.ts index 703856be..58f69c4a 100644 --- a/src/wmDB/dao/OfflineImageDAO.ts +++ b/src/wmDB/dao/OfflineImageDAO.ts @@ -1,51 +1,51 @@ import { database } from '../db'; -import { Q } from '@nozbe/watermelondb' +import { Q } from '@nozbe/watermelondb'; import { TableName } from '../const'; -const offlineImage = database.get(TableName.OFFLINE_IMAGES) +const offlineImage = database.get(TableName.OFFLINE_IMAGES); export default { - observeOfflineImage: () => offlineImage.query().observe(), - addImage: async (imageData: string, imageIdx: string) => { - try { - return await database.action(async () => { - return await offlineImage.create((image: any) => { - image.idx = imageIdx; - image.imageData = imageData; - }); - }); - } catch (e) { - console.log(e); - } - }, - getImage: async (imageId: string) => { - try { - return await database.action(async () => { - return await offlineImage.query(Q.where('idx', imageId), Q.take(1)).fetch() - }); - } catch (e) { - console.log(e); - return; - } - }, - deleteImages: async (imageIdList: Array) => { - try { - return await database.action(async () => { - await offlineImage.query(Q.where('idx', Q.oneOf(imageIdList))).destroyAllPermanently() - }); - } catch (e) { - console.log(e); - return; - } - }, - deleteAll: async () => { - try { - return await database.action(async () => { - await offlineImage.query().destroyAllPermanently(); - }); - } catch (e) { - console.log(e); - return; - } - }, + observeOfflineImage: () => offlineImage.query().observe(), + addImage: async (imageData: string, imageIdx: string) => { + try { + return await database.action(async () => { + return await offlineImage.create((image: any) => { + image.idx = imageIdx; + image.imageData = imageData; + }); + }); + } catch (e) { + console.log(e); + } + }, + getImage: async (imageId: string) => { + try { + return await database.action(async () => { + return await offlineImage.query(Q.where('idx', imageId), Q.take(1)).fetch(); + }); + } catch (e) { + console.log(e); + return; + } + }, + deleteImages: async (imageIdList: Array) => { + try { + return await database.action(async () => { + await offlineImage.query(Q.where('idx', Q.oneOf(imageIdList))).destroyAllPermanently(); + }); + } catch (e) { + console.log(e); + return; + } + }, + deleteAll: async () => { + try { + return await database.action(async () => { + await offlineImage.query().destroyAllPermanently(); + }); + } catch (e) { + console.log(e); + return; + } + }, }; diff --git a/src/wmDB/db.ts b/src/wmDB/db.ts index 09159d73..c863ebb4 100644 --- a/src/wmDB/db.ts +++ b/src/wmDB/db.ts @@ -8,13 +8,13 @@ import OfflineImage from './model/OfflineImage'; import schema from './schema'; const adapter = new SQLiteAdapter({ - dbName: DB_NAME, - schema, + dbName: DB_NAME, + schema, }); const database = new Database({ - adapter, - modelClasses: [OfflineImage, CustomerImage, ClickstreamEvents] + adapter, + modelClasses: [OfflineImage, CustomerImage, ClickstreamEvents], }); export { database }; diff --git a/src/wmDB/model/ClickstreamEvents.ts b/src/wmDB/model/ClickstreamEvents.ts index 00992deb..bcf3abce 100644 --- a/src/wmDB/model/ClickstreamEvents.ts +++ b/src/wmDB/model/ClickstreamEvents.ts @@ -5,13 +5,13 @@ import { TableName } from '../const'; const sanitizeAttributes = (json: any) => json; export default class ClickstreamEvents extends Model { - static table = TableName.CLICKSTREAM_EVENTS; + static table = TableName.CLICKSTREAM_EVENTS; - @field('event_name') event_name!: string; - @field('description') description!: string; - @field('agent_id') agentId!: string; - @field('device_id') deviceId!: string; - @field('network_status') networkStatus!: string; - @field('timestamp') timestamp!: number; - @json('attributes', sanitizeAttributes) attributes: any; + @field('event_name') event_name!: string; + @field('description') description!: string; + @field('agent_id') agentId!: string; + @field('device_id') deviceId!: string; + @field('network_status') networkStatus!: string; + @field('timestamp') timestamp!: number; + @json('attributes', sanitizeAttributes) attributes: any; } diff --git a/src/wmDB/model/CustomerImage.ts b/src/wmDB/model/CustomerImage.ts index dbde5bf7..ccde7cc7 100644 --- a/src/wmDB/model/CustomerImage.ts +++ b/src/wmDB/model/CustomerImage.ts @@ -1,17 +1,13 @@ import { Model } from '@nozbe/watermelondb'; -import { - field, - readonly, - date, -} from '@nozbe/watermelondb/decorators'; +import { field, readonly, date } from '@nozbe/watermelondb/decorators'; import { TableName } from '../const'; export default class CustomerImage extends Model { - static table = TableName.CUSTOMER_IMAGE; + static table = TableName.CUSTOMER_IMAGE; - @field('case_id') caseId!: string; - @field('image_url') imageURL!: string; - @field('image_64') image64!: string; - @readonly @date('created_at') createdAt!: any; - @readonly @date('updated_at') updatedAt!: any; -} \ No newline at end of file + @field('case_id') caseId!: string; + @field('image_url') imageURL!: string; + @field('image_64') image64!: string; + @readonly @date('created_at') createdAt!: any; + @readonly @date('updated_at') updatedAt!: any; +} diff --git a/src/wmDB/model/OfflineImage.ts b/src/wmDB/model/OfflineImage.ts index 2a000e93..074c7e5c 100644 --- a/src/wmDB/model/OfflineImage.ts +++ b/src/wmDB/model/OfflineImage.ts @@ -1,16 +1,12 @@ import { Model } from '@nozbe/watermelondb'; -import { - field, - readonly, - date, -} from '@nozbe/watermelondb/decorators'; +import { field, readonly, date } from '@nozbe/watermelondb/decorators'; import { TableName } from '../const'; export default class OfflineImage extends Model { - static table = TableName.OFFLINE_IMAGES; + static table = TableName.OFFLINE_IMAGES; - @field('idx') idx!: string; - @field('image_data') imageData!: string; - @readonly @date('created_at') createdAt!: any; - @readonly @date('updated_at') updatedAt!: any; -} \ No newline at end of file + @field('idx') idx!: string; + @field('image_data') imageData!: string; + @readonly @date('created_at') createdAt!: any; + @readonly @date('updated_at') updatedAt!: any; +} diff --git a/src/wmDB/schema.ts b/src/wmDB/schema.ts index 49731efa..3fa69273 100644 --- a/src/wmDB/schema.ts +++ b/src/wmDB/schema.ts @@ -2,34 +2,34 @@ import { appSchema, tableSchema } from '@nozbe/watermelondb'; import { DB_VERSION, TableName } from './const'; export default appSchema({ - version: DB_VERSION, - tables: [ - tableSchema({ - name: TableName.OFFLINE_IMAGES, - columns: [ - { name: 'idx', type: 'string' }, - { name: 'image_data', type: 'string' }, - ], - }), - tableSchema({ - name: TableName.CUSTOMER_IMAGE, - columns: [ - { name: 'case_id', type: 'string' }, - { name: 'image_url', type: 'string' }, - { name: 'image_64', type: 'string' }, - ], - }), - tableSchema({ - name: TableName.CLICKSTREAM_EVENTS, - columns: [ - { name: 'event_name', type: 'string' }, - { name: 'description', type: 'string'}, - { name: 'agent_id', type: 'string' }, - { name: 'device_id', type: 'string' }, - { name: 'attributes', type: 'string' }, - { name: 'network_status', type: 'string' }, - { name: 'timestamp', type: 'number' }, - ], - }), - ], + version: DB_VERSION, + tables: [ + tableSchema({ + name: TableName.OFFLINE_IMAGES, + columns: [ + { name: 'idx', type: 'string' }, + { name: 'image_data', type: 'string' }, + ], + }), + tableSchema({ + name: TableName.CUSTOMER_IMAGE, + columns: [ + { name: 'case_id', type: 'string' }, + { name: 'image_url', type: 'string' }, + { name: 'image_64', type: 'string' }, + ], + }), + tableSchema({ + name: TableName.CLICKSTREAM_EVENTS, + columns: [ + { name: 'event_name', type: 'string' }, + { name: 'description', type: 'string' }, + { name: 'agent_id', type: 'string' }, + { name: 'device_id', type: 'string' }, + { name: 'attributes', type: 'string' }, + { name: 'network_status', type: 'string' }, + { name: 'timestamp', type: 'number' }, + ], + }), + ], }); diff --git a/types.d.ts b/types.d.ts index 7b2c5c8a..28c5baec 100644 --- a/types.d.ts +++ b/types.d.ts @@ -1,7 +1,7 @@ export {}; declare global { - interface Window { - server: any; - } + interface Window { + server: any; + } } diff --git a/yarn.lock b/yarn.lock index 0a049afa..939cd4d3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2210,6 +2210,14 @@ agent-base@6, agent-base@^6.0.0, agent-base@^6.0.2: dependencies: debug "4" +aggregate-error@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/aggregate-error/-/aggregate-error-3.1.0.tgz#92670ff50f5359bdb7a3e0d40d0ec30c5737687a" + integrity sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA== + dependencies: + clean-stack "^2.0.0" + indent-string "^4.0.0" + ajv@^6.10.0, ajv@^6.12.4: version "6.12.6" resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" @@ -2225,7 +2233,7 @@ anser@^1.4.9: resolved "https://registry.yarnpkg.com/anser/-/anser-1.4.10.tgz#befa3eddf282684bd03b63dcda3927aef8c2e35b" integrity sha512-hCv9AqTQ8ycjpSd3upOJd7vFwW1JaoYQ7tpham03GJ1ca8/65rqn0RpaWpItOAd6ylW9wAw6luXYPJIyPFVOww== -ansi-escapes@^4.2.1: +ansi-escapes@^4.2.1, ansi-escapes@^4.3.0: version "4.3.2" resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ== @@ -2251,6 +2259,11 @@ ansi-regex@^5.0.0, ansi-regex@^5.0.1: resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== +ansi-regex@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-6.0.1.tgz#3183e38fae9a65d7cb5e53945cd5897d0260a06a" + integrity sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA== + ansi-styles@^3.2.0, ansi-styles@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" @@ -2265,6 +2278,11 @@ ansi-styles@^4.0.0, ansi-styles@^4.1.0: dependencies: color-convert "^2.0.1" +ansi-styles@^6.0.0: + version "6.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.2.1.tgz#0e62320cf99c21afff3b3012192546aacbfb05c5" + integrity sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug== + anymatch@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb" @@ -2449,6 +2467,11 @@ astral-regex@^1.0.0: resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9" integrity sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg== +astral-regex@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-2.0.0.tgz#483143c567aeed4785759c0865786dc77d7d2e31" + integrity sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ== + async-limiter@~1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.1.tgz#dd379e94f0db8310b08291f9d64c3209766617fd" @@ -2865,6 +2888,11 @@ capture-exit@^2.0.0: dependencies: rsvp "^4.8.4" +chalk@5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.2.0.tgz#249623b7d66869c673699fb66d65723e54dfcfb3" + integrity sha512-ree3Gqw/nazQAPuJJEy+avdl7QfZMcUvmHIKgEZkGL+xOBzRvup5Hxo6LHuMceSxOabuJLJm5Yp/92R9eMmMvA== + chalk@^2.0.0: version "2.4.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" @@ -2922,6 +2950,11 @@ class-utils@^0.3.5: isobject "^3.0.0" static-extend "^0.1.1" +clean-stack@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" + integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A== + cli-cursor@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307" @@ -2934,6 +2967,22 @@ cli-spinners@^2.5.0: resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-2.7.0.tgz#f815fd30b5f9eaac02db604c7a231ed7cb2f797a" integrity sha512-qu3pN8Y3qHNgE2AFweciB1IfMnmZ/fsNTEE+NOFjmGB2F/7rLhnhzppvpCnN4FovtP26k8lHyy9ptEbNwWFLzw== +cli-truncate@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/cli-truncate/-/cli-truncate-2.1.0.tgz#c39e28bf05edcde5be3b98992a22deed5a2b93c7" + integrity sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg== + dependencies: + slice-ansi "^3.0.0" + string-width "^4.2.0" + +cli-truncate@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/cli-truncate/-/cli-truncate-3.1.0.tgz#3f23ab12535e3d73e839bb43e73c9de487db1389" + integrity sha512-wfOBkjXteqSnI59oPcJkcPl/ZmwvMMOj340qUIY1SKZCv0B9Cf4D4fAucRkIKQmsIuYK3x1rrgU7MeGRruiuiA== + dependencies: + slice-ansi "^5.0.0" + string-width "^5.0.0" + cli-width@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-3.0.0.tgz#a2f48437a2caa9a22436e794bf071ec9e61cedf6" @@ -3056,6 +3105,11 @@ colorette@^1.0.7: resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.4.0.tgz#5190fbb87276259a86ad700bff2c6d6faa3fca40" integrity sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g== +colorette@^2.0.19: + version "2.0.20" + resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.20.tgz#9eb793e6833067f7235902fcd3b09917a000a95a" + integrity sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w== + combined-stream@^1.0.6, combined-stream@^1.0.8: version "1.0.8" resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" @@ -3068,6 +3122,11 @@ command-exists@^1.2.8: resolved "https://registry.yarnpkg.com/command-exists/-/command-exists-1.2.9.tgz#c50725af3808c8ab0260fd60b01fbfa25b954f69" integrity sha512-LTQ/SGc+s0Xc0Fu5WaKnR0YiygZkm9eKFvyS+fRsU7/ZWFF8ykFM6Pc9aCVf1+xasOOZpO3BAVgVrKvsqKHV7w== +commander@^10.0.0: + version "10.0.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-10.0.1.tgz#881ee46b4f77d1c1dccc5823433aa39b022cbe06" + integrity sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug== + commander@^9.4.0: version "9.4.1" resolved "https://registry.yarnpkg.com/commander/-/commander-9.4.1.tgz#d1dd8f2ce6faf93147295c0df13c7c21141cfbdd" @@ -3181,7 +3240,7 @@ cross-spawn@^6.0.0: shebang-command "^1.2.0" which "^1.2.9" -cross-spawn@^7.0.0, cross-spawn@^7.0.2: +cross-spawn@^7.0.0, cross-spawn@^7.0.2, cross-spawn@^7.0.3: version "7.0.3" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== @@ -3498,6 +3557,11 @@ domutils@^3.0.1: domelementtype "^2.3.0" domhandler "^5.0.1" +eastasianwidth@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb" + integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA== + ee-first@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" @@ -4026,6 +4090,21 @@ execa@^4.0.0: signal-exit "^3.0.2" strip-final-newline "^2.0.0" +execa@^7.0.0: + version "7.1.1" + resolved "https://registry.yarnpkg.com/execa/-/execa-7.1.1.tgz#3eb3c83d239488e7b409d48e8813b76bb55c9c43" + integrity sha512-wH0eMf/UXckdUYnO21+HDztteVv05rq2GXksxT4fCGeHkBhw1DROXh40wcjMcRqDOWE7iPJ4n3M7e2+YFP+76Q== + dependencies: + cross-spawn "^7.0.3" + get-stream "^6.0.1" + human-signals "^4.3.0" + is-stream "^3.0.0" + merge-stream "^2.0.0" + npm-run-path "^5.1.0" + onetime "^6.0.0" + signal-exit "^3.0.7" + strip-final-newline "^3.0.0" + exit@^0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" @@ -4456,6 +4535,11 @@ get-stream@^5.0.0: dependencies: pump "^3.0.0" +get-stream@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" + integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== + get-symbol-description@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.0.0.tgz#7fdb81c900101fbd564dd5f1a30af5aadc1e58d6" @@ -4744,6 +4828,16 @@ human-signals@^1.1.1: resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-1.1.1.tgz#c5b1cd14f50aeae09ab6c59fe63ba3395fe4dfa3" integrity sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw== +human-signals@^4.3.0: + version "4.3.1" + resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-4.3.1.tgz#ab7f811e851fca97ffbd2c1fe9a958964de321b2" + integrity sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ== + +husky@8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/husky/-/husky-8.0.0.tgz#65b2d94765199d651615716a42ea52f3c2d997a0" + integrity sha512-4qbE/5dzNDNxFEkX9MNRPKl5+omTXQzdILCUWiqG/lWIAioiM5vln265/l6I2Zx8gpW8l1ukZwGQeCFbBZ6+6w== + iconv-lite@0.4.24, iconv-lite@^0.4.24: version "0.4.24" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" @@ -4805,6 +4899,11 @@ imurmurhash@^0.1.4: resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA== +indent-string@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251" + integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg== + inflected@^2.0.4: version "2.1.0" resolved "https://registry.yarnpkg.com/inflected/-/inflected-2.1.0.tgz#2816ac17a570bbbc8303ca05bca8bf9b3f959687" @@ -5021,6 +5120,11 @@ is-fullwidth-code-point@^3.0.0: resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== +is-fullwidth-code-point@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz#fae3167c729e7463f8461ce512b080a49268aa88" + integrity sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ== + is-generator-fn@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/is-generator-fn/-/is-generator-fn-2.1.0.tgz#7d140adc389aaf3011a8f2a2a4cfa6faadffb118" @@ -5104,6 +5208,11 @@ is-stream@^2.0.0: resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== +is-stream@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-3.0.0.tgz#e6bfd7aa6bef69f4f472ce9bb681e3e57b4319ac" + integrity sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA== + is-string@^1.0.5, is-string@^1.0.7: version "1.0.7" resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.7.tgz#0dd12bf2006f255bb58f695110eff7491eebc0fd" @@ -5875,11 +5984,49 @@ levn@~0.3.0: prelude-ls "~1.1.2" type-check "~0.3.2" +lilconfig@2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-2.1.0.tgz#78e23ac89ebb7e1bfbf25b18043de756548e7f52" + integrity sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ== + lines-and-columns@^1.1.6: version "1.2.4" resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== +lint-staged@^13.2.1: + version "13.2.1" + resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-13.2.1.tgz#9d30a14e3e42897ef417bc98556fb757f75cae87" + integrity sha512-8gfzinVXoPfga5Dz/ZOn8I2GOhf81Wvs+KwbEXQn/oWZAvCVS2PivrXfVbFJc93zD16uC0neS47RXHIjXKYZQw== + dependencies: + chalk "5.2.0" + cli-truncate "^3.1.0" + commander "^10.0.0" + debug "^4.3.4" + execa "^7.0.0" + lilconfig "2.1.0" + listr2 "^5.0.7" + micromatch "^4.0.5" + normalize-path "^3.0.0" + object-inspect "^1.12.3" + pidtree "^0.6.0" + string-argv "^0.3.1" + yaml "^2.2.1" + +listr2@^5.0.7: + version "5.0.8" + resolved "https://registry.yarnpkg.com/listr2/-/listr2-5.0.8.tgz#a9379ffeb4bd83a68931a65fb223a11510d6ba23" + integrity sha512-mC73LitKHj9w6v30nLNGPetZIlfpUniNSsxxrbaPcWOjDb92SHPzJPi/t+v1YC/lxKz/AJ9egOjww0qUuFxBpA== + dependencies: + cli-truncate "^2.1.0" + colorette "^2.0.19" + log-update "^4.0.0" + p-map "^4.0.0" + rfdc "^1.3.0" + rxjs "^7.8.0" + through "^2.3.8" + wrap-ansi "^7.0.0" + locate-path@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" @@ -6045,6 +6192,16 @@ log-symbols@^4.1.0: chalk "^4.1.0" is-unicode-supported "^0.1.0" +log-update@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/log-update/-/log-update-4.0.0.tgz#589ecd352471f2a1c0c570287543a64dfd20e0a1" + integrity sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg== + dependencies: + ansi-escapes "^4.3.0" + cli-cursor "^3.1.0" + slice-ansi "^4.0.0" + wrap-ansi "^6.2.0" + logkitty@^0.7.1: version "0.7.1" resolved "https://registry.yarnpkg.com/logkitty/-/logkitty-0.7.1.tgz#8e8d62f4085a826e8d38987722570234e33c6aa7" @@ -6443,7 +6600,7 @@ micromatch@^3.1.10, micromatch@^3.1.4: snapdragon "^0.8.1" to-regex "^3.0.2" -micromatch@^4.0.2, micromatch@^4.0.4: +micromatch@^4.0.2, micromatch@^4.0.4, micromatch@^4.0.5: version "4.0.5" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6" integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== @@ -6478,6 +6635,11 @@ mimic-fn@^2.1.0: resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== +mimic-fn@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-4.0.0.tgz#60a90550d5cb0b239cca65d893b1a53b29871ecc" + integrity sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw== + mimic-response@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-3.1.0.tgz#2d1d59af9c1b129815accc2c46a022a5ce1fa3c9" @@ -6733,6 +6895,13 @@ npm-run-path@^4.0.0: dependencies: path-key "^3.0.0" +npm-run-path@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-5.1.0.tgz#bc62f7f3f6952d9894bd08944ba011a6ee7b7e00" + integrity sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q== + dependencies: + path-key "^4.0.0" + nth-check@^2.0.1: version "2.1.1" resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-2.1.1.tgz#c9eab428effce36cd6b92c924bdb000ef1f1ed1d" @@ -6774,6 +6943,11 @@ object-inspect@^1.12.2, object-inspect@^1.9.0: resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.2.tgz#c0641f26394532f28ab8d796ab954e43c009a8ea" integrity sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ== +object-inspect@^1.12.3: + version "1.12.3" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.3.tgz#ba62dffd67ee256c8c086dfae69e016cd1f198b9" + integrity sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g== + object-keys@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" @@ -6871,6 +7045,13 @@ onetime@^5.1.0: dependencies: mimic-fn "^2.1.0" +onetime@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-6.0.0.tgz#7c24c18ed1fd2e9bca4bd26806a33613c77d34b4" + integrity sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ== + dependencies: + mimic-fn "^4.0.0" + open@^6.2.0: version "6.4.0" resolved "https://registry.yarnpkg.com/open/-/open-6.4.0.tgz#5c13e96d0dc894686164f18965ecfe889ecfc8a9" @@ -6977,6 +7158,13 @@ p-locate@^5.0.0: dependencies: p-limit "^3.0.2" +p-map@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/p-map/-/p-map-4.0.0.tgz#bb2f95a5eda2ec168ec9274e06a747c3e2904d2b" + integrity sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ== + dependencies: + aggregate-error "^3.0.0" + p-try@^2.0.0: version "2.2.0" resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" @@ -7071,6 +7259,11 @@ path-key@^3.0.0, path-key@^3.1.0: resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== +path-key@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-4.0.0.tgz#295588dc3aee64154f877adb9d780b81c554bf18" + integrity sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ== + path-parse@^1.0.7: version "1.0.7" resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" @@ -7091,6 +7284,11 @@ picomatch@^2.0.4, picomatch@^2.2.3, picomatch@^2.3.1: resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== +pidtree@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/pidtree/-/pidtree-0.6.0.tgz#90ad7b6d42d5841e69e0a2419ef38f8883aa057c" + integrity sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g== + pify@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231" @@ -7833,6 +8031,11 @@ reusify@^1.0.4: resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== +rfdc@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.3.0.tgz#d0b7c441ab2720d05dc4cf26e01c89631d9da08b" + integrity sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA== + rimraf@^2.5.4: version "2.7.1" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" @@ -7889,7 +8092,7 @@ run-parallel@^1.1.9: dependencies: queue-microtask "^1.2.2" -rxjs@^7.3.0, rxjs@^7.5.5: +rxjs@^7.3.0, rxjs@^7.5.5, rxjs@^7.8.0: version "7.8.0" resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.8.0.tgz#90a938862a82888ff4c7359811a595e14e1e09a4" integrity sha512-F2+gxDshqmIub1KdvZkaEfGDwLNpPvk9Fs6LD/MyQxNgMds/WH9OdDDXOmxUZpME+iSK3rQCctkL0DYyytUqMg== @@ -8098,7 +8301,7 @@ side-channel@^1.0.4: get-intrinsic "^1.0.2" object-inspect "^1.9.0" -signal-exit@^3.0.0, signal-exit@^3.0.2: +signal-exit@^3.0.0, signal-exit@^3.0.2, signal-exit@^3.0.7: version "3.0.7" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== @@ -8152,6 +8355,32 @@ slice-ansi@^2.0.0: astral-regex "^1.0.0" is-fullwidth-code-point "^2.0.0" +slice-ansi@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-3.0.0.tgz#31ddc10930a1b7e0b67b08c96c2f49b77a789787" + integrity sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ== + dependencies: + ansi-styles "^4.0.0" + astral-regex "^2.0.0" + is-fullwidth-code-point "^3.0.0" + +slice-ansi@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-4.0.0.tgz#500e8dd0fd55b05815086255b3195adf2a45fe6b" + integrity sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ== + dependencies: + ansi-styles "^4.0.0" + astral-regex "^2.0.0" + is-fullwidth-code-point "^3.0.0" + +slice-ansi@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-5.0.0.tgz#b73063c57aa96f9cd881654b15294d95d285c42a" + integrity sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ== + dependencies: + ansi-styles "^6.0.0" + is-fullwidth-code-point "^4.0.0" + smart-buffer@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/smart-buffer/-/smart-buffer-4.2.0.tgz#6e1d71fa4f18c05f7d0ff216dd16a481d0e8d9ae" @@ -8372,6 +8601,11 @@ strict-uri-encode@^2.0.0: resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz#b9c7330c7042862f6b142dc274bbcc5866ce3546" integrity sha512-QwiXZgpRcKkhTj2Scnn++4PKtWsH0kpzZ62L2R6c/LUVYv7hVnZqcg2+sMuT6R7Jusu1vviK/MFsu6kNJfWlEQ== +string-argv@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/string-argv/-/string-argv-0.3.1.tgz#95e2fbec0427ae19184935f816d74aaa4c5c19da" + integrity sha512-a1uQGz7IyVy9YwhqjZIZu1c8JO8dNIe20xBmSS6qu9kv++k3JGzCVmprbNN5Kn+BgzD5E7YYwg1CcjuJMRNsvg== + string-length@^4.0.1: version "4.0.2" resolved "https://registry.yarnpkg.com/string-length/-/string-length-4.0.2.tgz#a8a8dc7bd5c1a82b9b3c8b87e125f66871b6e57a" @@ -8389,6 +8623,15 @@ string-width@^4.1.0, string-width@^4.2.0: is-fullwidth-code-point "^3.0.0" strip-ansi "^6.0.1" +string-width@^5.0.0: + version "5.1.2" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794" + integrity sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA== + dependencies: + eastasianwidth "^0.2.0" + emoji-regex "^9.2.2" + strip-ansi "^7.0.1" + string.prototype.matchall@^4.0.8: version "4.0.8" resolved "https://registry.yarnpkg.com/string.prototype.matchall/-/string.prototype.matchall-4.0.8.tgz#3bf85722021816dcd1bf38bb714915887ca79fd3" @@ -8454,6 +8697,13 @@ strip-ansi@^6.0.0, strip-ansi@^6.0.1: dependencies: ansi-regex "^5.0.1" +strip-ansi@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.0.1.tgz#61740a08ce36b61e50e65653f07060d000975fb2" + integrity sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw== + dependencies: + ansi-regex "^6.0.1" + strip-bom@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" @@ -8474,6 +8724,11 @@ strip-final-newline@^2.0.0: resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== +strip-final-newline@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-3.0.0.tgz#52894c313fbff318835280aed60ff71ebf12b8fd" + integrity sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw== + strip-json-comments@^3.1.0, strip-json-comments@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" @@ -8648,7 +8903,7 @@ through2@^2.0.1: readable-stream "~2.3.6" xtend "~4.0.1" -through@^2.3.6: +through@^2.3.6, through@^2.3.8: version "2.3.8" resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" integrity sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg== @@ -9258,6 +9513,11 @@ yallist@^4.0.0: resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== +yaml@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.2.1.tgz#3014bf0482dcd15147aa8e56109ce8632cd60ce4" + integrity sha512-e0WHiYql7+9wr4cWMx3TVQrNwejKaEe7/rHNmQmqRjazfOP5W8PB6Jpebb5o6fIapbz9o9+2ipcaTM2ZwDI6lw== + yargs-parser@^18.1.2: version "18.1.3" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-18.1.3.tgz#be68c4975c6b2abf469236b0c870362fab09a7b0"