From 56e74239d6b34df8f30ef046f0b0ff4ff0866a71 Mon Sep 17 00:00:00 2001 From: =Corey Hulen Date: Sun, 14 Jun 2015 23:53:32 -0800 Subject: first commit --- web/react/components/user_settings.jsx | 1151 ++++++++++++++++++++++++++++++++ 1 file changed, 1151 insertions(+) create mode 100644 web/react/components/user_settings.jsx (limited to 'web/react/components/user_settings.jsx') diff --git a/web/react/components/user_settings.jsx b/web/react/components/user_settings.jsx new file mode 100644 index 000000000..b165a59ad --- /dev/null +++ b/web/react/components/user_settings.jsx @@ -0,0 +1,1151 @@ +// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved. +// See License.txt for license information. + +var UserStore = require('../stores/user_store.jsx'); +var SettingItemMin = require('./setting_item_min.jsx'); +var SettingItemMax = require('./setting_item_max.jsx'); +var SettingPicture = require('./setting_picture.jsx'); +var client = require('../utils/client.jsx'); +var AsyncClient = require('../utils/async_client.jsx'); +var utils = require('../utils/utils.jsx'); +var Constants = require('../utils/constants.jsx'); + +function getNotificationsStateFromStores() { + var user = UserStore.getCurrentUser(); + var sound = (!user.notify_props || user.notify_props.desktop_sound == undefined) ? "true" : user.notify_props.desktop_sound; + var desktop = (!user.notify_props || user.notify_props.desktop == undefined) ? "all" : user.notify_props.desktop; + var email = (!user.notify_props || user.notify_props.email == undefined) ? "true" : user.notify_props.email; + + var username_key = false; + var mention_key = false; + var custom_keys = ""; + var first_name_key = false; + + if (!user.notify_props) { + mention_keys = user.username; + if (user.full_name.length > 0) mention_keys += ","+ user.full_name.split(" ")[0]; + } else { + if (user.notify_props.mention_keys !== undefined) { + var keys = user.notify_props.mention_keys.split(','); + + if (keys.indexOf(user.username) !== -1) { + username_key = true; + keys.splice(keys.indexOf(user.username), 1); + } else { + username_key = false; + } + + if (keys.indexOf('@'+user.username) !== -1) { + mention_key = true; + keys.splice(keys.indexOf('@'+user.username), 1); + } else { + mention_key = false; + } + + custom_keys = keys.join(','); + } + + if (user.notify_props.first_name !== undefined) { + first_name_key = user.notify_props.first_name === "true"; + } + } + + return { notify_level: desktop, enable_email: email, enable_sound: sound, username_key: username_key, mention_key: mention_key, custom_keys: custom_keys, custom_keys_checked: custom_keys.length > 0, first_name_key: first_name_key }; +} + + +var NotificationsTab = React.createClass({ + handleSubmit: function() { + data = {} + data["user_id"] = this.props.user.id; + data["email"] = this.state.enable_email; + data["desktop_sound"] = this.state.enable_sound; + data["desktop"] = this.state.notify_level; + + var mention_keys = []; + if (this.state.username_key) mention_keys.push(this.props.user.username); + if (this.state.mention_key) mention_keys.push('@'+this.props.user.username); + + var string_keys = mention_keys.join(','); + if (this.state.custom_keys.length > 0 && this.state.custom_keys_checked) { + string_keys += ',' + this.state.custom_keys; + } + + data["mention_keys"] = string_keys; + data["first_name"] = this.state.first_name_key ? "true" : "false"; + + client.updateUserNotifyProps(data, + function(data) { + this.props.updateSection(""); + AsyncClient.getMe(); + }.bind(this), + function(err) { + this.setState({ server_error: err.message }); + }.bind(this) + ); + }, + componentDidMount: function() { + UserStore.addChangeListener(this._onChange); + }, + componentWillUnmount: function() { + UserStore.removeChangeListener(this._onChange); + }, + _onChange: function() { + var newState = getNotificationsStateFromStores(); + if (!utils.areStatesEqual(newState, this.state)) { + this.setState(newState); + } + }, + getInitialState: function() { + return getNotificationsStateFromStores(); + }, + handleNotifyRadio: function(notifyLevel) { + this.setState({ notify_level: notifyLevel }); + this.refs.wrapper.getDOMNode().focus(); + }, + handleEmailRadio: function(enableEmail) { + this.setState({ enable_email: enableEmail }); + this.refs.wrapper.getDOMNode().focus(); + }, + handleSoundRadio: function(enableSound) { + this.setState({ enable_sound: enableSound }); + this.refs.wrapper.getDOMNode().focus(); + }, + updateUsernameKey: function(val) { + this.setState({ username_key: val }); + }, + updateMentionKey: function(val) { + this.setState({ mention_key: val }); + }, + updateFirstNameKey: function(val) { + this.setState({ first_name_key: val }); + }, + updateCustomMentionKeys: function() { + var checked = this.refs.customcheck.getDOMNode().checked; + + if (checked) { + var text = this.refs.custommentions.getDOMNode().value; + + // remove all spaces and split string into individual keys + this.setState({ custom_keys: text.replace(/ /g, ''), custom_keys_checked: true }); + } else { + this.setState({ custom_keys: "", custom_keys_checked: false }); + } + }, + onCustomChange: function() { + this.refs.customcheck.getDOMNode().checked = true; + this.updateCustomMentionKeys(); + }, + render: function() { + var server_error = this.state.server_error ? this.state.server_error : null; + + var self = this; + + var desktopSection; + if (this.props.activeSection === 'desktop') { + var notifyActive = [false, false, false]; + if (this.state.notify_level === "mention") { + notifyActive[1] = true; + } else if (this.state.notify_level === "none") { + notifyActive[2] = true; + } else { + notifyActive[0] = true; + } + + var inputs = []; + + inputs.push( +
+
+ +
+
+
+ +
+
+
+ +
+
+ ); + + desktopSection = ( + + ); + } else { + var describe = ""; + if (this.state.notify_level === "mention") { + describe = "Only for mentions and direct messages"; + } else if (this.state.notify_level === "none") { + describe = "Never"; + } else { + describe = "For all activity"; + } + + desktopSection = ( + + ); + } + + var soundSection; + if (this.props.activeSection === 'sound') { + var soundActive = ["",""]; + if (this.state.enable_sound === "false") { + soundActive[1] = "active"; + } else { + soundActive[0] = "active"; + } + + var inputs = []; + + inputs.push( +
+
+ + +
+
+ ); + + soundSection = ( + + ); + } else { + var describe = ""; + if (this.state.enable_sound === "false") { + describe = "Off"; + } else { + describe = "On"; + } + + soundSection = ( + + ); + } + + var emailSection; + if (this.props.activeSection === 'email') { + var emailActive = ["",""]; + if (this.state.enable_email === "false") { + emailActive[1] = "active"; + } else { + emailActive[0] = "active"; + } + + var inputs = []; + + inputs.push( +
+
+ + +
+

{"Email notifications are sent for mentions and direct messages after you have been away from " + config.SiteName + " for 5 minutes."}
+
+ ); + + emailSection = ( + + ); + } else { + var describe = ""; + if (this.state.enable_email === "false") { + describe = "Off"; + } else { + describe = "On"; + } + + emailSection = ( + + ); + } + + var keysSection; + if (this.props.activeSection === 'keys') { + var user = this.props.user; + var first_name = ""; + if (user.full_name.length > 0) { + first_name = user.full_name.split(' ')[0]; + } + + var inputs = []; + + if (first_name != "") { + inputs.push( +
+
+ +
+
+ ); + } + + inputs.push( +
+
+ +
+
+ ); + + inputs.push( +
+
+ +
+
+ ); + + inputs.push( +
+
+ +
+ +
+ ); + + keysSection = ( + + ); + } else { + var keys = []; + if (this.state.first_name_key) { + var first_name = ""; + var user = this.props.user; + if (user.full_name.length > 0) first_name = user.full_name.split(' ')[0]; + if (first_name != "") keys.push(first_name); + } + if (this.state.username_key) keys.push(this.props.user.username); + if (this.state.mention_key) keys.push('@'+this.props.user.username); + if (this.state.custom_keys.length > 0) keys = keys.concat(this.state.custom_keys.split(',')); + + var describe = ""; + for (var i = 0; i < keys.length; i++) { + describe += '"' + keys[i] + '", '; + } + + if (describe.length > 0) { + describe = describe.substring(0, describe.length - 2); + } else { + describe = "No words configured"; + } + + keysSection = ( + + ); + } + + return ( +
+
+ +

Notifications

+
+
+

Notifications

+
+ {desktopSection} +
+ {soundSection} +
+ {emailSection} +
+ {keysSection} +
+
+
+ + ); + } +}); + +function getStateFromStoresForSessions() { + return { + sessions: UserStore.getSessions(), + server_error: null, + client_error: null + }; +} + +var SessionsTab = React.createClass({ + submitRevoke: function(altId) { + client.revokeSession(altId, + function(data) { + AsyncClient.getSessions(); + }.bind(this), + function(err) { + state = this.getStateFromStoresForSessions(); + state.server_error = err; + this.setState(state); + }.bind(this) + ); + }, + componentDidMount: function() { + UserStore.addSessionsChangeListener(this._onChange); + AsyncClient.getSessions(); + }, + componentWillUnmount: function() { + UserStore.removeSessionsChangeListener(this._onChange); + }, + _onChange: function() { + this.setState(getStateFromStoresForSessions()); + }, + getInitialState: function() { + return getStateFromStoresForSessions(); + }, + render: function() { + var server_error = this.state.server_error ? this.state.server_error : null; + + return ( +
+
+ +

Sessions

+
+
+

Sessions

+
+ { server_error } +
+ + + + + + { + this.state.sessions.map(function(value, index) { + return ( + + + + + + + + + + ); + }, this) + } + +
IdPlatformOSBrowserCreatedLast ActivityRevoke
{ value.alt_id }{value.props.platform}{value.props.os}{value.props.browser}{ new Date(value.create_at).toLocaleString() }{ new Date(value.last_activity_at).toLocaleString() }
+
+
+
+
+ ); + } +}); + +function getStateFromStoresForAudits() { + return { + audits: UserStore.getAudits() + }; +} + +var AuditTab = React.createClass({ + componentDidMount: function() { + UserStore.addAuditsChangeListener(this._onChange); + AsyncClient.getAudits(); + }, + componentWillUnmount: function() { + UserStore.removeAuditsChangeListener(this._onChange); + }, + _onChange: function() { + this.setState(getStateFromStoresForAudits()); + }, + getInitialState: function() { + return getStateFromStoresForAudits(); + }, + render: function() { + return ( +
+
+ +

Activity Log

+
+
+

Activity Log

+
+
+ + + + + + + + + + + + { + this.state.audits.map(function(value, index) { + return ( + + + + + + + + ); + }, this) + } + +
TimeActionIP AddressSessionOther Info
{ new Date(value.create_at).toLocaleString() }{ value.action.replace("/api/v1", "") }{ value.ip_address }{ value.session_id }{ value.extra_info }
+
+
+
+
+ ); + } +}); + +var SecurityTab = React.createClass({ + submitPassword: function(e) { + e.preventDefault(); + + var user = UserStore.getCurrentUser(); + var currentPassword = this.state.current_password; + var newPassword = this.state.new_password; + var confirmPassword = this.state.confirm_password; + + if (currentPassword === '') { + this.setState({ password_error: "Please enter your current password" }); + return; + } + + if (newPassword.length < 5) { + this.setState({ password_error: "New passwords must be at least 5 characters" }); + return; + } + + if (newPassword != confirmPassword) { + this.setState({ password_error: "The new passwords you entered do not match" }); + return; + } + + var data = {}; + data.user_id = user.id; + data.current_password = currentPassword; + data.new_password = newPassword; + + client.updatePassword(data, + function(data) { + this.updateSection(""); + AsyncClient.getMe(); + this.setState({ current_password: '', new_password: '', confirm_password: '' }); + }.bind(this), + function(err) { + state = this.getInitialState(); + state.server_error = err; + this.setState(state); + }.bind(this) + ); + }, + updateCurrentPassword: function(e) { + this.setState({ current_password: e.target.value }); + }, + updateNewPassword: function(e) { + this.setState({ new_password: e.target.value }); + }, + updateConfirmPassword: function(e) { + this.setState({ confirm_password: e.target.value }); + }, + getInitialState: function() { + return { current_password: '', new_password: '', confirm_password: '' }; + }, + render: function() { + var server_error = this.state.server_error ? this.state.server_error : null; + var password_error = this.state.password_error ? this.state.password_error : null; + + var passwordSection; + var self = this; + if (this.props.activeSection === 'password') { + var inputs = []; + + inputs.push( +
+ +
+ +
+
+ ); + inputs.push( +
+ +
+ +
+
+ ); + inputs.push( +
+ +
+ +
+
+ ); + + passwordSection = ( + + ); + } else { + var d = new Date(this.props.user.last_password_update); + var hour = d.getHours() < 10 ? "0" + d.getHours() : String(d.getHours()); + var min = d.getMinutes() < 10 ? "0" + d.getMinutes() : String(d.getMinutes()); + var dateStr = "Last updated " + Constants.MONTHS[d.getMonth()] + " " + d.getDate() + ", " + d.getFullYear() + " at " + hour + ":" + min; + + passwordSection = ( + + ); + } + + return ( +
+
+ +

Security Settings

+
+
+

Security Settings

+
+ { passwordSection } +
+
+
+ ); + } +}); + +var GeneralTab = React.createClass({ + submitActive: false, + submitUsername: function(e) { + e.preventDefault(); + + var user = this.props.user; + var username = this.state.username.trim(); + + var username_error = utils.isValidUsername(username); + if (username_error === "Cannot use a reserved word as a username.") { + this.setState({client_error: "This username is reserved, please choose a new one." }); + return; + } else if (username_error) { + this.setState({client_error: "Username must begin with a letter, and contain between 3 to 15 lowercase characters made up of numbers, letters, and the symbols '.', '-' and '_'." }); + return; + } + + if (user.username === username) { + this.setState({client_error: "You must submit a new username"}); + return; + } + + user.username = username; + + this.submitUser(user); + }, + submitName: function(e) { + e.preventDefault(); + + var user = UserStore.getCurrentUser(); + var firstName = this.state.first_name.trim(); + var lastName = this.state.last_name.trim(); + + var fullName = firstName + ' ' + lastName; + + if (user.full_name === fullName) { + this.setState({client_error: "You must submit a new name"}) + return; + } + + user.full_name = fullName; + + this.submitUser(user); + }, + submitEmail: function(e) { + e.preventDefault(); + + var user = UserStore.getCurrentUser(); + var email = this.state.email.trim().toLowerCase(); + + if (user.email === email) { + return; + } + + if (email === '' || !utils.isEmail(email)) { + this.setState({ email_error: "Please enter a valid email address" }); + return; + } + + user.email = email; + + this.submitUser(user); + }, + submitUser: function(user) { + client.updateUser(user, + function(data) { + this.updateSection(""); + AsyncClient.getMe(); + }.bind(this), + function(err) { + state = this.getInitialState(); + state.server_error = err; + this.setState(state); + }.bind(this) + ); + }, + submitPicture: function(e) { + e.preventDefault(); + + if (!this.state.picture) return; + + if(!this.submitActive) return; + + formData = new FormData(); + formData.append('image', this.state.picture, this.state.picture.name); + + client.uploadProfileImage(formData, + function(data) { + this.submitActive = false; + window.location.reload(); + }.bind(this), + function(err) { + state = this.getInitialState(); + state.server_error = err; + this.setState(state); + }.bind(this) + ); + }, + updateUsername: function(e) { + this.setState({ username: e.target.value }); + }, + updateFirstName: function(e) { + this.setState({ first_name: e.target.value }); + }, + updateLastName: function(e) { + this.setState({ last_name: e.target.value}); + }, + updateEmail: function(e) { + this.setState({ email: e.target.value}); + }, + updatePicture: function(e) { + if (e.target.files && e.target.files[0]) { + this.setState({ picture: e.target.files[0] }); + } else { + this.setState({ picture: null }); + } + + this.submitActive = true + }, + updateSection: function(section) { + this.setState({client_error:""}) + this.submitActive = false + this.props.updateSection(section); + }, + getInitialState: function() { + var user = this.props.user; + + var splitStr = user.full_name.split(' '); + var firstName = splitStr.shift(); + var lastName = splitStr.join(' '); + + return { username: user.username, first_name: firstName, last_name: lastName, + email: user.email, picture: null }; + }, + render: function() { + var user = this.props.user; + + var client_error = this.state.client_error ? this.state.client_error : null; + var server_error = this.state.server_error ? this.state.server_error : null; + var email_error = this.state.email_error ? this.state.email_error : null; + + var nameSection; + var self = this; + + if (this.props.activeSection === 'name') { + var inputs = []; + + inputs.push( +
+ +
+ +
+
+ ); + + inputs.push( +
+ +
+ +
+
+ ); + + nameSection = ( + + ); + } else { + nameSection = ( + + ); + } + + var usernameSection; + if (this.props.activeSection === 'username') { + var inputs = []; + + inputs.push( +
+ +
+ +
+
+ ); + + usernameSection = ( + + ); + } else { + usernameSection = ( + + ); + } + var emailSection; + if (this.props.activeSection === 'email') { + var inputs = []; + + inputs.push( +
+ +
+ +
+
+ ); + + emailSection = ( + + ); + } else { + emailSection = ( + + ); + } + + var pictureSection; + if (this.props.activeSection === 'picture') { + pictureSection = ( + + ); + + } else { + pictureSection = ( + + ); + } + return ( +
+
+ +

General Settings

+
+
+

General Settings

+
+ {nameSection} +
+ {usernameSection} +
+ {emailSection} +
+ {pictureSection} +
+
+
+ ); + } +}); + + +var AppearanceTab = React.createClass({ + submitTheme: function(e) { + e.preventDefault(); + var user = UserStore.getCurrentUser(); + if (!user.props) user.props = {}; + user.props.theme = this.state.theme; + + client.updateUser(user, + function(data) { + this.props.updateSection(""); + window.location.reload(); + }.bind(this), + function(err) { + state = this.getInitialState(); + state.server_error = err; + this.setState(state); + }.bind(this) + ); + }, + updateTheme: function(e) { + var hex = utils.rgb2hex(e.target.style.backgroundColor); + this.setState({ theme: hex.toLowerCase() }); + }, + componentDidMount: function() { + if (this.props.activeSection === "theme") { + $(this.refs[this.state.theme].getDOMNode()).addClass('active-border'); + } + }, + componentDidUpdate: function() { + if (this.props.activeSection === "theme") { + $('.color-btn').removeClass('active-border'); + $(this.refs[this.state.theme].getDOMNode()).addClass('active-border'); + } + }, + getInitialState: function() { + var user = UserStore.getCurrentUser(); + var theme = config.ThemeColors != null ? config.ThemeColors[0] : "#2389d7"; + if (user.props && user.props.theme) { + theme = user.props.theme; + } + return { theme: theme.toLowerCase() }; + }, + render: function() { + var server_error = this.state.server_error ? this.state.server_error : null; + + + var themeSection; + var self = this; + + if (config.ThemeColors != null) { + if (this.props.activeSection === 'theme') { + var theme_buttons = []; + + for (var i = 0; i < config.ThemeColors.length; i++) { + theme_buttons.push( +

Appearance Settings

+
+
+

Appearance Settings

+
+ {themeSection} +
+
+
+ ); + } +}); + +module.exports = React.createClass({ + componentDidMount: function() { + UserStore.addChangeListener(this._onChange); + }, + componentWillUnmount: function() { + UserStore.removeChangeListener(this._onChange); + }, + _onChange: function () { + var user = UserStore.getCurrentUser(); + if (!utils.areStatesEqual(this.state.user, user)) { + this.setState({ user: user }); + } + }, + getInitialState: function() { + return { user: UserStore.getCurrentUser() }; + }, + render: function() { + if (this.props.activeTab === 'general') { + return ( +
+ +
+ ); + } else if (this.props.activeTab === 'security') { + return ( +
+ +
+ ); + } else if (this.props.activeTab === 'notifications') { + return ( +
+ +
+ ); + } else if (this.props.activeTab === 'sessions') { + return ( +
+ +
+ ); + } else if (this.props.activeTab === 'activity_log') { + return ( +
+ +
+ ); + } else if (this.props.activeTab === 'appearance') { + return ( +
+ +
+ ); + } else { + return
; + } + } +}); -- cgit v1.2.3-1-g7c22