diff --git a/src/notification-preferences/NotificationPreferenceApp.jsx b/src/notification-preferences/NotificationPreferenceApp.jsx
index 89e2438..f6a84c7 100644
--- a/src/notification-preferences/NotificationPreferenceApp.jsx
+++ b/src/notification-preferences/NotificationPreferenceApp.jsx
@@ -2,18 +2,20 @@ import React, { useCallback, useMemo } from 'react';
import PropTypes from 'prop-types';
import { useDispatch, useSelector } from 'react-redux';
import { useIntl } from '@edx/frontend-platform/i18n';
-import { Collapsible } from '@edx/paragon';
+import { Collapsible, NavItem } from '@edx/paragon';
+import classNames from 'classnames';
import messages from './messages';
import ToggleSwitch from './ToggleSwitch';
import {
- selectPreferenceAppToggleValue,
+ selectPreferenceAppToggleValue, selectPreferenceNonEditable,
selectPreferencesOfApp,
selectSelectedCourseId,
selectUpdatePreferencesStatus,
} from './data/selectors';
import NotificationPreferenceRow from './NotificationPreferenceRow';
-import { updateAppPreferenceToggle } from './data/thunks';
+import { updateAppPreferenceToggle, updateChannelPreferenceToggle } from './data/thunks';
import { LOADING_STATUS } from '../constants';
+import NOTIFICATION_CHANNELS from './data/constants';
const NotificationPreferenceApp = ({ appId }) => {
const dispatch = useDispatch();
@@ -22,6 +24,35 @@ const NotificationPreferenceApp = ({ appId }) => {
const appPreferences = useSelector(selectPreferencesOfApp(appId));
const appToggle = useSelector(selectPreferenceAppToggleValue(appId));
const updatePreferencesStatus = useSelector(selectUpdatePreferencesStatus());
+ const nonEditable = useSelector(selectPreferenceNonEditable(appId));
+
+ const onColumnToggle = useCallback(
+ (event) => {
+ const {
+ id: notificationChannel,
+ } = event.target;
+ const truePreferences = appPreferences.filter((preference) => {
+ const isPreferenceNonEditable = nonEditable?.[preference.id]?.includes(notificationChannel) || false;
+ return preference[notificationChannel] === true && !isPreferenceNonEditable;
+ });
+ if (truePreferences.length > 0) {
+ dispatch(updateChannelPreferenceToggle(
+ courseId,
+ appId,
+ notificationChannel,
+ false,
+ ));
+ } else {
+ dispatch(updateChannelPreferenceToggle(
+ courseId,
+ appId,
+ notificationChannel,
+ true,
+ ));
+ }
+ },
+ [appId, appPreferences, courseId, dispatch, nonEditable],
+ );
const preferences = useMemo(() => (
appPreferences.map(preference => (
@@ -36,7 +67,6 @@ const NotificationPreferenceApp = ({ appId }) => {
dispatch(updateAppPreferenceToggle(courseId, appId, event.target.checked));
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [appId]);
-
if (!courseId) {
return null;
}
@@ -62,7 +92,27 @@ const NotificationPreferenceApp = ({ appId }) => {
{intl.formatMessage(messages.typeLabel)}
- {intl.formatMessage(messages.webLabel)}
+ {NOTIFICATION_CHANNELS.map((channel) => (
+
+ {
+ // eslint-disable-next-line no-nested-ternary
+ channel === 'web' ? intl.formatMessage(messages.webLabel)
+ // eslint-disable-next-line no-nested-ternary
+ : channel === 'email' ? intl.formatMessage(messages.notificationHelpEmail)
+ : channel === 'push' ? intl.formatMessage(messages.notificationHelpPush) : null
+ }
+
+ ))}
diff --git a/src/notification-preferences/data/selectors.js b/src/notification-preferences/data/selectors.js
index d918705..d6f7ee4 100644
--- a/src/notification-preferences/data/selectors.js
+++ b/src/notification-preferences/data/selectors.js
@@ -54,6 +54,10 @@ export const selectPreferenceNonEditableChannels = (appId, name) => state => (
state?.notificationPreferences.preferences.nonEditable[appId]?.[name] || []
);
+export const selectPreferenceNonEditable = (appId) => state => (
+ state?.notificationPreferences.preferences.nonEditable[appId] || []
+);
+
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 c3deb56..6e357b1 100644
--- a/src/notification-preferences/data/service.js
+++ b/src/notification-preferences/data/service.js
@@ -42,3 +42,19 @@ export const patchPreferenceToggle = async (
const { data } = await getAuthenticatedHttpClient().patch(url, patchData);
return data;
};
+
+export const patchChannelPreferenceToggle = async (
+ courseId,
+ notificationApp,
+ notificationChannel,
+ value,
+) => {
+ const patchData = snakeCaseObject({
+ notificationApp,
+ notificationChannel,
+ value,
+ });
+ const url = `${getConfig().LMS_BASE_URL}/api/notifications/channel/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 86ff5c0..7b257c8 100644
--- a/src/notification-preferences/data/thunks.js
+++ b/src/notification-preferences/data/thunks.js
@@ -13,7 +13,7 @@ import {
import {
getCourseList,
getCourseNotificationPreferences,
- patchAppPreferenceToggle,
+ patchAppPreferenceToggle, patchChannelPreferenceToggle,
patchPreferenceToggle,
} from './service';
@@ -148,3 +148,25 @@ export const updatePreferenceToggle = (
}
}
);
+
+export const updateChannelPreferenceToggle = (
+ courseId,
+ notificationApp,
+ notificationChannel,
+ value,
+) => (
+ async (dispatch) => {
+ try {
+ const data = await patchChannelPreferenceToggle(
+ courseId,
+ notificationApp,
+ notificationChannel,
+ value,
+ );
+ const normalizedData = normalizePreferences(camelCaseObject(data));
+ dispatch(fetchNotificationPreferenceSuccess(courseId, normalizedData));
+ } catch (errors) {
+ dispatch(fetchNotificationPreferenceFailed());
+ }
+ }
+);