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 ef334e7..ea473f7 100644
--- a/src/components/bulk-email-tool/bulk-email-form/BulkEmailForm.jsx
+++ b/src/components/bulk-email-tool/bulk-email-form/BulkEmailForm.jsx
@@ -220,7 +220,7 @@ function BulkEmailForm(props) {
{intl.formatMessage(messages.bulkEmailTaskAlertRecipients, { subject: editor.emailSubject })}
{editor.emailRecipients.map((group) => (
- - {getDisplayTextFromRecipient(group)}
+ - {getDisplayTextFromRecipient(intl, group)}
))}
{!isScheduled && (
@@ -247,7 +247,7 @@ function BulkEmailForm(props) {
{intl.formatMessage(messages.bulkEmailTaskAlertEditingTo)}
{editor.emailRecipients.map((group) => (
- - {getDisplayTextFromRecipient(group)}
+ - {getDisplayTextFromRecipient(intl, group)}
))}
{intl.formatMessage(messages.bulkEmailTaskAlertEditingWarning)}
diff --git a/src/components/bulk-email-tool/bulk-email-form/bulk-email-recipient/BulkEmailRecipient.jsx b/src/components/bulk-email-tool/bulk-email-form/bulk-email-recipient/BulkEmailRecipient.jsx
index 4844599..98ca9b6 100644
--- a/src/components/bulk-email-tool/bulk-email-form/bulk-email-recipient/BulkEmailRecipient.jsx
+++ b/src/components/bulk-email-tool/bulk-email-form/bulk-email-recipient/BulkEmailRecipient.jsx
@@ -1,19 +1,12 @@
import React from 'react';
import PropTypes from 'prop-types';
import { Form } from '@openedx/paragon';
-import { FormattedMessage } from '@edx/frontend-platform/i18n';
-import { RECIPIENTS_DISPLAY_NAMES } from '../../utils';
+import { FormattedMessage, useIntl } from '@edx/frontend-platform/i18n';
+import { getDisplayTextFromRecipient } from '../../utils';
+import { DEFAULT_RECIPIENTS_GROUPS } from '../../constants';
import './bulkEmailRecepient.scss';
-const DEFAULT_GROUPS = {
- SELF: 'myself',
- STAFF: 'staff',
- ALL_LEARNERS: 'learners',
- VERIFIED: 'track:verified',
- AUDIT: 'track:audit',
-};
-
export default function BulkEmailRecipient(props) {
const {
handleCheckboxes,
@@ -21,6 +14,7 @@ export default function BulkEmailRecipient(props) {
additionalCohorts,
courseModes,
} = props;
+ const intl = useIntl();
const hasCourseModes = courseModes && courseModes.length > 1;
return (
@@ -40,22 +34,14 @@ export default function BulkEmailRecipient(props) {
value={selectedGroups}
>
-
+ {getDisplayTextFromRecipient(intl, DEFAULT_RECIPIENTS_GROUPS.SELF)}
-
+ {getDisplayTextFromRecipient(intl, DEFAULT_RECIPIENTS_GROUPS.STAFF)}
{
// additional modes
@@ -64,7 +50,7 @@ export default function BulkEmailRecipient(props) {
group === DEFAULT_GROUPS.ALL_LEARNERS)}
+ disabled={selectedGroups.find((group) => group === DEFAULT_RECIPIENTS_GROUPS.ALL_LEARNERS)}
className="col col-lg-4 col-sm-6 col-12"
>
group === DEFAULT_GROUPS.ALL_LEARNERS)}
+ disabled={selectedGroups.find((group) => group === DEFAULT_RECIPIENTS_GROUPS.ALL_LEARNERS)}
className="col col-lg-4 col-sm-6 col-12"
>
-
+ {getDisplayTextFromRecipient(intl, DEFAULT_RECIPIENTS_GROUPS.ALL_LEARNERS)}
{!props.isValid && (
diff --git a/src/components/bulk-email-tool/bulk-email-form/test/BulkEmailForm.test.jsx b/src/components/bulk-email-tool/bulk-email-form/test/BulkEmailForm.test.jsx
index 92d9de9..a2b8254 100644
--- a/src/components/bulk-email-tool/bulk-email-form/test/BulkEmailForm.test.jsx
+++ b/src/components/bulk-email-tool/bulk-email-form/test/BulkEmailForm.test.jsx
@@ -13,7 +13,6 @@ import { BulkEmailContext, BulkEmailProvider } from '../../bulk-email-context';
import { formatDate } from '../../../../utils/formatDateAndTime';
import cohortFactory from '../data/__factories__/bulkEmailFormCohort.factory';
import courseModeFactory from '../data/__factories__/bulkEmailFormCourseMode.factory';
-import { RECIPIENTS_DISPLAY_NAMES } from '../../utils';
jest.mock('../../text-editor/TextEditor');
@@ -76,8 +75,8 @@ describe('bulk-email-form', () => {
success: true,
});
render(renderBulkEmailForm());
- fireEvent.click(screen.getByRole('checkbox', { name: RECIPIENTS_DISPLAY_NAMES.myself }));
- expect(screen.getByRole('checkbox', { name: RECIPIENTS_DISPLAY_NAMES.myself })).toBeChecked();
+ fireEvent.click(screen.getByRole('checkbox', { name: 'Myself' }));
+ expect(screen.getByRole('checkbox', { name: 'Myself' })).toBeChecked();
fireEvent.change(screen.getByRole('textbox', { name: 'Subject' }), { target: { value: 'test subject' } });
fireEvent.change(screen.getByTestId('textEditor'), { target: { value: 'test body' } });
fireEvent.click(screen.getByText('Send email'));
@@ -91,7 +90,7 @@ describe('bulk-email-form', () => {
axiosMock.onPost(`${getConfig().LMS_BASE_URL}/courses/test/instructor/api/send_email`).reply(500);
render(renderBulkEmailForm());
const subjectLine = screen.getByRole('textbox', { name: 'Subject' });
- const recipient = screen.getByRole('checkbox', { name: RECIPIENTS_DISPLAY_NAMES.myself });
+ const recipient = screen.getByRole('checkbox', { name: 'Myself' });
fireEvent.click(recipient);
fireEvent.change(subjectLine, { target: { value: 'test subject' } });
fireEvent.change(screen.getByTestId('textEditor'), { target: { value: 'test body' } });
@@ -100,9 +99,9 @@ describe('bulk-email-form', () => {
fireEvent.click(await screen.findByRole('button', { name: /continue/i }));
expect(await screen.findByText('An error occured while attempting to send the email.')).toBeInTheDocument();
});
- test('Checking "All Students" disables each learner group', async () => {
+ test('Checking "All learners" disables each learner group', async () => {
render(renderBulkEmailForm());
- fireEvent.click(screen.getByRole('checkbox', { name: RECIPIENTS_DISPLAY_NAMES.learners }));
+ fireEvent.click(screen.getByRole('checkbox', { name: 'All learners' }));
const verifiedLearners = screen.getByRole('checkbox', { name: 'Learners in the Verified Certificate Track' });
const auditLearners = screen.getByRole('checkbox', { name: 'Learners in the Audit Track' });
const { cohorts } = cohortFactory.build();
@@ -131,7 +130,7 @@ describe('bulk-email-form', () => {
test('Adds scheduling data to POST requests when schedule is selected', async () => {
const postBulkEmailInstructorTask = jest.spyOn(bulkEmailFormApi, 'postBulkEmailInstructorTask');
render(renderBulkEmailForm());
- fireEvent.click(screen.getByRole('checkbox', { name: RECIPIENTS_DISPLAY_NAMES.myself }));
+ fireEvent.click(screen.getByRole('checkbox', { name: 'Myself' }));
fireEvent.change(screen.getByRole('textbox', { name: 'Subject' }), { target: { value: 'test subject' } });
fireEvent.change(screen.getByTestId('textEditor'), { target: { value: 'test body' } });
const scheduleCheckbox = screen.getByText('Schedule this email for a future date');
diff --git a/src/components/bulk-email-tool/bulk-email-task-manager/bulk-email-scheduled-emails-table/BulkEmailScheduledEmailsTable.jsx b/src/components/bulk-email-tool/bulk-email-task-manager/bulk-email-scheduled-emails-table/BulkEmailScheduledEmailsTable.jsx
index 6d7698c..a18fbef 100644
--- a/src/components/bulk-email-tool/bulk-email-task-manager/bulk-email-scheduled-emails-table/BulkEmailScheduledEmailsTable.jsx
+++ b/src/components/bulk-email-tool/bulk-email-task-manager/bulk-email-scheduled-emails-table/BulkEmailScheduledEmailsTable.jsx
@@ -19,9 +19,9 @@ import ViewEmailModal from '../ViewEmailModal';
import { copyToEditor } from '../../bulk-email-form/data/actions';
import TaskAlertModal from '../../task-alert-modal';
import { formatDate, formatTime } from '../../../../utils/formatDateAndTime';
-import { getDisplayTextFromRecipient, getRecipientFromDisplayText } from '../../utils';
+import { getDisplayTextFromRecipient } from '../../utils';
-function flattenScheduledEmailsArray(emails) {
+function flattenScheduledEmailsArray(intl, emails) {
return emails.map((email) => ({
schedulingId: email.id,
emailId: email.courseEmail.id,
@@ -29,11 +29,12 @@ function flattenScheduledEmailsArray(emails) {
taskDue: new Date(email.taskDue).toLocaleString(),
taskDueUTC: email.taskDue,
...email.courseEmail,
- targets: email.courseEmail.targets.map(getDisplayTextFromRecipient).join(', '),
+ targets: email.courseEmail.targets.join(', '),
+ targetsText: email.courseEmail.targets.map((mess) => getDisplayTextFromRecipient(intl, mess)).join(', '),
}));
}
-function BulkEmailScheduledEmailsTable({ intl, courseModes }) {
+function BulkEmailScheduledEmailsTable({ intl }) {
const { courseId } = useParams();
const [{ scheduledEmailsTable }, dispatch] = useContext(BulkEmailContext);
const [tableData, setTableData] = useState([]);
@@ -45,8 +46,8 @@ function BulkEmailScheduledEmailsTable({ intl, courseModes }) {
const [currentTask, setCurrentTask] = useState({});
useEffect(() => {
- setTableData(flattenScheduledEmailsArray(scheduledEmailsTable.results, courseModes));
- }, [scheduledEmailsTable.results, courseModes]);
+ setTableData(flattenScheduledEmailsArray(intl, scheduledEmailsTable.results));
+ }, [intl, scheduledEmailsTable.results]);
const fetchTableData = useCallback((args) => {
dispatch(getScheduledBulkEmailThunk(courseId, args.pageIndex + 1));
@@ -97,7 +98,7 @@ function BulkEmailScheduledEmailsTable({ intl, courseModes }) {
},
} = row;
const dateTime = new Date(taskDueUTC);
- const emailRecipients = targets.replaceAll('-', ':').split(', ').map(getRecipientFromDisplayText);
+ const emailRecipients = targets.replaceAll('-', ':').split(', ');
const scheduleDate = formatDate(dateTime);
const scheduleTime = formatTime(dateTime);
dispatch(
@@ -155,7 +156,7 @@ function BulkEmailScheduledEmailsTable({ intl, courseModes }) {
},
{
Header: intl.formatMessage(messages.bulkEmailScheduledEmailsTableSendTo),
- accessor: 'targets',
+ accessor: 'targetsText',
},
{
Header: intl.formatMessage(messages.bulkEmailScheduledEmailsTableSubject),
diff --git a/src/components/bulk-email-tool/bulk-email-task-manager/bulk-email-scheduled-emails-table/test/BulkEmailScheduledEmailsTable.test.jsx b/src/components/bulk-email-tool/bulk-email-task-manager/bulk-email-scheduled-emails-table/test/BulkEmailScheduledEmailsTable.test.jsx
index f461b2d..e540f72 100644
--- a/src/components/bulk-email-tool/bulk-email-task-manager/bulk-email-scheduled-emails-table/test/BulkEmailScheduledEmailsTable.test.jsx
+++ b/src/components/bulk-email-tool/bulk-email-task-manager/bulk-email-scheduled-emails-table/test/BulkEmailScheduledEmailsTable.test.jsx
@@ -13,7 +13,6 @@ import { BulkEmailProvider } from '../../../bulk-email-context';
import BulkEmailScheduledEmailsTable from '..';
import scheduledEmailsFactory from './__factories__/scheduledEmails.factory';
import * as actions from '../../../bulk-email-form/data/actions';
-import { RECIPIENTS_DISPLAY_NAMES } from '../../../utils';
jest.mock('react-router-dom', () => ({
...jest.requireActual('react-router-dom'),
@@ -43,7 +42,7 @@ describe('BulkEmailScheduledEmailsTable', () => {
.onGet(`${getConfig().LMS_BASE_URL}/api/instructor_task/v1/schedules/test-id/bulk_email/?page=1`)
.reply(200, scheduledEmailsFactory.build(1));
render(renderBulkEmailScheduledEmailsTable());
- expect(await screen.findByText(RECIPIENTS_DISPLAY_NAMES.learners)).toBeTruthy();
+ expect(await screen.findByText('All learners')).toBeTruthy();
expect(await screen.findByText('subject')).toBeTruthy();
expect(await screen.findByText('edx')).toBeTruthy();
expect(await screen.findByLabelText('View')).toBeTruthy();
diff --git a/src/components/bulk-email-tool/constants.js b/src/components/bulk-email-tool/constants.js
new file mode 100644
index 0000000..9cd9e4f
--- /dev/null
+++ b/src/components/bulk-email-tool/constants.js
@@ -0,0 +1,8 @@
+// eslint-disable-next-line import/prefer-default-export
+export const DEFAULT_RECIPIENTS_GROUPS = {
+ SELF: 'myself',
+ STAFF: 'staff',
+ ALL_LEARNERS: 'learners',
+ VERIFIED: 'track:verified',
+ AUDIT: 'track:audit',
+};
diff --git a/src/components/bulk-email-tool/messages.js b/src/components/bulk-email-tool/messages.js
new file mode 100644
index 0000000..f11a684
--- /dev/null
+++ b/src/components/bulk-email-tool/messages.js
@@ -0,0 +1,21 @@
+import { defineMessages } from '@edx/frontend-platform/i18n';
+
+const messages = defineMessages({
+ bulkEmailRecipientsMyselfLabel: {
+ id: 'bulk.email.recipients.myself.label',
+ defaultMessage: 'Myself',
+ description: 'Label for selecting the option to send a bulk email to oneself.',
+ },
+ bulkEmailRecipientsStaffLabel: {
+ id: 'bulk.email.recipients.staff.label',
+ defaultMessage: 'Staff and instructors',
+ description: 'Label for selecting the option to send a bulk email to all staff and instructors.',
+ },
+ bulkEmailRecipientsLearnersLabel: {
+ id: 'bulk.email.recipients.learners.label',
+ defaultMessage: 'All learners',
+ description: 'Label for selecting the option to send a bulk email to all learners.',
+ },
+});
+
+export default messages;
diff --git a/src/components/bulk-email-tool/utils.js b/src/components/bulk-email-tool/utils.js
index 2a37c88..50262db 100644
--- a/src/components/bulk-email-tool/utils.js
+++ b/src/components/bulk-email-tool/utils.js
@@ -1,14 +1,21 @@
-export const RECIPIENTS_DISPLAY_NAMES = {
- myself: 'Myself',
- staff: 'Staff and instructors',
- learners: 'All students',
+import { DEFAULT_RECIPIENTS_GROUPS } from './constants';
+import messages from './messages';
+
+const RECIPIENTS_DISPLAY_NAMES = {
+ [DEFAULT_RECIPIENTS_GROUPS.SELF]: messages.bulkEmailRecipientsMyselfLabel,
+ [DEFAULT_RECIPIENTS_GROUPS.STAFF]: messages.bulkEmailRecipientsStaffLabel,
+ [DEFAULT_RECIPIENTS_GROUPS.ALL_LEARNERS]: messages.bulkEmailRecipientsLearnersLabel,
};
-// Output: { 'Myself': 'myself', 'Staff and instructors': 'staff', 'All students': 'learners' }
-export const REVERSE_RECIPIENTS_DISPLAY_NAMES = Object.fromEntries(
- Object.entries(RECIPIENTS_DISPLAY_NAMES).map(([key, value]) => [value, key]),
+/**
+ * Retrieves the display text for a given recipient.
+ *
+ * @param {Object} intl - The internationalization object, provided by React Intl.
+ * @param {string} recipient - The recipient key used to look up the corresponding display name.
+ * @returns {string} - The formatted display name for the recipient,
+ * or the original recipient key if no display name is found.
+ */
+// eslint-disable-next-line import/prefer-default-export
+export const getDisplayTextFromRecipient = (intl, recipient) => (
+ intl.formatMessage(RECIPIENTS_DISPLAY_NAMES[recipient]) || recipient
);
-
-export const getDisplayTextFromRecipient = (recipient) => RECIPIENTS_DISPLAY_NAMES[recipient] || recipient;
-
-export const getRecipientFromDisplayText = (recipient) => REVERSE_RECIPIENTS_DISPLAY_NAMES[recipient] || recipient;