Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Payments: scaffold the checkout pending page, the 2nd attempt. #23827

Merged
merged 11 commits into from
Apr 13, 2018
Merged
113 changes: 113 additions & 0 deletions client/my-sites/checkout/checkout-thank-you/pending.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
/** @format */

/**
* External dependencies
*/
import page from 'page';
import { localize } from 'i18n-calypso';
import React, { PureComponent } from 'react';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
import { identity } from 'lodash';

/**
* Internal dependencies
*/
import { getOrderTransaction, getOrderTransactionError } from 'state/selectors';
import { ORDER_TRANSACTION_STATUS } from 'state/order-transactions/constants';
import { errorNotice } from 'state/notices/actions';

class CheckoutPending extends PureComponent {
static propTypes = {
orderId: PropTypes.number.isRequired,
siteSlug: PropTypes.string.isRequired,
transaction: PropTypes.object,
error: PropTypes.object,
errorNotice: PropTypes.func,
localize: PropTypes.func,
};

static defaultProps = {
localize: identity,
errorNotice: identity,
};

componentWillReceiveProps( nextProps ) {
const { transaction, error } = nextProps;
const { translate, showErrorNotice, siteSlug } = this.props;

const retryOnError = () => {
page( `/checkout/${ siteSlug }` );

showErrorNotice(
translate( "Sorry, we couldn't process your payment. Please try again later." )
);
};

const planRoute = `/plans/my-plan/${ siteSlug }`;

if ( transaction ) {
const { processingStatus } = transaction;

if ( ORDER_TRANSACTION_STATUS.SUCCESS === processingStatus ) {
page( `/checkout/thank-you/${ siteSlug }` );

return;
}

// It is mostly because the user has cancelled the payment.
// See the explanation in https://github.com/Automattic/wp-calypso/pull/23670#issuecomment-377186515
if ( ORDER_TRANSACTION_STATUS.FAILURE === processingStatus ) {
// Bring the user back to the plan page in this case.
page( planRoute );

return;
}

// or the processing status indicates that there was something wrong.
if ( ORDER_TRANSACTION_STATUS.ERROR === processingStatus ) {
// redirect users back to the checkout page so they can try again.
retryOnError();

return;
}

// The API has responded a status string that we don't expect somehow.
if ( ORDER_TRANSACTION_STATUS.UNKNOWN === processingStatus ) {
// Redirect users back to the plan page so that they won't be stuck here.
page( planRoute );

showErrorNotice( translate( 'Oops! Something went wrong. Please try again later.' ) );

return;
}
}

// A HTTP error occurs. We use the same handling
if ( error ) {
retryOnError();
}
}

render() {
const { orderId } = this.props;

// TODO:
// Replace this placeholder by the real one
return (
<div>
<p>Waiting for the payment result of { orderId }</p>
</div>
);
}
}

export default connect(
( state, props ) => ( {
transaction: getOrderTransaction( state, props.orderId ),
error: getOrderTransactionError( state, props.orderId ),
} ),
{
showErrorNotice: errorNotice,
}
)( localize( CheckoutPending ) );
19 changes: 19 additions & 0 deletions client/my-sites/checkout/controller.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import Checkout from './checkout';
import CheckoutData from 'components/data/checkout';
import CartData from 'components/data/cart';
import SecondaryCart from './cart/secondary-cart';
import CheckoutPendingComponent from './checkout-thank-you/pending';
import CheckoutThankYouComponent from './checkout-thank-you';

