0
Fork 0
mirror of https://github.com/TryGhost/Ghost.git synced 2025-04-15 03:01:37 -05:00

Added recommendation modal trigger on signup (#17925)

refs https://github.com/TryGhost/Product/issues/3771

- if recommendations are enabled, render the recommendation modal on
sign up, in Portal
- for free signups, the recommendations modal is rendered after clicking
on the magic link
- for paid signups, the recommendations modal is rendered after Stripe
Checkout
- the recommendations modal is not rendered on a free to paid upgrade
This commit is contained in:
Sag 2023-09-04 16:35:56 +02:00 committed by GitHub
parent d4b717493c
commit d7504bdbf5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 150 additions and 9 deletions

View file

@ -96,15 +96,25 @@ async function signin({data, api, state}) {
async function signup({data, state, api}) {
try {
const {recommendations_enabled: recommendationsEnabled = false} = state.site;
const {recommendations = []} = state.site;
let successUrl = undefined;
if (recommendationsEnabled && recommendations.length > 0) {
const currentUrl = window.location.origin + window.location.pathname;
successUrl = `${currentUrl}#/portal/recommendations`;
}
let {plan, tierId, cadence, email, name, newsletters, offerId} = data;
if (plan.toLowerCase() === 'free') {
await api.member.sendMagicLink({emailType: 'signup', ...data});
await api.member.sendMagicLink({emailType: 'signup', ...data, redirect: successUrl});
} else {
if (tierId && cadence) {
await api.member.checkoutPlan({plan, tierId, cadence, email, name, newsletters, offerId});
await api.member.checkoutPlan({plan, tierId, cadence, email, name, newsletters, offerId, successUrl});
} else {
({tierId, cadence} = getProductCadenceFromPrice({site: state?.site, priceId: plan}));
await api.member.checkoutPlan({plan, tierId, cadence, email, name, newsletters, offerId});
await api.member.checkoutPlan({plan, tierId, cadence, email, name, newsletters, offerId, successUrl});
}
return {
page: 'loading'

View file

@ -537,9 +537,7 @@ describe('Signup', () => {
window.location.hash = '';
});
});
});
describe('Signup', () => {
describe('as free member on multi tier site', () => {
test('with default settings', async () => {
const {
@ -784,4 +782,114 @@ describe('Signup', () => {
window.location.hash = '';
});
});
describe('recommendations', () => {
describe('free member signup', () => {
test('does not redirect to the recommendations modal if recommendations are disabled', async () => {
const {
ghostApi, emailInput, nameInput, chooseBtns
} = await setup({
// Recommendations are disabled (default)
site: FixtureSite.singleTier.basic
});
// Fill signup form as free member
fireEvent.change(nameInput, {target: {value: 'Jamie Larsen'}});
fireEvent.change(emailInput, {target: {value: 'jamie@example.com'}});
fireEvent.click(chooseBtns[0]);
expect(ghostApi.member.sendMagicLink).toHaveBeenLastCalledWith({
email: 'jamie@example.com',
emailType: 'signup',
name: 'Jamie Larsen',
plan: 'free',
redirect: undefined
});
});
test('redirects the recommendations modal if recommendations are enabled', async () => {
const {
ghostApi, emailInput, nameInput, chooseBtns
} = await setup({
// Recommendations are enabled
site: FixtureSite.singleTier.withRecommendations
});
// Fill signup form as free member
fireEvent.change(nameInput, {target: {value: 'Jamie Larsen'}});
fireEvent.change(emailInput, {target: {value: 'jamie@example.com'}});
fireEvent.click(chooseBtns[0]);
const currentUrl = new URL(window.location.origin + window.location.pathname);
expect(ghostApi.member.sendMagicLink).toHaveBeenLastCalledWith({
email: 'jamie@example.com',
emailType: 'signup',
name: 'Jamie Larsen',
plan: 'free',
redirect: `${currentUrl}#/portal/recommendations`
});
});
});
describe('paid member signup', () => {
test('does not redirect to the recommendations modal if recommendations are disabled', async () => {
const {
ghostApi, emailInput, nameInput, popupIframeDocument, submitButton
} = await setup({
// Recommendations are disabled (default)
site: FixtureSite.singleTier.basic
});
const yearlyPlanContainer = within(popupIframeDocument).queryByText(/Yearly$/);
const singleTierProduct = FixtureSite.singleTier.basic.products.find(p => p.type === 'paid');
// Fill signup form as free member
fireEvent.change(nameInput, {target: {value: 'Jamie Larsen'}});
fireEvent.change(emailInput, {target: {value: 'jamie@example.com'}});
fireEvent.click(yearlyPlanContainer.parentNode);
fireEvent.click(submitButton);
expect(ghostApi.member.checkoutPlan).toHaveBeenLastCalledWith({
email: 'jamie@example.com',
name: 'Jamie Larsen',
offerId: undefined,
plan: singleTierProduct.yearlyPrice.id,
tierId: singleTierProduct.id,
cadence: 'year',
successUrl: undefined
});
});
test('redirects to the recommendations modal if recommendations are enabled', async () => {
const {
ghostApi, emailInput, nameInput, popupIframeDocument, submitButton
} = await setup({
// Recommendations are disabled (default)
site: FixtureSite.singleTier.withRecommendations
});
const yearlyPlanContainer = within(popupIframeDocument).queryByText(/Yearly$/);
const singleTierProduct = FixtureSite.singleTier.basic.products.find(p => p.type === 'paid');
// Fill signup form as free member
fireEvent.change(nameInput, {target: {value: 'Jamie Larsen'}});
fireEvent.change(emailInput, {target: {value: 'jamie@example.com'}});
fireEvent.click(yearlyPlanContainer.parentNode);
fireEvent.click(submitButton);
const currentUrl = new URL(window.location.origin + window.location.pathname);
expect(ghostApi.member.checkoutPlan).toHaveBeenLastCalledWith({
email: 'jamie@example.com',
name: 'Jamie Larsen',
offerId: undefined,
plan: singleTierProduct.yearlyPrice.id,
tierId: singleTierProduct.id,
cadence: 'year',
successUrl: `${currentUrl}#/portal/recommendations`
});
});
});
});
});

View file

@ -40,7 +40,9 @@ export function getSiteData({
portalButtonStyle: portal_button_style = 'icon-and-text',
membersSupportAddress: members_support_address = 'support@example.com',
newsletters = [],
commentsEnabled
commentsEnabled,
recommendations = [],
recommendationsEnabled
} = {}) {
return {
title,
@ -65,7 +67,9 @@ export function getSiteData({
portal_button_style,
members_support_address,
comments_enabled: !!commentsEnabled,
newsletters
newsletters,
recommendations,
recommendations_enabled: !!recommendationsEnabled
};
}

View file

@ -102,7 +102,9 @@ const baseSingleTierSite = getSiteData({
portalButtonIcon: 'icon-1',
portalButtonSignupText: 'Subscribe now',
portalButtonStyle: 'icon-and-text',
membersSupportAddress: 'support@example.com'
membersSupportAddress: 'support@example.com',
recommendationsEnabled: false,
recommendations: []
});
const baseMultiTierSite = getSiteData({
@ -130,7 +132,9 @@ const baseMultiTierSite = getSiteData({
portalButtonIcon: 'icon-1',
portalButtonSignupText: 'Subscribe now',
portalButtonStyle: 'icon-and-text',
membersSupportAddress: 'support@example.com'
membersSupportAddress: 'support@example.com',
recommendationsEnabled: false,
recommendations: []
});
export const site = {
@ -168,6 +172,11 @@ export const site = {
membersDisabled: {
...baseSingleTierSite,
members_signup_access: 'none'
},
withRecommendations: {
...baseSingleTierSite,
recommendations_enabled: true,
recommendations: [{title: 'Recommendation 1', url: 'https://recommendation-1.org'}, {title: 'Recommendation 2', url: 'https://recommendation-2.org'}]
}
},
multipleTiers: {
@ -183,6 +192,11 @@ export const site = {
withoutName: {
...baseMultiTierSite,
portal_name: false
},
withRecommendations: {
...baseMultiTierSite,
recommendations_enabled: true,
recommendations: [{title: 'Recommendation 1', url: 'https://recommendation-1.org'}, {title: 'Recommendation 2', url: 'https://recommendation-2.org'}]
}
}
};

View file

@ -105,6 +105,11 @@ export default Model.extend(ValidationEngine, {
donationsCurrency: attr('string'),
donationsSuggestedAmount: attr('number'),
/**
* Recommendations
*/
recommendationsEnabled: attr('boolean'),
// HACK - not a real model attribute but a workaround for Ember Data not
// exposing meta from save responses
_meta: attr()