From 5c7e90bfb559dc85c037636d684c39d80fa6461c Mon Sep 17 00:00:00 2001 From: Martin Bedouret Date: Fri, 21 Apr 2023 23:21:36 -0300 Subject: [PATCH 1/6] initial commit --- .../Settings/Subscribe/Subscribe.component.js | 9 +- .../Settings/Subscribe/Subscribe.container.js | 200 +++++++++++------- .../Settings/Subscribe/SubscriptionPlans.js | 106 +++++++--- src/index.js | 38 ++-- .../SubscriptionProvider.container.js | 50 ++--- 5 files changed, 262 insertions(+), 141 deletions(-) diff --git a/src/components/Settings/Subscribe/Subscribe.component.js b/src/components/Settings/Subscribe/Subscribe.component.js index 1d852d835..cf67d293b 100644 --- a/src/components/Settings/Subscribe/Subscribe.component.js +++ b/src/components/Settings/Subscribe/Subscribe.component.js @@ -26,7 +26,8 @@ const propTypes = { /** * Handle refresh subscription */ - onRefreshSubscription: PropTypes.func + onRefreshSubscription: PropTypes.func, + onSubscribeCancel: PropTypes.func }; const defaultProps = { @@ -39,7 +40,9 @@ const Subscribe = ({ onSubscribe, location: { country, countryCode }, subscription, - onRefreshSubscription + onRefreshSubscription, + onSubscribeCancel, + onPaypalApprove }) => { return (
@@ -55,6 +58,8 @@ const Subscribe = ({ onRefreshSubscription={onRefreshSubscription} isLogged={isLogged} onSubscribe={onSubscribe} + onSubscribeCancel={onSubscribeCancel} + onPaypalApprove={onPaypalApprove} /> ) : ( diff --git a/src/components/Settings/Subscribe/Subscribe.container.js b/src/components/Settings/Subscribe/Subscribe.container.js index cc5d4c2df..d13220768 100644 --- a/src/components/Settings/Subscribe/Subscribe.container.js +++ b/src/components/Settings/Subscribe/Subscribe.container.js @@ -76,7 +76,56 @@ export class SubscribeContainer extends PureComponent { }, 3000); }; - handleSubscribe = product => async event => { + handleSubscribeCancel = () => { + const { updateSubscription } = this.props; + updateSubscription({ + isSubscribed: false, + expiryDate: null, + androidSubscriptionState: NOT_SUBSCRIBED, + ownedProduct: '' + }); + }; + + handlePaypalApprove = async (product, data) => { + const { updateSubscription } = this.props; + const { + facilitatorAccessToken, + orderID, + paymentSource, + subscriptionID + } = data; + const transaction = { + className: 'Transaction', + subscriptionID, + transactionId: subscriptionID, + state: 'approved', + products: [product], + platform: paymentSource, + nativePurchase: '', + purchaseId: orderID, + purchaseDate: '', + isPending: false, + subscriptionState: ACTIVE, + expiryDate: '', + facilitatorAccessToken + }; + try { + const res = await API.postTransaction(transaction); + if (!res.ok) throw res; + updateSubscription({ + ownedProduct: product, + androidSubscriptionState: ACTIVE, + isInFreeCountry: false, + isOnTrialPeriod: false, + isSubscribed: true + }); + } catch (err) { + console.error('Cannot subscribe product. Error: ', err.message); + this.handleError(err); + } + }; + + handleSubscribe = async product => { const { intl, user, @@ -86,40 +135,39 @@ export class SubscribeContainer extends PureComponent { updateSubscription, subscription } = this.props; - if (isAndroid()) { - if ( - (isLogged && - product && - subscription.androidSubscriptionState === NOT_SUBSCRIBED) || - subscription.androidSubscriptionState === EXPIRED - ) { - const newProduct = { - title: formatTitle(product.title), - billingPeriod: product.billingPeriod, - price: product.price, - tag: product.tag, - subscriptionId: product.subscriptionId - }; - const apiProduct = { - product: { - ...newProduct - } - }; + if ( + (isLogged && + product && + subscription.androidSubscriptionState === NOT_SUBSCRIBED) || + subscription.androidSubscriptionState === EXPIRED + ) { + const newProduct = { + title: formatTitle(product.title), + billingPeriod: product.billingPeriod, + price: product.price, + tag: product.tag, + subscriptionId: product.subscriptionId + }; + const apiProduct = { + product: { + ...newProduct + } + }; - updateSubscription({ - isSubscribed: false, - expiryDate: null, - androidSubscriptionState: PROCCESING, - ownedProduct: '' - }); + updateSubscription({ + isSubscribed: false, + expiryDate: null, + androidSubscriptionState: PROCCESING, + ownedProduct: '' + }); + let localReceipts = ''; + let offers, offer; + if (isAndroid()) { const prod = await window.CdvPurchase.store.products[0]; - const localReceipts = window.CdvPurchase.store.findInLocalReceipts( - prod - ); + localReceipts = window.CdvPurchase.store.findInLocalReceipts(prod); // get offer from the plugin - let offers, offer; try { await window.CdvPurchase.store.update(); offers = prod.offers; @@ -129,27 +177,29 @@ export class SubscribeContainer extends PureComponent { this.handleError(err); return; } + } - try { - // update the api - const subscriber = await API.getSubscriber(user.id); - updateSubscriberId(subscriber._id); + try { + // update the api + const subscriber = await API.getSubscriber(user.id); + updateSubscriberId(subscriber._id); - // check if current subscriber already bought in this device - if ( - localReceipts && - localReceipts.nativePurchase?.orderId !== - subscriber.transaction?.transactionId - ) { - this.handleError({ - code: '0001', - message: intl.formatMessage(messages.googleAccountAlreadyOwns) - }); - return; - } - await API.updateSubscriber(apiProduct); + // check if current subscriber already bought in this device + if ( + localReceipts && + localReceipts.nativePurchase?.orderId !== + subscriber.transaction?.transactionId + ) { + this.handleError({ + code: '0001', + message: intl.formatMessage(messages.googleAccountAlreadyOwns) + }); + return; + } + await API.updateSubscriber(apiProduct); - // proceed with the purchase + // proceed with the purchase + if (isAndroid()) { const order = await window.CdvPurchase.store.order(offer); if (order && order.isError) throw order; updateSubscription({ @@ -159,25 +209,27 @@ export class SubscribeContainer extends PureComponent { isOnTrialPeriod: false, isSubscribed: true }); - } catch (err) { - if (err.response?.data.error === 'subscriber not found') { - // check if current subscriber already bought in this device - if (localReceipts) { - this.handleError({ - code: '0001', - message: intl.formatMessage(messages.googleAccountAlreadyOwns) - }); - return; - } - try { - const newSubscriber = { - userId: user.id, - country: location.countryCode || 'Not localized', - status: NOT_SUBSCRIBED, - ...apiProduct - }; - const res = await API.createSubscriber(newSubscriber); - updateSubscriberId(res._id); + } + } catch (err) { + if (err.response?.data.error === 'subscriber not found') { + // check if current subscriber already bought in this device + if (localReceipts) { + this.handleError({ + code: '0001', + message: intl.formatMessage(messages.googleAccountAlreadyOwns) + }); + return; + } + try { + const newSubscriber = { + userId: user.id, + country: location.countryCode || 'Not localized', + status: NOT_SUBSCRIBED, + ...apiProduct + }; + const res = await API.createSubscriber(newSubscriber); + updateSubscriberId(res._id); + if (isAndroid()) { const order = await window.CdvPurchase.store.order(offer); if (order && order.isError) throw order; updateSubscription({ @@ -187,15 +239,15 @@ export class SubscribeContainer extends PureComponent { isOnTrialPeriod: false, isSubscribed: true }); - } catch (err) { - console.error('Cannot subscribe product. Error: ', err.message); - this.handleError(err); } - return; + } catch (err) { + console.error('Cannot subscribe product. Error: ', err.message); + this.handleError(err); } - console.error('Cannot subscribe product. Error: ', err.message); - this.handleError(err); + return; } + console.error('Cannot subscribe product. Error: ', err.message); + this.handleError(err); } } }; @@ -212,6 +264,8 @@ export class SubscribeContainer extends PureComponent { subscription={this.props.subscription} updateSubscriberId={this.props.updateSubscriberId} onRefreshSubscription={this.handleRefreshSubscription} + onSubscribeCancel={this.handleSubscribeCancel} + onPaypalApprove={this.handlePaypalApprove} /> ); } diff --git a/src/components/Settings/Subscribe/SubscriptionPlans.js b/src/components/Settings/Subscribe/SubscriptionPlans.js index e5e2dd256..3168c2058 100644 --- a/src/components/Settings/Subscribe/SubscriptionPlans.js +++ b/src/components/Settings/Subscribe/SubscriptionPlans.js @@ -7,6 +7,7 @@ import Typography from '@material-ui/core/Typography'; import PropTypes from 'prop-types'; import { makeStyles } from '@material-ui/core/styles'; import { FormattedMessage } from 'react-intl'; +import { PayPalButtons } from '@paypal/react-paypal-js'; import { INCLUDED_FEATURES, @@ -42,7 +43,9 @@ const propTypes = { subscription: PropTypes.object.isRequired, onRefreshSubscription: PropTypes.func.isRequired, isLogged: PropTypes.bool.isRequired, - onSubscribe: PropTypes.func.isRequired + onSubscribe: PropTypes.func.isRequired, + onSubscribeCancel: PropTypes.func.isRequired, + onPaypalApprove: PropTypes.func.isRequired }; const useStyles = makeStyles({ @@ -63,7 +66,9 @@ const SubscriptionPlans = ({ subscription, onRefreshSubscription, isLogged, - onSubscribe + onSubscribe, + onSubscribeCancel, + onPaypalApprove }) => { const { androidSubscriptionState, @@ -80,19 +85,16 @@ const SubscriptionPlans = ({ ); const subscriptionStatus = (function() { - if (isAndroid()) { - if (error.showError) return ERROR; - if ( - isOnTrialPeriod && - !isSubscribed && - androidSubscriptionState !== PROCCESING - ) - return ON_TRIAL_PERIOD; - if (products.length || androidSubscriptionState !== NOT_SUBSCRIBED) - return androidSubscriptionState || NOT_SUBSCRIBED; - return EMPTY_PRODUCT; - } - return NOT_SUBSCRIBED; + if (error.showError) return ERROR; + if ( + isOnTrialPeriod && + !isSubscribed && + androidSubscriptionState !== PROCCESING + ) + return ON_TRIAL_PERIOD; + if (products.length || androidSubscriptionState !== NOT_SUBSCRIBED) + return androidSubscriptionState || NOT_SUBSCRIBED; + return EMPTY_PRODUCT; })(); const alertProps = { @@ -110,6 +112,32 @@ const SubscriptionPlans = ({ expired: 'warning' //TODO }; + const paypalButtonsStyle = { + layout: 'horizontal', + color: 'blue', + shape: 'rect', + label: 'subscribe', + tagline: false + }; + + const onPaypalAction = (action, product, data = '') => { + if (action === 'onClick') { + console.log('onClick'); + console.log(data); + onSubscribe(product, data); + } + if (action === 'onCancel' || action === 'onError') { + console.log('onCancel'); + console.log(data); + onSubscribeCancel(product, data); + } + if (action === 'onApprove') { + console.log('onApprove'); + console.log(data); + onPaypalApprove(product, data); + } + }; + const fallbabackMessage = { id: 'cboard.components.Settings.Subscribe.fallback', defaultMessage: 'Wait please...' @@ -194,17 +222,43 @@ const SubscriptionPlans = ({ /{formatDuration(product.billingPeriod)} - + {isAndroid() && ( + + )} + {!isAndroid() && ( + { + return actions.subscription.create({ + plan_id: 'P-0V7548454K917654WMRBA3XY' + }); + }} + onClick={function(data, actions) { + onPaypalAction('onClick', product); + }} + onApprove={function(data, actions) { + onPaypalAction('onApprove', product, data); + }} + onCancel={function(data, actions) { + onPaypalAction('onCancel', product, data); + }} + onError={function(data, actions) { + onPaypalAction('onError', product, data); + }} + /> + )}

diff --git a/src/index.js b/src/index.js index e6fc82311..0fec39013 100644 --- a/src/index.js +++ b/src/index.js @@ -6,6 +6,7 @@ import { BrowserRouter, HashRouter, Route } from 'react-router-dom'; import { TouchBackend } from 'react-dnd-touch-backend'; import { DndProvider } from 'react-dnd'; import { PersistGate } from 'redux-persist/es/integration/react'; +import { PayPalScriptProvider } from '@paypal/react-paypal-js'; import App from './components/App'; import { isCordova, onCordovaReady, initCordovaPlugins } from './cordova-util'; @@ -56,6 +57,15 @@ const dndOptions = { // When running in Cordova, must use the HashRouter const PlatformRouter = isCordova() ? HashRouter : BrowserRouter; +// PayPal configuration +const paypalOptions = { + 'client-id': + 'AZ2vK0luRWMX9zzwLs-Ko_B_TJxeHYvIFCgXWcNBt50wmj7oZcUw8n4cf11GgdClTVnYMuEs5vRnxVEk', + currency: 'USD', + vault: true, + intent: 'subscription' +}; + const renderApp = () => { if (isCordova()) { initCordovaPlugins(); @@ -63,19 +73,21 @@ const renderApp = () => { ReactDOM.render( - - - - - - - - - - - - - + + + + + + + + + + + + + + + , document.getElementById('root') diff --git a/src/providers/SubscriptionProvider/SubscriptionProvider.container.js b/src/providers/SubscriptionProvider/SubscriptionProvider.container.js index 09d9f47f8..af0818e21 100644 --- a/src/providers/SubscriptionProvider/SubscriptionProvider.container.js +++ b/src/providers/SubscriptionProvider/SubscriptionProvider.container.js @@ -38,40 +38,36 @@ export class SubscriptionProvider extends Component { updatePlans } = this.props; - if (isAndroid()) { + const isSubscribed = await updateIsSubscribed(); + const isInFreeCountry = updateIsInFreeCountry(); + const isOnTrialPeriod = updateIsOnTrialPeriod(); + await updatePlans(); + if (isAndroid()) this.configInAppPurchasePlugin(); + onAndroidResume(async () => { + await updateIsSubscribed(); + updateIsInFreeCountry(); + updateIsOnTrialPeriod(); + }); + if (!isInFreeCountry && !isOnTrialPeriod && !isSubscribed && isLogged) { + showPremiumRequired({ showTryPeriodFinishedMessages: true }); + } + } + + componentDidUpdate = async prevProps => { + const { + isLogged, + updateIsSubscribed, + updateIsInFreeCountry, + updateIsOnTrialPeriod + } = this.props; + if (prevProps.isLogged !== isLogged) { const isSubscribed = await updateIsSubscribed(); const isInFreeCountry = updateIsInFreeCountry(); const isOnTrialPeriod = updateIsOnTrialPeriod(); - await updatePlans(); - this.configInAppPurchasePlugin(); - onAndroidResume(async () => { - await updateIsSubscribed(); - updateIsInFreeCountry(); - updateIsOnTrialPeriod(); - }); if (!isInFreeCountry && !isOnTrialPeriod && !isSubscribed && isLogged) { showPremiumRequired({ showTryPeriodFinishedMessages: true }); } } - } - - componentDidUpdate = async prevProps => { - if (isAndroid()) { - const { - isLogged, - updateIsSubscribed, - updateIsInFreeCountry, - updateIsOnTrialPeriod - } = this.props; - if (prevProps.isLogged !== isLogged) { - const isSubscribed = await updateIsSubscribed(); - const isInFreeCountry = updateIsInFreeCountry(); - const isOnTrialPeriod = updateIsOnTrialPeriod(); - if (!isInFreeCountry && !isOnTrialPeriod && !isSubscribed && isLogged) { - showPremiumRequired({ showTryPeriodFinishedMessages: true }); - } - } - } }; configPurchaseValidator = () => { From b6e8ea72248336e16d5351db6a973c20ff975fe2 Mon Sep 17 00:00:00 2001 From: Martin Bedouret Date: Sun, 23 Apr 2023 18:40:20 -0300 Subject: [PATCH 2/6] wip --- package.json | 1 + src/components/Settings/Settings.component.js | 2 +- .../Settings/Subscribe/Subscribe.container.js | 6 ++++-- .../Settings/Subscribe/SubscriptionPlans.js | 6 ++++-- .../SubscriptionProvider.actions.js | 11 ++++++++++- 5 files changed, 20 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index 6c52aed99..ac618252c 100644 --- a/package.json +++ b/package.json @@ -24,6 +24,7 @@ "@material-ui/icons": "^4.11.3", "@material-ui/lab": "4.0.0-alpha.57", "@microsoft/applicationinsights-web": "^2.8.11", + "@paypal/react-paypal-js": "^7.8.3", "@redux-beacon/google-analytics-gtag": "^1.1.0", "@redux-beacon/logger": "^1.0.0", "@redux-beacon/offline-web": "^1.0.0", diff --git a/src/components/Settings/Settings.component.js b/src/components/Settings/Settings.component.js index 50dc9c1cd..1fae0ce6c 100644 --- a/src/components/Settings/Settings.component.js +++ b/src/components/Settings/Settings.component.js @@ -98,7 +98,7 @@ export class Settings extends PureComponent { } ]; - if (isAndroid() && !isInFreeCountry) { + if (!isInFreeCountry) { const subscribeSection = { icon: , text: messages.subscribe, diff --git a/src/components/Settings/Subscribe/Subscribe.container.js b/src/components/Settings/Subscribe/Subscribe.container.js index d13220768..b69f650f5 100644 --- a/src/components/Settings/Subscribe/Subscribe.container.js +++ b/src/components/Settings/Subscribe/Subscribe.container.js @@ -96,7 +96,7 @@ export class SubscribeContainer extends PureComponent { } = data; const transaction = { className: 'Transaction', - subscriptionID, + subscriptionId: subscriptionID, transactionId: subscriptionID, state: 'approved', products: [product], @@ -112,12 +112,14 @@ export class SubscribeContainer extends PureComponent { try { const res = await API.postTransaction(transaction); if (!res.ok) throw res; + const subscriber = await API.getSubscriber(); updateSubscription({ ownedProduct: product, androidSubscriptionState: ACTIVE, isInFreeCountry: false, isOnTrialPeriod: false, - isSubscribed: true + isSubscribed: true, + expiryDate: subscriber.transaction.expiryDate }); } catch (err) { console.error('Cannot subscribe product. Error: ', err.message); diff --git a/src/components/Settings/Subscribe/SubscriptionPlans.js b/src/components/Settings/Subscribe/SubscriptionPlans.js index 3168c2058..1205ac187 100644 --- a/src/components/Settings/Subscribe/SubscriptionPlans.js +++ b/src/components/Settings/Subscribe/SubscriptionPlans.js @@ -133,7 +133,6 @@ const SubscriptionPlans = ({ } if (action === 'onApprove') { console.log('onApprove'); - console.log(data); onPaypalApprove(product, data); } }; @@ -246,9 +245,12 @@ const SubscriptionPlans = ({ }); }} onClick={function(data, actions) { - onPaypalAction('onClick', product); + onPaypalAction('onClick', product, data); }} onApprove={function(data, actions) { + // actions.subscription.get().then(details=>{ + // console.log(details); + // }); onPaypalAction('onApprove', product, data); }} onCancel={function(data, actions) { diff --git a/src/providers/SubscriptionProvider/SubscriptionProvider.actions.js b/src/providers/SubscriptionProvider/SubscriptionProvider.actions.js index 13e7a36ee..9d835c9cf 100644 --- a/src/providers/SubscriptionProvider/SubscriptionProvider.actions.js +++ b/src/providers/SubscriptionProvider/SubscriptionProvider.actions.js @@ -72,7 +72,9 @@ export function updateIsSubscribed() { ); } else { const userId = state.app.userData.id; - const { status, product } = await API.getSubscriber(userId); + const { status, product, transaction } = await API.getSubscriber( + userId + ); isSubscribed = status.toLowerCase() === ACTIVE || status.toLowerCase() === CANCELED || @@ -89,6 +91,13 @@ export function updateIsSubscribed() { title: product.title }; } + if (transaction && transaction.expiryDate) { + dispatch( + updateSubscription({ + expiryDate: transaction.expiryDate + }) + ); + } dispatch( updateSubscription({ ownedProduct, From 35514696eac2c75f64f39b768bb6ac7c21a8514c Mon Sep 17 00:00:00 2001 From: Martin Bedouret Date: Mon, 24 Apr 2023 01:43:20 -0300 Subject: [PATCH 3/6] wip --- .../Settings/Subscribe/Subscribe.component.js | 11 +++++--- .../Settings/Subscribe/Subscribe.container.js | 3 +++ .../Settings/Subscribe/Subscribe.messages.js | 4 +++ .../Settings/Subscribe/SubscriptionInfo.js | 25 +++++++++++++++---- .../SubscriptionProvider.actions.js | 20 ++++++++++----- .../SubscriptionProvider.constants.js | 1 + 6 files changed, 50 insertions(+), 14 deletions(-) diff --git a/src/components/Settings/Subscribe/Subscribe.component.js b/src/components/Settings/Subscribe/Subscribe.component.js index cf67d293b..fe4c254ec 100644 --- a/src/components/Settings/Subscribe/Subscribe.component.js +++ b/src/components/Settings/Subscribe/Subscribe.component.js @@ -27,7 +27,8 @@ const propTypes = { * Handle refresh subscription */ onRefreshSubscription: PropTypes.func, - onSubscribeCancel: PropTypes.func + onSubscribeCancel: PropTypes.func.isRequired, + onCancelSubscription: PropTypes.func.isRequired }; const defaultProps = { @@ -42,7 +43,8 @@ const Subscribe = ({ subscription, onRefreshSubscription, onSubscribeCancel, - onPaypalApprove + onPaypalApprove, + onCancelSubscription }) => { return (
@@ -62,7 +64,10 @@ const Subscribe = ({ onPaypalApprove={onPaypalApprove} /> ) : ( - + )}
diff --git a/src/components/Settings/Subscribe/Subscribe.container.js b/src/components/Settings/Subscribe/Subscribe.container.js index b69f650f5..1e3cbcf19 100644 --- a/src/components/Settings/Subscribe/Subscribe.container.js +++ b/src/components/Settings/Subscribe/Subscribe.container.js @@ -52,6 +52,8 @@ export class SubscribeContainer extends PureComponent { updatePlans(); }; + handleCancelSubscription = () => {}; + handleError = e => { const { updateSubscriptionError, updateSubscription } = this.props; @@ -268,6 +270,7 @@ export class SubscribeContainer extends PureComponent { onRefreshSubscription={this.handleRefreshSubscription} onSubscribeCancel={this.handleSubscribeCancel} onPaypalApprove={this.handlePaypalApprove} + onCancelSubscription={this.handleCancelSubscription} /> ); } diff --git a/src/components/Settings/Subscribe/Subscribe.messages.js b/src/components/Settings/Subscribe/Subscribe.messages.js index f7db0a44e..ee8d105c0 100644 --- a/src/components/Settings/Subscribe/Subscribe.messages.js +++ b/src/components/Settings/Subscribe/Subscribe.messages.js @@ -115,6 +115,10 @@ export default defineMessages({ id: 'cboard.components.Settings.Subscribe.manageSubscription', defaultMessage: 'Manage Subscription' }, + cancelSubscription: { + id: 'cboard.components.Settings.Subscribe.cancelSubscription', + defaultMessage: 'Cancel Subscription' + }, planAmount: { id: 'cboard.components.Settings.Subscribe.planAmount', defaultMessage: 'Plan amount:' diff --git a/src/components/Settings/Subscribe/SubscriptionInfo.js b/src/components/Settings/Subscribe/SubscriptionInfo.js index b6e40354e..3a02815c5 100644 --- a/src/components/Settings/Subscribe/SubscriptionInfo.js +++ b/src/components/Settings/Subscribe/SubscriptionInfo.js @@ -16,18 +16,21 @@ import { formatDuration } from './Subscribe.helpers'; import { ACTIVE, CANCELED, + CANCELLED, IN_GRACE_PERIOD } from '../../../providers/SubscriptionProvider/SubscriptionProvider.constants'; import RefreshIcon from '@material-ui/icons/Refresh'; import IconButton from '../../UI/IconButton'; +import { isAndroid } from '../../../cordova-util'; const propTypes = { ownedProduct: PropTypes.object.isRequired, expiryDate: PropTypes.string.isRequired, androidSubscriptionState: PropTypes.string.isRequired, onRefreshSubscription: PropTypes.func.isRequired, - intl: PropTypes.object.isRequired + intl: PropTypes.object.isRequired, + onCancelSubscription: PropTypes.func.isRequired }; const LABEL = 0; @@ -38,7 +41,8 @@ const subscriptionInfo = ({ expiryDate, androidSubscriptionState, onRefreshSubscription, - intl + intl, + onCancelSubscription }) => { const { title, billingPeriod, price } = ownedProduct; @@ -56,7 +60,11 @@ const subscriptionInfo = ({ const getPaymentLabel = () => { if (androidSubscriptionState === ACTIVE) return 'nextPayment'; if (androidSubscriptionState === IN_GRACE_PERIOD) return 'fixPaymentIssue'; - if (androidSubscriptionState === CANCELED) return 'premiumWillEnd'; + if ( + androidSubscriptionState === CANCELED || + androidSubscriptionState === CANCELLED + ) + return 'premiumWillEnd'; }; const subscription = { @@ -114,11 +122,18 @@ const subscriptionInfo = ({ fullWidth={false} color="primary" onClick={() => { - window.CdvPurchase.store.manageSubscriptions(); + isAndroid() + ? window.CdvPurchase.store.manageSubscriptions() + : onCancelSubscription(ownedProduct); }} style={{ marginLeft: '1em' }} > - + {' '} + {isAndroid() ? ( + + ) : ( + + )}
diff --git a/src/providers/SubscriptionProvider/SubscriptionProvider.actions.js b/src/providers/SubscriptionProvider/SubscriptionProvider.actions.js index 9d835c9cf..34387bbd0 100644 --- a/src/providers/SubscriptionProvider/SubscriptionProvider.actions.js +++ b/src/providers/SubscriptionProvider/SubscriptionProvider.actions.js @@ -8,6 +8,7 @@ import { REQUIRING_PREMIUM_COUNTRIES, ACTIVE, CANCELED, + CANCELLED, IN_GRACE_PERIOD } from './SubscriptionProvider.constants'; import API from '../../api'; @@ -78,6 +79,7 @@ export function updateIsSubscribed() { isSubscribed = status.toLowerCase() === ACTIVE || status.toLowerCase() === CANCELED || + status.toLowerCase() === CANCELLED || status.toLowerCase() === IN_GRACE_PERIOD ? true : false; @@ -108,12 +110,18 @@ export function updateIsSubscribed() { } } catch (err) { console.error(err.message); - isSubscribed = false; - dispatch( - updateSubscription({ - isSubscribed - }) - ); + if (err.response?.data.error === 'subscriber not found') { + let isSubscribed = false; + let ownedProduct = ''; + let androidSubscriptionState = NOT_SUBSCRIBED; + dispatch( + updateSubscription({ + ownedProduct, + androidSubscriptionState, + isSubscribed + }) + ); + } } return isSubscribed; }; diff --git a/src/providers/SubscriptionProvider/SubscriptionProvider.constants.js b/src/providers/SubscriptionProvider/SubscriptionProvider.constants.js index 860672022..3138f3f19 100644 --- a/src/providers/SubscriptionProvider/SubscriptionProvider.constants.js +++ b/src/providers/SubscriptionProvider/SubscriptionProvider.constants.js @@ -11,6 +11,7 @@ export const NOT_SUBSCRIBED = 'not_subscribed'; export const PROCCESING = 'proccesing'; export const ACTIVE = 'active'; export const CANCELED = 'canceled'; +export const CANCELLED = 'cancelled'; export const IN_GRACE_PERIOD = 'in_grace_period'; export const PAUSED = 'paused'; export const EXPIRED = 'expired'; From 44b88da99f8b32079c7a0392e5d5f7b4e3ba38c0 Mon Sep 17 00:00:00 2001 From: Martin Bedouret Date: Mon, 24 Apr 2023 16:30:54 -0300 Subject: [PATCH 4/6] initial version --- .../Settings/Subscribe/Subscribe.container.js | 19 ++++++------- .../Settings/Subscribe/SubscriptionInfo.js | 22 ++++++--------- .../Settings/Subscribe/SubscriptionPlans.js | 28 +++++++++++-------- .../SubscriptionProvider.actions.js | 13 +++++---- .../SubscriptionProvider.container.js | 8 +++--- .../SubscriptionProvider.reducer.js | 4 +-- 6 files changed, 47 insertions(+), 47 deletions(-) diff --git a/src/components/Settings/Subscribe/Subscribe.container.js b/src/components/Settings/Subscribe/Subscribe.container.js index 1e3cbcf19..6da680bd8 100644 --- a/src/components/Settings/Subscribe/Subscribe.container.js +++ b/src/components/Settings/Subscribe/Subscribe.container.js @@ -47,7 +47,6 @@ export class SubscribeContainer extends PureComponent { handleRefreshSubscription = () => { const { updateIsSubscribed, updatePlans } = this.props; - //window.CdvPurchase.store.restorePurchases(); updateIsSubscribed(); updatePlans(); }; @@ -66,7 +65,7 @@ export class SubscribeContainer extends PureComponent { updateSubscription({ isSubscribed: false, expiryDate: null, - androidSubscriptionState: NOT_SUBSCRIBED + status: NOT_SUBSCRIBED }); setTimeout(() => { @@ -83,7 +82,7 @@ export class SubscribeContainer extends PureComponent { updateSubscription({ isSubscribed: false, expiryDate: null, - androidSubscriptionState: NOT_SUBSCRIBED, + status: NOT_SUBSCRIBED, ownedProduct: '' }); }; @@ -117,7 +116,7 @@ export class SubscribeContainer extends PureComponent { const subscriber = await API.getSubscriber(); updateSubscription({ ownedProduct: product, - androidSubscriptionState: ACTIVE, + status: ACTIVE, isInFreeCountry: false, isOnTrialPeriod: false, isSubscribed: true, @@ -140,10 +139,8 @@ export class SubscribeContainer extends PureComponent { subscription } = this.props; if ( - (isLogged && - product && - subscription.androidSubscriptionState === NOT_SUBSCRIBED) || - subscription.androidSubscriptionState === EXPIRED + (isLogged && product && subscription.status === NOT_SUBSCRIBED) || + subscription.status === EXPIRED ) { const newProduct = { title: formatTitle(product.title), @@ -161,7 +158,7 @@ export class SubscribeContainer extends PureComponent { updateSubscription({ isSubscribed: false, expiryDate: null, - androidSubscriptionState: PROCCESING, + status: PROCCESING, ownedProduct: '' }); @@ -208,7 +205,7 @@ export class SubscribeContainer extends PureComponent { if (order && order.isError) throw order; updateSubscription({ ownedProduct: product, - androidSubscriptionState: ACTIVE, + status: ACTIVE, isInFreeCountry: false, isOnTrialPeriod: false, isSubscribed: true @@ -238,7 +235,7 @@ export class SubscribeContainer extends PureComponent { if (order && order.isError) throw order; updateSubscription({ ownedProduct: product, - androidSubscriptionState: ACTIVE, + status: ACTIVE, isInFreeCountry: false, isOnTrialPeriod: false, isSubscribed: true diff --git a/src/components/Settings/Subscribe/SubscriptionInfo.js b/src/components/Settings/Subscribe/SubscriptionInfo.js index 3a02815c5..1ce4fb43c 100644 --- a/src/components/Settings/Subscribe/SubscriptionInfo.js +++ b/src/components/Settings/Subscribe/SubscriptionInfo.js @@ -27,7 +27,7 @@ import { isAndroid } from '../../../cordova-util'; const propTypes = { ownedProduct: PropTypes.object.isRequired, expiryDate: PropTypes.string.isRequired, - androidSubscriptionState: PropTypes.string.isRequired, + status: PropTypes.string.isRequired, onRefreshSubscription: PropTypes.func.isRequired, intl: PropTypes.object.isRequired, onCancelSubscription: PropTypes.func.isRequired @@ -39,7 +39,7 @@ const VALUE = 1; const subscriptionInfo = ({ ownedProduct, expiryDate, - androidSubscriptionState, + status, onRefreshSubscription, intl, onCancelSubscription @@ -53,23 +53,19 @@ const subscriptionInfo = ({ const formatedDate = new Date(expiryDate).toLocaleString(); const statusColor = - androidSubscriptionState === ACTIVE + status === ACTIVE ? { backgroundColor: 'green' } : { backgroundColor: 'darkorange' }; const getPaymentLabel = () => { - if (androidSubscriptionState === ACTIVE) return 'nextPayment'; - if (androidSubscriptionState === IN_GRACE_PERIOD) return 'fixPaymentIssue'; - if ( - androidSubscriptionState === CANCELED || - androidSubscriptionState === CANCELLED - ) - return 'premiumWillEnd'; + if (status === ACTIVE) return 'nextPayment'; + if (status === IN_GRACE_PERIOD) return 'fixPaymentIssue'; + if (status === CANCELED || status === CANCELLED) return 'premiumWillEnd'; }; const subscription = { title, - status: androidSubscriptionState, + status: status, planAmount, paymentLabel: formatedDate }; @@ -143,11 +139,11 @@ const subscriptionInfo = ({ subscriptionInfo.propTypes = propTypes; const mapStateToProps = ({ - subscription: { ownedProduct, expiryDate, androidSubscriptionState } + subscription: { ownedProduct, expiryDate, status } }) => ({ ownedProduct, expiryDate, - androidSubscriptionState + status }); const mapDispatchToProps = {}; diff --git a/src/components/Settings/Subscribe/SubscriptionPlans.js b/src/components/Settings/Subscribe/SubscriptionPlans.js index 1205ac187..5daf9c5c1 100644 --- a/src/components/Settings/Subscribe/SubscriptionPlans.js +++ b/src/components/Settings/Subscribe/SubscriptionPlans.js @@ -71,7 +71,7 @@ const SubscriptionPlans = ({ onPaypalApprove }) => { const { - androidSubscriptionState, + status, expiryDate, error, isOnTrialPeriod, @@ -79,21 +79,27 @@ const SubscriptionPlans = ({ products } = subscription; + let plans = []; + console.log(products); + if (!isAndroid() && products) { + products.forEach(product => { + if (product.paypalId) plans.push(product); + }); + } else { + plans = products; + } + const classes = useStyles(); const canPurchase = [NOT_SUBSCRIBED, EXPIRED, ON_HOLD].includes( - subscription.androidSubscriptionState + subscription.status ); const subscriptionStatus = (function() { if (error.showError) return ERROR; - if ( - isOnTrialPeriod && - !isSubscribed && - androidSubscriptionState !== PROCCESING - ) + if (isOnTrialPeriod && !isSubscribed && status !== PROCCESING) return ON_TRIAL_PERIOD; - if (products.length || androidSubscriptionState !== NOT_SUBSCRIBED) - return androidSubscriptionState || NOT_SUBSCRIBED; + if (products.length || status !== NOT_SUBSCRIBED) + return status || NOT_SUBSCRIBED; return EMPTY_PRODUCT; })(); @@ -184,7 +190,7 @@ const SubscriptionPlans = ({ alignItems="center" justifyContent="space-around" > - {products.map(product => { + {plans.map(product => { return [ { return actions.subscription.create({ - plan_id: 'P-0V7548454K917654WMRBA3XY' + plan_id: product.paypalId }); }} onClick={function(data, actions) { diff --git a/src/providers/SubscriptionProvider/SubscriptionProvider.actions.js b/src/providers/SubscriptionProvider/SubscriptionProvider.actions.js index 34387bbd0..9f0fc232a 100644 --- a/src/providers/SubscriptionProvider/SubscriptionProvider.actions.js +++ b/src/providers/SubscriptionProvider/SubscriptionProvider.actions.js @@ -60,14 +60,14 @@ export function updateIsSubscribed() { return async (dispatch, getState) => { let isSubscribed = false; let ownedProduct = ''; - let androidSubscriptionState = NOT_SUBSCRIBED; + let status = NOT_SUBSCRIBED; try { const state = getState(); if (!isLogged(state)) { dispatch( updateSubscription({ ownedProduct, - androidSubscriptionState, + status, isSubscribed }) ); @@ -103,7 +103,7 @@ export function updateIsSubscribed() { dispatch( updateSubscription({ ownedProduct, - androidSubscriptionState: status.toLowerCase(), + status: status.toLowerCase(), isSubscribed }) ); @@ -113,11 +113,11 @@ export function updateIsSubscribed() { if (err.response?.data.error === 'subscriber not found') { let isSubscribed = false; let ownedProduct = ''; - let androidSubscriptionState = NOT_SUBSCRIBED; + let status = NOT_SUBSCRIBED; dispatch( updateSubscription({ ownedProduct, - androidSubscriptionState, + status, isSubscribed }) ); @@ -144,7 +144,8 @@ export function updatePlans() { billingPeriod: plan.period, price: getPrice(plan.countries, locationCode), title: plan.subscriptionName, - tag: plan.tags[0] + tag: plan.tags[0], + paypalId: plan.paypalId }; return result; }); diff --git a/src/providers/SubscriptionProvider/SubscriptionProvider.container.js b/src/providers/SubscriptionProvider/SubscriptionProvider.container.js index af0818e21..996be5c6e 100644 --- a/src/providers/SubscriptionProvider/SubscriptionProvider.container.js +++ b/src/providers/SubscriptionProvider/SubscriptionProvider.container.js @@ -112,18 +112,18 @@ export class SubscriptionProvider extends Component { }; configInAppPurchasePlugin = () => { - const { updateSubscription, androidSubscriptionState } = this.props; + const { updateSubscription, status } = this.props; this.configPurchaseValidator(); window.CdvPurchase.store .when() .productUpdated(product => { - if (androidSubscriptionState === PROCCESING) { + if (status === PROCCESING) { updateSubscription({ isSubscribed: false, expiryDate: null, - androidSubscriptionState: NOT_SUBSCRIBED + status: NOT_SUBSCRIBED }); } }) @@ -155,7 +155,7 @@ const mapStateToProps = state => ({ isInFreeCountry: state.subscription.isInFreeCountry, isSubscribed: state.subscription.isSubscribed, expiryDate: state.subscription.expiryDate, - androidSubscriptionState: state.subscription.androidSubscriptionState, + status: state.subscription.status, isOnTrialPeriod: state.subscription.isOnTrialPeriod, isLogged: isLogged(state), subscriberId: state.subscription.subscriberId diff --git a/src/providers/SubscriptionProvider/SubscriptionProvider.reducer.js b/src/providers/SubscriptionProvider/SubscriptionProvider.reducer.js index b6b9f208e..530cf88fa 100644 --- a/src/providers/SubscriptionProvider/SubscriptionProvider.reducer.js +++ b/src/providers/SubscriptionProvider/SubscriptionProvider.reducer.js @@ -13,7 +13,7 @@ import { const initialState = { subscriberId: '', - androidSubscriptionState: NOT_SUBSCRIBED, + status: NOT_SUBSCRIBED, isSubscribed: false, expiryDate: null, error: { @@ -73,7 +73,7 @@ function subscriptionProviderReducer(state = initialState, action) { return { ...state, subscriberId: id, - androidSubscriptionState: status, + status: status, expiryDate: expiry }; case LOGOUT: From 9a87a38d73ea6d2b49cdb719394248d193092383 Mon Sep 17 00:00:00 2001 From: Martin Bedouret Date: Tue, 25 Apr 2023 15:21:28 -0300 Subject: [PATCH 5/6] wip --- src/api/api.js | 18 ++++ src/components/Settings/Settings.component.js | 4 +- .../Settings/Subscribe/Subscribe.container.js | 12 ++- .../Settings/Subscribe/Subscribe.messages.js | 8 ++ .../Settings/Subscribe/SubscriptionInfo.js | 84 +++++++++++++++---- .../Settings/Subscribe/SubscriptionPlans.js | 4 +- .../SubscriptionProvider.actions.js | 3 +- 7 files changed, 109 insertions(+), 24 deletions(-) diff --git a/src/api/api.js b/src/api/api.js index 300d8dcc4..c4906ab24 100644 --- a/src/api/api.js +++ b/src/api/api.js @@ -531,6 +531,24 @@ class API { return data; } + async cancelPlan(subscriptionId = '') { + const authToken = getAuthToken(); + if (!(authToken && authToken.length)) { + throw new Error('Need to be authenticated to perform this request'); + } + const data = { reason: 'User cancelled the subscription' }; + + const headers = { + Authorization: `Bearer ${authToken}` + }; + const res = await this.axiosInstance.post( + `/subscriber/cancel/${subscriptionId}`, + { data }, + { headers } + ); + return res; + } + async postTransaction(transaction = {}) { const authToken = getAuthToken(); if (!(authToken && authToken.length)) { diff --git a/src/components/Settings/Settings.component.js b/src/components/Settings/Settings.component.js index 1fae0ce6c..e40874616 100644 --- a/src/components/Settings/Settings.component.js +++ b/src/components/Settings/Settings.component.js @@ -25,7 +25,7 @@ import Paper from '@material-ui/core/Paper'; import UserIcon from '../UI/UserIcon'; import SettingsTour from './SettingsTour.component'; -import { isCordova, isAndroid } from '../../cordova-util'; +import { isCordova, isAndroid, isElectron, isIOS } from '../../cordova-util'; import './Settings.css'; import { CircularProgress } from '@material-ui/core'; @@ -98,7 +98,7 @@ export class Settings extends PureComponent { } ]; - if (!isInFreeCountry) { + if (!isIOS() && !isElectron() && !isInFreeCountry) { const subscribeSection = { icon: , text: messages.subscribe, diff --git a/src/components/Settings/Subscribe/Subscribe.container.js b/src/components/Settings/Subscribe/Subscribe.container.js index 6da680bd8..68790aa99 100644 --- a/src/components/Settings/Subscribe/Subscribe.container.js +++ b/src/components/Settings/Subscribe/Subscribe.container.js @@ -51,7 +51,17 @@ export class SubscribeContainer extends PureComponent { updatePlans(); }; - handleCancelSubscription = () => {}; + handleCancelSubscription = async ownedProduct => { + console.log(ownedProduct); + const { updateIsSubscribed, updatePlans } = this.props; + try { + await API.cancelPlan(ownedProduct.paypalSubscriptionId); + updateIsSubscribed(); + updatePlans(); + } catch (err) { + console.error(err.message); + } + }; handleError = e => { const { updateSubscriptionError, updateSubscription } = this.props; diff --git a/src/components/Settings/Subscribe/Subscribe.messages.js b/src/components/Settings/Subscribe/Subscribe.messages.js index ee8d105c0..32352ff72 100644 --- a/src/components/Settings/Subscribe/Subscribe.messages.js +++ b/src/components/Settings/Subscribe/Subscribe.messages.js @@ -147,5 +147,13 @@ export default defineMessages({ id: 'cboard.components.Settings.Subscribe.googleAccountAlreadyOwns', defaultMessage: 'It looks that your Google account already owns this product.' + }, + close: { + id: 'cboard.components.Settings.Subscribe.close', + defaultMessage: 'Close' + }, + cancelSubscriptionDescription: { + id: 'cboard.components.Settings.Subscribe.cancelSubscriptionDescription', + defaultMessage: 'Are you sure you want to cancel your current plan?' } }); diff --git a/src/components/Settings/Subscribe/SubscriptionInfo.js b/src/components/Settings/Subscribe/SubscriptionInfo.js index 1ce4fb43c..c530fb2f3 100644 --- a/src/components/Settings/Subscribe/SubscriptionInfo.js +++ b/src/components/Settings/Subscribe/SubscriptionInfo.js @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { useState } from 'react'; import { connect } from 'react-redux'; import Button from '@material-ui/core/Button'; @@ -12,7 +12,13 @@ import TableBody from '@material-ui/core/TableBody'; import TableCell from '@material-ui/core/TableCell'; import TableRow from '@material-ui/core/TableRow'; import Paper from '@material-ui/core/Paper'; +import Dialog from '@material-ui/core/Dialog'; +import DialogTitle from '@material-ui/core/DialogTitle'; +import DialogContent from '@material-ui/core/DialogContent'; +import DialogContentText from '@material-ui/core/DialogContentText'; +import DialogActions from '@material-ui/core/DialogActions'; import { formatDuration } from './Subscribe.helpers'; +import LoadingIcon from '../../UI/LoadingIcon'; import { ACTIVE, CANCELED, @@ -36,7 +42,7 @@ const propTypes = { const LABEL = 0; const VALUE = 1; -const subscriptionInfo = ({ +const SubscriptionInfo = ({ ownedProduct, expiryDate, status, @@ -44,6 +50,8 @@ const subscriptionInfo = ({ intl, onCancelSubscription }) => { + const [cancelDialog, setCancelDialog] = useState(false); + const [isCanceling, setIsCanceling] = useState(false); const { title, billingPeriod, price } = ownedProduct; const planAmount = `${price?.currencyCode} ${price?.units} / ${formatDuration( @@ -63,6 +71,10 @@ const subscriptionInfo = ({ if (status === CANCELED || status === CANCELLED) return 'premiumWillEnd'; }; + const handleDialogClose = () => { + setCancelDialog(false); + }; + const subscription = { title, status: status, @@ -90,12 +102,20 @@ const subscriptionInfo = ({ {row[LABEL] === 'status' ? ( - } - size="small" - color="primary" - style={statusColor} - /> +
+ } + size="small" + color="primary" + style={statusColor} + /> + + + +
) : ( row[VALUE] )} @@ -107,20 +127,15 @@ const subscriptionInfo = ({
- - - + + + + + + + + + + + + + +
]; }; -subscriptionInfo.propTypes = propTypes; +SubscriptionInfo.propTypes = propTypes; const mapStateToProps = ({ subscription: { ownedProduct, expiryDate, status } @@ -151,4 +199,4 @@ const mapDispatchToProps = {}; export default connect( mapStateToProps, mapDispatchToProps -)(injectIntl(subscriptionInfo)); +)(injectIntl(SubscriptionInfo)); diff --git a/src/components/Settings/Subscribe/SubscriptionPlans.js b/src/components/Settings/Subscribe/SubscriptionPlans.js index 5daf9c5c1..802ca4d07 100644 --- a/src/components/Settings/Subscribe/SubscriptionPlans.js +++ b/src/components/Settings/Subscribe/SubscriptionPlans.js @@ -16,7 +16,7 @@ import { ON_TRIAL_PERIOD } from './Subscribe.constants'; import { formatDuration, formatTitle } from './Subscribe.helpers'; -import { isAndroid } from '../../../cordova-util'; +import { isAndroid, isCordova } from '../../../cordova-util'; import { CircularProgress } from '@material-ui/core'; import { Link } from 'react-router-dom'; @@ -240,7 +240,7 @@ const SubscriptionPlans = ({ )} - {!isAndroid() && ( + {!isCordova() && ( Date: Tue, 25 Apr 2023 19:52:52 -0300 Subject: [PATCH 6/6] initial version --- .../Settings/Subscribe/Subscribe.component.js | 7 +++- .../Settings/Subscribe/Subscribe.container.js | 14 ++++++- .../Settings/Subscribe/Subscribe.messages.js | 9 +++++ .../Settings/Subscribe/SubscriptionInfo.js | 39 ++++++++++++++++--- 4 files changed, 61 insertions(+), 8 deletions(-) diff --git a/src/components/Settings/Subscribe/Subscribe.component.js b/src/components/Settings/Subscribe/Subscribe.component.js index fe4c254ec..1188b7721 100644 --- a/src/components/Settings/Subscribe/Subscribe.component.js +++ b/src/components/Settings/Subscribe/Subscribe.component.js @@ -28,7 +28,8 @@ const propTypes = { */ onRefreshSubscription: PropTypes.func, onSubscribeCancel: PropTypes.func.isRequired, - onCancelSubscription: PropTypes.func.isRequired + onCancelSubscription: PropTypes.func.isRequired, + cancelSubscriptionStatus: PropTypes.string.isRequired }; const defaultProps = { @@ -44,7 +45,8 @@ const Subscribe = ({ onRefreshSubscription, onSubscribeCancel, onPaypalApprove, - onCancelSubscription + onCancelSubscription, + cancelSubscriptionStatus }) => { return (
@@ -67,6 +69,7 @@ const Subscribe = ({ )} diff --git a/src/components/Settings/Subscribe/Subscribe.container.js b/src/components/Settings/Subscribe/Subscribe.container.js index 68790aa99..c86caceec 100644 --- a/src/components/Settings/Subscribe/Subscribe.container.js +++ b/src/components/Settings/Subscribe/Subscribe.container.js @@ -32,6 +32,10 @@ export class SubscribeContainer extends PureComponent { subscription: PropTypes.object.isRequired }; + state = { + cancelSubscriptionStatus: '' + }; + componentDidMount() { const { updateIsSubscribed, updatePlans } = this.props; updateIsSubscribed(); @@ -55,11 +59,14 @@ export class SubscribeContainer extends PureComponent { console.log(ownedProduct); const { updateIsSubscribed, updatePlans } = this.props; try { + this.setState({ cancelSubscriptionStatus: 'cancelling' }); await API.cancelPlan(ownedProduct.paypalSubscriptionId); + this.setState({ cancelSubscriptionStatus: 'ok' }); updateIsSubscribed(); updatePlans(); } catch (err) { console.error(err.message); + this.setState({ cancelSubscriptionStatus: 'error' }); } }; @@ -125,7 +132,11 @@ export class SubscribeContainer extends PureComponent { if (!res.ok) throw res; const subscriber = await API.getSubscriber(); updateSubscription({ - ownedProduct: product, + ownedProduct: { + ...product, + paypalSubscriptionId: subscriptionID, + paypalOrderId: orderID + }, status: ACTIVE, isInFreeCountry: false, isOnTrialPeriod: false, @@ -278,6 +289,7 @@ export class SubscribeContainer extends PureComponent { onSubscribeCancel={this.handleSubscribeCancel} onPaypalApprove={this.handlePaypalApprove} onCancelSubscription={this.handleCancelSubscription} + cancelSubscriptionStatus={this.state.cancelSubscriptionStatus} /> ); } diff --git a/src/components/Settings/Subscribe/Subscribe.messages.js b/src/components/Settings/Subscribe/Subscribe.messages.js index 32352ff72..f78e72681 100644 --- a/src/components/Settings/Subscribe/Subscribe.messages.js +++ b/src/components/Settings/Subscribe/Subscribe.messages.js @@ -155,5 +155,14 @@ export default defineMessages({ cancelSubscriptionDescription: { id: 'cboard.components.Settings.Subscribe.cancelSubscriptionDescription', defaultMessage: 'Are you sure you want to cancel your current plan?' + }, + canceledSubscriptionOk: { + id: 'cboard.components.Settings.Subscribe.canceledSubscriptionOk', + defaultMessage: 'Your subscription was cancelled successfully.' + }, + canceledSubscriptionError: { + id: 'cboard.components.Settings.Subscribe.canceledSubscriptionError', + defaultMessage: + 'There was an error cancelling your subscription, please try again in a moment.' } }); diff --git a/src/components/Settings/Subscribe/SubscriptionInfo.js b/src/components/Settings/Subscribe/SubscriptionInfo.js index c530fb2f3..2d4bcdd70 100644 --- a/src/components/Settings/Subscribe/SubscriptionInfo.js +++ b/src/components/Settings/Subscribe/SubscriptionInfo.js @@ -17,6 +17,7 @@ import DialogTitle from '@material-ui/core/DialogTitle'; import DialogContent from '@material-ui/core/DialogContent'; import DialogContentText from '@material-ui/core/DialogContentText'; import DialogActions from '@material-ui/core/DialogActions'; +import Box from '@material-ui/core/Box'; import { formatDuration } from './Subscribe.helpers'; import LoadingIcon from '../../UI/LoadingIcon'; import { @@ -36,7 +37,8 @@ const propTypes = { status: PropTypes.string.isRequired, onRefreshSubscription: PropTypes.func.isRequired, intl: PropTypes.object.isRequired, - onCancelSubscription: PropTypes.func.isRequired + onCancelSubscription: PropTypes.func.isRequired, + cancelSubscriptionStatus: PropTypes.string.isRequired }; const LABEL = 0; @@ -48,10 +50,10 @@ const SubscriptionInfo = ({ status, onRefreshSubscription, intl, - onCancelSubscription + onCancelSubscription, + cancelSubscriptionStatus }) => { const [cancelDialog, setCancelDialog] = useState(false); - const [isCanceling, setIsCanceling] = useState(false); const { title, billingPeriod, price } = ownedProduct; const planAmount = `${price?.currencyCode} ${price?.units} / ${formatDuration( @@ -169,15 +171,42 @@ const SubscriptionInfo = ({ + {(cancelSubscriptionStatus === 'ok' || + cancelSubscriptionStatus === 'error') && ( + + {cancelSubscriptionStatus === 'ok' && ( + + + + )} + {cancelSubscriptionStatus === 'error' && ( + + + + )} + + )}