@@ -691,13 +693,14 @@ function FreeProductCard() {
{
setSelectedProduct('free');
}} />
- Free
+ {getFreeTierTitle({site})}
$
0
/{selectedInterval}
- Free preview of {(site.title)}
+ {freeProductDescription ? {freeProductDescription}
: ''}
+
>
);
diff --git a/ghost/portal/src/components/pages/SignupPage.js b/ghost/portal/src/components/pages/SignupPage.js
index dee5282cfa..49e2a3161a 100644
--- a/ghost/portal/src/components/pages/SignupPage.js
+++ b/ghost/portal/src/components/pages/SignupPage.js
@@ -5,7 +5,7 @@ import PlansSection, {SingleProductPlansSection} from '../common/PlansSection';
import ProductsSection from '../common/ProductsSection';
import InputForm from '../common/InputForm';
import {ValidateInputForm} from '../../utils/form';
-import {getSiteProducts, getSitePrices, hasMultipleProducts, hasOnlyFreePlan, isInviteOnlySite, getAvailableProducts, hasMultipleProductsFeature} from '../../utils/helpers';
+import {getSiteProducts, getSitePrices, hasMultipleProducts, hasOnlyFreePlan, isInviteOnlySite, getAvailableProducts, hasMultipleProductsFeature, freeHasBenefitsOrDescription} from '../../utils/helpers';
import {ReactComponent as InvitationIcon} from '../../images/icons/invitation.svg';
const React = require('react');
@@ -87,18 +87,6 @@ export const SignupPageStyles = `
height: unset;
}
- /* Needed to cover small horizontal line glitch by the scroll shadow */
- footer.gh-portal-signup-footer::before {
- position: absolute;
- content: "";
- top: -2px;
- left: 0;
- right: 0;
- height: 3px;
- background: #fff;
- z-index: 9999;
- }
-
.gh-portal-content.signup,
.gh-portal-content.signin {
max-height: unset !important;
@@ -231,7 +219,7 @@ export const SignupPageStyles = `
@media (min-width: 480px) and (max-width: 820px) {
.gh-portal-powered.outside {
- left: 50%;
+ left: 50%;
transform: translateX(-50%);
}
@@ -563,7 +551,7 @@ class SignupPage extends React.Component {
if (plansData.length <= 1 || isInviteOnlySite({site})) {
if ((plansData.length === 1 && plansData[0].type === 'free') || isInviteOnlySite({site, pageQuery})) {
- sectionClass = 'noplan';
+ sectionClass = freeHasBenefitsOrDescription({site}) ? 'singleplan' : 'noplan';
if (fields.length === 1) {
sectionClass = 'single-field';
}
diff --git a/ghost/portal/src/utils/fixtures-generator.js b/ghost/portal/src/utils/fixtures-generator.js
new file mode 100644
index 0000000000..49d19be199
--- /dev/null
+++ b/ghost/portal/src/utils/fixtures-generator.js
@@ -0,0 +1,384 @@
+export const sites = {
+ singleProduct: getSiteData({
+ products: getProductsData({numOfProducts: 1})
+ })
+};
+
+export function objectId() {
+ const timestamp = (new Date().getTime() / 1000 | 0).toString(16);
+ return timestamp + 'xxxxxxxxxxxxxxxx'.replace(/[x]/g, function () {
+ return (Math.random() * 16 | 0).toString(16);
+ }).toLowerCase();
+}
+
+export function getSiteData({
+ title = 'The Blueprint',
+ description = 'Thoughts, stories and ideas.',
+ logo = 'https://static.ghost.org/v4.0.0/images/ghost-orb-1.png',
+ icon = 'https://static.ghost.org/v4.0.0/images/ghost-orb-1.png',
+ url = 'https://portal.localhost',
+ plans = {
+ monthly: 5000,
+ yearly: 150000,
+ currency: 'USD'
+ },
+ products = getProductsData({numOfProducts: 1}),
+ portalProducts = products.map(p => p.id),
+ accentColor: accent_color = '#45C32E',
+ portalPlans: portal_plans = ['free', 'monthly', 'yearly'],
+ allowSelfSignup: allow_self_signup = true,
+ membersSignupAccess: members_signup_access = 'all',
+ freePriceName: free_price_name = 'Free',
+ freePriceDescription: free_price_description = 'Free preview',
+ isStripeConfigured: is_stripe_configured = true,
+ portalButton: portal_button = true,
+ portalName: portal_name = true,
+ portalButtonIcon: portal_button_icon = 'icon-1',
+ portalButtonSignupText: portal_button_signup_text = 'Subscribe now',
+ portalButtonStyle: portal_button_style = 'icon-and-text',
+ membersSupportAddress: members_support_address = 'support@example.com'
+} = {}) {
+ return {
+ title,
+ description,
+ logo,
+ icon,
+ accent_color,
+ url,
+ plans,
+ products,
+ portal_products: portalProducts,
+ allow_self_signup,
+ members_signup_access,
+ free_price_name,
+ free_price_description,
+ is_stripe_configured,
+ portal_button,
+ portal_name,
+ portal_plans,
+ portal_button_icon,
+ portal_button_signup_text,
+ portal_button_style,
+ members_support_address
+ };
+}
+
+export function getOfferData({
+ name = 'Black Friday',
+ code = 'black-friday',
+ displayTitle = 'Black Friday',
+ displayDescription = 'Special deal',
+ type = 'percent',
+ cadence = 'month',
+ amount = 50,
+ duration = 'repeating',
+ durationInMonths = null,
+ currencyRestriction = false,
+ currency = null,
+ status = 'active',
+ tierId = '',
+ tierName = 'Basic'
+} = {}) {
+ return {
+ id: `offer_${objectId()}`,
+ name,
+ code,
+ display_title: displayTitle,
+ display_description: displayDescription,
+ type,
+ cadence,
+ amount,
+ duration,
+ duration_in_months: durationInMonths,
+ currency_restriction: currencyRestriction,
+ currency,
+ status,
+ tier: {
+ id: `${tierId}`,
+ name: tierName
+ }
+ };
+}
+
+export function getMemberData({
+ name = 'Jamie Larson',
+ email = 'jamie@example.com',
+ firstname = 'Jamie',
+ subscriptions = [],
+ paid = false,
+ avatarImage: avatar_image = '',
+ subscribed = true
+} = {}) {
+ return {
+ uuid: `member_${objectId()}`,
+ email,
+ name,
+ firstname,
+ paid,
+ subscribed,
+ avatar_image,
+ subscriptions
+ };
+}
+
+export function getProductsData({numOfProducts = 3} = {}) {
+ const products = [
+ getProductData({
+ name: 'Bronze',
+ description: 'Access to all members articles',
+ monthlyPrice: getPriceData({
+ interval: 'month',
+ amount: 700
+ }),
+ yearlyPrice: getPriceData({
+ interval: 'year',
+ amount: 7000
+ }),
+ numOfBenefits: 2
+ }),
+ getProductData({
+ name: 'Silver',
+ description: 'Access to all members articles and weekly podcast',
+ monthlyPrice: getPriceData({
+ interval: 'month',
+ amount: 1200
+ }),
+ yearlyPrice: getPriceData({
+ interval: 'year',
+ amount: 12000
+ }),
+ numOfBenefits: 3
+ }),
+ getProductData({
+ name: 'Friends of the Blueprint',
+ description: 'Get access to everything and lock in early adopter pricing for life + listen to my podcast',
+ monthlyPrice: getPriceData({
+ interval: 'month',
+ amount: 18000
+ }),
+ yearlyPrice: getPriceData({
+ interval: 'year',
+ amount: 17000
+ }),
+ numOfBenefits: 4
+ })
+ ];
+ const paidProducts = products.slice(0, numOfProducts);
+ const freeProduct = getFreeProduct({});
+ return [
+ ...paidProducts,
+ freeProduct
+ ];
+}
+
+export function getProductData({
+ type = 'paid',
+ name = 'Basic',
+ description = '',
+ id = `product_${objectId()}`,
+ monthlyPrice = getPriceData(),
+ yearlyPrice = getPriceData({interval: 'year'}),
+ numOfBenefits = 2
+}) {
+ return {
+ id: id,
+ name: name,
+ description,
+ monthlyPrice: type === 'free' ? null : monthlyPrice,
+ yearlyPrice: type === 'free' ? null : yearlyPrice,
+ type: type,
+ benefits: getBenefits({numOfBenefits})
+ };
+}
+
+export function getFreeProduct({
+ name = 'Free tier',
+ description = 'Free tier description',
+ id = `product_${objectId()}`,
+ numOfBenefits = 2
+}) {
+ return {
+ id,
+ name: name,
+ type: 'free',
+ description,
+ benefits: getBenefits({numOfBenefits})
+ };
+}
+
+export function getBenefits({numOfBenefits}) {
+ const beenfits = [
+ getBenefitData({name: 'Limited early adopter pricing'}),
+ getBenefitData({name: 'Latest gear reviews'}),
+ getBenefitData({name: 'Weekly email newsletter'}),
+ getBenefitData({name: 'Listen to my podcast'})
+ ];
+ return beenfits.slice(0, numOfBenefits);
+}
+
+export function getBenefitData({
+ id = `benefit_${objectId()}`,
+ name = 'Benefit'
+}) {
+ return {
+ id,
+ name
+ };
+}
+
+export function getPriceData({
+ interval = 'month',
+ amount = (interval === 'month' ? 500 : 5000),
+ nickname = interval === 'month' ? 'Monthly' : 'Yearly',
+ description = null,
+ currency = 'usd',
+ active = true,
+ id = `price_${objectId()}`
+} = {}) {
+ return {
+ id: id,
+ active,
+ nickname,
+ currency,
+ amount,
+ interval,
+ description,
+ stripe_price_id: `price_${objectId()}`,
+ stripe_product_id: `prod_${objectId()}`,
+ type: 'recurring'
+ };
+}
+
+export function getSubscriptionData({
+ id = `sub_${objectId()}`,
+ status = 'active',
+ currency = 'USD',
+ interval = 'year',
+ amount = (interval === 'month' ? 500 : 5000),
+ nickname = (interval === 'month' ? 'Monthly' : 'Yearly'),
+ cardLast4 = '4242',
+ priceId: price_id = `price_${objectId()}`,
+ startDate: start_date = '2021-10-05T03:18:30.000Z',
+ currentPeriodEnd: current_period_end = '2022-10-05T03:18:30.000Z',
+ cancelAtPeriodEnd: cancel_at_period_end = false
+} = {}) {
+ return {
+ id,
+ customer: {
+ id: `cus_${objectId()}`,
+ name: 'Jamie',
+ email: 'jamie@example.com'
+ },
+ plan: {
+ id: `price_${objectId()}`,
+ nickname,
+ amount,
+ interval,
+ currency
+ },
+ offer,
+ status,
+ start_date,
+ default_payment_card_last4: cardLast4,
+ cancel_at_period_end,
+ cancellation_reason: null,
+ current_period_end,
+ price: {
+ id: `stripe_price_${objectId()}`,
+ price_id,
+ nickname,
+ amount,
+ interval,
+ type: 'recurring',
+ currency,
+ product: {
+ id: `stripe_prod_${objectId()}`,
+ product_id: `prod_${objectId()}`
+ }
+ }
+ };
+}
+
+export function getTestSite() {
+ const products = getProductsData({numOfProducts: 1});
+ const portalProducts = products.map(p => p.id);
+ const portalPlans = ['free', 'monthly', 'yearly'];
+ return getSiteData({
+ products,
+ portalPlans,
+ portalProducts
+ });
+}
+
+export const testSite = getTestSite();
+
+export const site = getSiteData({
+ products: [getProductData({numOfBenefits: 2, type: 'free'})]
+});
+
+export const offer = getOfferData({
+ tierId: site.products[0]?.id
+});
+
+export const member = {
+ free: getMemberData(),
+ paid: getMemberData({
+ paid: true,
+ subscriptions: [
+ getSubscriptionData()
+ ]
+ }),
+ complimentary: getMemberData({
+ paid: true,
+ subscriptions: []
+ }),
+ complimentaryWithSubscription: getMemberData({
+ paid: true,
+ subscriptions: [
+ getSubscriptionData({
+ amount: 0
+ })
+ ]
+ }),
+ preview: getMemberData({
+ paid: true,
+ subscriptions: [
+ getSubscriptionData({
+ amount: 1500,
+ startDate: '2019-05-01T11:42:40.000Z',
+ currentPeriodEnd: '2021-06-05T11:42:40.000Z'
+ })
+ ]
+ })
+};
+export function generateAccountPlanFixture() {
+ const products = getProductsData({numOfProducts: 3});
+ return {
+ site: getSiteData({
+ portalProducts: [products[1]]
+ }),
+ member: member.paid
+ };
+}
+
+export function basic() {
+ const products = getProductsData();
+ const siteData = getSiteData({
+ products
+ });
+ const defaultMemberPrice = products?.[0].monthlyPrice;
+ const memberData = getMemberData({
+ paid: true,
+ subscriptions: [
+ getSubscriptionData({
+ priceId: defaultMemberPrice.id,
+ amount: defaultMemberPrice.amount,
+ currency: defaultMemberPrice.currency
+ })
+ ]
+ });
+ return {
+ site: siteData,
+ member: memberData
+ };
+}
diff --git a/ghost/portal/src/utils/fixtures.js b/ghost/portal/src/utils/fixtures.js
index e379ff9582..47f3ef166c 100644
--- a/ghost/portal/src/utils/fixtures.js
+++ b/ghost/portal/src/utils/fixtures.js
@@ -1,290 +1,123 @@
-export const sites = {
- singleProduct: getSiteData({
- products: getProductsData({numOfProducts: 1})
- })
-};
-
-function objectId() {
- const timestamp = (new Date().getTime() / 1000 | 0).toString(16);
- return timestamp + 'xxxxxxxxxxxxxxxx'.replace(/[x]/g, function () {
- return (Math.random() * 16 | 0).toString(16);
- }).toLowerCase();
-}
-
-export function getSiteData({
- products = getProductsData({numOfProducts: 1}),
- portalProducts = products.map(p => p.id),
- portalPlans: portal_plans = ['free', 'monthly', 'yearly']
-} = {}) {
- return {
- title: 'The Blueprint',
- description: 'Thoughts, stories and ideas.',
- logo: 'https://static.ghost.org/v4.0.0/images/ghost-orb-1.png',
- icon: 'https://static.ghost.org/v4.0.0/images/ghost-orb-1.png',
- accent_color: '#45C32E',
- url: 'https://portal.localhost',
- plans: {
- monthly: 5000,
- yearly: 150000,
- currency: 'USD'
- },
- products,
- portal_products: portalProducts,
- allow_self_signup: true,
- members_signup_access: 'all',
- free_price_name: 'Free',
- free_price_description: 'Free preview',
- is_stripe_configured: true,
- portal_button: true,
- portal_name: true,
- portal_plans,
- portal_button_icon: 'icon-1',
- portal_button_signup_text: 'Subscribe now',
- portal_button_style: 'icon-and-text',
- members_support_address: 'support@example.com'
- };
-}
-
-function getOfferData({
- name = 'Black Friday',
- code = 'black-friday',
- displayTitle = 'Black Friday',
- displayDescription = 'Special deal',
- type = 'percent',
- cadence = 'month',
- amount = 50,
- duration = 'repeating',
- durationInMonths = null,
- currencyRestriction = false,
- currency = null,
- status = 'active',
- tierId = ''
-} = {}) {
- return {
- id: `offer_${objectId()}`,
- name,
- code,
- display_title: displayTitle,
- display_description: displayDescription,
- type,
- cadence,
- amount,
- duration,
- duration_in_months: durationInMonths,
- currency_restriction: currencyRestriction,
- currency,
- status,
- tier: {
- id: `${tierId}`,
- name: 'Basic'
- }
- };
-}
-
-function getMemberData({
- name = 'Jamie Larson',
- email = 'jamie@example.com',
- firstname = 'Jamie',
- subscriptions = [],
- paid = false,
- avatarImage: avatar_image = '',
- subscribed = true
-} = {}) {
- return {
- uuid: `member_${objectId()}`,
- email,
- name,
- firstname,
- paid,
- subscribed,
- avatar_image,
- subscriptions
- };
-}
-
-export function getProductsData({numOfProducts = 3} = {}) {
- const products = [
- getProductData({
- name: 'Bronze',
- description: 'Access to all members articles',
- monthlyPrice: getPriceData({
- interval: 'month',
- amount: 700
- }),
- yearlyPrice: getPriceData({
- interval: 'year',
- amount: 7000
- }),
- numOfBenefits: 2
- }),
- getProductData({
- name: 'Silver',
- description: 'Access to all members articles and weekly podcast',
- monthlyPrice: getPriceData({
- interval: 'month',
- amount: 1200
- }),
- yearlyPrice: getPriceData({
- interval: 'year',
- amount: 12000
- }),
- numOfBenefits: 3
- }),
- getProductData({
- name: 'Friends of the Blueprint',
- description: 'Get access to everything and lock in early adopter pricing for life + listen to my podcast',
- monthlyPrice: getPriceData({
- interval: 'month',
- amount: 18000
- }),
- yearlyPrice: getPriceData({
- interval: 'year',
- amount: 17000
- }),
- numOfBenefits: 4
- })
- ];
- return products.slice(0, numOfProducts);
-}
-
-function getProductData({
- name = 'Basic',
- description = '',
- id = `product_${objectId()}`,
- monthlyPrice = getPriceData(),
- yearlyPrice = getPriceData({interval: 'year'}),
- numOfBenefits = 2
-}) {
- return {
- id: id,
- name: name,
- description,
- monthlyPrice,
- yearlyPrice,
- benefits: getBenefits({numOfBenefits})
- };
-}
-
-function getBenefits({numOfBenefits}) {
- const beenfits = [
- getBenefitData({name: 'Limited early adopter pricing'}),
- getBenefitData({name: 'Latest gear reviews'}),
- getBenefitData({name: 'Weekly email newsletter'}),
- getBenefitData({name: 'Listen to my podcast'})
- ];
- return beenfits.slice(0, numOfBenefits);
-}
-
-function getBenefitData({
- id = `benefit_${objectId()}`,
- name = 'Benefit'
-}) {
- return {
- id,
- name
- };
-}
-
-function getPriceData({
- interval = 'month',
- amount = (interval === 'month' ? 500 : 5000),
- nickname = interval === 'month' ? 'Monthly' : 'Yearly',
- description = null,
- currency = 'usd',
- active = true,
- id = `price_${objectId()}`
-}) {
- return {
- id: id,
- active,
- nickname,
- currency,
- amount,
- interval,
- description,
- stripe_price_id: `price_${objectId()}`,
- stripe_product_id: `prod_${objectId()}`,
- type: 'recurring'
- };
-}
-
-function getSubscriptionData({
- id = `sub_${objectId()}`,
- status = 'active',
- currency = 'USD',
- interval = 'year',
- amount = (interval === 'month' ? 500 : 5000),
- nickname = (interval === 'month' ? 'Monthly' : 'Yearly'),
- cardLast4 = '4242',
- priceId: price_id = `price_${objectId()}`,
- startDate: start_date = '2021-10-05T03:18:30.000Z',
- currentPeriodEnd: current_period_end = '2022-10-05T03:18:30.000Z',
- cancelAtPeriodEnd: cancel_at_period_end = false
-} = {}) {
- return {
- id,
- customer: {
- id: `cus_${objectId()}`,
- name: 'Jamie',
- email: 'jamie@example.com'
- },
- plan: {
- id: `price_${objectId()}`,
- nickname,
- amount,
- interval,
- currency
- },
- offer,
- status,
- start_date,
- default_payment_card_last4: cardLast4,
- cancel_at_period_end,
- cancellation_reason: null,
- current_period_end,
- price: {
- id: `stripe_price_${objectId()}`,
- price_id,
- nickname,
- amount,
- interval,
- type: 'recurring',
- currency,
- product: {
- id: `stripe_prod_${objectId()}`,
- product_id: `prod_${objectId()}`
- }
- }
- };
-}
-
-function getTestSite() {
- const products = getProductsData({numOfProducts: 1});
- const portalProducts = products.map(p => p.id);
- const portalPlans = ['free', 'monthly', 'yearly'];
- return getSiteData({
- products,
- portalPlans,
- portalProducts
- });
-}
+/* eslint-disable no-unused-vars*/
+import {getFreeProduct, getMemberData, getOfferData, getPriceData, getProductData, getSiteData, getSubscriptionData, getTestSite} from './fixtures-generator';
export const testSite = getTestSite();
+const products = [
+ getFreeProduct({
+ name: 'Free',
+ // description: 'Free tier description which is actually a pretty long description',
+ description: '',
+ numOfBenefits: 0
+ })
+ ,
+ getProductData({
+ name: 'Bronze',
+ // description: 'Access to all members articles',
+ description: '',
+ monthlyPrice: getPriceData({
+ interval: 'month',
+ amount: 700
+ }),
+ yearlyPrice: getPriceData({
+ interval: 'year',
+ amount: 7000
+ }),
+ numOfBenefits: 2
+ })
+ // ,
+ // getProductData({
+ // name: 'Silver',
+ // description: 'Access to all members articles and weekly podcast',
+ // monthlyPrice: getPriceData({
+ // interval: 'month',
+ // amount: 1200
+ // }),
+ // yearlyPrice: getPriceData({
+ // interval: 'year',
+ // amount: 12000
+ // }),
+ // numOfBenefits: 3
+ // })
+ // ,
+ // getProductData({
+ // name: 'Friends of the Blueprint',
+ // description: 'Get access to everything and lock in early adopter pricing for life + listen to my podcast',
+ // monthlyPrice: getPriceData({
+ // interval: 'month',
+ // amount: 18000
+ // }),
+ // yearlyPrice: getPriceData({
+ // interval: 'year',
+ // amount: 17000
+ // }),
+ // numOfBenefits: 4
+ // })
+];
+
export const site = getSiteData({
- products: getProductsData({numOfProducts: 1})
+ title: 'The Blueprint',
+ description: 'Thoughts, stories and ideas.',
+ logo: 'https://static.ghost.org/v4.0.0/images/ghost-orb-1.png',
+ icon: 'https://static.ghost.org/v4.0.0/images/ghost-orb-1.png',
+ accentColor: '#45C32E',
+ url: 'https://portal.localhost',
+ plans: {
+ monthly: 5000,
+ yearly: 150000,
+ currency: 'USD'
+ },
+
+ // Simulate pre-multiple-tiers state:
+ // products: [products.find(d => d.type === 'paid')],
+ // portalProducts: null,
+
+ // Simulate multiple-tiers state:
+ products,
+ portalProducts: products.map(p => p.id),
+
+ //
+ allowSelfSignup: true,
+ membersSignupAccess: 'all',
+ freePriceName: 'Free',
+ freePriceDescription: 'Free preview',
+ isStripeConfigured: true,
+ portalButton: true,
+ portalName: true,
+ portalPlans: ['free', 'monthly', 'yearly'],
+ portalButtonIcon: 'icon-1',
+ portalButtonSignupText: 'Subscribe now',
+ portalButtonStyle: 'icon-and-text',
+ membersSupportAddress: 'support@example.com'
});
export const offer = getOfferData({
- tierId: site.products[0].id
+ tierId: site.products[0]?.id
});
export const member = {
- free: getMemberData(),
+ free: getMemberData({
+ name: 'Jamie Larson',
+ email: 'jamie@example.com',
+ firstname: 'Jamie',
+ subscriptions: [],
+ paid: false,
+ avatarImage: '',
+ subscribed: true
+ }),
paid: getMemberData({
paid: true,
subscriptions: [
- getSubscriptionData()
+ getSubscriptionData({
+ status: 'active',
+ currency: 'USD',
+ interval: 'year',
+ amount: 5000,
+ cardLast4: '4242',
+ startDate: '2021-10-05T03:18:30.000Z',
+ currentPeriodEnd: '2022-10-05T03:18:30.000Z',
+ cancelAtPeriodEnd: false
+ })
]
}),
complimentary: getMemberData({
@@ -310,34 +143,4 @@ export const member = {
]
})
};
-export function generateAccountPlanFixture() {
- const products = getProductsData({numOfProducts: 3});
- return {
- site: getSiteData({
- portalProducts: [products[1]]
- }),
- member: member.paid
- };
-}
-
-export function basic() {
- const products = getProductsData();
- const siteData = getSiteData({
- products
- });
- const defaultMemberPrice = products?.[0].monthlyPrice;
- const memberData = getMemberData({
- paid: true,
- subscriptions: [
- getSubscriptionData({
- priceId: defaultMemberPrice.id,
- amount: defaultMemberPrice.amount,
- currency: defaultMemberPrice.currency
- })
- ]
- });
- return {
- site: siteData,
- member: memberData
- };
-}
+/* eslint-enable no-unused-vars*/
diff --git a/ghost/portal/src/utils/helpers.js b/ghost/portal/src/utils/helpers.js
index da97f01d38..e0e24dd453 100644
--- a/ghost/portal/src/utils/helpers.js
+++ b/ghost/portal/src/utils/helpers.js
@@ -1,5 +1,3 @@
-// import calculateDiscount from './discount';
-
export function removePortalLinkFromUrl() {
const [path] = window.location.hash.substr(1).split('?');
const linkRegex = /^\/portal\/?(?:\/(\w+(?:\/\w+)*))?\/?$/;
@@ -215,6 +213,11 @@ export function getAvailableProducts({site}) {
});
}
+export function getFreeProduct({site}) {
+ const {products = []} = site || {};
+ return products.find(product => product.type === 'free');
+}
+
export function getAllProductsForSite({site}) {
const {products = [], portal_plans: portalPlans = []} = site || {};
@@ -263,10 +266,27 @@ export function getSiteProducts({site}) {
return products;
}
-export function getFreeBenefits() {
- return [{
- name: 'Access to free articles'
- }];
+export function getFreeProductBenefits({site}) {
+ const freeProduct = getFreeProduct({site});
+ return freeProduct?.benefits || [];
+}
+
+export function getFreeTierTitle({site}) {
+ return 'Free';
+}
+
+export function getFreeTierDescription({site}) {
+ const freeProduct = getFreeProduct({site});
+ return freeProduct?.description;
+}
+
+export function freeHasBenefitsOrDescription({site}) {
+ const freeProduct = getFreeProduct({site});
+
+ if (freeProduct?.description || freeProduct?.benefits?.length) {
+ return true;
+ }
+ return false;
}
export function getProductBenefits({product, site = null}) {
@@ -274,14 +294,6 @@ export function getProductBenefits({product, site = null}) {
const productBenefits = product?.benefits || [];
const monthlyBenefits = productBenefits;
const yearlyBenefits = productBenefits;
- // const availablePrices = getAvailablePrices({site, products: [product]});
- // const yearlyDiscount = calculateDiscount(product.monthlyPrice.amount, product.yearlyPrice.amount);
- // if (yearlyDiscount > 0 && availablePrices.length > 1) {
- // yearlyBenefits.push({
- // name: `${yearlyDiscount}% annual discount`,
- // className: `gh-portal-strong`
- // });
- // }
return {
monthly: monthlyBenefits,
yearly: yearlyBenefits
@@ -319,6 +331,9 @@ export function hasFreeProductPrice({site}) {
}
export function getProductFromPrice({site, priceId}) {
+ if (priceId === 'free') {
+ return getFreeProduct({site});
+ }
const products = getAllProductsForSite({site});
return products.find((product) => {
return (product?.monthlyPrice?.id === priceId) || (product?.yearlyPrice?.id === priceId);
@@ -396,7 +411,7 @@ export function getSitePrices({site = {}, pageQuery = ''} = {}) {
type: 'free',
price: 0,
amount: 0,
- name: 'Free',
+ name: getFreeTierTitle({site}),
...freePriceCurrencyDetail
});
diff --git a/ghost/portal/yarn.lock b/ghost/portal/yarn.lock
index 7d30a8e082..f8a9222153 100644
--- a/ghost/portal/yarn.lock
+++ b/ghost/portal/yarn.lock
@@ -9463,10 +9463,10 @@ react-dom@17.0.2:
object-assign "^4.1.1"
scheduler "^0.20.2"
-react-error-overlay@^6.0.9:
- version "6.0.10"
- resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-6.0.10.tgz#0fe26db4fa85d9dbb8624729580e90e7159a59a6"
- integrity sha512-mKR90fX7Pm5seCOfz8q9F+66VCc1PGsWSBxKbITjfKVQHMNF2zudxHnMdJiB1fRCb+XsbQV9sO9DCkgsMQgBIA==
+react-error-overlay@6.0.9, react-error-overlay@^6.0.9:
+ version "6.0.9"
+ resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-6.0.9.tgz#3c743010c9359608c375ecd6bc76f35d93995b0a"
+ integrity sha512-nQTTcUu+ATDbrSD1BZHr5kgSD4oF8OFjxun8uAaL8RwPBacGBNPf/yAuVVdx17N8XNzRDMrZ9XcKZHCjPW+9ew==
react-is@^16.13.1, react-is@^16.7.0:
version "16.13.1"