diff --git a/src/components/bulk-email-tool/BulkEmailTool.jsx b/src/components/bulk-email-tool/BulkEmailTool.jsx
index 015e1d0..f8a54a2 100644
--- a/src/components/bulk-email-tool/BulkEmailTool.jsx
+++ b/src/components/bulk-email-tool/BulkEmailTool.jsx
@@ -6,7 +6,7 @@ import { Spinner } from '@edx/paragon';
import { ErrorPage } from '@edx/frontend-platform/react';
import BulkEmailTaskManager from './bulk-email-task-manager/BulkEmailTaskManager';
import Navigationtabs from '../navigation-tabs/NavigationTabs';
-import { getCourseHomeCourseMetadata } from './data/api';
+import { getCohorts, getCourseHomeCourseMetadata } from './data/api';
import useMobileResponsive from '../../utils/useMobileResponsive';
import BulkEmailForm from './bulk-email-form';
@@ -18,20 +18,25 @@ export default function BulkEmailTool() {
useEffect(() => {
async function fetchTabData() {
- let data;
+ let metadataResponse;
+ let cohortsResponse;
try {
- data = await getCourseHomeCourseMetadata(courseId);
+ metadataResponse = await getCourseHomeCourseMetadata(courseId);
+ cohortsResponse = await getCohorts(courseId);
} catch (e) {
setCourseMetadata({
isStaff: false,
tabs: [],
+ cohorts: [],
});
return;
}
- const { tabs, is_staff: isStaff } = data;
+ const { tabs, is_staff: isStaff } = metadataResponse;
+ const { cohorts } = cohortsResponse;
setCourseMetadata({
isStaff,
tabs: [...tabs],
+ cohorts: cohorts.map(({ name }) => name),
});
}
fetchTabData();
@@ -43,7 +48,7 @@ export default function BulkEmailTool() {
-
+
diff --git a/src/components/bulk-email-tool/bulk-email-form/BulkEmailForm.jsx b/src/components/bulk-email-tool/bulk-email-form/BulkEmailForm.jsx
index dd19344..c2af641 100644
--- a/src/components/bulk-email-tool/bulk-email-form/BulkEmailForm.jsx
+++ b/src/components/bulk-email-tool/bulk-email-form/BulkEmailForm.jsx
@@ -20,7 +20,7 @@ export const FORM_SUBMIT_STATES = {
};
export default function BulkEmailForm(props) {
- const { courseId } = props;
+ const { courseId, cohorts } = props;
const [subject, setSubject] = useState('');
const [emailFormStatus, setEmailFormStatus] = useState(FORM_SUBMIT_STATES.DEFAULT);
const [emailFormValidation, setEmailFormValidation] = useState({
@@ -126,6 +126,7 @@ export default function BulkEmailForm(props) {
@@ -220,6 +221,11 @@ export default function BulkEmailForm(props) {
);
}
+BulkEmailForm.defaultProps = {
+ cohorts: [],
+};
+
BulkEmailForm.propTypes = {
courseId: PropTypes.string.isRequired,
+ cohorts: PropTypes.arrayOf(PropTypes.string),
};
diff --git a/src/components/bulk-email-tool/bulk-email-form/BulkEmailRecipient.jsx b/src/components/bulk-email-tool/bulk-email-form/BulkEmailRecipient.jsx
index 3fb3c04..5a486ac 100644
--- a/src/components/bulk-email-tool/bulk-email-form/BulkEmailRecipient.jsx
+++ b/src/components/bulk-email-tool/bulk-email-form/BulkEmailRecipient.jsx
@@ -12,7 +12,7 @@ const DEFAULT_GROUPS = {
};
export default function BulkEmailRecipient(props) {
- const { handleCheckboxes, selectedGroups } = props;
+ const { handleCheckboxes, selectedGroups, additionalCohorts } = props;
return (
@@ -22,8 +22,13 @@ export default function BulkEmailRecipient(props) {
description="A label before the list of potential recipients"
/>
-
-
+
+
+ {
+ // additional cohorts
+ additionalCohorts
+ && additionalCohorts.map((cohort) => (
+ group === (DEFAULT_GROUPS.AUDIT || DEFAULT_GROUPS.VERIFIED))}
+ >
+
+
+ ))
+ }
{!props.isValid && (
@@ -86,10 +108,12 @@ export default function BulkEmailRecipient(props) {
BulkEmailRecipient.defaultProps = {
isValid: true,
+ additionalCohorts: [],
};
BulkEmailRecipient.propTypes = {
selectedGroups: PropTypes.arrayOf(PropTypes.string).isRequired,
handleCheckboxes: PropTypes.func.isRequired,
isValid: PropTypes.bool,
+ additionalCohorts: PropTypes.arrayOf(PropTypes.string),
};
diff --git a/src/components/bulk-email-tool/data/__factories__/cohort.factory.js b/src/components/bulk-email-tool/data/__factories__/cohort.factory.js
new file mode 100644
index 0000000..ab51d27
--- /dev/null
+++ b/src/components/bulk-email-tool/data/__factories__/cohort.factory.js
@@ -0,0 +1,9 @@
+import { Factory } from 'rosie'; // eslint-disable-line import/no-extraneous-dependencies
+
+export default Factory.define('cohort')
+ .sequence('id', (i) => i)
+ .sequence('name', i => `test cohort ${i}`)
+ .attrs({
+ assignment_type: 'test',
+ user_count: 1,
+ });
diff --git a/src/components/bulk-email-tool/data/api.js b/src/components/bulk-email-tool/data/api.js
index 5a3eeb8..70d39ce 100644
--- a/src/components/bulk-email-tool/data/api.js
+++ b/src/components/bulk-email-tool/data/api.js
@@ -14,3 +14,9 @@ export async function getCourseHomeCourseMetadata(courseId) {
const { data } = await getAuthenticatedHttpClient().get(courseHomeMetadataUrl);
return data;
}
+
+export async function getCohorts(courseId) {
+ const url = `${getConfig().LMS_BASE_URL}/courses/${courseId}/cohorts/`;
+ const { data } = await getAuthenticatedHttpClient().get(url);
+ return data;
+}
diff --git a/src/components/bulk-email-tool/test/BulkEmailTool.test.jsx b/src/components/bulk-email-tool/test/BulkEmailTool.test.jsx
index 5ff2d15..ee02cf0 100644
--- a/src/components/bulk-email-tool/test/BulkEmailTool.test.jsx
+++ b/src/components/bulk-email-tool/test/BulkEmailTool.test.jsx
@@ -3,10 +3,11 @@
*/
import React from 'react';
import { Factory } from 'rosie';
-import { render, screen } from '../../../setupTest';
+import { render, screen, cleanup } from '../../../setupTest';
import BulkEmailTool from '../BulkEmailTool';
-import { getCourseHomeCourseMetadata } from '../data/api';
+import { getCourseHomeCourseMetadata, getCohorts } from '../data/api';
import '../data/__factories__/courseMetadata.factory';
+import '../data/__factories__/cohort.factory';
jest.mock('../text-editor/TextEditor');
jest.mock('../bulk-email-task-manager/api', () => ({
@@ -16,6 +17,7 @@ jest.mock('../bulk-email-task-manager/api', () => ({
jest.mock('../data/api', () => ({
__esModule: true,
getCourseHomeCourseMetadata: jest.fn(() => {}),
+ getCohorts: jest.fn(() => {}),
}));
jest.mock('react-router-dom', () => ({
...jest.requireActual('react-router-dom'),
@@ -25,15 +27,21 @@ jest.mock('react-router-dom', () => ({
}));
describe('BulkEmailTool', () => {
+ beforeEach(() => jest.resetModules());
+ afterEach(cleanup);
test('BulkEmailTool renders properly when given course metadata', async () => {
const courseMetadata = Factory.build('courseMetadata');
+ const cohorts = { cohorts: [Factory.build('cohort'), Factory.build('cohort')] };
getCourseHomeCourseMetadata.mockImplementation(() => courseMetadata);
+ getCohorts.mockImplementation(() => cohorts);
render();
expect(await screen.findByText('Course')).toBeTruthy();
});
test('BulkEmailTool renders error page on no staff user', async () => {
const courseMetadata = Factory.build('courseMetadata', { is_staff: false });
+ const cohorts = { cohorts: [Factory.build('cohort'), Factory.build('cohort')] };
getCourseHomeCourseMetadata.mockImplementation(() => courseMetadata);
+ getCohorts.mockImplementation(() => cohorts);
render();
expect(
await screen.findByText('An unexpected error occurred. Please click the button below to refresh the page.'),