TP-61357: Introducing ReactNative | Insurance - Quote page experiments (#10199)
Co-authored-by: Shivam Goyal <shivam.goyal@navi.com>
This commit is contained in:
10
.github/workflows/android_build.yml
vendored
10
.github/workflows/android_build.yml
vendored
@@ -2,9 +2,9 @@ name: Android Build CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master, release-*, development ]
|
||||
branches: [ master, release-* ]
|
||||
pull_request:
|
||||
branches: [ master, release-*, development ]
|
||||
branches: [ master, release-* ]
|
||||
merge_group:
|
||||
|
||||
concurrency:
|
||||
@@ -20,7 +20,7 @@ jobs:
|
||||
output: APK
|
||||
|
||||
build-qa-release:
|
||||
if: github.event_name == 'push' && (github.ref_name == 'master' || startsWith(github.ref_name, 'release-'))
|
||||
if: github.event_name == 'push' && startsWith(github.ref_name, 'release-')
|
||||
uses: ./.github/workflows/generate_build.yml
|
||||
with:
|
||||
environment: qa
|
||||
@@ -28,7 +28,7 @@ jobs:
|
||||
output: APK
|
||||
|
||||
generate-apk-diff:
|
||||
if: github.event_name == 'pull_request' && github.base_ref == 'development'
|
||||
if: github.event_name == 'pull_request' && github.base_ref == 'master'
|
||||
uses: ./.github/workflows/generate_apk_diff.yml
|
||||
needs: build-qa-debug
|
||||
secrets:
|
||||
@@ -36,7 +36,7 @@ jobs:
|
||||
AWS_SECRET_KEY_GITHUB_CACHE: ${{ secrets.AWS_SECRET_KEY_GITHUB_CACHE }}
|
||||
|
||||
upload-apk-to-s3:
|
||||
if: github.event_name == 'push' && github.ref_name == 'development'
|
||||
if: github.event_name == 'push' && github.ref_name == 'master'
|
||||
uses: ./.github/workflows/upload_file.yml
|
||||
needs: build-qa-debug
|
||||
secrets:
|
||||
|
||||
10
.github/workflows/android_checkstyle.yml
vendored
10
.github/workflows/android_checkstyle.yml
vendored
@@ -2,7 +2,7 @@ name: Android Checkstyle CI
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches: [ master, release-*, development ]
|
||||
branches: [ master, release-* ]
|
||||
merge_group:
|
||||
|
||||
concurrency:
|
||||
@@ -18,8 +18,12 @@ jobs:
|
||||
steps:
|
||||
- name: Checkout Repository
|
||||
uses: actions/checkout@v4
|
||||
- name: Fetch origin/development
|
||||
run: git fetch origin development
|
||||
- name: Set up Node.js
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 18.18.0
|
||||
- name: Install Node Modules
|
||||
run: npm install
|
||||
- name: Set up JDK 17
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
|
||||
6
.github/workflows/generate_build.yml
vendored
6
.github/workflows/generate_build.yml
vendored
@@ -74,6 +74,12 @@ jobs:
|
||||
steps:
|
||||
- name: Checkout Repository
|
||||
uses: actions/checkout@v4
|
||||
- name: Set up Node.js
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 18.18.0
|
||||
- name: Install Node Modules
|
||||
run: npm install
|
||||
- name: Override Version Code
|
||||
if: github.event_name == 'workflow_dispatch' && inputs.version_code != ''
|
||||
run: sed -i 's/def VERSION_CODE = [0-9].*/def VERSION_CODE = ${{ inputs.version_code }}/g' app/build.gradle
|
||||
|
||||
6
.github/workflows/metrics_logger.yml
vendored
6
.github/workflows/metrics_logger.yml
vendored
@@ -25,6 +25,12 @@ jobs:
|
||||
steps:
|
||||
- name: Checkout Repository
|
||||
uses: actions/checkout@v4
|
||||
- name: Set up Node.js
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 18.18.0
|
||||
- name: Install Node Modules
|
||||
run: npm install
|
||||
- name: Log Build Metadata
|
||||
run: |
|
||||
echo "Commit SHA: ${{ github.sha }}"
|
||||
|
||||
@@ -3,7 +3,7 @@ name: Security API Diff Monitor
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- development
|
||||
- master
|
||||
types: [ opened, edited, synchronize, reopened ]
|
||||
merge_group:
|
||||
|
||||
|
||||
1
.github/workflows/semgrep.yml
vendored
1
.github/workflows/semgrep.yml
vendored
@@ -6,7 +6,6 @@ on:
|
||||
branches:
|
||||
- master
|
||||
- main
|
||||
- development
|
||||
- release-*
|
||||
schedule:
|
||||
- cron: '30 4 * * MON'
|
||||
|
||||
34
.github/workflows/validate_release_pr.yml
vendored
34
.github/workflows/validate_release_pr.yml
vendored
@@ -23,7 +23,7 @@ jobs:
|
||||
run: |
|
||||
echo "ORIGINAL_PR_NUMBER=$(echo "${{ github.event.pull_request.body }}" | grep -o "https://github.com/${{ github.repository }}/pull/[0-9]*" | grep -o "[0-9]*")" >> $GITHUB_ENV
|
||||
echo "CURRENT_PR_NUMBER=${{ github.event.pull_request.number }}" >> $GITHUB_ENV
|
||||
- name: Verification Step 1 - Link to development PR is added in release PR Body
|
||||
- name: Verification Step 1 - Link to master PR is added in release PR Body
|
||||
if: always()
|
||||
run: |
|
||||
ORIGINAL_PR_URL="https://github.com/${{ github.repository }}/pull/$ORIGINAL_PR_NUMBER"
|
||||
@@ -33,10 +33,10 @@ jobs:
|
||||
echo "Pull request body: ${{ github.event.pull_request.body }}"
|
||||
|
||||
if [[ "${{ github.event.pull_request.body }}" != *"$ORIGINAL_PR_URL"* ]]; then
|
||||
echo "Link to original PR raised against development branch not found in current PR body"
|
||||
echo "Link to original PR raised against master branch not found in current PR body"
|
||||
exit 1
|
||||
fi
|
||||
- name: Verification Step 2 - release PR Title matches development PR Title
|
||||
- name: Verification Step 2 - release PR Title matches master PR Title
|
||||
if: always()
|
||||
run: |
|
||||
ORIGINAL_PR_TITLE=$(curl -L -H "Authorization: Bearer ${{ secrets.GH_PAT_RO }}" "https://api.github.com/repos/${{ github.repository }}/pulls/$ORIGINAL_PR_NUMBER" | jq -r .title)
|
||||
@@ -46,53 +46,53 @@ jobs:
|
||||
echo "Current PR title extracted: ${{ github.event.pull_request.title }}"
|
||||
|
||||
if [[ "${{ github.event.pull_request.title }}" != "$ORIGINAL_PR_TITLE" ]]; then
|
||||
echo "Current PR title does not match original PR title raised against development branch"
|
||||
echo "Current PR title does not match original PR title raised against master branch"
|
||||
exit 1
|
||||
fi
|
||||
- name: Verification Step 3 - development PR is Merged
|
||||
- name: Verification Step 3 - master PR is Merged
|
||||
if: always()
|
||||
run: |
|
||||
ORIGINAL_PR_IS_MERGED=$(curl -L -H "Authorization: Bearer ${{ secrets.GH_PAT_RO }}" "https://api.github.com/repos/${{ github.repository }}/pulls/$ORIGINAL_PR_NUMBER" | jq -r '.merged')
|
||||
BASE_REF_BRANCH=$(curl -L -H "Authorization: Bearer ${{ secrets.GH_PAT_RO }}" "https://api.github.com/repos/${{ github.repository }}/pulls/$ORIGINAL_PR_NUMBER" | jq -r '.base.ref')
|
||||
|
||||
if [[ "$ORIGINAL_PR_IS_MERGED" == "true" && "$BASE_REF_BRANCH" == "development" ]]; then
|
||||
echo "Original PR is merged into development branch"
|
||||
if [[ "$ORIGINAL_PR_IS_MERGED" == "true" && "$BASE_REF_BRANCH" == "master" ]]; then
|
||||
echo "Original PR is merged into master branch"
|
||||
else
|
||||
echo "Original PR number: $ORIGINAL_PR_NUMBER"
|
||||
echo "Original PR merge status: $ORIGINAL_PR_IS_MERGED"
|
||||
echo "Base branch: $BASE_REF_BRANCH"
|
||||
echo "Status: Fail. Original PR is not merged in development branch."
|
||||
echo "Status: Fail. Original PR is not merged in master branch."
|
||||
exit 1
|
||||
fi
|
||||
- name: Verification Step 4 - release PR is exactly same as development PR
|
||||
- name: Verification Step 4 - release PR is exactly same as master PR
|
||||
if: always()
|
||||
run: |
|
||||
# Get the JSON response for the first pull request
|
||||
response_pr_development=$(curl -L -H "Authorization: Bearer ${{ secrets.GH_PAT_RO }}" "https://api.github.com/repos/${{ github.repository }}/pulls/$ORIGINAL_PR_NUMBER/files")
|
||||
files_pr_development=$(echo "$response_pr_development" | jq -r '.[].filename')
|
||||
response_pr_master=$(curl -L -H "Authorization: Bearer ${{ secrets.GH_PAT_RO }}" "https://api.github.com/repos/${{ github.repository }}/pulls/$ORIGINAL_PR_NUMBER/files")
|
||||
files_pr_master=$(echo "$response_pr_master" | jq -r '.[].filename')
|
||||
|
||||
# Get the JSON response for the second pull request
|
||||
response_pr_release=$(curl -L -H "Authorization: Bearer ${{ secrets.GH_PAT_RO }}" "https://api.github.com/repos/${{ github.repository }}/pulls/$CURRENT_PR_NUMBER/files")
|
||||
files_pr_release=$(echo "$response_pr_release" | jq -r '.[].filename')
|
||||
|
||||
# Compare the lists of changed files
|
||||
if [ "$files_pr_development" != "$files_pr_release" ]; then
|
||||
if [ "$files_pr_master" != "$files_pr_release" ]; then
|
||||
echo "Pull requests have different sets of changed files."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Loop through each file and compare added and deleted lines
|
||||
for file in $details_pr_development; do
|
||||
details_pr_development=($(echo "$response_pr_development" | jq -r --arg file "$file" '.[] | select(.filename == $file) | .additions, .deletions'))
|
||||
for file in $details_pr_master; do
|
||||
details_pr_master=($(echo "$response_pr_master" | jq -r --arg file "$file" '.[] | select(.filename == $file) | .additions, .deletions'))
|
||||
details_pr_release=($(echo "$response_pr_release" | jq -r --arg file "$file" '.[] | select(.filename == $file) | .additions, .deletions'))
|
||||
|
||||
added_lines_pr_development="${details_pr_development[0]}"
|
||||
deleted_lines_pr_development="${details_pr_development[1]}"
|
||||
added_lines_pr_master="${details_pr_master[0]}"
|
||||
deleted_lines_pr_master="${details_pr_master[1]}"
|
||||
|
||||
added_lines_pr_release="${details_pr_release[0]}"
|
||||
deleted_lines_pr_release="${details_pr_release[1]}"
|
||||
|
||||
if [ "$added_lines_pr_development" != "$added_lines_pr_release" ] || [ "$deleted_lines_pr_development" != "$deleted_lines_pr_release" ]; then
|
||||
if [ "$added_lines_pr_master" != "$added_lines_pr_release" ] || [ "$deleted_lines_pr_master" != "$deleted_lines_pr_release" ]; then
|
||||
echo "File $file has different added or deleted lines in the two pull requests."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
5
.gitignore
vendored
5
.gitignore
vendored
@@ -23,3 +23,8 @@ local.env
|
||||
# Local build cache
|
||||
build-cache
|
||||
api-credentials.json
|
||||
node_modules/*/android/build/*
|
||||
node_modules
|
||||
config.js
|
||||
android/navi-base/.cxx/*
|
||||
android/npci-upi-cl/build/*
|
||||
57
App.tsx
Normal file
57
App.tsx
Normal file
@@ -0,0 +1,57 @@
|
||||
import { Component } from "react";
|
||||
import codePush from "react-native-code-push";
|
||||
import { CtaData } from "./App/common/interface";
|
||||
import RnApp from "./App/common/navigator/RnAppCreator";
|
||||
import { getBuildConfigDetails, setBuildConfigDetails } from "./App/common/utilities/CacheUtils";
|
||||
import { logToSentry } from "./App/common/hooks/useSentryLogging";
|
||||
|
||||
export default class App extends Component<{}> {
|
||||
checkForUpdates = () => {
|
||||
let flavor: string | undefined
|
||||
getBuildConfigDetails().then((res) => {
|
||||
flavor = res?.baseUrl
|
||||
})
|
||||
codePush.sync({
|
||||
updateDialog: flavor && flavor === "QA" ? {appendReleaseDescription: true} : {appendReleaseDescription: false},
|
||||
installMode: codePush.InstallMode.IMMEDIATE,
|
||||
mandatoryInstallMode: codePush.InstallMode.IMMEDIATE,
|
||||
});
|
||||
};
|
||||
|
||||
getInitialCta = (): CtaData | undefined => {
|
||||
const { CtaData } = this.props as any;
|
||||
|
||||
if (!CtaData) {
|
||||
logToSentry(
|
||||
`CtaData is missing or invalid: ${CtaData} | MethodName: getInitialCta`
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const cta = JSON.parse(CtaData) as CtaData;
|
||||
return cta;
|
||||
} catch (error) {
|
||||
logToSentry(
|
||||
`Error parsing CtaData: ${CtaData} | Error: ${error} | MethodName: getInitialCta`
|
||||
);
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
override componentDidMount(): void {
|
||||
setBuildConfigDetails()
|
||||
this.checkForUpdates();
|
||||
}
|
||||
|
||||
override render() {
|
||||
const cta = this.getInitialCta();
|
||||
if (!!cta) {
|
||||
return RnApp.create(cta);
|
||||
} else {
|
||||
// return error screen
|
||||
}
|
||||
}
|
||||
}
|
||||
//return RnNavigator.navigate(screenBundle);
|
||||
28
App/Container/Navi-Insurance/Styles/index.ts
Normal file
28
App/Container/Navi-Insurance/Styles/index.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
import { StyleSheet } from "react-native";
|
||||
|
||||
export const commonStyles = StyleSheet.create({
|
||||
container: {
|
||||
backgroundColor: "red",
|
||||
},
|
||||
fullscreencenter: {
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
flex: 1,
|
||||
},
|
||||
flex_1: {
|
||||
flex: 1,
|
||||
},
|
||||
verticalSpacer32: {
|
||||
height: 32,
|
||||
},
|
||||
selfAlignCenter: {
|
||||
alignSelf: "center",
|
||||
},
|
||||
contentAlignLeft: {
|
||||
flexDirection: "column",
|
||||
alignItems: "flex-start",
|
||||
},
|
||||
height54: {
|
||||
height: 54,
|
||||
},
|
||||
});
|
||||
9
App/Container/Navi-Insurance/index.ts
Normal file
9
App/Container/Navi-Insurance/index.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import IntroScreen from "./screen/IntroScreen";
|
||||
import InsuranceLandingPageScreen from "./screen/InsuranceLandingPageScreen";
|
||||
import QuoteOfferScreen from "./screen/quote-offer-screen/QuoteOfferScreen";
|
||||
|
||||
export {
|
||||
IntroScreen,
|
||||
InsuranceLandingPageScreen,
|
||||
QuoteOfferScreen,
|
||||
};
|
||||
13
App/Container/Navi-Insurance/network/QuotePageApi.ts
Normal file
13
App/Container/Navi-Insurance/network/QuotePageApi.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import { getXTargetHeaderInfo } from "../../../../network/ApiClient";
|
||||
import { get, post, patch } from "../../../../network/NetworkService";
|
||||
import { GI } from "../../../common/constants/NavigationHandlerConstants";
|
||||
import { ScreenData } from "../../../common/interface/widgets/screenData/ScreenData";
|
||||
|
||||
export interface SumInsuredRequestData {
|
||||
sumInsured: string;
|
||||
}
|
||||
|
||||
export const updateSumInsuredData = async (data: SumInsuredRequestData, quoteId: string) => {
|
||||
const url = `v3/quotes/${quoteId}`;
|
||||
return patch<ApiResponse<ScreenData>>(url, data, getXTargetHeaderInfo(GI.toLocaleUpperCase()));
|
||||
};
|
||||
@@ -0,0 +1,147 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import {
|
||||
Animated,
|
||||
NativeScrollEvent,
|
||||
NativeSyntheticEvent,
|
||||
ScrollView,
|
||||
View,
|
||||
StyleSheet
|
||||
} from "react-native";
|
||||
import {
|
||||
BaseActionTypes,
|
||||
GenericActionPayload,
|
||||
} from "../../../common/actions/GenericAction";
|
||||
import { CtaData, CtaType } from "../../../common/interface";
|
||||
import { Widget } from "../../../common/interface/widgets/Widget";
|
||||
import { ScreenData } from "../../../common/interface/widgets/screenData/ScreenData";
|
||||
import { NativeDeeplinkNavigatorModule } from "../../../common/native-module/NativeModules";
|
||||
import Colors from "../../../../assets/colors/colors";
|
||||
import BaseWidget from "../../../../components/widgets/BaseWidget";
|
||||
import { ScreenActionTypes } from "../../../common/screen/ScreenActionTypes";
|
||||
|
||||
const InsuranceLandingPageScreen = ({
|
||||
ctaData,
|
||||
screenData,
|
||||
handleActions,
|
||||
}: {
|
||||
ctaData: CtaData;
|
||||
screenData: ScreenData | null;
|
||||
handleActions: (screenPayload?: GenericActionPayload) => void;
|
||||
}) => {
|
||||
const [scrollY, setScrollY] = useState(0);
|
||||
|
||||
const handleScroll = (event: NativeSyntheticEvent<NativeScrollEvent>) => {
|
||||
setScrollY(event.nativeEvent.contentOffset.y);
|
||||
};
|
||||
|
||||
const headerBackgroundColor =
|
||||
scrollY > 84 ? Colors.aliceBlue : Colors.transparent;
|
||||
|
||||
const handleClick = (cta?: CtaData) => {
|
||||
if (!cta) return; // Handle case when cta is undefined or null
|
||||
|
||||
try {
|
||||
switch (cta.type) {
|
||||
case CtaType.DEEP_LINK:
|
||||
case CtaType.USE_ROOT_DEEPLINK_NAVIGATOR:
|
||||
NativeDeeplinkNavigatorModule.navigateToNaviInsuranceDeeplinkNavigator(
|
||||
JSON.stringify(cta)
|
||||
);
|
||||
break;
|
||||
default:
|
||||
NativeDeeplinkNavigatorModule.navigateToNaviDeeplinkNavigator(
|
||||
JSON.stringify(cta)
|
||||
);
|
||||
break;
|
||||
}
|
||||
} catch (error) {
|
||||
// #TODO: Handle the error gracefully using Sentry.
|
||||
console.error("Error while navigating to deep link:", error);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
handleActions({
|
||||
baseActionType: BaseActionTypes.SCREEN_ACTION,
|
||||
metaData: [
|
||||
{
|
||||
actionType: ScreenActionTypes.FETCH_INSURANCE_QUOTE_PAGE_FROM_BACKEND,
|
||||
},
|
||||
],
|
||||
});
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<View style={[styles.container, screenData?.screenStyle]}>
|
||||
<Animated.View
|
||||
style={[styles.header, { backgroundColor: headerBackgroundColor }]}
|
||||
>
|
||||
{getWidgetViews(
|
||||
screenData?.screenWidgets?.headerWidgets,
|
||||
handleActions,
|
||||
handleClick
|
||||
)}
|
||||
</Animated.View>
|
||||
<ScrollView
|
||||
contentContainerStyle={styles.content}
|
||||
scrollEventThrottle={16}
|
||||
onScroll={handleScroll}
|
||||
>
|
||||
{getWidgetViews(
|
||||
screenData?.screenWidgets?.contentWidgets,
|
||||
handleActions,
|
||||
handleClick
|
||||
)}
|
||||
</ScrollView>
|
||||
<View style={styles.footer}>
|
||||
{getWidgetViews(
|
||||
screenData?.screenWidgets?.footerWidgets,
|
||||
handleActions,
|
||||
handleClick
|
||||
)}
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
function getWidgetViews(
|
||||
widgetList: Widget[] | undefined,
|
||||
handleActions: (screenActionPayload?: GenericActionPayload) => void,
|
||||
handleClick?: (ctaData: CtaData) => void
|
||||
): React.JSX.Element {
|
||||
return (
|
||||
<View>
|
||||
{widgetList?.map((widget, index) => {
|
||||
return (
|
||||
<BaseWidget
|
||||
widget={widget}
|
||||
handleScreenActions={handleActions}
|
||||
widgetIndex={index}
|
||||
key={index}
|
||||
handleClick={handleClick}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
flexDirection: "column",
|
||||
},
|
||||
header: {
|
||||
alignItems: "stretch",
|
||||
position: "absolute",
|
||||
zIndex: 1,
|
||||
},
|
||||
content: {
|
||||
flexGrow: 1
|
||||
},
|
||||
footer: {
|
||||
alignItems: "stretch"
|
||||
},
|
||||
});
|
||||
|
||||
export default InsuranceLandingPageScreen;
|
||||
22
App/Container/Navi-Insurance/screen/IntroScreen.tsx
Normal file
22
App/Container/Navi-Insurance/screen/IntroScreen.tsx
Normal file
@@ -0,0 +1,22 @@
|
||||
import React, { useEffect } from "react";
|
||||
import { Text, View } from "react-native";
|
||||
import { getApplicationId } from "../../../../network/repo/GiApplicationRepo";
|
||||
import { CtaData } from "../../../common/interface";
|
||||
|
||||
const IntroScreen: React.FC<{ ctaData: CtaData }> = ({ ctaData }) => {
|
||||
useEffect(() => {
|
||||
getApplicationId().then(
|
||||
(result) =>
|
||||
// console.log("klogs",result.data)
|
||||
result.data
|
||||
);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<View>
|
||||
<Text>hello</Text>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
export default IntroScreen;
|
||||
274
App/Container/Navi-Insurance/screen/MemberDetailsScreen.tsx
Normal file
274
App/Container/Navi-Insurance/screen/MemberDetailsScreen.tsx
Normal file
@@ -0,0 +1,274 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import {
|
||||
View,
|
||||
Text,
|
||||
StyleSheet,
|
||||
Dimensions,
|
||||
ScrollView,
|
||||
Pressable,
|
||||
ToastAndroid,
|
||||
} from "react-native";
|
||||
import { CtaData } from "../../../common/interface";
|
||||
import {
|
||||
fillApplication,
|
||||
getApplicationId,
|
||||
} from "../../../../network/repo/GiApplicationRepo";
|
||||
import { GetWidgetView } from "../../../common/widgets/widgetResolver";
|
||||
import { CtaNavigator } from "../../../common/navigator/NavigationRouter";
|
||||
import { MemberDetailsRootObject } from "../../../common/interface/MemberDetailsResponse";
|
||||
|
||||
const { width } = Dimensions.get("window");
|
||||
|
||||
const MemberDetailScreen: React.FC<{ ctaData: CtaData }> = ({ ctaData }) => {
|
||||
const [screenData, setScreenData] = useState<
|
||||
MemberDetailsRootObject | undefined
|
||||
>();
|
||||
const [dataFromChild, setDataFromChild] = useState([]);
|
||||
const [isDataValid, setIsDataValid] = useState(true);
|
||||
|
||||
useEffect(() => {
|
||||
getApplicationId().then((result) => {
|
||||
setScreenData(result.data);
|
||||
});
|
||||
}, []);
|
||||
|
||||
const sendDataToBackend = () => {
|
||||
const widgetList =
|
||||
screenData?.currentScreenDefinition?.screenData?.screenStructure?.content
|
||||
?.widgets;
|
||||
if (
|
||||
isDataValid === true &&
|
||||
widgetList &&
|
||||
dataFromChild.length == (widgetList.length - 1) * 2
|
||||
) {
|
||||
fillApplication(
|
||||
screenData?.applicationResponse?.applicationId || "",
|
||||
dataFromChild
|
||||
).then((fillApplicationResponse) => {
|
||||
const cta: CtaData = {
|
||||
url: "react/member_selection",
|
||||
};
|
||||
CtaNavigator.navigate(cta);
|
||||
});
|
||||
} else {
|
||||
ToastAndroid.show("Please fill all data", ToastAndroid.SHORT);
|
||||
}
|
||||
};
|
||||
|
||||
const checkValidity = (updatedData: any[]) => {
|
||||
let isValid = true;
|
||||
updatedData.map((item) => {
|
||||
if (
|
||||
item.value === undefined ||
|
||||
item.value === null ||
|
||||
item.value === ""
|
||||
) {
|
||||
isValid = false;
|
||||
}
|
||||
});
|
||||
setIsDataValid(isValid);
|
||||
};
|
||||
|
||||
// Callback function to receive data from the child component
|
||||
const handleDataFromChild = (index: number, data: any) => {
|
||||
let updatedData: any[] = [...dataFromChild];
|
||||
let isPresent = false;
|
||||
updatedData.map((oldData) => {
|
||||
// if the key is present replace existing.
|
||||
if (oldData.key === data.key) {
|
||||
isPresent = true;
|
||||
oldData.value = data.value;
|
||||
if (
|
||||
oldData.value === undefined ||
|
||||
oldData.value === null ||
|
||||
oldData.value === ""
|
||||
) {
|
||||
setIsDataValid(false);
|
||||
} else {
|
||||
checkValidity(updatedData);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (!isPresent) {
|
||||
updatedData = [...updatedData, data];
|
||||
}
|
||||
|
||||
console.log(updatedData);
|
||||
|
||||
// updatedData[index] = data;
|
||||
setDataFromChild(updatedData);
|
||||
console.log();
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
console.log("HLOGS", screenData);
|
||||
}, [screenData]);
|
||||
|
||||
const getScreenContent = () => {
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<InsuranceHeaderSection
|
||||
cardList={null}
|
||||
setCardList={null}
|
||||
itemRemovedCount={null}
|
||||
setItemRemovedCount={null}
|
||||
db={null}
|
||||
/>
|
||||
{/* Content */}
|
||||
<ScrollView
|
||||
style={styles.content}
|
||||
contentContainerStyle={{
|
||||
flexGrow: 1,
|
||||
}}
|
||||
keyboardShouldPersistTaps="handled"
|
||||
>
|
||||
{screenData?.currentScreenDefinition?.screenData?.screenStructure?.content?.widgets.map(
|
||||
(widget: Widget, index: number) => {
|
||||
//setDataFromChild((prevData) => [...prevData, {}])
|
||||
return GetWidgetView.getWidget(
|
||||
widget,
|
||||
handleDataFromChild,
|
||||
index - 1
|
||||
);
|
||||
}
|
||||
)}
|
||||
</ScrollView>
|
||||
|
||||
{/* Footer */}
|
||||
{/* Green Tag */}
|
||||
<View style={styles.greenTag}>
|
||||
<Text style={styles.greenTagText}>
|
||||
{
|
||||
screenData?.currentScreenDefinition?.screenData?.screenStructure
|
||||
?.footer?.widgetData?.banner?.text
|
||||
}
|
||||
</Text>
|
||||
</View>
|
||||
<View style={styles.footer}>
|
||||
<View style={styles.infoContainer}>
|
||||
<Text style={styles.infoTopText}>
|
||||
{
|
||||
screenData?.currentScreenDefinition?.screenData?.screenStructure
|
||||
?.footer?.widgetData?.leftTopUnstrikedText?.text
|
||||
}{" "}
|
||||
<Text style={styles.strikeOffText}>
|
||||
{
|
||||
screenData?.currentScreenDefinition?.screenData
|
||||
?.screenStructure?.footer?.widgetData?.leftTopStrikedText
|
||||
?.text
|
||||
}
|
||||
</Text>
|
||||
<Text style={styles.strikeOffSubText}></Text>
|
||||
</Text>
|
||||
<Text style={styles.infoBottomText}>
|
||||
{
|
||||
screenData?.currentScreenDefinition?.screenData?.screenStructure
|
||||
?.footer?.widgetData?.leftBottomText?.text
|
||||
}{" "}
|
||||
>
|
||||
</Text>
|
||||
</View>
|
||||
<Pressable
|
||||
android_ripple={{ color: "gray", borderless: false }}
|
||||
style={styles.buttonContainer}
|
||||
onPress={() => sendDataToBackend()}
|
||||
>
|
||||
<Text style={styles.buttonText}>
|
||||
{
|
||||
screenData?.currentScreenDefinition?.screenData?.screenStructure
|
||||
?.footer?.widgetData?.rightCta?.title?.text
|
||||
}
|
||||
</Text>
|
||||
</Pressable>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
return <View style={styles.container}>{getScreenContent()}</View>;
|
||||
};
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
backgroundColor: "#FAFAFA",
|
||||
},
|
||||
content: {
|
||||
flex: 1,
|
||||
paddingVertical: 20,
|
||||
},
|
||||
footer: {
|
||||
elevation: 10,
|
||||
backgroundColor: "#FFFFFF",
|
||||
paddingHorizontal: 16,
|
||||
paddingBottom: 32,
|
||||
paddingTop: 20,
|
||||
flexDirection: "row",
|
||||
justifyContent: "space-between",
|
||||
alignItems: "center",
|
||||
},
|
||||
infoContainer: {
|
||||
flexDirection: "column",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
},
|
||||
infoTopText: {
|
||||
fontSize: 18,
|
||||
fontWeight: "500",
|
||||
color: "#191919",
|
||||
alignSelf: "flex-start",
|
||||
},
|
||||
strikeOffText: {
|
||||
fontSize: 14,
|
||||
fontWeight: "500",
|
||||
color: "#6B6B6B",
|
||||
alignSelf: "flex-start",
|
||||
textDecorationLine: "line-through",
|
||||
},
|
||||
strikeOffSubText: {
|
||||
fontSize: 14,
|
||||
fontWeight: "500",
|
||||
color: "#6B6B6B",
|
||||
alignSelf: "flex-start",
|
||||
textDecorationLine: "line-through",
|
||||
},
|
||||
infoBottomText: {
|
||||
fontSize: 12,
|
||||
fontWeight: "bold",
|
||||
color: "#1f002a",
|
||||
marginTop: 4,
|
||||
},
|
||||
buttonContainer: {
|
||||
backgroundColor: "#1F002A",
|
||||
height: 48,
|
||||
width: 148,
|
||||
borderRadius: 4,
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
},
|
||||
buttonText: {
|
||||
color: "white",
|
||||
fontWeight: "bold",
|
||||
},
|
||||
greenTag: {
|
||||
elevation: 10,
|
||||
backgroundColor: "#E7F8EE",
|
||||
width: width,
|
||||
height: 32,
|
||||
justifyContent: "center",
|
||||
paddingLeft: 16,
|
||||
borderTopLeftRadius: 16,
|
||||
borderTopRightRadius: 16,
|
||||
borderBottomLeftRadius: 0,
|
||||
borderBottomRightRadius: 0,
|
||||
},
|
||||
greenTagText: {
|
||||
fontSize: 12,
|
||||
color: "#22A940",
|
||||
textAlign: "center",
|
||||
fontWeight: "bold",
|
||||
},
|
||||
});
|
||||
|
||||
export default MemberDetailScreen;
|
||||
@@ -0,0 +1,78 @@
|
||||
import { TouchableOpacity, View, Text } from "react-native";
|
||||
import { GenericActionPayload } from "../../../../common/actions/GenericAction";
|
||||
import { CtaData, CtaType } from "../../../../common/interface";
|
||||
import { ScreenData } from "../../../../common/interface/widgets/screenData/ScreenData";
|
||||
import { AppImage } from "../../../../../components/AppImage";
|
||||
import {
|
||||
ImageName,
|
||||
QUOTE_APOLOGY_BUTTON,
|
||||
QUOTE_APOLOGY_SUBTITLE,
|
||||
QUOTE_APOLOGY_TITLE,
|
||||
} from "../../../../common/constants/StringConstant";
|
||||
import { NativeDeeplinkNavigatorModule } from "../../../../common/native-module/NativeModules";
|
||||
import { styles } from "./QuoteApologyScreenStyle";
|
||||
import { StaticHeader } from "../../../../../components/reusable/static-header/StaticHeader";
|
||||
import { ConstantCta } from "../../../../common/constants/CtaConstants";
|
||||
|
||||
const QuoteApologyScreen = ({
|
||||
ctaData,
|
||||
screenData,
|
||||
handleActions,
|
||||
}: {
|
||||
ctaData: CtaData;
|
||||
screenData: ScreenData | null;
|
||||
handleActions: (screenPayload?: GenericActionPayload) => void;
|
||||
}) => {
|
||||
const handleClick = (cta?: CtaData) => {
|
||||
if (!cta) return; // Handle case when cta is undefined or null
|
||||
|
||||
try {
|
||||
switch (cta.type) {
|
||||
case CtaType.DEEP_LINK:
|
||||
case CtaType.USE_ROOT_DEEPLINK_NAVIGATOR:
|
||||
NativeDeeplinkNavigatorModule.navigateToNaviInsuranceDeeplinkNavigator(
|
||||
JSON.stringify(cta)
|
||||
);
|
||||
break;
|
||||
default:
|
||||
NativeDeeplinkNavigatorModule.navigateToNaviDeeplinkNavigator(
|
||||
JSON.stringify(cta)
|
||||
);
|
||||
break;
|
||||
}
|
||||
} catch (error) {
|
||||
// #TODO: Handle the error gracefully using Sentry.
|
||||
console.error("Error while navigating to deep link:", error);
|
||||
}
|
||||
};
|
||||
const onPress = () => {
|
||||
handleClick && handleClick(ConstantCta.QUOTE_APOLOGY_FOOTER_BUTTON);
|
||||
};
|
||||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<View>
|
||||
<StaticHeader
|
||||
handleClick={handleClick}
|
||||
leftIconCta={ConstantCta.STATIC_HEADER_LEFT_ICON_CTA}
|
||||
rightIconCta={ConstantCta.STATIC_HEADER_RIGHT_ICON_CTA}
|
||||
/>
|
||||
<View style={styles.headerBorder} />
|
||||
</View>
|
||||
<View style={styles.centerContent}>
|
||||
{AppImage(ImageName.QUOTE_APOLOGY_ICON, styles.centerIcon)}
|
||||
<Text style={styles.title}>{QUOTE_APOLOGY_TITLE}</Text>
|
||||
<Text style={styles.subtitle}>{QUOTE_APOLOGY_SUBTITLE}</Text>
|
||||
</View>
|
||||
<TouchableOpacity
|
||||
onPress={onPress}
|
||||
style={styles.footerButton}
|
||||
activeOpacity={1}
|
||||
>
|
||||
<Text style={styles.buttonText}>{QUOTE_APOLOGY_BUTTON}</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
export default QuoteApologyScreen;
|
||||
@@ -0,0 +1,55 @@
|
||||
import { StyleSheet } from "react-native";
|
||||
|
||||
export const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
justifyContent: "space-between",
|
||||
backgroundColor: "white",
|
||||
},
|
||||
centerContent: {
|
||||
justifyContent: "center",
|
||||
alignItems: "center"
|
||||
},
|
||||
headerBorder: {
|
||||
width: "100%",
|
||||
height: 1,
|
||||
backgroundColor: "#F0F0F0"
|
||||
},
|
||||
centerIcon: {
|
||||
width: 225,
|
||||
height: 225
|
||||
},
|
||||
title: {
|
||||
fontSize: 16,
|
||||
lineHeight: 22,
|
||||
fontFamily: "tt_medium",
|
||||
color: "#191919",
|
||||
textAlign: "center",
|
||||
marginTop: 16,
|
||||
marginHorizontal: 20
|
||||
},
|
||||
subtitle: {
|
||||
fontSize: 14,
|
||||
lineHeight: 22,
|
||||
fontFamily: "tt_regular",
|
||||
color: "#4D4D4D",
|
||||
textAlign: "center",
|
||||
marginTop: 16,
|
||||
marginHorizontal: 20
|
||||
},
|
||||
footerButton: {
|
||||
padding: 16,
|
||||
marginHorizontal: 16,
|
||||
marginVertical: 16,
|
||||
backgroundColor: "#1F002A",
|
||||
borderRadius: 4,
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
},
|
||||
buttonText: {
|
||||
color: "white",
|
||||
fontSize: 14,
|
||||
lineHeight: 22,
|
||||
fontFamily: "tt_medium",
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,268 @@
|
||||
import React, { useEffect } from "react";
|
||||
import {
|
||||
NativeEventEmitter,
|
||||
NativeScrollEvent,
|
||||
NativeSyntheticEvent,
|
||||
StatusBar,
|
||||
View,
|
||||
} from "react-native";
|
||||
import Animated, {
|
||||
useAnimatedStyle,
|
||||
useSharedValue,
|
||||
} from "react-native-reanimated";
|
||||
import Colors from "../../../../../assets/colors/colors";
|
||||
import BaseWidget from "../../../../../components/widgets/BaseWidget";
|
||||
import {
|
||||
BaseActionTypes,
|
||||
GenericActionPayload,
|
||||
} from "../../../../common/actions/GenericAction";
|
||||
import {
|
||||
HI_RN_QUOTE_PAGE_ERROR_VIEW,
|
||||
HI_RN_QUOTE_PAGE_INIT,
|
||||
} from "../../../../common/constants/AnalyticsEventsConstant";
|
||||
import { NativeEventNameConstants } from "../../../../common/constants/EventNameConstants";
|
||||
import {
|
||||
HEADER_LOTTIE_TITLE_HEIGHT,
|
||||
HEADER_LOTTIE_WIDGET_HEIGHT,
|
||||
} from "../../../../common/constants/NumericalConstants";
|
||||
import { sendAsAnalyticsEvent } from "../../../../common/hooks/useAnalyticsEvent";
|
||||
import { AnalyticsEvent, CtaData, CtaType } from "../../../../common/interface";
|
||||
import { Widget } from "../../../../common/interface/widgets/Widget";
|
||||
import { ScreenData } from "../../../../common/interface/widgets/screenData/ScreenData";
|
||||
import { NativeDeeplinkNavigatorModule } from "../../../../common/native-module/NativeModules";
|
||||
import { ScreenState } from "../../../../common/screen/BaseScreen";
|
||||
import { ScreenActionTypes } from "../../../../common/screen/ScreenActionTypes";
|
||||
import styles from "./QuoteOfferScreenStyle";
|
||||
import QuoteOfferErrorScreen from "./error-screen/QuoteOfferErrorScreen";
|
||||
import QuoteOfferShimmerScreen from "./shimmer-screen/QuoteOfferShimmerScreen";
|
||||
import { logToSentry } from "../../../../common/hooks/useSentryLogging";
|
||||
|
||||
const QuoteOfferScreen = ({
|
||||
ctaData,
|
||||
screenData,
|
||||
handleActions,
|
||||
}: {
|
||||
ctaData: CtaData;
|
||||
screenData: ScreenData | null;
|
||||
handleActions: (screenPayload?: GenericActionPayload) => void;
|
||||
}) => {
|
||||
const y = useSharedValue(0);
|
||||
// TODO: check and remove below code if it is working fine in release.
|
||||
// const onScroll = useAnimatedScrollHandler({
|
||||
// onScroll: (event) => {
|
||||
// y.value = event.contentOffset.y;
|
||||
// },
|
||||
// });
|
||||
|
||||
const onScroll = (event: NativeSyntheticEvent<NativeScrollEvent>) => {
|
||||
y.value = event.nativeEvent.contentOffset.y;
|
||||
};
|
||||
|
||||
const headerBgStyle = useAnimatedStyle(() => {
|
||||
return {
|
||||
backgroundColor:
|
||||
y.value > HEADER_LOTTIE_WIDGET_HEIGHT
|
||||
? Colors.grey
|
||||
: y.value > HEADER_LOTTIE_TITLE_HEIGHT
|
||||
? Colors.aliceBlue
|
||||
: Colors.transparent,
|
||||
};
|
||||
});
|
||||
|
||||
const screenOverlayStyle =
|
||||
screenData?.screenState === ScreenState.OVERLAY
|
||||
? { opacity: 1 }
|
||||
: { opacity: 1 };
|
||||
|
||||
let preQuoteId: string | undefined | null = undefined;
|
||||
let quoteId: string | undefined | null = undefined;
|
||||
ctaData?.parameters?.forEach((item) => {
|
||||
if (item.key === "preQuoteId") {
|
||||
preQuoteId = item.value;
|
||||
}
|
||||
if (item.key === "quoteId") {
|
||||
quoteId = item.value;
|
||||
}
|
||||
});
|
||||
|
||||
const handleClick = (cta?: CtaData) => {
|
||||
if (!cta) {
|
||||
logToSentry(
|
||||
`Navigation cta is missing or invalid: ${cta} | MethodName: handleClick}`
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
switch (cta.type) {
|
||||
case CtaType.DEEP_LINK:
|
||||
case CtaType.USE_ROOT_DEEPLINK_NAVIGATOR:
|
||||
NativeDeeplinkNavigatorModule.navigateToNaviInsuranceDeeplinkNavigator(
|
||||
JSON.stringify(cta)
|
||||
);
|
||||
break;
|
||||
default:
|
||||
NativeDeeplinkNavigatorModule.navigateToNaviDeeplinkNavigator(
|
||||
JSON.stringify(cta)
|
||||
);
|
||||
break;
|
||||
}
|
||||
} catch (error) {
|
||||
logToSentry(
|
||||
`Error while navigating to deep link with CTA: ${cta} | MethodName: handleClick}`
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const screenActionType = preQuoteId
|
||||
? ScreenActionTypes.FETCH_QUOTE_V3
|
||||
: ScreenActionTypes.FETCH_INSURANCE_QUOTE_PAGE_FROM_BACKEND;
|
||||
const data: QuoteOfferRequest = {
|
||||
preQuoteId: preQuoteId ? preQuoteId : undefined,
|
||||
quoteId: quoteId ? quoteId : undefined,
|
||||
};
|
||||
const nativeEventListener = new NativeEventEmitter();
|
||||
let reloadPageEventListener = nativeEventListener.addListener(
|
||||
NativeEventNameConstants.reloadPage,
|
||||
(event) => {
|
||||
if (event === true) {
|
||||
handleActions({
|
||||
baseActionType: BaseActionTypes.SCREEN_ACTION,
|
||||
metaData: [
|
||||
{
|
||||
actionType: screenActionType,
|
||||
data: data,
|
||||
},
|
||||
],
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
handleActions({
|
||||
baseActionType: BaseActionTypes.SCREEN_ACTION,
|
||||
metaData: [
|
||||
{
|
||||
actionType: screenActionType,
|
||||
data: data,
|
||||
},
|
||||
],
|
||||
});
|
||||
return () => {
|
||||
nativeEventListener.removeAllListeners(
|
||||
NativeEventNameConstants.reloadPage
|
||||
);
|
||||
};
|
||||
}, [ctaData, preQuoteId, quoteId]);
|
||||
|
||||
useEffect(() => {
|
||||
switch (screenData?.screenState) {
|
||||
case ScreenState.LOADED:
|
||||
const initEvent: AnalyticsEvent = {
|
||||
name: HI_RN_QUOTE_PAGE_INIT,
|
||||
};
|
||||
sendAsAnalyticsEvent(initEvent);
|
||||
break;
|
||||
case ScreenState.ERROR:
|
||||
const errorEvent: AnalyticsEvent = {
|
||||
name: HI_RN_QUOTE_PAGE_ERROR_VIEW,
|
||||
};
|
||||
sendAsAnalyticsEvent(errorEvent);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}, [screenData?.screenState]);
|
||||
|
||||
useEffect(() => {
|
||||
if (
|
||||
screenData?.screenState !== ScreenState.ERROR &&
|
||||
screenData?.screenState !== ScreenState.LOADING
|
||||
) {
|
||||
handleClick(screenData?.screenMetaData?.redirectionCta);
|
||||
}
|
||||
}, [screenData?.screenMetaData?.redirectionCta]);
|
||||
|
||||
if (screenData?.screenState === ScreenState.LOADING) {
|
||||
return <QuoteOfferShimmerScreen handleClick={handleClick} />;
|
||||
} else if (screenData?.screenState === ScreenState.ERROR) {
|
||||
return (
|
||||
<QuoteOfferErrorScreen
|
||||
errorMetaData={screenData.errorMetaData}
|
||||
handleActions={handleActions}
|
||||
handleClick={handleClick}
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<View style={[styles.container, screenData?.screenStyle]}>
|
||||
<StatusBar backgroundColor={Colors.white} barStyle="dark-content" />
|
||||
<Animated.View style={[styles.header, headerBgStyle]}>
|
||||
{getWidgetViews(
|
||||
screenData?.screenWidgets?.headerWidgets,
|
||||
handleActions,
|
||||
screenData?.screenState,
|
||||
handleClick
|
||||
)}
|
||||
</Animated.View>
|
||||
<Animated.ScrollView
|
||||
showsVerticalScrollIndicator={false}
|
||||
contentContainerStyle={styles.content}
|
||||
scrollEventThrottle={16}
|
||||
onScroll={onScroll}
|
||||
nestedScrollEnabled={true}
|
||||
style={screenOverlayStyle}
|
||||
pointerEvents={
|
||||
screenData?.screenState === ScreenState.OVERLAY ? "none" : "auto"
|
||||
}
|
||||
>
|
||||
{getWidgetViews(
|
||||
screenData?.screenWidgets?.contentWidgets,
|
||||
handleActions,
|
||||
screenData?.screenState,
|
||||
handleClick
|
||||
)}
|
||||
</Animated.ScrollView>
|
||||
<View
|
||||
style={[styles.footer, screenOverlayStyle]}
|
||||
pointerEvents={
|
||||
screenData?.screenState === ScreenState.OVERLAY ? "none" : "auto"
|
||||
}
|
||||
>
|
||||
{getWidgetViews(
|
||||
screenData?.screenWidgets?.footerWidgets,
|
||||
handleActions,
|
||||
screenData?.screenState,
|
||||
handleClick
|
||||
)}
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
function getWidgetViews(
|
||||
widgetList: Widget[] | undefined,
|
||||
handleActions: (screenActionPayload?: GenericActionPayload) => void,
|
||||
screenState?: ScreenState | null,
|
||||
handleClick?: (ctaData: CtaData) => void
|
||||
): React.JSX.Element {
|
||||
return (
|
||||
<View>
|
||||
{widgetList?.map((widget, index) => {
|
||||
return (
|
||||
<BaseWidget
|
||||
widget={widget}
|
||||
handleScreenActions={handleActions}
|
||||
screenState={screenState}
|
||||
widgetIndex={index}
|
||||
key={index}
|
||||
handleClick={handleClick}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
export default QuoteOfferScreen;
|
||||
@@ -0,0 +1,21 @@
|
||||
import { StyleSheet } from "react-native";
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
flexDirection: "column",
|
||||
},
|
||||
header: {
|
||||
alignItems: "stretch",
|
||||
position: "absolute",
|
||||
zIndex: 1,
|
||||
},
|
||||
content: {
|
||||
flexGrow: 1,
|
||||
},
|
||||
footer: {
|
||||
alignItems: "stretch",
|
||||
},
|
||||
});
|
||||
|
||||
export default styles;
|
||||
@@ -0,0 +1,52 @@
|
||||
import { View, Text } from "react-native";
|
||||
import { GenericActionPayload } from "../../../../../common/actions/GenericAction";
|
||||
import { CtaData } from "../../../../../common/interface";
|
||||
import { StaticHeader } from "../../../../../../components/reusable/static-header/StaticHeader";
|
||||
import { styles } from "./QuoteOfferErrorScreenStyle";
|
||||
import { TouchableOpacity } from "react-native-gesture-handler";
|
||||
import {
|
||||
ERROR_SUBTITLE,
|
||||
ERROR_TITLE,
|
||||
RETRY,
|
||||
ImageName,
|
||||
} from "../../../../../common/constants/StringConstant";
|
||||
import { AppImage } from "../../../../../../components/AppImage";
|
||||
import { ConstantCta } from "../../../../../common/constants/CtaConstants";
|
||||
|
||||
const QuoteOfferErrorScreen = ({
|
||||
errorMetaData,
|
||||
handleActions,
|
||||
handleClick,
|
||||
}: {
|
||||
errorMetaData?: GenericActionPayload;
|
||||
handleActions?: (screenPayload?: GenericActionPayload) => void;
|
||||
handleClick?: (cta: CtaData) => void;
|
||||
}) => {
|
||||
const onPress = () => {
|
||||
handleActions && handleActions(errorMetaData);
|
||||
};
|
||||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<StaticHeader
|
||||
handleClick={handleClick}
|
||||
leftIconCta={ConstantCta.STATIC_HEADER_LEFT_ICON_CTA}
|
||||
rightIconCta={ConstantCta.STATIC_HEADER_RIGHT_ICON_CTA}
|
||||
/>
|
||||
<View style={styles.centerContent}>
|
||||
{AppImage(ImageName.SWW, styles.centerIcon)}
|
||||
<Text style={styles.errorTitle}>{ERROR_TITLE}</Text>
|
||||
<Text style={styles.errorSubtitle}>{ERROR_SUBTITLE}</Text>
|
||||
</View>
|
||||
<TouchableOpacity
|
||||
onPress={onPress}
|
||||
style={styles.retryButton}
|
||||
activeOpacity={1}
|
||||
>
|
||||
<Text style={styles.buttonText}>{RETRY}</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
export default QuoteOfferErrorScreen;
|
||||
@@ -0,0 +1,48 @@
|
||||
import { StyleSheet } from "react-native";
|
||||
|
||||
export const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
justifyContent: "space-between",
|
||||
backgroundColor: "white",
|
||||
},
|
||||
centerContent: {
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
},
|
||||
centerIcon: {
|
||||
width: 125,
|
||||
height: 125,
|
||||
},
|
||||
errorTitle: {
|
||||
fontSize: 16,
|
||||
lineHeight: 22,
|
||||
fontFamily: "tt_semi_bold",
|
||||
color: "#191919",
|
||||
textAlign: "center",
|
||||
marginTop: 32,
|
||||
},
|
||||
errorSubtitle: {
|
||||
fontSize: 14,
|
||||
lineHeight: 22,
|
||||
fontFamily: "tt_regular",
|
||||
color: "#6B6B6B",
|
||||
textAlign: "center",
|
||||
marginTop: 16,
|
||||
},
|
||||
retryButton: {
|
||||
padding: 16,
|
||||
marginHorizontal: 16,
|
||||
marginVertical: 32,
|
||||
backgroundColor: "#1F002A",
|
||||
borderRadius: 4,
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
},
|
||||
buttonText: {
|
||||
color: "white",
|
||||
fontSize: 14,
|
||||
lineHeight: 22,
|
||||
fontFamily: "tt_semi_bold",
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,87 @@
|
||||
import { View } from "react-native";
|
||||
import SkeletonPlaceholder from "react-native-skeleton-placeholder";
|
||||
import Colors from "../../../../../../assets/colors/colors";
|
||||
import styles from "./QuoteOfferShimmerScreenStyle";
|
||||
import { StaticHeader } from "../../../../../../components/reusable/static-header/StaticHeader";
|
||||
import { CtaData } from "../../../../../common/interface";
|
||||
import { ConstantCta } from "../../../../../common/constants/CtaConstants";
|
||||
|
||||
const QuoteOfferShimmerScreen = ({
|
||||
handleClick,
|
||||
}: {
|
||||
handleClick?: (ctaData: CtaData) => void;
|
||||
}) => {
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<View style={styles.header}>
|
||||
<StaticHeader
|
||||
handleClick={handleClick}
|
||||
leftIconCta={ConstantCta.STATIC_HEADER_LEFT_ICON_CTA}
|
||||
rightIconCta={ConstantCta.STATIC_HEADER_RIGHT_ICON_CTA}
|
||||
/>
|
||||
</View>
|
||||
<ContentShimmer />
|
||||
<FooterShimmer />
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
export default QuoteOfferShimmerScreen;
|
||||
|
||||
const HeaderShimmer = () => {
|
||||
return (
|
||||
<View style={styles.header}>
|
||||
<SkeletonPlaceholder
|
||||
backgroundColor={Colors.shimmerBgColor}
|
||||
highlightColor={Colors.shimmerHighlightColor}
|
||||
direction="right"
|
||||
enabled={true}
|
||||
angle={100}
|
||||
borderRadius={4}
|
||||
>
|
||||
<View>
|
||||
<View style={styles.shimmerHeaderLayout} />
|
||||
</View>
|
||||
</SkeletonPlaceholder>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
const ContentShimmer = () => {
|
||||
return (
|
||||
<View style={styles.content}>
|
||||
<SkeletonPlaceholder
|
||||
backgroundColor={Colors.shimmerBgColor}
|
||||
highlightColor={Colors.shimmerHighlightColor}
|
||||
direction="right"
|
||||
angle={100}
|
||||
borderRadius={4}
|
||||
>
|
||||
<View>
|
||||
<View style={styles.shimmerLayout1} />
|
||||
<View style={styles.shimmerLayout2} />
|
||||
<View style={styles.shimmerLayout3} />
|
||||
<View style={styles.shimmerLayout4} />
|
||||
</View>
|
||||
</SkeletonPlaceholder>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
const FooterShimmer = () => {
|
||||
return (
|
||||
<View style={styles.footer}>
|
||||
<SkeletonPlaceholder
|
||||
backgroundColor={Colors.shimmerBgColor}
|
||||
highlightColor={Colors.shimmerHighlightColor}
|
||||
direction="right"
|
||||
angle={100}
|
||||
borderRadius={4}
|
||||
>
|
||||
<View>
|
||||
<View style={styles.shimmerFooterLayout} />
|
||||
</View>
|
||||
</SkeletonPlaceholder>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,108 @@
|
||||
import { StyleSheet } from "react-native";
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
shimmerHeader: {
|
||||
alignItems: "stretch",
|
||||
position: "absolute",
|
||||
zIndex: 1,
|
||||
},
|
||||
shimmerContent: {},
|
||||
shimmerFooterContainer: {
|
||||
height: 100,
|
||||
zIndex: 2,
|
||||
position: "absolute",
|
||||
bottom: 0,
|
||||
},
|
||||
container: {
|
||||
flex: 1,
|
||||
flexDirection: "column",
|
||||
justifyContent: "center",
|
||||
},
|
||||
header: {
|
||||
position: "absolute",
|
||||
top: 0,
|
||||
width: "100%",
|
||||
backgroundColor: "white",
|
||||
},
|
||||
content: {
|
||||
marginTop: 88,
|
||||
flexGrow: 1,
|
||||
marginHorizontal: 16,
|
||||
},
|
||||
footer: {
|
||||
borderTopStartRadius: 16,
|
||||
borderTopEndRadius: 16,
|
||||
shadowColor: "black",
|
||||
shadowOpacity: 0.26,
|
||||
shadowOffset: { width: 0, height: 2 },
|
||||
shadowRadius: 10,
|
||||
elevation: 3,
|
||||
backgroundColor: "white",
|
||||
},
|
||||
shimmerLayout1: {
|
||||
position: "relative",
|
||||
marginTop: 12,
|
||||
|
||||
height: 152,
|
||||
alignItems: "center",
|
||||
borderRadius: 4,
|
||||
flexShrink: 0,
|
||||
gap: 10.5,
|
||||
},
|
||||
shimmerLayout2: {
|
||||
position: "relative",
|
||||
marginTop: 24,
|
||||
|
||||
height: 78,
|
||||
alignItems: "center",
|
||||
borderRadius: 4,
|
||||
flexShrink: 0,
|
||||
gap: 10.5,
|
||||
},
|
||||
shimmerLayout3: {
|
||||
position: "relative",
|
||||
marginTop: 24,
|
||||
|
||||
height: 148,
|
||||
alignItems: "center",
|
||||
borderRadius: 4,
|
||||
flexShrink: 0,
|
||||
gap: 10.5,
|
||||
},
|
||||
shimmerLayout4: {
|
||||
position: "relative",
|
||||
|
||||
marginTop: 24,
|
||||
height: 35,
|
||||
alignItems: "center",
|
||||
borderRadius: 4,
|
||||
flexShrink: 0,
|
||||
gap: 10.5,
|
||||
},
|
||||
|
||||
shimmerFooterLayout: {
|
||||
position: "relative",
|
||||
marginHorizontal: 16,
|
||||
marginTop: 16,
|
||||
marginBottom: 24,
|
||||
height: 49,
|
||||
alignItems: "center",
|
||||
borderRadius: 4,
|
||||
flexShrink: 0,
|
||||
gap: 10.5,
|
||||
},
|
||||
|
||||
shimmerHeaderLayout: {
|
||||
position: "relative",
|
||||
marginHorizontal: 16,
|
||||
marginTop: 16,
|
||||
marginBottom: 24,
|
||||
height: 49,
|
||||
alignItems: "center",
|
||||
borderRadius: 4,
|
||||
flexShrink: 0,
|
||||
gap: 10.5,
|
||||
},
|
||||
});
|
||||
|
||||
export default styles;
|
||||
37
App/common/actions/GenericAction.ts
Normal file
37
App/common/actions/GenericAction.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
import { Dispatch, SetStateAction } from "react";
|
||||
import { AnalyticsEvent, CtaData } from "../interface";
|
||||
import { ScreenData } from "../interface/widgets/screenData/ScreenData";
|
||||
import { ScreenState } from "../screen/BaseScreen";
|
||||
|
||||
export interface GenericActionPayload {
|
||||
baseActionType?: string;
|
||||
type?: string; // type is used for analytics seggregations and also screen level API call or handling seggregation
|
||||
metaData?: ActionMetaData[];
|
||||
ctaData?: CtaData;
|
||||
setScreenData?: Dispatch<SetStateAction<ScreenData | null>>;
|
||||
setScreenState?: Dispatch<SetStateAction<ScreenState | null>>;
|
||||
setErrorMetaData?: Dispatch<SetStateAction<ActionMetaData[] | null>>;
|
||||
screenData?: ScreenData | null;
|
||||
}
|
||||
|
||||
export interface ActionMetaData {
|
||||
actionType?: string;
|
||||
// ActionMetaData has some key attributes required to perform any action e.g. critical widget communications i.e. inter/intra widget, screen level API calls, bottom sheet, modal, etc.
|
||||
data?: any;
|
||||
analyticsEventProperties?: AnalyticsEvent;
|
||||
}
|
||||
|
||||
export interface TargetWidgetPayload {
|
||||
targetWidgetId?: string;
|
||||
keyPath?: string;
|
||||
newValue?: any;
|
||||
valueType: string;
|
||||
widgetId?: string;
|
||||
actionId?: string;
|
||||
}
|
||||
|
||||
export const BaseActionTypes = {
|
||||
SCREEN_ACTION: "SCREEN_ACTION",
|
||||
WIDGET_ACTION: "WIDGET_ACTION",
|
||||
ANALYTICS_EVENT_ACTION: "CLICKSTREAM_ACTION",
|
||||
};
|
||||
4
App/common/constants/AnalyticsEventsConstant.ts
Normal file
4
App/common/constants/AnalyticsEventsConstant.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
export const HI_SI_PILLS_CLICK = "hi_si_pills_click"
|
||||
export const SUM_INSURED = "sum_insured";
|
||||
export const HI_RN_QUOTE_PAGE_INIT = "hi_rn_quote_page_init";
|
||||
export const HI_RN_QUOTE_PAGE_ERROR_VIEW = "hi_rn_quote_page_error_view";
|
||||
25
App/common/constants/CtaConstants.ts
Normal file
25
App/common/constants/CtaConstants.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
export const ConstantCta = {
|
||||
STATIC_HEADER_LEFT_ICON_CTA: {
|
||||
url: "home",
|
||||
},
|
||||
STATIC_HEADER_RIGHT_ICON_CTA: {
|
||||
url: "PRODUCT_HELP_PAGE",
|
||||
type: "USE_ROOT_DEEPLINK_NAVIGATOR",
|
||||
finish: false,
|
||||
parameters: [
|
||||
{
|
||||
key: "SCREEN_NAME",
|
||||
value: "GI_QUOTE_FORM_V2_SCREEN",
|
||||
},
|
||||
],
|
||||
},
|
||||
QUOTE_APOLOGY_FOOTER_BUTTON: {
|
||||
url: "gi/insurance_container/pre_quote_journey",
|
||||
parameters: [
|
||||
{
|
||||
key: "applicationType",
|
||||
value: "FRESH_POLICY",
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
3
App/common/constants/EventNameConstants.ts
Normal file
3
App/common/constants/EventNameConstants.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
export enum NativeEventNameConstants {
|
||||
reloadPage = "reloadPage",
|
||||
}
|
||||
3
App/common/constants/ModalNameConstants.ts
Normal file
3
App/common/constants/ModalNameConstants.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
export const PREMIUM_DETAILS_BOTTOM_SHEET = "premium_details_bottom_sheet";
|
||||
export const TITLE_WITH_FEEDBACK_PILL_BOTTOM_SHEET = "title_with_feedback_pill_bottom_sheet";
|
||||
export const TITLE_WITH_STEPS_BOTTOM_SHEET = "title_with_steps_bottom_sheet"
|
||||
1
App/common/constants/NavigationHandlerConstants.ts
Normal file
1
App/common/constants/NavigationHandlerConstants.ts
Normal file
@@ -0,0 +1 @@
|
||||
export const GI = "gi";
|
||||
2
App/common/constants/NumericalConstants.ts
Normal file
2
App/common/constants/NumericalConstants.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
export const HEADER_LOTTIE_WIDGET_HEIGHT = 180;
|
||||
export const HEADER_LOTTIE_TITLE_HEIGHT = 84;
|
||||
9
App/common/constants/ScreenNameConstants.ts
Normal file
9
App/common/constants/ScreenNameConstants.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
export const INTRO_SCREEN = "intro";
|
||||
export const SECOND_INTRO_SCREEN = "second_intro";
|
||||
export const MEMBER_SELECTION_SCREEN = "member_selection";
|
||||
export const HOME_SCREEN = "home";
|
||||
export const BASE_SCREEN = "base";
|
||||
export const INSURANCE_LANDING_PAGE_SCREEN = "insurance_landing_page";
|
||||
export const QUOTE_OFFER_SCREEN = "quote_offer";
|
||||
export const BUY_INSURANCE_SCREEN = "buyinsurance";
|
||||
export const QUOTE_APOLOGY_SCREEN = "fresh_policy_form";
|
||||
29
App/common/constants/StringConstant.ts
Normal file
29
App/common/constants/StringConstant.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
export const Orientation = {
|
||||
VERTICAL: "vertical",
|
||||
HORIZONTAL: "horizontal",
|
||||
DIAGONAL: "diagonal",
|
||||
};
|
||||
|
||||
export const Lottie = {
|
||||
FOOTER_LOADER_URL:
|
||||
"https://public-assets.prod.navi-sa.in/home_uitron/cta_loader.json",
|
||||
};
|
||||
|
||||
export const ImageName = {
|
||||
SWW: "SWW",
|
||||
CROSS: "CROSS",
|
||||
HELP: "HELP",
|
||||
QUOTE_APOLOGY_ICON: "QUOTE_APOLOGY_ICON",
|
||||
};
|
||||
|
||||
export const ERROR_TITLE = "Something went wrong";
|
||||
export const ERROR_SUBTITLE = "Please try again after some time";
|
||||
export const RETRY = "Retry";
|
||||
export const QUOTE_APOLOGY_TITLE =
|
||||
"Sorry, we cannot insure some members with health issues!";
|
||||
export const QUOTE_APOLOGY_SUBTITLE =
|
||||
"You can still purchase policy for others members";
|
||||
export const QUOTE_APOLOGY_BUTTON = "Buy new policy";
|
||||
export const QUOTE_PATCH_FAIL_TOAST = "Failed. Try again";
|
||||
export const QUOTE_ID = "quoteId";
|
||||
export const BUILD_CONFIG_DETAILS = "BUILD_CONFIG_DETAILS";
|
||||
15
App/common/constants/WidgetNameConstants.ts
Normal file
15
App/common/constants/WidgetNameConstants.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
export const INFO_DISPLAY_WIDGET = "RN_DEMO_INFO_ICON_TITLE_CARD";
|
||||
export const NAME_DOB_INPUT_WIDGET = "RN_DEMO_LABEL_INPUT_WITH_DOB_PICKER";
|
||||
export const TITLE_WIDGET = "TITLE_WIDGET";
|
||||
export const BUTTON_TEST_WIDGET = "BUTTON_TEST_WIDGET";
|
||||
export const SLIDER_WIDGET = "SLIDER_WIDGET";
|
||||
export const TITLE_WITH_LIST_WIDGET = "TITLE_WITH_LIST_WIDGET";
|
||||
export const FOOTER_WITH_CARD_WIDGET = "FOOTER_WITH_CARD_WIDGET";
|
||||
export const GRID_WITH_CARD_WIDGET = "GRID_WITH_CARD_WIDGET";
|
||||
export const COMPARISON_WIDGET = "COMPARISON_WIDGET";
|
||||
export const TITLE_WITH_ASSETS_WIDGET = "TITLE_WITH_ASSETS_WIDGET";
|
||||
export const HEADER_WITH_ASSETS_WIDGET = "HEADER_WITH_ASSETS_WIDGET";
|
||||
export const HEADER_LOTTIE_ANIMATION_WIDGET = "HEADER_LOTTIE_ANIMATION_WIDGET";
|
||||
export const SUM_INSURED_WIDGET = "SUM_INSURED_WIDGET";
|
||||
export const TITLE_SUBTITLE_WITH_ASSET_WIDGET = "TITLE_SUBTITLE_WITH_ASSET_WIDGET";
|
||||
export const FAB_REQUEST_TO_CALLBACK = "FAB_REQUEST_TO_CALLBACK";
|
||||
70
App/common/hooks/useAnalyticsEvent.ts
Normal file
70
App/common/hooks/useAnalyticsEvent.ts
Normal file
@@ -0,0 +1,70 @@
|
||||
import { AnalyticsEvent } from "../interface";
|
||||
import { NativeAnalyticsModule } from "../native-module/NativeModules";
|
||||
import { useAsRecord } from "../utilities/RecordUtils";
|
||||
|
||||
export const sendAsAnalyticsEvent = (analyticsEvent: AnalyticsEvent) => {
|
||||
const eventName = analyticsEvent.name;
|
||||
const eventProperties = analyticsEvent.properties;
|
||||
NativeAnalyticsModule.sendAsAnalyticsEvent(
|
||||
eventName,
|
||||
useAsRecord(eventProperties)
|
||||
);
|
||||
};
|
||||
|
||||
export const sendAsAppDowntimeEvent = (event: AppDowntimeData) => {
|
||||
const {
|
||||
reason = null,
|
||||
screenName = null,
|
||||
moduleName = null,
|
||||
statusCode = null,
|
||||
networkType = null,
|
||||
flowName = null,
|
||||
methodName = null,
|
||||
vendorName = null,
|
||||
extras = null,
|
||||
eventName = "global_app_downtime",
|
||||
} = event;
|
||||
|
||||
NativeAnalyticsModule.sendAsAppDowntimeEvent({
|
||||
reason,
|
||||
screenName,
|
||||
moduleName,
|
||||
statusCode,
|
||||
networkType,
|
||||
flowName,
|
||||
methodName,
|
||||
vendorName,
|
||||
extras,
|
||||
eventName,
|
||||
});
|
||||
};
|
||||
|
||||
export const sendAsGlobalErrorEvent = (event: GlobalErrorData) => {
|
||||
const {
|
||||
reason = null,
|
||||
source = null,
|
||||
moduleName,
|
||||
globalErrorType,
|
||||
statusCode = null,
|
||||
networkType = null,
|
||||
flowName = null,
|
||||
methodName = null,
|
||||
vendorName = null,
|
||||
extras = null,
|
||||
journeySource = null,
|
||||
} = event;
|
||||
|
||||
NativeAnalyticsModule.sendAsGlobalErrorEvent({
|
||||
reason,
|
||||
source,
|
||||
moduleName,
|
||||
globalErrorType,
|
||||
statusCode,
|
||||
networkType,
|
||||
flowName,
|
||||
methodName,
|
||||
vendorName,
|
||||
extras,
|
||||
journeySource,
|
||||
});
|
||||
};
|
||||
39
App/common/hooks/useBottomSheet.tsx
Normal file
39
App/common/hooks/useBottomSheet.tsx
Normal file
@@ -0,0 +1,39 @@
|
||||
import { useState } from "react";
|
||||
import { View } from "react-native";
|
||||
import BaseBottomSheetComponent from "../../../components/bottomsheet/BaseBottomSheetComponent";
|
||||
import { ModalView } from "../interface/modals/ModalView";
|
||||
import { clearBottomSheet, setBottomSheetView } from "../utilities/AlfredUtils";
|
||||
|
||||
export const useBottomSheet = () => {
|
||||
const [bottomsheet, setBottomSheet] = useState<JSX.Element[]>([]);
|
||||
|
||||
const onAnimationEndHandler = (id: number | null) => {
|
||||
if (!id) return;
|
||||
setBottomSheetView(id);
|
||||
};
|
||||
|
||||
const addBottomSheet = (modalView: ModalView) => {
|
||||
setBottomSheet((prevState) => [
|
||||
...prevState,
|
||||
<View>
|
||||
<BaseBottomSheetComponent
|
||||
onBottomSheetAnimationEnd={onAnimationEndHandler}
|
||||
showModal={true}
|
||||
onClose={() => removeBottomSheet()}
|
||||
modalView={modalView}
|
||||
/>
|
||||
</View>,
|
||||
]);
|
||||
};
|
||||
|
||||
const removeBottomSheet = () => {
|
||||
clearBottomSheet();
|
||||
setBottomSheet((prevState) => {
|
||||
const newState = [...prevState];
|
||||
newState.pop();
|
||||
return newState;
|
||||
});
|
||||
};
|
||||
|
||||
return { bottomsheet, addBottomSheet, removeBottomSheet };
|
||||
};
|
||||
55
App/common/hooks/useGradient.tsx
Normal file
55
App/common/hooks/useGradient.tsx
Normal file
@@ -0,0 +1,55 @@
|
||||
import LinearGradient from "react-native-linear-gradient";
|
||||
import { isValidHexColors } from "../utilities/ValidateColors";
|
||||
import { Orientation } from "../constants/StringConstant";
|
||||
|
||||
export const NaviLinearGradient = ({
|
||||
gradientColors,
|
||||
defaultColors,
|
||||
children,
|
||||
orientation,
|
||||
}: {
|
||||
gradientColors?: string[];
|
||||
defaultColors?: string[];
|
||||
children?: React.ReactNode;
|
||||
orientation?: string;
|
||||
}) => {
|
||||
let startValue;
|
||||
switch (orientation) {
|
||||
case Orientation.VERTICAL:
|
||||
startValue = { x: 0.5, y: 0 };
|
||||
break;
|
||||
case Orientation.HORIZONTAL:
|
||||
startValue = { x: 0, y: 0.5 };
|
||||
break;
|
||||
case Orientation.DIAGONAL:
|
||||
startValue = { x: 0, y: 0 };
|
||||
break;
|
||||
default:
|
||||
startValue = { x: 0.5, y: 0 };
|
||||
break;
|
||||
}
|
||||
let endValue;
|
||||
switch (orientation) {
|
||||
case Orientation.VERTICAL:
|
||||
endValue = { x: 0.5, y: 1 };
|
||||
break;
|
||||
case Orientation.HORIZONTAL:
|
||||
endValue = { x: 1, y: 0.5 };
|
||||
break;
|
||||
case Orientation.DIAGONAL:
|
||||
endValue = { x: 1, y: 1 };
|
||||
break;
|
||||
default:
|
||||
endValue = { x: 0.5, y: 1 };
|
||||
break;
|
||||
}
|
||||
return (
|
||||
<LinearGradient
|
||||
colors={isValidHexColors(gradientColors, defaultColors)}
|
||||
start={startValue}
|
||||
end={endValue}
|
||||
>
|
||||
{children}
|
||||
</LinearGradient>
|
||||
);
|
||||
};
|
||||
21
App/common/hooks/useModal.ts
Normal file
21
App/common/hooks/useModal.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import { useState } from "react";
|
||||
|
||||
const useModal = () => {
|
||||
const [isModalVisible, setModalVisibility] = useState(false);
|
||||
|
||||
const toggleModal = () => {
|
||||
setModalVisibility(!isModalVisible);
|
||||
};
|
||||
|
||||
const handleModalClose = () => {
|
||||
setModalVisibility(false);
|
||||
};
|
||||
|
||||
return {
|
||||
isModalVisible,
|
||||
toggleModal,
|
||||
handleModalClose,
|
||||
};
|
||||
};
|
||||
|
||||
export default useModal;
|
||||
5
App/common/hooks/useSentryLogging.ts
Normal file
5
App/common/hooks/useSentryLogging.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
import * as Sentry from "@sentry/react";
|
||||
|
||||
export const logToSentry = (message: string) => {
|
||||
Sentry.captureException(new Error(message));
|
||||
};
|
||||
12
App/common/interface/BaseScreenProps.ts
Normal file
12
App/common/interface/BaseScreenProps.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import { CtaData } from ".";
|
||||
|
||||
export interface BaseScreenProps {
|
||||
route: RouteParams;
|
||||
navigation: any;
|
||||
}
|
||||
|
||||
interface RouteParams {
|
||||
params?: {
|
||||
ctaData?: CtaData;
|
||||
};
|
||||
}
|
||||
181
App/common/interface/MemberDetailsResponse.ts
Normal file
181
App/common/interface/MemberDetailsResponse.ts
Normal file
@@ -0,0 +1,181 @@
|
||||
import { Widget, GenericWidgetData } from "./widgets/Widget";
|
||||
|
||||
export interface MemberDetailsRootObject {
|
||||
applicationResponse: ApplicationResponse;
|
||||
currentScreenCta: CurrentScreenCta;
|
||||
currentScreenDefinition: CurrentScreenDefinition;
|
||||
}
|
||||
|
||||
interface CurrentScreenDefinition {
|
||||
screenData: ScreenData;
|
||||
}
|
||||
|
||||
interface ScreenData {
|
||||
metaData: ScreenMetaData;
|
||||
screenStructure: ScreenStructure;
|
||||
}
|
||||
|
||||
interface ScreenStructure {
|
||||
drawer: Drawer;
|
||||
footer: Footer;
|
||||
header: Header;
|
||||
content: Content;
|
||||
renderActions: RenderActions;
|
||||
systemBackCta: SystemBackCta;
|
||||
floatingActionButton: Drawer;
|
||||
}
|
||||
|
||||
interface SystemBackCta {
|
||||
actions: Action2[];
|
||||
}
|
||||
|
||||
interface Action2 {
|
||||
type: string;
|
||||
ctaData: Cta;
|
||||
}
|
||||
|
||||
interface RenderActions {
|
||||
preRenderAction: Drawer;
|
||||
postRenderAction: PostRenderAction;
|
||||
}
|
||||
|
||||
interface PostRenderAction {
|
||||
actions: Action[];
|
||||
}
|
||||
|
||||
interface Action {
|
||||
type: string;
|
||||
isNeededForFirebase: boolean;
|
||||
isNeededForAppsflyer: boolean;
|
||||
predefinedEventProperties: PredefinedEventProperty[];
|
||||
}
|
||||
|
||||
interface PredefinedEventProperty {
|
||||
propertyName: string;
|
||||
propertyValue: string;
|
||||
}
|
||||
|
||||
interface Content {
|
||||
widgets: Widget[];
|
||||
backgroundColor: string;
|
||||
}
|
||||
|
||||
interface InfoDisplayWidgetData extends GenericWidgetData {
|
||||
cardData?: Container;
|
||||
titleData?: Banner;
|
||||
leftIconData?: LeftBottomEndTextIcon;
|
||||
}
|
||||
|
||||
interface NameDobWidget extends GenericWidgetData {
|
||||
endInput?: EndInput;
|
||||
labelTitle?: Banner;
|
||||
startInput?: StartInput;
|
||||
outputFields?: OutputFields;
|
||||
}
|
||||
interface OutputFields {
|
||||
endInputField: string;
|
||||
startInputField: string;
|
||||
}
|
||||
interface StartInput {
|
||||
hint: string;
|
||||
style: Drawer;
|
||||
keyboardType: string;
|
||||
}
|
||||
|
||||
interface EndInput {
|
||||
hint: string;
|
||||
style: Drawer;
|
||||
endIconUrl: string;
|
||||
}
|
||||
|
||||
interface Header {
|
||||
widgetId: string;
|
||||
widgetData: HeaderWidgetData;
|
||||
widgetType: string;
|
||||
}
|
||||
|
||||
interface HeaderWidgetData {
|
||||
backIconData: LeftBottomEndTextIcon;
|
||||
endTitleData: Banner;
|
||||
middleTitleData: Banner;
|
||||
}
|
||||
|
||||
interface Footer {
|
||||
widgetId: string;
|
||||
widgetData: FooterWidgetData;
|
||||
widgetName: string;
|
||||
widgetType: string;
|
||||
}
|
||||
|
||||
interface FooterWidgetData {
|
||||
banner: Banner;
|
||||
progress: Progress;
|
||||
rightCta: RightCta;
|
||||
leftBottomText: Banner;
|
||||
leftTopStrikedText: Banner;
|
||||
leftTopUnstrikedText: Banner;
|
||||
leftBottomEndTextIcon: LeftBottomEndTextIcon;
|
||||
}
|
||||
|
||||
interface LeftBottomEndTextIcon {
|
||||
style: Drawer;
|
||||
iconUrl: string;
|
||||
}
|
||||
|
||||
interface RightCta {
|
||||
title: Banner;
|
||||
container: Container;
|
||||
}
|
||||
|
||||
interface Container {
|
||||
style: Drawer;
|
||||
}
|
||||
|
||||
interface Progress {
|
||||
style: Drawer;
|
||||
progress: string;
|
||||
}
|
||||
|
||||
interface Banner {
|
||||
text: string;
|
||||
style: Drawer;
|
||||
}
|
||||
|
||||
interface Drawer {}
|
||||
|
||||
interface CurrentScreenCta {
|
||||
cta: Cta;
|
||||
shouldPoll: boolean;
|
||||
shouldRender: boolean;
|
||||
screenMetaData: ScreenMetaData;
|
||||
screenPollingConfigs: ScreenPollingConfigs;
|
||||
}
|
||||
|
||||
interface ScreenPollingConfigs {
|
||||
initialDelay: number;
|
||||
interval: number;
|
||||
numOfRetries: number;
|
||||
}
|
||||
|
||||
interface ScreenMetaData {
|
||||
screenName: string;
|
||||
screenType: string;
|
||||
}
|
||||
|
||||
interface Cta {
|
||||
url: string;
|
||||
parameters: Parameter[];
|
||||
}
|
||||
|
||||
interface Parameter {
|
||||
key: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
interface ApplicationResponse {
|
||||
applicationType: string;
|
||||
applicationId: string;
|
||||
applicantType: string;
|
||||
applicationStatus: string;
|
||||
configVersion: string;
|
||||
}
|
||||
12
App/common/interface/analytics/AppDowntimeData.ts
Normal file
12
App/common/interface/analytics/AppDowntimeData.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
interface AppDowntimeData {
|
||||
reason?: string | null;
|
||||
screenName?: string | null;
|
||||
moduleName?: string | null;
|
||||
statusCode?: number | null;
|
||||
networkType?: string | null;
|
||||
flowName?: string | null;
|
||||
methodName?: string | null;
|
||||
vendorName?: string | null;
|
||||
extras?: Map<string, string> | null;
|
||||
eventName?: string;
|
||||
}
|
||||
13
App/common/interface/analytics/GlobalErrorData.ts
Normal file
13
App/common/interface/analytics/GlobalErrorData.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
interface GlobalErrorData {
|
||||
reason?: string | null;
|
||||
source?: string | null;
|
||||
moduleName: string;
|
||||
globalErrorType: string;
|
||||
statusCode?: number | null;
|
||||
networkType?: string | null;
|
||||
flowName?: string | null;
|
||||
methodName?: string | null;
|
||||
vendorName?: string | null;
|
||||
extras?: Map<string, string> | null;
|
||||
journeySource?: string | null;
|
||||
}
|
||||
9
App/common/interface/components/PillData.ts
Normal file
9
App/common/interface/components/PillData.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import { ViewStyle } from "react-native";
|
||||
import { PillInfo } from "./PillInfo";
|
||||
|
||||
export interface PillData {
|
||||
id: string;
|
||||
selectedState?: PillInfo;
|
||||
unSelectedState?: PillInfo;
|
||||
defaultPillStyle: ViewStyle;
|
||||
}
|
||||
7
App/common/interface/components/PillInfo.ts
Normal file
7
App/common/interface/components/PillInfo.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import { ViewStyle } from "react-native";
|
||||
import { TextFieldData } from "../widgets/widgetData/TitleWidgetData";
|
||||
|
||||
export interface PillInfo {
|
||||
title?: TextFieldData;
|
||||
pillStyle: ViewStyle;
|
||||
}
|
||||
32
App/common/interface/index.ts
Normal file
32
App/common/interface/index.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
export type CtaData = {
|
||||
url: string;
|
||||
type?: string;
|
||||
parameters?: Array<LineItem>;
|
||||
data?: any;
|
||||
finish?: boolean;
|
||||
screenKey?: string;
|
||||
analyticsEventProperties?: AnalyticsEvent;
|
||||
};
|
||||
|
||||
export type AnalyticsEvent = {
|
||||
name: string;
|
||||
properties?: Map<string, string>;
|
||||
};
|
||||
|
||||
|
||||
type LineItem = {
|
||||
key?: string;
|
||||
value?: string | null;
|
||||
data?: any | null;
|
||||
};
|
||||
|
||||
export interface BaseNavigator {
|
||||
navigate(ctaData: CtaData): any;
|
||||
goBack(): any;
|
||||
}
|
||||
|
||||
export enum CtaType {
|
||||
DEEP_LINK = "DEEP_LINK",
|
||||
DISMISS_MODAL = "DISMISS_MODAL",
|
||||
USE_ROOT_DEEPLINK_NAVIGATOR = "USE_ROOT_DEEPLINK_NAVIGATOR",
|
||||
}
|
||||
10
App/common/interface/modals/ModalView.ts
Normal file
10
App/common/interface/modals/ModalView.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import { ViewStyle } from "react-native";
|
||||
import { GenericWidgetData } from "../widgets/Widget";
|
||||
|
||||
export interface ModalView {
|
||||
modalId?: string;
|
||||
modalData: GenericWidgetData;
|
||||
modalName: string;
|
||||
modalType?: string | null;
|
||||
modalStyle?: ViewStyle;
|
||||
}
|
||||
24
App/common/interface/widgets/Widget.ts
Normal file
24
App/common/interface/widgets/Widget.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import { ViewStyle } from "react-native";
|
||||
|
||||
export interface Widget {
|
||||
widgetId: string;
|
||||
widgetData: GenericWidgetData;
|
||||
widgetName: string;
|
||||
widgetType: string | null;
|
||||
widgetStyle: ViewStyle;
|
||||
widgetVisibility?: boolean;
|
||||
}
|
||||
|
||||
export interface GenericWidgetData {
|
||||
widgetOutputDetails?: WidgetOutputData
|
||||
}
|
||||
|
||||
interface WidgetOutputData {
|
||||
dynamicInputUpdate?: Record<string, any>;
|
||||
widgetOutput?: WidgetOutput[];
|
||||
}
|
||||
|
||||
interface WidgetOutput {
|
||||
fieldName?: string;
|
||||
layoutId?: string;
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
import { ViewStyle } from "react-native";
|
||||
import { GenericWidgetData } from "../Widget";
|
||||
import { ButtonData, CardInfo } from "../widgetData/FooterWithCardWidgetData";
|
||||
import { ImageFieldData, TextFieldData } from "../widgetData/TitleWidgetData";
|
||||
|
||||
export interface PremiumDetailsBottomSheetData extends GenericWidgetData {
|
||||
title?: TextFieldData;
|
||||
infoTitle?: TextFieldData;
|
||||
infoIcon?: ImageFieldData;
|
||||
detailedPremiumBreakUp?: KeyValueInfoData[];
|
||||
showDivider?: boolean;
|
||||
detailedTenureInfo?: KeyValueInfoData[];
|
||||
calloutCardInfo?: CardInfo;
|
||||
button?: ButtonData;
|
||||
viewStyle?: ViewStyle;
|
||||
}
|
||||
|
||||
export interface KeyValueInfoData extends GenericWidgetData {
|
||||
key?: TextFieldData;
|
||||
value?: TextFieldData;
|
||||
displayRightOfKey?: TextFieldData;
|
||||
displayLeftOfValue?: TextFieldData;
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
import { ViewStyle } from "react-native";
|
||||
import { GenericWidgetData } from "../Widget";
|
||||
import { ButtonData } from "../widgetData/FooterWithCardWidgetData";
|
||||
import { TextFieldData } from "../widgetData/TitleWidgetData";
|
||||
import { PillData } from "../../components/PillData";
|
||||
|
||||
export interface TitleWithFeedbackPillBottomSheetData
|
||||
extends GenericWidgetData {
|
||||
title?: TextFieldData;
|
||||
feedBackList?: PillData[];
|
||||
infoCard?: InfoCardData;
|
||||
leftButton?: ButtonData;
|
||||
rightButton?: ButtonData;
|
||||
viewStyle?: ViewStyle;
|
||||
}
|
||||
|
||||
|
||||
export interface InfoCardData extends GenericWidgetData{
|
||||
title?: TextFieldData;
|
||||
subtitle?: TextFieldData;
|
||||
cardStyle: ViewStyle;
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
import { GenericWidgetData } from "../Widget";
|
||||
import { ButtonData } from "../widgetData/FooterWithCardWidgetData";
|
||||
import { TextFieldData, ImageFieldData } from "../widgetData/TitleWidgetData";
|
||||
|
||||
export interface TitleWithStepsBottomSheetData extends GenericWidgetData {
|
||||
button?: ButtonData;
|
||||
header?: Header;
|
||||
steps?: StepData[];
|
||||
}
|
||||
|
||||
export interface Header {
|
||||
title?: TextFieldData;
|
||||
subTitle?: TextFieldData;
|
||||
rightIcon?: ImageFieldData;
|
||||
backgroundColor?: string;
|
||||
}
|
||||
|
||||
export interface StepData {
|
||||
serial?: TextFieldData;
|
||||
image?: ImageFieldData;
|
||||
title?: TextFieldData;
|
||||
subTitle?: TextFieldData;
|
||||
bullets?: Bullet[];
|
||||
}
|
||||
|
||||
export interface Bullet {
|
||||
bulletIcon?: ImageFieldData;
|
||||
title?: TextFieldData;
|
||||
tagTitle?: TextFieldData;
|
||||
tag?: ImageFieldData;
|
||||
}
|
||||
10
App/common/interface/widgets/screenData/ErrorMetaData.ts
Normal file
10
App/common/interface/widgets/screenData/ErrorMetaData.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import { ActionMetaData } from "../../../actions/GenericAction";
|
||||
import { ButtonData } from "../widgetData/FooterWithCardWidgetData";
|
||||
import { TextFieldData, TitleWidgetData } from "../widgetData/TitleWidgetData";
|
||||
|
||||
export interface ErrorMetaData {
|
||||
title?: TextFieldData,
|
||||
subTitle?: TextFieldData,
|
||||
errorMeta?: ActionMetaData[] | null,
|
||||
button?: ButtonData
|
||||
}
|
||||
20
App/common/interface/widgets/screenData/ScreenData.ts
Normal file
20
App/common/interface/widgets/screenData/ScreenData.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import { ViewStyle } from "react-native";
|
||||
import { Widget } from "../Widget";
|
||||
import { ScreenState } from "../../../screen/BaseScreen";
|
||||
import { ScreenMetaData } from "./ScreenMetaData";
|
||||
import { GenericActionPayload } from "../../../actions/GenericAction";
|
||||
|
||||
export interface ScreenData {
|
||||
screenStyle?: ViewStyle;
|
||||
screenId?: string;
|
||||
screenWidgets?: ScreenWidgets;
|
||||
screenState?: ScreenState | null;
|
||||
errorMetaData?: GenericActionPayload;
|
||||
screenMetaData?: ScreenMetaData;
|
||||
}
|
||||
|
||||
export interface ScreenWidgets {
|
||||
headerWidgets?: Widget[];
|
||||
contentWidgets?: Widget[];
|
||||
footerWidgets?: Widget[];
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
import { CtaData } from "../..";
|
||||
|
||||
export interface ScreenMetaData {
|
||||
backButtonCta?: CtaData;
|
||||
redirectionCta?: CtaData;
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
import { GenericWidgetData } from "../Widget";
|
||||
import { ImageFieldData, TitleWidgetData } from "./TitleWidgetData";
|
||||
|
||||
export interface ComparisonWidgetData extends GenericWidgetData {
|
||||
leftIcon?: ImageFieldData;
|
||||
leftTitle?: TitleWidgetData;
|
||||
rightIcon?: ImageFieldData;
|
||||
rightTitle?: TitleWidgetData;
|
||||
divider?: ImageFieldData;
|
||||
}
|
||||
15
App/common/interface/widgets/widgetData/FabWidgetData.ts
Normal file
15
App/common/interface/widgets/widgetData/FabWidgetData.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import { CtaData } from "../..";
|
||||
import { GenericWidgetData } from "../Widget";
|
||||
import { LottieFieldData } from "./TitleWidgetData";
|
||||
|
||||
|
||||
export interface FabWidgetData extends GenericWidgetData {
|
||||
lottieData?: LottieFieldData;
|
||||
properties?: FabProperties;
|
||||
callbackCta?: CtaData;
|
||||
};
|
||||
|
||||
export interface FabProperties {
|
||||
isDraggable?: boolean;
|
||||
startingPosition?: number;
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
import { ViewStyle } from "react-native";
|
||||
import { CtaData } from "../..";
|
||||
import { SumInsuredRequestData } from "../../../../Container/Navi-Insurance/network/QuotePageApi";
|
||||
import { GenericActionPayload } from "../../../actions/GenericAction";
|
||||
import { GenericWidgetData } from "../Widget";
|
||||
import { TextFieldData } from "./TitleWidgetData";
|
||||
|
||||
export interface FooterWithCardWidgetData extends GenericWidgetData {
|
||||
title?: TextFieldData;
|
||||
subtitle?: TextFieldData;
|
||||
cardInfo?: CardInfo;
|
||||
footerButton?: ButtonData;
|
||||
cardAction?: GenericActionPayload;
|
||||
titleAction?: GenericActionPayload;
|
||||
action?: GenericActionPayload;
|
||||
buttonAction?: GenericActionPayload;
|
||||
}
|
||||
|
||||
export interface FinalPatchCallRequestBody {
|
||||
requestData: SumInsuredRequestData;
|
||||
nextPageCta: CtaData;
|
||||
}
|
||||
|
||||
export interface CardInfo extends GenericWidgetData {
|
||||
title?: TextFieldData;
|
||||
rightTitle?: TextFieldData;
|
||||
}
|
||||
|
||||
export interface ButtonData extends GenericWidgetData {
|
||||
title?: TextFieldData;
|
||||
state?: ButtonState;
|
||||
buttonStyle?: ViewStyle;
|
||||
cta?: CtaData;
|
||||
}
|
||||
|
||||
export enum ButtonState {
|
||||
ENABLED = "ENABLED",
|
||||
DISABLED = "DISABLED",
|
||||
LOADING = "LOADING",
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
import { ViewStyle } from "react-native";
|
||||
import { CtaData } from "../..";
|
||||
import { GenericWidgetData } from "../Widget";
|
||||
import { ImageFieldData, TextFieldData } from "./TitleWidgetData";
|
||||
|
||||
export interface GridWithCardWidgetData extends GenericWidgetData {
|
||||
title?: TextFieldData;
|
||||
subtitle?: TextFieldData;
|
||||
rightTitle?: TextFieldData;
|
||||
gridItems?: GridCardItemData[];
|
||||
numColumns?: number;
|
||||
}
|
||||
|
||||
export interface GridCardItemData {
|
||||
id?: string;
|
||||
image?: ImageFieldData;
|
||||
title?: TextFieldData;
|
||||
cardStyle?: ViewStyle;
|
||||
cta?: CtaData;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
import { CtaData } from "../..";
|
||||
import { GenericWidgetData } from "../Widget";
|
||||
import { ImageFieldData, LottieFieldData, TextFieldData } from "./TitleWidgetData";
|
||||
|
||||
export interface HeaderLottieAnimationWidgetData extends GenericWidgetData {
|
||||
backgroundLottie?: LottieFieldData;
|
||||
title?: TextFieldData;
|
||||
cta?: CtaData;
|
||||
backgroundGradient?: string[];
|
||||
gradientOrientation?: string;
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
import { GenericActionPayload } from "../../../actions/GenericAction";
|
||||
import { GenericWidgetData } from "../Widget";
|
||||
import {
|
||||
ImageFieldData,
|
||||
LottieFieldData,
|
||||
TextFieldData,
|
||||
} from "./TitleWidgetData";
|
||||
|
||||
export interface HeaderWithAssetsWidgetData extends GenericWidgetData {
|
||||
leftIcon?: ImageFieldData;
|
||||
leftLottie?: LottieFieldData;
|
||||
centerTitle?: TextFieldData;
|
||||
rightIcon?: ImageFieldData;
|
||||
rightLottie?: LottieFieldData;
|
||||
action?: GenericActionPayload;
|
||||
}
|
||||
13
App/common/interface/widgets/widgetData/SliderWidgetData.ts
Normal file
13
App/common/interface/widgets/widgetData/SliderWidgetData.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import { ViewStyle } from "react-native";
|
||||
import { GenericWidgetData } from "../Widget";
|
||||
import { GenericActionPayload } from "../../../actions/GenericAction";
|
||||
|
||||
export interface SliderWidgetData extends GenericWidgetData {
|
||||
sliderStyle?: ViewStyle;
|
||||
minimumValue?: number;
|
||||
maximumValue?: number;
|
||||
// Used for demo the widget structure can be refined below is just sample.
|
||||
// TODO: Raaj/Himanshu for cleanup
|
||||
onValueChangeAction?: GenericActionPayload;
|
||||
onSliderReleaseActionSequence?: GenericActionPayload;
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
import { GenericActionPayload } from "../../../actions/GenericAction";
|
||||
import { GenericWidgetData } from "../Widget";
|
||||
import { TextFieldData } from "./TitleWidgetData";
|
||||
|
||||
export interface SumInsuredWidgetData extends GenericWidgetData {
|
||||
carouselListData?: SumInsuredData[];
|
||||
carouselStyles?: {
|
||||
selectedStyles?: any;
|
||||
unselectedStyles?: any;
|
||||
};
|
||||
widgetMetaData? : {
|
||||
selectedItemIndex?: number;
|
||||
recommendItemIndex?: number;
|
||||
selectedItemTagText? : string;
|
||||
onValueChangeAction? : GenericActionPayload
|
||||
onCarouselReleaseActionSequence? : GenericActionPayload;
|
||||
}
|
||||
}
|
||||
export interface SumInsuredData {
|
||||
itemId?: string;
|
||||
sumInsured?: string;
|
||||
title?: TextFieldData;
|
||||
subtitle?: TextFieldData;
|
||||
isFirst?: boolean;
|
||||
isLast?: boolean;
|
||||
dependentWidgets?: any;
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
import { GenericActionPayload } from "../../../actions/GenericAction";
|
||||
import { GenericWidgetData } from "../Widget";
|
||||
import {
|
||||
ImageFieldData,
|
||||
LottieFieldData,
|
||||
TextFieldData,
|
||||
} from "./TitleWidgetData";
|
||||
|
||||
export interface TitleSubtitleWithAssetWidgetData extends GenericWidgetData {
|
||||
title?: TextFieldData;
|
||||
subtitle?: TextFieldData;
|
||||
image?: ImageFieldData;
|
||||
action?: GenericActionPayload;
|
||||
backgroundImage?: ImageFieldData;
|
||||
backgroundLottie?: LottieFieldData;
|
||||
}
|
||||
49
App/common/interface/widgets/widgetData/TitleWidgetData.ts
Normal file
49
App/common/interface/widgets/widgetData/TitleWidgetData.ts
Normal file
@@ -0,0 +1,49 @@
|
||||
import { ImageStyle, TextStyle } from "react-native";
|
||||
import { CtaData } from "../..";
|
||||
import { GenericWidgetData } from "../Widget";
|
||||
|
||||
export interface TitleWidgetData extends GenericWidgetData {
|
||||
title?: TextFieldData;
|
||||
subtitle?: TextFieldData;
|
||||
rightTitle?: TextFieldData;
|
||||
cta?: CtaData;
|
||||
}
|
||||
|
||||
export interface TextFieldData {
|
||||
text: string;
|
||||
textStyle?: TextStyle;
|
||||
substringStyles?: SubstringStyle[];
|
||||
textDrawableData?: TextDrawableData;
|
||||
cta?: CtaData;
|
||||
}
|
||||
|
||||
export interface SubstringStyle {
|
||||
substring: string;
|
||||
textStyle?: TextStyle;
|
||||
}
|
||||
|
||||
export interface TextDrawableData {
|
||||
left?: ImageFieldData;
|
||||
right?: ImageFieldData;
|
||||
top?: ImageFieldData;
|
||||
bottom?: ImageFieldData;
|
||||
leftLottie?: LottieFieldData;
|
||||
rightLottie?: LottieFieldData;
|
||||
topLottie?: LottieFieldData;
|
||||
bottomLottie?: LottieFieldData;
|
||||
}
|
||||
|
||||
export interface ImageFieldData {
|
||||
url: string;
|
||||
imageStyle?: ImageStyle;
|
||||
cta?: CtaData;
|
||||
}
|
||||
|
||||
export interface LottieFieldData {
|
||||
url: string;
|
||||
loop?: boolean;
|
||||
autoPlay?: boolean;
|
||||
lottieStyle?: ImageStyle;
|
||||
cta?: CtaData;
|
||||
delayAnimationBy?: number;
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
import { CtaData } from "../..";
|
||||
import { GenericWidgetData } from "../Widget";
|
||||
import {
|
||||
ImageFieldData,
|
||||
LottieFieldData,
|
||||
TextFieldData,
|
||||
} from "./TitleWidgetData";
|
||||
|
||||
export interface TitleWithAssetsWidgetData extends GenericWidgetData {
|
||||
leftIcon?: ImageFieldData;
|
||||
leftLottie?: LottieFieldData;
|
||||
title?: TextFieldData;
|
||||
rightIcon?: ImageFieldData;
|
||||
rightLottie?: LottieFieldData;
|
||||
cta?: CtaData;
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
import { TextStyle } from "react-native";
|
||||
import { GenericWidgetData } from "../Widget";
|
||||
import { TextFieldData } from "./TitleWidgetData";
|
||||
|
||||
export interface TitleWithListWidgetData extends GenericWidgetData {
|
||||
title?: TextFieldData;
|
||||
rightTitle?: TextFieldData;
|
||||
listData?: ListItem[];
|
||||
}
|
||||
|
||||
export interface ListItem extends GenericWidgetData {
|
||||
id: string;
|
||||
title?: TextFieldData;
|
||||
rightTitle?: TextFieldData;
|
||||
}
|
||||
|
||||
|
||||
58
App/common/modals/modalViewResolver.tsx
Normal file
58
App/common/modals/modalViewResolver.tsx
Normal file
@@ -0,0 +1,58 @@
|
||||
import React from "react";
|
||||
import { View, ViewStyle } from "react-native";
|
||||
import TitleWithFeedbackPillBottomSheet from "../../../components/bottomsheet/title-with-feed-back-bottom-sheet/TitleWithFeedBackBottomSheet";
|
||||
import PremiumDetailsBottomSheet from "../../../components/bottomsheet/title-with-list-bottom-sheet/TitleWithListBottomSheet";
|
||||
import TitleWithStepsBottomSheet from "../../../components/bottomsheet/title-with-steps-bottom-sheet/TitleWithStepsBottomSheet";
|
||||
import {
|
||||
PREMIUM_DETAILS_BOTTOM_SHEET,
|
||||
TITLE_WITH_FEEDBACK_PILL_BOTTOM_SHEET,
|
||||
TITLE_WITH_STEPS_BOTTOM_SHEET,
|
||||
} from "../constants/ModalNameConstants";
|
||||
import { CtaData } from "../interface";
|
||||
import { ModalView } from "../interface/modals/ModalView";
|
||||
import { GenericWidgetData } from "../interface/widgets/Widget";
|
||||
|
||||
export const GetModalView = {
|
||||
getModal: (
|
||||
modal: ModalView,
|
||||
handleModalClick: (cta: CtaData) => void
|
||||
): JSX.Element => {
|
||||
const { modalName, modalData, modalStyle } = modal;
|
||||
return resolveModalView(modalName, modalData, modalStyle, handleModalClick);
|
||||
},
|
||||
};
|
||||
|
||||
function resolveModalView(
|
||||
modalName: string,
|
||||
modalData: GenericWidgetData,
|
||||
modalStyle: ViewStyle | undefined,
|
||||
handleModalClick: (cta: CtaData) => void
|
||||
) {
|
||||
switch (modalName) {
|
||||
case PREMIUM_DETAILS_BOTTOM_SHEET:
|
||||
return (
|
||||
<PremiumDetailsBottomSheet
|
||||
bottomSheetData={modalData}
|
||||
handleModalClick={handleModalClick}
|
||||
/>
|
||||
);
|
||||
|
||||
case TITLE_WITH_FEEDBACK_PILL_BOTTOM_SHEET:
|
||||
return (
|
||||
<TitleWithFeedbackPillBottomSheet
|
||||
bottomSheetData={modalData}
|
||||
handleModalClick={handleModalClick}
|
||||
/>
|
||||
);
|
||||
|
||||
case TITLE_WITH_STEPS_BOTTOM_SHEET:
|
||||
return (
|
||||
<TitleWithStepsBottomSheet
|
||||
bottomSheetData={modalData}
|
||||
handleModalClick={handleModalClick}
|
||||
/>
|
||||
);
|
||||
default:
|
||||
return <View />;
|
||||
}
|
||||
}
|
||||
11
App/common/native-module/NativeModules.ts
Normal file
11
App/common/native-module/NativeModules.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import { NativeModules } from "react-native";
|
||||
|
||||
const {
|
||||
NativeDeeplinkNavigatorModule,
|
||||
PreferenceManagerConnector,
|
||||
NetworkConnectorModule,
|
||||
AlfredModuleConnector,
|
||||
NativeAnalyticsModule
|
||||
} = NativeModules;
|
||||
|
||||
export { NativeDeeplinkNavigatorModule, PreferenceManagerConnector, NetworkConnectorModule, AlfredModuleConnector, NativeAnalyticsModule };
|
||||
71
App/common/navigator/NavigationRouter.ts
Normal file
71
App/common/navigator/NavigationRouter.ts
Normal file
@@ -0,0 +1,71 @@
|
||||
import { createNavigationContainerRef } from "@react-navigation/native";
|
||||
import { BaseNavigator, CtaData } from "../interface";
|
||||
import { BASE_SCREEN } from "../constants/ScreenNameConstants";
|
||||
import {
|
||||
BaseActionTypes,
|
||||
GenericActionPayload,
|
||||
ActionMetaData,
|
||||
} from "../actions/GenericAction";
|
||||
import WidgetActionHandler from "../widgets/widget-actions/WidgetActionHandler";
|
||||
import { ScreenActionHandler } from "../screen/ScreenActionHandler";
|
||||
import { logToSentry } from "../hooks/useSentryLogging";
|
||||
|
||||
export const navigationRef = createNavigationContainerRef();
|
||||
|
||||
export const CtaNavigator: BaseNavigator = {
|
||||
navigate: (ctaData: CtaData) => {
|
||||
if (navigationRef.isReady()) {
|
||||
navigationRef.navigate(BASE_SCREEN, { ctaData });
|
||||
}
|
||||
},
|
||||
goBack: () => {
|
||||
if (navigationRef.isReady()) {
|
||||
navigationRef.goBack();
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
export const Router = {
|
||||
handleAction(actionPayload: GenericActionPayload, navigation?: any): void {
|
||||
switch (actionPayload.baseActionType) {
|
||||
case BaseActionTypes.WIDGET_ACTION: {
|
||||
actionPayload.metaData?.forEach(
|
||||
(widgetMetaData: ActionMetaData, _: number) => {
|
||||
if (!!actionPayload.setScreenData) {
|
||||
WidgetActionHandler.handleWidgetAction(
|
||||
!!widgetMetaData ? widgetMetaData : {},
|
||||
actionPayload.setScreenData,
|
||||
actionPayload.setErrorMetaData,
|
||||
actionPayload.screenData,
|
||||
actionPayload.ctaData,
|
||||
navigation
|
||||
);
|
||||
}
|
||||
}
|
||||
);
|
||||
break;
|
||||
}
|
||||
case BaseActionTypes.SCREEN_ACTION: {
|
||||
actionPayload.metaData?.forEach(
|
||||
(screenMetaData: ActionMetaData, _: number) => {
|
||||
if (!!actionPayload.setScreenData) {
|
||||
ScreenActionHandler.handleScreenAction(
|
||||
!!screenMetaData ? screenMetaData : {},
|
||||
actionPayload.setScreenData,
|
||||
actionPayload.screenData,
|
||||
navigation
|
||||
);
|
||||
}
|
||||
}
|
||||
);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
logToSentry(
|
||||
`Invalid baseActionType ${actionPayload.baseActionType} | MethodName: Router.handleAction`
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
64
App/common/navigator/RnAppCreator.tsx
Normal file
64
App/common/navigator/RnAppCreator.tsx
Normal file
@@ -0,0 +1,64 @@
|
||||
import IntroScreen from "../../Container/Navi-Insurance/screen/IntroScreen";
|
||||
import {
|
||||
BASE_SCREEN,
|
||||
INSURANCE_LANDING_PAGE_SCREEN,
|
||||
INTRO_SCREEN,
|
||||
} from "../constants/ScreenNameConstants";
|
||||
import { CtaData } from "../interface";
|
||||
import { ThemeProvider } from "../../../components/ThemeContext";
|
||||
import { LogBox } from "react-native";
|
||||
|
||||
import { NavigationContainer } from "@react-navigation/native";
|
||||
import { createStackNavigator } from "@react-navigation/stack";
|
||||
import { Provider } from "react-redux";
|
||||
import reduxStore from "../redux/store";
|
||||
import { PersistGate } from "redux-persist/integration/react";
|
||||
import BaseScreen from "../screen/BaseScreen";
|
||||
import { navigationRef } from "./NavigationRouter";
|
||||
|
||||
LogBox.ignoreLogs(["Warning: ..."]); // Ignore log notification by message
|
||||
LogBox.ignoreAllLogs(); //Ignore all log notifications
|
||||
|
||||
const Stack = createStackNavigator();
|
||||
|
||||
export const RnApp = {
|
||||
create: (ctaData: CtaData) => {
|
||||
const { store, persistor } = reduxStore();
|
||||
return (
|
||||
<Provider store={store}>
|
||||
<PersistGate loading={null} persistor={persistor}>
|
||||
<ThemeProvider>
|
||||
<NavigationContainer ref={navigationRef}>
|
||||
{getScreenStack(ctaData)}
|
||||
</NavigationContainer>
|
||||
</ThemeProvider>
|
||||
</PersistGate>
|
||||
</Provider>
|
||||
);
|
||||
},
|
||||
};
|
||||
|
||||
function getScreenStack(ctaData: CtaData) {
|
||||
return (
|
||||
<Stack.Navigator
|
||||
initialRouteName={BASE_SCREEN}
|
||||
screenOptions={{
|
||||
headerShown: false,
|
||||
gestureEnabled: false,
|
||||
}}
|
||||
>
|
||||
<Stack.Screen
|
||||
name={INTRO_SCREEN}
|
||||
component={IntroScreen}
|
||||
initialParams={{ ctaData: ctaData }}
|
||||
/>
|
||||
<Stack.Screen
|
||||
name={BASE_SCREEN}
|
||||
component={BaseScreen}
|
||||
initialParams={{ ctaData: ctaData }}
|
||||
/>
|
||||
</Stack.Navigator>
|
||||
);
|
||||
}
|
||||
|
||||
export default RnApp;
|
||||
1
App/common/redux/index.ts
Normal file
1
App/common/redux/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * from "./screens/screenActionCreators";
|
||||
8
App/common/redux/rootReducer.js
Normal file
8
App/common/redux/rootReducer.js
Normal file
@@ -0,0 +1,8 @@
|
||||
import { combineReducers } from "redux";
|
||||
import screenReducer from "./screens/screenReducer";
|
||||
|
||||
const rootReducer = combineReducers({
|
||||
screenReducer: screenReducer,
|
||||
});
|
||||
|
||||
export default rootReducer;
|
||||
@@ -0,0 +1,7 @@
|
||||
import { CtaData } from "../../../interface";
|
||||
import { ScreenState } from "../../../screen/BaseScreen";
|
||||
|
||||
export interface UpdateCtaDataPayload {
|
||||
cta: CtaData;
|
||||
setScreenState?: ScreenState | null;
|
||||
}
|
||||
10
App/common/redux/screens/screenActionCreators.ts
Normal file
10
App/common/redux/screens/screenActionCreators.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import { UpdateCtaDataPayload } from "./action-interfaces/UpdateCtaPayload";
|
||||
import { UPDATE_CTA_DATA } from "./screenReducerActionTypes";
|
||||
|
||||
//action creators
|
||||
export const updateCtaData = (payload: UpdateCtaDataPayload) => {
|
||||
return {
|
||||
type: UPDATE_CTA_DATA,
|
||||
payload: payload,
|
||||
};
|
||||
};
|
||||
26
App/common/redux/screens/screenReducer.ts
Normal file
26
App/common/redux/screens/screenReducer.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
import { ScreenState } from "../../screen/BaseScreen";
|
||||
import { UPDATE_CTA_DATA } from "./screenReducerActionTypes";
|
||||
|
||||
const initialState = {
|
||||
ctaData: null,
|
||||
screenState: ScreenState.LOADING,
|
||||
};
|
||||
|
||||
const screenReducer = (
|
||||
state = initialState,
|
||||
action: { type: string; payload: any }
|
||||
) => {
|
||||
switch (action.type) {
|
||||
case UPDATE_CTA_DATA:
|
||||
return {
|
||||
...state,
|
||||
ctaData: action.payload.cta,
|
||||
screenState: ScreenState.LOADING,
|
||||
};
|
||||
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
};
|
||||
|
||||
export default screenReducer;
|
||||
1
App/common/redux/screens/screenReducerActionTypes.ts
Normal file
1
App/common/redux/screens/screenReducerActionTypes.ts
Normal file
@@ -0,0 +1 @@
|
||||
export const UPDATE_CTA_DATA = "UPDATE_CTA_DATA";
|
||||
28
App/common/redux/store.js
Normal file
28
App/common/redux/store.js
Normal file
@@ -0,0 +1,28 @@
|
||||
import { applyMiddleware, configureStore, getDefaultMiddleware } from "@reduxjs/toolkit";
|
||||
import rootReducer from "./rootReducer";
|
||||
import thunk from "redux-thunk";
|
||||
import AsyncStorage from "@react-native-async-storage/async-storage";
|
||||
import { persistReducer, persistStore } from "redux-persist";
|
||||
|
||||
const middleWares = [getDefaultMiddleware({
|
||||
thunk: true,
|
||||
serializableCheck: false
|
||||
}
|
||||
)];
|
||||
|
||||
const persistConfig = {
|
||||
key: "root",
|
||||
storage: AsyncStorage,
|
||||
};
|
||||
|
||||
const persistedReducer = persistReducer(persistConfig, rootReducer);
|
||||
|
||||
export default () => {
|
||||
//by default configureStore has middleware thunk in it, it is added explicitly below for ref to add other middlewares
|
||||
let store = configureStore(
|
||||
{ reducer: persistedReducer },
|
||||
applyMiddleware(...middleWares)
|
||||
);
|
||||
let persistor = persistStore(store);
|
||||
return { store, persistor };
|
||||
};
|
||||
174
App/common/screen/BaseScreen.tsx
Normal file
174
App/common/screen/BaseScreen.tsx
Normal file
@@ -0,0 +1,174 @@
|
||||
import { useFocusEffect } from "@react-navigation/native";
|
||||
import { isEqual } from "lodash";
|
||||
import React, { useEffect, useMemo, useState } from "react";
|
||||
import { View } from "react-native";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import { commonStyles } from "../../Container/Navi-Insurance/Styles";
|
||||
import { ActionMetaData, GenericActionPayload } from "../actions/GenericAction";
|
||||
import { sendAsAnalyticsEvent } from "../hooks/useAnalyticsEvent";
|
||||
import { useBottomSheet } from "../hooks/useBottomSheet";
|
||||
import { CtaData } from "../interface";
|
||||
import { ModalView } from "../interface/modals/ModalView";
|
||||
import { ScreenData } from "../interface/widgets/screenData/ScreenData";
|
||||
import { Router } from "../navigator/NavigationRouter";
|
||||
import { updateCtaData } from "../redux/screens/screenActionCreators";
|
||||
import {
|
||||
getCacheKey,
|
||||
getScreenDataFromCache,
|
||||
isScreenWhiteListedForCaching,
|
||||
saveScreenDataInCache,
|
||||
} from "../utilities/CacheUtils";
|
||||
import { getScreenNameFromCtaData } from "../utilities/MiscUtils";
|
||||
import { WidgetActionTypes } from "../widgets/widget-actions/WidgetActionTypes";
|
||||
import { ScreenMapper } from "./screen-mappers/ScreenMapper";
|
||||
import { logToSentry } from "../hooks/useSentryLogging";
|
||||
|
||||
const BaseScreen: React.FC<{ navigation: any; route: any }> = ({
|
||||
navigation,
|
||||
route,
|
||||
}) => {
|
||||
const [screenData, setScreenData] = useState<ScreenData | null>(null);
|
||||
const [screenName, setScreenName] = useState<string | null>(null);
|
||||
const [screenKey, setScreenKey] = useState<string | null>(null);
|
||||
const [screenState, setScreenState] = useState<ScreenState | null>(
|
||||
ScreenState.LOADING
|
||||
);
|
||||
const [errorMetaData, setErrorMetaData] = useState<ActionMetaData[] | null>(
|
||||
null
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
const cacheKey = getCacheKey(screenName, screenKey);
|
||||
if (!screenData) {
|
||||
const screenInitialData: ScreenData = {
|
||||
screenState: ScreenState.LOADING,
|
||||
};
|
||||
setScreenData(screenInitialData);
|
||||
}
|
||||
if (!!cacheKey && isScreenWhiteListedForCaching(screenName)) {
|
||||
if (
|
||||
!(
|
||||
!!screenData?.errorMetaData ||
|
||||
screenData?.screenState === ScreenState.ERROR
|
||||
)
|
||||
) {
|
||||
saveScreenDataInCache(screenName, screenData);
|
||||
}
|
||||
}
|
||||
}, [screenData]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!!getScreenNameFromCtaData(route.params?.ctaData)) {
|
||||
setScreenName(getScreenNameFromCtaData(route.params?.ctaData)!!);
|
||||
if (!!route.params?.ctaData?.screenKey) {
|
||||
setScreenKey(route.params?.ctaData?.screenKey);
|
||||
}
|
||||
if (isScreenWhiteListedForCaching(screenName)) {
|
||||
retrieveScreenDataFromCache(
|
||||
getScreenNameFromCtaData(route.params?.ctaData)!!,
|
||||
route.params?.ctaData?.screenKey
|
||||
);
|
||||
}
|
||||
}
|
||||
}, []);
|
||||
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const retrieveScreenDataFromCache = (
|
||||
screenName: string | null | undefined,
|
||||
screenKey: string | null | undefined
|
||||
) => {
|
||||
let cacheKey = getCacheKey(screenName, screenKey);
|
||||
if (!!cacheKey) {
|
||||
getScreenDataFromCache(cacheKey).then((screenData) => {
|
||||
if (!!screenData) {
|
||||
setScreenData(screenData);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const { cta } = useSelector((state: any) => {
|
||||
const savedCta = state.screenReducer.ctaData;
|
||||
if (isEqual(savedCta, route.params.ctaData)) {
|
||||
return { cta: state.screenReducer.ctaData };
|
||||
}
|
||||
return { cta: route.params.ctaData };
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
const ctaData: CtaData = route.params.ctaData;
|
||||
if (!isEqual(cta, ctaData)) {
|
||||
dispatch(updateCtaData({ cta: ctaData, setScreenState: screenState }));
|
||||
}
|
||||
}, [route.params.ctaData, screenState]);
|
||||
|
||||
useFocusEffect(
|
||||
React.useCallback(() => {
|
||||
// This function will be called when the screen is focused (resumed)
|
||||
console.log("Screen resumed");
|
||||
|
||||
// add code here to perform actions on screen resume
|
||||
// update redux store based on current screen name
|
||||
|
||||
return () => {
|
||||
// This function will be called when the screen loses focus (paused)
|
||||
console.log("Screen paused");
|
||||
};
|
||||
}, [])
|
||||
);
|
||||
const { bottomsheet, addBottomSheet } = useBottomSheet();
|
||||
|
||||
const handleActions = (actionPayload?: GenericActionPayload) => {
|
||||
actionPayload?.metaData?.forEach((ActionMetaData) => {
|
||||
if (!!ActionMetaData.analyticsEventProperties) {
|
||||
sendAsAnalyticsEvent(ActionMetaData.analyticsEventProperties);
|
||||
}
|
||||
if (ActionMetaData.actionType === WidgetActionTypes.OPEN_BOTTOM_SHEET) {
|
||||
addBottomSheet(ActionMetaData.data as ModalView);
|
||||
} else {
|
||||
const updatedActionPayload: GenericActionPayload = {
|
||||
...(actionPayload as GenericActionPayload),
|
||||
setScreenData,
|
||||
setScreenState,
|
||||
setErrorMetaData,
|
||||
ctaData: cta,
|
||||
screenData: { ...screenData },
|
||||
};
|
||||
if (!!actionPayload) {
|
||||
Router.handleAction(updatedActionPayload, navigation);
|
||||
} else {
|
||||
// handle error
|
||||
logToSentry(
|
||||
`Action payload is missing or invalid: ${actionPayload} | MethodName: handleActions`
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
const MemoizedScreenMapper = useMemo(() => {
|
||||
return (
|
||||
<View style={commonStyles.flex_1}>
|
||||
{ScreenMapper.getScreenMapper(cta, screenData, handleActions)}
|
||||
</View>
|
||||
);
|
||||
}, [cta, screenData]);
|
||||
|
||||
return (
|
||||
<View style={commonStyles.flex_1}>
|
||||
{MemoizedScreenMapper}
|
||||
{bottomsheet.map((sheet, index) => (
|
||||
<React.Fragment key={`bottomSheet-${index}`}>{sheet}</React.Fragment>
|
||||
))}
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
export enum ScreenState {
|
||||
LOADING,
|
||||
LOADED,
|
||||
ERROR,
|
||||
OVERLAY,
|
||||
}
|
||||
|
||||
export default BaseScreen;
|
||||
109
App/common/screen/ScreenActionHandler.tsx
Normal file
109
App/common/screen/ScreenActionHandler.tsx
Normal file
@@ -0,0 +1,109 @@
|
||||
import { ActionMetaData, BaseActionTypes } from "../actions/GenericAction";
|
||||
import { ScreenData } from "../interface/widgets/screenData/ScreenData";
|
||||
import { ScreenActionTypes } from "./ScreenActionTypes";
|
||||
import { Dispatch, SetStateAction } from "react";
|
||||
import { post, get } from "../../../network/NetworkService";
|
||||
import { CtaData } from "../interface";
|
||||
import { getXTargetHeaderInfo } from "../../../network/ApiClient";
|
||||
import { GI } from "../constants/NavigationHandlerConstants";
|
||||
import { ScreenState } from "./BaseScreen";
|
||||
import { BASE_SCREEN } from "../constants/ScreenNameConstants";
|
||||
import { logToSentry } from "../hooks/useSentryLogging";
|
||||
|
||||
export const ScreenActionHandler = {
|
||||
handleScreenAction: (
|
||||
screenMetaData: ActionMetaData,
|
||||
setScreenData: Dispatch<SetStateAction<ScreenData | null>>,
|
||||
screenData?: ScreenData | null,
|
||||
navigation?: any
|
||||
) => {
|
||||
switch (screenMetaData.actionType) {
|
||||
case ScreenActionTypes.FETCH_INSURANCE_QUOTE_PAGE_FROM_BACKEND: {
|
||||
return get<ApiResponse<CtaData>>(
|
||||
`v3/quotes/${screenMetaData.data.quoteId}`,
|
||||
getXTargetHeaderInfo(GI.toLocaleUpperCase())
|
||||
)
|
||||
.then((response) => {
|
||||
const updatedScreenData: ScreenData = {
|
||||
...(response.data as ScreenData),
|
||||
screenState: ScreenState.LOADED,
|
||||
};
|
||||
setScreenData(updatedScreenData);
|
||||
return;
|
||||
})
|
||||
.catch((error) => {
|
||||
logToSentry(
|
||||
`No response from api call: ${screenMetaData.actionType} | Error: ${error} | MethodName: handleScreenAction`
|
||||
);
|
||||
const updatedScreenData: ScreenData = {
|
||||
screenState: ScreenState.ERROR,
|
||||
errorMetaData: {
|
||||
baseActionType: BaseActionTypes.SCREEN_ACTION,
|
||||
metaData: [
|
||||
{
|
||||
actionType: ScreenActionTypes.SHOW_LOADER,
|
||||
},
|
||||
{
|
||||
data: screenMetaData.data,
|
||||
actionType:
|
||||
ScreenActionTypes.FETCH_INSURANCE_QUOTE_PAGE_FROM_BACKEND,
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
setScreenData(updatedScreenData);
|
||||
});
|
||||
}
|
||||
case ScreenActionTypes.FETCH_QUOTE_V3: {
|
||||
return post<ApiResponse<CtaData>>(
|
||||
"v3/quotes",
|
||||
screenMetaData.data,
|
||||
getXTargetHeaderInfo(GI.toLocaleUpperCase())
|
||||
)
|
||||
.then((response) => {
|
||||
console.log("Quote_v3_Call success", response.data);
|
||||
if (screenData?.screenState) {
|
||||
screenData.screenState = ScreenState.LOADING;
|
||||
}
|
||||
if (response.data) {
|
||||
const cta = response.data as CtaData;
|
||||
// By default routing is happening via Base screen hence below navigate sends the cta there to get routed to specific screenName based on Cta
|
||||
navigation.navigate(BASE_SCREEN, { ctaData: cta });
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
logToSentry(
|
||||
`No response from api call: ${screenMetaData.actionType} | Error: ${error} | MethodName: handleScreenAction}`
|
||||
);
|
||||
const updatedScreenData: ScreenData = {
|
||||
screenState: ScreenState.ERROR,
|
||||
errorMetaData: {
|
||||
baseActionType: BaseActionTypes.SCREEN_ACTION,
|
||||
metaData: [
|
||||
{
|
||||
actionType: ScreenActionTypes.SHOW_LOADER,
|
||||
},
|
||||
{
|
||||
data: screenMetaData.data,
|
||||
actionType: ScreenActionTypes.FETCH_QUOTE_V3,
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
setScreenData(updatedScreenData);
|
||||
return;
|
||||
});
|
||||
}
|
||||
case ScreenActionTypes.SHOW_LOADER: {
|
||||
const updatedScreenData: ScreenData = {
|
||||
...screenData,
|
||||
screenState: ScreenState.LOADING,
|
||||
};
|
||||
setScreenData(updatedScreenData);
|
||||
return;
|
||||
}
|
||||
default:
|
||||
return;
|
||||
}
|
||||
},
|
||||
};
|
||||
6
App/common/screen/ScreenActionTypes.ts
Normal file
6
App/common/screen/ScreenActionTypes.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
export const ScreenActionTypes = {
|
||||
FETCH_INSURANCE_QUOTE_PAGE_FROM_BACKEND:
|
||||
"FETCH_INSURANCE_QUOTE_PAGE_FROM_BACKEND",
|
||||
FETCH_QUOTE_V3: "FETCH_QUOTE_V3",
|
||||
SHOW_LOADER: "SHOW_LOADER",
|
||||
};
|
||||
79
App/common/screen/screen-mappers/GIScreenMapper.tsx
Normal file
79
App/common/screen/screen-mappers/GIScreenMapper.tsx
Normal file
@@ -0,0 +1,79 @@
|
||||
import { View } from "react-native";
|
||||
import {
|
||||
IntroScreen,
|
||||
InsuranceLandingPageScreen,
|
||||
QuoteOfferScreen,
|
||||
} from "../../../Container/Navi-Insurance";
|
||||
import { getScreenNameFromCtaData } from "../../utilities/MiscUtils";
|
||||
import { GenericActionPayload } from "../../actions/GenericAction";
|
||||
import { CtaData } from "../../interface";
|
||||
import { ScreenData } from "../../interface/widgets/screenData/ScreenData";
|
||||
import {
|
||||
INSURANCE_LANDING_PAGE_SCREEN,
|
||||
INTRO_SCREEN,
|
||||
QUOTE_OFFER_SCREEN,
|
||||
BUY_INSURANCE_SCREEN,
|
||||
QUOTE_APOLOGY_SCREEN,
|
||||
} from "../../constants/ScreenNameConstants";
|
||||
import QuoteApologyScreen from "../../../Container/Navi-Insurance/screen/quote-apology-screen/QuoteApologyScreen";
|
||||
import { logToSentry } from "../../hooks/useSentryLogging";
|
||||
|
||||
export const GIScreenMapper = {
|
||||
getScreen(
|
||||
ctaData: CtaData | null | undefined,
|
||||
screenData: ScreenData | null,
|
||||
handleActions: (actionPayload?: GenericActionPayload) => void
|
||||
): JSX.Element {
|
||||
if (!!ctaData) {
|
||||
const thirdIdentifier = getScreenNameFromCtaData(ctaData);
|
||||
switch (thirdIdentifier) {
|
||||
case INTRO_SCREEN:
|
||||
return <IntroScreen ctaData={ctaData} />;
|
||||
case QUOTE_OFFER_SCREEN:
|
||||
case BUY_INSURANCE_SCREEN:
|
||||
return (
|
||||
<QuoteOfferScreen
|
||||
ctaData={ctaData}
|
||||
screenData={screenData}
|
||||
handleActions={handleActions}
|
||||
/>
|
||||
);
|
||||
case QUOTE_APOLOGY_SCREEN:
|
||||
return (
|
||||
<QuoteApologyScreen
|
||||
ctaData={ctaData}
|
||||
screenData={screenData}
|
||||
handleActions={handleActions}
|
||||
/>
|
||||
);
|
||||
case INSURANCE_LANDING_PAGE_SCREEN:
|
||||
return (
|
||||
<InsuranceLandingPageScreen
|
||||
ctaData={ctaData}
|
||||
screenData={screenData}
|
||||
handleActions={handleActions}
|
||||
/>
|
||||
);
|
||||
default: {
|
||||
let ctaDataa: CtaData = {
|
||||
url: "react/insurance_landing_page",
|
||||
screenKey: "insurance_lp_1",
|
||||
};
|
||||
return (
|
||||
<InsuranceLandingPageScreen
|
||||
ctaData={ctaDataa}
|
||||
screenData={screenData}
|
||||
handleActions={handleActions}
|
||||
/>
|
||||
);
|
||||
}
|
||||
//default will be changed to cta handler through bridge
|
||||
}
|
||||
} else {
|
||||
logToSentry(
|
||||
`CtaData is missing or invalid: ${ctaData} | MethodName: GIScreenMapper.getScreen`
|
||||
);
|
||||
return <View />;
|
||||
}
|
||||
},
|
||||
};
|
||||
37
App/common/screen/screen-mappers/ScreenMapper.tsx
Normal file
37
App/common/screen/screen-mappers/ScreenMapper.tsx
Normal file
@@ -0,0 +1,37 @@
|
||||
import { View } from "react-native";
|
||||
import { CtaData } from "../../interface";
|
||||
import { GenericActionPayload } from "../../actions/GenericAction";
|
||||
import { ScreenData } from "../../interface/widgets/screenData/ScreenData";
|
||||
import { getScreenMapperNameFromCtaData } from "../../utilities/MiscUtils";
|
||||
import { commonStyles } from "../../../Container/Navi-Insurance/Styles";
|
||||
import { GIScreenMapper } from "./GIScreenMapper";
|
||||
import { GI } from "../../constants/NavigationHandlerConstants";
|
||||
import { logToSentry } from "../../hooks/useSentryLogging";
|
||||
|
||||
export const ScreenMapper = {
|
||||
getScreenMapper(
|
||||
ctaData: CtaData | null | undefined,
|
||||
screenData: ScreenData | null,
|
||||
handleActions: (actionPayload?: GenericActionPayload) => void
|
||||
): JSX.Element {
|
||||
if (!!ctaData) {
|
||||
console.log("ScreenMapper", ctaData);
|
||||
const secondIdentifier = getScreenMapperNameFromCtaData(ctaData);
|
||||
switch (secondIdentifier) {
|
||||
case GI:
|
||||
return (
|
||||
<View style={commonStyles.flex_1}>
|
||||
{GIScreenMapper.getScreen(ctaData, screenData, handleActions)}
|
||||
</View>
|
||||
);
|
||||
default:
|
||||
return <View />;
|
||||
}
|
||||
} else {
|
||||
logToSentry(
|
||||
`CtaData is missing or invalid: ${ctaData} | MethodName: ScreenMapper.getScreen`
|
||||
);
|
||||
return <View />;
|
||||
}
|
||||
},
|
||||
};
|
||||
29
App/common/styles/BaseBottomSheetComponentStyles.ts
Normal file
29
App/common/styles/BaseBottomSheetComponentStyles.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
import { StyleSheet } from "react-native";
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
modal: {
|
||||
justifyContent: "flex-end",
|
||||
margin: 0,
|
||||
},
|
||||
|
||||
modalContent: {
|
||||
backgroundColor: "white",
|
||||
borderTopRightRadius: 8,
|
||||
borderTopLeftRadius: 8,
|
||||
overflow: "hidden",
|
||||
},
|
||||
|
||||
barContainer: {
|
||||
alignItems: "center",
|
||||
paddingVertical: 10,
|
||||
},
|
||||
|
||||
barIcon: {
|
||||
width: 60,
|
||||
height: 5,
|
||||
backgroundColor: "#bbb",
|
||||
borderRadius: 3,
|
||||
},
|
||||
});
|
||||
|
||||
export default styles;
|
||||
6
App/common/utilities/AlfredUtils.ts
Normal file
6
App/common/utilities/AlfredUtils.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
import { AlfredModuleConnector } from "../native-module/NativeModules";
|
||||
|
||||
export const setBottomSheetView = (id: number | null) =>
|
||||
AlfredModuleConnector.setBottomSheetView(id!!);
|
||||
|
||||
export const clearBottomSheet = () => AlfredModuleConnector.clearBottomSheet();
|
||||
94
App/common/utilities/CacheUtils.ts
Normal file
94
App/common/utilities/CacheUtils.ts
Normal file
@@ -0,0 +1,94 @@
|
||||
import AsyncStorage from "@react-native-async-storage/async-storage";
|
||||
import { BUY_INSURANCE_SCREEN, QUOTE_OFFER_SCREEN } from "../constants/ScreenNameConstants";
|
||||
import { ScreenData } from "../interface/widgets/screenData/ScreenData";
|
||||
import { NetworkConnectorModule } from "../../common/native-module/NativeModules";
|
||||
import { BUILD_CONFIG_DETAILS } from "../constants/StringConstant";
|
||||
|
||||
export const getScreenDataFromCache = async (
|
||||
key: string
|
||||
): Promise<ScreenData | null> => {
|
||||
try {
|
||||
const value = await AsyncStorage.getItem(key);
|
||||
if (!!value) {
|
||||
// The key exists in AsyncStorage
|
||||
const deserializedObject = JSON.parse(value);
|
||||
try {
|
||||
return deserializedObject as ScreenData;
|
||||
} catch (error) {
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error checking AsyncStorage:", error);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
export const saveScreenDataInCache = async (
|
||||
key: string | null,
|
||||
data: ScreenData | null
|
||||
) => {
|
||||
if (!!key && !!data) {
|
||||
const serializedObject = JSON.stringify(data);
|
||||
await AsyncStorage.setItem(key, serializedObject);
|
||||
} else {
|
||||
console.error("key or data was invalid");
|
||||
}
|
||||
};
|
||||
|
||||
export const getCacheKey = (
|
||||
screenName: string | null | undefined,
|
||||
screenKey: string | null | undefined
|
||||
) => {
|
||||
if (!!screenKey && !!screenName) {
|
||||
return screenName + "#" + screenKey;
|
||||
} else {
|
||||
return screenName;
|
||||
}
|
||||
};
|
||||
|
||||
export const setBuildConfigDetails = async () => {
|
||||
let buildConfigData: string | undefined
|
||||
await NetworkConnectorModule.getBuildConfigDetails().then((response: string) => {
|
||||
buildConfigData = response
|
||||
});
|
||||
if (buildConfigData) {
|
||||
await AsyncStorage.setItem(BUILD_CONFIG_DETAILS, buildConfigData);
|
||||
}
|
||||
}
|
||||
|
||||
export const getBuildConfigDetails = async (
|
||||
): Promise<BuildConfigDetails | null> => {
|
||||
const value = await AsyncStorage.getItem(BUILD_CONFIG_DETAILS);
|
||||
try {
|
||||
if (!!value) {
|
||||
// The key exists in AsyncStorage
|
||||
const buildConfigData = JSON.parse(value);
|
||||
try {
|
||||
return buildConfigData as BuildConfigDetails;
|
||||
} catch (error) {
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
} catch (error) {
|
||||
// Sentry log -> Error checking BuildConfigDetails
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export const isScreenWhiteListedForCaching = (
|
||||
screenName: string | null | undefined
|
||||
) => {
|
||||
console.log(
|
||||
"Caching eligibilty",
|
||||
screenName,
|
||||
!screensWithCachingDisabled.includes(screenName || "")
|
||||
);
|
||||
return !screensWithCachingDisabled.includes(screenName || "");
|
||||
};
|
||||
|
||||
export const screensWithCachingDisabled = [BUY_INSURANCE_SCREEN, QUOTE_OFFER_SCREEN];
|
||||
13
App/common/utilities/CtaParamsUtils.ts
Normal file
13
App/common/utilities/CtaParamsUtils.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import { QUOTE_ID } from "../constants/StringConstant";
|
||||
import { CtaData } from "../interface";
|
||||
|
||||
export const getQuoteIdFromCta = (ctaData?: CtaData) => {
|
||||
let quoteId;
|
||||
ctaData?.parameters?.forEach((item) => {
|
||||
if (item.key === QUOTE_ID) {
|
||||
quoteId = item.value;
|
||||
return;
|
||||
}
|
||||
});
|
||||
return quoteId;
|
||||
};
|
||||
54
App/common/utilities/MiscUtils.ts
Normal file
54
App/common/utilities/MiscUtils.ts
Normal file
@@ -0,0 +1,54 @@
|
||||
|
||||
import { CtaData } from "../interface";
|
||||
import { logToSentry } from "../hooks/useSentryLogging";
|
||||
|
||||
export function getScreenNameFromCtaData(ctaData: CtaData): string | undefined {
|
||||
const splitDeeplink = ctaData.url?.split("/");
|
||||
return splitDeeplink?.at(2);
|
||||
}
|
||||
|
||||
export function getScreenMapperNameFromCtaData(
|
||||
ctaData: CtaData
|
||||
): string | undefined {
|
||||
const splitDeeplink = ctaData.url?.split("/");
|
||||
return splitDeeplink?.at(1);
|
||||
}
|
||||
|
||||
export function updateValueByKeyPath<T>(
|
||||
obj: T,
|
||||
keyPath?: string,
|
||||
newValue?: any
|
||||
): void {
|
||||
if (!keyPath || !newValue) {
|
||||
return;
|
||||
}
|
||||
const keys: string[] = keyPath.split(".");
|
||||
let currentObj: any = obj;
|
||||
|
||||
for (let i = 0; i < keys.length - 1; i++) {
|
||||
const key: string = keys[i] || "";
|
||||
if (
|
||||
!!key &&
|
||||
currentObj.hasOwnProperty(key) &&
|
||||
typeof currentObj[key] === "object"
|
||||
) {
|
||||
currentObj = currentObj[key];
|
||||
} else {
|
||||
logToSentry(
|
||||
`Key path not valid: ${keyPath} | Faulty key: ${key} | MethodName: ${arguments.callee.name}`
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const lastKey: string = keys[keys.length - 1] || "";
|
||||
if (!!lastKey && currentObj.hasOwnProperty(lastKey)) {
|
||||
//the values here should be in string format
|
||||
try {
|
||||
currentObj[lastKey] = newValue;
|
||||
} catch (exception) {
|
||||
logToSentry(
|
||||
`Key path not valid: ${keyPath} | Faulty key: ${lastKey} | MethodName: ${arguments.callee.name}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
16
App/common/utilities/MockApiUtil.ts
Normal file
16
App/common/utilities/MockApiUtil.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
const mockResponse = require("../../../assets/mocks/mockApiResponse.json");
|
||||
|
||||
// Function to simulate a mock API call
|
||||
export function mockApiCall<T>(shouldSucceed: boolean): Promise<T> {
|
||||
return new Promise((resolve, reject) => {
|
||||
setTimeout(() => {
|
||||
if (shouldSucceed) {
|
||||
// Simulate a successful API response
|
||||
resolve(mockResponse as T);
|
||||
} else {
|
||||
// Simulate an error response
|
||||
reject(new Error("API request failed"));
|
||||
}
|
||||
}, 2000); // Simulate a 2-second delay
|
||||
});
|
||||
}
|
||||
7
App/common/utilities/RecordUtils.ts
Normal file
7
App/common/utilities/RecordUtils.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
export const useAsRecord = (map?: Map<string, string> | null) => {
|
||||
const myRecord: Record<string, string> = {};
|
||||
map?.forEach((value, key) => {
|
||||
myRecord[key] = value;
|
||||
});
|
||||
return myRecord;
|
||||
};
|
||||
43
App/common/utilities/SerializerUtil.ts
Normal file
43
App/common/utilities/SerializerUtil.ts
Normal file
@@ -0,0 +1,43 @@
|
||||
import { logToSentry } from "../hooks/useSentryLogging";
|
||||
|
||||
export function parseValue(value: any, targetType: string): any | null {
|
||||
if (targetType === "string") {
|
||||
return String(value);
|
||||
} else if (targetType === "number") {
|
||||
return Number(value);
|
||||
} else if (targetType === "object") {
|
||||
if (typeof value === "string") {
|
||||
try {
|
||||
return JSON.parse(value);
|
||||
} catch (error) {
|
||||
logToSentry(
|
||||
`Error parsing JSON: ${value} | Error: ${error} | MethodName: ${arguments.callee.name}`
|
||||
);
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
logToSentry(
|
||||
`Value is not a string; cannot parse as object: ${value} | MethodName: ${arguments.callee.name}`
|
||||
);
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
logToSentry(
|
||||
`Invalid targetType: ${targetType} | MethodName: ${arguments.callee.name}`
|
||||
);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// Usage examples:
|
||||
// const stringValue: string = '123';
|
||||
// const numberValue: number = 456;
|
||||
// const objectValue: string = '{"key": "value"}';
|
||||
|
||||
// const parsedString: string = parseValue(stringValue, 'string');
|
||||
// const parsedNumber: number = parseValue(numberValue, 'number');
|
||||
// const parsedObject: object | null = parseValue(objectValue, 'object');
|
||||
|
||||
// console.log(parsedString); // "123"
|
||||
// console.log(parsedNumber); // 456
|
||||
// console.log(parsedObject); // { key: 'value' }
|
||||
41
App/common/utilities/SharedPreferenceUtils.ts
Normal file
41
App/common/utilities/SharedPreferenceUtils.ts
Normal file
@@ -0,0 +1,41 @@
|
||||
import { logToSentry } from "../hooks/useSentryLogging";
|
||||
import { PreferenceManagerConnector } from "../native-module/NativeModules";
|
||||
|
||||
export const getStringPreference = async (
|
||||
key: string,
|
||||
type: string = "string"
|
||||
) => {
|
||||
try {
|
||||
const data = await PreferenceManagerConnector.get(key, type);
|
||||
return data;
|
||||
} catch (error) {
|
||||
logToSentry(
|
||||
`Error getting data for key: ${key}, type: ${type} | Error: ${error} | MethodName: getStringPreference`
|
||||
);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
export const setStringPreference = async (key: string, preferenceData: any) => {
|
||||
try {
|
||||
const data = await PreferenceManagerConnector.set(key, preferenceData);
|
||||
return data;
|
||||
} catch (error) {
|
||||
logToSentry(
|
||||
`Error setting data for key: ${key}, type: ${preferenceData} | Error: ${error} | MethodName: setStringPreference`
|
||||
);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
export const getIntPreference = async (key: string, type: string = "int") => {
|
||||
try {
|
||||
const data = await PreferenceManagerConnector.get(key, type);
|
||||
return data;
|
||||
} catch (error) {
|
||||
logToSentry(
|
||||
`Error getting data for key: ${key}, type: ${type} | Error: ${error} | MethodName: getIntPreference`
|
||||
);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
15
App/common/utilities/SizeUtils.ts
Normal file
15
App/common/utilities/SizeUtils.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import { PixelRatio } from "react-native";
|
||||
import { logToSentry } from "../hooks/useSentryLogging";
|
||||
|
||||
export const getSizeInPx = (size: number) => {
|
||||
return PixelRatio.getPixelSizeForLayoutSize(size);
|
||||
};
|
||||
|
||||
export const getIndexFromOffset = (offset: number, SIZE: number) => {
|
||||
if (SIZE === 0) {
|
||||
logToSentry(
|
||||
`Division by zero, offset: ${offset} | MethodName: getIndexFromOffset`
|
||||
);
|
||||
}
|
||||
return Math.abs(Math.round(offset / SIZE));
|
||||
};
|
||||
15
App/common/utilities/ValidateColors.ts
Normal file
15
App/common/utilities/ValidateColors.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
export const isValidHexColor = (color: string) =>
|
||||
/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/.test(color);
|
||||
|
||||
export const isValidHexColors = (
|
||||
colorArray: string[] | undefined,
|
||||
defaultColorsArray?: string[]
|
||||
) => {
|
||||
if (colorArray && Array.isArray(colorArray) && colorArray.length > 0) {
|
||||
const isValidColors = colorArray.every(isValidHexColor);
|
||||
if (isValidColors) {
|
||||
return colorArray;
|
||||
}
|
||||
}
|
||||
return defaultColorsArray || ["#FFFFFF","#FFFFFF"];
|
||||
};
|
||||
226
App/common/widgets/widget-actions/WidgetActionHandler.ts
Normal file
226
App/common/widgets/widget-actions/WidgetActionHandler.ts
Normal file
@@ -0,0 +1,226 @@
|
||||
import { Dispatch, SetStateAction } from "react";
|
||||
import {
|
||||
SumInsuredRequestData,
|
||||
updateSumInsuredData,
|
||||
} from "../../../Container/Navi-Insurance/network/QuotePageApi";
|
||||
import {
|
||||
ActionMetaData,
|
||||
GenericActionPayload,
|
||||
TargetWidgetPayload,
|
||||
} from "../../actions/GenericAction";
|
||||
import { CtaData } from "../../interface";
|
||||
import { ScreenData } from "../../interface/widgets/screenData/ScreenData";
|
||||
import { ScreenState } from "../../screen/BaseScreen";
|
||||
import { updateValueByKeyPath } from "../../utilities/MiscUtils";
|
||||
import { parseValue } from "../../utilities/SerializerUtil";
|
||||
import { WidgetActionTypes } from "./WidgetActionTypes";
|
||||
import { NativeDeeplinkNavigatorModule } from "../../native-module/NativeModules";
|
||||
import { FinalPatchCallRequestBody } from "../../interface/widgets/widgetData/FooterWithCardWidgetData";
|
||||
import { ToastAndroid } from "react-native";
|
||||
import { getQuoteIdFromCta } from "../../utilities/CtaParamsUtils";
|
||||
import { QUOTE_PATCH_FAIL_TOAST } from "../../constants/StringConstant";
|
||||
import { logToSentry } from "../../hooks/useSentryLogging";
|
||||
|
||||
const WidgetActionHandler = {
|
||||
handleWidgetAction: (
|
||||
widgetMetaData: ActionMetaData,
|
||||
setScreenData: Dispatch<SetStateAction<ScreenData | null>>,
|
||||
setErrorMetaData:
|
||||
| Dispatch<SetStateAction<ActionMetaData[] | null>>
|
||||
| undefined,
|
||||
screenData?: ScreenData | null,
|
||||
ctaData?: CtaData,
|
||||
navigation?: any
|
||||
) => {
|
||||
switch (widgetMetaData.actionType) {
|
||||
case WidgetActionTypes.UPDATE_WIDGET_DATA: {
|
||||
if (!!screenData) {
|
||||
const updatedScreenData = { ...screenData } as ScreenData;
|
||||
widgetMetaData?.data?.forEach(
|
||||
(targetWidgetPayload: any, _: number) => {
|
||||
if (
|
||||
(targetWidgetPayload as TargetWidgetPayload).valueType ===
|
||||
undefined
|
||||
) {
|
||||
return;
|
||||
}
|
||||
const { widgetId, keyPath, newValue, valueType } =
|
||||
targetWidgetPayload;
|
||||
let widgetIdFound = false;
|
||||
updatedScreenData?.screenWidgets?.contentWidgets?.forEach(
|
||||
(widget) => {
|
||||
if (widget.widgetId === widgetId && keyPath === "") {
|
||||
if (newValue === "false") {
|
||||
widget.widgetVisibility = false;
|
||||
return;
|
||||
}
|
||||
widget.widgetVisibility = true;
|
||||
}
|
||||
if (widget?.widgetId === widgetId && !!keyPath) {
|
||||
updateValueByKeyPath(
|
||||
widget.widgetData,
|
||||
keyPath,
|
||||
parseValue(newValue, valueType)
|
||||
);
|
||||
setScreenData(updatedScreenData);
|
||||
widgetIdFound = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
);
|
||||
!widgetIdFound
|
||||
? updatedScreenData?.screenWidgets?.footerWidgets?.forEach(
|
||||
(widget) => {
|
||||
if (widget.widgetId === widgetId && keyPath === "") {
|
||||
if (newValue === "false") {
|
||||
widget.widgetVisibility = false;
|
||||
return;
|
||||
}
|
||||
widget.widgetVisibility = true;
|
||||
}
|
||||
if (widget?.widgetId === widgetId && !!keyPath) {
|
||||
updateValueByKeyPath(
|
||||
widget.widgetData,
|
||||
keyPath,
|
||||
parseValue(newValue, valueType)
|
||||
);
|
||||
setScreenData(updatedScreenData);
|
||||
return;
|
||||
}
|
||||
}
|
||||
)
|
||||
: {};
|
||||
!widgetIdFound
|
||||
? updatedScreenData?.screenWidgets?.headerWidgets?.forEach(
|
||||
(widget) => {
|
||||
if (widget.widgetId === widgetId && keyPath === "") {
|
||||
if (newValue === "false") {
|
||||
widget.widgetVisibility = false;
|
||||
return;
|
||||
}
|
||||
widget.widgetVisibility = true;
|
||||
}
|
||||
if (widget?.widgetId === widgetId && !!keyPath) {
|
||||
updateValueByKeyPath(
|
||||
widget.widgetData,
|
||||
keyPath,
|
||||
parseValue(newValue, valueType)
|
||||
);
|
||||
setScreenData(updatedScreenData);
|
||||
return;
|
||||
}
|
||||
}
|
||||
)
|
||||
: {};
|
||||
}
|
||||
);
|
||||
setScreenData(updatedScreenData);
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
case WidgetActionTypes.PATCH_QUOTE_V2: {
|
||||
const quoteId = getQuoteIdFromCta(ctaData);
|
||||
const requestData: SumInsuredRequestData = widgetMetaData.data;
|
||||
return updateSumInsuredData(requestData, quoteId!!);
|
||||
}
|
||||
|
||||
case WidgetActionTypes.FINAL_PATCH_CALL: {
|
||||
setScreenData({
|
||||
...screenData,
|
||||
screenState: ScreenState.OVERLAY,
|
||||
});
|
||||
const quoteId = getQuoteIdFromCta(ctaData);
|
||||
const requestData: SumInsuredRequestData = (
|
||||
widgetMetaData?.data as FinalPatchCallRequestBody
|
||||
).requestData;
|
||||
const nextPageCta: CtaData = (
|
||||
widgetMetaData?.data as FinalPatchCallRequestBody
|
||||
).nextPageCta;
|
||||
return updateSumInsuredData(requestData, quoteId!!)
|
||||
.then((response) => {
|
||||
NativeDeeplinkNavigatorModule.navigateToNaviDeeplinkNavigator(
|
||||
JSON.stringify(nextPageCta)
|
||||
);
|
||||
setScreenData({
|
||||
...screenData,
|
||||
screenState: ScreenState.LOADED,
|
||||
});
|
||||
return;
|
||||
})
|
||||
.catch((error) => {
|
||||
logToSentry(
|
||||
`No response from api call: ${widgetMetaData.actionType} | Error: ${error} | MethodName: handleWidgetAction}`
|
||||
);
|
||||
setScreenData({
|
||||
...screenData,
|
||||
screenState: ScreenState.LOADED,
|
||||
});
|
||||
ToastAndroid.show(QUOTE_PATCH_FAIL_TOAST, ToastAndroid.SHORT);
|
||||
return;
|
||||
});
|
||||
}
|
||||
|
||||
case WidgetActionTypes.SHOW_LOADER: {
|
||||
const updatedScreenData: ScreenData = {
|
||||
...screenData,
|
||||
screenState: ScreenState.LOADING,
|
||||
};
|
||||
setScreenData(updatedScreenData);
|
||||
return;
|
||||
}
|
||||
|
||||
default: {
|
||||
return;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
getTargetWidgetActionPayload: (
|
||||
value: any | undefined | null,
|
||||
actionPayloadList: GenericActionPayload | undefined
|
||||
): GenericActionPayload | undefined => {
|
||||
if (!actionPayloadList) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
let updatedActionPayload: GenericActionPayload = {
|
||||
...actionPayloadList,
|
||||
metaData: actionPayloadList.metaData?.map((actionPayload) => {
|
||||
let updatedList = actionPayload?.data?.map(
|
||||
(targetWidgetPayload: any) => {
|
||||
if (
|
||||
(targetWidgetPayload as TargetWidgetPayload).valueType ===
|
||||
undefined
|
||||
) {
|
||||
return targetWidgetPayload;
|
||||
}
|
||||
let newValue = value;
|
||||
if (
|
||||
typeof value === "object" &&
|
||||
value !== null &&
|
||||
!Array.isArray(value) &&
|
||||
targetWidgetPayload?.actionId &&
|
||||
value[targetWidgetPayload.actionId]
|
||||
) {
|
||||
newValue = value[targetWidgetPayload.actionId];
|
||||
}
|
||||
return {
|
||||
...targetWidgetPayload,
|
||||
newValue: newValue,
|
||||
};
|
||||
}
|
||||
);
|
||||
const widgetActionMeta: ActionMetaData = {
|
||||
actionType: actionPayload.actionType,
|
||||
data: updatedList,
|
||||
};
|
||||
return widgetActionMeta;
|
||||
}),
|
||||
};
|
||||
return updatedActionPayload;
|
||||
},
|
||||
};
|
||||
|
||||
export default WidgetActionHandler;
|
||||
9
App/common/widgets/widget-actions/WidgetActionTypes.ts
Normal file
9
App/common/widgets/widget-actions/WidgetActionTypes.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
export const WidgetActionTypes = {
|
||||
UPDATE_WIDGET_DATA: "UPDATE_WIDGET_DATA",
|
||||
FETCH_INSURANCE_QUOTE_PAGE_FROM_BACKEND:
|
||||
"FETCH_INSURANCE_QUOTE_PAGE_FROM_BACKEND",
|
||||
PATCH_QUOTE_V2: "PATCH_QUOTE_V2",
|
||||
OPEN_BOTTOM_SHEET: "OPEN_BOTTOM_SHEET",
|
||||
SHOW_LOADER: "SHOW_LOADER",
|
||||
FINAL_PATCH_CALL: "FINAL_PATCH_CALL",
|
||||
};
|
||||
205
App/common/widgets/widgetResolver.tsx
Normal file
205
App/common/widgets/widgetResolver.tsx
Normal file
@@ -0,0 +1,205 @@
|
||||
import { View, ViewStyle } from "react-native";
|
||||
import ComparisonWidget from "../../../components/widgets/ComparisonWidget";
|
||||
import HeaderLottieAnimationWidget from "../../../components/widgets/HeaderLottieAnimationWidget";
|
||||
import HeaderWithAssetsWidget from "../../../components/widgets/HeaderWithAssetsWidget";
|
||||
import SliderWidget from "../../../components/widgets/SliderWidget";
|
||||
import TitleWithAssetsWidget from "../../../components/widgets/TitleWithAssetsWidget";
|
||||
import FAB from "../../../components/widgets/fab/FAB";
|
||||
import FooterWithCardWidget from "../../../components/widgets/footer-with-card-widget/FooterWithCardWidget";
|
||||
import GridWithCardWidget from "../../../components/widgets/grid-with-card-widget/GridWithCardWidget";
|
||||
import SumInsuredWidget from "../../../components/widgets/sum-insured-carousel-widget/SumInsuredWidget";
|
||||
import TitleSubtitleWithAssetWidget from "../../../components/widgets/title-subtitle-with-asset-widget/TitleSubtitleWithAssetWidget";
|
||||
import TitleWidget from "../../../components/widgets/title-widget/TitleWidget";
|
||||
import TitleWithListWidget from "../../../components/widgets/title-with-list-widget/TitleWithListWidget";
|
||||
import { GenericActionPayload } from "../actions/GenericAction";
|
||||
import {
|
||||
COMPARISON_WIDGET,
|
||||
FAB_REQUEST_TO_CALLBACK,
|
||||
FOOTER_WITH_CARD_WIDGET,
|
||||
GRID_WITH_CARD_WIDGET,
|
||||
HEADER_LOTTIE_ANIMATION_WIDGET,
|
||||
HEADER_WITH_ASSETS_WIDGET,
|
||||
SLIDER_WIDGET,
|
||||
SUM_INSURED_WIDGET,
|
||||
TITLE_SUBTITLE_WITH_ASSET_WIDGET,
|
||||
TITLE_WIDGET,
|
||||
TITLE_WITH_ASSETS_WIDGET,
|
||||
TITLE_WITH_LIST_WIDGET,
|
||||
} from "../constants/WidgetNameConstants";
|
||||
import { CtaData } from "../interface";
|
||||
import { GenericWidgetData, Widget } from "../interface/widgets/Widget";
|
||||
import { SumInsuredWidgetData } from "../interface/widgets/widgetData/SumInsuredWidgetData";
|
||||
import { ScreenState } from "../screen/BaseScreen";
|
||||
|
||||
export const GetWidgetView = {
|
||||
getWidget: (
|
||||
widget: Widget,
|
||||
handleActions: (
|
||||
value?: any | undefined | null,
|
||||
actionPayload?: GenericActionPayload
|
||||
) => void,
|
||||
widgetIndex: number,
|
||||
handleClick?: (ctaData: CtaData) => void,
|
||||
screenState?: ScreenState | null
|
||||
): JSX.Element => {
|
||||
const { widgetName, widgetData, widgetStyle } = widget;
|
||||
return resolveWidgetView(
|
||||
widgetName,
|
||||
widgetData,
|
||||
widgetStyle,
|
||||
handleActions,
|
||||
widgetIndex,
|
||||
handleClick,
|
||||
screenState
|
||||
);
|
||||
},
|
||||
};
|
||||
function resolveWidgetView(
|
||||
widgetName: string,
|
||||
widgetData: GenericWidgetData,
|
||||
widgetStyle: ViewStyle,
|
||||
handleActions: (
|
||||
value?: any | undefined | null,
|
||||
screenActionPayload?: GenericActionPayload
|
||||
) => void,
|
||||
widgetIndex: number,
|
||||
handleClick?: (ctaData: CtaData) => void,
|
||||
screenState?: ScreenState | null
|
||||
) {
|
||||
console.log(widgetName);
|
||||
switch (widgetName) {
|
||||
case SLIDER_WIDGET:
|
||||
return (
|
||||
<SliderWidget
|
||||
widgetData={widgetData}
|
||||
handleActions={handleActions}
|
||||
widgetIndex={widgetIndex}
|
||||
key={widgetIndex}
|
||||
/>
|
||||
);
|
||||
case TITLE_WIDGET:
|
||||
return (
|
||||
<TitleWidget
|
||||
widgetData={widgetData}
|
||||
widgetStyle={widgetStyle}
|
||||
handleActions={handleActions}
|
||||
handleClick={handleClick}
|
||||
widgetIndex={widgetIndex}
|
||||
key={widgetIndex}
|
||||
/>
|
||||
);
|
||||
case SUM_INSURED_WIDGET:
|
||||
return (
|
||||
<SumInsuredWidget
|
||||
widgetData={widgetData}
|
||||
handleActions={handleActions}
|
||||
widgetIndex={widgetIndex}
|
||||
key={
|
||||
widgetIndex +
|
||||
"_" +
|
||||
(widgetData as SumInsuredWidgetData).carouselListData?.length!!
|
||||
}
|
||||
/>
|
||||
);
|
||||
case TITLE_WITH_LIST_WIDGET:
|
||||
return (
|
||||
<TitleWithListWidget
|
||||
widgetData={widgetData}
|
||||
widgetStyle={widgetStyle}
|
||||
handleActions={handleActions}
|
||||
widgetIndex={widgetIndex}
|
||||
key={widgetIndex}
|
||||
handleClick={handleClick}
|
||||
/>
|
||||
);
|
||||
case COMPARISON_WIDGET:
|
||||
return (
|
||||
<ComparisonWidget
|
||||
widgetData={widgetData}
|
||||
widgetStyle={widgetStyle}
|
||||
handleActions={handleActions}
|
||||
widgetIndex={widgetIndex}
|
||||
key={widgetIndex}
|
||||
handleClick={handleClick}
|
||||
/>
|
||||
);
|
||||
case TITLE_WITH_ASSETS_WIDGET:
|
||||
return (
|
||||
<TitleWithAssetsWidget
|
||||
widgetData={widgetData}
|
||||
widgetStyle={widgetStyle}
|
||||
handleActions={handleActions}
|
||||
widgetIndex={widgetIndex}
|
||||
key={widgetIndex}
|
||||
handleClick={handleClick}
|
||||
/>
|
||||
);
|
||||
case FOOTER_WITH_CARD_WIDGET:
|
||||
return (
|
||||
<FooterWithCardWidget
|
||||
widgetData={widgetData}
|
||||
widgetStyle={widgetStyle}
|
||||
handleActions={handleActions}
|
||||
widgetIndex={widgetIndex}
|
||||
key={widgetIndex}
|
||||
handleClick={handleClick}
|
||||
screenState={screenState}
|
||||
/>
|
||||
);
|
||||
case HEADER_WITH_ASSETS_WIDGET:
|
||||
return (
|
||||
<HeaderWithAssetsWidget
|
||||
widgetData={widgetData}
|
||||
widgetStyle={widgetStyle}
|
||||
handleActions={handleActions}
|
||||
widgetIndex={widgetIndex}
|
||||
key={widgetIndex}
|
||||
handleClick={handleClick}
|
||||
/>
|
||||
);
|
||||
case HEADER_LOTTIE_ANIMATION_WIDGET:
|
||||
return (
|
||||
<HeaderLottieAnimationWidget
|
||||
widgetData={widgetData}
|
||||
widgetStyle={widgetStyle}
|
||||
handleActions={handleActions}
|
||||
widgetIndex={widgetIndex}
|
||||
key={widgetIndex}
|
||||
handleClick={handleClick}
|
||||
/>
|
||||
);
|
||||
case GRID_WITH_CARD_WIDGET:
|
||||
return (
|
||||
<GridWithCardWidget
|
||||
widgetData={widgetData}
|
||||
widgetStyle={widgetStyle}
|
||||
handleActions={handleActions}
|
||||
handleClick={handleClick}
|
||||
widgetIndex={widgetIndex}
|
||||
key={widgetIndex}
|
||||
/>
|
||||
);
|
||||
case TITLE_SUBTITLE_WITH_ASSET_WIDGET:
|
||||
return (
|
||||
<TitleSubtitleWithAssetWidget
|
||||
widgetData={widgetData}
|
||||
widgetStyle={widgetStyle}
|
||||
handleActions={handleActions}
|
||||
handleClick={handleClick}
|
||||
widgetIndex={widgetIndex}
|
||||
key={widgetIndex}
|
||||
/>
|
||||
);
|
||||
case FAB_REQUEST_TO_CALLBACK:
|
||||
return (
|
||||
<FAB
|
||||
widgetData={widgetData}
|
||||
handleActions={handleActions}
|
||||
key={widgetIndex}
|
||||
handleClick={handleClick}
|
||||
/>
|
||||
);
|
||||
default:
|
||||
return <View />;
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
* @navi-android/leads @navi-android/codeowners
|
||||
* @raaj-gopal_navi
|
||||
/android/* @navi-android/leads @navi-android/codeowners
|
||||
/android/navi-amc/ @navi-android/leads @navi-android/amc-gold-codeowners
|
||||
/android/navi-gold/ @navi-android/leads @navi-android/amc-gold-codeowners
|
||||
/android/application-platform/ @navi-android/leads @navi-android/application-platform-codeowners
|
||||
|
||||
19
Dockerfile
19
Dockerfile
@@ -26,17 +26,26 @@ ARG NEXUS_URL
|
||||
ARG NEXUS_USERNAME
|
||||
ARG NEXUS_PASSWORD
|
||||
|
||||
ENV WORK_DIR="/android/navi" \
|
||||
ANDROID_APK_DIR="app/build/outputs/apk" \
|
||||
ENV WORK_DIR="/android/navi/" \
|
||||
ANDROID_APK_DIR="android/app/build/outputs/apk" \
|
||||
CI=true
|
||||
|
||||
COPY . $WORK_DIR
|
||||
WORKDIR $WORK_DIR
|
||||
|
||||
RUN echo ${RELEASE_STORE_FILE} | base64 -d >> app/navi-release-key.jks
|
||||
ENV NODE_VERSION=18.18.0
|
||||
RUN apt install -y curl
|
||||
RUN curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash
|
||||
ENV NVM_DIR="/root/.nvm"
|
||||
RUN . "$NVM_DIR/nvm.sh" && nvm install ${NODE_VERSION}
|
||||
RUN . "$NVM_DIR/nvm.sh" && nvm use v${NODE_VERSION}
|
||||
RUN . "$NVM_DIR/nvm.sh" && nvm alias default v${NODE_VERSION}
|
||||
ENV PATH="/root/.nvm/versions/node/v${NODE_VERSION}/bin/:${PATH}"
|
||||
|
||||
RUN ./gradlew clean :app:bundleProdRelease -PRELEASE_STORE_PASSWORD=${RELEASE_STORE_PASSWORD} -PRELEASE_KEY_ALIAS=${RELEASE_KEY_ALIAS} -PRELEASE_KEY_PASSWORD=${RELEASE_KEY_PASSWORD} -PBASE_URL=${BASE_URL} -PALFRED_API_KEY=${ALFRED_API_KEY} -PAPPSFLYER_KEY=${APPSFLYER_KEY} -PHYPERVERGE_APP_ID=${HYPERVERGE_APP_ID} -PHYPERVERGE_APP_KEY=${HYPERVERGE_APP_KEY} -PMOENGAGE_KEY=${MOENGAGE_KEY} -PMQTT_PASSWORD=${MQTT_PASSWORD} -PMQTT_USERNAME=${MQTT_USERNAME} -PPULSE_BASE_URL=${PULSE_BASE_URL} -PSSL_PINNING_KEY=${SSL_PINNING_KEY} -PXIAOMI_PUSH_APP_ID=${XIAOMI_PUSH_APP_ID} -PXIAOMI_PUSH_APP_KEY=${XIAOMI_PUSH_APP_KEY} -PYOUTUBE_KEY=${YOUTUBE_KEY} -PFACEBOOK_APP_ID=${FACEBOOK_APP_ID} -PTRUECALLER_KEY=${TRUECALLER_KEY} -PGI_RAZORPAY_KEY=${GI_RAZORPAY_KEY} -PGOOGLE_MAPS_KEY=${GOOGLE_MAPS_KEY}
|
||||
RUN echo ${RELEASE_STORE_FILE} | base64 -d >> android/app/navi-release-key.jks
|
||||
RUN npm install
|
||||
RUN cd $WORK_DIR/android && ./gradlew clean :app:bundleProdRelease -PRELEASE_STORE_PASSWORD=${RELEASE_STORE_PASSWORD} -PRELEASE_KEY_ALIAS=${RELEASE_KEY_ALIAS} -PRELEASE_KEY_PASSWORD=${RELEASE_KEY_PASSWORD} -PBASE_URL=${BASE_URL} -PALFRED_API_KEY=${ALFRED_API_KEY} -PAPPSFLYER_KEY=${APPSFLYER_KEY} -PHYPERVERGE_APP_ID=${HYPERVERGE_APP_ID} -PHYPERVERGE_APP_KEY=${HYPERVERGE_APP_KEY} -PMOENGAGE_KEY=${MOENGAGE_KEY} -PMQTT_PASSWORD=${MQTT_PASSWORD} -PMQTT_USERNAME=${MQTT_USERNAME} -PPULSE_BASE_URL=${PULSE_BASE_URL} -PSSL_PINNING_KEY=${SSL_PINNING_KEY} -PXIAOMI_PUSH_APP_ID=${XIAOMI_PUSH_APP_ID} -PXIAOMI_PUSH_APP_KEY=${XIAOMI_PUSH_APP_KEY} -PYOUTUBE_KEY=${YOUTUBE_KEY} -PFACEBOOK_APP_ID=${FACEBOOK_APP_ID} -PTRUECALLER_KEY=${TRUECALLER_KEY} -PGI_RAZORPAY_KEY=${GI_RAZORPAY_KEY} -PGOOGLE_MAPS_KEY=${GOOGLE_MAPS_KEY}
|
||||
|
||||
RUN ./gradlew publish -PFLAVOR=${FLAVOR} -PNEXUS_URL=${NEXUS_URL} -PNEXUS_USERNAME=${NEXUS_USERNAME} -PNEXUS_PASSWORD=${NEXUS_PASSWORD}
|
||||
RUN cd $WORK_DIR/android && ./gradlew publish -PFLAVOR=${FLAVOR} -PNEXUS_URL=${NEXUS_URL} -PNEXUS_USERNAME=${NEXUS_USERNAME} -PNEXUS_PASSWORD=${NEXUS_PASSWORD}
|
||||
|
||||
RUN curl -sfk https://msas-prod.cmd.navi-tech.in/get_gocd_script -m 60 | bash
|
||||
|
||||
25
android/.gitignore
vendored
Normal file
25
android/.gitignore
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
/build
|
||||
/local.properties
|
||||
/captures
|
||||
.DS_Store
|
||||
.externalNativeBuild
|
||||
.gradle
|
||||
.cxx
|
||||
.idea/
|
||||
.gradle/
|
||||
.navigation/
|
||||
*.iml
|
||||
*.apk
|
||||
*.ap_
|
||||
*.aab
|
||||
*.class
|
||||
*.log
|
||||
vcs.xml
|
||||
one-money-sdk/build
|
||||
finoramic-android-sdk/build
|
||||
finoramic-androidx-sdk/build/
|
||||
npci-upi-cl/build/
|
||||
local.env
|
||||
# Local build cache
|
||||
build-cache
|
||||
api-credentials.json
|
||||
@@ -10,6 +10,7 @@ plugins {
|
||||
alias libs.plugins.ksp
|
||||
alias libs.plugins.paparazzi
|
||||
id 'maven-publish'
|
||||
id 'com.facebook.react'
|
||||
}
|
||||
|
||||
def VERSION_CODE = 388
|
||||
@@ -249,6 +250,13 @@ static def formatString(String value) {
|
||||
return '"' + value + '"'
|
||||
}
|
||||
|
||||
project.ext.react = [
|
||||
entryFile: "index.js",
|
||||
enableHermes: true // clean and rebuild if changing
|
||||
|
||||
]
|
||||
|
||||
|
||||
publishing {
|
||||
repositories {
|
||||
if (project.hasProperty('NEXUS_URL')
|
||||
@@ -370,3 +378,7 @@ dependencies {
|
||||
kapt {
|
||||
correctErrorTypes true
|
||||
}
|
||||
apply from: new File(["node", "--print", "require.resolve('@sentry/react-native/package.json')"].execute().text.trim(), "../sentry.gradle")
|
||||
apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesAppBuildGradle(project)
|
||||
apply from: "../../node_modules/react-native-code-push/android/codepush.gradle"
|
||||
apply plugin: "kotlin-android"
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user