Skip to content

Commit

Permalink
feat(Bonus Pagamenti Digitali): [#175889351,#175889362,#175889493,#17…
Browse files Browse the repository at this point in the history
…5890975] Action, store & reducer Bpay (#2673)

* [#175889351] wip

* [#175889351] add missing navigation

* [#175889351] fix compile

* [#175889351] renaming

* [#175889351] remove navigation bar

* [#175889351] fix and link with data

* [#175889351] remove unused import

* [#175889351] remove all the bancomat reference

* [#175889351] fix add bpay

* [#175889351] fix ts

* Update ts/features/wallet/onboarding/bancomatPay/screens/add-account/AddBPayScreen.tsx

Co-authored-by: Matteo Boschi <[email protected]>

* [#175889351] simplify code

* [#175889351] add sectionstatus

* [#175889351] simplify code

Co-authored-by: Matteo Boschi <[email protected]>
  • Loading branch information
fabriziofff and Undermaken authored Jan 7, 2021
1 parent c6719d6 commit 3f9bb70
Show file tree
Hide file tree
Showing 34 changed files with 1,041 additions and 15 deletions.
3 changes: 3 additions & 0 deletions locales/en/index.yml
Original file line number Diff line number Diff line change
Expand Up @@ -810,6 +810,9 @@ wallet:
body1: "Turn on your methods saved into your wallet and start collecting cashback on your valid transactions."
body2: "If you prefer, you can activate cashback on these methods later as well."
skip: "Maybe later"
bPay:
headerTitle: "Add BANCOMAT Pay"
placeholderTMP: "placeholder TMP"
satispay:
headerTitle: "Add Satispay"
start:
Expand Down
3 changes: 3 additions & 0 deletions locales/it/index.yml
Original file line number Diff line number Diff line change
Expand Up @@ -830,6 +830,9 @@ wallet:
body1: "Attiva il Cashback sui metodi salvati nel tuo portafoglio per iniziare a collezionare le transazioni valide."
body2: "Se preferisci, puoi attivare il Cashback su questi metodi anche in un secondo momento."
skip: "Non ora"
bPay:
headerTitle: "Aggiungi BANCOMAT Pay"
placeholderTMP: "placeholder TMP"
satispay:
headerTitle: "Aggiungi Satispay"
start:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { getType } from "typesafe-actions";
import { mixpanel } from "../../../../mixpanel";
import { Action } from "../../../../store/actions/types";
import { mixpanel } from "../../../../../mixpanel";
import { Action } from "../../../../../store/actions/types";
import {
addBancomatToWallet,
loadAbi,
Expand All @@ -9,8 +9,8 @@ import {
walletAddBancomatCancel,
walletAddBancomatCompleted,
walletAddBancomatStart
} from "../../../wallet/onboarding/bancomat/store/actions";
import { isTimeoutError } from "../../../../utils/errors";
} from "../store/actions";
import { isTimeoutError } from "../../../../../utils/errors";

// eslint-disable-next-line complexity
const trackAction = (mp: NonNullable<typeof mixpanel>) => (
Expand Down
Empty file.
27 changes: 27 additions & 0 deletions ts/features/wallet/onboarding/bancomatPay/navigation/action.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { NavigationActions } from "react-navigation";
import WALLET_ONBOARDING_BPAY_ROUTES from "./routes";

export const navigateToOnboardingBPaySearchStartScreen = () =>
NavigationActions.navigate({
routeName: WALLET_ONBOARDING_BPAY_ROUTES.START
});

export const navigateToOnboardingBPayChooseBank = () =>
NavigationActions.navigate({
routeName: WALLET_ONBOARDING_BPAY_ROUTES.CHOOSE_BANK
});

export const navigateToOnboardingBPaySearchAvailableUserAccount = () =>
NavigationActions.navigate({
routeName: WALLET_ONBOARDING_BPAY_ROUTES.SEARCH_AVAILABLE_USER_ACCOUNT
});

export const navigateToOnboardingBPayAdd = () =>
NavigationActions.navigate({
routeName: WALLET_ONBOARDING_BPAY_ROUTES.ADD_BPAY
});

export const navigateToActivateBpdOnNewBPay = () =>
NavigationActions.navigate({
routeName: WALLET_ONBOARDING_BPAY_ROUTES.ACTIVATE_BPD_NEW
});
36 changes: 36 additions & 0 deletions ts/features/wallet/onboarding/bancomatPay/navigation/navigator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { createStackNavigator } from "react-navigation";
import SearchBankScreen from "../../bancomat/screens/search/SearchBankScreen";
import ActivateBpdOnNewBPayScreen from "../screens/ActivateBpdOnNewBPayScreen";
import AddBPayScreen from "../screens/add-account/AddBPayScreen";
import BPaySearchStartScreen from "../screens/search/BPaySearchStartScreen";
import SearchAvailableUserBPayScreen from "../screens/searchBPay/SearchAvailableUserBPayScreen";
import WALLET_ONBOARDING_BPAY_ROUTES from "./routes";

const PaymentMethodOnboardingBPayNavigator = createStackNavigator(
{
[WALLET_ONBOARDING_BPAY_ROUTES.START]: {
screen: BPaySearchStartScreen
},
[WALLET_ONBOARDING_BPAY_ROUTES.CHOOSE_BANK]: {
screen: SearchBankScreen
},
[WALLET_ONBOARDING_BPAY_ROUTES.SEARCH_AVAILABLE_USER_ACCOUNT]: {
screen: SearchAvailableUserBPayScreen
},
[WALLET_ONBOARDING_BPAY_ROUTES.ADD_BPAY]: {
screen: AddBPayScreen
},
[WALLET_ONBOARDING_BPAY_ROUTES.ACTIVATE_BPD_NEW]: {
screen: ActivateBpdOnNewBPayScreen
}
},
{
// Let each screen handle the header and navigation
headerMode: "none",
defaultNavigationOptions: {
gesturesEnabled: false
}
}
);

export default PaymentMethodOnboardingBPayNavigator;
13 changes: 13 additions & 0 deletions ts/features/wallet/onboarding/bancomatPay/navigation/routes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
const WALLET_ONBOARDING_BPAY_ROUTES = {
MAIN: "WALLET_ONBOARDING_BPAY_MAIN",

START: "WALLET_ONBOARDING_BPAY_START",
CHOOSE_BANK: "WALLET_ONBOARDING_BPAY_CHOOSE_BANK_SCREEN",
SEARCH_AVAILABLE_USER_ACCOUNT:
"WALLET_ONBOARDING_BPAY_SEARCH_AVAILABLE_USER_ACCOUNT",

ADD_BPAY: "WALLET_ONBOARDING_BPAY_ADD",
ACTIVATE_BPD_NEW: "WALLET_ONBOARDING_BPAY_ACTIVATE_BPD_NEW"
};

export default WALLET_ONBOARDING_BPAY_ROUTES;
25 changes: 25 additions & 0 deletions ts/features/wallet/onboarding/bancomatPay/saga/networking/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { delay, put } from "redux-saga/effects";
import { ActionType } from "typesafe-actions";
import { rawBPay } from "../../../../../../store/reducers/wallet/__mocks__/wallets";
import { addBPayToWallet, searchUserBPay } from "../../store/actions";

/**
* Load all the user BPay accounts
* TODO: replace with real implementation
*/
export function* loadBPaySaga(_: ActionType<typeof searchUserBPay.request>) {
yield delay(100);
yield put(searchUserBPay.success([{}]));
}

/**
* Add bpay account to the wallet
* TODO: replace with real implementation
*/
export function* addBPayToWalletSaga(
_: ActionType<typeof addBPayToWallet.request>
) {
yield delay(100);

yield put(addBPayToWallet.success(rawBPay));
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import { NavigationActions } from "react-navigation";
import { call, put, select } from "redux-saga/effects";
import {
executeWorkUnit,
withResetNavigationStack
} from "../../../../../../sagas/workUnit";
import { navigateToWalletHome } from "../../../../../../store/actions/navigation";
import { fetchWalletsRequest } from "../../../../../../store/actions/wallet/wallets";
import { navigationCurrentRouteSelector } from "../../../../../../store/reducers/navigation";
import { SagaCallReturnType } from "../../../../../../types/utils";
import { activateBpdOnNewPaymentMethods } from "../../../../../bonus/bpd/saga/orchestration/activateBpdOnNewAddedPaymentMethods";
import {
navigateToActivateBpdOnNewBPay,
navigateToOnboardingBPaySearchStartScreen
} from "../../navigation/action";
import WALLET_ONBOARDING_BPAY_ROUTES from "../../navigation/routes";
import {
walletAddBPayBack,
walletAddBPayCancel,
walletAddBPayCompleted
} from "../../store/actions";
import { onboardingBPayAddedAccountSelector } from "../../store/reducers/addedBPay";

/**
* Define the workflow that allows the user to add BPay accounts to the wallet.
* The workflow ends when:
* - The user add at least one owned BPay to the wallet {@link walletAddBPayCompleted}
* - The user abort the insertion of a BPay {@link walletAddBPayCancel}
* - The user choose back from the first screen {@link walletAddBPayBack}
*/
function* bPayWorkUnit() {
return yield call(executeWorkUnit, {
startScreenNavigation: navigateToOnboardingBPaySearchStartScreen(),
startScreenName: WALLET_ONBOARDING_BPAY_ROUTES.START,
complete: walletAddBPayCompleted,
back: walletAddBPayBack,
cancel: walletAddBPayCancel
});
}

/**
* A saga that invokes the addition of a BPay workflow {@link bPayWorkUnit} and return
* to the wallet after the insertion.
*/
export function* addBPayToWalletGeneric() {
const res: SagaCallReturnType<typeof executeWorkUnit> = yield call(
withResetNavigationStack,
bPayWorkUnit
);
if (res !== "back") {
yield put(navigateToWalletHome());
}
}

/**
* Chain the add BPay to wallet with "activate bpd on the new BPay accounts"
*/
export function* addBPayToWalletAndActivateBpd() {
const res: SagaCallReturnType<typeof executeWorkUnit> = yield call(
withResetNavigationStack,
bPayWorkUnit
);
if (res !== "back") {
// integration with the legacy "Add a payment"
// If the payment starts from "WALLET_ADD_PAYMENT_METHOD", remove from stack
// This shouldn't happens if all the workflow will use the executeWorkUnit
const currentRoute: ReturnType<typeof navigationCurrentRouteSelector> = yield select(
navigationCurrentRouteSelector
);

if (
currentRoute.isSome() &&
currentRoute.value === "WALLET_ADD_PAYMENT_METHOD"
) {
yield put(NavigationActions.back());
}
}

if (res === "completed") {
// refresh wallets list
yield put(fetchWalletsRequest());
// read the new added BPay
const bPayAdded: ReturnType<typeof onboardingBPayAddedAccountSelector> = yield select(
onboardingBPayAddedAccountSelector
);

yield call(
activateBpdOnNewPaymentMethods,
bPayAdded,
navigateToActivateBpdOnNewBPay()
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import * as React from "react";
import { connect } from "react-redux";
import I18n from "../../../../../i18n";
import { GlobalState } from "../../../../../store/reducers/types";
import { emptyContextualHelp } from "../../../../../utils/emptyContextualHelp";
import ActivateBpdOnNewPaymentMethodScreen from "../../common/screens/bpd/ActivateBpdOnNewPaymentMethodScreen";
import { onboardingBPayAddedAccountSelector } from "../store/reducers/addedBPay";

type Props = ReturnType<typeof mapStateToProps>;

/**
* The user can activate the cashback on the new added BPay account
* @param props
* @constructor
*/
const ActivateBpdOnNewBPayScreen = (props: Props) => (
<ActivateBpdOnNewPaymentMethodScreen
paymentMethods={props.newBPay}
title={I18n.t("wallet.onboarding.bPay.headerTitle")}
contextualHelp={emptyContextualHelp}
/>
);

const mapStateToProps = (state: GlobalState) => ({
newBPay: onboardingBPayAddedAccountSelector(state)
});
export default connect(mapStateToProps)(ActivateBpdOnNewBPayScreen);
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
import { index } from "fp-ts/lib/Array";
import { fromNullable } from "fp-ts/lib/Option";
import * as pot from "italia-ts-commons/lib/pot";
import { Button } from "native-base";
import * as React from "react";
import { SafeAreaView } from "react-native";
import { connect } from "react-redux";
import { Dispatch } from "redux";
import { BPay } from "../../../../../../../definitions/pagopa/BPay";
import { Label } from "../../../../../../components/core/typography/Label";
import BaseScreenComponent from "../../../../../../components/screens/BaseScreenComponent";
import { profileSelector } from "../../../../../../store/reducers/profile";
import { GlobalState } from "../../../../../../store/reducers/types";
import {
getValueOrElse,
isError,
isLoading,
isReady
} from "../../../../../bonus/bpd/model/RemoteValue";
import {
addBPayToWallet,
walletAddBPayCancel,
walletAddBPayCompleted
} from "../../store/actions";
import {
onboardingBPayAddingResultSelector,
onboardingBPayChosenPanSelector
} from "../../store/reducers/addingBPay";
import { onboardingBPayFoundAccountsSelector } from "../../store/reducers/foundBpay";
import LoadAddBPayComponent from "./LoadAddBPayComponent";

type Props = ReturnType<typeof mapStateToProps> &
ReturnType<typeof mapDispatchToProps> &
Pick<React.ComponentProps<typeof BaseScreenComponent>, "contextualHelp">;

type NextAction = {
index: number;
skip: boolean;
};
/**
* This screen is displayed when BPay are found and ready to be added in wallet
* @constructor
*/
const AddBPayScreen: React.FunctionComponent<Props> = (props: Props) => {
// next could be skip or not (a pan should be added)
const [currentAction, setNextAction] = React.useState<NextAction>({
index: 0,
skip: false
});

const currentIndex = currentAction.index;

React.useEffect(() => {
// call onCompleted when the end of bpay pans has been reached
// and the adding phase has been completed (or it was skipped step)
if (
currentIndex >= props.bPayAccounts.length &&
(currentAction.skip || props.isAddingReady)
) {
props.onCompleted();
}
}, [currentAction, props.isAddingReady]);

const nextPan = (skip: boolean) => {
const nextIndex = currentIndex + 1;
setNextAction({ index: nextIndex, skip });
};

const handleOnContinue = () => {
if (currentIndex < props.bPayAccounts.length) {
props.addBPay(props.bPayAccounts[currentIndex]);
}
nextPan(false);
};

const currentPan = index(currentIndex, [...props.bPayAccounts]);

return props.loading || props.isAddingResultError ? (
<LoadAddBPayComponent
isLoading={!props.isAddingResultError}
onCancel={props.onCancel}
onRetry={() => fromNullable(props.selectedBPay).map(props.onRetry)}
/>
) : currentPan.isSome() ? (
// TODO: Replace with Iterative add component
<SafeAreaView>
<Button onPress={handleOnContinue}>
<Label>ContinueTMP</Label>
</Button>
</SafeAreaView>
) : null; // this should not happen
};

const mapDispatchToProps = (dispatch: Dispatch) => ({
addBPay: (bPay: BPay) => dispatch(addBPayToWallet.request(bPay)),
onCompleted: () => dispatch(walletAddBPayCompleted()),
onCancel: () => dispatch(walletAddBPayCancel()),
onRetry: (bPay: BPay) => dispatch(addBPayToWallet.request(bPay))
});

const mapStateToProps = (state: GlobalState) => {
const remoteBPay = onboardingBPayFoundAccountsSelector(state);
const addingResult = onboardingBPayAddingResultSelector(state);
const bPayAccounts = getValueOrElse(remoteBPay, []);
return {
isAddingReady: isReady(addingResult),
loading: isLoading(addingResult),
isAddingResultError: isError(addingResult),
remoteBPay,
selectedBPay: onboardingBPayChosenPanSelector(state),
bPayAccounts,
profile: pot.toUndefined(profileSelector(state))
};
};

export default connect(mapStateToProps, mapDispatchToProps)(AddBPayScreen);
Loading

0 comments on commit 3f9bb70

Please sign in to comment.