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()); + } + } +);