From 098782a5c622a8dc6f2c3ba94c3f5d4183205162 Mon Sep 17 00:00:00 2001 From: Grzegorz Ziolkowski Date: Thu, 19 Nov 2015 13:05:08 +0100 Subject: [PATCH 1/6] Purchases: Change cancel flow for non-refundable purchases --- client/lib/upgrades/actions/purchases.js | 28 +++++++ client/lib/upgrades/constants.js | 3 + .../me/purchases/cancel-purchase/button.jsx | 81 ++++++++++++++----- client/me/purchases/cancel-purchase/index.jsx | 3 +- .../confirm-cancel-purchase/index.jsx | 3 +- .../load-endpoint-form.js | 2 +- client/me/purchases/purchases-mixin.js | 6 -- .../wpcom-undocumented/lib/undocumented.js | 24 ++++-- 8 files changed, 113 insertions(+), 37 deletions(-) diff --git a/client/lib/upgrades/actions/purchases.js b/client/lib/upgrades/actions/purchases.js index 0837ad8862ed17..a3adcc496ca641 100644 --- a/client/lib/upgrades/actions/purchases.js +++ b/client/lib/upgrades/actions/purchases.js @@ -17,6 +17,33 @@ const debug = debugFactory( 'calypso:upgrades:actions:purchases' ), const PURCHASES_FETCH_ERROR_MESSAGE = i18n.translate( 'There was an error retrieving purchases.' ); +function cancelPurchase( purchaseId, onComplete ) { + Dispatcher.handleViewAction( { + type: ActionTypes.PURCHASES_CANCEL, + purchaseId + } ); + + wpcom.cancelPurchase( purchaseId, ( error, data ) => { + debug( error, data ); + + const success = ! error && data.success; + + if ( success ) { + Dispatcher.handleServerAction( { + type: ActionTypes.PURCHASES_CANCEL_COMPLETED, + purchaseId + } ); + } else { + Dispatcher.handleServerAction( { + type: ActionTypes.PURCHASES_CANCEL_FAILED, + purchaseId + } ); + } + + onComplete( success ); + } ); +} + function cancelPrivateRegistration( purchaseId, onComplete ) { Dispatcher.handleViewAction( { type: ActionTypes.PURCHASES_PRIVATE_REGISTRATION_CANCEL, @@ -142,6 +169,7 @@ function fetchUserPurchases() { } export { + cancelPurchase, cancelPrivateRegistration, deleteStoredCard, fetchSitePurchases, diff --git a/client/lib/upgrades/constants.js b/client/lib/upgrades/constants.js index 63545666782bc8..7a1f8d19dcc3da 100644 --- a/client/lib/upgrades/constants.js +++ b/client/lib/upgrades/constants.js @@ -31,6 +31,9 @@ module.exports.action = keyMirror( { PRIMARY_DOMAIN_SET: null, PRIMARY_DOMAIN_SET_COMPLETED: null, PRIMARY_DOMAIN_SET_FAILED: null, + PURCHASES_CANCEL: null, + PURCHASES_CANCEL_COMPLETED: null, + PURCHASES_CANCEL_FAILED: null, PURCHASES_PRIVATE_REGISTRATION_CANCEL: null, PURCHASES_PRIVATE_REGISTRATION_CANCEL_COMPLETED: null, PURCHASES_PRIVATE_REGISTRATION_CANCEL_FAILED: null, diff --git a/client/me/purchases/cancel-purchase/button.jsx b/client/me/purchases/cancel-purchase/button.jsx index c2e35428cf74ab..274ed69e889dab 100644 --- a/client/me/purchases/cancel-purchase/button.jsx +++ b/client/me/purchases/cancel-purchase/button.jsx @@ -1,41 +1,84 @@ /** * External Dependencies */ +import page from 'page'; import React from 'react'; /** * Internal Dependencies */ -import { purchaseTitle } from 'lib/purchases'; +import Button from 'components/button'; +import { cancelPurchase } from 'lib/upgrades/actions'; +import paths from 'me/purchases/paths'; +import notices from 'notices'; +import { isRefundable, purchaseTitle } from 'lib/purchases'; const CancelPurchaseButton = React.createClass( { propTypes: { purchase: React.PropTypes.object.isRequired }, - render() { - return ( - - ); + getInitialState() { + return { + disabled: false + }; }, - renderText() { - const { isRefundable } = this.props.purchase, - productName = purchaseTitle( this.props.purchase ); + goToCancelConfirmation() { + const { domain, id } = this.props.purchase; - if ( isRefundable ) { - return this.translate( 'Cancel and Refund %(productName)s', { - args: { productName } - } ); - } + page( paths.confirmCancelPurchase( domain, id ) ); + }, + + cancelPurchase() { + const { id } = this.props.purchase; + + this.toggleDisabled(); + + cancelPurchase( id, ( success ) => { + if ( success ) { + notices.success( this.translate( 'Purchase successfully cancelled.' ), { persistent: true } ); + page.redirect( paths.list() ); + } else { + notices.error( this.translate( + 'There was a problem canceling this purchase. ' + + 'Please try again later or contact support.' + ) ); + this.toggleDisabled(); + } + } ); + }, - return this.translate( 'Cancel %(productName)s', { - args: { productName } + toggleDisabled() { + this.setState( { + disabled: ! this.state.disabled } ); + }, + + render() { + const purchase = this.props.purchase, + productName = purchaseTitle( purchase ); + + if ( isRefundable( purchase ) ) { + return ( + + ); + } + + return ( + + ); } } ); diff --git a/client/me/purchases/cancel-purchase/index.jsx b/client/me/purchases/cancel-purchase/index.jsx index bb2d13d3c818e7..b7dc2a2c1d1189 100644 --- a/client/me/purchases/cancel-purchase/index.jsx +++ b/client/me/purchases/cancel-purchase/index.jsx @@ -87,8 +87,7 @@ const CancelPurchase = React.createClass( { + purchase={ purchase } /> ); diff --git a/client/me/purchases/confirm-cancel-purchase/index.jsx b/client/me/purchases/confirm-cancel-purchase/index.jsx index d3d83793ca91df..0f7e8e0385fd19 100644 --- a/client/me/purchases/confirm-cancel-purchase/index.jsx +++ b/client/me/purchases/confirm-cancel-purchase/index.jsx @@ -59,7 +59,8 @@ const ConfirmCancelPurchase = React.createClass( { handleSubmit( error, response ) { if ( error ) { notices.error( this.translate( - "Something went wrong and we couldn't cancel your subscription." + 'There was a problem canceling this purchase. ' + + 'Please try again later or contact support.' ) ); return; } diff --git a/client/me/purchases/confirm-cancel-purchase/load-endpoint-form.js b/client/me/purchases/confirm-cancel-purchase/load-endpoint-form.js index 258d1db7e05a31..abbf0657bb31fa 100644 --- a/client/me/purchases/confirm-cancel-purchase/load-endpoint-form.js +++ b/client/me/purchases/confirm-cancel-purchase/load-endpoint-form.js @@ -63,7 +63,7 @@ function submitForm( { form, onSubmit, selectedPurchase, selectedSite } ) { button.disabled = true; - wpcom.cancelProduct( selectedPurchase.id, formData, ( error, response ) => { + wpcom.cancelAndRefundPurchase( selectedPurchase.id, formData, ( error, response ) => { if ( error ) { button.disabled = false; onSubmit( error ); diff --git a/client/me/purchases/purchases-mixin.js b/client/me/purchases/purchases-mixin.js index 5a9d6d6d89d563..569798f12f88f8 100644 --- a/client/me/purchases/purchases-mixin.js +++ b/client/me/purchases/purchases-mixin.js @@ -17,12 +17,6 @@ export default { page( paths.list() ); }, - goToCancelConfirmation() { - const { domain, id } = this.getPurchase(); - - page( paths.confirmCancelPurchase( domain, id ) ); - }, - goToEditCardDetails() { const { domain, id, payment: { creditCard } } = this.getPurchase(); diff --git a/shared/lib/wpcom-undocumented/lib/undocumented.js b/shared/lib/wpcom-undocumented/lib/undocumented.js index 4028e7e374a38d..ca8b3f6f54ae65 100644 --- a/shared/lib/wpcom-undocumented/lib/undocumented.js +++ b/shared/lib/wpcom-undocumented/lib/undocumented.js @@ -1706,23 +1706,31 @@ Undocumented.prototype.getHelpLinks = function( searchQuery, fn ) { }, fn ); }; -Undocumented.prototype.getCancellationPageHTML = function( cancellationId, productId, fn ) { - debug( 'upgrades/{cancellationId}/cancel_form?product_id={productId}' ); +Undocumented.prototype.cancelPurchase = function( purchaseId, fn ) { + debug( 'upgrades/{purchaseId}/disable-auto-renew' ); + + this.wpcom.req.post( { + path: `/upgrades/${purchaseId}/disable-auto-renew` + }, fn ); +}; + +Undocumented.prototype.getCancellationPageHTML = function( purchaseId, productId, fn ) { + debug( 'upgrades/{purchaseId}/cancel_form?product_id={productId}' ); this.wpcom.req.get( { - path: `/upgrades/${cancellationId}/cancel_form`, + path: `/upgrades/${purchaseId}/cancel_form`, body: { client_timezone_offset: moment().format( 'Z' ) } }, { product_id: productId }, fn ); -} +}; -Undocumented.prototype.cancelProduct = function( cancellationId, data, fn ) { - debug( 'upgrades/{cancellationId}/cancel' ); +Undocumented.prototype.cancelAndRefundPurchase = function( purchaseId, data, fn ) { + debug( 'upgrades/{purchaseId}/cancel' ); this.wpcom.req.post( { - path: `/upgrades/${cancellationId}/cancel`, + path: `/upgrades/${purchaseId}/cancel`, body: data }, fn ); -} +}; Undocumented.prototype.cancelPrivateRegistration = function( purchaseId, fn ) { debug( 'upgrades/{purchaseId}/cancel-privacy-protection' ); From c7a87d15faf977b437b0423df8a29be0bd36f8f6 Mon Sep 17 00:00:00 2001 From: Grzegorz Ziolkowski Date: Thu, 19 Nov 2015 15:29:47 +0100 Subject: [PATCH 2/6] Purchases: Update notices for cancel purchase action --- client/lib/purchases/index.js | 32 +++++++++++++--- .../me/purchases/cancel-purchase/button.jsx | 37 +++++++++++++------ client/me/purchases/cancel-purchase/index.jsx | 6 +-- .../cancel-purchase/refund-information.jsx | 12 ++++-- client/me/purchases/manage-purchase/index.jsx | 5 ++- 5 files changed, 68 insertions(+), 24 deletions(-) diff --git a/client/lib/purchases/index.js b/client/lib/purchases/index.js index 3701a6aaddbc3f..97342f321e4fb5 100644 --- a/client/lib/purchases/index.js +++ b/client/lib/purchases/index.js @@ -36,6 +36,18 @@ function getPurchasesBySite( purchases ) { }, [] ); } +function getName( purchase ) { + if ( isDomainRegistration( purchase ) ) { + return purchase.meta; + } + + return purchase.productName; +} + +function getSubscriptionEndDate( purchase ) { + return i18n.moment( purchase.expiryDate ).format( 'LL' ) +} + function hasPaymentMethod( purchase ) { return isPaidWithPaypal( purchase ) || isPaidWithCreditCard( purchase ); } @@ -44,6 +56,14 @@ function hasPrivateRegistration( purchase ) { return purchase.hasPrivateRegistration; } +function isCancelable( purchase ) { + if ( purchase.isRefundable ) { + return true; + } + + return true; +} + function isExpired( purchase ) { return 'expired' === purchase.expiryStatus; } @@ -133,12 +153,11 @@ function purchaseType( purchase ) { return null; } +/** + * @deprecated Use getName instead. + */ function purchaseTitle( purchase ) { - if ( isDomainRegistration( purchase ) ) { - return purchase.meta; - } - - return purchase.productName; + return getName( purchase ); } function showCreditCardExpiringWarning( purchase ) { @@ -154,9 +173,12 @@ function showEditPaymentDetails( purchase ) { export { creditCardExpiresBeforeSubscription, + getName, getPurchasesBySite, + getSubscriptionEndDate, hasPaymentMethod, hasPrivateRegistration, + isCancelable, isPaidWithCreditCard, isPaidWithPaypal, isExpired, diff --git a/client/me/purchases/cancel-purchase/button.jsx b/client/me/purchases/cancel-purchase/button.jsx index 274ed69e889dab..7e36be2e455308 100644 --- a/client/me/purchases/cancel-purchase/button.jsx +++ b/client/me/purchases/cancel-purchase/button.jsx @@ -11,7 +11,7 @@ import Button from 'components/button'; import { cancelPurchase } from 'lib/upgrades/actions'; import paths from 'me/purchases/paths'; import notices from 'notices'; -import { isRefundable, purchaseTitle } from 'lib/purchases'; +import { getName, getSubscriptionEndDate, isRefundable } from 'lib/purchases'; const CancelPurchaseButton = React.createClass( { propTypes: { @@ -31,18 +31,33 @@ const CancelPurchaseButton = React.createClass( { }, cancelPurchase() { - const { id } = this.props.purchase; + const { purchase } = this.props, + { id } = purchase; this.toggleDisabled(); cancelPurchase( id, ( success ) => { + const purchaseName = getName( purchase ), + subscriptionEndDate = getSubscriptionEndDate( purchase ); + if ( success ) { - notices.success( this.translate( 'Purchase successfully cancelled.' ), { persistent: true } ); + notices.success( this.translate( + '%(purchaseName)s was successfully cancelled. It will be available for use until it expires on %(subscriptionEndDate)s.', + { + args: { + purchaseName, + subscriptionEndDate + } + } + ), { persistent: true } ); page.redirect( paths.list() ); } else { notices.error( this.translate( - 'There was a problem canceling this purchase. ' + - 'Please try again later or contact support.' + 'There was a problem canceling %(purchaseName)s. ' + + 'Please try again later or contact support.', + { + args: { purchaseName } + } ) ); this.toggleDisabled(); } @@ -56,15 +71,15 @@ const CancelPurchaseButton = React.createClass( { }, render() { - const purchase = this.props.purchase, - productName = purchaseTitle( purchase ); + const { purchase } = this.props, + purchaseName = getName( purchase ); if ( isRefundable( purchase ) ) { return ( ); @@ -74,8 +89,8 @@ const CancelPurchaseButton = React.createClass( { ); diff --git a/client/me/purchases/cancel-purchase/index.jsx b/client/me/purchases/cancel-purchase/index.jsx index b7dc2a2c1d1189..1476fa60389fb5 100644 --- a/client/me/purchases/cancel-purchase/index.jsx +++ b/client/me/purchases/cancel-purchase/index.jsx @@ -16,7 +16,7 @@ import CompactCard from 'components/card/compact'; import HeaderCake from 'components/header-cake'; import Main from 'components/main'; import paths from '../paths'; -import { purchaseTitle } from 'lib/purchases'; +import { isCancelable, purchaseTitle } from 'lib/purchases'; import purchasesMixin from '../purchases-mixin'; const CancelPurchase = React.createClass( { @@ -101,9 +101,9 @@ const CancelPurchase = React.createClass( { const purchase = this.getPurchase(); if ( purchase ) { - const { domain, id, isCancelable } = purchase; + const { domain, id } = purchase; - if ( ! isCancelable ) { + if ( ! isCancelable( purchase ) ) { page.redirect( paths.managePurchase( domain, id ) ); } } else { diff --git a/client/me/purchases/cancel-purchase/refund-information.jsx b/client/me/purchases/cancel-purchase/refund-information.jsx index ad882063cf7a4c..527565cba204c8 100644 --- a/client/me/purchases/cancel-purchase/refund-information.jsx +++ b/client/me/purchases/cancel-purchase/refund-information.jsx @@ -3,16 +3,22 @@ */ import React from 'react'; +/** + * Internal Dependencies + */ +import { getSubscriptionEndDate, isRefundable } from 'lib/purchases'; + const CancelPurchaseRefundInformation = React.createClass( { propTypes: { purchase: React.PropTypes.object.isRequired }, render() { - const { expiryDate, isRefundable, priceText, refundPeriodInDays } = this.props.purchase, + const purchase = this.props.purchase, + { priceText, refundPeriodInDays } = purchase, refundsSupportLink = ; - if ( isRefundable ) { + if ( isRefundable( purchase ) ) { return (

{ this.translate( 'Yes! You are canceling this purchase within the %(refundPeriodInDays)d day refund period. ' + @@ -38,7 +44,7 @@ const CancelPurchaseRefundInformation = React.createClass( { '{{a}}Learn more.{{/a}}', { args: { - subscriptionEndDate: this.moment( expiryDate ).format( 'LL' ), + subscriptionEndDate: getSubscriptionEndDate( purchase ), refundPeriodInDays }, components: { diff --git a/client/me/purchases/manage-purchase/index.jsx b/client/me/purchases/manage-purchase/index.jsx index ea1be3f08ea4a5..7f94576f38a2a5 100644 --- a/client/me/purchases/manage-purchase/index.jsx +++ b/client/me/purchases/manage-purchase/index.jsx @@ -28,6 +28,7 @@ import { creditCardExpiresBeforeSubscription, hasPaymentMethod, hasPrivateRegistration, + isCancelable, isExpired, isExpiring, isPaidWithCreditCard, @@ -433,9 +434,9 @@ const ManagePurchase = React.createClass( { renderCancelPurchaseNavItem() { const purchase = this.getPurchase(), - { domain, id, isCancelable } = purchase; + { domain, id } = purchase; - if ( isExpired( purchase ) || ! isCancelable ) { + if ( isExpired( purchase ) || ! isCancelable( purchase ) ) { return null; } From e57f0c00c022b470c8d70b88e9a7b6043c77470c Mon Sep 17 00:00:00 2001 From: Grzegorz Ziolkowski Date: Fri, 20 Nov 2015 08:43:31 +0100 Subject: [PATCH 3/6] Purchases: Update purchase title method --- client/lib/purchases/index.js | 8 ------- client/me/purchases/cancel-purchase/index.jsx | 6 +++--- client/me/purchases/list/item/index.jsx | 4 ++-- client/me/purchases/manage-purchase/index.jsx | 21 ++++++++++++------- 4 files changed, 18 insertions(+), 21 deletions(-) diff --git a/client/lib/purchases/index.js b/client/lib/purchases/index.js index 97342f321e4fb5..9cb0042df3aeb1 100644 --- a/client/lib/purchases/index.js +++ b/client/lib/purchases/index.js @@ -153,13 +153,6 @@ function purchaseType( purchase ) { return null; } -/** - * @deprecated Use getName instead. - */ -function purchaseTitle( purchase ) { - return getName( purchase ); -} - function showCreditCardExpiringWarning( purchase ) { return ! isIncludedWithPlan( purchase ) && isPaidWithCreditCard( purchase ) && @@ -191,7 +184,6 @@ export { isRenewing, paymentLogoType, purchaseType, - purchaseTitle, showCreditCardExpiringWarning, showEditPaymentDetails } diff --git a/client/me/purchases/cancel-purchase/index.jsx b/client/me/purchases/cancel-purchase/index.jsx index 1476fa60389fb5..b73408ce27975c 100644 --- a/client/me/purchases/cancel-purchase/index.jsx +++ b/client/me/purchases/cancel-purchase/index.jsx @@ -16,7 +16,7 @@ import CompactCard from 'components/card/compact'; import HeaderCake from 'components/header-cake'; import Main from 'components/main'; import paths from '../paths'; -import { isCancelable, purchaseTitle } from 'lib/purchases'; +import { getName, isCancelable } from 'lib/purchases'; import purchasesMixin from '../purchases-mixin'; const CancelPurchase = React.createClass( { @@ -54,9 +54,9 @@ const CancelPurchase = React.createClass( {

- { this.translate( 'Cancel %(productName)s', { + { this.translate( 'Cancel %(purchaseName)s', { args: { - productName: purchaseTitle( purchase ) + purchaseName: getName( purchase ) } } ) }

diff --git a/client/me/purchases/list/item/index.jsx b/client/me/purchases/list/item/index.jsx index a3c51cbc5f3827..4567d0c6a105f1 100644 --- a/client/me/purchases/list/item/index.jsx +++ b/client/me/purchases/list/item/index.jsx @@ -11,13 +11,13 @@ import paths from '../../paths'; import CompactCard from 'components/card/compact'; import Flag from 'components/flag'; import { + getName, isExpired, isExpiring, isRenewing, isIncludedWithPlan, isOneTimePurchase, purchaseType, - purchaseTitle, showCreditCardExpiringWarning } from 'lib/purchases'; @@ -119,7 +119,7 @@ const PurchaseItem = React.createClass( { content = (
- { purchaseTitle( this.props.purchase ) } + { getName( this.props.purchase ) }
{ purchaseType( this.props.purchase ) }
diff --git a/client/me/purchases/manage-purchase/index.jsx b/client/me/purchases/manage-purchase/index.jsx index 7f94576f38a2a5..2eeed4c5fdec1d 100644 --- a/client/me/purchases/manage-purchase/index.jsx +++ b/client/me/purchases/manage-purchase/index.jsx @@ -26,6 +26,7 @@ import { domainManagementEdit } from 'my-sites/upgrades/paths'; import { oldShowcaseUrl } from 'lib/themes/helpers'; import { creditCardExpiresBeforeSubscription, + getName, hasPaymentMethod, hasPrivateRegistration, isCancelable, @@ -40,9 +41,13 @@ import { isOneTimePurchase, paymentLogoType, purchaseType, +<<<<<<< 17f2d714fdd2b60b75a324128bc12e87d24219e9 purchaseTitle, showCreditCardExpiringWarning, showEditPaymentDetails +======= + showCreditCardExpiringWarning +>>>>>>> Purchases: Update purchase title method } from 'lib/purchases'; import purchasesMixin from '../purchases-mixin'; @@ -81,10 +86,10 @@ const ManagePurchase = React.createClass( { className="manage-purchase__purchase-expiring-notice" showDismiss={ false } status={ noticeStatus } - text={ this.translate( '%(purchase)s will expire and be removed from your site %(expiry)s.', + text={ this.translate( '%(purchaseName)s will expire and be removed from your site %(expiry)s.', { args: { - purchase: purchaseTitle( purchase ), + purchaseName: getName( purchase ), expiry: this.moment( purchase.expiryMoment ).fromNow() } } @@ -142,9 +147,9 @@ const ManagePurchase = React.createClass( { let text; if ( 'thank-you' === this.props.destinationType ) { - text = this.translate( '%(purchase)s has been renewed and will now auto renew in the future. {{a}}Learn more{{/a}}', { + text = this.translate( '%(purchaseName)s has been renewed and will now auto renew in the future. {{a}}Learn more{{/a}}', { args: { - purchase: purchaseTitle( purchase ) + purchaseName: getName( purchase ) }, components: { a: @@ -441,15 +446,15 @@ const ManagePurchase = React.createClass( { } const translateArgs = { - args: { purchase: purchaseTitle( purchase ) } + args: { purchaseName: getName( purchase ) } }; return ( { isRefundable( purchase ) - ? this.translate( 'Cancel and Refund %(purchase)s', translateArgs ) - : this.translate( 'Cancel %(purchase)s', translateArgs ) + ? this.translate( 'Cancel and Refund %(purchaseName)s', translateArgs ) + : this.translate( 'Cancel %(purchaseName)s', translateArgs ) } ); @@ -498,7 +503,7 @@ const ManagePurchase = React.createClass( { 'is-expired': purchase && isExpired( purchase ) } ); purchaseTypeSeparator = purchaseType( purchase ) ? '|' : ''; - purchaseTitleText = purchaseTitle( purchase ); + purchaseTitleText = getName( purchase ); purchaseTypeText = purchaseType( purchase ); siteName = purchase.siteName; siteDomain = purchase.domain; From 17fad8ccca120e16b66215405707c09b8a0b6d73 Mon Sep 17 00:00:00 2001 From: Grzegorz Ziolkowski Date: Fri, 20 Nov 2015 09:07:31 +0100 Subject: [PATCH 4/6] Purchases: Change logic which checks if user can cancel purchase --- client/lib/purchases/assembler.js | 2 +- client/lib/purchases/index.js | 8 ++++++-- client/lib/purchases/test/assembler-test.js | 2 +- client/lib/upgrades/actions/purchases.js | 17 ----------------- client/lib/upgrades/constants.js | 3 --- client/me/purchases/cancel-purchase/button.jsx | 2 +- client/me/purchases/manage-purchase/index.jsx | 5 ----- 7 files changed, 9 insertions(+), 30 deletions(-) diff --git a/client/lib/purchases/assembler.js b/client/lib/purchases/assembler.js index 430ab39bf640fa..04131dca00ce0a 100644 --- a/client/lib/purchases/assembler.js +++ b/client/lib/purchases/assembler.js @@ -22,6 +22,7 @@ function createPurchasesArray( dataTransferObject ) { active: Boolean( purchase.active ), amount: Number( purchase.amount ), attachedToPurchaseId: Number( purchase.attached_to_purchase_id ), + canDisableAutoRenew: Boolean( purchase.can_disable_auto_renew ), currencyCode: purchase.currency_code, currencySymbol: purchase.currency_symbol, domain: purchase.domain, @@ -31,7 +32,6 @@ function createPurchasesArray( dataTransferObject ) { expiryStatus: camelCase( purchase.expiry_status ), hasPrivateRegistration: Boolean( purchase.has_private_registration ), includedDomain: purchase.included_domain, - isCancelable: Boolean( purchase.is_cancelable ), isDomainRegistration: Boolean( purchase.is_domain_registration ), isRedeemable: Boolean( purchase.is_redeemable ), isRefundable: Boolean( purchase.is_refundable ), diff --git a/client/lib/purchases/index.js b/client/lib/purchases/index.js index 9cb0042df3aeb1..5b49df34ea2827 100644 --- a/client/lib/purchases/index.js +++ b/client/lib/purchases/index.js @@ -57,11 +57,15 @@ function hasPrivateRegistration( purchase ) { } function isCancelable( purchase ) { - if ( purchase.isRefundable ) { + if ( isRefundable( purchase ) ) { return true; } - return true; + if ( isIncludedWithPlan( purchase ) ) { + return false; + } + + return purchase.canDisableAutoRenew; } function isExpired( purchase ) { diff --git a/client/lib/purchases/test/assembler-test.js b/client/lib/purchases/test/assembler-test.js index 350d67b5006926..b0279fb32163b7 100644 --- a/client/lib/purchases/test/assembler-test.js +++ b/client/lib/purchases/test/assembler-test.js @@ -7,7 +7,7 @@ import moment from 'moment'; /** * Internal dependencies */ -import { createPurchasesArray } from '../assembler.js'; +import { createPurchasesArray } from '../assembler'; describe( 'Purchases assembler', () => { it( 'should be a function', () => { diff --git a/client/lib/upgrades/actions/purchases.js b/client/lib/upgrades/actions/purchases.js index a3adcc496ca641..767c07c9af560e 100644 --- a/client/lib/upgrades/actions/purchases.js +++ b/client/lib/upgrades/actions/purchases.js @@ -18,28 +18,11 @@ const debug = debugFactory( 'calypso:upgrades:actions:purchases' ), const PURCHASES_FETCH_ERROR_MESSAGE = i18n.translate( 'There was an error retrieving purchases.' ); function cancelPurchase( purchaseId, onComplete ) { - Dispatcher.handleViewAction( { - type: ActionTypes.PURCHASES_CANCEL, - purchaseId - } ); - wpcom.cancelPurchase( purchaseId, ( error, data ) => { debug( error, data ); const success = ! error && data.success; - if ( success ) { - Dispatcher.handleServerAction( { - type: ActionTypes.PURCHASES_CANCEL_COMPLETED, - purchaseId - } ); - } else { - Dispatcher.handleServerAction( { - type: ActionTypes.PURCHASES_CANCEL_FAILED, - purchaseId - } ); - } - onComplete( success ); } ); } diff --git a/client/lib/upgrades/constants.js b/client/lib/upgrades/constants.js index 7a1f8d19dcc3da..63545666782bc8 100644 --- a/client/lib/upgrades/constants.js +++ b/client/lib/upgrades/constants.js @@ -31,9 +31,6 @@ module.exports.action = keyMirror( { PRIMARY_DOMAIN_SET: null, PRIMARY_DOMAIN_SET_COMPLETED: null, PRIMARY_DOMAIN_SET_FAILED: null, - PURCHASES_CANCEL: null, - PURCHASES_CANCEL_COMPLETED: null, - PURCHASES_CANCEL_FAILED: null, PURCHASES_PRIVATE_REGISTRATION_CANCEL: null, PURCHASES_PRIVATE_REGISTRATION_CANCEL_COMPLETED: null, PURCHASES_PRIVATE_REGISTRATION_CANCEL_FAILED: null, diff --git a/client/me/purchases/cancel-purchase/button.jsx b/client/me/purchases/cancel-purchase/button.jsx index 7e36be2e455308..eb16cf70cda139 100644 --- a/client/me/purchases/cancel-purchase/button.jsx +++ b/client/me/purchases/cancel-purchase/button.jsx @@ -50,7 +50,7 @@ const CancelPurchaseButton = React.createClass( { } } ), { persistent: true } ); - page.redirect( paths.list() ); + page( paths.list() ); } else { notices.error( this.translate( 'There was a problem canceling %(purchaseName)s. ' + diff --git a/client/me/purchases/manage-purchase/index.jsx b/client/me/purchases/manage-purchase/index.jsx index 2eeed4c5fdec1d..cc72b416c3f33e 100644 --- a/client/me/purchases/manage-purchase/index.jsx +++ b/client/me/purchases/manage-purchase/index.jsx @@ -41,13 +41,8 @@ import { isOneTimePurchase, paymentLogoType, purchaseType, -<<<<<<< 17f2d714fdd2b60b75a324128bc12e87d24219e9 - purchaseTitle, showCreditCardExpiringWarning, showEditPaymentDetails -======= - showCreditCardExpiringWarning ->>>>>>> Purchases: Update purchase title method } from 'lib/purchases'; import purchasesMixin from '../purchases-mixin'; From edac540ff501fc9b8f365ad9fef71ab307498592 Mon Sep 17 00:00:00 2001 From: Grzegorz Ziolkowski Date: Fri, 20 Nov 2015 12:26:02 +0100 Subject: [PATCH 5/6] Purchases: Improve code quality for new cancel purchase flow --- client/lib/purchases/index.js | 2 +- client/me/purchases/cancel-purchase/button.jsx | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/client/lib/purchases/index.js b/client/lib/purchases/index.js index 5b49df34ea2827..9a98b749468493 100644 --- a/client/lib/purchases/index.js +++ b/client/lib/purchases/index.js @@ -45,7 +45,7 @@ function getName( purchase ) { } function getSubscriptionEndDate( purchase ) { - return i18n.moment( purchase.expiryDate ).format( 'LL' ) + return purchase.expiryMoment.format( 'LL' ); } function hasPaymentMethod( purchase ) { diff --git a/client/me/purchases/cancel-purchase/button.jsx b/client/me/purchases/cancel-purchase/button.jsx index eb16cf70cda139..6e50b3c316e6ca 100644 --- a/client/me/purchases/cancel-purchase/button.jsx +++ b/client/me/purchases/cancel-purchase/button.jsx @@ -9,9 +9,9 @@ import React from 'react'; */ import Button from 'components/button'; import { cancelPurchase } from 'lib/upgrades/actions'; -import paths from 'me/purchases/paths'; -import notices from 'notices'; import { getName, getSubscriptionEndDate, isRefundable } from 'lib/purchases'; +import notices from 'notices'; +import paths from 'me/purchases/paths'; const CancelPurchaseButton = React.createClass( { propTypes: { From 2c6cc4634ccebe9cc608c6997421215c32d4176c Mon Sep 17 00:00:00 2001 From: Grzegorz Ziolkowski Date: Mon, 23 Nov 2015 07:36:25 +0100 Subject: [PATCH 6/6] Purchases: Revert isCancelable flag for single purchase --- client/lib/purchases/assembler.js | 1 + 1 file changed, 1 insertion(+) diff --git a/client/lib/purchases/assembler.js b/client/lib/purchases/assembler.js index 04131dca00ce0a..5902b12a6f2549 100644 --- a/client/lib/purchases/assembler.js +++ b/client/lib/purchases/assembler.js @@ -32,6 +32,7 @@ function createPurchasesArray( dataTransferObject ) { expiryStatus: camelCase( purchase.expiry_status ), hasPrivateRegistration: Boolean( purchase.has_private_registration ), includedDomain: purchase.included_domain, + isCancelable: Boolean( purchase.is_cancelable ), isDomainRegistration: Boolean( purchase.is_domain_registration ), isRedeemable: Boolean( purchase.is_redeemable ), isRefundable: Boolean( purchase.is_refundable ),