Skip to content

Commit 5dcc11e

Browse files
authored
Merge pull request #20149 from mozilla/fxa-13020-otp-cms-customization
feat(auth): add cms customization to otp
2 parents 4882bcb + 29a12d4 commit 5dcc11e

29 files changed

Lines changed: 1918 additions & 107 deletions

File tree

libs/accounts/email-renderer/src/renderer/__snapshots__/fxa-email-renderer.spec.ts.snap

Lines changed: 820 additions & 10 deletions
Large diffs are not rendered by default.

libs/accounts/email-renderer/src/renderer/fxa-email-renderer.spec.ts

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,12 @@ const defaultLayoutTemplateValues = {
4545
unsubscribeUrl: 'http://localhost:3030/unsubscribe',
4646
};
4747

48+
const defaultCmsValues = {
49+
subject: 'subject line',
50+
headline: 'headline...line',
51+
description: 'description line',
52+
};
53+
4854
describe('FxA Email Renderer', () => {
4955
let renderer: FxaEmailRenderer;
5056

@@ -206,7 +212,24 @@ describe('FxA Email Renderer', () => {
206212
time: '12:00 PM',
207213
device: mockDevice,
208214
location: mockLocation,
215+
target: 'index',
216+
...defaultLayoutTemplateValues,
217+
});
218+
expect(email).toBeDefined();
219+
expect(email.html).toMatchSnapshot('matches full email snapshot');
220+
});
221+
222+
it('should render renderPasswordlessSigninOtp strapi', async () => {
223+
const email = await renderer.renderPasswordlessSigninOtp({
224+
code: '96318398',
225+
codeExpiryMinutes: 10,
226+
date: 'Jan 1, 2024',
227+
time: '12:00 PM',
228+
device: mockDevice,
229+
location: mockLocation,
230+
target: 'strapi',
209231
...defaultLayoutTemplateValues,
232+
...defaultCmsValues,
210233
});
211234
expect(email).toBeDefined();
212235
expect(email.html).toMatchSnapshot('matches full email snapshot');
@@ -220,7 +243,24 @@ describe('FxA Email Renderer', () => {
220243
time: '12:00 PM',
221244
device: mockDevice,
222245
location: mockLocation,
246+
target: 'index',
247+
...defaultLayoutTemplateValues,
248+
});
249+
expect(email).toBeDefined();
250+
expect(email.html).toMatchSnapshot('matches full email snapshot');
251+
});
252+
253+
it('should render renderPasswordlessSignupOtp strapi', async () => {
254+
const email = await renderer.renderPasswordlessSignupOtp({
255+
code: '96318398',
256+
codeExpiryMinutes: 10,
257+
date: 'Jan 1, 2024',
258+
time: '12:00 PM',
259+
device: mockDevice,
260+
location: mockLocation,
261+
target: 'strapi',
223262
...defaultLayoutTemplateValues,
263+
...defaultCmsValues,
224264
});
225265
expect(email).toBeDefined();
226266
expect(email.html).toMatchSnapshot('matches full email snapshot');

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,12 @@ export default {
1111
title: 'FxA Emails/Templates/passwordlessSigninOtp',
1212
} as Meta;
1313

14-
const data = {
14+
const data: TemplateData = {
1515
...MOCK_USER_INFO,
1616
code: '96318398',
1717
codeExpiryMinutes: 10,
1818
supportUrl: 'https://support.mozilla.org',
19+
target: 'index',
1920
};
2021

2122
const createStory = storyWithProps<TemplateData>(

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,14 @@ export type TemplateData = AutomatedEmailNoActionTemplateData &
1111
codeExpiryMinutes: number;
1212
time: string;
1313
date: string;
14+
15+
cmsRpClientId?: string;
16+
cmsRpFromName?: string;
17+
entrypoint?: string;
18+
subject?: string;
19+
headline?: string;
20+
description?: string;
21+
target: 'index' | 'strapi';
1422
};
1523

1624
export const template = 'passwordlessSigninOtp';
@@ -26,3 +34,4 @@ export const includes = {
2634
message: 'Code expires in <%- codeExpiryMinutes %> minutes',
2735
},
2836
};
37+
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
<%# This Source Code Form is subject to the terms of the Mozilla Public
2+
# License, v. 2.0. If a copy of the MPL was not distributed with this
3+
# file, You can obtain one at http://mozilla.org/MPL/2.0/. %>
4+
5+
<mj-section>
6+
<mj-column>
7+
<mj-text css-class="text-header">
8+
<span><%- locals.headline %></span>
9+
</mj-text>
10+
11+
<mj-text css-class="text-body">
12+
<span><%- locals.description %></span>
13+
</mj-text>
14+
</mj-column>
15+
</mj-section>
16+
17+
<%- include('/partials/userInfo/index.mjml') %>
18+
19+
<mj-section>
20+
<mj-column>
21+
22+
<mj-text css-class="text-body">
23+
<span data-l10n-id="passwordless-signin-otp-code">
24+
Use this confirmation code:
25+
</span>
26+
</mj-text>
27+
28+
<mj-text css-class="code-large"><%- code %></mj-text>
29+
30+
<mj-text css-class="text-body-no-margin">
31+
<span data-l10n-id="passwordless-signin-otp-expiry-notice" data-l10n-args='{"codeExpiryMinutes": <%- codeExpiryMinutes %>}'>It expires in <%- codeExpiryMinutes %> minutes.</span>
32+
</mj-text>
33+
</mj-column>
34+
</mj-section>
35+
36+
<mj-section>
37+
<mj-column>
38+
<mj-text css-class="text-body-subtext">
39+
<%- include('/partials/automatedEmailNoAction/index.mjml') %>
40+
</mj-text>
41+
</mj-column>
42+
</mj-section>
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/* This Source Code Form is subject to the terms of the Mozilla Public
2+
* License, v. 2.0. If a copy of the MPL was not distributed with this
3+
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4+
5+
import { Meta } from '@storybook/html';
6+
import { MOCK_USER_INFO } from '../../partials/userInfo/mocks';
7+
import { includes, TemplateData } from './index';
8+
import { storyWithProps } from '../../storybook-email';
9+
10+
export default {
11+
title: 'FxA Emails/Templates/passwordlessSigninOtp/Strapi',
12+
} as Meta;
13+
14+
const data: TemplateData = {
15+
...MOCK_USER_INFO,
16+
code: '12345678',
17+
codeExpiryMinutes: 10,
18+
supportUrl: 'https://support.mozilla.org',
19+
time: '11:45 AM',
20+
date: 'March 5, 2026',
21+
cmsRpClientId: '00f00f',
22+
cmsRpFromName: 'Testo Inc.',
23+
entrypoint: 'quux',
24+
subject: 'Finish your sign in',
25+
headline: 'Complete your sign in to Product',
26+
description:
27+
'Use the code below to verify your sign-in and access your account.',
28+
target: 'strapi',
29+
};
30+
31+
const createStory = storyWithProps<TemplateData>(
32+
'passwordlessSigninOtp',
33+
'Sent to verify a passwordless sign-in via OTP code.',
34+
data,
35+
includes
36+
);
37+
38+
export const PasswordlessSigninOtpEmailStrapi = createStory();
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<%- locals.headline %>
2+
3+
<%- locals.description %>
4+
5+
<%- include('/partials/userInfo/index.txt') %>
6+
7+
passwordless-signin-otp-code = "Use this confirmation code:"
8+
9+
<%- code %>
10+
11+
passwordless-signin-otp-expiry-notice = "It expires in <%- codeExpiryMinutes %> minutes."
12+
13+
<%- include('/partials/automatedEmailNoAction/index.txt') %>

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,12 @@ export default {
1111
title: 'FxA Emails/Templates/passwordlessSignupOtp',
1212
} as Meta;
1313

14-
const data = {
14+
const data: TemplateData = {
1515
...MOCK_USER_INFO,
1616
code: '96318398',
1717
codeExpiryMinutes: 10,
1818
supportUrl: 'https://support.mozilla.org',
19+
target: 'index',
1920
};
2021

2122
const createStory = storyWithProps<TemplateData>(

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,14 @@ export type TemplateData = AutomatedEmailNoActionTemplateData &
1111
codeExpiryMinutes: number;
1212
time: string;
1313
date: string;
14+
15+
cmsRpClientId?: string;
16+
cmsRpFromName?: string;
17+
entrypoint?: string;
18+
subject?: string;
19+
headline?: string;
20+
description?: string;
21+
target: 'index' | 'strapi';
1422
};
1523

1624
export const template = 'passwordlessSignupOtp';
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
<%# This Source Code Form is subject to the terms of the Mozilla Public
2+
# License, v. 2.0. If a copy of the MPL was not distributed with this
3+
# file, You can obtain one at http://mozilla.org/MPL/2.0/. %>
4+
5+
<mj-section>
6+
<mj-column>
7+
<mj-text css-class="text-header">
8+
<span><%- locals.headline %></span>
9+
</mj-text>
10+
11+
<mj-text css-class="text-body">
12+
<span><%- locals.description %></span>
13+
</mj-text>
14+
</mj-column>
15+
</mj-section>
16+
17+
<%- include('/partials/userInfo/index.mjml') %>
18+
19+
<mj-section>
20+
<mj-column>
21+
22+
<mj-text css-class="text-body">
23+
<span data-l10n-id="passwordless-signup-otp-code">
24+
Use this confirmation code:
25+
</span>
26+
</mj-text>
27+
28+
<mj-text css-class="code-large"><%- code %></mj-text>
29+
30+
<mj-text css-class="text-body-no-margin">
31+
<span data-l10n-id="passwordless-signup-otp-expiry-notice" data-l10n-args='{"codeExpiryMinutes": <%- codeExpiryMinutes %>}'>It expires in <%- codeExpiryMinutes %> minutes.</span>
32+
</mj-text>
33+
</mj-column>
34+
</mj-section>
35+
36+
<mj-section>
37+
<mj-column>
38+
<mj-text css-class="text-body-subtext">
39+
<%- include('/partials/automatedEmailNoAction/index.mjml') %>
40+
</mj-text>
41+
</mj-column>
42+
</mj-section>

0 commit comments

Comments
 (0)