diff --git a/.env b/.env index 435e8c3..d29c3f6 100644 --- a/.env +++ b/.env @@ -42,5 +42,6 @@ CAREER_LINK_URL='' ENABLE_EDX_PERSONAL_DASHBOARD=false ENABLE_PROGRAMS=false NON_BROWSABLE_COURSES=false +SHOW_UNENROLL_SURVEY=true # Fallback in local style files PARAGON_THEME_URLS={} diff --git a/.env.development b/.env.development index ea1ca4c..792ebcf 100644 --- a/.env.development +++ b/.env.development @@ -48,5 +48,6 @@ CAREER_LINK_URL='' ENABLE_EDX_PERSONAL_DASHBOARD=false ENABLE_PROGRAMS=false NON_BROWSABLE_COURSES=false +SHOW_UNENROLL_SURVEY=true # Fallback in local style files PARAGON_THEME_URLS={} diff --git a/.env.test b/.env.test index 4dec30e..1918ccb 100644 --- a/.env.test +++ b/.env.test @@ -47,4 +47,5 @@ CAREER_LINK_URL='' ENABLE_EDX_PERSONAL_DASHBOARD=true ENABLE_PROGRAMS=false NON_BROWSABLE_COURSES=false +SHOW_UNENROLL_SURVEY=true PARAGON_THEME_URLS={} diff --git a/example.env.config.js b/example.env.config.js index 96fa650..70907c7 100644 --- a/example.env.config.js +++ b/example.env.config.js @@ -70,4 +70,5 @@ module.exports = { ACCOUNT_PROFILE_URL: 'http://localhost:1995', CAREER_LINK_URL: '', EXPERIMENT_08_23_VAN_PAINTED_DOOR: true, + SHOW_UNENROLL_SURVEY: true }; diff --git a/src/config/index.js b/src/config/index.js index 5c23538..43b10af 100644 --- a/src/config/index.js +++ b/src/config/index.js @@ -21,6 +21,7 @@ const configuration = { SEARCH_CATALOG_URL: process.env.SEARCH_CATALOG_URL || null, ENABLE_PROGRAMS: process.env.ENABLE_PROGRAMS === 'true', NON_BROWSABLE_COURSES: process.env.NON_BROWSABLE_COURSES === 'true', + SHOW_UNENROLL_SURVEY: process.env.SHOW_UNENROLL_SURVEY === 'true', }; const features = {}; diff --git a/src/containers/UnenrollConfirmModal/hooks/index.js b/src/containers/UnenrollConfirmModal/hooks/index.js index 067e938..c0d60eb 100644 --- a/src/containers/UnenrollConfirmModal/hooks/index.js +++ b/src/containers/UnenrollConfirmModal/hooks/index.js @@ -2,7 +2,9 @@ import React from 'react'; import { StrictDict } from 'utils'; -import { useInitializeLearnerHome } from 'data/hooks'; +import { useInitializeLearnerHome, useUnenrollFromCourse } from 'data/hooks'; +import { configuration } from 'config'; +import { useCourseData } from 'hooks'; import { useUnenrollReasons } from './reasons'; import * as module from '.'; @@ -18,13 +20,23 @@ export const modalStates = StrictDict({ export const useUnenrollData = ({ closeModal, cardId }) => { const [isConfirmed, setIsConfirmed] = module.state.confirmed(false); - const confirm = () => setIsConfirmed(true); const reason = useUnenrollReasons({ cardId }); const { refetch: refreshList } = useInitializeLearnerHome(); + const courseData = useCourseData(cardId); + const courseId = courseData?.courseRun?.courseId; + + const { mutate: unenrollFromCourse } = useUnenrollFromCourse(); + + const confirm = () => { + if (!configuration.SHOW_UNENROLL_SURVEY) { + unenrollFromCourse({ courseId }); + } + setIsConfirmed(true); + }; let modalState; if (isConfirmed) { - modalState = (reason.isSubmitted) + modalState = (reason.isSubmitted || !configuration.SHOW_UNENROLL_SURVEY) ? modalStates.finished : modalStates.reason; } else { modalState = modalStates.confirm; diff --git a/src/containers/UnenrollConfirmModal/hooks/index.test.js b/src/containers/UnenrollConfirmModal/hooks/index.test.js index 319de8c..8a6759c 100644 --- a/src/containers/UnenrollConfirmModal/hooks/index.test.js +++ b/src/containers/UnenrollConfirmModal/hooks/index.test.js @@ -1,6 +1,8 @@ import { MockUseState } from 'testUtils'; +import { configuration } from 'config'; -import { useInitializeLearnerHome } from 'data/hooks'; +import { useInitializeLearnerHome, useUnenrollFromCourse } from 'data/hooks'; +import { useCourseData } from 'hooks'; import * as reasons from './reasons'; import * as hooks from '.'; @@ -11,12 +13,26 @@ jest.mock('./reasons', () => ({ jest.mock('data/hooks', () => ({ useInitializeLearnerHome: jest.fn(), + useUnenrollFromCourse: jest.fn(), +})); + +jest.mock('hooks', () => ({ + useCourseData: jest.fn(), +})); + +jest.mock('config', () => ({ + configuration: { + SHOW_UNENROLL_SURVEY: true, + }, })); const state = new MockUseState(hooks); const testValue = 'test-value'; const mockRefreshList = jest.fn(); +const unenrollFromCourse = jest.fn(); useInitializeLearnerHome.mockReturnValue({ refetch: mockRefreshList }); +useUnenrollFromCourse.mockReturnValue({ mutate: unenrollFromCourse }); +useCourseData.mockReturnValue({ courseRun: { courseId: 'test-course-id' } }); let out; const mockReason = { @@ -78,22 +94,66 @@ describe('UnenrollConfirmModal hooks', () => { expect(mockRefreshList).toHaveBeenCalled(); }); }); - describe('modalState', () => { - it('returns modalStates.finished if confirmed and submitted', () => { + }); + + describe('SHOW_UNENROLL_SURVEY configuration tests', () => { + beforeEach(() => { + state.mock(); + jest.clearAllMocks(); + }); + afterEach(() => { + state.restore(); + }); + + describe('when SHOW_UNENROLL_SURVEY is true (default)', () => { + beforeEach(() => { + configuration.SHOW_UNENROLL_SURVEY = true; + }); + + test('confirm does not call unenrollFromCourse immediately', () => { + out = createUseUnenrollData(); + out.confirm(); + expect(unenrollFromCourse).not.toHaveBeenCalled(); + expect(state.setState.confirmed).toHaveBeenCalledWith(true); + }); + + test('modalState returns reason when confirmed but not submitted', () => { + state.mockVal(state.keys.confirmed, true); + reasons.useUnenrollReasons.mockReturnValueOnce({ ...mockReason, isSubmitted: false }); + out = createUseUnenrollData(); + expect(out.modalState).toEqual(hooks.modalStates.reason); + }); + + test('modalState returns finished when confirmed and submitted', () => { state.mockVal(state.keys.confirmed, true); reasons.useUnenrollReasons.mockReturnValueOnce({ ...mockReason, isSubmitted: true }); out = createUseUnenrollData(); expect(out.modalState).toEqual(hooks.modalStates.finished); }); - it('returns modalStates.reason if confirmed and not submitted', () => { - state.mockVal(state.keys.confirmed, true); - out = createUseUnenrollData(); - expect(out.modalState).toEqual(hooks.modalStates.reason); + }); + + describe('when SHOW_UNENROLL_SURVEY is false', () => { + beforeEach(() => { + configuration.SHOW_UNENROLL_SURVEY = false; }); - it('returns modalStates.confirm if not confirmed', () => { - state.mockVal(state.keys.confirmed, false); + + afterEach(() => { + // Reset to default + configuration.SHOW_UNENROLL_SURVEY = true; + }); + + test('confirm calls unenrollFromCourse immediately', () => { out = createUseUnenrollData(); - expect(out.modalState).toEqual(hooks.modalStates.confirm); + out.confirm(); + expect(unenrollFromCourse).toHaveBeenCalled(); + expect(state.setState.confirmed).toHaveBeenCalledWith(true); + }); + + test('modalState returns finished when confirmed regardless of submission status', () => { + state.mockVal(state.keys.confirmed, true); + reasons.useUnenrollReasons.mockReturnValueOnce({ ...mockReason, isSubmitted: false }); + out = createUseUnenrollData(); + expect(out.modalState).toEqual(hooks.modalStates.finished); }); }); });