mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-12-24 11:22:19 +03:00
Handled updated tiers API data structure (#247)
refs https://github.com/TryGhost/Team/issues/1575 - updated to work with new tiers api data structure which removes stripe id references
This commit is contained in:
parent
7699424cee
commit
b306b0747d
@ -1,4 +1,4 @@
|
|||||||
import {createPopupNotification, getMemberEmail, getMemberName, removePortalLinkFromUrl} from './utils/helpers';
|
import {createPopupNotification, getMemberEmail, getMemberName, getProductCadenceFromPrice, removePortalLinkFromUrl} from './utils/helpers';
|
||||||
|
|
||||||
function switchPage({data, state}) {
|
function switchPage({data, state}) {
|
||||||
return {
|
return {
|
||||||
@ -99,7 +99,8 @@ async function signup({data, state, api}) {
|
|||||||
if (plan.toLowerCase() === 'free') {
|
if (plan.toLowerCase() === 'free') {
|
||||||
await api.member.sendMagicLink(data);
|
await api.member.sendMagicLink(data);
|
||||||
} else {
|
} else {
|
||||||
await api.member.checkoutPlan({plan, email, name, newsletters, offerId});
|
const {tierId, cadence} = getProductCadenceFromPrice({site: state?.site, priceId: plan});
|
||||||
|
await api.member.checkoutPlan({plan, tierId, cadence, email, name, newsletters, offerId});
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
page: 'magiclink',
|
page: 'magiclink',
|
||||||
@ -119,8 +120,11 @@ async function signup({data, state, api}) {
|
|||||||
async function checkoutPlan({data, state, api}) {
|
async function checkoutPlan({data, state, api}) {
|
||||||
try {
|
try {
|
||||||
const {plan, offerId} = data;
|
const {plan, offerId} = data;
|
||||||
|
const {tierId, cadence} = getProductCadenceFromPrice({site: state?.site, priceId: plan});
|
||||||
await api.member.checkoutPlan({
|
await api.member.checkoutPlan({
|
||||||
plan,
|
plan,
|
||||||
|
tierId,
|
||||||
|
cadence,
|
||||||
offerId,
|
offerId,
|
||||||
metadata: {
|
metadata: {
|
||||||
checkoutType: 'upgrade'
|
checkoutType: 'upgrade'
|
||||||
@ -140,8 +144,15 @@ async function checkoutPlan({data, state, api}) {
|
|||||||
async function updateSubscription({data, state, api}) {
|
async function updateSubscription({data, state, api}) {
|
||||||
try {
|
try {
|
||||||
const {plan, planId, subscriptionId, cancelAtPeriodEnd} = data;
|
const {plan, planId, subscriptionId, cancelAtPeriodEnd} = data;
|
||||||
|
const {tierId, cadence} = getProductCadenceFromPrice({site: state?.site, priceId: planId});
|
||||||
|
|
||||||
await api.member.updateSubscription({
|
await api.member.updateSubscription({
|
||||||
planName: plan, subscriptionId, cancelAtPeriodEnd, planId: planId
|
planName: plan,
|
||||||
|
tierId,
|
||||||
|
cadence,
|
||||||
|
subscriptionId,
|
||||||
|
cancelAtPeriodEnd,
|
||||||
|
planId: planId
|
||||||
});
|
});
|
||||||
const member = await api.member.sessionData();
|
const member = await api.member.sessionData();
|
||||||
const action = 'updateSubscription:success';
|
const action = 'updateSubscription:success';
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import React, {useContext, useEffect, useState} from 'react';
|
import React, {useContext, useEffect, useState} from 'react';
|
||||||
import {ReactComponent as LoaderIcon} from '../../images/icons/loader.svg';
|
import {ReactComponent as LoaderIcon} from '../../images/icons/loader.svg';
|
||||||
import {ReactComponent as CheckmarkIcon} from '../../images/icons/checkmark.svg';
|
import {ReactComponent as CheckmarkIcon} from '../../images/icons/checkmark.svg';
|
||||||
import {getCurrencySymbol, getPriceString, getStripeAmount, getMemberActivePrice, getProductFromPrice, getFreeTierTitle, getFreeTierDescription, getFreeProduct, getFreeProductBenefits, formatNumber, isCookiesDisabled, hasOnlyFreeProduct} from '../../utils/helpers';
|
import {getCurrencySymbol, getPriceString, getStripeAmount, getMemberActivePrice, getProductFromPrice, getFreeTierTitle, getFreeTierDescription, getFreeProduct, getFreeProductBenefits, formatNumber, isCookiesDisabled, hasOnlyFreeProduct, isMemberActivePrice} from '../../utils/helpers';
|
||||||
import AppContext from '../../AppContext';
|
import AppContext from '../../AppContext';
|
||||||
import calculateDiscount from '../../utils/discount';
|
import calculateDiscount from '../../utils/discount';
|
||||||
|
|
||||||
@ -882,7 +882,7 @@ function ProductDescription({product, selectedPrice, activePrice}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function ChangeProductCard({product, onPlanSelect}) {
|
function ChangeProductCard({product, onPlanSelect}) {
|
||||||
const {member} = useContext(AppContext);
|
const {member, site} = useContext(AppContext);
|
||||||
const {selectedProduct, setSelectedProduct, selectedInterval} = useContext(ProductsContext);
|
const {selectedProduct, setSelectedProduct, selectedInterval} = useContext(ProductsContext);
|
||||||
const cardClass = selectedProduct === product.id ? 'gh-portal-product-card checked' : 'gh-portal-product-card';
|
const cardClass = selectedProduct === product.id ? 'gh-portal-product-card checked' : 'gh-portal-product-card';
|
||||||
const monthlyPrice = product.monthlyPrice;
|
const monthlyPrice = product.monthlyPrice;
|
||||||
@ -891,7 +891,7 @@ function ChangeProductCard({product, onPlanSelect}) {
|
|||||||
|
|
||||||
const selectedPrice = selectedInterval === 'month' ? monthlyPrice : yearlyPrice;
|
const selectedPrice = selectedInterval === 'month' ? monthlyPrice : yearlyPrice;
|
||||||
|
|
||||||
const currentPlan = (selectedPrice.id === memberActivePrice.id);
|
const currentPlan = isMemberActivePrice({member, site, priceId: selectedPrice.id});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={cardClass + (currentPlan ? ' disabled' : '')} key={product.id} onClick={(e) => {
|
<div className={cardClass + (currentPlan ? ' disabled' : '')} key={product.id} onClick={(e) => {
|
||||||
|
@ -327,7 +327,9 @@ describe('Signup', () => {
|
|||||||
email: 'jamie@example.com',
|
email: 'jamie@example.com',
|
||||||
name: 'Jamie Larsen',
|
name: 'Jamie Larsen',
|
||||||
offerId: undefined,
|
offerId: undefined,
|
||||||
plan: singleTierProduct.yearlyPrice.id
|
plan: singleTierProduct.yearlyPrice.id,
|
||||||
|
tierId: singleTierProduct.id,
|
||||||
|
cadence: 'year'
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -367,7 +369,9 @@ describe('Signup', () => {
|
|||||||
email: 'jamie@example.com',
|
email: 'jamie@example.com',
|
||||||
name: 'Jamie Larsen',
|
name: 'Jamie Larsen',
|
||||||
offerId: undefined,
|
offerId: undefined,
|
||||||
plan: singleTierProduct.yearlyPrice.id
|
plan: singleTierProduct.yearlyPrice.id,
|
||||||
|
tierId: singleTierProduct.id,
|
||||||
|
cadence: 'year'
|
||||||
});
|
});
|
||||||
const magicLink = await within(popupIframeDocument).findByText(/now check your email/i);
|
const magicLink = await within(popupIframeDocument).findByText(/now check your email/i);
|
||||||
expect(magicLink).toBeInTheDocument();
|
expect(magicLink).toBeInTheDocument();
|
||||||
@ -408,7 +412,9 @@ describe('Signup', () => {
|
|||||||
email: 'jamie@example.com',
|
email: 'jamie@example.com',
|
||||||
name: '',
|
name: '',
|
||||||
offerId: undefined,
|
offerId: undefined,
|
||||||
plan: singleTierProduct.monthlyPrice.id
|
plan: singleTierProduct.monthlyPrice.id,
|
||||||
|
tierId: singleTierProduct.id,
|
||||||
|
cadence: 'month'
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -444,7 +450,9 @@ describe('Signup', () => {
|
|||||||
email: 'jamie@example.com',
|
email: 'jamie@example.com',
|
||||||
name: 'Jamie Larsen',
|
name: 'Jamie Larsen',
|
||||||
offerId: undefined,
|
offerId: undefined,
|
||||||
plan: singleTierProduct.yearlyPrice.id
|
plan: singleTierProduct.yearlyPrice.id,
|
||||||
|
tierId: singleTierProduct.id,
|
||||||
|
cadence: 'year'
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -459,6 +467,7 @@ describe('Signup', () => {
|
|||||||
offer: FixtureOffer
|
offer: FixtureOffer
|
||||||
});
|
});
|
||||||
let planId = FixtureSite.singleTier.basic.products.find(p => p.type === 'paid').monthlyPrice.id;
|
let planId = FixtureSite.singleTier.basic.products.find(p => p.type === 'paid').monthlyPrice.id;
|
||||||
|
let tier = FixtureSite.singleTier.basic.products.find(p => p.type === 'paid');
|
||||||
let offerId = FixtureOffer.id;
|
let offerId = FixtureOffer.id;
|
||||||
expect(popupFrame).toBeInTheDocument();
|
expect(popupFrame).toBeInTheDocument();
|
||||||
expect(triggerButtonFrame).toBeInTheDocument();
|
expect(triggerButtonFrame).toBeInTheDocument();
|
||||||
@ -480,7 +489,9 @@ describe('Signup', () => {
|
|||||||
email: 'jamie@example.com',
|
email: 'jamie@example.com',
|
||||||
name: 'Jamie Larsen',
|
name: 'Jamie Larsen',
|
||||||
offerId,
|
offerId,
|
||||||
plan: planId
|
plan: planId,
|
||||||
|
tierId: tier.id,
|
||||||
|
cadence: 'month'
|
||||||
});
|
});
|
||||||
|
|
||||||
window.location.hash = '';
|
window.location.hash = '';
|
||||||
@ -501,6 +512,7 @@ describe('Signup', () => {
|
|||||||
offer: FixtureOffer
|
offer: FixtureOffer
|
||||||
});
|
});
|
||||||
let planId = FixtureSite.singleTier.basic.products.find(p => p.type === 'paid').monthlyPrice.id;
|
let planId = FixtureSite.singleTier.basic.products.find(p => p.type === 'paid').monthlyPrice.id;
|
||||||
|
let tier = FixtureSite.singleTier.basic.products.find(p => p.type === 'paid');
|
||||||
let offerId = FixtureOffer.id;
|
let offerId = FixtureOffer.id;
|
||||||
expect(popupFrame).toBeInTheDocument();
|
expect(popupFrame).toBeInTheDocument();
|
||||||
expect(triggerButtonFrame).not.toBeInTheDocument();
|
expect(triggerButtonFrame).not.toBeInTheDocument();
|
||||||
@ -516,7 +528,9 @@ describe('Signup', () => {
|
|||||||
email: undefined,
|
email: undefined,
|
||||||
name: undefined,
|
name: undefined,
|
||||||
offerId: offerId,
|
offerId: offerId,
|
||||||
plan: planId
|
plan: planId,
|
||||||
|
tierId: tier.id,
|
||||||
|
cadence: 'month'
|
||||||
});
|
});
|
||||||
|
|
||||||
window.location.hash = '';
|
window.location.hash = '';
|
||||||
@ -679,6 +693,7 @@ describe('Signup', () => {
|
|||||||
offer: FixtureOffer
|
offer: FixtureOffer
|
||||||
});
|
});
|
||||||
let planId = FixtureSite.singleTier.basic.products.find(p => p.type === 'paid').monthlyPrice.id;
|
let planId = FixtureSite.singleTier.basic.products.find(p => p.type === 'paid').monthlyPrice.id;
|
||||||
|
let tier = FixtureSite.singleTier.basic.products.find(p => p.type === 'paid');
|
||||||
let offerId = FixtureOffer.id;
|
let offerId = FixtureOffer.id;
|
||||||
expect(popupFrame).toBeInTheDocument();
|
expect(popupFrame).toBeInTheDocument();
|
||||||
expect(triggerButtonFrame).toBeInTheDocument();
|
expect(triggerButtonFrame).toBeInTheDocument();
|
||||||
@ -700,7 +715,9 @@ describe('Signup', () => {
|
|||||||
email: 'jamie@example.com',
|
email: 'jamie@example.com',
|
||||||
name: 'Jamie Larsen',
|
name: 'Jamie Larsen',
|
||||||
offerId,
|
offerId,
|
||||||
plan: planId
|
plan: planId,
|
||||||
|
tierId: tier.id,
|
||||||
|
cadence: 'month'
|
||||||
});
|
});
|
||||||
|
|
||||||
window.location.hash = '';
|
window.location.hash = '';
|
||||||
@ -720,6 +737,7 @@ describe('Signup', () => {
|
|||||||
site,
|
site,
|
||||||
offer: FixtureOffer
|
offer: FixtureOffer
|
||||||
});
|
});
|
||||||
|
const singleTier = FixtureSite.singleTier.basic.products.find(p => p.type === 'paid');
|
||||||
let planId = FixtureSite.singleTier.basic.products.find(p => p.type === 'paid').monthlyPrice.id;
|
let planId = FixtureSite.singleTier.basic.products.find(p => p.type === 'paid').monthlyPrice.id;
|
||||||
let offerId = FixtureOffer.id;
|
let offerId = FixtureOffer.id;
|
||||||
expect(popupFrame).toBeInTheDocument();
|
expect(popupFrame).toBeInTheDocument();
|
||||||
@ -736,7 +754,9 @@ describe('Signup', () => {
|
|||||||
email: undefined,
|
email: undefined,
|
||||||
name: undefined,
|
name: undefined,
|
||||||
offerId: offerId,
|
offerId: offerId,
|
||||||
plan: planId
|
plan: planId,
|
||||||
|
tierId: singleTier.id,
|
||||||
|
cadence: 'month'
|
||||||
});
|
});
|
||||||
|
|
||||||
window.location.hash = '';
|
window.location.hash = '';
|
||||||
|
@ -215,7 +215,9 @@ describe('Logged-in free member', () => {
|
|||||||
checkoutType: 'upgrade'
|
checkoutType: 'upgrade'
|
||||||
},
|
},
|
||||||
offerId: undefined,
|
offerId: undefined,
|
||||||
plan: singleTierProduct.monthlyPrice.id
|
plan: singleTierProduct.monthlyPrice.id,
|
||||||
|
tierId: singleTierProduct.id,
|
||||||
|
cadence: 'month'
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -250,7 +252,9 @@ describe('Logged-in free member', () => {
|
|||||||
checkoutType: 'upgrade'
|
checkoutType: 'upgrade'
|
||||||
},
|
},
|
||||||
offerId: undefined,
|
offerId: undefined,
|
||||||
plan: singleTierProduct.yearlyPrice.id
|
plan: singleTierProduct.yearlyPrice.id,
|
||||||
|
tierId: singleTierProduct.id,
|
||||||
|
cadence: 'year'
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -266,6 +270,7 @@ describe('Logged-in free member', () => {
|
|||||||
offer: FixtureOffer
|
offer: FixtureOffer
|
||||||
});
|
});
|
||||||
let planId = FixtureSite.singleTier.basic.products.find(p => p.type === 'paid').monthlyPrice.id;
|
let planId = FixtureSite.singleTier.basic.products.find(p => p.type === 'paid').monthlyPrice.id;
|
||||||
|
let singleTierProduct = FixtureSite.singleTier.basic.products.find(p => p.type === 'paid');
|
||||||
let offerId = FixtureOffer.id;
|
let offerId = FixtureOffer.id;
|
||||||
expect(popupFrame).toBeInTheDocument();
|
expect(popupFrame).toBeInTheDocument();
|
||||||
expect(triggerButtonFrame).toBeInTheDocument();
|
expect(triggerButtonFrame).toBeInTheDocument();
|
||||||
@ -285,7 +290,9 @@ describe('Logged-in free member', () => {
|
|||||||
email: 'jimmie@example.com',
|
email: 'jimmie@example.com',
|
||||||
name: 'Jimmie Larson',
|
name: 'Jimmie Larson',
|
||||||
offerId,
|
offerId,
|
||||||
plan: planId
|
plan: planId,
|
||||||
|
tierId: singleTierProduct.id,
|
||||||
|
cadence: 'month'
|
||||||
});
|
});
|
||||||
|
|
||||||
window.location.hash = '';
|
window.location.hash = '';
|
||||||
@ -308,6 +315,7 @@ describe('Logged-in free member', () => {
|
|||||||
offer: FixtureOffer
|
offer: FixtureOffer
|
||||||
});
|
});
|
||||||
let planId = FixtureSite.singleTier.basic.products.find(p => p.type === 'paid').monthlyPrice.id;
|
let planId = FixtureSite.singleTier.basic.products.find(p => p.type === 'paid').monthlyPrice.id;
|
||||||
|
let singleTierProduct = FixtureSite.singleTier.basic.products.find(p => p.type === 'paid');
|
||||||
let offerId = FixtureOffer.id;
|
let offerId = FixtureOffer.id;
|
||||||
expect(popupFrame).toBeInTheDocument();
|
expect(popupFrame).toBeInTheDocument();
|
||||||
expect(triggerButtonFrame).not.toBeInTheDocument();
|
expect(triggerButtonFrame).not.toBeInTheDocument();
|
||||||
@ -324,7 +332,9 @@ describe('Logged-in free member', () => {
|
|||||||
checkoutType: 'upgrade'
|
checkoutType: 'upgrade'
|
||||||
},
|
},
|
||||||
offerId: offerId,
|
offerId: offerId,
|
||||||
plan: planId
|
plan: planId,
|
||||||
|
tierId: singleTierProduct.id,
|
||||||
|
cadence: 'month'
|
||||||
});
|
});
|
||||||
|
|
||||||
window.location.hash = '';
|
window.location.hash = '';
|
||||||
@ -364,7 +374,9 @@ describe('Logged-in free member', () => {
|
|||||||
checkoutType: 'upgrade'
|
checkoutType: 'upgrade'
|
||||||
},
|
},
|
||||||
offerId: undefined,
|
offerId: undefined,
|
||||||
plan: singleTierProduct.yearlyPrice.id
|
plan: singleTierProduct.yearlyPrice.id,
|
||||||
|
tierId: singleTierProduct.id,
|
||||||
|
cadence: 'year'
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -380,6 +392,7 @@ describe('Logged-in free member', () => {
|
|||||||
offer: FixtureOffer
|
offer: FixtureOffer
|
||||||
});
|
});
|
||||||
let planId = FixtureSite.multipleTiers.basic.products.find(p => p.type === 'paid').monthlyPrice.id;
|
let planId = FixtureSite.multipleTiers.basic.products.find(p => p.type === 'paid').monthlyPrice.id;
|
||||||
|
let singleTierProduct = FixtureSite.multipleTiers.basic.products.find(p => p.type === 'paid');
|
||||||
let offerId = FixtureOffer.id;
|
let offerId = FixtureOffer.id;
|
||||||
expect(popupFrame).toBeInTheDocument();
|
expect(popupFrame).toBeInTheDocument();
|
||||||
expect(triggerButtonFrame).toBeInTheDocument();
|
expect(triggerButtonFrame).toBeInTheDocument();
|
||||||
@ -399,7 +412,9 @@ describe('Logged-in free member', () => {
|
|||||||
email: 'jimmie@example.com',
|
email: 'jimmie@example.com',
|
||||||
name: 'Jimmie Larson',
|
name: 'Jimmie Larson',
|
||||||
offerId,
|
offerId,
|
||||||
plan: planId
|
plan: planId,
|
||||||
|
tierId: singleTierProduct.id,
|
||||||
|
cadence: 'month'
|
||||||
});
|
});
|
||||||
|
|
||||||
window.location.hash = '';
|
window.location.hash = '';
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import {transformApiSiteData} from './helpers';
|
import {transformApiSiteData, transformApiTiersData} from './helpers';
|
||||||
|
|
||||||
function getAnalyticsMetadata() {
|
function getAnalyticsMetadata() {
|
||||||
const analyticsTag = document.querySelector('meta[name=ghost-analytics-id]');
|
const analyticsTag = document.querySelector('meta[name=ghost-analytics-id]');
|
||||||
@ -311,7 +311,7 @@ function setupGhostApi({siteUrl = window.location.origin, apiUrl, apiKey}) {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
async checkoutPlan({plan, cancelUrl, successUrl, email: customerEmail, name, offerId, newsletters, metadata = {}} = {}) {
|
async checkoutPlan({plan, tierId, cadence, cancelUrl, successUrl, email: customerEmail, name, offerId, newsletters, metadata = {}} = {}) {
|
||||||
const siteUrlObj = new URL(siteUrl);
|
const siteUrlObj = new URL(siteUrl);
|
||||||
const identity = await api.member.identity();
|
const identity = await api.member.identity();
|
||||||
const url = endpointFor({type: 'members', resource: 'create-stripe-checkout-session'});
|
const url = endpointFor({type: 'members', resource: 'create-stripe-checkout-session'});
|
||||||
@ -328,10 +328,20 @@ function setupGhostApi({siteUrl = window.location.origin, apiUrl, apiKey}) {
|
|||||||
fp_tid: (window.FPROM || window.$FPROM)?.data?.tid,
|
fp_tid: (window.FPROM || window.$FPROM)?.data?.tid,
|
||||||
...metadata
|
...metadata
|
||||||
};
|
};
|
||||||
const analyticsData = getAnalyticsMetadata();
|
|
||||||
if (analyticsData) {
|
const body = {
|
||||||
metadataObj.ghost_analytics_entry_id = analyticsData.entry_id;
|
priceId: offerId ? null : plan,
|
||||||
metadataObj.ghost_analytics_source_url = analyticsData.source_url;
|
offerId,
|
||||||
|
identity: identity,
|
||||||
|
metadata: metadataObj,
|
||||||
|
successUrl,
|
||||||
|
cancelUrl,
|
||||||
|
customerEmail: customerEmail
|
||||||
|
};
|
||||||
|
if (tierId && cadence) {
|
||||||
|
delete body.priceId;
|
||||||
|
body.tierId = offerId ? null : tierId;
|
||||||
|
body.cadence = offerId ? null : cadence;
|
||||||
}
|
}
|
||||||
return makeRequest({
|
return makeRequest({
|
||||||
url,
|
url,
|
||||||
@ -339,15 +349,7 @@ function setupGhostApi({siteUrl = window.location.origin, apiUrl, apiKey}) {
|
|||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json'
|
'Content-Type': 'application/json'
|
||||||
},
|
},
|
||||||
body: JSON.stringify({
|
body: JSON.stringify(body)
|
||||||
priceId: offerId ? null : plan,
|
|
||||||
offerId,
|
|
||||||
identity: identity,
|
|
||||||
metadata: metadataObj,
|
|
||||||
successUrl,
|
|
||||||
cancelUrl,
|
|
||||||
customerEmail: customerEmail
|
|
||||||
})
|
|
||||||
}).then(function (res) {
|
}).then(function (res) {
|
||||||
if (!res.ok) {
|
if (!res.ok) {
|
||||||
throw new Error('Could not create stripe checkout session');
|
throw new Error('Could not create stripe checkout session');
|
||||||
@ -413,7 +415,7 @@ function setupGhostApi({siteUrl = window.location.origin, apiUrl, apiKey}) {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
async updateSubscription({subscriptionId, planName, planId, smartCancel, cancelAtPeriodEnd, cancellationReason}) {
|
async updateSubscription({subscriptionId, tierId, cadence, planId, smartCancel, cancelAtPeriodEnd, cancellationReason}) {
|
||||||
const identity = await api.member.identity();
|
const identity = await api.member.identity();
|
||||||
const url = endpointFor({type: 'members', resource: 'subscriptions'}) + subscriptionId + '/';
|
const url = endpointFor({type: 'members', resource: 'subscriptions'}) + subscriptionId + '/';
|
||||||
const body = {
|
const body = {
|
||||||
@ -427,6 +429,13 @@ function setupGhostApi({siteUrl = window.location.origin, apiUrl, apiKey}) {
|
|||||||
if (body) {
|
if (body) {
|
||||||
body.metadata = analyticsData;
|
body.metadata = analyticsData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (tierId && cadence) {
|
||||||
|
delete body.priceId;
|
||||||
|
body.tierId = tierId;
|
||||||
|
body.cadence = cadence;
|
||||||
|
}
|
||||||
|
|
||||||
return makeRequest({
|
return makeRequest({
|
||||||
url,
|
url,
|
||||||
method: 'PUT',
|
method: 'PUT',
|
||||||
@ -456,7 +465,7 @@ function setupGhostApi({siteUrl = window.location.origin, apiUrl, apiKey}) {
|
|||||||
site = {
|
site = {
|
||||||
...settings,
|
...settings,
|
||||||
newsletters,
|
newsletters,
|
||||||
tiers
|
tiers: transformApiTiersData({tiers})
|
||||||
};
|
};
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// Ignore
|
// Ignore
|
||||||
|
@ -110,6 +110,8 @@ export function getPriceFromSubscription({subscription}) {
|
|||||||
id: subscription.price.price_id,
|
id: subscription.price.price_id,
|
||||||
price: subscription.price.amount / 100,
|
price: subscription.price.amount / 100,
|
||||||
name: subscription.price.nickname,
|
name: subscription.price.nickname,
|
||||||
|
tierId: subscription.tier?.id,
|
||||||
|
cadence: subscription.price?.interval === 'month' ? 'month' : 'year',
|
||||||
currency: subscription.price.currency.toLowerCase(),
|
currency: subscription.price.currency.toLowerCase(),
|
||||||
currency_symbol: getCurrencySymbol(subscription.price.currency)
|
currency_symbol: getCurrencySymbol(subscription.price.currency)
|
||||||
};
|
};
|
||||||
@ -122,6 +124,15 @@ export function getMemberActivePrice({member}) {
|
|||||||
return getPriceFromSubscription({subscription});
|
return getPriceFromSubscription({subscription});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function isMemberActivePrice({priceId, site, member}) {
|
||||||
|
const activePrice = getMemberActivePrice({member});
|
||||||
|
const {tierId, cadence} = getProductCadenceFromPrice({site, priceId});
|
||||||
|
if (activePrice?.tierId === tierId && activePrice?.cadence === cadence) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
export function getSubscriptionFromId({member, subscriptionId}) {
|
export function getSubscriptionFromId({member, subscriptionId}) {
|
||||||
if (isPaidMember({member})) {
|
if (isPaidMember({member})) {
|
||||||
const subscriptions = member.subscriptions || [];
|
const subscriptions = member.subscriptions || [];
|
||||||
@ -452,6 +463,24 @@ export function getProductFromPrice({site, priceId}) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getProductCadenceFromPrice({site, priceId}) {
|
||||||
|
if (priceId === 'free') {
|
||||||
|
return getFreeProduct({site});
|
||||||
|
}
|
||||||
|
const products = getAllProductsForSite({site});
|
||||||
|
const tier = products.find((product) => {
|
||||||
|
return (product?.monthlyPrice?.id === priceId) || (product?.yearlyPrice?.id === priceId);
|
||||||
|
});
|
||||||
|
let cadence = 'month';
|
||||||
|
if (tier?.yearlyPrice?.id === priceId) {
|
||||||
|
cadence = 'year';
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
tierId: tier?.id,
|
||||||
|
cadence
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
export function getAvailablePrices({site, products = null}) {
|
export function getAvailablePrices({site, products = null}) {
|
||||||
const {
|
const {
|
||||||
portal_plans: portalPlans = [],
|
portal_plans: portalPlans = [],
|
||||||
@ -659,3 +688,61 @@ export const getUpdatedOfferPrice = ({offer, price, useFormatted = false}) => {
|
|||||||
export const isActiveOffer = ({offer}) => {
|
export const isActiveOffer = ({offer}) => {
|
||||||
return offer?.status === 'active';
|
return offer?.status === 'active';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function createMonthlyPrice({tier, priceId}) {
|
||||||
|
if (tier?.monthly_price) {
|
||||||
|
return {
|
||||||
|
id: `price-${priceId}`,
|
||||||
|
active: true,
|
||||||
|
type: 'recurring',
|
||||||
|
nickname: 'Monthly',
|
||||||
|
currency: tier.currency,
|
||||||
|
amount: tier.monthly_price,
|
||||||
|
interval: 'month'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function createYearlyPrice({tier, priceId}) {
|
||||||
|
if (tier?.yearly_price) {
|
||||||
|
return {
|
||||||
|
id: `price-${priceId}`,
|
||||||
|
active: true,
|
||||||
|
type: 'recurring',
|
||||||
|
nickname: 'Yearly',
|
||||||
|
currency: tier.currency,
|
||||||
|
amount: tier.yearly_price,
|
||||||
|
interval: 'year'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function createBenefits({tier}) {
|
||||||
|
tier?.benefits?.map((benefit) => {
|
||||||
|
return {
|
||||||
|
name: benefit
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export const transformApiTiersData = ({tiers}) => {
|
||||||
|
let priceId = 0;
|
||||||
|
|
||||||
|
return tiers.map((tier) => {
|
||||||
|
let monthlyPrice = createMonthlyPrice({tier, priceId});
|
||||||
|
priceId += 1;
|
||||||
|
|
||||||
|
let yearlyPrice = createYearlyPrice({tier, priceId});
|
||||||
|
priceId += 1;
|
||||||
|
|
||||||
|
let benefits = createBenefits({tier});
|
||||||
|
return {
|
||||||
|
...tier,
|
||||||
|
benefits: benefits,
|
||||||
|
monthly_price: monthlyPrice,
|
||||||
|
yearly_price: yearlyPrice
|
||||||
|
};
|
||||||
|
});
|
||||||
|
};
|
||||||
|
@ -169,6 +169,8 @@ describe('Helpers - ', () => {
|
|||||||
const value = getPriceFromSubscription({subscription});
|
const value = getPriceFromSubscription({subscription});
|
||||||
expect(value).toStrictEqual({
|
expect(value).toStrictEqual({
|
||||||
...subscription.price,
|
...subscription.price,
|
||||||
|
tierId: undefined,
|
||||||
|
cadence: 'year',
|
||||||
stripe_price_id: subscription.price.id,
|
stripe_price_id: subscription.price.id,
|
||||||
id: subscription.price.price_id,
|
id: subscription.price.price_id,
|
||||||
price: subscription.price.amount / 100,
|
price: subscription.price.amount / 100,
|
||||||
|
Loading…
Reference in New Issue
Block a user