0
Fork 0
mirror of https://github.com/TryGhost/Ghost.git synced 2025-02-17 23:44:39 -05:00

Updated account plan page to include confirmation screen

no issue

Adds confirmation screen on plan change/cancel on the plans screen
This commit is contained in:
Rish 2020-09-15 18:16:38 +05:30
parent 856f56f04e
commit 51382bbee9
3 changed files with 177 additions and 30 deletions

View file

@ -13,7 +13,7 @@ const DEV_MODE_DATA = {
showPopup: true,
site: Fixtures.site,
member: Fixtures.member.paid,
page: 'signup'
page: 'accountPlan'
};
export default class App extends React.Component {
constructor(props) {

View file

@ -3,7 +3,7 @@ import ActionButton from '../common/ActionButton';
import BackButton from '../common/BackButton';
import PlansSection from '../common/PlansSection';
import {getDateString} from '../../utils/date-time';
import {getMemberSubscription, getSitePlans} from '../../utils/helpers';
import {getMemberSubscription, getPlanFromSubscription, getSitePlans, getSubscriptionFromId} from '../../utils/helpers';
export const AccountPlanPageStyles = `
.gh-portal-accountplans-main {
@ -17,6 +17,16 @@ export const AccountPlanPageStyles = `
const React = require('react');
function getConfirmationPageTitle({confirmationType}) {
if (confirmationType === 'changePlan') {
return 'Change plan';
} else if (confirmationType === 'cancel') {
return 'Confirm cancellation';
} else if (confirmationType === 'subscribe') {
return 'Subscribe';
}
}
const GlobalError = ({message, style}) => {
if (!message) {
return null;
@ -30,7 +40,7 @@ const GlobalError = ({message, style}) => {
);
};
export const CancelContinueSubscription = ({member, onAction, action, brandColor, showOnlyContinue = false}) => {
export const CancelContinueSubscription = ({member, onCancelContinueSubscription, onAction, action, brandColor, showOnlyContinue = false}) => {
if (!member.paid) {
return null;
}
@ -65,7 +75,11 @@ export const CancelContinueSubscription = ({member, onAction, action, brandColor
<CancelNotice />
<ActionButton
onClick={(e) => {
onAction('cancelSubscription', {
// onAction('cancelSubscription', {
// subscriptionId: subscription.id,
// cancelAtPeriodEnd: !subscription.cancel_at_period_end
// });
onCancelContinueSubscription({
subscriptionId: subscription.id,
cancelAtPeriodEnd: !subscription.cancel_at_period_end
});
@ -83,8 +97,11 @@ export const CancelContinueSubscription = ({member, onAction, action, brandColor
);
};
const Header = ({member, brandColor, onBack}) => {
const title = member.paid ? 'Choose Plan' : 'Choose your subscription';
const Header = ({member, brandColor, onBack, showConfirmation, confirmationType}) => {
let title = member.paid ? 'Choose Plan' : 'Choose your subscription';
if (showConfirmation) {
title = getConfirmationPageTitle({confirmationType});
}
return (
<header className='gh-portal-detail-header'>
<BackButton brandColor={brandColor} onClick={e => onBack(e)} />
@ -127,11 +144,37 @@ const SubmitButton = ({member, action, plan, brandColor, onPlanCheckout}) => {
);
};
const PlanConfirmation = ({newPlan, onCancelConfirmation, onPlanCheckout}) => {
return `Please confirm your new Plan ${newPlan}`;
const PlanConfirmation = ({plan, type, brandColor, onConfirm}) => {
let actionDescription = '';
let confirmMessage = 'Are you sure ?';
if (type === 'changePlan') {
actionDescription = `You are switching to a ${plan.name} plan with pricing ${plan.currency} ${plan.price} / ${plan.type} `;
} else if (type === 'subscribe') {
actionDescription = `You are subscribing to a ${plan.name} plan with pricing ${plan.currency} ${plan.price} / ${plan.type} `;
} else if (type === 'cancel') {
actionDescription = `You are about to cancel your subscription for ${plan.currency} ${plan.price} ${plan.name} plan`;
}
const label = 'Confirm';
return (
<div>
<div> {actionDescription} </div>
<div> {confirmMessage} </div>
<ActionButton
onClick={e => onConfirm(e, plan)}
isRunning={false}
isPrimary={true}
brandColor={brandColor}
label={label}
style={{
width: '100%',
height: '40px'
}}
/>
</div>
);
};
const PlanChooser = ({plans, selectedPlan, errors, member, onAction, action, brandColor, onPlanSelect}) => {
const PlanChooser = ({plans, selectedPlan, errors, member, onAction, onCancelContinueSubscription, action, brandColor, onPlanSelect}) => {
const {global} = errors || {};
return (
<section>
@ -144,24 +187,25 @@ const PlanChooser = ({plans, selectedPlan, errors, member, onAction, action, bra
/>
<GlobalError message={global} />
</div>
<CancelContinueSubscription {...{member, onAction, action, brandColor}} />
<CancelContinueSubscription {...{member, onCancelContinueSubscription, action, brandColor}} />
</section>
);
};
const PlanMain = ({
plans, selectedPlan, newPlan, errors, member, onAction, action, brandColor,
showConfirmation = false, onPlanSelect, onCancelConfirmation, onPlanCheckout
plans, selectedPlan, confirmationPlan, confirmationType,
errors, member, onAction, action, brandColor,
showConfirmation = false, onPlanSelect, onConfirm, onCancelContinueSubscription
}) => {
if (!showConfirmation) {
return (
<PlanChooser
{...{plans, selectedPlan, errors, member, onAction, action, brandColor, onPlanSelect}}
{...{plans, selectedPlan, errors, member, onAction, onCancelContinueSubscription, action, brandColor, onPlanSelect}}
/>
);
}
return (
<PlanConfirmation {...{newPlan, onCancelConfirmation, onPlanCheckout}}/>
<PlanConfirmation {...{plan: confirmationPlan, type: confirmationType, onConfirm}}/>
);
};
export default class AccountPlanPage extends React.Component {
@ -172,13 +216,16 @@ export default class AccountPlanPage extends React.Component {
const {member} = this.context;
const {site} = this.context;
this.plans = getSitePlans({site});
let activePlan = this.getActivePlanName({member}) || this.plans[0].name;
const activePlanExists = this.plans.some(d => d.name === activePlan);
if (!activePlanExists) {
activePlan = this.plans[0].name;
}
let activePlan = this.getActivePlan({member});
const selectedPlan = activePlan ? this.plans.find((d) => {
return (d.name === activePlan.name && d.price === activePlan.price && d.currency === activePlan.currency);
}) : null;
// const activePlanExists = this.plans.some(d => d.name === activePlan);
// if (!activePlanExists) {
// activePlan = this.plans[0].name;
// }
this.state = {
plan: activePlan
plan: selectedPlan ? selectedPlan.name : null
};
}
@ -188,10 +235,22 @@ export default class AccountPlanPage extends React.Component {
}
onBack(e) {
this.context.onAction('back');
if (this.state.showConfirmation) {
this.cancelConfirmPage();
} else {
this.context.onAction('back');
}
}
onPlanCheckout(e) {
cancelConfirmPage() {
this.setState({
showConfirmation: false,
confirmationPlan: null,
confirmationType: null
});
}
onPlanCheckoutOld(e) {
e.preventDefault();
this.setState((state) => {
const errors = this.validateForm({state});
@ -214,11 +273,31 @@ export default class AccountPlanPage extends React.Component {
});
}
onPlanCheckout(e) {
const {onAction, member} = this.context;
const {confirmationPlan: plan, errors} = this.state;
const hasFormErrors = (errors && Object.values(errors).filter(d => !!d).length > 0);
if (!hasFormErrors) {
if (member.paid) {
const {subscriptions} = member;
const subscriptionId = subscriptions[0].id;
onAction('updateSubscription', {plan: plan.name, subscriptionId});
} else {
onAction('checkoutPlan', {plan: plan.name});
}
}
}
onPlanSelect(e, name) {
const {member} = this.context;
e.preventDefault();
const confirmationPlan = this.plans.find(d => d.name === name);
const activePlan = this.getActivePlanName({member});
const confirmationType = activePlan ? 'changePlan' : 'subscribe';
if (name !== this.state.plan) {
this.setState({
newPlan: name,
confirmationPlan,
confirmationType,
showConfirmation: true
});
}
@ -232,13 +311,49 @@ export default class AccountPlanPage extends React.Component {
// }, 5);
}
onCancelConfirmation() {
this.setState({
newPlan: null,
showConfirmation: false
onCancelContinueSubscription({subscriptionId, cancelAtPeriodEnd}) {
const {member} = this.context;
const subscription = getSubscriptionFromId({subscriptionId, member});
const subscriptionPlan = getPlanFromSubscription({subscription});
if (!cancelAtPeriodEnd) {
this.context.onAction('cancelSubscription', {
subscriptionId,
cancelAtPeriodEnd
});
} else {
this.setState({
showConfirmation: true,
confirmationPlan: subscriptionPlan,
confirmationType: 'cancel'
});
}
}
onCancelSubscriptionConfirmation() {
const {member} = this.context;
const subscription = getMemberSubscription({member});
if (!subscription) {
return null;
}
this.context.onAction('cancelSubscription', {
subscriptionId: subscription.id,
cancelAtPeriodEnd: true
});
}
getActivePlan({member}) {
if (member && member.paid && member.subscriptions[0]) {
const {plan} = member.subscriptions[0];
return {
type: plan.interval,
price: plan.amount / 100,
currency: plan.currency_symbol,
name: plan.nickname
};
}
return null;
}
getActivePlanName({member}) {
if (member && member.paid && member.subscriptions[0]) {
const {plan} = member.subscriptions[0];
@ -263,14 +378,26 @@ export default class AccountPlanPage extends React.Component {
const plans = this.plans;
const selectedPlan = this.state.plan;
const errors = this.state.errors || {};
const {showConfirmation, newPlan} = this.state;
const {showConfirmation, confirmationPlan, confirmationType} = this.state;
let onConfirm = () => {};
if (confirmationType === 'cancel') {
onConfirm = () => this.onCancelSubscriptionConfirmation();
} else if (['changePlan', 'subscribe'].includes(confirmationType)) {
onConfirm = e => this.onPlanCheckout(e);
}
return (
<div>
<div className='gh-portal-content'>
<Header member={member} brandColor={brandColor} onBack={e => this.onBack} />
<Header
member={member} brandColor={brandColor} onBack={e => this.onBack(e)}
confirmationType = {confirmationType}
showConfirmation = {showConfirmation}
/>
<PlanMain
{...this.context}
{...{plans, selectedPlan, showConfirmation, newPlan, errors}}
{...{plans, selectedPlan, showConfirmation, confirmationPlan, confirmationType, onConfirm, errors}}
onCancelSubscriptionConfirmation = {() => this.onCancelSubscriptionConfirmation()}
onCancelContinueSubscription = {data => this.onCancelContinueSubscription(data)}
onPlanSelect = {(e, name) => this.onPlanSelect(e, name)}
/>
</div>

View file

@ -21,6 +21,26 @@ export function isPaidMember({member = {}}) {
return (member && member.paid);
}
export function getPlanFromSubscription({subscription}) {
if (subscription && subscription.plan) {
return {
type: subscription.plan.interval,
price: subscription.plan.amount / 100,
currency: subscription.plan.currency_symbol,
name: subscription.plan.nickname
};
}
return null;
}
export function getSubscriptionFromId({member, subscriptionId}) {
if (member.paid) {
const subscriptions = member.subscriptions || [];
return subscriptions.find(d => d.id === subscriptionId);
}
return null;
}
export function getSitePlans({site = {}}) {
const {plans} = site;
const discount = CalculateDiscount(plans.monthly, plans.yearly);