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

Handled custom prices query in links/attributes

refs https://github.com/TryGhost/Team/issues/643

Previously, Portal only worked with hardcoded `Monthly` and `Yearly` plans as those were the only possible prices available to members. With custom prices and products, Portal is now expanded to work with any number of custom prices as well as allow links/attributes for them to work via IDs.

Also, to continue backwards compatibility with Monthly/Yearly, Portal will support their data attributes/links, finding the first relevant Monthly/Yearly plan by nickname, falling back on interval if needed.
This commit is contained in:
Rishabh 2021-05-07 22:24:36 +05:30 committed by Rishabh Garg
parent 811067b7a7
commit 815e00c761
3 changed files with 72 additions and 4 deletions

View file

@ -9,7 +9,7 @@ import * as Fixtures from './utils/fixtures';
import ActionHandler from './actions';
import './App.css';
import NotificationParser from './utils/notifications';
import {createPopupNotification, getCurrencySymbol, getFirstpromoterId, getSiteDomain, hasPrice, isComplimentaryMember, removePortalLinkFromUrl} from './utils/helpers';
import {createPopupNotification, getAvailablePrices, getCurrencySymbol, getFirstpromoterId, getQueryPrice, getSiteDomain, isComplimentaryMember, removePortalLinkFromUrl} from './utils/helpers';
const React = require('react');
const DEV_MODE_DATA = {
@ -440,10 +440,12 @@ export default class App extends React.Component {
/** Handle direct signup link for a price */
handleSignupQuery({site, pageQuery}) {
const queryPrice = hasPrice({site: site, plan: pageQuery});
const queryPrice = getQueryPrice({site: site, priceId: pageQuery});
const availablePrices = getAvailablePrices({site, includeFree: false});
const isQueryPriceAvailable = availablePrices.some(d => d.id === pageQuery);
if (!this.state.member
&& ['monthly', 'yearly'].includes(pageQuery)
&& queryPrice
&& isQueryPriceAvailable
) {
removePortalLinkFromUrl();
this.dispatchAction('signup', {plan: queryPrice.id});
@ -452,10 +454,17 @@ export default class App extends React.Component {
/**Get Portal page from Link/Data-attribute path*/
getPageFromLinkPath(path) {
const customPricesSignupRegex = /^signup\/?(?:\/(\w+?))?\/?$/;
if (path === 'signup') {
return {
page: 'signup'
};
} else if (customPricesSignupRegex.test(path)) {
const [, pageQuery] = path.match(customPricesSignupRegex);
return {
page: 'signup',
pageQuery: pageQuery
};
} else if (path === 'signup/free') {
return {
page: 'signup',

View file

@ -108,7 +108,7 @@ export const site = {
description: 'The default product'
},
prices: prices,
allow_self_signup: false,
allow_self_signup: true,
members_signup_access: 'all',
is_stripe_configured: true,
portal_button: true,

View file

@ -101,10 +101,26 @@ export function hasPrice({site = {}, plan}) {
return prices && prices.length > 0 && prices.find(p => p.name === 'Monthly');
} else if (plan === 'yearly') {
return prices && prices.length > 0 && prices.find(p => p.name === 'Yearly');
} else if (plan) {
return prices && prices.length > 0 && prices.find(p => p.id === plan);
}
return false;
}
export function getQueryPrice({site = {}, priceId}) {
const prices = getAvailablePrices({site});
if (priceId === 'free') {
return !prices || prices.length === 0 || prices.find(p => p.type === 'free');
} else if (priceId === 'monthly') {
return prices && prices.length > 0 && prices.find(p => p.name === 'Monthly');
} else if (priceId === 'yearly') {
return prices && prices.length > 0 && prices.find(p => p.name === 'Yearly');
} else if (priceId) {
return prices && prices.length > 0 && prices.find(p => p.id === priceId);
}
return null;
}
export function getProductDetails({site}) {
if (site && site.product) {
return {
@ -130,6 +146,49 @@ export function isInviteOnlySite({site = {}, pageQuery}) {
return prices.length === 0 || (site && site.members_signup_access === 'invite');
}
export function getAvailablePrices({site = {}, includeFree = true} = {}) {
const {
prices,
allow_self_signup: allowSelfSignup,
is_stripe_configured: isStripeConfigured
} = site || {};
if (!prices) {
return [];
}
const plansData = [];
const stripePrices = prices.map((d) => {
return {
...d,
price_id: d.id,
price: d.amount / 100,
name: d.nickname,
currency_symbol: getCurrencySymbol(d.currency)
};
}).filter((price) => {
return price.amount !== 0 && price.type === 'recurring';
});
if (allowSelfSignup && includeFree) {
plansData.push({
id: 'free',
type: 'free',
price: 0,
currency_symbol: '$',
name: 'Free'
});
}
if (isStripeConfigured) {
stripePrices.forEach((price) => {
plansData.push(price);
});
}
return plansData;
}
export function getSitePrices({site = {}, includeFree = true, pageQuery} = {}) {
const {
prices,