summaryrefslogtreecommitdiffstats
path: root/web/react/components/user_settings/user_settings_theme.jsx
diff options
context:
space:
mode:
Diffstat (limited to 'web/react/components/user_settings/user_settings_theme.jsx')
-rw-r--r--web/react/components/user_settings/user_settings_theme.jsx301
1 files changed, 301 insertions, 0 deletions
diff --git a/web/react/components/user_settings/user_settings_theme.jsx b/web/react/components/user_settings/user_settings_theme.jsx
new file mode 100644
index 000000000..a0656feaa
--- /dev/null
+++ b/web/react/components/user_settings/user_settings_theme.jsx
@@ -0,0 +1,301 @@
+// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+import CustomThemeChooser from './custom_theme_chooser.jsx';
+import PremadeThemeChooser from './premade_theme_chooser.jsx';
+import SettingItemMin from '../setting_item_min.jsx';
+import SettingItemMax from '../setting_item_max.jsx';
+
+import UserStore from '../../stores/user_store.jsx';
+
+import AppDispatcher from '../../dispatcher/app_dispatcher.jsx';
+import * as Client from '../../utils/client.jsx';
+import * as Utils from '../../utils/utils.jsx';
+
+import Constants from '../../utils/constants.jsx';
+
+import {intlShape, injectIntl, defineMessages, FormattedMessage} from 'mm-intl';
+
+const ActionTypes = Constants.ActionTypes;
+
+const holders = defineMessages({
+ themeTitle: {
+ id: 'user.settings.display.theme.title',
+ defaultMessage: 'Theme'
+ },
+ themeDescribe: {
+ id: 'user.settings.display.theme.describe',
+ defaultMessage: 'Open to manage your theme'
+ }
+});
+
+export default class ThemeSetting extends React.Component {
+ constructor(props) {
+ super(props);
+
+ this.onChange = this.onChange.bind(this);
+ this.submitTheme = this.submitTheme.bind(this);
+ this.updateTheme = this.updateTheme.bind(this);
+ this.deactivate = this.deactivate.bind(this);
+ this.resetFields = this.resetFields.bind(this);
+ this.handleImportModal = this.handleImportModal.bind(this);
+
+ this.state = this.getStateFromStores();
+
+ this.originalTheme = Object.assign({}, this.state.theme);
+ }
+ componentDidMount() {
+ UserStore.addChangeListener(this.onChange);
+
+ if (this.props.selected) {
+ $(ReactDOM.findDOMNode(this.refs[this.state.theme])).addClass('active-border');
+ }
+ }
+ componentDidUpdate() {
+ if (this.props.selected) {
+ $('.color-btn').removeClass('active-border');
+ $(ReactDOM.findDOMNode(this.refs[this.state.theme])).addClass('active-border');
+ }
+ }
+ componentWillReceiveProps(nextProps) {
+ if (!this.props.selected && nextProps.selected) {
+ this.resetFields();
+ }
+ }
+ componentWillUnmount() {
+ UserStore.removeChangeListener(this.onChange);
+ }
+ getStateFromStores() {
+ const user = UserStore.getCurrentUser();
+ let theme = null;
+
+ if ($.isPlainObject(user.theme_props) && !$.isEmptyObject(user.theme_props)) {
+ theme = Object.assign({}, user.theme_props);
+ } else {
+ theme = $.extend(true, {}, Constants.THEMES.default);
+ }
+
+ let type = 'premade';
+ if (theme.type === 'custom') {
+ type = 'custom';
+ }
+
+ if (!theme.codeTheme) {
+ theme.codeTheme = Constants.DEFAULT_CODE_THEME;
+ }
+
+ return {theme, type};
+ }
+ onChange() {
+ const newState = this.getStateFromStores();
+
+ if (!Utils.areObjectsEqual(this.state, newState)) {
+ this.setState(newState);
+ }
+
+ this.props.setEnforceFocus(true);
+ }
+ scrollToTop() {
+ $('.ps-container.modal-body').scrollTop(0);
+ $('.ps-container.modal-body').perfectScrollbar('update');
+ }
+ submitTheme(e) {
+ e.preventDefault();
+ var user = UserStore.getCurrentUser();
+ user.theme_props = this.state.theme;
+
+ Client.updateUser(user,
+ (data) => {
+ AppDispatcher.handleServerAction({
+ type: ActionTypes.RECIEVED_ME,
+ me: data
+ });
+
+ this.props.setRequireConfirm(false);
+ this.originalTheme = Object.assign({}, this.state.theme);
+ this.scrollToTop();
+ this.props.updateSection('');
+ },
+ (err) => {
+ var state = this.getStateFromStores();
+ state.serverError = err;
+ this.setState(state);
+ }
+ );
+ }
+ updateTheme(theme) {
+ let themeChanged = this.state.theme.length === theme.length;
+ if (!themeChanged) {
+ for (const field in theme) {
+ if (theme.hasOwnProperty(field)) {
+ if (this.state.theme[field] !== theme[field]) {
+ themeChanged = true;
+ break;
+ }
+ }
+ }
+ }
+
+ this.props.setRequireConfirm(themeChanged);
+
+ this.setState({theme});
+ Utils.applyTheme(theme);
+ }
+ updateType(type) {
+ this.setState({type});
+ }
+ deactivate() {
+ const state = this.getStateFromStores();
+
+ Utils.applyTheme(state.theme);
+ }
+ resetFields() {
+ const state = this.getStateFromStores();
+ state.serverError = null;
+ this.setState(state);
+ this.scrollToTop();
+
+ Utils.applyTheme(state.theme);
+
+ this.props.setRequireConfirm(false);
+ }
+ handleImportModal() {
+ AppDispatcher.handleViewAction({
+ type: ActionTypes.TOGGLE_IMPORT_THEME_MODAL,
+ value: true
+ });
+
+ this.props.setEnforceFocus(false);
+ }
+ render() {
+ const {formatMessage} = this.props.intl;
+
+ var serverError;
+ if (this.state.serverError) {
+ serverError = this.state.serverError;
+ }
+
+ const displayCustom = this.state.type === 'custom';
+
+ let custom;
+ let premade;
+ if (displayCustom) {
+ custom = (
+ <div key='customThemeChooser'>
+ <br/>
+ <CustomThemeChooser
+ theme={this.state.theme}
+ updateTheme={this.updateTheme}
+ />
+ </div>
+ );
+ } else {
+ premade = (
+ <div key='premadeThemeChooser'>
+ <br/>
+ <PremadeThemeChooser
+ theme={this.state.theme}
+ updateTheme={this.updateTheme}
+ />
+ </div>
+ );
+ }
+
+ let themeUI;
+ if (this.props.selected) {
+ let inputs = [];
+
+ inputs.push(
+ <div
+ className='radio'
+ key='premadeThemeColorLabel'
+ >
+ <label>
+ <input type='radio'
+ checked={!displayCustom}
+ onChange={this.updateType.bind(this, 'premade')}
+ />
+ <FormattedMessage
+ id='user.settings.display.theme.themeColors'
+ defaultMessage='Theme Colors'
+ />
+ </label>
+ <br/>
+ </div>
+ );
+
+ inputs.push(premade);
+
+ inputs.push(
+ <div
+ className='radio'
+ key='customThemeColorLabel'
+ >
+ <label>
+ <input type='radio'
+ checked={displayCustom}
+ onChange={this.updateType.bind(this, 'custom')}
+ />
+ <FormattedMessage
+ id='user.settings.display.theme.customTheme'
+ defaultMessage='Custom Theme'
+ />
+ </label>
+ <br/>
+ </div>
+ );
+
+ inputs.push(custom);
+
+ inputs.push(
+ <div key='importSlackThemeButton'>
+ <br/>
+ <a
+ className='theme'
+ onClick={this.handleImportModal}
+ >
+ <FormattedMessage
+ id='user.settings.display.theme.import'
+ defaultMessage='Import theme colors from Slack'
+ />
+ </a>
+ </div>
+ );
+
+ themeUI = (
+ <SettingItemMax
+ inputs={inputs}
+ submit={this.submitTheme}
+ server_error={serverError}
+ width='full'
+ updateSection={(e) => {
+ this.props.updateSection('');
+ e.preventDefault();
+ }}
+ />
+ );
+ } else {
+ themeUI = (
+ <SettingItemMin
+ title={formatMessage(holders.themeTitle)}
+ describe={formatMessage(holders.themeDescribe)}
+ updateSection={() => {
+ this.props.updateSection('theme');
+ }}
+ />
+ );
+ }
+
+ return themeUI;
+ }
+}
+
+ThemeSetting.propTypes = {
+ intl: intlShape.isRequired,
+ selected: React.PropTypes.bool.isRequired,
+ updateSection: React.PropTypes.func.isRequired,
+ setRequireConfirm: React.PropTypes.func.isRequired,
+ setEnforceFocus: React.PropTypes.func.isRequired
+};
+
+export default injectIntl(ThemeSetting);