Skip to content

Commit

Permalink
feat(Carta Giovani Nazionale): [#179282600] Integrates CGN Merchant L…
Browse files Browse the repository at this point in the history
…anding page discount option (#3316)

* [#179282600] Integrates CGN Merchant Landing page discount option

* [#179282600] Adds missing localized string

* [#179282600] Implements common webview component with error and loading handlers

* [#179282600] Adds snapshot testing on new common component

Co-authored-by: pietro909 <[email protected]>
  • Loading branch information
CrisTofani and pietro909 authored Aug 30, 2021
1 parent 1390e0b commit 25f7bfa
Show file tree
Hide file tree
Showing 12 changed files with 327 additions and 14 deletions.
1 change: 1 addition & 0 deletions locales/en/index.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2466,6 +2466,7 @@ bonus:
conditions: Conditions
cta:
label: Navigate to merchant website
landingPage: Get the benefit
categories:
theater: theater, cinema and entertainment
travel: travel
Expand Down
1 change: 1 addition & 0 deletions locales/it/index.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2494,6 +2494,7 @@ bonus:
conditions: Condizioni
cta:
label: Vai al sito dell'esercente
landingPage: Accedi all’agevolazione
categories:
theater: teatro, cinema e spettacolo
travel: viaggi
Expand Down
46 changes: 46 additions & 0 deletions ts/components/WebviewComponent.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import * as React from "react";
import WebView from "react-native-webview";
import { useState } from "react";
import { WebViewSource } from "react-native-webview/lib/WebViewTypes";
import GenericErrorComponent from "./screens/GenericErrorComponent";
import LoadingSpinnerOverlay from "./LoadingSpinnerOverlay";
import { IOStyles } from "./core/variables/IOStyles";

type Props = {
source: WebViewSource;
};

const WebviewComponent = (props: Props) => {
const [loading, setLoading] = useState(true);
const [hasError, setHasError] = useState(false);

const ref = React.createRef<WebView>();

const handleReload = () => {
setHasError(false);
setLoading(true);
if (ref.current) {
ref.current.reload();
}
};

return (
<>
{hasError ? (
<GenericErrorComponent onRetry={handleReload} />
) : (
<LoadingSpinnerOverlay isLoading={loading}>
<WebView
style={IOStyles.flex}
ref={ref}
onLoadEnd={() => setLoading(false)}
onError={() => setHasError(true)}
source={props.source}
/>
</LoadingSpinnerOverlay>
)}
</>
);
};

export default WebviewComponent;
12 changes: 12 additions & 0 deletions ts/components/__tests__/WebviewComponent.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { render } from "@testing-library/react-native";
import React from "react";
import WebviewComponent from "../WebviewComponent";

describe("WebviewComponent tests", () => {
it("snapshot for component", () => {
const component = render(
<WebviewComponent source={{ uri: "https://google.com" }} />
);
expect(component).toMatchSnapshot();
});
});
134 changes: 134 additions & 0 deletions ts/components/__tests__/__snapshots__/WebviewComponent.test.tsx.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`WebviewComponent tests snapshot for component 1`] = `
<View
style={
Object {
"flex": 1,
}
}
testID="overlayComponent"
>
<View
style={
Array [
Object {
"backgroundColor": "#fff",
"bottom": 0,
"justifyContent": "center",
"left": 0,
"position": "absolute",
"right": 0,
"top": 0,
"zIndex": 1,
},
Object {
"backgroundColor": "rgba(255,255,255,0.7)",
"opacity": 1,
},
]
}
>
<View
style={
Array [
Object {
"alignItems": "center",
"flex": 1,
"height": 100,
"justifyContent": "center",
},
undefined,
]
}
>
<ActivityIndicator
animating={true}
color="#999999"
hidesWhenStopped={true}
size="large"
/>
<Text
accessible={true}
alignCenter={true}
style={
Array [
Object {
"color": "#000",
"fontFamily": "System",
"fontSize": 16,
},
Object {
"padding": 24,
},
]
}
>
Wait a few seconds..
</Text>
</View>
</View>
<View
style={
Array [
Object {
"flex": 1,
},
Object {
"zIndex": 0,
},
]
}
>
<View
style={
Array [
Object {
"flex": 1,
"overflow": "hidden",
},
undefined,
]
}
>
<RNCWebView
cacheEnabled={true}
injectedJavaScriptBeforeContentLoadedForMainFrameOnly={true}
injectedJavaScriptForMainFrameOnly={true}
javaScriptEnabled={true}
messagingEnabled={false}
onContentProcessDidTerminate={[Function]}
onError={[Function]}
onHttpError={[Function]}
onLoadEnd={[Function]}
onLoadingError={[Function]}
onLoadingFinish={[Function]}
onLoadingProgress={[Function]}
onLoadingStart={[Function]}
onMessage={[Function]}
onShouldStartLoadWithRequest={[Function]}
source={
Object {
"uri": "https://google.com",
}
}
style={
Array [
Object {
"flex": 1,
"overflow": "hidden",
},
Object {
"backgroundColor": "#ffffff",
},
Object {
"flex": 1,
},
]
}
useSharedProcessPool={true}
/>
</View>
</View>
</View>
`;
55 changes: 48 additions & 7 deletions ts/features/bonus/cgn/components/merchants/CgnDiscountDetail.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ import { StyleSheet } from "react-native";
import { TouchableWithoutFeedback } from "@gorhom/bottom-sheet";
import { Millisecond } from "italia-ts-commons/lib/units";
import { index } from "fp-ts/lib/Array";
import { useIOBottomSheet } from "../../../../../utils/bottomSheet";
import {
bottomSheetContent,
useIOBottomSheetRaw
} from "../../../../../utils/bottomSheet";
import I18n from "../../../../../i18n";
import { IOStyles } from "../../../../../components/core/variables/IOStyles";
import { H3 } from "../../../../../components/core/typography/H3";
Expand All @@ -17,10 +20,13 @@ import { BaseTypography } from "../../../../../components/core/typography/BaseTy
import { addEvery } from "../../../../../utils/strings";
import { Discount } from "../../../../../../definitions/cgn/merchants/Discount";
import { getCategorySpecs } from "../../utils/filters";
import ButtonDefaultOpacity from "../../../../../components/ButtonDefaultOpacity";
import { Label } from "../../../../../components/core/typography/Label";
import CgnDiscountValueBox from "./CgnDiscountValueBox";

type Props = {
discount: Discount;
onLandingCtaPress?: (url: string, referer: string) => void;
};

const styles = StyleSheet.create({
Expand Down Expand Up @@ -54,7 +60,8 @@ const CATEGORY_ICON_SIZE = 22;
const COPY_ICON_SIZE = 24;

const CgnDiscountDetail: React.FunctionComponent<Props> = ({
discount
discount,
onLandingCtaPress
}: Props) => {
const [isTap, setIsTap] = React.useState(false);
const timerRetry = React.useRef<number | undefined>(undefined);
Expand Down Expand Up @@ -142,6 +149,22 @@ const CgnDiscountDetail: React.FunctionComponent<Props> = ({
<H4 weight={"Regular"}>{discount.condition}</H4>
</>
)}
{discount.landingPageUrl && discount.landingPageReferrer && (
<ButtonDefaultOpacity
style={{ width: "100%" }}
onPress={() => {
onLandingCtaPress?.(
discount.landingPageUrl as string,
discount.landingPageReferrer as string
);
}}
onPressWithGestureHandler={true}
>
<Label color={"white"}>
{I18n.t("bonus.cgn.merchantDetail.cta.landingPage")}
</Label>
</ButtonDefaultOpacity>
)}
</View>
);
};
Expand All @@ -158,9 +181,27 @@ const CgnDiscountDetailHeader = ({ discount }: Props) => (
</View>
);

export const useCgnDiscountDetailBottomSheet = (discount: Discount) =>
useIOBottomSheet(
<CgnDiscountDetail {...{ discount }} />,
<CgnDiscountDetailHeader {...{ discount }} />,
520
export const useCgnDiscountDetailBottomSheet = (
discount: Discount,
landingPageHandler?: (url: string, referer: string) => void
) => {
const { present: openBottomSheet, dismiss } = useIOBottomSheetRaw(
385,
bottomSheetContent
);

return {
dismiss,
present: () =>
openBottomSheet(
<CgnDiscountDetail
discount={discount}
onLandingCtaPress={(url: string, referer: string) => {
landingPageHandler?.(url, referer);
dismiss();
}}
/>,
<CgnDiscountDetailHeader {...{ discount }} />
)
};
};
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import * as React from "react";
import { View } from "native-base";
import { StyleSheet } from "react-native";
import { index } from "fp-ts/lib/Array";
import { connect } from "react-redux";
import IconFont from "../../../../../components/ui/IconFont";
import { IOColors } from "../../../../../components/core/variables/IOColors";
import { H5 } from "../../../../../components/core/typography/H5";
Expand All @@ -12,12 +13,16 @@ import TouchableDefaultOpacity from "../../../../../components/TouchableDefaultO
import { Discount } from "../../../../../../definitions/cgn/merchants/Discount";
import { getCategorySpecs } from "../../utils/filters";
import I18n from "../../../../../i18n";
import { navigateToCgnMerchantLandingWebview } from "../../navigation/actions";
import { Dispatch } from "../../../../../store/actions/types";
import { GlobalState } from "../../../../../store/reducers/types";
import { useCgnDiscountDetailBottomSheet } from "./CgnDiscountDetail";
import CgnDiscountValueBox from "./CgnDiscountValueBox";

type Props = {
discount: Discount;
};
} & ReturnType<typeof mapStateToProps> &
ReturnType<typeof mapDispatchToProps>;

const styles = StyleSheet.create({
container: { justifyContent: "space-between", alignItems: "center" },
Expand All @@ -31,9 +36,13 @@ const styles = StyleSheet.create({
});

const CgnMerchantDiscountItem: React.FunctionComponent<Props> = ({
discount
discount,
navigateToLandingWebview
}: Props) => {
const { present } = useCgnDiscountDetailBottomSheet(discount);
const { present } = useCgnDiscountDetailBottomSheet(
discount,
navigateToLandingWebview
);
return (
<TouchableDefaultOpacity style={styles.verticalPadding} onPress={present}>
<ShadowBox>
Expand Down Expand Up @@ -72,4 +81,18 @@ const CgnMerchantDiscountItem: React.FunctionComponent<Props> = ({
);
};

export default CgnMerchantDiscountItem;
const mapStateToProps = (_: GlobalState) => ({});

const mapDispatchToProps = (dispatch: Dispatch) => ({
navigateToLandingWebview: (url: string, referer: string) =>
dispatch(
navigateToCgnMerchantLandingWebview({
landingPageUrl: url,
landingPageReferrer: referer
})
)
});
export default connect(
mapStateToProps,
mapDispatchToProps
)(CgnMerchantDiscountItem);
9 changes: 9 additions & 0 deletions ts/features/bonus/cgn/navigation/actions.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { NavigationActions } from "react-navigation";
import { InferNavigationParams } from "../../../../types/react";
import CgnMerchantDetailScreen from "../screens/merchants/CgnMerchantDetailScreen";
import CgnMerchantLandingWebview from "../screens/merchants/CgnMerchantLandingWebview";
import CGN_ROUTES from "./routes";

export const navigateToCgnActivationLoadActivationStatus = () =>
Expand Down Expand Up @@ -77,3 +78,11 @@ export const navigateToCgnMerchantDetail = (
routeName: CGN_ROUTES.MERCHANTS.DETAIL,
params
});

export const navigateToCgnMerchantLandingWebview = (
params: InferNavigationParams<typeof CgnMerchantLandingWebview>
) =>
NavigationActions.navigate({
routeName: CGN_ROUTES.MERCHANTS.LANDING_WEBVIEW,
params
});
Loading

0 comments on commit 25f7bfa

Please sign in to comment.