Skip to content

Commit 04a9e51

Browse files
Merge pull request #20423 from mozilla/PAY-3656
fix(payments-next): Add free trial reactivation email variant
2 parents 448ad5b + 4a5f421 commit 04a9e51

17 files changed

Lines changed: 132 additions & 21 deletions

File tree

libs/accounts/email-renderer/src/renderer/subplat-email-renderer.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,9 @@ export class SubplatEmailRender extends EmailRenderer {
237237
template: SubscriptionReactivation.template,
238238
version: SubscriptionReactivation.version,
239239
layout: SubscriptionReactivation.layout,
240-
includes: SubscriptionReactivation.includes,
240+
includes: SubscriptionReactivation.getIncludes(
241+
templateValues.isFreeTrialReactivation
242+
),
241243
...templateValues,
242244
...layoutTemplateValues,
243245
});
Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,16 @@
11
# Variables:
22
# $productName (String) - The name of the subscribed product, e.g. Mozilla VPN
3-
subscriptionReactivation-subject = { $productName } subscription reactivated
3+
subscriptionReactivation-subject-2 = Your { $productName } subscription has been reactivated
4+
# Variables:
5+
# $productName (String) - The name of the subscribed product, e.g. Mozilla VPN
6+
subscriptionReactivation-freeTrial-subject = Your { $productName } trial has been reactivated
47
# Variables:
58
# $productName (String) - The name of the subscribed product, e.g. Mozilla VPN
69
subscriptionReactivation-title = Thank you for reactivating your { $productName } subscription!
710
# Variables:
11+
# $productName (String) - The name of the subscribed product, e.g. Mozilla VPN
12+
subscriptionReactivation-freeTrial-title = Thank you for reactivating your { $productName } trial!
13+
# Variables:
814
# $invoiceTotal (String) - The amount of the subscription invoice, including currency, e.g. $10.00
915
# $nextInvoiceDateOnly (String) - The date of the next invoice, e.g. 2016/01/20
1016
subscriptionReactivation-content = Your billing cycle and payment will remain the same. Your next charge will be { $invoiceTotal } on { $nextInvoiceDateOnly }. Your subscription will automatically renew each billing period unless you choose to cancel.

libs/accounts/email-renderer/src/templates/subscriptionReactivation/index.mjml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,11 @@
77
<mj-section>
88
<mj-column>
99
<mj-text css-class="text-header">
10-
<span data-l10n-id="subscriptionReactivation-title" data-l10n-args="<%= JSON.stringify({productName}) %>">Thank you for reactivating your <%- productName %> subscription!</span>
10+
<% if (isFreeTrialReactivation) { %>
11+
<span data-l10n-id="subscriptionReactivation-freeTrial-title" data-l10n-args="<%= JSON.stringify({productName}) %>">Thank you for reactivating your <%- productName %> trial!</span>
12+
<% } else { %>
13+
<span data-l10n-id="subscriptionReactivation-title" data-l10n-args="<%= JSON.stringify({productName}) %>">Thank you for reactivating your <%- productName %> subscription!</span>
14+
<% } %>
1115
</mj-text>
1216

1317
<mj-text css-class="text-body">

libs/accounts/email-renderer/src/templates/subscriptionReactivation/index.stories.ts

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
import { Meta } from '@storybook/html';
66
import { subplatStoryWithProps } from '../../storybook-email';
7-
import { includes, TemplateData } from './index';
7+
import { getIncludes, TemplateData } from './index';
88

99
export default {
1010
title: 'SubPlat Emails/Templates/subscriptionReactivation',
@@ -16,13 +16,28 @@ const data = {
1616
nextInvoiceDateOnly: '11/13/2021',
1717
icon: 'https://placekitten.com/512/512',
1818
subscriptionSupportUrl: 'http://localhost:3030/support',
19+
isFreeTrialReactivation: false,
1920
};
2021

2122
const createStory = subplatStoryWithProps<TemplateData>(
2223
'subscriptionReactivation',
2324
'Sent when a user reactivates their subscription.',
2425
data,
25-
includes
26+
getIncludes(data.isFreeTrialReactivation)
2627
);
2728

2829
export const SubscriptionReactivation = createStory();
30+
31+
const freeTrialData = {
32+
...data,
33+
isFreeTrialReactivation: true,
34+
};
35+
36+
const createFreeTrialStory = subplatStoryWithProps<TemplateData>(
37+
'subscriptionReactivation',
38+
'Sent when a user reactivates their subscription while still in a free trial.',
39+
freeTrialData,
40+
getIncludes(freeTrialData.isFreeTrialReactivation)
41+
);
42+
43+
export const SubscriptionReactivationFreeTrial = createFreeTrialStory();

libs/accounts/email-renderer/src/templates/subscriptionReactivation/index.ts

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,23 @@ export type TemplateData = IconTemplateData &
1212
nextInvoiceDateOnly: string;
1313
icon: string;
1414
subscriptionSupportUrl: string;
15+
isFreeTrialReactivation: boolean;
1516
};
1617

