AA-388: CourseExitPage UI improvements (#237)
This commit is contained in:
@@ -3,6 +3,7 @@ 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';
|
||||
@@ -12,13 +13,22 @@ import { faCalendarAlt } from '@fortawesome/free-regular-svg-icons';
|
||||
import { getConfig } from '@edx/frontend-platform';
|
||||
import { getAuthenticatedUser } from '@edx/frontend-platform/auth';
|
||||
|
||||
import celebration from './assets/celebration_456x328.gif';
|
||||
import CelebrationMobile from './assets/celebration_456x328.gif';
|
||||
import CelebrationDesktop from './assets/celebration_750x540.gif';
|
||||
import certificate from './assets/certificate.png';
|
||||
import messages from './messages';
|
||||
import { useModel } from '../../../generic/model-store';
|
||||
import { requestCert } from '../../../course-home/data/thunks';
|
||||
|
||||
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 {
|
||||
@@ -31,7 +41,7 @@ function CourseCelebration({ intl }) {
|
||||
certStatus,
|
||||
certWebViewUrl,
|
||||
downloadUrl,
|
||||
} = certificateData || { downloadUrl: 'google.com', certWebViewUrl: 'duckduckgo.com' };
|
||||
} = certificateData;
|
||||
|
||||
const { username } = getAuthenticatedUser();
|
||||
|
||||
@@ -43,6 +53,7 @@ function CourseCelebration({ intl }) {
|
||||
{intl.formatMessage(messages.dashboardLink)}
|
||||
</Hyperlink>
|
||||
);
|
||||
// todo: remove this hardcoded link to edX support
|
||||
const idVerificationSupportLink = getConfig().SUPPORT_URL && (
|
||||
<Hyperlink
|
||||
style={{ textDecoration: 'underline' }}
|
||||
@@ -75,7 +86,6 @@ function CourseCelebration({ intl }) {
|
||||
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}."
|
||||
description="Body in certificate banner"
|
||||
values={{ dashboardLink, profileLink }}
|
||||
/>
|
||||
);
|
||||
@@ -91,17 +101,31 @@ function CourseCelebration({ intl }) {
|
||||
const endDate = <FormattedDate value={end} day="numeric" month="long" year="numeric" />;
|
||||
title = intl.formatMessage(messages.certificateHeaderNotAvailable);
|
||||
message = (
|
||||
<FormattedMessage
|
||||
id="courseCelebration.certificateBody.notAvailable"
|
||||
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é.
|
||||
You will be able to access your certificate any time from your
|
||||
{dashboardLink} and {profileLink}."
|
||||
description="Body in certificate banner"
|
||||
values={{ endDate, dashboardLink, profileLink }}
|
||||
/>
|
||||
<>
|
||||
<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."
|
||||
values={{ endDate }}
|
||||
/>
|
||||
</div>
|
||||
<div className="mb-2">
|
||||
<FormattedMessage
|
||||
id="courseCelebration.certificateBody.notAvailable.shareSuggestion"
|
||||
defaultMessage="Once you have your certificate, be sure to showcase your accomplishment on
|
||||
LinkedIn or your resumé."
|
||||
/>
|
||||
</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;
|
||||
}
|
||||
@@ -114,12 +138,12 @@ function CourseCelebration({ intl }) {
|
||||
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."
|
||||
description="Body in certificate banner"
|
||||
values={{ idVerificationSupportLink }}
|
||||
/>
|
||||
);
|
||||
@@ -131,43 +155,78 @@ function CourseCelebration({ intl }) {
|
||||
return (
|
||||
<>
|
||||
<Helmet>
|
||||
<title>{`Congratulations! | ${getConfig().SITE_NAME}`}</title>
|
||||
<title>{`${intl.formatMessage(messages.congratulationsHeader)} | ${getConfig().SITE_NAME}`}</title>
|
||||
</Helmet>
|
||||
<div className="align-items-center d-flex flex-column border border-light p-3 mb-3 mt-5">
|
||||
<h2>{ intl.formatMessage(messages.congratulationsHeader) }</h2>
|
||||
<div className="mb-3 h4 font-weight-normal">{ intl.formatMessage(messages.shareHeader) }</div>
|
||||
<div className="mb-5"><img src={celebration} alt="" className="img-fluid" /></div>
|
||||
<div className="d-flex flex-row p-4 mb-3 bg-primary-100">
|
||||
<div className="d-flex flex-column justify-content-between">
|
||||
<div className="h4 mb-0">{title}</div>
|
||||
{message}
|
||||
{/* The requesting status needs a different button because it does a POST instead of a GET */}
|
||||
{certStatus === 'requesting' ? (
|
||||
<div>
|
||||
<Button variant="outline-primary" onClick={() => dispatch(requestCert(courseId))} style={{ backgroundColor: '#FFFFFF' }}>
|
||||
<div className="row w-100 mx-0 my-4 px-5 py-3 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">
|
||||
<div className="row w-100 m-0 p-4 bg-primary-100">
|
||||
<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
|
||||
variant="outline-primary"
|
||||
onClick={() => dispatch(requestCert(courseId))}
|
||||
style={{ backgroundColor: 'white' }}
|
||||
>
|
||||
{buttonText}
|
||||
</Button>
|
||||
</div>
|
||||
) : (
|
||||
<div>
|
||||
<Button variant="outline-primary" href={buttonLocation} style={{ backgroundColor: '#FFFFFF' }}>
|
||||
)}
|
||||
{buttonLocation && (
|
||||
<Button
|
||||
variant="outline-primary"
|
||||
href={buttonLocation}
|
||||
style={{ backgroundColor: 'white' }}
|
||||
>
|
||||
{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>
|
||||
)}
|
||||
</div>
|
||||
{certStatus !== 'unverified' && (
|
||||
<div className="col-3"><img src={certificate} alt="" className="img-fluid" /></div>
|
||||
)}
|
||||
</div>
|
||||
<div className="mb-3 text-gray-500">
|
||||
<FontAwesomeIcon icon={faCalendarAlt} className="mr-2" style={{ width: '20px' }} />
|
||||
<FormattedMessage
|
||||
id="courseCelebration.dashboardInfo"
|
||||
defaultMessage="You can always access this course and its materials on your {dashboardLink}."
|
||||
description="Text letting the user know they can view their dashboard"
|
||||
values={{ dashboardLink }}
|
||||
/>
|
||||
<div className="row w-100 mx-0 my-3 justify-content-center">
|
||||
<p className="text-gray-700">
|
||||
<FontAwesomeIcon icon={faCalendarAlt} style={{ width: '20px' }} />
|
||||
<FormattedMessage
|
||||
id="courseCelebration.dashboardInfo"
|
||||
defaultMessage="You can always access this course and its materials on your {dashboardLink}."
|
||||
values={{ dashboardLink }}
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
import React from 'react';
|
||||
|
||||
import { getConfig } from '@edx/frontend-platform';
|
||||
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
|
||||
import { Button } from '@edx/paragon';
|
||||
import { Redirect, useParams } from 'react-router-dom';
|
||||
|
||||
import CourseCelebration from './CourseCelebration';
|
||||
import messages from './messages';
|
||||
import { useModel } from '../../../generic/model-store';
|
||||
|
||||
// These are taken from the edx-platform `get_cert_data` function found in lms/courseware/views/views.py
|
||||
@@ -13,7 +17,7 @@ const CELEBRATION_STATUSES = [
|
||||
'unverified',
|
||||
];
|
||||
|
||||
export default function CourseExit() {
|
||||
function CourseExit({ intl }) {
|
||||
const { courseId } = useParams();
|
||||
const {
|
||||
courseExitPageIsActive,
|
||||
@@ -31,8 +35,26 @@ export default function CourseExit() {
|
||||
} = certificateData;
|
||||
|
||||
if (CELEBRATION_STATUSES.indexOf(certStatus) !== -1) {
|
||||
return (<CourseCelebration />);
|
||||
return (
|
||||
<>
|
||||
<div className="row w-100 m-0 justify-content-end">
|
||||
<Button
|
||||
variant="outline-primary"
|
||||
href={`${getConfig().LMS_BASE_URL}/dashboard`}
|
||||
>
|
||||
{intl.formatMessage(messages.viewCoursesButton)}
|
||||
</Button>
|
||||
</div>
|
||||
<CourseCelebration />
|
||||
</>
|
||||
);
|
||||
}
|
||||
// Just to be safe
|
||||
return (<Redirect to={`/course/${courseId}`} />);
|
||||
}
|
||||
|
||||
CourseExit.propTypes = {
|
||||
intl: intlShape.isRequired,
|
||||
};
|
||||
|
||||
export default injectIntl(CourseExit);
|
||||
|
||||
BIN
src/courseware/course/course-exit/assets/celebration_750x540.gif
Normal file
BIN
src/courseware/course/course-exit/assets/celebration_750x540.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 650 KiB |
@@ -9,7 +9,7 @@ const messages = defineMessages({
|
||||
certificateHeaderNotAvailable: {
|
||||
id: 'courseCelebration.certificateHeader.notAvailable',
|
||||
defaultMessage: 'Your certificate will be available soon!',
|
||||
description: 'Text displayed when course certificate is not yet available to view',
|
||||
description: 'Text displayed when course certificate is not yet available to be viewed',
|
||||
},
|
||||
certificateHeaderUnverified: {
|
||||
id: 'courseCelebration.certificateHeader.unverified',
|
||||
@@ -21,55 +21,67 @@ 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',
|
||||
},
|
||||
certificateImage: {
|
||||
id: 'courseCelebration.certificateImage',
|
||||
defaultMessage: 'Sample certificate',
|
||||
description: 'Alt text used to describe an image of a certificate',
|
||||
},
|
||||
congratulationsHeader: {
|
||||
id: 'courseCelebration.congratulationsHeader',
|
||||
defaultMessage: 'Congratulations!',
|
||||
description: 'Congratulations header on course completion page',
|
||||
},
|
||||
congratulationsImage: {
|
||||
id: 'courseCelebration.congratulationsImage',
|
||||
defaultMessage: 'Four people raising their hands in celebration',
|
||||
description: 'Alt text used to describe celebratory image',
|
||||
},
|
||||
dashboardLink: {
|
||||
id: 'courseExit.dashboardLink',
|
||||
defaultMessage: 'Dashboard',
|
||||
description: "Link to learner's dashboard",
|
||||
description: "Link to user's dashboard",
|
||||
},
|
||||
downloadButton: {
|
||||
id: 'courseCelebration.downloadButton',
|
||||
defaultMessage: 'Download my certificate',
|
||||
description: 'Text for download button in certificate banner',
|
||||
description: 'Button to download the course certificate',
|
||||
},
|
||||
idVerificationSupportLink: {
|
||||
id: 'courseExit.idVerificationSupportLink',
|
||||
defaultMessage: 'Learn more about ID verification',
|
||||
description: 'Link to help article about ID verification',
|
||||
description: 'Link to an article about identity verification',
|
||||
},
|
||||
profileLink: {
|
||||
id: 'courseExit.profileLink',
|
||||
defaultMessage: 'Profile',
|
||||
description: 'Link to profile',
|
||||
description: "Link to user's profile",
|
||||
},
|
||||
requestCertificateBodyText: {
|
||||
id: 'courseCelebration.requestCertificateBodyText',
|
||||
defaultMessage: 'In order to access your certificate, request it below.',
|
||||
description: 'Body text for certificate banner',
|
||||
},
|
||||
requestCertificateButton: {
|
||||
id: 'courseCelebration.requestCertificateButton',
|
||||
defaultMessage: 'Request certificate',
|
||||
description: 'Text for request certificate button in certificate banner',
|
||||
description: 'Button to request the course certificate',
|
||||
},
|
||||
shareHeader: {
|
||||
id: 'courseCelebration.shareHeader',
|
||||
defaultMessage: 'You have completed your course. Share your success on social media or email.',
|
||||
description: 'Social media/email share header',
|
||||
},
|
||||
verifyIdentityButton: {
|
||||
id: 'courseCelebration.verifyIdentityButton',
|
||||
defaultMessage: 'Verify now',
|
||||
description: 'Text for verify identity button in certificate banner',
|
||||
defaultMessage: 'Verify ID now',
|
||||
description: 'Button to verify the identify of the user',
|
||||
},
|
||||
viewCertificateButton: {
|
||||
id: 'courseCelebration.viewCertificateButton',
|
||||
defaultMessage: 'View now',
|
||||
description: 'Text for view certificate button in certificate banner',
|
||||
defaultMessage: 'View my certificate',
|
||||
description: 'Button to view the course certificate',
|
||||
},
|
||||
viewCoursesButton: {
|
||||
id: 'courseExit.viewCoursesButton',
|
||||
defaultMessage: 'View my courses',
|
||||
description: 'Button to redirect user to their course dashboard',
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ import { Button } from '@edx/paragon';
|
||||
import classNames from 'classnames';
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
import { faChevronLeft, faChevronRight } from '@fortawesome/free-solid-svg-icons';
|
||||
import { FormattedMessage } from '@edx/frontend-platform/i18n';
|
||||
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
|
||||
|
||||
import { useSelector } from 'react-redux';
|
||||
import UnitButton from './UnitButton';
|
||||
@@ -13,7 +13,10 @@ import { useSequenceNavigationMetadata } from './hooks';
|
||||
import { useModel } from '../../../../generic/model-store';
|
||||
import { LOADED } from '../../../data/slice';
|
||||
|
||||
export default function SequenceNavigation({
|
||||
import messages from './messages';
|
||||
|
||||
function SequenceNavigation({
|
||||
intl,
|
||||
unitId,
|
||||
sequenceId,
|
||||
className,
|
||||
@@ -64,21 +67,9 @@ export default function SequenceNavigation({
|
||||
// AA-198: The userHasPassingGrade condition can be removed once we have a view for learners with failing grades
|
||||
const disabled = isLastUnit && (!courseExitPageIsActive || !userHasPassingGrade);
|
||||
|
||||
let buttonText = (
|
||||
<FormattedMessage
|
||||
defaultMessage="Next"
|
||||
id="learn.sequence.navigation.next.button"
|
||||
description="The Next button in the sequence nav"
|
||||
/>
|
||||
);
|
||||
let buttonText = (intl.formatMessage(messages.nextButton));
|
||||
if (isLastUnit && courseExitPageIsActive && userHasPassingGrade) {
|
||||
buttonText = (
|
||||
<FormattedMessage
|
||||
defaultMessage="Complete the course"
|
||||
id="learn.sequence.navigation.completeCourse.button"
|
||||
description="The 'Complete the course' button in the sequence nav"
|
||||
/>
|
||||
);
|
||||
buttonText = (intl.formatMessage(messages.completeCourseButton));
|
||||
}
|
||||
// AA-198: Uncomment once there is a view for learners with failing grades
|
||||
// else if (isLastUnit && courseExitPageIsActive && !userHasPassingGrade) {
|
||||
@@ -107,11 +98,7 @@ export default function SequenceNavigation({
|
||||
<nav className={classNames('sequence-navigation', className)}>
|
||||
<Button variant="link" className="previous-btn" onClick={previousSequenceHandler} disabled={isFirstUnit}>
|
||||
<FontAwesomeIcon icon={faChevronLeft} className="mr-2" size="sm" />
|
||||
<FormattedMessage
|
||||
defaultMessage="Previous"
|
||||
id="learn.sequence.navigation.previous.button"
|
||||
description="The Previous button in the sequence nav"
|
||||
/>
|
||||
{intl.formatMessage(messages.previousButton)}
|
||||
</Button>
|
||||
{renderUnitButtons()}
|
||||
{renderNextButton()}
|
||||
@@ -120,6 +107,7 @@ export default function SequenceNavigation({
|
||||
}
|
||||
|
||||
SequenceNavigation.propTypes = {
|
||||
intl: intlShape.isRequired,
|
||||
sequenceId: PropTypes.string.isRequired,
|
||||
unitId: PropTypes.string,
|
||||
className: PropTypes.string,
|
||||
@@ -133,3 +121,5 @@ SequenceNavigation.defaultProps = {
|
||||
className: null,
|
||||
unitId: null,
|
||||
};
|
||||
|
||||
export default injectIntl(SequenceNavigation);
|
||||
|
||||
@@ -28,6 +28,7 @@ describe('Sequence Navigation', () => {
|
||||
previousSequenceHandler: () => {},
|
||||
onNavigate: () => {},
|
||||
nextSequenceHandler: () => {},
|
||||
goToCourseExitPage: () => {},
|
||||
};
|
||||
});
|
||||
|
||||
|
||||
@@ -3,20 +3,21 @@ import PropTypes from 'prop-types';
|
||||
import { Button } from '@edx/paragon';
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
import { faChevronLeft, faChevronRight } from '@fortawesome/free-solid-svg-icons';
|
||||
import { FormattedMessage } from '@edx/frontend-platform/i18n';
|
||||
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { useSequenceNavigationMetadata } from './hooks';
|
||||
import { useModel } from '../../../../generic/model-store';
|
||||
|
||||
export default function UnitNavigation(props) {
|
||||
const {
|
||||
sequenceId,
|
||||
unitId,
|
||||
onClickPrevious,
|
||||
onClickNext,
|
||||
goToCourseExitPage,
|
||||
} = props;
|
||||
import messages from './messages';
|
||||
|
||||
function UnitNavigation({
|
||||
intl,
|
||||
sequenceId,
|
||||
unitId,
|
||||
onClickPrevious,
|
||||
onClickNext,
|
||||
goToCourseExitPage,
|
||||
}) {
|
||||
const { isFirstUnit, isLastUnit } = useSequenceNavigationMetadata(sequenceId, unitId);
|
||||
const { courseId } = useSelector(state => state.courseware);
|
||||
const {
|
||||
@@ -38,45 +39,18 @@ export default function UnitNavigation(props) {
|
||||
<div className="m-2">
|
||||
<span role="img" aria-hidden="true">🤗</span> {/* This is a hugging face emoji */}
|
||||
{' '}
|
||||
<FormattedMessage
|
||||
id="learn.end.of.course"
|
||||
description="Message shown to students in place of a 'Next' button when they're at the end of a course."
|
||||
defaultMessage="You've reached the end of this course!"
|
||||
/>
|
||||
{intl.formatMessage(messages.endOfCourse)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
let buttonText = (
|
||||
<FormattedMessage
|
||||
id="learn.sequence.navigation.after.unit.next"
|
||||
description="The button to go to the next unit"
|
||||
defaultMessage="Next"
|
||||
/>
|
||||
);
|
||||
let buttonText = (intl.formatMessage(messages.nextButton));
|
||||
if (isLastUnit && courseExitPageIsActive && userHasPassingGrade) {
|
||||
buttonText = (
|
||||
<FormattedMessage
|
||||
defaultMessage="Complete the course"
|
||||
id="learn.sequence.navigation.after.unit.completeCourse"
|
||||
description="The 'Complete the course' button in the unit nav"
|
||||
/>
|
||||
);
|
||||
buttonText = (intl.formatMessage(messages.completeCourseButton));
|
||||
}
|
||||
// AA-198: Uncomment once there is a view for learners with failing grades
|
||||
// else if (isLastUnit && courseExitPageIsActive && !userHasPassingGrade) {
|
||||
// buttonText = (
|
||||
// <FormattedMessage
|
||||
// defaultMessage="Next"
|
||||
// id="learn.sequence.navigation.endOfCourse.button.next"
|
||||
// description="The 'next' text in the end of course button in the sequence nav"
|
||||
// />
|
||||
// <FormattedMessage
|
||||
// defaultMessage="(end of course)"
|
||||
// id="learn.sequence.navigation.endOfCourse.button.endOfCourse"
|
||||
// description="The '(end of course)' text in the end of course button in the sequence nav"
|
||||
// />
|
||||
// )
|
||||
// buttonText = (`${intl.formatMessage(messages.nextButton)} (${intl.formatMessage(messages.endOfCourse)})`);
|
||||
// }
|
||||
return (
|
||||
<Button variant="outline-primary" className="next-button" onClick={buttonOnClick} disabled={disabled}>
|
||||
@@ -95,11 +69,7 @@ export default function UnitNavigation(props) {
|
||||
onClick={onClickPrevious}
|
||||
>
|
||||
<FontAwesomeIcon icon={faChevronLeft} className="mr-2" size="sm" />
|
||||
<FormattedMessage
|
||||
id="learn.sequence.navigation.after.unit.previous"
|
||||
description="The button to go to the previous unit"
|
||||
defaultMessage="Previous"
|
||||
/>
|
||||
{intl.formatMessage(messages.previousButton)}
|
||||
</Button>
|
||||
{renderNextButton()}
|
||||
</div>
|
||||
@@ -107,6 +77,7 @@ export default function UnitNavigation(props) {
|
||||
}
|
||||
|
||||
UnitNavigation.propTypes = {
|
||||
intl: intlShape.isRequired,
|
||||
sequenceId: PropTypes.string.isRequired,
|
||||
unitId: PropTypes.string,
|
||||
onClickPrevious: PropTypes.func.isRequired,
|
||||
@@ -117,3 +88,5 @@ UnitNavigation.propTypes = {
|
||||
UnitNavigation.defaultProps = {
|
||||
unitId: null,
|
||||
};
|
||||
|
||||
export default injectIntl(UnitNavigation);
|
||||
|
||||
@@ -22,6 +22,7 @@ describe('Unit Navigation', () => {
|
||||
sequenceId: courseware.sequenceId,
|
||||
onClickPrevious: () => {},
|
||||
onClickNext: () => {},
|
||||
goToCourseExitPage: () => {},
|
||||
};
|
||||
});
|
||||
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
import { defineMessages } from '@edx/frontend-platform/i18n';
|
||||
|
||||
const messages = defineMessages({
|
||||
completeCourseButton: {
|
||||
id: 'learn.sequence.navigation.complete.button',
|
||||
defaultMessage: 'Complete the course',
|
||||
description: 'Button to advance to the course completion page',
|
||||
},
|
||||
endOfCourse: {
|
||||
id: 'learn.end.of.course',
|
||||
defaultMessage: "You've reached the end of this course!",
|
||||
},
|
||||
nextButton: {
|
||||
id: 'learn.sequence.navigation.next.button',
|
||||
defaultMessage: 'Next',
|
||||
description: 'Button to advance to the next section',
|
||||
},
|
||||
previousButton: {
|
||||
id: 'learn.sequence.navigation.previous.button',
|
||||
defaultMessage: 'Previous',
|
||||
description: 'Button to return to the previous section',
|
||||
},
|
||||
});
|
||||
|
||||
export default messages;
|
||||
@@ -246,7 +246,9 @@ $primary: #1176B2;
|
||||
}
|
||||
}
|
||||
@media (min-width: map-get($grid-breakpoints, 'sm')) {
|
||||
min-width: 10rem;
|
||||
min-width: fit-content;
|
||||
padding-left: 2rem;
|
||||
padding-right: 2rem;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user