diff --git a/RN-UI-LIB b/RN-UI-LIB
index 50f7e796..b162be37 160000
--- a/RN-UI-LIB
+++ b/RN-UI-LIB
@@ -1 +1 @@
-Subproject commit 50f7e796a8fb9ddd6d1b7ce4d8ffe8afc657d683
+Subproject commit b162be37b29efb75fea7ef59ca659ac046ea8a59
diff --git a/android/app/build.gradle b/android/app/build.gradle
index e1d4e6e6..890ec9b6 100644
--- a/android/app/build.gradle
+++ b/android/app/build.gradle
@@ -131,8 +131,8 @@ def reactNativeArchitectures() {
return value ? value.split(",") : ["armeabi-v7a", "x86", "x86_64", "arm64-v8a"]
}
-def VERSION_CODE = 52
-def VERSION_NAME = "2.1.11"
+def VERSION_CODE = 53
+def VERSION_NAME = "2.1.12"
android {
ndkVersion rootProject.ext.ndkVersion
diff --git a/config/dev/config.js b/config/dev/config.js
index 44347f15..0130b0f3 100644
--- a/config/dev/config.js
+++ b/config/dev/config.js
@@ -4,4 +4,4 @@ export const JANUS_SERVICE_URL = 'https://dev-longhorn-portal.np.navi-tech.in/ap
export const ENV = 'dev';
export const IS_SSO_ENABLED = false;
export const APM_APP_NAME = 'cosmos-app';
-export const APM_BASE_URL = 'https://apm-server.np.navi-tech.in';
+export const APM_BASE_URL = 'https://dev-longhorn-portal.np.navi-tech.in/apm-events';
diff --git a/config/prod/config.js b/config/prod/config.js
index 3b8d9028..88d6ad00 100644
--- a/config/prod/config.js
+++ b/config/prod/config.js
@@ -2,6 +2,6 @@ export const BASE_AV_APP_URL = 'https://longhorn.navi.com/field-app';
export const SENTRY_DSN = 'https://5daa4832fade44b389b265de9b26c2fd@longhorn.navi.com/glitchtip-events/172';
export const JANUS_SERVICE_URL = 'https://longhorn.navi.com/api/events/json';
export const ENV = 'prod';
-export const IS_SSO_ENABLED = false;
+export const IS_SSO_ENABLED = true;
export const APM_APP_NAME = 'cosmos-app';
-export const APM_BASE_URL = 'https://apm-server.prod.navi-tech.in';
+export const APM_BASE_URL = 'https://longhorn.navi.com/apm-events';
diff --git a/config/qa/config.js b/config/qa/config.js
index b4c6f94e..f35a71d1 100644
--- a/config/qa/config.js
+++ b/config/qa/config.js
@@ -4,4 +4,4 @@ export const JANUS_SERVICE_URL = 'https://qa-longhorn-portal.np.navi-tech.in/api
export const ENV = 'qa';
export const IS_SSO_ENABLED = false;
export const APM_APP_NAME = 'cosmos-app';
-export const APM_BASE_URL = 'https://apm-server.np.navi-tech.in';
+export const APM_BASE_URL = 'https://qa-longhorn-portal.np.navi-tech.in/apm-events';
diff --git a/package.json b/package.json
index 3c838a63..b34d38fa 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "AV_APP",
- "version": "2.1.11",
+ "version": "2.1.12",
"private": true,
"scripts": {
"android:dev": "yarn move:dev && react-native run-android",
@@ -56,6 +56,7 @@
"react-native-device-info": "10.3.0",
"react-native-fast-image": "8.6.3",
"react-native-geolocation-service": "5.3.1",
+ "react-native-get-random-values": "^1.8.0",
"react-native-image-picker": "4.10.2",
"react-native-pager-view": "6.1.2",
"react-native-permissions": "3.6.1",
diff --git a/src/action/authActions.ts b/src/action/authActions.ts
index 679e9615..505d25a2 100644
--- a/src/action/authActions.ts
+++ b/src/action/authActions.ts
@@ -1,3 +1,5 @@
+import { ToastMessages } from './../screens/allCases/constants';
+import 'react-native-get-random-values';
import crypto from 'crypto-js';
import { IUser, setAuthData } from '../reducer/userSlice';
import axiosInstance, { ApiKeys, API_STATUS_CODE, getApiUrl } from '../components/utlis/apiHelper';
@@ -19,7 +21,6 @@ import { toast } from '../../RN-UI-LIB/src/components/toast';
import AsyncStorage from '@react-native-async-storage/async-storage';
import { clearAllAsyncStorage, setAsyncStorageItem } from '../components/utlis/commonFunctions';
import { logError } from '../components/utlis/errorUtils';
-import { getUniqueId } from 'react-native-device-info';
import { Linking } from 'react-native';
export interface GenerateOTPPayload {
@@ -78,7 +79,6 @@ export const signInGoogle = () => async (dispatch: Dispatch) => {
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,
@@ -87,15 +87,14 @@ export const signInGoogle = () => async (dispatch: Dispatch) => {
headers: { donotHandleError: false },
});
if (response?.data?.signInUrl) {
- Linking.openURL(response.data.signInUrl);
+ await Linking.openURL(response.data.signInUrl);
}
} catch (error) {
+ logError(error as Error);
toast({
text1: 'Error in google sign in',
type: 'error',
});
- } finally {
- dispatch(setFormLoading(false));
}
};
@@ -108,16 +107,12 @@ export const verifyGoogleSignIn =
return;
}
const parsedCodeVerify = JSON.parse(codeVerify);
- const response = await axiosInstance.post(
- url,
- {
- code,
- state,
- codeVerifier: parsedCodeVerify,
- deviceId: deviceId,
- },
- { headers: { donotHandleError: true } }
- );
+ const response = await axiosInstance.post(url, {
+ code,
+ state,
+ codeVerifier: parsedCodeVerify,
+ deviceId: deviceId,
+ });
if (response?.data?.sessionDetails) {
const { sessionDetails, user } = response.data;
dispatch(
@@ -132,12 +127,17 @@ export const verifyGoogleSignIn =
}
} catch (error) {
logError(error as Error);
- toast({
- text1: 'error in google sign in',
- type: 'error',
- });
- } finally {
- () => dispatch(setFormLoading(false));
+ if (error?.response?.status === API_STATUS_CODE.NOT_FOUND) {
+ toast({
+ text1: ToastMessages.GENERIC_ERROR_TOAST,
+ type: 'error',
+ });
+ } else {
+ toast({
+ text1: error?.response?.data?.message ?? ToastMessages.SSO_SERVER_SIGN_IN_ERROR,
+ type: 'error',
+ });
+ }
}
};
diff --git a/src/action/notificationActions.ts b/src/action/notificationActions.ts
index 23d5d4e8..a57f3e86 100644
--- a/src/action/notificationActions.ts
+++ b/src/action/notificationActions.ts
@@ -32,7 +32,11 @@ export const getNotifications =
const startTime = yesterday.getTime();
const url = getApiUrl(ApiKeys.NOTIFICATIONS, {}, { ...payload, startTime });
return axiosInstance
- .get(url)
+ .get(url, {
+ headers: {
+ showInSpecificComponents: ['Notifications'],
+ },
+ })
.then((response) => {
const notifications = response?.data?.notificationResponse?.notifications;
const { totalElements, totalPages, totalUnreadElements } = response?.data;
@@ -66,9 +70,19 @@ export const getNotifications =
export const notificationAction = (payload: INotificationAction[]) => (dispatch: AppDispatch) => {
const url = getApiUrl(ApiKeys.NOTIFICATION_ACTION);
- return axiosInstance.post(url, payload).then(() => {
- dispatch(addActionToNotifications(payload));
- });
+ return axiosInstance
+ .post(
+ url,
+ {
+ headers: {
+ showInSpecificComponents: ['Notifications'],
+ },
+ },
+ payload
+ )
+ .then(() => {
+ dispatch(addActionToNotifications(payload));
+ });
};
export const notificationDelivered = (payload: { ids: string[] }) => (dispatch: AppDispatch) => {
diff --git a/src/assets/icons/GoogleIcon.tsx b/src/assets/icons/GoogleIcon.tsx
new file mode 100644
index 00000000..eb610c59
--- /dev/null
+++ b/src/assets/icons/GoogleIcon.tsx
@@ -0,0 +1,43 @@
+import * as React from 'react';
+import Svg, { Path } from 'react-native-svg';
+
+function GoogleIcon(props) {
+ return (
+
+ );
+}
+
+export default GoogleIcon;
diff --git a/src/constants/config.js b/src/constants/config.js
index b4c6f94e..f35a71d1 100644
--- a/src/constants/config.js
+++ b/src/constants/config.js
@@ -4,4 +4,4 @@ export const JANUS_SERVICE_URL = 'https://qa-longhorn-portal.np.navi-tech.in/api
export const ENV = 'qa';
export const IS_SSO_ENABLED = false;
export const APM_APP_NAME = 'cosmos-app';
-export const APM_BASE_URL = 'https://apm-server.np.navi-tech.in';
+export const APM_BASE_URL = 'https://qa-longhorn-portal.np.navi-tech.in/apm-events';
diff --git a/src/screens/allCases/constants.ts b/src/screens/allCases/constants.ts
index 2319fd6f..38406770 100644
--- a/src/screens/allCases/constants.ts
+++ b/src/screens/allCases/constants.ts
@@ -56,4 +56,6 @@ export const ToastMessages = {
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',
+ GENERIC_ERROR_TOAST: 'Something went wrong',
+ SSO_SERVER_SIGN_IN_ERROR: 'Error while signing in to cosmos',
};
diff --git a/src/screens/emiSchedule/EmiBreakupBottomSheet.tsx b/src/screens/emiSchedule/EmiBreakupBottomSheet.tsx
index a66b74c0..38d958e0 100644
--- a/src/screens/emiSchedule/EmiBreakupBottomSheet.tsx
+++ b/src/screens/emiSchedule/EmiBreakupBottomSheet.tsx
@@ -16,79 +16,74 @@ interface IEmiBreakupBottomSheet {
emiItem: IEmiItem;
listNumber: number;
}
-const EmiBreakupBottomSheet: React.FC = props => {
+const EmiBreakupBottomSheet: React.FC = (props) => {
const { openBottomSheet, setOpenBottomSheet, emiItem, listNumber } = props;
return (
- (
-
-
- EMI {listNumber} breakup
-
- setOpenBottomSheet(prev => !prev)}>
-
-
-
- )}
- setVisible={() => setOpenBottomSheet(prev => !prev)}>
-
-
- Principal
- {formatAmount(emiItem?.totalUnpaidPrincipal ?? 0)}
-
-
- Interest
-
- {formatAmount(emiItem?.totalUnpaidInterest ?? 0)}
-
-
- {
- emiItem?.totalUnpaidEmiPenaltyCharges ?
- (
- <>
-
- Interest
-
- {formatAmount(emiItem?.totalUnpaidEmiPenaltyCharges ?? 0)}
-
-
- >
- ) :
- (
- <>
-
- Other fees
-
- {formatAmount(emiItem?.totalUnpaidOtherFees ?? 0)}
-
-
- >
- )
- }
-
-
-
- Total Overdue Amount
-
-
- {formatAmount(emiItem?.totalOverDueAmount ?? 0)}
-
-
-
-
+ (
+
+
+ EMI {listNumber} breakup
+
+ setOpenBottomSheet((prev) => !prev)}>
+
+
+
+ )}
+ setVisible={() => setOpenBottomSheet((prev) => !prev)}
+ >
+
+
+ Principal
+ {formatAmount(emiItem?.totalUnpaidPrincipal ?? 0)}
+
+
+ Interest
+
+ {formatAmount(emiItem?.totalUnpaidInterest ?? 0)}
+
+
+ {emiItem?.totalUnpaidEmiPenaltyCharges ? (
+ <>
+
+ Interest
+
+ {formatAmount(emiItem?.totalUnpaidEmiPenaltyCharges ?? 0)}
+
+
+ >
+ ) : (
+ <>
+
+ Other fees
+
+ {formatAmount(emiItem?.totalUnpaidOtherFees ?? 0)}
+
+
+ >
+ )}
+
+
+
+ Total Overdue Amount
+
+
+ {formatAmount(emiItem?.totalOverDueAmount ?? 0)}
+
+
+
+
);
};
const styles = StyleSheet.create({
- horizontalLine: {
- height: 1,
- backgroundColor: COLORS.BORDER.PRIMARY,
- width: '100%',
- marginBottom: 16,
- },
+ horizontalLine: {
+ height: 1,
+ backgroundColor: COLORS.BORDER.PRIMARY,
+ width: '100%',
+ marginBottom: 16,
+ },
});
export default EmiBreakupBottomSheet;
diff --git a/src/screens/emiSchedule/EmiScheduleItem.tsx b/src/screens/emiSchedule/EmiScheduleItem.tsx
index e3fe3dc7..94635f1e 100644
--- a/src/screens/emiSchedule/EmiScheduleItem.tsx
+++ b/src/screens/emiSchedule/EmiScheduleItem.tsx
@@ -13,140 +13,122 @@ import Tag from '../../../RN-UI-LIB/src/components/Tag';
import { formatAmount } from '../../../RN-UI-LIB/src/utlis/amount';
export interface IEmiItem {
- status: 'SCHEDULED' | 'PAID' | 'UNPAID' | 'CANCELLED';
- dueDate: string; //YYYY-MM-DD
- totalOverDueAmount: number;
- paidOnDate: string; //YYYY-MM-DD
- totalUnpaidPrincipal: number;
- totalUnpaidInterest: number;
- totalUnpaidPenalInterest: number;
- totalUnpaidLateFeeAmount: number;
- totalUnpaidBounceFeeAmount: number;
- totalUnpaidEmiPenaltyCharges: number;
- totalUnpaidOtherFees?: number;
+ status: 'SCHEDULED' | 'PAID' | 'UNPAID' | 'CANCELLED';
+ dueDate: string; //YYYY-MM-DD
+ totalOverDueAmount: number;
+ paidOnDate: string; //YYYY-MM-DD
+ totalUnpaidPrincipal: number;
+ totalUnpaidInterest: number;
+ totalUnpaidPenalInterest: number;
+ totalUnpaidLateFeeAmount: number;
+ totalUnpaidBounceFeeAmount: number;
+ totalUnpaidEmiPenaltyCharges: number;
+ totalUnpaidOtherFees?: number;
}
interface IEmiScheduleItem {
- listNumber: number;
- emiItem: IEmiItem;
- selectedTab: EmiSelectedTab;
+ listNumber: number;
+ emiItem: IEmiItem;
+ selectedTab: EmiSelectedTab;
}
-const EmiScheduleItem: React.FC = ({
- listNumber,
- emiItem,
- selectedTab,
-}) => {
- const [openBottomSheet, setOpenBottomSheet] = React.useState(false);
+const EmiScheduleItem: React.FC = ({ listNumber, emiItem, selectedTab }) => {
+ const [openBottomSheet, setOpenBottomSheet] = React.useState(false);
- return (
-
-
-
- {listNumber}
-
-
- EMI
-
-
-
-
-
- {formatAmount(emiItem?.totalOverDueAmount)}
-
-
- {dateFormat(
- new Date(emiItem.dueDate),
- BUSINESS_DATE_FORMAT,
- )}
-
-
-
- {emiItem.status === 'UNPAID' ? (
- <>
- {selectedTab === EmiSelectedTab.ALL ? (
-
- ) : (
-
-
-
+ return (
+
+
+
+ {listNumber}
+
+
+ EMI
+
+
+
+
+
+ {formatAmount(emiItem?.totalOverDueAmount)}
+
+ {dateFormat(new Date(emiItem.dueDate), BUSINESS_DATE_FORMAT)}
- );
+
+ {emiItem.status === 'UNPAID' ? (
+ <>
+ {selectedTab === EmiSelectedTab.ALL ? (
+
+ ) : (
+
+
+
+
+ );
};
const styles = StyleSheet.create({
- container: {
- borderWidth: 1,
- borderColor: COLORS.BORDER.PRIMARY,
- borderRadius: 4,
- marginBottom: 12,
- height: 68,
- flexDirection: 'row',
- alignContent: 'center',
- },
- leftContainer: {
- alignContent: 'center',
- justifyContent: 'center',
- backgroundColor: COLORS.BACKGROUND.SILVER,
- width: 43,
- },
+ container: {
+ borderWidth: 1,
+ borderColor: COLORS.BORDER.PRIMARY,
+ borderRadius: 4,
+ marginBottom: 12,
+ height: 68,
+ flexDirection: 'row',
+ alignContent: 'center',
+ },
+ leftContainer: {
+ alignContent: 'center',
+ justifyContent: 'center',
+ backgroundColor: COLORS.BACKGROUND.SILVER,
+ width: 43,
+ },
});
export default EmiScheduleItem;
diff --git a/src/screens/login/index.tsx b/src/screens/login/index.tsx
index abfb88ce..da300f07 100644
--- a/src/screens/login/index.tsx
+++ b/src/screens/login/index.tsx
@@ -2,6 +2,7 @@ import React, { useEffect } from 'react';
import { Controller, useForm } from 'react-hook-form';
import { SafeAreaView } from 'react-native-safe-area-context';
import { useSelector } from 'react-redux';
+import { StyleSheet, View } from 'react-native';
import Button from '../../../RN-UI-LIB/src/components/Button';
import Heading from '../../../RN-UI-LIB/src/components/Heading';
import Text from '../../../RN-UI-LIB/src/components/Text';
@@ -10,29 +11,39 @@ import { GenericStyles } from '../../../RN-UI-LIB/src/styles';
import NaviLogoIcon from '../../../RN-UI-LIB/src/Icons/NaviLogoIcon';
import {
generateOTP,
- GenerateOTPPayload,
+ type GenerateOTPPayload,
signInGoogle,
} from '../../action/authActions';
import { useAppDispatch } from '../../hooks';
-import { RootState } from '../../store/store';
+import { type RootState } from '../../store/store';
import { addClickstreamEvent } from '../../services/clickstreamEventService';
import { CLICKSTREAM_EVENT_NAMES } from '../../common/Constants';
-import { StyleSheet } from 'react-native';
import Layout from '../layout/Layout';
import { IS_SSO_ENABLED } from '../../constants/config';
+import { COLORS } from '../../../RN-UI-LIB/src/styles/colors';
+import GoogleIcon from '../../assets/icons/GoogleIcon';
interface ILoginForm {
phoneNumber: string;
}
-const Login = () => {
+function Login() {
const {
handleSubmit,
control,
getValues,
- formState: { errors, isValid },
+ formState: { isValid },
} = useForm();
+ const dispatch = useAppDispatch();
+ const { phoneNumber, OTPError, isLoading, deviceId } = useSelector((state: RootState) => ({
+ deviceId: state.user.deviceId,
+ phoneNumber: state.loginInfo.phoneNumber,
+ OTPError: state.loginInfo.OTPError,
+ isLoading: state.loginInfo.isLoading,
+ }));
+
+
useEffect(() => {
isValid &&
@@ -45,13 +56,8 @@ const Login = () => {
useEffect(() => {
addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.AV_LOGIN_SCREEN_LOAD);
-
}, []);
- const dispatch = useAppDispatch();
- const { phoneNumber, OTPError, isLoading } = useSelector(
- (state: RootState) => state.loginInfo,
- );
const handleGenerateOTP = (data: GenerateOTPPayload) => {
addClickstreamEvent(
@@ -64,17 +70,18 @@ const Login = () => {
dispatch(signInGoogle());
}
+
return (
- Login to Cosmos
+ Login to COSMOS
Use your registered mobile number
@@ -98,42 +105,77 @@ const Login = () => {
name="phoneNumber"
rules={{ required: true, minLength: 10, maxLength: 10 }}
/>
+
{IS_SSO_ENABLED ? <>
-
+
+
+
+ or
+
+
+
+
+