diff --git a/package-lock.json b/package-lock.json
index ff95d9d..97ef54d 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -39,6 +39,7 @@
"lodash.omit": "4.5.0",
"lodash.pick": "4.4.0",
"lodash.pickby": "4.6.0",
+ "lodash.snakecase": "4.1.1",
"long": "5.2.3",
"memoize-one": "5.2.1",
"prop-types": "15.8.1",
diff --git a/package.json b/package.json
index 89ecb48..fd4daa4 100644
--- a/package.json
+++ b/package.json
@@ -57,6 +57,7 @@
"lodash.omit": "4.5.0",
"lodash.pick": "4.4.0",
"lodash.pickby": "4.6.0",
+ "lodash.snakecase": "4.1.1",
"long": "5.2.3",
"memoize-one": "5.2.1",
"prop-types": "15.8.1",
diff --git a/src/notification-preferences/NotificationCourses.jsx b/src/notification-preferences/NotificationCourses.jsx
index 4697b90..236150b 100644
--- a/src/notification-preferences/NotificationCourses.jsx
+++ b/src/notification-preferences/NotificationCourses.jsx
@@ -5,21 +5,32 @@ import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
import { Container, Icon, Spinner } from '@edx/paragon';
import { ArrowForwardIos } from '@edx/paragon/icons';
import { fetchCourseList } from './data/thunks';
-import { courseListStatus, getCourseList } from './data/selectors';
-import { IDLE_STATUS, LOADING_STATUS } from '../constants';
+import { selectCourseListStatus, selectCourseList } from './data/selectors';
+import {
+ IDLE_STATUS,
+ LOADING_STATUS,
+ SUCCESS_STATUS,
+} from '../constants';
import { messages } from './messages';
+import { NotFoundPage } from '../account-settings';
const NotificationCourses = ({ intl }) => {
const dispatch = useDispatch();
- const courseStatus = useSelector(courseListStatus());
- const coursesList = useSelector(getCourseList());
+ const coursesList = useSelector(selectCourseList());
+ const courseListStatus = useSelector(selectCourseListStatus());
+
useEffect(() => {
- if (courseStatus === IDLE_STATUS || coursesList.length === 0) {
+ if (courseListStatus === IDLE_STATUS) {
dispatch(fetchCourseList());
}
// eslint-disable-next-line react-hooks/exhaustive-deps
- }, [courseStatus]);
- if (courseStatus === LOADING_STATUS) {
+ }, []);
+
+ if (courseListStatus === SUCCESS_STATUS && coursesList.length === 0) {
+ return ;
+ }
+
+ if (courseListStatus === LOADING_STATUS) {
return (
{
{
coursesList.map(course => (
diff --git a/src/notification-preferences/NotificationPreferenceGroup.jsx b/src/notification-preferences/NotificationPreferenceApp.jsx
similarity index 60%
rename from src/notification-preferences/NotificationPreferenceGroup.jsx
rename to src/notification-preferences/NotificationPreferenceApp.jsx
index c7a0929..adc3536 100644
--- a/src/notification-preferences/NotificationPreferenceGroup.jsx
+++ b/src/notification-preferences/NotificationPreferenceApp.jsx
@@ -1,4 +1,4 @@
-import React, { useCallback, useMemo, useState } from 'react';
+import React, { useCallback, useMemo } from 'react';
import PropTypes from 'prop-types';
import { useDispatch, useSelector } from 'react-redux';
import { useIntl } from '@edx/frontend-platform/i18n';
@@ -6,46 +6,50 @@ import { Collapsible } from '@edx/paragon';
import { messages } from './messages';
import ToggleSwitch from './ToggleSwitch';
import {
- getPreferenceGroup,
- getSelectedCourse,
+ selectPreferenceAppToggleValue,
+ selectPreferencesOfApp,
+ selectSelectedCourseId,
} from './data/selectors';
import NotificationPreferenceRow from './NotificationPreferenceRow';
-import { updateGroupValue } from './data/actions';
+import { updateAppPreferenceToggle } from './data/thunks';
-const NotificationPreferenceGroup = ({ groupId }) => {
+const NotificationPreferenceApp = ({ appId }) => {
const dispatch = useDispatch();
const intl = useIntl();
- const courseId = useSelector(getSelectedCourse());
- const preferenceGroup = useSelector(getPreferenceGroup(groupId));
- const [groupToggle, setGroupToggle] = useState(true);
+ const courseId = useSelector(selectSelectedCourseId());
+ const appPreferences = useSelector(selectPreferencesOfApp(appId));
+ const appToggle = useSelector(selectPreferenceAppToggleValue(appId));
const preferences = useMemo(() => (
- preferenceGroup.map(preference => (
+ appPreferences.map(preference => (
- ))), [groupId, preferenceGroup]);
+ ))), [appId, appPreferences]);
- const onChangeGroupSettings = useCallback((checked) => {
- setGroupToggle(checked);
- dispatch(updateGroupValue(courseId, groupId, checked));
+ const onChangeAppSettings = useCallback((event) => {
+ dispatch(updateAppPreferenceToggle(courseId, appId, event.target.checked));
// eslint-disable-next-line react-hooks/exhaustive-deps
- }, [groupId]);
+ }, [appId]);
if (!courseId) {
return null;
}
return (
-
+
- {intl.formatMessage(messages.notificationGroupTitle, { key: groupId })}
+ {intl.formatMessage(messages.notificationAppTitle, { key: appId })}
-
+
@@ -67,8 +71,8 @@ const NotificationPreferenceGroup = ({ groupId }) => {
);
};
-NotificationPreferenceGroup.propTypes = {
- groupId: PropTypes.string.isRequired,
+NotificationPreferenceApp.propTypes = {
+ appId: PropTypes.string.isRequired,
};
-export default React.memo(NotificationPreferenceGroup);
+export default React.memo(NotificationPreferenceApp);
diff --git a/src/notification-preferences/NotificationPreferenceRow.jsx b/src/notification-preferences/NotificationPreferenceRow.jsx
index fd6eda7..a16e586 100644
--- a/src/notification-preferences/NotificationPreferenceRow.jsx
+++ b/src/notification-preferences/NotificationPreferenceRow.jsx
@@ -1,50 +1,91 @@
import React, { useCallback } from 'react';
import PropTypes from 'prop-types';
+import classNames from 'classnames';
import { useDispatch, useSelector } from 'react-redux';
import { useIntl } from '@edx/frontend-platform/i18n';
+import { Icon, OverlayTrigger, Tooltip } from '@edx/paragon';
+import { InfoOutline } from '@edx/paragon/icons';
import { messages } from './messages';
import ToggleSwitch from './ToggleSwitch';
-import { getPreferenceAttribute } from './data/selectors';
-import { updatePreferenceValue } from './data/actions';
+import {
+ selectPreference,
+ selectPreferenceNonEditableChannels,
+ selectSelectedCourseId,
+} from './data/selectors';
+import { updatePreferenceToggle } from './data/thunks';
-const NotificationPreferenceRow = ({ groupId, preferenceName }) => {
+const NotificationPreferenceRow = ({ appId, preferenceName }) => {
const dispatch = useDispatch();
const intl = useIntl();
- const preference = useSelector(getPreferenceAttribute(groupId, preferenceName));
- const onToggle = useCallback((checked, notificationChannel) => {
- dispatch(updatePreferenceValue(groupId, preferenceName, notificationChannel, checked));
- }, [dispatch, groupId, preferenceName]);
+ const courseId = useSelector(selectSelectedCourseId());
+ const preference = useSelector(selectPreference(appId, preferenceName));
+ const nonEditable = useSelector(selectPreferenceNonEditableChannels(appId, preferenceName));
+
+ const onToggle = useCallback((event) => {
+ const {
+ checked,
+ name: notificationChannel,
+ } = event.target;
+ dispatch(updatePreferenceToggle(
+ courseId,
+ appId,
+ preferenceName,
+ notificationChannel,
+ checked,
+ ));
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [appId, preferenceName]);
+
+ const tooltipId = `${preferenceName}-tooltip`;
return (
-
+
{intl.formatMessage(messages.notificationTitle, { text: preferenceName })}
+ {
+ preference.info !== '' && (
+
+ {preference.info}
+
+ )}
+ >
+
+
+
+
+ )
+ }
-
- onToggle(checked, 'web')}
- />
-
-
- onToggle(checked, 'email')}
- />
-
-
- onToggle(checked, 'push')}
- />
-
+ {
+ ['web', 'email', 'push'].map((channel) => (
+
+
+
+ ))
+ }
);
};
NotificationPreferenceRow.propTypes = {
- groupId: PropTypes.string.isRequired,
+ appId: PropTypes.string.isRequired,
preferenceName: PropTypes.string.isRequired,
};
diff --git a/src/notification-preferences/NotificationPreferences.jsx b/src/notification-preferences/NotificationPreferences.jsx
index 6341b66..db5ec35 100644
--- a/src/notification-preferences/NotificationPreferences.jsx
+++ b/src/notification-preferences/NotificationPreferences.jsx
@@ -6,40 +6,44 @@ import { useIntl } from '@edx/frontend-platform/i18n';
import { Container, Icon, Spinner } from '@edx/paragon';
import { ArrowBack } from '@edx/paragon/icons';
import {
- courseListStatus,
- getCourse,
- getPreferenceGroupIds,
- notificationPreferencesStatus,
+ selectCourseListStatus,
+ selectCourse,
+ selectPreferenceAppsId,
+ selectNotificationPreferencesStatus,
+ selectCourseList,
} from './data/selectors';
import { fetchCourseList, fetchCourseNotificationPreferences } from './data/thunks';
import { messages } from './messages';
-import NotificationPreferenceGroup from './NotificationPreferenceGroup';
-import { updateSelectedCourse } from './data/actions';
-import { LOADING_STATUS, SUCCESS_STATUS } from '../constants';
+import NotificationPreferenceApp from './NotificationPreferenceApp';
+import {
+ FAILURE_STATUS,
+ IDLE_STATUS,
+ LOADING_STATUS,
+ SUCCESS_STATUS,
+} from '../constants';
+import { NotFoundPage } from '../account-settings';
const NotificationPreferences = () => {
const { courseId } = useParams();
const dispatch = useDispatch();
const intl = useIntl();
- const courseStatus = useSelector(courseListStatus());
- const notificationStatus = useSelector(notificationPreferencesStatus());
- const course = useSelector(getCourse(courseId));
- const preferenceGroups = useSelector(getPreferenceGroupIds());
+ const courseStatus = useSelector(selectCourseListStatus());
+ const coursesList = useSelector(selectCourseList());
+ const course = useSelector(selectCourse(courseId));
+ const notificationStatus = useSelector(selectNotificationPreferencesStatus());
+ const preferenceAppsIds = useSelector(selectPreferenceAppsId());
const preferencesList = useMemo(() => (
- preferenceGroups.map(key => (
-
+ preferenceAppsIds.map(appId => (
+
))
- ), [preferenceGroups]);
+ ), [preferenceAppsIds]);
useEffect(() => {
- dispatch(updateSelectedCourse(courseId));
- if (courseStatus !== SUCCESS_STATUS) {
+ if ([IDLE_STATUS, FAILURE_STATUS].includes(courseStatus)) {
dispatch(fetchCourseList());
}
- if (notificationStatus !== SUCCESS_STATUS) {
- dispatch(fetchCourseNotificationPreferences(courseId));
- }
+ dispatch(fetchCourseNotificationPreferences(courseId));
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [courseId]);
@@ -55,6 +59,14 @@ const NotificationPreferences = () => {
);
}
+
+ if (
+ (courseStatus === SUCCESS_STATUS && coursesList.length === 0)
+ || (notificationStatus === FAILURE_STATUS && coursesList.length !== 0)
+ ) {
+ return ;
+ }
+
return (
diff --git a/src/notification-preferences/ToggleSwitch.jsx b/src/notification-preferences/ToggleSwitch.jsx
index 373e0ba..913cbfd 100644
--- a/src/notification-preferences/ToggleSwitch.jsx
+++ b/src/notification-preferences/ToggleSwitch.jsx
@@ -2,17 +2,30 @@ import { Form } from '@edx/paragon';
import React from 'react';
import PropTypes from 'prop-types';
-const ToggleSwitch = ({ value, onChange }) => (
-
onChange(event.target.checked)} />
+const ToggleSwitch = ({
+ name,
+ value,
+ disabled,
+ onChange,
+}) => (
+
);
ToggleSwitch.propTypes = {
+ name: PropTypes.string.isRequired,
value: PropTypes.bool.isRequired,
+ disabled: PropTypes.bool,
onChange: PropTypes.func,
};
ToggleSwitch.defaultProps = {
onChange: () => null,
+ disabled: false,
};
export default React.memo(ToggleSwitch);
diff --git a/src/notification-preferences/data/actions.js b/src/notification-preferences/data/actions.js
index 7ccbba8..e59cdc9 100644
--- a/src/notification-preferences/data/actions.js
+++ b/src/notification-preferences/data/actions.js
@@ -7,7 +7,7 @@ export const Actions = {
FAILED_COURSE_LIST: 'failedCourseList',
UPDATE_SELECTED_COURSE: 'updateSelectedCourse',
UPDATE_PREFERENCE: 'updatePreference',
- UPDATE_GROUP_PREFERENCE: 'updateGroupValue',
+ UPDATE_APP_PREFERENCE: 'updateAppValue',
};
export const fetchNotificationPreferenceSuccess = (courseId, payload) => dispatch => (
@@ -38,21 +38,21 @@ export const updateSelectedCourse = courseId => dispatch => (
dispatch({ type: Actions.UPDATE_SELECTED_COURSE, courseId })
);
-export const updatePreferenceValue = (groupName, preferenceName, notificationChannel, value) => dispatch => (
+export const updatePreferenceValue = (appId, preferenceName, notificationChannel, value) => dispatch => (
dispatch({
type: Actions.UPDATE_PREFERENCE,
- groupName,
+ appId,
preferenceName,
notificationChannel,
value,
})
);
-export const updateGroupValue = (courseId, groupName, value) => dispatch => (
+export const updateAppToggle = (courseId, appId, value) => dispatch => (
dispatch({
- type: Actions.UPDATE_GROUP_PREFERENCE,
+ type: Actions.UPDATE_APP_PREFERENCE,
courseId,
- groupName,
+ appId,
value,
})
);
diff --git a/src/notification-preferences/data/reducers.js b/src/notification-preferences/data/reducers.js
index da0ac8b..189b832 100644
--- a/src/notification-preferences/data/reducers.js
+++ b/src/notification-preferences/data/reducers.js
@@ -15,13 +15,14 @@ export const defaultState = {
status: IDLE_STATUS,
selectedCourse: null,
preferences: [],
- groups: [],
+ apps: [],
+ notEditable: {},
},
};
const notificationPreferencesReducer = (state = defaultState, action = {}) => {
const {
- courseId, groupName, notificationChannel, preferenceName, value,
+ courseId, appId, notificationChannel, preferenceName, value,
} = action;
switch (action.type) {
case Actions.FETCHING_COURSE_LIST:
@@ -54,7 +55,9 @@ const notificationPreferencesReducer = (state = defaultState, action = {}) => {
preferences: {
...state.preferences,
status: LOADING_STATUS,
- preferences: {},
+ preferences: [],
+ apps: [],
+ notEditable: {},
},
};
case Actions.FETCHED_PREFERENCES:
@@ -70,8 +73,11 @@ const notificationPreferencesReducer = (state = defaultState, action = {}) => {
return {
...state,
preferences: {
+ ...state.preferences,
status: FAILURE_STATUS,
- preferences: {},
+ preferences: [],
+ apps: [],
+ notEditable: {},
},
};
case Actions.UPDATE_SELECTED_COURSE:
@@ -87,27 +93,22 @@ const notificationPreferencesReducer = (state = defaultState, action = {}) => {
...state,
preferences: {
...state.preferences,
- preferences: state.preferences.preferences.map((element) => (
- element.id === preferenceName
- ? { ...element, [notificationChannel]: value }
- : element
+ preferences: state.preferences.preferences.map((preference) => (
+ preference.id === preferenceName
+ ? { ...preference, [notificationChannel]: value }
+ : preference
)),
},
};
- case Actions.UPDATE_GROUP_PREFERENCE:
+ case Actions.UPDATE_APP_PREFERENCE:
return {
...state,
preferences: {
...state.preferences,
- preferences: state.preferences.preferences.map((element) => (
- element.groupId === groupName
- ? {
- ...element,
- web: value,
- email: value,
- push: value,
- }
- : element
+ apps: state.preferences.apps.map(app => (
+ app.id === appId
+ ? { ...app, enabled: value }
+ : app
)),
},
};
diff --git a/src/notification-preferences/data/selectors.js b/src/notification-preferences/data/selectors.js
index 0f8b270..728f1aa 100644
--- a/src/notification-preferences/data/selectors.js
+++ b/src/notification-preferences/data/selectors.js
@@ -1,41 +1,55 @@
-export const notificationPreferencesStatus = () => state => (
+export const selectNotificationPreferencesStatus = () => state => (
state.notificationPreferences.preferences.status
);
-export const getPreferences = () => state => (
- state.notificationPreferences?.preferences?.preferences
+export const selectPreferences = () => state => (
+ state.notificationPreferences.preferences?.preferences
);
-export const courseListStatus = () => state => (
+export const selectCourseListStatus = () => state => (
state.notificationPreferences.courses.status
);
-export const getCourseList = () => state => (
+export const selectCourseList = () => state => (
state.notificationPreferences.courses.courses
);
-export const getCourse = courseId => state => (
- getCourseList()(state).find(
- element => element.id === courseId,
+export const selectCourse = courseId => state => (
+ selectCourseList()(state).find(
+ course => course.id === courseId,
)
);
-export const getPreferenceGroupIds = () => state => (
- state.notificationPreferences.preferences.groups
+export const selectPreferenceAppsId = () => state => (
+ state.notificationPreferences.preferences.apps.map(app => app.id)
);
-export const getPreferenceGroup = group => state => (
- getPreferences()(state).filter((preference) => (
- preference.groupId === group
+export const selectPreferencesOfApp = appId => state => (
+ selectPreferences()(state).filter(preference => (
+ preference.appId === appId
))
);
-export const getPreferenceAttribute = (group, name) => state => (
- getPreferenceGroup(group)(state).find((preference) => (
- preference.id === name
+export const selectPreferenceApp = appId => state => (
+ state.notificationPreferences.preferences.apps.find(app => (
+ app.id === appId
))
);
-export const getSelectedCourse = () => state => (
+export const selectPreferenceAppToggleValue = appId => state => (
+ selectPreferenceApp(appId)(state).enabled
+);
+
+export const selectPreference = (appId, name) => state => (
+ selectPreferences()(state).find((preference) => (
+ preference.id === name && preference.appId === appId
+ ))
+);
+
+export const selectPreferenceNonEditableChannels = (appId, name) => state => (
+ state?.notificationPreferences.preferences.notEditable[appId]?.[name] || []
+);
+
+export const selectSelectedCourseId = () => state => (
state.notificationPreferences.preferences.selectedCourse
);
diff --git a/src/notification-preferences/data/service.js b/src/notification-preferences/data/service.js
index e53ba9f..4b6e939 100644
--- a/src/notification-preferences/data/service.js
+++ b/src/notification-preferences/data/service.js
@@ -1,46 +1,43 @@
-/* eslint-disable no-unused-vars */
+import { getConfig, snakeCaseObject } from '@edx/frontend-platform';
+import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';
+import snakeCase from 'lodash.snakecase';
-// import { getConfig } from '@edx/frontend-platform';
-// import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';
-
-export async function getCourseNotificationPreferences(courseId) {
- // const url = `${getConfig().LMS_BASE_URL}/api/notifications/${courseId}`;
- // const { data } = await getAuthenticatedHttpClient().get(url);
- const data = {
- discussion: {
- new_post: {
- web: true,
- push: false,
- email: false,
- },
- new_comment: {
- web: true,
- push: false,
- email: false,
- },
- },
- coursework: {
- new_assignment: {
- web: true,
- push: false,
- email: false,
- },
- new_grade: {
- web: true,
- push: false,
- email: false,
- },
- },
- };
+export const getCourseNotificationPreferences = async (courseId) => {
+ const url = `${getConfig().LMS_BASE_URL}/api/notifications/configurations/${courseId}`;
+ const { data } = await getAuthenticatedHttpClient().get(url);
return data;
-}
+};
-export async function getCourseList() {
- // const url = `${getConfig().LMS_BASE_URL}/api/notifications/${courseId}`;
- // const { data } = await getAuthenticatedHttpClient().get(url);
- return [
- { id: 'course-v1:edX+Supply+Demo_Course', name: 'Supply Chain Analytics' },
- { id: 'course-v1:edX+Happiness+At+Work_Course', name: 'The Foundation of Happiness At Work' },
- { id: 'course-v1:edX+Empathy+At+Work_Course', name: 'Empathy and Emotional Intelligence At Work' },
- ];
-}
+export const getCourseList = async () => {
+ const url = `${getConfig().LMS_BASE_URL}/api/notifications/enrollments/`;
+ const { data } = await getAuthenticatedHttpClient().get(url);
+ return data;
+};
+
+export const patchAppPreferenceToggle = async (courseId, appId, value) => {
+ const patchData = snakeCaseObject({
+ notificationApp: appId,
+ value,
+ });
+ const url = `${getConfig().LMS_BASE_URL}/api/notifications/configurations/${courseId}`;
+ const { data } = await getAuthenticatedHttpClient().patch(url, patchData);
+ return data;
+};
+
+export const patchPreferenceToggle = async (
+ courseId,
+ notificationApp,
+ notificationType,
+ notificationChannel,
+ value,
+) => {
+ const patchData = snakeCaseObject({
+ notificationApp,
+ notificationType: snakeCase(notificationType),
+ notificationChannel,
+ value,
+ });
+ const url = `${getConfig().LMS_BASE_URL}/api/notifications/configurations/${courseId}`;
+ const { data } = await getAuthenticatedHttpClient().patch(url, patchData);
+ return data;
+};
diff --git a/src/notification-preferences/data/thunks.js b/src/notification-preferences/data/thunks.js
index 8640981..e980283 100644
--- a/src/notification-preferences/data/thunks.js
+++ b/src/notification-preferences/data/thunks.js
@@ -6,30 +6,56 @@ import {
fetchNotificationPreferenceFailed,
fetchNotificationPreferenceFetching,
fetchNotificationPreferenceSuccess,
+ updateAppToggle,
+ updatePreferenceValue,
+ updateSelectedCourse,
} from './actions';
import {
getCourseList,
getCourseNotificationPreferences,
+ patchAppPreferenceToggle,
+ patchPreferenceToggle,
} from './service';
-const normalizePreferences = (preferences) => {
- const groups = Object.keys(preferences);
- const preferenceList = groups.map(groupId => {
- const preferencesKeys = Object.keys(preferences[groupId]);
+const normalizeCourses = (responseData) => (
+ responseData.map((enrollment) => ({
+ id: enrollment.course.id,
+ name: enrollment.course.displayName,
+ }))
+);
+
+const normalizePreferences = (responseData) => {
+ const preferences = responseData.notificationPreferenceConfig;
+
+ const appKeys = Object.keys(preferences);
+ const apps = appKeys.map((appId) => ({
+ id: appId,
+ enabled: preferences[appId].enabled,
+ }));
+
+ const notEditable = {};
+ const preferenceList = appKeys.map(appId => {
+ const preferencesKeys = Object.keys(preferences[appId].notificationTypes);
const flatPreferences = preferencesKeys.map(preferenceId => (
{
id: preferenceId,
- groupId,
- web: preferences?.[groupId]?.[preferenceId].web,
- push: preferences?.[groupId]?.[preferenceId].push,
- mobile: preferences?.[groupId]?.[preferenceId].mobile,
+ appId,
+ web: preferences[appId].notificationTypes[preferenceId].web,
+ push: preferences[appId].notificationTypes[preferenceId].push,
+ email: preferences[appId].notificationTypes[preferenceId].email,
+ info: preferences[appId].notificationTypes[preferenceId].info || '',
}
));
+
+ notEditable[appId] = preferences[appId].notEditable;
+
return flatPreferences;
}).flat();
+
const normalizedPreferences = {
- groups,
+ apps,
preferences: preferenceList,
+ notEditable,
};
return normalizedPreferences;
};
@@ -39,7 +65,8 @@ export const fetchCourseList = () => (
try {
dispatch(fetchCourseListFetching());
const data = await getCourseList();
- dispatch(fetchCourseListSuccess(data));
+ const normalizedData = normalizeCourses(camelCaseObject(data));
+ dispatch(fetchCourseListSuccess(normalizedData));
} catch (errors) {
dispatch(fetchCourseListFailed());
}
@@ -49,6 +76,7 @@ export const fetchCourseList = () => (
export const fetchCourseNotificationPreferences = (courseId) => (
async (dispatch) => {
try {
+ dispatch(updateSelectedCourse(courseId));
dispatch(fetchNotificationPreferenceFetching());
const data = await getCourseNotificationPreferences(courseId);
const normalizedData = normalizePreferences(camelCaseObject(data));
@@ -58,3 +86,53 @@ export const fetchCourseNotificationPreferences = (courseId) => (
}
}
);
+
+export const updateAppPreferenceToggle = (courseId, appId, value) => (
+ async (dispatch) => {
+ try {
+ dispatch(updateAppToggle(courseId, appId, value));
+ const data = await patchAppPreferenceToggle(courseId, appId, value);
+ const normalizedData = normalizePreferences(camelCaseObject(data));
+ dispatch(fetchNotificationPreferenceSuccess(courseId, normalizedData));
+ } catch (errors) {
+ dispatch(updateAppToggle(courseId, appId, !value));
+ dispatch(fetchNotificationPreferenceFailed());
+ }
+ }
+);
+
+export const updatePreferenceToggle = (
+ courseId,
+ notificationApp,
+ notificationType,
+ notificationChannel,
+ value,
+) => (
+ async (dispatch) => {
+ try {
+ dispatch(updatePreferenceValue(
+ notificationApp,
+ notificationType,
+ notificationChannel,
+ value,
+ ));
+ const data = await patchPreferenceToggle(
+ courseId,
+ notificationApp,
+ notificationType,
+ notificationChannel,
+ value,
+ );
+ const normalizedData = normalizePreferences(camelCaseObject(data));
+ dispatch(fetchNotificationPreferenceSuccess(courseId, normalizedData));
+ } catch (errors) {
+ dispatch(updatePreferenceValue(
+ notificationApp,
+ notificationType,
+ notificationChannel,
+ !value,
+ ));
+ dispatch(fetchNotificationPreferenceFailed());
+ }
+ }
+);
diff --git a/src/notification-preferences/messages.js b/src/notification-preferences/messages.js
index d0dbf4e..fdd8346 100644
--- a/src/notification-preferences/messages.js
+++ b/src/notification-preferences/messages.js
@@ -7,8 +7,8 @@ export const messages = defineMessages({
defaultMessage: 'Notifications',
description: 'Notification title',
},
- notificationGroupTitle: {
- id: 'notification.preference.group.title',
+ notificationAppTitle: {
+ id: 'notification.preference.app.title',
defaultMessage: `{
key, select,
discussion {Discussions}
@@ -21,8 +21,12 @@ export const messages = defineMessages({
id: 'notification.preference.title',
defaultMessage: `{
text, select,
+ core {Core}
newPost {New Post}
newComment {New Comment}
+ newCommentOnPost {New Comment On Post}
+ newResponseOnPost {New Response On Post}
+ newResponseOnComment {New Response On Comment}
newAssignment {New Assignment}
newGrade {New Grade}
other {{text}}