Cleaned site and product helper usage

no refs

- cleans up helpers for site and products to more consistent and predictable usage
This commit is contained in:
Rishabh 2021-06-23 22:09:14 +05:30
parent c7a3fdc639
commit 21d1c1b9e8
5 changed files with 108 additions and 122 deletions

View File

@ -93,13 +93,12 @@ export default class App extends React.Component {
const target = event.currentTarget;
const pagePath = (target && target.dataset.portal);
const {page, pageQuery} = this.getPageFromLinkPath(pagePath) || {};
if (this.state.initStatus === 'success') {
this.handleSignupQuery({site: this.state.site, pageQuery});
}
if (page) {
this.dispatchAction('openPopup', {page, pageQuery});
if (pageQuery && pageQuery !== 'free') {
this.handleSignupQuery({site: this.state.site, pageQuery});
} else {
this.dispatchAction('openPopup', {page, pageQuery});
}
}
};
const customTriggerSelector = '[data-portal]';
@ -485,11 +484,11 @@ export default class App extends React.Component {
handleSignupQuery({site, pageQuery}) {
const queryPrice = getQueryPrice({site: site, priceId: pageQuery});
if (!this.state.member
&& pageQuery
&& pageQuery !== 'free'
&& queryPrice
) {
removePortalLinkFromUrl();
this.dispatchAction('signup', {plan: queryPrice.id});
this.dispatchAction('signup', {plan: queryPrice?.id || pageQuery});
}
}

View File

@ -1,11 +1,11 @@
import React, {useContext, useEffect, useState} from 'react';
import Switch from '../common/Switch';
import {ReactComponent as CheckmarkIcon} from '../../images/icons/checkmark.svg';
import {getAllProducts, getCurrencySymbol, getPriceString, getStripeAmount, isCookiesDisabled} from '../../utils/helpers';
import {getSiteProducts, getCurrencySymbol, getPriceString, getStripeAmount, isCookiesDisabled} from '../../utils/helpers';
import AppContext from '../../AppContext';
export const ProductsSectionStyles = ({site}) => {
const products = getAllProducts({site});
const products = getSiteProducts({site});
const noOfProducts = products.length;
return `
.gh-portal-products {

View File

@ -3,9 +3,9 @@ import AppContext from '../../AppContext';
import ActionButton from '../common/ActionButton';
import CloseButton from '../common/CloseButton';
import BackButton from '../common/BackButton';
import PlansSection from '../common/PlansSection';
import PlansSection, {MultipleProductsPlansSection} from '../common/PlansSection';
import {getDateString} from '../../utils/date-time';
import {formatNumber, getFilteredPrices, getMemberActivePrice, getMemberSubscription, getPriceFromSubscription, getSitePrices, getSubscriptionFromId, isPaidMember} from '../../utils/helpers';
import {formatNumber, getAvailablePrices, getFilteredPrices, getMemberActivePrice, getMemberSubscription, getPriceFromSubscription, getSubscriptionFromId, getUpgradeProducts, hasMultipleProducts, isPaidMember} from '../../utils/helpers';
export const AccountPlanPageStyles = `
.gh-portal-accountplans-main {
@ -188,7 +188,7 @@ const ChangePlanSection = ({plans, selectedPlan, onPlanSelect, onCancelSubscript
return (
<section>
<div className='gh-portal-section gh-portal-accountplans-main'>
<PlansSection
<PlansOrProductSection
showLabel={false}
plans={plans}
selectedPlan={selectedPlan}
@ -264,6 +264,7 @@ const PlansContainer = ({
/>
);
};
export default class AccountPlanPage extends React.Component {
static contextType = AppContext;
@ -286,15 +287,19 @@ export default class AccountPlanPage extends React.Component {
}
getInitialState() {
const {member, site, pageQuery} = this.context;
this.prices = getSitePrices({site, pageQuery, includeFree: false});
const {member, site} = this.context;
this.prices = getAvailablePrices({site});
let activePrice = getMemberActivePrice({member});
if (activePrice) {
this.prices = getFilteredPrices({prices: this.prices, currency: activePrice.currency});
}
let selectedPrice = activePrice ? this.prices.find((d) => {
return (d.id === activePrice.id);
}) : null;
if (selectedPrice) {
this.prices = getFilteredPrices({prices: this.prices, currency: selectedPrice.currency});
}
// Select first plan as default for free member
if (!isPaidMember({member}) && this.prices.length > 0) {
selectedPrice = this.prices[0];

View File

@ -5,7 +5,7 @@ import PlansSection from '../common/PlansSection';
import ProductsSection from '../common/ProductsSection';
import InputForm from '../common/InputForm';
import {ValidateInputForm} from '../../utils/form';
import {getAllProducts, getSitePrices, hasMultipleProducts, hasOnlyFreePlan, isInviteOnlySite} from '../../utils/helpers';
import {getSiteProducts, getSitePrices, hasMultipleProducts, hasOnlyFreePlan, isInviteOnlySite} from '../../utils/helpers';
import {ReactComponent as InvitationIcon} from '../../images/icons/invitation.svg';
const React = require('react');
@ -391,7 +391,7 @@ class SignupPage extends React.Component {
renderProducts() {
const {site} = this.context;
const products = getAllProducts({site});
const products = getSiteProducts({site});
return (
<>
<ProductsSection

View File

@ -8,12 +8,8 @@ export function removePortalLinkFromUrl() {
export function getPortalLinkPath({page}) {
const Links = {
default: '#/portal',
signin: '#/portal/signin',
signup: '#/portal/signup',
account: '#/portal/account',
'account-plans': '#/portal/account/plans',
'account-profile': '#/portal/account/profile'
signup: '#/portal/signup'
};
if (Object.keys(Links).includes(page)) {
return Links[page];
@ -55,6 +51,34 @@ export function isPaidMember({member = {}}) {
return (member && member.paid);
}
export function getUpgradePrices({site, member}) {
const activePrice = getMemberActivePrice({member});
if (activePrice) {
return getFilteredPrices({prices: this.prices, currency: activePrice.currency});
}
return getAvailablePrices({site});
}
export function getProductCurrency({product}) {
if (!product?.monthlyPrice) {
return null;
}
return product.monthlyPrice.currency;
}
export function getUpgradeProducts({site, member}) {
const activePrice = getMemberActivePrice({member});
const activePriceCurrency = activePrice?.currency;
const availableProducts = getAvailableProducts({site});
if (!activePrice) {
return availableProducts;
}
return availableProducts.filter((product) => {
return (getProductCurrency({product}) === activePriceCurrency);
});
}
export function getFilteredPrices({prices, currency}) {
return prices.filter((d) => {
return (d.currency || '').toLowerCase() === (currency || '').toLowerCase();
@ -69,6 +93,7 @@ export function getPriceFromSubscription({subscription}) {
id: subscription.price.price_id,
price: subscription.price.amount / 100,
name: subscription.price.nickname,
currency: subscription.price.currency.toLowerCase(),
currency_symbol: getCurrencySymbol(subscription.price.currency)
};
}
@ -138,43 +163,44 @@ export function isInviteOnlySite({site = {}, pageQuery = ''}) {
}
export function hasMultipleProducts({site = {}}) {
const {
products = []
} = site || {};
if (site.portal_plans && !site.portal_plans.includes('monthly') && !site.portal_plans.includes('yearly')) {
return false;
}
if (site.portal_products && site.portal_products.length < 2) {
return false;
}
const products = getAvailableProducts({site});
if (products?.length > 1) {
return true;
}
return false;
}
export function getSiteProducts({site = {}}) {
const products = site?.products || [];
return products.filter(product => !!product).sort((productA, productB) => {
return productA?.monthlyPrice?.amount - productB?.monthlyPrice.amount;
});
}
export function getAvailableProducts({site}) {
const {portal_products: portalProducts} = site;
const products = getSiteProducts({site}).filter((product) => {
const {portal_products: portalProducts, products = [], portal_plans: portalPlans = []} = site || {};
if (!portalPlans.includes('monthly') && !portalPlans.includes('yearly')) {
return [];
}
return products.filter(product => !!product).filter((product) => {
if (portalProducts) {
return portalProducts.includes(product.id);
}
return true;
}).sort((productA, productB) => {
return productA?.monthlyPrice?.amount - productB?.monthlyPrice.amount;
}).map((product) => {
product.monthlyPrice = {
...product.monthlyPrice,
currency_symbol: getCurrencySymbol(product.monthlyPrice.currency)
};
product.yearlyPrice = {
...product.yearlyPrice,
currency_symbol: getCurrencySymbol(product.yearlyPrice.currency)
};
return product;
});
return products;
}
export function getAllProducts({site}) {
export function getSiteProducts({site}) {
const products = getAvailableProducts({site});
if (hasFreeProduct({site}) && products.length > 0) {
if (hasFreeProductPrice({site}) && products.length > 0) {
products.unshift({
id: 'free'
});
@ -182,7 +208,7 @@ export function getAllProducts({site}) {
return products;
}
export function getProductPrices({site}) {
export function getPricesFromProducts({site}) {
const products = getAvailableProducts({site}) || [];
const prices = products.reduce((accumPrices, product) => {
if (product.monthlyPrice && product.yearlyPrice) {
@ -194,63 +220,7 @@ export function getProductPrices({site}) {
return prices;
}
export function getAvailablePrices({site = {}, includeFree = true} = {}) {
let {
prices,
products,
allow_self_signup: allowSelfSignup,
is_stripe_configured: isStripeConfigured
} = site || {};
if (!prices) {
prices = [];
}
if (products) {
prices = [];
products.forEach((product) => {
if (product.prices) {
prices = prices.concat(product.prices);
}
});
}
const plansData = [];
const stripePrices = prices.filter((d) => {
return !!(d && d.id);
}).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: 'usd',
currency_symbol: '$',
name: 'Free'
});
}
if (isStripeConfigured) {
stripePrices.forEach((price) => {
plansData.push(price);
});
}
return plansData;
}
export function hasFreeProduct({site}) {
export function hasFreeProductPrice({site}) {
const {
allow_self_signup: allowSelfSignup,
portal_plans: portalPlans
@ -258,22 +228,19 @@ export function hasFreeProduct({site}) {
return allowSelfSignup && portalPlans.includes('free');
}
export function getSitePrices({site = {}, includeFree = true, pageQuery = ''} = {}) {
export function getAvailablePrices({site}) {
const {
prices = [],
allow_self_signup: allowSelfSignup,
is_stripe_configured: isStripeConfigured,
portal_plans: portalPlans
portal_plans: portalPlans = [],
is_stripe_configured: isStripeConfigured
} = site || {};
if (!prices) {
if (!isStripeConfigured) {
return [];
}
const availablePrices = getProductPrices({site});
const plansData = [];
const productPrices = getPricesFromProducts({site});
const stripePrices = availablePrices.filter((d) => {
return productPrices.filter((d) => {
return !!(d && d.id);
}).map((d) => {
return {
@ -287,10 +254,10 @@ export function getSitePrices({site = {}, includeFree = true, pageQuery = ''} =
return price.amount !== 0 && price.type === 'recurring';
}).filter((price) => {
if (price.interval === 'month') {
return (portalPlans || []).includes('monthly');
return portalPlans.includes('monthly');
}
if (price.interval === 'year') {
return (portalPlans || []).includes('yearly');
return portalPlans.includes('yearly');
}
return false;
}).sort((a, b) => {
@ -300,19 +267,33 @@ export function getSitePrices({site = {}, includeFree = true, pageQuery = ''} =
return 0;
}
return a.currency.localeCompare(b.currency, undefined, {ignorePunctuation: true});
}).sort((a, b) => {
return (a.active === b.active) ? 0 : (a.active ? -1 : 1);
});
}
export function getFreePriceCurrency({site}) {
const stripePrices = getAvailablePrices({site});
let freePriceCurrencyDetail = {
currency: 'usd',
currency_symbol: '$'
};
if (stripePrices && stripePrices.length > 0) {
if (stripePrices?.length > 0) {
freePriceCurrencyDetail.currency = stripePrices[0].currency;
freePriceCurrencyDetail.currency_symbol = stripePrices[0].currency_symbol;
}
return freePriceCurrencyDetail;
}
if (allowSelfSignup && portalPlans.includes('free') && includeFree) {
export function getSitePrices({site = {}, pageQuery = ''} = {}) {
const {
allow_self_signup: allowSelfSignup,
portal_plans: portalPlans
} = site || {};
const plansData = [];
if (allowSelfSignup && portalPlans.includes('free')) {
const freePriceCurrencyDetail = getFreePriceCurrency({site});
plansData.push({
id: 'free',
type: 'free',
@ -323,9 +304,10 @@ export function getSitePrices({site = {}, includeFree = true, pageQuery = ''} =
});
}
const showOnlyFree = pageQuery === 'free' && hasPrice({site, plan: 'free'});
const showOnlyFree = pageQuery === 'free' && hasFreeProductPrice({site});
if (isStripeConfigured && !showOnlyFree) {
if (!showOnlyFree) {
const stripePrices = getAvailablePrices({site});
stripePrices.forEach((price) => {
plansData.push(price);
});