diff --git a/locales/en/index.yml b/locales/en/index.yml
index 64537c9e6ea..11f8768ca6f 100644
--- a/locales/en/index.yml
+++ b/locales/en/index.yml
@@ -2047,13 +2047,16 @@ bonus:
body: "The ranking is based on the **number of transactions** made with the payment methods on which you have Cashback enabled.\n\n
We will show your ranking **when the distribution of participants will be more meaningful**. Currently, many users collected the same number of transactions.\n\n
Once published, the ranking will **continue to change** depending on the number of transactions among all participants, until the end of the 6 months."
-
transaction:
label:
one: "1 transaction"
other: "{{transactions}} transactions"
title: "Your transactions"
goToButton: "Transactions detail"
+ loading: "We're retrieving your transactions\n\nPlease hold on..."
+ error:
+ title: "Systems are taking longer than expected"
+ body: "We're currently unable to retrieve your transactions. Don't worry! The list will be available again soon."
noPaymentMethod:
text1: "You must activate "
text2: "at least one payment method "
diff --git a/locales/it/index.yml b/locales/it/index.yml
index 87a4f8100d7..8e8d78298f0 100644
--- a/locales/it/index.yml
+++ b/locales/it/index.yml
@@ -2085,6 +2085,10 @@ bonus:
other: "{{transactions}} transazioni"
title: "Le tue transazioni"
goToButton: "Dettaglio transazioni"
+ loading: "Stiamo recuperando la lista delle tue transazioni\n\nAttendi qualche secondo..."
+ error:
+ title: "I sistemi stanno impiegando più tempo del previsto"
+ body: "In questo momento non riusciamo a recuperare le tue transazioni. Non preoccuparti, a breve l’elenco tornerà nuovamente disponibile."
noPaymentMethod:
text1: "Devi attivare "
text2: "almeno un metodo di pagamento "
diff --git a/ts/components/infoScreen/InfoScreenComponent.tsx b/ts/components/infoScreen/InfoScreenComponent.tsx
index b729b73fedf..b0b8fa6cd9d 100644
--- a/ts/components/infoScreen/InfoScreenComponent.tsx
+++ b/ts/components/infoScreen/InfoScreenComponent.tsx
@@ -35,7 +35,11 @@ export const InfoScreenStyle = styles;
const renderNode = (body: string | React.ReactNode) => {
if (typeof body === "string") {
- return {body};
+ return (
+
+ {body}
+
+ );
}
return body;
@@ -53,7 +57,13 @@ export const InfoScreenComponent: React.FunctionComponent = props => {
setAccessibilityFocus(elementRef)} />
{props.image}
-
+
{props.title}
diff --git a/ts/components/infoScreen/imageRendering.tsx b/ts/components/infoScreen/imageRendering.tsx
index e3e12096b15..bd4df6e97af 100644
--- a/ts/components/infoScreen/imageRendering.tsx
+++ b/ts/components/infoScreen/imageRendering.tsx
@@ -33,7 +33,12 @@ const styles = StyleSheet.create({
* @param image
*/
export const renderInfoRasterImage = (image: ImageSourcePropType) => (
-
+
);
export const renderInfoIconImage = (
diff --git a/ts/features/bonus/bpd/screens/details/BpdDetailsScreen.tsx b/ts/features/bonus/bpd/screens/details/BpdDetailsScreen.tsx
index ac04dcf582c..fc99635c794 100644
--- a/ts/features/bonus/bpd/screens/details/BpdDetailsScreen.tsx
+++ b/ts/features/bonus/bpd/screens/details/BpdDetailsScreen.tsx
@@ -121,7 +121,6 @@ const BpdDetailsScreen: React.FunctionComponent = props => {
};
const mapDispatchToProps = (dispatch: Dispatch) => ({
- load: () => dispatch(bpdAllData.request()),
completeUnsubscription: () => {
dispatch(bpdAllData.request());
dispatch(bpdUnsubscribeCompleted());
diff --git a/ts/features/bonus/bpd/screens/details/transaction/BpdAvailableTransactionsScreen.tsx b/ts/features/bonus/bpd/screens/details/transaction/BpdAvailableTransactionsScreen.tsx
new file mode 100644
index 00000000000..ed0901ae6d9
--- /dev/null
+++ b/ts/features/bonus/bpd/screens/details/transaction/BpdAvailableTransactionsScreen.tsx
@@ -0,0 +1,316 @@
+import { compareDesc } from "date-fns";
+import { index, reverse } from "fp-ts/lib/Array";
+import { fromNullable } from "fp-ts/lib/Option";
+import * as pot from "italia-ts-commons/lib/pot";
+import { View } from "native-base";
+import * as React from "react";
+import {
+ SafeAreaView,
+ ScrollView,
+ SectionList,
+ SectionListData,
+ SectionListRenderItem
+} from "react-native";
+import { connect } from "react-redux";
+import { Dispatch } from "redux";
+import { InfoBox } from "../../../../../../components/box/InfoBox";
+import { H1 } from "../../../../../../components/core/typography/H1";
+import { H4 } from "../../../../../../components/core/typography/H4";
+import { IOStyles } from "../../../../../../components/core/variables/IOStyles";
+import BaseScreenComponent from "../../../../../../components/screens/BaseScreenComponent";
+import I18n from "../../../../../../i18n";
+import { GlobalState } from "../../../../../../store/reducers/types";
+import { emptyContextualHelp } from "../../../../../../utils/emptyContextualHelp";
+import { localeDateFormat } from "../../../../../../utils/locale";
+import BaseDailyTransactionHeader from "../../../components/BaseDailyTransactionHeader";
+import BpdTransactionSummaryComponent from "../../../components/BpdTransactionSummaryComponent";
+import {
+ BpdTransactionItem,
+ EnhancedBpdTransaction
+} from "../../../components/transactionItem/BpdTransactionItem";
+import {
+ atLeastOnePaymentMethodHasBpdEnabledSelector,
+ bpdDisplayTransactionsSelector,
+ paymentMethodsWithActivationStatusSelector
+} from "../../../store/reducers/details/combiner";
+import { bpdSelectedPeriodSelector } from "../../../store/reducers/details/selectedPeriod";
+import BpdCashbackMilestoneComponent from "./BpdCashbackMilestoneComponent";
+import BpdEmptyTransactionsList from "./BpdEmptyTransactionsList";
+
+export type Props = ReturnType &
+ ReturnType;
+
+type TotalCashbackPerDate = {
+ trxDate: Date;
+ totalCashBack: number;
+};
+
+const dataForFlatList = (
+ transactions: pot.Pot, Error>
+) => pot.getOrElse(transactions, []);
+
+export const isTotalCashback = (item: any): item is TotalCashbackPerDate =>
+ item.totalCashBack !== undefined;
+
+/**
+ * Builds the array of objects needed to show the sectionsList grouped by transaction day.
+ *
+ * We check the subtotal of TotalCashback earned on each transaction to check when the user reaches the cashback.
+ *
+ * When creating the final array if we reached the cashback amount we set all the following transaction cashback value to 0
+ *
+ * If the sum of cashback comes over the award we remove the exceeding part on the transaction.
+ * @param transactions
+ * @param cashbackAward
+ */
+const getTransactionsByDaySections = (
+ transactions: ReadonlyArray,
+ cashbackAward: number
+): ReadonlyArray<
+ SectionListData
+> => {
+ const dates = [
+ ...new Set(
+ transactions.map(trx =>
+ localeDateFormat(trx.trxDate, I18n.t("global.dateFormats.dayFullMonth"))
+ )
+ )
+ ];
+
+ const transactionsAsc = reverse([...transactions]);
+
+ // accumulator to define when the user reached the cashback award amount
+ // and tracing the sum of all the cashback value to check if any negative trx may cause a revoke of cashback award
+ const amountWinnerAccumulator = transactionsAsc.reduce(
+ (
+ acc: {
+ winner?: {
+ amount: number;
+ index: number;
+ date: Date;
+ };
+ sumAmount: number;
+ },
+ t: EnhancedBpdTransaction,
+ currIndex: number
+ ) => {
+ const sum = acc.sumAmount + t.cashback;
+ if (sum >= cashbackAward && !acc.winner) {
+ return {
+ winner: {
+ amount: sum,
+ index: currIndex,
+ date: new Date(t.trxDate)
+ },
+ sumAmount: sum
+ };
+ } else if (sum < cashbackAward) {
+ return {
+ sumAmount: sum
+ };
+ }
+ return {
+ ...acc,
+ sumAmount: sum
+ };
+ },
+ {
+ sumAmount: 0
+ }
+ );
+
+ const maybeWinner = fromNullable(amountWinnerAccumulator.winner);
+
+ // If the user reached the cashback amount within transactions we actualize all the cashback value starting from the index of winning transaction
+ // if the winning transaction makes cashback value exceed the limit we set the amount to the difference of transaction cashback value, total amout at winnign transaction and cashback award limit.
+ // all the following transactions will be set to 0 cashback value, since the limit has been reached (a dedicated item will be displayed)
+ const updatedTransactions = [...transactionsAsc].map((t, i) => {
+ if (maybeWinner.isSome()) {
+ if (
+ i === maybeWinner.value.index &&
+ maybeWinner.value.amount > cashbackAward
+ ) {
+ return {
+ ...t,
+ cashback: t.cashback - (maybeWinner.value.amount - cashbackAward)
+ };
+ } else if (i > maybeWinner.value.index) {
+ return {
+ ...t,
+ cashback: 0
+ };
+ }
+ }
+ return t;
+ });
+
+ return dates.map(d => ({
+ title: d,
+ data: [
+ ...updatedTransactions.filter(
+ t =>
+ localeDateFormat(
+ t.trxDate,
+ I18n.t("global.dateFormats.dayFullMonth")
+ ) === d
+ ),
+ // we add the the data array an item to display the milestone reached
+ // in order to display the milestone after the latest transaction summed in the total we add 1 ms so that the ordering will set it correctly
+ ...maybeWinner.fold([], w => {
+ if (
+ localeDateFormat(
+ w.date,
+ I18n.t("global.dateFormats.dayFullMonth")
+ ) === d
+ ) {
+ return [
+ {
+ totalCashBack: w.amount,
+ trxDate: new Date(
+ w.date.setMilliseconds(w.date.getMilliseconds() + 1)
+ )
+ }
+ ];
+ }
+ return [];
+ })
+ ].sort((trx1, trx2) => compareDesc(trx1.trxDate, trx2.trxDate))
+ }));
+};
+
+const renderSectionHeader = (info: {
+ section: SectionListData;
+}): React.ReactNode => (
+ !isTotalCashback(i)).length
+ }
+ />
+);
+
+export const NoPaymentMethodAreActiveWarning = () => (
+
+
+
+ {I18n.t("bonus.bpd.details.transaction.noPaymentMethod.text1")}
+
+ {I18n.t("bonus.bpd.details.transaction.noPaymentMethod.text2")}
+
+ {I18n.t("bonus.bpd.details.transaction.noPaymentMethod.text3")}
+
+
+
+
+);
+
+/**
+ * Display all the transactions for a specific period
+ * TODO: scroll to refresh, display error, display loading
+ * @constructor
+ */
+const BpdAvailableTransactionsScreen: React.FunctionComponent = props => {
+ const transactions = dataForFlatList(props.transactionForSelectedPeriod);
+
+ const trxSortByDate = [...transactions].sort((trx1, trx2) =>
+ compareDesc(trx1.trxDate, trx2.trxDate)
+ );
+
+ const maybeLastUpdateDate = index(0, [...trxSortByDate]).map(t => t.trxDate);
+
+ const renderTransactionItem: SectionListRenderItem<
+ EnhancedBpdTransaction | TotalCashbackPerDate
+ > = info => {
+ if (isTotalCashback(info.item)) {
+ return (
+ p.maxPeriodCashback
+ )}
+ />
+ );
+ }
+ return ;
+ };
+
+ return (
+
+
+
+
+ {I18n.t("bonus.bpd.details.transaction.title")}
+
+
+
+
+ {props.selectedPeriod && maybeLastUpdateDate.isSome() && (
+ <>
+
+
+ >
+ )}
+
+ {props.selectedPeriod &&
+ (transactions.length > 0 ? (
+
+ isTotalCashback(t)
+ ? `awarded_cashback_item${t.totalCashBack}`
+ : t.keyId
+ }
+ />
+ ) : !props.atLeastOnePaymentMethodActive &&
+ pot.isSome(props.potWallets) &&
+ props.potWallets.value.length > 0 ? (
+
+
+
+ ) : (
+
+
+
+ ))}
+
+
+
+ );
+};
+
+const mapDispatchToProps = (_: Dispatch) => ({});
+
+const mapStateToProps = (state: GlobalState) => ({
+ transactionForSelectedPeriod: bpdDisplayTransactionsSelector(state),
+ selectedPeriod: bpdSelectedPeriodSelector(state),
+ potWallets: paymentMethodsWithActivationStatusSelector(state),
+ atLeastOnePaymentMethodActive: atLeastOnePaymentMethodHasBpdEnabledSelector(
+ state
+ )
+});
+
+export default connect(
+ mapStateToProps,
+ mapDispatchToProps
+)(BpdAvailableTransactionsScreen);
diff --git a/ts/features/bonus/bpd/screens/details/transaction/BpdTransactionsScreen.tsx b/ts/features/bonus/bpd/screens/details/transaction/BpdTransactionsScreen.tsx
index f487c3a1d88..0253aa6ec0c 100644
--- a/ts/features/bonus/bpd/screens/details/transaction/BpdTransactionsScreen.tsx
+++ b/ts/features/bonus/bpd/screens/details/transaction/BpdTransactionsScreen.tsx
@@ -1,310 +1,71 @@
-import { compareDesc } from "date-fns";
-import { index, reverse } from "fp-ts/lib/Array";
-import { fromNullable } from "fp-ts/lib/Option";
import * as pot from "italia-ts-commons/lib/pot";
-import { View } from "native-base";
import * as React from "react";
-import {
- SafeAreaView,
- ScrollView,
- SectionList,
- SectionListData,
- SectionListRenderItem
-} from "react-native";
import { connect } from "react-redux";
import { Dispatch } from "redux";
-import { InfoBox } from "../../../../../../components/box/InfoBox";
-import { H1 } from "../../../../../../components/core/typography/H1";
-import { H4 } from "../../../../../../components/core/typography/H4";
-import { IOStyles } from "../../../../../../components/core/variables/IOStyles";
-import BaseScreenComponent from "../../../../../../components/screens/BaseScreenComponent";
-import I18n from "../../../../../../i18n";
import { GlobalState } from "../../../../../../store/reducers/types";
-import { emptyContextualHelp } from "../../../../../../utils/emptyContextualHelp";
-import { localeDateFormat } from "../../../../../../utils/locale";
-import BaseDailyTransactionHeader from "../../../components/BaseDailyTransactionHeader";
-import BpdTransactionSummaryComponent from "../../../components/BpdTransactionSummaryComponent";
-import {
- BpdTransactionItem,
- EnhancedBpdTransaction
-} from "../../../components/transactionItem/BpdTransactionItem";
-import {
- atLeastOnePaymentMethodHasBpdEnabledSelector,
- bpdDisplayTransactionsSelector,
- paymentMethodsWithActivationStatusSelector
-} from "../../../store/reducers/details/combiner";
-import { bpdSelectedPeriodSelector } from "../../../store/reducers/details/selectedPeriod";
-import BpdCashbackMilestoneComponent from "./BpdCashbackMilestoneComponent";
-import BpdEmptyTransactionsList from "./BpdEmptyTransactionsList";
+import { EnhancedBpdTransaction } from "../../../components/transactionItem/BpdTransactionItem";
+import { bpdAllData } from "../../../store/actions/details";
+import { bpdDisplayTransactionsSelector } from "../../../store/reducers/details/combiner";
+import { bpdLastUpdateSelector } from "../../../store/reducers/details/lastUpdate";
+import BpdAvailableTransactionsScreen from "./BpdAvailableTransactionsScreen";
+import LoadTransactions from "./LoadTransactions";
+import TransactionsUnavailable from "./TransactionsUnavailable";
export type Props = ReturnType &
ReturnType;
-type TotalCashbackPerDate = {
- trxDate: Date;
- totalCashBack: number;
-};
-
-const dataForFlatList = (
- transactions: pot.Pot, Error>
-) => pot.getOrElse(transactions, []);
-
-export const isTotalCashback = (item: any): item is TotalCashbackPerDate =>
- item.totalCashBack !== undefined;
-
/**
- * Builds the array of objects needed to show the sectionsList grouped by transaction day.
- *
- * We check the subtotal of TotalCashback earned on each transaction to check when the user reaches the cashback.
- *
- * When creating the final array if we reached the cashback amount we set all the following transaction cashback value to 0
- *
- * If the sum of cashback comes over the award we remove the exceeding part on the transaction.
+ * Associate at every state of the pot transactions status the right screen to show
* @param transactions
- * @param cashbackAward
*/
-const getTransactionsByDaySections = (
- transactions: ReadonlyArray,
- cashbackAward: number
-): ReadonlyArray<
- SectionListData
-> => {
- const dates = [
- ...new Set(
- transactions.map(trx =>
- localeDateFormat(trx.trxDate, I18n.t("global.dateFormats.dayFullMonth"))
- )
- )
- ];
-
- const transactionsAsc = reverse([...transactions]);
-
- // accumulator to define when the user reached the cashback award amount
- // and tracing the sum of all the cashback value to check if any negative trx may cause a revoke of cashback award
- const amountWinnerAccumulator = transactionsAsc.reduce(
- (
- acc: {
- winner?: {
- amount: number;
- index: number;
- date: Date;
- };
- sumAmount: number;
- },
- t: EnhancedBpdTransaction,
- currIndex: number
- ) => {
- const sum = acc.sumAmount + t.cashback;
- if (sum >= cashbackAward && !acc.winner) {
- return {
- winner: {
- amount: sum,
- index: currIndex,
- date: new Date(t.trxDate)
- },
- sumAmount: sum
- };
- } else if (sum < cashbackAward) {
- return {
- sumAmount: sum
- };
- }
- return {
- ...acc,
- sumAmount: sum
- };
- },
- {
- sumAmount: 0
- }
+const handleTransactionsStatus = (
+ transactions: pot.Pot, Error>
+) =>
+ pot.fold(
+ transactions,
+ () => ,
+ () => ,
+ _ => ,
+ _ => ,
+ _ => ,
+ _ => ,
+ _ => ,
+ _ =>
);
- const maybeWinner = fromNullable(amountWinnerAccumulator.winner);
-
- // If the user reached the cashback amount within transactions we actualize all the cashback value starting from the index of winning transaction
- // if the the winning transaction makes cashback value exceed the limit we set the amount to the difference of transaction cashback value, total amout at winnign transaction and cashback award limit.
- // all the following transactions will be set to 0 cashback value, since the limit has been reached (a dedicated item will be displayed)
- const updatedTransactions = [...transactionsAsc].map((t, i) => {
- if (maybeWinner.isSome()) {
- if (
- i === maybeWinner.value.index &&
- maybeWinner.value.amount > cashbackAward
- ) {
- return {
- ...t,
- cashback: t.cashback - (maybeWinner.value.amount - cashbackAward)
- };
- } else if (i > maybeWinner.value.index) {
- return {
- ...t,
- cashback: 0
- };
- }
- }
- return t;
- });
-
- return dates.map(d => ({
- title: d,
- data: [
- ...updatedTransactions.filter(
- t =>
- localeDateFormat(
- t.trxDate,
- I18n.t("global.dateFormats.dayFullMonth")
- ) === d
- ),
- // we add the the data array an item to display the milestone reached
- // in order to display the milestone after the latest transaction summed in the total we add 1 ms so that the ordering will set it correctly
- ...maybeWinner.fold([], w => {
- if (
- localeDateFormat(
- w.date,
- I18n.t("global.dateFormats.dayFullMonth")
- ) === d
- ) {
- return [
- {
- totalCashBack: w.amount,
- trxDate: new Date(
- w.date.setMilliseconds(w.date.getMilliseconds() + 1)
- )
- }
- ];
- }
- return [];
- })
- ].sort((trx1, trx2) => compareDesc(trx1.trxDate, trx2.trxDate))
- }));
-};
-
-const renderSectionHeader = (info: {
- section: SectionListData;
-}): React.ReactNode => (
- !isTotalCashback(i)).length
- }
- />
-);
-
-export const NoPaymentMethodAreActiveWarning = () => (
-
-
-
- {I18n.t("bonus.bpd.details.transaction.noPaymentMethod.text1")}
-
- {I18n.t("bonus.bpd.details.transaction.noPaymentMethod.text2")}
-
- {I18n.t("bonus.bpd.details.transaction.noPaymentMethod.text3")}
-
-
-
-
-);
-
/**
- * Display all the transactions for a specific period
- * TODO: scroll to refresh, display error, display loading
+ * Display all the transactions for a specific period if available, in other case show a loading or an error screen.
+ * First check the whole bpd status than if is some check the transactions status.
* @constructor
*/
-const BpdTransactionsScreen: React.FunctionComponent = props => {
- const transactions = dataForFlatList(props.transactionForSelectedPeriod);
-
- const trxSortByDate = [...transactions].sort((trx1, trx2) =>
- compareDesc(trx1.trxDate, trx2.trxDate)
- );
-
- const maybeLastUpdateDate = index(0, [...trxSortByDate]).map(t => t.trxDate);
-
- const renderTransactionItem: SectionListRenderItem<
- EnhancedBpdTransaction | TotalCashbackPerDate
- > = info => {
- if (isTotalCashback(info.item)) {
- return (
- p.maxPeriodCashback
- )}
- />
- );
+const BpdTransactionsScreen: React.FC = (props: Props) => {
+ React.useEffect(() => {
+ if (
+ pot.isError(props.bpdLastUpdate) ||
+ pot.isError(props.transactionForSelectedPeriod)
+ ) {
+ props.loadTransactions();
}
- return ;
- };
-
- return (
-
-
-
-
- {I18n.t("bonus.bpd.details.transaction.title")}
-
-
-
-
- {props.selectedPeriod && maybeLastUpdateDate.isSome() && (
- <>
-
-
- >
- )}
-
- {props.selectedPeriod &&
- (transactions.length > 0 ? (
-
- isTotalCashback(t)
- ? `awarded_cashback_item${t.totalCashBack}`
- : t.keyId
- }
- />
- ) : !props.atLeastOnePaymentMethodActive &&
- pot.isSome(props.potWallets) &&
- props.potWallets.value.length > 0 ? (
-
-
-
- ) : (
-
-
-
- ))}
-
-
-
+ }, []);
+ return pot.fold(
+ props.bpdLastUpdate,
+ () => ,
+ () => ,
+ _ => ,
+ _ => ,
+ _ => handleTransactionsStatus(props.transactionForSelectedPeriod),
+ _ => ,
+ _ => ,
+ _ =>
);
};
-
-const mapDispatchToProps = (_: Dispatch) => ({});
+const mapDispatchToProps = (dispatch: Dispatch) => ({
+ loadTransactions: () => dispatch(bpdAllData.request())
+});
const mapStateToProps = (state: GlobalState) => ({
transactionForSelectedPeriod: bpdDisplayTransactionsSelector(state),
- selectedPeriod: bpdSelectedPeriodSelector(state),
- potWallets: paymentMethodsWithActivationStatusSelector(state),
- atLeastOnePaymentMethodActive: atLeastOnePaymentMethodHasBpdEnabledSelector(
- state
- )
+ bpdLastUpdate: bpdLastUpdateSelector(state)
});
export default connect(
diff --git a/ts/features/bonus/bpd/screens/details/transaction/LoadTransactions.tsx b/ts/features/bonus/bpd/screens/details/transaction/LoadTransactions.tsx
new file mode 100644
index 00000000000..30eee57e5e0
--- /dev/null
+++ b/ts/features/bonus/bpd/screens/details/transaction/LoadTransactions.tsx
@@ -0,0 +1,29 @@
+import { View } from "native-base";
+import * as React from "react";
+import { ActivityIndicator } from "react-native";
+import { IOStyles } from "../../../../../../components/core/variables/IOStyles";
+import { InfoScreenComponent } from "../../../../../../components/infoScreen/InfoScreenComponent";
+import I18n from "../../../../../../i18n";
+
+/**
+ * This screen is displayed when loading the list of transactions
+ * @constructor
+ */
+const LoadTransactions: React.FunctionComponent = () => (
+
+
+ }
+ title={I18n.t("bonus.bpd.details.transaction.loading")}
+ />
+
+);
+
+export default LoadTransactions;
diff --git a/ts/features/bonus/bpd/screens/details/transaction/TransactionsUnavailable.tsx b/ts/features/bonus/bpd/screens/details/transaction/TransactionsUnavailable.tsx
new file mode 100644
index 00000000000..19e18989f5f
--- /dev/null
+++ b/ts/features/bonus/bpd/screens/details/transaction/TransactionsUnavailable.tsx
@@ -0,0 +1,45 @@
+import * as React from "react";
+import { SafeAreaView } from "react-native";
+import image from "../../../../../../../img/wallet/errors/payment-unavailable-icon.png";
+import { IOStyles } from "../../../../../../components/core/variables/IOStyles";
+import { renderInfoRasterImage } from "../../../../../../components/infoScreen/imageRendering";
+import { InfoScreenComponent } from "../../../../../../components/infoScreen/InfoScreenComponent";
+import BaseScreenComponent from "../../../../../../components/screens/BaseScreenComponent";
+import I18n from "../../../../../../i18n";
+
+export type Props = Pick<
+ React.ComponentProps,
+ "contextualHelp"
+>;
+
+const loadLocales = () => ({
+ headerTitle: I18n.t("bonus.bpd.details.transaction.goToButton"),
+ title: I18n.t("bonus.bpd.details.transaction.error.title"),
+ body: I18n.t("bonus.bpd.details.transaction.error.body")
+});
+
+/**
+ * This screen informs the user that there are problems retrieving the transactions list.
+ * @constructor
+ */
+const TransactionsUnavailable: React.FunctionComponent = props => {
+ const { headerTitle, title, body } = loadLocales();
+
+ return (
+
+
+
+
+
+ );
+};
+
+export default TransactionsUnavailable;
diff --git a/ts/features/bonus/bpd/screens/details/transaction/__test__/BpdTransactionsScreen.test.tsx b/ts/features/bonus/bpd/screens/details/transaction/__test__/BpdTransactionsScreen.test.tsx
new file mode 100644
index 00000000000..be2b1e054dc
--- /dev/null
+++ b/ts/features/bonus/bpd/screens/details/transaction/__test__/BpdTransactionsScreen.test.tsx
@@ -0,0 +1,530 @@
+import * as React from "react";
+import { Action, createStore } from "redux";
+import { NavigationParams } from "react-navigation";
+import { View } from "native-base";
+import * as pot from "italia-ts-commons/lib/pot";
+import BpdTransactionsScreen from "../BpdTransactionsScreen";
+import { appReducer } from "../../../../../../../store/reducers";
+import { applicationChangeState } from "../../../../../../../store/actions/application";
+import { renderScreenFakeNavRedux } from "../../../../../../../utils/testWrapper";
+import { GlobalState } from "../../../../../../../store/reducers/types";
+import ROUTES from "../../../../../../../navigation/routes";
+import { reproduceSequence } from "../../../../../../../utils/tests";
+import { bpdAllData } from "../../../../store/actions/details";
+import * as lastUpdateReducer from "../../../../store/reducers/details/lastUpdate";
+import * as transactionsReducer from "../../../../store/reducers/details/combiner";
+import {
+ BpdTransaction,
+ BpdTransactions,
+ bpdTransactionsLoad
+} from "../../../../store/actions/transactions";
+import { AwardPeriodId } from "../../../../store/actions/periods";
+import { navigateToBpdDetails } from "../../../../navigation/actions";
+import { BpdPeriodWithInfo } from "../../../../store/reducers/details/periods";
+import * as BpdTransactionItem from "../../../../components/transactionItem/BpdTransactionItem";
+import * as BpdTransactionSummaryComponent from "../../../../components/BpdTransactionSummaryComponent";
+
+// Be sure that navigation is unmocked
+jest.unmock("react-navigation");
+jest.mock("react-native-share", () => ({
+ open: jest.fn()
+}));
+describe("BpdTransactionsScreen", () => {
+ beforeEach(() => jest.useFakeTimers());
+ it("should show the TransactionUnavailable screen if bpdLastUpdate is pot.none", () => {
+ const globalState = appReducer(undefined, applicationChangeState("active"));
+
+ const component = renderScreenFakeNavRedux(
+ () => ,
+ ROUTES.WALLET_BPAY_DETAIL,
+ {},
+ createStore(appReducer, globalState as any)
+ );
+
+ expect(component).toBeDefined();
+ expect(component.queryByTestId("TransactionUnavailable")).toBeTruthy();
+ expect(component.queryByTestId("LoadTransactions")).toBeNull();
+ expect(
+ component.queryByTestId("BpdAvailableTransactionsScreen")
+ ).toBeNull();
+ });
+ it("should show the LoadTransactions screen if bpdLastUpdate is pot.noneLoading", () => {
+ const sequenceOfActions: ReadonlyArray = [bpdAllData.request()];
+
+ const finalState = reproduceSequence(
+ {} as GlobalState,
+ appReducer,
+ sequenceOfActions
+ );
+ const component = renderScreenFakeNavRedux(
+ () => ,
+ ROUTES.WALLET_BPAY_DETAIL,
+ {},
+ createStore(appReducer, finalState as any)
+ );
+
+ expect(component).toBeDefined();
+ expect(component.queryByTestId("LoadTransactions")).toBeTruthy();
+ expect(component.queryByTestId("TransactionUnavailable")).toBeNull();
+ expect(
+ component.queryByTestId("BpdAvailableTransactionsScreen")
+ ).toBeNull();
+ });
+ it("should show the LoadTransactions screen if bpdLastUpdate is pot.noneUpdating", () => {
+ const globalState = appReducer(undefined, applicationChangeState("active"));
+ const finalState: GlobalState = {
+ ...globalState,
+ bonus: {
+ ...globalState.bonus,
+ bpd: {
+ ...globalState.bonus.bpd,
+ details: {
+ ...globalState.bonus.bpd.details,
+ lastUpdate: pot.noneUpdating({} as Date)
+ }
+ }
+ }
+ };
+ const component = renderScreenFakeNavRedux(
+ () => ,
+ ROUTES.WALLET_BPAY_DETAIL,
+ {},
+ createStore(appReducer, finalState as any)
+ );
+
+ expect(component).toBeDefined();
+ expect(component.queryByTestId("LoadTransactions")).toBeTruthy();
+ expect(component.queryByTestId("TransactionUnavailable")).toBeNull();
+ expect(
+ component.queryByTestId("BpdAvailableTransactionsScreen")
+ ).toBeNull();
+ });
+ it("should show the TransactionUnavailable screen if bpdLastUpdate is pot.noneError", () => {
+ const myspy = jest
+ .spyOn(lastUpdateReducer, "bpdLastUpdateSelector")
+ .mockReturnValue(pot.noneError({} as Error));
+
+ const sequenceOfActions: ReadonlyArray = [
+ bpdAllData.request(),
+ bpdAllData.failure({ message: "error" } as Error)
+ ];
+
+ const finalState = reproduceSequence(
+ {} as GlobalState,
+ appReducer,
+ sequenceOfActions
+ );
+
+ const component = renderScreenFakeNavRedux(
+ () => ,
+ ROUTES.WALLET_BPAY_DETAIL,
+ {},
+ createStore(appReducer, finalState as any)
+ );
+
+ expect(component).toBeDefined();
+ expect(component.queryByTestId("TransactionUnavailable")).toBeTruthy();
+ expect(component.queryByTestId("LoadTransactions")).toBeNull();
+ expect(
+ component.queryByTestId("BpdAvailableTransactionsScreen")
+ ).toBeNull();
+
+ myspy.mockRestore();
+ });
+ it("should show the LoadTransactions screen if bpdLastUpdate is pot.someLoading", () => {
+ const sequenceOfActions: ReadonlyArray = [
+ bpdAllData.request(),
+ bpdAllData.success(),
+ bpdAllData.request()
+ ];
+
+ const finalState = reproduceSequence(
+ {} as GlobalState,
+ appReducer,
+ sequenceOfActions
+ );
+ const component = renderScreenFakeNavRedux(
+ () => ,
+ ROUTES.WALLET_BPAY_DETAIL,
+ {},
+ createStore(appReducer, finalState as any)
+ );
+
+ expect(component).toBeDefined();
+ expect(component.queryByTestId("LoadTransactions")).toBeTruthy();
+ expect(component.queryByTestId("TransactionUnavailable")).toBeNull();
+ expect(
+ component.queryByTestId("BpdAvailableTransactionsScreen")
+ ).toBeNull();
+ });
+ it("should show the TransactionUnavailable screen if bpdLastUpdate is pot.someError", () => {
+ const myspy = jest
+ .spyOn(lastUpdateReducer, "bpdLastUpdateSelector")
+ .mockReturnValue(pot.someError({} as Date, {} as Error));
+
+ const sequenceOfActions: ReadonlyArray = [
+ bpdAllData.request(),
+ bpdAllData.success(),
+ bpdAllData.request()
+ ];
+
+ const finalState = reproduceSequence(
+ {} as GlobalState,
+ appReducer,
+ sequenceOfActions
+ );
+ const component = renderScreenFakeNavRedux(
+ () => ,
+ ROUTES.WALLET_BPAY_DETAIL,
+ {},
+ createStore(appReducer, finalState as any)
+ );
+
+ expect(component).toBeDefined();
+ expect(component.queryByTestId("TransactionUnavailable")).toBeTruthy();
+ expect(component.queryByTestId("LoadTransactions")).toBeNull();
+ expect(
+ component.queryByTestId("BpdAvailableTransactionsScreen")
+ ).toBeNull();
+ myspy.mockRestore();
+ });
+ it("should show the LoadTransactions screen if bpdLastUpdate is pot.someUpdating", () => {
+ const globalState = appReducer(undefined, applicationChangeState("active"));
+ const finalState: GlobalState = {
+ ...globalState,
+ bonus: {
+ ...globalState.bonus,
+ bpd: {
+ ...globalState.bonus.bpd,
+ details: {
+ ...globalState.bonus.bpd.details,
+ lastUpdate: pot.someUpdating({} as Date, {} as Date)
+ }
+ }
+ }
+ };
+ const component = renderScreenFakeNavRedux(
+ () => ,
+ ROUTES.WALLET_BPAY_DETAIL,
+ {},
+ createStore(appReducer, finalState as any)
+ );
+
+ expect(component).toBeDefined();
+ expect(component.queryByTestId("LoadTransactions")).toBeTruthy();
+ expect(component.queryByTestId("TransactionUnavailable")).toBeNull();
+ expect(
+ component.queryByTestId("BpdAvailableTransactionsScreen")
+ ).toBeNull();
+ });
+ it("should show the BpdAvailableTransactionsScreen if bpdLastUpdate is pot.some and transactionForSelectedPeriod is pot.none", () => {
+ const sequenceOfActions: ReadonlyArray = [
+ navigateToBpdDetails({
+ awardPeriodId: 1 as AwardPeriodId
+ } as BpdPeriodWithInfo),
+ bpdAllData.request(),
+ bpdAllData.success()
+ ];
+
+ const finalState = reproduceSequence(
+ {} as GlobalState,
+ appReducer,
+ sequenceOfActions
+ );
+ const component = renderScreenFakeNavRedux(
+ () => ,
+ ROUTES.WALLET_BPAY_DETAIL,
+ {},
+ createStore(appReducer, finalState as any)
+ );
+
+ expect(component).toBeDefined();
+ expect(
+ component.queryByTestId("BpdAvailableTransactionsScreen")
+ ).toBeTruthy();
+ expect(component.queryByTestId("TransactionUnavailable")).toBeNull();
+ expect(component.queryByTestId("LoadTransactions")).toBeNull();
+ });
+ it("should show the LoadTransactions screen if bpdLastUpdate is pot.some and transactionForSelectedPeriod is pot.noneLoading", () => {
+ const sequenceOfActions: ReadonlyArray = [
+ navigateToBpdDetails({
+ awardPeriodId: 1 as AwardPeriodId
+ } as BpdPeriodWithInfo),
+ bpdAllData.request(),
+ bpdAllData.success(),
+ bpdTransactionsLoad.request(1 as AwardPeriodId)
+ ];
+
+ const finalState = reproduceSequence(
+ {} as GlobalState,
+ appReducer,
+ sequenceOfActions
+ );
+ const component = renderScreenFakeNavRedux(
+ () => ,
+ ROUTES.WALLET_BPAY_DETAIL,
+ {},
+ createStore(appReducer, finalState as any)
+ );
+
+ expect(component).toBeDefined();
+ expect(component.queryByTestId("LoadTransactions")).toBeTruthy();
+ expect(component.queryByTestId("TransactionUnavailable")).toBeNull();
+ expect(
+ component.queryByTestId("BpdAvailableTransactionsScreen")
+ ).toBeNull();
+ });
+ it("should show the LoadTransactions screen if bpdLastUpdate is pot.some and transactionForSelectedPeriod is pot.noneUpdating", () => {
+ const globalState = appReducer(undefined, applicationChangeState("active"));
+ const finalState: GlobalState = {
+ ...globalState,
+ bonus: {
+ ...globalState.bonus,
+ bpd: {
+ ...globalState.bonus.bpd,
+ details: {
+ ...globalState.bonus.bpd.details,
+ lastUpdate: pot.some({} as Date),
+ selectedPeriod: {
+ awardPeriodId: 1 as AwardPeriodId
+ } as BpdPeriodWithInfo,
+ transactions: {
+ 1: pot.noneUpdating([])
+ }
+ }
+ }
+ }
+ };
+ const component = renderScreenFakeNavRedux(
+ () => ,
+ ROUTES.WALLET_BPAY_DETAIL,
+ {},
+ createStore(appReducer, finalState as any)
+ );
+
+ expect(component).toBeDefined();
+ expect(component.queryByTestId("LoadTransactions")).toBeTruthy();
+ expect(component.queryByTestId("TransactionUnavailable")).toBeNull();
+ expect(
+ component.queryByTestId("BpdAvailableTransactionsScreen")
+ ).toBeNull();
+ });
+ it("should show the TransactionUnavailable screen if bpdLastUpdate is pot.some and transactionForSelectedPeriod is pot.noneError", () => {
+ const lastUpdateSpy = jest
+ .spyOn(lastUpdateReducer, "bpdLastUpdateSelector")
+ .mockReturnValue(pot.some({} as Date));
+ const transactionsSpy = jest
+ .spyOn(transactionsReducer, "bpdDisplayTransactionsSelector")
+ .mockReturnValue(pot.noneError({} as Error));
+
+ const sequenceOfActions: ReadonlyArray = [
+ navigateToBpdDetails({
+ awardPeriodId: 1 as AwardPeriodId
+ } as BpdPeriodWithInfo),
+ bpdAllData.request(),
+ bpdAllData.success(),
+ bpdTransactionsLoad.request(1 as AwardPeriodId),
+ bpdTransactionsLoad.failure({
+ awardPeriodId: 1 as AwardPeriodId,
+ error: {} as Error
+ })
+ ];
+
+ const finalState = reproduceSequence(
+ {} as GlobalState,
+ appReducer,
+ sequenceOfActions
+ );
+ const component = renderScreenFakeNavRedux(
+ () => ,
+ ROUTES.WALLET_BPAY_DETAIL,
+ {},
+ createStore(appReducer, finalState as any)
+ );
+
+ expect(component).toBeDefined();
+ expect(component.queryByTestId("TransactionUnavailable")).toBeTruthy();
+ expect(component.queryByTestId("LoadTransactions")).toBeNull();
+ expect(
+ component.queryByTestId("BpdAvailableTransactionsScreen")
+ ).toBeNull();
+ lastUpdateSpy.mockRestore();
+ transactionsSpy.mockRestore();
+ });
+ it("should show the BpdAvailableTransactionsScreen if bpdLastUpdate is pot.some and transactionForSelectedPeriod is pot.some", () => {
+ jest
+ .spyOn(BpdTransactionItem, "BpdTransactionItem")
+ .mockReturnValue();
+ jest
+ .spyOn(BpdTransactionSummaryComponent, "default")
+ .mockReturnValue();
+ const sequenceOfActions: ReadonlyArray = [
+ navigateToBpdDetails({
+ awardPeriodId: 1 as AwardPeriodId
+ } as BpdPeriodWithInfo),
+ bpdAllData.request(),
+ bpdAllData.success(),
+ bpdTransactionsLoad.request(1 as AwardPeriodId),
+ bpdTransactionsLoad.success({
+ awardPeriodId: 1 as AwardPeriodId,
+ results: [
+ {
+ amount: 0.7114042004081611,
+ awardPeriodId: 1 as AwardPeriodId,
+ cashback: 0.5640133257839899,
+ circuitType: "Unknown",
+ hashPan: "hashPan",
+ idTrxAcquirer: "idTrxAcquirer",
+ idTrxIssuer: "idTrxIssuer",
+ trxDate: new Date()
+ } as BpdTransaction
+ ]
+ } as BpdTransactions)
+ ];
+
+ const finalState = reproduceSequence(
+ {} as GlobalState,
+ appReducer,
+ sequenceOfActions
+ );
+ const component = renderScreenFakeNavRedux(
+ () => ,
+ ROUTES.WALLET_BPAY_DETAIL,
+ {},
+ createStore(appReducer, finalState as any)
+ );
+
+ expect(component).toBeDefined();
+ expect(
+ component.queryByTestId("BpdAvailableTransactionsScreen")
+ ).toBeTruthy();
+ expect(component.queryByTestId("LoadTransactions")).toBeNull();
+ expect(component.queryByTestId("TransactionUnavailable")).toBeNull();
+ });
+ it("should show the LoadTransactions screen if bpdLastUpdate is pot.some and transactionForSelectedPeriod is pot.someLoading", () => {
+ const sequenceOfActions: ReadonlyArray = [
+ navigateToBpdDetails({
+ awardPeriodId: 1 as AwardPeriodId
+ } as BpdPeriodWithInfo),
+ bpdAllData.request(),
+ bpdAllData.success(),
+ bpdTransactionsLoad.request(1 as AwardPeriodId),
+ bpdTransactionsLoad.success({
+ awardPeriodId: 1 as AwardPeriodId,
+ results: [
+ {
+ amount: 0.7114042004081611,
+ awardPeriodId: 1 as AwardPeriodId,
+ cashback: 0.5640133257839899,
+ circuitType: "Unknown",
+ hashPan: "hashPan",
+ idTrxAcquirer: "idTrxAcquirer",
+ idTrxIssuer: "idTrxIssuer",
+ trxDate: new Date()
+ } as BpdTransaction
+ ]
+ } as BpdTransactions),
+ bpdTransactionsLoad.request(1 as AwardPeriodId)
+ ];
+
+ const finalState = reproduceSequence(
+ {} as GlobalState,
+ appReducer,
+ sequenceOfActions
+ );
+
+ const component = renderScreenFakeNavRedux(
+ () => ,
+ ROUTES.WALLET_BPAY_DETAIL,
+ {},
+ createStore(appReducer, finalState as any)
+ );
+
+ expect(component).toBeDefined();
+ expect(component.queryByTestId("LoadTransactions")).toBeTruthy();
+ expect(component.queryByTestId("TransactionUnavailable")).toBeNull();
+ expect(
+ component.queryByTestId("BpdAvailableTransactionsScreen")
+ ).toBeNull();
+ });
+ it("should show the LoadTransactions screen if bpdLastUpdate is pot.some and transactionForSelectedPeriod is pot.someUpdating", () => {
+ const globalState = appReducer(undefined, applicationChangeState("active"));
+ const finalState: GlobalState = {
+ ...globalState,
+ bonus: {
+ ...globalState.bonus,
+ bpd: {
+ ...globalState.bonus.bpd,
+ details: {
+ ...globalState.bonus.bpd.details,
+ lastUpdate: pot.some({} as Date),
+ selectedPeriod: {
+ awardPeriodId: 1 as AwardPeriodId
+ } as BpdPeriodWithInfo,
+ transactions: {
+ 1: pot.someUpdating([], [])
+ }
+ }
+ }
+ }
+ };
+ const component = renderScreenFakeNavRedux(
+ () => ,
+ ROUTES.WALLET_BPAY_DETAIL,
+ {},
+ createStore(appReducer, finalState as any)
+ );
+
+ expect(component).toBeDefined();
+ expect(component.queryByTestId("LoadTransactions")).toBeTruthy();
+ expect(component.queryByTestId("TransactionUnavailable")).toBeNull();
+ expect(
+ component.queryByTestId("BpdAvailableTransactionsScreen")
+ ).toBeNull();
+ });
+ it("should show the TransactionUnavailable screen if bpdLastUpdate is pot.some and transactionForSelectedPeriod is pot.someError", () => {
+ const lastUpdateSpy = jest
+ .spyOn(lastUpdateReducer, "bpdLastUpdateSelector")
+ .mockReturnValue(pot.some({} as Date));
+ const transactionsSpy = jest
+ .spyOn(transactionsReducer, "bpdDisplayTransactionsSelector")
+ .mockReturnValue(pot.someError([], {} as Error));
+
+ const sequenceOfActions: ReadonlyArray = [
+ navigateToBpdDetails({
+ awardPeriodId: 1 as AwardPeriodId
+ } as BpdPeriodWithInfo),
+ bpdAllData.request(),
+ bpdAllData.success(),
+ bpdTransactionsLoad.request(1 as AwardPeriodId),
+ bpdTransactionsLoad.success({} as BpdTransactions),
+ bpdTransactionsLoad.request(1 as AwardPeriodId),
+ bpdTransactionsLoad.failure({
+ awardPeriodId: 1 as AwardPeriodId,
+ error: {} as Error
+ })
+ ];
+
+ const finalState = reproduceSequence(
+ {} as GlobalState,
+ appReducer,
+ sequenceOfActions
+ );
+ const component = renderScreenFakeNavRedux(
+ () => ,
+ ROUTES.WALLET_BPAY_DETAIL,
+ {},
+ createStore(appReducer, finalState as any)
+ );
+
+ // expect(finalState.bonus.bpd.details.transactions).toBe("");
+ expect(component).toBeDefined();
+ expect(component.queryByTestId("TransactionUnavailable")).toBeTruthy();
+ expect(component.queryByTestId("LoadTransactions")).toBeNull();
+ expect(
+ component.queryByTestId("BpdAvailableTransactionsScreen")
+ ).toBeNull();
+ transactionsSpy.mockRestore();
+ lastUpdateSpy.mockRestore();
+ });
+});
diff --git a/ts/features/bonus/bpd/screens/details/transaction/__test__/LoadTransactions.test.tsx b/ts/features/bonus/bpd/screens/details/transaction/__test__/LoadTransactions.test.tsx
new file mode 100644
index 00000000000..65af8ec8008
--- /dev/null
+++ b/ts/features/bonus/bpd/screens/details/transaction/__test__/LoadTransactions.test.tsx
@@ -0,0 +1,38 @@
+import { render } from "@testing-library/react-native";
+import * as React from "react";
+import I18n from "../../../../../../../i18n";
+import LoadTransactions from "../LoadTransactions";
+
+jest.mock("react-navigation", () => ({
+ NavigationEvents: "mockNavigationEvents",
+ StackActions: {
+ push: jest
+ .fn()
+ .mockImplementation(x => ({ ...x, type: "Navigation/PUSH" })),
+ replace: jest
+ .fn()
+ .mockImplementation(x => ({ ...x, type: "Navigation/REPLACE" })),
+ reset: jest.fn()
+ },
+ NavigationActions: {
+ navigate: jest.fn().mockImplementation(x => x)
+ },
+ createStackNavigator: jest.fn(),
+ withNavigation: (component: any) => component
+}));
+describe("LoadTransactions component", () => {
+ it("should show the activity indicator", () => {
+ const component = render();
+ const activityIndicator = component.queryByTestId("activityIndicator");
+
+ expect(activityIndicator).not.toBe(null);
+ });
+ it("should show the right title", () => {
+ const component = render();
+ const title = component.getByText(
+ I18n.t("bonus.bpd.details.transaction.loading")
+ );
+
+ expect(title).not.toBeEmpty();
+ });
+});
diff --git a/ts/features/bonus/bpd/screens/details/transaction/__test__/TransactionsUnavailable.test.tsx b/ts/features/bonus/bpd/screens/details/transaction/__test__/TransactionsUnavailable.test.tsx
new file mode 100644
index 00000000000..bc818b4e5eb
--- /dev/null
+++ b/ts/features/bonus/bpd/screens/details/transaction/__test__/TransactionsUnavailable.test.tsx
@@ -0,0 +1,73 @@
+import { render } from "@testing-library/react-native";
+import configureMockStore from "redux-mock-store";
+import * as React from "react";
+import { Provider } from "react-redux";
+import { Store } from "redux";
+import I18n from "../../../../../../../i18n";
+import TransactionsUnavailable from "../TransactionsUnavailable";
+
+jest.mock("react-navigation", () => ({
+ NavigationEvents: "mockNavigationEvents",
+ StackActions: {
+ push: jest
+ .fn()
+ .mockImplementation(x => ({ ...x, type: "Navigation/PUSH" })),
+ replace: jest
+ .fn()
+ .mockImplementation(x => ({ ...x, type: "Navigation/REPLACE" })),
+ reset: jest.fn()
+ },
+ NavigationActions: {
+ navigate: jest.fn().mockImplementation(x => x)
+ },
+ createStackNavigator: jest.fn(),
+ withNavigation: (component: any) => component
+}));
+describe("TransactionsUnavailable component", () => {
+ const mockStore = configureMockStore();
+ // eslint-disable-next-line functional/no-let
+ let store: ReturnType;
+
+ beforeEach(() => {
+ jest.useFakeTimers();
+ store = mockStore({
+ search: { isSearchEnabled: false },
+ persistedPreferences: { isPagoPATestEnabled: false },
+ network: { isConnected: true },
+ instabug: { unreadMessages: 0 }
+ });
+ });
+
+ it("should show the payment-unavailable-icon.png", () => {
+ const component = getComponent(store);
+ const rasterImageComponent = component.queryByTestId("rasterImage");
+ const paymentUnavailableIconPath =
+ "../../../img/wallet/errors/payment-unavailable-icon.png";
+
+ expect(rasterImageComponent).toHaveProp("source", {
+ testUri: paymentUnavailableIconPath
+ });
+ });
+ it("should use the right string as header, title and body", () => {
+ const component = getComponent(store);
+ const headerTitle = component.getByText(
+ I18n.t("bonus.bpd.details.transaction.goToButton")
+ );
+ const title = component.getByText(
+ I18n.t("bonus.bpd.details.transaction.error.title")
+ );
+ const body = component.getByText(
+ I18n.t("bonus.bpd.details.transaction.error.body")
+ );
+
+ expect(headerTitle).not.toBeEmpty();
+ expect(title).not.toBeEmpty();
+ expect(body).not.toBeEmpty();
+ });
+});
+const getComponent = (store: Store) =>
+ render(
+
+
+
+ );