From 0b6f8d54d7149956ac49b511d5b4502e8ed5fbc2 Mon Sep 17 00:00:00 2001 From: Grzegorz Ziolkowski Date: Wed, 25 Jan 2017 15:23:29 +0100 Subject: [PATCH 01/10] Signup: Change signup flow for domain only sites --- client/lib/signup/step-actions.js | 19 ++++++++++++++++--- client/signup/config/steps.js | 2 +- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/client/lib/signup/step-actions.js b/client/lib/signup/step-actions.js index c6ca0f08f74ea3..da74f4ca4bd610 100644 --- a/client/lib/signup/step-actions.js +++ b/client/lib/signup/step-actions.js @@ -28,6 +28,19 @@ import { import { getSiteTitle } from 'state/signup/steps/site-title/selectors'; import { getSurveyVertical, getSurveySiteType } from 'state/signup/steps/survey/selectors'; +function createCart( callback, dependencies, data ) { + const { designType } = dependencies; + const { domainItem, themeItem } = data; + + if ( designType === 'domain' ) { + // TODO: Find a way to create cart without a site + // SignupCart.addToCart depends on the site's slug + callback( undefined, [ null, null, domainItem, themeItem ] ); + } else { + createSiteWithCart( callback, dependencies, data ); + } +} + function createSiteWithCart( callback, dependencies, { cartItem, domainItem, @@ -49,8 +62,6 @@ function createSiteWithCart( callback, dependencies, { // query. See `getThemeSlug` in `DomainsStep`. theme: dependencies.themeSlugWithRepo || themeSlugWithRepo, vertical: surveyVertical || undefined, - // the API wants the `is_domain_only` flag provided as a number - is_domain_only: dependencies.designType === 'domain' ? 1 : 0 }, validate: false, find_available_url: isPurchasingItem @@ -222,7 +233,9 @@ function getUsernameSuggestion( username, reduxState ) { } module.exports = { - createSiteWithCart: createSiteWithCart, + createCart, + + createSiteWithCart, createSiteWithCartAndStartFreeTrial( callback, dependencies, data ) { createSiteWithCart( ( error, providedDependencies ) => { diff --git a/client/signup/config/steps.js b/client/signup/config/steps.js index 2bf7347be5c154..66abf793519cd5 100644 --- a/client/signup/config/steps.js +++ b/client/signup/config/steps.js @@ -107,7 +107,7 @@ module.exports = { 'domain-only': { stepName: 'domain-only', - apiRequestFunction: stepActions.createSiteWithCart, + apiRequestFunction: stepActions.createCart, props: { isDomainOnly: true }, From 9e1a1b299a77ac748b1f85f58ec15ba4bd67fc0f Mon Sep 17 00:00:00 2001 From: Grzegorz Ziolkowski Date: Tue, 31 Jan 2017 15:08:42 +0100 Subject: [PATCH 02/10] Checkout: Refactor shopping cart to use new API endpoint --- client/lib/cart/store/cart-synchronizer.js | 10 +++--- client/lib/cart/store/index.js | 10 +++--- .../lib/cart/store/test/cart-synchronizer.js | 16 ++++----- client/lib/signup/cart.js | 6 ++-- client/lib/signup/step-actions.js | 12 +++++-- .../wpcom-undocumented/lib/undocumented.js | 8 ++--- client/my-sites/upgrades/controller.jsx | 34 +++++++++++++++++++ client/my-sites/upgrades/index.js | 5 +++ 8 files changed, 73 insertions(+), 28 deletions(-) diff --git a/client/lib/cart/store/cart-synchronizer.js b/client/lib/cart/store/cart-synchronizer.js index 09b2624a4a4266..9b7dc8d50c95a5 100644 --- a/client/lib/cart/store/cart-synchronizer.js +++ b/client/lib/cart/store/cart-synchronizer.js @@ -56,12 +56,12 @@ function preprocessCartForServer( cart ) { return newCart; } -function CartSynchronizer( siteID, wpcom ) { +function CartSynchronizer( cartKey, wpcom ) { if ( ! ( this instanceof CartSynchronizer ) ) { - return new CartSynchronizer( siteID, wpcom ); + return new CartSynchronizer( cartKey, wpcom ); } - this._siteID = siteID; + this._cartKey = cartKey; this._wpcom = wpcom; this._latestValue = null; this._hasLoadedFromServer = false; @@ -151,7 +151,7 @@ CartSynchronizer.prototype._processQueuedChanges = function() { }; CartSynchronizer.prototype._postToServer = function( callback ) { - this._wpcom.cart( this._siteID, 'POST', preprocessCartForServer( this._latestValue ), function( error, newValue ) { + this._wpcom.cart( this._cartKey, 'POST', preprocessCartForServer( this._latestValue ), function( error, newValue ) { if ( error ) { callback( error ); return; @@ -170,7 +170,7 @@ CartSynchronizer.prototype.fetch = function() { }; CartSynchronizer.prototype._getFromServer = function( callback ) { - this._wpcom.cart( this._siteID, 'GET', function( error, newValue ) { + this._wpcom.cart( this._cartKey, 'GET', function( error, newValue ) { if ( error ) { callback( error ); return; diff --git a/client/lib/cart/store/index.js b/client/lib/cart/store/index.js index d86e5a8fbc542d..c81d3d4a3c2f2a 100644 --- a/client/lib/cart/store/index.js +++ b/client/lib/cart/store/index.js @@ -22,7 +22,7 @@ var UpgradesActionTypes = require( 'lib/upgrades/constants' ).action, applyCoupon = cartValues.applyCoupon, cartItems = cartValues.cartItems; -var _selectedSiteID = null, +var _cartItem = null, _synchronizer = null, _poller = null; @@ -51,11 +51,11 @@ function setSelectedSite() { var selectedSite = sites.getSelectedSite(); if ( ! selectedSite ) { - _selectedSiteID = null; + _cartItem = null; return; } - if ( _selectedSiteID === selectedSite.ID ) { + if ( _cartItem === selectedSite.ID ) { return; } @@ -64,9 +64,9 @@ function setSelectedSite() { _synchronizer.off( 'change', emitChange ); } - _selectedSiteID = selectedSite.ID; + _cartItem = selectedSite.ID; - _synchronizer = cartSynchronizer( selectedSite.ID, wpcom ); + _synchronizer = cartSynchronizer( _cartItem, wpcom ); _synchronizer.on( 'change', emitChange ); _poller = PollerPool.add( CartStore, _synchronizer._poll.bind( _synchronizer ) ); diff --git a/client/lib/cart/store/test/cart-synchronizer.js b/client/lib/cart/store/test/cart-synchronizer.js index 7d7efe3841dad9..c2866ef5ba5fb8 100644 --- a/client/lib/cart/store/test/cart-synchronizer.js +++ b/client/lib/cart/store/test/cart-synchronizer.js @@ -10,7 +10,7 @@ import CartSynchronizer from '../cart-synchronizer'; import FakeWPCOM from './fake-wpcom'; import useFilesystemMocks from 'test/helpers/use-filesystem-mocks'; -var TEST_SITE_ID = 91234567890; +var TEST_CART_KEY = 91234567890; var poller = { add: function() {} @@ -31,7 +31,7 @@ describe( 'cart-synchronizer', function() { describe( '*before* the first fetch from the server', function() { it( 'should *not* allow the value to be read', function() { var wpcom = FakeWPCOM(), - synchronizer = CartSynchronizer( TEST_SITE_ID, wpcom, poller ); + synchronizer = CartSynchronizer( TEST_CART_KEY, wpcom, poller ); assert.throws( () => { synchronizer.getLatestValue(); @@ -40,8 +40,8 @@ describe( 'cart-synchronizer', function() { it( 'should enqueue local changes and POST them after fetching', function() { var wpcom = FakeWPCOM(), - synchronizer = CartSynchronizer( TEST_SITE_ID, wpcom, poller ), - serverCart = emptyCart( TEST_SITE_ID ); + synchronizer = CartSynchronizer( TEST_CART_KEY, wpcom, poller ), + serverCart = emptyCart( TEST_CART_KEY ); synchronizer.fetch(); synchronizer.update( applyCoupon( 'foo' ) ); @@ -63,8 +63,8 @@ describe( 'cart-synchronizer', function() { describe( '*after* the first fetch from the server', function() { it( 'should allow the value to be read', function() { var wpcom = FakeWPCOM(), - synchronizer = CartSynchronizer( TEST_SITE_ID, wpcom, poller ), - serverCart = emptyCart( TEST_SITE_ID ); + synchronizer = CartSynchronizer( TEST_CART_KEY, wpcom, poller ), + serverCart = emptyCart( TEST_CART_KEY ); synchronizer.fetch(); wpcom.resolveRequest( 0, serverCart ); @@ -75,8 +75,8 @@ describe( 'cart-synchronizer', function() { it( 'should make local changes visible immediately', function() { var wpcom = FakeWPCOM(), - synchronizer = CartSynchronizer( TEST_SITE_ID, wpcom, poller ), - serverCart = emptyCart( TEST_SITE_ID ); + synchronizer = CartSynchronizer( TEST_CART_KEY, wpcom, poller ), + serverCart = emptyCart( TEST_CART_KEY ); synchronizer.fetch(); wpcom.resolveRequest( 0, serverCart ); diff --git a/client/lib/signup/cart.js b/client/lib/signup/cart.js index 0108a12cf1c719..94cb5a470b6218 100644 --- a/client/lib/signup/cart.js +++ b/client/lib/signup/cart.js @@ -12,8 +12,8 @@ var wpcom = require( 'lib/wp' ), cartItems = cartValues.cartItems; module.exports = { - addToCart: function( siteSlug, newCartItems, callback ) { - wpcom.undocumented().cart( siteSlug, function( error, data ) { + addToCart: function( cartKey, newCartItems, callback ) { + wpcom.undocumented().cart( cartKey, function( error, data ) { if ( error ) { return callback( error ); } @@ -33,7 +33,7 @@ module.exports = { newCart = cartValues.fillInAllCartItemAttributes( addFunction( newCart ), productsList.get() ); } ); - wpcom.undocumented().cart( siteSlug, 'POST', newCart, function( postError ) { + wpcom.undocumented().cart( cartKey, 'POST', newCart, function( postError ) { callback( postError ); } ); } ); diff --git a/client/lib/signup/step-actions.js b/client/lib/signup/step-actions.js index da74f4ca4bd610..df0d87d4d71b24 100644 --- a/client/lib/signup/step-actions.js +++ b/client/lib/signup/step-actions.js @@ -33,9 +33,15 @@ function createCart( callback, dependencies, data ) { const { domainItem, themeItem } = data; if ( designType === 'domain' ) { - // TODO: Find a way to create cart without a site - // SignupCart.addToCart depends on the site's slug - callback( undefined, [ null, null, domainItem, themeItem ] ); + const cartKey = 'no-site'; + const providedDependencies = { + siteId: null, + siteSlug: cartKey, + domainItem, + themeItem + }; + + SignupCart.addToCart( cartKey, [ domainItem ], error => callback( error, providedDependencies ) ); } else { createSiteWithCart( callback, dependencies, data ); } diff --git a/client/lib/wpcom-undocumented/lib/undocumented.js b/client/lib/wpcom-undocumented/lib/undocumented.js index afd894379c2edc..6f92e69c0f5926 100644 --- a/client/lib/wpcom-undocumented/lib/undocumented.js +++ b/client/lib/wpcom-undocumented/lib/undocumented.js @@ -643,14 +643,14 @@ Undocumented.prototype.getSitePlans = function( siteDomain, fn ) { /** * GET/POST cart * - * @param {string} [siteDomain] The site's slug + * @param {string} [cartKey] The cart's key * @param {string} [method] The request method * @param {object} [data] The REQUEST data * @param {Function} fn The callback function * @api public */ -Undocumented.prototype.cart = function( siteDomain, method, data, fn ) { - debug( '/sites/:site_id:/shopping-cart query' ); +Undocumented.prototype.cart = function( cartKey, method, data, fn ) { + debug( '/me/shopping-cart/:cart-key query' ); if ( arguments.length === 2 ) { fn = method; method = 'GET'; @@ -661,7 +661,7 @@ Undocumented.prototype.cart = function( siteDomain, method, data, fn ) { data = {}; } return this._sendRequestWithLocale( { - path: '/sites/' + siteDomain + '/shopping-cart', + path: '/me/shopping-cart/' + cartKey, method: method, body: data }, fn ); diff --git a/client/my-sites/upgrades/controller.jsx b/client/my-sites/upgrades/controller.jsx index 8bf21096039c77..4390521ab0374d 100644 --- a/client/my-sites/upgrades/controller.jsx +++ b/client/my-sites/upgrades/controller.jsx @@ -214,6 +214,40 @@ module.exports = { ); }, + sitelessCheckout: function( context ) { + const Checkout = require( './checkout' ), + CheckoutData = require( 'components/data/checkout' ), + CartData = require( 'components/data/cart' ), + SecondaryCart = require( './cart/secondary-cart' ); + + analytics.pageView.record( '/checkout/no-site', 'Checkout' ); + + // FIXME: Auto-converted from the Flux setTitle action. Please use instead. + context.store.dispatch( setTitle( i18n.translate( 'Checkout' ) ) ); + + renderWithReduxStore( + ( + + + + ), + document.getElementById( 'primary' ), + context.store + ); + + renderWithReduxStore( + ( + + + + ), + document.getElementById( 'secondary' ), + context.store + ); + }, + checkoutThankYou: function( context ) { const CheckoutThankYouComponent = require( './checkout-thank-you' ), basePath = route.sectionify( context.path ), diff --git a/client/my-sites/upgrades/index.js b/client/my-sites/upgrades/index.js index 6a651b5dbbc54d..577d6dd51f2ea0 100644 --- a/client/my-sites/upgrades/index.js +++ b/client/my-sites/upgrades/index.js @@ -251,6 +251,11 @@ module.exports = function() { upgradesController.checkoutThankYou ); + page( + '/checkout/no-site', + upgradesController.sitelessCheckout + ); + page( '/checkout/:domain/:product?', controller.siteSelection, From bcbadd9fa60aa77582c377234298c50a3902e0fa Mon Sep 17 00:00:00 2001 From: Drew Blaisdell Date: Tue, 31 Jan 2017 16:47:32 -0800 Subject: [PATCH 03/10] Checkout: Initialize `cartSynchronizer` with `cartKey` derived from selected site --- client/lib/cart/store/index.js | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/client/lib/cart/store/index.js b/client/lib/cart/store/index.js index c81d3d4a3c2f2a..6c8ca8e010c9f3 100644 --- a/client/lib/cart/store/index.js +++ b/client/lib/cart/store/index.js @@ -22,7 +22,7 @@ var UpgradesActionTypes = require( 'lib/upgrades/constants' ).action, applyCoupon = cartValues.applyCoupon, cartItems = cartValues.cartItems; -var _cartItem = null, +var _cartKey = null, _synchronizer = null, _poller = null; @@ -50,13 +50,14 @@ function hasPendingServerUpdates() { function setSelectedSite() { var selectedSite = sites.getSelectedSite(); - if ( ! selectedSite ) { - _cartItem = null; + if ( _cartKey === selectedSite.ID ) { return; } - if ( _cartItem === selectedSite.ID ) { - return; + if ( ! selectedSite ) { + _cartKey = 'no-site'; + } else { + _cartKey = selectedSite.ID; } if ( _synchronizer && _poller ) { @@ -64,9 +65,7 @@ function setSelectedSite() { _synchronizer.off( 'change', emitChange ); } - _cartItem = selectedSite.ID; - - _synchronizer = cartSynchronizer( _cartItem, wpcom ); + _synchronizer = cartSynchronizer( _cartKey, wpcom ); _synchronizer.on( 'change', emitChange ); _poller = PollerPool.add( CartStore, _synchronizer._poll.bind( _synchronizer ) ); From 8ec669078a296ec9cade2e5c709c1a70335e4981 Mon Sep 17 00:00:00 2001 From: Drew Blaisdell Date: Tue, 31 Jan 2017 16:55:58 -0800 Subject: [PATCH 04/10] Checkout: Add `propTypes` to `SecondaryCart` --- client/my-sites/upgrades/cart/secondary-cart.jsx | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/client/my-sites/upgrades/cart/secondary-cart.jsx b/client/my-sites/upgrades/cart/secondary-cart.jsx index 66c198c7a04fd1..9d377627e88927 100644 --- a/client/my-sites/upgrades/cart/secondary-cart.jsx +++ b/client/my-sites/upgrades/cart/secondary-cart.jsx @@ -1,7 +1,7 @@ /** * External dependencies */ -import React from 'react'; +import React, { PropTypes } from 'react'; import { localize } from 'i18n-calypso'; /** @@ -17,6 +17,14 @@ import observe from 'lib/mixins/data-observe'; import CartBodyLoadingPlaceholder from 'my-sites/upgrades/cart/cart-body/loading-placeholder'; const SecondaryCart = React.createClass( { + propTypes: { + cart: PropTypes.object.isRequired, + selectedSite: PropTypes.oneOfType( [ + PropTypes.bool, + PropTypes.object + ] ) + }, + mixins: [ CartMessagesMixin, observe( 'sites' ) ], render() { From ce1f6173e092fd206aaf513c30cb3f1bdb4d834b Mon Sep 17 00:00:00 2001 From: Drew Blaisdell Date: Tue, 31 Jan 2017 16:59:26 -0800 Subject: [PATCH 05/10] Checkout: Add `propTypes` to `CartPlanAd` --- client/my-sites/upgrades/cart/cart-plan-ad.jsx | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/client/my-sites/upgrades/cart/cart-plan-ad.jsx b/client/my-sites/upgrades/cart/cart-plan-ad.jsx index 39b3bca21224ae..bfebe395058e43 100644 --- a/client/my-sites/upgrades/cart/cart-plan-ad.jsx +++ b/client/my-sites/upgrades/cart/cart-plan-ad.jsx @@ -4,7 +4,7 @@ import { connect } from 'react-redux'; import { localize } from 'i18n-calypso'; import page from 'page'; -import React, { Component } from 'react'; +import React, { Component, PropTypes } from 'react'; /** * Internal dependencies @@ -54,6 +54,15 @@ class CartPlanAd extends Component { } } +CartPlanAd.propTypes = { + cart: PropTypes.object.isRequired, + isDomainOnlySite: PropTypes.bool, + selectedSite: PropTypes.oneOfType( [ + PropTypes.bool, + PropTypes.object + ] ) +}; + export default connect( ( state ) => { const selectedSiteId = getSelectedSiteId( state ); From 0e950e87941367a0f45ac9a932cc42d0bb51781c Mon Sep 17 00:00:00 2001 From: Drew Blaisdell Date: Tue, 31 Jan 2017 17:07:37 -0800 Subject: [PATCH 06/10] Checkout: Don't display `CartPlanAd` when checking out without a site --- client/my-sites/upgrades/cart/cart-plan-ad.jsx | 1 + 1 file changed, 1 insertion(+) diff --git a/client/my-sites/upgrades/cart/cart-plan-ad.jsx b/client/my-sites/upgrades/cart/cart-plan-ad.jsx index bfebe395058e43..1c11706aac7726 100644 --- a/client/my-sites/upgrades/cart/cart-plan-ad.jsx +++ b/client/my-sites/upgrades/cart/cart-plan-ad.jsx @@ -31,6 +31,7 @@ class CartPlanAd extends Component { cart.hasLoadedFromServer && ! cartItems.hasDomainCredit( cart ) && cartItems.getDomainRegistrations( cart ).length === 1 && + selectedSite && selectedSite.plan && ! isPlan( selectedSite.plan ); } From 99d2d36668af98c8824489b449ffbdf7aafa6d99 Mon Sep 17 00:00:00 2001 From: Drew Blaisdell Date: Wed, 1 Feb 2017 12:37:11 -0800 Subject: [PATCH 07/10] Checkout: Remove side effects from `getCheckoutCompleteRedirectPath` and add `handleCheckoutCompleteRedirect` --- .../my-sites/upgrades/checkout/checkout.jsx | 77 +++++++++++++------ .../upgrades/checkout/secure-payment-form.jsx | 3 +- .../checkout/transaction-steps-mixin.jsx | 5 +- 3 files changed, 57 insertions(+), 28 deletions(-) diff --git a/client/my-sites/upgrades/checkout/checkout.jsx b/client/my-sites/upgrades/checkout/checkout.jsx index b27912e0363878..0f891377e58274 100644 --- a/client/my-sites/upgrades/checkout/checkout.jsx +++ b/client/my-sites/upgrades/checkout/checkout.jsx @@ -178,23 +178,65 @@ const Checkout = React.createClass( { }, getCheckoutCompleteRedirectPath: function() { + let renewalItem; + const { + cart, + isDomainOnly, + selectedSite, + selectedSiteSlug, + transaction: { + step: { + data: receipt + } + } + } = this.props; + + if ( cartItems.hasRenewalItem( cart ) ) { + renewalItem = cartItems.getRenewalItems( cart )[ 0 ]; + + return purchasePaths.managePurchase( renewalItem.extra.purchaseDomain, renewalItem.extra.purchaseId ); + } else if ( cartItems.hasFreeTrial( cart ) ) { + return selectedSiteSlug + ? `/plans/${ selectedSiteSlug }/thank-you` + : '/checkout/thank-you/plans'; + } else if ( isDomainOnly && cartItems.hasDomainRegistration( cart ) && ! cartItems.hasPlan( cart ) ) { + // TODO: Use purchased domain name once it is possible to set it as a primary domain when site is created. + return domainManagementList( selectedSite.slug ); + } + + if ( ! selectedSiteSlug ) { + return '/checkout/thank-you/features'; + } + + // The `:receiptId` string is filled in by our callback page after the PayPal checkout + const receiptId = receipt ? receipt.receipt_id : ':receiptId'; + + return this.props.selectedFeature && isValidFeatureKey( this.props.selectedFeature ) + ? `/checkout/thank-you/features/${ this.props.selectedFeature }/${ selectedSiteSlug }/${ receiptId }` + : `/checkout/thank-you/${ selectedSiteSlug }/${ receiptId }`; + }, + + handleCheckoutCompleteRedirect: function() { let product, purchasedProducts, - renewalItem, - receiptId = ':receiptId'; + renewalItem; const { cart, - isDomainOnly, - selectedSite, selectedSiteId, - selectedSiteSlug + transaction: { + step: { + data: receipt + } + } } = this.props; - const receipt = this.props.transaction.step.data; + const redirectPath = this.getCheckoutCompleteRedirectPath(); this.props.clearPurchases(); if ( cartItems.hasRenewalItem( cart ) ) { + // checkouts for renewals redirect back to `/purchases` with a notice + renewalItem = cartItems.getRenewalItems( cart )[ 0 ]; // group all purchases into an array purchasedProducts = reduce( receipt && receipt.purchases || {}, function( result, value ) { @@ -234,21 +276,12 @@ const Checkout = React.createClass( { { persistent: true } ); } - - return purchasePaths.managePurchase( renewalItem.extra.purchaseDomain, renewalItem.extra.purchaseId ); } else if ( cartItems.hasFreeTrial( cart ) ) { this.props.clearSitePlans( selectedSiteId ); - - return selectedSiteSlug - ? `/plans/${ selectedSiteSlug }/thank-you` - : '/checkout/thank-you/plans'; - } else if ( isDomainOnly && cartItems.hasDomainRegistration( cart ) && ! cartItems.hasPlan( cart ) ) { - // TODO: Use purchased domain name once it is possible to set it as a primary domain when site is created. - return domainManagementList( selectedSite.slug ); } if ( receipt && receipt.receipt_id ) { - receiptId = receipt.receipt_id; + const receiptId = receipt.receipt_id; this.props.fetchReceiptCompleted( receiptId, { receiptId: receiptId, @@ -257,13 +290,7 @@ const Checkout = React.createClass( { } ); } - if ( ! selectedSiteSlug ) { - return '/checkout/thank-you/features'; - } - - return this.props.selectedFeature && isValidFeatureKey( this.props.selectedFeature ) - ? `/checkout/thank-you/features/${ this.props.selectedFeature }/${ selectedSiteSlug }/${ receiptId }` - : `/checkout/thank-you/${ selectedSiteSlug }/${ receiptId }`; + page( redirectPath ); }, content: function() { @@ -290,7 +317,9 @@ const Checkout = React.createClass( { cards={ this.props.cards } products={ this.props.productsList.get() } selectedSite={ selectedSite } - redirectTo={ this.getCheckoutCompleteRedirectPath } /> + redirectTo={ this.getCheckoutCompleteRedirectPath } + handleCheckoutCompleteRedirect={ this.handleCheckoutCompleteRedirect } + /> ); }, diff --git a/client/my-sites/upgrades/checkout/secure-payment-form.jsx b/client/my-sites/upgrades/checkout/secure-payment-form.jsx index e70d6af3d861d7..9127dc18545324 100644 --- a/client/my-sites/upgrades/checkout/secure-payment-form.jsx +++ b/client/my-sites/upgrades/checkout/secure-payment-form.jsx @@ -40,8 +40,9 @@ const SecurePaymentForm = React.createClass( { mixins: [ TransactionStepsMixin ], propTypes: { + handleCheckoutCompleteRedirect: React.PropTypes.func.isRequired, products: React.PropTypes.object.isRequired, - redirectTo: React.PropTypes.func.isRequired + redirectTo: React.PropTypes.func.isRequired, }, getInitialState() { diff --git a/client/my-sites/upgrades/checkout/transaction-steps-mixin.jsx b/client/my-sites/upgrades/checkout/transaction-steps-mixin.jsx index dd384884612410..35c4f82724fe0b 100644 --- a/client/my-sites/upgrades/checkout/transaction-steps-mixin.jsx +++ b/client/my-sites/upgrades/checkout/transaction-steps-mixin.jsx @@ -5,8 +5,7 @@ var React = require( 'react' ), // eslint-disable-line no-unused-vars debug = require( 'debug' )( 'calypso:my-sites:upgrades:checkout:transaction-steps-mixin' ), pick = require( 'lodash/pick' ), defer = require( 'lodash/defer' ), - isEqual = require( 'lodash/isEqual' ), - page = require( 'page' ); + isEqual = require( 'lodash/isEqual' ); /** * Internal dependencies @@ -140,7 +139,7 @@ var TransactionStepsMixin = { defer( () => { // The Thank You page throws a rendering error if this is not in a defer. - page( this.props.redirectTo() ); + this.props.handleCheckoutCompleteRedirect(); } ); } }; From 6eb787e720c24ac5bf1a68c0d36d04527784ffb1 Mon Sep 17 00:00:00 2001 From: Drew Blaisdell Date: Wed, 1 Feb 2017 15:55:30 -0800 Subject: [PATCH 08/10] Checkout: Refetch the sites/user when a site has been created during checkout We do the same during signup. --- client/lib/signup/step-actions.js | 2 ++ .../my-sites/upgrades/checkout/checkout.jsx | 21 +++++++++++-------- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/client/lib/signup/step-actions.js b/client/lib/signup/step-actions.js index df0d87d4d71b24..67f2d2b9653227 100644 --- a/client/lib/signup/step-actions.js +++ b/client/lib/signup/step-actions.js @@ -321,6 +321,8 @@ module.exports = { } ); }, + fetchSitesAndUser: fetchSitesAndUser, + setThemeOnSite: setThemeOnSite, getUsernameSuggestion: getUsernameSuggestion diff --git a/client/my-sites/upgrades/checkout/checkout.jsx b/client/my-sites/upgrades/checkout/checkout.jsx index 0f891377e58274..c5df4b6a748baf 100644 --- a/client/my-sites/upgrades/checkout/checkout.jsx +++ b/client/my-sites/upgrades/checkout/checkout.jsx @@ -43,10 +43,8 @@ import { getSelectedSiteId, getSelectedSiteSlug, } from 'state/ui/selectors'; -import { - getSiteOption -} from 'state/sites/selectors'; import { domainManagementList } from 'my-sites/upgrades/paths'; +import { fetchSitesAndUser } from 'lib/signup/step-actions'; const Checkout = React.createClass( { mixins: [ observe( 'sites', 'productsList' ) ], @@ -181,8 +179,6 @@ const Checkout = React.createClass( { let renewalItem; const { cart, - isDomainOnly, - selectedSite, selectedSiteSlug, transaction: { step: { @@ -199,9 +195,9 @@ const Checkout = React.createClass( { return selectedSiteSlug ? `/plans/${ selectedSiteSlug }/thank-you` : '/checkout/thank-you/plans'; - } else if ( isDomainOnly && cartItems.hasDomainRegistration( cart ) && ! cartItems.hasPlan( cart ) ) { - // TODO: Use purchased domain name once it is possible to set it as a primary domain when site is created. - return domainManagementList( selectedSite.slug ); + } else if ( cart.create_new_blog && cartItems.hasDomainRegistration( cart ) && ! cartItems.hasPlan( cart ) ) { + const domainName = cartItems.getDomainRegistrations( cart )[ 0 ].meta; + return domainManagementList( domainName ); } if ( ! selectedSiteSlug ) { @@ -280,6 +276,14 @@ const Checkout = React.createClass( { this.props.clearSitePlans( selectedSiteId ); } + if ( cart.create_new_blog ) { + const domainName = cartItems.getDomainRegistrations( cart )[ 0 ].meta; + fetchSitesAndUser( domainName, () => { + page( redirectPath ); + } ); + return; + } + if ( receipt && receipt.receipt_id ) { const receiptId = receipt.receipt_id; @@ -360,7 +364,6 @@ module.exports = connect( return { cards: getStoredCards( state ), - isDomainOnly: getSiteOption( state, selectedSiteId, 'is_domain_only' ), selectedSite: getSelectedSite( state ), selectedSiteId, selectedSiteSlug: getSelectedSiteSlug( state ), From 3e8df06db38624316f1743b6adff9215df4428c0 Mon Sep 17 00:00:00 2001 From: Drew Blaisdell Date: Wed, 1 Feb 2017 15:57:07 -0800 Subject: [PATCH 09/10] Checkout: Remove `completed` state in `PayButton` The user will be redirected away from `PayButton` when the payment is complete. For some payments, we refetch the sites/user before redirecting, so the transaction will complete before we want the loading state to change. --- client/my-sites/upgrades/checkout/pay-button.jsx | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/client/my-sites/upgrades/checkout/pay-button.jsx b/client/my-sites/upgrades/checkout/pay-button.jsx index 7014974f9f61b8..28dc1385c05001 100644 --- a/client/my-sites/upgrades/checkout/pay-button.jsx +++ b/client/my-sites/upgrades/checkout/pay-button.jsx @@ -43,7 +43,7 @@ var PayButton = React.createClass( { if ( this.props.transactionStep.error || ! this.props.transactionStep.data.success ) { state = this.beforeSubmit(); } else { - state = this.completed(); + state = this.completing(); } break; @@ -126,13 +126,6 @@ var PayButton = React.createClass( { }; }, - completed: function() { - return { - disabled: true, - text: this.translate( 'Purchase complete', { context: 'Loading state on /checkout' } ) - }; - }, - render: function() { var buttonState = this.buttonState(); From dd9d46b3d2a9aaca5ea165bf50a49a4fc5c798d5 Mon Sep 17 00:00:00 2001 From: Drew Blaisdell Date: Wed, 1 Feb 2017 16:18:54 -0800 Subject: [PATCH 10/10] Checkout: Add notice to give user feedback while sites/user refetch --- client/my-sites/upgrades/checkout/checkout.jsx | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/client/my-sites/upgrades/checkout/checkout.jsx b/client/my-sites/upgrades/checkout/checkout.jsx index c5df4b6a748baf..b323406de37f3f 100644 --- a/client/my-sites/upgrades/checkout/checkout.jsx +++ b/client/my-sites/upgrades/checkout/checkout.jsx @@ -277,7 +277,12 @@ const Checkout = React.createClass( { } if ( cart.create_new_blog ) { + notices.info( + this.translate( 'Almost doneā€¦' ) + ); + const domainName = cartItems.getDomainRegistrations( cart )[ 0 ].meta; + fetchSitesAndUser( domainName, () => { page( redirectPath ); } );