const checkoutRoutes = [
Expand All @@ -36,6 +37,11 @@ const checkoutGSuiteNudgeRoutes = [
new Route( '/checkout/:site/with-gsuite/:domain' ),
];

const checkoutPendingRoutes = [
new Route( '/checkout/thank-you/no-site/pending/:orderId' ),
new Route( '/checkout/thank-you/:site/pending/:orderId' ),
];

const checkoutThankYouRoutes = [
new Route( '/checkout/thank-you/no-site/:receipt' ),
new Route( '/checkout/thank-you/no-site' ),
Expand Down Expand Up @@ -104,6 +110,19 @@ export default {
next();
},

checkoutPending: function( context, next ) {
const { routePath, routeParams } = sectionifyWithRoutes( context.path, checkoutPendingRoutes );
const orderId = Number( context.params.orderId );
const siteSlug = context.params.site;

analytics.pageView.record( routePath, 'Checkout Pending', routeParams );
context.store.dispatch( setSection( { name: 'checkout-thank-you' }, { hasSidebar: false } ) );

context.primary = <CheckoutPendingComponent orderId={ orderId } siteSlug={ siteSlug } />;

next();
},

checkoutThankYou: function( context, next ) {
const { routePath, routeParams } = sectionifyWithRoutes( context.path, checkoutThankYouRoutes );
const receiptId = Number( context.params.receiptId );
Expand Down
16 changes: 16 additions & 0 deletions client/my-sites/checkout/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,14 @@ export default function() {
return;
}

page(
'/checkout/thank-you/no-site/pending/:orderId',
siteSelection,
checkoutController.checkoutPending,
makeLayout,
clientRender
);

page(
'/checkout/thank-you/no-site/:receiptId?',
noSite,
Expand All @@ -40,6 +48,14 @@ export default function() {
clientRender
);

page(
'/checkout/thank-you/:site/pending/:orderId',
siteSelection,
checkoutController.checkoutPending,
makeLayout,
clientRender
);

page(
'/checkout/thank-you/:site/:receiptId?',
siteSelection,
Expand Down
9 changes: 2 additions & 7 deletions client/state/data-layer/wpcom/me/transactions/order/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,13 @@
/**
* External dependencies
*/
import { translate } from 'i18n-calypso';

/**
* Internal dependencies
*/
import { http } from 'state/data-layer/wpcom-http/actions';
import { dispatchRequestEx } from 'state/data-layer/wpcom-http/utils';
import { errorNotice } from 'state/notices/actions';
import { setOrderTransaction } from 'state/order-transactions/actions';
import { setOrderTransaction, setOrderTransactionError } from 'state/order-transactions/actions';
import { ORDER_TRANSACTION_FETCH } from 'state/action-types';
import fromApi from './from-api';

Expand All @@ -32,10 +30,7 @@ export const fetchOrderTransaction = action =>

export const onSuccess = ( { orderId }, detail ) => setOrderTransaction( orderId, detail );

export const onError = () =>
errorNotice(
translate( 'We have problems fetching your payment status. Please try again later.' )
);
export const onError = ( { orderId }, error ) => setOrderTransactionError( orderId, error );

export default {
[ ORDER_TRANSACTION_FETCH ]: [
Expand Down
21 changes: 10 additions & 11 deletions client/state/data-layer/wpcom/me/transactions/order/test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,16 @@
*/
import { fetchOrderTransaction, onSuccess, onError } from '../';
import { http } from 'state/data-layer/wpcom-http/actions';
import { errorNotice } from 'state/notices/actions';
import { setOrderTransaction } from 'state/order-transactions/actions';

// we are mocking impure-lodash here, so that conciergeShiftsFetchError() will contain the expected id in the tests
jest.mock( 'lib/impure-lodash', () => ( {
uniqueId: () => 'mock-unique-id',
} ) );
import { setOrderTransaction, setOrderTransactionError } from 'state/order-transactions/actions';

describe( 'wpcom-api', () => {
describe( 'me/transactions/order', () => {
const orderId = 123;

describe( 'fetchOrderTransaction()', () => {
test( 'should return the expected http request action.', () => {
const action = {
orderId: 123,
orderId,
};

expect( fetchOrderTransaction( action ) ).toEqual(
Expand All @@ -40,7 +36,7 @@ describe( 'wpcom-api', () => {
describe( 'onSuccess()', () => {
test( 'should return the expected setting action for populating state.', () => {
const action = {
orderId: 123,
orderId,
};
const detail = {
status: 'profit!',
Expand All @@ -54,8 +50,11 @@ describe( 'wpcom-api', () => {

describe( 'onError()', () => {
test( 'should return the expected error notice action.', () => {
expect( onError() ).toEqual(
errorNotice( 'We have problems fetching your payment status. Please try again later.' )
const error = {
message: 'something goes wrong!',
};
expect( onError( { orderId }, error ) ).toEqual(
setOrderTransactionError( orderId, error )
);
} );
} );
Expand Down