diff --git a/.prettierrc.json b/.prettierrc.json new file mode 100644 index 0000000000..e7700607bd --- /dev/null +++ b/.prettierrc.json @@ -0,0 +1,11 @@ +{ + "semi": true, + "tabWidth": 2, + "printWidth": 80, + "singleQuote": false, + "trailingComma": "all", + "bracketSameLine": false, + "useTabs": false, + "arrowParens": "avoid", + "bracketSpacing": true +} diff --git a/App.tsx b/App.tsx index 71e063ce4d..86793c3330 100644 --- a/App.tsx +++ b/App.tsx @@ -1,4 +1,3 @@ - import { init } from "@sentry/react-native"; import { Component } from "react"; import codePush from "react-native-code-push"; @@ -17,9 +16,9 @@ init({ }); export default class App extends Component<{}> { - checkForUpdates = async() => { + checkForUpdates = async () => { let flavor: string | undefined; - getBuildConfigDetails().then((res) => { + getBuildConfigDetails().then(res => { flavor = res?.baseUrl; }); await codePush.sync( @@ -27,9 +26,9 @@ export default class App extends Component<{}> { installMode: codePush.InstallMode.ON_NEXT_RESUME, mandatoryInstallMode: codePush.InstallMode.IMMEDIATE, }, - (status) => { + status => { this.onCodepushStatusChange(status); - } + }, ); }; @@ -37,31 +36,32 @@ export default class App extends Component<{}> { switch (status) { case codePush.SyncStatus.UPDATE_IGNORED: logToSentry( - `Codepush Ignored | Status: ${status} | MethodName: onCodepushStatusChange` + `Codepush Ignored | Status: ${status} | MethodName: onCodepushStatusChange`, ); break; case codePush.SyncStatus.UNKNOWN_ERROR: logToSentry( - `Codepush Failed | Status: ${status} | MethodName: onCodepushStatusChange` + `Codepush Failed | Status: ${status} | MethodName: onCodepushStatusChange`, ); - break; } }; + getInitialCta = (): CtaData | undefined => { const { CtaData } = this.props as any; if (!CtaData) { logToSentry( - `CtaData is missing or invalid: ${CtaData} | MethodName: getInitialCta` + `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` + `Error parsing CtaData: ${CtaData} | Error: ${error} | MethodName: getInitialCta`, ); return; } diff --git a/App/Container/Navi-Insurance/index.ts b/App/Container/Navi-Insurance/index.ts index 0314258901..d55c7c9f1e 100644 --- a/App/Container/Navi-Insurance/index.ts +++ b/App/Container/Navi-Insurance/index.ts @@ -1,6 +1,3 @@ - -import QuoteOfferScreen from "./screen/quote-offer-screen/QuoteOfferScreen"; - -export { - QuoteOfferScreen, -}; +export { default as QuoteOfferScreen } from "./screen/quote-offer-screen/QuoteOfferScreen"; +export { default as QuoteApologyScreen } from "./screen/quote-apology-screen/QuoteApologyScreen"; +export { default as ComparePlanScreen } from "./screen/compare-plan-screen/ComparePlanScreen"; \ No newline at end of file diff --git a/App/Container/Navi-Insurance/network/QuotePageApi.ts b/App/Container/Navi-Insurance/network/QuotePageApi.ts index 9bd24b3f84..690590e46a 100644 --- a/App/Container/Navi-Insurance/network/QuotePageApi.ts +++ b/App/Container/Navi-Insurance/network/QuotePageApi.ts @@ -5,9 +5,17 @@ import { ScreenData } from "../../../common/interface/widgets/screenData/ScreenD export interface SumInsuredRequestData { sumInsured: string; + planId?: string; } -export const updateSumInsuredData = async (data: SumInsuredRequestData, quoteId: string) => { +export const updateSumInsuredData = async ( + data: SumInsuredRequestData, + quoteId: string, +) => { const url = `v3/quotes/${quoteId}`; - return patch>(url, data, getXTargetHeaderInfo(GI.toLocaleUpperCase())); + return patch>( + url, + data, + getXTargetHeaderInfo(GI.toLocaleUpperCase()), + ); }; diff --git a/App/Container/Navi-Insurance/screen/compare-plan-screen/ComparePlanScreen.tsx b/App/Container/Navi-Insurance/screen/compare-plan-screen/ComparePlanScreen.tsx new file mode 100644 index 0000000000..57e3f757cd --- /dev/null +++ b/App/Container/Navi-Insurance/screen/compare-plan-screen/ComparePlanScreen.tsx @@ -0,0 +1,149 @@ +import React, { useEffect } from "react"; +import { ScrollView, Text, View } from "react-native"; +import { CtaData, CtaType } from "../../../../common/interface"; +import { ScreenData } from "../../../../common/interface/widgets/screenData/ScreenData"; +import { + BaseActionTypes, + GenericActionPayload, +} from "../../../../common/actions/GenericAction"; +import { ScreenActionTypes } from "../../../../common/screen/ScreenActionTypes"; +import { Widget } from "../../../../common/interface/widgets/Widget"; +import { ScreenState } from "../../../../common/screen/BaseScreen"; +import BaseWidget from "../../../../../components/widgets/BaseWidget"; +import { logToSentry } from "../../../../common/hooks/useSentryLogging"; +import { NativeDeeplinkNavigatorModule } from "../../../../common/native-module/NativeModules"; +import { useNavigation } from "@react-navigation/native"; +import ComparePlanShimmerScreen from "./shimmer-screen/ComparePlanShimmerScreen"; +import { + CtaNavigator, + extractCtaParameters, +} from "../../../../common/navigator/NavigationRouter"; +import QuoteOfferErrorScreen from "../quote-offer-screen/error-screen/QuoteOfferErrorScreen"; +import { ConstantCta } from "../../../../common/constants"; + +const ComparePlanScreen = ({ + ctaData, + screenData, + handleActions, +}: { + ctaData: CtaData; + screenData: ScreenData | null; + handleActions: (screenPayload?: GenericActionPayload) => void; +}) => { + const navigation = useNavigation(); + const handleClick = (cta?: CtaData) => { + if (!cta) { + logToSentry( + `Navigation cta is missing or invalid: ${cta} | MethodName: handleClick}`, + ); + return; + } + + const { navigatorType } = extractCtaParameters(cta); + + try { + switch (cta.type) { + case CtaType.DEEP_LINK: + case CtaType.USE_ROOT_DEEPLINK_NAVIGATOR: + NativeDeeplinkNavigatorModule.navigateToNaviInsuranceDeeplinkNavigator( + JSON.stringify(cta), + ); + break; + case CtaType.RN_NAVIGATOR: + CtaNavigator.performNavigation(navigation, navigatorType, cta); + break; + default: + NativeDeeplinkNavigatorModule.navigateToNaviDeeplinkNavigator( + JSON.stringify(cta), + ); + break; + } + } catch (error) { + logToSentry( + `Error while navigating to deep link with CTA: ${cta} | MethodName: handleClick}`, + ); + } + }; + useEffect(() => { + handleActions({ + baseActionType: BaseActionTypes.SCREEN_ACTION, + metaData: [ + { + actionType: ScreenActionTypes.FETCH_COMPARE_PLAN_LIST, + data: ctaData?.data, + }, + ], + }); + }, [ctaData]); + + const Header = () => { + return getWidgetViews( + screenData?.screenWidgets?.headerWidgets, + handleActions, + screenData?.screenState, + handleClick, + ); + }; + + const ContentWidgets = () => { + return getWidgetViews( + screenData?.screenWidgets?.contentWidgets, + handleActions, + screenData?.screenState, + handleClick, + ); + }; + + if (screenData?.screenState === ScreenState.LOADING) { + return ; + } + + if (screenData?.screenState === ScreenState.ERROR) { + return ( + + ); + } + + return ( + +
+ + + + + ); +}; + +function getWidgetViews( + widgetList: Widget[] | undefined, + handleActions: (screenActionPayload?: GenericActionPayload) => void, + screenState?: ScreenState | null, + handleClick?: (ctaData: CtaData) => void, +): React.JSX.Element { + return ( + + {widgetList?.map((widget, index) => { + return ( + + ); + })} + + ); +} + +export default ComparePlanScreen; diff --git a/App/Container/Navi-Insurance/screen/compare-plan-screen/shimmer-screen/ComparePlanShimmerScreen.tsx b/App/Container/Navi-Insurance/screen/compare-plan-screen/shimmer-screen/ComparePlanShimmerScreen.tsx new file mode 100644 index 0000000000..2d3309ff4a --- /dev/null +++ b/App/Container/Navi-Insurance/screen/compare-plan-screen/shimmer-screen/ComparePlanShimmerScreen.tsx @@ -0,0 +1,51 @@ +import { View } from "react-native"; +import SkeletonPlaceholder from "react-native-skeleton-placeholder"; +import Colors from "../../../../../../assets/colors/colors"; +import styles from "./ComparePlanShimmerScreenStyle"; +import { StaticHeader } from "../../../../../../components/reusable/static-header/StaticHeader"; +import { CtaData } from "../../../../../common/interface"; +import { ConstantCta } from "../../../../../common/constants/CtaConstants"; + +const ComparePlanShimmerScreen = ({ + handleClick, +}: { + handleClick?: (ctaData: CtaData) => void; +}) => { + return ( + + + + + + + ); +}; + +export default ComparePlanShimmerScreen; + +const ContentShimmer = () => { + return ( + + + + + + + + + + + + + ); +}; diff --git a/App/Container/Navi-Insurance/screen/compare-plan-screen/shimmer-screen/ComparePlanShimmerScreenStyle.ts b/App/Container/Navi-Insurance/screen/compare-plan-screen/shimmer-screen/ComparePlanShimmerScreenStyle.ts new file mode 100644 index 0000000000..7f789ff6c5 --- /dev/null +++ b/App/Container/Navi-Insurance/screen/compare-plan-screen/shimmer-screen/ComparePlanShimmerScreenStyle.ts @@ -0,0 +1,70 @@ +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: { + marginTop: 12, + alignSelf : "flex-end", + width: "50%", + height: 94, + borderRadius: 4 + }, + shimmerLayout2: { + marginTop: 24, + height: 94, + alignItems: "center", + borderRadius: 4, + flexShrink: 0, + gap: 10.5, + }, + + shimmerHeaderLayout: { + marginHorizontal: 16, + marginTop: 16, + marginBottom: 24, + height: 49, + alignItems: "center", + borderRadius: 4, + flexShrink: 0, + gap: 10.5, + }, +}); + +export default styles; diff --git a/App/Container/Navi-Insurance/screen/quote-offer-screen/QuoteOfferScreen.tsx b/App/Container/Navi-Insurance/screen/quote-offer-screen/QuoteOfferScreen.tsx index 354c511624..c1a1380ed6 100644 --- a/App/Container/Navi-Insurance/screen/quote-offer-screen/QuoteOfferScreen.tsx +++ b/App/Container/Navi-Insurance/screen/quote-offer-screen/QuoteOfferScreen.tsx @@ -1,4 +1,4 @@ -import React, { useEffect } from "react"; +import React, { useCallback, useEffect } from "react"; import { EmitterSubscription, NativeEventEmitter, @@ -13,7 +13,6 @@ import Animated, { } from "react-native-reanimated"; import Colors from "../../../../../assets/colors/colors"; import BaseWidget from "../../../../../components/widgets/BaseWidget"; -import FAB from "../../../../../components/widgets/fab/FAB"; import { BaseActionTypes, GenericActionPayload, @@ -30,15 +29,18 @@ import { AnalyticsEvent, CtaData, CtaType } from "../../../../common/interface"; import { Widget } from "../../../../common/interface/widgets/Widget"; import { ScreenData } from "../../../../common/interface/widgets/screenData/ScreenData"; import { FabWidgetData } from "../../../../common/interface/widgets/widgetData/FabWidgetData"; -import { - NativeDeeplinkNavigatorModule, - PreferenceManagerConnector, -} from "../../../../common/native-module/NativeModules"; +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 FAB from "../../../../../components/widgets/fab/FAB"; +import { useNavigation } from "@react-navigation/native"; +import { + CtaNavigator, + extractCtaParameters, +} from "../../../../common/navigator/NavigationRouter"; import { getStringPreference, setStringPreference, @@ -47,6 +49,8 @@ import { invalidateCacheWithUrl, shouldInvalidateSavedData, } from "../../../../common/utilities/CacheUtils"; +import throttle from "lodash/throttle"; +import { ConstantCta, ScreenProperties } from "../../../../common/constants"; const QuoteOfferScreen = ({ ctaData, screenData, @@ -58,6 +62,7 @@ const QuoteOfferScreen = ({ }) => { const y = useSharedValue(0); const lastScrollPosition = useSharedValue(0); + const navigation = useNavigation(); const onScroll = (event: NativeSyntheticEvent) => { lastScrollPosition.value = y.value; @@ -68,30 +73,40 @@ const QuoteOfferScreen = ({ return { maxWidth: withTiming( y.value < lastScrollPosition.value || y.value <= 0 ? 120 : 0, - { duration: 100 } + { duration: 100 }, ), paddingRight: withTiming( y.value < lastScrollPosition.value || y.value <= 0 ? 16 : 0, - { duration: 100 } + { duration: 100 }, ), opacity: withTiming( y.value < lastScrollPosition.value || y.value <= 0 ? 1 : 0, - { duration: 100 } + { duration: 100 }, ), }; }); + let animateHeader = true; + + screenData?.screenMetaData?.screenProperties?.forEach(item => { + if (item.key === ScreenProperties.ANIMATE_HEADER) + animateHeader = !!item?.value; + }); + const headerBgStyle = useAnimatedStyle(() => { + if (!animateHeader) return { backgroundColor: Colors.white }; return { backgroundColor: y.value > HEADER_LOTTIE_WIDGET_HEIGHT ? Colors.grey : y.value > HEADER_LOTTIE_TITLE_HEIGHT - ? Colors.aliceBlue - : Colors.transparent, + ? Colors.aliceBlue + : Colors.transparent, }; }); + const { preQuoteId, quoteId, navigatorType } = extractCtaParameters(ctaData); + const validatePostApiData = async () => { return await getStringPreference("POST_API_CALLED", "string"); }; @@ -100,23 +115,13 @@ const QuoteOfferScreen = ({ return setStringPreference("POST_API_CALLED", "false"); }; - 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 nativeEventListener = new NativeEventEmitter(); let reloadPageEventListener = {} as EmitterSubscription; const handleClick = (cta?: CtaData) => { if (!cta) { logToSentry( - `Navigation cta is missing or invalid: ${cta} | MethodName: handleClick}` + `Navigation cta is missing or invalid: ${cta} | MethodName: handleClick}`, ); return; } @@ -130,26 +135,37 @@ const QuoteOfferScreen = ({ case CtaType.DEEP_LINK: case CtaType.USE_ROOT_DEEPLINK_NAVIGATOR: NativeDeeplinkNavigatorModule.navigateToNaviInsuranceDeeplinkNavigator( - JSON.stringify(cta) + JSON.stringify(cta), ); break; + case CtaType.RN_NAVIGATOR: + CtaNavigator.performNavigation(navigation, navigatorType, cta); + break; default: NativeDeeplinkNavigatorModule.navigateToNaviDeeplinkNavigator( - JSON.stringify(cta) + JSON.stringify(cta), ); break; } } catch (error) { logToSentry( - `Error while navigating to deep link with CTA: ${cta} | MethodName: handleClick}` + `Error while navigating to deep link with CTA: ${cta} | MethodName: handleClick}`, ); } }; + const throttledHandleClick = useCallback( + throttle(handleClick, 700, { + leading: true, + trailing: false, + }), + [], + ); + useEffect(() => { let postApiCalled = "false"; validatePostApiData() - .then((value) => { + .then(value => { postApiCalled = value; }) .then(() => { @@ -157,8 +173,8 @@ const QuoteOfferScreen = ({ postApiCalled === "true" ? ScreenActionTypes.FETCH_INSURANCE_QUOTE_PAGE_FROM_BACKEND : preQuoteId - ? ScreenActionTypes.FETCH_QUOTE_V3 - : ScreenActionTypes.FETCH_INSURANCE_QUOTE_PAGE_FROM_BACKEND; + ? ScreenActionTypes.FETCH_QUOTE_V3 + : ScreenActionTypes.FETCH_INSURANCE_QUOTE_PAGE_FROM_BACKEND; const data: QuoteOfferRequest = { preQuoteId: preQuoteId ? preQuoteId : undefined, quoteId: quoteId ? quoteId : undefined, @@ -173,17 +189,17 @@ const QuoteOfferScreen = ({ ], }); }); - return () => { }; + return () => {}; }, [ctaData, preQuoteId, quoteId]); useEffect(() => { reloadPageEventListener = nativeEventListener.addListener( NativeEventNameConstants.reloadPage, - (event) => { + event => { if (event === true) { let postApiCalled = "false"; validatePostApiData() - .then((value) => { + .then(value => { postApiCalled = value; }) .then(() => { @@ -191,8 +207,8 @@ const QuoteOfferScreen = ({ postApiCalled === "true" ? ScreenActionTypes.FETCH_INSURANCE_QUOTE_PAGE_FROM_BACKEND : preQuoteId - ? ScreenActionTypes.FETCH_QUOTE_V3 - : ScreenActionTypes.FETCH_INSURANCE_QUOTE_PAGE_FROM_BACKEND; + ? ScreenActionTypes.FETCH_QUOTE_V3 + : ScreenActionTypes.FETCH_INSURANCE_QUOTE_PAGE_FROM_BACKEND; const data: QuoteOfferRequest = { preQuoteId: preQuoteId ? preQuoteId : undefined, quoteId: quoteId ? quoteId : undefined, @@ -208,12 +224,12 @@ const QuoteOfferScreen = ({ }); }); } - } + }, ); return () => { reloadPageEventListener.remove(); nativeEventListener.removeAllListeners( - NativeEventNameConstants.reloadPage + NativeEventNameConstants.reloadPage, ); }; }, [reloadPageEventListener]); @@ -249,76 +265,80 @@ const QuoteOfferScreen = ({ if (screenData?.screenState === ScreenState.LOADING) { return ; - } else if (screenData?.screenState === ScreenState.ERROR) { + } + if (screenData?.screenState === ScreenState.ERROR) { return ( ); - } else { - const getPointerEvents = () => { - return screenData?.screenState === ScreenState.OVERLAY ? "none" : "auto"; - }; - return ( - - + } + const getPointerEvents = () => + screenData?.screenState === ScreenState.OVERLAY ? "none" : "auto"; + + return ( + + + {getWidgetViews( + screenData?.screenWidgets?.headerWidgets, + handleActions, + screenData?.screenState, + throttledHandleClick, + )} + + + {getWidgetViews( - screenData?.screenWidgets?.headerWidgets, + screenData?.screenWidgets?.contentWidgets, handleActions, screenData?.screenState, - handleClick - )} - - - - {getWidgetViews( - screenData?.screenWidgets?.contentWidgets, - handleActions, - screenData?.screenState, - handleClick - )} - - - - {getWidgetViews( - screenData?.screenWidgets?.footerWidgets, - handleActions, - screenData?.screenState, - handleClick + throttledHandleClick, )} - {screenData?.screenMetaData?.floatingWidgets?.map( - (fabWidget: Widget, index: number) => { - return ( - - ); - } + + + {getWidgetViews( + screenData?.screenWidgets?.footerWidgets, + handleActions, + screenData?.screenState, + throttledHandleClick, )} - ); - } + {screenData?.screenMetaData?.floatingWidgets?.map( + (fabWidget: Widget, index: number) => { + return ( + + ); + }, + )} + + ); }; function getWidgetViews( widgetList: Widget[] | undefined, handleActions: (screenActionPayload?: GenericActionPayload) => void, screenState?: ScreenState | null, - handleClick?: (ctaData: CtaData) => void + handleClick?: (ctaData: CtaData) => void, ): React.JSX.Element { return ( diff --git a/App/Container/Navi-Insurance/screen/quote-offer-screen/error-screen/QuoteOfferErrorScreen.tsx b/App/Container/Navi-Insurance/screen/quote-offer-screen/error-screen/QuoteOfferErrorScreen.tsx index 1b9f230e30..ccfbbe8c29 100644 --- a/App/Container/Navi-Insurance/screen/quote-offer-screen/error-screen/QuoteOfferErrorScreen.tsx +++ b/App/Container/Navi-Insurance/screen/quote-offer-screen/error-screen/QuoteOfferErrorScreen.tsx @@ -1,6 +1,9 @@ import { View, Text } from "react-native"; import { GenericActionPayload } from "../../../../../common/actions/GenericAction"; -import { CtaData } from "../../../../../common/interface"; +import { + CtaData, + StaticHeaderProperties, +} from "../../../../../common/interface"; import { StaticHeader } from "../../../../../../components/reusable/static-header/StaticHeader"; import { styles } from "./QuoteOfferErrorScreenStyle"; import { TouchableOpacity } from "react-native-gesture-handler"; @@ -11,16 +14,17 @@ import { ImageName, } from "../../../../../common/constants/StringConstant"; import { AppImage } from "../../../../../../components/AppImage"; -import { ConstantCta } from "../../../../../common/constants/CtaConstants"; const QuoteOfferErrorScreen = ({ errorMetaData, handleActions, handleClick, + headerProperties, }: { errorMetaData?: GenericActionPayload; handleActions?: (screenPayload?: GenericActionPayload) => void; handleClick?: (cta: CtaData) => void; + headerProperties: StaticHeaderProperties; }) => { const onPress = () => { handleActions && handleActions(errorMetaData); @@ -30,8 +34,10 @@ const QuoteOfferErrorScreen = ({ {AppImage(ImageName.SWW, styles.centerIcon)} diff --git a/App/common/constants/AnalyticsEventsConstant.ts b/App/common/constants/AnalyticsEventsConstant.ts index 1105c69152..2a3be6c6b8 100644 --- a/App/common/constants/AnalyticsEventsConstant.ts +++ b/App/common/constants/AnalyticsEventsConstant.ts @@ -24,6 +24,7 @@ export const AnalyticsMethodNameConstant = { FETCH_INSURANCE_QUOTE_PAGE_FROM_BACKEND: "fetchInsuranceQuotePageFromBackend", FETCH_QUOTE_V3: "fetchQuoteV3", FINAL_PATCH_CALL: "finalPatchCall", + COMPARE_PLAN_LIST : "comparePlanList", }; export const AnalyticsGlobalErrorTypeConstant = { diff --git a/App/common/constants/CtaConstants.ts b/App/common/constants/CtaConstants.ts index 7b46205e5b..4ded7b6454 100644 --- a/App/common/constants/CtaConstants.ts +++ b/App/common/constants/CtaConstants.ts @@ -2,6 +2,16 @@ export const ConstantCta = { STATIC_HEADER_LEFT_ICON_CTA: { url: "home", }, + GO_BACK_CTA: { + url: "", + type: "RN_NAVIGATOR", + parameters: [ + { + key: "RnNavigatorType", + value: "goBack", + }, + ], + }, STATIC_HEADER_RIGHT_ICON_CTA: { url: "PRODUCT_HELP_PAGE", type: "USE_ROOT_DEEPLINK_NAVIGATOR", diff --git a/App/common/constants/ModalNameConstants.ts b/App/common/constants/ModalNameConstants.ts index f1c6c3fbae..5bb2ea41cf 100644 --- a/App/common/constants/ModalNameConstants.ts +++ b/App/common/constants/ModalNameConstants.ts @@ -1,3 +1,5 @@ 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" \ No newline at end of file +export const TITLE_WITH_STEPS_BOTTOM_SHEET = "title_with_steps_bottom_sheet" +export const MEMBER_DETAILS_BOTTOM_SHEET = "member_details_bottom_sheet" +export const POLICY_AMOUNT_BOTTOM_SHEET = "policy_amount_bottom_sheet" \ No newline at end of file diff --git a/App/common/constants/ScreenNameConstants.ts b/App/common/constants/ScreenNameConstants.ts index 091536d509..e0e8d73178 100644 --- a/App/common/constants/ScreenNameConstants.ts +++ b/App/common/constants/ScreenNameConstants.ts @@ -6,4 +6,5 @@ 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"; \ No newline at end of file +export const QUOTE_APOLOGY_SCREEN = "fresh_policy_form"; +export const COMPARE_PLAN_SCREEN = "compare_plans"; \ No newline at end of file diff --git a/App/common/constants/StringConstant.ts b/App/common/constants/StringConstant.ts index 8da926cdbc..83af560112 100644 --- a/App/common/constants/StringConstant.ts +++ b/App/common/constants/StringConstant.ts @@ -12,10 +12,19 @@ export const Lottie = { export const ImageName = { SWW: "SWW", CROSS: "CROSS", + BACK_ARROW: "BACK_ARROW", HELP: "HELP", QUOTE_APOLOGY_ICON: "QUOTE_APOLOGY_ICON", }; +export enum SelectButtonType { + RADIO = "RADIO", +} + +export enum ScreenProperties { + ANIMATE_HEADER = "ANIMATE_HEADER", +} + export const ERROR_TITLE = "Something went wrong"; export const ERROR_SUBTITLE = "Please try again after some time"; export const RETRY = "Retry"; @@ -27,4 +36,4 @@ 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"; -export const SPACE_UNICODE = "\u00A0" +export const SPACE_UNICODE = "\u00A0"; diff --git a/App/common/constants/WidgetNameConstants.ts b/App/common/constants/WidgetNameConstants.ts index 655a2c57a3..c876df59c7 100644 --- a/App/common/constants/WidgetNameConstants.ts +++ b/App/common/constants/WidgetNameConstants.ts @@ -17,3 +17,5 @@ export const TITLE_WITH_COLUMN_WIDGET = "TITLE_WITH_COLUMN_WIDGET"; export const TITLE_WITH_ASSET_BACKGROUND_WIDGET = "TITLE_WITH_ASSET_BACKGROUND_WIDGET"; export const CARD_WITH_ICON_WIDGET = "CARD_WITH_ICON_WIDGET"; export const SPACER_WIDGET = "SPACER_WIDGET"; +export const SELECT_CARD_WITH_DETAIL_LIST_WIDGET = "SELECT_CARD_WITH_DETAIL_LIST_WIDGET"; +export const TABLE_WIDGET = "TABLE_WIDGET"; diff --git a/App/common/constants/index.ts b/App/common/constants/index.ts new file mode 100644 index 0000000000..743dc3d171 --- /dev/null +++ b/App/common/constants/index.ts @@ -0,0 +1,10 @@ +export * from "./AnalyticsEventsConstant"; +export * from "./CtaConstants"; +export * from "./EventNameConstants"; +export * from "./ModalNameConstants"; +export * from "./NavigationHandlerConstants"; +export * from "./NumericalConstants"; +export * from "./ScreenNameConstants"; +export * from "./SentryConstants"; +export * from "./StringConstant"; +export * from "./WidgetNameConstants"; diff --git a/App/common/hooks/useBottomSheet.tsx b/App/common/hooks/useBottomSheet.tsx index e38905b6da..c652d10c75 100644 --- a/App/common/hooks/useBottomSheet.tsx +++ b/App/common/hooks/useBottomSheet.tsx @@ -3,8 +3,11 @@ import { View } from "react-native"; import BaseBottomSheetComponent from "../../../components/bottomsheet/BaseBottomSheetComponent"; import { ModalView } from "../interface/modals/ModalView"; import { clearBottomSheet, setBottomSheetView } from "../utilities/AlfredUtils"; +import { GenericActionPayload } from "../actions/GenericAction"; -export const useBottomSheet = () => { +export const useBottomSheet = ( + handleActions: (actionPayload?: GenericActionPayload) => void, +) => { const [bottomsheet, setBottomSheet] = useState([]); const onAnimationEndHandler = (id: number | null) => { @@ -13,7 +16,7 @@ export const useBottomSheet = () => { }; const addBottomSheet = (modalView: ModalView) => { - setBottomSheet((prevState) => [ + setBottomSheet(prevState => [ ...prevState, { showModal={true} onClose={() => removeBottomSheet()} modalView={modalView} + handleActions={handleActions} /> , ]); @@ -28,7 +32,7 @@ export const useBottomSheet = () => { const removeBottomSheet = () => { clearBottomSheet(); - setBottomSheet((prevState) => { + setBottomSheet(prevState => { const newState = [...prevState]; newState.pop(); return newState; diff --git a/App/common/interface/components/PillData.ts b/App/common/interface/components/PillData.ts index 92ad050c59..4b892f1564 100644 --- a/App/common/interface/components/PillData.ts +++ b/App/common/interface/components/PillData.ts @@ -2,8 +2,8 @@ import { ViewStyle } from "react-native"; import { PillInfo } from "./PillInfo"; export interface PillData { - id: string; + id?: string; selectedState?: PillInfo; unSelectedState?: PillInfo; - defaultPillStyle: ViewStyle; + defaultPillStyle?: ViewStyle; } \ No newline at end of file diff --git a/App/common/interface/index.ts b/App/common/interface/index.ts index bb656b6013..683f2972a6 100644 --- a/App/common/interface/index.ts +++ b/App/common/interface/index.ts @@ -1,3 +1,5 @@ +import { ImageName } from "../constants"; + export type CtaData = { url: string; type?: string; @@ -13,7 +15,6 @@ export type AnalyticsEvent = { properties?: Map; }; - type LineItem = { key?: string; value?: string | null; @@ -21,12 +22,40 @@ type LineItem = { }; export interface BaseNavigator { - navigate(ctaData: CtaData): any; - goBack(): any; + navigate(navigationRef: any, ctaData: CtaData): any; + goBack(navigationRef: any): any; + push(navigationRef: any, ctaData: CtaData): any; + performNavigation(navigation: any, type: any, ctaData: CtaData): any; +} + +export enum NavigationType { + NAVIGATE = "navigate", + GO_BACK = "goBack", + PUSH = "push", +} + +export interface CtaParameter { + key: string; + value: string | undefined | null; +} + +export interface StaticHeaderProperties { + leftIcon?: keyof typeof ImageName; + rightIcon?: keyof typeof ImageName; + leftIconCta?: CtaData | null; + rightIconCta?: CtaData | null; +} + +export enum ParameterType { + PRE_QUOTE_ID = "preQuoteId", + QUOTE_ID = "quoteId", + NAVIGATOR_TYPE = "RnNavigatorType", } export enum CtaType { DEEP_LINK = "DEEP_LINK", DISMISS_MODAL = "DISMISS_MODAL", USE_ROOT_DEEPLINK_NAVIGATOR = "USE_ROOT_DEEPLINK_NAVIGATOR", + RN_NAVIGATOR = "RN_NAVIGATOR", } + diff --git a/App/common/interface/widgets/Widget.ts b/App/common/interface/widgets/Widget.ts index d69f161ead..8e1f309a4f 100644 --- a/App/common/interface/widgets/Widget.ts +++ b/App/common/interface/widgets/Widget.ts @@ -1,4 +1,5 @@ import { ViewStyle } from "react-native"; +import { GenericActionPayload } from "../../actions/GenericAction"; export interface Widget { widgetId: string; @@ -7,6 +8,7 @@ export interface Widget { widgetType: string | null; widgetStyle: ViewStyle; widgetVisibility?: boolean; + widgetRenderActions?: GenericActionPayload } export interface GenericWidgetData { diff --git a/App/common/interface/widgets/modalData/MemberDetailsBottomSheetData.ts b/App/common/interface/widgets/modalData/MemberDetailsBottomSheetData.ts new file mode 100644 index 0000000000..f156f0bc56 --- /dev/null +++ b/App/common/interface/widgets/modalData/MemberDetailsBottomSheetData.ts @@ -0,0 +1,11 @@ +import { ViewStyle } from "react-native"; +import { GenericWidgetData } from "../Widget"; +import { ButtonData } from "../widgetData/FooterWithCardWidgetData"; +import { TitleWithAssetsWidgetData } from "../widgetData/TitleWithAssetsWidgetData"; +import { TitleWithListWidgetData } from "../widgetData/TitleWithListWidgetData"; + +export interface MemberDetailsBottomSheetData extends GenericWidgetData{ + membersWidget?: TitleWithListWidgetData + addMembersWidget?: TitleWithAssetsWidgetData + footerData?: ButtonData +} \ No newline at end of file diff --git a/App/common/interface/widgets/modalData/PolicyAmountBottomSheetData.ts b/App/common/interface/widgets/modalData/PolicyAmountBottomSheetData.ts new file mode 100644 index 0000000000..7918f5af76 --- /dev/null +++ b/App/common/interface/widgets/modalData/PolicyAmountBottomSheetData.ts @@ -0,0 +1,33 @@ +import { AnalyticsEvent } from "../.."; +import { GenericActionPayload } from "../../../actions/GenericAction"; +import { PillData } from "../../components/PillData"; +import { GenericWidgetData } from "../Widget"; +import { ButtonData } from "../widgetData/FooterWithCardWidgetData"; +import { TextFieldData } from "../widgetData/TitleWidgetData"; +import { TitleWithListWidgetData } from "../widgetData/TitleWithListWidgetData"; + +export interface PolicyAmountBottomSheetData extends GenericWidgetData { + title?: TextFieldData + policyAmountList?: CoverAmountPillData[] + policyPlanData?: TitleWithListWidgetData + footerData?: ButtonData + bottomSheetMetaData?: BottomSheetMetaData +} + +export interface CoverAmountPillData extends PillData { + coverAmount?: string + standardPlanMonthlyPremium?: string + comprehensivePlanMonthlyPremium?: string + dependentWidgets?: any, + analyticEvents?: PillAnalyticsEvents +} + +export interface PillAnalyticsEvents { + onViewEvent?: AnalyticsEvent + onSelectedEvent?: AnalyticsEvent +} + +export interface BottomSheetMetaData { + selectedPill?: string, + onValueChangeAction?: GenericActionPayload +} \ No newline at end of file diff --git a/App/common/interface/widgets/screenData/ScreenMetaData.ts b/App/common/interface/widgets/screenData/ScreenMetaData.ts index 968bec6b98..5fd1d4e87d 100644 --- a/App/common/interface/widgets/screenData/ScreenMetaData.ts +++ b/App/common/interface/widgets/screenData/ScreenMetaData.ts @@ -5,4 +5,11 @@ export interface ScreenMetaData { backButtonCta?: CtaData; redirectionCta?: CtaData; floatingWidgets?: Widget[]; + screenProperties?: Array; } + +type LineItem = { + key?: string; + value?: string | null; + data?: any | null; +}; diff --git a/App/common/interface/widgets/widgetData/SelectCardWithDetailListData.ts b/App/common/interface/widgets/widgetData/SelectCardWithDetailListData.ts new file mode 100644 index 0000000000..c3f0f86365 --- /dev/null +++ b/App/common/interface/widgets/widgetData/SelectCardWithDetailListData.ts @@ -0,0 +1,70 @@ +import { ViewStyle } from "react-native"; +import { GenericWidgetData } from "../Widget"; +import { ImageFieldData, TextFieldData } from "./TitleWidgetData"; +import { GenericActionPayload } from "../../../actions/GenericAction"; +import { AnalyticsEvent, CtaData } from "../.."; + +export interface ContainerTag { + tagTitle?: TextFieldData; + tag?: ImageFieldData; +} + +export interface Detail { + leftText?: TextFieldData; + leftTextWithImage?: TextFieldData; + rightText?: TextFieldData; +} + +export interface Item { + title?: TextFieldData; + subtitle?: TextFieldData; + details?: Detail[]; + itemType?: string; + dependentWidgets?: any; + analyticEvents?: ItemAnalyticsEvents +} + +interface WidgetMetaData { + selectedItem?: string; + showContainerTag?: string; + onValueChangeAction?: GenericActionPayload; +} + +export interface SelectCardWithDetailListData extends GenericWidgetData { + title?: TextFieldData; + containerTag?: ContainerTag; + items?: Item[]; + widgetMetaData?: WidgetMetaData; +} + +export interface SelectCardWithDetailListProps { + widgetData: SelectCardWithDetailListData; + widgetStyle: ViewStyle; + handleActions: ( + value?: any | undefined | null, + screenActionPayload?: GenericActionPayload, + ) => void; + handleClick?: (cta: CtaData) => void; + widgetIndex: number; +} + +export interface ItemCardProps { + handleClick?: (cta: CtaData) => void; + item?: Item; + selected?: boolean; + onSelect?: () => void; + showContainerTag?: string; + containerTag?: ContainerTag; +} + +export interface ItemDetailProps { + detail?: Detail; + selected?: boolean; + handleClick?: (cta: CtaData) => void; + showBorder? : boolean; +} + +export interface ItemAnalyticsEvents { + onViewEvent?: AnalyticsEvent + onSelectedEvent?: AnalyticsEvent +} diff --git a/App/common/interface/widgets/widgetData/TableWidgetData.ts b/App/common/interface/widgets/widgetData/TableWidgetData.ts new file mode 100644 index 0000000000..151d142b45 --- /dev/null +++ b/App/common/interface/widgets/widgetData/TableWidgetData.ts @@ -0,0 +1,64 @@ +import { ViewStyle } from "react-native"; +import { GenericWidgetData } from "../Widget"; +import { ImageFieldData, TextFieldData } from "./TitleWidgetData"; +import { GenericActionPayload } from "../../../actions/GenericAction"; +import { AnalyticsEvent, CtaData } from "../.."; + +export interface Column { + title: TextFieldData; + subtitle: TextFieldData; + columnStyle?: ViewStyle; +} + +export interface Cell { + title?: TextFieldData; + subtitle?: TextFieldData; + image?: ImageFieldData; + cta?: CtaData; + analyticEvents?: CellAnalyticEvents +} + +export interface Row { + cells?: Cell[]; +} + +export interface TableWidgetData extends GenericWidgetData { + rowsToDisplay?: number; + viewButton? : TextFieldData; + columns?: Column[]; + rows?: Row[]; +} + +export interface TableWidgetProps { + widgetData: TableWidgetData; + widgetStyle: ViewStyle; + handleActions: ( + value?: any | undefined | null, + screenActionPayload?: GenericActionPayload, + ) => void; + handleClick?: (cta: CtaData) => void; + widgetIndex?: number; + +} + +export interface ColumnsProps { + widgetData?: TableWidgetData; +} + +export interface RowsProps { + widgetData?: TableWidgetData; + rowsToDisplay?: number; + handleClick?: (cta: CtaData) => void; + +} + +export interface CellProps { + widgetData?: TableWidgetData; + cell?: Cell; + index: number; + handleClick?: (cta: CtaData) => void; +} + +export interface CellAnalyticEvents{ + onViewEvent?: AnalyticsEvent +} diff --git a/App/common/interface/widgets/widgetData/TitleWidgetData.ts b/App/common/interface/widgets/widgetData/TitleWidgetData.ts index cde8d23148..4ff128d0b7 100644 --- a/App/common/interface/widgets/widgetData/TitleWidgetData.ts +++ b/App/common/interface/widgets/widgetData/TitleWidgetData.ts @@ -1,6 +1,7 @@ import { ImageStyle, TextStyle } from "react-native"; import { CtaData } from "../.."; import { GenericWidgetData } from "../Widget"; +import { GenericActionPayload } from "../../../actions/GenericAction"; export interface TitleWidgetData extends GenericWidgetData { title?: TextFieldData; @@ -15,6 +16,7 @@ export interface TextFieldData { substringStyles?: SubstringStyle[]; textDrawableData?: TextDrawableData; cta?: CtaData; + actions?: GenericActionPayload } export interface SubstringStyle { diff --git a/App/common/interface/widgets/widgetData/TitleWithAssetsWidgetData.ts b/App/common/interface/widgets/widgetData/TitleWithAssetsWidgetData.ts index 9d98f04eeb..40d409f5b5 100644 --- a/App/common/interface/widgets/widgetData/TitleWithAssetsWidgetData.ts +++ b/App/common/interface/widgets/widgetData/TitleWithAssetsWidgetData.ts @@ -1,3 +1,4 @@ +import { ViewStyle } from "react-native"; import { CtaData } from "../.."; import { GenericWidgetData } from "../Widget"; import { @@ -10,6 +11,7 @@ export interface TitleWithAssetsWidgetData extends GenericWidgetData { leftIcon?: ImageFieldData; leftLottie?: LottieFieldData; title?: TextFieldData; + titleStyle?: ViewStyle; rightIcon?: ImageFieldData; rightLottie?: LottieFieldData; cta?: CtaData; diff --git a/App/common/interface/widgets/widgetData/TitleWithListWidgetData.ts b/App/common/interface/widgets/widgetData/TitleWithListWidgetData.ts index 45cb64eb2a..d40b9412d2 100644 --- a/App/common/interface/widgets/widgetData/TitleWithListWidgetData.ts +++ b/App/common/interface/widgets/widgetData/TitleWithListWidgetData.ts @@ -1,17 +1,20 @@ -import { TextStyle } from "react-native"; +import { TextStyle, ViewStyle } from "react-native"; import { GenericWidgetData } from "../Widget"; import { TextFieldData } from "./TitleWidgetData"; +import { AnalyticsEvent } from "../.."; export interface TitleWithListWidgetData extends GenericWidgetData { title?: TextFieldData; rightTitle?: TextFieldData; listData?: ListItem[]; + listStyle?: ViewStyle } export interface ListItem extends GenericWidgetData { id: string; title?: TextFieldData; rightTitle?: TextFieldData; + onViewEvent?: AnalyticsEvent } diff --git a/App/common/interface/widgets/widgetData/index.ts b/App/common/interface/widgets/widgetData/index.ts new file mode 100644 index 0000000000..919e81d19b --- /dev/null +++ b/App/common/interface/widgets/widgetData/index.ts @@ -0,0 +1,20 @@ +export type { + SelectCardWithDetailListData, + Item, + ContainerTag, + Detail, + SelectCardWithDetailListProps, + ItemCardProps, + ItemDetailProps, +} from "./SelectCardWithDetailListData"; + +export type { + TableWidgetProps, + TableWidgetData, + Column, + Row, + Cell, + ColumnsProps, + RowsProps, + CellProps, +} from "./TableWidgetData"; diff --git a/App/common/modals/modalViewResolver.tsx b/App/common/modals/modalViewResolver.tsx index afb36952ab..e5cc57cbcc 100644 --- a/App/common/modals/modalViewResolver.tsx +++ b/App/common/modals/modalViewResolver.tsx @@ -4,6 +4,8 @@ import TitleWithFeedbackPillBottomSheet from "../../../components/bottomsheet/ti import PremiumDetailsBottomSheet from "../../../components/bottomsheet/title-with-list-bottom-sheet/TitleWithListBottomSheet"; import TitleWithStepsBottomSheet from "../../../components/bottomsheet/title-with-steps-bottom-sheet/TitleWithStepsBottomSheet"; import { + MEMBER_DETAILS_BOTTOM_SHEET, + POLICY_AMOUNT_BOTTOM_SHEET, PREMIUM_DETAILS_BOTTOM_SHEET, TITLE_WITH_FEEDBACK_PILL_BOTTOM_SHEET, TITLE_WITH_STEPS_BOTTOM_SHEET, @@ -11,14 +13,18 @@ import { import { CtaData } from "../interface"; import { ModalView } from "../interface/modals/ModalView"; import { GenericWidgetData } from "../interface/widgets/Widget"; +import { MemberDetailBottomSheet } from "../../../components/bottomsheet/member-details-bottom-sheet/MemberDetailsBottomSheet"; +import { PolicyAmountBottomSheet } from "../../../components/bottomsheet/policy-amount-bottom-sheet/PolicyAmountBottomSheet"; +import { GenericActionPayload } from "../actions/GenericAction"; export const GetModalView = { getModal: ( modal: ModalView, - handleModalClick: (cta: CtaData) => void + handleModalClick: (cta: CtaData) => void, + handleActions: (actionPayload?: GenericActionPayload) => void ): JSX.Element => { const { modalName, modalData, modalStyle } = modal; - return resolveModalView(modalName, modalData, modalStyle, handleModalClick); + return resolveModalView(modalName, modalData, modalStyle, handleModalClick, handleActions); }, }; @@ -26,7 +32,8 @@ function resolveModalView( modalName: string, modalData: GenericWidgetData, modalStyle: ViewStyle | undefined, - handleModalClick: (cta: CtaData) => void + handleModalClick: (cta: CtaData) => void, + handleActions: (actionPayload?: GenericActionPayload) => void ) { switch (modalName) { case PREMIUM_DETAILS_BOTTOM_SHEET: @@ -52,6 +59,22 @@ function resolveModalView( handleModalClick={handleModalClick} /> ); + case MEMBER_DETAILS_BOTTOM_SHEET: + return ( + + ) + case POLICY_AMOUNT_BOTTOM_SHEET: + return ( + + ) default: return ; } diff --git a/App/common/navigator/NavigationRouter.ts b/App/common/navigator/NavigationRouter.ts index a371be5381..b8840bcaf7 100644 --- a/App/common/navigator/NavigationRouter.ts +++ b/App/common/navigator/NavigationRouter.ts @@ -1,5 +1,9 @@ -import { createNavigationContainerRef } from "@react-navigation/native"; -import { BaseNavigator, CtaData } from "../interface"; +import { + BaseNavigator, + NavigationType, + CtaParameter, + ParameterType, +} from "../interface"; import { BASE_SCREEN } from "../constants/ScreenNameConstants"; import { BaseActionTypes, @@ -10,19 +14,63 @@ 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 }); + navigate: (navigationRef, ctaData) => { + navigationRef?.navigate(BASE_SCREEN, { ctaData }); + }, + goBack: navigationRef => { + navigationRef?.goBack(); + }, + push: (navigationRef, ctaData) => { + navigationRef?.push(BASE_SCREEN, { ctaData }); + }, + + performNavigation: (navigation, type, ctaData) => { + switch (type) { + case NavigationType.NAVIGATE: + CtaNavigator.navigate(navigation, ctaData); + break; + case NavigationType.GO_BACK: + CtaNavigator.goBack(navigation); + break; + case NavigationType.PUSH: + CtaNavigator.navigate(navigation, ctaData); + break; + default: + CtaNavigator.push(navigation, ctaData); + break; } }, - goBack: () => { - if (navigationRef.isReady()) { - navigationRef.goBack(); +}; + +export const extractCtaParameters = ( + ctaData: any, +): { + preQuoteId?: string | undefined | null; + quoteId?: string | undefined | null; + navigatorType?: string | undefined | null; +} => { + let preQuoteId: string | undefined | null = undefined; + let quoteId: string | undefined | null = undefined; + let navigatorType: string | undefined | null = undefined; + + ctaData?.parameters?.forEach((item: CtaParameter) => { + switch (item.key) { + case ParameterType.PRE_QUOTE_ID: + preQuoteId = item.value; + break; + case ParameterType.QUOTE_ID: + quoteId = item.value; + break; + case ParameterType.NAVIGATOR_TYPE: + navigatorType = item.value; + break; + default: + break; } - }, + }); + + return { preQuoteId, quoteId, navigatorType }; }; export const Router = { @@ -38,10 +86,10 @@ export const Router = { actionPayload.setErrorMetaData, actionPayload.screenData, actionPayload.ctaData, - navigation + navigation, ); } - } + }, ); break; } @@ -53,16 +101,16 @@ export const Router = { !!screenMetaData ? screenMetaData : {}, actionPayload.setScreenData, actionPayload.screenData, - navigation + navigation, ); } - } + }, ); break; } default: { logToSentry( - `Invalid baseActionType ${actionPayload.baseActionType} | MethodName: Router.handleAction` + `Invalid baseActionType ${actionPayload.baseActionType} | MethodName: Router.handleAction`, ); break; } diff --git a/App/common/navigator/RnAppCreator.tsx b/App/common/navigator/RnAppCreator.tsx index 2022cb3ec0..5618d32b18 100644 --- a/App/common/navigator/RnAppCreator.tsx +++ b/App/common/navigator/RnAppCreator.tsx @@ -1,24 +1,21 @@ - +import React from "react"; import { LogBox, StatusBar } from "react-native"; import { ThemeProvider } from "../../../components/ThemeContext"; -import { - BASE_SCREEN -} from "../constants/ScreenNameConstants"; +import { BASE_SCREEN } from "../constants/ScreenNameConstants"; import { CtaData } from "../interface"; - -import { NavigationContainer } from "@react-navigation/native"; +import { createNavigationContainerRef, NavigationContainer } from "@react-navigation/native"; import { createStackNavigator } from "@react-navigation/stack"; import { Provider } from "react-redux"; import { PersistGate } from "redux-persist/integration/react"; import Colors from "../../../assets/colors/colors"; import reduxStore from "../redux/store"; 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 navigationRef = createNavigationContainerRef(); export const RnApp = { create: (ctaData: CtaData) => { diff --git a/App/common/screen/BaseScreen.tsx b/App/common/screen/BaseScreen.tsx index a2e2abb896..998441e7de 100644 --- a/App/common/screen/BaseScreen.tsx +++ b/App/common/screen/BaseScreen.tsx @@ -105,9 +105,7 @@ const BaseScreen: React.FC<{ navigation: any; route: any }> = ({ dispatch(updateCtaData({ cta: ctaData, setScreenState: screenState })); } }, [route.params.ctaData, screenState]); - - const { bottomsheet, addBottomSheet } = useBottomSheet(); - + const handleActions = (actionPayload?: GenericActionPayload) => { actionPayload?.metaData?.forEach((ActionMetaData) => { if (!!ActionMetaData.analyticsEventProperties) { @@ -135,6 +133,9 @@ const BaseScreen: React.FC<{ navigation: any; route: any }> = ({ } }); }; + + const { bottomsheet, addBottomSheet } = useBottomSheet(handleActions); + const MemoizedScreenMapper = useMemo(() => { const secondIdentifier = getScreenMapperNameFromCtaData(cta); setCurrentScreenName( diff --git a/App/common/screen/ScreenActionHandler.tsx b/App/common/screen/ScreenActionHandler.tsx index f26c70e123..9ede1f3d79 100644 --- a/App/common/screen/ScreenActionHandler.tsx +++ b/App/common/screen/ScreenActionHandler.tsx @@ -19,7 +19,6 @@ import { AnalyticsMethodNameConstant, AnalyticsModuleNameConstant, } from "../constants/AnalyticsEventsConstant"; -import { PreferenceManagerConnector } from "../native-module/NativeModules"; import { getStringPreference, setStringPreference, @@ -30,29 +29,29 @@ export const ScreenActionHandler = { screenMetaData: ActionMetaData, setScreenData: Dispatch>, screenData?: ScreenData | null, - navigation?: any + navigation?: any, ) => { switch (screenMetaData.actionType) { case ScreenActionTypes.FETCH_INSURANCE_QUOTE_PAGE_FROM_BACKEND: { let quoteId = screenMetaData.data.quoteId; if (!quoteId) { - getQuoteIdFromCache().then((value) => { + getQuoteIdFromCache().then(value => { if (!!value) { quoteId = value; return get>( `v3/quotes/${quoteId}`, - getXTargetHeaderInfo(GI.toLocaleUpperCase()) + getXTargetHeaderInfo(GI.toLocaleUpperCase()), ) - .then((response) => { + .then(response => { handleResponseData(setScreenData, response); }) - .catch((error) => { + .catch(error => { handleErrorData( error, setScreenData, screenMetaData, AnalyticsMethodNameConstant.FETCH_INSURANCE_QUOTE_PAGE_FROM_BACKEND, - ScreenActionTypes.FETCH_INSURANCE_QUOTE_PAGE_FROM_BACKEND + ScreenActionTypes.FETCH_INSURANCE_QUOTE_PAGE_FROM_BACKEND, ); }); } @@ -61,18 +60,18 @@ export const ScreenActionHandler = { } else { return get>( `v3/quotes/${quoteId}`, - getXTargetHeaderInfo(GI.toLocaleUpperCase()) + getXTargetHeaderInfo(GI.toLocaleUpperCase()), ) - .then((response) => { + .then(response => { handleResponseData(setScreenData, response); }) - .catch((error) => { + .catch(error => { handleErrorData( error, setScreenData, screenMetaData, AnalyticsMethodNameConstant.FETCH_INSURANCE_QUOTE_PAGE_FROM_BACKEND, - ScreenActionTypes.FETCH_INSURANCE_QUOTE_PAGE_FROM_BACKEND + ScreenActionTypes.FETCH_INSURANCE_QUOTE_PAGE_FROM_BACKEND, ); }); } @@ -82,10 +81,9 @@ export const ScreenActionHandler = { return post>( "v3/quotes", screenMetaData.data, - getXTargetHeaderInfo(GI.toLocaleUpperCase()) + getXTargetHeaderInfo(GI.toLocaleUpperCase()), ) - .then((response) => { - console.log("Quote_v3_Call success", response.data); + .then(response => { if (screenData?.screenState) { screenData.screenState = ScreenState.LOADING; } @@ -93,7 +91,7 @@ export const ScreenActionHandler = { if (response.data) { const cta = response.data as CtaData; let quoteId; - cta?.parameters?.forEach((item) => { + cta?.parameters?.forEach(item => { if (item.key === "quoteId") { quoteId = item.value; } @@ -108,13 +106,37 @@ export const ScreenActionHandler = { navigation.navigate(BASE_SCREEN, { ctaData: cta }); } }) - .catch((error) => { + .catch(error => { handleErrorData( error, setScreenData, screenMetaData, AnalyticsMethodNameConstant.FETCH_QUOTE_V3, - ScreenActionTypes.FETCH_QUOTE_V3 + ScreenActionTypes.FETCH_QUOTE_V3, + ); + }); + } + case ScreenActionTypes.FETCH_COMPARE_PLAN_LIST: { + return post>( + "quotes/compare-plans", + screenMetaData.data, + getXTargetHeaderInfo(GI.toLocaleUpperCase()), + ) + .then(response => { + const updatedScreenData: ScreenData = { + ...(response.data as ScreenData), + screenState: ScreenState.LOADED, + }; + setScreenData(updatedScreenData); + return; + }) + .catch(error => { + handleErrorData( + error, + setScreenData, + screenMetaData, + AnalyticsMethodNameConstant.COMPARE_PLAN_LIST, + ScreenActionTypes.FETCH_COMPARE_PLAN_LIST, ); }); } @@ -146,7 +168,7 @@ const getQuoteIdFromCache = async () => { const handleResponseData = ( setScreenData: Dispatch>, - response: any + response: any, ) => { const updatedScreenData: ScreenData = { ...(response.data as ScreenData), @@ -161,10 +183,10 @@ const handleErrorData = ( setScreenData: Dispatch>, screenMetaData: ActionMetaData, methodName: string, - actionType: string + actionType: string, ) => { logToSentry( - `No response from api call: ${screenMetaData.actionType} | Error: ${error} | MethodName: handleScreenAction` + `No response from api call: ${screenMetaData.actionType} | Error: ${error} | MethodName: handleScreenAction`, ); const errorEvent: GlobalErrorData = { reason: error.toString(), diff --git a/App/common/screen/ScreenActionTypes.ts b/App/common/screen/ScreenActionTypes.ts index 13a8d0c784..679d5855af 100644 --- a/App/common/screen/ScreenActionTypes.ts +++ b/App/common/screen/ScreenActionTypes.ts @@ -3,4 +3,5 @@ export const ScreenActionTypes = { "FETCH_INSURANCE_QUOTE_PAGE_FROM_BACKEND", FETCH_QUOTE_V3: "FETCH_QUOTE_V3", SHOW_LOADER: "SHOW_LOADER", + FETCH_COMPARE_PLAN_LIST: "FETCH_COMPARE_PLAN_LIST", }; diff --git a/App/common/screen/screen-mappers/GIScreenMapper.tsx b/App/common/screen/screen-mappers/GIScreenMapper.tsx index cb28a8bde8..c3e3c47e08 100644 --- a/App/common/screen/screen-mappers/GIScreenMapper.tsx +++ b/App/common/screen/screen-mappers/GIScreenMapper.tsx @@ -1,14 +1,16 @@ import { View } from "react-native"; import { QuoteOfferScreen, + QuoteApologyScreen, + ComparePlanScreen, } from "../../../Container/Navi-Insurance"; -import QuoteApologyScreen from "../../../Container/Navi-Insurance/screen/quote-apology-screen/QuoteApologyScreen"; import { GenericActionPayload } from "../../actions/GenericAction"; import { + QUOTE_OFFER_SCREEN, BUY_INSURANCE_SCREEN, QUOTE_APOLOGY_SCREEN, - QUOTE_OFFER_SCREEN -} from "../../constants/ScreenNameConstants"; + COMPARE_PLAN_SCREEN, +} from "../../constants"; import { logToSentry } from "../../hooks/useSentryLogging"; import { CtaData } from "../../interface"; import { ScreenData } from "../../interface/widgets/screenData/ScreenData"; @@ -18,7 +20,7 @@ export const GIScreenMapper = { getScreen( ctaData: CtaData | null | undefined, screenData: ScreenData | null, - handleActions: (actionPayload?: GenericActionPayload) => void + handleActions: (actionPayload?: GenericActionPayload) => void, ): JSX.Element { if (!!ctaData) { const thirdIdentifier = getScreenNameFromCtaData(ctaData); @@ -40,6 +42,14 @@ export const GIScreenMapper = { handleActions={handleActions} /> ); + case COMPARE_PLAN_SCREEN: + return ( + + ); default: { return ; } @@ -47,9 +57,9 @@ export const GIScreenMapper = { } } else { logToSentry( - `CtaData is missing or invalid: ${ctaData} | MethodName: GIScreenMapper.getScreen` + `CtaData is missing or invalid: ${ctaData} | MethodName: GIScreenMapper.getScreen`, ); return ; } }, -}; \ No newline at end of file +}; diff --git a/App/common/screen/screen-mappers/ScreenMapper.tsx b/App/common/screen/screen-mappers/ScreenMapper.tsx index 8f446f7067..fa4775d499 100644 --- a/App/common/screen/screen-mappers/ScreenMapper.tsx +++ b/App/common/screen/screen-mappers/ScreenMapper.tsx @@ -12,7 +12,7 @@ export const ScreenMapper = { getScreenMapper( ctaData: CtaData | null | undefined, screenData: ScreenData | null, - handleActions: (actionPayload?: GenericActionPayload) => void + handleActions: (actionPayload?: GenericActionPayload) => void, ): JSX.Element { if (!!ctaData) { const secondIdentifier = getScreenMapperNameFromCtaData(ctaData); diff --git a/App/common/utilities/CacheUtils.ts b/App/common/utilities/CacheUtils.ts index 41637de835..c667af4318 100644 --- a/App/common/utilities/CacheUtils.ts +++ b/App/common/utilities/CacheUtils.ts @@ -1,5 +1,5 @@ import AsyncStorage from "@react-native-async-storage/async-storage"; -import { BUY_INSURANCE_SCREEN, QUOTE_OFFER_SCREEN } from "../constants/ScreenNameConstants"; +import { BUY_INSURANCE_SCREEN, COMPARE_PLAN_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"; @@ -87,7 +87,7 @@ export const isScreenWhiteListedForCaching = ( return !screensWithCachingDisabled.includes(screenName || ""); }; -export const screensWithCachingDisabled = [BUY_INSURANCE_SCREEN, QUOTE_OFFER_SCREEN]; +export const screensWithCachingDisabled = [BUY_INSURANCE_SCREEN, QUOTE_OFFER_SCREEN, COMPARE_PLAN_SCREEN]; export const invalidateCacheWithUrl = ( diff --git a/App/common/utilities/CtaParamsUtils.ts b/App/common/utilities/CtaParamsUtils.ts index 54c9767def..d71607aea6 100644 --- a/App/common/utilities/CtaParamsUtils.ts +++ b/App/common/utilities/CtaParamsUtils.ts @@ -3,7 +3,7 @@ import { CtaData } from "../interface"; export const getQuoteIdFromCta = (ctaData?: CtaData) => { let quoteId; - ctaData?.parameters?.forEach((item) => { + ctaData?.parameters?.forEach(item => { if (item.key === QUOTE_ID) { quoteId = item.value; return; diff --git a/App/common/utilities/MockApiUtil.ts b/App/common/utilities/MockApiUtil.ts index a114b69778..6b198d0831 100644 --- a/App/common/utilities/MockApiUtil.ts +++ b/App/common/utilities/MockApiUtil.ts @@ -5,7 +5,7 @@ export function mockApiCall(shouldSucceed: boolean): Promise { return new Promise((resolve, reject) => { setTimeout(() => { if (shouldSucceed) { - // Simulate a successful API response + // Simulate a successful API response resolve(mockResponse as T); } else { // Simulate an error response diff --git a/App/common/widgets/widget-actions/WidgetActionHandler.ts b/App/common/widgets/widget-actions/WidgetActionHandler.ts index 86c52aa37c..7e5d65c898 100644 --- a/App/common/widgets/widget-actions/WidgetActionHandler.ts +++ b/App/common/widgets/widget-actions/WidgetActionHandler.ts @@ -14,7 +14,7 @@ import { AnalyticsMethodNameConstant, AnalyticsModuleNameConstant, } from "../../constants/AnalyticsEventsConstant"; -import { sendAsGlobalErrorEvent } from "../../hooks/useAnalyticsEvent"; +import { sendAsAnalyticsEvent, sendAsGlobalErrorEvent } from "../../hooks/useAnalyticsEvent"; import { logToSentry } from "../../hooks/useSentryLogging"; import { CtaData } from "../../interface"; import { ScreenData } from "../../interface/widgets/screenData/ScreenData"; @@ -39,7 +39,7 @@ const WidgetActionHandler = { | undefined, screenData?: ScreenData | null, ctaData?: CtaData, - navigation?: any + navigation?: any, ) => { switch (widgetMetaData.actionType) { case WidgetActionTypes.UPDATE_WIDGET_DATA: { @@ -57,7 +57,7 @@ const WidgetActionHandler = { targetWidgetPayload; let widgetIdFound = false; updatedScreenData?.screenWidgets?.contentWidgets?.forEach( - (widget) => { + widget => { if (widget.widgetId === widgetId && keyPath === "") { if (newValue === "false") { widget.widgetVisibility = false; @@ -69,17 +69,17 @@ const WidgetActionHandler = { updateValueByKeyPath( widget.widgetData, keyPath, - parseValue(newValue, valueType) + parseValue(newValue, valueType), ); setScreenData(updatedScreenData); widgetIdFound = true; return; } - } + }, ); !widgetIdFound ? updatedScreenData?.screenWidgets?.footerWidgets?.forEach( - (widget) => { + widget => { if (widget.widgetId === widgetId && keyPath === "") { if (newValue === "false") { widget.widgetVisibility = false; @@ -91,17 +91,17 @@ const WidgetActionHandler = { updateValueByKeyPath( widget.widgetData, keyPath, - parseValue(newValue, valueType) + parseValue(newValue, valueType), ); setScreenData(updatedScreenData); return; } - } + }, ) : {}; !widgetIdFound ? updatedScreenData?.screenWidgets?.headerWidgets?.forEach( - (widget) => { + widget => { if (widget.widgetId === widgetId && keyPath === "") { if (newValue === "false") { widget.widgetVisibility = false; @@ -113,15 +113,15 @@ const WidgetActionHandler = { updateValueByKeyPath( widget.widgetData, keyPath, - parseValue(newValue, valueType) + parseValue(newValue, valueType), ); setScreenData(updatedScreenData); return; } - } + }, ) : {}; - } + }, ); setScreenData(updatedScreenData); return; @@ -205,6 +205,10 @@ const WidgetActionHandler = { setScreenData(updatedScreenData); return; } + case WidgetActionTypes.ANALYTIC_ACTION: { + widgetMetaData?.analyticsEventProperties && sendAsAnalyticsEvent(widgetMetaData?.analyticsEventProperties) + return + } default: { return; @@ -214,7 +218,7 @@ const WidgetActionHandler = { getTargetWidgetActionPayload: ( value: any | undefined | null, - actionPayloadList: GenericActionPayload | undefined + actionPayloadList: GenericActionPayload | undefined, ): GenericActionPayload | undefined => { if (!actionPayloadList) { return undefined; @@ -222,7 +226,7 @@ const WidgetActionHandler = { let updatedActionPayload: GenericActionPayload = { ...actionPayloadList, - metaData: actionPayloadList.metaData?.map((actionPayload) => { + metaData: actionPayloadList.metaData?.map(actionPayload => { let updatedList = actionPayload?.data?.map( (targetWidgetPayload: any) => { if ( @@ -245,7 +249,7 @@ const WidgetActionHandler = { ...targetWidgetPayload, newValue: newValue, }; - } + }, ); const widgetActionMeta: ActionMetaData = { actionType: actionPayload.actionType, diff --git a/App/common/widgets/widget-actions/WidgetActionTypes.ts b/App/common/widgets/widget-actions/WidgetActionTypes.ts index 636f410e7f..6d16b7ddb7 100644 --- a/App/common/widgets/widget-actions/WidgetActionTypes.ts +++ b/App/common/widgets/widget-actions/WidgetActionTypes.ts @@ -6,4 +6,5 @@ export const WidgetActionTypes = { OPEN_BOTTOM_SHEET: "OPEN_BOTTOM_SHEET", SHOW_LOADER: "SHOW_LOADER", FINAL_PATCH_CALL: "FINAL_PATCH_CALL", + ANALYTIC_ACTION: "ANALYTIC_ACTION" }; diff --git a/App/common/widgets/widgetResolver.tsx b/App/common/widgets/widgetResolver.tsx index ed42788e08..6c398be213 100644 --- a/App/common/widgets/widgetResolver.tsx +++ b/App/common/widgets/widgetResolver.tsx @@ -30,25 +30,31 @@ import { TITLE_WITH_ASSET_BACKGROUND_WIDGET, TITLE_WITH_COLUMN_WIDGET, TITLE_WITH_LIST_WIDGET, -} from "../constants/WidgetNameConstants"; + SELECT_CARD_WITH_DETAIL_LIST_WIDGET, + TABLE_WIDGET, +} from "../constants"; import { CtaData } from "../interface"; import { GenericWidgetData, Widget } from "../interface/widgets/Widget"; import { SumInsuredWidgetData } from "../interface/widgets/widgetData/SumInsuredWidgetData"; import { ScreenState } from "../screen/BaseScreen"; import { TitleWithColumnWidget } from "../../../components/widgets/title-with-column-widget/TitleWithColumnWidget"; -import { TitleWithAssetBackgroundWidget } from "../../../components/widgets/title-with-asset-background/TitleWithAssetBackground"; import CardWithIconWidget from "../../../components/widgets/card-with-icon-widget/CardWithIconWidget"; +import { + SelectCardWithDetailListWidget, + TableWidget, + TitleWithAssetBackgroundWidget, +} from "../../../components/widgets"; export const GetWidgetView = { getWidget: ( widget: Widget, handleActions: ( value?: any | undefined | null, - actionPayload?: GenericActionPayload + actionPayload?: GenericActionPayload, ) => void, widgetIndex: number, handleClick?: (ctaData: CtaData) => void, - screenState?: ScreenState | null + screenState?: ScreenState | null, ): JSX.Element => { const { widgetName, widgetData, widgetStyle } = widget; return resolveWidgetView( @@ -58,7 +64,7 @@ export const GetWidgetView = { handleActions, widgetIndex, handleClick, - screenState + screenState, ); }, }; @@ -68,11 +74,11 @@ function resolveWidgetView( widgetStyle: ViewStyle, handleActions: ( value?: any | undefined | null, - screenActionPayload?: GenericActionPayload + screenActionPayload?: GenericActionPayload, ) => void, widgetIndex: number, handleClick?: (ctaData: CtaData) => void, - screenState?: ScreenState | null + screenState?: ScreenState | null, ) { switch (widgetName) { case SLIDER_WIDGET: @@ -243,6 +249,28 @@ function resolveWidgetView( handleClick={handleClick} /> ); + case SELECT_CARD_WITH_DETAIL_LIST_WIDGET: + return ( + + ); + case TABLE_WIDGET: + return ( + + ); default: return ; } diff --git a/assets/images/arrow_left.webp b/assets/images/arrow_left.webp new file mode 100644 index 0000000000..a97c19958e Binary files /dev/null and b/assets/images/arrow_left.webp differ diff --git a/components/AppImage.tsx b/components/AppImage.tsx index dcded9c6f4..0d97f3928e 100644 --- a/components/AppImage.tsx +++ b/components/AppImage.tsx @@ -21,6 +21,13 @@ export const AppImage = (imageCode?: string, style?: StyleProp) => { style={style} /> ); + case ImageName.BACK_ARROW: + return ( + + ); default: return null; } diff --git a/components/bottomsheet/BaseBottomSheetComponent.tsx b/components/bottomsheet/BaseBottomSheetComponent.tsx index cc92b29c63..fe6194d31f 100644 --- a/components/bottomsheet/BaseBottomSheetComponent.tsx +++ b/components/bottomsheet/BaseBottomSheetComponent.tsx @@ -8,17 +8,25 @@ import { GetModalView } from "../../App/common/modals/modalViewResolver"; import { NativeDeeplinkNavigatorModule } from "../../App/common/native-module/NativeModules"; import styles from "../../App/common/styles/BaseBottomSheetComponentStyles"; import { BOTTOMSHEET_ANIMATION_DURATION } from "../../App/common/constants/NumericalConstants"; +import { GenericActionPayload } from "../../App/common/actions/GenericAction"; +import { + invalidateCacheWithUrl, + shouldInvalidateSavedData, +} from "../../App/common/utilities/CacheUtils"; +import { setStringPreference } from "../../App/common/utilities/SharedPreferenceUtils"; const BaseBottomSheetComponent = ({ onBottomSheetAnimationEnd, showModal, onClose, modalView, + handleActions, }: { onBottomSheetAnimationEnd?: (id: number | null) => void; showModal: boolean; onClose: () => void; modalView: ModalView | undefined; + handleActions: (actionPayload?: GenericActionPayload) => void; }) => { const [isModalVisible, setModalVisible] = useState(showModal); const modalRef = useRef(null); @@ -30,7 +38,14 @@ const BaseBottomSheetComponent = ({ }, BOTTOMSHEET_ANIMATION_DURATION); }; + const invalidatePostApiData = () => { + return setStringPreference("POST_API_CALLED", "false"); + }; + const handleModalClick = (cta: CtaData) => { + if (invalidateCacheWithUrl(cta.url) || shouldInvalidateSavedData(cta)) { + invalidatePostApiData(); + } switch (cta?.type) { case CtaType.DISMISS_MODAL: if (!!cta?.analyticsEventProperties) { @@ -41,7 +56,7 @@ const BaseBottomSheetComponent = ({ default: try { NativeDeeplinkNavigatorModule.navigateToNaviDeeplinkNavigator( - JSON.stringify(cta) + JSON.stringify(cta), ); } catch (error) { // #TODO: Handle the error gracefully using Sentry. @@ -83,10 +98,10 @@ const BaseBottomSheetComponent = ({ {/* */} - {GetModalView.getModal(modalView!!, handleModalClick)} + {GetModalView.getModal(modalView!!, handleModalClick, handleActions)} ); }; -export default BaseBottomSheetComponent; \ No newline at end of file +export default BaseBottomSheetComponent; diff --git a/components/bottomsheet/member-details-bottom-sheet/MemberDetailsBottomSheet.tsx b/components/bottomsheet/member-details-bottom-sheet/MemberDetailsBottomSheet.tsx new file mode 100644 index 0000000000..748055c98f --- /dev/null +++ b/components/bottomsheet/member-details-bottom-sheet/MemberDetailsBottomSheet.tsx @@ -0,0 +1,51 @@ +import { View } from "react-native"; +import { CtaData } from "../../../App/common/interface"; +import { MemberDetailsBottomSheetData } from "../../../App/common/interface/widgets/modalData/MemberDetailsBottomSheetData"; +import styles from "./MemberDetailsBottomSheetStyle"; +import TitleWithListWidget from "../../widgets/title-with-list-widget/TitleWithListWidget"; +import CtaButton from "../../reusable/cta-button/CtaButton"; +import { StyledText } from "../../widgets/styled-text/StyledText"; +import TitleWithAssetsWidget from "../../widgets/TitleWithAssetsWidget"; +import { GenericActionPayload } from "../../../App/common/actions/GenericAction"; + +export const MemberDetailBottomSheet = ({ + bottomSheetData, + handleModalClick, + handleActions, +}: { + bottomSheetData?: MemberDetailsBottomSheetData; + handleModalClick: (cta: CtaData) => void; + handleActions: (actionPayload?: GenericActionPayload) => void; +}) => { + const onPress = () => { + bottomSheetData?.footerData?.cta && + handleModalClick && + handleModalClick(bottomSheetData?.footerData?.cta); + }; + return ( + + + {}} + handleClick={handleModalClick} + /> + {}} + handleClick={handleModalClick} + /> + + {bottomSheetData?.footerData?.title && ( + + )} + + + + ); +}; diff --git a/components/bottomsheet/member-details-bottom-sheet/MemberDetailsBottomSheetStyle.ts b/components/bottomsheet/member-details-bottom-sheet/MemberDetailsBottomSheetStyle.ts new file mode 100644 index 0000000000..0757117893 --- /dev/null +++ b/components/bottomsheet/member-details-bottom-sheet/MemberDetailsBottomSheetStyle.ts @@ -0,0 +1,27 @@ +import { StyleSheet } from "react-native"; + +const styles = StyleSheet.create({ + columnContainer: { + width: "100%", + flexDirection: "column", + padding: 16, + }, + addMembersWidgetStyle: { + backgroundColor : "#DDEAFF", + marginTop: 16, + borderRadius: 32, + paddingVertical: 8, + paddingHorizontal: 16, + borderColor: "#BED7FF", + borderWidth: 1 + }, + footerWidgetStyle: { + marginTop: 16, + borderRadius: 4, + overflow: "hidden", + padding:16, + backgroundColor: "#F5F5F5" +} +}) + +export default styles \ No newline at end of file diff --git a/components/bottomsheet/policy-amount-bottom-sheet/PolicyAmountBottomSheet.tsx b/components/bottomsheet/policy-amount-bottom-sheet/PolicyAmountBottomSheet.tsx new file mode 100644 index 0000000000..2f5cc770f3 --- /dev/null +++ b/components/bottomsheet/policy-amount-bottom-sheet/PolicyAmountBottomSheet.tsx @@ -0,0 +1,168 @@ +import { FlatList, TouchableOpacity, View } from "react-native"; +import { CtaData } from "../../../App/common/interface"; +import styles from "./PolicyAmountBottomSheetStyle"; +import { + CoverAmountPillData, + PolicyAmountBottomSheetData, +} from "../../../App/common/interface/widgets/modalData/PolicyAmountBottomSheetData"; +import TitleWidget from "../../widgets/title-widget/TitleWidget"; +import CtaButton from "../../reusable/cta-button/CtaButton"; +import { StyledText } from "../../widgets/styled-text/StyledText"; +import TitleWithListWidget from "../../widgets/title-with-list-widget/TitleWithListWidget"; +import { Dispatch, useEffect, useState } from "react"; +import { GenericActionPayload } from "../../../App/common/actions/GenericAction"; +import { WidgetActionTypes } from "../../../App/common/widgets/widget-actions/WidgetActionTypes"; +import WidgetActionHandler from "../../../App/common/widgets/widget-actions/WidgetActionHandler"; +import { sendAsAnalyticsEvent } from "../../../App/common/hooks/useAnalyticsEvent"; + +export const PolicyAmountBottomSheet = ({ + bottomSheetData, + handleModalClick, + handleActions, +}: { + bottomSheetData?: PolicyAmountBottomSheetData; + handleModalClick: (cta: CtaData) => void; + handleActions: (actionPayload?: GenericActionPayload) => void; +}) => { + const onPress = () => { + bottomSheetData?.footerData?.cta && + handleModalClick && + handleModalClick(bottomSheetData?.footerData?.cta); + }; + const [selectedPill, setSelectedPill] = useState({ + id: bottomSheetData?.bottomSheetMetaData?.selectedPill, + }); + + function handleWidgetActions( + value: any | undefined | null, + actionPayloadList: GenericActionPayload | undefined, + ) { + let payload = actionPayloadList; + let needPayloadCompression = false; + actionPayloadList?.metaData?.forEach(actionPayload => { + if (actionPayload?.actionType === WidgetActionTypes.UPDATE_WIDGET_DATA) { + needPayloadCompression = true; + return; + } + }); + if (!!value && needPayloadCompression) { + payload = WidgetActionHandler.getTargetWidgetActionPayload( + value, + actionPayloadList, + ); + } + handleActions(payload); + } + + return ( + + + ( + + )} + keyExtractor={(item, index) => item.id || index.toString()} + numColumns={3} + /> + {}} + /> + + {bottomSheetData?.footerData?.title && ( + + )} + + + ); +}; + +export const CoverAmountPill = ({ + item, + selectedItem, + setSelectedPill, + handleActions, + onValueChangeAction, +}: { + item: CoverAmountPillData; + selectedItem?: CoverAmountPillData; + setSelectedPill: Dispatch>; + handleActions: any; + onValueChangeAction: any; +}) => { + const isSelected = selectedItem?.id === item.id; + + useEffect(() => { + item?.analyticEvents?.onViewEvent && sendAsAnalyticsEvent(item?.analyticEvents?.onViewEvent) + }, []) + + const onPillChangeHandler = () => { + setSelectedPill(item); + item?.analyticEvents?.onSelectedEvent && sendAsAnalyticsEvent(item?.analyticEvents?.onSelectedEvent) + handleActions(item.dependentWidgets, onValueChangeAction); + }; + + const pillStyle = isSelected + ? [item?.defaultPillStyle, item?.selectedState?.pillStyle] + : [item?.defaultPillStyle, item?.unSelectedState?.pillStyle]; + + const title = isSelected + ? item?.selectedState?.title + : item?.unSelectedState?.title; + if (item.selectedState === undefined) { + return ; + } else { + return ( + + {title && } + + ); + } +}; + +const formatData = ( + data: CoverAmountPillData[] | undefined, + numColumns: number, +): CoverAmountPillData[] => { + if (!data || data.length === 0 || numColumns <= 0) return []; + + const elementsInLastRow = data.length % numColumns; + + // Ensure numColumns is a positive integer + if (elementsInLastRow === 0 || elementsInLastRow === numColumns) { + return data; + } else { + const fillCount = numColumns - elementsInLastRow; + const fillerData: CoverAmountPillData = { + coverAmount: undefined, + standardPlanMonthlyPremium: undefined, + comprehensivePlanMonthlyPremium: undefined, + dependentWidgets: undefined, + }; + const filledArray = Array(fillCount).fill(fillerData); + return [...data, ...filledArray]; + } +}; diff --git a/components/bottomsheet/policy-amount-bottom-sheet/PolicyAmountBottomSheetStyle.ts b/components/bottomsheet/policy-amount-bottom-sheet/PolicyAmountBottomSheetStyle.ts new file mode 100644 index 0000000000..985a5fe4b1 --- /dev/null +++ b/components/bottomsheet/policy-amount-bottom-sheet/PolicyAmountBottomSheetStyle.ts @@ -0,0 +1,52 @@ +import { StyleSheet } from "react-native"; + +const styles = StyleSheet.create({ + columnContainer: { + width: "100%", + flexDirection: "column", + padding: 16, + }, + addMembersWidgetStyle: { + marginTop: 16 + }, + footerWidgetStyle: { + marginTop: 16 + }, + pillsContainerStyle: { + marginTop: 16, + marginBottom: 8 + }, + titleStyle: { + width: "100%", + display: "flex", + flexDirection: "row", + flexWrap: "wrap", + justifyContent:"space-between" + }, + cardItem: { + flex: 1, + marginHorizontal: 4, + marginBottom: 8, + backgroundColor: "#FFFFFF", + flexDirection: "column", + justifyContent: "center", + paddingHorizontal: 16, + paddingBottom: 8, + paddingTop: 8, + borderRadius: 4, + borderColor: "#EBEBEB", + borderWidth: 1, + alignItems: "center", + shadowColor: "grey", + shadowOpacity: 1, + shadowRadius: 32, + shadowOffset: { width: 3, height: 3 } + }, + cardItemInvisible: { + backgroundColor: "transparent", + borderColor: "transparent", + } + +}) + +export default styles \ No newline at end of file diff --git a/components/bottomsheet/title-with-feed-back-bottom-sheet/TitleWithFeedBackBottomSheet.tsx b/components/bottomsheet/title-with-feed-back-bottom-sheet/TitleWithFeedBackBottomSheet.tsx index 37a07b1c62..b749967c32 100644 --- a/components/bottomsheet/title-with-feed-back-bottom-sheet/TitleWithFeedBackBottomSheet.tsx +++ b/components/bottomsheet/title-with-feed-back-bottom-sheet/TitleWithFeedBackBottomSheet.tsx @@ -12,7 +12,7 @@ import TitleWidget from "../../widgets/title-widget/TitleWidget"; import styles from "./TitleWithFeedBackBottomSheetStyle"; import { CtaData } from "../../../App/common/interface"; -const ItemComponent = ({ item }: { item: PillData }) => { +export const ItemComponent = ({ item }: { item: PillData }) => { const [isSelected, setIsSelected] = useState(false); const onItemPress = () => { diff --git a/components/reusable/cta-button/CtaButton.tsx b/components/reusable/cta-button/CtaButton.tsx index 9e28fde051..d7a0e43c1e 100644 --- a/components/reusable/cta-button/CtaButton.tsx +++ b/components/reusable/cta-button/CtaButton.tsx @@ -1,4 +1,4 @@ -import { TouchableHighlight, ViewStyle } from "react-native"; +import { TouchableHighlight, TouchableOpacity, ViewStyle } from "react-native"; import { Lottie } from "../../../App/common/constants/StringConstant"; import { ButtonState } from "../../../App/common/interface/widgets/widgetData/FooterWithCardWidgetData"; import { LottieFieldData } from "../../../App/common/interface/widgets/widgetData/TitleWidgetData"; @@ -22,7 +22,8 @@ const CtaButton = ({ lottieStyle: styles.loaderLottieStyle, }; return ( - + ); }; diff --git a/components/reusable/index.ts b/components/reusable/index.ts new file mode 100644 index 0000000000..30ebf6e26e --- /dev/null +++ b/components/reusable/index.ts @@ -0,0 +1 @@ +export { default as SelectButton } from "./select-button/SelectButton"; diff --git a/components/reusable/select-button/SelectButton.tsx b/components/reusable/select-button/SelectButton.tsx new file mode 100644 index 0000000000..496e157390 --- /dev/null +++ b/components/reusable/select-button/SelectButton.tsx @@ -0,0 +1,27 @@ +import { View } from "react-native"; +import { styles } from "./SelectButtonStyles"; +import { SelectButtonType } from "../../../App/common/constants"; + +interface SelectButtonProps { + selected?: boolean; + type?: string; +} + +const RadioButton = ({ selected }: SelectButtonProps) => { + return ( + + {selected && } + + ); +}; + +const SelectButton = ({ selected, type }: SelectButtonProps) => { + switch (type) { + case SelectButtonType.RADIO: + return ; + default: + return ; + } +}; + +export default SelectButton; diff --git a/components/reusable/select-button/SelectButtonStyles.ts b/components/reusable/select-button/SelectButtonStyles.ts new file mode 100644 index 0000000000..f6b1b5aa8c --- /dev/null +++ b/components/reusable/select-button/SelectButtonStyles.ts @@ -0,0 +1,23 @@ +import { StyleSheet } from "react-native"; + +export const styles = StyleSheet.create({ + radioButton: { + width: 24, + height: 24, + borderRadius: 12, + borderWidth: 2, + marginRight: 10, + borderColor: "#A8A8A8A6", + justifyContent: "center", + alignItems: "center", + }, + selectedRadioButton: { + borderColor: "#1F002A", + }, + innerRadio: { + width: 12, + height: 12, + borderRadius: 6, + backgroundColor: "#1F002A", + }, +}); diff --git a/components/reusable/static-header/StaticHeader.tsx b/components/reusable/static-header/StaticHeader.tsx index e3f88feee7..3a10acf33b 100644 --- a/components/reusable/static-header/StaticHeader.tsx +++ b/components/reusable/static-header/StaticHeader.tsx @@ -1,37 +1,59 @@ import { TouchableOpacity } from "react-native-gesture-handler"; -import { View } from "react-native"; +import { BackHandler, View } from "react-native"; import { CtaData } from "../../../App/common/interface"; import { styles } from "./StaticHeaderStyle"; import { ImageName } from "../../../App/common/constants/StringConstant"; import { AppImage } from "../../AppImage"; +import { useEffect } from "react"; export const StaticHeader = ({ handleClick, + leftIcon, + rightIcon, leftIconCta, rightIconCta, }: { handleClick?: (ctaData: CtaData) => void; - leftIconCta?: CtaData; - rightIconCta?: CtaData; + leftIcon?: keyof typeof ImageName; + rightIcon?: keyof typeof ImageName; + leftIconCta?: CtaData | null; + rightIconCta?: CtaData | null; }) => { + const handleBackButtonClick = () => { + handleClick && leftIconCta && handleClick(leftIconCta); + return true; + }; + useEffect(() => { + BackHandler.addEventListener("hardwareBackPress", handleBackButtonClick); + return () => { + BackHandler.removeEventListener( + "hardwareBackPress", + handleBackButtonClick, + ); + }; + }, [leftIconCta]); return ( - { - handleClick && leftIconCta && handleClick(leftIconCta); - }} - activeOpacity={1} - > - {AppImage(ImageName.CROSS, styles.leftImageStyle)} - - { - handleClick && rightIconCta && handleClick(rightIconCta); - }} - activeOpacity={1} - > - {AppImage(ImageName.HELP, styles.rightImageStyle)} - + {!!leftIconCta && ( + { + handleClick && leftIconCta && handleClick(leftIconCta); + }} + activeOpacity={1} + > + {AppImage(leftIcon || ImageName.CROSS, styles.leftImageStyle)} + + )} + {!!rightIconCta && ( + { + handleClick && rightIconCta && handleClick(rightIconCta); + }} + activeOpacity={1} + > + {AppImage(rightIcon || ImageName.HELP, styles.rightImageStyle)} + + )} ); }; diff --git a/components/widgets/BaseWidget.tsx b/components/widgets/BaseWidget.tsx index a9f447a481..c2311f623e 100644 --- a/components/widgets/BaseWidget.tsx +++ b/components/widgets/BaseWidget.tsx @@ -1,4 +1,4 @@ -import React from "react"; +import React, { useEffect } from "react"; import { View } from "react-native"; import { GenericActionPayload } from "../../App/common/actions/GenericAction"; import { CtaData } from "../../App/common/interface"; @@ -46,6 +46,10 @@ const BaseWidget = ({ widgetVisibility: widget.widgetVisibility !== undefined ? widget.widgetVisibility : true, }; + useEffect(() => { + if (widget.widgetVisibility) + handleWidgetActions(null, widget?.widgetRenderActions) + }, []) return widget.widgetVisibility ? ( {GetWidgetView.getWidget( diff --git a/components/widgets/HeaderWithAssetsWidget.tsx b/components/widgets/HeaderWithAssetsWidget.tsx index 7d51b4ac70..9bc59fea43 100644 --- a/components/widgets/HeaderWithAssetsWidget.tsx +++ b/components/widgets/HeaderWithAssetsWidget.tsx @@ -25,7 +25,7 @@ const HeaderWithAssetsWidget = ({ widgetStyle: ViewStyle; handleActions: ( value?: any | undefined | null, - screenActionPayload?: GenericActionPayload + screenActionPayload?: GenericActionPayload, ) => void; widgetIndex: number; handleClick?: (ctaData: CtaData) => void; @@ -43,7 +43,7 @@ const HeaderWithAssetsWidget = ({ return () => { BackHandler.removeEventListener( "hardwareBackPress", - handleBackButtonClick + handleBackButtonClick, ); }; }, [widgetData]); @@ -69,10 +69,12 @@ const HeaderWithAssetsWidget = ({ )} {widgetData.rightIcon && (widgetData.isRightAssetVisible === false ? false : true) && ( - + + + )} {widgetData.rightLottie && (widgetData.isRightAssetVisible === false ? false : true) && ( diff --git a/components/widgets/TitleWithAssetsWidget.tsx b/components/widgets/TitleWithAssetsWidget.tsx index c0b6c3998d..f1f2cd299f 100644 --- a/components/widgets/TitleWithAssetsWidget.tsx +++ b/components/widgets/TitleWithAssetsWidget.tsx @@ -2,10 +2,10 @@ import { StyleSheet, TouchableOpacity, View, ViewStyle } from "react-native"; import { GenericActionPayload } from "../../App/common/actions/GenericAction"; import { CtaData } from "../../App/common/interface"; import { TitleWithAssetsWidgetData } from "../../App/common/interface/widgets/widgetData/TitleWithAssetsWidgetData"; -import Colors from "../../assets/colors/colors"; import { StyledImage } from "../StyledImage"; import { StyledLottie } from "./styled-lottie/StyledLottie"; import { StyledText } from "./styled-text/StyledText"; +import Colors from "../../assets/colors/colors"; const TitleWithAssetsWidget = ({ widgetData, @@ -17,29 +17,45 @@ const TitleWithAssetsWidget = ({ widgetData: TitleWithAssetsWidgetData; widgetStyle: ViewStyle; handleActions: (screenActionPayload?: GenericActionPayload) => void; - widgetIndex: number; + widgetIndex?: number; handleClick?: (ctaData: CtaData) => void; }) => { return ( { - handleClick && widgetData.cta && handleClick(widgetData.cta); + handleClick && widgetData?.cta && handleClick(widgetData?.cta); }} activeOpacity={1} > - - {widgetData.leftIcon && ( - + + {widgetData?.leftIcon && ( + + + )} - {widgetData.leftLottie && ( - + {widgetData?.leftLottie && ( + + + )} - {widgetData.title && } - {widgetData.rightIcon && ( - + {widgetData?.title && ( + + + )} - {widgetData.rightLottie && ( - + {widgetData?.rightIcon && ( + + + + )} + {widgetData?.rightLottie && ( + + + )} diff --git a/components/widgets/footer-with-card-widget/FooterWithCardWidget.tsx b/components/widgets/footer-with-card-widget/FooterWithCardWidget.tsx index 42514b07c2..386b3540bf 100644 --- a/components/widgets/footer-with-card-widget/FooterWithCardWidget.tsx +++ b/components/widgets/footer-with-card-widget/FooterWithCardWidget.tsx @@ -1,11 +1,6 @@ - import throttle from "lodash/throttle"; import React, { useCallback } from "react"; -import { View, ViewStyle } from "react-native"; -import { - TouchableOpacity, - TouchableWithoutFeedback, -} from "react-native-gesture-handler"; +import { TouchableOpacity, View, ViewStyle } from "react-native"; import { commonStyles } from "../../../App/Container/Navi-Insurance/Styles"; import { GenericActionPayload } from "../../../App/common/actions/GenericAction"; import { sendAsAnalyticsEvent } from "../../../App/common/hooks/useAnalyticsEvent"; @@ -55,7 +50,7 @@ const FooterWithCardWidget = ({ widgetStyle: ViewStyle; handleActions: ( value?: any | undefined | null, - screenActionPayload?: GenericActionPayload + screenActionPayload?: GenericActionPayload, ) => void; widgetIndex: number; handleClick?: (ctaData: CtaData) => void; @@ -88,9 +83,9 @@ const FooterWithCardWidget = ({ { leading: true, trailing: false, - } + }, ), - [widgetData] + [widgetData], ); const cardAction = () => { @@ -144,16 +139,18 @@ const FooterWithCardWidget = ({ )} - - - - - + {widgetData?.title && ( + + + + + + )} { + return ( + + + {containerTag?.tagTitle?.text && ( + + )} + + {containerTag?.tag?.url && ( + + )} + + ); +}; + +export const ItemCard = ({ + handleClick, + item, + selected, + onSelect, + showContainerTag, + containerTag, +}: ItemCardProps) => { + useEffect(() => { + item?.analyticEvents?.onViewEvent && + sendAsAnalyticsEvent(item?.analyticEvents?.onViewEvent); + }, []); + + return ( + + {item?.itemType === showContainerTag && ( + + )} + + + + {item?.title?.text && } + {item?.subtitle?.text && ( + + )} + + + + {item?.details?.map((detail, index) => ( + + ))} + + + ); +}; diff --git a/components/widgets/select-card-with-detail-list/ItemDetail.tsx b/components/widgets/select-card-with-detail-list/ItemDetail.tsx new file mode 100644 index 0000000000..b7a17febdf --- /dev/null +++ b/components/widgets/select-card-with-detail-list/ItemDetail.tsx @@ -0,0 +1,39 @@ +import { TouchableOpacity, View } from "react-native"; +import { styles } from "./SelectCardWithDetailListStyles"; +import { ItemDetailProps } from "../../../App/common/interface/widgets/widgetData"; +import { StyledText } from ".."; + +const ItemDetail = ({ + detail, + selected, + handleClick, + showBorder, +}: ItemDetailProps) => { + const onPress = () => + detail?.rightText?.cta && + handleClick && + handleClick(detail?.rightText?.cta); + return ( + + + {detail?.leftTextWithImage && ( + + )} + {detail?.leftText && } + + {detail?.rightText?.cta && ( + + + + )} + + ); +}; + +export default ItemDetail; diff --git a/components/widgets/select-card-with-detail-list/SelectCardWithDetailList.tsx b/components/widgets/select-card-with-detail-list/SelectCardWithDetailList.tsx new file mode 100644 index 0000000000..79c49d1d3c --- /dev/null +++ b/components/widgets/select-card-with-detail-list/SelectCardWithDetailList.tsx @@ -0,0 +1,61 @@ +import { useState } from "react"; +import { TitleWidget } from ".."; +import { + Item, + SelectCardWithDetailListProps, +} from "../../../App/common/interface/widgets/widgetData"; +import { ItemCard } from "./ItemCard"; +import { styles } from "./SelectCardWithDetailListStyles"; +import { sendAsAnalyticsEvent } from "../../../App/common/hooks/useAnalyticsEvent"; + +const SelectCardWithDetailList = ({ + widgetData, + widgetStyle, + handleActions, + handleClick, + widgetIndex, +}: SelectCardWithDetailListProps) => { + const [selectedItem, setSelectedItem] = useState( + widgetData?.widgetMetaData?.selectedItem, + ); + + const handleSelect = (itemType?: string) => { + setSelectedItem(itemType); + const item = widgetData?.items?.find( + item => item?.itemType === itemType, + ); + item?.analyticEvents?.onSelectedEvent && sendAsAnalyticsEvent(item?.analyticEvents?.onSelectedEvent) + if (item?.dependentWidgets) { + handleActions( + item?.dependentWidgets, + widgetData?.widgetMetaData?.onValueChangeAction, + ); + } + }; + + return ( + <> + + {widgetData?.items?.map((item: Item) => { + return ( + handleSelect(item?.itemType)} + /> + ); + })} + + ); +}; + +export default SelectCardWithDetailList; diff --git a/components/widgets/select-card-with-detail-list/SelectCardWithDetailListStyles.ts b/components/widgets/select-card-with-detail-list/SelectCardWithDetailListStyles.ts new file mode 100644 index 0000000000..c11f9dada9 --- /dev/null +++ b/components/widgets/select-card-with-detail-list/SelectCardWithDetailListStyles.ts @@ -0,0 +1,69 @@ +import { StyleSheet } from "react-native"; + +export const styles = StyleSheet.create({ + card: { + backgroundColor: "#fff", + borderRadius: 4, + padding: 16, + marginTop: 16, + width: "100%", + borderColor: "#EBEBEB", + borderWidth: 1, + position: "relative", + elevation: 3, + shadowColor: "#B0C0D9", + shadowOffset: { width: 3, height: 3 }, + shadowOpacity: 0.3, + shadowRadius: 16, + }, + selectedCard: { + borderColor: "#1F002A", + backgroundColor: "#EAF2FF", + }, + detailCardContainer: { + borderRadius: 4, + overflow: "hidden", + }, + detailCard: { + display: "flex", + flexDirection: "row", + justifyContent: "space-between", + alignItems: "center", + backgroundColor: "#F5F5F5", + paddingHorizontal: 12, + paddingVertical: 8, + }, + detailLeftText: { + flexDirection: "row", + justifyContent: "flex-start", + }, + alignStart: { + alignItems: "flex-start", + }, + borderBottom: { + borderBottomWidth: 1, + borderBottomColor: "#E3E5E5", + }, + selectedDetailCard: { + backgroundColor: "#FFFFFF", + }, + headerContainer: { + flexDirection: "row", + marginBottom: 16, + }, + tag: { + justifyContent: "flex-start", + alignItems: "flex-end", + top: 14, + right: -3, + position: "absolute", + }, + tagContainer: { + backgroundColor: "#3C7DFF", + paddingHorizontal: 8, + paddingVertical: 4, + borderTopStartRadius: 2, + borderTopEndRadius: 2, + borderBottomStartRadius: 2, + }, +}); diff --git a/components/widgets/styled-lottie/StyledLottie.tsx b/components/widgets/styled-lottie/StyledLottie.tsx index 2a6865d05b..b56e4591f3 100644 --- a/components/widgets/styled-lottie/StyledLottie.tsx +++ b/components/widgets/styled-lottie/StyledLottie.tsx @@ -23,7 +23,6 @@ export const StyledLottie = ({ }, [lottieFieldData]); if (!lottieFieldData?.url) return <>; - return ( { diff --git a/components/widgets/table-widget/Table.tsx b/components/widgets/table-widget/Table.tsx new file mode 100644 index 0000000000..6f02ab4557 --- /dev/null +++ b/components/widgets/table-widget/Table.tsx @@ -0,0 +1,114 @@ +import { useEffect, useState } from "react"; +import { TouchableOpacity, View } from "react-native"; +import { + TableWidgetProps, + Column, + Row, + Cell as CellData, + ColumnsProps, + RowsProps, + CellProps, +} from "../../../App/common/interface/widgets/widgetData"; +import { StyledImage, StyledText } from ".."; +import { styles } from "./TableWidgetStyles"; +import { sendAsAnalyticsEvent } from "../../../App/common/hooks/useAnalyticsEvent"; + +const Cell = ({ widgetData, cell, index, handleClick }: CellProps) => { + useEffect(()=>{ + cell?.analyticEvents?.onViewEvent && sendAsAnalyticsEvent(cell?.analyticEvents?.onViewEvent) + },[]) + return ( + { + handleClick && cell?.cta && handleClick(cell?.cta); + }} + activeOpacity={1} + > + {cell?.title?.text && ( + + )} + + {cell?.image?.url && ( + + )} + + ); +}; + +const Rows = ({ widgetData, rowsToDisplay, handleClick }: RowsProps) => { + return ( + <> + {widgetData?.rows && + widgetData?.rows + ?.slice(0, rowsToDisplay) + ?.map((row: Row, index: number) => { + return ( + + {row?.cells?.map((cell: CellData, index: number) => ( + + ))} + + ); + })} + + ); +}; +const Columns = ({ widgetData }: ColumnsProps) => { + return ( + + {widgetData?.columns && + widgetData?.columns?.map((column: Column, index: number) => { + return ( + + {column?.title?.text && ( + + )} + {column?.subtitle?.text && ( + + )} + + ); + })} + + ); +}; + +const Table = ({ widgetData, handleClick }: TableWidgetProps) => { + const [rowsToDisplay, setRowsToDisplay] = useState( + widgetData?.rowsToDisplay || widgetData?.rows?.length, + ); + + const handleSelect = () => { + setRowsToDisplay(widgetData?.rows?.length); + widgetData.viewButton?.cta?.analyticsEventProperties && sendAsAnalyticsEvent(widgetData.viewButton?.cta?.analyticsEventProperties) + }; + + return ( + <> + + + {rowsToDisplay !== widgetData?.rows?.length && + widgetData.viewButton?.text && ( + + + + )} + + ); +}; + +export default Table; diff --git a/components/widgets/table-widget/TableWidgetStyles.ts b/components/widgets/table-widget/TableWidgetStyles.ts new file mode 100644 index 0000000000..1a4d02395a --- /dev/null +++ b/components/widgets/table-widget/TableWidgetStyles.ts @@ -0,0 +1,21 @@ +import { StyleSheet } from "react-native"; + +export const styles = StyleSheet.create({ + row: { + flexDirection: "row", + }, + header: { + alignItems: "center", + flexDirection: "column" + }, + cell: { + flex: 1, + padding: 10, + flexDirection: "row", + textAlign: "left", + alignItems: "center", + justifyContent: "space-between", + borderBottomWidth: 1, + borderBottomColor: "#F5F5F5", + }, +}); diff --git a/components/widgets/title-widget/TitleWidget.tsx b/components/widgets/title-widget/TitleWidget.tsx index e516548ccc..18172cc8d8 100644 --- a/components/widgets/title-widget/TitleWidget.tsx +++ b/components/widgets/title-widget/TitleWidget.tsx @@ -1,5 +1,5 @@ import { View, ViewStyle } from "react-native"; -import { TouchableWithoutFeedback } from "react-native-gesture-handler"; +import { TouchableOpacity } from "react-native"; import { GenericActionPayload } from "../../../App/common/actions/GenericAction"; import { CtaData } from "../../../App/common/interface"; import { TitleWidgetData } from "../../../App/common/interface/widgets/widgetData/TitleWidgetData"; @@ -14,7 +14,10 @@ const TitleWidget = ({ }: { widgetData: TitleWidgetData; widgetStyle?: ViewStyle; - handleActions?: (screenActionPayload?: GenericActionPayload) => void; + handleActions?: ( + value: any | undefined | null, + actionPayloadList: GenericActionPayload | undefined + ) => void; handleClick?: (cta: CtaData) => void; widgetIndex?: number; }) => { @@ -22,28 +25,32 @@ const TitleWidget = ({ handleClick && (widgetData?.title?.cta) && handleClick(widgetData?.title?.cta); + widgetData?.title?.actions && handleActions && + handleActions(null,widgetData?.title?.actions) }; const handleRightTitleClick = () => { handleClick && (widgetData?.rightTitle?.cta) && handleClick(widgetData?.rightTitle?.cta); + widgetData?.rightTitle?.actions && handleActions && + handleActions(null, widgetData?.rightTitle?.actions) }; return ( {widgetData.title && ( - + - + )} {widgetData.subtitle && ( )} {widgetData.rightTitle && ( - + - + )} ); diff --git a/components/widgets/title-with-asset-background/TitleWithAssetBackground.tsx b/components/widgets/title-with-asset-background/TitleWithAssetBackground.tsx index c4e1db5971..4061980b22 100644 --- a/components/widgets/title-with-asset-background/TitleWithAssetBackground.tsx +++ b/components/widgets/title-with-asset-background/TitleWithAssetBackground.tsx @@ -105,3 +105,5 @@ export const TitleWithAssetBackgroundWidget = ({ ); }; + +export default TitleWithAssetBackgroundWidget; \ No newline at end of file diff --git a/components/widgets/title-with-list-widget/TitleWithListWidget.tsx b/components/widgets/title-with-list-widget/TitleWithListWidget.tsx index 6634d44bc2..dda5e32edb 100644 --- a/components/widgets/title-with-list-widget/TitleWithListWidget.tsx +++ b/components/widgets/title-with-list-widget/TitleWithListWidget.tsx @@ -7,13 +7,26 @@ import { } from "../../../App/common/interface/widgets/widgetData/TitleWithListWidgetData"; import TitleWidget from "../title-widget/TitleWidget"; import styles from "./TitleWithListWidgetStyle"; +import { useEffect } from "react"; +import { sendAsAnalyticsEvent } from "../../../App/common/hooks/useAnalyticsEvent"; +import { useCallback } from "react"; +import throttle from "lodash/throttle"; -const ListItemComponent = ({ item }: { item: ListItem }) => { +const ListItemComponent = ({ + item, + handleActions, +}: { + item: ListItem; + handleActions?: (screenActionPayload?: GenericActionPayload) => void; +}) => { + useEffect(() => { + item.onViewEvent && sendAsAnalyticsEvent(item.onViewEvent); + }); return ( {}} + handleActions={handleActions} widgetIndex={Number(item.id)} /> ); @@ -30,22 +43,33 @@ const TitleWithListWidget = ({ widgetStyle: ViewStyle; handleActions: (screenActionPayload?: GenericActionPayload) => void; handleClick?: (cta: CtaData) => void; - widgetIndex: number; + widgetIndex?: number; }) => { + const throttledHandleActions = useCallback( + throttle(handleActions, 700, { leading: true, trailing: false }), + [], + ); return ( - + ( - + )} keyExtractor={(item, index) => item.id || index.toString()} /> diff --git a/components/widgets/title-with-list-widget/TitleWithListWidgetStyle.ts b/components/widgets/title-with-list-widget/TitleWithListWidgetStyle.ts index f6b08fcfe2..a902a180c3 100644 --- a/components/widgets/title-with-list-widget/TitleWithListWidgetStyle.ts +++ b/components/widgets/title-with-list-widget/TitleWithListWidgetStyle.ts @@ -13,6 +13,11 @@ const styles = StyleSheet.create({ borderRadius: 4, borderWidth: 1, borderColor: "#EBEBEB", + elevation: 4, + shadowColor: "#B0C0D9", + shadowOffset: { width: 3, height: 3 }, + shadowOpacity: 1, + shadowRadius: 32.962 / 2 }, itemRowContainer: { flexDirection: "row",