Compare commits
2 Commits
open-relea
...
open-relea
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
41bd035132 | ||
|
|
eae2037d20 |
@@ -33,7 +33,11 @@ export default function BulkEmailTool() {
|
||||
</h1>
|
||||
</div>
|
||||
<div className="row">
|
||||
<BulkEmailForm courseId={courseId} cohorts={courseMetadata.cohorts} />
|
||||
<BulkEmailForm
|
||||
courseId={courseId}
|
||||
cohorts={courseMetadata.cohorts}
|
||||
courseModes={courseMetadata.courseModes}
|
||||
/>
|
||||
</div>
|
||||
<div className="row py-5">
|
||||
<BulkEmailTaskManager courseId={courseId} />
|
||||
|
||||
@@ -47,7 +47,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({
|
||||
@@ -272,10 +277,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)}
|
||||
@@ -384,6 +393,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);
|
||||
|
||||
@@ -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>
|
||||
@@ -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
|
||||
@@ -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"
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
@@ -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',
|
||||
|
||||
@@ -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');
|
||||
|
||||
@@ -20,12 +21,17 @@ 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>
|
||||
);
|
||||
}
|
||||
@@ -33,7 +39,7 @@ function renderBulkEmailForm() {
|
||||
function renderBulkEmailFormContext(value) {
|
||||
return (
|
||||
<BulkEmailContext.Provider value={[value, dispatchMock]}>
|
||||
<BulkEmailForm courseId="test" />
|
||||
<BulkEmailForm courseId="test" courseMode={courseMode} />
|
||||
</BulkEmailContext.Provider>
|
||||
);
|
||||
}
|
||||
@@ -96,8 +102,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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -48,6 +48,7 @@ export default function PageContainer(props) {
|
||||
number,
|
||||
title,
|
||||
originalUserIsStaff,
|
||||
courseModes,
|
||||
tabs: [...tabs],
|
||||
cohorts: cohorts.map(({ name }) => name),
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user