Skip to content

Commit

Permalink
fix: solve conflicts
Browse files Browse the repository at this point in the history
  • Loading branch information
johnvente committed Mar 7, 2024
2 parents fc0b1bf + 6dd835d commit f2716f0
Show file tree
Hide file tree
Showing 13 changed files with 123 additions and 53 deletions.
2 changes: 1 addition & 1 deletion catalog-info.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,6 @@ metadata:
annotations:
openedx.org/arch-interest-groups: ""
spec:
owner: group:frontend-all
owner: group:committers-frontend
type: "service"
lifecycle: "production"
6 changes: 5 additions & 1 deletion src/components/bulk-email-tool/BulkEmailTool.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,11 @@ export default function BulkEmailTool() {
</h1>
</div>
<div className="row">
<BuildEmailFormExtensible courseId={courseId} cohorts={courseMetadata.cohorts} />
<BuildEmailFormExtensible
courseId={courseId}
cohorts={courseMetadata.cohorts}
courseModes={courseMetadata.courseModes}
/>
</div>
<div className="row py-5">
<PluggableComponent
Expand Down
19 changes: 17 additions & 2 deletions src/components/bulk-email-tool/bulk-email-form/BulkEmailForm.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,12 @@ const FORM_ACTIONS = {
};

function BulkEmailForm(props) {
const { courseId, cohorts, intl } = props;
const {
courseId,
cohorts,
courseModes,
intl,
} = props;
const [{ editor }, dispatch] = useContext(BulkEmailContext);
const [emailFormStatus, setEmailFormStatus] = useState(FORM_SUBMIT_STATES.DEFAULT);
const [emailFormValidation, setEmailFormValidation] = useState({
Expand Down Expand Up @@ -312,10 +317,14 @@ function BulkEmailForm(props) {
handleCheckboxes={onRecipientChange}
additionalCohorts={cohorts}
isValid={emailFormValidation.recipients}
courseModes={courseModes}
/>
<Form.Group controlId="emailSubject">
<Form.Label className="h3 text-primary-500">{intl.formatMessage(messages.bulkEmailSubjectLabel)}</Form.Label>
<Form.Control name="emailSubject" className="w-lg-50" onChange={onFormChange} value={editor.emailSubject} />
<Form.Control name="emailSubject" className="w-lg-50" onChange={onFormChange} value={editor.emailSubject} maxLength={128} />
<Form.Control.Feedback className="px-3" type="default">
{intl.formatMessage(messages.bulkEmailFormSubjectTip)}
</Form.Control.Feedback>
{!emailFormValidation.subject && (
<Form.Control.Feedback className="px-3" hasIcon type="invalid">
{intl.formatMessage(messages.bulkEmailFormSubjectError)}
Expand Down Expand Up @@ -424,6 +433,12 @@ BulkEmailForm.propTypes = {
courseId: PropTypes.string.isRequired,
cohorts: PropTypes.arrayOf(PropTypes.string),
intl: intlShape.isRequired,
courseModes: PropTypes.arrayOf(
PropTypes.shape({
slug: PropTypes.string.isRequired,
name: PropTypes.string.isRequired,
}),
).isRequired,
};

export default injectIntl(BulkEmailForm);
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,13 @@ const DEFAULT_GROUPS = {
};

export default function BulkEmailRecipient(props) {
const { handleCheckboxes, selectedGroups, additionalCohorts } = props;
const {
handleCheckboxes,
selectedGroups,
additionalCohorts,
courseModes,
} = props;
const hasCourseModes = courseModes && courseModes.length > 1;
return (
<Form.Group>
<Form.Label>
Expand Down Expand Up @@ -50,18 +56,24 @@ export default function BulkEmailRecipient(props) {
description="A selectable choice from a list of potential email recipients"
/>
</Form.Checkbox>
<Form.Checkbox
key="track:verified"
value="track:verified"
disabled={selectedGroups.find((group) => group === DEFAULT_GROUPS.ALL_LEARNERS)}
className="col col-lg-4 col-sm-6 col-12"
>
<FormattedMessage
id="bulk.email.form.recipients.verified"
defaultMessage="Learners in the verified certificate track"
description="A selectable choice from a list of potential email recipients"
/>
</Form.Checkbox>
{
// additional modes
hasCourseModes
&& courseModes.map((courseMode) => (
<Form.Checkbox
key={`track:${courseMode.slug}`}
value={`track:${courseMode.slug}`}
disabled={selectedGroups.find((group) => group === DEFAULT_GROUPS.ALL_LEARNERS)}
className="col col-lg-4 col-sm-6 col-12"
>
<FormattedMessage
id="bulk.email.form.mode.label"
defaultMessage="Learners in the {courseModeName} Track"
values={{ courseModeName: courseMode.name }}
/>
</Form.Checkbox>
))
}
{
// additional cohorts
additionalCohorts
Expand All @@ -80,18 +92,6 @@ export default function BulkEmailRecipient(props) {
</Form.Checkbox>
))
}
<Form.Checkbox
key="track:audit"
value="track:audit"
disabled={selectedGroups.find((group) => group === DEFAULT_GROUPS.ALL_LEARNERS)}
className="col col-lg-4 col-sm-6 col-12"
>
<FormattedMessage
id="bulk.email.form.recipients.audit"
defaultMessage="Learners in the audit track"
description="A selectable choice from a list of potential email recipients"
/>
</Form.Checkbox>
<Form.Checkbox
key="learners"
value="learners"
Expand Down Expand Up @@ -127,4 +127,10 @@ BulkEmailRecipient.propTypes = {
handleCheckboxes: PropTypes.func.isRequired,
isValid: PropTypes.bool,
additionalCohorts: PropTypes.arrayOf(PropTypes.string),
courseModes: PropTypes.arrayOf(
PropTypes.shape({
slug: PropTypes.string.isRequired,
name: PropTypes.string.isRequired,
}),
).isRequired,
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { Factory } from 'rosie'; // eslint-disable-line import/no-extraneous-dependencies

/**
* Generates an array of course mode objects using Rosie Factory.
* @returns {Array<Object>} An array of course mode objects with attributes 'slug' and 'name'.
*/
const courseModeFactory = () => {
const AuditModeFactory = Factory.define('AuditModeFactory')
.attr('slug', 'audit')
.attr('name', 'Audit');

const VerifiedModeFactory = Factory.define('VerifiedModeFactory')
.attr('slug', 'verified')
.attr('name', 'Verified Certificate');

return [
AuditModeFactory.build(),
VerifiedModeFactory.build(),
];
};

export default courseModeFactory;
5 changes: 5 additions & 0 deletions src/components/bulk-email-tool/bulk-email-form/messages.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,11 @@ const messages = defineMessages({
defaultMessage: 'Subject',
description: 'Email subject line input label. Meant to have colon or equivilant punctuation.',
},
bulkEmailFormSubjectTip: {
id: 'bulk.email.form.subject.tip',
defaultMessage: '(Maximum 128 characters)',
description: 'Default Subject tip',
},
bulkEmailFormSubjectError: {
id: 'bulk.email.form.subject.error',
defaultMessage: 'A subject is required',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import * as bulkEmailFormApi from '../data/api';
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';

jest.mock('../../text-editor/TextEditor');
jest.mock('../../../PluggableComponent', () => () => null);
Expand All @@ -21,20 +22,25 @@ const dispatchMock = jest.fn();

const tomorrow = new Date();
tomorrow.setDate(new Date().getDate() + 1);
const courseMode = courseModeFactory();

function renderBulkEmailForm() {
const { cohorts } = cohortFactory.build();
return (
<BulkEmailProvider>
<BulkEmailForm courseId="test" cohorts={cohorts} />
<BulkEmailForm
courseId="test"
cohorts={cohorts}
courseModes={courseMode}
/>
</BulkEmailProvider>
);
}

function renderBulkEmailFormContext(value) {
return (
<BulkEmailContext.Provider value={[value, dispatchMock]}>
<BulkEmailForm courseId="test" />
<BulkEmailForm courseId="test" courseMode={courseMode} />
</BulkEmailContext.Provider>
);
}
Expand Down Expand Up @@ -97,8 +103,8 @@ describe('bulk-email-form', () => {
test('Checking "All Learners" disables each learner group', async () => {
render(renderBulkEmailForm());
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 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();
cohorts.forEach(cohort => expect(screen.getByRole('checkbox', { name: `Cohort: ${cohort}` })).toBeDisabled());
expect(verifiedLearners).toBeDisabled();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* eslint-disable react/no-unstable-nested-components */

import React, { useState } from 'react';
import React, { useMemo, useState } from 'react';
import PropTypes from 'prop-types';
import { useParams } from 'react-router-dom';
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
Expand Down Expand Up @@ -51,17 +51,15 @@ function BulkEmailContentHistory({ intl }) {
* up a level (the `subject` field). We also convert the `sent_to` data to be a String rather than an array to fix a
* display bug in the table.
*/
function transformDataForTable() {
let tableData = [];
if (emailHistoryData) {
tableData = emailHistoryData.map((item) => ({
...item,
subject: item.email.subject,
sent_to: item.sent_to.join(', '),
}));
}
return tableData;
}
const transformDataForTable = useMemo(() => {
const tableData = emailHistoryData?.map((item) => ({
...item,
subject: item.email.subject,
sent_to: item.sent_to.join(', '),
created: new Date(item.created).toLocaleString(),
}));
return tableData || [];
}, [emailHistoryData]);

/**
* This function is responsible for setting the current `messageContent` state data. This will be the contents of a
Expand Down Expand Up @@ -102,7 +100,7 @@ function BulkEmailContentHistory({ intl }) {
* contents of a previously sent message.
*/
const additionalColumns = () => {
const tableData = transformDataForTable();
const tableData = transformDataForTable;

return [
{
Expand Down Expand Up @@ -139,7 +137,7 @@ function BulkEmailContentHistory({ intl }) {
{showHistoricalEmailContentTable ? (
<BulkEmailTaskManagerTable
errorRetrievingData={errorRetrievingData}
tableData={transformDataForTable()}
tableData={transformDataForTable}
tableDescription={intl.formatMessage(messages.emailHistoryTableViewMessageInstructions)}
alertWarningMessage={intl.formatMessage(messages.noEmailData)}
alertErrorMessage={intl.formatMessage(messages.errorFetchingEmailHistoryData)}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useState } from 'react';
import React, { useMemo, useState } from 'react';
import { useParams } from 'react-router-dom';
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';

Expand Down Expand Up @@ -41,6 +41,14 @@ function BulkEmailTaskHistory({ intl }) {
setShowHistoricalTaskContentTable(true);
}

const transformDataForTable = useMemo(() => {
const tableData = emailTaskHistoryData?.map((item) => ({
...item,
created: new Date(item.created).toLocaleString(),
}));
return tableData || [];
}, [emailTaskHistoryData]);

const tableColumns = [
{
Header: `${intl.formatMessage(messages.taskHistoryTableColumnHeaderTaskType)}`,
Expand Down Expand Up @@ -95,7 +103,7 @@ function BulkEmailTaskHistory({ intl }) {
{showHistoricalTaskContentTable ? (
<BulkEmailTaskManagerTable
errorRetrievingData={errorRetrievingData}
tableData={emailTaskHistoryData}
tableData={transformDataForTable}
alertWarningMessage={intl.formatMessage(messages.noTaskHistoryData)}
alertErrorMessage={intl.formatMessage(messages.errorFetchingTaskHistoryData)}
columns={tableColumns}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,8 @@ describe('BulkEmailContentHistory component', () => {
// verify table contents
const { emails } = emailHistoryData;
const email = emails[0];
expect(await screen.findByText(email.created)).toBeTruthy();
const createdDate = new Date(email.created).toLocaleString();
expect(await screen.findByText(createdDate)).toBeTruthy();
expect(await screen.findByText(email.number_sent)).toBeTruthy();
expect(await screen.findByText(email.requester)).toBeTruthy();
expect(await screen.findByText(email.sent_to.join(', '))).toBeTruthy();
Expand Down Expand Up @@ -103,7 +104,8 @@ describe('BulkEmailContentHistory component', () => {
expect(await screen.findByText('Message:')).toBeTruthy();
expect(await screen.findAllByText(email.email.subject)).toBeTruthy();
expect(await screen.findAllByText(email.requester)).toBeTruthy();
expect(await screen.findAllByText(email.created)).toBeTruthy();
const createdDate = new Date(email.created).toLocaleString();
expect(await screen.findAllByText(createdDate)).toBeTruthy();
expect(await screen.findAllByText(email.sent_to.join(', '))).toBeTruthy();
// .replace() call strips the HTML tags from the string
expect(await screen.findByText(email.email.html_message.replace(/<[^>]*>?/gm, ''))).toBeTruthy();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,8 @@ describe('BulkEmailTaskHistory component', () => {
// verification of row contents
const { tasks } = taskHistoryData;
const task = tasks[0];
expect(await screen.findByText(task.created)).toBeTruthy();
const createdDate = new Date(task.created).toLocaleString();
expect(await screen.findByText(createdDate)).toBeTruthy();
expect(await screen.findByText(task.duration_sec)).toBeTruthy();
expect(await screen.findByText(task.requester)).toBeTruthy();
expect(await screen.findByText(task.status)).toBeTruthy();
Expand Down
3 changes: 2 additions & 1 deletion src/components/page-container/PageContainer.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ export default function PageContainer(props) {
}

const {
org, number, title, tabs, originalUserIsStaff,
org, number, title, tabs, originalUserIsStaff, courseModes,
} = metadataResponse;
const { cohorts } = cohortsResponse;

Expand All @@ -48,6 +48,7 @@ export default function PageContainer(props) {
number,
title,
originalUserIsStaff,
courseModes,
tabs: [...tabs],
cohorts: cohorts.map(({ name }) => name),
});
Expand Down
2 changes: 2 additions & 0 deletions src/setupTest.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ Object.defineProperty(window, 'matchMedia', {
})),
});

global.Date.prototype.toLocaleDateString = jest.fn();

export function initializeMockApp() {
mergeConfig({
// MICROBA-1505: Remove this when we remove the flag from config
Expand Down

0 comments on commit f2716f0

Please sign in to comment.