Compare commits

...

7 Commits

Author SHA1 Message Date
ayesha waris
6acce16bff Merge branch 'master' into eemaanamir/INF-1062 2024-02-06 19:18:47 +05:00
eemaanamir
09c02cb367 perf: updated onChannelToggle to improve performance 2024-01-24 16:35:19 +05:00
eemaanamir
36f7c939e5 refactor: further simplified onChannelToggle 2024-01-24 15:53:09 +05:00
eemaanamir
aeb8109d94 refactor: onChannelToggle updated 2024-01-24 13:26:30 +05:00
eemaanamir
a6699f94c9 refactor: onChannelToggle updated for readability 2024-01-23 19:47:59 +05:00
eemaanamir
a3497adb6d chore: refactoring the code for readability according to ESLint 2024-01-23 15:07:40 +05:00
eemaanamir
d3e8b36e69 feat: make notification channel headings clickable in notification preferences 2024-01-22 15:01:11 +05:00
5 changed files with 69 additions and 4 deletions

View File

@@ -2,18 +2,21 @@ 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 '@openedx/paragon';
import { Collapsible, NavItem } from '@edx/paragon';
import classNames from 'classnames';
import messages from './messages';
import ToggleSwitch from './ToggleSwitch';
import {
selectPreferenceAppToggleValue,
selectNonEditablePreferences,
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 +25,18 @@ const NotificationPreferenceApp = ({ appId }) => {
const appPreferences = useSelector(selectPreferencesOfApp(appId));
const appToggle = useSelector(selectPreferenceAppToggleValue(appId));
const updatePreferencesStatus = useSelector(selectUpdatePreferencesStatus());
const nonEditable = useSelector(selectNonEditablePreferences(appId));
const onChannelToggle = useCallback((event) => {
const { id: notificationChannel } = event.target;
const isPreferenceNonEditable = (preference) => nonEditable?.[preference.id]?.includes(notificationChannel);
const hasActivePreferences = appPreferences.some(
(preference) => preference[notificationChannel] && !isPreferenceNonEditable(preference),
);
dispatch(updateChannelPreferenceToggle(courseId, appId, notificationChannel, !hasActivePreferences));
}, [appId, appPreferences, courseId, dispatch, nonEditable]);
const preferences = useMemo(() => (
appPreferences.map(preference => (
@@ -36,10 +51,10 @@ const NotificationPreferenceApp = ({ appId }) => {
dispatch(updateAppPreferenceToggle(courseId, appId, event.target.checked));
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [appId]);
if (!courseId) {
return null;
}
return (
<Collapsible.Advanced open={appToggle} data-testid="notification-app" className="mb-5">
<Collapsible.Trigger>
@@ -62,7 +77,22 @@ const NotificationPreferenceApp = ({ appId }) => {
<div className="d-flex flex-row header-label">
<span className="col-8 px-0">{intl.formatMessage(messages.typeLabel)}</span>
<span className="d-flex col-4 px-0">
<span className="ml-auto">{intl.formatMessage(messages.webLabel)}</span>
{NOTIFICATION_CHANNELS.map((channel) => (
<NavItem
id={channel}
key={channel}
className={classNames(
'd-flex',
{ 'ml-auto': channel === 'web' },
{ 'mx-auto': channel === 'email' },
{ 'ml-auto mr-0': channel === 'push' },
)}
role="button"
onClick={onChannelToggle}
>
{intl.formatMessage(messages.notificationChannel, { text: channel })}
</NavItem>
))}
</span>
</div>
<div className="my-3">

View File

@@ -54,6 +54,10 @@ export const selectPreferenceNonEditableChannels = (appId, name) => state => (
state?.notificationPreferences.preferences.nonEditable[appId]?.[name] || []
);
export const selectNonEditablePreferences = appId => state => (
state?.notificationPreferences.preferences.nonEditable[appId] || []
);
export const selectSelectedCourseId = () => state => (
state.notificationPreferences.preferences.selectedCourse
);

View File

@@ -42,3 +42,10 @@ 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;
};

View File

@@ -14,6 +14,7 @@ import {
getCourseList,
getCourseNotificationPreferences,
patchAppPreferenceToggle,
patchChannelPreferenceToggle,
patchPreferenceToggle,
} from './service';
@@ -148,3 +149,15 @@ 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());
}
}
);

View File

@@ -28,6 +28,17 @@ const messages = defineMessages({
}`,
description: 'Display text for Notification Types',
},
notificationChannel: {
id: 'notification.preference.channel',
defaultMessage: `{
text, select,
web {Web}
email {Email}
push {Push}
other {{text}}
}`,
description: 'Display text for Notification Channel',
},
typeLabel: {
id: 'notification.preference.type.label',
defaultMessage: 'Type',