From 6f415544be041db1047080755312aa218af5f67a Mon Sep 17 00:00:00 2001 From: Michael Terry Date: Tue, 27 Oct 2020 11:28:52 -0400 Subject: [PATCH] AA-197: Handle non-cert learners that can upgrade (#263) Tell them about verified certificates and link to ecommerce. Also fixes AA-376 by handling the no-verified-mode-to-upgrade-to case. --- .../course/course-exit/CourseCelebration.jsx | 66 ++++++++++++++++-- .../course/course-exit/CourseExit.test.jsx | 37 ++++++++++ .../course/course-exit/UpgradeFootnote.jsx | 56 +++++++++++++++ .../assets/edx_certificate_locked.png | Bin 0 -> 35897 bytes src/courseware/course/course-exit/messages.js | 16 +++++ src/courseware/course/course-exit/utils.js | 25 +++++-- .../SequenceNavigation.test.jsx | 16 +++-- .../UnitNavigation.test.jsx | 13 +++- .../__factories__/courseMetadata.factory.js | 1 + 9 files changed, 209 insertions(+), 21 deletions(-) create mode 100644 src/courseware/course/course-exit/UpgradeFootnote.jsx create mode 100644 src/courseware/course/course-exit/assets/edx_certificate_locked.png diff --git a/src/courseware/course/course-exit/CourseCelebration.jsx b/src/courseware/course/course-exit/CourseCelebration.jsx index 2b099724..67d29426 100644 --- a/src/courseware/course/course-exit/CourseCelebration.jsx +++ b/src/courseware/course/course-exit/CourseCelebration.jsx @@ -15,10 +15,12 @@ import { getAuthenticatedUser } from '@edx/frontend-platform/auth'; import CelebrationMobile from './assets/celebration_456x328.gif'; import CelebrationDesktop from './assets/celebration_750x540.gif'; import certificate from './assets/edx_certificate.png'; +import certificateLocked from './assets/edx_certificate_locked.png'; import messages from './messages'; import { useModel } from '../../../generic/model-store'; import { requestCert } from '../../../course-home/data/thunks'; import DashboardFootnote from './DashboardFootnote'; +import UpgradeFootnote from './UpgradeFootnote'; const LINKEDIN_BLUE = '#007fb1'; @@ -37,6 +39,7 @@ function CourseCelebration({ intl }) { certificateData, end, linkedinAddToProfileUrl, + verifiedMode, verifyIdentityUrl, } = useModel('courses', courseId); @@ -44,7 +47,7 @@ function CourseCelebration({ intl }) { certStatus, certWebViewUrl, downloadUrl, - } = certificateData; + } = certificateData || {}; const { administrator, username } = getAuthenticatedUser(); @@ -87,6 +90,10 @@ function CourseCelebration({ intl }) { let buttonLocation; let buttonText; + let buttonBackground = 'bg-white'; + let buttonVariant = 'outline-primary'; + let certificateImage = certificate; + let footnote; let message; let title; // These cases are taken from the edx-platform `get_cert_data` function found in lms/courseware/views/views.py @@ -112,6 +119,7 @@ function CourseCelebration({ intl }) { buttonLocation = downloadUrl; buttonText = intl.formatMessage(messages.downloadButton); } + footnote = ; break; case 'earned_but_not_available': { const endDate = ; @@ -137,12 +145,14 @@ function CourseCelebration({ intl }) {

); + footnote = ; break; } case 'requesting': buttonText = intl.formatMessage(messages.requestCertificateButton); title = intl.formatMessage(messages.certificateHeaderRequestable); message = (

{intl.formatMessage(messages.requestCertificateBodyText)}

); + footnote = ; break; case 'unverified': buttonText = intl.formatMessage(messages.verifyIdentityButton); @@ -159,6 +169,46 @@ function CourseCelebration({ intl }) { />

); + footnote = ; + break; + case 'audit_passing': + case 'honor_passing': + if (verifiedMode) { + title = intl.formatMessage(messages.certificateHeaderUpgradable); + message = ( +

+ +
+ { /* todo: remove this hardcoded link to edX support */ } + {getConfig().SUPPORT_URL && ( + + {intl.formatMessage(messages.verifiedCertificateSupportLink)} + + )} +

+ ); + buttonText = intl.formatMessage(messages.upgradeButton); + buttonLocation = verifiedMode.upgradeUrl; + buttonBackground = ''; + buttonVariant = 'primary'; + certificateImage = certificateLocked; + if (verifiedMode.accessExpirationDate) { + footnote = ; + } else { + footnote = ; + } + } break; default: break; @@ -194,6 +244,7 @@ function CourseCelebration({ intl }) {
+ {title && (
{title}
@@ -201,8 +252,8 @@ function CourseCelebration({ intl }) { {/* 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 01b86c95..e30cdcd4 100644 --- a/src/courseware/course/course-exit/CourseExit.test.jsx +++ b/src/courseware/course/course-exit/CourseExit.test.jsx @@ -72,6 +72,11 @@ describe('Course Exit Pages', () => { }); it('Redirects if it does not match any statuses', async () => { + setMetadata({ + certificate_data: { + cert_status: 'bogus_status', + }, + }); await fetchAndRender(); expect(global.location.href).toEqual(`http://localhost/course/${defaultMetadata.id}`); }); @@ -123,6 +128,38 @@ describe('Course Exit Pages', () => { expect(screen.queryByRole('img', { name: 'Sample certificate' })).not.toBeInTheDocument(); }); + it('Displays upgrade link when available', async () => { + setMetadata({ + certificate_data: { cert_status: 'audit_passing' }, + verified_mode: { + access_expiration_date: '9999-08-06T12:00:00Z', + upgrade_url: 'http://localhost:18130/basket/add/?sku=8CF08E5', + price: 600, + currency_symbol: '€', + }, + }); + await fetchAndRender(); + // Keep these text checks in sync with "audit only" test below, so it doesn't end up checking for text that is + // never actually there, when/if the text changes. + expect(screen.getByText('Upgrade to pursue a verified certificate')).toBeInTheDocument(); + expect(screen.getByText('For €600 you will unlock access', { exact: false })).toBeInTheDocument(); + expect(screen.getByRole('link', { name: 'Upgrade now' })).toBeInTheDocument(); + const node = screen.getByText('Access to this course and its materials', { exact: false }); + expect(node.textContent).toMatch(/until August 6, 9999\./); + }); + + it('Displays nothing if audit only', async () => { + setMetadata({ + certificate_data: { cert_status: 'audit_passing' }, + verified_mode: null, + }); + await fetchAndRender(); + // Keep these queries in sync with "upgrade link" test above, so we don't end up checking for text that is + // never actually there, when/if the text changes. + expect(screen.queryByText('Upgrade to pursue a verified certificate')).not.toBeInTheDocument(); + expect(screen.queryByRole('button', { name: 'Upgrade now' })).not.toBeInTheDocument(); + }); + it('Displays LinkedIn Add to Profile button', async () => { setMetadata({ certificate_data: { diff --git a/src/courseware/course/course-exit/UpgradeFootnote.jsx b/src/courseware/course/course-exit/UpgradeFootnote.jsx new file mode 100644 index 00000000..31a96afd --- /dev/null +++ b/src/courseware/course/course-exit/UpgradeFootnote.jsx @@ -0,0 +1,56 @@ +import React from 'react'; +import PropTypes from 'prop-types'; + +import { + FormattedDate, FormattedMessage, injectIntl, intlShape, +} from '@edx/frontend-platform/i18n'; +import { Hyperlink } from '@edx/paragon'; +import { faCalendarAlt } from '@fortawesome/free-regular-svg-icons'; + +import Footnote from './Footnote'; +import messages from './messages'; + +function UpgradeFootnote({ deadline, href, intl }) { + const upgradeLink = ( + + {intl.formatMessage(messages.upgradeLink)} + + ); + + const expirationDate = ( + + ); + + return ( + + )} + /> + ); +} + +UpgradeFootnote.propTypes = { + deadline: PropTypes.instanceOf(Date).isRequired, + href: PropTypes.string.isRequired, + intl: intlShape.isRequired, +}; + +export default injectIntl(UpgradeFootnote); diff --git a/src/courseware/course/course-exit/assets/edx_certificate_locked.png b/src/courseware/course/course-exit/assets/edx_certificate_locked.png new file mode 100644 index 0000000000000000000000000000000000000000..dd9187c6ba9dc1a459b1febe1c4a27a18f3912c2 GIT binary patch literal 35897 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 literal 0 HcmV?d00001 diff --git a/src/courseware/course/course-exit/messages.js b/src/courseware/course/course-exit/messages.js index df4e3b7e..392587da 100644 --- a/src/courseware/course/course-exit/messages.js +++ b/src/courseware/course/course-exit/messages.js @@ -21,6 +21,10 @@ const messages = defineMessages({ defaultMessage: 'Congratulations, you qualified for a certificate!', description: 'Text displayed when a user has completed the course and can request a certificate', }, + certificateHeaderUpgradable: { + id: 'courseCelebration.certificateHeader.upgradable', + defaultMessage: 'Upgrade to pursue a verified certificate', + }, certificateImage: { id: 'courseCelebration.certificateImage', defaultMessage: 'Sample certificate', @@ -93,6 +97,18 @@ const messages = defineMessages({ id: 'courseCelebration.shareHeader', defaultMessage: 'You have completed your course. Share your success on social media or email.', }, + upgradeButton: { + id: 'courseExit.upgradeButton', + defaultMessage: 'Upgrade now', + }, + upgradeLink: { + id: 'courseExit.upgradeLink', + defaultMessage: 'upgrade now', + }, + verifiedCertificateSupportLink: { + id: 'courseExit.verifiedCertificateSupportLink', + defaultMessage: 'Learn more about verified certificates', + }, verifyIdentityButton: { id: 'courseCelebration.verifyIdentityButton', defaultMessage: 'Verify ID now', diff --git a/src/courseware/course/course-exit/utils.js b/src/courseware/course/course-exit/utils.js index a7bbfb16..df225fb2 100644 --- a/src/courseware/course/course-exit/utils.js +++ b/src/courseware/course/course-exit/utils.js @@ -10,14 +10,16 @@ const COURSE_EXIT_MODES = { // These are taken from the edx-platform `get_cert_data` function found in lms/courseware/views/views.py const CELEBRATION_STATUSES = [ + 'audit_passing', 'downloadable', 'earned_but_not_available', + 'honor_passing', 'requesting', 'unverified', ]; const NON_CERTIFICATE_STATUSES = [ // no certificate will be given, though a valid certificateData block is provided 'audit_passing', - 'honor_passing', // honor can be configured to not give a certificate + 'honor_passing', // provided when honor is configured to not give a certificate ]; function getCourseExitMode(courseId) { @@ -27,19 +29,28 @@ function getCourseExitMode(courseId) { userHasPassingGrade, } = useModel('courses', courseId); - if (!courseExitPageIsActive || !certificateData) { + if (!courseExitPageIsActive) { return COURSE_EXIT_MODES.disabled; } - const { - certStatus, - } = certificateData; - const isEligibleForCertificate = NON_CERTIFICATE_STATUSES.indexOf(certStatus) === -1; + // Set defaults for our status-calculated variables, used when no certificateData is provided. + // This happens when `get_cert_data` in edx-platform returns None, which it does if we are + // in a certificate-earning mode, but the certificate is not available (maybe they didn't pass + // or course is not set up for certificates or something). Audit users will always have a + // certificateData sent over. + let isCelebratoryStatus = true; + let isEligibleForCertificate = true; + + if (certificateData) { + const { certStatus } = certificateData; + isCelebratoryStatus = CELEBRATION_STATUSES.indexOf(certStatus) !== -1; + isEligibleForCertificate = NON_CERTIFICATE_STATUSES.indexOf(certStatus) === -1; + } if (isEligibleForCertificate && !userHasPassingGrade) { return COURSE_EXIT_MODES.nonPassing; } - if (CELEBRATION_STATUSES.indexOf(certStatus) !== -1) { + if (isCelebratoryStatus) { return COURSE_EXIT_MODES.celebration; } return COURSE_EXIT_MODES.disabled; diff --git a/src/courseware/course/sequence/sequence-navigation/SequenceNavigation.test.jsx b/src/courseware/course/sequence/sequence-navigation/SequenceNavigation.test.jsx index 567fa54a..a1b023b1 100644 --- a/src/courseware/course/sequence/sequence-navigation/SequenceNavigation.test.jsx +++ b/src/courseware/course/sequence/sequence-navigation/SequenceNavigation.test.jsx @@ -98,11 +98,17 @@ describe('Sequence Navigation', () => { expect(screen.getByRole('button', { name: /next/i })).toBeEnabled(); }); - it('has the "Next" button disabled for the last unit of the sequence', () => { - render(); + it('has the "Next" button disabled for the last unit of the sequence if there is no Exit page', async () => { + const testMetadata = { ...courseMetadata, certificate_data: { cert_status: 'bogus_status' }, user_has_passing_grade: true }; + const testStore = await initializeTestStore({ courseMetadata: testMetadata, unitBlocks }, false); + // Have to refetch the sequenceId since the new store generates new sequences + const { courseware } = testStore.getState(); + const testData = { ...mockData, sequenceId: courseware.sequenceId }; + + render( + , + { store: testStore }, + ); expect(screen.getByRole('button', { name: /previous/i })).toBeEnabled(); expect(screen.getByRole('button', { name: /next/i })).toBeDisabled(); diff --git a/src/courseware/course/sequence/sequence-navigation/UnitNavigation.test.jsx b/src/courseware/course/sequence/sequence-navigation/UnitNavigation.test.jsx index fe891763..b483e7f9 100644 --- a/src/courseware/course/sequence/sequence-navigation/UnitNavigation.test.jsx +++ b/src/courseware/course/sequence/sequence-navigation/UnitNavigation.test.jsx @@ -73,8 +73,17 @@ describe('Unit Navigation', () => { expect(screen.getByRole('button', { name: /next/i })).toBeEnabled(); }); - it('has the "Next" button disabled for the last unit in the sequence if there is no Exit Page', () => { - render(); + it('has the "Next" button disabled for the last unit in the sequence if there is no Exit Page', async () => { + const testCourseMetadata = { ...courseMetadata, certificate_data: { cert_status: 'bogus_status' }, user_has_passing_grade: true }; + const testStore = await initializeTestStore({ courseMetadata: testCourseMetadata, unitBlocks }, false); + // Have to refetch the sequenceId since the new store generates new sequences + const { courseware } = testStore.getState(); + const testData = { ...mockData, sequenceId: courseware.sequenceId }; + + render( + , + { store: testStore }, + ); expect(screen.getByRole('button', { name: /previous/i })).toBeEnabled(); expect(screen.getByRole('button', { name: /next/i })).toBeDisabled(); diff --git a/src/courseware/data/__factories__/courseMetadata.factory.js b/src/courseware/data/__factories__/courseMetadata.factory.js index 4647ac31..37ca76ee 100644 --- a/src/courseware/data/__factories__/courseMetadata.factory.js +++ b/src/courseware/data/__factories__/courseMetadata.factory.js @@ -26,6 +26,7 @@ Factory.define('courseMetadata') is_active: null, }, verified_mode: { + access_expiration_date: null, currency: 'USD', upgrade_url: 'http://localhost:18130/basket/add/?sku=8CF08E5', sku: '8CF08E5',