mirror of
https://github.com/mattermost/mattermost.git
synced 2025-02-25 18:55:24 -06:00
[MM-60218] Resettting to default doesnt reset to user's global notification setting in a channel's setting (#28046)
This commit is contained in:
parent
bb4d7de2b5
commit
4c6ac0a432
@ -142,82 +142,97 @@ describe('CRT Desktop notifications', () => {
|
||||
|
||||
it('MM-T4417_2 Click on sameMobileSettingsDesktop and check if additional settings still appears', () => {
|
||||
cy.visit(testChannelUrl);
|
||||
|
||||
// # Open channel's notification preferences
|
||||
cy.uiOpenChannelMenu('Notification Preferences');
|
||||
|
||||
cy.get('#desktopNotification-mention').scrollIntoView().should('be.visible').click().then(() => {
|
||||
cy.get('[data-testid="desktopReplyThreads"]').scrollIntoView().should('be.visible').click();
|
||||
});
|
||||
cy.get('.channel-notifications-settings-modal__body').scrollTo('center').get('[data-testid="desktopReplyThreads"]').should('be.visible').click();
|
||||
cy.get('.channel-notifications-settings-modal__body').get('[data-testid="sameMobileSettingsDesktop"]').scrollIntoView().click().should('be.checked').then(() => {
|
||||
cy.findByText('Notify me about…').should('not.be.visible');
|
||||
// * As per previous conditions the mobile and desktop settings should be the same
|
||||
cy.get('[data-testid="sameMobileSettingsDesktop"]').scrollIntoView().should('be.checked');
|
||||
|
||||
// * Verify that Notify me about section of mobile settings is not visible
|
||||
cy.get('[data-testid="mobile-notify-me-radio-section"]').should('not.exist');
|
||||
|
||||
// # Now uncheck the sameMobileSettingsDesktop so that mobile and desktop settings are different
|
||||
cy.get('[data-testid="sameMobileSettingsDesktop"]').scrollIntoView().should('be.visible').click();
|
||||
|
||||
// * Verify that Notify me about section of mobile settings is visible
|
||||
cy.get('[data-testid="mobile-notify-me-radio-section"]').should('be.visible').scrollIntoView().within(() => {
|
||||
cy.findByText('Notify me about…').should('be.visible');
|
||||
|
||||
// # Click on mentions option
|
||||
cy.get('[data-testid="MobileNotification-mention"]').should('be.visible').click();
|
||||
});
|
||||
|
||||
// check the box to see if the additional settings appears
|
||||
cy.get('.channel-notifications-settings-modal__body').get('[data-testid="sameMobileSettingsDesktop"]').scrollIntoView().click();
|
||||
cy.get('.mm-modal-generic-section-item__title').should('be.visible').and('contain', 'Notify me about');
|
||||
|
||||
cy.get('#MobileNotification-all').should('be.visible').click();
|
||||
cy.get('#MobileNotification-mention').should('be.visible').click().then(() => {
|
||||
cy.get('[data-testid="mobileReplyThreads"]').should('be.visible').click();
|
||||
// * Verify that Thread reply notifications section of mobile settings is visible
|
||||
cy.get('[data-testid="mobile-reply-threads-checkbox-section"]').should('be.visible').scrollIntoView().within(() => {
|
||||
cy.findByText('Notify me about replies to threads I’m following').should('be.visible');
|
||||
});
|
||||
cy.get('#MobileNotification-none').should('be.visible').click();
|
||||
|
||||
cy.get('[data-testid="autoFollowThreads"]').should('be.visible').click();
|
||||
|
||||
// # Save the changes
|
||||
cy.findByText('Save').should('be.visible').click();
|
||||
// # Close the modal
|
||||
cy.get('body').type('{esc}');
|
||||
});
|
||||
|
||||
it('MM-T4417_3 Trigger notifications only on mention replies when channel setting is unchecked', () => {
|
||||
// # Visit the test channel
|
||||
cy.visit(testChannelUrl);
|
||||
|
||||
// Setup notification spy
|
||||
spyNotificationAs('notifySpy', 'granted');
|
||||
// # Setup notification spy
|
||||
spyNotificationAs('notifySpy1', 'granted');
|
||||
|
||||
// # Open channel's notification preferences for test channel
|
||||
cy.uiOpenChannelMenu('Notification Preferences');
|
||||
|
||||
// # Select "Mentions, direct messages, and keywords only" as notify me about option
|
||||
cy.get('#desktopNotification-mention').scrollIntoView().should('be.visible').click();
|
||||
|
||||
// # Unselect "Notify me about replies to threads I’m following"
|
||||
cy.get('[data-testid="desktopReplyThreads"]').scrollIntoView().should('be.visible').then(($el) => {
|
||||
if ($el.is(':checked')) {
|
||||
cy.wrap($el).click();
|
||||
}
|
||||
});
|
||||
|
||||
// # Select notification checkbox active
|
||||
cy.get('[data-testid="desktopNotificationSoundsCheckbox"]').scrollIntoView().should('be.visible').then(($el) => {
|
||||
if (!$el.is(':checked')) {
|
||||
cy.wrap($el).click();
|
||||
}
|
||||
});
|
||||
|
||||
// # Select a notification sound from dropdown
|
||||
cy.get('#desktopNotificationSoundsSelect').scrollIntoView().should('be.visible').click();
|
||||
cy.findByText('Crackle').should('be.visible').click();
|
||||
|
||||
// # Save the changes
|
||||
cy.findByText('Save').should('be.visible').click();
|
||||
|
||||
// # Post a root message as other user
|
||||
cy.postMessageAs({sender, message: 'This is a not followed root message', channelId: testChannelId, rootId: ''}).then(({id: postId}) => {
|
||||
// # Switch to town-square so that unread notifications in test channel may be triggered
|
||||
cy.uiClickSidebarItem('town-square');
|
||||
// # Go to the town-square channel
|
||||
cy.visit(`/${testTeam.name}/channels/town-square`);
|
||||
|
||||
// # Post a message in unfollowed thread as another user
|
||||
cy.postMessageAs({sender, message: 'This is a reply to the unfollowed thread', channelId: testChannelId, rootId: postId});
|
||||
|
||||
// * Verify stub was not called for unfollowed thread
|
||||
cy.get('@notifySpy').should('not.be.called');
|
||||
// # Post a root message as other user in the test channel
|
||||
cy.postMessageAs({sender, message: 'This is the root message which will not have a at-mention in thread', channelId: testChannelId, rootId: ''}).then(({id: postId}) => {
|
||||
// # Post a message in the thread without at-mention
|
||||
cy.postMessageAs({sender, message: 'Reply without at-mention', channelId: testChannelId, rootId: postId}).then(() => {
|
||||
// * Verify Notification stub was not called for threads which does not have at-mention as per channel settings
|
||||
cy.get('@notifySpy1').should('not.be.called');
|
||||
});
|
||||
|
||||
// # Visit channel
|
||||
cy.visit(testChannelUrl);
|
||||
// # Cleanup
|
||||
cy.apiDeletePost(postId);
|
||||
});
|
||||
|
||||
// Setup notification spy
|
||||
spyNotificationAs('notifySpy', 'granted');
|
||||
// Setup another notification spy
|
||||
spyNotificationAs('notifySpy2', 'granted');
|
||||
|
||||
// # Post a message
|
||||
cy.postMessage('Hi there, this is a root message');
|
||||
|
||||
// # Get post id of message
|
||||
cy.getLastPostId().then((postId) => {
|
||||
// # Switch to town-square so that unread notifications in test channel may be triggered
|
||||
cy.uiClickSidebarItem('town-square');
|
||||
|
||||
// # Post a message in original thread as another user
|
||||
cy.postMessageAs({sender, message: 'This is a reply to the root post', channelId: testChannelId, rootId: postId});
|
||||
|
||||
// * Verify stub was not called
|
||||
cy.get('@notifySpy').should('not.be.called');
|
||||
|
||||
// # Post a mention message in original thread as another user
|
||||
const message = `@${receiver.username} this is a mention to receiver`;
|
||||
// # Post another message in the test channel
|
||||
cy.postMessageAs({sender, message: 'This is another root message which will have a at-mention in thread', channelId: testChannelId, rootId: ''}).then(({id: postId}) => {
|
||||
const message = `Reply with at-mention @${receiver.username}`;
|
||||
|
||||
// # Post a message in the thread with at-mention
|
||||
cy.postMessageAs({sender, message, channelId: testChannelId, rootId: postId});
|
||||
|
||||
// * Verify stub was called with correct title and body
|
||||
cy.get('@notifySpy').should('have.been.calledWithMatch', `Reply in ${testChannelName}`, (args) => {
|
||||
// * Verify Notification stub was called with correct title and body with at-mention as per channel settings
|
||||
cy.get('@notifySpy2').should('have.been.calledWithMatch', `Reply in ${testChannelName}`, (args) => {
|
||||
expect(args.body, `Notification body: "${args.body}" should match: "${message}"`).to.equal(`@${sender.username}: ${message}`);
|
||||
return true;
|
||||
});
|
||||
|
@ -18,11 +18,11 @@ import {getChannelURL, getPermalinkURL} from 'selectors/urls';
|
||||
import {isThreadOpen} from 'selectors/views/threads';
|
||||
|
||||
import {getHistory} from 'utils/browser_history';
|
||||
import Constants, {NotificationLevels, UserStatuses, IgnoreChannelMentions} from 'utils/constants';
|
||||
import Constants, {NotificationLevels, UserStatuses, IgnoreChannelMentions, DesktopSound} from 'utils/constants';
|
||||
import DesktopApp from 'utils/desktop_api';
|
||||
import {stripMarkdown, formatWithRenderer} from 'utils/markdown';
|
||||
import MentionableRenderer from 'utils/markdown/mentionable_renderer';
|
||||
import * as NotificationSounds from 'utils/notification_sounds';
|
||||
import {DesktopNotificationSounds, ding} from 'utils/notification_sounds';
|
||||
import {showNotification} from 'utils/notifications';
|
||||
import {cjkrPattern, escapeRegex} from 'utils/text_formatting';
|
||||
import {isDesktopApp, isMobileApp} from 'utils/user_agent';
|
||||
@ -30,21 +30,52 @@ import * as Utils from 'utils/utils';
|
||||
|
||||
import {runDesktopNotificationHooks} from './hooks';
|
||||
|
||||
const getSoundFromChannelMemberAndUser = (member, user) => {
|
||||
if (member?.notify_props?.desktop_sound) {
|
||||
return member.notify_props.desktop_sound === 'on';
|
||||
/**
|
||||
* This function is used to determine if the desktop sound is enabled.
|
||||
* It checks if desktop sound is defined in the channel member and if not, it checks if it's defined in the user preferences.
|
||||
*/
|
||||
export function isDesktopSoundEnabled(channelMember, user) {
|
||||
const soundInChannelMemberNotifyProps = channelMember?.notify_props?.desktop_sound;
|
||||
const soundInUserNotifyProps = user?.notify_props?.desktop_sound;
|
||||
|
||||
if (soundInChannelMemberNotifyProps === DesktopSound.ON) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return !user.notify_props || user.notify_props.desktop_sound === 'true';
|
||||
};
|
||||
|
||||
const getNotificationSoundFromChannelMemberAndUser = (member, user) => {
|
||||
if (member?.notify_props?.desktop_notification_sound) {
|
||||
return member.notify_props.desktop_notification_sound;
|
||||
if (soundInChannelMemberNotifyProps === DesktopSound.OFF) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return user.notify_props?.desktop_notification_sound ? user.notify_props.desktop_notification_sound : 'Bing';
|
||||
};
|
||||
if (soundInChannelMemberNotifyProps === DesktopSound.DEFAULT) {
|
||||
return soundInUserNotifyProps ? soundInUserNotifyProps === 'true' : true;
|
||||
}
|
||||
|
||||
if (soundInUserNotifyProps) {
|
||||
return soundInUserNotifyProps === 'true';
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function returns the desktop notification sound from the channel member and user.
|
||||
* It checks if desktop notification sound is defined in the channel member and if not, it checks if it's defined in the user preferences.
|
||||
* If neither is defined, it returns the default sound 'BING'.
|
||||
*/
|
||||
export function getDesktopNotificationSound(channelMember, user) {
|
||||
const notificationSoundInChannelMember = channelMember?.notify_props?.desktop_notification_sound;
|
||||
const notificationSoundInUser = user?.notify_props?.desktop_notification_sound;
|
||||
|
||||
if (notificationSoundInChannelMember && notificationSoundInChannelMember !== DesktopNotificationSounds.DEFAULT) {
|
||||
return notificationSoundInChannelMember;
|
||||
}
|
||||
|
||||
if (notificationSoundInUser && notificationSoundInUser !== DesktopNotificationSounds.DEFAULT) {
|
||||
return notificationSoundInUser;
|
||||
}
|
||||
|
||||
return DesktopNotificationSounds.BING;
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {import('mattermost-redux/types/actions').ThunkActionFunc<Promise<import('utils/notifications').NotificationResult>, GlobalState>}
|
||||
@ -259,7 +290,7 @@ export function sendDesktopNotification(post, msgProps) {
|
||||
}
|
||||
|
||||
//Play a sound if explicitly set in settings
|
||||
const sound = getSoundFromChannelMemberAndUser(member, user);
|
||||
const desktopSoundEnabled = isDesktopSoundEnabled(member, user);
|
||||
|
||||
// Notify if you're not looking in the right channel or when
|
||||
// the window itself is not active
|
||||
@ -285,7 +316,7 @@ export function sendDesktopNotification(post, msgProps) {
|
||||
notify = true;
|
||||
}
|
||||
|
||||
let soundName = getNotificationSoundFromChannelMemberAndUser(member, user);
|
||||
let soundName = getDesktopNotificationSound(member, user);
|
||||
|
||||
const updatedState = getState();
|
||||
let url = getChannelURL(updatedState, channel, teamId);
|
||||
@ -295,7 +326,7 @@ export function sendDesktopNotification(post, msgProps) {
|
||||
}
|
||||
|
||||
// Allow plugins to change the notification, or re-enable a notification
|
||||
const args = {title, body, silent: !sound, soundName, url, notify};
|
||||
const args = {title, body, silent: !desktopSoundEnabled, soundName, url, notify};
|
||||
const hookResult = await dispatch(runDesktopNotificationHooks(post, msgProps, channel, teamId, args));
|
||||
if (hookResult.error) {
|
||||
dispatch(logError(hookResult.error));
|
||||
@ -309,8 +340,8 @@ export function sendDesktopNotification(post, msgProps) {
|
||||
const result = dispatch(notifyMe(title, body, channel, teamId, silent, soundName, url));
|
||||
|
||||
//Don't add extra sounds on native desktop clients
|
||||
if (sound && !isDesktopApp() && !isMobileApp()) {
|
||||
NotificationSounds.ding(soundName);
|
||||
if (desktopSoundEnabled && !isDesktopApp() && !isMobileApp()) {
|
||||
ding(soundName);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
@ -7,7 +7,7 @@ import Constants, {NotificationLevels, UserStatuses} from 'utils/constants';
|
||||
import * as NotificationSounds from 'utils/notification_sounds';
|
||||
import * as utils from 'utils/notifications';
|
||||
|
||||
import {sendDesktopNotification} from './notification_actions';
|
||||
import {sendDesktopNotification, isDesktopSoundEnabled, getDesktopNotificationSound} from './notification_actions';
|
||||
|
||||
describe('notification_actions', () => {
|
||||
describe('sendDesktopNotification', () => {
|
||||
@ -195,7 +195,7 @@ describe('notification_actions', () => {
|
||||
expect(spy).toHaveBeenCalledWith({
|
||||
body: '@username: Where is Jessica Hyde?',
|
||||
requireInteraction: false,
|
||||
silent: true,
|
||||
silent: false,
|
||||
title: 'Utopia',
|
||||
onClick: expect.any(Function),
|
||||
});
|
||||
@ -415,7 +415,7 @@ describe('notification_actions', () => {
|
||||
expect(spy).toHaveBeenCalledWith({
|
||||
body: '@username: Where is Jessica Hyde?',
|
||||
requireInteraction: false,
|
||||
silent: true,
|
||||
silent: false,
|
||||
title: 'Reply in Utopia',
|
||||
onClick: expect.any(Function),
|
||||
});
|
||||
@ -509,3 +509,163 @@ describe('notification_actions', () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('isDesktopSoundEnabled', () => {
|
||||
test('should return channel member sound if it exists', () => {
|
||||
const channelMember1 = {
|
||||
notify_props: {
|
||||
desktop_sound: 'on',
|
||||
},
|
||||
};
|
||||
const user1 = {
|
||||
notify_props: {
|
||||
desktop_sound: 'false',
|
||||
},
|
||||
};
|
||||
expect(isDesktopSoundEnabled(channelMember1, user1)).toBe(true);
|
||||
|
||||
const channelMember2 = {
|
||||
notify_props: {
|
||||
desktop_sound: 'off',
|
||||
},
|
||||
};
|
||||
const user2 = {
|
||||
notify_props: {
|
||||
desktop_sound: 'false',
|
||||
},
|
||||
};
|
||||
expect(isDesktopSoundEnabled(channelMember2, user2)).toBe(false);
|
||||
|
||||
const channelMember3 = {
|
||||
notify_props: {
|
||||
desktop_sound: 'default',
|
||||
},
|
||||
};
|
||||
const user3 = {
|
||||
notify_props: {
|
||||
desktop_sound: 'false',
|
||||
},
|
||||
};
|
||||
expect(isDesktopSoundEnabled(channelMember3, user3)).toBe(false);
|
||||
|
||||
const channelMember4 = {
|
||||
notify_props: {
|
||||
desktop_sound: 'default',
|
||||
},
|
||||
};
|
||||
const user4 = {
|
||||
notify_props: {
|
||||
desktop_sound: 'true',
|
||||
},
|
||||
};
|
||||
expect(isDesktopSoundEnabled(channelMember4, user4)).toBe(true);
|
||||
|
||||
const channelMember5 = {
|
||||
notify_props: {
|
||||
desktop_sound: 'on',
|
||||
},
|
||||
};
|
||||
const user5 = {
|
||||
notify_props: {
|
||||
desktop_sound: '',
|
||||
},
|
||||
};
|
||||
expect(isDesktopSoundEnabled(channelMember5, user5)).toBe(true);
|
||||
});
|
||||
|
||||
test('should return user sound if channel member sound is not defined', () => {
|
||||
const channelMember1 = {
|
||||
notify_props: {
|
||||
desktop_sound: '',
|
||||
},
|
||||
};
|
||||
const user1 = {
|
||||
notify_props: {
|
||||
desktop_sound: 'true',
|
||||
},
|
||||
};
|
||||
expect(isDesktopSoundEnabled(channelMember1, user1)).toBe(true);
|
||||
|
||||
const channelMember2 = {
|
||||
notify_props: {
|
||||
desktop_sound: '',
|
||||
},
|
||||
};
|
||||
const user2 = {
|
||||
notify_props: {
|
||||
desktop_sound: 'false',
|
||||
},
|
||||
};
|
||||
expect(isDesktopSoundEnabled(channelMember2, user2)).toBe(false);
|
||||
|
||||
const channelMember3 = {
|
||||
notify_props: {},
|
||||
};
|
||||
const user3 = {
|
||||
notify_props: {
|
||||
desktop_sound: 'false',
|
||||
},
|
||||
};
|
||||
expect(isDesktopSoundEnabled(channelMember3, user3)).toBe(false);
|
||||
});
|
||||
|
||||
test('should return default if both channel member and user are not defined', () => {
|
||||
const channelMember = {};
|
||||
const user = {};
|
||||
expect(isDesktopSoundEnabled(channelMember, user)).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getDesktopNotificationSound', () => {
|
||||
test('should return channel member notification sound if it exists', () => {
|
||||
const channelMember1 = {
|
||||
notify_props: {
|
||||
desktop_notification_sound: 'default',
|
||||
},
|
||||
};
|
||||
const user1 = {
|
||||
notify_props: {
|
||||
desktop_notification_sound: 'Crackle',
|
||||
},
|
||||
};
|
||||
expect(getDesktopNotificationSound(channelMember1, user1)).toBe('Crackle');
|
||||
|
||||
const channelMember2 = {
|
||||
notify_props: {
|
||||
desktop_notification_sound: 'default',
|
||||
},
|
||||
};
|
||||
const user2 = {
|
||||
notify_props: {
|
||||
desktop_notification_sound: '',
|
||||
},
|
||||
};
|
||||
expect(getDesktopNotificationSound(channelMember2, user2)).toBe('Bing');
|
||||
|
||||
const channelMember3 = {
|
||||
notify_props: {
|
||||
desktop_notification_sound: 'Crackle',
|
||||
},
|
||||
};
|
||||
const user3 = {
|
||||
notify_props: {
|
||||
desktop_notification_sound: 'Bing',
|
||||
},
|
||||
};
|
||||
expect(getDesktopNotificationSound(channelMember3, user3)).toBe('Crackle');
|
||||
});
|
||||
|
||||
test('should return user notification sound if channel member sound is not defined', () => {
|
||||
const channelMember1 = {};
|
||||
const user1 = {
|
||||
notify_props: {
|
||||
desktop_notification_sound: 'Crackle',
|
||||
},
|
||||
};
|
||||
expect(getDesktopNotificationSound(channelMember1, user1)).toBe('Crackle');
|
||||
|
||||
const channelMember2 = {};
|
||||
const user2 = {};
|
||||
expect(getDesktopNotificationSound(channelMember2, user2)).toBe('Bing');
|
||||
});
|
||||
});
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -50,6 +50,7 @@
|
||||
|
||||
&__reset-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 5px 8px;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
@ -58,8 +59,10 @@
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
gap: 4px;
|
||||
line-height: 9.5px;
|
||||
place-items: center;
|
||||
|
||||
i {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
&:hover,
|
||||
&:active {
|
||||
|
@ -2,54 +2,57 @@
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {screen, fireEvent, waitFor} from '@testing-library/react';
|
||||
import type {ComponentProps} from 'react';
|
||||
import React from 'react';
|
||||
|
||||
import type {ChannelMembership} from '@mattermost/types/channels';
|
||||
import type {UserNotifyProps} from '@mattermost/types/users';
|
||||
|
||||
import ChannelNotificationsModal from 'components/channel_notifications_modal/channel_notifications_modal';
|
||||
import ChannelNotificationsModal, {createChannelNotifyPropsFromSelectedSettings, getInitialValuesOfChannelNotifyProps, areDesktopAndMobileSettingsDifferent} from 'components/channel_notifications_modal/channel_notifications_modal';
|
||||
import type {Props} from 'components/channel_notifications_modal/channel_notifications_modal';
|
||||
|
||||
import {renderWithContext} from 'tests/react_testing_utils';
|
||||
import {IgnoreChannelMentions, NotificationLevels} from 'utils/constants';
|
||||
import {DesktopSound, IgnoreChannelMentions, NotificationLevels} from 'utils/constants';
|
||||
import {DesktopNotificationSounds, convertDesktopSoundNotifyPropFromUserToDesktop} from 'utils/notification_sounds';
|
||||
import {TestHelper} from 'utils/test_helper';
|
||||
|
||||
describe('components/channel_notifications_modal/ChannelNotificationsModal', () => {
|
||||
const baseProps: ComponentProps<typeof ChannelNotificationsModal> = {
|
||||
describe('ChannelNotificationsModal', () => {
|
||||
const baseProps: Props = {
|
||||
onExited: jest.fn(),
|
||||
channel: TestHelper.getChannelMock({
|
||||
id: 'channel_id',
|
||||
display_name: 'channel_display_name',
|
||||
}),
|
||||
channelMember: {
|
||||
notify_props: {
|
||||
desktop: NotificationLevels.ALL,
|
||||
desktop_sound: 'on',
|
||||
desktop_notification_sound: 'Bing',
|
||||
mark_unread: NotificationLevels.ALL,
|
||||
push: NotificationLevels.DEFAULT,
|
||||
ignore_channel_mentions: IgnoreChannelMentions.DEFAULT,
|
||||
desktop_threads: NotificationLevels.ALL,
|
||||
push_threads: NotificationLevels.DEFAULT,
|
||||
},
|
||||
} as unknown as ChannelMembership,
|
||||
currentUser: TestHelper.getUserMock({
|
||||
id: 'current_user_id',
|
||||
notify_props: {
|
||||
desktop: NotificationLevels.ALL,
|
||||
desktop_threads: NotificationLevels.MENTION,
|
||||
desktop_sound: 'true',
|
||||
desktop_notification_sound: 'Bing',
|
||||
desktop_threads: NotificationLevels.ALL,
|
||||
push: NotificationLevels.MENTION,
|
||||
push_threads: NotificationLevels.MENTION,
|
||||
} as UserNotifyProps,
|
||||
}),
|
||||
channelMember: {
|
||||
notify_props: {
|
||||
desktop: NotificationLevels.ALL,
|
||||
desktop_threads: NotificationLevels.ALL,
|
||||
desktop_sound: 'on',
|
||||
desktop_notification_sound: 'Bing',
|
||||
push: NotificationLevels.ALL,
|
||||
push_threads: NotificationLevels.ALL,
|
||||
mark_unread: NotificationLevels.ALL,
|
||||
ignore_channel_mentions: IgnoreChannelMentions.DEFAULT,
|
||||
},
|
||||
} as unknown as ChannelMembership,
|
||||
sendPushNotifications: true,
|
||||
actions: {
|
||||
updateChannelNotifyProps: jest.fn().mockImplementation(() => Promise.resolve({data: true})),
|
||||
},
|
||||
collapsedReplyThreads: false,
|
||||
collapsedReplyThreads: true,
|
||||
};
|
||||
|
||||
it('should not show other settings if channel is mute', async () => {
|
||||
test('should not show other settings if channel is mute', async () => {
|
||||
const wrapper = renderWithContext(
|
||||
<ChannelNotificationsModal {...baseProps}/>,
|
||||
);
|
||||
@ -64,7 +67,7 @@ describe('components/channel_notifications_modal/ChannelNotificationsModal', ()
|
||||
expect(screen.queryByText('Desktop Notifications')).toBeNull();
|
||||
|
||||
expect(screen.queryByText('Mobile Notifications')).toBeNull();
|
||||
expect(screen.queryByText('Follow all threads in this channel')).toBeNull();
|
||||
expect(screen.queryByText('Follow all threads in this channel')).not.toBeNull();
|
||||
|
||||
fireEvent.click(screen.getByRole('button', {name: /Save/i}));
|
||||
|
||||
@ -73,19 +76,22 @@ describe('components/channel_notifications_modal/ChannelNotificationsModal', ()
|
||||
'current_user_id',
|
||||
'channel_id',
|
||||
{
|
||||
desktop: baseProps.channelMember?.notify_props.desktop,
|
||||
ignore_channel_mentions: 'off',
|
||||
mark_unread: 'mention',
|
||||
desktop: 'default',
|
||||
desktop_threads: 'all',
|
||||
desktop_sound: 'default',
|
||||
desktop_notification_sound: 'default',
|
||||
push: 'all',
|
||||
desktop_sound: 'on',
|
||||
desktop_notification_sound: 'Bing',
|
||||
push_threads: 'all',
|
||||
mark_unread: 'mention',
|
||||
ignore_channel_mentions: 'off',
|
||||
channel_auto_follow_threads: 'off',
|
||||
},
|
||||
),
|
||||
);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('should Ignore mentions for @channel, @here and @all', async () => {
|
||||
test('should save correctly for \'Ignore mentions for @channel, @here and @all\'', async () => {
|
||||
const wrapper = renderWithContext(
|
||||
<ChannelNotificationsModal {...baseProps}/>,
|
||||
);
|
||||
@ -99,13 +105,15 @@ describe('components/channel_notifications_modal/ChannelNotificationsModal', ()
|
||||
'current_user_id',
|
||||
'channel_id',
|
||||
{
|
||||
desktop: 'all',
|
||||
ignore_channel_mentions: 'on',
|
||||
mark_unread:
|
||||
baseProps.channelMember?.notify_props.mark_unread,
|
||||
desktop: 'default',
|
||||
desktop_threads: 'all',
|
||||
desktop_sound: 'default',
|
||||
desktop_notification_sound: 'default',
|
||||
push: 'all',
|
||||
desktop_sound: 'on',
|
||||
desktop_notification_sound: 'Bing',
|
||||
push_threads: 'all',
|
||||
mark_unread: 'all',
|
||||
ignore_channel_mentions: 'on',
|
||||
channel_auto_follow_threads: 'off',
|
||||
},
|
||||
),
|
||||
);
|
||||
@ -144,11 +152,14 @@ describe('components/channel_notifications_modal/ChannelNotificationsModal', ()
|
||||
'channel_id',
|
||||
{
|
||||
desktop: 'none',
|
||||
channel_auto_follow_threads: 'off',
|
||||
desktop_threads: 'all',
|
||||
push_threads: 'all',
|
||||
desktop_notification_sound: 'default',
|
||||
desktop_sound: 'default',
|
||||
ignore_channel_mentions: 'off',
|
||||
mark_unread: 'all',
|
||||
push: 'all',
|
||||
desktop_sound: 'on',
|
||||
desktop_notification_sound: 'Bing',
|
||||
push: 'none',
|
||||
},
|
||||
),
|
||||
);
|
||||
@ -158,7 +169,7 @@ describe('components/channel_notifications_modal/ChannelNotificationsModal', ()
|
||||
test('should disable message notification sound if option is unchecked', async () => {
|
||||
renderWithContext(<ChannelNotificationsModal {...baseProps}/>);
|
||||
|
||||
// Since the default value is on, we will uncheck the checkbox
|
||||
// Since the default value is checked, we will uncheck the checkbox
|
||||
fireEvent.click(screen.getByTestId('desktopNotificationSoundsCheckbox'));
|
||||
expect(screen.getByTestId('desktopNotificationSoundsCheckbox')).not.toBeChecked();
|
||||
|
||||
@ -168,12 +179,15 @@ describe('components/channel_notifications_modal/ChannelNotificationsModal', ()
|
||||
'current_user_id',
|
||||
'channel_id',
|
||||
{
|
||||
desktop: 'all',
|
||||
ignore_channel_mentions: 'off',
|
||||
mark_unread: 'all',
|
||||
push: 'all',
|
||||
desktop: 'default',
|
||||
desktop_threads: 'all',
|
||||
desktop_sound: 'off',
|
||||
desktop_notification_sound: 'Bing',
|
||||
desktop_notification_sound: 'default',
|
||||
push: 'all',
|
||||
push_threads: 'all',
|
||||
mark_unread: 'all',
|
||||
ignore_channel_mentions: 'off',
|
||||
channel_auto_follow_threads: 'off',
|
||||
},
|
||||
);
|
||||
});
|
||||
@ -203,7 +217,6 @@ describe('components/channel_notifications_modal/ChannelNotificationsModal', ()
|
||||
const sameAsDesktop: HTMLInputElement = screen.getByTestId(
|
||||
'sameMobileSettingsDesktop',
|
||||
);
|
||||
fireEvent.click(sameAsDesktop);
|
||||
expect(sameAsDesktop.checked).toEqual(true);
|
||||
|
||||
expect(screen.queryByText('All new messages')).toBeNull();
|
||||
@ -214,12 +227,15 @@ describe('components/channel_notifications_modal/ChannelNotificationsModal', ()
|
||||
'current_user_id',
|
||||
'channel_id',
|
||||
{
|
||||
desktop: 'all',
|
||||
ignore_channel_mentions: 'off',
|
||||
mark_unread: 'all',
|
||||
desktop: 'default',
|
||||
desktop_threads: 'all',
|
||||
desktop_sound: 'default',
|
||||
desktop_notification_sound: 'default',
|
||||
push: 'all',
|
||||
desktop_sound: 'on',
|
||||
desktop_notification_sound: 'Bing',
|
||||
push_threads: 'all',
|
||||
mark_unread: 'all',
|
||||
ignore_channel_mentions: 'off',
|
||||
channel_auto_follow_threads: 'off',
|
||||
},
|
||||
),
|
||||
);
|
||||
@ -227,56 +243,59 @@ describe('components/channel_notifications_modal/ChannelNotificationsModal', ()
|
||||
});
|
||||
|
||||
test('should check the options in the mobile notifications', async () => {
|
||||
const wrapper = renderWithContext(
|
||||
<ChannelNotificationsModal {...baseProps}/>,
|
||||
);
|
||||
|
||||
const AlllabelRadio: HTMLInputElement = screen.getByTestId(
|
||||
'MobileNotification-all',
|
||||
);
|
||||
fireEvent.click(AlllabelRadio);
|
||||
expect(AlllabelRadio.checked).toEqual(true);
|
||||
|
||||
const MentionslabelRadio: HTMLInputElement = screen.getByTestId(
|
||||
'MobileNotification-mention',
|
||||
);
|
||||
fireEvent.click(MentionslabelRadio);
|
||||
expect(MentionslabelRadio.checked).toEqual(true);
|
||||
|
||||
const NothinglabelRadio: HTMLInputElement = screen.getByTestId(
|
||||
'MobileNotification-none',
|
||||
);
|
||||
fireEvent.click(NothinglabelRadio);
|
||||
expect(NothinglabelRadio.checked).toEqual(true);
|
||||
|
||||
fireEvent.click(screen.getByRole('button', {name: /Save/i}));
|
||||
await waitFor(() =>
|
||||
expect(baseProps.actions.updateChannelNotifyProps).toHaveBeenCalledWith(
|
||||
'current_user_id',
|
||||
'channel_id',
|
||||
{
|
||||
desktop: 'all',
|
||||
ignore_channel_mentions: 'off',
|
||||
mark_unread: 'all',
|
||||
push: 'none',
|
||||
desktop_sound: 'on',
|
||||
desktop_notification_sound: 'Bing',
|
||||
},
|
||||
),
|
||||
);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should show auto follow, desktop threads and mobile threads settings if collapsed reply threads is enabled', async () => {
|
||||
const props = {
|
||||
...baseProps,
|
||||
collapsedReplyThreads: true,
|
||||
channelMember: {
|
||||
notify_props: {
|
||||
...baseProps.channelMember?.notify_props,
|
||||
push: NotificationLevels.MENTION,
|
||||
},
|
||||
} as unknown as ChannelMembership,
|
||||
};
|
||||
const wrapper = renderWithContext(
|
||||
<ChannelNotificationsModal {...props}/>,
|
||||
);
|
||||
|
||||
expect(screen.queryByText('Follow all threads in this channel')).toBeVisible();
|
||||
fireEvent.click(screen.getByTestId('MobileNotification-all'));
|
||||
expect(screen.getByTestId('MobileNotification-all')).toBeChecked();
|
||||
|
||||
fireEvent.click(screen.getByTestId('MobileNotification-mention'));
|
||||
expect(screen.getByTestId('MobileNotification-mention')).toBeChecked();
|
||||
|
||||
fireEvent.click(screen.getByTestId('MobileNotification-none'));
|
||||
expect(screen.getByTestId('MobileNotification-none')).toBeChecked();
|
||||
|
||||
fireEvent.click(screen.getByRole('button', {name: /Save/i}));
|
||||
await waitFor(() =>
|
||||
expect(baseProps.actions.updateChannelNotifyProps).toHaveBeenCalledWith(
|
||||
'current_user_id',
|
||||
'channel_id',
|
||||
{
|
||||
desktop: 'default',
|
||||
channel_auto_follow_threads: 'off',
|
||||
desktop_threads: 'all',
|
||||
push_threads: 'all',
|
||||
desktop_notification_sound: 'default',
|
||||
desktop_sound: 'default',
|
||||
ignore_channel_mentions: 'off',
|
||||
mark_unread: 'all',
|
||||
push: 'none',
|
||||
},
|
||||
),
|
||||
);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('should show not auto follow, desktop threads and mobile threads settings if collapsed reply threads is enabled', async () => {
|
||||
const props = {
|
||||
...baseProps,
|
||||
collapsedReplyThreads: false,
|
||||
};
|
||||
const wrapper = renderWithContext(
|
||||
<ChannelNotificationsModal {...props}/>,
|
||||
);
|
||||
|
||||
expect(screen.queryByText('Follow all threads in this channel')).toBeNull();
|
||||
|
||||
fireEvent.click(screen.getByRole('button', {name: /Save/i}));
|
||||
|
||||
@ -285,18 +304,660 @@ describe('components/channel_notifications_modal/ChannelNotificationsModal', ()
|
||||
'current_user_id',
|
||||
'channel_id',
|
||||
{
|
||||
desktop: baseProps.channelMember?.notify_props.desktop,
|
||||
channel_auto_follow_threads: 'off',
|
||||
desktop: 'default',
|
||||
desktop_notification_sound: 'default',
|
||||
desktop_sound: 'default',
|
||||
desktop_threads: 'all',
|
||||
ignore_channel_mentions: 'off',
|
||||
mark_unread: 'all',
|
||||
channel_auto_follow_threads: 'off',
|
||||
push: 'all',
|
||||
push_threads: 'default',
|
||||
desktop_threads: 'all',
|
||||
desktop_sound: 'on',
|
||||
desktop_notification_sound: 'Bing',
|
||||
push_threads: 'all',
|
||||
},
|
||||
),
|
||||
);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
describe('createChannelNotifyPropsFromSelectedSettings', () => {
|
||||
test('should return passed in mark_unread, ignore_channel_mentions, channel_auto_follow_threads', () => {
|
||||
const userNotifyProps = TestHelper.getUserMock().notify_props;
|
||||
const savedChannelNotifyProps = TestHelper.getChannelMembershipMock({
|
||||
notify_props: {
|
||||
mark_unread: 'all',
|
||||
ignore_channel_mentions: 'off',
|
||||
channel_auto_follow_threads: 'off',
|
||||
},
|
||||
}).notify_props;
|
||||
|
||||
const channelNotifyProps = createChannelNotifyPropsFromSelectedSettings(userNotifyProps, savedChannelNotifyProps, true);
|
||||
expect(channelNotifyProps.mark_unread).toEqual('all');
|
||||
expect(channelNotifyProps.ignore_channel_mentions).toEqual('off');
|
||||
expect(channelNotifyProps.channel_auto_follow_threads).toEqual('off');
|
||||
});
|
||||
|
||||
test('should return default if channel\'s desktop is same as user\'s desktop value', () => {
|
||||
const userNotifyProps1 = TestHelper.getUserMock({
|
||||
notify_props: {
|
||||
desktop: 'all',
|
||||
} as UserNotifyProps,
|
||||
}).notify_props;
|
||||
const savedChannelNotifyProps1 = TestHelper.getChannelMembershipMock({
|
||||
notify_props: {
|
||||
desktop: 'all',
|
||||
},
|
||||
}).notify_props;
|
||||
|
||||
const channelNotifyProps1 = createChannelNotifyPropsFromSelectedSettings(userNotifyProps1, savedChannelNotifyProps1, true);
|
||||
expect(channelNotifyProps1.desktop).toEqual('default');
|
||||
|
||||
const userNotifyProps2 = TestHelper.getUserMock({
|
||||
notify_props: {
|
||||
desktop: 'mention',
|
||||
} as UserNotifyProps,
|
||||
}).notify_props;
|
||||
const savedChannelNotifyProps2 = TestHelper.getChannelMembershipMock({
|
||||
notify_props: {
|
||||
desktop: 'mention',
|
||||
},
|
||||
}).notify_props;
|
||||
|
||||
const channelNotifyProps2 = createChannelNotifyPropsFromSelectedSettings(userNotifyProps2, savedChannelNotifyProps2, true);
|
||||
expect(channelNotifyProps2.desktop).toEqual('default');
|
||||
});
|
||||
|
||||
test('should return desktop value if channel\'s desktop is different from user\'s desktop value', () => {
|
||||
const userNotifyProps = TestHelper.getUserMock({
|
||||
notify_props: {
|
||||
desktop: 'mention',
|
||||
} as UserNotifyProps,
|
||||
}).notify_props;
|
||||
const savedChannelNotifyProps = TestHelper.getChannelMembershipMock({
|
||||
notify_props: {
|
||||
desktop: 'all',
|
||||
},
|
||||
}).notify_props;
|
||||
|
||||
const channelNotifyProps = createChannelNotifyPropsFromSelectedSettings(userNotifyProps, savedChannelNotifyProps, true);
|
||||
expect(channelNotifyProps.desktop).toEqual('all');
|
||||
});
|
||||
|
||||
test('should return correct desktop_threads when user\'s desktop_threads is defined', () => {
|
||||
const userNotifyProps1 = TestHelper.getUserMock({
|
||||
notify_props: {
|
||||
desktop_threads: 'mention',
|
||||
} as UserNotifyProps,
|
||||
}).notify_props;
|
||||
const savedChannelNotifyProps1 = TestHelper.getChannelMembershipMock({
|
||||
notify_props: {
|
||||
desktop_threads: 'mention',
|
||||
},
|
||||
}).notify_props;
|
||||
const channelNotifyProps1 = createChannelNotifyPropsFromSelectedSettings(userNotifyProps1, savedChannelNotifyProps1, true);
|
||||
expect(channelNotifyProps1.desktop_threads).toEqual('default');
|
||||
|
||||
const userNotifyProps2 = TestHelper.getUserMock({
|
||||
notify_props: {
|
||||
desktop_threads: 'all',
|
||||
} as UserNotifyProps,
|
||||
}).notify_props;
|
||||
const savedChannelNotifyProps2 = TestHelper.getChannelMembershipMock({
|
||||
notify_props: {
|
||||
desktop_threads: 'mention',
|
||||
},
|
||||
}).notify_props;
|
||||
const channelNotifyProps2 = createChannelNotifyPropsFromSelectedSettings(userNotifyProps2, savedChannelNotifyProps2, true);
|
||||
expect(channelNotifyProps2.desktop_threads).toEqual('mention');
|
||||
});
|
||||
|
||||
test('should return correct desktop_threads when user\'s desktop_threads is not defined', () => {
|
||||
const userNotifyProps1 = TestHelper.getUserMock({
|
||||
notify_props: {} as UserNotifyProps,
|
||||
}).notify_props;
|
||||
const savedChannelNotifyProps1 = TestHelper.getChannelMembershipMock({
|
||||
notify_props: {
|
||||
desktop_threads: 'mention',
|
||||
},
|
||||
}).notify_props;
|
||||
const channelNotifyProps1 = createChannelNotifyPropsFromSelectedSettings(userNotifyProps1, savedChannelNotifyProps1, true);
|
||||
expect(channelNotifyProps1.desktop_threads).toEqual('default');
|
||||
|
||||
const userNotifyProps2 = TestHelper.getUserMock({
|
||||
notify_props: {} as UserNotifyProps,
|
||||
}).notify_props;
|
||||
const savedChannelNotifyProps2 = TestHelper.getChannelMembershipMock({
|
||||
notify_props: {
|
||||
desktop_threads: 'default',
|
||||
},
|
||||
}).notify_props;
|
||||
const channelNotifyProps2 = createChannelNotifyPropsFromSelectedSettings(userNotifyProps2, savedChannelNotifyProps2, true);
|
||||
expect(channelNotifyProps2.desktop_threads).toEqual('default');
|
||||
|
||||
const userNotifyProps3 = TestHelper.getUserMock({
|
||||
notify_props: {} as UserNotifyProps,
|
||||
}).notify_props;
|
||||
const savedChannelNotifyProps3 = TestHelper.getChannelMembershipMock({
|
||||
notify_props: {
|
||||
desktop_threads: 'none',
|
||||
},
|
||||
}).notify_props;
|
||||
const channelNotifyProps3 = createChannelNotifyPropsFromSelectedSettings(userNotifyProps3, savedChannelNotifyProps3, true);
|
||||
expect(channelNotifyProps3.desktop_threads).toEqual('none');
|
||||
|
||||
const userNotifyProps4 = TestHelper.getUserMock({
|
||||
notify_props: {
|
||||
desktop_threads: '' as any,
|
||||
} as UserNotifyProps,
|
||||
}).notify_props;
|
||||
const savedChannelNotifyProps4 = TestHelper.getChannelMembershipMock({
|
||||
notify_props: {
|
||||
desktop_threads: 'none',
|
||||
},
|
||||
}).notify_props;
|
||||
const channelNotifyProps4 = createChannelNotifyPropsFromSelectedSettings(userNotifyProps4, savedChannelNotifyProps4, true);
|
||||
expect(channelNotifyProps4.desktop_threads).toEqual('none');
|
||||
});
|
||||
|
||||
test('should return correct desktop_sound value', () => {
|
||||
const userNotifyProps1 = TestHelper.getUserMock({
|
||||
notify_props: {
|
||||
desktop_sound: 'true',
|
||||
} as UserNotifyProps,
|
||||
}).notify_props;
|
||||
const savedChannelNotifyProps1 = TestHelper.getChannelMembershipMock({
|
||||
notify_props: {
|
||||
desktop_sound: 'on',
|
||||
},
|
||||
}).notify_props;
|
||||
const channelNotifyProps1 = createChannelNotifyPropsFromSelectedSettings(userNotifyProps1, savedChannelNotifyProps1, true);
|
||||
expect(channelNotifyProps1.desktop_sound).toEqual('default');
|
||||
|
||||
const userNotifyProps2 = {
|
||||
desktop_sound: 'false',
|
||||
} as UserNotifyProps;
|
||||
const savedChannelNotifyProps2 = TestHelper.getChannelMembershipMock({
|
||||
notify_props: {
|
||||
desktop_sound: 'off',
|
||||
},
|
||||
}).notify_props;
|
||||
const channelNotifyProps2 = createChannelNotifyPropsFromSelectedSettings(userNotifyProps2, savedChannelNotifyProps2, true);
|
||||
expect(channelNotifyProps2.desktop_sound).toEqual('default');
|
||||
|
||||
const userNotifyProps3 = {
|
||||
desktop_sound: '' as any,
|
||||
} as UserNotifyProps;
|
||||
const savedChannelNotifyProps3 = TestHelper.getChannelMembershipMock({
|
||||
notify_props: {
|
||||
desktop_sound: 'on',
|
||||
},
|
||||
}).notify_props;
|
||||
const channelNotifyProps3 = createChannelNotifyPropsFromSelectedSettings(userNotifyProps3, savedChannelNotifyProps3, true);
|
||||
expect(channelNotifyProps3.desktop_sound).toEqual('default');
|
||||
|
||||
const userNotifyProps4 = {
|
||||
desktop_sound: '' as any,
|
||||
} as UserNotifyProps;
|
||||
const savedChannelNotifyProps4 = TestHelper.getChannelMembershipMock({
|
||||
notify_props: {
|
||||
desktop_sound: 'off',
|
||||
},
|
||||
}).notify_props;
|
||||
const channelNotifyProps4 = createChannelNotifyPropsFromSelectedSettings(userNotifyProps4, savedChannelNotifyProps4, true);
|
||||
expect(channelNotifyProps4.desktop_sound).toEqual('off');
|
||||
|
||||
const userNotifyProps5 = {} as UserNotifyProps;
|
||||
const savedChannelNotifyProps5 = TestHelper.getChannelMembershipMock({
|
||||
notify_props: {
|
||||
desktop_sound: 'off',
|
||||
},
|
||||
}).notify_props;
|
||||
const channelNotifyProps5 = createChannelNotifyPropsFromSelectedSettings(userNotifyProps5, savedChannelNotifyProps5, true);
|
||||
expect(channelNotifyProps5.desktop_sound).toEqual('off');
|
||||
});
|
||||
|
||||
test('should return correct desktop_notification_sound when user\'s desktop_notification_sound is defined', () => {
|
||||
const userNotifyProps = TestHelper.getUserMock({
|
||||
notify_props: {
|
||||
desktop_notification_sound: 'Bing',
|
||||
} as UserNotifyProps,
|
||||
}).notify_props;
|
||||
const savedChannelNotifyProps = TestHelper.getChannelMembershipMock({
|
||||
notify_props: {
|
||||
desktop_notification_sound: 'Bing',
|
||||
},
|
||||
}).notify_props;
|
||||
const channelNotifyProps = createChannelNotifyPropsFromSelectedSettings(userNotifyProps, savedChannelNotifyProps, true);
|
||||
expect(channelNotifyProps.desktop_notification_sound).toEqual('default');
|
||||
|
||||
const userNotifyProps2 = TestHelper.getUserMock({
|
||||
notify_props: {
|
||||
desktop_notification_sound: 'Crackle',
|
||||
} as UserNotifyProps,
|
||||
}).notify_props;
|
||||
const savedChannelNotifyProps2 = TestHelper.getChannelMembershipMock({
|
||||
notify_props: {
|
||||
desktop_notification_sound: 'Bing',
|
||||
},
|
||||
}).notify_props;
|
||||
const channelNotifyProps2 = createChannelNotifyPropsFromSelectedSettings(userNotifyProps2, savedChannelNotifyProps2, true);
|
||||
expect(channelNotifyProps2.desktop_notification_sound).toEqual('Bing');
|
||||
});
|
||||
|
||||
test('should return correct desktop_notification_sound when user\'s desktop_notification_sound is not defined', () => {
|
||||
const userNotifyProps = TestHelper.getUserMock({
|
||||
notify_props: {} as UserNotifyProps,
|
||||
}).notify_props;
|
||||
const savedChannelNotifyProps = TestHelper.getChannelMembershipMock({
|
||||
notify_props: {
|
||||
desktop_notification_sound: 'Bing',
|
||||
},
|
||||
}).notify_props;
|
||||
const channelNotifyProps = createChannelNotifyPropsFromSelectedSettings(userNotifyProps, savedChannelNotifyProps, true);
|
||||
expect(channelNotifyProps.desktop_notification_sound).toEqual('default');
|
||||
|
||||
const userNotifyProps2 = TestHelper.getUserMock({
|
||||
notify_props: {} as UserNotifyProps,
|
||||
}).notify_props;
|
||||
const savedChannelNotifyProps2 = TestHelper.getChannelMembershipMock({
|
||||
notify_props: {
|
||||
desktop_notification_sound: 'default',
|
||||
},
|
||||
}).notify_props;
|
||||
const channelNotifyProps2 = createChannelNotifyPropsFromSelectedSettings(userNotifyProps2, savedChannelNotifyProps2, true);
|
||||
expect(channelNotifyProps2.desktop_notification_sound).toEqual('default');
|
||||
|
||||
const userNotifyProps3 = TestHelper.getUserMock({
|
||||
notify_props: {} as UserNotifyProps,
|
||||
}).notify_props;
|
||||
const savedChannelNotifyProps3 = TestHelper.getChannelMembershipMock({
|
||||
notify_props: {
|
||||
desktop_notification_sound: 'Crackle',
|
||||
},
|
||||
}).notify_props;
|
||||
const channelNotifyProps3 = createChannelNotifyPropsFromSelectedSettings(userNotifyProps3, savedChannelNotifyProps3, true);
|
||||
expect(channelNotifyProps3.desktop_notification_sound).toEqual('Crackle');
|
||||
});
|
||||
|
||||
test('should return correct push value', () => {
|
||||
const userNotifyProps1 = TestHelper.getUserMock({
|
||||
notify_props: {
|
||||
push: 'mention',
|
||||
} as UserNotifyProps,
|
||||
}).notify_props;
|
||||
const savedChannelNotifyProps1 = TestHelper.getChannelMembershipMock({
|
||||
notify_props: {
|
||||
push: 'all',
|
||||
},
|
||||
}).notify_props;
|
||||
const channelNotifyProps1 = createChannelNotifyPropsFromSelectedSettings(userNotifyProps1, savedChannelNotifyProps1, true);
|
||||
expect(channelNotifyProps1.push).toEqual('all');
|
||||
|
||||
const userNotifyProps2 = TestHelper.getUserMock({
|
||||
notify_props: {
|
||||
push: 'all',
|
||||
} as UserNotifyProps,
|
||||
}).notify_props;
|
||||
const savedChannelNotifyProps2 = TestHelper.getChannelMembershipMock({
|
||||
notify_props: {
|
||||
push: 'all',
|
||||
},
|
||||
}).notify_props;
|
||||
const channelNotifyProps2 = createChannelNotifyPropsFromSelectedSettings(userNotifyProps2, savedChannelNotifyProps2, true);
|
||||
expect(channelNotifyProps2.push).toEqual('default');
|
||||
});
|
||||
|
||||
test('should return correct push value when desktop and mobile settings are the same', () => {
|
||||
const userNotifyProps1 = TestHelper.getUserMock({
|
||||
notify_props: {
|
||||
desktop: 'all',
|
||||
push: 'mention',
|
||||
} as UserNotifyProps,
|
||||
}).notify_props;
|
||||
const savedChannelNotifyProps1 = TestHelper.getChannelMembershipMock({
|
||||
notify_props: {
|
||||
desktop: 'all',
|
||||
push: 'all',
|
||||
},
|
||||
}).notify_props;
|
||||
const channelNotifyProps1 = createChannelNotifyPropsFromSelectedSettings(userNotifyProps1, savedChannelNotifyProps1, false);
|
||||
expect(channelNotifyProps1.push).toEqual('all');
|
||||
|
||||
const userNotifyProps2 = TestHelper.getUserMock({
|
||||
notify_props: {
|
||||
desktop: 'all',
|
||||
push: 'all',
|
||||
} as UserNotifyProps,
|
||||
}).notify_props;
|
||||
const savedChannelNotifyProps2 = TestHelper.getChannelMembershipMock({
|
||||
notify_props: {
|
||||
desktop: 'mention',
|
||||
push: 'all',
|
||||
},
|
||||
}).notify_props;
|
||||
const channelNotifyProps2 = createChannelNotifyPropsFromSelectedSettings(userNotifyProps2, savedChannelNotifyProps2, false);
|
||||
expect(channelNotifyProps2.push).toEqual('mention');
|
||||
});
|
||||
|
||||
test('should return correct push_threads value', () => {
|
||||
const userNotifyProps1 = TestHelper.getUserMock({
|
||||
notify_props: {
|
||||
push: 'mention',
|
||||
push_threads: 'mention',
|
||||
} as UserNotifyProps,
|
||||
}).notify_props;
|
||||
const savedChannelNotifyProps1 = TestHelper.getChannelMembershipMock({
|
||||
notify_props: {
|
||||
push: 'all',
|
||||
push_threads: 'all',
|
||||
},
|
||||
}).notify_props;
|
||||
const channelNotifyProps1 = createChannelNotifyPropsFromSelectedSettings(userNotifyProps1, savedChannelNotifyProps1, true);
|
||||
expect(channelNotifyProps1.push).toEqual('all');
|
||||
expect(channelNotifyProps1.push_threads).toEqual('all');
|
||||
|
||||
const userNotifyProps2 = TestHelper.getUserMock({
|
||||
notify_props: {
|
||||
push: 'mention',
|
||||
} as UserNotifyProps,
|
||||
}).notify_props;
|
||||
const savedChannelNotifyProps2 = TestHelper.getChannelMembershipMock({
|
||||
notify_props: {
|
||||
push: 'all',
|
||||
push_threads: 'all',
|
||||
},
|
||||
}).notify_props;
|
||||
const channelNotifyProps2 = createChannelNotifyPropsFromSelectedSettings(userNotifyProps2, savedChannelNotifyProps2, true);
|
||||
expect(channelNotifyProps2.push).toEqual('all');
|
||||
expect(channelNotifyProps2.push_threads).toEqual('all');
|
||||
|
||||
const userNotifyProps3 = TestHelper.getUserMock({
|
||||
notify_props: {
|
||||
} as UserNotifyProps,
|
||||
}).notify_props;
|
||||
const savedChannelNotifyProps3 = TestHelper.getChannelMembershipMock({
|
||||
notify_props: {
|
||||
push: 'all',
|
||||
push_threads: 'all',
|
||||
},
|
||||
}).notify_props;
|
||||
const channelNotifyProps3 = createChannelNotifyPropsFromSelectedSettings(userNotifyProps3, savedChannelNotifyProps3, true);
|
||||
expect(channelNotifyProps3.push).toEqual('all');
|
||||
expect(channelNotifyProps3.push_threads).toEqual('all');
|
||||
|
||||
const userNotifyProps4 = TestHelper.getUserMock({
|
||||
notify_props: {
|
||||
desktop_threads: 'all',
|
||||
} as UserNotifyProps,
|
||||
}).notify_props;
|
||||
const savedChannelNotifyProps4 = TestHelper.getChannelMembershipMock({
|
||||
notify_props: {
|
||||
desktop_threads: 'mention',
|
||||
push_threads: 'none',
|
||||
},
|
||||
}).notify_props;
|
||||
const channelNotifyProps4 = createChannelNotifyPropsFromSelectedSettings(userNotifyProps4, savedChannelNotifyProps4, false);
|
||||
expect(channelNotifyProps4.push_threads).toEqual('mention');
|
||||
|
||||
const userNotifyProps5 = TestHelper.getUserMock({
|
||||
notify_props: {
|
||||
desktop_threads: 'none',
|
||||
} as UserNotifyProps,
|
||||
}).notify_props;
|
||||
const savedChannelNotifyProps5 = TestHelper.getChannelMembershipMock({
|
||||
notify_props: {
|
||||
desktop_threads: 'all',
|
||||
push_threads: 'none',
|
||||
},
|
||||
}).notify_props;
|
||||
const channelNotifyProps5 = createChannelNotifyPropsFromSelectedSettings(userNotifyProps5, savedChannelNotifyProps5, false);
|
||||
expect(channelNotifyProps5.push_threads).toEqual('all');
|
||||
});
|
||||
});
|
||||
|
||||
describe('getInitialValuesOfChannelNotifyProps', () => {
|
||||
test('should return correct value for desktop', () => {
|
||||
const userNotifyProps1 = TestHelper.getUserMock({
|
||||
notify_props: {
|
||||
desktop: 'all',
|
||||
} as UserNotifyProps,
|
||||
}).notify_props;
|
||||
const channelMemberNotifyProps1 = TestHelper.getChannelMembershipMock({
|
||||
notify_props: {
|
||||
desktop: 'default',
|
||||
},
|
||||
}).notify_props;
|
||||
const desktop = getInitialValuesOfChannelNotifyProps(NotificationLevels.ALL, channelMemberNotifyProps1.desktop, userNotifyProps1.desktop);
|
||||
expect(desktop).toEqual(NotificationLevels.ALL);
|
||||
|
||||
const userNotifyProps2 = TestHelper.getUserMock({
|
||||
notify_props: {
|
||||
desktop: NotificationLevels.ALL,
|
||||
} as UserNotifyProps,
|
||||
}).notify_props;
|
||||
const channelMemberNotifyProps2 = TestHelper.getChannelMembershipMock({
|
||||
notify_props: {
|
||||
desktop: NotificationLevels.MENTION,
|
||||
},
|
||||
}).notify_props;
|
||||
const desktop2 = getInitialValuesOfChannelNotifyProps(NotificationLevels.ALL, channelMemberNotifyProps2.desktop, userNotifyProps2.desktop);
|
||||
expect(desktop2).toEqual(NotificationLevels.MENTION);
|
||||
|
||||
const userNotifyProps3 = TestHelper.getUserMock({
|
||||
notify_props: {
|
||||
desktop: NotificationLevels.ALL,
|
||||
} as UserNotifyProps,
|
||||
}).notify_props;
|
||||
const channelMemberNotifyProps3 = TestHelper.getChannelMembershipMock({
|
||||
notify_props: {},
|
||||
}).notify_props;
|
||||
const desktop3 = getInitialValuesOfChannelNotifyProps(NotificationLevels.ALL, channelMemberNotifyProps3.desktop, userNotifyProps3.desktop);
|
||||
expect(desktop3).toEqual(NotificationLevels.ALL);
|
||||
|
||||
const userNotifyProps4 = TestHelper.getUserMock({
|
||||
notify_props: {} as UserNotifyProps,
|
||||
}).notify_props;
|
||||
const channelMemberNotifyProps4 = TestHelper.getChannelMembershipMock({
|
||||
notify_props: {},
|
||||
}).notify_props;
|
||||
const desktop4 = getInitialValuesOfChannelNotifyProps(NotificationLevels.ALL, channelMemberNotifyProps4.desktop, userNotifyProps4.desktop);
|
||||
expect(desktop4).toEqual(NotificationLevels.ALL);
|
||||
});
|
||||
|
||||
test('should return correct value for desktop_threads', () => {
|
||||
const userNotifyProps1 = TestHelper.getUserMock({
|
||||
notify_props: {
|
||||
desktop_threads: NotificationLevels.ALL,
|
||||
} as UserNotifyProps,
|
||||
}).notify_props;
|
||||
const channelMemberNotifyProps1 = TestHelper.getChannelMembershipMock({
|
||||
notify_props: {
|
||||
desktop_threads: NotificationLevels.DEFAULT,
|
||||
},
|
||||
}).notify_props;
|
||||
const desktopThreads = getInitialValuesOfChannelNotifyProps(NotificationLevels.ALL, channelMemberNotifyProps1.desktop_threads, userNotifyProps1.desktop_threads);
|
||||
expect(desktopThreads).toEqual(NotificationLevels.ALL);
|
||||
|
||||
const userNotifyProps2 = TestHelper.getUserMock({
|
||||
notify_props: {} as UserNotifyProps,
|
||||
}).notify_props;
|
||||
const channelMemberNotifyProps2 = TestHelper.getChannelMembershipMock({
|
||||
notify_props: {
|
||||
desktop_threads: NotificationLevels.MENTION,
|
||||
},
|
||||
}).notify_props;
|
||||
const desktopThreads2 = getInitialValuesOfChannelNotifyProps(NotificationLevels.ALL, channelMemberNotifyProps2.desktop_threads, userNotifyProps2.desktop_threads);
|
||||
expect(desktopThreads2).toEqual(NotificationLevels.MENTION);
|
||||
|
||||
const userNotifyProps3 = TestHelper.getUserMock({
|
||||
notify_props: {
|
||||
desktop_threads: NotificationLevels.ALL,
|
||||
} as UserNotifyProps,
|
||||
}).notify_props;
|
||||
const channelMemberNotifyProps3 = TestHelper.getChannelMembershipMock({
|
||||
notify_props: {},
|
||||
}).notify_props;
|
||||
const desktopThreads3 = getInitialValuesOfChannelNotifyProps(NotificationLevels.ALL, channelMemberNotifyProps3.desktop_threads, userNotifyProps3.desktop_threads);
|
||||
expect(desktopThreads3).toEqual(NotificationLevels.ALL);
|
||||
|
||||
const userNotifyProps4 = TestHelper.getUserMock({
|
||||
notify_props: {} as UserNotifyProps,
|
||||
}).notify_props;
|
||||
const channelMemberNotifyProps4 = TestHelper.getChannelMembershipMock({
|
||||
notify_props: {},
|
||||
}).notify_props;
|
||||
const desktopThreads4 = getInitialValuesOfChannelNotifyProps(NotificationLevels.ALL, channelMemberNotifyProps4.desktop_threads, userNotifyProps4.desktop_threads);
|
||||
expect(desktopThreads4).toEqual(NotificationLevels.ALL);
|
||||
});
|
||||
|
||||
test('should return correct value for desktop_sound', () => {
|
||||
const userNotifyProps1 = TestHelper.getUserMock({
|
||||
notify_props: {
|
||||
desktop_sound: 'false',
|
||||
} as UserNotifyProps,
|
||||
}).notify_props;
|
||||
const channelMemberNotifyProps1 = TestHelper.getChannelMembershipMock({
|
||||
notify_props: {
|
||||
desktop_sound: DesktopSound.DEFAULT,
|
||||
},
|
||||
}).notify_props;
|
||||
const desktopSound = getInitialValuesOfChannelNotifyProps(DesktopSound.ON, channelMemberNotifyProps1?.desktop_sound, convertDesktopSoundNotifyPropFromUserToDesktop(userNotifyProps1?.desktop_sound));
|
||||
expect(desktopSound).toEqual(DesktopSound.OFF);
|
||||
|
||||
const userNotifyProps2 = TestHelper.getUserMock({
|
||||
notify_props: {
|
||||
desktop_sound: 'false',
|
||||
} as UserNotifyProps,
|
||||
}).notify_props;
|
||||
const channelMemberNotifyProps2 = TestHelper.getChannelMembershipMock({
|
||||
notify_props: {
|
||||
desktop_sound: DesktopSound.OFF,
|
||||
},
|
||||
}).notify_props;
|
||||
const desktopSound2 = getInitialValuesOfChannelNotifyProps(DesktopSound.ON, channelMemberNotifyProps2?.desktop_sound, convertDesktopSoundNotifyPropFromUserToDesktop(userNotifyProps2?.desktop_sound));
|
||||
expect(desktopSound2).toEqual(DesktopSound.OFF);
|
||||
|
||||
const userNotifyProps3 = TestHelper.getUserMock({
|
||||
notify_props: {
|
||||
desktop_sound: 'false',
|
||||
} as UserNotifyProps,
|
||||
}).notify_props;
|
||||
const channelMemberNotifyProps3 = TestHelper.getChannelMembershipMock({
|
||||
notify_props: {},
|
||||
}).notify_props;
|
||||
const desktopSound3 = getInitialValuesOfChannelNotifyProps(DesktopSound.ON, channelMemberNotifyProps3?.desktop_sound, convertDesktopSoundNotifyPropFromUserToDesktop(userNotifyProps3?.desktop_sound));
|
||||
expect(desktopSound3).toEqual(DesktopSound.OFF);
|
||||
|
||||
const userNotifyProps4 = TestHelper.getUserMock({
|
||||
notify_props: {} as UserNotifyProps,
|
||||
}).notify_props;
|
||||
const channelMemberNotifyProps4 = TestHelper.getChannelMembershipMock({
|
||||
notify_props: {},
|
||||
}).notify_props;
|
||||
const desktopSound4 = getInitialValuesOfChannelNotifyProps(DesktopSound.ON, channelMemberNotifyProps4?.desktop_sound, convertDesktopSoundNotifyPropFromUserToDesktop(userNotifyProps4?.desktop_sound));
|
||||
expect(desktopSound4).toEqual(DesktopSound.ON);
|
||||
});
|
||||
|
||||
test('should return correct value for desktop_notification_sound', () => {
|
||||
const userNotifyProps1 = TestHelper.getUserMock({
|
||||
notify_props: {
|
||||
desktop_notification_sound: DesktopNotificationSounds.BING,
|
||||
} as UserNotifyProps,
|
||||
}).notify_props;
|
||||
const channelMemberNotifyProps1 = TestHelper.getChannelMembershipMock({
|
||||
notify_props: {
|
||||
desktop_notification_sound: DesktopNotificationSounds.DEFAULT,
|
||||
},
|
||||
}).notify_props;
|
||||
const desktopNotificationSound = getInitialValuesOfChannelNotifyProps(DesktopNotificationSounds.BING, channelMemberNotifyProps1?.desktop_notification_sound, userNotifyProps1?.desktop_notification_sound);
|
||||
expect(desktopNotificationSound).toEqual(DesktopNotificationSounds.BING);
|
||||
|
||||
const userNotifyProps2 = TestHelper.getUserMock({
|
||||
notify_props: {
|
||||
desktop_notification_sound: DesktopNotificationSounds.CRACKLE,
|
||||
} as UserNotifyProps,
|
||||
}).notify_props;
|
||||
const channelMemberNotifyProps2 = TestHelper.getChannelMembershipMock({
|
||||
notify_props: {
|
||||
desktop_notification_sound: DesktopNotificationSounds.BING,
|
||||
},
|
||||
}).notify_props;
|
||||
const desktopNotificationSound2 = getInitialValuesOfChannelNotifyProps(DesktopNotificationSounds.BING, channelMemberNotifyProps2?.desktop_notification_sound, userNotifyProps2?.desktop_notification_sound);
|
||||
expect(desktopNotificationSound2).toEqual(DesktopNotificationSounds.BING);
|
||||
|
||||
const userNotifyProps3 = TestHelper.getUserMock({
|
||||
notify_props: {
|
||||
desktop_notification_sound: DesktopNotificationSounds.CRACKLE,
|
||||
} as UserNotifyProps,
|
||||
}).notify_props;
|
||||
const channelMemberNotifyProps3 = TestHelper.getChannelMembershipMock({
|
||||
notify_props: {},
|
||||
}).notify_props;
|
||||
const desktopNotificationSound3 = getInitialValuesOfChannelNotifyProps(DesktopNotificationSounds.BING, channelMemberNotifyProps3?.desktop_notification_sound, userNotifyProps3?.desktop_notification_sound);
|
||||
expect(desktopNotificationSound3).toEqual(DesktopNotificationSounds.CRACKLE);
|
||||
|
||||
const userNotifyProps4 = TestHelper.getUserMock({
|
||||
notify_props: {} as UserNotifyProps,
|
||||
}).notify_props;
|
||||
const channelMemberNotifyProps4 = TestHelper.getChannelMembershipMock({
|
||||
notify_props: {},
|
||||
}).notify_props;
|
||||
const desktopNotificationSound4 = getInitialValuesOfChannelNotifyProps(DesktopNotificationSounds.BING, channelMemberNotifyProps4?.desktop_notification_sound, userNotifyProps4?.desktop_notification_sound);
|
||||
expect(desktopNotificationSound4).toEqual(DesktopNotificationSounds.BING);
|
||||
});
|
||||
|
||||
test('should return correct value for push', () => {
|
||||
const userNotifyProps1 = TestHelper.getUserMock({
|
||||
notify_props: {
|
||||
push: NotificationLevels.ALL,
|
||||
} as UserNotifyProps,
|
||||
}).notify_props;
|
||||
const channelMemberNotifyProps1 = TestHelper.getChannelMembershipMock({
|
||||
notify_props: {
|
||||
push: NotificationLevels.DEFAULT,
|
||||
},
|
||||
}).notify_props;
|
||||
const push = getInitialValuesOfChannelNotifyProps(NotificationLevels.ALL, channelMemberNotifyProps1.push, userNotifyProps1.push);
|
||||
expect(push).toEqual(NotificationLevels.ALL);
|
||||
|
||||
const userNotifyProps2 = TestHelper.getUserMock({
|
||||
notify_props: {} as UserNotifyProps,
|
||||
}).notify_props;
|
||||
const channelMemberNotifyProps2 = TestHelper.getChannelMembershipMock({
|
||||
notify_props: {},
|
||||
}).notify_props;
|
||||
const push2 = getInitialValuesOfChannelNotifyProps(NotificationLevels.ALL, channelMemberNotifyProps2.push, userNotifyProps2.push);
|
||||
expect(push2).toEqual(NotificationLevels.ALL);
|
||||
});
|
||||
|
||||
test('should return correct value for push_threads', () => {
|
||||
const userNotifyProps1 = TestHelper.getUserMock({
|
||||
notify_props: {
|
||||
push_threads: NotificationLevels.ALL,
|
||||
} as UserNotifyProps,
|
||||
}).notify_props;
|
||||
const channelMemberNotifyProps1 = TestHelper.getChannelMembershipMock({
|
||||
notify_props: {
|
||||
push_threads: NotificationLevels.DEFAULT,
|
||||
},
|
||||
}).notify_props;
|
||||
const pushThreads = getInitialValuesOfChannelNotifyProps(NotificationLevels.ALL, channelMemberNotifyProps1.push_threads, userNotifyProps1.push_threads);
|
||||
expect(pushThreads).toEqual(NotificationLevels.ALL);
|
||||
});
|
||||
});
|
||||
|
||||
describe('areDesktopAndMobileSettingsDifferent', () => {
|
||||
test('should return correct value for collapsed threads', () => {
|
||||
expect(areDesktopAndMobileSettingsDifferent(true, NotificationLevels.ALL, NotificationLevels.ALL, NotificationLevels.DEFAULT, NotificationLevels.DEFAULT)).toEqual(true);
|
||||
|
||||
expect(areDesktopAndMobileSettingsDifferent(true, NotificationLevels.ALL, NotificationLevels.ALL, NotificationLevels.ALL, NotificationLevels.ALL)).toEqual(false);
|
||||
|
||||
expect(areDesktopAndMobileSettingsDifferent(true, NotificationLevels.ALL, NotificationLevels.ALL)).toEqual(true);
|
||||
|
||||
expect(areDesktopAndMobileSettingsDifferent(true, NotificationLevels.ALL, NotificationLevels.ALL, NotificationLevels.ALL)).toEqual(true);
|
||||
|
||||
expect(areDesktopAndMobileSettingsDifferent(true, NotificationLevels.MENTION, NotificationLevels.ALL, NotificationLevels.MENTION, NotificationLevels.ALL)).toEqual(false);
|
||||
|
||||
expect(areDesktopAndMobileSettingsDifferent(true, NotificationLevels.DEFAULT, NotificationLevels.DEFAULT)).toEqual(true);
|
||||
});
|
||||
});
|
||||
|
@ -6,8 +6,8 @@ import {Modal} from 'react-bootstrap';
|
||||
import {FormattedMessage, useIntl} from 'react-intl';
|
||||
import type {ValueType} from 'react-select';
|
||||
|
||||
import {BellOffOutlineIcon, RefreshIcon} from '@mattermost/compass-icons/components';
|
||||
import type {Channel, ChannelNotifyProps} from '@mattermost/types/channels';
|
||||
import {BellOffOutlineIcon} from '@mattermost/compass-icons/components';
|
||||
import type {Channel, ChannelMembership, ChannelNotifyProps} from '@mattermost/types/channels';
|
||||
import type {UserNotifyProps, UserProfile} from '@mattermost/types/users';
|
||||
|
||||
import AlertBanner from 'components/alert_banner';
|
||||
@ -18,17 +18,17 @@ import ModalSection from 'components/widgets/modals/components/modal_section';
|
||||
import RadioSettingItem from 'components/widgets/modals/components/radio_setting_item';
|
||||
import type {Option} from 'components/widgets/modals/components/react_select_item';
|
||||
|
||||
import {IgnoreChannelMentions, NotificationLevels, DesktopSound} from 'utils/constants';
|
||||
import {getValueOfNotificationSoundsSelect, notificationSoundKeys, stopTryNotificationRing, tryNotificationSound} from 'utils/notification_sounds';
|
||||
import {NotificationLevels, DesktopSound, IgnoreChannelMentions} from 'utils/constants';
|
||||
import {convertDesktopSoundNotifyPropFromUserToDesktop, DesktopNotificationSounds, getValueOfNotificationSoundsSelect, stopTryNotificationRing, tryNotificationSound} from 'utils/notification_sounds';
|
||||
|
||||
import type {ChannelMemberNotifyProps} from './utils';
|
||||
import utils, {convertDesktopSoundNotifyPropFromUserToDesktop} from './utils';
|
||||
import ResetToDefaultButton, {SectionName} from './reset_to_default_button';
|
||||
import utils from './utils';
|
||||
|
||||
import type {PropsFromRedux} from './index';
|
||||
|
||||
import './channel_notifications_modal.scss';
|
||||
|
||||
type Props = PropsFromRedux & {
|
||||
export type Props = PropsFromRedux & {
|
||||
|
||||
/**
|
||||
* Function that is called when the modal has been hidden and should be removed
|
||||
@ -46,74 +46,21 @@ type Props = PropsFromRedux & {
|
||||
currentUser: UserProfile;
|
||||
};
|
||||
|
||||
function getUseSameDesktopSetting(currentUserNotifyProps: UserNotifyProps, channelMemberNotifyProps?: ChannelMemberNotifyProps) {
|
||||
const isSameAsDesktop = channelMemberNotifyProps ? channelMemberNotifyProps?.desktop === channelMemberNotifyProps?.push : currentUserNotifyProps.push === currentUserNotifyProps.desktop;
|
||||
const isSameAsDesktopThreads = channelMemberNotifyProps ? channelMemberNotifyProps?.desktop_threads === channelMemberNotifyProps?.push_threads : currentUserNotifyProps.push_threads === currentUserNotifyProps.desktop_threads;
|
||||
return isSameAsDesktop && isSameAsDesktopThreads;
|
||||
}
|
||||
|
||||
function getStateFromNotifyProps(currentUserNotifyProps: UserNotifyProps, channelMemberNotifyProps?: ChannelMemberNotifyProps) {
|
||||
let ignoreChannelMentionsDefault: ChannelNotifyProps['ignore_channel_mentions'] = IgnoreChannelMentions.OFF;
|
||||
|
||||
if (channelMemberNotifyProps?.mark_unread === NotificationLevels.MENTION || (currentUserNotifyProps.channel && currentUserNotifyProps.channel === 'false')) {
|
||||
ignoreChannelMentionsDefault = IgnoreChannelMentions.ON;
|
||||
}
|
||||
|
||||
let ignoreChannelMentions = channelMemberNotifyProps?.ignore_channel_mentions;
|
||||
if (!ignoreChannelMentions || ignoreChannelMentions === IgnoreChannelMentions.DEFAULT) {
|
||||
ignoreChannelMentions = ignoreChannelMentionsDefault;
|
||||
}
|
||||
|
||||
const desktop = channelMemberNotifyProps?.desktop === NotificationLevels.DEFAULT ? currentUserNotifyProps.desktop : (channelMemberNotifyProps?.desktop || currentUserNotifyProps.desktop);
|
||||
const push = channelMemberNotifyProps?.push === NotificationLevels.DEFAULT ? currentUserNotifyProps.desktop : (channelMemberNotifyProps?.push || currentUserNotifyProps.push);
|
||||
|
||||
let desktopSound;
|
||||
if (channelMemberNotifyProps && channelMemberNotifyProps.desktop_sound) {
|
||||
desktopSound = channelMemberNotifyProps.desktop_sound;
|
||||
} else {
|
||||
desktopSound = convertDesktopSoundNotifyPropFromUserToDesktop(currentUserNotifyProps.desktop_sound);
|
||||
}
|
||||
|
||||
let desktopNotificationSound;
|
||||
if (channelMemberNotifyProps && channelMemberNotifyProps.desktop_notification_sound) {
|
||||
desktopNotificationSound = channelMemberNotifyProps.desktop_notification_sound;
|
||||
} else if (currentUserNotifyProps && currentUserNotifyProps.desktop_notification_sound) {
|
||||
desktopNotificationSound = currentUserNotifyProps.desktop_notification_sound;
|
||||
} else {
|
||||
desktopNotificationSound = notificationSoundKeys[0] as ChannelNotifyProps['desktop_notification_sound'];
|
||||
}
|
||||
|
||||
return {
|
||||
desktop,
|
||||
desktop_threads: channelMemberNotifyProps?.desktop_threads || NotificationLevels.ALL,
|
||||
desktop_sound: desktopSound,
|
||||
desktop_notification_sound: desktopNotificationSound,
|
||||
mark_unread: channelMemberNotifyProps?.mark_unread || NotificationLevels.ALL,
|
||||
push,
|
||||
push_threads: channelMemberNotifyProps?.push_threads || NotificationLevels.ALL,
|
||||
ignore_channel_mentions: ignoreChannelMentions,
|
||||
channel_auto_follow_threads: channelMemberNotifyProps?.channel_auto_follow_threads || 'off',
|
||||
};
|
||||
}
|
||||
|
||||
type SettingsType = {
|
||||
desktop: ChannelNotifyProps['desktop'];
|
||||
desktop_threads: ChannelNotifyProps['desktop_threads'];
|
||||
desktop_sound: ChannelNotifyProps['desktop_sound'];
|
||||
desktop_notification_sound: ChannelNotifyProps['desktop_notification_sound'];
|
||||
mark_unread: ChannelNotifyProps['mark_unread'];
|
||||
push: ChannelNotifyProps['push'];
|
||||
push_threads: ChannelNotifyProps['push_threads'];
|
||||
ignore_channel_mentions: ChannelNotifyProps['ignore_channel_mentions'];
|
||||
channel_auto_follow_threads: ChannelNotifyProps['channel_auto_follow_threads'];
|
||||
};
|
||||
|
||||
export default function ChannelNotificationsModal(props: Props) {
|
||||
const {formatMessage} = useIntl();
|
||||
|
||||
const [show, setShow] = useState(true);
|
||||
const [serverError, setServerError] = useState('');
|
||||
const [mobileSettingsSameAsDesktop, setMobileSettingsSameAsDesktop] = useState<boolean>(getUseSameDesktopSetting(props.currentUser.notify_props, props.channelMember?.notify_props));
|
||||
const [settings, setSettings] = useState<SettingsType>(getStateFromNotifyProps(props.currentUser.notify_props, props.channelMember?.notify_props));
|
||||
|
||||
const [settings, setSettings] = useState(getStateFromNotifyProps(props.currentUser.notify_props, props.channelMember?.notify_props));
|
||||
|
||||
const [desktopAndMobileSettingsDifferent, setDesktopAndMobileSettingDifferent] = useState<boolean>(areDesktopAndMobileSettingsDifferent(
|
||||
props.collapsedReplyThreads,
|
||||
getInitialValuesOfChannelNotifyProps(NotificationLevels.ALL, props?.channelMember?.notify_props?.desktop, props.currentUser.notify_props.desktop),
|
||||
getInitialValuesOfChannelNotifyProps(NotificationLevels.ALL, props?.channelMember?.notify_props?.desktop_threads, props.currentUser.notify_props.desktop_threads),
|
||||
getInitialValuesOfChannelNotifyProps(NotificationLevels.ALL, props?.channelMember?.notify_props?.push, props.currentUser.notify_props.push),
|
||||
getInitialValuesOfChannelNotifyProps(NotificationLevels.ALL, props?.channelMember?.notify_props?.push_threads, props.currentUser.notify_props.push_threads),
|
||||
));
|
||||
|
||||
function handleHide() {
|
||||
setShow(false);
|
||||
@ -123,10 +70,49 @@ export default function ChannelNotificationsModal(props: Props) {
|
||||
setSettings((prevSettings) => ({...prevSettings, ...values}));
|
||||
}, []);
|
||||
|
||||
const handleMobileSettingsChange = useCallback(() => {
|
||||
setMobileSettingsSameAsDesktop((prevSettings) => !prevSettings);
|
||||
setSettings((prevSettings) => ({...prevSettings, push: prevSettings.desktop, push_threads: prevSettings.desktop_threads}));
|
||||
}, []);
|
||||
function handleUseSameMobileSettingsAsDesktopCheckboxChange(value: boolean) {
|
||||
const newValueOfSettings = {...settings};
|
||||
const newValueOfDesktopAndMobileSettingsDifferent = !value;
|
||||
|
||||
if (newValueOfDesktopAndMobileSettingsDifferent === false) {
|
||||
newValueOfSettings.push = settings.desktop;
|
||||
newValueOfSettings.push_threads = settings.desktop_threads;
|
||||
} else {
|
||||
newValueOfSettings.push = getInitialValuesOfChannelNotifyProps(NotificationLevels.ALL, props.channelMember?.notify_props?.push, props.currentUser?.notify_props?.push);
|
||||
newValueOfSettings.push_threads = getInitialValuesOfChannelNotifyProps(NotificationLevels.ALL, props.channelMember?.notify_props?.push_threads, props.currentUser?.notify_props?.push_threads);
|
||||
}
|
||||
setSettings(newValueOfSettings);
|
||||
setDesktopAndMobileSettingDifferent(newValueOfDesktopAndMobileSettingsDifferent);
|
||||
}
|
||||
|
||||
function handleResetToDefaultClicked(channelNotifyPropsDefaultedToUserNotifyProps: ChannelMembership['notify_props'], sectionName: SectionName) {
|
||||
if (sectionName === SectionName.Mobile) {
|
||||
const desktopAndMobileSettingsDifferent = areDesktopAndMobileSettingsDifferent(
|
||||
props.collapsedReplyThreads,
|
||||
settings.desktop,
|
||||
settings.desktop_threads,
|
||||
channelNotifyPropsDefaultedToUserNotifyProps.push,
|
||||
channelNotifyPropsDefaultedToUserNotifyProps.push_threads,
|
||||
);
|
||||
|
||||
setDesktopAndMobileSettingDifferent(desktopAndMobileSettingsDifferent);
|
||||
}
|
||||
|
||||
setSettings({...settings, ...channelNotifyPropsDefaultedToUserNotifyProps});
|
||||
}
|
||||
|
||||
function handleSave() {
|
||||
const channelNotifyProps = createChannelNotifyPropsFromSelectedSettings(props.currentUser.notify_props, settings, desktopAndMobileSettingsDifferent);
|
||||
|
||||
props.actions.updateChannelNotifyProps(props.currentUser.id, props.channel.id, channelNotifyProps).then((value) => {
|
||||
const {error} = value;
|
||||
if (error) {
|
||||
setServerError(error.message);
|
||||
} else {
|
||||
handleHide();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const muteOrIgnoreSectionContent = (
|
||||
<>
|
||||
@ -179,7 +165,7 @@ export default function ChannelNotificationsModal(props: Props) {
|
||||
id: 'channel_notifications.NotifyMeTitle',
|
||||
defaultMessage: 'Notify me about…',
|
||||
})}
|
||||
inputFieldValue={settings.desktop}
|
||||
inputFieldValue={settings.desktop || ''}
|
||||
inputFieldData={utils.desktopNotificationInputFieldData(props.currentUser.notify_props.desktop)}
|
||||
handleChange={(e) => handleChange({desktop: e.target.value})}
|
||||
/>
|
||||
@ -237,23 +223,25 @@ export default function ChannelNotificationsModal(props: Props) {
|
||||
defaultMessage='Use the same notification settings as desktop'
|
||||
/>
|
||||
}
|
||||
inputFieldValue={mobileSettingsSameAsDesktop}
|
||||
inputFieldValue={!desktopAndMobileSettingsDifferent}
|
||||
inputFieldData={utils.sameMobileSettingsDesktopInputFieldData}
|
||||
handleChange={() => handleMobileSettingsChange()}
|
||||
handleChange={handleUseSameMobileSettingsAsDesktopCheckboxChange}
|
||||
/>
|
||||
{!mobileSettingsSameAsDesktop && (
|
||||
{desktopAndMobileSettingsDifferent && (
|
||||
<>
|
||||
<RadioSettingItem
|
||||
dataTestId='mobile-notify-me-radio-section'
|
||||
title={formatMessage({
|
||||
id: 'channel_notifications.NotifyMeTitle',
|
||||
defaultMessage: 'Notify me about…',
|
||||
})}
|
||||
inputFieldValue={settings.push}
|
||||
inputFieldValue={settings.push || ''}
|
||||
inputFieldData={utils.mobileNotificationInputFieldData(props.currentUser.notify_props.push)}
|
||||
handleChange={(e) => handleChange({push: e.target.value})}
|
||||
/>
|
||||
{props.collapsedReplyThreads && settings.push === 'mention' &&
|
||||
<CheckboxSettingItem
|
||||
dataTestId='mobile-reply-threads-checkbox-section'
|
||||
title={formatMessage({
|
||||
id: 'channel_notifications.ThreadsReplyTitle',
|
||||
defaultMessage: 'Thread reply notifications',
|
||||
@ -287,75 +275,6 @@ export default function ChannelNotificationsModal(props: Props) {
|
||||
/>
|
||||
);
|
||||
|
||||
function handleSave() {
|
||||
const userSettings: Partial<SettingsType> = {...settings};
|
||||
if (!props.collapsedReplyThreads) {
|
||||
delete userSettings.push_threads;
|
||||
delete userSettings.desktop_threads;
|
||||
delete userSettings.channel_auto_follow_threads;
|
||||
}
|
||||
props.actions.updateChannelNotifyProps(props.currentUser.id, props.channel.id, userSettings).then((value) => {
|
||||
const {error} = value;
|
||||
if (error) {
|
||||
setServerError(error.message);
|
||||
} else {
|
||||
handleHide();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const resetToDefaultBtn = useCallback((sectionName: string) => {
|
||||
const userNotifyProps = {
|
||||
...props.currentUser.notify_props,
|
||||
desktop_notification_sound: props.currentUser.notify_props?.desktop_notification_sound ?? notificationSoundKeys[0] as ChannelNotifyProps['desktop_notification_sound'],
|
||||
};
|
||||
|
||||
function resetToDefault(sectionName: string) {
|
||||
if (sectionName === 'desktop') {
|
||||
setSettings({
|
||||
...settings,
|
||||
desktop: userNotifyProps.desktop,
|
||||
desktop_threads: userNotifyProps.desktop_threads || settings.desktop_threads,
|
||||
desktop_sound: convertDesktopSoundNotifyPropFromUserToDesktop(userNotifyProps.desktop_sound),
|
||||
desktop_notification_sound: userNotifyProps?.desktop_notification_sound ?? notificationSoundKeys[0] as ChannelNotifyProps['desktop_notification_sound'],
|
||||
});
|
||||
}
|
||||
|
||||
if (sectionName === 'push') {
|
||||
setSettings({...settings, push: userNotifyProps.desktop, push_threads: userNotifyProps.push_threads || settings.push_threads});
|
||||
}
|
||||
}
|
||||
|
||||
const isDesktopSameAsDefault =
|
||||
userNotifyProps.desktop === settings.desktop &&
|
||||
userNotifyProps.desktop_threads === settings.desktop_threads &&
|
||||
userNotifyProps.desktop_notification_sound === settings.desktop_notification_sound &&
|
||||
convertDesktopSoundNotifyPropFromUserToDesktop(userNotifyProps.desktop_sound) === settings.desktop_sound;
|
||||
|
||||
const isPushSameAsDefault = (userNotifyProps.push === settings.push && userNotifyProps.push_threads === settings.push_threads);
|
||||
|
||||
if ((sectionName === 'desktop' && isDesktopSameAsDefault) || (sectionName === 'push' && isPushSameAsDefault)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return (
|
||||
<button
|
||||
className='channel-notifications-settings-modal__reset-btn'
|
||||
onClick={() => resetToDefault(sectionName)}
|
||||
data-testid={`resetToDefaultButton-${sectionName}`}
|
||||
>
|
||||
<RefreshIcon
|
||||
size={14}
|
||||
color={'currentColor'}
|
||||
/>
|
||||
<FormattedMessage
|
||||
id='channel_notifications.resetToDefault'
|
||||
defaultMessage='Reset to default'
|
||||
/>
|
||||
</button>
|
||||
);
|
||||
}, [props.currentUser.notify_props, settings]);
|
||||
|
||||
const desktopAndMobileNotificationSectionContent = settings.mark_unread === 'all' ? (
|
||||
<>
|
||||
<div className='channel-notifications-settings-modal__divider'/>
|
||||
@ -364,7 +283,14 @@ export default function ChannelNotificationsModal(props: Props) {
|
||||
id: 'channel_notifications.desktopNotificationsTitle',
|
||||
defaultMessage: 'Desktop Notifications',
|
||||
})}
|
||||
titleSuffix={resetToDefaultBtn('desktop')}
|
||||
titleSuffix={
|
||||
<ResetToDefaultButton
|
||||
sectionName={SectionName.Desktop}
|
||||
userNotifyProps={props.currentUser.notify_props}
|
||||
userSelectedChannelNotifyProps={settings}
|
||||
onClick={handleResetToDefaultClicked}
|
||||
/>
|
||||
}
|
||||
description={formatMessage({
|
||||
id: 'channel_notifications.desktopNotificationsDesc',
|
||||
defaultMessage: 'Available on Chrome, Edge, Firefox, and the Mattermost Desktop App.',
|
||||
@ -377,7 +303,14 @@ export default function ChannelNotificationsModal(props: Props) {
|
||||
id: 'channel_notifications.mobileNotificationsTitle',
|
||||
defaultMessage: 'Mobile Notifications',
|
||||
})}
|
||||
titleSuffix={resetToDefaultBtn('push')}
|
||||
titleSuffix={
|
||||
<ResetToDefaultButton
|
||||
sectionName={SectionName.Mobile}
|
||||
userNotifyProps={props.currentUser.notify_props}
|
||||
userSelectedChannelNotifyProps={settings}
|
||||
onClick={handleResetToDefaultClicked}
|
||||
/>
|
||||
}
|
||||
description={formatMessage({
|
||||
id: 'channel_notifications.mobileNotificationsDesc',
|
||||
defaultMessage: 'Notification alerts are pushed to your mobile device when there is activity in Mattermost.',
|
||||
@ -485,3 +418,176 @@ export default function ChannelNotificationsModal(props: Props) {
|
||||
);
|
||||
}
|
||||
|
||||
function getStateFromNotifyProps(currentUserNotifyProps: UserNotifyProps, channelMemberNotifyProps?: ChannelMembership['notify_props']): Required<Omit<ChannelMembership['notify_props'], 'email'>> {
|
||||
return {
|
||||
mark_unread: channelMemberNotifyProps?.mark_unread ?? NotificationLevels.ALL,
|
||||
ignore_channel_mentions: getInitialValuesOfIgnoreChannelMentions(channelMemberNotifyProps?.mark_unread, channelMemberNotifyProps?.ignore_channel_mentions, currentUserNotifyProps?.channel),
|
||||
desktop: getInitialValuesOfChannelNotifyProps<ChannelMembership['notify_props']['desktop']>(NotificationLevels.ALL, channelMemberNotifyProps?.desktop, currentUserNotifyProps?.desktop),
|
||||
desktop_threads: getInitialValuesOfChannelNotifyProps<ChannelMembership['notify_props']['desktop_threads']>(NotificationLevels.ALL, channelMemberNotifyProps?.desktop_threads, currentUserNotifyProps?.desktop_threads),
|
||||
desktop_sound: getInitialValuesOfChannelNotifyProps<ChannelMembership['notify_props']['desktop_sound']>(DesktopSound.ON, channelMemberNotifyProps?.desktop_sound, convertDesktopSoundNotifyPropFromUserToDesktop(currentUserNotifyProps?.desktop_sound)),
|
||||
desktop_notification_sound: getInitialValuesOfChannelNotifyProps<ChannelMembership['notify_props']['desktop_notification_sound']>(DesktopNotificationSounds.BING, channelMemberNotifyProps?.desktop_notification_sound, currentUserNotifyProps?.desktop_notification_sound),
|
||||
push: getInitialValuesOfChannelNotifyProps<ChannelMembership['notify_props']['push']>(NotificationLevels.ALL, channelMemberNotifyProps?.push, currentUserNotifyProps?.push),
|
||||
push_threads: getInitialValuesOfChannelNotifyProps<ChannelMembership['notify_props']['push_threads']>(NotificationLevels.ALL, channelMemberNotifyProps?.push_threads, currentUserNotifyProps?.push_threads),
|
||||
channel_auto_follow_threads: channelMemberNotifyProps?.channel_auto_follow_threads ?? 'off',
|
||||
};
|
||||
}
|
||||
|
||||
export function getInitialValuesOfChannelNotifyProps<KeyInNotifyProps>(defaultValue: NonNullable<KeyInNotifyProps>, channelMemberNotifyProp: KeyInNotifyProps | undefined = undefined, userNotifyProp: KeyInNotifyProps | undefined = undefined) {
|
||||
let value = defaultValue;
|
||||
|
||||
// Check if channel_member's notify_prop is defined for the selected notify_prop
|
||||
if (channelMemberNotifyProp) {
|
||||
// If channel_member's notify_prop is default and user's notify_prop is defined, we should use user's notify_prop
|
||||
if (channelMemberNotifyProp === NotificationLevels.DEFAULT && userNotifyProp) {
|
||||
value = userNotifyProp;
|
||||
} else {
|
||||
// Otherwise, we should use channel_member's notify_prop as is
|
||||
value = channelMemberNotifyProp;
|
||||
}
|
||||
} else if (userNotifyProp) {
|
||||
// If channel_member's notify_prop is not defined and user's notify_prop is defined, we should use user's notify_prop as is
|
||||
value = userNotifyProp;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
export function getInitialValuesOfIgnoreChannelMentions(
|
||||
markUnread: ChannelMembership['notify_props']['mark_unread'],
|
||||
ignoreChannelMentions: ChannelMembership['notify_props']['ignore_channel_mentions'],
|
||||
userNotifyPropForChannel: UserNotifyProps['channel'],
|
||||
): NonNullable<ChannelMembership['notify_props']['ignore_channel_mentions']> {
|
||||
let ignoreChannelMentionsDefault: ChannelNotifyProps['ignore_channel_mentions'] = IgnoreChannelMentions.OFF;
|
||||
if (markUnread === NotificationLevels.MENTION || (userNotifyPropForChannel && userNotifyPropForChannel === 'false')) {
|
||||
ignoreChannelMentionsDefault = IgnoreChannelMentions.ON;
|
||||
}
|
||||
|
||||
if (ignoreChannelMentions) {
|
||||
if (ignoreChannelMentions === IgnoreChannelMentions.DEFAULT) {
|
||||
return ignoreChannelMentionsDefault;
|
||||
}
|
||||
return ignoreChannelMentions;
|
||||
}
|
||||
|
||||
return ignoreChannelMentionsDefault;
|
||||
}
|
||||
|
||||
export function createChannelNotifyPropsFromSelectedSettings(
|
||||
userNotifyProps: UserNotifyProps,
|
||||
savedChannelNotifyProps: ChannelMembership['notify_props'],
|
||||
desktopAndMobileSettingsDifferent: boolean,
|
||||
) {
|
||||
const channelNotifyProps: ChannelMembership['notify_props'] = {
|
||||
mark_unread: savedChannelNotifyProps.mark_unread,
|
||||
ignore_channel_mentions: savedChannelNotifyProps.ignore_channel_mentions,
|
||||
channel_auto_follow_threads: savedChannelNotifyProps.channel_auto_follow_threads,
|
||||
};
|
||||
|
||||
if (savedChannelNotifyProps.desktop === userNotifyProps.desktop) {
|
||||
channelNotifyProps.desktop = NotificationLevels.DEFAULT;
|
||||
} else {
|
||||
channelNotifyProps.desktop = savedChannelNotifyProps.desktop;
|
||||
}
|
||||
|
||||
// Check if USER's desktop_thread setting are defined
|
||||
if (userNotifyProps?.desktop_threads?.length) {
|
||||
// If USER's desktop_thread setting is same as CHANNEL's new desktop_threads setting, we should set it to default
|
||||
if (userNotifyProps.desktop_threads === savedChannelNotifyProps.desktop_threads) {
|
||||
channelNotifyProps.desktop_threads = NotificationLevels.DEFAULT;
|
||||
} else {
|
||||
// Otherwise, we should use the CHANNEL's new desktop_threads setting as is
|
||||
channelNotifyProps.desktop_threads = savedChannelNotifyProps.desktop_threads;
|
||||
}
|
||||
} else if (savedChannelNotifyProps.desktop_threads === NotificationLevels.MENTION || savedChannelNotifyProps.desktop_threads === NotificationLevels.DEFAULT) {
|
||||
// If USER's desktop_thread setting is not defined and CHANNEL's new desktop_threads setting is MENTION or DEFAULT, then save it as default
|
||||
channelNotifyProps.desktop_threads = NotificationLevels.DEFAULT;
|
||||
} else {
|
||||
// Otherwise, we should use the CHANNEL's new desktop_threads setting as is
|
||||
channelNotifyProps.desktop_threads = savedChannelNotifyProps.desktop_threads;
|
||||
}
|
||||
|
||||
if (convertDesktopSoundNotifyPropFromUserToDesktop(userNotifyProps?.desktop_sound) === savedChannelNotifyProps.desktop_sound) {
|
||||
channelNotifyProps.desktop_sound = DesktopSound.DEFAULT;
|
||||
} else {
|
||||
channelNotifyProps.desktop_sound = savedChannelNotifyProps.desktop_sound;
|
||||
}
|
||||
|
||||
// Check if USER's desktop_notification_sound setting is defined
|
||||
if (userNotifyProps?.desktop_notification_sound?.length) {
|
||||
// If USER's desktop_notification_sound setting is same as CHANNEL's new desktop_notification_sound setting, we should set it to default
|
||||
if (userNotifyProps.desktop_notification_sound === savedChannelNotifyProps.desktop_notification_sound) {
|
||||
channelNotifyProps.desktop_notification_sound = DesktopNotificationSounds.DEFAULT;
|
||||
} else {
|
||||
// Otherwise, we should use the CHANNEL's new desktop_notification_sound setting as is
|
||||
channelNotifyProps.desktop_notification_sound = savedChannelNotifyProps.desktop_notification_sound;
|
||||
}
|
||||
} else if (savedChannelNotifyProps.desktop_notification_sound === DesktopNotificationSounds.BING || savedChannelNotifyProps.desktop_notification_sound === DesktopNotificationSounds.DEFAULT) {
|
||||
// If USER's desktop_notification_sound setting is not defined and CHANNEL's new desktop_notification_sound setting is either BING or DEFAULT, then save it as default
|
||||
channelNotifyProps.desktop_notification_sound = DesktopNotificationSounds.DEFAULT;
|
||||
} else {
|
||||
// Otherwise, we should use the CHANNEL's new desktop_notification_sound setting as is
|
||||
channelNotifyProps.desktop_notification_sound = savedChannelNotifyProps.desktop_notification_sound;
|
||||
}
|
||||
|
||||
if (savedChannelNotifyProps.push === userNotifyProps.push) {
|
||||
channelNotifyProps.push = NotificationLevels.DEFAULT;
|
||||
} else {
|
||||
channelNotifyProps.push = savedChannelNotifyProps.push;
|
||||
}
|
||||
|
||||
// Check if USER's push_threads setting are defined
|
||||
if (userNotifyProps?.push_threads?.length) {
|
||||
// If USER's push_threads setting is same as CHANNEL's new push_threads setting, we should set it to default
|
||||
if (userNotifyProps.push_threads === savedChannelNotifyProps.push_threads) {
|
||||
channelNotifyProps.push_threads = NotificationLevels.DEFAULT;
|
||||
} else {
|
||||
// Otherwise, we should use the CHANNEL's new push_threads setting as is
|
||||
channelNotifyProps.push_threads = savedChannelNotifyProps.push_threads;
|
||||
}
|
||||
} else if (savedChannelNotifyProps.push_threads === NotificationLevels.MENTION || savedChannelNotifyProps.push_threads === NotificationLevels.DEFAULT) {
|
||||
// If USER's push_threads setting is not defined and CHANNEL's new push_threads setting is MENTION or DEFAULT, then save it as default
|
||||
channelNotifyProps.push_threads = NotificationLevels.DEFAULT;
|
||||
} else {
|
||||
// Otherwise, we should use the CHANNEL's new push_threads setting as is
|
||||
channelNotifyProps.push_threads = savedChannelNotifyProps.push_threads;
|
||||
}
|
||||
|
||||
// If desktop and mobile settings are checked to be same, then same settings should be applied to push and push_threads
|
||||
// as that of desktop and desktop_threads
|
||||
if (desktopAndMobileSettingsDifferent === false) {
|
||||
// If desktop is set to default, it means it is synced to the user's notification settings.
|
||||
// Since we checked the box to use the same settings for mobile, we need to set channel's mobile to match channel's desktop.
|
||||
// Setting mobile to default would sync it to the user's notification settings, which we want to avoid.
|
||||
if (channelNotifyProps.desktop === NotificationLevels.DEFAULT) {
|
||||
channelNotifyProps.push = userNotifyProps.desktop;
|
||||
} else {
|
||||
// Otherwise, we should use the CHANNEL's desktop setting as is to match mobile settings
|
||||
channelNotifyProps.push = channelNotifyProps.desktop;
|
||||
}
|
||||
|
||||
if (channelNotifyProps.desktop_threads === NotificationLevels.DEFAULT) {
|
||||
channelNotifyProps.push_threads = userNotifyProps.desktop_threads;
|
||||
} else {
|
||||
channelNotifyProps.push_threads = channelNotifyProps.desktop_threads;
|
||||
}
|
||||
}
|
||||
|
||||
return channelNotifyProps;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check's if channel's notification settings for desktop and mobile are different
|
||||
*/
|
||||
export function areDesktopAndMobileSettingsDifferent(
|
||||
isCollapsedThreadsEnabled: boolean,
|
||||
desktop: UserNotifyProps['desktop'],
|
||||
desktopThreads: UserNotifyProps['desktop_threads'],
|
||||
push?: UserNotifyProps['push'],
|
||||
pushThreads?: UserNotifyProps['push_threads'],
|
||||
): boolean {
|
||||
if (push === NotificationLevels.DEFAULT || push === desktop) {
|
||||
return isCollapsedThreadsEnabled && desktopThreads !== pushThreads;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -0,0 +1,15 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`ResetToDefaultButton should render if section name is valid 1`] = `
|
||||
<div>
|
||||
<button
|
||||
class="channel-notifications-settings-modal__reset-btn"
|
||||
data-testid="resetToDefaultButton-desktop"
|
||||
>
|
||||
<i
|
||||
class="icon icon-refresh"
|
||||
/>
|
||||
Reset to default
|
||||
</button>
|
||||
</div>
|
||||
`;
|
@ -0,0 +1,173 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import type {ChannelMembership} from '@mattermost/types/channels';
|
||||
import type {UserNotifyProps} from '@mattermost/types/users';
|
||||
|
||||
import {renderWithContext, screen} from 'tests/react_testing_utils';
|
||||
import {NotificationLevels, DesktopSound} from 'utils/constants';
|
||||
import {notificationSoundKeys, convertDesktopSoundNotifyPropFromUserToDesktop} from 'utils/notification_sounds';
|
||||
import {TestHelper} from 'utils/test_helper';
|
||||
|
||||
import ResetToDefaultButton, {SectionName} from './index';
|
||||
import type {Props} from './index';
|
||||
|
||||
describe('ResetToDefaultButton', () => {
|
||||
const defaultProps: Props = {
|
||||
sectionName: SectionName.Desktop,
|
||||
userNotifyProps: TestHelper.getUserMock().notify_props,
|
||||
userSelectedChannelNotifyProps: TestHelper.getChannelMembershipMock({}).notify_props,
|
||||
onClick: jest.fn(),
|
||||
};
|
||||
|
||||
test('should not show if section name is not valid', () => {
|
||||
// Mock console.error to suppress PropTypes warning
|
||||
const originalError = console.error;
|
||||
console.error = jest.fn();
|
||||
|
||||
const props = {
|
||||
...defaultProps,
|
||||
sectionName: 'invalidSectionName' as any,
|
||||
};
|
||||
|
||||
const {container} = renderWithContext(<ResetToDefaultButton {...props}/>);
|
||||
expect(container).toBeEmptyDOMElement();
|
||||
|
||||
console.error = originalError;
|
||||
});
|
||||
|
||||
test('should render if section name is valid', () => {
|
||||
const {container} = renderWithContext(<ResetToDefaultButton {...defaultProps}/>);
|
||||
expect(container).not.toBeEmptyDOMElement();
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('should not show if desktop notifications are same as default user notification settings', () => {
|
||||
const props = {
|
||||
...defaultProps,
|
||||
userNotifyProps: {
|
||||
...defaultProps.userNotifyProps,
|
||||
desktop: NotificationLevels.ALL,
|
||||
desktop_threads: NotificationLevels.ALL,
|
||||
desktop_sound: 'true' as UserNotifyProps['desktop_sound'],
|
||||
desktop_notification_sound: notificationSoundKeys[0] as UserNotifyProps['desktop_notification_sound'],
|
||||
},
|
||||
userSelectedChannelNotifyProps: {
|
||||
...defaultProps.userSelectedChannelNotifyProps,
|
||||
desktop: NotificationLevels.ALL,
|
||||
desktop_threads: NotificationLevels.ALL,
|
||||
desktop_sound: DesktopSound.ON,
|
||||
desktop_notification_sound: notificationSoundKeys[0] as ChannelMembership['notify_props']['desktop_notification_sound'],
|
||||
},
|
||||
};
|
||||
|
||||
const {container} = renderWithContext(<ResetToDefaultButton {...props}/>);
|
||||
expect(container).toBeEmptyDOMElement();
|
||||
});
|
||||
|
||||
test('should show if desktop notifications are not same as user notification settings', () => {
|
||||
const props1 = {
|
||||
...defaultProps,
|
||||
userNotifyProps: {
|
||||
...defaultProps.userNotifyProps,
|
||||
desktop: NotificationLevels.ALL,
|
||||
desktop_threads: NotificationLevels.ALL,
|
||||
desktop_sound: 'true' as UserNotifyProps['desktop_sound'],
|
||||
desktop_notification_sound: notificationSoundKeys[0] as UserNotifyProps['desktop_notification_sound'],
|
||||
},
|
||||
userSelectedChannelNotifyProps: {
|
||||
...defaultProps.userSelectedChannelNotifyProps,
|
||||
desktop: NotificationLevels.MENTION,
|
||||
desktop_threads: NotificationLevels.ALL,
|
||||
desktop_sound: DesktopSound.ON,
|
||||
},
|
||||
};
|
||||
|
||||
const {rerender} = renderWithContext(<ResetToDefaultButton {...props1}/>);
|
||||
expect(screen.getByText('Reset to default')).toBeInTheDocument();
|
||||
|
||||
const props2 = {
|
||||
...props1,
|
||||
userSelectedChannelNotifyProps: {
|
||||
...defaultProps.userSelectedChannelNotifyProps,
|
||||
desktop: NotificationLevels.ALL,
|
||||
desktop_sound: DesktopSound.OFF,
|
||||
desktop_notification_sound: notificationSoundKeys[0] as UserNotifyProps['desktop_notification_sound'],
|
||||
},
|
||||
};
|
||||
|
||||
rerender(<ResetToDefaultButton {...props2}/>);
|
||||
expect(screen.getByText('Reset to default')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
test('should not show if mobile notifications are same as default user notification settings', () => {
|
||||
const props = {
|
||||
...defaultProps,
|
||||
sectionName: SectionName.Mobile,
|
||||
userNotifyProps: {
|
||||
...defaultProps.userNotifyProps,
|
||||
push: NotificationLevels.ALL,
|
||||
push_threads: NotificationLevels.ALL,
|
||||
},
|
||||
userSelectedChannelNotifyProps: {
|
||||
...defaultProps.userSelectedChannelNotifyProps,
|
||||
push: NotificationLevels.ALL,
|
||||
push_threads: NotificationLevels.ALL,
|
||||
},
|
||||
};
|
||||
|
||||
const {container} = renderWithContext(<ResetToDefaultButton {...props}/>);
|
||||
expect(container).toBeEmptyDOMElement();
|
||||
});
|
||||
|
||||
test('should show if mobile notifications are not same as user notification settings', () => {
|
||||
const props = {
|
||||
...defaultProps,
|
||||
sectionName: SectionName.Mobile,
|
||||
userNotifyProps: {
|
||||
...defaultProps.userNotifyProps,
|
||||
push: NotificationLevels.ALL,
|
||||
push_threads: NotificationLevels.ALL,
|
||||
},
|
||||
userSelectedChannelNotifyProps: {
|
||||
...defaultProps.userSelectedChannelNotifyProps,
|
||||
push: NotificationLevels.MENTION,
|
||||
push_threads: NotificationLevels.ALL,
|
||||
},
|
||||
};
|
||||
|
||||
const {rerender} = renderWithContext(<ResetToDefaultButton {...props}/>);
|
||||
expect(screen.getByText('Reset to default')).toBeInTheDocument();
|
||||
|
||||
const props2 = {
|
||||
...defaultProps,
|
||||
userSelectedChannelNotifyProps: {
|
||||
...defaultProps.userSelectedChannelNotifyProps,
|
||||
push: NotificationLevels.ALL,
|
||||
push_threads: NotificationLevels.MENTION,
|
||||
},
|
||||
};
|
||||
|
||||
rerender(<ResetToDefaultButton {...props2}/>);
|
||||
expect(screen.getByText('Reset to default')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
describe('convertDesktopSoundNotifyPropFromUserToDesktop', () => {
|
||||
test('should return ON if user desktop sound is true', () => {
|
||||
const desktopSound = convertDesktopSoundNotifyPropFromUserToDesktop('true');
|
||||
expect(desktopSound).toBe(DesktopSound.ON);
|
||||
});
|
||||
|
||||
test('should return ON if user desktop sound is not present', () => {
|
||||
const desktopSound = convertDesktopSoundNotifyPropFromUserToDesktop();
|
||||
expect(desktopSound).toBe(DesktopSound.ON);
|
||||
});
|
||||
|
||||
test('should return OFF if user desktop sound is false', () => {
|
||||
const desktopSound = convertDesktopSoundNotifyPropFromUserToDesktop('false');
|
||||
expect(desktopSound).toBe(DesktopSound.OFF);
|
||||
});
|
||||
});
|
@ -0,0 +1,117 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import React, {useMemo} from 'react';
|
||||
import {FormattedMessage} from 'react-intl';
|
||||
|
||||
import type {ChannelMembership, ChannelNotifyProps} from '@mattermost/types/channels';
|
||||
import type {UserNotifyProps, UserProfile} from '@mattermost/types/users';
|
||||
|
||||
import {DesktopSound, NotificationLevels} from 'utils/constants';
|
||||
import {notificationSoundKeys, convertDesktopSoundNotifyPropFromUserToDesktop} from 'utils/notification_sounds';
|
||||
|
||||
export enum SectionName {
|
||||
Desktop = 'desktop',
|
||||
Mobile = 'mobile',
|
||||
}
|
||||
|
||||
const VALID_SECTION_NAMES = Object.values(SectionName);
|
||||
|
||||
export interface Props {
|
||||
sectionName: SectionName;
|
||||
userNotifyProps: UserProfile['notify_props'];
|
||||
|
||||
/** The user's selected channel notify props which is not yet saved */
|
||||
userSelectedChannelNotifyProps: ChannelMembership['notify_props'];
|
||||
onClick: (channelNotifyPropsDefaultedToUserNotifyProps: ChannelMembership['notify_props'], sectionName: SectionName) => void;
|
||||
}
|
||||
|
||||
export default function ResetToDefaultButton(props: Props) {
|
||||
const areDesktopNotificationsSameAsDefault = useMemo(() => {
|
||||
const isNotifyMeAboutSame = props.userNotifyProps.desktop === props.userSelectedChannelNotifyProps.desktop;
|
||||
const isThreadReplyNotificationsSame = props.userNotifyProps.desktop_threads === props.userSelectedChannelNotifyProps.desktop_threads;
|
||||
const isSoundSame = convertDesktopSoundNotifyPropFromUserToDesktop(props.userNotifyProps.desktop_sound) === props.userSelectedChannelNotifyProps.desktop_sound;
|
||||
|
||||
let isNotificationSoundSame = false;
|
||||
if (props.userNotifyProps.desktop_notification_sound) {
|
||||
isNotificationSoundSame = props.userNotifyProps.desktop_notification_sound === props.userSelectedChannelNotifyProps.desktop_notification_sound;
|
||||
} else {
|
||||
// It could happen that the notification sound is not set in the user's notify props. That case we should assume its the Bing sound.
|
||||
isNotificationSoundSame = props.userSelectedChannelNotifyProps.desktop_notification_sound === notificationSoundKeys[0] as ChannelNotifyProps['desktop_notification_sound'];
|
||||
}
|
||||
|
||||
return isNotifyMeAboutSame && isThreadReplyNotificationsSame && isSoundSame && isNotificationSoundSame;
|
||||
}, [
|
||||
props.userNotifyProps.desktop,
|
||||
props.userSelectedChannelNotifyProps.desktop,
|
||||
props.userNotifyProps.desktop_threads,
|
||||
props.userSelectedChannelNotifyProps.desktop_threads,
|
||||
props.userNotifyProps.desktop_sound,
|
||||
props.userSelectedChannelNotifyProps.desktop_sound,
|
||||
props.userNotifyProps.desktop_notification_sound,
|
||||
props.userSelectedChannelNotifyProps.desktop_notification_sound,
|
||||
]);
|
||||
|
||||
const areMobileNotificationsSameAsDefault = useMemo(() => {
|
||||
const isNotifyMeAboutSame = props.userNotifyProps.push === props.userSelectedChannelNotifyProps.push;
|
||||
const isThreadReplyNotificationsSame = props.userNotifyProps.push_threads === props.userSelectedChannelNotifyProps.push_threads;
|
||||
|
||||
return isNotifyMeAboutSame && isThreadReplyNotificationsSame;
|
||||
}, [
|
||||
props.userNotifyProps.push,
|
||||
props.userSelectedChannelNotifyProps.push,
|
||||
props.userNotifyProps.push_threads,
|
||||
props.userSelectedChannelNotifyProps.push_threads,
|
||||
]);
|
||||
|
||||
if (!VALID_SECTION_NAMES.includes(props.sectionName)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (props.sectionName === SectionName.Desktop && areDesktopNotificationsSameAsDefault) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (props.sectionName === SectionName.Mobile && areMobileNotificationsSameAsDefault) {
|
||||
return null;
|
||||
}
|
||||
|
||||
function handleOnClick() {
|
||||
const channelNotifyPropsDefaultedToUserNotifyProps = resetChannelsNotificationToUsersDefault(props.userNotifyProps, props.sectionName);
|
||||
props.onClick(channelNotifyPropsDefaultedToUserNotifyProps, props.sectionName);
|
||||
}
|
||||
|
||||
return (
|
||||
<button
|
||||
className='channel-notifications-settings-modal__reset-btn'
|
||||
onClick={handleOnClick}
|
||||
data-testid={`resetToDefaultButton-${props.sectionName}`}
|
||||
>
|
||||
<i className='icon icon-refresh'/>
|
||||
<FormattedMessage
|
||||
id='channel_notifications.resetToDefault'
|
||||
defaultMessage='Reset to default'
|
||||
/>
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
export function resetChannelsNotificationToUsersDefault(userNotifyProps: UserNotifyProps, sectionName: SectionName): ChannelMembership['notify_props'] {
|
||||
if (sectionName === SectionName.Desktop) {
|
||||
return {
|
||||
desktop: userNotifyProps.desktop,
|
||||
desktop_threads: userNotifyProps?.desktop_threads ?? NotificationLevels.ALL,
|
||||
desktop_sound: userNotifyProps && userNotifyProps.desktop_sound ? convertDesktopSoundNotifyPropFromUserToDesktop(userNotifyProps.desktop_sound) : DesktopSound.ON,
|
||||
desktop_notification_sound: userNotifyProps?.desktop_notification_sound ?? notificationSoundKeys[0] as ChannelNotifyProps['desktop_notification_sound'],
|
||||
};
|
||||
}
|
||||
|
||||
if (sectionName === SectionName.Mobile) {
|
||||
return {
|
||||
push: userNotifyProps.push,
|
||||
push_threads: userNotifyProps?.push_threads ?? NotificationLevels.ALL,
|
||||
};
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
@ -4,18 +4,13 @@
|
||||
import React from 'react';
|
||||
import {FormattedMessage} from 'react-intl';
|
||||
|
||||
import type {ChannelNotifyProps} from '@mattermost/types/channels';
|
||||
import type {UserNotifyProps} from '@mattermost/types/users';
|
||||
|
||||
import type {FieldsetCheckbox} from 'components/widgets/modals/components/checkbox_setting_item';
|
||||
import type {FieldsetRadio} from 'components/widgets/modals/components/radio_setting_item';
|
||||
import type {FieldsetReactSelect} from 'components/widgets/modals/components/react_select_item';
|
||||
|
||||
import {DesktopSound, NotificationLevels} from 'utils/constants';
|
||||
import {NotificationLevels} from 'utils/constants';
|
||||
import {optionsOfMessageNotificationSoundsSelect} from 'utils/notification_sounds';
|
||||
|
||||
export type ChannelMemberNotifyProps = Partial<ChannelNotifyProps> & Pick<UserNotifyProps, 'desktop_threads' | 'push_threads'>
|
||||
|
||||
const MuteChannelInputFieldData: FieldsetCheckbox = {
|
||||
name: 'mute channel',
|
||||
dataTestId: 'muteChannel',
|
||||
@ -53,52 +48,58 @@ export const desktopNotificationInputFieldData = (defaultOption: string): Fields
|
||||
dataTestId: `desktopNotification-${NotificationLevels.ALL}`,
|
||||
title: (
|
||||
<FormattedMessage
|
||||
id='channel_notifications.desktopNotificationAllLabel'
|
||||
defaultMessage='All new messages'
|
||||
id='channelNotifications.desktopNotification.allMessages'
|
||||
defaultMessage='All new messages {optionalDefault}'
|
||||
values={{
|
||||
optionalDefault: defaultOption === NotificationLevels.ALL ? (
|
||||
<FormattedMessage
|
||||
id='channel_notifications.default'
|
||||
defaultMessage='(default)'
|
||||
/>) : undefined,
|
||||
}}
|
||||
/>
|
||||
),
|
||||
name: `desktopNotification-${NotificationLevels.ALL}`,
|
||||
key: `desktopNotification-${NotificationLevels.ALL}`,
|
||||
value: NotificationLevels.ALL,
|
||||
suffix: defaultOption === NotificationLevels.ALL ? (
|
||||
<FormattedMessage
|
||||
id='channel_notifications.default'
|
||||
defaultMessage='(default)'
|
||||
/>) : undefined,
|
||||
},
|
||||
{
|
||||
dataTestId: `desktopNotification-${NotificationLevels.MENTION}`,
|
||||
title: (
|
||||
<FormattedMessage
|
||||
id='channel_notifications.desktopNotificationMentionLabel'
|
||||
defaultMessage='Mentions, direct messages, and keywords only'
|
||||
id='channelNotifications.desktopNotification.mention'
|
||||
defaultMessage='Mentions, direct messages, and keywords only {optionalDefault}'
|
||||
values={{
|
||||
optionalDefault: defaultOption === NotificationLevels.MENTION ? (
|
||||
<FormattedMessage
|
||||
id='channel_notifications.default'
|
||||
defaultMessage='(default)'
|
||||
/>) : undefined,
|
||||
}}
|
||||
/>
|
||||
),
|
||||
name: `desktopNotification-${NotificationLevels.MENTION}`,
|
||||
key: `desktopNotification-${NotificationLevels.MENTION}`,
|
||||
value: NotificationLevels.MENTION,
|
||||
suffix: defaultOption === NotificationLevels.MENTION ? (
|
||||
<FormattedMessage
|
||||
id='channel_notifications.default'
|
||||
defaultMessage='(default)'
|
||||
/>) : undefined,
|
||||
},
|
||||
{
|
||||
dataTestId: `desktopNotification-${NotificationLevels.NONE}`,
|
||||
title: (
|
||||
<FormattedMessage
|
||||
id='channel_notifications.desktopNotificationNothingLabel'
|
||||
defaultMessage='Nothing'
|
||||
id='channelNotifications.desktopNotification.nothing'
|
||||
defaultMessage='Nothing {optionalDefault}'
|
||||
values={{
|
||||
optionalDefault: defaultOption === NotificationLevels.NONE ? (
|
||||
<FormattedMessage
|
||||
id='channel_notifications.default'
|
||||
defaultMessage='(default)'
|
||||
/>) : undefined,
|
||||
}}
|
||||
/>
|
||||
),
|
||||
name: `desktopNotification-${NotificationLevels.NONE}`,
|
||||
key: `desktopNotification-${NotificationLevels.NONE}`,
|
||||
value: NotificationLevels.NONE,
|
||||
suffix: defaultOption === NotificationLevels.NONE ? (
|
||||
<FormattedMessage
|
||||
id='channel_notifications.default'
|
||||
defaultMessage='(default)'
|
||||
/>) : undefined,
|
||||
},
|
||||
],
|
||||
};
|
||||
@ -122,74 +123,64 @@ export const mobileNotificationInputFieldData = (defaultOption: string): Fieldse
|
||||
dataTestId: `MobileNotification-${NotificationLevels.ALL}`,
|
||||
title: (
|
||||
<FormattedMessage
|
||||
id='channel_notifications.MobileNotificationAllLabel'
|
||||
defaultMessage='All new messages'
|
||||
id='channelNotifications.mobileNotification.newMessages'
|
||||
defaultMessage='All new messages {optionalDefault}'
|
||||
values={{
|
||||
optionalDefault: defaultOption === NotificationLevels.ALL ? (
|
||||
<FormattedMessage
|
||||
id='channel_notifications.default'
|
||||
defaultMessage='(default)'
|
||||
/>) : undefined,
|
||||
}}
|
||||
/>
|
||||
),
|
||||
name: `MobileNotification-${NotificationLevels.ALL}`,
|
||||
key: `MobileNotification-${NotificationLevels.ALL}`,
|
||||
value: NotificationLevels.ALL,
|
||||
suffix: defaultOption === NotificationLevels.ALL ? (
|
||||
<FormattedMessage
|
||||
id='channel_notifications.default'
|
||||
defaultMessage='(default)'
|
||||
/>) : undefined,
|
||||
},
|
||||
{
|
||||
dataTestId: `MobileNotification-${NotificationLevels.MENTION}`,
|
||||
title: (
|
||||
<FormattedMessage
|
||||
id='channel_notifications.MobileNotificationMentionLabel'
|
||||
defaultMessage='Mentions, direct messages, and keywords only'
|
||||
id='channelNotifications.mobileNotification.mention'
|
||||
defaultMessage='Mentions, direct messages, and keywords only {optionalDefault}'
|
||||
values={{
|
||||
optionalDefault: defaultOption === NotificationLevels.MENTION ? (
|
||||
<FormattedMessage
|
||||
id='channel_notifications.default'
|
||||
defaultMessage='(default)'
|
||||
/>) : undefined,
|
||||
}}
|
||||
/>
|
||||
),
|
||||
name: `MobileNotification-${NotificationLevels.MENTION}`,
|
||||
key: `MobileNotification-${NotificationLevels.MENTION}`,
|
||||
value: NotificationLevels.MENTION,
|
||||
suffix: defaultOption === NotificationLevels.MENTION ? (
|
||||
<FormattedMessage
|
||||
id='channel_notifications.default'
|
||||
defaultMessage='(default)'
|
||||
/>) : undefined,
|
||||
},
|
||||
{
|
||||
dataTestId: `MobileNotification-${NotificationLevels.NONE}`,
|
||||
title: (
|
||||
<FormattedMessage
|
||||
id='channel_notifications.MobileNotificationNothingLabel'
|
||||
defaultMessage='Nothing'
|
||||
id='channelNotifications.mobileNotification.nothing'
|
||||
defaultMessage='Nothing {optionalDefault}'
|
||||
values={{
|
||||
optionalDefault: defaultOption === NotificationLevels.NONE ? (
|
||||
<FormattedMessage
|
||||
id='channel_notifications.default'
|
||||
defaultMessage='(default)'
|
||||
/>) : undefined,
|
||||
}}
|
||||
/>
|
||||
),
|
||||
name: `MobileNotification-${NotificationLevels.NONE}`,
|
||||
key: `MobileNotification-${NotificationLevels.NONE}`,
|
||||
value: NotificationLevels.NONE,
|
||||
suffix: defaultOption === NotificationLevels.NONE ? (
|
||||
<FormattedMessage
|
||||
id='channel_notifications.default'
|
||||
defaultMessage='(default)'
|
||||
/>) : undefined,
|
||||
},
|
||||
],
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* This conversion is needed because User's preference for desktop sound is stored as either true or false. On the other hand,
|
||||
* Channel's specific desktop sound is stored as either On or Off.
|
||||
*/
|
||||
export function convertDesktopSoundNotifyPropFromUserToDesktop(userNotifyDesktopSound?: UserNotifyProps['desktop_sound']) {
|
||||
if (!userNotifyDesktopSound) {
|
||||
return DesktopSound.OFF;
|
||||
}
|
||||
|
||||
if (userNotifyDesktopSound === 'true') {
|
||||
return DesktopSound.ON;
|
||||
}
|
||||
|
||||
return DesktopSound.ON;
|
||||
}
|
||||
|
||||
const utils = {
|
||||
export default {
|
||||
desktopNotificationInputFieldData,
|
||||
desktopNotificationSoundsCheckboxFieldData,
|
||||
desktopNotificationSoundsSelectFieldData,
|
||||
@ -201,5 +192,3 @@ const utils = {
|
||||
AutoFollowThreadsInputFieldData,
|
||||
sameMobileSettingsDesktopInputFieldData,
|
||||
};
|
||||
|
||||
export default utils;
|
||||
|
@ -429,7 +429,7 @@ class NotificationsTab extends React.PureComponent<Props, State> {
|
||||
}
|
||||
};
|
||||
|
||||
handleChangeForCustomKeysWithHightlightInput = (values: ValueType<{ value: string }>) => {
|
||||
handleChangeForCustomKeysWithHighlightInput = (values: ValueType<{ value: string }>) => {
|
||||
if (values && Array.isArray(values) && values.length > 0) {
|
||||
const customKeysWithHighlight = values.
|
||||
map((value: MultiInputValue) => {
|
||||
@ -682,7 +682,7 @@ class NotificationsTab extends React.PureComponent<Props, State> {
|
||||
MenuList: () => null,
|
||||
}}
|
||||
aria-labelledby='mentionKeysWithHighlightInput'
|
||||
onChange={this.handleChangeForCustomKeysWithHightlightInput}
|
||||
onChange={this.handleChangeForCustomKeysWithHighlightInput}
|
||||
value={this.state.customKeysWithHighlight}
|
||||
inputValue={this.state.customKeysWithHighlightInputValue}
|
||||
onInputChange={this.handleChangeForCustomKeysWithHighlightInputValue}
|
||||
@ -1142,9 +1142,12 @@ const customKeywordsSelectorStyles: ReactSelectStyles = {
|
||||
|
||||
const validNotificationLevels = Object.values(NotificationLevels);
|
||||
|
||||
/**
|
||||
* Check's if user's global notification settings for desktop and mobile are different
|
||||
*/
|
||||
export function areDesktopAndMobileSettingsDifferent(
|
||||
desktopActivity: UserNotifyProps['desktop'],
|
||||
pushActivity: UserNotifyProps['push'],
|
||||
pushActivity?: UserNotifyProps['push'],
|
||||
desktopThreads?: UserNotifyProps['desktop_threads'],
|
||||
pushThreads?: UserNotifyProps['push_threads'],
|
||||
isCollapsedThreadsEnabled?: boolean,
|
||||
|
@ -19,6 +19,7 @@ export type BaseSettingItemProps = {
|
||||
title?: string;
|
||||
description?: string;
|
||||
error?: ExtendedMessageDescriptor;
|
||||
dataTestId?: string;
|
||||
};
|
||||
|
||||
type Props = BaseSettingItemProps & {
|
||||
@ -28,7 +29,7 @@ type Props = BaseSettingItemProps & {
|
||||
descriptionAboveContent?: boolean;
|
||||
}
|
||||
|
||||
function BaseSettingItem({title, description, content, className, error, descriptionAboveContent = false, isContentInline = false}: Props): JSX.Element {
|
||||
function BaseSettingItem({title, description, content, className, error, descriptionAboveContent = false, isContentInline = false, dataTestId}: Props): JSX.Element {
|
||||
const {formatMessage} = useIntl();
|
||||
|
||||
const titleComponent = title && (
|
||||
@ -60,7 +61,10 @@ function BaseSettingItem({title, description, content, className, error, descrip
|
||||
);
|
||||
|
||||
return (
|
||||
<div className={classNames('mm-modal-generic-section-item', className)}>
|
||||
<div
|
||||
data-testid={dataTestId}
|
||||
className={classNames('mm-modal-generic-section-item', className)}
|
||||
>
|
||||
{titleComponent}
|
||||
{descriptionAboveContent ? descriptionComponent : undefined}
|
||||
<div
|
||||
|
@ -33,6 +33,7 @@ export default function CheckboxSettingItem({
|
||||
inputFieldTitle,
|
||||
handleChange,
|
||||
className,
|
||||
dataTestId,
|
||||
descriptionAboveContent = false,
|
||||
}: Props) {
|
||||
const content = (
|
||||
@ -59,6 +60,7 @@ export default function CheckboxSettingItem({
|
||||
content={content}
|
||||
title={title}
|
||||
description={description}
|
||||
dataTestId={dataTestId}
|
||||
className={className}
|
||||
descriptionAboveContent={descriptionAboveContent}
|
||||
/>
|
||||
|
@ -14,7 +14,6 @@ export type FieldsetRadio = {
|
||||
name: string;
|
||||
key: string;
|
||||
value: string;
|
||||
suffix?: JSX.Element;
|
||||
}>;
|
||||
}
|
||||
|
||||
@ -32,6 +31,7 @@ function RadioSettingItem({
|
||||
inputFieldData,
|
||||
inputFieldValue,
|
||||
handleChange,
|
||||
dataTestId,
|
||||
}: Props): JSX.Element {
|
||||
const fields = inputFieldData.options.map((option) => {
|
||||
return (
|
||||
@ -49,7 +49,6 @@ function RadioSettingItem({
|
||||
onChange={handleChange}
|
||||
/>
|
||||
{option.title}
|
||||
{option.suffix}
|
||||
</label>
|
||||
);
|
||||
});
|
||||
@ -61,6 +60,7 @@ function RadioSettingItem({
|
||||
);
|
||||
return (
|
||||
<BaseSettingItem
|
||||
dataTestId={dataTestId}
|
||||
className={className}
|
||||
content={content}
|
||||
title={title}
|
||||
|
@ -3202,9 +3202,6 @@
|
||||
"channel_notifications.checkbox.sameMobileSettingsDesktop": "Use the same notification settings as desktop",
|
||||
"channel_notifications.checkbox.threadsReplyTitle": "Notify me about replies to threads I’m following",
|
||||
"channel_notifications.default": "(default)",
|
||||
"channel_notifications.desktopNotificationAllLabel": "All new messages",
|
||||
"channel_notifications.desktopNotificationMentionLabel": "Mentions, direct messages, and keywords only",
|
||||
"channel_notifications.desktopNotificationNothingLabel": "Nothing",
|
||||
"channel_notifications.desktopNotifications.soundEnable": "Message notification sounds",
|
||||
"channel_notifications.desktopNotifications.soundSelectPlaceholder": "Select a sound",
|
||||
"channel_notifications.desktopNotifications.title": "Sounds",
|
||||
@ -3213,9 +3210,6 @@
|
||||
"channel_notifications.ignoreMentionsDesc": "When enabled, @channel, @here and @all will not trigger mentions or mention notifications in this channel",
|
||||
"channel_notifications.ignoreMentionsTitle": "Ignore mentions for @channel, @here and @all",
|
||||
"channel_notifications.levels.all": "All",
|
||||
"channel_notifications.MobileNotificationAllLabel": "All new messages",
|
||||
"channel_notifications.MobileNotificationMentionLabel": "Mentions, direct messages, and keywords only",
|
||||
"channel_notifications.MobileNotificationNothingLabel": "Nothing",
|
||||
"channel_notifications.mobileNotificationsDesc": "Notification alerts are pushed to your mobile device when there is activity in Mattermost.",
|
||||
"channel_notifications.mobileNotificationsTitle": "Mobile Notifications",
|
||||
"channel_notifications.muteAndIgnore": "Mute or ignore",
|
||||
@ -3234,6 +3228,12 @@
|
||||
"channelHeader.removeFromFavorites": "Remove from Favorites",
|
||||
"channelHeader.unmute": "Unmute",
|
||||
"channelHeader.viewInfo": "View Info",
|
||||
"channelNotifications.desktopNotification.allMessages": "All new messages {optionalDefault}",
|
||||
"channelNotifications.desktopNotification.mention": "Mentions, direct messages, and keywords only {optionalDefault}",
|
||||
"channelNotifications.desktopNotification.nothing": "Nothing {optionalDefault}",
|
||||
"channelNotifications.mobileNotification.mention": "Mentions, direct messages, and keywords only {optionalDefault}",
|
||||
"channelNotifications.mobileNotification.newMessages": "All new messages {optionalDefault}",
|
||||
"channelNotifications.mobileNotification.nothing": "Nothing {optionalDefault}",
|
||||
"channelView.login.successfull": "Login Successful",
|
||||
"claim.email_to_ldap.enterLdapPwd": "Enter the ID and password for your AD/LDAP account",
|
||||
"claim.email_to_ldap.enterPwd": "Enter the password for your {site} email account",
|
||||
|
@ -990,6 +990,7 @@ export const NotificationLevels = {
|
||||
} as const;
|
||||
|
||||
export const DesktopSound = {
|
||||
DEFAULT: 'default',
|
||||
ON: 'on',
|
||||
OFF: 'off',
|
||||
} as const;
|
||||
|
@ -5,6 +5,9 @@ import type {ReactNode} from 'react';
|
||||
import React from 'react';
|
||||
import {FormattedMessage} from 'react-intl';
|
||||
|
||||
import type {ChannelNotifyProps} from '@mattermost/types/channels';
|
||||
import type {UserNotifyProps} from '@mattermost/types/users';
|
||||
|
||||
import bing from 'sounds/bing.mp3';
|
||||
import calls_calm from 'sounds/calls_calm.mp3';
|
||||
import calls_cheerful from 'sounds/calls_cheerful.mp3';
|
||||
@ -15,21 +18,32 @@ import down from 'sounds/down.mp3';
|
||||
import hello from 'sounds/hello.mp3';
|
||||
import ripple from 'sounds/ripple.mp3';
|
||||
import upstairs from 'sounds/upstairs.mp3';
|
||||
import {DesktopSound} from 'utils/constants';
|
||||
import * as UserAgent from 'utils/user_agent';
|
||||
|
||||
export const notificationSounds = new Map([
|
||||
['Bing', bing],
|
||||
['Crackle', crackle],
|
||||
['Down', down],
|
||||
['Hello', hello],
|
||||
['Ripple', ripple],
|
||||
['Upstairs', upstairs],
|
||||
export const DesktopNotificationSounds = {
|
||||
DEFAULT: 'default',
|
||||
BING: 'Bing',
|
||||
CRACKLE: 'Crackle',
|
||||
DOWN: 'Down',
|
||||
HELLO: 'Hello',
|
||||
RIPPLE: 'Ripple',
|
||||
UPSTAIRS: 'Upstairs',
|
||||
} as const;
|
||||
|
||||
export const notificationSounds = new Map<string, string>([
|
||||
[DesktopNotificationSounds.BING, bing],
|
||||
[DesktopNotificationSounds.CRACKLE, crackle],
|
||||
[DesktopNotificationSounds.DOWN, down],
|
||||
[DesktopNotificationSounds.HELLO, hello],
|
||||
[DesktopNotificationSounds.RIPPLE, ripple],
|
||||
[DesktopNotificationSounds.UPSTAIRS, upstairs],
|
||||
]);
|
||||
|
||||
export const notificationSoundKeys = Array.from(notificationSounds.keys());
|
||||
|
||||
export const optionsOfMessageNotificationSoundsSelect: Array<{value: string; label: ReactNode}> = notificationSoundKeys.map((soundName) => {
|
||||
if (soundName === 'Bing') {
|
||||
if (soundName === DesktopNotificationSounds.BING) {
|
||||
return {
|
||||
value: soundName,
|
||||
label: (
|
||||
@ -39,7 +53,7 @@ export const optionsOfMessageNotificationSoundsSelect: Array<{value: string; lab
|
||||
/>
|
||||
),
|
||||
};
|
||||
} else if (soundName === 'Crackle') {
|
||||
} else if (soundName === DesktopNotificationSounds.CRACKLE) {
|
||||
return {
|
||||
value: soundName,
|
||||
label: (
|
||||
@ -49,7 +63,7 @@ export const optionsOfMessageNotificationSoundsSelect: Array<{value: string; lab
|
||||
/>
|
||||
),
|
||||
};
|
||||
} else if (soundName === 'Down') {
|
||||
} else if (soundName === DesktopNotificationSounds.DOWN) {
|
||||
return {
|
||||
value: soundName,
|
||||
label: (
|
||||
@ -59,7 +73,7 @@ export const optionsOfMessageNotificationSoundsSelect: Array<{value: string; lab
|
||||
/>
|
||||
),
|
||||
};
|
||||
} else if (soundName === 'Hello') {
|
||||
} else if (soundName === DesktopNotificationSounds.HELLO) {
|
||||
return {
|
||||
value: soundName,
|
||||
label: (
|
||||
@ -69,7 +83,7 @@ export const optionsOfMessageNotificationSoundsSelect: Array<{value: string; lab
|
||||
/>
|
||||
),
|
||||
};
|
||||
} else if (soundName === 'Ripple') {
|
||||
} else if (soundName === DesktopNotificationSounds.RIPPLE) {
|
||||
return {
|
||||
value: soundName,
|
||||
label: (
|
||||
@ -79,7 +93,7 @@ export const optionsOfMessageNotificationSoundsSelect: Array<{value: string; lab
|
||||
/>
|
||||
),
|
||||
};
|
||||
} else if (soundName === 'Upstairs') {
|
||||
} else if (soundName === DesktopNotificationSounds.UPSTAIRS) {
|
||||
return {
|
||||
value: soundName,
|
||||
label: (
|
||||
@ -249,3 +263,15 @@ export function loopNotificationRing(name: string) {
|
||||
export function hasSoundOptions() {
|
||||
return (!UserAgent.isEdge());
|
||||
}
|
||||
|
||||
/**
|
||||
* This conversion is needed because User's preference for desktop sound is stored as either true or false. On the other hand,
|
||||
* Channel's specific desktop sound is stored as either On or Off.
|
||||
*/
|
||||
export function convertDesktopSoundNotifyPropFromUserToDesktop(userNotifyDesktopSound?: UserNotifyProps['desktop_sound']): ChannelNotifyProps['desktop_sound'] {
|
||||
if (userNotifyDesktopSound && userNotifyDesktopSound === 'false') {
|
||||
return DesktopSound.OFF;
|
||||
}
|
||||
|
||||
return DesktopSound.ON;
|
||||
}
|
||||
|
@ -22,8 +22,8 @@ export type ChannelStats = {
|
||||
export type ChannelNotifyProps = {
|
||||
desktop_threads: 'default' | 'all' | 'mention' | 'none';
|
||||
desktop: 'default' | 'all' | 'mention' | 'none';
|
||||
desktop_sound: 'on' | 'off';
|
||||
desktop_notification_sound?: 'Bing' | 'Crackle' | 'Down' | 'Hello' | 'Ripple' | 'Upstairs';
|
||||
desktop_sound: 'default' | 'on' | 'off';
|
||||
desktop_notification_sound?: 'default' | 'Bing' | 'Crackle' | 'Down' | 'Hello' | 'Ripple' | 'Upstairs';
|
||||
email: 'default' | 'all' | 'mention' | 'none';
|
||||
mark_unread: 'all' | 'mention';
|
||||
push: 'default' | 'all' | 'mention' | 'none';
|
||||
|
@ -10,7 +10,7 @@ import type {IDMappedObjects, RelationOneToManyUnique, RelationOneToOne} from '.
|
||||
|
||||
export type UserNotifyProps = {
|
||||
desktop: 'default' | 'all' | 'mention' | 'none';
|
||||
desktop_sound: 'true' | 'false';
|
||||
desktop_sound: 'default' | 'true' | 'false';
|
||||
calls_desktop_sound: 'true' | 'false';
|
||||
email: 'true' | 'false';
|
||||
mark_unread: 'all' | 'mention';
|
||||
@ -21,7 +21,7 @@ export type UserNotifyProps = {
|
||||
channel: 'true' | 'false';
|
||||
mention_keys: string;
|
||||
highlight_keys: string;
|
||||
desktop_notification_sound?: 'Bing' | 'Crackle' | 'Down' | 'Hello' | 'Ripple' | 'Upstairs';
|
||||
desktop_notification_sound?: 'default' | 'Bing' | 'Crackle' | 'Down' | 'Hello' | 'Ripple' | 'Upstairs';
|
||||
calls_notification_sound?: 'Dynamic' | 'Calm' | 'Urgent' | 'Cheerful';
|
||||
desktop_threads?: 'default' | 'all' | 'mention' | 'none';
|
||||
email_threads?: 'default' | 'all' | 'mention' | 'none';
|
||||
|
Loading…
Reference in New Issue
Block a user