Files
frontend-app-learning/src/courseware/course/course-exit/CourseCelebration.jsx
Michael Terry c5821faee8 AA-377: Add non-passing course exit screen (#246)
- Adds a non-passing cert learner course exit screen
- Moves all the logic about what course-exit mode we're in into
  a utility method in the course-exit folder
- Moves all the logic about how the 'Next' button should read into
  a utility method in the course-exit folder
2020-10-19 11:00:44 -04:00

228 lines
7.9 KiB
JavaScript

import React from 'react';
import {
FormattedDate, FormattedMessage, injectIntl, intlShape,
} from '@edx/frontend-platform/i18n';
import { layoutGenerator } from 'react-break';
import { Helmet } from 'react-helmet';
import { useDispatch } from 'react-redux';
import { useParams } from 'react-router-dom';
import { Alert, Button, Hyperlink } from '@edx/paragon';
import { getConfig } from '@edx/frontend-platform';
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 messages from './messages';
import { useModel } from '../../../generic/model-store';
import { requestCert } from '../../../course-home/data/thunks';
import DashboardFootnote from './DashboardFootnote';
function CourseCelebration({ intl }) {
const layout = layoutGenerator({
mobile: 0,
tablet: 768,
});
const OnMobile = layout.is('mobile');
const OnAtLeastTablet = layout.isAtLeast('tablet');
const { courseId } = useParams();
const dispatch = useDispatch();
const {
certificateData,
end,
verifyIdentityUrl,
} = useModel('courses', courseId);
const {
certStatus,
certWebViewUrl,
downloadUrl,
} = certificateData;
const { username } = getAuthenticatedUser();
const dashboardLink = (
<Hyperlink
className="text-gray-700"
style={{ textDecoration: 'underline' }}
destination={`${getConfig().LMS_BASE_URL}/dashboard`}
>
{intl.formatMessage(messages.dashboardLink)}
</Hyperlink>
);
// todo: remove this hardcoded link to edX support
const idVerificationSupportLink = getConfig().SUPPORT_URL && (
<Hyperlink
className="text-gray-700"
style={{ textDecoration: 'underline' }}
destination={`${getConfig().SUPPORT_URL}/hc/en-us/articles/206503858-How-do-I-verify-my-identity`}
>
{intl.formatMessage(messages.idVerificationSupportLink)}
</Hyperlink>
);
const profileLink = (
<Hyperlink
className="text-gray-700"
style={{ textDecoration: 'underline' }}
destination={`${getConfig().LMS_BASE_URL}/u/${username}`}
>
{intl.formatMessage(messages.profileLink)}
</Hyperlink>
);
let buttonLocation;
let buttonText;
let message;
let title;
// 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);
message = (
<FormattedMessage
id="courseCelebration.certificateBody.available"
defaultMessage="
Showcase your accomplishment on LinkedIn or your resumé today.
You can download your certificate now and access it any time from your
{dashboardLink} and {profileLink}."
values={{ dashboardLink, profileLink }}
/>
);
if (certWebViewUrl) {
buttonLocation = `${getConfig().LMS_BASE_URL}${certWebViewUrl}`;
buttonText = intl.formatMessage(messages.viewCertificateButton);
} else if (downloadUrl) {
buttonLocation = downloadUrl;
buttonText = intl.formatMessage(messages.downloadButton);
}
break;
case 'earned_but_not_available': {
const endDate = <FormattedDate value={end} day="numeric" month="long" year="numeric" />;
title = intl.formatMessage(messages.certificateHeaderNotAvailable);
message = (
<>
<div className="mb-2">
<FormattedMessage
id="courseCelebration.certificateBody.notAvailable.endDate"
defaultMessage="After this course officially ends on {endDate}, you will receive an
email notification with your certificate. Once you have your certificate, be sure
to showcase your accomplishment on LinkedIn or your resumé."
values={{ endDate }}
/>
</div>
<div className="mb-2">
<FormattedMessage
id="courseCelebration.certificateBody.notAvailable.accessCertificate"
defaultMessage="You will be able to access your certificate any time from your
{dashboardLink} and {profileLink}."
values={{ dashboardLink, profileLink }}
/>
</div>
</>
);
break;
}
case 'requesting':
buttonText = intl.formatMessage(messages.requestCertificateButton);
title = intl.formatMessage(messages.certificateHeaderRequestable);
message = intl.formatMessage(messages.requestCertificateBodyText);
break;
case 'unverified':
buttonText = intl.formatMessage(messages.verifyIdentityButton);
buttonLocation = verifyIdentityUrl;
title = intl.formatMessage(messages.certificateHeaderUnverified);
// todo: check for idVerificationSupportLink null
message = (
<FormattedMessage
id="courseCelebration.certificateBody.unverified"
defaultMessage="In order to generate a certificate, you must complete ID verification.
{idVerificationSupportLink} now."
values={{ idVerificationSupportLink }}
/>
);
break;
default:
break;
}
return (
<>
<Helmet>
<title>{`${intl.formatMessage(messages.congratulationsHeader)} | ${getConfig().SITE_NAME}`}</title>
</Helmet>
<div className="row w-100 mx-0 mb-4 px-5 py-4 border border-light">
<div className="col-12 p-0 h2 text-center">
{intl.formatMessage(messages.congratulationsHeader)}
</div>
<div className="col-12 p-0 font-weight-normal lead text-center">
{intl.formatMessage(messages.shareHeader)}
</div>
<div className="col-12 my-4 px-0 px-md-5 text-center">
<OnMobile>
<img
src={CelebrationMobile}
alt={`${intl.formatMessage(messages.congratulationsImage)}`}
className="img-fluid"
/>
</OnMobile>
<OnAtLeastTablet>
<img
src={CelebrationDesktop}
alt={`${intl.formatMessage(messages.congratulationsImage)}`}
className="img-fluid"
style={{ width: '36rem' }}
/>
</OnAtLeastTablet>
</div>
<div className="col-12 px-0 px-md-5">
<Alert variant="primary" className="row w-100 m-0">
<div className="col order-1 order-md-0 pl-0 pr-0 pr-md-5">
<div className="h4">{title}</div>
<p>{message}</p>
{/* The requesting status needs a different button because it does a POST instead of a GET */}
{certStatus === 'requesting' && (
<Button
className="bg-white"
variant="outline-primary"
onClick={() => dispatch(requestCert(courseId))}
>
{buttonText}
</Button>
)}
{buttonLocation && (
<Button
className="bg-white"
variant="outline-primary"
href={buttonLocation}
>
{buttonText}
</Button>
)}
</div>
{certStatus !== 'unverified' && (
<div className="col-12 order-0 col-md-3 order-md-1 w-100 mb-3 p-0 text-center">
<img
src={certificate}
alt={`${intl.formatMessage(messages.certificateImage)}`}
className="w-100"
style={{ maxWidth: '13rem' }}
/>
</div>
)}
</Alert>
<DashboardFootnote />
</div>
</div>
</>
);
}
CourseCelebration.propTypes = {
intl: intlShape.isRequired,
};
export default injectIntl(CourseCelebration);