feat: implemented notifications configurations V3 API (#1401)

* feat: implemented notifications configurations V3 API

* fix: removed default daily email cadence when email toggle is turned on
This commit is contained in:
Awais Ansari
2026-01-15 18:56:02 +05:00
committed by GitHub
parent c70eca1fde
commit 4f51f71acc
10 changed files with 18 additions and 37 deletions

View File

@@ -71,5 +71,5 @@ export function useFeedbackWrapper() {
export function useIsOnMobile() {
const windowSize = useWindowSize();
return windowSize.width <= breakpoints.small.minWidth;
return windowSize.width <= breakpoints.small.maxWidth;
}

View File

@@ -18,9 +18,7 @@ import {
selectUpdatePreferencesStatus,
} from './data/selectors';
import { notificationChannels, shouldHideAppPreferences } from './data/utils';
import {
EMAIL, EMAIL_CADENCE, EMAIL_CADENCE_PREFERENCES, MIXED,
} from './data/constants';
import { EMAIL, EMAIL_CADENCE } from './data/constants';
const NotificationPreferenceColumn = ({ appId, channel, appPreference }) => {
const dispatch = useDispatch();
@@ -39,13 +37,11 @@ const NotificationPreferenceColumn = ({ appId, channel, appPreference }) => {
return checked;
}, []);
const getEmailCadence = useCallback((notificationChannel, checked, innerText, emailCadence) => {
const getEmailCadence = useCallback((notificationChannel, innerText, emailCadence) => {
if (notificationChannel === EMAIL_CADENCE) {
return innerText;
}
if (notificationChannel === EMAIL && checked) {
return EMAIL_CADENCE_PREFERENCES.DAILY;
}
return emailCadence;
}, []);
@@ -56,7 +52,6 @@ const NotificationPreferenceColumn = ({ appId, channel, appPreference }) => {
const value = getValue(notificationChannel, innerText, checked);
const emailCadence = getEmailCadence(
notificationChannel,
checked,
innerText,
appNotificationPreference.emailCadence,
);
@@ -66,12 +61,11 @@ const NotificationPreferenceColumn = ({ appId, channel, appPreference }) => {
notificationType,
notificationChannel,
value,
emailCadence !== MIXED ? emailCadence : undefined,
emailCadence,
));
}, [appPreferences, getValue, getEmailCadence, dispatch, appId]);
const renderPreference = (preference) => (
(preference?.coreNotificationTypes?.length > 0 || preference.id !== 'core') && (
<div
key={`${preference.id}-${channel}`}
id={`${preference.id}-${channel}`}
@@ -100,7 +94,6 @@ const NotificationPreferenceColumn = ({ appId, channel, appPreference }) => {
/>
)}
</div>
)
);
return (

View File

@@ -249,7 +249,7 @@ describe('Notification Preferences API v2 Logic', () => {
describe('getNotificationPreferences', () => {
it('should call the v2 configurations URL', async () => {
const expectedUrl = `${LMS_BASE_URL}/api/notifications/v2/configurations/`;
const expectedUrl = `${LMS_BASE_URL}/api/notifications/v3/configurations/`;
await getNotificationPreferences();
@@ -260,7 +260,7 @@ describe('Notification Preferences API v2 Logic', () => {
describe('postPreferenceToggle', () => {
it('should call the v2 configurations URL with PUT method', async () => {
const expectedUrl = `${LMS_BASE_URL}/api/notifications/v2/configurations/`;
const expectedUrl = `${LMS_BASE_URL}/api/notifications/v3/configurations/`;
const testArgs = ['app_name', 'notification_type', 'web', true, 'daily'];
await postPreferenceToggle(...testArgs);

View File

@@ -23,7 +23,6 @@ const NotificationTypes = ({ appId }) => {
return (
<div className="d-flex flex-column mr-auto px-0">
{preferences.map(preference => (
(preference?.coreNotificationTypes?.length > 0 || preference.id !== 'core') && (
<>
<div
key={preference.id}
@@ -56,8 +55,6 @@ const NotificationTypes = ({ appId }) => {
</div>
)}
</>
)
))}
</div>
);

View File

@@ -5,7 +5,6 @@ export const EMAIL_CADENCE_PREFERENCES = {
};
export const EMAIL_CADENCE = 'email_cadence';
export const EMAIL = 'email';
export const MIXED = 'Mixed';
export const RequestStatus = /** @type {const} */ ({
IN_PROGRESS: 'in-progress',
SUCCESSFUL: 'successful',

View File

@@ -3,7 +3,7 @@ import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';
import snakeCase from 'lodash.snakecase';
export const getNotificationPreferences = async () => {
const url = `${getConfig().LMS_BASE_URL}/api/notifications/v2/configurations/`;
const url = `${getConfig().LMS_BASE_URL}/api/notifications/v3/configurations/`;
const { data } = await getAuthenticatedHttpClient().get(url);
return data;
};
@@ -16,13 +16,13 @@ export const postPreferenceToggle = async (
emailCadence,
) => {
const patchData = snakeCaseObject({
notificationApp,
notificationApp: snakeCase(notificationApp),
notificationType: snakeCase(notificationType),
notificationChannel,
value,
emailCadence,
});
const url = `${getConfig().LMS_BASE_URL}/api/notifications/v2/configurations/`;
const url = `${getConfig().LMS_BASE_URL}/api/notifications/v3/configurations/`;
const { data } = await getAuthenticatedHttpClient().put(url, patchData);
return data;
};

View File

@@ -38,7 +38,7 @@ describe('Notification Preferences Service', () => {
const result = await getNotificationPreferences();
expect(mockHttpClient.get).toHaveBeenCalledWith(
'http://test.lms/api/notifications/v2/configurations/',
'http://test.lms/api/notifications/v3/configurations/',
);
expect(result).toEqual(mockData);
});
@@ -50,7 +50,7 @@ describe('Notification Preferences Service', () => {
mockHttpClient.put.mockResolvedValue({ data: mockData });
const result = await postPreferenceToggle(
'appName',
'app_name',
'someType',
'email',
true,
@@ -58,9 +58,9 @@ describe('Notification Preferences Service', () => {
);
expect(mockHttpClient.put).toHaveBeenCalledWith(
'http://test.lms/api/notifications/v2/configurations/',
'http://test.lms/api/notifications/v3/configurations/',
expect.objectContaining({
notification_app: 'appName',
notification_app: 'app_name',
notification_type: 'some_type',
notification_channel: 'email',
value: true,

View File

@@ -35,7 +35,7 @@ const normalizePreferences = (responseData) => {
const apps = appKeys.map((appId) => ({
id: appId,
enabled: preferences[appId].enabled,
}));
})).sort((a, b) => a.id.localeCompare(b.id));
const nonEditable = {};
const preferenceList = appKeys.map(appId => {
@@ -50,7 +50,6 @@ const normalizePreferences = (responseData) => {
info: preferences[appId].notificationTypes[preferenceId].info || '',
emailCadence: preferences[appId].notificationTypes[preferenceId].emailCadence
|| EMAIL_CADENCE_PREFERENCES.DAILY,
coreNotificationTypes: preferences[appId].coreNotificationTypes || [],
}
));
nonEditable[appId] = preferences[appId].nonEditable;
@@ -122,7 +121,7 @@ export const updatePreferenceToggle = (
const emailCadenceData = await togglePreference(
EMAIL_CADENCE,
value,
EMAIL_CADENCE_PREFERENCES.DAILY,
emailCadence,
);
handleSuccessResponse(emailCadenceData);

View File

@@ -10,12 +10,5 @@ export const notificationChannels = () => ({
export const shouldHideAppPreferences = (preferences, appId) => {
const appPreferences = preferences.filter(pref => pref.appId === appId);
if (appPreferences.length !== 1) {
return false;
}
const firstPreference = appPreferences[0];
return firstPreference?.id === 'core' && (!firstPreference.coreNotificationTypes?.length);
return appPreferences.length === 0;
};

View File

@@ -22,7 +22,7 @@ const messages = defineMessages({
id: 'notification.preference.title',
defaultMessage: `{
text, select,
core {Activity notifications}
groupedNotification {Activity notifications}
newDiscussionPost {New discussion posts}
newQuestionPost {New question posts}
contentReported {Reported content}