Compare commits
5 Commits
master
...
aj/MICROBA
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7680871ca2 | ||
|
|
013e7bd9a1 | ||
|
|
059525c729 | ||
|
|
b9448d917a | ||
|
|
e18d6f0dae |
@@ -686,7 +686,7 @@ describe('Outline Tab', () => {
|
|||||||
],
|
],
|
||||||
});
|
});
|
||||||
await fetchAndRender();
|
await fetchAndRender();
|
||||||
await screen.findByText('We are working on generating course certificates.');
|
await screen.findByText('Your grade and certificate will be ready soon!');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,51 +1,38 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { getConfig } from '@edx/frontend-platform';
|
import { FormattedDate, FormattedMessage } from '@edx/frontend-platform/i18n';
|
||||||
import { FormattedMessage, FormattedRelative } from '@edx/frontend-platform/i18n';
|
|
||||||
import { Hyperlink } from '@edx/paragon';
|
|
||||||
|
|
||||||
import { Alert, ALERT_TYPES } from '../../../../generic/user-messages';
|
import { Alert, ALERT_TYPES } from '../../../../generic/user-messages';
|
||||||
|
|
||||||
function CertificateAvailableAlert({ payload }) {
|
function CertificateAvailableAlert({ payload }) {
|
||||||
const {
|
const {
|
||||||
certDate,
|
certDate,
|
||||||
username,
|
|
||||||
userTimezone,
|
userTimezone,
|
||||||
|
courseEndDate,
|
||||||
} = payload;
|
} = payload;
|
||||||
|
|
||||||
const timezoneFormatArgs = userTimezone ? { timeZone: userTimezone } : {};
|
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 (
|
return (
|
||||||
<Alert type={ALERT_TYPES.INFO}>
|
<Alert type={ALERT_TYPES.SUCCESS}>
|
||||||
<strong>
|
<strong>
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
id="learning.outline.alert.cert.title"
|
id="learning.outline.alert.cert.title"
|
||||||
defaultMessage="We are working on generating course certificates."
|
defaultMessage="Your grade and certificate will be ready soon!"
|
||||||
/>
|
/>
|
||||||
</strong>
|
</strong>
|
||||||
<br />
|
<br />
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
id="learning.outline.alert.cert.when"
|
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={{
|
values={{
|
||||||
profileLink: (
|
courseEndDateFormatted,
|
||||||
<Hyperlink
|
certificateAvailableDate: certificateAvailableDateFormatted,
|
||||||
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}
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
}}
|
}}
|
||||||
|
{...timezoneFormatArgs}
|
||||||
/>
|
/>
|
||||||
</Alert>
|
</Alert>
|
||||||
);
|
);
|
||||||
@@ -54,8 +41,7 @@ function CertificateAvailableAlert({ payload }) {
|
|||||||
CertificateAvailableAlert.propTypes = {
|
CertificateAvailableAlert.propTypes = {
|
||||||
payload: PropTypes.shape({
|
payload: PropTypes.shape({
|
||||||
certDate: PropTypes.string,
|
certDate: PropTypes.string,
|
||||||
username: PropTypes.string,
|
courseEndDate: PropTypes.string,
|
||||||
userTimezone: PropTypes.string,
|
|
||||||
}).isRequired,
|
}).isRequired,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ function useCertificateAvailableAlert(courseId) {
|
|||||||
} = useModel('outline', courseId);
|
} = useModel('outline', courseId);
|
||||||
const authenticatedUser = getAuthenticatedUser();
|
const authenticatedUser = getAuthenticatedUser();
|
||||||
const username = authenticatedUser ? authenticatedUser.username : '';
|
const username = authenticatedUser ? authenticatedUser.username : '';
|
||||||
|
|
||||||
const certBlock = courseDateBlocks.find(b => b.dateType === 'certificate-available-date');
|
const certBlock = courseDateBlocks.find(b => b.dateType === 'certificate-available-date');
|
||||||
const endBlock = courseDateBlocks.find(b => b.dateType === 'course-end-date');
|
const endBlock = courseDateBlocks.find(b => b.dateType === 'course-end-date');
|
||||||
const endDate = endBlock ? new Date(endBlock.date) : null;
|
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 isVisible = isEnrolled && certBlock && hasEnded; // only show if we're between end and cert dates
|
||||||
const payload = {
|
const payload = {
|
||||||
certDate: certBlock && certBlock.date,
|
certDate: certBlock && certBlock.date,
|
||||||
|
courseEndDate: endDate,
|
||||||
username,
|
username,
|
||||||
userTimezone,
|
userTimezone,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -60,6 +60,7 @@ function CourseCelebration({ intl }) {
|
|||||||
certStatus,
|
certStatus,
|
||||||
certWebViewUrl,
|
certWebViewUrl,
|
||||||
downloadUrl,
|
downloadUrl,
|
||||||
|
certificateAvailableDate,
|
||||||
} = certificateData || {};
|
} = certificateData || {};
|
||||||
|
|
||||||
/** [WS-1681 experiment] */
|
/** [WS-1681 experiment] */
|
||||||
@@ -125,25 +126,20 @@ function CourseCelebration({ intl }) {
|
|||||||
break;
|
break;
|
||||||
case 'earned_but_not_available': {
|
case 'earned_but_not_available': {
|
||||||
const endDate = <FormattedDate value={end} day="numeric" month="long" year="numeric" />;
|
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);
|
certHeader = intl.formatMessage(messages.certificateHeaderNotAvailable);
|
||||||
message = (
|
message = (
|
||||||
<>
|
<>
|
||||||
<p>
|
<p>
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
id="courseCelebration.certificateBody.notAvailable.endDate"
|
id="courseCelebration.certificateBody.notAvailable.endDate"
|
||||||
defaultMessage="After this course officially ends on {endDate}, you will receive an
|
defaultMessage="This course ended on {endDate} and final grades and certificates are scheduled to be
|
||||||
email notification with your certificate. Once you have your certificate, be sure
|
available after {certAvailableDate}."
|
||||||
to showcase your accomplishment on LinkedIn or your resumé."
|
values={{ endDate, certAvailableDate }}
|
||||||
values={{ endDate }}
|
|
||||||
/>
|
/>
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
<FormattedMessage
|
{intl.formatMessage(messages.certificateNotAvailableBodyAccessCert)}
|
||||||
id="courseCelebration.certificateBody.notAvailable.accessCertificate"
|
|
||||||
defaultMessage="You will be able to access your certificate any time from your
|
|
||||||
{dashboardLink} and {profileLink}."
|
|
||||||
values={{ dashboardLink, profileLink }}
|
|
||||||
/>
|
|
||||||
</p>
|
</p>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
@@ -294,7 +290,7 @@ function CourseCelebration({ intl }) {
|
|||||||
</div>
|
</div>
|
||||||
<div className="col-12 px-0 px-md-5">
|
<div className="col-12 px-0 px-md-5">
|
||||||
{certHeader && (
|
{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="col order-1 order-md-0 pl-0 pr-0 pr-md-5">
|
||||||
<div className="h4">{certHeader}</div>
|
<div className="h4">{certHeader}</div>
|
||||||
{message}
|
{message}
|
||||||
|
|||||||
@@ -115,9 +115,14 @@ describe('Course Exit Pages', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('Displays certificate is earned but unavailable message', async () => {
|
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 />);
|
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 () => {
|
it('Displays request certificate link', async () => {
|
||||||
|
|||||||
@@ -13,7 +13,12 @@ const messages = defineMessages({
|
|||||||
},
|
},
|
||||||
certificateHeaderNotAvailable: {
|
certificateHeaderNotAvailable: {
|
||||||
id: 'courseCelebration.certificateHeader.notAvailable',
|
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',
|
description: 'Text displayed when course certificate is not yet available to be viewed',
|
||||||
},
|
},
|
||||||
certificateHeaderUnverified: {
|
certificateHeaderUnverified: {
|
||||||
@@ -180,6 +185,7 @@ const messages = defineMessages({
|
|||||||
id: 'courseExit.viewGradesButton',
|
id: 'courseExit.viewGradesButton',
|
||||||
defaultMessage: 'View grades',
|
defaultMessage: 'View grades',
|
||||||
},
|
},
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export default messages;
|
export default messages;
|
||||||
|
|||||||
@@ -41,6 +41,12 @@ function getAlertIcon(type) {
|
|||||||
return faInfoCircle;
|
return faInfoCircle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getAlertIconColor(type) {
|
||||||
|
if (type === ALERT_TYPES.SUCCESS) {
|
||||||
|
return 'text-success-500';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function Alert({
|
function Alert({
|
||||||
type, dismissible, children, footer, intl, onDismiss,
|
type, dismissible, children, footer, intl, onDismiss,
|
||||||
}) {
|
}) {
|
||||||
@@ -49,7 +55,7 @@ function Alert({
|
|||||||
<div className="row w-100 m-0">
|
<div className="row w-100 m-0">
|
||||||
{type !== ALERT_TYPES.WELCOME && (
|
{type !== ALERT_TYPES.WELCOME && (
|
||||||
<div className="col-auto p-0 mr-3">
|
<div className="col-auto p-0 mr-3">
|
||||||
<FontAwesomeIcon icon={getAlertIcon(type)} />
|
<FontAwesomeIcon icon={getAlertIcon(type)} className={getAlertIconColor(type)}/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<div className="col mr-4 p-0 align-items-start">
|
<div className="col mr-4 p-0 align-items-start">
|
||||||
|
|||||||
Reference in New Issue
Block a user