Compare commits

...

5 Commits

Author SHA1 Message Date
Albert (AJ) St. Aubin
7680871ca2 PR 2021-05-21 12:57:28 -04:00
Albert (AJ) St. Aubin
013e7bd9a1 test 2021-05-20 20:17:21 -04:00
Albert (AJ) St. Aubin
059525c729 tests 2021-05-20 20:14:54 -04:00
Albert (AJ) St. Aubin
b9448d917a quality 2021-05-20 19:56:32 -04:00
Albert (AJ) St. Aubin
e18d6f0dae refactor: Updating the messages for certificate availability.
[MICROBA-678]
2021-05-20 16:27:34 -04:00
7 changed files with 42 additions and 43 deletions

View File

@@ -686,7 +686,7 @@ describe('Outline Tab', () => {
],
});
await fetchAndRender();
await screen.findByText('We are working on generating course certificates.');
await screen.findByText('Your grade and certificate will be ready soon!');
});
});

View File

@@ -1,51 +1,38 @@
import React from 'react';
import PropTypes from 'prop-types';
import { getConfig } from '@edx/frontend-platform';
import { FormattedMessage, FormattedRelative } from '@edx/frontend-platform/i18n';
import { Hyperlink } from '@edx/paragon';
import { FormattedDate, FormattedMessage } from '@edx/frontend-platform/i18n';
import { Alert, ALERT_TYPES } from '../../../../generic/user-messages';
function CertificateAvailableAlert({ payload }) {
const {
certDate,
username,
userTimezone,
courseEndDate,
} = payload;
const timezoneFormatArgs = userTimezone ? { timeZone: userTimezone } : {};
const certificateAvailableDateFormatted = <FormattedDate value={certDate} day="numeric" month="long" year="numeric" />;
const courseEndDateFormatted = <FormattedDate value={courseEndDate} day="numeric" month="long" year="numeric" />;
return (
<Alert type={ALERT_TYPES.INFO}>
<Alert type={ALERT_TYPES.SUCCESS}>
<strong>
<FormattedMessage
id="learning.outline.alert.cert.title"
defaultMessage="We are working on generating course certificates."
defaultMessage="Your grade and certificate will be ready soon!"
/>
</strong>
<br />
<FormattedMessage
id="learning.outline.alert.cert.when"
defaultMessage="If you have earned a certificate, you will be able to access it {timeRemaining}. You will also be able to view your certificates on your {profileLink}."
defaultMessage="This course ended on {courseEndDateFormatted} and final grades and certificates are
scheduled to be available after {certificateAvailableDate}."
values={{
profileLink: (
<Hyperlink
destination={`${getConfig().LMS_BASE_URL}/u/${username}`}
>
<FormattedMessage
id="learning.outline.alert.cert.profile"
defaultMessage="Learner Profile"
/>
</Hyperlink>
),
timeRemaining: (
<FormattedRelative
key="timeRemaining"
value={certDate}
{...timezoneFormatArgs}
/>
),
courseEndDateFormatted,
certificateAvailableDate: certificateAvailableDateFormatted,
}}
{...timezoneFormatArgs}
/>
</Alert>
);
@@ -54,8 +41,7 @@ function CertificateAvailableAlert({ payload }) {
CertificateAvailableAlert.propTypes = {
payload: PropTypes.shape({
certDate: PropTypes.string,
username: PropTypes.string,
userTimezone: PropTypes.string,
courseEndDate: PropTypes.string,
}).isRequired,
};

View File

@@ -18,7 +18,6 @@ function useCertificateAvailableAlert(courseId) {
} = useModel('outline', courseId);
const authenticatedUser = getAuthenticatedUser();
const username = authenticatedUser ? authenticatedUser.username : '';
const certBlock = courseDateBlocks.find(b => b.dateType === 'certificate-available-date');
const endBlock = courseDateBlocks.find(b => b.dateType === 'course-end-date');
const endDate = endBlock ? new Date(endBlock.date) : null;
@@ -26,6 +25,7 @@ function useCertificateAvailableAlert(courseId) {
const isVisible = isEnrolled && certBlock && hasEnded; // only show if we're between end and cert dates
const payload = {
certDate: certBlock && certBlock.date,
courseEndDate: endDate,
username,
userTimezone,
};

View File

@@ -60,6 +60,7 @@ function CourseCelebration({ intl }) {
certStatus,
certWebViewUrl,
downloadUrl,
certificateAvailableDate,
} = certificateData || {};
/** [WS-1681 experiment] */
@@ -125,25 +126,20 @@ function CourseCelebration({ intl }) {
break;
case 'earned_but_not_available': {
const endDate = <FormattedDate value={end} day="numeric" month="long" year="numeric" />;
const certAvailableDate = <FormattedDate value={certificateAvailableDate} day="numeric" month="long" year="numeric" />;
certHeader = intl.formatMessage(messages.certificateHeaderNotAvailable);
message = (
<>
<p>
<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 }}
defaultMessage="This course ended on {endDate} and final grades and certificates are scheduled to be
available after {certAvailableDate}."
values={{ endDate, certAvailableDate }}
/>
</p>
<p>
<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 }}
/>
{intl.formatMessage(messages.certificateNotAvailableBodyAccessCert)}
</p>
</>
);
@@ -294,7 +290,7 @@ function CourseCelebration({ intl }) {
</div>
<div className="col-12 px-0 px-md-5">
{certHeader && (
<Alert variant="primary" className="row w-100 m-0">
<Alert variant="success" className="row w-100 m-0">
<div className="col order-1 order-md-0 pl-0 pr-0 pr-md-5">
<div className="h4">{certHeader}</div>
{message}

View File

@@ -115,9 +115,14 @@ describe('Course Exit Pages', () => {
});
it('Displays certificate is earned but unavailable message', async () => {
setMetadata({ certificate_data: { cert_status: 'earned_but_not_available' } });
setMetadata({
certificate_data: {
cert_status: 'earned_but_not_available',
certificate_available_date: '2021-05-21T12:00:00Z',
},
});
await fetchAndRender(<CourseCelebration />);
expect(screen.getByText('Your certificate will be available soon!')).toBeInTheDocument();
expect(screen.getByText('Your grade and certificate will be ready soon!')).toBeInTheDocument();
});
it('Displays request certificate link', async () => {

View File

@@ -13,7 +13,12 @@ const messages = defineMessages({
},
certificateHeaderNotAvailable: {
id: 'courseCelebration.certificateHeader.notAvailable',
defaultMessage: 'Your certificate will be available soon!',
defaultMessage: 'Your grade and certificate will be ready soon!',
description: 'Header displayed when course certificate is not yet available to be viewed',
},
certificateNotAvailableBodyAccessCert: {
id: 'courseCelebration.certificateBody.notAvailable.accessCertificate',
defaultMessage: 'If you have earned a passing grade, your certificate will be automatically issued.',
description: 'Text displayed when course certificate is not yet available to be viewed',
},
certificateHeaderUnverified: {
@@ -180,6 +185,7 @@ const messages = defineMessages({
id: 'courseExit.viewGradesButton',
defaultMessage: 'View grades',
},
});
export default messages;

View File

@@ -41,6 +41,12 @@ function getAlertIcon(type) {
return faInfoCircle;
}
function getAlertIconColor(type) {
if (type === ALERT_TYPES.SUCCESS) {
return 'text-success-500';
}
}
function Alert({
type, dismissible, children, footer, intl, onDismiss,
}) {
@@ -49,7 +55,7 @@ function Alert({
<div className="row w-100 m-0">
{type !== ALERT_TYPES.WELCOME && (
<div className="col-auto p-0 mr-3">
<FontAwesomeIcon icon={getAlertIcon(type)} />
<FontAwesomeIcon icon={getAlertIcon(type)} className={getAlertIconColor(type)}/>
</div>
)}
<div className="col mr-4 p-0 align-items-start">