NTP-8231 | RN Error Screen (#13193)

This commit is contained in:
Prajjaval Verma
2024-10-24 11:52:11 +05:30
committed by GitHub
parent 86e0fe2d66
commit 722ea0a17c
21 changed files with 127 additions and 125 deletions

View File

@@ -28,7 +28,7 @@ const GenericErrorScreen = () => {
leftIcon={"CROSS"} leftIcon={"CROSS"}
/> />
<View style={styles.centerContent}> <View style={styles.centerContent}>
{AppImage(ImageName.SWW, styles.centerIcon)} <AppImage imageCode={ImageName.SWW} style={styles.centerIcon} />
<Text style={styles.errorTitle}>{ERROR_TITLE}</Text> <Text style={styles.errorTitle}>{ERROR_TITLE}</Text>
<Text style={styles.errorSubtitle}>{ERROR_SUBTITLE}</Text> <Text style={styles.errorSubtitle}>{ERROR_SUBTITLE}</Text>
</View> </View>

View File

@@ -44,7 +44,10 @@ const QuoteApologyScreen = ({
<View style={styles.headerBorder} /> <View style={styles.headerBorder} />
</View> </View>
<View style={styles.centerContent}> <View style={styles.centerContent}>
{AppImage(ImageName.QUOTE_APOLOGY_ICON, styles.centerIcon)} <AppImage
imageCode={ImageName.QUOTE_APOLOGY_ICON}
style={styles.centerIcon}
/>
<Text style={styles.title}>{QUOTE_APOLOGY_TITLE}</Text> <Text style={styles.title}>{QUOTE_APOLOGY_TITLE}</Text>
<Text style={styles.subtitle}>{QUOTE_APOLOGY_SUBTITLE}</Text> <Text style={styles.subtitle}>{QUOTE_APOLOGY_SUBTITLE}</Text>
</View> </View>

View File

@@ -1,19 +1,17 @@
import { View, Text } from "react-native"; import { Text, TouchableOpacity, View } from "react-native";
import { GenericActionPayload } from "../../../../../common/actions/GenericAction"; import { AppImage } from "../../../../../../components/AppImage";
import { StaticHeader } from "../../../../../../components/reusable/static-header/StaticHeader";
import {
ErrorMetaData,
GenericActionPayload,
} from "../../../../../common/actions/GenericAction";
import { RETRY } from "../../../../../common/constants";
import { import {
CtaData, CtaData,
StaticHeaderProperties, StaticHeaderProperties,
} from "../../../../../common/interface"; } from "../../../../../common/interface";
import { StaticHeader } from "../../../../../../components/reusable/static-header/StaticHeader"; import { getErrorResponseFromStatusCode } from "../../../../../common/utilities/ErrorUtils";
import { styles } from "./QuoteOfferErrorScreenStyle"; import { styles } from "./QuoteOfferErrorScreenStyle";
import { TouchableOpacity } from "react-native-gesture-handler";
import {
ERROR_SUBTITLE,
ERROR_TITLE,
RETRY,
ImageName,
} from "../../../../../common/constants/StringConstant";
import { AppImage } from "../../../../../../components/AppImage";
const QuoteOfferErrorScreen = ({ const QuoteOfferErrorScreen = ({
errorMetaData, errorMetaData,
@@ -21,7 +19,7 @@ const QuoteOfferErrorScreen = ({
handleClick, handleClick,
headerProperties, headerProperties,
}: { }: {
errorMetaData?: GenericActionPayload; errorMetaData?: ErrorMetaData;
handleActions?: (screenPayload?: GenericActionPayload) => void; handleActions?: (screenPayload?: GenericActionPayload) => void;
handleClick?: (cta: CtaData) => void; handleClick?: (cta: CtaData) => void;
headerProperties: StaticHeaderProperties; headerProperties: StaticHeaderProperties;
@@ -29,7 +27,9 @@ const QuoteOfferErrorScreen = ({
const onPress = () => { const onPress = () => {
handleActions && handleActions(errorMetaData); handleActions && handleActions(errorMetaData);
}; };
const errorResponse = getErrorResponseFromStatusCode(
errorMetaData?.errorStatusCode,
);
return ( return (
<View style={styles.container}> <View style={styles.container}>
<StaticHeader <StaticHeader
@@ -40,9 +40,15 @@ const QuoteOfferErrorScreen = ({
rightIcon={headerProperties?.rightIcon} rightIcon={headerProperties?.rightIcon}
/> />
<View style={styles.centerContent}> <View style={styles.centerContent}>
{AppImage(ImageName.SWW, styles.centerIcon)} {errorResponse.image && (
<Text style={styles.errorTitle}>{ERROR_TITLE}</Text> <AppImage imageCode={errorResponse.image} style={styles.centerIcon} />
<Text style={styles.errorSubtitle}>{ERROR_SUBTITLE}</Text> )}
{errorResponse.title && (
<Text style={styles.errorTitle}>{errorResponse.title}</Text>
)}
{errorResponse.subtitle && (
<Text style={styles.errorSubtitle}>{errorResponse.subtitle}</Text>
)}
</View> </View>
<TouchableOpacity <TouchableOpacity
onPress={onPress} onPress={onPress}

View File

@@ -14,6 +14,10 @@ export interface GenericActionPayload {
screenData?: ScreenData | null; screenData?: ScreenData | null;
} }
export interface ErrorMetaData extends GenericActionPayload {
errorStatusCode?: number;
}
export interface ActionMetaData { export interface ActionMetaData {
actionType?: string; actionType?: string;
// ActionMetaData has some key attributes required to perform any action e.g. critical widget communications i.e. inter/intra widget, screen level API calls, bottom sheet, modal, etc. // ActionMetaData has some key attributes required to perform any action e.g. critical widget communications i.e. inter/intra widget, screen level API calls, bottom sheet, modal, etc.

View File

@@ -0,0 +1,11 @@
export const STATUS_CODE_NO_INTERNET = 20;
export const STATUS_CODE_UNAUTHORIZED = 401;
export const STATUS_CODE_FORBIDDEN = 403;
export const STATUS_CODE_NOT_FOUND = 404;
export const STATUS_CODE_INTERNAL_SERVER_ERROR = 500;
export const STATUS_CODE_BAD_REQUEST = 400;
export const STATUS_CODE_SERVICE_UNAVAILABLE = 503;
export const STATUS_CODE_TIMEOUT = 408;
export const STATUS_CODE_CONFLICT = 409;
export const STATUS_CODE_GATEWAY_TIMEOUT = 504;
export const STATUS_CODE_TOO_MANY_REQUESTS = 429;

View File

@@ -11,6 +11,7 @@ export const Lottie = {
export const ImageName = { export const ImageName = {
SWW: "SWW", SWW: "SWW",
NO_INTERNET: "NO_INTERNET",
CROSS: "CROSS", CROSS: "CROSS",
BACK_ARROW: "BACK_ARROW", BACK_ARROW: "BACK_ARROW",
HELP: "HELP", HELP: "HELP",
@@ -34,7 +35,10 @@ export enum BundleState {
export const CODEPUSH_METHOD = "onCodepushStatusChange"; export const CODEPUSH_METHOD = "onCodepushStatusChange";
export const ERROR_TITLE = "Something went wrong"; export const ERROR_TITLE = "Something went wrong";
export const ERROR_INTERNET_TITLE = "No internet connection!";
export const ERROR_SUBTITLE = "Please try again after some time"; export const ERROR_SUBTITLE = "Please try again after some time";
export const ERROR_INTERNET_SUBTITLE =
"Please check your internet connectivity and try again";
export const RETRY = "Retry"; export const RETRY = "Retry";
export const QUOTE_APOLOGY_TITLE = export const QUOTE_APOLOGY_TITLE =
"Sorry, we cannot insure some members with health issues!"; "Sorry, we cannot insure some members with health issues!";

View File

@@ -8,3 +8,4 @@ export * from "./ScreenNameConstants";
export * from "./SentryConstants"; export * from "./SentryConstants";
export * from "./StringConstant"; export * from "./StringConstant";
export * from "./WidgetNameConstants"; export * from "./WidgetNameConstants";
export * from "./StatusCodeConstant";

View File

@@ -0,0 +1,5 @@
export interface ErrorResponse {
title?: string;
subtitle?: string;
image?: string;
}

View File

@@ -1,10 +0,0 @@
import { ActionMetaData } from "../../../actions/GenericAction";
import { ButtonData } from "../widgetData/FooterWithCardWidgetData";
import { TextFieldData, TitleWidgetData } from "../widgetData/TitleWidgetData";
export interface ErrorMetaData {
title?: TextFieldData,
subTitle?: TextFieldData,
errorMeta?: ActionMetaData[] | null,
button?: ButtonData
}

View File

@@ -1,15 +1,15 @@
import { ViewStyle } from "react-native"; import { ViewStyle } from "react-native";
import { Widget } from "../Widget"; import { ErrorMetaData } from "../../../actions/GenericAction";
import { ScreenState } from "../../../screen/BaseScreen"; import { ScreenState } from "../../../screen/BaseScreen";
import { Widget } from "../Widget";
import { ScreenMetaData } from "./ScreenMetaData"; import { ScreenMetaData } from "./ScreenMetaData";
import { GenericActionPayload } from "../../../actions/GenericAction";
export interface ScreenData { export interface ScreenData {
screenStyle?: ViewStyle; screenStyle?: ViewStyle;
screenId?: string; screenId?: string;
screenWidgets?: ScreenWidgets; screenWidgets?: ScreenWidgets;
screenState?: ScreenState | null; screenState?: ScreenState | null;
errorMetaData?: GenericActionPayload; errorMetaData?: ErrorMetaData;
screenMetaData?: ScreenMetaData; screenMetaData?: ScreenMetaData;
} }

View File

@@ -103,6 +103,7 @@ export const handleErrorData = (
}, },
screenMetaData, screenMetaData,
], ],
errorStatusCode: error.statusCode,
}, },
}; };
setScreenData(updatedScreenData); setScreenData(updatedScreenData);

View File

@@ -1,4 +1,13 @@
import { AnalyticsGlobalErrorTypeConstant } from "../constants"; import {
AnalyticsGlobalErrorTypeConstant,
ERROR_INTERNET_SUBTITLE,
ERROR_INTERNET_TITLE,
ERROR_SUBTITLE,
ERROR_TITLE,
ImageName,
STATUS_CODE_NO_INTERNET,
} from "../constants";
import { ErrorResponse } from "../interface/components/ErrorResponse";
export const getErrorTypeFromStatusCode = (statusCode: number) => { export const getErrorTypeFromStatusCode = (statusCode: number) => {
const statusCodeforGenericError = [20, 23, 24, 401, 404]; const statusCodeforGenericError = [20, 23, 24, 401, 404];
@@ -9,3 +18,22 @@ export const getErrorTypeFromStatusCode = (statusCode: number) => {
return AnalyticsGlobalErrorTypeConstant.GLOBAL_INTERNAL_ERRORS; return AnalyticsGlobalErrorTypeConstant.GLOBAL_INTERNAL_ERRORS;
}; };
export const getErrorResponseFromStatusCode = (
statusCode?: number,
): ErrorResponse => {
switch (statusCode) {
case STATUS_CODE_NO_INTERNET:
return {
title: ERROR_INTERNET_TITLE,
subtitle: ERROR_INTERNET_SUBTITLE,
image: ImageName.NO_INTERNET,
};
default:
return {
title: ERROR_TITLE,
subtitle: ERROR_SUBTITLE,
image: ImageName.SWW,
};
}
};

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

View File

@@ -1,11 +1,19 @@
import { Image, ImageStyle, StyleProp } from "react-native"; import { Image, ImageStyle, StyleProp } from "react-native";
import { ImageName } from "../App/common/constants/StringConstant"; import { ImageName } from "../App/common/constants/StringConstant";
export const AppImage = (imageCode?: string, style?: StyleProp<ImageStyle>) => {
export const AppImage: React.FC<AppImageProps> = ({ imageCode, style }) => {
switch (imageCode) { switch (imageCode) {
case ImageName.SWW: case ImageName.SWW:
return ( return (
<Image source={require("../assets/images/sww.webp")} style={style} /> <Image source={require("../assets/images/sww.webp")} style={style} />
); );
case ImageName.NO_INTERNET:
return (
<Image
source={require("../assets/images/no_internet.webp")}
style={style}
/>
);
case ImageName.CROSS: case ImageName.CROSS:
return ( return (
<Image source={require("../assets/images/cross.webp")} style={style} /> <Image source={require("../assets/images/cross.webp")} style={style} />
@@ -32,3 +40,8 @@ export const AppImage = (imageCode?: string, style?: StyleProp<ImageStyle>) => {
return null; return null;
} }
}; };
interface AppImageProps {
imageCode?: string;
style?: StyleProp<ImageStyle>;
}

View File

@@ -1,7 +1,6 @@
import React from "react"; import React from "react";
import { ImageFieldData } from "../App/common/interface/widgets/widgetData/TitleWidgetData"; import { ImageFieldData } from "../App/common/interface/widgets/widgetData/TitleWidgetData";
import { Image } from "react-native"; import { Image, TouchableOpacity } from "react-native";
import { TouchableOpacity } from "react-native-gesture-handler";
import { CtaData } from "../App/common/interface"; import { CtaData } from "../App/common/interface";
import { GenericActionPayload } from "../App/common/actions/GenericAction"; import { GenericActionPayload } from "../App/common/actions/GenericAction";

View File

@@ -1,6 +1,5 @@
import React from "react"; import React from "react";
import { View } from "react-native"; import { FlatList, View } from "react-native";
import { FlatList } from "react-native-gesture-handler";
import { commonStyles } from "../../../App/Container/Navi-Insurance/Styles"; import { commonStyles } from "../../../App/Container/Navi-Insurance/Styles";
import { CtaData } from "../../../App/common/interface"; import { CtaData } from "../../../App/common/interface";
import { import {

View File

@@ -40,7 +40,10 @@ export const StaticHeader = ({
}} }}
activeOpacity={1} activeOpacity={1}
> >
{AppImage(leftIcon || ImageName.CROSS, styles.leftImageStyle)} <AppImage
imageCode={leftIcon || ImageName.CROSS}
style={styles.leftImageStyle}
/>
</TouchableOpacity> </TouchableOpacity>
)} )}
{!!rightIconCta && ( {!!rightIconCta && (
@@ -50,7 +53,10 @@ export const StaticHeader = ({
}} }}
activeOpacity={1} activeOpacity={1}
> >
{AppImage(rightIcon || ImageName.HELP, styles.rightImageStyle)} <AppImage
imageCode={rightIcon || ImageName.HELP}
style={styles.rightImageStyle}
/>
</TouchableOpacity> </TouchableOpacity>
)} )}
</View> </View>

View File

@@ -1,64 +0,0 @@
import { Text, View, ViewStyle } from "react-native";
import { TouchableOpacity } from "react-native-gesture-handler";
import { GenericActionPayload } from "../../App/common/actions/GenericAction";
import { TitleWidgetData } from "../../App/common/interface/widgets/widgetData/TitleWidgetData";
import { NativeDeeplinkNavigatorModule } from "../../App/common/native-module/NativeModules";
const ButtonTestWidget = ({
widgetData,
widgetStyle,
handleActions,
widgetIndex,
}: {
widgetData: TitleWidgetData;
widgetStyle: ViewStyle;
handleActions: (
value: any | undefined | null,
screenActionPayload: GenericActionPayload
) => void;
widgetIndex: number;
}) => {
const handleButtonClick = (): void => {
NativeDeeplinkNavigatorModule.navigateToNaviDeeplinkNavigator(
JSON.stringify({
url: "gi/fresh_policy_form/form",
type: "REDIRECTION_CTA",
parameters: [
{
key: "type",
value: "FRESH_POLICY",
},
{
key: "applicationType",
value: "FRESH_POLICY",
},
{
key: "landingPageVersion",
value: "3",
},
],
})
);
// handleActions({
// actionType: WidgetActionTypes.UPDATE_WIDGET_DATA,
// metaData: {
// widgetActionMeta: {
// targetWidgetId: "title_widget_1",
// keyPath: "subtitle.text",
// newValue: "THIS IS THE SUBTITLE"
// }
// }
// }
// );
};
return (
<View style={widgetStyle}>
<TouchableOpacity onPress={handleButtonClick}>
<Text>Click me</Text>
</TouchableOpacity>
</View>
);
};
export default ButtonTestWidget;

View File

@@ -1,14 +1,12 @@
import { View, ViewStyle } from "react-native"; import { TouchableOpacity, View } from "react-native";
import { CardWithIconWidgetData } from "../../../App/common/interface/widgets/widgetData/CardWithIconWidgetData"; import { commonStyles } from "../../../App/Container/Navi-Insurance/Styles";
import { GenericActionPayload } from "../../../App/common/actions/GenericAction"; import { GenericActionPayload } from "../../../App/common/actions/GenericAction";
import { CtaData } from "../../../App/common/interface"; import { CtaData } from "../../../App/common/interface";
import { styles } from "./CardWithIconWidgetStyle"; import { CardWithIconWidgetData } from "../../../App/common/interface/widgets/widgetData/CardWithIconWidgetData";
import { StyledText } from "../styled-text/StyledText";
import CtaButton from "../../reusable/cta-button/CtaButton";
import { StyledImage } from "../../StyledImage"; import { StyledImage } from "../../StyledImage";
import { commonStyles } from "../../../App/Container/Navi-Insurance/Styles"; import CtaButton from "../../reusable/cta-button/CtaButton";
import { TouchableOpacity } from "react-native-gesture-handler"; import { StyledText } from "../styled-text/StyledText";
import { styles } from "./CardWithIconWidgetStyle";
const CardWithIconWidget = ({ const CardWithIconWidget = ({
widgetData, widgetData,
handleActions, handleActions,
@@ -17,7 +15,7 @@ const CardWithIconWidget = ({
widgetData: CardWithIconWidgetData; widgetData: CardWithIconWidgetData;
handleActions: ( handleActions: (
value?: any | undefined | null, value?: any | undefined | null,
screenActionPayload?: GenericActionPayload screenActionPayload?: GenericActionPayload,
) => void; ) => void;
handleClick?: (cta: CtaData) => void; handleClick?: (cta: CtaData) => void;
}) => { }) => {
@@ -31,7 +29,9 @@ const CardWithIconWidget = ({
activeOpacity={1} activeOpacity={1}
> >
<View style={styles.columnContainer}> <View style={styles.columnContainer}>
{widgetData.title?.text && <StyledText textFieldData={widgetData.title} />} {widgetData.title?.text && (
<StyledText textFieldData={widgetData.title} />
)}
{widgetData.title?.text && widgetData.subtitle && ( {widgetData.title?.text && widgetData.subtitle && (
<View style={commonStyles.verticalSpacer4} /> <View style={commonStyles.verticalSpacer4} />
)} )}

View File

@@ -1,5 +1,4 @@
import { TextStyle, ViewStyle } from "react-native"; import { TextStyle, TouchableWithoutFeedback, ViewStyle } from "react-native";
import { TouchableWithoutFeedback } from "react-native-gesture-handler";
import Animated, { SharedValue } from "react-native-reanimated"; import Animated, { SharedValue } from "react-native-reanimated";
import { import {
SumInsuredData, SumInsuredData,
@@ -114,7 +113,7 @@ const SubtitleComponent = ({
substring: sub.substring, substring: sub.substring,
textStyle: substringStyle, textStyle: substringStyle,
}; };
} },
), ),
}} }}
/> />

View File

@@ -1,7 +1,5 @@
import { useCallback, useMemo } from "react"; import { useCallback, useMemo } from "react";
import { View, ViewStyle } from "react-native"; import { TouchableWithoutFeedback, View, ViewStyle } from "react-native";
import { TouchableWithoutFeedback } from "react-native-gesture-handler";
import { GenericActionPayload } from "../../../App/common/actions/GenericAction"; import { GenericActionPayload } from "../../../App/common/actions/GenericAction";
import { CtaData } from "../../../App/common/interface"; import { CtaData } from "../../../App/common/interface";
import { TitleSubtitleWithAssetWidgetData } from "../../../App/common/interface/widgets/widgetData/TitleSubtitleWithAssetWidgetData"; import { TitleSubtitleWithAssetWidgetData } from "../../../App/common/interface/widgets/widgetData/TitleSubtitleWithAssetWidgetData";
@@ -22,18 +20,17 @@ const TitleSubtitleWithAssetWidget = ({
widgetStyle: ViewStyle; widgetStyle: ViewStyle;
handleActions: ( handleActions: (
value?: any | undefined | null, value?: any | undefined | null,
screenActionPayload?: GenericActionPayload screenActionPayload?: GenericActionPayload,
) => void; ) => void;
handleClick?: (cta: CtaData) => void; handleClick?: (cta: CtaData) => void;
widgetIndex: number; widgetIndex: number;
}) => { }) => {
const getBackgroundAsset = () => { const getBackgroundAsset = () => {
return useMemo(() => { return useMemo(() => {
if (widgetData?.backgroundImage?.url) { if (widgetData?.backgroundImage?.url) {
return <StyledImage imageFieldData={widgetData.backgroundImage} />; return <StyledImage imageFieldData={widgetData.backgroundImage} />;
} else if (widgetData?.backgroundLottie?.url) { } else if (widgetData?.backgroundLottie?.url) {
return <StyledLottie return <StyledLottie lottieFieldData={widgetData.backgroundLottie} />;
lottieFieldData={widgetData.backgroundLottie} />;
} else { } else {
return <View style={styles.background}></View>; return <View style={styles.background}></View>;
} }
@@ -44,7 +41,7 @@ const TitleSubtitleWithAssetWidget = ({
leading: true, leading: true,
trailing: false, trailing: false,
}), }),
[widgetData] [widgetData],
); );
return ( return (
<TouchableWithoutFeedback onPress={throttledHandleActions}> <TouchableWithoutFeedback onPress={throttledHandleActions}>
@@ -68,4 +65,4 @@ const TitleSubtitleWithAssetWidget = ({
); );
}; };
export default TitleSubtitleWithAssetWidget; export default TitleSubtitleWithAssetWidget;