diff --git a/src/containers/CheckoutPage/CheckoutPage.js b/src/containers/CheckoutPage/CheckoutPage.js index a1d2597d..4b35a1f8 100644 --- a/src/containers/CheckoutPage/CheckoutPage.js +++ b/src/containers/CheckoutPage/CheckoutPage.js @@ -15,6 +15,7 @@ import { isTransactionInitiateAmountTooLowError, isTransactionInitiateListingNotFoundError, isTransactionInitiateMissingStripeAccountError, + transactionInitiateOrderStripeErrors, isTransactionInitiateBookingTimeNotAvailableError, } from '../../util/errors'; import { @@ -273,6 +274,7 @@ export class CheckoutPageComponent extends Component { const isBookingTimeNotAvailableError = isTransactionInitiateBookingTimeNotAvailableError( initiateOrderError ); + const stripeErrors = transactionInitiateOrderStripeErrors(initiateOrderError); let initiateOrderErrorMessage = null; @@ -288,6 +290,18 @@ export class CheckoutPageComponent extends Component {

); + } else if (!listingNotFound && stripeErrors && stripeErrors.length > 0) { + // NOTE: Error messages from Stripes are not part of translations. + // By default they are in English. + const stripeErrorsAsString = stripeErrors.join(', '); + initiateOrderErrorMessage = ( +

+ +

+ ); } else if (!listingNotFound && initiateOrderError) { initiateOrderErrorMessage = (

diff --git a/src/translations/en.json b/src/translations/en.json index d537de3d..1ebd6b19 100644 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -73,6 +73,7 @@ "CheckoutPage.hostedBy": "Hosted by {name}", "CheckoutPage.initiateOrderAmountTooLow": "We are unable to process this payment since the payment amount is too low. Please contact the marketplace administrator.", "CheckoutPage.initiateOrderError": "Payment request failed. Please go back to {listingLink} and try again. If the error persists, try refreshing the page or contacting the marketplace administrator.", + "CheckoutPage.initiateOrderStripeError": "The payment processor gave the following errors: {stripeErrors}", "CheckoutPage.listingNotFoundError": "Unfortunately, the listing is no longer available.", "CheckoutPage.loadingData": "Loading checkout data…", "CheckoutPage.paymentInfo": "You'll only be charged if your request is accepted by the provider.", diff --git a/src/util/errors.js b/src/util/errors.js index 732d52bd..f60fd02c 100644 --- a/src/util/errors.js +++ b/src/util/errors.js @@ -136,6 +136,24 @@ export const isTransactionInitiateAmountTooLowError = error => { }); }; +/** + * Check if the given API error (from `sdk.transaction.initiate()`) is + * due to other error in Stripe. + */ +export const transactionInitiateOrderStripeErrors = error => { + if (error) { + return errorAPIErrors(error).reduce((messages, apiError) => { + const isPaymentFailedError = + apiError.status === 402 && apiError.code === ERROR_CODE_PAYMENT_FAILED; + const hasStripeError = apiError && apiError.meta && apiError.meta.stripeMessage; + const stripeMessageMaybe = + isPaymentFailedError && hasStripeError ? [apiError.meta.stripeMessage] : []; + return [...messages, ...stripeMessageMaybe]; + }, []); + } + return null; +}; + /** * Check if the given API error (from `sdk.transactions.transition(id, transition, params)`) * is due to invalid transition attempt.