diff --git a/src/course-home/progress-tab/certificate-status/CertificateStatus.jsx b/src/course-home/progress-tab/certificate-status/CertificateStatus.jsx
index cc73ca06..03837ee1 100644
--- a/src/course-home/progress-tab/certificate-status/CertificateStatus.jsx
+++ b/src/course-home/progress-tab/certificate-status/CertificateStatus.jsx
@@ -19,6 +19,10 @@ const CertificateStatus = ({ intl }) => {
courseId,
} = useSelector(state => state.courseHome);
+ const {
+ entranceExamData,
+ } = useModel('coursewareMeta', courseId);
+
const {
isEnrolled,
org,
@@ -42,6 +46,8 @@ const CertificateStatus = ({ intl }) => {
certificateAvailableDate,
} = certificateData || {};
+ const entranceExamPassed = entranceExamData?.entranceExamPassed ?? null;
+
const mode = getCourseExitMode(
certificateData,
hasScheduledContent,
@@ -49,6 +55,7 @@ const CertificateStatus = ({ intl }) => {
userHasPassingGrade,
null, // CourseExitPageIsActive
canViewCertificate,
+ entranceExamPassed,
);
const eventProperties = {
diff --git a/src/courseware/course/course-exit/utils.js b/src/courseware/course/course-exit/utils.js
index da1d3530..c989a150 100644
--- a/src/courseware/course/course-exit/utils.js
+++ b/src/courseware/course/course-exit/utils.js
@@ -9,6 +9,7 @@ const COURSE_EXIT_MODES = {
celebration: 1,
nonPassing: 2,
inProgress: 3,
+ entranceExamFail: 4,
};
// These are taken from the edx-platform `get_cert_data` function found in lms/courseware/views/views.py
@@ -32,9 +33,14 @@ function getCourseExitMode(
userHasPassingGrade,
courseExitPageIsActive = null,
canImmediatelyViewCertificate = false,
+ entranceExamPassed = null,
) {
const authenticatedUser = getAuthenticatedUser();
+ if (entranceExamPassed === false) {
+ return COURSE_EXIT_MODES.entranceExamFail;
+ }
+
if (courseExitPageIsActive === false || !authenticatedUser || !isEnrolled) {
return COURSE_EXIT_MODES.disabled;
}
@@ -73,6 +79,7 @@ function GetCourseExitNavigation(courseId, intl) {
isEnrolled,
userHasPassingGrade,
courseExitPageIsActive,
+ entranceExamData: { entranceExamPassed },
} = useModel('coursewareMeta', courseId);
const { canViewCertificate } = useModel('courseHomeMeta', courseId);
const exitMode = getCourseExitMode(
@@ -82,8 +89,15 @@ function GetCourseExitNavigation(courseId, intl) {
userHasPassingGrade,
courseExitPageIsActive,
canViewCertificate,
+ entranceExamPassed,
);
- const exitActive = exitMode !== COURSE_EXIT_MODES.disabled;
+
+ /** exitActive is used to enable/disable the exit i.e. next buttons.
+ COURSE_EXIT_MODES denote the current status of the course.
+ Available COURSE_EXIT_MODES: disabled, celebration, nonPassing, inProgress, entranceExamFail
+ If the user fails the entrance exam,
+ access to further course sections should not be allowed i.e. disable the next buttons. */
+ const exitActive = ((exitMode !== COURSE_EXIT_MODES.disabled) && (exitMode !== COURSE_EXIT_MODES.entranceExamFail));
let exitText;
switch (exitMode) {
diff --git a/src/courseware/course/sequence/sequence-navigation/UnitNavigation.test.jsx b/src/courseware/course/sequence/sequence-navigation/UnitNavigation.test.jsx
index 89603e65..779769d2 100644
--- a/src/courseware/course/sequence/sequence-navigation/UnitNavigation.test.jsx
+++ b/src/courseware/course/sequence/sequence-navigation/UnitNavigation.test.jsx
@@ -86,6 +86,50 @@ describe('Unit Navigation', () => {
expect(screen.getByRole('button', { name: /next/i })).toBeDisabled();
});
+ it('has the "Next" button disabled for entrance exam failed', async () => {
+ const testCourseMetadata = {
+ ...courseMetadata,
+ certificate_data: { cert_status: 'bogus_status' },
+ enrollment: { is_active: true },
+ entrance_exam_data: {
+ entrance_exam_current_score: 0, entrance_exam_enabled: true, entrance_exam_id: '1', entrance_exam_minimum_score_pct: 0.65, entrance_exam_passed: false,
+ },
+ };
+ const testStore = await initializeTestStore({ courseMetadata: testCourseMetadata, unitBlocks }, false);
+ // Have to refetch the sequenceId since the new store generates new sequences
+ const { courseware } = testStore.getState();
+ const testData = { ...mockData, sequenceId: courseware.sequenceId };
+
+ render(
+ ,
+ { store: testStore, wrapWithRouter: true },
+ );
+
+ expect(screen.getByRole('button', { name: /next/i })).toBeDisabled();
+ });
+
+ it('has the "Next" button enabled for entrance exam pass', async () => {
+ const testCourseMetadata = {
+ ...courseMetadata,
+ certificate_data: { cert_status: 'bogus_status' },
+ enrollment: { is_active: true },
+ entrance_exam_data: {
+ entrance_exam_current_score: 1.0, entrance_exam_enabled: true, entrance_exam_id: '1', entrance_exam_minimum_score_pct: 0.65, entrance_exam_passed: true,
+ },
+ };
+ const testStore = await initializeTestStore({ courseMetadata: testCourseMetadata, unitBlocks }, false);
+ // Have to refetch the sequenceId since the new store generates new sequences
+ const { courseware } = testStore.getState();
+ const testData = { ...mockData, sequenceId: courseware.sequenceId };
+
+ render(
+ ,
+ { store: testStore, wrapWithRouter: true },
+ );
+
+ expect(screen.getByRole('link', { name: /next/i })).toBeEnabled();
+ });
+
it('displays end of course message instead of the "Next" button as needed', async () => {
const testCourseMetadata = { ...courseMetadata, certificate_data: { cert_status: 'notpassing' }, enrollment: { is_active: true } };
const testStore = await initializeTestStore({ courseMetadata: testCourseMetadata, unitBlocks }, false);
diff --git a/src/courseware/course/sequence/sequence-navigation/hooks.js b/src/courseware/course/sequence/sequence-navigation/hooks.js
index ef0db203..d0195468 100644
--- a/src/courseware/course/sequence/sequence-navigation/hooks.js
+++ b/src/courseware/course/sequence/sequence-navigation/hooks.js
@@ -13,6 +13,7 @@ export function useSequenceNavigationMetadata(currentSequenceId, currentUnitId)
const sequence = useModel('sequences', currentSequenceId);
const courseId = useSelector(state => state.courseware.courseId);
const courseStatus = useSelector(state => state.courseware.courseStatus);
+ const { entranceExamData: { entranceExamPassed } } = useModel('coursewareMeta', courseId);
const sequenceStatus = useSelector(state => state.courseware.sequenceStatus);
// If we don't know the sequence and unit yet, then assume no.
@@ -25,6 +26,16 @@ export function useSequenceNavigationMetadata(currentSequenceId, currentUnitId)
};
}
+ // if entrance exam is not passed then we should treat this as 1st and last unit
+ if (entranceExamPassed === false) {
+ return {
+ isFirstUnit: true,
+ isLastUnit: true,
+ navigationDisabledNextSequence: false,
+ navigationDisabledPrevSequence: false,
+ };
+ }
+
const sequenceIndex = sequenceIds.indexOf(currentSequenceId);
const unitIndex = sequence.unitIds.indexOf(currentUnitId);