1718
export const template = 'subscriptionReactivation';
18-
export const version = 2;
19+
export const version = 3;
1920
export const layout = 'subscription';
20-
export const includes = {
21-
subject: {
22-
id: 'subscriptionReactivation-subject-2',
23-
message: 'Your <%- productName %> subscription has been reactivated',
24-
},
25-
};
21+
22+
export function getIncludes(isFreeTrialReactivation: boolean) {
23+
return {
24+
subject: isFreeTrialReactivation
25+
? {
26+
id: 'subscriptionReactivation-freeTrial-subject',
27+
message: 'Your <%- productName %> trial has been reactivated',
28+
}
29+
: {
30+
id: 'subscriptionReactivation-subject-2',
31+
message: 'Your <%- productName %> subscription has been reactivated',
32+
},
33+
};
34+
}

libs/accounts/email-renderer/src/templates/subscriptionReactivation/index.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1+
<% if (isFreeTrialReactivation) { %>
2+
subscriptionReactivation-freeTrial-title = "Thank you for reactivating your <%- productName %> trial!"
3+
<% } else { %>
14
subscriptionReactivation-title = "Thank you for reactivating your <%- productName %> subscription!"
5+
<% } %>
26

37
subscriptionReactivation-content = "Your billing cycle and payment will remain the same. Your next charge will be <%- invoiceTotal %> on <%- nextInvoiceDateOnly %>. Your subscription will automatically renew each billing period unless you choose to cancel."
48

packages/fxa-auth-server/lib/payments/stripe.spec.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7237,6 +7237,7 @@ describe('StripeHelper', () => {
72377237
cardType: card.brand,
72387238
lastFour: card.last4,
72397239
nextInvoiceDate: new Date(mockInvoice.lines.data[0].period.end * 1000),
7240+
isFreeTrialReactivation: false,
72407241
};
72417242

72427243
const { lastFour, cardType } = defaultExpected;
@@ -7279,6 +7280,24 @@ describe('StripeHelper', () => {
72797280
expect(result).toEqual(defaultExpected);
72807281
});
72817282

7283+
it('sets isFreeTrialReactivation to true when subscription status is trialing', async () => {
7284+
const event = deepCopy(eventCustomerSubscriptionUpdated);
7285+
event.data.object.status = 'trialing';
7286+
jest
7287+
.spyOn(stripeHelper, 'fetchCustomer')
7288+
.mockResolvedValue(reactivationMockCustomer);
7289+
const result =
7290+
await stripeHelper.extractSubscriptionUpdateReactivationDetailsForEmail(
7291+
event.data.object,
7292+
expectedBaseUpdateDetails,
7293+
mockInvoice
7294+
);
7295+
expect(result).toEqual({
7296+
...defaultExpected,
7297+
isFreeTrialReactivation: true,
7298+
});
7299+
});
7300+
72827301
it('does not throw an exception when payment method is missing', async () => {
72837302
const event = deepCopy(eventCustomerSubscriptionUpdated);
72847303
const customerNoPayment = deepCopy(reactivationMockCustomer);

packages/fxa-auth-server/lib/payments/stripe.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3380,6 +3380,7 @@ export class StripeHelper extends StripeHelperBase {
33803380
nextInvoiceDate: nextInvoiceDate
33813381
? new Date(nextInvoiceDate * 1000)
33823382
: null,
3383+
isFreeTrialReactivation: subscription.status === 'trialing',
33833384
planConfig,
33843385
};
33853386
}

packages/fxa-auth-server/lib/senders/email.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3092,6 +3092,7 @@ module.exports = function (log, config, bounces, statsd) {
30923092
lastFour,
30933093
nextInvoiceDate,
30943094
payment_provider,
3095+
isFreeTrialReactivation = false,
30953096
} = message;
30963097

30973098
const enabled = config.subscriptions.transactionalEmails.enabled;
@@ -3142,6 +3143,7 @@ module.exports = function (log, config, bounces, statsd) {
31423143
cardName: cardTypeToText(cardType),
31433144
lastFour,
31443145
nextInvoiceDate,
3146+
isFreeTrialReactivation,
31453147
},
31463148
});
31473149
};

packages/fxa-auth-server/lib/senders/emails/templates/_versions.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"freeTrialEndingReminder": 2,
3-
"subscriptionReactivation": 2,
3+
"subscriptionReactivation": 3,
44
"subscriptionRenewalReminder": 4,
55
"subscriptionEndingReminder": 2,
66
"subscriptionUpgrade": 7,

0 commit comments

Comments
 (0)