Skip to content

Commit 7ebdf1b

Browse files
ayesha-warishassan-raza-1Ayesha Waris
authored
feat: Add notify all learners discussion post checkbox (#779)
* feat: Add notify all learners discussion post checkbox * refactor: refactored post editor * test: added test cases * fix: fixed lint errors --------- Co-authored-by: Hassan Raza <[email protected]> Co-authored-by: Ayesha Waris <[email protected]>
1 parent 5d75e03 commit 7ebdf1b

File tree

6 files changed

+71
-0
lines changed

6 files changed

+71
-0
lines changed

src/discussions/data/selectors.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ export const selectEnableInContext = state => state.config.enableInContext;
3131

3232
export const selectIsPostingEnabled = state => state.config.isPostingEnabled;
3333

34+
export const selectIsNotifyAllLearnersEnabled = state => state.config.isNotifyAllLearnersEnabled;
35+
3436
export const selectModerationSettings = state => ({
3537
postCloseReasons: state.config.postCloseReasons,
3638
editReasons: state.config.editReasons,

src/discussions/posts/data/api.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ export const postThread = async (
9898
cohort,
9999
anonymous,
100100
anonymousToPeers,
101+
notifyAllLearners,
101102
} = {},
102103
enableInContextSidebar = false,
103104
) => {
@@ -112,6 +113,7 @@ export const postThread = async (
112113
anonymousToPeers,
113114
groupId: cohort,
114115
enableInContextSidebar,
116+
notifyAllLearners,
115117
});
116118
const { data } = await getAuthenticatedHttpClient()
117119
.post(getThreadsApiUrl(), postData);

src/discussions/posts/data/thunks.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,7 @@ export function createNewThread({
204204
anonymousToPeers,
205205
cohort,
206206
enableInContextSidebar,
207+
notifyAllLearners,
207208
}) {
208209
return async (dispatch) => {
209210
try {
@@ -217,12 +218,14 @@ export function createNewThread({
217218
anonymous,
218219
anonymousToPeers,
219220
cohort,
221+
notifyAllLearners,
220222
}));
221223
const data = await postThread(courseId, topicId, type, title, content, {
222224
cohort,
223225
following,
224226
anonymous,
225227
anonymousToPeers,
228+
notifyAllLearners,
226229
}, enableInContextSidebar);
227230
dispatch(postThreadSuccess(camelCaseObject(data)));
228231
} catch (error) {

src/discussions/posts/post-editor/PostEditor.jsx

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import {
2929
selectAnonymousPostingConfig,
3030
selectDivisionSettings,
3131
selectEnableInContext,
32+
selectIsNotifyAllLearnersEnabled,
3233
selectModerationSettings,
3334
selectUserHasModerationPrivileges,
3435
selectUserIsGroupTa,
@@ -79,6 +80,7 @@ const PostEditor = ({
7980
const userIsStaff = useSelector(selectUserIsStaff);
8081
const archivedTopics = useSelector(selectArchivedTopics);
8182
const postEditorId = `post-editor-${editExisting ? postId : 'new'}`;
83+
const isNotifyAllLearnersEnabled = useSelector(selectIsNotifyAllLearnersEnabled);
8284

8385
const canDisplayEditReason = (editExisting
8486
&& (userHasModerationPrivileges || userIsGroupTa || userIsStaff)
@@ -108,6 +110,7 @@ const PostEditor = ({
108110
title: post?.title || '',
109111
comment: post?.rawBody || '',
110112
follow: isEmpty(post?.following) ? true : post?.following,
113+
notifyAllLearners: false,
111114
anonymous: allowAnonymous ? false : undefined,
112115
anonymousToPeers: allowAnonymousToPeers ? false : undefined,
113116
cohort: post?.cohort || 'default',
@@ -161,6 +164,7 @@ const PostEditor = ({
161164
anonymousToPeers: allowAnonymousToPeers ? values.anonymousToPeers : undefined,
162165
cohort,
163166
enableInContextSidebar,
167+
notifyAllLearners: values.notifyAllLearners,
164168
}));
165169
}
166170
/* istanbul ignore if: TinyMCE is mocked so this cannot be easily tested */
@@ -216,6 +220,8 @@ const PostEditor = ({
216220
anonymousToPeers: Yup.bool()
217221
.default(false)
218222
.nullable(),
223+
notifyAllLearners: Yup.bool()
224+
.default(false),
219225
cohort: Yup.string()
220226
.nullable()
221227
.default(null),
@@ -417,6 +423,21 @@ const PostEditor = ({
417423
<div className="d-flex flex-row mt-n4 w-75 text-primary font-style">
418424
{!editExisting && (
419425
<>
426+
{isNotifyAllLearnersEnabled && (
427+
<Form.Group>
428+
<Form.Checkbox
429+
name="notifyAllLearners"
430+
checked={values.notifyAllLearners}
431+
onChange={handleChange}
432+
onBlur={handleBlur}
433+
className="mr-4.5"
434+
>
435+
<span>
436+
{intl.formatMessage(messages.notifyAllLearners)}
437+
</span>
438+
</Form.Checkbox>
439+
</Form.Group>
440+
)}
420441
<Form.Group>
421442
<Form.Checkbox
422443
name="follow"

src/discussions/posts/post-editor/PostEditor.test.jsx

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ import { initializeStore } from '../../../store';
1919
import executeThunk from '../../../test-utils';
2020
import { getCohortsApiUrl } from '../../cohorts/data/api';
2121
import DiscussionContext from '../../common/context';
22+
import { getCourseConfigApiUrl } from '../../data/api';
23+
import fetchCourseConfig from '../../data/thunks';
2224
import fetchCourseTopics from '../../topics/data/thunks';
2325
import { getThreadsApiUrl } from '../data/api';
2426
import { fetchThread } from '../data/thunks';
@@ -31,6 +33,7 @@ import '../data/__factories__';
3133

3234
const courseId = 'course-v1:edX+DemoX+Demo_Course';
3335
const topicsApiUrl = `${getApiBaseUrl()}/api/discussion/v1/course_topics/${courseId}`;
36+
const courseConfigApiUrl = getCourseConfigApiUrl();
3437
const threadsApiUrl = getThreadsApiUrl();
3538
let store;
3639
let axiosMock;
@@ -143,6 +146,42 @@ describe('PostEditor', () => {
143146
});
144147
});
145148

149+
describe.each([
150+
{
151+
isNotifyAllLearnersEnabled: true,
152+
description: 'when "Notify All Learners" is enabled',
153+
},
154+
{
155+
isNotifyAllLearnersEnabled: false,
156+
description: 'when "Notify All Learners" is disabled',
157+
},
158+
])('$description', ({ isNotifyAllLearnersEnabled }) => {
159+
beforeEach(async () => {
160+
store = initializeStore({
161+
config: {
162+
provider: 'legacy',
163+
is_notify_all_learners_enabled: isNotifyAllLearnersEnabled,
164+
moderationSettings: {},
165+
},
166+
});
167+
168+
axiosMock
169+
.onGet(`${courseConfigApiUrl}${courseId}/`)
170+
.reply(200, { is_notify_all_learners_enabled: isNotifyAllLearnersEnabled });
171+
172+
await store.dispatch(fetchCourseConfig(courseId));
173+
renderComponent();
174+
});
175+
176+
test(`should ${isNotifyAllLearnersEnabled ? 'show' : 'not show'} the "Notify All Learners" option`, async () => {
177+
if (isNotifyAllLearnersEnabled) {
178+
await waitFor(() => expect(screen.queryByText('Notify All Learners')).toBeInTheDocument());
179+
} else {
180+
await waitFor(() => expect(screen.queryByText('Notify All Learners')).not.toBeInTheDocument());
181+
}
182+
});
183+
});
184+
146185
describe('cohorting', () => {
147186
const dividedncw = ['ncw-topic-2'];
148187
const dividedcw = ['category-1-topic-2', 'category-2-topic-1', 'category-2-topic-2'];

src/discussions/posts/post-editor/messages.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,10 @@ const messages = defineMessages({
8989
id: 'discussions.post.editor.anonymousToPeersPost',
9090
defaultMessage: 'Post anonymously to peers',
9191
},
92+
notifyAllLearners: {
93+
id: 'discussions.post.editor.notifyAllLearners',
94+
defaultMessage: 'Notify All Learners',
95+
},
9296
submit: {
9397
id: 'discussions.editor.submit',
9498
defaultMessage: 'Submit',

0 commit comments

Comments
 (0)