diff --git a/src/courseware/course/celebration/CelebrationModal.jsx b/src/courseware/course/celebration/CelebrationModal.jsx
index cb8a57c8..927cbda7 100644
--- a/src/courseware/course/celebration/CelebrationModal.jsx
+++ b/src/courseware/course/celebration/CelebrationModal.jsx
@@ -7,7 +7,7 @@ import { layoutGenerator } from 'react-break';
import ClapsMobile from './assets/claps_280x201.gif';
import ClapsTablet from './assets/claps_456x328.gif';
import messages from './messages';
-import SocialIcons from './SocialIcons';
+import SocialIcons from '../../social-share/SocialIcons';
import { recordFirstSectionCelebration } from './utils';
function CelebrationModal({
@@ -41,7 +41,12 @@ function CelebrationModal({
{intl.formatMessage(messages.earned)} {intl.formatMessage(messages.share)}
-
+
>
)}
closeText={intl.formatMessage(messages.forward)}
diff --git a/src/courseware/course/celebration/messages.js b/src/courseware/course/celebration/messages.js
index 1744187c..8fa81c65 100644
--- a/src/courseware/course/celebration/messages.js
+++ b/src/courseware/course/celebration/messages.js
@@ -13,11 +13,6 @@ const messages = defineMessages({
id: 'learning.celebration.earned',
defaultMessage: 'You earned it!',
},
- emailBody: {
- id: 'learning.celebration.emailBody',
- defaultMessage: 'What are you spending your time learning?',
- description: 'Body when sharing course progress via email',
- },
emailSubject: {
id: 'learning.celebration.emailSubject',
defaultMessage: "I'm on my way to completing {title} online with {platform}!",
@@ -32,15 +27,7 @@ const messages = defineMessages({
id: 'learning.celebration.share',
defaultMessage: 'Take a moment to celebrate and share your progress.',
},
- shareEmail: {
- id: 'learning.celebration.share.email',
- defaultMessage: 'Share your progress via email.',
- },
- shareService: {
- id: 'learning.celebration.share.service',
- defaultMessage: 'Share your progress on {service}.',
- },
- social: {
+ socialMessage: {
id: 'learning.celebration.social',
defaultMessage: 'I’m on my way to completing {title} online with {platform}. What are you spending your time learning?',
description: 'Shown when sharing course progress on a social network',
diff --git a/src/courseware/course/course-exit/CourseCelebration.jsx b/src/courseware/course/course-exit/CourseCelebration.jsx
index 67d29426..fe6c81d5 100644
--- a/src/courseware/course/course-exit/CourseCelebration.jsx
+++ b/src/courseware/course/course-exit/CourseCelebration.jsx
@@ -21,6 +21,7 @@ import { useModel } from '../../../generic/model-store';
import { requestCert } from '../../../course-home/data/thunks';
import DashboardFootnote from './DashboardFootnote';
import UpgradeFootnote from './UpgradeFootnote';
+import SocialIcons from '../../social-share/SocialIcons';
const LINKEDIN_BLUE = '#007fb1';
@@ -95,11 +96,11 @@ function CourseCelebration({ intl }) {
let certificateImage = certificate;
let footnote;
let message;
- let title;
+ let certHeader;
// These cases are taken from the edx-platform `get_cert_data` function found in lms/courseware/views/views.py
switch (certStatus) {
case 'downloadable':
- title = intl.formatMessage(messages.certificateHeaderDownloadable);
+ certHeader = intl.formatMessage(messages.certificateHeaderDownloadable);
message = (
;
- title = intl.formatMessage(messages.certificateHeaderNotAvailable);
+ certHeader = intl.formatMessage(messages.certificateHeaderNotAvailable);
message = (
<>
@@ -150,14 +151,14 @@ function CourseCelebration({ intl }) {
}
case 'requesting':
buttonText = intl.formatMessage(messages.requestCertificateButton);
- title = intl.formatMessage(messages.certificateHeaderRequestable);
+ certHeader = intl.formatMessage(messages.certificateHeaderRequestable);
message = (
{intl.formatMessage(messages.requestCertificateBodyText)}
);
footnote = ;
break;
case 'unverified':
buttonText = intl.formatMessage(messages.verifyIdentityButton);
buttonLocation = verifyIdentityUrl;
- title = intl.formatMessage(messages.certificateHeaderUnverified);
+ certHeader = intl.formatMessage(messages.certificateHeaderUnverified);
// todo: check for idVerificationSupportLink null
message = (
@@ -174,7 +175,7 @@ function CourseCelebration({ intl }) {
case 'audit_passing':
case 'honor_passing':
if (verifiedMode) {
- title = intl.formatMessage(messages.certificateHeaderUpgradable);
+ certHeader = intl.formatMessage(messages.certificateHeaderUpgradable);
message = (
{intl.formatMessage(messages.shareHeader)}
+
-
+
- {title && (
+ {certHeader && (
-
{title}
+
{certHeader}
{message}
{/* The requesting status needs a different button because it does a POST instead of a GET */}
{certStatus === 'requesting' && (
diff --git a/src/courseware/course/course-exit/CourseExit.test.jsx b/src/courseware/course/course-exit/CourseExit.test.jsx
index e30cdcd4..ea176258 100644
--- a/src/courseware/course/course-exit/CourseExit.test.jsx
+++ b/src/courseware/course/course-exit/CourseExit.test.jsx
@@ -118,6 +118,24 @@ describe('Course Exit Pages', () => {
expect(screen.getByRole('button', { name: 'Request certificate' })).toBeInTheDocument();
});
+ it('Displays social share icons', async () => {
+ setMetadata({ certificate_data: { cert_status: 'unverified' }, marketing_url: 'https://edx.org' });
+ await fetchAndRender(
);
+ expect(screen.getByRole('button', { name: 'linkedin' })).toBeInTheDocument();
+ expect(screen.getByRole('button', { name: 'facebook' })).toBeInTheDocument();
+ expect(screen.getByRole('button', { name: 'twitter' })).toBeInTheDocument();
+ expect(screen.getByRole('button', { name: 'email' })).toBeInTheDocument();
+ });
+
+ it('Does not display social share icons if no marketing URL', async () => {
+ setMetadata({ certificate_data: { cert_status: 'unverified' } });
+ await fetchAndRender(
);
+ expect(screen.queryByRole('button', { name: 'linkedin' })).not.toBeInTheDocument();
+ expect(screen.queryByRole('button', { name: 'facebook' })).not.toBeInTheDocument();
+ expect(screen.queryByRole('button', { name: 'twitter' })).not.toBeInTheDocument();
+ expect(screen.queryByRole('button', { name: 'email' })).not.toBeInTheDocument();
+ });
+
it('Displays verify identity link', async () => {
setMetadata({
certificate_data: { cert_status: 'unverified' },
diff --git a/src/courseware/course/course-exit/messages.js b/src/courseware/course/course-exit/messages.js
index 392587da..c2a2aaaf 100644
--- a/src/courseware/course/course-exit/messages.js
+++ b/src/courseware/course/course-exit/messages.js
@@ -97,6 +97,11 @@ const messages = defineMessages({
id: 'courseCelebration.shareHeader',
defaultMessage: 'You have completed your course. Share your success on social media or email.',
},
+ socialMessage: {
+ id: 'courseExit.social.shareCompletionMessage',
+ defaultMessage: 'I just completed {title} with {platform}!',
+ description: 'Shown when sharing course progress on a social network',
+ },
upgradeButton: {
id: 'courseExit.upgradeButton',
defaultMessage: 'Upgrade now',
diff --git a/src/courseware/course/celebration/SocialIcons.jsx b/src/courseware/social-share/SocialIcons.jsx
similarity index 68%
rename from src/courseware/course/celebration/SocialIcons.jsx
rename to src/courseware/social-share/SocialIcons.jsx
index 3c4e4d91..b093a33a 100644
--- a/src/courseware/course/celebration/SocialIcons.jsx
+++ b/src/courseware/social-share/SocialIcons.jsx
@@ -17,9 +17,18 @@ import { getAuthenticatedUser } from '@edx/frontend-platform/auth';
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
import messages from './messages';
-import { useModel } from '../../../generic/model-store';
+import { useModel } from '../../generic/model-store';
-function SocialIcons({ courseId, intl }) {
+function SocialIcons({
+ analyticsId,
+ className,
+ courseId,
+ emailBody,
+ emailSubject,
+ hashtags,
+ intl,
+ socialMessage,
+}) {
const {
marketingUrl,
title,
@@ -33,8 +42,12 @@ function SocialIcons({ courseId, intl }) {
const twitterAccount = twitterUrl && twitterUrl.substring(twitterUrl.lastIndexOf('/') + 1);
const logClick = (service) => {
+ if (!analyticsId) {
+ return;
+ }
+
const { administrator } = getAuthenticatedUser();
- sendTrackEvent('edx.ui.lms.celebration.social_share.clicked', {
+ sendTrackEvent(analyticsId, {
course_id: courseId,
is_staff: administrator,
service,
@@ -44,7 +57,7 @@ function SocialIcons({ courseId, intl }) {
const socialUtmMarketingUrl = `${marketingUrl}?utm_campaign=edxmilestone&utm_medium=social`;
return (
-
+
logClick('linkedin')}
url={`${socialUtmMarketingUrl}&utm_source=linkedin`}
@@ -52,12 +65,12 @@ function SocialIcons({ courseId, intl }) {
{intl.formatMessage(messages.shareService, { service: 'LinkedIn' })}
- { twitterAccount && (
+ {twitterAccount && (
logClick('twitter')}
className="ml-2"
- hashtags={['myedxjourney']}
- title={intl.formatMessage(messages.social, { platform: `@${twitterAccount}`, title })}
+ hashtags={hashtags}
+ title={socialMessage ? intl.formatMessage(socialMessage, { platform: `@${twitterAccount}`, title }) : ''}
url={`${socialUtmMarketingUrl}&utm_source=twitter`}
>
@@ -67,7 +80,7 @@ function SocialIcons({ courseId, intl }) {
logClick('facebook')}
className="ml-2"
- quote={intl.formatMessage(messages.social, { platform: getConfig().SITE_NAME, title })}
+ quote={socialMessage ? intl.formatMessage(socialMessage, { platform: getConfig().SITE_NAME, title }) : ''}
url={`${socialUtmMarketingUrl}&utm_source=facebook`}
>
@@ -75,9 +88,9 @@ function SocialIcons({ courseId, intl }) {
logClick('email')}
- body={`${intl.formatMessage(messages.emailBody)}\n\n`}
+ body={emailBody ? `${intl.formatMessage(emailBody)}\n\n` : ''}
className="ml-2"
- subject={intl.formatMessage(messages.emailSubject, { platform: getConfig().SITE_NAME, title })}
+ subject={emailSubject ? intl.formatMessage(emailSubject, { platform: getConfig().SITE_NAME, title }) : ''}
url={`${marketingUrl}?utm_campaign=edxmilestone&utm_medium=email&utm_source=email`}
>
@@ -87,9 +100,24 @@ function SocialIcons({ courseId, intl }) {
);
}
+SocialIcons.defaultProps = {
+ analyticsId: '',
+ className: '',
+ emailBody: messages.defaultEmailBody,
+ emailSubject: null,
+ hashtags: ['myedxjourney'],
+ socialMessage: null,
+};
+
SocialIcons.propTypes = {
+ analyticsId: PropTypes.string,
+ className: PropTypes.string,
courseId: PropTypes.string.isRequired,
+ emailBody: PropTypes.shape({}),
+ emailSubject: PropTypes.shape({}),
+ hashtags: PropTypes.arrayOf(PropTypes.string),
intl: intlShape.isRequired,
+ socialMessage: PropTypes.shape({}),
};
export default injectIntl(SocialIcons);
diff --git a/src/courseware/social-share/messages.js b/src/courseware/social-share/messages.js
new file mode 100644
index 00000000..3fc85ffd
--- /dev/null
+++ b/src/courseware/social-share/messages.js
@@ -0,0 +1,19 @@
+import { defineMessages } from '@edx/frontend-platform/i18n';
+
+const messages = defineMessages({
+ defaultEmailBody: {
+ id: 'learning.celebration.emailBody',
+ defaultMessage: 'What are you spending your time learning?',
+ description: 'Body when sharing course progress via email',
+ },
+ shareEmail: {
+ id: 'learning.social.shareEmail',
+ defaultMessage: 'Share your progress via email.',
+ },
+ shareService: {
+ id: 'learning.social.shareService',
+ defaultMessage: 'Share your progress on {service}.',
+ },
+});
+
+export default messages;
diff --git a/src/index.scss b/src/index.scss
index 45b86375..416b99b2 100755
--- a/src/index.scss
+++ b/src/index.scss
@@ -233,7 +233,6 @@ $primary: #1176B2;
}
.previous-btn, .next-btn {
- min-width: 4rem;
color: theme-color('gray', 700);
display: inline-flex;
justify-content: center;
diff --git a/src/setupTest.js b/src/setupTest.js
index 269ce6db..26de9e7a 100755
--- a/src/setupTest.js
+++ b/src/setupTest.js
@@ -63,6 +63,7 @@ export function initializeMockApp() {
mergeConfig({
INSIGHTS_BASE_URL: process.env.INSIGHTS_BASE_URL || null,
STUDIO_BASE_URL: process.env.STUDIO_BASE_URL || null,
+ TWITTER_URL: process.env.TWITTER_URL || null,
authenticatedUser: {
userId: 'abc123',
username: 'Mock User',