mirror of
https://github.com/mattermost/mattermost.git
synced 2025-02-25 18:55:24 -06:00
[MM-56695] Consolidate desktop and mobile Notifications to one and a new desktop notification sound settings (#26198)
This commit is contained in:
parent
a81ee87832
commit
9698cfcc19
@ -31,12 +31,12 @@ describe('Verify Accessibility Support in different sections in Settings and Pro
|
|||||||
|
|
||||||
const settings = {
|
const settings = {
|
||||||
notifications: [
|
notifications: [
|
||||||
{key: 'desktop', label: 'Desktop Notifications', type: 'radio'},
|
{key: 'desktopAndMobile', label: 'Desktop and mobile notifications', type: 'radio'},
|
||||||
{key: 'email', label: 'Email Notifications', type: 'radio'},
|
{key: 'desktopNotificationSound', label: 'Desktop notification sounds', type: 'radio'},
|
||||||
{key: 'push', label: 'Mobile Push Notifications', type: 'radio'},
|
{key: 'email', label: 'Email notifications', type: 'radio'},
|
||||||
{key: 'keysWithNotification', label: 'Keywords That Trigger Notifications', type: 'checkbox'},
|
{key: 'keywordsAndMentions', label: 'Keywords that trigger notifications', type: 'checkbox'},
|
||||||
{key: 'keysWithHighlight', label: 'Keywords That Get Highlighted (Without Notifications)', type: 'checkbox'},
|
{key: 'keywordsAndHighlight', label: 'Keywords that get highlighted (without notifications)', type: 'checkbox'},
|
||||||
{key: 'comments', label: 'Reply Notifications', type: 'radio'},
|
{key: 'replyNotifications', label: 'Reply notifications', type: 'radio'},
|
||||||
],
|
],
|
||||||
display: [
|
display: [
|
||||||
{key: 'theme', label: 'Theme', type: 'radio'},
|
{key: 'theme', label: 'Theme', type: 'radio'},
|
||||||
@ -147,18 +147,6 @@ describe('Verify Accessibility Support in different sections in Settings and Pro
|
|||||||
verifySettings(settings.advanced);
|
verifySettings(settings.advanced);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('MM-T1481 Verify Correct Radio button behavior in Settings and Profile', () => {
|
|
||||||
cy.visit(url);
|
|
||||||
cy.postMessage('hello');
|
|
||||||
cy.uiOpenSettingsModal();
|
|
||||||
|
|
||||||
cy.get('#notificationsButton').click();
|
|
||||||
cy.get('#desktopEdit').click();
|
|
||||||
cy.get('#desktopNotificationAllActivity').check().should('be.checked').tab().check();
|
|
||||||
cy.get('#desktopNotificationMentions').should('be.checked').tab().check();
|
|
||||||
cy.get('#desktopNotificationNever').should('be.checked');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('MM-T1482 Input fields in Settings and Profile should read labels', () => {
|
it('MM-T1482 Input fields in Settings and Profile should read labels', () => {
|
||||||
cy.visit(url);
|
cy.visit(url);
|
||||||
cy.postMessage('hello');
|
cy.postMessage('hello');
|
||||||
|
@ -48,7 +48,7 @@ describe('Auto Response In DMs', () => {
|
|||||||
// # Open 'Settings' modal and view 'Notifications'
|
// # Open 'Settings' modal and view 'Notifications'
|
||||||
cy.uiOpenSettingsModal().within(() => {
|
cy.uiOpenSettingsModal().within(() => {
|
||||||
// # Click on 'Edit' for 'Automatic Direct Message Replies
|
// # Click on 'Edit' for 'Automatic Direct Message Replies
|
||||||
cy.get('#auto-responderEdit').should('exist').scrollIntoView().and('be.visible').click();
|
cy.get('#autoResponderEdit').should('exist').scrollIntoView().and('be.visible').click();
|
||||||
|
|
||||||
// # Click on 'Enabled' checkbox
|
// # Click on 'Enabled' checkbox
|
||||||
cy.get('#autoResponderActive').should('be.visible').click();
|
cy.get('#autoResponderActive').should('be.visible').click();
|
||||||
|
@ -23,8 +23,8 @@ describe('Notifications', () => {
|
|||||||
|
|
||||||
// # Open 'Settings' modal
|
// # Open 'Settings' modal
|
||||||
cy.uiOpenSettingsModal().within(() => {
|
cy.uiOpenSettingsModal().within(() => {
|
||||||
// # Open 'Keywords That Trigger Notifications' setting and uncheck all the checkboxes
|
// # Open 'Keywords that trigger notifications' setting and uncheck all the checkboxes
|
||||||
cy.findByRole('heading', {name: 'Keywords That Trigger Notifications'}).should('be.visible').click();
|
cy.findByRole('heading', {name: 'Keywords that trigger notifications'}).should('be.visible').click();
|
||||||
cy.findByRole('checkbox', {name: `Your case-sensitive first name "${otherUser.first_name}"`}).should('not.be.checked');
|
cy.findByRole('checkbox', {name: `Your case-sensitive first name "${otherUser.first_name}"`}).should('not.be.checked');
|
||||||
cy.findByRole('checkbox', {name: `Your non case-sensitive username "${otherUser.username}"`}).should('not.be.checked');
|
cy.findByRole('checkbox', {name: `Your non case-sensitive username "${otherUser.username}"`}).should('not.be.checked');
|
||||||
cy.findByRole('checkbox', {name: 'Channel-wide mentions "@channel", "@all", "@here"'}).click().should('not.be.checked');
|
cy.findByRole('checkbox', {name: 'Channel-wide mentions "@channel", "@all", "@here"'}).click().should('not.be.checked');
|
||||||
|
@ -252,7 +252,7 @@ function setNotificationSettings(desiredSettings = {first: true, username: true,
|
|||||||
cy.findAllByText('Notifications').should('be.visible');
|
cy.findAllByText('Notifications').should('be.visible');
|
||||||
|
|
||||||
// Open up 'Words that trigger mentions' sub-section
|
// Open up 'Words that trigger mentions' sub-section
|
||||||
cy.findByText('Keywords That Trigger Notifications').
|
cy.findByText('Keywords that trigger notifications').
|
||||||
scrollIntoView().
|
scrollIntoView().
|
||||||
click();
|
click();
|
||||||
|
|
||||||
|
@ -50,8 +50,8 @@ describe('Notifications', () => {
|
|||||||
|
|
||||||
// # Open 'Notifications' of 'Settings' modal
|
// # Open 'Notifications' of 'Settings' modal
|
||||||
cy.uiOpenSettingsModal().within(() => {
|
cy.uiOpenSettingsModal().within(() => {
|
||||||
// # Open 'Email Notifications' setting and set to 'Immediately'
|
// # Open 'Email notifications' setting and set to 'Immediately'
|
||||||
cy.findByRole('heading', {name: 'Email Notifications'}).should('be.visible').click();
|
cy.findByRole('heading', {name: 'Email notifications'}).should('be.visible').click();
|
||||||
cy.findByRole('radio', {name: 'Immediately'}).click().should('be.checked');
|
cy.findByRole('radio', {name: 'Immediately'}).click().should('be.checked');
|
||||||
|
|
||||||
// # Save then close the modal
|
// # Save then close the modal
|
||||||
|
@ -29,8 +29,8 @@ describe('Notifications', () => {
|
|||||||
|
|
||||||
// # Open 'Settings' modal
|
// # Open 'Settings' modal
|
||||||
cy.uiOpenSettingsModal().within(() => {
|
cy.uiOpenSettingsModal().within(() => {
|
||||||
// # Open 'Keywords That Trigger Notifications' setting
|
// # Open 'Keywords that trigger notifications' setting
|
||||||
cy.findByRole('heading', {name: 'Keywords That Trigger Notifications'}).should('be.visible').click();
|
cy.findByRole('heading', {name: 'Keywords that trigger notifications'}).should('be.visible').click();
|
||||||
|
|
||||||
// * As otherUser, ensure that 'Your non-case sensitive username' is not checked
|
// * As otherUser, ensure that 'Your non-case sensitive username' is not checked
|
||||||
cy.findByRole('checkbox', {name: `Your non case-sensitive username "${otherUser.username}"`}).should('not.be.checked');
|
cy.findByRole('checkbox', {name: `Your non case-sensitive username "${otherUser.username}"`}).should('not.be.checked');
|
||||||
|
@ -48,7 +48,7 @@ describe('Desktop notifications', () => {
|
|||||||
spyNotificationAs('withoutNotification', 'granted');
|
spyNotificationAs('withoutNotification', 'granted');
|
||||||
|
|
||||||
// # Ensure notifications are set up to fire a desktop notification if are mentioned.
|
// # Ensure notifications are set up to fire a desktop notification if are mentioned.
|
||||||
changeDesktopNotificationAs('#desktopNotificationMentions');
|
changeDesktopNotificationAs('mentions');
|
||||||
|
|
||||||
cy.apiGetChannelByName(testTeam.name, 'Off-Topic').then(({channel}) => {
|
cy.apiGetChannelByName(testTeam.name, 'Off-Topic').then(({channel}) => {
|
||||||
// # Logout the user
|
// # Logout the user
|
||||||
@ -100,7 +100,7 @@ describe('Desktop notifications', () => {
|
|||||||
const expected = '@' + otherUser.username + ': I\'m hungry :taco: Mattermost';
|
const expected = '@' + otherUser.username + ': I\'m hungry :taco: Mattermost';
|
||||||
|
|
||||||
// # Ensure notifications are set up to fire a desktop notification if are mentioned.
|
// # Ensure notifications are set up to fire a desktop notification if are mentioned.
|
||||||
changeDesktopNotificationAs('#desktopNotificationAllActivity');
|
changeDesktopNotificationAs('all');
|
||||||
|
|
||||||
cy.apiGetChannelByName(testTeam.name, 'Off-Topic').then(({channel}) => {
|
cy.apiGetChannelByName(testTeam.name, 'Off-Topic').then(({channel}) => {
|
||||||
// # Have another user send a post.
|
// # Have another user send a post.
|
||||||
@ -147,7 +147,7 @@ describe('Desktop notifications', () => {
|
|||||||
const expected = '@' + otherUser.username + ' did something new';
|
const expected = '@' + otherUser.username + ' did something new';
|
||||||
|
|
||||||
// # Ensure notifications are set up to fire a desktop notification for all activity.
|
// # Ensure notifications are set up to fire a desktop notification for all activity.
|
||||||
changeDesktopNotificationAs('#desktopNotificationAllActivity');
|
changeDesktopNotificationAs('all');
|
||||||
|
|
||||||
cy.apiGetChannelByName(testTeam.name, 'Off-Topic').then(({channel}) => {
|
cy.apiGetChannelByName(testTeam.name, 'Off-Topic').then(({channel}) => {
|
||||||
// # Have another user send a post.
|
// # Have another user send a post.
|
||||||
@ -169,7 +169,7 @@ describe('Desktop notifications', () => {
|
|||||||
spyNotificationAs('withNotification', 'granted');
|
spyNotificationAs('withNotification', 'granted');
|
||||||
|
|
||||||
// # Ensure notifications are set up to fire a desktop notification if are mentioned
|
// # Ensure notifications are set up to fire a desktop notification if are mentioned
|
||||||
changeDesktopNotificationAs('#desktopNotificationMentions');
|
changeDesktopNotificationAs('mentions');
|
||||||
|
|
||||||
// # Ensure display settings are set to "Show username"
|
// # Ensure display settings are set to "Show username"
|
||||||
changeTeammateNameDisplayAs('#name_formatFormatA');
|
changeTeammateNameDisplayAs('#name_formatFormatA');
|
||||||
@ -194,7 +194,7 @@ describe('Desktop notifications', () => {
|
|||||||
spyNotificationAs('withNotification', 'granted');
|
spyNotificationAs('withNotification', 'granted');
|
||||||
|
|
||||||
// # Ensure notifications are set up to fire a desktop notification if are mentioned
|
// # Ensure notifications are set up to fire a desktop notification if are mentioned
|
||||||
changeDesktopNotificationAs('#desktopNotificationMentions');
|
changeDesktopNotificationAs('mentions');
|
||||||
|
|
||||||
// # Ensure display settings are set to "Show first and last name"
|
// # Ensure display settings are set to "Show first and last name"
|
||||||
changeTeammateNameDisplayAs('#name_formatFormatC');
|
changeTeammateNameDisplayAs('#name_formatFormatC');
|
||||||
@ -235,7 +235,7 @@ describe('Desktop notifications', () => {
|
|||||||
spyNotificationAs('withNotification', 'granted');
|
spyNotificationAs('withNotification', 'granted');
|
||||||
|
|
||||||
// # Ensure notifications are set up to fire a desktop notification
|
// # Ensure notifications are set up to fire a desktop notification
|
||||||
changeDesktopNotificationAs('#desktopNotificationMentions');
|
changeDesktopNotificationAs('mentions');
|
||||||
|
|
||||||
cy.apiGetChannelByName(testTeam.name, 'Off-Topic').then(({channel}) => {
|
cy.apiGetChannelByName(testTeam.name, 'Off-Topic').then(({channel}) => {
|
||||||
const messageWithoutNotification = 'message without notification';
|
const messageWithoutNotification = 'message without notification';
|
||||||
@ -271,7 +271,7 @@ describe('Desktop notifications', () => {
|
|||||||
spyNotificationAs('withNotification', 'granted');
|
spyNotificationAs('withNotification', 'granted');
|
||||||
|
|
||||||
// # Ensure notifications are set up to never fire a desktop notification
|
// # Ensure notifications are set up to never fire a desktop notification
|
||||||
changeDesktopNotificationAs('#desktopNotificationNever');
|
changeDesktopNotificationAs('nothing');
|
||||||
|
|
||||||
cy.apiGetChannelByName(testTeam.name, 'Off-Topic').then(({channel}) => {
|
cy.apiGetChannelByName(testTeam.name, 'Off-Topic').then(({channel}) => {
|
||||||
const messageWithNotification = `random message with mention @${testUser.username}`;
|
const messageWithNotification = `random message with mention @${testUser.username}`;
|
||||||
@ -297,14 +297,11 @@ describe('Desktop notifications', () => {
|
|||||||
|
|
||||||
// # Open settings modal
|
// # Open settings modal
|
||||||
cy.uiOpenSettingsModal().within(() => {
|
cy.uiOpenSettingsModal().within(() => {
|
||||||
// # Click "Desktop"
|
// # Click "Desktop sound notifications"
|
||||||
cy.findByText('Desktop Notifications').should('be.visible').click();
|
cy.findByText('Desktop notification sounds').should('be.visible').click();
|
||||||
|
|
||||||
// # Select sound off.
|
// # Select sound off.
|
||||||
cy.get('#soundOff').check();
|
cy.findByText('Message notification sound').click({force: true});
|
||||||
|
|
||||||
// # Ensure sound dropdown is not visible
|
|
||||||
cy.get('#displaySoundNotification').should('not.exist');
|
|
||||||
|
|
||||||
// # Click "Save" and close the modal
|
// # Click "Save" and close the modal
|
||||||
cy.uiSaveAndClose();
|
cy.uiSaveAndClose();
|
||||||
|
@ -43,7 +43,7 @@ describe('Desktop notifications', () => {
|
|||||||
|
|
||||||
it('MM-T885 Channel notifications: Desktop notifications mentions only', () => {
|
it('MM-T885 Channel notifications: Desktop notifications mentions only', () => {
|
||||||
// # Ensure notifications are set up to fire a desktop notification
|
// # Ensure notifications are set up to fire a desktop notification
|
||||||
changeDesktopNotificationAs('#desktopNotificationAllActivity');
|
changeDesktopNotificationAs('all');
|
||||||
|
|
||||||
const messageWithNotification = `random message with mention @${testUser.username}`;
|
const messageWithNotification = `random message with mention @${testUser.username}`;
|
||||||
const expected = `@${otherUser.username}: ${messageWithNotification}`;
|
const expected = `@${otherUser.username}: ${messageWithNotification}`;
|
||||||
|
@ -48,7 +48,7 @@ describe('Desktop notifications', () => {
|
|||||||
spyNotificationAs('withNotification', 'granted');
|
spyNotificationAs('withNotification', 'granted');
|
||||||
|
|
||||||
// # Ensure notifications are set up to fire a desktop notification if are mentioned
|
// # Ensure notifications are set up to fire a desktop notification if are mentioned
|
||||||
changeDesktopNotificationAs('#desktopNotificationMentions');
|
changeDesktopNotificationAs('mentions');
|
||||||
|
|
||||||
// # Ensure display settings are set to "Show nickname if one exists, otherwise show first and last name"
|
// # Ensure display settings are set to "Show nickname if one exists, otherwise show first and last name"
|
||||||
changeTeammateNameDisplayAs('#name_formatFormatB');
|
changeTeammateNameDisplayAs('#name_formatFormatB');
|
||||||
@ -76,7 +76,7 @@ describe('Desktop notifications', () => {
|
|||||||
spyNotificationAs('withNotification', 'granted');
|
spyNotificationAs('withNotification', 'granted');
|
||||||
|
|
||||||
// # Ensure notifications are set up to fire a desktop notification if are mentioned
|
// # Ensure notifications are set up to fire a desktop notification if are mentioned
|
||||||
changeDesktopNotificationAs('#desktopNotificationMentions');
|
changeDesktopNotificationAs('mentions');
|
||||||
|
|
||||||
// # Ensure display settings are set to "Show nickname if one exists, otherwise show first and last name"
|
// # Ensure display settings are set to "Show nickname if one exists, otherwise show first and last name"
|
||||||
changeTeammateNameDisplayAs('#name_formatFormatB');
|
changeTeammateNameDisplayAs('#name_formatFormatB');
|
||||||
|
@ -4,11 +4,21 @@
|
|||||||
export function changeDesktopNotificationAs(category) {
|
export function changeDesktopNotificationAs(category) {
|
||||||
// # Open settings modal
|
// # Open settings modal
|
||||||
cy.uiOpenSettingsModal().within(() => {
|
cy.uiOpenSettingsModal().within(() => {
|
||||||
// # Click "Desktop Notifications"
|
// # Click "Desktop and mobile notifications"
|
||||||
cy.findByText('Desktop Notifications').should('be.visible').click();
|
cy.findByText('Desktop and mobile notifications').should('be.visible').click();
|
||||||
|
|
||||||
// # Select category.
|
cy.get('#sendDesktopNotificationsSection').should('exist').within(() => {
|
||||||
cy.get(category).check();
|
if (category === 'all') {
|
||||||
|
// # Click "For all All new messages"
|
||||||
|
cy.findByText('All new messages').should('be.visible').click({force: true});
|
||||||
|
} else if (category === 'mentions') {
|
||||||
|
// # Click "For mentions"
|
||||||
|
cy.findByText('Mentions, direct messages, and group messages').should('be.visible').click({force: true});
|
||||||
|
} else if (category === 'nothing') {
|
||||||
|
// # Click "For nothing"
|
||||||
|
cy.findByText('Nothing').should('be.visible').click({force: true});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// # Click "Save" and close the modal
|
// # Click "Save" and close the modal
|
||||||
cy.uiSaveAndClose();
|
cy.uiSaveAndClose();
|
||||||
|
@ -31,17 +31,17 @@ describe('Notifications', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('MM-T555 Notification Preferences do not save when modal is closed without saving', () => {
|
it('MM-T555 Notification Preferences do not save when modal is closed without saving', () => {
|
||||||
// # Call function that clicks on Settings -> Notifications -> Email Notifications -> Send Email Notifications -> Never without saving
|
// # Call function that clicks on Settings -> Notifications -> Email notifications -> Send Email notifications -> Never without saving
|
||||||
openSettingsAndClickEmailEdit(true);
|
openSettingsAndClickEmailEdit(true);
|
||||||
|
|
||||||
// # Call function that checks Settings -> Notifications -> Email Notifications -> Send Email Notifications -> Never is not saved
|
// # Call function that checks Settings -> Notifications -> Email notifications -> Send Email notifications -> Never is not saved
|
||||||
openSettingsAndClickEmailEdit(false);
|
openSettingsAndClickEmailEdit(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
function openSettingsAndClickEmailEdit(shouldBeClicked = false) {
|
function openSettingsAndClickEmailEdit(shouldBeClicked = false) {
|
||||||
// # Open 'Settings' modal
|
// # Open 'Settings' modal
|
||||||
cy.uiOpenSettingsModal().within(() => {
|
cy.uiOpenSettingsModal().within(() => {
|
||||||
// # Click on the 'Edit' button next to Email Notifications
|
// # Click on the 'Edit' button next to Email notifications
|
||||||
cy.get('#emailEdit').click();
|
cy.get('#emailEdit').click();
|
||||||
|
|
||||||
if (shouldBeClicked) {
|
if (shouldBeClicked) {
|
||||||
|
@ -239,9 +239,7 @@ function setReplyNotificationsSetting(idToToggle) {
|
|||||||
and('contain', 'Notifications');
|
and('contain', 'Notifications');
|
||||||
|
|
||||||
// Open up 'Reply Notifications' sub-section
|
// Open up 'Reply Notifications' sub-section
|
||||||
cy.get('#commentsTitle').
|
cy.findByText('Reply notifications').should('be.visible').scrollIntoView().click();
|
||||||
scrollIntoView().
|
|
||||||
click();
|
|
||||||
|
|
||||||
cy.get(idToToggle).check().should('be.checked');
|
cy.get(idToToggle).check().should('be.checked');
|
||||||
|
|
||||||
|
@ -20,47 +20,27 @@ describe('Notifications', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('MM-T5458 Notification sound modal selection should reset when settings canceled', () => {
|
it('MM-T5458 Notification sound modal selection should reset when settings canceled', () => {
|
||||||
// # Call function that clicks on Settings -> Notifications -> Desktop Notifications -> Notification sound -> Change sound -> Cancel -> Desktop Notifications
|
|
||||||
openSettingsAndChangeNotification();
|
|
||||||
});
|
|
||||||
|
|
||||||
function openSettingsAndChangeNotification() {
|
|
||||||
// # Open 'Settings' modal
|
// # Open 'Settings' modal
|
||||||
cy.uiOpenSettingsModal().within(() => {
|
cy.uiOpenSettingsModal();
|
||||||
// # Navigate to Desktop Notification Settings
|
|
||||||
navigateToDesktopNotificationSettings();
|
|
||||||
|
|
||||||
// # Change Notification selection
|
// # Navigate to Desktop Notification Settings
|
||||||
setNotificationSound();
|
cy.get('#desktopNotificationSoundEdit').should('be.visible').click();
|
||||||
|
|
||||||
// # Click Cancel button
|
// # Change Notification selection
|
||||||
cy.uiCancelButton().click();
|
cy.get('#messageNotificationSoundSelect').click();
|
||||||
|
|
||||||
// # Navigate to Desktop Notification Settings
|
// # Select 'Bing' sound
|
||||||
navigateToDesktopNotificationSettings();
|
|
||||||
cy.uiClose();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function setNotificationSound() {
|
|
||||||
// # Change Notification sound selection value is set to Down
|
|
||||||
cy.get('#displaySoundNotification').click();
|
|
||||||
cy.findByText('Down').click();
|
cy.findByText('Down').click();
|
||||||
|
|
||||||
// * Verify Notification display changed to Down
|
// # Click Cancel button to close the settings
|
||||||
verifyNotificationSelectionValue('Down');
|
cy.uiCancelButton().click();
|
||||||
}
|
|
||||||
|
|
||||||
function navigateToDesktopNotificationSettings() {
|
// # Click on the 'Edit' button next to Desktop sound notification again
|
||||||
// # Click on the 'Edit' button next to Desktop Notifications
|
cy.get('#desktopNotificationSoundEdit').should('be.visible').click();
|
||||||
cy.get('#desktopEdit').should('be.visible').click();
|
|
||||||
|
|
||||||
// * Verify that the Notification sound is set to Bing
|
// * Verify that the Notification sound is set to Bing as we canceled the settings
|
||||||
verifyNotificationSelectionValue('Bing');
|
cy.findByText('Bing').should('be.visible');
|
||||||
}
|
|
||||||
|
|
||||||
function verifyNotificationSelectionValue(value) {
|
cy.uiClose();
|
||||||
// * Verify that the Notification sound is set to certain value
|
});
|
||||||
cy.get('#displaySoundNotification').findByTestId('displaySoundNotificationValue').should('contain', value);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
@ -34,7 +34,7 @@ describe('Authentication', () => {
|
|||||||
// # Open settings modal
|
// # Open settings modal
|
||||||
cy.uiOpenSettingsModal().within(() => {
|
cy.uiOpenSettingsModal().within(() => {
|
||||||
// Click "Desktop"
|
// Click "Desktop"
|
||||||
cy.findByText('Desktop Notifications').should('be.visible').click();
|
cy.findByText('Desktop and mobile notifications').should('be.visible').click();
|
||||||
|
|
||||||
// # Set your desktop notifications to Never
|
// # Set your desktop notifications to Never
|
||||||
cy.get('#desktopNotificationNever').check();
|
cy.get('#desktopNotificationNever').check();
|
||||||
|
@ -102,13 +102,13 @@ export function sendDesktopNotification(post, msgProps) {
|
|||||||
notifyLevel = user?.notify_props?.desktop || NotificationLevels.ALL;
|
notifyLevel = user?.notify_props?.desktop || NotificationLevels.ALL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (channel.type === 'G' && channelNotifyProp === NotificationLevels.DEFAULT && user?.notify_props?.desktop === NotificationLevels.MENTION) {
|
if (channel?.type === 'G' && channelNotifyProp === NotificationLevels.DEFAULT && user?.notify_props?.desktop === NotificationLevels.MENTION) {
|
||||||
notifyLevel = NotificationLevels.ALL;
|
notifyLevel = NotificationLevels.ALL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (notifyLevel === NotificationLevels.NONE) {
|
if (notifyLevel === NotificationLevels.NONE) {
|
||||||
return;
|
return;
|
||||||
} else if (channel.type === 'G' && notifyLevel === NotificationLevels.MENTION) {
|
} else if (channel?.type === 'G' && notifyLevel === NotificationLevels.MENTION) {
|
||||||
// Compose the whole text in the message, including interactive messages.
|
// Compose the whole text in the message, including interactive messages.
|
||||||
let text = post.message;
|
let text = post.message;
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ exports[`components/SettingItemMax should match snapshot 1`] = `
|
|||||||
title
|
title
|
||||||
</h4>
|
</h4>
|
||||||
<div
|
<div
|
||||||
className="col-sm-12"
|
className="sectionContent col-sm-10 col-sm-offset-2"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className="setting-list"
|
className="setting-list"
|
||||||
@ -72,7 +72,7 @@ exports[`components/SettingItemMax should match snapshot, on clientError 1`] = `
|
|||||||
title
|
title
|
||||||
</h4>
|
</h4>
|
||||||
<div
|
<div
|
||||||
className="col-sm-12"
|
className="sectionContent col-sm-10 col-sm-offset-2"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className="setting-list"
|
className="setting-list"
|
||||||
@ -143,7 +143,7 @@ exports[`components/SettingItemMax should match snapshot, on serverError 1`] = `
|
|||||||
title
|
title
|
||||||
</h4>
|
</h4>
|
||||||
<div
|
<div
|
||||||
className="col-sm-12"
|
className="sectionContent col-sm-10 col-sm-offset-2"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className="setting-list"
|
className="setting-list"
|
||||||
@ -214,7 +214,7 @@ exports[`components/SettingItemMax should match snapshot, with new saveTextButto
|
|||||||
title
|
title
|
||||||
</h4>
|
</h4>
|
||||||
<div
|
<div
|
||||||
className="col-sm-12"
|
className="sectionContent col-sm-10 col-sm-offset-2"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className="setting-list"
|
className="setting-list"
|
||||||
@ -270,7 +270,7 @@ exports[`components/SettingItemMax should match snapshot, without submit 1`] = `
|
|||||||
title
|
title
|
||||||
</h4>
|
</h4>
|
||||||
<div
|
<div
|
||||||
className="col-sm-12"
|
className="sectionContent col-sm-10 col-sm-offset-2"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className="setting-list"
|
className="setting-list"
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||||
// See LICENSE.txt for license information.
|
// See LICENSE.txt for license information.
|
||||||
|
|
||||||
|
import classNames from 'classnames';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import type {ReactNode} from 'react';
|
import type {ReactNode} from 'react';
|
||||||
import {FormattedMessage} from 'react-intl';
|
import {FormattedMessage} from 'react-intl';
|
||||||
@ -44,7 +45,7 @@ type Props = {
|
|||||||
submitExtra?: ReactNode;
|
submitExtra?: ReactNode;
|
||||||
saving?: boolean;
|
saving?: boolean;
|
||||||
title?: ReactNode;
|
title?: ReactNode;
|
||||||
width?: string;
|
isFullWidth?: boolean;
|
||||||
cancelButtonText?: ReactNode;
|
cancelButtonText?: ReactNode;
|
||||||
shiftEnter?: boolean;
|
shiftEnter?: boolean;
|
||||||
saveButtonText?: string;
|
saveButtonText?: string;
|
||||||
@ -177,14 +178,6 @@ export default class SettingItemMax extends React.PureComponent<Props> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const inputs = this.props.inputs;
|
const inputs = this.props.inputs;
|
||||||
let widthClass;
|
|
||||||
if (this.props.width === 'full') {
|
|
||||||
widthClass = 'col-sm-12';
|
|
||||||
} else if (this.props.width === 'medium') {
|
|
||||||
widthClass = 'col-sm-10 col-sm-offset-2';
|
|
||||||
} else {
|
|
||||||
widthClass = 'col-sm-9 col-sm-offset-3';
|
|
||||||
}
|
|
||||||
|
|
||||||
let title;
|
let title;
|
||||||
if (this.props.title) {
|
if (this.props.title) {
|
||||||
@ -231,7 +224,12 @@ export default class SettingItemMax extends React.PureComponent<Props> {
|
|||||||
className={`section-max form-horizontal ${this.props.containerStyle}`}
|
className={`section-max form-horizontal ${this.props.containerStyle}`}
|
||||||
>
|
>
|
||||||
{title}
|
{title}
|
||||||
<div className={widthClass}>
|
<div
|
||||||
|
className={classNames('sectionContent', {
|
||||||
|
'col-sm-12': this.props.isFullWidth,
|
||||||
|
'col-sm-10 col-sm-offset-2': !this.props.isFullWidth,
|
||||||
|
})}
|
||||||
|
>
|
||||||
<div
|
<div
|
||||||
tabIndex={-1}
|
tabIndex={-1}
|
||||||
ref={this.settingList}
|
ref={this.settingList}
|
||||||
|
@ -256,7 +256,6 @@ export class ManageLanguage extends React.PureComponent<Props, State> {
|
|||||||
defaultMessage='Language'
|
defaultMessage='Language'
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
width='medium'
|
|
||||||
submit={this.changeLanguage}
|
submit={this.changeLanguage}
|
||||||
saving={this.state.isSaving}
|
saving={this.state.isSaving}
|
||||||
inputs={[input]}
|
inputs={[input]}
|
||||||
|
@ -245,7 +245,6 @@ export default class ManageTimezones extends React.PureComponent<Props, State> {
|
|||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
containerStyle='timezone-container'
|
containerStyle='timezone-container'
|
||||||
width='medium'
|
|
||||||
submit={this.changeTimezone}
|
submit={this.changeTimezone}
|
||||||
saving={this.state.isSaving}
|
saving={this.state.isSaving}
|
||||||
inputs={inputs}
|
inputs={inputs}
|
||||||
|
@ -309,7 +309,7 @@ export default class ThemeSetting extends React.PureComponent<Props, State> {
|
|||||||
disableEnterSubmit={true}
|
disableEnterSubmit={true}
|
||||||
saving={this.state.isSaving}
|
saving={this.state.isSaving}
|
||||||
serverError={serverError}
|
serverError={serverError}
|
||||||
width='full'
|
isFullWidth={true}
|
||||||
updateSection={this.handleUpdateSection}
|
updateSection={this.handleUpdateSection}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
@ -34,7 +34,7 @@ Object {
|
|||||||
class="fa fa-angle-left"
|
class="fa fa-angle-left"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
Notification Settings
|
Notification settings
|
||||||
</h4>
|
</h4>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
@ -88,15 +88,15 @@ Object {
|
|||||||
>
|
>
|
||||||
<h4
|
<h4
|
||||||
class="section-min__title"
|
class="section-min__title"
|
||||||
id="desktopTitle"
|
id="desktopAndMobileTitle"
|
||||||
>
|
>
|
||||||
Desktop Notifications
|
Desktop and mobile notifications
|
||||||
</h4>
|
</h4>
|
||||||
<button
|
<button
|
||||||
aria-expanded="false"
|
aria-expanded="false"
|
||||||
aria-labelledby="desktopTitle desktopEdit"
|
aria-labelledby="desktopAndMobileTitle desktopAndMobileEdit"
|
||||||
class="color--link style--none section-min__edit"
|
class="color--link style--none section-min__edit"
|
||||||
id="desktopEdit"
|
id="desktopAndMobileEdit"
|
||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
class="icon-pencil-outline"
|
class="icon-pencil-outline"
|
||||||
@ -107,9 +107,44 @@ Object {
|
|||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="section-min__describe"
|
class="section-min__describe"
|
||||||
id="desktopDesc"
|
id="desktopAndMobileDesc"
|
||||||
>
|
>
|
||||||
For all activity, without sound
|
Configure desktop and mobile settings
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="divider-light"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="section-min"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="secion-min__header"
|
||||||
|
>
|
||||||
|
<h4
|
||||||
|
class="section-min__title"
|
||||||
|
id="desktopNotificationSoundTitle"
|
||||||
|
>
|
||||||
|
Desktop notification sounds
|
||||||
|
</h4>
|
||||||
|
<button
|
||||||
|
aria-expanded="false"
|
||||||
|
aria-labelledby="desktopNotificationSoundTitle desktopNotificationSoundEdit"
|
||||||
|
class="color--link style--none section-min__edit"
|
||||||
|
id="desktopNotificationSoundEdit"
|
||||||
|
>
|
||||||
|
<i
|
||||||
|
class="icon-pencil-outline"
|
||||||
|
title="Edit Icon"
|
||||||
|
/>
|
||||||
|
Edit
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="section-min__describe"
|
||||||
|
id="desktopNotificationSoundDesc"
|
||||||
|
>
|
||||||
|
No sound
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
@ -125,7 +160,7 @@ Object {
|
|||||||
class="section-min__title"
|
class="section-min__title"
|
||||||
id="emailTitle"
|
id="emailTitle"
|
||||||
>
|
>
|
||||||
Email Notifications
|
Email notifications
|
||||||
</h4>
|
</h4>
|
||||||
<button
|
<button
|
||||||
aria-expanded="false"
|
aria-expanded="false"
|
||||||
@ -158,15 +193,15 @@ Object {
|
|||||||
>
|
>
|
||||||
<h4
|
<h4
|
||||||
class="section-min__title"
|
class="section-min__title"
|
||||||
id="pushTitle"
|
id="keywordsAndMentionsTitle"
|
||||||
>
|
>
|
||||||
Mobile Push Notifications
|
Keywords that trigger notifications
|
||||||
</h4>
|
</h4>
|
||||||
<button
|
<button
|
||||||
aria-expanded="false"
|
aria-expanded="false"
|
||||||
aria-labelledby="pushTitle pushEdit"
|
aria-labelledby="keywordsAndMentionsTitle keywordsAndMentionsEdit"
|
||||||
class="color--link style--none section-min__edit"
|
class="color--link style--none section-min__edit"
|
||||||
id="pushEdit"
|
id="keywordsAndMentionsEdit"
|
||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
class="icon-pencil-outline"
|
class="icon-pencil-outline"
|
||||||
@ -177,42 +212,7 @@ Object {
|
|||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="section-min__describe"
|
class="section-min__describe"
|
||||||
id="pushDesc"
|
id="keywordsAndMentionsDesc"
|
||||||
>
|
|
||||||
Never
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
class="divider-light"
|
|
||||||
/>
|
|
||||||
<div
|
|
||||||
class="section-min"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="secion-min__header"
|
|
||||||
>
|
|
||||||
<h4
|
|
||||||
class="section-min__title"
|
|
||||||
id="keysWithNotificationTitle"
|
|
||||||
>
|
|
||||||
Keywords That Trigger Notifications
|
|
||||||
</h4>
|
|
||||||
<button
|
|
||||||
aria-expanded="false"
|
|
||||||
aria-labelledby="keysWithNotificationTitle keysWithNotificationEdit"
|
|
||||||
class="color--link style--none section-min__edit"
|
|
||||||
id="keysWithNotificationEdit"
|
|
||||||
>
|
|
||||||
<i
|
|
||||||
class="icon-pencil-outline"
|
|
||||||
title="Edit Icon"
|
|
||||||
/>
|
|
||||||
Edit
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
class="section-min__describe"
|
|
||||||
id="keysWithNotificationDesc"
|
|
||||||
>
|
>
|
||||||
"@some-user"
|
"@some-user"
|
||||||
</div>
|
</div>
|
||||||
@ -228,15 +228,15 @@ Object {
|
|||||||
>
|
>
|
||||||
<h4
|
<h4
|
||||||
class="section-min__title"
|
class="section-min__title"
|
||||||
id="keysWithHighlightTitle"
|
id="keywordsAndHighlightTitle"
|
||||||
>
|
>
|
||||||
Keywords That Get Highlighted (Without Notifications)
|
Keywords that get highlighted (without notifications)
|
||||||
</h4>
|
</h4>
|
||||||
<button
|
<button
|
||||||
aria-expanded="false"
|
aria-expanded="false"
|
||||||
aria-labelledby="keysWithHighlightTitle keysWithHighlightEdit"
|
aria-labelledby="keywordsAndHighlightTitle keywordsAndHighlightEdit"
|
||||||
class="color--link style--none section-min__edit"
|
class="color--link style--none section-min__edit"
|
||||||
id="keysWithHighlightEdit"
|
id="keywordsAndHighlightEdit"
|
||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
class="icon-pencil-outline"
|
class="icon-pencil-outline"
|
||||||
@ -247,7 +247,7 @@ Object {
|
|||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="section-min__describe"
|
class="section-min__describe"
|
||||||
id="keysWithHighlightDesc"
|
id="keywordsAndHighlightDesc"
|
||||||
>
|
>
|
||||||
None
|
None
|
||||||
</div>
|
</div>
|
||||||
@ -292,7 +292,7 @@ Object {
|
|||||||
class="fa fa-angle-left"
|
class="fa fa-angle-left"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
Notification Settings
|
Notification settings
|
||||||
</h4>
|
</h4>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
@ -346,15 +346,15 @@ Object {
|
|||||||
>
|
>
|
||||||
<h4
|
<h4
|
||||||
class="section-min__title"
|
class="section-min__title"
|
||||||
id="desktopTitle"
|
id="desktopAndMobileTitle"
|
||||||
>
|
>
|
||||||
Desktop Notifications
|
Desktop and mobile notifications
|
||||||
</h4>
|
</h4>
|
||||||
<button
|
<button
|
||||||
aria-expanded="false"
|
aria-expanded="false"
|
||||||
aria-labelledby="desktopTitle desktopEdit"
|
aria-labelledby="desktopAndMobileTitle desktopAndMobileEdit"
|
||||||
class="color--link style--none section-min__edit"
|
class="color--link style--none section-min__edit"
|
||||||
id="desktopEdit"
|
id="desktopAndMobileEdit"
|
||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
class="icon-pencil-outline"
|
class="icon-pencil-outline"
|
||||||
@ -365,9 +365,44 @@ Object {
|
|||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="section-min__describe"
|
class="section-min__describe"
|
||||||
id="desktopDesc"
|
id="desktopAndMobileDesc"
|
||||||
>
|
>
|
||||||
For all activity, without sound
|
Configure desktop and mobile settings
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="divider-light"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="section-min"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="secion-min__header"
|
||||||
|
>
|
||||||
|
<h4
|
||||||
|
class="section-min__title"
|
||||||
|
id="desktopNotificationSoundTitle"
|
||||||
|
>
|
||||||
|
Desktop notification sounds
|
||||||
|
</h4>
|
||||||
|
<button
|
||||||
|
aria-expanded="false"
|
||||||
|
aria-labelledby="desktopNotificationSoundTitle desktopNotificationSoundEdit"
|
||||||
|
class="color--link style--none section-min__edit"
|
||||||
|
id="desktopNotificationSoundEdit"
|
||||||
|
>
|
||||||
|
<i
|
||||||
|
class="icon-pencil-outline"
|
||||||
|
title="Edit Icon"
|
||||||
|
/>
|
||||||
|
Edit
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="section-min__describe"
|
||||||
|
id="desktopNotificationSoundDesc"
|
||||||
|
>
|
||||||
|
No sound
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
@ -383,7 +418,7 @@ Object {
|
|||||||
class="section-min__title"
|
class="section-min__title"
|
||||||
id="emailTitle"
|
id="emailTitle"
|
||||||
>
|
>
|
||||||
Email Notifications
|
Email notifications
|
||||||
</h4>
|
</h4>
|
||||||
<button
|
<button
|
||||||
aria-expanded="false"
|
aria-expanded="false"
|
||||||
@ -416,15 +451,15 @@ Object {
|
|||||||
>
|
>
|
||||||
<h4
|
<h4
|
||||||
class="section-min__title"
|
class="section-min__title"
|
||||||
id="pushTitle"
|
id="keywordsAndMentionsTitle"
|
||||||
>
|
>
|
||||||
Mobile Push Notifications
|
Keywords that trigger notifications
|
||||||
</h4>
|
</h4>
|
||||||
<button
|
<button
|
||||||
aria-expanded="false"
|
aria-expanded="false"
|
||||||
aria-labelledby="pushTitle pushEdit"
|
aria-labelledby="keywordsAndMentionsTitle keywordsAndMentionsEdit"
|
||||||
class="color--link style--none section-min__edit"
|
class="color--link style--none section-min__edit"
|
||||||
id="pushEdit"
|
id="keywordsAndMentionsEdit"
|
||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
class="icon-pencil-outline"
|
class="icon-pencil-outline"
|
||||||
@ -435,42 +470,7 @@ Object {
|
|||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="section-min__describe"
|
class="section-min__describe"
|
||||||
id="pushDesc"
|
id="keywordsAndMentionsDesc"
|
||||||
>
|
|
||||||
Never
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
class="divider-light"
|
|
||||||
/>
|
|
||||||
<div
|
|
||||||
class="section-min"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="secion-min__header"
|
|
||||||
>
|
|
||||||
<h4
|
|
||||||
class="section-min__title"
|
|
||||||
id="keysWithNotificationTitle"
|
|
||||||
>
|
|
||||||
Keywords That Trigger Notifications
|
|
||||||
</h4>
|
|
||||||
<button
|
|
||||||
aria-expanded="false"
|
|
||||||
aria-labelledby="keysWithNotificationTitle keysWithNotificationEdit"
|
|
||||||
class="color--link style--none section-min__edit"
|
|
||||||
id="keysWithNotificationEdit"
|
|
||||||
>
|
|
||||||
<i
|
|
||||||
class="icon-pencil-outline"
|
|
||||||
title="Edit Icon"
|
|
||||||
/>
|
|
||||||
Edit
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
class="section-min__describe"
|
|
||||||
id="keysWithNotificationDesc"
|
|
||||||
>
|
>
|
||||||
"@some-user"
|
"@some-user"
|
||||||
</div>
|
</div>
|
||||||
@ -486,15 +486,15 @@ Object {
|
|||||||
>
|
>
|
||||||
<h4
|
<h4
|
||||||
class="section-min__title"
|
class="section-min__title"
|
||||||
id="keysWithHighlightTitle"
|
id="keywordsAndHighlightTitle"
|
||||||
>
|
>
|
||||||
Keywords That Get Highlighted (Without Notifications)
|
Keywords that get highlighted (without notifications)
|
||||||
</h4>
|
</h4>
|
||||||
<button
|
<button
|
||||||
aria-expanded="false"
|
aria-expanded="false"
|
||||||
aria-labelledby="keysWithHighlightTitle keysWithHighlightEdit"
|
aria-labelledby="keywordsAndHighlightTitle keywordsAndHighlightEdit"
|
||||||
class="color--link style--none section-min__edit"
|
class="color--link style--none section-min__edit"
|
||||||
id="keysWithHighlightEdit"
|
id="keywordsAndHighlightEdit"
|
||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
class="icon-pencil-outline"
|
class="icon-pencil-outline"
|
||||||
@ -505,7 +505,7 @@ Object {
|
|||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="section-min__describe"
|
class="section-min__describe"
|
||||||
id="keysWithHighlightDesc"
|
id="keywordsAndHighlightDesc"
|
||||||
>
|
>
|
||||||
None
|
None
|
||||||
</div>
|
</div>
|
||||||
@ -609,7 +609,7 @@ Object {
|
|||||||
class="fa fa-angle-left"
|
class="fa fa-angle-left"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
Notification Settings
|
Notification settings
|
||||||
</h4>
|
</h4>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
@ -663,15 +663,15 @@ Object {
|
|||||||
>
|
>
|
||||||
<h4
|
<h4
|
||||||
class="section-min__title"
|
class="section-min__title"
|
||||||
id="desktopTitle"
|
id="desktopAndMobileTitle"
|
||||||
>
|
>
|
||||||
Desktop Notifications
|
Desktop and mobile notifications
|
||||||
</h4>
|
</h4>
|
||||||
<button
|
<button
|
||||||
aria-expanded="false"
|
aria-expanded="false"
|
||||||
aria-labelledby="desktopTitle desktopEdit"
|
aria-labelledby="desktopAndMobileTitle desktopAndMobileEdit"
|
||||||
class="color--link style--none section-min__edit"
|
class="color--link style--none section-min__edit"
|
||||||
id="desktopEdit"
|
id="desktopAndMobileEdit"
|
||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
class="icon-pencil-outline"
|
class="icon-pencil-outline"
|
||||||
@ -682,9 +682,44 @@ Object {
|
|||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="section-min__describe"
|
class="section-min__describe"
|
||||||
id="desktopDesc"
|
id="desktopAndMobileDesc"
|
||||||
>
|
>
|
||||||
For all activity, without sound
|
Configure desktop and mobile settings
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="divider-light"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="section-min"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="secion-min__header"
|
||||||
|
>
|
||||||
|
<h4
|
||||||
|
class="section-min__title"
|
||||||
|
id="desktopNotificationSoundTitle"
|
||||||
|
>
|
||||||
|
Desktop notification sounds
|
||||||
|
</h4>
|
||||||
|
<button
|
||||||
|
aria-expanded="false"
|
||||||
|
aria-labelledby="desktopNotificationSoundTitle desktopNotificationSoundEdit"
|
||||||
|
class="color--link style--none section-min__edit"
|
||||||
|
id="desktopNotificationSoundEdit"
|
||||||
|
>
|
||||||
|
<i
|
||||||
|
class="icon-pencil-outline"
|
||||||
|
title="Edit Icon"
|
||||||
|
/>
|
||||||
|
Edit
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="section-min__describe"
|
||||||
|
id="desktopNotificationSoundDesc"
|
||||||
|
>
|
||||||
|
No sound
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
@ -700,7 +735,7 @@ Object {
|
|||||||
class="section-min__title"
|
class="section-min__title"
|
||||||
id="emailTitle"
|
id="emailTitle"
|
||||||
>
|
>
|
||||||
Email Notifications
|
Email notifications
|
||||||
</h4>
|
</h4>
|
||||||
<button
|
<button
|
||||||
aria-expanded="false"
|
aria-expanded="false"
|
||||||
@ -733,15 +768,15 @@ Object {
|
|||||||
>
|
>
|
||||||
<h4
|
<h4
|
||||||
class="section-min__title"
|
class="section-min__title"
|
||||||
id="pushTitle"
|
id="keywordsAndMentionsTitle"
|
||||||
>
|
>
|
||||||
Mobile Push Notifications
|
Keywords that trigger notifications
|
||||||
</h4>
|
</h4>
|
||||||
<button
|
<button
|
||||||
aria-expanded="false"
|
aria-expanded="false"
|
||||||
aria-labelledby="pushTitle pushEdit"
|
aria-labelledby="keywordsAndMentionsTitle keywordsAndMentionsEdit"
|
||||||
class="color--link style--none section-min__edit"
|
class="color--link style--none section-min__edit"
|
||||||
id="pushEdit"
|
id="keywordsAndMentionsEdit"
|
||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
class="icon-pencil-outline"
|
class="icon-pencil-outline"
|
||||||
@ -752,42 +787,7 @@ Object {
|
|||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="section-min__describe"
|
class="section-min__describe"
|
||||||
id="pushDesc"
|
id="keywordsAndMentionsDesc"
|
||||||
>
|
|
||||||
Never
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
class="divider-light"
|
|
||||||
/>
|
|
||||||
<div
|
|
||||||
class="section-min"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="secion-min__header"
|
|
||||||
>
|
|
||||||
<h4
|
|
||||||
class="section-min__title"
|
|
||||||
id="keysWithNotificationTitle"
|
|
||||||
>
|
|
||||||
Keywords That Trigger Notifications
|
|
||||||
</h4>
|
|
||||||
<button
|
|
||||||
aria-expanded="false"
|
|
||||||
aria-labelledby="keysWithNotificationTitle keysWithNotificationEdit"
|
|
||||||
class="color--link style--none section-min__edit"
|
|
||||||
id="keysWithNotificationEdit"
|
|
||||||
>
|
|
||||||
<i
|
|
||||||
class="icon-pencil-outline"
|
|
||||||
title="Edit Icon"
|
|
||||||
/>
|
|
||||||
Edit
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
class="section-min__describe"
|
|
||||||
id="keysWithNotificationDesc"
|
|
||||||
>
|
>
|
||||||
"@some-user"
|
"@some-user"
|
||||||
</div>
|
</div>
|
||||||
@ -806,9 +806,9 @@ Object {
|
|||||||
>
|
>
|
||||||
<h4
|
<h4
|
||||||
class="section-min__title isDisabled"
|
class="section-min__title isDisabled"
|
||||||
id="keysWithHighlightTitle"
|
id="keywordsAndHighlightTitle"
|
||||||
>
|
>
|
||||||
Keywords That Get Highlighted (Without Notifications)
|
Keywords that get highlighted (without notifications)
|
||||||
</h4>
|
</h4>
|
||||||
<span
|
<span
|
||||||
class="RestrictedIndicator__icon-tooltip-container"
|
class="RestrictedIndicator__icon-tooltip-container"
|
||||||
@ -828,7 +828,7 @@ Object {
|
|||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="section-min__describe isDisabled"
|
class="section-min__describe isDisabled"
|
||||||
id="keysWithHighlightDesc"
|
id="keywordsAndHighlightDesc"
|
||||||
>
|
>
|
||||||
None
|
None
|
||||||
</div>
|
</div>
|
||||||
@ -870,7 +870,7 @@ Object {
|
|||||||
class="fa fa-angle-left"
|
class="fa fa-angle-left"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
Notification Settings
|
Notification settings
|
||||||
</h4>
|
</h4>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
@ -924,15 +924,15 @@ Object {
|
|||||||
>
|
>
|
||||||
<h4
|
<h4
|
||||||
class="section-min__title"
|
class="section-min__title"
|
||||||
id="desktopTitle"
|
id="desktopAndMobileTitle"
|
||||||
>
|
>
|
||||||
Desktop Notifications
|
Desktop and mobile notifications
|
||||||
</h4>
|
</h4>
|
||||||
<button
|
<button
|
||||||
aria-expanded="false"
|
aria-expanded="false"
|
||||||
aria-labelledby="desktopTitle desktopEdit"
|
aria-labelledby="desktopAndMobileTitle desktopAndMobileEdit"
|
||||||
class="color--link style--none section-min__edit"
|
class="color--link style--none section-min__edit"
|
||||||
id="desktopEdit"
|
id="desktopAndMobileEdit"
|
||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
class="icon-pencil-outline"
|
class="icon-pencil-outline"
|
||||||
@ -943,9 +943,44 @@ Object {
|
|||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="section-min__describe"
|
class="section-min__describe"
|
||||||
id="desktopDesc"
|
id="desktopAndMobileDesc"
|
||||||
>
|
>
|
||||||
For all activity, without sound
|
Configure desktop and mobile settings
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="divider-light"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="section-min"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="secion-min__header"
|
||||||
|
>
|
||||||
|
<h4
|
||||||
|
class="section-min__title"
|
||||||
|
id="desktopNotificationSoundTitle"
|
||||||
|
>
|
||||||
|
Desktop notification sounds
|
||||||
|
</h4>
|
||||||
|
<button
|
||||||
|
aria-expanded="false"
|
||||||
|
aria-labelledby="desktopNotificationSoundTitle desktopNotificationSoundEdit"
|
||||||
|
class="color--link style--none section-min__edit"
|
||||||
|
id="desktopNotificationSoundEdit"
|
||||||
|
>
|
||||||
|
<i
|
||||||
|
class="icon-pencil-outline"
|
||||||
|
title="Edit Icon"
|
||||||
|
/>
|
||||||
|
Edit
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="section-min__describe"
|
||||||
|
id="desktopNotificationSoundDesc"
|
||||||
|
>
|
||||||
|
No sound
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
@ -961,7 +996,7 @@ Object {
|
|||||||
class="section-min__title"
|
class="section-min__title"
|
||||||
id="emailTitle"
|
id="emailTitle"
|
||||||
>
|
>
|
||||||
Email Notifications
|
Email notifications
|
||||||
</h4>
|
</h4>
|
||||||
<button
|
<button
|
||||||
aria-expanded="false"
|
aria-expanded="false"
|
||||||
@ -994,15 +1029,15 @@ Object {
|
|||||||
>
|
>
|
||||||
<h4
|
<h4
|
||||||
class="section-min__title"
|
class="section-min__title"
|
||||||
id="pushTitle"
|
id="keywordsAndMentionsTitle"
|
||||||
>
|
>
|
||||||
Mobile Push Notifications
|
Keywords that trigger notifications
|
||||||
</h4>
|
</h4>
|
||||||
<button
|
<button
|
||||||
aria-expanded="false"
|
aria-expanded="false"
|
||||||
aria-labelledby="pushTitle pushEdit"
|
aria-labelledby="keywordsAndMentionsTitle keywordsAndMentionsEdit"
|
||||||
class="color--link style--none section-min__edit"
|
class="color--link style--none section-min__edit"
|
||||||
id="pushEdit"
|
id="keywordsAndMentionsEdit"
|
||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
class="icon-pencil-outline"
|
class="icon-pencil-outline"
|
||||||
@ -1013,42 +1048,7 @@ Object {
|
|||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="section-min__describe"
|
class="section-min__describe"
|
||||||
id="pushDesc"
|
id="keywordsAndMentionsDesc"
|
||||||
>
|
|
||||||
Never
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
class="divider-light"
|
|
||||||
/>
|
|
||||||
<div
|
|
||||||
class="section-min"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="secion-min__header"
|
|
||||||
>
|
|
||||||
<h4
|
|
||||||
class="section-min__title"
|
|
||||||
id="keysWithNotificationTitle"
|
|
||||||
>
|
|
||||||
Keywords That Trigger Notifications
|
|
||||||
</h4>
|
|
||||||
<button
|
|
||||||
aria-expanded="false"
|
|
||||||
aria-labelledby="keysWithNotificationTitle keysWithNotificationEdit"
|
|
||||||
class="color--link style--none section-min__edit"
|
|
||||||
id="keysWithNotificationEdit"
|
|
||||||
>
|
|
||||||
<i
|
|
||||||
class="icon-pencil-outline"
|
|
||||||
title="Edit Icon"
|
|
||||||
/>
|
|
||||||
Edit
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
class="section-min__describe"
|
|
||||||
id="keysWithNotificationDesc"
|
|
||||||
>
|
>
|
||||||
"@some-user"
|
"@some-user"
|
||||||
</div>
|
</div>
|
||||||
@ -1067,9 +1067,9 @@ Object {
|
|||||||
>
|
>
|
||||||
<h4
|
<h4
|
||||||
class="section-min__title isDisabled"
|
class="section-min__title isDisabled"
|
||||||
id="keysWithHighlightTitle"
|
id="keywordsAndHighlightTitle"
|
||||||
>
|
>
|
||||||
Keywords That Get Highlighted (Without Notifications)
|
Keywords that get highlighted (without notifications)
|
||||||
</h4>
|
</h4>
|
||||||
<span
|
<span
|
||||||
class="RestrictedIndicator__icon-tooltip-container"
|
class="RestrictedIndicator__icon-tooltip-container"
|
||||||
@ -1089,7 +1089,7 @@ Object {
|
|||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="section-min__describe isDisabled"
|
class="section-min__describe isDisabled"
|
||||||
id="keysWithHighlightDesc"
|
id="keywordsAndHighlightDesc"
|
||||||
>
|
>
|
||||||
None
|
None
|
||||||
</div>
|
</div>
|
||||||
@ -1190,7 +1190,7 @@ Object {
|
|||||||
class="fa fa-angle-left"
|
class="fa fa-angle-left"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
Notification Settings
|
Notification settings
|
||||||
</h4>
|
</h4>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
@ -1244,15 +1244,15 @@ Object {
|
|||||||
>
|
>
|
||||||
<h4
|
<h4
|
||||||
class="section-min__title"
|
class="section-min__title"
|
||||||
id="desktopTitle"
|
id="desktopAndMobileTitle"
|
||||||
>
|
>
|
||||||
Desktop Notifications
|
Desktop and mobile notifications
|
||||||
</h4>
|
</h4>
|
||||||
<button
|
<button
|
||||||
aria-expanded="false"
|
aria-expanded="false"
|
||||||
aria-labelledby="desktopTitle desktopEdit"
|
aria-labelledby="desktopAndMobileTitle desktopAndMobileEdit"
|
||||||
class="color--link style--none section-min__edit"
|
class="color--link style--none section-min__edit"
|
||||||
id="desktopEdit"
|
id="desktopAndMobileEdit"
|
||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
class="icon-pencil-outline"
|
class="icon-pencil-outline"
|
||||||
@ -1263,9 +1263,44 @@ Object {
|
|||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="section-min__describe"
|
class="section-min__describe"
|
||||||
id="desktopDesc"
|
id="desktopAndMobileDesc"
|
||||||
>
|
>
|
||||||
For all activity, without sound
|
Configure desktop and mobile settings
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="divider-light"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="section-min"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="secion-min__header"
|
||||||
|
>
|
||||||
|
<h4
|
||||||
|
class="section-min__title"
|
||||||
|
id="desktopNotificationSoundTitle"
|
||||||
|
>
|
||||||
|
Desktop notification sounds
|
||||||
|
</h4>
|
||||||
|
<button
|
||||||
|
aria-expanded="false"
|
||||||
|
aria-labelledby="desktopNotificationSoundTitle desktopNotificationSoundEdit"
|
||||||
|
class="color--link style--none section-min__edit"
|
||||||
|
id="desktopNotificationSoundEdit"
|
||||||
|
>
|
||||||
|
<i
|
||||||
|
class="icon-pencil-outline"
|
||||||
|
title="Edit Icon"
|
||||||
|
/>
|
||||||
|
Edit
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="section-min__describe"
|
||||||
|
id="desktopNotificationSoundDesc"
|
||||||
|
>
|
||||||
|
No sound
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
@ -1281,7 +1316,7 @@ Object {
|
|||||||
class="section-min__title"
|
class="section-min__title"
|
||||||
id="emailTitle"
|
id="emailTitle"
|
||||||
>
|
>
|
||||||
Email Notifications
|
Email notifications
|
||||||
</h4>
|
</h4>
|
||||||
<button
|
<button
|
||||||
aria-expanded="false"
|
aria-expanded="false"
|
||||||
@ -1314,15 +1349,15 @@ Object {
|
|||||||
>
|
>
|
||||||
<h4
|
<h4
|
||||||
class="section-min__title"
|
class="section-min__title"
|
||||||
id="pushTitle"
|
id="keywordsAndMentionsTitle"
|
||||||
>
|
>
|
||||||
Mobile Push Notifications
|
Keywords that trigger notifications
|
||||||
</h4>
|
</h4>
|
||||||
<button
|
<button
|
||||||
aria-expanded="false"
|
aria-expanded="false"
|
||||||
aria-labelledby="pushTitle pushEdit"
|
aria-labelledby="keywordsAndMentionsTitle keywordsAndMentionsEdit"
|
||||||
class="color--link style--none section-min__edit"
|
class="color--link style--none section-min__edit"
|
||||||
id="pushEdit"
|
id="keywordsAndMentionsEdit"
|
||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
class="icon-pencil-outline"
|
class="icon-pencil-outline"
|
||||||
@ -1333,42 +1368,7 @@ Object {
|
|||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="section-min__describe"
|
class="section-min__describe"
|
||||||
id="pushDesc"
|
id="keywordsAndMentionsDesc"
|
||||||
>
|
|
||||||
Never
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
class="divider-light"
|
|
||||||
/>
|
|
||||||
<div
|
|
||||||
class="section-min"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="secion-min__header"
|
|
||||||
>
|
|
||||||
<h4
|
|
||||||
class="section-min__title"
|
|
||||||
id="keysWithNotificationTitle"
|
|
||||||
>
|
|
||||||
Keywords That Trigger Notifications
|
|
||||||
</h4>
|
|
||||||
<button
|
|
||||||
aria-expanded="false"
|
|
||||||
aria-labelledby="keysWithNotificationTitle keysWithNotificationEdit"
|
|
||||||
class="color--link style--none section-min__edit"
|
|
||||||
id="keysWithNotificationEdit"
|
|
||||||
>
|
|
||||||
<i
|
|
||||||
class="icon-pencil-outline"
|
|
||||||
title="Edit Icon"
|
|
||||||
/>
|
|
||||||
Edit
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
class="section-min__describe"
|
|
||||||
id="keysWithNotificationDesc"
|
|
||||||
>
|
>
|
||||||
"@some-user"
|
"@some-user"
|
||||||
</div>
|
</div>
|
||||||
@ -1413,7 +1413,7 @@ Object {
|
|||||||
class="fa fa-angle-left"
|
class="fa fa-angle-left"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
Notification Settings
|
Notification settings
|
||||||
</h4>
|
</h4>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
@ -1467,15 +1467,15 @@ Object {
|
|||||||
>
|
>
|
||||||
<h4
|
<h4
|
||||||
class="section-min__title"
|
class="section-min__title"
|
||||||
id="desktopTitle"
|
id="desktopAndMobileTitle"
|
||||||
>
|
>
|
||||||
Desktop Notifications
|
Desktop and mobile notifications
|
||||||
</h4>
|
</h4>
|
||||||
<button
|
<button
|
||||||
aria-expanded="false"
|
aria-expanded="false"
|
||||||
aria-labelledby="desktopTitle desktopEdit"
|
aria-labelledby="desktopAndMobileTitle desktopAndMobileEdit"
|
||||||
class="color--link style--none section-min__edit"
|
class="color--link style--none section-min__edit"
|
||||||
id="desktopEdit"
|
id="desktopAndMobileEdit"
|
||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
class="icon-pencil-outline"
|
class="icon-pencil-outline"
|
||||||
@ -1486,9 +1486,44 @@ Object {
|
|||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="section-min__describe"
|
class="section-min__describe"
|
||||||
id="desktopDesc"
|
id="desktopAndMobileDesc"
|
||||||
>
|
>
|
||||||
For all activity, without sound
|
Configure desktop and mobile settings
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="divider-light"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="section-min"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="secion-min__header"
|
||||||
|
>
|
||||||
|
<h4
|
||||||
|
class="section-min__title"
|
||||||
|
id="desktopNotificationSoundTitle"
|
||||||
|
>
|
||||||
|
Desktop notification sounds
|
||||||
|
</h4>
|
||||||
|
<button
|
||||||
|
aria-expanded="false"
|
||||||
|
aria-labelledby="desktopNotificationSoundTitle desktopNotificationSoundEdit"
|
||||||
|
class="color--link style--none section-min__edit"
|
||||||
|
id="desktopNotificationSoundEdit"
|
||||||
|
>
|
||||||
|
<i
|
||||||
|
class="icon-pencil-outline"
|
||||||
|
title="Edit Icon"
|
||||||
|
/>
|
||||||
|
Edit
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="section-min__describe"
|
||||||
|
id="desktopNotificationSoundDesc"
|
||||||
|
>
|
||||||
|
No sound
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
@ -1504,7 +1539,7 @@ Object {
|
|||||||
class="section-min__title"
|
class="section-min__title"
|
||||||
id="emailTitle"
|
id="emailTitle"
|
||||||
>
|
>
|
||||||
Email Notifications
|
Email notifications
|
||||||
</h4>
|
</h4>
|
||||||
<button
|
<button
|
||||||
aria-expanded="false"
|
aria-expanded="false"
|
||||||
@ -1537,15 +1572,15 @@ Object {
|
|||||||
>
|
>
|
||||||
<h4
|
<h4
|
||||||
class="section-min__title"
|
class="section-min__title"
|
||||||
id="pushTitle"
|
id="keywordsAndMentionsTitle"
|
||||||
>
|
>
|
||||||
Mobile Push Notifications
|
Keywords that trigger notifications
|
||||||
</h4>
|
</h4>
|
||||||
<button
|
<button
|
||||||
aria-expanded="false"
|
aria-expanded="false"
|
||||||
aria-labelledby="pushTitle pushEdit"
|
aria-labelledby="keywordsAndMentionsTitle keywordsAndMentionsEdit"
|
||||||
class="color--link style--none section-min__edit"
|
class="color--link style--none section-min__edit"
|
||||||
id="pushEdit"
|
id="keywordsAndMentionsEdit"
|
||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
class="icon-pencil-outline"
|
class="icon-pencil-outline"
|
||||||
@ -1556,42 +1591,7 @@ Object {
|
|||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="section-min__describe"
|
class="section-min__describe"
|
||||||
id="pushDesc"
|
id="keywordsAndMentionsDesc"
|
||||||
>
|
|
||||||
Never
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
class="divider-light"
|
|
||||||
/>
|
|
||||||
<div
|
|
||||||
class="section-min"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="secion-min__header"
|
|
||||||
>
|
|
||||||
<h4
|
|
||||||
class="section-min__title"
|
|
||||||
id="keysWithNotificationTitle"
|
|
||||||
>
|
|
||||||
Keywords That Trigger Notifications
|
|
||||||
</h4>
|
|
||||||
<button
|
|
||||||
aria-expanded="false"
|
|
||||||
aria-labelledby="keysWithNotificationTitle keysWithNotificationEdit"
|
|
||||||
class="color--link style--none section-min__edit"
|
|
||||||
id="keysWithNotificationEdit"
|
|
||||||
>
|
|
||||||
<i
|
|
||||||
class="icon-pencil-outline"
|
|
||||||
title="Edit Icon"
|
|
||||||
/>
|
|
||||||
Edit
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
class="section-min__describe"
|
|
||||||
id="keysWithNotificationDesc"
|
|
||||||
>
|
>
|
||||||
"@some-user"
|
"@some-user"
|
||||||
</div>
|
</div>
|
||||||
|
@ -0,0 +1,359 @@
|
|||||||
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
|
exports[`DesktopNotificationSettings should match snapshot, on max setting 1`] = `
|
||||||
|
<div>
|
||||||
|
<section
|
||||||
|
class="section-max form-horizontal "
|
||||||
|
>
|
||||||
|
<h4
|
||||||
|
class="col-sm-12 section-title"
|
||||||
|
id="settingTitle"
|
||||||
|
>
|
||||||
|
Desktop and mobile notifications
|
||||||
|
</h4>
|
||||||
|
<div
|
||||||
|
class="sectionContent col-sm-10 col-sm-offset-2"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="setting-list"
|
||||||
|
tabindex="-1"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="setting-list-item"
|
||||||
|
>
|
||||||
|
<fieldset
|
||||||
|
id="sendDesktopNotificationsSection"
|
||||||
|
>
|
||||||
|
<legend
|
||||||
|
class="form-legend"
|
||||||
|
>
|
||||||
|
Send notifications for:
|
||||||
|
</legend>
|
||||||
|
<div
|
||||||
|
class="radio"
|
||||||
|
>
|
||||||
|
<label>
|
||||||
|
<input
|
||||||
|
type="radio"
|
||||||
|
value="all"
|
||||||
|
/>
|
||||||
|
All new messages
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="radio"
|
||||||
|
>
|
||||||
|
<label>
|
||||||
|
<input
|
||||||
|
type="radio"
|
||||||
|
value="mention"
|
||||||
|
/>
|
||||||
|
Mentions, direct messages, and group messages
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="radio"
|
||||||
|
>
|
||||||
|
<label>
|
||||||
|
<input
|
||||||
|
type="radio"
|
||||||
|
value="none"
|
||||||
|
/>
|
||||||
|
Nothing
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</fieldset>
|
||||||
|
<br />
|
||||||
|
<div
|
||||||
|
class="checkbox single-checkbox"
|
||||||
|
>
|
||||||
|
<label>
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
/>
|
||||||
|
Notify me about replies to threads I'm following
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<hr />
|
||||||
|
<div
|
||||||
|
class="checkbox single-checkbox"
|
||||||
|
>
|
||||||
|
<label>
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
/>
|
||||||
|
Use different settings for my mobile devices
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<br />
|
||||||
|
<label
|
||||||
|
class="singleSelectLabel"
|
||||||
|
for="pushMobileNotificationSelectInput"
|
||||||
|
id="pushMobileNotificationsLabel"
|
||||||
|
>
|
||||||
|
Trigger mobile notifications when I am:
|
||||||
|
</label>
|
||||||
|
<div
|
||||||
|
class="react-select singleSelect css-2b097c-container"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="react-select__control css-yk16xz-control"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="react-select__value-container react-select__value-container--has-value css-1hwfws3"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="react-select__single-value css-1uccc91-singleValue"
|
||||||
|
>
|
||||||
|
Offline
|
||||||
|
</div>
|
||||||
|
<input
|
||||||
|
class="css-62g3xt-dummyInput"
|
||||||
|
id="pushMobileNotificationSelectInput"
|
||||||
|
readonly=""
|
||||||
|
tabindex="0"
|
||||||
|
value=""
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="react-select__indicators css-1hb7zxy-IndicatorsContainer"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
aria-hidden="true"
|
||||||
|
class="react-select__indicator react-select__dropdown-indicator css-tlfecz-indicatorContainer"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
aria-hidden="true"
|
||||||
|
class="css-6q0nyr-Svg"
|
||||||
|
focusable="false"
|
||||||
|
height="20"
|
||||||
|
viewBox="0 0 20 20"
|
||||||
|
width="20"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M4.516 7.548c0.436-0.446 1.043-0.481 1.576 0l3.908 3.747 3.908-3.747c0.533-0.481 1.141-0.446 1.574 0 0.436 0.445 0.408 1.197 0 1.615-0.406 0.418-4.695 4.502-4.695 4.502-0.217 0.223-0.502 0.335-0.787 0.335s-0.57-0.112-0.789-0.335c0 0-4.287-4.084-4.695-4.502s-0.436-1.17 0-1.615z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="setting-list-item"
|
||||||
|
>
|
||||||
|
<hr />
|
||||||
|
<button
|
||||||
|
class="btn btn-primary "
|
||||||
|
data-testid="saveSetting"
|
||||||
|
id="saveSetting"
|
||||||
|
type="submit"
|
||||||
|
>
|
||||||
|
<span>
|
||||||
|
Save
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class="btn btn-tertiary"
|
||||||
|
id="cancelSetting"
|
||||||
|
>
|
||||||
|
Cancel
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`DesktopNotificationSettings should match snapshot, on min setting 1`] = `
|
||||||
|
<div>
|
||||||
|
<div
|
||||||
|
class="section-min"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="secion-min__header"
|
||||||
|
>
|
||||||
|
<h4
|
||||||
|
class="section-min__title"
|
||||||
|
id="desktopAndMobileTitle"
|
||||||
|
>
|
||||||
|
Desktop and mobile notifications
|
||||||
|
</h4>
|
||||||
|
<button
|
||||||
|
aria-expanded="false"
|
||||||
|
aria-labelledby="desktopAndMobileTitle desktopAndMobileEdit"
|
||||||
|
class="color--link style--none section-min__edit"
|
||||||
|
id="desktopAndMobileEdit"
|
||||||
|
>
|
||||||
|
<i
|
||||||
|
class="icon-pencil-outline"
|
||||||
|
title="Edit Icon"
|
||||||
|
/>
|
||||||
|
Edit
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="section-min__describe"
|
||||||
|
id="desktopAndMobileDesc"
|
||||||
|
>
|
||||||
|
Configure desktop and mobile settings
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`DesktopNotificationSettings should not show desktop thread notification checkbox when collapsed threads are not enabled 1`] = `
|
||||||
|
<div>
|
||||||
|
<section
|
||||||
|
class="section-max form-horizontal "
|
||||||
|
>
|
||||||
|
<h4
|
||||||
|
class="col-sm-12 section-title"
|
||||||
|
id="settingTitle"
|
||||||
|
>
|
||||||
|
Desktop and mobile notifications
|
||||||
|
</h4>
|
||||||
|
<div
|
||||||
|
class="sectionContent col-sm-10 col-sm-offset-2"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="setting-list"
|
||||||
|
tabindex="-1"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="setting-list-item"
|
||||||
|
>
|
||||||
|
<fieldset
|
||||||
|
id="sendDesktopNotificationsSection"
|
||||||
|
>
|
||||||
|
<legend
|
||||||
|
class="form-legend"
|
||||||
|
>
|
||||||
|
Send notifications for:
|
||||||
|
</legend>
|
||||||
|
<div
|
||||||
|
class="radio"
|
||||||
|
>
|
||||||
|
<label>
|
||||||
|
<input
|
||||||
|
type="radio"
|
||||||
|
value="all"
|
||||||
|
/>
|
||||||
|
All new messages
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="radio"
|
||||||
|
>
|
||||||
|
<label>
|
||||||
|
<input
|
||||||
|
type="radio"
|
||||||
|
value="mention"
|
||||||
|
/>
|
||||||
|
Mentions, direct messages, and group messages
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="radio"
|
||||||
|
>
|
||||||
|
<label>
|
||||||
|
<input
|
||||||
|
type="radio"
|
||||||
|
value="none"
|
||||||
|
/>
|
||||||
|
Nothing
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</fieldset>
|
||||||
|
<hr />
|
||||||
|
<div
|
||||||
|
class="checkbox single-checkbox"
|
||||||
|
>
|
||||||
|
<label>
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
/>
|
||||||
|
Use different settings for my mobile devices
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<br />
|
||||||
|
<label
|
||||||
|
class="singleSelectLabel"
|
||||||
|
for="pushMobileNotificationSelectInput"
|
||||||
|
id="pushMobileNotificationsLabel"
|
||||||
|
>
|
||||||
|
Trigger mobile notifications when I am:
|
||||||
|
</label>
|
||||||
|
<div
|
||||||
|
class="react-select singleSelect css-2b097c-container"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="react-select__control css-yk16xz-control"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="react-select__value-container react-select__value-container--has-value css-1hwfws3"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="react-select__single-value css-1uccc91-singleValue"
|
||||||
|
>
|
||||||
|
Offline
|
||||||
|
</div>
|
||||||
|
<input
|
||||||
|
class="css-62g3xt-dummyInput"
|
||||||
|
id="pushMobileNotificationSelectInput"
|
||||||
|
readonly=""
|
||||||
|
tabindex="0"
|
||||||
|
value=""
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="react-select__indicators css-1hb7zxy-IndicatorsContainer"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
aria-hidden="true"
|
||||||
|
class="react-select__indicator react-select__dropdown-indicator css-tlfecz-indicatorContainer"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
aria-hidden="true"
|
||||||
|
class="css-6q0nyr-Svg"
|
||||||
|
focusable="false"
|
||||||
|
height="20"
|
||||||
|
viewBox="0 0 20 20"
|
||||||
|
width="20"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M4.516 7.548c0.436-0.446 1.043-0.481 1.576 0l3.908 3.747 3.908-3.747c0.533-0.481 1.141-0.446 1.574 0 0.436 0.445 0.408 1.197 0 1.615-0.406 0.418-4.695 4.502-4.695 4.502-0.217 0.223-0.502 0.335-0.787 0.335s-0.57-0.112-0.789-0.335c0 0-4.287-4.084-4.695-4.502s-0.436-1.17 0-1.615z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="setting-list-item"
|
||||||
|
>
|
||||||
|
<hr />
|
||||||
|
<button
|
||||||
|
class="btn btn-primary "
|
||||||
|
data-testid="saveSetting"
|
||||||
|
id="saveSetting"
|
||||||
|
type="submit"
|
||||||
|
>
|
||||||
|
<span>
|
||||||
|
Save
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class="btn btn-tertiary"
|
||||||
|
id="cancelSetting"
|
||||||
|
>
|
||||||
|
Cancel
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
`;
|
@ -0,0 +1,312 @@
|
|||||||
|
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||||
|
// See LICENSE.txt for license information.
|
||||||
|
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import {renderWithContext, screen} from 'tests/react_testing_utils';
|
||||||
|
import Constants, {NotificationLevels} from 'utils/constants';
|
||||||
|
|
||||||
|
import type {SelectOption, Props} from './index';
|
||||||
|
import DesktopNotificationSettings, {
|
||||||
|
shouldShowDesktopThreadsSection,
|
||||||
|
shouldShowMobileThreadsSection,
|
||||||
|
getValueOfSendMobileNotificationForSelect,
|
||||||
|
getValueOfSendMobileNotificationWhenSelect,
|
||||||
|
shouldShowTriggerMobileNotificationsSection,
|
||||||
|
} from './index';
|
||||||
|
|
||||||
|
const validNotificationLevels = Object.values(NotificationLevels);
|
||||||
|
|
||||||
|
describe('DesktopNotificationSettings', () => {
|
||||||
|
const baseProps: Props = {
|
||||||
|
active: true,
|
||||||
|
updateSection: jest.fn(),
|
||||||
|
onSubmit: jest.fn(),
|
||||||
|
onCancel: jest.fn(),
|
||||||
|
saving: false,
|
||||||
|
error: '',
|
||||||
|
setParentState: jest.fn(),
|
||||||
|
areAllSectionsInactive: false,
|
||||||
|
isCollapsedThreadsEnabled: true,
|
||||||
|
desktopActivity: NotificationLevels.DEFAULT,
|
||||||
|
pushActivity: NotificationLevels.DEFAULT,
|
||||||
|
pushStatus: Constants.UserStatuses.OFFLINE,
|
||||||
|
desktopThreads: NotificationLevels.DEFAULT,
|
||||||
|
pushThreads: NotificationLevels.DEFAULT,
|
||||||
|
sendPushNotifications: true,
|
||||||
|
desktopAndMobileSettingsDifferent: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
test('should match snapshot, on max setting', () => {
|
||||||
|
const {container} = renderWithContext(
|
||||||
|
<DesktopNotificationSettings {...baseProps}/>,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(container).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should match snapshot, on min setting', () => {
|
||||||
|
const props = {...baseProps, active: false};
|
||||||
|
const {container} = renderWithContext(
|
||||||
|
<DesktopNotificationSettings {...props}/>,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(container).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should not show desktop thread notification checkbox when collapsed threads are not enabled', () => {
|
||||||
|
const props = {...baseProps, isCollapsedThreadsEnabled: false};
|
||||||
|
const {container} = renderWithContext(
|
||||||
|
<DesktopNotificationSettings {...props}/>,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(screen.queryByText('Notify me about replies to threads I\'m following')).toBeNull();
|
||||||
|
expect(container).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should not show desktop thread notification checkbox when desktop is all', () => {
|
||||||
|
const props = {...baseProps, desktopActivity: NotificationLevels.ALL};
|
||||||
|
renderWithContext(
|
||||||
|
<DesktopNotificationSettings {...props}/>,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(screen.queryByText('Notify me about replies to threads I\'m following')).toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should not show desktop thread notification checkbox when desktop is none', () => {
|
||||||
|
const props = {...baseProps, desktopActivity: NotificationLevels.NONE};
|
||||||
|
renderWithContext(
|
||||||
|
<DesktopNotificationSettings {...props}/>,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(screen.queryByText('Notify me about replies to threads I\'m following')).toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should show desktop thread notification checkbox when desktop is mention', () => {
|
||||||
|
const props = {...baseProps, desktopActivity: NotificationLevels.MENTION};
|
||||||
|
renderWithContext(
|
||||||
|
<DesktopNotificationSettings {...props}/>,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(screen.getByText('Notify me about replies to threads I\'m following')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should show mobile notification when checkbox for use different mobile settings is checked', () => {
|
||||||
|
const props = {...baseProps, desktopAndMobileSettingsDifferent: true};
|
||||||
|
renderWithContext(
|
||||||
|
<DesktopNotificationSettings {...props}/>,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(screen.getByText('Send mobile notifications for:')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should not show mobile notification when checkbox for use different mobile settings is not checked', () => {
|
||||||
|
const props = {...baseProps, desktopAndMobileSettingsDifferent: false};
|
||||||
|
renderWithContext(
|
||||||
|
<DesktopNotificationSettings {...props}/>,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(screen.queryByText('Send mobile notifications for:')).toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should shown notify me about mobile threads when mobile setting is mention and desktop setting is anything', () => {
|
||||||
|
const {rerender} = renderWithContext(
|
||||||
|
<DesktopNotificationSettings
|
||||||
|
{...baseProps}
|
||||||
|
desktopAndMobileSettingsDifferent={true}
|
||||||
|
pushActivity={NotificationLevels.MENTION}
|
||||||
|
desktopActivity={NotificationLevels.NONE}
|
||||||
|
/>,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(screen.getByText('Notify me on mobile about replies to threads I\'m following')).toBeInTheDocument();
|
||||||
|
|
||||||
|
rerender(
|
||||||
|
<DesktopNotificationSettings
|
||||||
|
{...baseProps}
|
||||||
|
desktopAndMobileSettingsDifferent={true}
|
||||||
|
pushActivity={NotificationLevels.MENTION}
|
||||||
|
desktopActivity={NotificationLevels.ALL}
|
||||||
|
/>,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(screen.getByText('Notify me on mobile about replies to threads I\'m following')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should not show notify me about mobile threads when mobile setting is anything other than mention', () => {
|
||||||
|
const {rerender} = renderWithContext(
|
||||||
|
<DesktopNotificationSettings
|
||||||
|
{...baseProps}
|
||||||
|
desktopAndMobileSettingsDifferent={true}
|
||||||
|
pushActivity={NotificationLevels.NONE}
|
||||||
|
desktopActivity={NotificationLevels.NONE}
|
||||||
|
/>,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(screen.queryByText('Notify me on mobile about replies to threads I\'m following')).toBeNull();
|
||||||
|
|
||||||
|
rerender(
|
||||||
|
<DesktopNotificationSettings
|
||||||
|
{...baseProps}
|
||||||
|
desktopAndMobileSettingsDifferent={true}
|
||||||
|
pushActivity={NotificationLevels.ALL}
|
||||||
|
desktopActivity={NotificationLevels.ALL}
|
||||||
|
/>,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(screen.queryByText('Notify me on mobile about replies to threads I\'m following')).toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should show trigger mobile notifications section when desktop setting is mention', () => {
|
||||||
|
const props = {...baseProps, desktopActivity: NotificationLevels.MENTION, desktopAndMobileSettingsDifferent: false};
|
||||||
|
renderWithContext(
|
||||||
|
<DesktopNotificationSettings {...props}/>,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(screen.getByText('Trigger mobile notifications when I am:')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should not show trigger mobile notifications section when desktop setting is none', () => {
|
||||||
|
const props = {...baseProps, desktopActivity: NotificationLevels.NONE, desktopAndMobileSettingsDifferent: false};
|
||||||
|
renderWithContext(
|
||||||
|
<DesktopNotificationSettings {...props}/>,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(screen.queryByText('Trigger mobile notifications when I am:')).toBeNull();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('shouldShowDesktopThreadsSection', () => {
|
||||||
|
test('should not show when collapsed threads are not enabled', () => {
|
||||||
|
expect(shouldShowDesktopThreadsSection(false, 'hello' as any)).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should not show when desktop setting is either none or all', () => {
|
||||||
|
expect(shouldShowDesktopThreadsSection(true, NotificationLevels.NONE)).toBe(false);
|
||||||
|
expect(shouldShowDesktopThreadsSection(true, NotificationLevels.ALL)).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should show when desktop setting is mention', () => {
|
||||||
|
expect(shouldShowDesktopThreadsSection(true, NotificationLevels.MENTION)).toBe(true);
|
||||||
|
expect(shouldShowDesktopThreadsSection(true, NotificationLevels.DEFAULT)).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should show by default when desktop setting is undefined', () => {
|
||||||
|
expect(shouldShowDesktopThreadsSection(true, undefined as any)).toBe(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('shouldShowMobileThreadsSection', () => {
|
||||||
|
test('should return false if sendPushNotifications is false', () => {
|
||||||
|
const result = shouldShowMobileThreadsSection(false, true, true, 'any' as any);
|
||||||
|
expect(result).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should return false if isCollapsedThreadsEnabled is false', () => {
|
||||||
|
const result = shouldShowMobileThreadsSection(true, false, true, 'any' as any);
|
||||||
|
expect(result).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should return false if desktop and mobile settings are same', () => {
|
||||||
|
const result = shouldShowMobileThreadsSection(true, true, false, 'any' as any);
|
||||||
|
expect(result).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should return false if pushActivity is all', () => {
|
||||||
|
const result = shouldShowMobileThreadsSection(true, true, true, NotificationLevels.ALL);
|
||||||
|
expect(result).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should return false if pushActivity is none', () => {
|
||||||
|
const result = shouldShowMobileThreadsSection(true, true, true, NotificationLevels.NONE);
|
||||||
|
expect(result).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('getValueOfSendMobileNotificationForSelect', () => {
|
||||||
|
test('should return the middle option when input is undefined', () => {
|
||||||
|
expect(getValueOfSendMobileNotificationForSelect(undefined as any)).not.toBeUndefined();
|
||||||
|
|
||||||
|
const result = getValueOfSendMobileNotificationForSelect(undefined as any) as SelectOption;
|
||||||
|
expect(result.value).toBe(NotificationLevels.MENTION);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should return the middle option when input is not a valid option', () => {
|
||||||
|
expect(getValueOfSendMobileNotificationForSelect('invalid' as any)).not.toBeUndefined();
|
||||||
|
|
||||||
|
const result = getValueOfSendMobileNotificationForSelect('invalid' as any) as SelectOption;
|
||||||
|
expect(result.value).toBe(NotificationLevels.MENTION);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should return the same option when input is a valid option', () => {
|
||||||
|
validNotificationLevels.
|
||||||
|
filter((level) => level !== NotificationLevels.DEFAULT).
|
||||||
|
forEach((level) => {
|
||||||
|
expect(getValueOfSendMobileNotificationForSelect(level)).not.toBeUndefined();
|
||||||
|
|
||||||
|
const result = getValueOfSendMobileNotificationForSelect(level) as SelectOption;
|
||||||
|
expect(result.value).toBe(level);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('shouldShowTriggerMobileNotificationsSection', () => {
|
||||||
|
test('should not show when push notifications are off', () => {
|
||||||
|
expect(shouldShowTriggerMobileNotificationsSection(false, NotificationLevels.ALL, NotificationLevels.ALL, true)).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should show if either of desktop or mobile settings are not defined', () => {
|
||||||
|
expect(shouldShowTriggerMobileNotificationsSection(true, undefined as any, NotificationLevels.ALL, true)).toBe(true);
|
||||||
|
expect(shouldShowTriggerMobileNotificationsSection(true, NotificationLevels.ALL, undefined as any, true)).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should show if desktop is either mention or all for same mobile setting', () => {
|
||||||
|
expect(shouldShowTriggerMobileNotificationsSection(true, NotificationLevels.MENTION, NotificationLevels.MENTION, false)).toBe(true);
|
||||||
|
expect(shouldShowTriggerMobileNotificationsSection(true, NotificationLevels.ALL, NotificationLevels.ALL, false)).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should not show if desktop is none for same mobile setting', () => {
|
||||||
|
expect(shouldShowTriggerMobileNotificationsSection(true, NotificationLevels.NONE, NotificationLevels.NONE, false)).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should show for any desktop setting if mobile setting is mention', () => {
|
||||||
|
expect(shouldShowTriggerMobileNotificationsSection(true, NotificationLevels.ALL, NotificationLevels.MENTION, true)).toBe(true);
|
||||||
|
expect(shouldShowTriggerMobileNotificationsSection(true, NotificationLevels.MENTION, NotificationLevels.MENTION, true)).toBe(true);
|
||||||
|
expect(shouldShowTriggerMobileNotificationsSection(true, NotificationLevels.NONE, NotificationLevels.MENTION, true)).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should not show for any desktop setting if mobile setting is none', () => {
|
||||||
|
expect(shouldShowTriggerMobileNotificationsSection(true, NotificationLevels.ALL, NotificationLevels.NONE, true)).toBe(false);
|
||||||
|
expect(shouldShowTriggerMobileNotificationsSection(true, NotificationLevels.MENTION, NotificationLevels.NONE, true)).toBe(false);
|
||||||
|
expect(shouldShowTriggerMobileNotificationsSection(true, NotificationLevels.NONE, NotificationLevels.NONE, true)).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('getValueOfSendMobileNotificationWhenSelect', () => {
|
||||||
|
test('When input is undefined it should return the last option', () => {
|
||||||
|
expect(getValueOfSendMobileNotificationWhenSelect(undefined)).not.toBeUndefined();
|
||||||
|
|
||||||
|
const result = getValueOfSendMobileNotificationWhenSelect(undefined) as SelectOption;
|
||||||
|
expect(result.value).toBe(Constants.UserStatuses.OFFLINE);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('when input is defined but is not a valid option it should return the last option', () => {
|
||||||
|
// We are purposely testing with an invalid value hence the 'any'
|
||||||
|
expect(getValueOfSendMobileNotificationWhenSelect('invalid' as any)).not.toBeUndefined();
|
||||||
|
|
||||||
|
const result = getValueOfSendMobileNotificationWhenSelect('invalid' as any) as SelectOption;
|
||||||
|
expect(result.value).toBe(Constants.UserStatuses.OFFLINE);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('When input is a valid option it should return the same option', () => {
|
||||||
|
expect(getValueOfSendMobileNotificationWhenSelect(Constants.UserStatuses.ONLINE)).not.toBeUndefined();
|
||||||
|
|
||||||
|
const result = getValueOfSendMobileNotificationWhenSelect(Constants.UserStatuses.ONLINE) as SelectOption;
|
||||||
|
expect(result.value).toBe(Constants.UserStatuses.ONLINE);
|
||||||
|
|
||||||
|
expect(getValueOfSendMobileNotificationWhenSelect(Constants.UserStatuses.AWAY)).not.toBeUndefined();
|
||||||
|
|
||||||
|
const result2 = getValueOfSendMobileNotificationWhenSelect(Constants.UserStatuses.AWAY) as SelectOption;
|
||||||
|
expect(result2.value).toBe(Constants.UserStatuses.AWAY);
|
||||||
|
});
|
||||||
|
});
|
@ -0,0 +1,582 @@
|
|||||||
|
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||||
|
// See LICENSE.txt for license information.
|
||||||
|
|
||||||
|
import React, {Fragment, useCallback, useEffect, useMemo, useRef, memo} from 'react';
|
||||||
|
import type {ChangeEvent, ReactNode} from 'react';
|
||||||
|
import {FormattedMessage} from 'react-intl';
|
||||||
|
import ReactSelect from 'react-select';
|
||||||
|
import type {ValueType, OptionsType} from 'react-select';
|
||||||
|
|
||||||
|
import type {UserNotifyProps} from '@mattermost/types/users';
|
||||||
|
|
||||||
|
import SettingItemMax from 'components/setting_item_max';
|
||||||
|
import SettingItemMin from 'components/setting_item_min';
|
||||||
|
import type SettingItemMinComponent from 'components/setting_item_min';
|
||||||
|
|
||||||
|
import Constants, {NotificationLevels, UserSettingsNotificationSections} from 'utils/constants';
|
||||||
|
|
||||||
|
import type {Props as UserSettingsNotificationsProps} from '../user_settings_notifications';
|
||||||
|
|
||||||
|
export type SelectOption = {
|
||||||
|
label: ReactNode;
|
||||||
|
value: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type Props = {
|
||||||
|
active: boolean;
|
||||||
|
updateSection: (section: string) => void;
|
||||||
|
onSubmit: () => void;
|
||||||
|
onCancel: () => void;
|
||||||
|
saving: boolean;
|
||||||
|
error: string;
|
||||||
|
setParentState: (key: string, value: string | boolean) => void;
|
||||||
|
areAllSectionsInactive: boolean;
|
||||||
|
isCollapsedThreadsEnabled: boolean;
|
||||||
|
desktopActivity: UserNotifyProps['desktop'];
|
||||||
|
sendPushNotifications: UserSettingsNotificationsProps['sendPushNotifications'];
|
||||||
|
pushActivity: UserNotifyProps['push'];
|
||||||
|
pushStatus: UserNotifyProps['push_status'];
|
||||||
|
desktopThreads: UserNotifyProps['desktop_threads'];
|
||||||
|
pushThreads: UserNotifyProps['push_threads'];
|
||||||
|
desktopAndMobileSettingsDifferent: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
function DesktopAndMobileNotificationSettings({
|
||||||
|
active,
|
||||||
|
updateSection,
|
||||||
|
onSubmit,
|
||||||
|
onCancel,
|
||||||
|
saving,
|
||||||
|
error,
|
||||||
|
setParentState,
|
||||||
|
areAllSectionsInactive,
|
||||||
|
isCollapsedThreadsEnabled,
|
||||||
|
desktopActivity,
|
||||||
|
sendPushNotifications,
|
||||||
|
pushActivity,
|
||||||
|
pushStatus,
|
||||||
|
desktopThreads,
|
||||||
|
pushThreads,
|
||||||
|
desktopAndMobileSettingsDifferent,
|
||||||
|
}: Props) {
|
||||||
|
const editButtonRef = useRef<SettingItemMinComponent>(null);
|
||||||
|
const previousActiveRef = useRef(active);
|
||||||
|
|
||||||
|
// Focus back on the edit button, after this section was closed after it was opened
|
||||||
|
useEffect(() => {
|
||||||
|
if (previousActiveRef.current && !active && areAllSectionsInactive) {
|
||||||
|
editButtonRef.current?.focus();
|
||||||
|
}
|
||||||
|
|
||||||
|
previousActiveRef.current = active;
|
||||||
|
}, [active, areAllSectionsInactive]);
|
||||||
|
|
||||||
|
const handleChangeForSendDesktopNotificationsRadio = useCallback((event: ChangeEvent<HTMLInputElement>) => {
|
||||||
|
const value = event.target.value;
|
||||||
|
setParentState('desktopActivity', value);
|
||||||
|
}, [setParentState]);
|
||||||
|
|
||||||
|
const handleChangeForDesktopThreadsCheckbox = useCallback((event: ChangeEvent<HTMLInputElement>) => {
|
||||||
|
const value = event.target.checked ? NotificationLevels.ALL : NotificationLevels.MENTION;
|
||||||
|
setParentState('desktopThreads', value);
|
||||||
|
}, [setParentState]);
|
||||||
|
|
||||||
|
const handleChangeForDifferentMobileNotificationsCheckbox = useCallback((event: ChangeEvent<HTMLInputElement>) => {
|
||||||
|
const value = event.target.checked;
|
||||||
|
setParentState('desktopAndMobileSettingsDifferent', value);
|
||||||
|
}, [setParentState]);
|
||||||
|
|
||||||
|
const handleChangeForSendMobileNotificationsSelect = useCallback((selectedOption: ValueType<SelectOption>) => {
|
||||||
|
if (selectedOption && 'value' in selectedOption) {
|
||||||
|
setParentState('pushActivity', selectedOption.value);
|
||||||
|
}
|
||||||
|
}, [setParentState]);
|
||||||
|
|
||||||
|
const handleChangeForMobileThreadsCheckbox = useCallback((event: ChangeEvent<HTMLInputElement>) => {
|
||||||
|
const value = event.target.checked ? NotificationLevels.ALL : NotificationLevels.MENTION;
|
||||||
|
setParentState('pushThreads', value);
|
||||||
|
}, [setParentState]);
|
||||||
|
|
||||||
|
const handleChangeForTriggerMobileNotificationsSelect = useCallback((selectedOption: ValueType<SelectOption>) => {
|
||||||
|
if (selectedOption && 'value' in selectedOption) {
|
||||||
|
setParentState('pushStatus', selectedOption.value);
|
||||||
|
}
|
||||||
|
}, [setParentState]);
|
||||||
|
|
||||||
|
const maximizedSettingsInputs = useMemo(() => {
|
||||||
|
const maximizedSettingInputs = [];
|
||||||
|
|
||||||
|
const sendDesktopNotificationsSection = (
|
||||||
|
<fieldset
|
||||||
|
id='sendDesktopNotificationsSection'
|
||||||
|
key='sendDesktopNotificationsSection'
|
||||||
|
>
|
||||||
|
<legend className='form-legend'>
|
||||||
|
<FormattedMessage
|
||||||
|
id='user.settings.notifications.desktopAndMobile.sendDesktopNotificationFor'
|
||||||
|
defaultMessage='Send notifications for:'
|
||||||
|
/>
|
||||||
|
</legend>
|
||||||
|
{optionsOfSendNotifications.map((optionOfSendNotifications) => (
|
||||||
|
<div
|
||||||
|
key={optionOfSendNotifications.value}
|
||||||
|
className='radio'
|
||||||
|
>
|
||||||
|
<label>
|
||||||
|
<input
|
||||||
|
type='radio'
|
||||||
|
checked={desktopActivity === optionOfSendNotifications.value}
|
||||||
|
value={optionOfSendNotifications.value}
|
||||||
|
onChange={handleChangeForSendDesktopNotificationsRadio}
|
||||||
|
/>
|
||||||
|
{optionOfSendNotifications.label}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</fieldset>
|
||||||
|
);
|
||||||
|
maximizedSettingInputs.push(sendDesktopNotificationsSection);
|
||||||
|
|
||||||
|
if (shouldShowDesktopThreadsSection(isCollapsedThreadsEnabled, desktopActivity)) {
|
||||||
|
const desktopThreadNotificationSection = (
|
||||||
|
<Fragment key='desktopThreadNotificationSection'>
|
||||||
|
<br/>
|
||||||
|
<div className='checkbox single-checkbox'>
|
||||||
|
<label>
|
||||||
|
<input
|
||||||
|
type='checkbox'
|
||||||
|
checked={desktopThreads === NotificationLevels.ALL}
|
||||||
|
onChange={handleChangeForDesktopThreadsCheckbox}
|
||||||
|
/>
|
||||||
|
<FormattedMessage
|
||||||
|
id='user.settings.notifications.desktopAndMobile.notifyForDesktopthreads'
|
||||||
|
defaultMessage={'Notify me about replies to threads I\'m following'}
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</Fragment>
|
||||||
|
);
|
||||||
|
maximizedSettingInputs.push(desktopThreadNotificationSection);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sendPushNotifications) {
|
||||||
|
const differentMobileNotificationsSection = (
|
||||||
|
<Fragment key='differentMobileNotificationsSection'>
|
||||||
|
<hr/>
|
||||||
|
<div className='checkbox single-checkbox'>
|
||||||
|
<label>
|
||||||
|
<input
|
||||||
|
type='checkbox'
|
||||||
|
checked={desktopAndMobileSettingsDifferent}
|
||||||
|
onChange={handleChangeForDifferentMobileNotificationsCheckbox}
|
||||||
|
/>
|
||||||
|
<FormattedMessage
|
||||||
|
id='user.settings.notifications.desktopAndMobile.differentMobileNotificationsTitle'
|
||||||
|
defaultMessage='Use different settings for my mobile devices'
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</Fragment>
|
||||||
|
);
|
||||||
|
maximizedSettingInputs.push(differentMobileNotificationsSection);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shouldShowSendMobileNotificationsSection(sendPushNotifications, desktopAndMobileSettingsDifferent)) {
|
||||||
|
const sendMobileNotificationsSection = (
|
||||||
|
<React.Fragment key='sendMobileNotificationsSection'>
|
||||||
|
<br/>
|
||||||
|
<label
|
||||||
|
id='sendMobileNotificationsLabel'
|
||||||
|
htmlFor='sendMobileNotificationsSelectInput'
|
||||||
|
className='singleSelectLabel'
|
||||||
|
>
|
||||||
|
<FormattedMessage
|
||||||
|
id='user.settings.notifications.desktopAndMobile.sendMobileNotificationsFor'
|
||||||
|
defaultMessage='Send mobile notifications for:'
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
<ReactSelect
|
||||||
|
inputId='sendMobileNotificationsSelectInput'
|
||||||
|
aria-labelledby='sendMobileNotificationsLabel'
|
||||||
|
className='react-select singleSelect'
|
||||||
|
classNamePrefix='react-select'
|
||||||
|
options={optionsOfSendNotifications}
|
||||||
|
clearable={false}
|
||||||
|
isClearable={false}
|
||||||
|
isSearchable={false}
|
||||||
|
components={{IndicatorSeparator: NoIndicatorSeparatorComponent}}
|
||||||
|
value={getValueOfSendMobileNotificationForSelect(pushActivity)}
|
||||||
|
onChange={handleChangeForSendMobileNotificationsSelect}
|
||||||
|
/>
|
||||||
|
</React.Fragment>
|
||||||
|
);
|
||||||
|
maximizedSettingInputs.push(sendMobileNotificationsSection);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shouldShowMobileThreadsSection(sendPushNotifications, isCollapsedThreadsEnabled, desktopAndMobileSettingsDifferent, pushActivity)) {
|
||||||
|
const threadNotificationSection = (
|
||||||
|
<Fragment key='threadNotificationSection'>
|
||||||
|
<br/>
|
||||||
|
<div className='checkbox single-checkbox'>
|
||||||
|
<label>
|
||||||
|
<input
|
||||||
|
type='checkbox'
|
||||||
|
checked={pushThreads === NotificationLevels.ALL}
|
||||||
|
onChange={handleChangeForMobileThreadsCheckbox}
|
||||||
|
/>
|
||||||
|
<FormattedMessage
|
||||||
|
id='user.settings.notifications.desktopAndMobile.notifyForMobilethreads'
|
||||||
|
defaultMessage={'Notify me on mobile about replies to threads I\'m following'}
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</Fragment>
|
||||||
|
);
|
||||||
|
maximizedSettingInputs.push(threadNotificationSection);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shouldShowTriggerMobileNotificationsSection(sendPushNotifications, desktopActivity, pushActivity, desktopAndMobileSettingsDifferent)) {
|
||||||
|
const triggerMobileNotificationsSection = (
|
||||||
|
<React.Fragment key='triggerMobileNotificationsSection'>
|
||||||
|
<br/>
|
||||||
|
<label
|
||||||
|
id='pushMobileNotificationsLabel'
|
||||||
|
htmlFor='pushMobileNotificationSelectInput'
|
||||||
|
className='singleSelectLabel'
|
||||||
|
>
|
||||||
|
<FormattedMessage
|
||||||
|
id='user.settings.notifications.desktopAndMobile.pushNotification'
|
||||||
|
defaultMessage='Trigger mobile notifications when I am:'
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
<ReactSelect
|
||||||
|
inputId='pushMobileNotificationSelectInput'
|
||||||
|
aria-labelledby='pushMobileNotificationsLabel'
|
||||||
|
className='react-select singleSelect'
|
||||||
|
classNamePrefix='react-select'
|
||||||
|
options={optionsOfSendMobileNotificationsWhenSelect}
|
||||||
|
clearable={false}
|
||||||
|
isClearable={false}
|
||||||
|
isSearchable={false}
|
||||||
|
components={{IndicatorSeparator: NoIndicatorSeparatorComponent}}
|
||||||
|
value={getValueOfSendMobileNotificationWhenSelect(pushStatus)}
|
||||||
|
onChange={handleChangeForTriggerMobileNotificationsSelect}
|
||||||
|
/>
|
||||||
|
</React.Fragment>
|
||||||
|
);
|
||||||
|
maximizedSettingInputs.push(triggerMobileNotificationsSection);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!sendPushNotifications) {
|
||||||
|
const disabledPushNotificationsSection = (
|
||||||
|
<>
|
||||||
|
<br/>
|
||||||
|
<FormattedMessage
|
||||||
|
id='user.settings.notifications.desktopAndMobile.pushNotificationsDisabled'
|
||||||
|
defaultMessage={'Mobile push notifications haven\'t been enabled by your system administrator.'}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
maximizedSettingInputs.push(disabledPushNotificationsSection);
|
||||||
|
}
|
||||||
|
|
||||||
|
return maximizedSettingInputs;
|
||||||
|
},
|
||||||
|
[
|
||||||
|
desktopActivity,
|
||||||
|
handleChangeForSendDesktopNotificationsRadio,
|
||||||
|
isCollapsedThreadsEnabled,
|
||||||
|
desktopThreads,
|
||||||
|
handleChangeForDesktopThreadsCheckbox,
|
||||||
|
sendPushNotifications,
|
||||||
|
desktopAndMobileSettingsDifferent,
|
||||||
|
handleChangeForDifferentMobileNotificationsCheckbox,
|
||||||
|
pushActivity,
|
||||||
|
handleChangeForSendMobileNotificationsSelect,
|
||||||
|
pushThreads,
|
||||||
|
handleChangeForMobileThreadsCheckbox,
|
||||||
|
pushStatus,
|
||||||
|
handleChangeForTriggerMobileNotificationsSelect,
|
||||||
|
]);
|
||||||
|
|
||||||
|
function handleChangeForMaxSection(section: string) {
|
||||||
|
updateSection(section);
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleChangeForMinSection(section: string) {
|
||||||
|
updateSection(section);
|
||||||
|
onCancel();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (active) {
|
||||||
|
return (
|
||||||
|
<SettingItemMax
|
||||||
|
title={
|
||||||
|
<FormattedMessage
|
||||||
|
id={'user.settings.notifications.desktopAndMobile.title'}
|
||||||
|
defaultMessage='Desktop and mobile notifications'
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
inputs={maximizedSettingsInputs}
|
||||||
|
submit={onSubmit}
|
||||||
|
saving={saving}
|
||||||
|
serverError={error}
|
||||||
|
updateSection={handleChangeForMaxSection}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SettingItemMin
|
||||||
|
ref={editButtonRef}
|
||||||
|
title={
|
||||||
|
<FormattedMessage
|
||||||
|
id='user.settings.notifications.desktopAndMobile.title'
|
||||||
|
defaultMessage='Desktop and mobile notifications'
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
describe={getCollapsedText(desktopActivity, pushActivity)}
|
||||||
|
section={UserSettingsNotificationSections.DESKTOP_AND_MOBILE}
|
||||||
|
updateSection={handleChangeForMinSection}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function NoIndicatorSeparatorComponent() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const optionsOfSendNotifications = [
|
||||||
|
{
|
||||||
|
label: (
|
||||||
|
<FormattedMessage
|
||||||
|
id='user.settings.notifications.desktopAndMobile.allNewMessages'
|
||||||
|
defaultMessage='All new messages'
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
value: NotificationLevels.ALL,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: (
|
||||||
|
<FormattedMessage
|
||||||
|
id='user.settings.notifications.desktopAndMobile.onlyMentions'
|
||||||
|
defaultMessage='Mentions, direct messages, and group messages'
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
value: NotificationLevels.MENTION,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: (
|
||||||
|
<FormattedMessage
|
||||||
|
id='user.settings.notifications.desktopAndMobile.nothing'
|
||||||
|
defaultMessage='Nothing'
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
value: NotificationLevels.NONE,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export function shouldShowDesktopThreadsSection(isCollapsedThreadsEnabled: boolean, desktopActivity: UserNotifyProps['desktop']) {
|
||||||
|
if (!isCollapsedThreadsEnabled) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (desktopActivity === NotificationLevels.ALL || desktopActivity === NotificationLevels.NONE) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function shouldShowMobileThreadsSection(sendPushNotifications: UserSettingsNotificationsProps['sendPushNotifications'], isCollapsedThreadsEnabled: boolean, desktopAndMobileSettingsDifferent: boolean, pushActivity: UserNotifyProps['push']) {
|
||||||
|
if (!sendPushNotifications) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isCollapsedThreadsEnabled) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!desktopAndMobileSettingsDifferent) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pushActivity === NotificationLevels.ALL || pushActivity === NotificationLevels.NONE) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function shouldShowSendMobileNotificationsSection(sendPushNotifications: UserSettingsNotificationsProps['sendPushNotifications'], desktopAndMobileSettingsDifferent: boolean) {
|
||||||
|
if (!sendPushNotifications) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (desktopAndMobileSettingsDifferent) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getValueOfSendMobileNotificationForSelect(pushActivity: UserNotifyProps['push']): ValueType<SelectOption> {
|
||||||
|
if (!pushActivity) {
|
||||||
|
return optionsOfSendNotifications[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
const option = optionsOfSendNotifications.find((option) => option.value === pushActivity);
|
||||||
|
if (!option) {
|
||||||
|
return optionsOfSendNotifications[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
return option;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function shouldShowTriggerMobileNotificationsSection(sendPushNotifications: UserSettingsNotificationsProps['sendPushNotifications'], desktopActivity: UserNotifyProps['desktop'], pushActivity: UserNotifyProps['push'], desktopAndMobileSettingsDifferent: boolean): boolean {
|
||||||
|
if (!sendPushNotifications) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!desktopActivity || !pushActivity) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!desktopAndMobileSettingsDifferent) {
|
||||||
|
if (desktopActivity === NotificationLevels.NONE) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pushActivity === NotificationLevels.NONE) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const optionsOfSendMobileNotificationsWhenSelect: OptionsType<SelectOption> = [
|
||||||
|
{
|
||||||
|
label: (
|
||||||
|
<FormattedMessage
|
||||||
|
id='user.settings.notifications.desktopAndMobile.online'
|
||||||
|
defaultMessage='Online, away, or offline'
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
value: Constants.UserStatuses.ONLINE,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: (
|
||||||
|
<FormattedMessage
|
||||||
|
id='user.settings.notifications.desktopAndMobile.away'
|
||||||
|
defaultMessage='Away or offline'
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
value: Constants.UserStatuses.AWAY,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: (
|
||||||
|
<FormattedMessage
|
||||||
|
id='user.settings.notifications.desktopAndMobile.offline'
|
||||||
|
defaultMessage='Offline'
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
value: Constants.UserStatuses.OFFLINE,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export function getValueOfSendMobileNotificationWhenSelect(pushStatus?: UserNotifyProps['push_status']): ValueType<SelectOption> {
|
||||||
|
if (!pushStatus) {
|
||||||
|
return optionsOfSendMobileNotificationsWhenSelect[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
const option = optionsOfSendMobileNotificationsWhenSelect.find((option) => option.value === pushStatus);
|
||||||
|
if (!option) {
|
||||||
|
return optionsOfSendMobileNotificationsWhenSelect[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
return option;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getCollapsedText(desktopActivity: UserNotifyProps['desktop'], pushActivity: UserNotifyProps['push']): ReactNode {
|
||||||
|
if (desktopActivity === NotificationLevels.ALL) {
|
||||||
|
if (pushActivity === NotificationLevels.ALL) {
|
||||||
|
return (
|
||||||
|
<FormattedMessage
|
||||||
|
id='user.settings.notifications.desktopAndMobile.allForDesktopAndMobile'
|
||||||
|
defaultMessage='All new messages'
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
} else if (pushActivity === NotificationLevels.MENTION) {
|
||||||
|
return (
|
||||||
|
<FormattedMessage
|
||||||
|
id='user.settings.notifications.desktopAndMobile.allDesktopButMobileMentions'
|
||||||
|
defaultMessage='All new messages on desktop; mentions, direct messages, and group messages on mobile'
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
} else if (pushActivity === NotificationLevels.NONE) {
|
||||||
|
return (
|
||||||
|
<FormattedMessage
|
||||||
|
id='user.settings.notifications.desktopAndMobile.allDesktopButMobileNone'
|
||||||
|
defaultMessage='All new messages on desktop; never on mobile'
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else if (desktopActivity === NotificationLevels.MENTION) {
|
||||||
|
if (pushActivity === NotificationLevels.ALL) {
|
||||||
|
return (
|
||||||
|
<FormattedMessage
|
||||||
|
id='user.settings.notifications.desktopAndMobile.mentionsDesktopButMobileAll'
|
||||||
|
defaultMessage='Mentions, direct messages, and group messages on desktop; all new messages on mobile'
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
} else if (pushActivity === NotificationLevels.MENTION) {
|
||||||
|
return (
|
||||||
|
<FormattedMessage
|
||||||
|
id='user.settings.notifications.desktopAndMobile.mentionsForDesktopAndMobile'
|
||||||
|
defaultMessage='Mentions, direct messages, and group messages'
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
} else if (pushActivity === NotificationLevels.NONE) {
|
||||||
|
return (
|
||||||
|
<FormattedMessage
|
||||||
|
id='user.settings.notifications.desktopAndMobile.mentionsForDesktopButMobileNone'
|
||||||
|
defaultMessage='Mentions, direct messages, and group messages on desktop; never on mobile'
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else if (desktopActivity === NotificationLevels.NONE) {
|
||||||
|
if (pushActivity === NotificationLevels.ALL) {
|
||||||
|
return (
|
||||||
|
<FormattedMessage
|
||||||
|
id='user.settings.notifications.desktopAndMobile.noneDesktopButMobileAll'
|
||||||
|
defaultMessage='Never on desktop; all new messages on mobile'
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
} else if (pushActivity === NotificationLevels.MENTION) {
|
||||||
|
return (
|
||||||
|
<FormattedMessage
|
||||||
|
id='user.settings.notifications.desktopAndMobile.noneDesktopButMobileMentions'
|
||||||
|
defaultMessage='Never on desktop; mentions, direct messages, and group messages on mobile'
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
} else if (pushActivity === NotificationLevels.NONE) {
|
||||||
|
return (
|
||||||
|
<FormattedMessage
|
||||||
|
id='user.settings.notifications.desktopAndMobile.noneForDesktopAndMobile'
|
||||||
|
defaultMessage='Never'
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<FormattedMessage
|
||||||
|
id='user.settings.notifications.desktopAndMobile.noValidSettings'
|
||||||
|
defaultMessage='Configure desktop and mobile settings'
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default memo(DesktopAndMobileNotificationSettings);
|
File diff suppressed because it is too large
Load Diff
@ -1,155 +0,0 @@
|
|||||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
|
||||||
// See LICENSE.txt for license information.
|
|
||||||
|
|
||||||
import {shallow} from 'enzyme';
|
|
||||||
import React from 'react';
|
|
||||||
import type {ComponentProps} from 'react';
|
|
||||||
|
|
||||||
import {NotificationLevels} from 'utils/constants';
|
|
||||||
|
|
||||||
import DesktopNotificationSettings from './desktop_notification_settings';
|
|
||||||
|
|
||||||
jest.mock('utils/notification_sounds', () => {
|
|
||||||
const original = jest.requireActual('utils/notification_sounds');
|
|
||||||
return {
|
|
||||||
...original,
|
|
||||||
hasSoundOptions: jest.fn(() => true),
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('components/user_settings/notifications/DesktopNotificationSettings', () => {
|
|
||||||
const baseProps: ComponentProps<typeof DesktopNotificationSettings> = {
|
|
||||||
active: true,
|
|
||||||
updateSection: jest.fn(),
|
|
||||||
onSubmit: jest.fn(),
|
|
||||||
onCancel: jest.fn(),
|
|
||||||
saving: false,
|
|
||||||
error: '',
|
|
||||||
setParentState: jest.fn(),
|
|
||||||
areAllSectionsInactive: false,
|
|
||||||
isCollapsedThreadsEnabled: false,
|
|
||||||
activity: NotificationLevels.MENTION,
|
|
||||||
threads: NotificationLevels.ALL,
|
|
||||||
sound: 'false',
|
|
||||||
callsSound: 'false',
|
|
||||||
selectedSound: 'Bing',
|
|
||||||
callsSelectedSound: 'Dynamic',
|
|
||||||
isCallsRingingEnabled: false,
|
|
||||||
};
|
|
||||||
|
|
||||||
test('should match snapshot, on max setting', () => {
|
|
||||||
const wrapper = shallow(
|
|
||||||
<DesktopNotificationSettings {...baseProps}/>,
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(wrapper).toMatchSnapshot();
|
|
||||||
});
|
|
||||||
|
|
||||||
test('should match snapshot, on max setting with sound enabled', () => {
|
|
||||||
const props = {...baseProps, sound: 'true'};
|
|
||||||
const wrapper = shallow(
|
|
||||||
<DesktopNotificationSettings {...props}/>,
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(wrapper).toMatchSnapshot();
|
|
||||||
});
|
|
||||||
|
|
||||||
test('should match snapshot, on max setting with Calls enabled', () => {
|
|
||||||
const props = {...baseProps, isCallsRingingEnabled: true};
|
|
||||||
const wrapper = shallow(
|
|
||||||
<DesktopNotificationSettings {...props}/>,
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(wrapper).toMatchSnapshot();
|
|
||||||
});
|
|
||||||
|
|
||||||
test('should match snapshot, on max setting with Calls enabled, calls sound true', () => {
|
|
||||||
const props = {...baseProps, isCallsRingingEnabled: true, callsSound: 'true'};
|
|
||||||
const wrapper = shallow(
|
|
||||||
<DesktopNotificationSettings {...props}/>,
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(wrapper).toMatchSnapshot();
|
|
||||||
});
|
|
||||||
|
|
||||||
test('should match snapshot, on min setting', () => {
|
|
||||||
const props = {...baseProps, active: false};
|
|
||||||
const wrapper = shallow(
|
|
||||||
<DesktopNotificationSettings {...props}/>,
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(wrapper).toMatchSnapshot();
|
|
||||||
});
|
|
||||||
|
|
||||||
test('should call props.updateSection and props.onCancel on handleMinUpdateSection', () => {
|
|
||||||
const props = {...baseProps, updateSection: jest.fn(), onCancel: jest.fn()};
|
|
||||||
const wrapper = shallow<DesktopNotificationSettings>(
|
|
||||||
<DesktopNotificationSettings {...props}/>,
|
|
||||||
);
|
|
||||||
|
|
||||||
wrapper.instance().handleMinUpdateSection('');
|
|
||||||
expect(props.updateSection).toHaveBeenCalledTimes(1);
|
|
||||||
expect(props.updateSection).toHaveBeenCalledWith('');
|
|
||||||
expect(props.onCancel).toHaveBeenCalledTimes(1);
|
|
||||||
expect(props.onCancel).toHaveBeenCalledWith();
|
|
||||||
|
|
||||||
wrapper.instance().handleMinUpdateSection('desktop');
|
|
||||||
expect(props.updateSection).toHaveBeenCalledTimes(2);
|
|
||||||
expect(props.updateSection).toHaveBeenCalledWith('desktop');
|
|
||||||
expect(props.onCancel).toHaveBeenCalledTimes(2);
|
|
||||||
expect(props.onCancel).toHaveBeenCalledWith();
|
|
||||||
});
|
|
||||||
|
|
||||||
test('should call props.updateSection on handleMaxUpdateSection', () => {
|
|
||||||
const props = {...baseProps, updateSection: jest.fn()};
|
|
||||||
const wrapper = shallow<DesktopNotificationSettings>(
|
|
||||||
<DesktopNotificationSettings {...props}/>,
|
|
||||||
);
|
|
||||||
|
|
||||||
wrapper.instance().handleMaxUpdateSection('');
|
|
||||||
expect(props.updateSection).toHaveBeenCalledTimes(1);
|
|
||||||
expect(props.updateSection).toHaveBeenCalledWith('');
|
|
||||||
|
|
||||||
wrapper.instance().handleMaxUpdateSection('desktop');
|
|
||||||
expect(props.updateSection).toHaveBeenCalledTimes(2);
|
|
||||||
expect(props.updateSection).toHaveBeenCalledWith('desktop');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('should call props.setParentState on handleOnChange', () => {
|
|
||||||
const props = {...baseProps, setParentState: jest.fn()};
|
|
||||||
const wrapper = shallow<DesktopNotificationSettings>(
|
|
||||||
<DesktopNotificationSettings {...props}/>,
|
|
||||||
);
|
|
||||||
|
|
||||||
wrapper.instance().handleOnChange({
|
|
||||||
currentTarget: {getAttribute: (key: string) => {
|
|
||||||
return {'data-key': 'dataKey', 'data-value': 'dataValue'}[key];
|
|
||||||
}},
|
|
||||||
} as unknown as React.ChangeEvent<HTMLInputElement>);
|
|
||||||
|
|
||||||
expect(props.setParentState).toHaveBeenCalledTimes(1);
|
|
||||||
expect(props.setParentState).toHaveBeenCalledWith('dataKey', 'dataValue');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('should match snapshot, on buildMaximizedSetting', () => {
|
|
||||||
const wrapper = shallow<DesktopNotificationSettings>(
|
|
||||||
<DesktopNotificationSettings {...baseProps}/>,
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(wrapper.instance().buildMaximizedSetting()).toMatchSnapshot();
|
|
||||||
|
|
||||||
wrapper.setProps({activity: NotificationLevels.NONE});
|
|
||||||
expect(wrapper.instance().buildMaximizedSetting()).toMatchSnapshot();
|
|
||||||
});
|
|
||||||
|
|
||||||
test('should match snapshot, on buildMinimizedSetting', () => {
|
|
||||||
const wrapper = shallow<DesktopNotificationSettings>(
|
|
||||||
<DesktopNotificationSettings {...baseProps}/>,
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(wrapper.instance().buildMinimizedSetting()).toMatchSnapshot();
|
|
||||||
|
|
||||||
wrapper.setProps({activity: NotificationLevels.NONE});
|
|
||||||
expect(wrapper.instance().buildMinimizedSetting()).toMatchSnapshot();
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,547 +0,0 @@
|
|||||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
|
||||||
// See LICENSE.txt for license information.
|
|
||||||
|
|
||||||
import React, {type ChangeEvent, type RefObject, type ReactNode} from 'react';
|
|
||||||
import {FormattedMessage} from 'react-intl';
|
|
||||||
import ReactSelect, {type ValueType} from 'react-select';
|
|
||||||
|
|
||||||
import SettingItemMax from 'components/setting_item_max';
|
|
||||||
import SettingItemMin from 'components/setting_item_min';
|
|
||||||
import type SettingItemMinComponent from 'components/setting_item_min';
|
|
||||||
|
|
||||||
import {NotificationLevels} from 'utils/constants';
|
|
||||||
import * as NotificationSounds from 'utils/notification_sounds';
|
|
||||||
import {a11yFocus} from 'utils/utils';
|
|
||||||
|
|
||||||
type SelectedOption = {
|
|
||||||
label: string;
|
|
||||||
value: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
type Props = {
|
|
||||||
active: boolean;
|
|
||||||
updateSection: (section: string) => void;
|
|
||||||
onSubmit: () => void;
|
|
||||||
onCancel: () => void;
|
|
||||||
saving: boolean;
|
|
||||||
error: string;
|
|
||||||
setParentState: (key: string, value: string | boolean) => void;
|
|
||||||
areAllSectionsInactive: boolean;
|
|
||||||
isCollapsedThreadsEnabled: boolean;
|
|
||||||
activity: string;
|
|
||||||
threads?: string;
|
|
||||||
sound: string;
|
|
||||||
callsSound: string;
|
|
||||||
selectedSound: string;
|
|
||||||
callsSelectedSound: string;
|
|
||||||
isCallsRingingEnabled: boolean;
|
|
||||||
};
|
|
||||||
|
|
||||||
type State = {
|
|
||||||
selectedOption: SelectedOption;
|
|
||||||
callsSelectedOption: SelectedOption;
|
|
||||||
blurDropdown: boolean;
|
|
||||||
};
|
|
||||||
|
|
||||||
export default class DesktopNotificationSettings extends React.PureComponent<Props, State> {
|
|
||||||
dropdownSoundRef: RefObject<ReactSelect>;
|
|
||||||
callsDropdownRef: RefObject<ReactSelect>;
|
|
||||||
editButtonRef: RefObject<SettingItemMinComponent>;
|
|
||||||
|
|
||||||
constructor(props: Props) {
|
|
||||||
super(props);
|
|
||||||
|
|
||||||
this.state = {
|
|
||||||
selectedOption: {value: props.selectedSound, label: props.selectedSound},
|
|
||||||
callsSelectedOption: {value: props.callsSelectedSound, label: props.callsSelectedSound},
|
|
||||||
blurDropdown: false,
|
|
||||||
};
|
|
||||||
|
|
||||||
this.dropdownSoundRef = React.createRef();
|
|
||||||
this.callsDropdownRef = React.createRef();
|
|
||||||
this.editButtonRef = React.createRef();
|
|
||||||
}
|
|
||||||
|
|
||||||
focusEditButton(): void {
|
|
||||||
this.editButtonRef.current?.focus();
|
|
||||||
}
|
|
||||||
|
|
||||||
handleMinUpdateSection = (section: string): void => {
|
|
||||||
this.props.updateSection(section);
|
|
||||||
this.props.onCancel();
|
|
||||||
};
|
|
||||||
|
|
||||||
handleMaxUpdateSection = (section: string): void => this.props.updateSection(section);
|
|
||||||
|
|
||||||
handleOnChange = (e: ChangeEvent<HTMLInputElement>): void => {
|
|
||||||
const key = e.currentTarget.getAttribute('data-key');
|
|
||||||
const value = e.currentTarget.getAttribute('data-value');
|
|
||||||
if (key && value) {
|
|
||||||
this.props.setParentState(key, value);
|
|
||||||
a11yFocus(e.currentTarget);
|
|
||||||
}
|
|
||||||
if (key === 'callsDesktopSound' && value === 'false') {
|
|
||||||
NotificationSounds.stopTryNotificationRing();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
handleThreadsOnChange = (e: ChangeEvent<HTMLInputElement>): void => {
|
|
||||||
const value = e.target.checked ? NotificationLevels.ALL : NotificationLevels.MENTION;
|
|
||||||
this.props.setParentState('desktopThreads', value);
|
|
||||||
};
|
|
||||||
|
|
||||||
setDesktopNotificationSound: ReactSelect['onChange'] = (selectedOption: ValueType<SelectedOption>): void => {
|
|
||||||
if (selectedOption && 'value' in selectedOption) {
|
|
||||||
this.props.setParentState('desktopNotificationSound', selectedOption.value);
|
|
||||||
this.setState({selectedOption});
|
|
||||||
NotificationSounds.tryNotificationSound(selectedOption.value);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
setCallsNotificationRing: ReactSelect['onChange'] = (selectedOption: ValueType<SelectedOption>): void => {
|
|
||||||
if (selectedOption && 'value' in selectedOption) {
|
|
||||||
this.props.setParentState('callsNotificationSound', selectedOption.value);
|
|
||||||
this.setState({callsSelectedOption: selectedOption});
|
|
||||||
NotificationSounds.tryNotificationRing(selectedOption.value);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
blurDropdown(): void {
|
|
||||||
if (!this.state.blurDropdown) {
|
|
||||||
this.setState({blurDropdown: true});
|
|
||||||
if (this.dropdownSoundRef.current) {
|
|
||||||
this.dropdownSoundRef.current.blur();
|
|
||||||
}
|
|
||||||
if (this.callsDropdownRef.current) {
|
|
||||||
this.callsDropdownRef.current.blur();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
buildMaximizedSetting = (): JSX.Element => {
|
|
||||||
const inputs = [];
|
|
||||||
|
|
||||||
const activityRadio = [false, false, false];
|
|
||||||
if (this.props.activity === NotificationLevels.MENTION) {
|
|
||||||
activityRadio[1] = true;
|
|
||||||
} else if (this.props.activity === NotificationLevels.NONE) {
|
|
||||||
activityRadio[2] = true;
|
|
||||||
} else {
|
|
||||||
activityRadio[0] = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
let soundSection;
|
|
||||||
let notificationSelection;
|
|
||||||
let threadsNotificationSelection;
|
|
||||||
let callsSection;
|
|
||||||
let callsNotificationSelection;
|
|
||||||
if (this.props.activity !== NotificationLevels.NONE) {
|
|
||||||
const soundRadio = [false, false];
|
|
||||||
if (this.props.sound === 'false') {
|
|
||||||
soundRadio[1] = true;
|
|
||||||
} else {
|
|
||||||
soundRadio[0] = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.props.sound === 'true') {
|
|
||||||
const sounds = Array.from(NotificationSounds.notificationSounds.keys());
|
|
||||||
const options = sounds.map((sound) => {
|
|
||||||
return {value: sound, label: sound};
|
|
||||||
});
|
|
||||||
|
|
||||||
notificationSelection = (<div className='pt-2'>
|
|
||||||
<ReactSelect
|
|
||||||
className='react-select notification-sound-dropdown'
|
|
||||||
classNamePrefix='react-select'
|
|
||||||
id='displaySoundNotification'
|
|
||||||
options={options}
|
|
||||||
clearable={false}
|
|
||||||
onChange={this.setDesktopNotificationSound}
|
|
||||||
value={this.state.selectedOption}
|
|
||||||
isSearchable={false}
|
|
||||||
ref={this.dropdownSoundRef}
|
|
||||||
components={{SingleValue: (props) => <div data-testid='displaySoundNotificationValue'>{props.children}</div>}}
|
|
||||||
/></div>);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.props.isCallsRingingEnabled) {
|
|
||||||
const callsSoundRadio = [false, false];
|
|
||||||
if (this.props.callsSound === 'false') {
|
|
||||||
callsSoundRadio[1] = true;
|
|
||||||
} else {
|
|
||||||
callsSoundRadio[0] = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.props.callsSound === 'true') {
|
|
||||||
const callsSounds = Array.from(NotificationSounds.callsNotificationSounds.keys());
|
|
||||||
const callsOptions = callsSounds.map((sound) => {
|
|
||||||
return {value: sound, label: sound};
|
|
||||||
});
|
|
||||||
|
|
||||||
callsNotificationSelection = (<div className='pt-2'>
|
|
||||||
<ReactSelect
|
|
||||||
className='react-select notification-sound-dropdown'
|
|
||||||
classNamePrefix='react-select'
|
|
||||||
id='displayCallsSoundNotification'
|
|
||||||
options={callsOptions}
|
|
||||||
clearable={false}
|
|
||||||
onChange={this.setCallsNotificationRing}
|
|
||||||
value={this.state.callsSelectedOption}
|
|
||||||
isSearchable={false}
|
|
||||||
ref={this.callsDropdownRef}
|
|
||||||
components={{SingleValue: (props) => <div data-testid='displayCallsSoundNotificationValue'>{props.children}</div>}}
|
|
||||||
/></div>);
|
|
||||||
}
|
|
||||||
|
|
||||||
callsSection = (
|
|
||||||
<>
|
|
||||||
<hr/>
|
|
||||||
<fieldset>
|
|
||||||
<legend className='form-legend'>
|
|
||||||
<FormattedMessage
|
|
||||||
id='user.settings.notifications.desktop.calls_sound'
|
|
||||||
defaultMessage='Notification sound for incoming calls'
|
|
||||||
/>
|
|
||||||
</legend>
|
|
||||||
<div className='radio'>
|
|
||||||
<label>
|
|
||||||
<input
|
|
||||||
id='callsSoundOn'
|
|
||||||
type='radio'
|
|
||||||
name='callsNotificationSounds'
|
|
||||||
checked={callsSoundRadio[0]}
|
|
||||||
data-key={'callsDesktopSound'}
|
|
||||||
data-value={'true'}
|
|
||||||
onChange={this.handleOnChange}
|
|
||||||
/>
|
|
||||||
<FormattedMessage
|
|
||||||
id='user.settings.notifications.on'
|
|
||||||
defaultMessage='On'
|
|
||||||
/>
|
|
||||||
</label>
|
|
||||||
<br/>
|
|
||||||
</div>
|
|
||||||
<div className='radio'>
|
|
||||||
<label>
|
|
||||||
<input
|
|
||||||
id='soundOff'
|
|
||||||
type='radio'
|
|
||||||
name='callsNotificationSounds'
|
|
||||||
checked={callsSoundRadio[1]}
|
|
||||||
data-key={'callsDesktopSound'}
|
|
||||||
data-value={'false'}
|
|
||||||
onChange={this.handleOnChange}
|
|
||||||
/>
|
|
||||||
<FormattedMessage
|
|
||||||
id='user.settings.notifications.off'
|
|
||||||
defaultMessage='Off'
|
|
||||||
/>
|
|
||||||
</label>
|
|
||||||
<br/>
|
|
||||||
</div>
|
|
||||||
{callsNotificationSelection}
|
|
||||||
</fieldset>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (NotificationSounds.hasSoundOptions()) {
|
|
||||||
soundSection = (
|
|
||||||
<fieldset>
|
|
||||||
<legend className='form-legend'>
|
|
||||||
<FormattedMessage
|
|
||||||
id='user.settings.notifications.desktop.sound'
|
|
||||||
defaultMessage='Notification sound'
|
|
||||||
/>
|
|
||||||
</legend>
|
|
||||||
<div className='radio'>
|
|
||||||
<label>
|
|
||||||
<input
|
|
||||||
id='soundOn'
|
|
||||||
type='radio'
|
|
||||||
name='notificationSounds'
|
|
||||||
checked={soundRadio[0]}
|
|
||||||
data-key={'desktopSound'}
|
|
||||||
data-value={'true'}
|
|
||||||
onChange={this.handleOnChange}
|
|
||||||
/>
|
|
||||||
<FormattedMessage
|
|
||||||
id='user.settings.notifications.on'
|
|
||||||
defaultMessage='On'
|
|
||||||
/>
|
|
||||||
</label>
|
|
||||||
<br/>
|
|
||||||
</div>
|
|
||||||
<div className='radio'>
|
|
||||||
<label>
|
|
||||||
<input
|
|
||||||
id='soundOff'
|
|
||||||
type='radio'
|
|
||||||
name='notificationSounds'
|
|
||||||
checked={soundRadio[1]}
|
|
||||||
data-key={'desktopSound'}
|
|
||||||
data-value={'false'}
|
|
||||||
onChange={this.handleOnChange}
|
|
||||||
/>
|
|
||||||
<FormattedMessage
|
|
||||||
id='user.settings.notifications.off'
|
|
||||||
defaultMessage='Off'
|
|
||||||
/>
|
|
||||||
</label>
|
|
||||||
<br/>
|
|
||||||
</div>
|
|
||||||
{notificationSelection}
|
|
||||||
<div className='mt-5'>
|
|
||||||
<FormattedMessage
|
|
||||||
id='user.settings.notifications.sounds_info'
|
|
||||||
defaultMessage='Notification sounds are available on Firefox, Edge, Safari, Chrome and Mattermost Desktop Apps.'
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</fieldset>
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
soundSection = (
|
|
||||||
<fieldset>
|
|
||||||
<legend className='form-legend'>
|
|
||||||
<FormattedMessage
|
|
||||||
id='user.settings.notifications.desktop.sound'
|
|
||||||
defaultMessage='Notification sound'
|
|
||||||
/>
|
|
||||||
</legend>
|
|
||||||
<br/>
|
|
||||||
<FormattedMessage
|
|
||||||
id='user.settings.notifications.soundConfig'
|
|
||||||
defaultMessage='Please configure notification sounds in your browser settings'
|
|
||||||
/>
|
|
||||||
</fieldset>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.props.isCollapsedThreadsEnabled && NotificationLevels.MENTION === this.props.activity) {
|
|
||||||
threadsNotificationSelection = (
|
|
||||||
<>
|
|
||||||
<fieldset>
|
|
||||||
<legend className='form-legend'>
|
|
||||||
<FormattedMessage
|
|
||||||
id='user.settings.notifications.threads.desktop'
|
|
||||||
defaultMessage='Thread reply notifications'
|
|
||||||
/>
|
|
||||||
</legend>
|
|
||||||
<div className='checkbox'>
|
|
||||||
<label>
|
|
||||||
<input
|
|
||||||
id='desktopThreadsNotificationAllActivity'
|
|
||||||
type='checkbox'
|
|
||||||
name='desktopThreadsNotificationLevel'
|
|
||||||
checked={this.props.threads === NotificationLevels.ALL}
|
|
||||||
onChange={this.handleThreadsOnChange}
|
|
||||||
/>
|
|
||||||
<FormattedMessage
|
|
||||||
id='user.settings.notifications.threads.allActivity'
|
|
||||||
defaultMessage={'Notify me about threads I\'m following'}
|
|
||||||
/>
|
|
||||||
</label>
|
|
||||||
<br/>
|
|
||||||
</div>
|
|
||||||
<div className='mt-5'>
|
|
||||||
<FormattedMessage
|
|
||||||
id='user.settings.notifications.threads'
|
|
||||||
defaultMessage={'When enabled, any reply to a thread you\'re following will send a desktop notification.'}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</fieldset>
|
|
||||||
<hr/>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
inputs.push(
|
|
||||||
<div key='userNotificationLevelOption'>
|
|
||||||
<fieldset>
|
|
||||||
<legend className='form-legend'>
|
|
||||||
<FormattedMessage
|
|
||||||
id='user.settings.notifications.desktop'
|
|
||||||
defaultMessage='Send desktop notifications'
|
|
||||||
/>
|
|
||||||
</legend>
|
|
||||||
<div className='radio'>
|
|
||||||
<label>
|
|
||||||
<input
|
|
||||||
id='desktopNotificationAllActivity'
|
|
||||||
type='radio'
|
|
||||||
name='desktopNotificationLevel'
|
|
||||||
checked={activityRadio[0]}
|
|
||||||
data-key={'desktopActivity'}
|
|
||||||
data-value={NotificationLevels.ALL}
|
|
||||||
onChange={this.handleOnChange}
|
|
||||||
/>
|
|
||||||
<FormattedMessage
|
|
||||||
id='user.settings.notifications.allActivity'
|
|
||||||
defaultMessage='For all activity'
|
|
||||||
/>
|
|
||||||
</label>
|
|
||||||
<br/>
|
|
||||||
</div>
|
|
||||||
<div className='radio'>
|
|
||||||
<label>
|
|
||||||
<input
|
|
||||||
id='desktopNotificationMentions'
|
|
||||||
type='radio'
|
|
||||||
name='desktopNotificationLevel'
|
|
||||||
checked={activityRadio[1]}
|
|
||||||
data-key={'desktopActivity'}
|
|
||||||
data-value={NotificationLevels.MENTION}
|
|
||||||
onChange={this.handleOnChange}
|
|
||||||
/>
|
|
||||||
<FormattedMessage
|
|
||||||
id='user.settings.notifications.onlyMentions'
|
|
||||||
defaultMessage='Only for mentions, direct messages, and group messages'
|
|
||||||
/>
|
|
||||||
</label>
|
|
||||||
<br/>
|
|
||||||
</div>
|
|
||||||
<div className='radio'>
|
|
||||||
<label>
|
|
||||||
<input
|
|
||||||
id='desktopNotificationNever'
|
|
||||||
type='radio'
|
|
||||||
name='desktopNotificationLevel'
|
|
||||||
checked={activityRadio[2]}
|
|
||||||
data-key={'desktopActivity'}
|
|
||||||
data-value={NotificationLevels.NONE}
|
|
||||||
onChange={this.handleOnChange}
|
|
||||||
/>
|
|
||||||
<FormattedMessage
|
|
||||||
id='user.settings.notifications.never'
|
|
||||||
defaultMessage='Never'
|
|
||||||
/>
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
<div className='mt-5'>
|
|
||||||
<FormattedMessage
|
|
||||||
id='user.settings.notifications.info'
|
|
||||||
defaultMessage='Desktop notifications are available on Edge, Firefox, Safari, Chrome and Mattermost Desktop Apps.'
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</fieldset>
|
|
||||||
<hr/>
|
|
||||||
{threadsNotificationSelection}
|
|
||||||
{soundSection}
|
|
||||||
{callsSection}
|
|
||||||
</div>,
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<SettingItemMax
|
|
||||||
title={
|
|
||||||
<FormattedMessage
|
|
||||||
id={'user.settings.notifications.desktop.title'}
|
|
||||||
defaultMessage={'Desktop Notifications'}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
inputs={inputs}
|
|
||||||
submit={this.props.onSubmit}
|
|
||||||
saving={this.props.saving}
|
|
||||||
serverError={this.props.error}
|
|
||||||
updateSection={this.handleMaxUpdateSection}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
buildMinimizedSetting = () => {
|
|
||||||
const hasSoundOption = NotificationSounds.hasSoundOptions();
|
|
||||||
let collapsedDescription: ReactNode = null;
|
|
||||||
|
|
||||||
if (this.props.activity === NotificationLevels.MENTION) {
|
|
||||||
if (hasSoundOption && this.props.sound !== 'false') {
|
|
||||||
collapsedDescription = (
|
|
||||||
<FormattedMessage
|
|
||||||
id='user.settings.notifications.desktop.mentionsSound'
|
|
||||||
defaultMessage='For mentions and direct messages, with sound'
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
} else if (hasSoundOption && this.props.sound === 'false') {
|
|
||||||
collapsedDescription = (
|
|
||||||
<FormattedMessage
|
|
||||||
id='user.settings.notifications.desktop.mentionsNoSound'
|
|
||||||
defaultMessage='For mentions and direct messages, without sound'
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
collapsedDescription = (
|
|
||||||
<FormattedMessage
|
|
||||||
id='user.settings.notifications.desktop.mentionsSoundHidden'
|
|
||||||
defaultMessage='For mentions and direct messages'
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} else if (this.props.activity === NotificationLevels.NONE) {
|
|
||||||
collapsedDescription = (
|
|
||||||
<FormattedMessage
|
|
||||||
id='user.settings.notifications.off'
|
|
||||||
defaultMessage='Off'
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
if (hasSoundOption && this.props.sound !== 'false') { //eslint-disable-line no-lonely-if
|
|
||||||
collapsedDescription = (
|
|
||||||
<FormattedMessage
|
|
||||||
id='user.settings.notifications.desktop.allSound'
|
|
||||||
defaultMessage='For all activity, with sound'
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
} else if (hasSoundOption && this.props.sound === 'false') {
|
|
||||||
collapsedDescription = (
|
|
||||||
<FormattedMessage
|
|
||||||
id='user.settings.notifications.desktop.allNoSound'
|
|
||||||
defaultMessage='For all activity, without sound'
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
collapsedDescription = (
|
|
||||||
<FormattedMessage
|
|
||||||
id='user.settings.notifications.desktop.allSoundHidden'
|
|
||||||
defaultMessage='For all activity'
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<SettingItemMin
|
|
||||||
ref={this.editButtonRef}
|
|
||||||
title={
|
|
||||||
<FormattedMessage
|
|
||||||
id={'user.settings.notifications.desktop.title'}
|
|
||||||
defaultMessage={'Desktop Notifications'}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
describe={collapsedDescription}
|
|
||||||
section={'desktop'}
|
|
||||||
updateSection={this.handleMinUpdateSection}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
componentDidUpdate(prevProps: Props) {
|
|
||||||
this.blurDropdown();
|
|
||||||
if (prevProps.active && !this.props.active && this.props.areAllSectionsInactive) {
|
|
||||||
this.focusEditButton();
|
|
||||||
}
|
|
||||||
if (this.props.selectedSound !== prevProps.selectedSound) {
|
|
||||||
this.setState({selectedOption: {value: this.props.selectedSound, label: this.props.selectedSound}});
|
|
||||||
}
|
|
||||||
if (this.props.callsSelectedSound !== prevProps.callsSelectedSound) {
|
|
||||||
this.setState({callsSelectedOption: {value: this.props.callsSelectedSound, label: this.props.callsSelectedSound}});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
if (this.props.active) {
|
|
||||||
return this.buildMaximizedSetting();
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.buildMinimizedSetting();
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,493 @@
|
|||||||
|
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||||
|
// See LICENSE.txt for license information.
|
||||||
|
|
||||||
|
import type {ChangeEvent, ReactNode} from 'react';
|
||||||
|
import React, {memo, useEffect, useRef, Fragment, useMemo, useCallback} from 'react';
|
||||||
|
import {FormattedMessage, useIntl} from 'react-intl';
|
||||||
|
import type {ValueType} from 'react-select';
|
||||||
|
import ReactSelect from 'react-select';
|
||||||
|
|
||||||
|
import type {UserNotifyProps} from '@mattermost/types/users';
|
||||||
|
|
||||||
|
import SettingItemMax from 'components/setting_item_max';
|
||||||
|
import SettingItemMin from 'components/setting_item_min';
|
||||||
|
import type SettingItemMinComponent from 'components/setting_item_min';
|
||||||
|
|
||||||
|
import {UserSettingsNotificationSections} from 'utils/constants';
|
||||||
|
import {
|
||||||
|
callsNotificationSounds,
|
||||||
|
notificationSounds,
|
||||||
|
stopTryNotificationRing,
|
||||||
|
tryNotificationSound,
|
||||||
|
tryNotificationRing,
|
||||||
|
} from 'utils/notification_sounds';
|
||||||
|
|
||||||
|
import type {Props as UserSettingsNotificationsProps} from '../user_settings_notifications';
|
||||||
|
|
||||||
|
export type SelectOption = {
|
||||||
|
value: string;
|
||||||
|
label: ReactNode;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type Props = {
|
||||||
|
active: boolean;
|
||||||
|
updateSection: (section: string) => void;
|
||||||
|
onSubmit: () => void;
|
||||||
|
onCancel: () => void;
|
||||||
|
saving: boolean;
|
||||||
|
error: string;
|
||||||
|
setParentState: (key: string, value: string | boolean) => void;
|
||||||
|
areAllSectionsInactive: boolean;
|
||||||
|
desktopSound: UserNotifyProps['desktop_sound'];
|
||||||
|
desktopNotificationSound: UserNotifyProps['desktop_notification_sound'];
|
||||||
|
isCallsRingingEnabled: UserSettingsNotificationsProps['isCallsRingingEnabled'];
|
||||||
|
callsDesktopSound: UserNotifyProps['calls_desktop_sound'];
|
||||||
|
callsNotificationSound: UserNotifyProps['calls_notification_sound'];
|
||||||
|
};
|
||||||
|
|
||||||
|
function DesktopNotificationSoundsSettings({
|
||||||
|
active,
|
||||||
|
updateSection,
|
||||||
|
onSubmit,
|
||||||
|
onCancel,
|
||||||
|
saving,
|
||||||
|
error,
|
||||||
|
setParentState,
|
||||||
|
areAllSectionsInactive,
|
||||||
|
desktopSound,
|
||||||
|
desktopNotificationSound,
|
||||||
|
isCallsRingingEnabled,
|
||||||
|
callsDesktopSound,
|
||||||
|
callsNotificationSound,
|
||||||
|
}: Props) {
|
||||||
|
const intl = useIntl();
|
||||||
|
|
||||||
|
const editButtonRef = useRef<SettingItemMinComponent>(null);
|
||||||
|
const previousActiveRef = useRef(active);
|
||||||
|
|
||||||
|
// Focus back on the edit button, after this section was closed after it was opened
|
||||||
|
useEffect(() => {
|
||||||
|
if (previousActiveRef.current && !active && areAllSectionsInactive) {
|
||||||
|
editButtonRef.current?.focus();
|
||||||
|
}
|
||||||
|
|
||||||
|
previousActiveRef.current = active;
|
||||||
|
}, [active, areAllSectionsInactive]);
|
||||||
|
|
||||||
|
const handleChangeForMessageNotificationSoundCheckbox = useCallback((event: ChangeEvent<HTMLInputElement>) => {
|
||||||
|
const value = event.target.checked ? 'true' : 'false';
|
||||||
|
setParentState('desktopSound', value);
|
||||||
|
|
||||||
|
if (value === 'false') {
|
||||||
|
stopTryNotificationRing();
|
||||||
|
}
|
||||||
|
}, [setParentState]);
|
||||||
|
|
||||||
|
const handleChangeForIncomginCallSoundCheckbox = useCallback((event: ChangeEvent<HTMLInputElement>) => {
|
||||||
|
const value = event.target.checked ? 'true' : 'false';
|
||||||
|
setParentState('callsDesktopSound', value);
|
||||||
|
|
||||||
|
if (value === 'false') {
|
||||||
|
stopTryNotificationRing();
|
||||||
|
}
|
||||||
|
}, [setParentState]);
|
||||||
|
|
||||||
|
const handleChangeForMessageNotificationSoundSelect = useCallback((selectedOption: ValueType<SelectOption>) => {
|
||||||
|
stopTryNotificationRing();
|
||||||
|
|
||||||
|
if (selectedOption && 'value' in selectedOption) {
|
||||||
|
setParentState('desktopNotificationSound', selectedOption.value);
|
||||||
|
tryNotificationSound(selectedOption.value);
|
||||||
|
}
|
||||||
|
}, [setParentState]);
|
||||||
|
|
||||||
|
const handleChangeForIncomingCallSoundSelect = useCallback((selectedOption: ValueType<SelectOption>) => {
|
||||||
|
stopTryNotificationRing();
|
||||||
|
|
||||||
|
if (selectedOption && 'value' in selectedOption) {
|
||||||
|
setParentState('callsNotificationSound', selectedOption.value);
|
||||||
|
tryNotificationRing(selectedOption.value);
|
||||||
|
}
|
||||||
|
}, [setParentState]);
|
||||||
|
|
||||||
|
const maximizedSettingInputs = useMemo(() => {
|
||||||
|
const maximizedSettingInputs = [];
|
||||||
|
|
||||||
|
const isMessageNotificationSoundChecked = desktopSound === 'true';
|
||||||
|
const messageSoundSection = (
|
||||||
|
<Fragment key='messageSoundSection'>
|
||||||
|
<div className='checkbox inlineCheckboxSelect'>
|
||||||
|
<label>
|
||||||
|
<input
|
||||||
|
type='checkbox'
|
||||||
|
checked={desktopSound === 'true'}
|
||||||
|
onChange={handleChangeForMessageNotificationSoundCheckbox}
|
||||||
|
/>
|
||||||
|
<FormattedMessage
|
||||||
|
id='user.settings.notifications.desktopNotificationSound.messageNotificationSound'
|
||||||
|
defaultMessage='Message notification sound'
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
<ReactSelect
|
||||||
|
id='messageNotificationSoundSelect'
|
||||||
|
inputId='messageNotificationSoundSelectInput'
|
||||||
|
className='react-select inlineSelect'
|
||||||
|
classNamePrefix='react-select'
|
||||||
|
options={optionsOfMessageNotificationSoundsSelect}
|
||||||
|
clearable={false}
|
||||||
|
isClearable={false}
|
||||||
|
isSearchable={false}
|
||||||
|
isDisabled={!isMessageNotificationSoundChecked}
|
||||||
|
placeholder={intl.formatMessage({
|
||||||
|
id: 'user.settings.notifications.desktopNotificationSound.soundSelectPlaceholder',
|
||||||
|
defaultMessage: 'Select a sound',
|
||||||
|
})}
|
||||||
|
components={{IndicatorSeparator: NoIndicatorSeparatorComponent}}
|
||||||
|
value={getValueOfMessageNotificationSoundsSelect(desktopNotificationSound)}
|
||||||
|
onChange={handleChangeForMessageNotificationSoundSelect}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</Fragment>
|
||||||
|
);
|
||||||
|
maximizedSettingInputs.push(messageSoundSection);
|
||||||
|
|
||||||
|
if (isCallsRingingEnabled) {
|
||||||
|
const isIncomingCallSoundChecked = callsDesktopSound === 'true';
|
||||||
|
const callSoundSection = (
|
||||||
|
<Fragment key='callSoundSection'>
|
||||||
|
<br/>
|
||||||
|
<div className='checkbox inlineCheckboxSelect'>
|
||||||
|
<label>
|
||||||
|
<input
|
||||||
|
type='checkbox'
|
||||||
|
checked={isIncomingCallSoundChecked}
|
||||||
|
onChange={handleChangeForIncomginCallSoundCheckbox}
|
||||||
|
/>
|
||||||
|
<FormattedMessage
|
||||||
|
id='user.settings.notifications.desktopNotificationSound.incomingCallSound'
|
||||||
|
defaultMessage='Incoming call sound'
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
<ReactSelect
|
||||||
|
id='incomingCallSoundNotificationSelect'
|
||||||
|
inputId='incomingCallSoundNotificationSelectInput'
|
||||||
|
className='react-select inlineSelect'
|
||||||
|
classNamePrefix='react-select'
|
||||||
|
options={optionsOfIncomingCallSoundsSelect}
|
||||||
|
clearable={false}
|
||||||
|
isClearable={false}
|
||||||
|
isSearchable={false}
|
||||||
|
isDisabled={!isIncomingCallSoundChecked}
|
||||||
|
components={{IndicatorSeparator: NoIndicatorSeparatorComponent}}
|
||||||
|
placeholder={intl.formatMessage({
|
||||||
|
id: 'user.settings.notifications.desktopNotificationSound.soundSelectPlaceholder',
|
||||||
|
defaultMessage: 'Select a sound',
|
||||||
|
})}
|
||||||
|
value={getValueOfIncomingCallSoundsSelect(callsNotificationSound)}
|
||||||
|
onChange={handleChangeForIncomingCallSoundSelect}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</Fragment>
|
||||||
|
);
|
||||||
|
maximizedSettingInputs.push(callSoundSection);
|
||||||
|
}
|
||||||
|
return maximizedSettingInputs;
|
||||||
|
},
|
||||||
|
[
|
||||||
|
desktopSound,
|
||||||
|
handleChangeForMessageNotificationSoundCheckbox,
|
||||||
|
handleChangeForMessageNotificationSoundSelect,
|
||||||
|
desktopNotificationSound,
|
||||||
|
isCallsRingingEnabled,
|
||||||
|
callsDesktopSound,
|
||||||
|
handleChangeForIncomginCallSoundCheckbox,
|
||||||
|
callsNotificationSound,
|
||||||
|
handleChangeForIncomingCallSoundSelect,
|
||||||
|
]);
|
||||||
|
|
||||||
|
function handleChangeForMaxSection(section: string) {
|
||||||
|
stopTryNotificationRing();
|
||||||
|
updateSection(section);
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleChangeForMinSection(section: string) {
|
||||||
|
stopTryNotificationRing();
|
||||||
|
updateSection(section);
|
||||||
|
onCancel();
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleSubmit() {
|
||||||
|
stopTryNotificationRing();
|
||||||
|
onSubmit();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (active) {
|
||||||
|
return (
|
||||||
|
<SettingItemMax
|
||||||
|
title={
|
||||||
|
<FormattedMessage
|
||||||
|
id='user.settings.notifications.desktopNotificationSounds.title'
|
||||||
|
defaultMessage='Desktop notification sounds'
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
inputs={maximizedSettingInputs}
|
||||||
|
submit={handleSubmit}
|
||||||
|
saving={saving}
|
||||||
|
serverError={error}
|
||||||
|
updateSection={handleChangeForMaxSection}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SettingItemMin
|
||||||
|
ref={editButtonRef}
|
||||||
|
title={
|
||||||
|
<FormattedMessage
|
||||||
|
id='user.settings.notifications.desktopNotificationSounds.title'
|
||||||
|
defaultMessage='Desktop notification sounds'
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
describe={getCollapsedText(isCallsRingingEnabled, desktopSound, desktopNotificationSound, callsDesktopSound, callsNotificationSound)}
|
||||||
|
section={UserSettingsNotificationSections.DESKTOP_NOTIFICATION_SOUND}
|
||||||
|
updateSection={handleChangeForMinSection}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function NoIndicatorSeparatorComponent() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const notificationSoundKeys = Array.from(notificationSounds.keys());
|
||||||
|
|
||||||
|
const optionsOfMessageNotificationSoundsSelect: SelectOption[] = notificationSoundKeys.map((soundName) => {
|
||||||
|
if (soundName === 'Bing') {
|
||||||
|
return {
|
||||||
|
value: soundName,
|
||||||
|
label: (
|
||||||
|
<FormattedMessage
|
||||||
|
id='user.settings.notifications.desktopNotificationSound.soundBing'
|
||||||
|
defaultMessage='Bing'
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
};
|
||||||
|
} else if (soundName === 'Crackle') {
|
||||||
|
return {
|
||||||
|
value: soundName,
|
||||||
|
label: (
|
||||||
|
<FormattedMessage
|
||||||
|
id='user.settings.notifications.desktopNotificationSound.soundCrackle'
|
||||||
|
defaultMessage='Crackle'
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
};
|
||||||
|
} else if (soundName === 'Down') {
|
||||||
|
return {
|
||||||
|
value: soundName,
|
||||||
|
label: (
|
||||||
|
<FormattedMessage
|
||||||
|
id='user.settings.notifications.desktopNotificationSound.soundDown'
|
||||||
|
defaultMessage='Down'
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
};
|
||||||
|
} else if (soundName === 'Hello') {
|
||||||
|
return {
|
||||||
|
value: soundName,
|
||||||
|
label: (
|
||||||
|
<FormattedMessage
|
||||||
|
id='user.settings.notifications.desktopNotificationSound.soundHello'
|
||||||
|
defaultMessage='Hello'
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
};
|
||||||
|
} else if (soundName === 'Ripple') {
|
||||||
|
return {
|
||||||
|
value: soundName,
|
||||||
|
label: (
|
||||||
|
<FormattedMessage
|
||||||
|
id='user.settings.notifications.desktopNotificationSound.soundRipple'
|
||||||
|
defaultMessage='Ripple'
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
};
|
||||||
|
} else if (soundName === 'Upstairs') {
|
||||||
|
return {
|
||||||
|
value: soundName,
|
||||||
|
label: (
|
||||||
|
<FormattedMessage
|
||||||
|
id='user.settings.notifications.desktopNotificationSound.soundUpstairs'
|
||||||
|
defaultMessage='Upstairs'
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
value: '',
|
||||||
|
label: '',
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
function getValueOfMessageNotificationSoundsSelect(soundName?: string) {
|
||||||
|
const soundOption = optionsOfMessageNotificationSoundsSelect.find((option) => option.value === soundName);
|
||||||
|
|
||||||
|
if (!soundOption) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
return soundOption;
|
||||||
|
}
|
||||||
|
|
||||||
|
const callNotificationSoundKeys = Array.from(callsNotificationSounds.keys());
|
||||||
|
|
||||||
|
const optionsOfIncomingCallSoundsSelect: SelectOption[] = callNotificationSoundKeys.map((soundName) => {
|
||||||
|
if (soundName === 'Dynamic') {
|
||||||
|
return {
|
||||||
|
value: soundName,
|
||||||
|
label: (
|
||||||
|
<FormattedMessage
|
||||||
|
id='user.settings.notifications.desktopNotificationSound.soundDynamic'
|
||||||
|
defaultMessage='Dynamic'
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
};
|
||||||
|
} else if (soundName === 'Calm') {
|
||||||
|
return {
|
||||||
|
value: soundName,
|
||||||
|
label: (
|
||||||
|
<FormattedMessage
|
||||||
|
id='user.settings.notifications.desktopNotificationSound.soundCalm'
|
||||||
|
defaultMessage='Calm'
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
};
|
||||||
|
} else if (soundName === 'Urgent') {
|
||||||
|
return {
|
||||||
|
value: soundName,
|
||||||
|
label: (
|
||||||
|
<FormattedMessage
|
||||||
|
id='user.settings.notifications.desktopNotificationSound.soundUrgent'
|
||||||
|
defaultMessage='Urgent'
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
};
|
||||||
|
} else if (soundName === 'Cheerful') {
|
||||||
|
return {
|
||||||
|
value: soundName,
|
||||||
|
label: (
|
||||||
|
<FormattedMessage
|
||||||
|
id='user.settings.notifications.desktopNotificationSound.soundCheerful'
|
||||||
|
defaultMessage='Cheerful'
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
value: '',
|
||||||
|
label: '',
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
function getValueOfIncomingCallSoundsSelect(soundName?: string) {
|
||||||
|
const soundOption = optionsOfIncomingCallSoundsSelect.find((option) => option.value === soundName);
|
||||||
|
|
||||||
|
if (!soundOption) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
return soundOption;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getCollapsedText(
|
||||||
|
isCallsRingingEnabled: UserSettingsNotificationsProps['isCallsRingingEnabled'],
|
||||||
|
desktopSound: UserNotifyProps['desktop_sound'],
|
||||||
|
desktopNotificationSound: UserNotifyProps['desktop_notification_sound'],
|
||||||
|
callsDesktopSound: UserNotifyProps['calls_desktop_sound'],
|
||||||
|
callsNotificationSound: UserNotifyProps['calls_notification_sound'],
|
||||||
|
) {
|
||||||
|
const desktopNotificationSoundIsSelected = notificationSoundKeys.includes(desktopNotificationSound as string);
|
||||||
|
const callNotificationSoundIsSelected = callNotificationSoundKeys.includes(callsNotificationSound as string);
|
||||||
|
|
||||||
|
let hasCallsSound: boolean | null = null;
|
||||||
|
if (isCallsRingingEnabled && callNotificationSoundIsSelected) {
|
||||||
|
if (callsDesktopSound === 'true') {
|
||||||
|
hasCallsSound = true;
|
||||||
|
} else {
|
||||||
|
hasCallsSound = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let hasDesktopSound: boolean | null = null;
|
||||||
|
if (desktopNotificationSoundIsSelected) {
|
||||||
|
if (desktopSound === 'true') {
|
||||||
|
hasDesktopSound = true;
|
||||||
|
} else {
|
||||||
|
hasDesktopSound = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasDesktopSound !== null && hasCallsSound !== null) {
|
||||||
|
if (hasDesktopSound && hasCallsSound) {
|
||||||
|
return (
|
||||||
|
<FormattedMessage
|
||||||
|
id='user.settings.notifications.desktopNotificationSound.hasDesktopAndCallsSound'
|
||||||
|
defaultMessage='"{desktopSound}" for messages, "{callsSound}" for calls'
|
||||||
|
values={{
|
||||||
|
desktopSound: desktopNotificationSound,
|
||||||
|
callsSound: callsNotificationSound,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
} else if (!hasDesktopSound && hasCallsSound) {
|
||||||
|
return (
|
||||||
|
<FormattedMessage
|
||||||
|
id='user.settings.notifications.desktopNotificationSound.noDesktopAndhasCallsSound'
|
||||||
|
defaultMessage='No sound for messages, "{callsSound}" for calls'
|
||||||
|
values={{callsSound: callsNotificationSound}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
} else if (hasDesktopSound && !hasCallsSound) {
|
||||||
|
return (
|
||||||
|
<FormattedMessage
|
||||||
|
id='user.settings.notifications.desktopNotificationSound.hasDesktopAndNoCallsSound'
|
||||||
|
defaultMessage='"{desktopSound}" for messages, no sound for calls'
|
||||||
|
values={{desktopSound: desktopNotificationSound}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<FormattedMessage
|
||||||
|
id='user.settings.notifications.desktopNotificationSound.noDesktopAndNoCallsSound'
|
||||||
|
defaultMessage='No sound'
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
} else if (hasDesktopSound !== null && hasCallsSound === null) {
|
||||||
|
if (hasDesktopSound) {
|
||||||
|
return (
|
||||||
|
<FormattedMessage
|
||||||
|
id='user.settings.notifications.desktopNotificationSound.hasDesktopSound'
|
||||||
|
defaultMessage='"{desktopSound}" for messages'
|
||||||
|
values={{desktopSound: desktopNotificationSound}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<FormattedMessage
|
||||||
|
id='user.settings.notifications.desktopNotificationSound.noDesktopSound'
|
||||||
|
defaultMessage='No sound'
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<FormattedMessage
|
||||||
|
id='user.settings.notifications.desktopNotificationSound.noValidSound'
|
||||||
|
defaultMessage='Configure desktop notification sounds'
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default memo(DesktopNotificationSoundsSettings);
|
@ -95,7 +95,7 @@ exports[`components/user_settings/notifications/EmailNotificationSetting should
|
|||||||
submit={[Function]}
|
submit={[Function]}
|
||||||
title={
|
title={
|
||||||
<Memo(MemoizedFormattedMessage)
|
<Memo(MemoizedFormattedMessage)
|
||||||
defaultMessage="Email Notifications"
|
defaultMessage="Email notifications"
|
||||||
id="user.settings.notifications.emailNotifications"
|
id="user.settings.notifications.emailNotifications"
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
@ -109,16 +109,16 @@ exports[`components/user_settings/notifications/EmailNotificationSetting should
|
|||||||
id="settingTitle"
|
id="settingTitle"
|
||||||
>
|
>
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
defaultMessage="Email Notifications"
|
defaultMessage="Email notifications"
|
||||||
id="user.settings.notifications.emailNotifications"
|
id="user.settings.notifications.emailNotifications"
|
||||||
>
|
>
|
||||||
<span>
|
<span>
|
||||||
Email Notifications
|
Email notifications
|
||||||
</span>
|
</span>
|
||||||
</FormattedMessage>
|
</FormattedMessage>
|
||||||
</h4>
|
</h4>
|
||||||
<div
|
<div
|
||||||
className="col-sm-9 col-sm-offset-3"
|
className="sectionContent col-sm-10 col-sm-offset-2"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className="setting-list"
|
className="setting-list"
|
||||||
@ -289,7 +289,7 @@ exports[`components/user_settings/notifications/EmailNotificationSetting should
|
|||||||
section="email"
|
section="email"
|
||||||
title={
|
title={
|
||||||
<Memo(MemoizedFormattedMessage)
|
<Memo(MemoizedFormattedMessage)
|
||||||
defaultMessage="Email Notifications"
|
defaultMessage="Email notifications"
|
||||||
id="user.settings.notifications.emailNotifications"
|
id="user.settings.notifications.emailNotifications"
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
@ -308,7 +308,7 @@ exports[`components/user_settings/notifications/EmailNotificationSetting should
|
|||||||
section="email"
|
section="email"
|
||||||
title={
|
title={
|
||||||
<Memo(MemoizedFormattedMessage)
|
<Memo(MemoizedFormattedMessage)
|
||||||
defaultMessage="Email Notifications"
|
defaultMessage="Email notifications"
|
||||||
id="user.settings.notifications.emailNotifications"
|
id="user.settings.notifications.emailNotifications"
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
@ -327,7 +327,7 @@ exports[`components/user_settings/notifications/EmailNotificationSetting should
|
|||||||
section="email"
|
section="email"
|
||||||
title={
|
title={
|
||||||
<Memo(MemoizedFormattedMessage)
|
<Memo(MemoizedFormattedMessage)
|
||||||
defaultMessage="Email Notifications"
|
defaultMessage="Email notifications"
|
||||||
id="user.settings.notifications.emailNotifications"
|
id="user.settings.notifications.emailNotifications"
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
@ -479,7 +479,7 @@ exports[`components/user_settings/notifications/EmailNotificationSetting should
|
|||||||
submit={[Function]}
|
submit={[Function]}
|
||||||
title={
|
title={
|
||||||
<Memo(MemoizedFormattedMessage)
|
<Memo(MemoizedFormattedMessage)
|
||||||
defaultMessage="Email Notifications"
|
defaultMessage="Email notifications"
|
||||||
id="user.settings.notifications.emailNotifications"
|
id="user.settings.notifications.emailNotifications"
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
@ -493,16 +493,16 @@ exports[`components/user_settings/notifications/EmailNotificationSetting should
|
|||||||
id="settingTitle"
|
id="settingTitle"
|
||||||
>
|
>
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
defaultMessage="Email Notifications"
|
defaultMessage="Email notifications"
|
||||||
id="user.settings.notifications.emailNotifications"
|
id="user.settings.notifications.emailNotifications"
|
||||||
>
|
>
|
||||||
<span>
|
<span>
|
||||||
Email Notifications
|
Email notifications
|
||||||
</span>
|
</span>
|
||||||
</FormattedMessage>
|
</FormattedMessage>
|
||||||
</h4>
|
</h4>
|
||||||
<div
|
<div
|
||||||
className="col-sm-9 col-sm-offset-3"
|
className="sectionContent col-sm-10 col-sm-offset-2"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className="setting-list"
|
className="setting-list"
|
||||||
@ -744,7 +744,7 @@ exports[`components/user_settings/notifications/EmailNotificationSetting should
|
|||||||
serverError=""
|
serverError=""
|
||||||
title={
|
title={
|
||||||
<Memo(MemoizedFormattedMessage)
|
<Memo(MemoizedFormattedMessage)
|
||||||
defaultMessage="Email Notifications"
|
defaultMessage="Email notifications"
|
||||||
id="user.settings.notifications.emailNotifications"
|
id="user.settings.notifications.emailNotifications"
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
@ -824,7 +824,7 @@ exports[`components/user_settings/notifications/EmailNotificationSetting should
|
|||||||
submit={[Function]}
|
submit={[Function]}
|
||||||
title={
|
title={
|
||||||
<Memo(MemoizedFormattedMessage)
|
<Memo(MemoizedFormattedMessage)
|
||||||
defaultMessage="Email Notifications"
|
defaultMessage="Email notifications"
|
||||||
id="user.settings.notifications.emailNotifications"
|
id="user.settings.notifications.emailNotifications"
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
@ -898,16 +898,8 @@ exports[`components/user_settings/notifications/EmailNotificationSetting should
|
|||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
<hr />
|
<hr />
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<legend
|
|
||||||
className="form-legend"
|
|
||||||
>
|
|
||||||
<Memo(MemoizedFormattedMessage)
|
|
||||||
defaultMessage="Thread reply notifications"
|
|
||||||
id="user.settings.notifications.threads.desktop"
|
|
||||||
/>
|
|
||||||
</legend>
|
|
||||||
<div
|
<div
|
||||||
className="checkbox"
|
className="checkbox single-checkbox"
|
||||||
>
|
>
|
||||||
<label>
|
<label>
|
||||||
<input
|
<input
|
||||||
@ -918,19 +910,10 @@ exports[`components/user_settings/notifications/EmailNotificationSetting should
|
|||||||
type="checkbox"
|
type="checkbox"
|
||||||
/>
|
/>
|
||||||
<Memo(MemoizedFormattedMessage)
|
<Memo(MemoizedFormattedMessage)
|
||||||
defaultMessage="Notify me about threads I'm following"
|
defaultMessage="Notify me about replies to threads I’m following"
|
||||||
id="user.settings.notifications.threads.allActivity"
|
id="user.settings.notifications.email.notifyForthreads"
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
<br />
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
className="mt-5"
|
|
||||||
>
|
|
||||||
<Memo(MemoizedFormattedMessage)
|
|
||||||
defaultMessage="When enabled, any reply to a thread you're following will send an email notification."
|
|
||||||
id="user.settings.notifications.email_threads"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
</React.Fragment>,
|
</React.Fragment>,
|
||||||
@ -942,7 +925,7 @@ exports[`components/user_settings/notifications/EmailNotificationSetting should
|
|||||||
submit={[Function]}
|
submit={[Function]}
|
||||||
title={
|
title={
|
||||||
<Memo(MemoizedFormattedMessage)
|
<Memo(MemoizedFormattedMessage)
|
||||||
defaultMessage="Email Notifications"
|
defaultMessage="Email notifications"
|
||||||
id="user.settings.notifications.emailNotifications"
|
id="user.settings.notifications.emailNotifications"
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
@ -1022,7 +1005,7 @@ exports[`components/user_settings/notifications/EmailNotificationSetting should
|
|||||||
submit={[Function]}
|
submit={[Function]}
|
||||||
title={
|
title={
|
||||||
<Memo(MemoizedFormattedMessage)
|
<Memo(MemoizedFormattedMessage)
|
||||||
defaultMessage="Email Notifications"
|
defaultMessage="Email notifications"
|
||||||
id="user.settings.notifications.emailNotifications"
|
id="user.settings.notifications.emailNotifications"
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
|
@ -237,8 +237,8 @@ export default class EmailNotificationSetting extends React.PureComponent<Props,
|
|||||||
ref={this.editButtonRef}
|
ref={this.editButtonRef}
|
||||||
title={
|
title={
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
id={'user.settings.notifications.emailNotifications'}
|
id='user.settings.notifications.emailNotifications'
|
||||||
defaultMessage={'Email Notifications'}
|
defaultMessage='Email notifications'
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
describe={description}
|
describe={description}
|
||||||
@ -254,8 +254,8 @@ export default class EmailNotificationSetting extends React.PureComponent<Props,
|
|||||||
<SettingItemMax
|
<SettingItemMax
|
||||||
title={
|
title={
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
id={'user.settings.notifications.emailNotifications'}
|
id='user.settings.notifications.emailNotifications'
|
||||||
defaultMessage={'Email Notifications'}
|
defaultMessage='Email notifications'
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
inputs={[
|
inputs={[
|
||||||
@ -334,13 +334,7 @@ export default class EmailNotificationSetting extends React.PureComponent<Props,
|
|||||||
<React.Fragment key='userNotificationEmailThreadsOptions'>
|
<React.Fragment key='userNotificationEmailThreadsOptions'>
|
||||||
<hr/>
|
<hr/>
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<legend className='form-legend'>
|
<div className='checkbox single-checkbox'>
|
||||||
<FormattedMessage
|
|
||||||
id='user.settings.notifications.threads.desktop'
|
|
||||||
defaultMessage='Thread reply notifications'
|
|
||||||
/>
|
|
||||||
</legend>
|
|
||||||
<div className='checkbox'>
|
|
||||||
<label>
|
<label>
|
||||||
<input
|
<input
|
||||||
id='desktopThreadsNotificationAllActivity'
|
id='desktopThreadsNotificationAllActivity'
|
||||||
@ -350,17 +344,10 @@ export default class EmailNotificationSetting extends React.PureComponent<Props,
|
|||||||
onChange={this.handleThreadsOnChange}
|
onChange={this.handleThreadsOnChange}
|
||||||
/>
|
/>
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
id='user.settings.notifications.threads.allActivity'
|
id='user.settings.notifications.email.notifyForthreads'
|
||||||
defaultMessage={'Notify me about threads I\'m following'}
|
defaultMessage={'Notify me about replies to threads I’m following'}
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
<br/>
|
|
||||||
</div>
|
|
||||||
<div className='mt-5'>
|
|
||||||
<FormattedMessage
|
|
||||||
id='user.settings.notifications.email_threads'
|
|
||||||
defaultMessage={'When enabled, any reply to a thread you\'re following will send an email notification.'}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
@ -371,8 +358,8 @@ export default class EmailNotificationSetting extends React.PureComponent<Props,
|
|||||||
<SettingItemMax
|
<SettingItemMax
|
||||||
title={
|
title={
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
id={'user.settings.notifications.emailNotifications'}
|
id='user.settings.notifications.emailNotifications'
|
||||||
defaultMessage={'Email Notifications'}
|
defaultMessage='Email notifications'
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
inputs={[
|
inputs={[
|
||||||
|
@ -48,12 +48,11 @@ exports[`components/user_settings/notifications/ManageAutoResponder should match
|
|||||||
submit={[MockFunction]}
|
submit={[MockFunction]}
|
||||||
title={
|
title={
|
||||||
<Memo(MemoizedFormattedMessage)
|
<Memo(MemoizedFormattedMessage)
|
||||||
defaultMessage="Automatic Direct Message Replies"
|
defaultMessage="Automatic direct message replies"
|
||||||
id="user.settings.notifications.autoResponder"
|
id="user.settings.notifications.autoResponder"
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
updateSection={[MockFunction]}
|
updateSection={[MockFunction]}
|
||||||
width="medium"
|
|
||||||
>
|
>
|
||||||
<section
|
<section
|
||||||
className="section-max form-horizontal "
|
className="section-max form-horizontal "
|
||||||
@ -63,16 +62,16 @@ exports[`components/user_settings/notifications/ManageAutoResponder should match
|
|||||||
id="settingTitle"
|
id="settingTitle"
|
||||||
>
|
>
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
defaultMessage="Automatic Direct Message Replies"
|
defaultMessage="Automatic direct message replies"
|
||||||
id="user.settings.notifications.autoResponder"
|
id="user.settings.notifications.autoResponder"
|
||||||
>
|
>
|
||||||
<span>
|
<span>
|
||||||
Automatic Direct Message Replies
|
Automatic direct message replies
|
||||||
</span>
|
</span>
|
||||||
</FormattedMessage>
|
</FormattedMessage>
|
||||||
</h4>
|
</h4>
|
||||||
<div
|
<div
|
||||||
className="col-sm-10 col-sm-offset-2"
|
className="sectionContent col-sm-10 col-sm-offset-2"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className="setting-list"
|
className="setting-list"
|
||||||
@ -262,12 +261,11 @@ exports[`components/user_settings/notifications/ManageAutoResponder should match
|
|||||||
submit={[MockFunction]}
|
submit={[MockFunction]}
|
||||||
title={
|
title={
|
||||||
<Memo(MemoizedFormattedMessage)
|
<Memo(MemoizedFormattedMessage)
|
||||||
defaultMessage="Automatic Direct Message Replies"
|
defaultMessage="Automatic direct message replies"
|
||||||
id="user.settings.notifications.autoResponder"
|
id="user.settings.notifications.autoResponder"
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
updateSection={[MockFunction]}
|
updateSection={[MockFunction]}
|
||||||
width="medium"
|
|
||||||
>
|
>
|
||||||
<section
|
<section
|
||||||
className="section-max form-horizontal "
|
className="section-max form-horizontal "
|
||||||
@ -277,16 +275,16 @@ exports[`components/user_settings/notifications/ManageAutoResponder should match
|
|||||||
id="settingTitle"
|
id="settingTitle"
|
||||||
>
|
>
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
defaultMessage="Automatic Direct Message Replies"
|
defaultMessage="Automatic direct message replies"
|
||||||
id="user.settings.notifications.autoResponder"
|
id="user.settings.notifications.autoResponder"
|
||||||
>
|
>
|
||||||
<span>
|
<span>
|
||||||
Automatic Direct Message Replies
|
Automatic direct message replies
|
||||||
</span>
|
</span>
|
||||||
</FormattedMessage>
|
</FormattedMessage>
|
||||||
</h4>
|
</h4>
|
||||||
<div
|
<div
|
||||||
className="col-sm-10 col-sm-offset-2"
|
className="sectionContent col-sm-10 col-sm-offset-2"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className="setting-list"
|
className="setting-list"
|
||||||
|
@ -106,10 +106,9 @@ export default class ManageAutoResponder extends React.PureComponent<Props> {
|
|||||||
title={
|
title={
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
id='user.settings.notifications.autoResponder'
|
id='user.settings.notifications.autoResponder'
|
||||||
defaultMessage='Automatic Direct Message Replies'
|
defaultMessage='Automatic direct message replies'
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
width='medium'
|
|
||||||
shiftEnter={true}
|
shiftEnter={true}
|
||||||
submit={this.props.submit}
|
submit={this.props.submit}
|
||||||
saving={this.props.saving}
|
saving={this.props.saving}
|
||||||
|
@ -5,9 +5,10 @@ import React from 'react';
|
|||||||
import {type IntlShape} from 'react-intl';
|
import {type IntlShape} from 'react-intl';
|
||||||
|
|
||||||
import {renderWithContext, screen} from 'tests/react_testing_utils';
|
import {renderWithContext, screen} from 'tests/react_testing_utils';
|
||||||
|
import {NotificationLevels} from 'utils/constants';
|
||||||
import {TestHelper} from 'utils/test_helper';
|
import {TestHelper} from 'utils/test_helper';
|
||||||
|
|
||||||
import UserSettingsNotifications from './user_settings_notifications';
|
import UserSettingsNotifications, {areDesktopAndMobileSettingsDifferent} from './user_settings_notifications';
|
||||||
|
|
||||||
describe('components/user_settings/display/UserSettingsDisplay', () => {
|
describe('components/user_settings/display/UserSettingsDisplay', () => {
|
||||||
const defaultProps = {
|
const defaultProps = {
|
||||||
@ -20,7 +21,7 @@ describe('components/user_settings/display/UserSettingsDisplay', () => {
|
|||||||
isCollapsedThreadsEnabled: true,
|
isCollapsedThreadsEnabled: true,
|
||||||
sendPushNotifications: false,
|
sendPushNotifications: false,
|
||||||
enableAutoResponder: false,
|
enableAutoResponder: false,
|
||||||
isCallsRingingEnabled: true,
|
isCallsRingingEnabled: false,
|
||||||
intl: {} as IntlShape,
|
intl: {} as IntlShape,
|
||||||
isEnterpriseOrCloudOrSKUStarterFree: false,
|
isEnterpriseOrCloudOrSKUStarterFree: false,
|
||||||
isEnterpriseReady: true,
|
isEnterpriseReady: true,
|
||||||
@ -62,3 +63,27 @@ describe('components/user_settings/display/UserSettingsDisplay', () => {
|
|||||||
expect(screen.getByText('Reply notifications')).toBeInTheDocument();
|
expect(screen.getByText('Reply notifications')).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('areDesktopAndMobileSettingsDifferent', () => {
|
||||||
|
test('should return true when desktop and push notification levels are different', () => {
|
||||||
|
expect(areDesktopAndMobileSettingsDifferent(NotificationLevels.ALL, NotificationLevels.MENTION, NotificationLevels.ALL, NotificationLevels.NONE, true)).toBe(true);
|
||||||
|
expect(areDesktopAndMobileSettingsDifferent(NotificationLevels.ALL, NotificationLevels.NONE, NotificationLevels.ALL, NotificationLevels.MENTION, true)).toBe(true);
|
||||||
|
expect(areDesktopAndMobileSettingsDifferent(NotificationLevels.ALL, NotificationLevels.NONE, NotificationLevels.MENTION, NotificationLevels.NONE, true)).toBe(true);
|
||||||
|
expect(areDesktopAndMobileSettingsDifferent(NotificationLevels.ALL, NotificationLevels.MENTION, NotificationLevels.NONE, NotificationLevels.NONE, true)).toBe(true);
|
||||||
|
expect(areDesktopAndMobileSettingsDifferent(NotificationLevels.ALL, NotificationLevels.NONE, NotificationLevels.NONE, NotificationLevels.NONE, true)).toBe(true);
|
||||||
|
expect(areDesktopAndMobileSettingsDifferent(NotificationLevels.ALL, NotificationLevels.MENTION, NotificationLevels.ALL, NotificationLevels.MENTION, true)).toBe(true);
|
||||||
|
expect(areDesktopAndMobileSettingsDifferent(NotificationLevels.ALL, NotificationLevels.NONE, NotificationLevels.ALL, NotificationLevels.NONE, true)).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should return false when desktop and push notification levels are the same', () => {
|
||||||
|
expect(areDesktopAndMobileSettingsDifferent(NotificationLevels.ALL, NotificationLevels.ALL, NotificationLevels.ALL, NotificationLevels.ALL, true)).toBe(false);
|
||||||
|
expect(areDesktopAndMobileSettingsDifferent(NotificationLevels.MENTION, NotificationLevels.MENTION, NotificationLevels.MENTION, NotificationLevels.MENTION, false)).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should return true any of desktop or push settings are undefined', () => {
|
||||||
|
expect(areDesktopAndMobileSettingsDifferent(undefined as any, NotificationLevels.ALL, NotificationLevels.ALL, NotificationLevels.ALL, true)).toBe(true);
|
||||||
|
expect(areDesktopAndMobileSettingsDifferent(NotificationLevels.ALL, undefined as any, NotificationLevels.ALL, NotificationLevels.ALL, true)).toBe(true);
|
||||||
|
expect(areDesktopAndMobileSettingsDifferent(NotificationLevels.ALL, NotificationLevels.ALL, undefined as any, NotificationLevels.ALL, true)).toBe(true);
|
||||||
|
expect(areDesktopAndMobileSettingsDifferent(NotificationLevels.ALL, NotificationLevels.ALL, NotificationLevels.ALL, undefined as any, true)).toBe(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
@ -11,21 +11,19 @@ import type {Styles as ReactSelectStyles, ValueType} from 'react-select';
|
|||||||
import CreatableReactSelect from 'react-select/creatable';
|
import CreatableReactSelect from 'react-select/creatable';
|
||||||
|
|
||||||
import {LightbulbOutlineIcon} from '@mattermost/compass-icons/components';
|
import {LightbulbOutlineIcon} from '@mattermost/compass-icons/components';
|
||||||
import type {ServerError} from '@mattermost/types/errors';
|
|
||||||
import type {UserNotifyProps, UserProfile} from '@mattermost/types/users';
|
import type {UserNotifyProps, UserProfile} from '@mattermost/types/users';
|
||||||
|
|
||||||
import type {ActionResult} from 'mattermost-redux/types/actions';
|
|
||||||
|
|
||||||
import ExternalLink from 'components/external_link';
|
import ExternalLink from 'components/external_link';
|
||||||
import SettingItem from 'components/setting_item';
|
import SettingItem from 'components/setting_item';
|
||||||
import SettingItemMax from 'components/setting_item_max';
|
import SettingItemMax from 'components/setting_item_max';
|
||||||
import RestrictedIndicator from 'components/widgets/menu/menu_items/restricted_indicator';
|
import RestrictedIndicator from 'components/widgets/menu/menu_items/restricted_indicator';
|
||||||
|
|
||||||
import Constants, {NotificationLevels, MattermostFeatures, LicenseSkus} from 'utils/constants';
|
import Constants, {NotificationLevels, MattermostFeatures, LicenseSkus, UserSettingsNotificationSections} from 'utils/constants';
|
||||||
import {stopTryNotificationRing} from 'utils/notification_sounds';
|
import {stopTryNotificationRing} from 'utils/notification_sounds';
|
||||||
import {a11yFocus} from 'utils/utils';
|
import {a11yFocus} from 'utils/utils';
|
||||||
|
|
||||||
import DesktopNotificationSettings from './desktop_notification_setting/desktop_notification_settings';
|
import DesktopAndMobileNotificationSettings from './desktop_and_mobile_notification_setting';
|
||||||
|
import DesktopNotificationSoundsSettings from './desktop_notification_sounds_setting';
|
||||||
import EmailNotificationSetting from './email_notification_setting';
|
import EmailNotificationSetting from './email_notification_setting';
|
||||||
import ManageAutoResponder from './manage_auto_responder/manage_auto_responder';
|
import ManageAutoResponder from './manage_auto_responder/manage_auto_responder';
|
||||||
|
|
||||||
@ -50,7 +48,7 @@ type OwnProps = {
|
|||||||
collapseModal: () => void;
|
collapseModal: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
type Props = PropsFromRedux & OwnProps & WrappedComponentProps;
|
export type Props = PropsFromRedux & OwnProps & WrappedComponentProps;
|
||||||
|
|
||||||
type State = {
|
type State = {
|
||||||
enableEmail: UserNotifyProps['email'];
|
enableEmail: UserNotifyProps['email'];
|
||||||
@ -77,6 +75,7 @@ type State = {
|
|||||||
notifyCommentsLevel: UserNotifyProps['comments'];
|
notifyCommentsLevel: UserNotifyProps['comments'];
|
||||||
isSaving: boolean;
|
isSaving: boolean;
|
||||||
serverError: string;
|
serverError: string;
|
||||||
|
desktopAndMobileSettingsDifferent: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
function getDefaultStateFromProps(props: Props): State {
|
function getDefaultStateFromProps(props: Props): State {
|
||||||
@ -97,6 +96,7 @@ function getDefaultStateFromProps(props: Props): State {
|
|||||||
id: 'user.settings.notifications.autoResponderDefault',
|
id: 'user.settings.notifications.autoResponderDefault',
|
||||||
defaultMessage: 'Hello, I am out of office and unable to respond to messages.',
|
defaultMessage: 'Hello, I am out of office and unable to respond to messages.',
|
||||||
});
|
});
|
||||||
|
let desktopAndMobileSettingsDifferent = true;
|
||||||
|
|
||||||
if (props.user.notify_props) {
|
if (props.user.notify_props) {
|
||||||
if (props.user.notify_props.desktop) {
|
if (props.user.notify_props.desktop) {
|
||||||
@ -143,6 +143,10 @@ function getDefaultStateFromProps(props: Props): State {
|
|||||||
if (props.user.notify_props.auto_responder_message) {
|
if (props.user.notify_props.auto_responder_message) {
|
||||||
autoResponderMessage = props.user.notify_props.auto_responder_message;
|
autoResponderMessage = props.user.notify_props.auto_responder_message;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (props.user.notify_props.desktop && props.user.notify_props.push) {
|
||||||
|
desktopAndMobileSettingsDifferent = areDesktopAndMobileSettingsDifferent(props.user.notify_props.desktop, props.user.notify_props.push, props.user.notify_props?.desktop_threads, props.user.notify_props?.push_threads, props.isCollapsedThreadsEnabled);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let usernameKey = false;
|
let usernameKey = false;
|
||||||
@ -211,6 +215,7 @@ function getDefaultStateFromProps(props: Props): State {
|
|||||||
notifyCommentsLevel: comments,
|
notifyCommentsLevel: comments,
|
||||||
isSaving: false,
|
isSaving: false,
|
||||||
serverError: '',
|
serverError: '',
|
||||||
|
desktopAndMobileSettingsDifferent,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -235,8 +240,6 @@ class NotificationsTab extends React.PureComponent<Props, State> {
|
|||||||
data.desktop = this.state.desktopActivity;
|
data.desktop = this.state.desktopActivity;
|
||||||
data.desktop_threads = this.state.desktopThreads;
|
data.desktop_threads = this.state.desktopThreads;
|
||||||
data.email_threads = this.state.emailThreads;
|
data.email_threads = this.state.emailThreads;
|
||||||
data.push_threads = this.state.pushThreads;
|
|
||||||
data.push = this.state.pushActivity;
|
|
||||||
data.push_status = this.state.pushStatus;
|
data.push_status = this.state.pushStatus;
|
||||||
data.comments = this.state.notifyCommentsLevel;
|
data.comments = this.state.notifyCommentsLevel;
|
||||||
data.auto_responder_active = this.state.autoResponderActive ? 'true' : 'false';
|
data.auto_responder_active = this.state.autoResponderActive ? 'true' : 'false';
|
||||||
@ -244,6 +247,14 @@ class NotificationsTab extends React.PureComponent<Props, State> {
|
|||||||
data.first_name = this.state.firstNameKey ? 'true' : 'false';
|
data.first_name = this.state.firstNameKey ? 'true' : 'false';
|
||||||
data.channel = this.state.channelKey ? 'true' : 'false';
|
data.channel = this.state.channelKey ? 'true' : 'false';
|
||||||
|
|
||||||
|
if (this.state.desktopAndMobileSettingsDifferent) {
|
||||||
|
data.push = this.state.pushActivity;
|
||||||
|
data.push_threads = this.state.pushThreads;
|
||||||
|
} else {
|
||||||
|
data.push = this.state.desktopActivity;
|
||||||
|
data.push_threads = this.state.desktopThreads;
|
||||||
|
}
|
||||||
|
|
||||||
if (!data.auto_responder_message || data.auto_responder_message === '') {
|
if (!data.auto_responder_message || data.auto_responder_message === '') {
|
||||||
data.auto_responder_message = this.props.intl.formatMessage({
|
data.auto_responder_message = this.props.intl.formatMessage({
|
||||||
id: 'user.settings.notifications.autoResponderDefault',
|
id: 'user.settings.notifications.autoResponderDefault',
|
||||||
@ -273,7 +284,7 @@ class NotificationsTab extends React.PureComponent<Props, State> {
|
|||||||
this.setState({isSaving: true});
|
this.setState({isSaving: true});
|
||||||
stopTryNotificationRing();
|
stopTryNotificationRing();
|
||||||
|
|
||||||
const {data: updatedUser, error} = await this.props.updateMe({notify_props: data}) as ActionResult<Partial<UserProfile>, ServerError>; // Fix in MM-46907
|
const {data: updatedUser, error} = await this.props.updateMe({notify_props: data});
|
||||||
if (updatedUser) {
|
if (updatedUser) {
|
||||||
this.handleUpdateSection('');
|
this.handleUpdateSection('');
|
||||||
this.setState(getDefaultStateFromProps(this.props));
|
this.setState(getDefaultStateFromProps(this.props));
|
||||||
@ -305,26 +316,11 @@ class NotificationsTab extends React.PureComponent<Props, State> {
|
|||||||
this.setState((prevState) => ({...prevState, ...data}));
|
this.setState((prevState) => ({...prevState, ...data}));
|
||||||
};
|
};
|
||||||
|
|
||||||
handleNotifyPushThread = (e: ChangeEvent<HTMLInputElement>): void => {
|
|
||||||
const pushThreads = e.target.checked ? NotificationLevels.ALL : NotificationLevels.MENTION;
|
|
||||||
this.setState({pushThreads});
|
|
||||||
};
|
|
||||||
|
|
||||||
handleNotifyCommentsRadio = (notifyCommentsLevel: UserNotifyProps['comments'], e?: React.ChangeEvent): void => {
|
handleNotifyCommentsRadio = (notifyCommentsLevel: UserNotifyProps['comments'], e?: React.ChangeEvent): void => {
|
||||||
this.setState({notifyCommentsLevel});
|
this.setState({notifyCommentsLevel});
|
||||||
a11yFocus(e?.currentTarget as HTMLElement);
|
a11yFocus(e?.currentTarget as HTMLElement);
|
||||||
};
|
};
|
||||||
|
|
||||||
handlePushRadio = (pushActivity: UserNotifyProps['push'], e?: React.ChangeEvent): void => {
|
|
||||||
this.setState({pushActivity});
|
|
||||||
a11yFocus(e?.currentTarget as HTMLElement);
|
|
||||||
};
|
|
||||||
|
|
||||||
handlePushStatusRadio = (pushStatus: UserNotifyProps['push_status'], e?: React.ChangeEvent): void => {
|
|
||||||
this.setState({pushStatus});
|
|
||||||
a11yFocus(e?.currentTarget as HTMLElement);
|
|
||||||
};
|
|
||||||
|
|
||||||
handleEmailRadio = (enableEmail: UserNotifyProps['email']): void => {
|
handleEmailRadio = (enableEmail: UserNotifyProps['email']): void => {
|
||||||
this.setState({enableEmail});
|
this.setState({enableEmail});
|
||||||
};
|
};
|
||||||
@ -472,311 +468,10 @@ class NotificationsTab extends React.PureComponent<Props, State> {
|
|||||||
this.props.closeModal();
|
this.props.closeModal();
|
||||||
};
|
};
|
||||||
|
|
||||||
createPushNotificationSection = () => {
|
|
||||||
const active = this.props.activeSection === 'push';
|
|
||||||
const inputs = [];
|
|
||||||
let submit = null;
|
|
||||||
let max = null;
|
|
||||||
|
|
||||||
if (active) {
|
|
||||||
if (this.props.sendPushNotifications) {
|
|
||||||
const pushActivityRadio = [false, false, false];
|
|
||||||
if (this.state.pushActivity === NotificationLevels.ALL) {
|
|
||||||
pushActivityRadio[0] = true;
|
|
||||||
} else if (this.state.pushActivity === NotificationLevels.NONE) {
|
|
||||||
pushActivityRadio[2] = true;
|
|
||||||
} else {
|
|
||||||
pushActivityRadio[1] = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
const pushStatusRadio = [false, false, false];
|
|
||||||
if (this.state.pushStatus === Constants.UserStatuses.ONLINE) {
|
|
||||||
pushStatusRadio[0] = true;
|
|
||||||
} else if (this.state.pushStatus === Constants.UserStatuses.AWAY) {
|
|
||||||
pushStatusRadio[1] = true;
|
|
||||||
} else {
|
|
||||||
pushStatusRadio[2] = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
let pushThreadsNotificationSelection = null;
|
|
||||||
if (this.props.isCollapsedThreadsEnabled && this.state.pushActivity === NotificationLevels.MENTION) {
|
|
||||||
pushThreadsNotificationSelection = (
|
|
||||||
<React.Fragment key='userNotificationPushThreadsOptions'>
|
|
||||||
<hr/>
|
|
||||||
<fieldset>
|
|
||||||
<legend className='form-legend'>
|
|
||||||
<FormattedMessage
|
|
||||||
id='user.settings.notifications.threads.push'
|
|
||||||
defaultMessage='Thread reply notifications'
|
|
||||||
/>
|
|
||||||
</legend>
|
|
||||||
<div className='checkbox'>
|
|
||||||
<label>
|
|
||||||
<input
|
|
||||||
id='pushThreadsNotificationAllActivity'
|
|
||||||
type='checkbox'
|
|
||||||
name='pushThreadsNotificationLevel'
|
|
||||||
checked={this.state.pushThreads === NotificationLevels.ALL}
|
|
||||||
onChange={this.handleNotifyPushThread}
|
|
||||||
/>
|
|
||||||
<FormattedMessage
|
|
||||||
id='user.settings.notifications.push_threads.allActivity'
|
|
||||||
defaultMessage={'Notify me about threads I\'m following'}
|
|
||||||
/>
|
|
||||||
</label>
|
|
||||||
<br/>
|
|
||||||
</div>
|
|
||||||
<div className='mt-5'>
|
|
||||||
<FormattedMessage
|
|
||||||
id='user.settings.notifications.push_threads'
|
|
||||||
defaultMessage={'When enabled, any reply to a thread you\'re following will send a mobile push notification.'}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</fieldset>
|
|
||||||
</React.Fragment>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
let pushStatusSettings;
|
|
||||||
if (this.state.pushActivity !== NotificationLevels.NONE) {
|
|
||||||
pushStatusSettings = (
|
|
||||||
<React.Fragment key='userNotificationPushStatusOptions'>
|
|
||||||
<hr/>
|
|
||||||
<fieldset>
|
|
||||||
<legend className='form-legend'>
|
|
||||||
<FormattedMessage
|
|
||||||
id='user.settings.notifications.push_notification.status'
|
|
||||||
defaultMessage='Trigger push notifications when'
|
|
||||||
/>
|
|
||||||
</legend>
|
|
||||||
<div className='radio'>
|
|
||||||
<label>
|
|
||||||
<input
|
|
||||||
id='pushNotificationOnline'
|
|
||||||
type='radio'
|
|
||||||
name='pushNotificationStatus'
|
|
||||||
checked={pushStatusRadio[0]}
|
|
||||||
onChange={this.handlePushStatusRadio.bind(this, Constants.UserStatuses.ONLINE)}
|
|
||||||
/>
|
|
||||||
<FormattedMessage
|
|
||||||
id='user.settings.push_notification.online'
|
|
||||||
defaultMessage='Online, away or offline'
|
|
||||||
/>
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
<div className='radio'>
|
|
||||||
<label>
|
|
||||||
<input
|
|
||||||
id='pushNotificationAway'
|
|
||||||
type='radio'
|
|
||||||
name='pushNotificationStatus'
|
|
||||||
checked={pushStatusRadio[1]}
|
|
||||||
onChange={this.handlePushStatusRadio.bind(this, Constants.UserStatuses.AWAY)}
|
|
||||||
/>
|
|
||||||
<FormattedMessage
|
|
||||||
id='user.settings.push_notification.away'
|
|
||||||
defaultMessage='Away or offline'
|
|
||||||
/>
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
<div className='radio'>
|
|
||||||
<label>
|
|
||||||
<input
|
|
||||||
id='pushNotificationOffline'
|
|
||||||
type='radio'
|
|
||||||
name='pushNotificationStatus'
|
|
||||||
checked={pushStatusRadio[2]}
|
|
||||||
onChange={this.handlePushStatusRadio.bind(this, Constants.UserStatuses.OFFLINE)}
|
|
||||||
/>
|
|
||||||
<FormattedMessage
|
|
||||||
id='user.settings.push_notification.offline'
|
|
||||||
defaultMessage='Offline'
|
|
||||||
/>
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
<div className='mt-5'>
|
|
||||||
<span>
|
|
||||||
<FormattedMessage
|
|
||||||
id='user.settings.push_notification.status_info'
|
|
||||||
defaultMessage='Notification alerts are only pushed to your mobile device when your availability matches the selection above.'
|
|
||||||
/>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</fieldset>
|
|
||||||
</React.Fragment>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
inputs.push(
|
|
||||||
<div>
|
|
||||||
<fieldset key='userNotificationLevelOption'>
|
|
||||||
<legend className='form-legend'>
|
|
||||||
<FormattedMessage
|
|
||||||
id='user.settings.push_notification.send'
|
|
||||||
defaultMessage='Send mobile push notifications'
|
|
||||||
/>
|
|
||||||
</legend>
|
|
||||||
<div className='radio'>
|
|
||||||
<label>
|
|
||||||
<input
|
|
||||||
id='pushNotificationAllActivity'
|
|
||||||
type='radio'
|
|
||||||
name='pushNotificationLevel'
|
|
||||||
checked={pushActivityRadio[0]}
|
|
||||||
onChange={this.handlePushRadio.bind(this, NotificationLevels.ALL)}
|
|
||||||
/>
|
|
||||||
<FormattedMessage
|
|
||||||
id='user.settings.push_notification.allActivity'
|
|
||||||
defaultMessage='For all activity'
|
|
||||||
/>
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
<div className='radio'>
|
|
||||||
<label>
|
|
||||||
<input
|
|
||||||
id='pushNotificationMentions'
|
|
||||||
type='radio'
|
|
||||||
name='pushNotificationLevel'
|
|
||||||
checked={pushActivityRadio[1]}
|
|
||||||
onChange={this.handlePushRadio.bind(this, NotificationLevels.MENTION)}
|
|
||||||
/>
|
|
||||||
<FormattedMessage
|
|
||||||
id='user.settings.push_notification.onlyMentions'
|
|
||||||
defaultMessage='For mentions and direct messages'
|
|
||||||
/>
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
<div className='radio'>
|
|
||||||
<label>
|
|
||||||
<input
|
|
||||||
id='pushNotificationNever'
|
|
||||||
type='radio'
|
|
||||||
name='pushNotificationLevel'
|
|
||||||
checked={pushActivityRadio[2]}
|
|
||||||
onChange={this.handlePushRadio.bind(this, NotificationLevels.NONE)}
|
|
||||||
/>
|
|
||||||
<FormattedMessage
|
|
||||||
id='user.settings.notifications.never'
|
|
||||||
defaultMessage='Never'
|
|
||||||
/>
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
<div className='mt-5'>
|
|
||||||
<FormattedMessage
|
|
||||||
id='user.settings.push_notification.info'
|
|
||||||
defaultMessage='Notification alerts are pushed to your mobile device when there is activity in Mattermost.'
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</fieldset>
|
|
||||||
</div>,
|
|
||||||
pushStatusSettings,
|
|
||||||
pushThreadsNotificationSelection,
|
|
||||||
);
|
|
||||||
|
|
||||||
submit = this.handleSubmit;
|
|
||||||
} else {
|
|
||||||
inputs.push(
|
|
||||||
<div
|
|
||||||
key='oauthEmailInfo'
|
|
||||||
className='pt-2'
|
|
||||||
>
|
|
||||||
<FormattedMessage
|
|
||||||
id='user.settings.push_notification.disabled_long'
|
|
||||||
defaultMessage='Push notifications have not been enabled by your System Administrator.'
|
|
||||||
/>
|
|
||||||
</div>,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
max = (
|
|
||||||
<SettingItemMax
|
|
||||||
title={this.props.intl.formatMessage({id: 'user.settings.notifications.push', defaultMessage: 'Mobile Push Notifications'})}
|
|
||||||
inputs={inputs}
|
|
||||||
submit={submit}
|
|
||||||
serverError={this.state.serverError}
|
|
||||||
updateSection={this.handleUpdateSection}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
let describe: JSX.Element;
|
|
||||||
if (this.state.pushActivity === NotificationLevels.ALL) {
|
|
||||||
if (this.state.pushStatus === Constants.UserStatuses.AWAY) {
|
|
||||||
describe = (
|
|
||||||
<FormattedMessage
|
|
||||||
id='user.settings.push_notification.allActivityAway'
|
|
||||||
defaultMessage='For all activity when away or offline'
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
} else if (this.state.pushStatus === Constants.UserStatuses.OFFLINE) {
|
|
||||||
describe = (
|
|
||||||
<FormattedMessage
|
|
||||||
id='user.settings.push_notification.allActivityOffline'
|
|
||||||
defaultMessage='For all activity when offline'
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
describe = (
|
|
||||||
<FormattedMessage
|
|
||||||
id='user.settings.push_notification.allActivityOnline'
|
|
||||||
defaultMessage='For all activity when online, away or offline'
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} else if (this.state.pushActivity === NotificationLevels.NONE) {
|
|
||||||
describe = (
|
|
||||||
<FormattedMessage
|
|
||||||
id='user.settings.notifications.never'
|
|
||||||
defaultMessage='Never'
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
} else if (this.props.sendPushNotifications) {
|
|
||||||
if (this.state.pushStatus === Constants.UserStatuses.AWAY) { //eslint-disable-line no-lonely-if
|
|
||||||
describe = (
|
|
||||||
<FormattedMessage
|
|
||||||
id='user.settings.push_notification.onlyMentionsAway'
|
|
||||||
defaultMessage='For mentions and direct messages when away or offline'
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
} else if (this.state.pushStatus === Constants.UserStatuses.OFFLINE) {
|
|
||||||
describe = (
|
|
||||||
<FormattedMessage
|
|
||||||
id='user.settings.push_notification.onlyMentionsOffline'
|
|
||||||
defaultMessage='For mentions and direct messages when offline'
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
describe = (
|
|
||||||
<FormattedMessage
|
|
||||||
id='user.settings.push_notification.onlyMentionsOnline'
|
|
||||||
defaultMessage='For mentions and direct messages when online, away or offline'
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
describe = (
|
|
||||||
<FormattedMessage
|
|
||||||
id='user.settings.push_notification.disabled'
|
|
||||||
defaultMessage='Push notifications are not enabled'
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<SettingItem
|
|
||||||
title={this.props.intl.formatMessage({id: 'user.settings.notifications.push', defaultMessage: 'Mobile Push Notifications'})}
|
|
||||||
active={active}
|
|
||||||
areAllSectionsInactive={this.props.activeSection === ''}
|
|
||||||
describe={describe}
|
|
||||||
section={'push'}
|
|
||||||
updateSection={this.handleUpdateSection}
|
|
||||||
max={max}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
createKeywordsWithNotificationSection = () => {
|
createKeywordsWithNotificationSection = () => {
|
||||||
const serverError = this.state.serverError;
|
const serverError = this.state.serverError;
|
||||||
const user = this.props.user;
|
const user = this.props.user;
|
||||||
const isSectionExpanded = this.props.activeSection === 'keysWithNotification';
|
const isSectionExpanded = this.props.activeSection === UserSettingsNotificationSections.KEYWORDS_MENTIONS;
|
||||||
|
|
||||||
let expandedSection = null;
|
let expandedSection = null;
|
||||||
if (isSectionExpanded) {
|
if (isSectionExpanded) {
|
||||||
@ -901,7 +596,7 @@ class NotificationsTab extends React.PureComponent<Props, State> {
|
|||||||
|
|
||||||
expandedSection = (
|
expandedSection = (
|
||||||
<SettingItemMax
|
<SettingItemMax
|
||||||
title={this.props.intl.formatMessage({id: 'user.settings.notifications.keywordsWithNotification.title', defaultMessage: 'Keywords That Trigger Notifications'})}
|
title={this.props.intl.formatMessage({id: 'user.settings.notifications.keywordsWithNotification.title', defaultMessage: 'Keywords that trigger notifications'})}
|
||||||
inputs={inputs}
|
inputs={inputs}
|
||||||
submit={this.handleSubmit}
|
submit={this.handleSubmit}
|
||||||
saving={this.state.isSaving}
|
saving={this.state.isSaving}
|
||||||
@ -932,8 +627,8 @@ class NotificationsTab extends React.PureComponent<Props, State> {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<SettingItem
|
<SettingItem
|
||||||
title={this.props.intl.formatMessage({id: 'user.settings.notifications.keywordsWithNotification.title', defaultMessage: 'Keywords That Trigger Notifications'})}
|
title={this.props.intl.formatMessage({id: 'user.settings.notifications.keywordsWithNotification.title', defaultMessage: 'Keywords that trigger notifications'})}
|
||||||
section='keysWithNotification'
|
section={UserSettingsNotificationSections.KEYWORDS_MENTIONS}
|
||||||
active={isSectionExpanded}
|
active={isSectionExpanded}
|
||||||
areAllSectionsInactive={this.props.activeSection === ''}
|
areAllSectionsInactive={this.props.activeSection === ''}
|
||||||
describe={collapsedDescription}
|
describe={collapsedDescription}
|
||||||
@ -943,7 +638,7 @@ class NotificationsTab extends React.PureComponent<Props, State> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
createKeywordsWithHighlightSection = () => {
|
createKeywordsWithHighlightSection = () => {
|
||||||
const isSectionExpanded = this.props.activeSection === 'keysWithHighlight';
|
const isSectionExpanded = this.props.activeSection === UserSettingsNotificationSections.KEYWORDS_HIGHLIGHT;
|
||||||
|
|
||||||
let expandedSection = null;
|
let expandedSection = null;
|
||||||
if (isSectionExpanded) {
|
if (isSectionExpanded) {
|
||||||
@ -990,7 +685,7 @@ class NotificationsTab extends React.PureComponent<Props, State> {
|
|||||||
|
|
||||||
expandedSection = (
|
expandedSection = (
|
||||||
<SettingItemMax
|
<SettingItemMax
|
||||||
title={this.props.intl.formatMessage({id: 'user.settings.notifications.keywordsWithHighlight.title', defaultMessage: 'Keywords That Get Highlighted (Without Notifications)'})}
|
title={this.props.intl.formatMessage({id: 'user.settings.notifications.keywordsWithHighlight.title', defaultMessage: 'Keywords that get highlighted (without notifications)'})}
|
||||||
inputs={inputs}
|
inputs={inputs}
|
||||||
submit={this.handleSubmit}
|
submit={this.handleSubmit}
|
||||||
saving={this.state.isSaving}
|
saving={this.state.isSaving}
|
||||||
@ -1063,8 +758,8 @@ class NotificationsTab extends React.PureComponent<Props, State> {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<SettingItem
|
<SettingItem
|
||||||
title={this.props.intl.formatMessage({id: 'user.settings.notifications.keywordsWithHighlight.title', defaultMessage: 'Keywords That Get Highlighted (Without Notifications)'})}
|
title={this.props.intl.formatMessage({id: 'user.settings.notifications.keywordsWithHighlight.title', defaultMessage: 'Keywords that get highlighted (without notifications)'})}
|
||||||
section='keysWithHighlight'
|
section={UserSettingsNotificationSections.KEYWORDS_HIGHLIGHT}
|
||||||
active={isSectionExpanded}
|
active={isSectionExpanded}
|
||||||
areAllSectionsInactive={this.props.activeSection === ''}
|
areAllSectionsInactive={this.props.activeSection === ''}
|
||||||
describe={collapsedDescription}
|
describe={collapsedDescription}
|
||||||
@ -1078,9 +773,8 @@ class NotificationsTab extends React.PureComponent<Props, State> {
|
|||||||
createCommentsSection = () => {
|
createCommentsSection = () => {
|
||||||
const serverError = this.state.serverError;
|
const serverError = this.state.serverError;
|
||||||
|
|
||||||
const active = this.props.activeSection === 'comments';
|
|
||||||
let max = null;
|
let max = null;
|
||||||
if (active) {
|
if (this.props.activeSection === UserSettingsNotificationSections.REPLY_NOTIFCATIONS) {
|
||||||
const commentsActive = [false, false, false];
|
const commentsActive = [false, false, false];
|
||||||
if (this.state.notifyCommentsLevel === 'never') {
|
if (this.state.notifyCommentsLevel === 'never') {
|
||||||
commentsActive[2] = true;
|
commentsActive[2] = true;
|
||||||
@ -1097,7 +791,7 @@ class NotificationsTab extends React.PureComponent<Props, State> {
|
|||||||
<legend className='form-legend hidden-label'>
|
<legend className='form-legend hidden-label'>
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
id='user.settings.notifications.comments'
|
id='user.settings.notifications.comments'
|
||||||
defaultMessage='Reply Notifications'
|
defaultMessage='Reply notifications'
|
||||||
/>
|
/>
|
||||||
</legend>
|
</legend>
|
||||||
<div className='radio'>
|
<div className='radio'>
|
||||||
@ -1161,7 +855,7 @@ class NotificationsTab extends React.PureComponent<Props, State> {
|
|||||||
|
|
||||||
max = (
|
max = (
|
||||||
<SettingItemMax
|
<SettingItemMax
|
||||||
title={this.props.intl.formatMessage({id: 'user.settings.notifications.comments', defaultMessage: 'Reply Notifications'})}
|
title={this.props.intl.formatMessage({id: 'user.settings.notifications.comments', defaultMessage: 'Reply notifications'})}
|
||||||
extraInfo={extraInfo}
|
extraInfo={extraInfo}
|
||||||
inputs={inputs}
|
inputs={inputs}
|
||||||
submit={this.handleSubmit}
|
submit={this.handleSubmit}
|
||||||
@ -1199,9 +893,9 @@ class NotificationsTab extends React.PureComponent<Props, State> {
|
|||||||
return (
|
return (
|
||||||
<SettingItem
|
<SettingItem
|
||||||
title={this.props.intl.formatMessage({id: 'user.settings.notifications.comments', defaultMessage: 'Reply notifications'})}
|
title={this.props.intl.formatMessage({id: 'user.settings.notifications.comments', defaultMessage: 'Reply notifications'})}
|
||||||
active={active}
|
active={this.props.activeSection === UserSettingsNotificationSections.REPLY_NOTIFCATIONS}
|
||||||
describe={describe}
|
describe={describe}
|
||||||
section={'comments'}
|
section={UserSettingsNotificationSections.REPLY_NOTIFCATIONS}
|
||||||
updateSection={this.handleUpdateSection}
|
updateSection={this.handleUpdateSection}
|
||||||
max={max}
|
max={max}
|
||||||
areAllSectionsInactive={this.props.activeSection === ''}
|
areAllSectionsInactive={this.props.activeSection === ''}
|
||||||
@ -1224,16 +918,16 @@ class NotificationsTab extends React.PureComponent<Props, State> {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<SettingItem
|
<SettingItem
|
||||||
active={this.props.activeSection === 'auto-responder'}
|
active={this.props.activeSection === UserSettingsNotificationSections.AUTO_RESPONDER}
|
||||||
areAllSectionsInactive={this.props.activeSection === ''}
|
areAllSectionsInactive={this.props.activeSection === ''}
|
||||||
title={
|
title={
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
id='user.settings.notifications.autoResponder'
|
id='user.settings.notifications.autoResponder'
|
||||||
defaultMessage='Automatic Direct Message Replies'
|
defaultMessage='Automatic direct message replies'
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
describe={describe}
|
describe={describe}
|
||||||
section={'auto-responder'}
|
section={UserSettingsNotificationSections.AUTO_RESPONDER}
|
||||||
updateSection={this.handleUpdateSection}
|
updateSection={this.handleUpdateSection}
|
||||||
max={(
|
max={(
|
||||||
<div>
|
<div>
|
||||||
@ -1254,12 +948,13 @@ class NotificationsTab extends React.PureComponent<Props, State> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const pushNotificationSection = this.createPushNotificationSection();
|
|
||||||
const keywordsWithNotificationSection = this.createKeywordsWithNotificationSection();
|
const keywordsWithNotificationSection = this.createKeywordsWithNotificationSection();
|
||||||
const keywordsWithHighlightSection = this.createKeywordsWithHighlightSection();
|
const keywordsWithHighlightSection = this.createKeywordsWithHighlightSection();
|
||||||
const commentsSection = this.createCommentsSection();
|
const commentsSection = this.createCommentsSection();
|
||||||
const autoResponderSection = this.createAutoResponderSection();
|
const autoResponderSection = this.createAutoResponderSection();
|
||||||
|
|
||||||
|
const areAllSectionsInactive = this.props.activeSection === '';
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div id='notificationSettings'>
|
<div id='notificationSettings'>
|
||||||
<SettingMobileHeader
|
<SettingMobileHeader
|
||||||
@ -1268,7 +963,7 @@ class NotificationsTab extends React.PureComponent<Props, State> {
|
|||||||
text={
|
text={
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
id='user.settings.notifications.title'
|
id='user.settings.notifications.title'
|
||||||
defaultMessage='Notification Settings'
|
defaultMessage='Notification settings'
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
@ -1302,42 +997,56 @@ class NotificationsTab extends React.PureComponent<Props, State> {
|
|||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<div className='divider-dark first'/>
|
<div className='divider-dark first'/>
|
||||||
<DesktopNotificationSettings
|
<DesktopAndMobileNotificationSettings
|
||||||
active={this.props.activeSection === 'desktop'}
|
active={this.props.activeSection === UserSettingsNotificationSections.DESKTOP_AND_MOBILE}
|
||||||
updateSection={this.handleUpdateSection}
|
updateSection={this.handleUpdateSection}
|
||||||
onSubmit={this.handleSubmit}
|
onSubmit={this.handleSubmit}
|
||||||
onCancel={this.handleCancel}
|
onCancel={this.handleCancel}
|
||||||
saving={this.state.isSaving}
|
saving={this.state.isSaving}
|
||||||
error={this.state.serverError}
|
error={this.state.serverError}
|
||||||
setParentState={this.setStateValue}
|
setParentState={this.setStateValue}
|
||||||
areAllSectionsInactive={this.props.activeSection === ''}
|
areAllSectionsInactive={areAllSectionsInactive}
|
||||||
isCollapsedThreadsEnabled={this.props.isCollapsedThreadsEnabled}
|
isCollapsedThreadsEnabled={this.props.isCollapsedThreadsEnabled}
|
||||||
activity={this.state.desktopActivity}
|
desktopActivity={this.state.desktopActivity}
|
||||||
threads={this.state.desktopThreads}
|
pushActivity={this.state.pushActivity}
|
||||||
sound={this.state.desktopSound}
|
sendPushNotifications={this.props.sendPushNotifications}
|
||||||
callsSound={this.state.callsDesktopSound}
|
pushStatus={this.state.pushStatus}
|
||||||
selectedSound={this.state.desktopNotificationSound || 'default'}
|
desktopThreads={this.state.desktopThreads}
|
||||||
callsSelectedSound={this.state.callsNotificationSound || 'default'}
|
pushThreads={this.state.pushThreads}
|
||||||
|
desktopAndMobileSettingsDifferent={this.state.desktopAndMobileSettingsDifferent}
|
||||||
|
/>
|
||||||
|
<div className='divider-light'/>
|
||||||
|
<DesktopNotificationSoundsSettings
|
||||||
|
active={this.props.activeSection === UserSettingsNotificationSections.DESKTOP_NOTIFICATION_SOUND}
|
||||||
|
updateSection={this.handleUpdateSection}
|
||||||
|
onSubmit={this.handleSubmit}
|
||||||
|
onCancel={this.handleCancel}
|
||||||
|
saving={this.state.isSaving}
|
||||||
|
error={this.state.serverError}
|
||||||
|
setParentState={this.setStateValue}
|
||||||
|
areAllSectionsInactive={areAllSectionsInactive}
|
||||||
|
desktopSound={this.state.desktopSound}
|
||||||
|
desktopNotificationSound={this.state.desktopNotificationSound}
|
||||||
isCallsRingingEnabled={this.props.isCallsRingingEnabled}
|
isCallsRingingEnabled={this.props.isCallsRingingEnabled}
|
||||||
|
callsDesktopSound={this.state.callsDesktopSound}
|
||||||
|
callsNotificationSound={this.state.callsNotificationSound}
|
||||||
/>
|
/>
|
||||||
<div className='divider-light'/>
|
<div className='divider-light'/>
|
||||||
<EmailNotificationSetting
|
<EmailNotificationSetting
|
||||||
active={this.props.activeSection === 'email'}
|
active={this.props.activeSection === UserSettingsNotificationSections.EMAIL}
|
||||||
updateSection={this.handleUpdateSection}
|
updateSection={this.handleUpdateSection}
|
||||||
onSubmit={this.handleSubmit}
|
onSubmit={this.handleSubmit}
|
||||||
onCancel={this.handleCancel}
|
onCancel={this.handleCancel}
|
||||||
saving={this.state.isSaving}
|
saving={this.state.isSaving}
|
||||||
error={this.state.serverError}
|
error={this.state.serverError}
|
||||||
setParentState={this.setStateValue}
|
setParentState={this.setStateValue}
|
||||||
areAllSectionsInactive={this.props.activeSection === ''}
|
areAllSectionsInactive={areAllSectionsInactive}
|
||||||
isCollapsedThreadsEnabled={this.props.isCollapsedThreadsEnabled}
|
isCollapsedThreadsEnabled={this.props.isCollapsedThreadsEnabled}
|
||||||
enableEmail={this.state.enableEmail === 'true'}
|
enableEmail={this.state.enableEmail === 'true'}
|
||||||
onChange={this.handleEmailRadio}
|
onChange={this.handleEmailRadio}
|
||||||
threads={this.state.emailThreads || ''}
|
threads={this.state.emailThreads || ''}
|
||||||
/>
|
/>
|
||||||
<div className='divider-light'/>
|
<div className='divider-light'/>
|
||||||
{pushNotificationSection}
|
|
||||||
<div className='divider-light'/>
|
|
||||||
{keywordsWithNotificationSection}
|
{keywordsWithNotificationSection}
|
||||||
{(!this.props.isEnterpriseOrCloudOrSKUStarterFree && this.props.isEnterpriseReady) && (
|
{(!this.props.isEnterpriseOrCloudOrSKUStarterFree && this.props.isEnterpriseReady) && (
|
||||||
<>
|
<>
|
||||||
@ -1414,4 +1123,39 @@ const customKeywordsSelectorStyles: ReactSelectStyles = {
|
|||||||
})),
|
})),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const validNotificationLevels = Object.values(NotificationLevels);
|
||||||
|
|
||||||
|
export function areDesktopAndMobileSettingsDifferent(
|
||||||
|
desktopActivity: UserNotifyProps['desktop'],
|
||||||
|
pushActivity: UserNotifyProps['push'],
|
||||||
|
desktopThreads?: UserNotifyProps['desktop_threads'],
|
||||||
|
pushThreads?: UserNotifyProps['push_threads'],
|
||||||
|
isCollapsedThreadsEnabled?: boolean,
|
||||||
|
): boolean {
|
||||||
|
if (!desktopActivity || !pushActivity || !desktopThreads || !pushThreads) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
!validNotificationLevels.includes(desktopActivity) ||
|
||||||
|
!validNotificationLevels.includes(pushActivity) ||
|
||||||
|
!validNotificationLevels.includes(desktopThreads) ||
|
||||||
|
!validNotificationLevels.includes(pushThreads)
|
||||||
|
) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (desktopActivity === pushActivity) {
|
||||||
|
if (isCollapsedThreadsEnabled) {
|
||||||
|
if (desktopThreads === pushThreads) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
export default injectIntl(NotificationsTab);
|
export default injectIntl(NotificationsTab);
|
||||||
|
@ -77,7 +77,6 @@ exports[`MfaSection rendering when section is expanded and MFA is active and enf
|
|||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
updateSection={[MockFunction]}
|
updateSection={[MockFunction]}
|
||||||
width="medium"
|
|
||||||
/>
|
/>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
@ -118,7 +117,6 @@ exports[`MfaSection rendering when section is expanded and MFA is active but not
|
|||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
updateSection={[MockFunction]}
|
updateSection={[MockFunction]}
|
||||||
width="medium"
|
|
||||||
/>
|
/>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
@ -159,7 +157,6 @@ exports[`MfaSection rendering when section is expanded and MFA is not active 1`]
|
|||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
updateSection={[MockFunction]}
|
updateSection={[MockFunction]}
|
||||||
width="medium"
|
|
||||||
/>
|
/>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
@ -200,6 +197,5 @@ exports[`MfaSection rendering when section is expanded with a server error 1`] =
|
|||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
updateSection={[MockFunction]}
|
updateSection={[MockFunction]}
|
||||||
width="medium"
|
|
||||||
/>
|
/>
|
||||||
`;
|
`;
|
||||||
|
@ -219,7 +219,6 @@ export default class MfaSection extends React.PureComponent<Props, State> {
|
|||||||
extraInfo={this.renderHelpText()}
|
extraInfo={this.renderHelpText()}
|
||||||
serverError={this.state.serverError}
|
serverError={this.state.serverError}
|
||||||
updateSection={this.props.updateSection}
|
updateSection={this.props.updateSection}
|
||||||
width='medium'
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -627,7 +627,7 @@ export default class UserAccessTokenSection extends React.PureComponent<Props, S
|
|||||||
infoPosition='top'
|
infoPosition='top'
|
||||||
serverError={this.state.serverError}
|
serverError={this.state.serverError}
|
||||||
updateSection={this.props.updateSection}
|
updateSection={this.props.updateSection}
|
||||||
width='full'
|
isFullWidth={true}
|
||||||
saving={this.state.saving}
|
saving={this.state.saving}
|
||||||
cancelButtonText={
|
cancelButtonText={
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
|
@ -918,7 +918,7 @@ export class SecurityTab extends React.PureComponent<Props, State> {
|
|||||||
inputs={inputs}
|
inputs={inputs}
|
||||||
serverError={this.state.serverError}
|
serverError={this.state.serverError}
|
||||||
updateSection={this.handleUpdateSection}
|
updateSection={this.handleUpdateSection}
|
||||||
width='full'
|
isFullWidth={true}
|
||||||
cancelButtonText={
|
cancelButtonText={
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
id='user.settings.security.close'
|
id='user.settings.security.close'
|
||||||
|
@ -5643,50 +5643,83 @@
|
|||||||
"user.settings.modal.security": "Security",
|
"user.settings.modal.security": "Security",
|
||||||
"user.settings.modal.sidebar": "Sidebar",
|
"user.settings.modal.sidebar": "Sidebar",
|
||||||
"user.settings.modal.title": "Profile",
|
"user.settings.modal.title": "Profile",
|
||||||
"user.settings.notifications.allActivity": "For all activity",
|
"user.settings.notifications.autoResponder": "Automatic direct message replies",
|
||||||
"user.settings.notifications.autoResponder": "Automatic Direct Message Replies",
|
|
||||||
"user.settings.notifications.autoResponderDefault": "Hello, I am out of office and unable to respond to messages.",
|
"user.settings.notifications.autoResponderDefault": "Hello, I am out of office and unable to respond to messages.",
|
||||||
"user.settings.notifications.autoResponderDisabled": "Disabled",
|
"user.settings.notifications.autoResponderDisabled": "Disabled",
|
||||||
"user.settings.notifications.autoResponderEnabled": "Enabled",
|
"user.settings.notifications.autoResponderEnabled": "Enabled",
|
||||||
"user.settings.notifications.autoResponderHint": "Set a custom message that will be automatically sent in response to Direct Messages. Mentions in Public and Private Channels will not trigger the automated reply. Enabling Automatic Replies sets your status to Out of Office and disables email and push notifications.",
|
"user.settings.notifications.autoResponderHint": "Set a custom message that will be automatically sent in response to Direct Messages. Mentions in Public and Private Channels will not trigger the automated reply. Enabling Automatic Replies sets your status to Out of Office and disables email and push notifications.",
|
||||||
"user.settings.notifications.autoResponderPlaceholder": "Message",
|
"user.settings.notifications.autoResponderPlaceholder": "Message",
|
||||||
"user.settings.notifications.channelWide": "Channel-wide mentions \"@channel\", \"@all\", \"@here\"",
|
"user.settings.notifications.channelWide": "Channel-wide mentions \"@channel\", \"@all\", \"@here\"",
|
||||||
"user.settings.notifications.comments": "Reply Notifications",
|
"user.settings.notifications.comments": "Reply notifications",
|
||||||
"user.settings.notifications.commentsAny": "Trigger notifications on messages in reply threads that I start or participate in",
|
"user.settings.notifications.commentsAny": "Trigger notifications on messages in reply threads that I start or participate in",
|
||||||
"user.settings.notifications.commentsInfo": "In addition to notifications for when you're mentioned, select if you would like to receive notifications on reply threads.",
|
"user.settings.notifications.commentsInfo": "In addition to notifications for when you're mentioned, select if you would like to receive notifications on reply threads.",
|
||||||
"user.settings.notifications.commentsNever": "Do not trigger notifications on messages in reply threads unless I'm mentioned",
|
"user.settings.notifications.commentsNever": "Do not trigger notifications on messages in reply threads unless I'm mentioned",
|
||||||
"user.settings.notifications.commentsRoot": "Trigger notifications on messages in threads that I start",
|
"user.settings.notifications.commentsRoot": "Trigger notifications on messages in threads that I start",
|
||||||
"user.settings.notifications.desktop": "Send desktop notifications",
|
"user.settings.notifications.desktopAndMobile.allDesktopButMobileMentions": "All new messages on desktop; mentions, direct messages, and group messages on mobile",
|
||||||
"user.settings.notifications.desktop.allNoSound": "For all activity, without sound",
|
"user.settings.notifications.desktopAndMobile.allDesktopButMobileNone": "All new messages on desktop; never on mobile",
|
||||||
"user.settings.notifications.desktop.allSound": "For all activity, with sound",
|
"user.settings.notifications.desktopAndMobile.allForDesktopAndMobile": "All new messages",
|
||||||
"user.settings.notifications.desktop.allSoundHidden": "For all activity",
|
"user.settings.notifications.desktopAndMobile.allNewMessages": "All new messages",
|
||||||
"user.settings.notifications.desktop.calls_sound": "Notification sound for incoming calls",
|
"user.settings.notifications.desktopAndMobile.away": "Away or offline",
|
||||||
"user.settings.notifications.desktop.mentionsNoSound": "For mentions and direct messages, without sound",
|
"user.settings.notifications.desktopAndMobile.differentMobileNotificationsTitle": "Use different settings for my mobile devices",
|
||||||
"user.settings.notifications.desktop.mentionsSound": "For mentions and direct messages, with sound",
|
"user.settings.notifications.desktopAndMobile.mentionsDesktopButMobileAll": "Mentions, direct messages, and group messages on desktop; all new messages on mobile",
|
||||||
"user.settings.notifications.desktop.mentionsSoundHidden": "For mentions and direct messages",
|
"user.settings.notifications.desktopAndMobile.mentionsForDesktopAndMobile": "Mentions, direct messages, and group messages",
|
||||||
"user.settings.notifications.desktop.sound": "Notification sound",
|
"user.settings.notifications.desktopAndMobile.mentionsForDesktopButMobileNone": "Mentions, direct messages, and group messages on desktop; never on mobile",
|
||||||
"user.settings.notifications.desktop.title": "Desktop Notifications",
|
"user.settings.notifications.desktopAndMobile.noneDesktopButMobileAll": "Never on desktop; all new messages on mobile",
|
||||||
"user.settings.notifications.email_threads": "When enabled, any reply to a thread you're following will send an email notification.",
|
"user.settings.notifications.desktopAndMobile.noneDesktopButMobileMentions": "Never on desktop; mentions, direct messages, and group messages on mobile",
|
||||||
|
"user.settings.notifications.desktopAndMobile.noneForDesktopAndMobile": "Never",
|
||||||
|
"user.settings.notifications.desktopAndMobile.nothing": "Nothing",
|
||||||
|
"user.settings.notifications.desktopAndMobile.notifyForDesktopthreads": "Notify me about replies to threads I'm following",
|
||||||
|
"user.settings.notifications.desktopAndMobile.notifyForMobilethreads": "Notify me on mobile about replies to threads I'm following",
|
||||||
|
"user.settings.notifications.desktopAndMobile.noValidSettings": "Configure desktop and mobile settings",
|
||||||
|
"user.settings.notifications.desktopAndMobile.offline": "Offline",
|
||||||
|
"user.settings.notifications.desktopAndMobile.online": "Online, away, or offline",
|
||||||
|
"user.settings.notifications.desktopAndMobile.onlyMentions": "Mentions, direct messages, and group messages",
|
||||||
|
"user.settings.notifications.desktopAndMobile.pushNotification": "Trigger mobile notifications when I am:",
|
||||||
|
"user.settings.notifications.desktopAndMobile.pushNotificationsDisabled": "Mobile push notifications haven't been enabled by your system administrator.",
|
||||||
|
"user.settings.notifications.desktopAndMobile.sendDesktopNotificationFor": "Send notifications for:",
|
||||||
|
"user.settings.notifications.desktopAndMobile.sendMobileNotificationsFor": "Send mobile notifications for:",
|
||||||
|
"user.settings.notifications.desktopAndMobile.title": "Desktop and mobile notifications",
|
||||||
|
"user.settings.notifications.desktopNotificationSound.hasDesktopAndCallsSound": "\"{desktopSound}\" for messages, \"{callsSound}\" for calls",
|
||||||
|
"user.settings.notifications.desktopNotificationSound.hasDesktopAndNoCallsSound": "\"{desktopSound}\" for messages, no sound for calls",
|
||||||
|
"user.settings.notifications.desktopNotificationSound.hasDesktopSound": "\"{desktopSound}\" for messages",
|
||||||
|
"user.settings.notifications.desktopNotificationSound.incomingCallSound": "Incoming call sound",
|
||||||
|
"user.settings.notifications.desktopNotificationSound.messageNotificationSound": "Message notification sound",
|
||||||
|
"user.settings.notifications.desktopNotificationSound.noDesktopAndhasCallsSound": "No sound for messages, \"{callsSound}\" for calls",
|
||||||
|
"user.settings.notifications.desktopNotificationSound.noDesktopAndNoCallsSound": "No sound",
|
||||||
|
"user.settings.notifications.desktopNotificationSound.noDesktopSound": "No sound",
|
||||||
|
"user.settings.notifications.desktopNotificationSound.noValidSound": "Configure desktop notification sounds",
|
||||||
|
"user.settings.notifications.desktopNotificationSound.soundBing": "Bing",
|
||||||
|
"user.settings.notifications.desktopNotificationSound.soundCalm": "Calm",
|
||||||
|
"user.settings.notifications.desktopNotificationSound.soundCheerful": "Cheerful",
|
||||||
|
"user.settings.notifications.desktopNotificationSound.soundCrackle": "Crackle",
|
||||||
|
"user.settings.notifications.desktopNotificationSound.soundDown": "Down",
|
||||||
|
"user.settings.notifications.desktopNotificationSound.soundDynamic": "Dynamic",
|
||||||
|
"user.settings.notifications.desktopNotificationSound.soundHello": "Hello",
|
||||||
|
"user.settings.notifications.desktopNotificationSound.soundRipple": "Ripple",
|
||||||
|
"user.settings.notifications.desktopNotificationSound.soundSelectPlaceholder": "Select a sound",
|
||||||
|
"user.settings.notifications.desktopNotificationSound.soundUpstairs": "Upstairs",
|
||||||
|
"user.settings.notifications.desktopNotificationSound.soundUrgent": "Urgent",
|
||||||
|
"user.settings.notifications.desktopNotificationSounds.title": "Desktop notification sounds",
|
||||||
"user.settings.notifications.email.disabled": "Email notifications are not enabled",
|
"user.settings.notifications.email.disabled": "Email notifications are not enabled",
|
||||||
"user.settings.notifications.email.disabled_long": "Email notifications have not been enabled by your System Administrator.",
|
"user.settings.notifications.email.disabled_long": "Email notifications have not been enabled by your System Administrator.",
|
||||||
"user.settings.notifications.email.everyHour": "Every hour",
|
"user.settings.notifications.email.everyHour": "Every hour",
|
||||||
"user.settings.notifications.email.everyXMinutes": "Every {count, plural, one {minute} other {{count, number} minutes}}",
|
"user.settings.notifications.email.everyXMinutes": "Every {count, plural, one {minute} other {{count, number} minutes}}",
|
||||||
"user.settings.notifications.email.immediately": "Immediately",
|
"user.settings.notifications.email.immediately": "Immediately",
|
||||||
"user.settings.notifications.email.never": "Never",
|
"user.settings.notifications.email.never": "Never",
|
||||||
|
"user.settings.notifications.email.notifyForthreads": "Notify me about replies to threads I’m following",
|
||||||
"user.settings.notifications.email.send": "Send email notifications",
|
"user.settings.notifications.email.send": "Send email notifications",
|
||||||
"user.settings.notifications.emailBatchingInfo": "Notifications received over the time period selected are combined and sent in a single email.",
|
"user.settings.notifications.emailBatchingInfo": "Notifications received over the time period selected are combined and sent in a single email.",
|
||||||
"user.settings.notifications.emailInfo": "Email notifications are sent for mentions and direct messages when you are offline or away for more than 5 minutes.",
|
"user.settings.notifications.emailInfo": "Email notifications are sent for mentions and direct messages when you are offline or away for more than 5 minutes.",
|
||||||
"user.settings.notifications.emailNotifications": "Email Notifications",
|
"user.settings.notifications.emailNotifications": "Email notifications",
|
||||||
"user.settings.notifications.header": "Notifications",
|
"user.settings.notifications.header": "Notifications",
|
||||||
"user.settings.notifications.icon": "Notification Settings Icon",
|
"user.settings.notifications.icon": "Notification Settings Icon",
|
||||||
"user.settings.notifications.info": "Desktop notifications are available on Edge, Firefox, Safari, Chrome and Mattermost Desktop Apps.",
|
|
||||||
"user.settings.notifications.keywordsWithHighlight.disabledTooltipMessage": "This feature is available on the Professional plan",
|
"user.settings.notifications.keywordsWithHighlight.disabledTooltipMessage": "This feature is available on the Professional plan",
|
||||||
"user.settings.notifications.keywordsWithHighlight.disabledTooltipTitle": "Professional feature",
|
"user.settings.notifications.keywordsWithHighlight.disabledTooltipTitle": "Professional feature",
|
||||||
"user.settings.notifications.keywordsWithHighlight.extraInfo": "These keywords will be shown to you with a highlight when anyone sends a message that includes them.",
|
"user.settings.notifications.keywordsWithHighlight.extraInfo": "These keywords will be shown to you with a highlight when anyone sends a message that includes them.",
|
||||||
"user.settings.notifications.keywordsWithHighlight.inputTitle": "Enter non case-sensitive keywords, press Tab or use commas to separate them:",
|
"user.settings.notifications.keywordsWithHighlight.inputTitle": "Enter non case-sensitive keywords, press Tab or use commas to separate them:",
|
||||||
"user.settings.notifications.keywordsWithHighlight.none": "None",
|
"user.settings.notifications.keywordsWithHighlight.none": "None",
|
||||||
"user.settings.notifications.keywordsWithHighlight.professional": "Professional",
|
"user.settings.notifications.keywordsWithHighlight.professional": "Professional",
|
||||||
"user.settings.notifications.keywordsWithHighlight.title": "Keywords That Get Highlighted (Without Notifications)",
|
"user.settings.notifications.keywordsWithHighlight.title": "Keywords that get highlighted (without notifications)",
|
||||||
"user.settings.notifications.keywordsWithHighlight.userModal.messageAdminPostTrial": "Get the ability to passively highlight keywords that you care about. Upgrade to Professional plan to unlock this feature.",
|
"user.settings.notifications.keywordsWithHighlight.userModal.messageAdminPostTrial": "Get the ability to passively highlight keywords that you care about. Upgrade to Professional plan to unlock this feature.",
|
||||||
"user.settings.notifications.keywordsWithHighlight.userModal.messageAdminPreTrial": "Get the ability to passively highlight keywords that you care about. Upgrade to Professional plan to unlock this feature.",
|
"user.settings.notifications.keywordsWithHighlight.userModal.messageAdminPreTrial": "Get the ability to passively highlight keywords that you care about. Upgrade to Professional plan to unlock this feature.",
|
||||||
"user.settings.notifications.keywordsWithHighlight.userModal.messageEndUser": "Get the ability to passively highlight keywords that you care about.{br}{br}Request your admin to upgrade to Mattermost Professional to access this feature.",
|
"user.settings.notifications.keywordsWithHighlight.userModal.messageEndUser": "Get the ability to passively highlight keywords that you care about.{br}{br}Request your admin to upgrade to Mattermost Professional to access this feature.",
|
||||||
@ -5694,44 +5727,14 @@
|
|||||||
"user.settings.notifications.keywordsWithHighlight.userModal.titleAdminPreTrial": "Highlight keywords without notifications with Mattermost Professional",
|
"user.settings.notifications.keywordsWithHighlight.userModal.titleAdminPreTrial": "Highlight keywords without notifications with Mattermost Professional",
|
||||||
"user.settings.notifications.keywordsWithHighlight.userModal.titleEndUser": "Highlight keywords without notifications with Mattermost Professional",
|
"user.settings.notifications.keywordsWithHighlight.userModal.titleEndUser": "Highlight keywords without notifications with Mattermost Professional",
|
||||||
"user.settings.notifications.keywordsWithNotification.extraInfo": "Notifications are triggered when someone sends a message that includes your username (\"@{username}\") or any of the options selected above.",
|
"user.settings.notifications.keywordsWithNotification.extraInfo": "Notifications are triggered when someone sends a message that includes your username (\"@{username}\") or any of the options selected above.",
|
||||||
"user.settings.notifications.keywordsWithNotification.title": "Keywords That Trigger Notifications",
|
"user.settings.notifications.keywordsWithNotification.title": "Keywords that trigger notifications",
|
||||||
"user.settings.notifications.learnMore": "<a>Learn more about notifications</a>",
|
"user.settings.notifications.learnMore": "<a>Learn more about notifications</a>",
|
||||||
"user.settings.notifications.never": "Never",
|
|
||||||
"user.settings.notifications.off": "Off",
|
|
||||||
"user.settings.notifications.on": "On",
|
|
||||||
"user.settings.notifications.onlyMentions": "Only for mentions, direct messages, and group messages",
|
|
||||||
"user.settings.notifications.push": "Mobile Push Notifications",
|
|
||||||
"user.settings.notifications.push_notification.status": "Trigger push notifications when",
|
|
||||||
"user.settings.notifications.push_threads": "When enabled, any reply to a thread you're following will send a mobile push notification.",
|
|
||||||
"user.settings.notifications.push_threads.allActivity": "Notify me about threads I'm following",
|
|
||||||
"user.settings.notifications.sensitiveCustomWords": "Other non case-sensitive words, press Tab or use commas to separate keywords:",
|
"user.settings.notifications.sensitiveCustomWords": "Other non case-sensitive words, press Tab or use commas to separate keywords:",
|
||||||
"user.settings.notifications.sensitiveName": "Your case-sensitive first name \"{first_name}\"",
|
"user.settings.notifications.sensitiveName": "Your case-sensitive first name \"{first_name}\"",
|
||||||
"user.settings.notifications.sensitiveUsername": "Your non case-sensitive username \"{username}\"",
|
"user.settings.notifications.sensitiveUsername": "Your non case-sensitive username \"{username}\"",
|
||||||
"user.settings.notifications.soundConfig": "Please configure notification sounds in your browser settings",
|
"user.settings.notifications.title": "Notification settings",
|
||||||
"user.settings.notifications.sounds_info": "Notification sounds are available on Firefox, Edge, Safari, Chrome and Mattermost Desktop Apps.",
|
|
||||||
"user.settings.notifications.threads": "When enabled, any reply to a thread you're following will send a desktop notification.",
|
|
||||||
"user.settings.notifications.threads.allActivity": "Notify me about threads I'm following",
|
|
||||||
"user.settings.notifications.threads.desktop": "Thread reply notifications",
|
|
||||||
"user.settings.notifications.threads.push": "Thread reply notifications",
|
|
||||||
"user.settings.notifications.title": "Notification Settings",
|
|
||||||
"user.settings.plugins.title": "{pluginName} Settings",
|
"user.settings.plugins.title": "{pluginName} Settings",
|
||||||
"user.settings.profile.icon": "Profile Settings Icon",
|
"user.settings.profile.icon": "Profile Settings Icon",
|
||||||
"user.settings.push_notification.allActivity": "For all activity",
|
|
||||||
"user.settings.push_notification.allActivityAway": "For all activity when away or offline",
|
|
||||||
"user.settings.push_notification.allActivityOffline": "For all activity when offline",
|
|
||||||
"user.settings.push_notification.allActivityOnline": "For all activity when online, away or offline",
|
|
||||||
"user.settings.push_notification.away": "Away or offline",
|
|
||||||
"user.settings.push_notification.disabled": "Push notifications are not enabled",
|
|
||||||
"user.settings.push_notification.disabled_long": "Push notifications have not been enabled by your System Administrator.",
|
|
||||||
"user.settings.push_notification.info": "Notification alerts are pushed to your mobile device when there is activity in Mattermost.",
|
|
||||||
"user.settings.push_notification.offline": "Offline",
|
|
||||||
"user.settings.push_notification.online": "Online, away or offline",
|
|
||||||
"user.settings.push_notification.onlyMentions": "For mentions and direct messages",
|
|
||||||
"user.settings.push_notification.onlyMentionsAway": "For mentions and direct messages when away or offline",
|
|
||||||
"user.settings.push_notification.onlyMentionsOffline": "For mentions and direct messages when offline",
|
|
||||||
"user.settings.push_notification.onlyMentionsOnline": "For mentions and direct messages when online, away or offline",
|
|
||||||
"user.settings.push_notification.send": "Send mobile push notifications",
|
|
||||||
"user.settings.push_notification.status_info": "Notification alerts are only pushed to your mobile device when your availability matches the selection above.",
|
|
||||||
"user.settings.security.active": "Active",
|
"user.settings.security.active": "Active",
|
||||||
"user.settings.security.close": "Close",
|
"user.settings.security.close": "Close",
|
||||||
"user.settings.security.currentPassword": "Current Password",
|
"user.settings.security.currentPassword": "Current Password",
|
||||||
|
@ -204,7 +204,3 @@ input[type="radio"]:focus,
|
|||||||
input[type="checkbox"]:focus {
|
input[type="checkbox"]:focus {
|
||||||
outline: none;
|
outline: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.notification-sound-dropdown {
|
|
||||||
padding-top: 5px;
|
|
||||||
}
|
|
||||||
|
@ -79,8 +79,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
label {
|
label {
|
||||||
font-weight: 600;
|
|
||||||
|
|
||||||
&.text-left {
|
&.text-left {
|
||||||
text-align: left;
|
text-align: left;
|
||||||
}
|
}
|
||||||
@ -221,17 +219,56 @@
|
|||||||
.section-max {
|
.section-max {
|
||||||
@include pie-clearfix;
|
@include pie-clearfix;
|
||||||
|
|
||||||
padding: 1em 0 1.3em;
|
padding: 12px;
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
background: rgba(var(--center-channel-color-rgb), 0.04);
|
background: rgba(var(--center-channel-color-rgb), 0.04);
|
||||||
|
|
||||||
.section-title {
|
.section-title {
|
||||||
padding-left: 14px;
|
padding: 0;
|
||||||
margin: 0 0 5px;
|
margin: 0;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
font-weight: 600;
|
font-weight: 400;
|
||||||
line-height: 20px;
|
line-height: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.sectionContent {
|
||||||
|
padding: 20px 0 0 0;
|
||||||
|
|
||||||
|
.checkbox.single-checkbox {
|
||||||
|
min-height: unset;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.inlineCheckboxSelect {
|
||||||
|
display: flex;
|
||||||
|
min-height: unset;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 0;
|
||||||
|
|
||||||
|
label {
|
||||||
|
margin-inline-end: 24px;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.inlineSelect {
|
||||||
|
width: 40%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.singleSelectLabel {
|
||||||
|
margin-bottom: 12px;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 600;
|
||||||
|
line-height: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
hr {
|
||||||
|
padding: 0;
|
||||||
|
margin-block-end: 24px;
|
||||||
|
margin-block-start: 24px;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.timezone-container {
|
.timezone-container {
|
||||||
|
@ -966,13 +966,14 @@ export const ChannelAutoFollowThreads = {
|
|||||||
OFF: 'off',
|
OFF: 'off',
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
export const NotificationSections = {
|
export const UserSettingsNotificationSections = {
|
||||||
IGNORE_CHANNEL_MENTIONS: 'ignoreChannelMentions',
|
DESKTOP_AND_MOBILE: 'desktopAndMobile',
|
||||||
CHANNEL_AUTO_FOLLOW_THREADS: 'channelAutoFollowThreads',
|
DESKTOP_NOTIFICATION_SOUND: 'desktopNotificationSound',
|
||||||
MARK_UNREAD: 'markUnread',
|
EMAIL: 'email',
|
||||||
DESKTOP: 'desktop',
|
KEYWORDS_MENTIONS: 'keywordsAndMentions',
|
||||||
PUSH: 'push',
|
KEYWORDS_HIGHLIGHT: 'keywordsAndHighlight',
|
||||||
NONE: '',
|
REPLY_NOTIFCATIONS: 'replyNotifications',
|
||||||
|
AUTO_RESPONDER: 'autoResponder',
|
||||||
};
|
};
|
||||||
|
|
||||||
export const AdvancedSections = {
|
export const AdvancedSections = {
|
||||||
|
Loading…
Reference in New Issue
Block a user