Skip to content

Commit 5ca1e9d

Browse files
authored
fix: MailToLink to account for no emails (#230)
2 parents c2a20af + b83f128 commit 5ca1e9d

File tree

11 files changed

+226
-71
lines changed

11 files changed

+226
-71
lines changed

src/components/EmailLink.jsx

Lines changed: 0 additions & 17 deletions
This file was deleted.

src/components/EmailLink.test.jsx

Lines changed: 0 additions & 16 deletions
This file was deleted.

src/components/__snapshots__/EmailLink.test.jsx.snap

Lines changed: 0 additions & 11 deletions
This file was deleted.

src/containers/CourseCard/components/CourseCardBanners/CertificateBanner.jsx

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,17 +26,14 @@ export const CertificateBanner = ({ cardId }) => {
2626
const { formatMessage } = useIntl();
2727
const formatDate = useFormatDate();
2828

29-
const emailLink = address => address && <MailtoLink to={address}>{address}</MailtoLink>;
29+
const emailLink = address => <MailtoLink to={address}>{address}</MailtoLink>;
3030

3131
if (certificate.isRestricted) {
3232
return (
3333
<Banner variant="danger">
34-
{formatMessage(messages.certRestricted, { supportEmail: emailLink(supportEmail) })}
34+
{ supportEmail ? formatMessage(messages.certRestricted, { supportEmail: emailLink(supportEmail) }) : formatMessage(messages.certRestrictedNoEmail)}
3535
{isVerified && ' '}
36-
{isVerified && formatMessage(
37-
messages.certRefundContactBilling,
38-
{ billingEmail: emailLink(billingEmail) },
39-
)}
36+
{isVerified && (billingEmail ? formatMessage(messages.certRefundContactBilling, { billingEmail: emailLink(billingEmail) }) : formatMessage(messages.certRefundContactBillingNoEmail))}
4037
</Banner>
4138
);
4239
}

src/containers/CourseCard/components/CourseCardBanners/CertificateBanner.test.jsx

Lines changed: 76 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,6 @@ jest.mock('components/Banner', () => 'Banner');
2121

2222
describe('CertificateBanner', () => {
2323
const props = { cardId: 'cardId' };
24-
reduxHooks.usePlatformSettingsData.mockReturnValue({
25-
supportEmail: 'suport@email',
26-
billingEmail: 'billing@email',
27-
});
2824
reduxHooks.useCardCourseRunData.mockReturnValue({
2925
minPassingGrade: 0.8,
3026
progressUrl: 'progressUrl',
@@ -42,16 +38,19 @@ describe('CertificateBanner', () => {
4238
};
4339
const defaultCourseRun = { isArchived: false };
4440
const defaultGrade = { isPassing: false };
41+
const defaultPlatformSettings = {};
4542
const createWrapper = ({
4643
certificate = {},
4744
enrollment = {},
4845
grade = {},
4946
courseRun = {},
47+
platformSettings = {},
5048
}) => {
5149
reduxHooks.useCardGradeData.mockReturnValueOnce({ ...defaultGrade, ...grade });
5250
reduxHooks.useCardCertificateData.mockReturnValueOnce({ ...defaultCertificate, ...certificate });
5351
reduxHooks.useCardEnrollmentData.mockReturnValueOnce({ ...defaultEnrollment, ...enrollment });
5452
reduxHooks.useCardCourseRunData.mockReturnValueOnce({ ...defaultCourseRun, ...courseRun });
53+
reduxHooks.usePlatformSettingsData.mockReturnValueOnce({ ...defaultPlatformSettings, ...platformSettings });
5554
return shallow(<CertificateBanner {...props} />);
5655
};
5756
/** TODO: Update tests to validate snapshots **/
@@ -64,6 +63,28 @@ describe('CertificateBanner', () => {
6463
});
6564
expect(wrapper).toMatchSnapshot();
6665
});
66+
test('is restricted with support email', () => {
67+
const wrapper = createWrapper({
68+
certificate: {
69+
isRestricted: true,
70+
},
71+
platformSettings: {
72+
supportEmail: 'suport@email',
73+
},
74+
});
75+
expect(wrapper).toMatchSnapshot();
76+
});
77+
test('is restricted with billing email', () => {
78+
const wrapper = createWrapper({
79+
certificate: {
80+
isRestricted: true,
81+
},
82+
platformSettings: {
83+
billingEmail: 'billing@email',
84+
},
85+
});
86+
expect(wrapper).toMatchSnapshot();
87+
});
6788
test('is restricted and verified', () => {
6889
const wrapper = createWrapper({
6990
certificate: {
@@ -75,6 +96,49 @@ describe('CertificateBanner', () => {
7596
});
7697
expect(wrapper).toMatchSnapshot();
7798
});
99+
test('is restricted and verified with support email', () => {
100+
const wrapper = createWrapper({
101+
certificate: {
102+
isRestricted: true,
103+
},
104+
enrollment: {
105+
isVerified: true,
106+
},
107+
platformSettings: {
108+
supportEmail: 'suport@email',
109+
},
110+
});
111+
expect(wrapper).toMatchSnapshot();
112+
});
113+
test('is restricted and verified with billing email', () => {
114+
const wrapper = createWrapper({
115+
certificate: {
116+
isRestricted: true,
117+
},
118+
enrollment: {
119+
isVerified: true,
120+
},
121+
platformSettings: {
122+
billingEmail: 'billing@email',
123+
},
124+
});
125+
expect(wrapper).toMatchSnapshot();
126+
});
127+
test('is restricted and verified with support and billing email', () => {
128+
const wrapper = createWrapper({
129+
certificate: {
130+
isRestricted: true,
131+
},
132+
enrollment: {
133+
isVerified: true,
134+
},
135+
platformSettings: {
136+
supportEmail: 'suport@email',
137+
billingEmail: 'billing@email',
138+
},
139+
});
140+
expect(wrapper).toMatchSnapshot();
141+
});
78142
test('is passing and is downloadable', () => {
79143
const wrapper = createWrapper({
80144
grade: { isPassing: true },
@@ -133,6 +197,10 @@ describe('CertificateBanner', () => {
133197
certificate: {
134198
isRestricted: true,
135199
},
200+
platformSettings: {
201+
supportEmail: 'suport@email',
202+
billingEmail: 'billing@email',
203+
},
136204
});
137205
const bannerMessage = wrapper.find('format-message-function').map(el => el.prop('message').defaultMessage).join('\n');
138206
expect(bannerMessage).toEqual(messages.certRestricted.defaultMessage);
@@ -146,6 +214,10 @@ describe('CertificateBanner', () => {
146214
enrollment: {
147215
isVerified: true,
148216
},
217+
platformSettings: {
218+
supportEmail: 'suport@email',
219+
billingEmail: 'billing@email',
220+
},
149221
});
150222
const bannerMessage = wrapper.find('format-message-function').map(el => el.prop('message').defaultMessage).join('\n');
151223
expect(bannerMessage).toContain(messages.certRestricted.defaultMessage);

src/containers/CourseCard/components/CourseCardBanners/CreditBanner/__snapshots__/index.test.jsx.snap

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,11 @@ exports[`CreditBanner component render with error state snapshot 1`] = `
1717
}
1818
values={
1919
Object {
20-
"supportEmailLink": <EmailLink
21-
address="test-support-email"
22-
/>,
20+
"supportEmailLink": <MailtoLink
21+
to="test-support-email"
22+
>
23+
test-support-email
24+
</MailtoLink>,
2325
}
2426
}
2527
/>
@@ -30,6 +32,21 @@ exports[`CreditBanner component render with error state snapshot 1`] = `
3032
</Banner>
3133
`;
3234

35+
exports[`CreditBanner component render with error state with no email snapshot 1`] = `
36+
<Banner
37+
variant="danger"
38+
>
39+
<p
40+
className="credit-error-msg"
41+
>
42+
An error occurred with this transaction.
43+
</p>
44+
<ContentComponent
45+
cardId="test-card-id"
46+
/>
47+
</Banner>
48+
`;
49+
3350
exports[`CreditBanner component render with no error state snapshot 1`] = `
3451
<Banner>
3552
<ContentComponent

src/containers/CourseCard/components/CourseCardBanners/CreditBanner/index.jsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ import PropTypes from 'prop-types';
44
import { useIntl } from '@edx/frontend-platform/i18n';
55

66
import Banner from 'components/Banner';
7-
import EmailLink from 'components/EmailLink';
87

8+
import { MailtoLink } from '@edx/paragon';
99
import hooks from './hooks';
1010
import messages from './messages';
1111

@@ -15,13 +15,14 @@ export const CreditBanner = ({ cardId }) => {
1515
if (hookData === null) {
1616
return null;
1717
}
18+
1819
const { ContentComponent, error, supportEmail } = hookData;
19-
const supportEmailLink = (<EmailLink address={supportEmail} />);
20+
const supportEmailLink = (<MailtoLink to={supportEmail}>{supportEmail}</MailtoLink>);
2021
return (
2122
<Banner {...(error && { variant: 'danger' })}>
2223
{error && (
2324
<p className="credit-error-msg">
24-
{formatMessage(messages.error, { supportEmailLink })}
25+
{supportEmail ? formatMessage(messages.error, { supportEmailLink }) : formatMessage(messages.errorNoEmail)}
2526
</p>
2627
)}
2728
<ContentComponent cardId={cardId} />

src/containers/CourseCard/components/CourseCardBanners/CreditBanner/index.test.jsx

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,13 @@ import React from 'react';
22
import { shallow } from 'enzyme';
33

44
import { formatMessage } from 'testUtils';
5-
6-
import EmailLink from 'components/EmailLink';
5+
import { MailtoLink } from '@edx/paragon';
76

87
import hooks from './hooks';
98
import messages from './messages';
109
import CreditBanner from '.';
1110

1211
jest.mock('components/Banner', () => 'Banner');
13-
jest.mock('components/EmailLink', () => 'EmailLink');
1412

1513
jest.mock('./hooks', () => ({
1614
useCreditBannerData: jest.fn(),
@@ -54,14 +52,33 @@ describe('CreditBanner component', () => {
5452
it('includes credit-error-msg with support email link', () => {
5553
expect(el.find('.credit-error-msg').containsMatchingElement(
5654
formatMessage(messages.error, {
57-
supportEmailLink: (<EmailLink address={supportEmail} />),
55+
supportEmailLink: (<MailtoLink to={supportEmail}>{supportEmail}</MailtoLink>),
5856
}),
5957
)).toEqual(true);
6058
});
6159
it('loads ContentComponent with cardId', () => {
6260
expect(el.find('ContentComponent').props().cardId).toEqual(cardId);
6361
});
6462
});
63+
64+
describe('with error state with no email', () => {
65+
beforeEach(() => {
66+
hooks.useCreditBannerData.mockReturnValue({
67+
error: true,
68+
ContentComponent,
69+
});
70+
el = shallow(<CreditBanner cardId={cardId} />);
71+
});
72+
test('snapshot', () => {
73+
expect(el).toMatchSnapshot();
74+
});
75+
it('includes credit-error-msg without support email link', () => {
76+
expect(el.find('.credit-error-msg').containsMatchingElement(
77+
formatMessage(messages.errorNoEmail),
78+
)).toEqual(true);
79+
});
80+
});
81+
6582
describe('with no error state', () => {
6683
beforeEach(() => {
6784
hooks.useCreditBannerData.mockReturnValue({

src/containers/CourseCard/components/CourseCardBanners/CreditBanner/messages.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,11 @@ export const messages = StrictDict({
66
description: '',
77
defaultMessage: 'An error occurred with this transaction. For help, contact {supportEmailLink}.',
88
},
9+
errorNoEmail: {
10+
id: 'learner-dash.courseCard.banners.credit.errorNoEmail',
11+
description: '',
12+
defaultMessage: 'An error occurred with this transaction.',
13+
},
914
});
1015

1116
export default messages;

0 commit comments

Comments
 (0)