Refined multiple product flows

closes https://github.com/TryGhost/Team/issues/835

- updates change flow to consider portal_plans setting
- updates confirm subscription screen to show product name
- removed discount benefit on yearly if only one plan
This commit is contained in:
Rishabh 2021-06-29 21:26:48 +05:30
parent db12a9976f
commit bda6f36a3c
3 changed files with 21 additions and 10 deletions

View File

@ -1,7 +1,7 @@
import React, {useContext, useEffect, useState} from 'react';
import Switch from '../common/Switch';
import {ReactComponent as CheckmarkIcon} from '../../images/icons/checkmark.svg';
import {getSiteProducts, getCurrencySymbol, getPriceString, getStripeAmount, isCookiesDisabled, getPricesFromProducts, getMemberActivePrice} from '../../utils/helpers';
import {getSiteProducts, getCurrencySymbol, getPriceString, getStripeAmount, isCookiesDisabled, getMemberActivePrice, getAvailablePrices} from '../../utils/helpers';
import AppContext from '../../AppContext';
import {ChangeProductPlansSection} from './PlansSection';
@ -331,7 +331,7 @@ export const ProductsSectionStyles = ({site}) => {
grid-gap: 20px;
width: 100%;
}
.gh-portal-upgrade-product .gh-portal-products-grid:not(.change-plan) {
padding: 32px 0 0;
}
@ -710,7 +710,8 @@ function ProductsSection({onPlanSelect, products, type = null}) {
function ChangeProductCard({product, onPlanSelect}) {
const {member} = useContext(AppContext);
const cardClass = 'gh-portal-product-card';
const plans = getPricesFromProducts({products: [product]});
const {site} = useContext(AppContext);
const plans = getAvailablePrices({site, products: [product]});
const selectedPlan = getMemberActivePrice({member});
return (
<div>

View File

@ -5,7 +5,7 @@ import CloseButton from '../common/CloseButton';
import BackButton from '../common/BackButton';
import PlansSection, {MultipleProductsPlansSection, SingleProductPlansSection} from '../common/PlansSection';
import {getDateString} from '../../utils/date-time';
import {formatNumber, getAvailablePrices, getFilteredPrices, getMemberActivePrice, getMemberSubscription, getPriceFromSubscription, getSubscriptionFromId, getUpgradeProducts, hasMultipleProducts, hasMultipleProductsFeature, isPaidMember} from '../../utils/helpers';
import {formatNumber, getAvailablePrices, getFilteredPrices, getMemberActivePrice, getMemberSubscription, getPriceFromSubscription, getProductFromPrice, getSubscriptionFromId, getUpgradeProducts, hasMultipleProducts, hasMultipleProductsFeature, isPaidMember} from '../../utils/helpers';
export const AccountPlanPageStyles = `
.gh-portal-accountplans-main {
@ -103,7 +103,7 @@ const CancelSubscriptionButton = ({member, onCancelSubscription, action, brandCo
// For confirmation flows
const PlanConfirmationSection = ({plan, type, onConfirm}) => {
const {action, member, brandColor} = useContext(AppContext);
const {site, action, member, brandColor} = useContext(AppContext);
const [reason, setReason] = useState('');
const subscription = getMemberSubscription({member});
const isRunning = ['updateSubscription:running', 'checkoutPlan:running', 'cancelSubscription:running'].includes(action);
@ -115,6 +115,8 @@ const PlanConfirmationSection = ({plan, type, onConfirm}) => {
}
const priceString = formatNumber(plan.price);
const planStartMessage = `${plan.currency_symbol}${priceString}/${plan.interval} Starting ${planStartDate}`;
const product = getProductFromPrice({site, priceId: plan?.id});
const priceLabel = hasMultipleProductsFeature({site}) ? product.name : 'Price';
if (type === 'changePlan') {
return (
<>
@ -127,7 +129,7 @@ const PlanConfirmationSection = ({plan, type, onConfirm}) => {
</section>
<section>
<div className='gh-portal-list-detail'>
<h3>Price</h3>
<h3>{priceLabel}</h3>
<p>{planStartMessage}</p>
</div>
</section>

View File

@ -244,15 +244,16 @@ export function getFreeBenefits() {
}];
}
export function getProductBenefits({product}) {
export function getProductBenefits({product, site = null}) {
if (product?.monthlyPrice && product?.yearlyPrice) {
const availablePrices = getAvailablePrices({site, products: [product]});
const yearlyDiscount = calculateDiscount(product.monthlyPrice.amount, product.yearlyPrice.amount);
const productBenefits = product?.benefits || [];
const monthlyBenefits = product?.benefits?.length > 0 ? [...productBenefits] : [{
name: 'Full access'
}];
const yearlyBenefits = [...monthlyBenefits];
if (yearlyDiscount > 0) {
if (yearlyDiscount > 0 && availablePrices.length > 1) {
yearlyBenefits.push({
name: `${yearlyDiscount}% discount`
});
@ -288,7 +289,14 @@ export function hasFreeProductPrice({site}) {
return allowSelfSignup && portalPlans.includes('free');
}
export function getAvailablePrices({site}) {
export function getProductFromPrice({site, priceId}) {
const products = getAvailableProducts({site});
return products.find((product) => {
return (product?.monthlyPrice?.id === priceId) || (product?.yearlyPrice?.id === priceId);
});
}
export function getAvailablePrices({site, products = null}) {
const {
portal_plans: portalPlans = [],
is_stripe_configured: isStripeConfigured
@ -298,7 +306,7 @@ export function getAvailablePrices({site}) {
return [];
}
const productPrices = getPricesFromProducts({site});
const productPrices = getPricesFromProducts({site, products});
return productPrices.filter((d) => {
return !!(d && d.id);