feat: showing course unenroll survey is configurable now (#738)

This commit is contained in:
Muhammad Arslan
2026-03-06 19:36:09 +05:00
committed by GitHub
parent 0d2eb96c86
commit ca954e139d
7 changed files with 90 additions and 13 deletions

1
.env
View File

@@ -42,5 +42,6 @@ CAREER_LINK_URL=''
ENABLE_EDX_PERSONAL_DASHBOARD=false ENABLE_EDX_PERSONAL_DASHBOARD=false
ENABLE_PROGRAMS=false ENABLE_PROGRAMS=false
NON_BROWSABLE_COURSES=false NON_BROWSABLE_COURSES=false
SHOW_UNENROLL_SURVEY=true
# Fallback in local style files # Fallback in local style files
PARAGON_THEME_URLS={} PARAGON_THEME_URLS={}

View File

@@ -48,5 +48,6 @@ CAREER_LINK_URL=''
ENABLE_EDX_PERSONAL_DASHBOARD=false ENABLE_EDX_PERSONAL_DASHBOARD=false
ENABLE_PROGRAMS=false ENABLE_PROGRAMS=false
NON_BROWSABLE_COURSES=false NON_BROWSABLE_COURSES=false
SHOW_UNENROLL_SURVEY=true
# Fallback in local style files # Fallback in local style files
PARAGON_THEME_URLS={} PARAGON_THEME_URLS={}

View File

@@ -47,4 +47,5 @@ CAREER_LINK_URL=''
ENABLE_EDX_PERSONAL_DASHBOARD=true ENABLE_EDX_PERSONAL_DASHBOARD=true
ENABLE_PROGRAMS=false ENABLE_PROGRAMS=false
NON_BROWSABLE_COURSES=false NON_BROWSABLE_COURSES=false
SHOW_UNENROLL_SURVEY=true
PARAGON_THEME_URLS={} PARAGON_THEME_URLS={}

View File

@@ -70,4 +70,5 @@ module.exports = {
ACCOUNT_PROFILE_URL: 'http://localhost:1995', ACCOUNT_PROFILE_URL: 'http://localhost:1995',
CAREER_LINK_URL: '', CAREER_LINK_URL: '',
EXPERIMENT_08_23_VAN_PAINTED_DOOR: true, EXPERIMENT_08_23_VAN_PAINTED_DOOR: true,
SHOW_UNENROLL_SURVEY: true
}; };

View File

@@ -21,6 +21,7 @@ const configuration = {
SEARCH_CATALOG_URL: process.env.SEARCH_CATALOG_URL || null, SEARCH_CATALOG_URL: process.env.SEARCH_CATALOG_URL || null,
ENABLE_PROGRAMS: process.env.ENABLE_PROGRAMS === 'true', ENABLE_PROGRAMS: process.env.ENABLE_PROGRAMS === 'true',
NON_BROWSABLE_COURSES: process.env.NON_BROWSABLE_COURSES === 'true', NON_BROWSABLE_COURSES: process.env.NON_BROWSABLE_COURSES === 'true',
SHOW_UNENROLL_SURVEY: process.env.SHOW_UNENROLL_SURVEY === 'true',
}; };
const features = {}; const features = {};

View File

@@ -2,7 +2,9 @@ import React from 'react';
import { StrictDict } from 'utils'; 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 { useUnenrollReasons } from './reasons';
import * as module from '.'; import * as module from '.';
@@ -18,13 +20,23 @@ export const modalStates = StrictDict({
export const useUnenrollData = ({ closeModal, cardId }) => { export const useUnenrollData = ({ closeModal, cardId }) => {
const [isConfirmed, setIsConfirmed] = module.state.confirmed(false); const [isConfirmed, setIsConfirmed] = module.state.confirmed(false);
const confirm = () => setIsConfirmed(true);
const reason = useUnenrollReasons({ cardId }); const reason = useUnenrollReasons({ cardId });
const { refetch: refreshList } = useInitializeLearnerHome(); 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; let modalState;
if (isConfirmed) { if (isConfirmed) {
modalState = (reason.isSubmitted) modalState = (reason.isSubmitted || !configuration.SHOW_UNENROLL_SURVEY)
? modalStates.finished : modalStates.reason; ? modalStates.finished : modalStates.reason;
} else { } else {
modalState = modalStates.confirm; modalState = modalStates.confirm;

View File

@@ -1,6 +1,8 @@
import { MockUseState } from 'testUtils'; 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 reasons from './reasons';
import * as hooks from '.'; import * as hooks from '.';
@@ -11,12 +13,26 @@ jest.mock('./reasons', () => ({
jest.mock('data/hooks', () => ({ jest.mock('data/hooks', () => ({
useInitializeLearnerHome: jest.fn(), 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 state = new MockUseState(hooks);
const testValue = 'test-value'; const testValue = 'test-value';
const mockRefreshList = jest.fn(); const mockRefreshList = jest.fn();
const unenrollFromCourse = jest.fn();
useInitializeLearnerHome.mockReturnValue({ refetch: mockRefreshList }); useInitializeLearnerHome.mockReturnValue({ refetch: mockRefreshList });
useUnenrollFromCourse.mockReturnValue({ mutate: unenrollFromCourse });
useCourseData.mockReturnValue({ courseRun: { courseId: 'test-course-id' } });
let out; let out;
const mockReason = { const mockReason = {
@@ -78,22 +94,66 @@ describe('UnenrollConfirmModal hooks', () => {
expect(mockRefreshList).toHaveBeenCalled(); 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); state.mockVal(state.keys.confirmed, true);
reasons.useUnenrollReasons.mockReturnValueOnce({ ...mockReason, isSubmitted: true }); reasons.useUnenrollReasons.mockReturnValueOnce({ ...mockReason, isSubmitted: true });
out = createUseUnenrollData(); out = createUseUnenrollData();
expect(out.modalState).toEqual(hooks.modalStates.finished); expect(out.modalState).toEqual(hooks.modalStates.finished);
}); });
it('returns modalStates.reason if confirmed and not submitted', () => { });
state.mockVal(state.keys.confirmed, true);
out = createUseUnenrollData(); describe('when SHOW_UNENROLL_SURVEY is false', () => {
expect(out.modalState).toEqual(hooks.modalStates.reason); 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(); 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);
}); });
}); });
}); });