// 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) }
Time Action IP Address Session Other 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
; } } });