Skip to content

Commit

Permalink
Added direct links for monthly/yearly checkout
Browse files Browse the repository at this point in the history
refs #12365

Currently, while its possible to open Stripe checkout directly on a monthly/yearly plan, Portal links don't allow similar feature. This change allows opening a site on a specific Portal link that can directly open Stripe checkout for monthly/yearly plan, if the plan is allowed.

- Adds handling for new portal signup link for monthly plan - `/#/portal/signup?plan=monthly`
- Adds handling for new portal signup link for yearly plan - `/#/portal/signup?plan=yearly`
  • Loading branch information
rishabhgrg committed Nov 17, 2020
1 parent a665ca5 commit bbea4f7
Show file tree
Hide file tree
Showing 4 changed files with 32 additions and 5 deletions.
9 changes: 6 additions & 3 deletions ghost/portal/src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -96,12 +96,13 @@ export default class App extends React.Component {
async initSetup() {
try {
// Fetch data from API, links, preview, dev sources
const {site, member, page, showPopup, popupNotification, lastPage} = await this.fetchData();
const {site, member, page, showPopup, popupNotification, lastPage, pageQuery} = await this.fetchData();
this.setState({
site,
member,
page,
lastPage,
pageQuery,
showPopup,
popupNotification,
action: 'init:success',
Expand Down Expand Up @@ -222,7 +223,7 @@ export default class App extends React.Component {

/** Fetch state from Portal Links */
fetchLinkData() {
const [path] = window.location.hash.substr(1).split('?');
const [path, pathQuery] = window.location.hash.substr(1).split('?');
const linkRegex = /^\/portal(?:\/(\w+(?:\/\w+)?))?$/;
if (path && linkRegex.test(path)) {
const [,pagePath] = path.match(linkRegex);
Expand All @@ -231,6 +232,7 @@ export default class App extends React.Component {
return {
showPopup: true,
...(page ? {page} : {}),
...(pathQuery ? {pageQuery: pathQuery} : {}),
...(lastPage ? {lastPage} : {})
};
}
Expand Down Expand Up @@ -375,14 +377,15 @@ export default class App extends React.Component {

/**Get final App level context from data/state*/
getContextFromState() {
const {site, member, action, page, lastPage, showPopup, popupNotification} = this.state;
const {site, member, action, page, lastPage, showPopup, pageQuery, popupNotification} = this.state;
const contextPage = this.getContextPage({page, member});
const contextMember = this.getContextMember({page: contextPage, member});
return {
site,
action,
brandColor: this.getAccentColor(),
page: contextPage,
pageQuery,
member: contextMember,
lastPage,
showPopup,
Expand Down
1 change: 1 addition & 0 deletions ghost/portal/src/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ function closePopup({state}) {
return {
showPopup: false,
lastPage: null,
pageQuery: '',
popupNotification: null,
page: state.page === 'magiclink' ? '' : state.page
};
Expand Down
8 changes: 6 additions & 2 deletions ghost/portal/src/components/pages/SignupPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import PlansSection from '../common/PlansSection';
import InputForm from '../common/InputForm';
import {ValidateInputForm} from '../../utils/form';
import CalculateDiscount from '../../utils/discount';
import {getSitePlans, hasOnlyFreePlan} from '../../utils/helpers';
import {capitalize, getSitePlans, hasOnlyFreePlan, hasPlan} from '../../utils/helpers';
import {ReactComponent as InvitationIcon} from '../../images/icons/invitation.svg';

const React = require('react');
Expand Down Expand Up @@ -149,7 +149,7 @@ class SignupPage extends React.Component {
}

componentDidMount() {
const {member} = this.context;
const {member, site, pageQuery = ''} = this.context;
if (member) {
this.context.onAction('switchPage', {
page: 'accountHome'
Expand All @@ -158,6 +158,10 @@ class SignupPage extends React.Component {

// Handle the default plan if not set
const plans = this.getPlans();
const queryPlan = pageQuery ? (new URLSearchParams(pageQuery)).get('plan') : '';
if (['monthly', 'yearly'].includes(queryPlan) && hasPlan({site, plan: queryPlan})) {
this.context.onAction('signup', {plan: capitalize(queryPlan)});
}
const selectedPlan = this.state.plan;
const defaultSelectedPlan = this.getDefaultSelectedPlan(plans, this.state.plan);
if (defaultSelectedPlan !== selectedPlan) {
Expand Down
19 changes: 19 additions & 0 deletions ghost/portal/src/utils/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,25 @@ export function hasOnlyFreePlan({site = {}}) {
return !plans || plans.length === 0 || (plans.length === 1 && plans[0].type === 'free');
}

export function hasPlan({site = {}, plan}) {
const plans = getSitePlans({site});
if (plan === 'free') {
return !plans || plans.length === 0 || plans.find(p => p.type === 'free');
} else if (plan === 'monthly') {
return plans && plans.length > 0 && plans.find(p => p.type === 'month');
} else if (plan === 'yearly') {
return plans && plans.length > 0 && plans.find(p => p.type === 'year');
}
return false;
}

export function capitalize(str) {
if (typeof str !== 'string' || !str) {
return '';
}
return str.charAt(0).toUpperCase() + str.slice(1);
}

export function getSitePlans({site = {}, includeFree = true}) {
const {
plans,
Expand Down

0 comments on commit bbea4f7

Please sign in to comment.