[MM-56824] Componentize the Mobile and Desktop section headers in the user settings modal. (#26193)

This commit is contained in:
M-ZubairAhmed 2024-02-15 09:56:25 +00:00 committed by GitHub
parent 86c880cf87
commit 114b3dc8d2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
24 changed files with 705 additions and 1217 deletions

View File

@ -17,7 +17,6 @@ import {emitUserLoggedOutEvent} from 'actions/global_actions';
import ConfirmModal from 'components/confirm_modal';
import SettingItem from 'components/setting_item';
import SettingItemMax from 'components/setting_item_max';
import BackIcon from 'components/widgets/icons/fa_back_icon';
import Constants, {AdvancedSections, Preferences} from 'utils/constants';
import {t} from 'utils/i18n';
@ -27,6 +26,9 @@ import {a11yFocus, localizeMessage} from 'utils/utils';
import JoinLeaveSection from './join_leave_section';
import PerformanceDebuggingSection from './performance_debugging_section';
import SettingDesktopHeader from '../headers/setting_desktop_header';
import SettingMobileHeader from '../headers/setting_mobile_header';
const PreReleaseFeatures = Constants.PRE_RELEASE_FEATURES;
type Settings = {
@ -898,38 +900,25 @@ export default class AdvancedSettingsDisplay extends React.PureComponent<Props,
return (
<div>
<div className='modal-header'>
<button
id='closeButton'
type='button'
className='close'
data-dismiss='modal'
aria-label='Close'
onClick={this.props.closeModal}
>
<span aria-hidden='true'>{'×'}</span>
</button>
<h4
className='modal-title'
>
<div className='modal-back'>
<span onClick={this.props.collapseModal}>
<BackIcon/>
</span>
</div>
<SettingMobileHeader
closeModal={this.props.closeModal}
collapseModal={this.props.collapseModal}
text={
<FormattedMessage
id='user.settings.advance.title'
defaultMessage='Advanced Settings'
/>
</h4>
</div>
}
/>
<div className='user-settings'>
<h3 className='tab-header'>
<FormattedMessage
id='user.settings.advance.title'
defaultMessage='Advanced Settings'
/>
</h3>
<SettingDesktopHeader
text={
<FormattedMessage
id='user.settings.advance.title'
defaultMessage='Advanced Settings'
/>
}
/>
<div className='divider-dark first'/>
{ctrlSendSection}
{formattingSectionDivider}

View File

@ -4,53 +4,28 @@ exports[`components/user_settings/display/UserSettingsDisplay should match snaps
<div
id="displaySettings"
>
<div
className="modal-header"
>
<button
aria-label="Close"
className="close"
data-dismiss="modal"
id="closeButton"
onClick={[MockFunction]}
type="button"
>
<span
aria-hidden="true"
>
×
</span>
</button>
<h4
className="modal-title"
>
<div
className="modal-back"
>
<span
onClick={[MockFunction]}
>
<BackIcon />
</span>
</div>
<MemoizedFormattedMessage
<SettingMobileHeader
closeModal={[MockFunction]}
collapseModal={[MockFunction]}
text={
<Memo(MemoizedFormattedMessage)
defaultMessage="Display Settings"
id="user.settings.display.title"
/>
</h4>
</div>
}
/>
<div
className="user-settings"
>
<h3
className="tab-header"
<SettingDesktopHeader
id="displaySettingsTitle"
>
<MemoizedFormattedMessage
defaultMessage="Display Settings"
id="user.settings.display.title"
/>
</h3>
text={
<Memo(MemoizedFormattedMessage)
defaultMessage="Display Settings"
id="user.settings.display.title"
/>
}
/>
<div
className="divider-dark first"
/>
@ -381,53 +356,28 @@ exports[`components/user_settings/display/UserSettingsDisplay should match snaps
<div
id="displaySettings"
>
<div
className="modal-header"
>
<button
aria-label="Close"
className="close"
data-dismiss="modal"
id="closeButton"
onClick={[MockFunction]}
type="button"
>
<span
aria-hidden="true"
>
×
</span>
</button>
<h4
className="modal-title"
>
<div
className="modal-back"
>
<span
onClick={[MockFunction]}
>
<BackIcon />
</span>
</div>
<MemoizedFormattedMessage
<SettingMobileHeader
closeModal={[MockFunction]}
collapseModal={[MockFunction]}
text={
<Memo(MemoizedFormattedMessage)
defaultMessage="Display Settings"
id="user.settings.display.title"
/>
</h4>
</div>
}
/>
<div
className="user-settings"
>
<h3
className="tab-header"
<SettingDesktopHeader
id="displaySettingsTitle"
>
<MemoizedFormattedMessage
defaultMessage="Display Settings"
id="user.settings.display.title"
/>
</h3>
text={
<Memo(MemoizedFormattedMessage)
defaultMessage="Display Settings"
id="user.settings.display.title"
/>
}
/>
<div
className="divider-dark first"
/>
@ -758,53 +708,28 @@ exports[`components/user_settings/display/UserSettingsDisplay should match snaps
<div
id="displaySettings"
>
<div
className="modal-header"
>
<button
aria-label="Close"
className="close"
data-dismiss="modal"
id="closeButton"
onClick={[MockFunction]}
type="button"
>
<span
aria-hidden="true"
>
×
</span>
</button>
<h4
className="modal-title"
>
<div
className="modal-back"
>
<span
onClick={[MockFunction]}
>
<BackIcon />
</span>
</div>
<MemoizedFormattedMessage
<SettingMobileHeader
closeModal={[MockFunction]}
collapseModal={[MockFunction]}
text={
<Memo(MemoizedFormattedMessage)
defaultMessage="Display Settings"
id="user.settings.display.title"
/>
</h4>
</div>
}
/>
<div
className="user-settings"
>
<h3
className="tab-header"
<SettingDesktopHeader
id="displaySettingsTitle"
>
<MemoizedFormattedMessage
defaultMessage="Display Settings"
id="user.settings.display.title"
/>
</h3>
text={
<Memo(MemoizedFormattedMessage)
defaultMessage="Display Settings"
id="user.settings.display.title"
/>
}
/>
<div
className="divider-dark first"
/>
@ -1135,53 +1060,28 @@ exports[`components/user_settings/display/UserSettingsDisplay should match snaps
<div
id="displaySettings"
>
<div
className="modal-header"
>
<button
aria-label="Close"
className="close"
data-dismiss="modal"
id="closeButton"
onClick={[MockFunction]}
type="button"
>
<span
aria-hidden="true"
>
×
</span>
</button>
<h4
className="modal-title"
>
<div
className="modal-back"
>
<span
onClick={[MockFunction]}
>
<BackIcon />
</span>
</div>
<MemoizedFormattedMessage
<SettingMobileHeader
closeModal={[MockFunction]}
collapseModal={[MockFunction]}
text={
<Memo(MemoizedFormattedMessage)
defaultMessage="Display Settings"
id="user.settings.display.title"
/>
</h4>
</div>
}
/>
<div
className="user-settings"
>
<h3
className="tab-header"
<SettingDesktopHeader
id="displaySettingsTitle"
>
<MemoizedFormattedMessage
defaultMessage="Display Settings"
id="user.settings.display.title"
/>
</h3>
text={
<Memo(MemoizedFormattedMessage)
defaultMessage="Display Settings"
id="user.settings.display.title"
/>
}
/>
<div
className="divider-dark first"
/>
@ -1512,53 +1412,28 @@ exports[`components/user_settings/display/UserSettingsDisplay should match snaps
<div
id="displaySettings"
>
<div
className="modal-header"
>
<button
aria-label="Close"
className="close"
data-dismiss="modal"
id="closeButton"
onClick={[MockFunction]}
type="button"
>
<span
aria-hidden="true"
>
×
</span>
</button>
<h4
className="modal-title"
>
<div
className="modal-back"
>
<span
onClick={[MockFunction]}
>
<BackIcon />
</span>
</div>
<MemoizedFormattedMessage
<SettingMobileHeader
closeModal={[MockFunction]}
collapseModal={[MockFunction]}
text={
<Memo(MemoizedFormattedMessage)
defaultMessage="Display Settings"
id="user.settings.display.title"
/>
</h4>
</div>
}
/>
<div
className="user-settings"
>
<h3
className="tab-header"
<SettingDesktopHeader
id="displaySettingsTitle"
>
<MemoizedFormattedMessage
defaultMessage="Display Settings"
id="user.settings.display.title"
/>
</h3>
text={
<Memo(MemoizedFormattedMessage)
defaultMessage="Display Settings"
id="user.settings.display.title"
/>
}
/>
<div
className="divider-dark first"
/>
@ -1816,53 +1691,28 @@ exports[`components/user_settings/display/UserSettingsDisplay should match snaps
<div
id="displaySettings"
>
<div
className="modal-header"
>
<button
aria-label="Close"
className="close"
data-dismiss="modal"
id="closeButton"
onClick={[MockFunction]}
type="button"
>
<span
aria-hidden="true"
>
×
</span>
</button>
<h4
className="modal-title"
>
<div
className="modal-back"
>
<span
onClick={[MockFunction]}
>
<BackIcon />
</span>
</div>
<MemoizedFormattedMessage
<SettingMobileHeader
closeModal={[MockFunction]}
collapseModal={[MockFunction]}
text={
<Memo(MemoizedFormattedMessage)
defaultMessage="Display Settings"
id="user.settings.display.title"
/>
</h4>
</div>
}
/>
<div
className="user-settings"
>
<h3
className="tab-header"
<SettingDesktopHeader
id="displaySettingsTitle"
>
<MemoizedFormattedMessage
defaultMessage="Display Settings"
id="user.settings.display.title"
/>
</h3>
text={
<Memo(MemoizedFormattedMessage)
defaultMessage="Display Settings"
id="user.settings.display.title"
/>
}
/>
<div
className="divider-dark first"
/>
@ -2102,53 +1952,28 @@ exports[`components/user_settings/display/UserSettingsDisplay should match snaps
<div
id="displaySettings"
>
<div
className="modal-header"
>
<button
aria-label="Close"
className="close"
data-dismiss="modal"
id="closeButton"
onClick={[MockFunction]}
type="button"
>
<span
aria-hidden="true"
>
×
</span>
</button>
<h4
className="modal-title"
>
<div
className="modal-back"
>
<span
onClick={[MockFunction]}
>
<BackIcon />
</span>
</div>
<MemoizedFormattedMessage
<SettingMobileHeader
closeModal={[MockFunction]}
collapseModal={[MockFunction]}
text={
<Memo(MemoizedFormattedMessage)
defaultMessage="Display Settings"
id="user.settings.display.title"
/>
</h4>
</div>
}
/>
<div
className="user-settings"
>
<h3
className="tab-header"
<SettingDesktopHeader
id="displaySettingsTitle"
>
<MemoizedFormattedMessage
defaultMessage="Display Settings"
id="user.settings.display.title"
/>
</h3>
text={
<Memo(MemoizedFormattedMessage)
defaultMessage="Display Settings"
id="user.settings.display.title"
/>
}
/>
<div
className="divider-dark first"
/>
@ -2479,53 +2304,28 @@ exports[`components/user_settings/display/UserSettingsDisplay should match snaps
<div
id="displaySettings"
>
<div
className="modal-header"
>
<button
aria-label="Close"
className="close"
data-dismiss="modal"
id="closeButton"
onClick={[MockFunction]}
type="button"
>
<span
aria-hidden="true"
>
×
</span>
</button>
<h4
className="modal-title"
>
<div
className="modal-back"
>
<span
onClick={[MockFunction]}
>
<BackIcon />
</span>
</div>
<MemoizedFormattedMessage
<SettingMobileHeader
closeModal={[MockFunction]}
collapseModal={[MockFunction]}
text={
<Memo(MemoizedFormattedMessage)
defaultMessage="Display Settings"
id="user.settings.display.title"
/>
</h4>
</div>
}
/>
<div
className="user-settings"
>
<h3
className="tab-header"
<SettingDesktopHeader
id="displaySettingsTitle"
>
<MemoizedFormattedMessage
defaultMessage="Display Settings"
id="user.settings.display.title"
/>
</h3>
text={
<Memo(MemoizedFormattedMessage)
defaultMessage="Display Settings"
id="user.settings.display.title"
/>
}
/>
<div
className="divider-dark first"
/>
@ -2874,53 +2674,28 @@ exports[`components/user_settings/display/UserSettingsDisplay should match snaps
<div
id="displaySettings"
>
<div
className="modal-header"
>
<button
aria-label="Close"
className="close"
data-dismiss="modal"
id="closeButton"
onClick={[MockFunction]}
type="button"
>
<span
aria-hidden="true"
>
×
</span>
</button>
<h4
className="modal-title"
>
<div
className="modal-back"
>
<span
onClick={[MockFunction]}
>
<BackIcon />
</span>
</div>
<MemoizedFormattedMessage
<SettingMobileHeader
closeModal={[MockFunction]}
collapseModal={[MockFunction]}
text={
<Memo(MemoizedFormattedMessage)
defaultMessage="Display Settings"
id="user.settings.display.title"
/>
</h4>
</div>
}
/>
<div
className="user-settings"
>
<h3
className="tab-header"
<SettingDesktopHeader
id="displaySettingsTitle"
>
<MemoizedFormattedMessage
defaultMessage="Display Settings"
id="user.settings.display.title"
/>
</h3>
text={
<Memo(MemoizedFormattedMessage)
defaultMessage="Display Settings"
id="user.settings.display.title"
/>
}
/>
<div
className="divider-dark first"
/>
@ -3178,53 +2953,28 @@ exports[`components/user_settings/display/UserSettingsDisplay should match snaps
<div
id="displaySettings"
>
<div
className="modal-header"
>
<button
aria-label="Close"
className="close"
data-dismiss="modal"
id="closeButton"
onClick={[MockFunction]}
type="button"
>
<span
aria-hidden="true"
>
×
</span>
</button>
<h4
className="modal-title"
>
<div
className="modal-back"
>
<span
onClick={[MockFunction]}
>
<BackIcon />
</span>
</div>
<MemoizedFormattedMessage
<SettingMobileHeader
closeModal={[MockFunction]}
collapseModal={[MockFunction]}
text={
<Memo(MemoizedFormattedMessage)
defaultMessage="Display Settings"
id="user.settings.display.title"
/>
</h4>
</div>
}
/>
<div
className="user-settings"
>
<h3
className="tab-header"
<SettingDesktopHeader
id="displaySettingsTitle"
>
<MemoizedFormattedMessage
defaultMessage="Display Settings"
id="user.settings.display.title"
/>
</h3>
text={
<Memo(MemoizedFormattedMessage)
defaultMessage="Display Settings"
id="user.settings.display.title"
/>
}
/>
<div
className="divider-dark first"
/>
@ -3482,53 +3232,28 @@ exports[`components/user_settings/display/UserSettingsDisplay should match snaps
<div
id="displaySettings"
>
<div
className="modal-header"
>
<button
aria-label="Close"
className="close"
data-dismiss="modal"
id="closeButton"
onClick={[MockFunction]}
type="button"
>
<span
aria-hidden="true"
>
×
</span>
</button>
<h4
className="modal-title"
>
<div
className="modal-back"
>
<span
onClick={[MockFunction]}
>
<BackIcon />
</span>
</div>
<MemoizedFormattedMessage
<SettingMobileHeader
closeModal={[MockFunction]}
collapseModal={[MockFunction]}
text={
<Memo(MemoizedFormattedMessage)
defaultMessage="Display Settings"
id="user.settings.display.title"
/>
</h4>
</div>
}
/>
<div
className="user-settings"
>
<h3
className="tab-header"
<SettingDesktopHeader
id="displaySettingsTitle"
>
<MemoizedFormattedMessage
defaultMessage="Display Settings"
id="user.settings.display.title"
/>
</h3>
text={
<Memo(MemoizedFormattedMessage)
defaultMessage="Display Settings"
id="user.settings.display.title"
/>
}
/>
<div
className="divider-dark first"
/>
@ -3786,53 +3511,28 @@ exports[`components/user_settings/display/UserSettingsDisplay should match snaps
<div
id="displaySettings"
>
<div
className="modal-header"
>
<button
aria-label="Close"
className="close"
data-dismiss="modal"
id="closeButton"
onClick={[MockFunction]}
type="button"
>
<span
aria-hidden="true"
>
×
</span>
</button>
<h4
className="modal-title"
>
<div
className="modal-back"
>
<span
onClick={[MockFunction]}
>
<BackIcon />
</span>
</div>
<MemoizedFormattedMessage
<SettingMobileHeader
closeModal={[MockFunction]}
collapseModal={[MockFunction]}
text={
<Memo(MemoizedFormattedMessage)
defaultMessage="Display Settings"
id="user.settings.display.title"
/>
</h4>
</div>
}
/>
<div
className="user-settings"
>
<h3
className="tab-header"
<SettingDesktopHeader
id="displaySettingsTitle"
>
<MemoizedFormattedMessage
defaultMessage="Display Settings"
id="user.settings.display.title"
/>
</h3>
text={
<Memo(MemoizedFormattedMessage)
defaultMessage="Display Settings"
id="user.settings.display.title"
/>
}
/>
<div
className="divider-dark first"
/>
@ -4103,53 +3803,28 @@ exports[`components/user_settings/display/UserSettingsDisplay should match snaps
<div
id="displaySettings"
>
<div
className="modal-header"
>
<button
aria-label="Close"
className="close"
data-dismiss="modal"
id="closeButton"
onClick={[MockFunction]}
type="button"
>
<span
aria-hidden="true"
>
×
</span>
</button>
<h4
className="modal-title"
>
<div
className="modal-back"
>
<span
onClick={[MockFunction]}
>
<BackIcon />
</span>
</div>
<MemoizedFormattedMessage
<SettingMobileHeader
closeModal={[MockFunction]}
collapseModal={[MockFunction]}
text={
<Memo(MemoizedFormattedMessage)
defaultMessage="Display Settings"
id="user.settings.display.title"
/>
</h4>
</div>
}
/>
<div
className="user-settings"
>
<h3
className="tab-header"
<SettingDesktopHeader
id="displaySettingsTitle"
>
<MemoizedFormattedMessage
defaultMessage="Display Settings"
id="user.settings.display.title"
/>
</h3>
text={
<Memo(MemoizedFormattedMessage)
defaultMessage="Display Settings"
id="user.settings.display.title"
/>
}
/>
<div
className="divider-dark first"
/>
@ -4407,53 +4082,28 @@ exports[`components/user_settings/display/UserSettingsDisplay should not show la
<div
id="displaySettings"
>
<div
className="modal-header"
>
<button
aria-label="Close"
className="close"
data-dismiss="modal"
id="closeButton"
onClick={[MockFunction]}
type="button"
>
<span
aria-hidden="true"
>
×
</span>
</button>
<h4
className="modal-title"
>
<div
className="modal-back"
>
<span
onClick={[MockFunction]}
>
<BackIcon />
</span>
</div>
<MemoizedFormattedMessage
<SettingMobileHeader
closeModal={[MockFunction]}
collapseModal={[MockFunction]}
text={
<Memo(MemoizedFormattedMessage)
defaultMessage="Display Settings"
id="user.settings.display.title"
/>
</h4>
</div>
}
/>
<div
className="user-settings"
>
<h3
className="tab-header"
<SettingDesktopHeader
id="displaySettingsTitle"
>
<MemoizedFormattedMessage
defaultMessage="Display Settings"
id="user.settings.display.title"
/>
</h3>
text={
<Memo(MemoizedFormattedMessage)
defaultMessage="Display Settings"
id="user.settings.display.title"
/>
}
/>
<div
className="divider-dark first"
/>

View File

@ -19,7 +19,6 @@ import {trackEvent} from 'actions/telemetry_actions';
import SettingItem from 'components/setting_item';
import SettingItemMax from 'components/setting_item_max';
import ThemeSetting from 'components/user_settings/display/user_settings_theme';
import BackIcon from 'components/widgets/icons/fa_back_icon';
import * as I18n from 'i18n/i18n.jsx';
import Constants from 'utils/constants';
@ -30,6 +29,9 @@ import {a11yFocus} from 'utils/utils';
import ManageLanguages from './manage_languages';
import ManageTimezones from './manage_timezones';
import SettingDesktopHeader from '../headers/setting_desktop_header';
import SettingMobileHeader from '../headers/setting_mobile_header';
const Preferences = Constants.Preferences;
function getDisplayStateFromProps(props: Props) {
@ -94,8 +96,8 @@ type Props = {
user: UserProfile;
updateSection: (section: string) => void;
activeSection?: string;
closeModal?: () => void;
collapseModal?: () => void;
closeModal: () => void;
collapseModal: () => void;
setRequireConfirm?: () => void;
setEnforceFocus?: () => void;
timezones: Timezone[];
@ -1100,39 +1102,26 @@ export default class UserSettingsDisplay extends React.PureComponent<Props, Stat
return (
<div id='displaySettings'>
<div className='modal-header'>
<button
id='closeButton'
type='button'
className='close'
data-dismiss='modal'
aria-label='Close'
onClick={this.props.closeModal}
>
<span aria-hidden='true'>{'×'}</span>
</button>
<h4 className='modal-title'>
<div className='modal-back'>
<span onClick={this.props.collapseModal}>
<BackIcon/>
</span>
</div>
<SettingMobileHeader
closeModal={this.props.closeModal}
collapseModal={this.props.collapseModal}
text={
<FormattedMessage
id='user.settings.display.title'
defaultMessage='Display Settings'
/>
</h4>
</div>
}
/>
<div className='user-settings'>
<h3
<SettingDesktopHeader
id='displaySettingsTitle'
className='tab-header'
>
<FormattedMessage
id='user.settings.display.title'
defaultMessage='Display Settings'
/>
</h3>
text={
<FormattedMessage
id='user.settings.display.title'
defaultMessage='Display Settings'
/>
}
/>
<div className='divider-dark first'/>
{themeSection}
{collapsedReplyThreads}

View File

@ -7,7 +7,7 @@ import {setThemeDefaults} from 'mattermost-redux/utils/theme_utils';
import {mountWithIntl, shallowWithIntl} from 'tests/helpers/intl-test-helper';
import ImportThemeModal from './import_theme_modal';
import ImportThemeModal from './index';
describe('components/user_settings/ImportThemeModal', () => {
const props = {

View File

@ -11,7 +11,7 @@ import ExternalLink from 'components/external_link';
import SettingItemMax from 'components/setting_item_max';
import SettingItemMin from 'components/setting_item_min';
import type SettingItemMinComponent from 'components/setting_item_min';
import ImportThemeModal from 'components/user_settings/import_theme_modal';
import ImportThemeModal from 'components/user_settings/display/user_settings_theme/import_theme_modal';
import {Constants, ModalIdentifiers} from 'utils/constants';
import {applyTheme} from 'utils/utils';

View File

@ -3,7 +3,7 @@
/* eslint-disable max-lines */
import React from 'react';
import React, {PureComponent} from 'react';
import {defineMessages, FormattedDate, FormattedMessage, injectIntl} from 'react-intl';
import type {IntlShape} from 'react-intl';
@ -22,6 +22,9 @@ import LoadingWrapper from 'components/widgets/loading/loading_wrapper';
import {AnnouncementBarMessages, AnnouncementBarTypes, AcceptedProfileImageTypes, Constants, ValidationErrors} from 'utils/constants';
import * as Utils from 'utils/utils';
import SettingDesktopHeader from '../headers/setting_desktop_header';
import SettingMobileHeader from '../headers/setting_mobile_header';
const holders = defineMessages({
usernameReserved: {
id: 'user.settings.general.usernameReserved',
@ -143,7 +146,7 @@ type State = {
emailError?: string;
}
export class UserSettingsGeneralTab extends React.Component<Props, State> {
export class UserSettingsGeneralTab extends PureComponent<Props, State> {
public submitActive = false;
constructor(props: Props) {
@ -1352,8 +1355,6 @@ export class UserSettingsGeneralTab extends React.Component<Props, State> {
};
render() {
const {formatMessage} = this.props.intl;
const nameSection = this.createNameSection();
const nicknameSection = this.createNicknameSection();
const usernameSection = this.createUsernameSection();
@ -1363,41 +1364,26 @@ export class UserSettingsGeneralTab extends React.Component<Props, State> {
return (
<div id='generalSettings'>
<div className='modal-header'>
<button
id='closeUserSettings'
type='button'
className='close'
data-dismiss='modal'
aria-label={formatMessage(holders.close)}
onClick={this.props.closeModal}
>
<span aria-hidden='true'>{'×'}</span>
</button>
<h4 className='modal-title'>
<div className='modal-back'>
<i
className='fa fa-angle-left'
title={this.props.intl.formatMessage({id: 'generic_icons.collapse', defaultMessage: 'Collapse Icon'})}
onClick={this.props.collapseModal}
/>
</div>
<SettingMobileHeader
closeModal={this.props.closeModal}
collapseModal={this.props.collapseModal}
text={
<FormattedMessage
id='user.settings.modal.profile'
defaultMessage='Profile'
/>
</h4>
</div>
}
/>
<div className='user-settings'>
<h3
<SettingDesktopHeader
id='generalSettingsTitle'
className='tab-header'
>
<FormattedMessage
id='user.settings.modal.profile'
defaultMessage='Profile'
/>
</h3>
text={
<FormattedMessage
id='user.settings.modal.profile'
defaultMessage='Profile'
/>
}
/>
<div className='divider-dark first'/>
{nameSection}
<div className='divider-light'/>

View File

@ -0,0 +1,20 @@
.userSettingDesktopHeader {
display: flex;
align-items: center;
justify-content: space-between;
.userSettingDesktopHeaderInfo {
a {
font-size: 12px;
}
svg.circular-border {
width: 18px;
height: 18px;
padding: 2px;
background: rgba(var(--button-bg-rgb), 0.12);
border-radius: 50%;
text-align: center;
}
}
}

View File

@ -11,14 +11,14 @@ import SettingDesktopHeader from './setting_desktop_header';
type Props = ComponentProps<typeof SettingDesktopHeader>;
const baseProps: Props = {
text: 'setting header',
};
describe('settings_desktop_header', () => {
const baseProps: Props = {
text: 'setting section header',
};
describe('plugin tab', () => {
it('properly renders the header', () => {
renderWithContext(<SettingDesktopHeader {...baseProps}/>);
const header = screen.queryByText('setting header');
const header = screen.queryByText('setting section header');
expect(header).toBeInTheDocument();
// The className is important for how the modal system work

View File

@ -0,0 +1,27 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import type {ReactNode} from 'react';
import React from 'react';
import './setting_desktop_header.scss';
interface Props {
id?: string;
text: ReactNode;
info?: ReactNode;
}
export default function SettingDesktopHeader(props: Props) {
return (
<div className='userSettingDesktopHeader'>
<h3
id={props.id}
className='tab-header'
>
{props.text}
</h3>
{props.info && <div className='userSettingDesktopHeaderInfo'>{props.info}</div>}
</div>
);
}

View File

@ -1,11 +1,12 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import type {ReactNode} from 'react';
import React from 'react';
import {useIntl} from 'react-intl';
type Props = {
text: string;
text: ReactNode;
closeModal: () => void;
collapseModal: () => void;
}

View File

@ -11,7 +11,7 @@ import AdvancedTab from './advanced';
import DisplayTab from './display';
import GeneralTab from './general';
import NotificationsTab from './notifications';
import PluginTab from './plugin/plugin';
import PluginTab from './plugin';
import SecurityTab from './security';
import SidebarTab from './sidebar';
@ -28,96 +28,94 @@ export type Props = {
pluginSettings: {[tabName: string]: PluginConfiguration};
};
export default class UserSettings extends React.PureComponent<Props> {
render() {
if (this.props.activeTab === 'profile') {
return (
<div>
<GeneralTab
user={this.props.user}
activeSection={this.props.activeSection}
updateSection={this.props.updateSection}
updateTab={this.props.updateTab}
closeModal={this.props.closeModal}
collapseModal={this.props.collapseModal}
/>
</div>
);
} else if (this.props.activeTab === 'security') {
return (
<div>
<SecurityTab
user={this.props.user}
activeSection={this.props.activeSection}
updateSection={this.props.updateSection}
closeModal={this.props.closeModal}
collapseModal={this.props.collapseModal}
setRequireConfirm={this.props.setRequireConfirm}
/>
</div>
);
} else if (this.props.activeTab === 'notifications') {
return (
<div>
<NotificationsTab
user={this.props.user}
activeSection={this.props.activeSection}
updateSection={this.props.updateSection}
closeModal={this.props.closeModal}
collapseModal={this.props.collapseModal}
/>
</div>
);
} else if (this.props.activeTab === 'display') {
return (
<div>
<DisplayTab
user={this.props.user}
activeSection={this.props.activeSection}
updateSection={this.props.updateSection}
closeModal={this.props.closeModal}
collapseModal={this.props.collapseModal}
setEnforceFocus={this.props.setEnforceFocus}
setRequireConfirm={this.props.setRequireConfirm}
/>
</div>
);
} else if (this.props.activeTab === 'sidebar') {
return (
<div>
<SidebarTab
activeSection={this.props.activeSection}
updateSection={this.props.updateSection}
closeModal={this.props.closeModal}
collapseModal={this.props.collapseModal}
/>
</div>
);
} else if (this.props.activeTab === 'advanced') {
return (
<div>
<AdvancedTab
activeSection={this.props.activeSection}
updateSection={this.props.updateSection}
closeModal={this.props.closeModal}
collapseModal={this.props.collapseModal}
/>
</div>
);
} else if (this.props.activeTab && this.props.pluginSettings[this.props.activeTab]) {
return (
<div>
<PluginTab
activeSection={this.props.activeSection}
updateSection={this.props.updateSection}
closeModal={this.props.closeModal}
collapseModal={this.props.collapseModal}
settings={this.props.pluginSettings[this.props.activeTab]}
/>
</div>
);
}
return <div/>;
export default function UserSettings(props: Props) {
if (props.activeTab === 'profile') {
return (
<div>
<GeneralTab
user={props.user}
activeSection={props.activeSection}
updateSection={props.updateSection}
updateTab={props.updateTab}
closeModal={props.closeModal}
collapseModal={props.collapseModal}
/>
</div>
);
} else if (props.activeTab === 'security') {
return (
<div>
<SecurityTab
user={props.user}
activeSection={props.activeSection}
updateSection={props.updateSection}
closeModal={props.closeModal}
collapseModal={props.collapseModal}
setRequireConfirm={props.setRequireConfirm}
/>
</div>
);
} else if (props.activeTab === 'notifications') {
return (
<div>
<NotificationsTab
user={props.user}
activeSection={props.activeSection}
updateSection={props.updateSection}
closeModal={props.closeModal}
collapseModal={props.collapseModal}
/>
</div>
);
} else if (props.activeTab === 'display') {
return (
<div>
<DisplayTab
user={props.user}
activeSection={props.activeSection}
updateSection={props.updateSection}
closeModal={props.closeModal}
collapseModal={props.collapseModal}
setEnforceFocus={props.setEnforceFocus}
setRequireConfirm={props.setRequireConfirm}
/>
</div>
);
} else if (props.activeTab === 'sidebar') {
return (
<div>
<SidebarTab
activeSection={props.activeSection}
updateSection={props.updateSection}
closeModal={props.closeModal}
collapseModal={props.collapseModal}
/>
</div>
);
} else if (props.activeTab === 'advanced') {
return (
<div>
<AdvancedTab
activeSection={props.activeSection}
updateSection={props.updateSection}
closeModal={props.closeModal}
collapseModal={props.collapseModal}
/>
</div>
);
} else if (props.activeTab && props.pluginSettings[props.activeTab]) {
return (
<div>
<PluginTab
activeSection={props.activeSection}
updateSection={props.updateSection}
closeModal={props.closeModal}
collapseModal={props.collapseModal}
settings={props.pluginSettings[props.activeTab]}
/>
</div>
);
}
return null;
}

View File

@ -41,7 +41,7 @@ Object {
class="user-settings"
>
<div
class="notificationSettingsModalHeader"
class="userSettingDesktopHeader"
>
<h3
class="tab-header"
@ -49,27 +49,33 @@ Object {
>
Notifications
</h3>
<a
href="https://mattermost.com/pl/about-notifications?utm_source=mattermost&utm_medium=in-product&utm_content=&uid=&sid="
rel="noopener noreferrer"
target="_blank"
<div
class="userSettingDesktopHeaderInfo"
>
<svg
fill="currentColor"
height="1em"
version="1.1"
viewBox="0 0 24 24"
width="1em"
xmlns="http://www.w3.org/2000/svg"
<a
class="btn btn-link"
href="https://mattermost.com/pl/about-notifications?utm_source=mattermost&utm_medium=in-product&utm_content=&uid=&sid="
rel="noopener noreferrer"
target="_blank"
>
<path
d="M12,2A7,7 0 0,1 19,9C19,11.38 17.81,13.47 16,14.74V17A1,1 0 0,1 15,18H9A1,1 0 0,1 8,17V14.74C6.19,13.47 5,11.38 5,9A7,7 0 0,1 12,2M9,21V20H15V21A1,1 0 0,1 14,22H10A1,1 0 0,1 9,21M12,4A5,5 0 0,0 7,9C7,11.05 8.23,12.81 10,13.58V16H14V13.58C15.77,12.81 17,11.05 17,9A5,5 0 0,0 12,4Z"
/>
</svg>
<span>
Learn more about notifications
</span>
</a>
<svg
class="circular-border"
fill="currentColor"
height="1em"
version="1.1"
viewBox="0 0 24 24"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M12,2A7,7 0 0,1 19,9C19,11.38 17.81,13.47 16,14.74V17A1,1 0 0,1 15,18H9A1,1 0 0,1 8,17V14.74C6.19,13.47 5,11.38 5,9A7,7 0 0,1 12,2M9,21V20H15V21A1,1 0 0,1 14,22H10A1,1 0 0,1 9,21M12,4A5,5 0 0,0 7,9C7,11.05 8.23,12.81 10,13.58V16H14V13.58C15.77,12.81 17,11.05 17,9A5,5 0 0,0 12,4Z"
/>
</svg>
<span>
Learn more about notifications
</span>
</a>
</div>
</div>
<div
class="divider-dark first"
@ -293,7 +299,7 @@ Object {
class="user-settings"
>
<div
class="notificationSettingsModalHeader"
class="userSettingDesktopHeader"
>
<h3
class="tab-header"
@ -301,27 +307,33 @@ Object {
>
Notifications
</h3>
<a
href="https://mattermost.com/pl/about-notifications?utm_source=mattermost&utm_medium=in-product&utm_content=&uid=&sid="
rel="noopener noreferrer"
target="_blank"
<div
class="userSettingDesktopHeaderInfo"
>
<svg
fill="currentColor"
height="1em"
version="1.1"
viewBox="0 0 24 24"
width="1em"
xmlns="http://www.w3.org/2000/svg"
<a
class="btn btn-link"
href="https://mattermost.com/pl/about-notifications?utm_source=mattermost&utm_medium=in-product&utm_content=&uid=&sid="
rel="noopener noreferrer"
target="_blank"
>
<path
d="M12,2A7,7 0 0,1 19,9C19,11.38 17.81,13.47 16,14.74V17A1,1 0 0,1 15,18H9A1,1 0 0,1 8,17V14.74C6.19,13.47 5,11.38 5,9A7,7 0 0,1 12,2M9,21V20H15V21A1,1 0 0,1 14,22H10A1,1 0 0,1 9,21M12,4A5,5 0 0,0 7,9C7,11.05 8.23,12.81 10,13.58V16H14V13.58C15.77,12.81 17,11.05 17,9A5,5 0 0,0 12,4Z"
/>
</svg>
<span>
Learn more about notifications
</span>
</a>
<svg
class="circular-border"
fill="currentColor"
height="1em"
version="1.1"
viewBox="0 0 24 24"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M12,2A7,7 0 0,1 19,9C19,11.38 17.81,13.47 16,14.74V17A1,1 0 0,1 15,18H9A1,1 0 0,1 8,17V14.74C6.19,13.47 5,11.38 5,9A7,7 0 0,1 12,2M9,21V20H15V21A1,1 0 0,1 14,22H10A1,1 0 0,1 9,21M12,4A5,5 0 0,0 7,9C7,11.05 8.23,12.81 10,13.58V16H14V13.58C15.77,12.81 17,11.05 17,9A5,5 0 0,0 12,4Z"
/>
</svg>
<span>
Learn more about notifications
</span>
</a>
</div>
</div>
<div
class="divider-dark first"
@ -604,7 +616,7 @@ Object {
class="user-settings"
>
<div
class="notificationSettingsModalHeader"
class="userSettingDesktopHeader"
>
<h3
class="tab-header"
@ -612,27 +624,33 @@ Object {
>
Notifications
</h3>
<a
href="https://mattermost.com/pl/about-notifications?utm_source=mattermost&utm_medium=in-product&utm_content=&uid=&sid="
rel="noopener noreferrer"
target="_blank"
<div
class="userSettingDesktopHeaderInfo"
>
<svg
fill="currentColor"
height="1em"
version="1.1"
viewBox="0 0 24 24"
width="1em"
xmlns="http://www.w3.org/2000/svg"
<a
class="btn btn-link"
href="https://mattermost.com/pl/about-notifications?utm_source=mattermost&utm_medium=in-product&utm_content=&uid=&sid="
rel="noopener noreferrer"
target="_blank"
>
<path
d="M12,2A7,7 0 0,1 19,9C19,11.38 17.81,13.47 16,14.74V17A1,1 0 0,1 15,18H9A1,1 0 0,1 8,17V14.74C6.19,13.47 5,11.38 5,9A7,7 0 0,1 12,2M9,21V20H15V21A1,1 0 0,1 14,22H10A1,1 0 0,1 9,21M12,4A5,5 0 0,0 7,9C7,11.05 8.23,12.81 10,13.58V16H14V13.58C15.77,12.81 17,11.05 17,9A5,5 0 0,0 12,4Z"
/>
</svg>
<span>
Learn more about notifications
</span>
</a>
<svg
class="circular-border"
fill="currentColor"
height="1em"
version="1.1"
viewBox="0 0 24 24"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M12,2A7,7 0 0,1 19,9C19,11.38 17.81,13.47 16,14.74V17A1,1 0 0,1 15,18H9A1,1 0 0,1 8,17V14.74C6.19,13.47 5,11.38 5,9A7,7 0 0,1 12,2M9,21V20H15V21A1,1 0 0,1 14,22H10A1,1 0 0,1 9,21M12,4A5,5 0 0,0 7,9C7,11.05 8.23,12.81 10,13.58V16H14V13.58C15.77,12.81 17,11.05 17,9A5,5 0 0,0 12,4Z"
/>
</svg>
<span>
Learn more about notifications
</span>
</a>
</div>
</div>
<div
class="divider-dark first"
@ -859,7 +877,7 @@ Object {
class="user-settings"
>
<div
class="notificationSettingsModalHeader"
class="userSettingDesktopHeader"
>
<h3
class="tab-header"
@ -867,27 +885,33 @@ Object {
>
Notifications
</h3>
<a
href="https://mattermost.com/pl/about-notifications?utm_source=mattermost&utm_medium=in-product&utm_content=&uid=&sid="
rel="noopener noreferrer"
target="_blank"
<div
class="userSettingDesktopHeaderInfo"
>
<svg
fill="currentColor"
height="1em"
version="1.1"
viewBox="0 0 24 24"
width="1em"
xmlns="http://www.w3.org/2000/svg"
<a
class="btn btn-link"
href="https://mattermost.com/pl/about-notifications?utm_source=mattermost&utm_medium=in-product&utm_content=&uid=&sid="
rel="noopener noreferrer"
target="_blank"
>
<path
d="M12,2A7,7 0 0,1 19,9C19,11.38 17.81,13.47 16,14.74V17A1,1 0 0,1 15,18H9A1,1 0 0,1 8,17V14.74C6.19,13.47 5,11.38 5,9A7,7 0 0,1 12,2M9,21V20H15V21A1,1 0 0,1 14,22H10A1,1 0 0,1 9,21M12,4A5,5 0 0,0 7,9C7,11.05 8.23,12.81 10,13.58V16H14V13.58C15.77,12.81 17,11.05 17,9A5,5 0 0,0 12,4Z"
/>
</svg>
<span>
Learn more about notifications
</span>
</a>
<svg
class="circular-border"
fill="currentColor"
height="1em"
version="1.1"
viewBox="0 0 24 24"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M12,2A7,7 0 0,1 19,9C19,11.38 17.81,13.47 16,14.74V17A1,1 0 0,1 15,18H9A1,1 0 0,1 8,17V14.74C6.19,13.47 5,11.38 5,9A7,7 0 0,1 12,2M9,21V20H15V21A1,1 0 0,1 14,22H10A1,1 0 0,1 9,21M12,4A5,5 0 0,0 7,9C7,11.05 8.23,12.81 10,13.58V16H14V13.58C15.77,12.81 17,11.05 17,9A5,5 0 0,0 12,4Z"
/>
</svg>
<span>
Learn more about notifications
</span>
</a>
</div>
</div>
<div
class="divider-dark first"
@ -1173,7 +1197,7 @@ Object {
class="user-settings"
>
<div
class="notificationSettingsModalHeader"
class="userSettingDesktopHeader"
>
<h3
class="tab-header"
@ -1181,27 +1205,33 @@ Object {
>
Notifications
</h3>
<a
href="https://mattermost.com/pl/about-notifications?utm_source=mattermost&utm_medium=in-product&utm_content=&uid=&sid="
rel="noopener noreferrer"
target="_blank"
<div
class="userSettingDesktopHeaderInfo"
>
<svg
fill="currentColor"
height="1em"
version="1.1"
viewBox="0 0 24 24"
width="1em"
xmlns="http://www.w3.org/2000/svg"
<a
class="btn btn-link"
href="https://mattermost.com/pl/about-notifications?utm_source=mattermost&utm_medium=in-product&utm_content=&uid=&sid="
rel="noopener noreferrer"
target="_blank"
>
<path
d="M12,2A7,7 0 0,1 19,9C19,11.38 17.81,13.47 16,14.74V17A1,1 0 0,1 15,18H9A1,1 0 0,1 8,17V14.74C6.19,13.47 5,11.38 5,9A7,7 0 0,1 12,2M9,21V20H15V21A1,1 0 0,1 14,22H10A1,1 0 0,1 9,21M12,4A5,5 0 0,0 7,9C7,11.05 8.23,12.81 10,13.58V16H14V13.58C15.77,12.81 17,11.05 17,9A5,5 0 0,0 12,4Z"
/>
</svg>
<span>
Learn more about notifications
</span>
</a>
<svg
class="circular-border"
fill="currentColor"
height="1em"
version="1.1"
viewBox="0 0 24 24"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M12,2A7,7 0 0,1 19,9C19,11.38 17.81,13.47 16,14.74V17A1,1 0 0,1 15,18H9A1,1 0 0,1 8,17V14.74C6.19,13.47 5,11.38 5,9A7,7 0 0,1 12,2M9,21V20H15V21A1,1 0 0,1 14,22H10A1,1 0 0,1 9,21M12,4A5,5 0 0,0 7,9C7,11.05 8.23,12.81 10,13.58V16H14V13.58C15.77,12.81 17,11.05 17,9A5,5 0 0,0 12,4Z"
/>
</svg>
<span>
Learn more about notifications
</span>
</a>
</div>
</div>
<div
class="divider-dark first"
@ -1390,7 +1420,7 @@ Object {
class="user-settings"
>
<div
class="notificationSettingsModalHeader"
class="userSettingDesktopHeader"
>
<h3
class="tab-header"
@ -1398,27 +1428,33 @@ Object {
>
Notifications
</h3>
<a
href="https://mattermost.com/pl/about-notifications?utm_source=mattermost&utm_medium=in-product&utm_content=&uid=&sid="
rel="noopener noreferrer"
target="_blank"
<div
class="userSettingDesktopHeaderInfo"
>
<svg
fill="currentColor"
height="1em"
version="1.1"
viewBox="0 0 24 24"
width="1em"
xmlns="http://www.w3.org/2000/svg"
<a
class="btn btn-link"
href="https://mattermost.com/pl/about-notifications?utm_source=mattermost&utm_medium=in-product&utm_content=&uid=&sid="
rel="noopener noreferrer"
target="_blank"
>
<path
d="M12,2A7,7 0 0,1 19,9C19,11.38 17.81,13.47 16,14.74V17A1,1 0 0,1 15,18H9A1,1 0 0,1 8,17V14.74C6.19,13.47 5,11.38 5,9A7,7 0 0,1 12,2M9,21V20H15V21A1,1 0 0,1 14,22H10A1,1 0 0,1 9,21M12,4A5,5 0 0,0 7,9C7,11.05 8.23,12.81 10,13.58V16H14V13.58C15.77,12.81 17,11.05 17,9A5,5 0 0,0 12,4Z"
/>
</svg>
<span>
Learn more about notifications
</span>
</a>
<svg
class="circular-border"
fill="currentColor"
height="1em"
version="1.1"
viewBox="0 0 24 24"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M12,2A7,7 0 0,1 19,9C19,11.38 17.81,13.47 16,14.74V17A1,1 0 0,1 15,18H9A1,1 0 0,1 8,17V14.74C6.19,13.47 5,11.38 5,9A7,7 0 0,1 12,2M9,21V20H15V21A1,1 0 0,1 14,22H10A1,1 0 0,1 9,21M12,4A5,5 0 0,0 7,9C7,11.05 8.23,12.81 10,13.58V16H14V13.58C15.77,12.81 17,11.05 17,9A5,5 0 0,0 12,4Z"
/>
</svg>
<span>
Learn more about notifications
</span>
</a>
</div>
</div>
<div
class="divider-dark first"

View File

@ -1,50 +0,0 @@
.customKeywordsWithNotificationSubsection {
& .multiInput {
margin-block-start: 10px;
}
}
.notificationSettingsModalHeader {
display: flex;
> span {
align-self: center;
margin-left: auto;
a {
display: flex;
align-items: center;
&:hover,
&:active,
&:focus {
color: var(--button-bg);
text-decoration: none;
}
> i {
font-size: 14.4px;
}
> span {
font-size: 12px;
font-weight: 600;
line-height: 16px;
&:hover {
text-decoration: underline;
}
}
> svg {
width: 18px;
height: 18px;
padding: 2px;
margin-right: 4px;
background: rgba(var(--button-bg-rgb), 0.12);
border-radius: 50%;
text-align: center;
}
}
}
}

View File

@ -4,7 +4,7 @@
/* eslint-disable max-lines */
import React from 'react';
import type {ChangeEvent, RefObject} from 'react';
import type {ChangeEvent} from 'react';
import type {WrappedComponentProps} from 'react-intl';
import {FormattedMessage, injectIntl} from 'react-intl';
import type {Styles as ReactSelectStyles, ValueType} from 'react-select';
@ -29,8 +29,10 @@ import DesktopNotificationSettings from './desktop_notification_setting/desktop_
import EmailNotificationSetting from './email_notification_setting';
import ManageAutoResponder from './manage_auto_responder/manage_auto_responder';
import SettingDesktopHeader from '../headers/setting_desktop_header';
import SettingMobileHeader from '../headers/setting_mobile_header';
import type {PropsFromRedux} from './index';
import './user_settings_notifications.scss';
const WHITE_SPACE_REGEX = /\s+/g;
const COMMA_REGEX = /,/g;
@ -213,9 +215,6 @@ function getDefaultStateFromProps(props: Props): State {
}
class NotificationsTab extends React.PureComponent<Props, State> {
drawerRef: RefObject<HTMLHeadingElement>;
wrapperRef: RefObject<HTMLDivElement>;
static defaultProps = {
activeSection: '',
};
@ -224,8 +223,6 @@ class NotificationsTab extends React.PureComponent<Props, State> {
super(props);
this.state = getDefaultStateFromProps(props);
this.drawerRef = React.createRef();
this.wrapperRef = React.createRef();
}
handleSubmit = async () => {
@ -328,7 +325,9 @@ class NotificationsTab extends React.PureComponent<Props, State> {
a11yFocus(e?.currentTarget as HTMLElement);
};
handleEmailRadio = (enableEmail: UserNotifyProps['email']): void => this.setState({enableEmail});
handleEmailRadio = (enableEmail: UserNotifyProps['email']): void => {
this.setState({enableEmail});
};
handleChangeForUsernameKeyCheckbox = (event: ChangeEvent<HTMLInputElement>) => {
const {target: {checked}} = event;
@ -873,7 +872,6 @@ class NotificationsTab extends React.PureComponent<Props, State> {
isClearable={false}
isMulti={true}
styles={customKeywordsSelectorStyles}
className='multiInput'
placeholder=''
components={{
DropdownIndicator: () => null,
@ -966,7 +964,6 @@ class NotificationsTab extends React.PureComponent<Props, State> {
isClearable={false}
isMulti={true}
styles={customKeywordsSelectorStyles}
className='multiInput'
placeholder=''
components={{
DropdownIndicator: () => null,
@ -1265,63 +1262,45 @@ class NotificationsTab extends React.PureComponent<Props, State> {
return (
<div id='notificationSettings'>
<div className='modal-header'>
<button
id='closeButton'
type='button'
className='close'
data-dismiss='modal'
onClick={this.props.closeModal}
>
<span aria-hidden='true'>{'×'}</span>
</button>
<h4
className='modal-title'
ref={this.drawerRef}
>
<div className='modal-back'>
<i
className='fa fa-angle-left'
aria-label={this.props.intl.formatMessage({
id: 'generic_icons.collapse',
defaultMessage: 'Collapse Icon',
})}
onClick={this.props.collapseModal}
/>
</div>
<SettingMobileHeader
closeModal={this.props.closeModal}
collapseModal={this.props.collapseModal}
text={
<FormattedMessage
id='user.settings.notifications.title'
defaultMessage='Notification Settings'
/>
</h4>
</div>
}
/>
<div
ref={this.wrapperRef}
className='user-settings'
>
<div className='notificationSettingsModalHeader'>
<h3
id='notificationSettingsTitle'
className='tab-header'
>
<SettingDesktopHeader
id='notificationSettingsTitle'
text={
<FormattedMessage
id='user.settings.notifications.header'
defaultMessage='Notifications'
/>
</h3>
<FormattedMessage
id='user.settings.notifications.learnMore'
defaultMessage='<a>Learn more about notifications</a>'
values={{
a: (chunks: string) => ((
<ExternalLink href='https://mattermost.com/pl/about-notifications'>
<LightbulbOutlineIcon/>
<span>{chunks}</span>
</ExternalLink>
)),
}}
/>
</div>
}
info={
<FormattedMessage
id='user.settings.notifications.learnMore'
defaultMessage='<a>Learn more about notifications</a>'
values={{
a: (chunks: string) => ((
<ExternalLink
href='https://mattermost.com/pl/about-notifications'
className='btn btn-link'
>
<LightbulbOutlineIcon className='circular-border'/>
<span>{chunks}</span>
</ExternalLink>
)),
}}
/>
}
/>
<div className='divider-dark first'/>
<DesktopNotificationSettings
active={this.props.activeSection === 'desktop'}
@ -1396,6 +1375,10 @@ class NotificationsTab extends React.PureComponent<Props, State> {
}
const customKeywordsSelectorStyles: ReactSelectStyles = {
container: ((baseStyle) => ({
...baseStyle,
marginBlockStart: '10px',
})),
control: ((baseStyles) => ({
...baseStyles,
backgroundColor: 'var(--center-channel-bg)',

View File

@ -8,7 +8,7 @@ import React from 'react';
import {renderWithContext} from 'tests/react_testing_utils';
import PluginTab from './plugin';
import PluginTab from './index';
type Props = ComponentProps<typeof PluginTab>;

View File

@ -9,8 +9,8 @@ import type {PluginConfiguration} from 'types/plugins/user_settings';
import PluginAction from './plugin_action';
import PluginSetting from './plugin_setting';
import SettingDesktopHeader from '../setting_desktop_header';
import SettingMobileHeader from '../setting_mobile_header';
import SettingDesktopHeader from '../headers/setting_desktop_header';
import SettingMobileHeader from '../headers/setting_mobile_header';
type Props = {
updateSection: (section: string) => void;

View File

@ -2,51 +2,27 @@
exports[`components/user_settings/display/UserSettingsDisplay should match snapshot, enable gitlab 1`] = `
<div>
<div
className="modal-header"
>
<button
aria-label="Close"
className="close"
data-dismiss="modal"
onClick={[MockFunction]}
type="button"
>
<span
aria-hidden="true"
>
×
</span>
</button>
<h4
className="modal-title"
>
<div
className="modal-back"
>
<i
className="fa fa-angle-left"
onClick={[MockFunction]}
title="Collapse Icon"
/>
</div>
<MemoizedFormattedMessage
<SettingMobileHeader
closeModal={[MockFunction]}
collapseModal={[MockFunction]}
text={
<Memo(MemoizedFormattedMessage)
defaultMessage="Security Settings"
id="user.settings.security.title"
/>
</h4>
</div>
}
/>
<div
className="user-settings"
>
<h3
className="tab-header"
>
<MemoizedFormattedMessage
defaultMessage="Security Settings"
id="user.settings.security.title"
/>
</h3>
<SettingDesktopHeader
text={
<Memo(MemoizedFormattedMessage)
defaultMessage="Security Settings"
id="user.settings.security.title"
/>
}
/>
<div
className="divider-dark first"
/>
@ -163,51 +139,27 @@ exports[`components/user_settings/display/UserSettingsDisplay should match snaps
exports[`components/user_settings/display/UserSettingsDisplay should match snapshot, enable google 1`] = `
<div>
<div
className="modal-header"
>
<button
aria-label="Close"
className="close"
data-dismiss="modal"
onClick={[MockFunction]}
type="button"
>
<span
aria-hidden="true"
>
×
</span>
</button>
<h4
className="modal-title"
>
<div
className="modal-back"
>
<i
className="fa fa-angle-left"
onClick={[MockFunction]}
title="Collapse Icon"
/>
</div>
<MemoizedFormattedMessage
<SettingMobileHeader
closeModal={[MockFunction]}
collapseModal={[MockFunction]}
text={
<Memo(MemoizedFormattedMessage)
defaultMessage="Security Settings"
id="user.settings.security.title"
/>
</h4>
</div>
}
/>
<div
className="user-settings"
>
<h3
className="tab-header"
>
<MemoizedFormattedMessage
defaultMessage="Security Settings"
id="user.settings.security.title"
/>
</h3>
<SettingDesktopHeader
text={
<Memo(MemoizedFormattedMessage)
defaultMessage="Security Settings"
id="user.settings.security.title"
/>
}
/>
<div
className="divider-dark first"
/>
@ -324,51 +276,27 @@ exports[`components/user_settings/display/UserSettingsDisplay should match snaps
exports[`components/user_settings/display/UserSettingsDisplay should match snapshot, enable office365 1`] = `
<div>
<div
className="modal-header"
>
<button
aria-label="Close"
className="close"
data-dismiss="modal"
onClick={[MockFunction]}
type="button"
>
<span
aria-hidden="true"
>
×
</span>
</button>
<h4
className="modal-title"
>
<div
className="modal-back"
>
<i
className="fa fa-angle-left"
onClick={[MockFunction]}
title="Collapse Icon"
/>
</div>
<MemoizedFormattedMessage
<SettingMobileHeader
closeModal={[MockFunction]}
collapseModal={[MockFunction]}
text={
<Memo(MemoizedFormattedMessage)
defaultMessage="Security Settings"
id="user.settings.security.title"
/>
</h4>
</div>
}
/>
<div
className="user-settings"
>
<h3
className="tab-header"
>
<MemoizedFormattedMessage
defaultMessage="Security Settings"
id="user.settings.security.title"
/>
</h3>
<SettingDesktopHeader
text={
<Memo(MemoizedFormattedMessage)
defaultMessage="Security Settings"
id="user.settings.security.title"
/>
}
/>
<div
className="divider-dark first"
/>
@ -485,51 +413,27 @@ exports[`components/user_settings/display/UserSettingsDisplay should match snaps
exports[`components/user_settings/display/UserSettingsDisplay should match snapshot, enable openID 1`] = `
<div>
<div
className="modal-header"
>
<button
aria-label="Close"
className="close"
data-dismiss="modal"
onClick={[MockFunction]}
type="button"
>
<span
aria-hidden="true"
>
×
</span>
</button>
<h4
className="modal-title"
>
<div
className="modal-back"
>
<i
className="fa fa-angle-left"
onClick={[MockFunction]}
title="Collapse Icon"
/>
</div>
<MemoizedFormattedMessage
<SettingMobileHeader
closeModal={[MockFunction]}
collapseModal={[MockFunction]}
text={
<Memo(MemoizedFormattedMessage)
defaultMessage="Security Settings"
id="user.settings.security.title"
/>
</h4>
</div>
}
/>
<div
className="user-settings"
>
<h3
className="tab-header"
>
<MemoizedFormattedMessage
defaultMessage="Security Settings"
id="user.settings.security.title"
/>
</h3>
<SettingDesktopHeader
text={
<Memo(MemoizedFormattedMessage)
defaultMessage="Security Settings"
id="user.settings.security.title"
/>
}
/>
<div
className="divider-dark first"
/>

View File

@ -27,6 +27,9 @@ import * as Utils from 'utils/utils';
import MfaSection from './mfa_section';
import UserAccessTokenSection from './user_access_token_section';
import SettingDesktopHeader from '../headers/setting_desktop_header';
import SettingMobileHeader from '../headers/setting_mobile_header';
const SECTION_MFA = 'mfa';
const SECTION_PASSWORD = 'password';
const SECTION_SIGNIN = 'signin';
@ -990,45 +993,25 @@ export class SecurityTab extends React.PureComponent<Props, State> {
return (
<div>
<div className='modal-header'>
<button
type='button'
className='close'
data-dismiss='modal'
aria-label={this.props.intl.formatMessage({
id: 'user.settings.security.close',
defaultMessage: 'Close',
})}
onClick={this.props.closeModal}
>
<span aria-hidden='true'>{'×'}</span>
</button>
<h4
className='modal-title'
>
<div className='modal-back'>
<i
className='fa fa-angle-left'
title={this.props.intl.formatMessage({
id: 'generic_icons.collapse',
defaultMessage: 'Collapse Icon',
})}
onClick={this.props.collapseModal}
/>
</div>
<SettingMobileHeader
closeModal={this.props.closeModal}
collapseModal={this.props.collapseModal}
text={
<FormattedMessage
id='user.settings.security.title'
defaultMessage='Security Settings'
/>
</h4>
</div>
}
/>
<div className='user-settings'>
<h3 className='tab-header'>
<FormattedMessage
id='user.settings.security.title'
defaultMessage='Security Settings'
/>
</h3>
<SettingDesktopHeader
text={
<FormattedMessage
id='user.settings.security.title'
defaultMessage='Security Settings'
/>
}
/>
<div className='divider-dark first'/>
{passwordSection}
<div className='divider-light'/>

View File

@ -1,15 +0,0 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React from 'react';
type Props = {
text: string;
}
const SettingDesktopHeader = ({text}: Props) => (
<h3 className='tab-header'>
{text}
</h3>
);
export default SettingDesktopHeader;

View File

@ -2,11 +2,14 @@
// See LICENSE.txt for license information.
import React from 'react';
import {FormattedMessage, useIntl} from 'react-intl';
import {FormattedMessage} from 'react-intl';
import LimitVisibleGMsDMs from './limit_visible_gms_dms';
import ShowUnreadsCategory from './show_unreads_category';
import SettingDesktopHeader from '../headers/setting_desktop_header';
import SettingMobileHeader from '../headers/setting_mobile_header';
export interface Props {
updateSection: (section: string) => void;
activeSection: string;
@ -15,47 +18,31 @@ export interface Props {
}
export default function UserSettingsSidebar(props: Props): JSX.Element {
const {formatMessage} = useIntl();
return (
<div>
<div className='modal-header'>
<button
id='closeButton'
type='button'
className='close'
data-dismiss='modal'
aria-label='Close'
onClick={props.closeModal}
>
<span aria-hidden='true'>{'×'}</span>
</button>
<h4 className='modal-title'>
<div
className='modal-back'
onClick={props.collapseModal}
>
<i
className='fa fa-angle-left'
title={formatMessage({id: 'generic_icons.collapse', defaultMessage: 'Collapse Icon'})}
/>
</div>
<SettingMobileHeader
closeModal={props.closeModal}
collapseModal={props.collapseModal}
text={
<FormattedMessage
id='user.settings.sidebar.title'
defaultMessage='Sidebar Settings'
/>
</h4>
</div>
}
/>
<div
id='sidebarTitle'
className='user-settings'
>
<h3 className='tab-header'>
<FormattedMessage
id='user.settings.sidebar.title'
defaultMessage='Sidebar Settings'
/>
</h3>
<SettingDesktopHeader
text={
<FormattedMessage
id='user.settings.sidebar.title'
defaultMessage='Sidebar Settings'
/>
}
/>
<div className='divider-dark first'/>
<ShowUnreadsCategory
active={props.activeSection === 'showUnreadsCategory'}