diff --git a/src/containers/CourseCard/CourseCard.scss b/src/containers/CourseCard/CourseCard.scss index af203b6..48d232d 100644 --- a/src/containers/CourseCard/CourseCard.scss +++ b/src/containers/CourseCard/CourseCard.scss @@ -1,3 +1,5 @@ +@import "@edx/paragon/scss/core/core"; + .course-card { .card { overflow: hidden; @@ -17,6 +19,8 @@ > .alert { border-top-left-radius: 0; border-top-right-radius: 0; + box-shadow: none; + padding: map-get($spacers, 3) map-get($spacers, 4); } } } diff --git a/src/containers/CourseCard/components/CourseCardBanners/CourseBanner.jsx b/src/containers/CourseCard/components/CourseCardBanners/CourseBanner.jsx index e443e58..4eb36e7 100644 --- a/src/containers/CourseCard/components/CourseCardBanners/CourseBanner.jsx +++ b/src/containers/CourseCard/components/CourseCardBanners/CourseBanner.jsx @@ -13,43 +13,59 @@ export const CourseBanner = ({ cardId }) => { isVerified, isAuditAccessExpired, canUpgrade, + coursewareAccess = {}, } = appHooks.useCardEnrollmentData(cardId); const courseRun = appHooks.useCardCourseRunData(cardId); const course = appHooks.useCardCourseData(cardId); const { formatMessage } = useIntl(); + const { hasUnmetPrerequisites, isStaff, isTooEarly } = coursewareAccess; + if (isVerified) { return null; } - if (isAuditAccessExpired) { - if (canUpgrade) { - return ( + return ( + <> + {isAuditAccessExpired + && (canUpgrade ? ( + + {formatMessage(messages.auditAccessExpired)} + {' '} + {formatMessage(messages.upgradeToAccess)} + + ) : ( + + {formatMessage(messages.auditAccessExpired)} + {' '} + { + + {formatMessage(messages.findAnotherCourse)} + + } + + ))} + + {courseRun.isActive && !canUpgrade && ( - {formatMessage(messages.auditAccessExpired)} + {formatMessage(messages.upgradeDeadlinePassed)} {' '} - {formatMessage(messages.upgradeToAccess)} + + {formatMessage(messages.exploreCourseDetails)} + - ); - } - return ( - - {formatMessage(messages.auditAccessExpired)} - {' '} - {formatMessage(messages.findAnotherCourse)} - - ); - } - if (courseRun.isActive && !canUpgrade) { - return ( - - {formatMessage(messages.upgradeDeadlinePassed)} - {' '} - - {formatMessage(messages.exploreCourseDetails)} - - - ); - } - return null; + )} + {isTooEarly && ( + + {formatMessage(messages.courseHasNotStarted, { + startDate: courseRun.startDate, + })} + + )} + {hasUnmetPrerequisites && ( + {formatMessage(messages.prerequisitesNotMet)} + )} + {isStaff && {formatMessage(messages.staffAccessOnly)}} + + ); }; CourseBanner.propTypes = { cardId: PropTypes.string.isRequired, diff --git a/src/containers/CourseCard/components/CourseCardBanners/CourseBanner.test.jsx b/src/containers/CourseCard/components/CourseCardBanners/CourseBanner.test.jsx index b224fce..b0049e4 100644 --- a/src/containers/CourseCard/components/CourseCardBanners/CourseBanner.test.jsx +++ b/src/containers/CourseCard/components/CourseCardBanners/CourseBanner.test.jsx @@ -3,6 +3,7 @@ import { shallow } from 'enzyme'; import { Hyperlink } from '@edx/paragon'; import { hooks as appHooks } from 'data/redux'; +import { formatMessage } from 'testUtils'; import { CourseBanner } from './CourseBanner'; import messages from './messages'; @@ -24,9 +25,15 @@ const enrollmentData = { isVerified: false, canUpgrade: false, isAuditAccessExpired: false, + coursewareAccess: { + hasUnmetPrerequisites: false, + isStaff: false, + isTooEarly: false, + }, }; const courseRunData = { isActive: false, + startDate: '11/11/3030', }; const courseData = { website: 'test-course-website', @@ -104,8 +111,54 @@ describe('CourseBanner', () => { }); test('no display if audit access not expired and (course is not active or can upgrade)', () => { render(); - expect(el.isEmptyRender()).toEqual(true); + // isEmptyRender() isn't true because the minimal is + expect(el.html()).toEqual(''); render({ enrollment: { canUpgrade: true }, courseRun: { isActive: true } }); - expect(el.isEmptyRender()).toEqual(true); + expect(el.html()).toEqual(''); + }); + describe('unmet prerequisites', () => { + beforeEach(() => { + render({ enrollment: { coursewareAccess: { hasUnmetPrerequisites: true } } }); + }); + test('snapshot: unmetPrerequisites', () => { + expect(el).toMatchSnapshot(); + }); + test('messages: prerequisitesNotMet', () => { + expect(el.text()).toContain(messages.prerequisitesNotMet.defaultMessage); + }); + }); + describe('too early', () => { + beforeEach(() => { + render({ enrollment: { coursewareAccess: { isTooEarly: true } } }); + }); + test('snapshot: tooEarly', () => { + expect(el).toMatchSnapshot(); + }); + test('messages: courseHasNotStarted', () => { + expect(el.text()).toContain(formatMessage(messages.courseHasNotStarted, { startDate: courseRunData.startDate })); + }); + }); + describe('staff', () => { + beforeEach(() => { + render({ enrollment: { coursewareAccess: { isStaff: true } } }); + }); + test('snapshot: isStaff', () => { + expect(el).toMatchSnapshot(); + }); + test('messages: staffAccessOnly', () => { + expect(el.text()).toContain(messages.staffAccessOnly.defaultMessage); + }); + }); + test('snapshot: stacking banners', () => { + render({ + enrollment: { + coursewareAccess: { + isStaff: true, + isTooEarly: true, + hasUnmetPrerequisites: true, + }, + }, + }); + expect(el).toMatchSnapshot(); }); }); diff --git a/src/containers/CourseCard/components/CourseCardBanners/__snapshots__/CourseBanner.test.jsx.snap b/src/containers/CourseCard/components/CourseCardBanners/__snapshots__/CourseBanner.test.jsx.snap index 5c3160a..aea9258 100644 --- a/src/containers/CourseCard/components/CourseCardBanners/__snapshots__/CourseBanner.test.jsx.snap +++ b/src/containers/CourseCard/components/CourseCardBanners/__snapshots__/CourseBanner.test.jsx.snap @@ -1,33 +1,77 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`CourseBanner audit access expired, can upgrade snapshot: (auditAccessExpired, upgradeToAccess) 1`] = ` - - Your audit access to this course has expired. - - Upgrade now to access your course again. - + + + Your audit access to this course has expired. + + Upgrade now to access your course again. + + `; exports[`CourseBanner audit access expired, cannot upgrade snapshot: (auditAccessExpired, findAnotherCourse hyperlink) 1`] = ` - - Your audit access to this course has expired. - - - Find another course - - + + + Your audit access to this course has expired. + + + Find another course + + + `; exports[`CourseBanner course run active and cannot upgrade snapshot: (upgradseDeadlinePassed, exploreCourseDetails hyperlink) 1`] = ` - - Your upgrade deadline for this course has passed. To upgrade, enroll in a session that is farther in the future. - - - Explore course details. - - + + + Your upgrade deadline for this course has passed. To upgrade, enroll in a session that is farther in the future. + + + Explore course details. + + + +`; + +exports[`CourseBanner snapshot: stacking banners 1`] = ` + + + You can't access this course just yet because the course hasn't started yet. The course will start on 11/11/3030. + + + You can't access this course just yet because you have not met the pre-requisites. + + + Staff access only. + + +`; + +exports[`CourseBanner staff snapshot: isStaff 1`] = ` + + + Staff access only. + + +`; + +exports[`CourseBanner too early snapshot: tooEarly 1`] = ` + + + You can't access this course just yet because the course hasn't started yet. The course will start on 11/11/3030. + + +`; + +exports[`CourseBanner unmet prerequisites snapshot: unmetPrerequisites 1`] = ` + + + You can't access this course just yet because you have not met the pre-requisites. + + `; diff --git a/src/containers/CourseCard/components/CourseCardBanners/messages.js b/src/containers/CourseCard/components/CourseCardBanners/messages.js index 5b030c5..0d49392 100644 --- a/src/containers/CourseCard/components/CourseCardBanners/messages.js +++ b/src/containers/CourseCard/components/CourseCardBanners/messages.js @@ -96,6 +96,21 @@ export const messages = StrictDict({ description: 'Entitlement session selection link text', defaultMessage: 'select a session', }, + prerequisitesNotMet: { + id: 'learner-dash.courseCard.banners.prerequisitesNotMet', + description: 'Message to learners with unmet prerequisites', + defaultMessage: 'You can\'t access this course just yet because you have not met the pre-requisites.', + }, + courseHasNotStarted: { + id: 'learner-dash.courseCard.banners.courseHasNotStarted', + description: 'Course has not started message', + defaultMessage: 'You can\'t access this course just yet because the course hasn\'t started yet. The course will start on {startDate}.', + }, + staffAccessOnly: { + id: 'learner-dash.courseCard.banners.staffAccessOnly', + description: 'Message to learners with staff access only', + defaultMessage: 'Staff access only.', + }, }); export default messages; diff --git a/src/data/redux/app/selectors.js b/src/data/redux/app/selectors.js index f3102d6..291ff4b 100644 --- a/src/data/redux/app/selectors.js +++ b/src/data/redux/app/selectors.js @@ -78,6 +78,7 @@ export const courseCard = StrictDict({ accessExpirationDate: enrollment.accessExpirationDate, canUpgrade: enrollment.canUpgrade, hasStarted: enrollment.hasStarted, + coursewareAccess: enrollment.coursewareAccess, hasFinished: enrollment.hasFinished, isAudit: enrollment.isAudit, isAuditAccessExpired: enrollment.isAuditAccessExpired,