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 29de06d7..ea473f78 100644 --- a/src/components/bulk-email-tool/bulk-email-form/BulkEmailForm.jsx +++ b/src/components/bulk-email-tool/bulk-email-form/BulkEmailForm.jsx @@ -28,6 +28,7 @@ import { } from './data/actions'; import { editScheduledEmailThunk, postBulkEmailThunk } from './data/thunks'; import { getScheduledBulkEmailThunk } from '../bulk-email-task-manager/bulk-email-scheduled-emails-table/data/thunks'; +import { getDisplayTextFromRecipient } from '../utils'; import './bulkEmailForm.scss'; @@ -219,7 +220,7 @@ function BulkEmailForm(props) {

{intl.formatMessage(messages.bulkEmailTaskAlertRecipients, { subject: editor.emailSubject })}

{!isScheduled && ( @@ -246,7 +247,7 @@ function BulkEmailForm(props) {

{intl.formatMessage(messages.bulkEmailTaskAlertEditingTo)}

{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 d60b316b..98ca9b67 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,18 +1,12 @@ import React from 'react'; import PropTypes from 'prop-types'; import { Form } from '@openedx/paragon'; -import { FormattedMessage } from '@edx/frontend-platform/i18n'; +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, @@ -20,6 +14,7 @@ export default function BulkEmailRecipient(props) { additionalCohorts, courseModes, } = props; + const intl = useIntl(); const hasCourseModes = courseModes && courseModes.length > 1; return ( @@ -39,22 +34,14 @@ export default function BulkEmailRecipient(props) { value={selectedGroups} > - + {getDisplayTextFromRecipient(intl, DEFAULT_RECIPIENTS_GROUPS.SELF)} - + {getDisplayTextFromRecipient(intl, DEFAULT_RECIPIENTS_GROUPS.STAFF)} { // additional modes @@ -63,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 2d0dd1c3..a2b8254a 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 @@ -99,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 Learners" disables each learner group', async () => { + test('Checking "All learners" disables each learner group', async () => { render(renderBulkEmailForm()); - fireEvent.click(screen.getByRole('checkbox', { name: 'All 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(); diff --git a/src/components/bulk-email-tool/bulk-email-task-manager/ViewEmailModal.jsx b/src/components/bulk-email-tool/bulk-email-task-manager/ViewEmailModal.jsx index 03b9f547..03d39a0c 100644 --- a/src/components/bulk-email-tool/bulk-email-task-manager/ViewEmailModal.jsx +++ b/src/components/bulk-email-tool/bulk-email-task-manager/ViewEmailModal.jsx @@ -33,7 +33,7 @@ function ViewEmailModal({

{messageContent.created}

-

{intl.formatMessage(messages.modalMessageSentTo)}

+

{intl.formatMessage(messages.modalMessageSentTo)}

{messageContent.sent_to}


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 0e5a5487..a18fbefb 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,8 +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 } from '../../utils'; -function flattenScheduledEmailsArray(emails) { +function flattenScheduledEmailsArray(intl, emails) { return emails.map((email) => ({ schedulingId: email.id, emailId: email.courseEmail.id, @@ -29,6 +30,7 @@ function flattenScheduledEmailsArray(emails) { taskDueUTC: email.taskDue, ...email.courseEmail, targets: email.courseEmail.targets.join(', '), + targetsText: email.courseEmail.targets.map((mess) => getDisplayTextFromRecipient(intl, mess)).join(', '), })); } @@ -44,8 +46,8 @@ function BulkEmailScheduledEmailsTable({ intl }) { const [currentTask, setCurrentTask] = useState({}); useEffect(() => { - setTableData(flattenScheduledEmailsArray(scheduledEmailsTable.results)); - }, [scheduledEmailsTable.results]); + setTableData(flattenScheduledEmailsArray(intl, scheduledEmailsTable.results)); + }, [intl, scheduledEmailsTable.results]); const fetchTableData = useCallback((args) => { dispatch(getScheduledBulkEmailThunk(courseId, args.pageIndex + 1)); @@ -154,7 +156,7 @@ function BulkEmailScheduledEmailsTable({ intl }) { }, { 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 3495bef2..e540f727 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 @@ -42,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('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 00000000..9cd9e4f5 --- /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 00000000..f11a684c --- /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 new file mode 100644 index 00000000..674fabaa --- /dev/null +++ b/src/components/bulk-email-tool/utils.js @@ -0,0 +1,22 @@ +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, +}; + +/** + * 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) => ( + const msg = RECIPIENTS_DISPLAY_NAMES[recipient]; + return msg ? intl.formatMessage(msg) : recipient; // Fall back to the recipient key if no display name is found. +);