feat: implement update email setting

This commit is contained in:
Leangseu Kim
2022-10-18 15:23:35 -04:00
committed by leangseu-edx
parent 0f4e2e28dd
commit e4900351f8
8 changed files with 95 additions and 67 deletions

View File

@@ -19,10 +19,10 @@ exports[`EmailSettingsModal render snapshot: emails disabled, show: false 1`] =
Receive course emails?
</h4>
<Form.Switch
checked={true}
checked={false}
onChange={[MockFunction hooks.onToggle]}
>
Course emails are on
Course emails are off
</Form.Switch>
<p>
Course emails include important information about your course from instructors.
@@ -45,50 +45,6 @@ exports[`EmailSettingsModal render snapshot: emails disabled, show: false 1`] =
`;
exports[`EmailSettingsModal render snapshot: emails disabled, show: true 1`] = `
<ModalDialog
hasCloseButton={false}
isOpen={true}
onClose={[MockFunction hooks.nullMethod]}
title=""
>
<div
className="bg-white p-3 rounded shadow"
style={
Object {
"textAlign": "start",
}
}
>
<h4>
Receive course emails?
</h4>
<Form.Switch
checked={true}
onChange={[MockFunction hooks.onToggle]}
>
Course emails are on
</Form.Switch>
<p>
Course emails include important information about your course from instructors.
</p>
<ActionRow>
<Button
onClick={[MockFunction closeModal]}
variant="tertiary"
>
Never mind
</Button>
<Button
onClick={[MockFunction hooks.save]}
>
Save settings
</Button>
</ActionRow>
</div>
</ModalDialog>
`;
exports[`EmailSettingsModal render snapshot: emails enabled, show: true 1`] = `
<ModalDialog
hasCloseButton={false}
isOpen={true}
@@ -131,3 +87,47 @@ exports[`EmailSettingsModal render snapshot: emails enabled, show: true 1`] = `
</div>
</ModalDialog>
`;
exports[`EmailSettingsModal render snapshot: emails enabled, show: true 1`] = `
<ModalDialog
hasCloseButton={false}
isOpen={true}
onClose={[MockFunction hooks.nullMethod]}
title=""
>
<div
className="bg-white p-3 rounded shadow"
style={
Object {
"textAlign": "start",
}
}
>
<h4>
Receive course emails?
</h4>
<Form.Switch
checked={true}
onChange={[MockFunction hooks.onToggle]}
>
Course emails are on
</Form.Switch>
<p>
Course emails include important information about your course from instructors.
</p>
<ActionRow>
<Button
onClick={[MockFunction closeModal]}
variant="tertiary"
>
Never mind
</Button>
<Button
onClick={[MockFunction hooks.save]}
>
Save settings
</Button>
</ActionRow>
</div>
</ModalDialog>
`;

View File

