Skip to content

Commit

Permalink
feat: [IOBP-514] Move authorization creation request upon payment met…
Browse files Browse the repository at this point in the history
…hod selection (#5419)

## Short description
This PR moves the transaction creation request from the payment summary
screen (`WalletPaymentConfirmScreen`) to the payment method selection
(`WalletPaymentPickMethodScreen`), after the payment method selection.

## List of changes proposed in this pull request
- Refactored `walletPaymentCreateTransaction` action to accept an
`onSuccess` callback
- Added `walletPaymentCreateTransaction` dispatch in
`WalletPaymentPickMethodScreen`, after _Continue_ button press

## How to test
With the
[io-dev-api-server,](https://github.com/pagopa/io-dev-api-server) start
a new payment flow from the **Profile > Playgrounds > New Wallet >
Payment** screen. With reactotron, check that the transaction creation
request is dispatched before the PSP selection screen.

---------

Co-authored-by: Alessandro Izzo <[email protected]>
Co-authored-by: Alessandro Izzo <[email protected]>
Co-authored-by: Martino Cesari Tomba <[email protected]>
  • Loading branch information
4 people authored Jan 25, 2024
1 parent e300141 commit dffbbc0
Show file tree
Hide file tree
Showing 9 changed files with 140 additions and 85 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
"lollipop_api": "https://raw.githubusercontent.com/pagopa/io-backend/v13.25.1-RELEASE/api_lollipop_first_consumer.yaml",
"fast_login_api": "https://raw.githubusercontent.com/pagopa/io-backend/v13.25.1-RELEASE/openapi/generated/api_fast_login.yaml",
"pagopa_api_walletv3": "https://raw.githubusercontent.com/pagopa/pagopa-infra/740e7dcc5ea2ea19639316fea6797bbd504dd0ae/src/domains/wallet-app/api/payment-wallet/v1/_openapi.json.tpl",
"pagopa_api_ecommerce": "https://raw.githubusercontent.com/pagopa/pagopa-infra/5190135ac34791cf66c1986735d4134bcaf4096f/src/domains/ecommerce-app/api/ecommerce-io/v1/_openapi.json.tpl",
"pagopa_api_ecommerce": "https://raw.githubusercontent.com/pagopa/pagopa-infra/a5299db39de86a951d353fdc2bfed48188c0c125/src/domains/ecommerce-app/api/ecommerce-io/v1/_openapi.json.tpl",
"private": true,
"scripts": {
"start": "react-native start",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,16 @@ import { PaymentMethodStatusEnum } from "../../../../../../../definitions/pagopa
import { getGenericError } from "../../../../../../utils/errors";
import { readablePrivacyReport } from "../../../../../../utils/reporters";
import { withRefreshApiCall } from "../../../../../fastLogin/saga/utils";
import {
WalletPaymentCalculateFeesPayload,
walletPaymentCalculateFees
} from "../../../store/actions/networking";
import { walletPaymentCalculateFees } from "../../../store/actions/networking";
import { handleWalletPaymentCalculateFees } from "../handleWalletPaymentCalculateFees";
import { CalculateFeeRequest } from "../../../../../../../definitions/pagopa/ecommerce/CalculateFeeRequest";

describe("Test handleWalletPaymentCalculateFees saga", () => {
const calculateFeesPayload: WalletPaymentCalculateFeesPayload = {
walletId: "1234",
paymentAmountInCents: 1234
const calculateFeesPayload: CalculateFeeRequest & {
paymentMethodId: string;
} = {
paymentMethodId: "1234",
paymentAmount: 1234
};

it(`should put ${getType(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import * as O from "fp-ts/lib/Option";

import { call, put, select } from "typed-redux-saga/macro";
import { ActionType } from "typesafe-actions";
import { CalculateFeeRequest } from "../../../../../../definitions/pagopa/ecommerce/CalculateFeeRequest";
import { SagaCallReturnType } from "../../../../../types/utils";
import { getGenericError, getNetworkError } from "../../../../../utils/errors";
import { readablePrivacyReport } from "../../../../../utils/reporters";
Expand All @@ -19,14 +18,10 @@ export function* handleWalletPaymentCalculateFees(
calculateFees: PaymentClient["calculateFees"],
action: ActionType<(typeof walletPaymentCalculateFees)["request"]>
) {
const requestBody: CalculateFeeRequest = {
paymentAmount: action.payload.paymentAmountInCents,
walletId: action.payload.walletId
};

const { paymentMethodId, ...body } = action.payload;
const calculateFeesRequest = calculateFees({
id: action.payload.walletId,
body: requestBody
id: paymentMethodId,
body
});

try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ export function* handleWalletPaymentCreateTransaction(
}),
({ status, value }) => {
if (status === 200) {
action.payload.onSucces?.();
return walletPaymentCreateTransaction.success(value);
} else if (status === 400) {
return walletPaymentCreateTransaction.failure({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {
VSpacer
} from "@pagopa/io-app-design-system";
import * as pot from "@pagopa/ts-commons/lib/pot";
import { useFocusEffect, useNavigation } from "@react-navigation/native";
import { useNavigation } from "@react-navigation/native";
import { sequenceS } from "fp-ts/lib/Apply";
import * as O from "fp-ts/lib/Option";
import { pipe } from "fp-ts/lib/function";
Expand All @@ -18,22 +18,20 @@ import {
AppParamsList,
IOStackNavigationProp
} from "../../../../navigation/params/AppParamsList";
import { useIODispatch, useIOSelector } from "../../../../store/hooks";
import { useIOSelector } from "../../../../store/hooks";
import { emptyContextualHelp } from "../../../../utils/emptyContextualHelp";
import { WalletPaymentConfirmContent } from "../components/WalletPaymentConfirmContent";
import { useWalletPaymentAuthorizationModal } from "../hooks/useWalletPaymentAuthorizationModal";
import { WalletPaymentRoutes } from "../navigation/routes";
import { walletPaymentCreateTransaction } from "../store/actions/networking";
import {
walletPaymentDetailsSelector,
walletPaymentPickedPaymentMethodSelector,
walletPaymentPickedPspSelector,
walletPaymentTransactionSelector
} from "../store/selectors";
import { WalletPaymentOutcome } from "../types/PaymentOutcomeEnum";
import { useWalletPaymentAuthorizationModal } from "../hooks/useWalletPaymentAuthorizationModal";

const WalletPaymentConfirmScreen = () => {
const dispatch = useIODispatch();
const navigation = useNavigation<IOStackNavigationProp<AppParamsList>>();

const paymentDetailsPot = useIOSelector(walletPaymentDetailsSelector);
Expand All @@ -43,22 +41,13 @@ const WalletPaymentConfirmScreen = () => {
);
const selectedPspOption = useIOSelector(walletPaymentPickedPspSelector);

const isTransactionLoading = pot.isLoading(transactionPot);
const isTransactionError = pot.isError(transactionPot);

useHeaderSecondLevel({
title: "",
contextualHelp: emptyContextualHelp,
faqCategories: ["payment"],
supportRequest: true
});

useFocusEffect(
React.useCallback(() => {
dispatch(walletPaymentCreateTransaction.request({ paymentNotices: [] }));
}, [dispatch])
);

const handleStartPaymentAuthorization = () =>
pipe(
sequenceS(O.Monad)({
Expand Down Expand Up @@ -96,9 +85,8 @@ const WalletPaymentConfirmScreen = () => {
onAuthorizationOutcome: handleAuthorizationOutcome
});

const isLoading =
isTransactionLoading || isAuthUrlLoading || isPendingAuthorization;
const isError = isTransactionError || isAuthUrlError;
const isLoading = isAuthUrlLoading || isPendingAuthorization;
const isError = isAuthUrlError;

if (isError) {
// TODO: Failure handling (https://pagopa.atlassian.net/browse/IOBP-471)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {
} from "@pagopa/io-app-design-system";
import * as pot from "@pagopa/ts-commons/lib/pot";
import { useFocusEffect, useNavigation } from "@react-navigation/native";
import { sequenceS } from "fp-ts/lib/Apply";
import { sequenceS, sequenceT } from "fp-ts/lib/Apply";
import * as A from "fp-ts/lib/Array";
import * as O from "fp-ts/lib/Option";
import { pipe } from "fp-ts/lib/function";
Expand All @@ -30,19 +30,24 @@ import { useIODispatch, useIOSelector } from "../../../../store/hooks";
import { ComponentProps } from "../../../../types/react";
import { emptyContextualHelp } from "../../../../utils/emptyContextualHelp";
import { findFirstCaseInsensitive } from "../../../../utils/object";
import { UIWalletInfoDetails } from "../../details/types/UIWalletInfoDetails";
import { WalletPaymentMissingMethodsError } from "../components/WalletPaymentMissingMethodsError";
import { useWalletPaymentGoBackHandler } from "../hooks/useWalletPaymentGoBackHandler";
import { WalletPaymentRoutes } from "../navigation/routes";
import { walletPaymentGetUserWallets } from "../store/actions/networking";
import {
walletPaymentCreateTransaction,
walletPaymentGetUserWallets
} from "../store/actions/networking";
import { walletPaymentPickPaymentMethod } from "../store/actions/orchestration";
import {
walletPaymentAllMethodsSelector,
walletPaymentAmountSelector,
walletPaymentDetailsSelector,
walletPaymentSavedMethodByIdSelector,
walletPaymentTransactionSelector,
walletPaymentUserWalletsSelector
} from "../store/selectors";
import { WalletPaymentMissingMethodsError } from "../components/WalletPaymentMissingMethodsError";
import { useWalletPaymentGoBackHandler } from "../hooks/useWalletPaymentGoBackHandler";
import { UIWalletInfoDetails } from "../../details/types/UIWalletInfoDetails";
import { WalletPaymentOutcomeEnum } from "../types/PaymentOutcomeEnum";

type SavedMethodState = {
kind: "saved";
Expand Down Expand Up @@ -72,6 +77,7 @@ const WalletPaymentPickMethodScreen = () => {
supportRequest: true
});

const paymentDetailsPot = useIOSelector(walletPaymentDetailsSelector);
const transactionPot = useIOSelector(walletPaymentTransactionSelector);
const getSavedtMethodById = useIOSelector(
walletPaymentSavedMethodByIdSelector
Expand All @@ -84,29 +90,37 @@ const WalletPaymentPickMethodScreen = () => {
const alertRef = React.useRef<View>(null);

const isLoading =
pot.isLoading(paymentMethodsPot) ||
pot.isLoading(userWalletsPots) ||
pot.isLoading(transactionPot);
pot.isLoading(paymentMethodsPot) || pot.isLoading(userWalletsPots);
const isLoadingTransaction = pot.isLoading(transactionPot);

const isError =
pot.isError(transactionPot) ||
pot.isError(paymentMethodsPot) ||
pot.isError(userWalletsPots);

const [shouldShowWarningBanner, setShouldShowWarningBanner] =
React.useState<boolean>(false);
const [selectedMethod, setSelectedMethod] =
React.useState<SelectedMethodState>(undefined);

useHeaderSecondLevel({
title: "",
contextualHelp: emptyContextualHelp,
faqCategories: ["payment"],
supportRequest: true
});

useFocusEffect(
React.useCallback(() => {
// dispatch(walletPaymentGetAllMethods.request()); // currently we do not allow onboarding new methods in payment flow
dispatch(walletPaymentGetUserWallets.request());
}, [dispatch])
);

React.useEffect(() => {
if (isError) {
navigation.navigate(WalletPaymentRoutes.WALLET_PAYMENT_MAIN, {
screen: WalletPaymentRoutes.WALLET_PAYMENT_OUTCOME,
params: {
outcome: WalletPaymentOutcomeEnum.GENERIC_ERROR
}
});
}
}, [isError, navigation]);

const paymentAmount = pot.getOrElse(paymentAmountPot, undefined);
const canContinue = selectedMethod !== undefined;

Expand Down Expand Up @@ -152,19 +166,32 @@ const WalletPaymentPickMethodScreen = () => {
};
*/

const navigateToPspSelectionScreen = () => {
navigation.navigate(WalletPaymentRoutes.WALLET_PAYMENT_MAIN, {
screen: WalletPaymentRoutes.WALLET_PAYMENT_PICK_PSP
});
};

const handleContinue = () => {
// todo:: should handle the case where the user
// selects a non saved method
if (selectedMethod?.kind === "saved") {
pipe(
getSavedtMethodById(selectedMethod.walletId),
O.map(walletPaymentPickPaymentMethod),
O.map(dispatch),
O.map(() =>
navigation.navigate(WalletPaymentRoutes.WALLET_PAYMENT_MAIN, {
screen: WalletPaymentRoutes.WALLET_PAYMENT_PICK_PSP
})
)
sequenceT(O.Monad)(
getSavedtMethodById(selectedMethod.walletId),
pot.toOption(paymentDetailsPot)
),
O.map(([method, paymentDetails]) => {
dispatch(walletPaymentPickPaymentMethod(method));
dispatch(
walletPaymentCreateTransaction.request({
paymentNotices: [
{ rptId: paymentDetails.rptId, amount: paymentDetails.amount }
],
onSucces: navigateToPspSelectionScreen
})
);
})
);
}
};
Expand All @@ -185,13 +212,17 @@ const WalletPaymentPickMethodScreen = () => {

return (
<GradientScrollView
primaryActionProps={{
label: I18n.t("global.buttons.continue"),
accessibilityLabel: I18n.t("global.buttons.continue"),
onPress: handleContinue,
disabled: isLoading || !canContinue,
loading: isLoading
}}
primaryActionProps={
canContinue
? {
label: I18n.t("global.buttons.continue"),
accessibilityLabel: I18n.t("global.buttons.continue"),
onPress: handleContinue,
disabled: isLoading || isLoadingTransaction,
loading: isLoading || isLoadingTransaction
}
: undefined
}
>
<H2>{I18n.t("wallet.payment.methodSelection.header")}</H2>
<VSpacer size={16} />
Expand Down
Loading

0 comments on commit dffbbc0

Please sign in to comment.