Files
mattermost/webapp/components/user_settings/user_settings_display.jsx
Harrison Healey fb6f2a123c PLT-5860 Updated copyright date (#6058)
* PLT-5860 Updated copyright date in about modal

* PLT-5860 Updated copyright notice in JSX files

* PLT-5860 Updated copyright notice in go files

* Fixed misc copyright dates

* Fixed component snapshots
2017-04-12 08:27:57 -04:00

914 lines
34 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
import $ from 'jquery';
import SettingItemMin from '../setting_item_min.jsx';
import SettingItemMax from '../setting_item_max.jsx';
import ManageLanguages from './manage_languages.jsx';
import ThemeSetting from './user_settings_theme.jsx';
import * as AsyncClient from 'utils/async_client.jsx';
import PreferenceStore from 'stores/preference_store.jsx';
import UserStore from 'stores/user_store.jsx';
import * as Utils from 'utils/utils.jsx';
import * as I18n from 'i18n/i18n.jsx';
import Constants from 'utils/constants.jsx';
const Preferences = Constants.Preferences;
import {FormattedMessage} from 'react-intl';
function getDisplayStateFromStores() {
return {
militaryTime: PreferenceStore.get(Preferences.CATEGORY_DISPLAY_SETTINGS, 'use_military_time', 'false'),
nameFormat: PreferenceStore.get(Preferences.CATEGORY_DISPLAY_SETTINGS, 'name_format', 'username'),
selectedFont: PreferenceStore.get(Preferences.CATEGORY_DISPLAY_SETTINGS, 'selected_font', Constants.DEFAULT_FONT),
channelDisplayMode: PreferenceStore.get(Preferences.CATEGORY_DISPLAY_SETTINGS, Preferences.CHANNEL_DISPLAY_MODE, Preferences.CHANNEL_DISPLAY_MODE_DEFAULT),
messageDisplay: PreferenceStore.get(Preferences.CATEGORY_DISPLAY_SETTINGS, Preferences.MESSAGE_DISPLAY, Preferences.MESSAGE_DISPLAY_DEFAULT),
collapseDisplay: PreferenceStore.get(Preferences.CATEGORY_DISPLAY_SETTINGS, Preferences.COLLAPSE_DISPLAY, Preferences.COLLAPSE_DISPLAY_DEFAULT)
};
}
import React from 'react';
export default class UserSettingsDisplay extends React.Component {
constructor(props) {
super(props);
this.handleSubmit = this.handleSubmit.bind(this);
this.handleClockRadio = this.handleClockRadio.bind(this);
this.handleNameRadio = this.handleNameRadio.bind(this);
this.handleFont = this.handleFont.bind(this);
this.updateSection = this.updateSection.bind(this);
this.updateState = this.updateState.bind(this);
this.createCollapseSection = this.createCollapseSection.bind(this);
this.state = getDisplayStateFromStores();
}
componentWillUnmount() {
Utils.applyFont(PreferenceStore.get(Preferences.CATEGORY_DISPLAY_SETTINGS, 'selected_font', Constants.DEFAULT_FONT));
}
handleSubmit() {
const userId = UserStore.getCurrentId();
const timePreference = {
user_id: userId,
category: Preferences.CATEGORY_DISPLAY_SETTINGS,
name: 'use_military_time',
value: this.state.militaryTime
};
const namePreference = {
user_id: userId,
category: Preferences.CATEGORY_DISPLAY_SETTINGS,
name: 'name_format',
value: this.state.nameFormat
};
const fontPreference = {
user_id: userId,
category: Preferences.CATEGORY_DISPLAY_SETTINGS,
name: 'selected_font',
value: this.state.selectedFont
};
const channelDisplayModePreference = {
user_id: userId,
category: Preferences.CATEGORY_DISPLAY_SETTINGS,
name: Preferences.CHANNEL_DISPLAY_MODE,
value: this.state.channelDisplayMode
};
const messageDisplayPreference = {
user_id: userId,
category: Preferences.CATEGORY_DISPLAY_SETTINGS,
name: Preferences.MESSAGE_DISPLAY,
value: this.state.messageDisplay
};
const collapseDisplayPreference = {
user_id: userId,
category: Preferences.CATEGORY_DISPLAY_SETTINGS,
name: Preferences.COLLAPSE_DISPLAY,
value: this.state.collapseDisplay
};
AsyncClient.savePreferences([timePreference, namePreference, fontPreference, channelDisplayModePreference, messageDisplayPreference, collapseDisplayPreference],
() => {
this.updateSection('');
},
(err) => {
this.setState({serverError: err.message});
}
);
}
handleClockRadio(militaryTime) {
this.setState({militaryTime});
}
handleNameRadio(nameFormat) {
this.setState({nameFormat});
}
handleChannelDisplayModeRadio(channelDisplayMode) {
this.setState({channelDisplayMode});
}
handlemessageDisplayRadio(messageDisplay) {
this.setState({messageDisplay});
}
handleFont(selectedFont) {
Utils.applyFont(selectedFont);
this.setState({selectedFont});
}
handleCollapseRadio(collapseDisplay) {
this.setState({collapseDisplay});
}
updateSection(section) {
if ($('.section-max').length) {
$('.settings-modal .modal-body').scrollTop(0).perfectScrollbar('update');
}
this.updateState();
this.props.updateSection(section);
}
updateState() {
const newState = getDisplayStateFromStores();
if (!Utils.areObjectsEqual(newState, this.state)) {
this.handleFont(newState.selectedFont);
this.setState(newState);
}
}
createCollapseSection() {
if (this.props.activeSection === 'collapse') {
const collapseFormat = [false, false];
if (this.state.collapseDisplay === 'false') {
collapseFormat[0] = true;
} else {
collapseFormat[1] = true;
}
const handleUpdateCollapseSection = (e) => {
this.updateSection('');
e.preventDefault();
};
const inputs = [
<div key='userDisplayCollapseOptions'>
<div className='radio'>
<label>
<input
id='collapseFormat'
type='radio'
name='collapseFormat'
checked={collapseFormat[0]}
onChange={this.handleCollapseRadio.bind(this, 'false')}
/>
<FormattedMessage
id='user.settings.display.collapseOn'
defaultMessage='On'
/>
</label>
<br/>
</div>
<div className='radio'>
<label>
<input
id='collapseFormatOff'
type='radio'
name='collapseFormat'
checked={collapseFormat[1]}
onChange={this.handleCollapseRadio.bind(this, 'true')}
/>
<FormattedMessage
id='user.settings.display.collapseOff'
defaultMessage='Off'
/>
</label>
<br/>
</div>
<div>
<br/>
<FormattedMessage
id='user.settings.display.collapseDesc'
defaultMessage='Set whether previews of image links show as expanded or collapsed by default. This setting can also be controlled using the slash commands /expand and /collapse.'
/>
</div>
</div>
];
return (
<SettingItemMax
title={
<FormattedMessage
id='user.settings.display.collapseDisplay'
defaultMessage='Default appearance of image link previews'
/>
}
inputs={inputs}
submit={this.handleSubmit}
server_error={this.state.serverError}
updateSection={handleUpdateCollapseSection}
/>
);
}
let describe;
if (this.state.collapseDisplay === 'false') {
describe = (
<FormattedMessage
id='user.settings.display.collapseOn'
defaultMessage='Expanded'
/>
);
} else {
describe = (
<FormattedMessage
id='user.settings.display.collapseOff'
defaultMessage='Collapsed'
/>
);
}
const handleUpdateCollapseSection = () => {
this.props.updateSection('collapse');
};
return (
<SettingItemMin
title={
<FormattedMessage
id='user.settings.display.collapseDisplay'
defaultMessage='Default appearance of image link previews'
/>
}
describe={describe}
updateSection={handleUpdateCollapseSection}
/>
);
}
render() {
const serverError = this.state.serverError || null;
let clockSection;
let nameFormatSection;
let channelDisplayModeSection;
let fontSection;
let languagesSection;
let messageDisplaySection;
const collapseSection = this.createCollapseSection();
if (this.props.activeSection === 'clock') {
const clockFormat = [false, false];
if (this.state.militaryTime === 'true') {
clockFormat[1] = true;
} else {
clockFormat[0] = true;
}
const handleUpdateClockSection = (e) => {
this.updateSection('');
e.preventDefault();
};
const inputs = [
<div key='userDisplayClockOptions'>
<div className='radio'>
<label>
<input
id='clockFormat12h'
type='radio'
name='clockFormat'
checked={clockFormat[0]}
onChange={this.handleClockRadio.bind(this, 'false')}
/>
<FormattedMessage
id='user.settings.display.normalClock'
defaultMessage='12-hour clock (example: 4:00 PM)'
/>
</label>
<br/>
</div>
<div className='radio'>
<label>
<input
id='clockFormat24h'
type='radio'
name='clockFormat'
checked={clockFormat[1]}
onChange={this.handleClockRadio.bind(this, 'true')}
/>
<FormattedMessage
id='user.settings.display.militaryClock'
defaultMessage='24-hour clock (example: 16:00)'
/>
</label>
<br/>
</div>
<div>
<br/>
<FormattedMessage
id='user.settings.display.preferTime'
defaultMessage='Select how you prefer time displayed.'
/>
</div>
</div>
];
clockSection = (
<SettingItemMax
title={
<FormattedMessage
id='user.settings.display.clockDisplay'
defaultMessage='Clock Display'
/>
}
inputs={inputs}
submit={this.handleSubmit}
server_error={serverError}
updateSection={handleUpdateClockSection}
/>
);
} else {
let describe;
if (this.state.militaryTime === 'true') {
describe = (
<FormattedMessage
id='user.settings.display.militaryClock'
defaultMessage='24-hour clock (example: 16:00)'
/>
);
} else {
describe = (
<FormattedMessage
id='user.settings.display.normalClock'
defaultMessage='12-hour clock (example: 4:00 PM)'
/>
);
}
const handleUpdateClockSection = () => {
this.props.updateSection('clock');
};
clockSection = (
<SettingItemMin
title={
<FormattedMessage
id='user.settings.display.clockDisplay'
defaultMessage='Clock Display'
/>
}
describe={describe}
updateSection={handleUpdateClockSection}
/>
);
}
const showUsername = (
<FormattedMessage
id='user.settings.display.showUsername'
defaultMessage='Show username (default)'
/>
);
const showNickname = (
<FormattedMessage
id='user.settings.display.showNickname'
defaultMessage='Show nickname if one exists, otherwise show first and last name'
/>
);
const showFullName = (
<FormattedMessage
id='user.settings.display.showFullname'
defaultMessage='Show first and last name'
/>
);
if (this.props.activeSection === 'name_format') {
const nameFormat = [false, false, false];
if (this.state.nameFormat === 'nickname_full_name') {
nameFormat[0] = true;
} else if (this.state.nameFormat === 'full_name') {
nameFormat[2] = true;
} else {
nameFormat[1] = true;
}
const inputs = [
<div key='userDisplayNameOptions'>
<div className='radio'>
<label>
<input
id='nameFormatUsername'
type='radio'
name='nameFormat'
checked={nameFormat[1]}
onChange={this.handleNameRadio.bind(this, 'username')}
/>
{showUsername}
</label>
<br/>
</div>
<div className='radio'>
<label>
<input
id='nameFormatNickname'
type='radio'
name='nameFormat'
checked={nameFormat[0]}
onChange={this.handleNameRadio.bind(this, 'nickname_full_name')}
/>
{showNickname}
</label>
<br/>
</div>
<div className='radio'>
<label>
<input
id='nameFormatFullName'
type='radio'
name='nameFormat'
checked={nameFormat[2]}
onChange={this.handleNameRadio.bind(this, 'full_name')}
/>
{showFullName}
</label>
<br/>
</div>
<div>
<br/>
<FormattedMessage
id='user.settings.display.nameOptsDesc'
defaultMessage="Set how to display other user's names in posts and the Direct Messages list."
/>
</div>
</div>
];
nameFormatSection = (
<SettingItemMax
title={
<FormattedMessage
id='user.settings.display.teammateDisplay'
defaultMessage='Teammate Name Display'
/>
}
inputs={inputs}
submit={this.handleSubmit}
server_error={serverError}
updateSection={(e) => {
this.updateSection('');
e.preventDefault();
}}
/>
);
} else {
let describe;
if (this.state.nameFormat === 'username') {
describe = (
<FormattedMessage
id='user.settings.display.showUsername'
defaultMessage='Show username (default)'
/>
);
} else if (this.state.nameFormat === 'full_name') {
describe = (
<FormattedMessage
id='user.settings.display.showFullname'
defaultMessage='Show first and last name'
/>
);
} else {
describe = (
<FormattedMessage
id='user.settings.display.showNickname'
defaultMessage='Show nickname if one exists, otherwise show first and last name'
/>
);
}
nameFormatSection = (
<SettingItemMin
title={
<FormattedMessage
id='user.settings.display.teammateDisplay'
defaultMessage='Teammate Name Display'
/>
}
describe={describe}
updateSection={() => {
this.props.updateSection('name_format');
}}
/>
);
}
if (this.props.activeSection === Preferences.MESSAGE_DISPLAY) {
const messageDisplay = [false, false];
if (this.state.messageDisplay === Preferences.MESSAGE_DISPLAY_CLEAN) {
messageDisplay[0] = true;
} else {
messageDisplay[1] = true;
}
const inputs = [
<div key='userDisplayNameOptions'>
<div className='radio'>
<label>
<input
id='messageFormatStandard'
type='radio'
name='messageDisplay'
checked={messageDisplay[0]}
onChange={this.handlemessageDisplayRadio.bind(this, Preferences.MESSAGE_DISPLAY_CLEAN)}
/>
<FormattedMessage
id='user.settings.display.messageDisplayClean'
defaultMessage='Standard'
/>
{': '}
<span className='font-weight--normal'>
<FormattedMessage
id='user.settings.display.messageDisplayCleanDes'
defaultMessage='Easy to scan and read.'
/>
</span>
</label>
<br/>
</div>
<div className='radio'>
<label>
<input
id='messageFormatCompact'
type='radio'
name='messageDisplay'
checked={messageDisplay[1]}
onChange={this.handlemessageDisplayRadio.bind(this, Preferences.MESSAGE_DISPLAY_COMPACT)}
/>
<FormattedMessage
id='user.settings.display.messageDisplayCompact'
defaultMessage='Compact'
/>
{': '}
<span className='font-weight--normal'>
<FormattedMessage
id='user.settings.display.messageDisplayCompactDes'
defaultMessage='Fit as many messages on the screen as we can.'
/>
</span>
</label>
<br/>
</div>
<div>
<br/>
<FormattedMessage
id='user.settings.display.messageDisplayDescription'
defaultMessage='Select how messages in a channel should be displayed.'
/>
</div>
</div>
];
messageDisplaySection = (
<SettingItemMax
title={
<FormattedMessage
id='user.settings.display.messageDisplayTitle'
defaultMessage='Message Display'
/>
}
inputs={inputs}
submit={this.handleSubmit}
server_error={serverError}
updateSection={(e) => {
this.updateSection('');
e.preventDefault();
}}
/>
);
} else {
let describe;
if (this.state.messageDisplay === Preferences.MESSAGE_DISPLAY_CLEAN) {
describe = (
<FormattedMessage
id='user.settings.display.messageDisplayClean'
defaultMessage='Standard'
/>
);
} else {
describe = (
<FormattedMessage
id='user.settings.display.messageDisplayCompact'
defaultMessage='Compact'
/>
);
}
messageDisplaySection = (
<SettingItemMin
title={
<FormattedMessage
id='user.settings.display.messageDisplayTitle'
defaultMessage='Message Display'
/>
}
describe={describe}
updateSection={() => {
this.props.updateSection(Preferences.MESSAGE_DISPLAY);
}}
/>
);
}
if (this.props.activeSection === Preferences.CHANNEL_DISPLAY_MODE) {
const channelDisplayMode = [false, false];
if (this.state.channelDisplayMode === Preferences.CHANNEL_DISPLAY_MODE_FULL_SCREEN) {
channelDisplayMode[0] = true;
} else {
channelDisplayMode[1] = true;
}
const inputs = [
<div key='userDisplayNameOptions'>
<div className='radio'>
<label>
<input
id='channelDisplayFormatFullScreen'
type='radio'
name='channelDisplayMode'
checked={channelDisplayMode[0]}
onChange={this.handleChannelDisplayModeRadio.bind(this, Preferences.CHANNEL_DISPLAY_MODE_FULL_SCREEN)}
/>
<FormattedMessage
id='user.settings.display.fullScreen'
defaultMessage='Full width'
/>
</label>
<br/>
</div>
<div className='radio'>
<label>
<input
id='channelDisplayFormatCentered'
type='radio'
name='channelDisplayMode'
checked={channelDisplayMode[1]}
onChange={this.handleChannelDisplayModeRadio.bind(this, Preferences.CHANNEL_DISPLAY_MODE_CENTERED)}
/>
<FormattedMessage
id='user.settings.display.fixedWidthCentered'
defaultMessage='Fixed width, centered'
/>
</label>
<br/>
</div>
<div>
<br/>
<FormattedMessage
id='user.settings.display.channeldisplaymode'
defaultMessage='Select the width of the center channel.'
/>
</div>
</div>
];
channelDisplayModeSection = (
<SettingItemMax
title={
<FormattedMessage
id='user.settings.display.channelDisplayTitle'
defaultMessage='Channel Display Mode'
/>
}
inputs={inputs}
submit={this.handleSubmit}
server_error={serverError}
updateSection={(e) => {
this.updateSection('');
e.preventDefault();
}}
/>
);
} else {
let describe;
if (this.state.channelDisplayMode === Preferences.CHANNEL_DISPLAY_MODE_FULL_SCREEN) {
describe = (
<FormattedMessage
id='user.settings.display.fullScreen'
defaultMessage='Full width'
/>
);
} else {
describe = (
<FormattedMessage
id='user.settings.display.fixedWidthCentered'
defaultMessage='Fixed width, centered'
/>
);
}
channelDisplayModeSection = (
<SettingItemMin
title={
<FormattedMessage
id='user.settings.display.channelDisplayTitle'
defaultMessage='Channel Display Mode'
/>
}
describe={describe}
updateSection={() => {
this.props.updateSection(Preferences.CHANNEL_DISPLAY_MODE);
}}
/>
);
}
if (this.props.activeSection === 'font') {
const options = [];
Object.keys(Constants.FONTS).forEach((fontName, idx) => {
const className = Constants.FONTS[fontName];
options.push(
<option
key={'font_' + idx}
value={fontName}
className={className}
>
{fontName}
</option>
);
});
const inputs = [
<div key='userDisplayNameOptions'>
<div
className='dropdown'
>
<select
id='displayFontSelect'
className='form-control'
type='text'
value={this.state.selectedFont}
onChange={(e) => this.handleFont(e.target.value)}
>
{options}
</select>
</div>
<div>
<br/>
<FormattedMessage
id='user.settings.display.fontDesc'
defaultMessage='Select the font displayed in the Mattermost user interface.'
/>
</div>
</div>
];
fontSection = (
<SettingItemMax
title={
<FormattedMessage
id='user.settings.display.fontTitle'
defaultMessage='Display Font'
/>
}
inputs={inputs}
submit={this.handleSubmit}
server_error={serverError}
updateSection={(e) => {
this.updateSection('');
e.preventDefault();
}}
/>
);
} else {
fontSection = (
<SettingItemMin
title={
<FormattedMessage
id='user.settings.display.fontTitle'
defaultMessage='Display Font'
/>
}
describe={this.state.selectedFont}
updateSection={() => {
this.props.updateSection('font');
}}
/>
);
}
const userLocale = this.props.user.locale;
if (this.props.activeSection === 'languages') {
if (!I18n.isLanguageAvailable(userLocale)) {
this.props.user.locale = global.window.mm_config.DefaultClientLocale;
}
languagesSection = (
<ManageLanguages
user={this.props.user}
updateSection={(e) => {
this.updateSection('');
e.preventDefault();
}}
/>
);
} else {
let locale;
if (I18n.isLanguageAvailable(userLocale)) {
locale = I18n.getLanguageInfo(userLocale).name;
} else {
locale = I18n.getLanguageInfo(global.window.mm_config.DefaultClientLocale).name;
}
languagesSection = (
<SettingItemMin
title={
<FormattedMessage
id='user.settings.display.language'
defaultMessage='Language'
/>
}
width='medium'
describe={locale}
updateSection={() => {
this.updateSection('languages');
}}
/>
);
}
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'
ref='title'
>
<div className='modal-back'>
<i
className='fa fa-angle-left'
onClick={this.props.collapseModal}
/>
</div>
<FormattedMessage
id='user.settings.display.title'
defaultMessage='Display Settings'
/>
</h4>
</div>
<div className='user-settings'>
<h3 className='tab-header'>
<FormattedMessage
id='user.settings.display.title'
defaultMessage='Display Settings'
/>
</h3>
<div className='divider-dark first'/>
<ThemeSetting
selected={this.props.activeSection === 'theme'}
updateSection={this.updateSection}
setRequireConfirm={this.props.setRequireConfirm}
setEnforceFocus={this.props.setEnforceFocus}
/>
<div className='divider-dark'/>
{fontSection}
<div className='divider-dark'/>
{clockSection}
<div className='divider-dark'/>
{nameFormatSection}
<div className='divider-dark'/>
{collapseSection}
<div className='divider-dark'/>
{messageDisplaySection}
<div className='divider-dark'/>
{channelDisplayModeSection}
<div className='divider-dark'/>
{languagesSection}
</div>
</div>
);
}
}
UserSettingsDisplay.propTypes = {
user: React.PropTypes.object,
updateSection: React.PropTypes.func,
updateTab: React.PropTypes.func,
activeSection: React.PropTypes.string,
closeModal: React.PropTypes.func.isRequired,
collapseModal: React.PropTypes.func.isRequired,
setRequireConfirm: React.PropTypes.func.isRequired,
setEnforceFocus: React.PropTypes.func.isRequired
};