@@ -1,8 +1,7 @@
import React from 'react';
import { StrictDict } from 'utils';
// import { thunkActions } from 'data/redux';
import { hooks as appHooks } from 'data/redux';
import { hooks as appHooks, thunkActions } from 'data/redux';
import * as module from './hooks';
@@ -13,7 +12,7 @@ export const state = StrictDict({
export const useEmailData = ({
closeModal,
cardId,
// dispatch,
dispatch,
}) => {
const { isEmailEnabled } = appHooks.useCardEnrollmentData(cardId);
const [toggleValue, setToggleValue] = module.state.toggle(isEmailEnabled);
@@ -23,9 +22,10 @@ export const useEmailData = ({
);
const save = React.useCallback(
() => {
dispatch(thunkActions.app.updateEmailSettings(cardId, toggleValue));
closeModal();
},
[closeModal],
[cardId, closeModal, dispatch, toggleValue],
);
return {

View File

@@ -1,5 +1,5 @@
import { MockUseState } from 'testUtils';
import { hooks as appHooks } from 'data/redux';
import { hooks as appHooks, thunkActions } from 'data/redux';
import * as hooks from './hooks';
@@ -7,10 +7,16 @@ jest.mock('data/redux', () => ({
hooks: {
useCardEnrollmentData: jest.fn(),
},
thunkActions: {
app: {
updateEmailSettings: jest.fn(),
},
},
}));
const cardId = 'my-test-course-number';
const closeModal = jest.fn();
const dispatch = jest.fn();
const state = new MockUseState(hooks);
@@ -26,7 +32,7 @@ describe('EmailSettingsModal hooks', () => {
beforeEach(() => {
state.mock();
appHooks.useCardEnrollmentData.mockReturnValueOnce({ isEmailEnabled: true });
out = hooks.useEmailData({ closeModal, cardId });
out = hooks.useEmailData({ closeModal, cardId, dispatch });
});
afterEach(state.restore);
@@ -53,8 +59,14 @@ describe('EmailSettingsModal hooks', () => {
});
});
describe('save', () => {
it('returns a callback', () => {
expect(out.save.useCallback.prereqs).toEqual([closeModal]);
it('calls dispatch with thunkActions.app.updateEmailSettings', () => {
out.save.useCallback.cb();
expect(thunkActions.app.updateEmailSettings).toHaveBeenCalledWith(cardId, out.toggleValue);
expect(dispatch).toHaveBeenCalledWith(thunkActions.app.updateEmailSettings(cardId, out.toggleValue));
});
it('calls closeModal', () => {
out.save.useCallback.cb();
expect(closeModal).toHaveBeenCalled();
});
});
});

View File

@@ -37,8 +37,8 @@ export const EmailSettingsModal = ({
>
<div className="bg-white p-3 rounded shadow" style={{ textAlign: 'start' }}>
<h4>{formatMessage(messages.header)}</h4>
<Form.Switch checked={!toggleValue} onChange={onToggle}>
{formatMessage(toggleValue ? messages.emailsOff : messages.emailsOn)}
<Form.Switch checked={toggleValue} onChange={onToggle}>
{formatMessage(!toggleValue ? messages.emailsOff : messages.emailsOn)}
</Form.Switch>
<p>{formatMessage(messages.description)}</p>
<ActionRow>

View File

@@ -89,6 +89,14 @@ export const clearMasquerade = () => (dispatch) => {
dispatch(module.initialize());
};
export const updateEmailSettings = (cardId, enable) => (dispatch, getState) => {
const { courseId } = selectors.app.courseCard.courseRun(getState(), cardId);
dispatch(requests.updateEmailSettings({
courseId,
enable,
}));
};
export default StrictDict({
loadData,
initialize,
@@ -100,4 +108,5 @@ export default StrictDict({
unenrollFromCourse,
masqueradeAs,
clearMasquerade,
updateEmailSettings,
});

View File

@@ -45,6 +45,7 @@ jest.mock('./requests', () => ({
unenrollFromCourse: jest.fn((args) => ({ unenrollFromCourse: args })),
masqueradeAs: jest.fn((args) => ({ masqueradeAs: args })),
clearMasquerade: jest.fn((args) => ({ clearMasquerade: args })),
updateEmailSettings: jest.fn((args) => ({ updateEmailSettings: args })),
}));
const dispatch = jest.fn(action => action);
@@ -204,4 +205,14 @@ describe('app thunk actions', () => {
expect(dispatch).toHaveBeenCalledWith(mockInitialize());
});
});
describe('update email settings', () => {
it('dispatches updateEmailSettings request action', () => {
module.updateEmailSettings(cardId, testString)(dispatch, getState);
expect(selectors.app.courseCard.courseRun).toHaveBeenCalledWith(testState, cardId);
expect(dispatch).toHaveBeenCalledWith(requests.updateEmailSettings({
courseId,
enable: testString,
}));
});
});
});

View File

@@ -29,10 +29,10 @@ const deleteEntitlementEnrollment = ({ uuid }) => client().delete(stringifyUrl(
{ [apiKeys.courseRunId]: null },
));
const updateEmailSettings = ({ courseId, enable }) => post(stringifyUrl(
urls.updateEmailSettings,
const updateEmailSettings = ({ courseId, enable }) => post(
stringifyUrl(urls.updateEmailSettings),
{ [apiKeys.courseId]: courseId, ...(enable && enableEmailsAction) },
));
);
const unenrollFromCourse = ({ courseId }) => post(stringifyUrl(urls.courseUnenroll), {
[apiKeys.courseId]: courseId,

View File

@@ -63,10 +63,8 @@ describe('lms api methods', () => {
expect(
api.updateEmailSettings({ courseId: testCourseId, enable: false }),
).toEqual(
utils.post(utils.stringifyUrl(
urls.updateEmailSettings,
{ [apiKeys.courseId]: testCourseId },
)),
utils.post(utils.stringifyUrl(urls.updateEmailSettings),
{ [apiKeys.courseId]: testCourseId }),
);
});
});
@@ -75,10 +73,8 @@ describe('lms api methods', () => {
expect(
api.updateEmailSettings({ courseId: testCourseId, enable: true }),
).toEqual(
utils.post(utils.stringifyUrl(
urls.updateEmailSettings,
{ [apiKeys.courseId]: testCourseId, ...enableEmailsAction },
)),
utils.post(utils.stringifyUrl(urls.updateEmailSettings),
{ [apiKeys.courseId]: testCourseId, ...enableEmailsAction }),
);
});
});