diff --git a/src/skins/vector/css/molecules/RoomHeader.css b/src/skins/vector/css/molecules/RoomHeader.css index 5519c14de..e033d735c 100644 --- a/src/skins/vector/css/molecules/RoomHeader.css +++ b/src/skins/vector/css/molecules/RoomHeader.css @@ -94,7 +94,16 @@ limitations under the License. font-size: 24px; font-weight: bold; overflow: hidden; + margin-left: 63px; text-overflow: ellipsis; + width: 100%; +} + +.mx_RoomHeader_simpleHeaderCancel { + float: right; + margin-top: 8px; + padding: 24px; + cursor: pointer; } .mx_RoomHeader_name { diff --git a/src/skins/vector/css/organisms/UserSettings.css b/src/skins/vector/css/organisms/UserSettings.css index 2b0aca3d0..6511439ca 100644 --- a/src/skins/vector/css/organisms/UserSettings.css +++ b/src/skins/vector/css/organisms/UserSettings.css @@ -19,3 +19,101 @@ limitations under the License. margin-left: auto; margin-right: auto; } + +.mx_UserSettings_spinner { + display: inline-block; + vertical-align: middle; + margin-right: 12px; + width: 32px; + height: 32px; +} + +.mx_UserSettings_button { + display: inline; + vertical-align: middle; + border: 0px; + height: 36px; + border-radius: 36px; + font-weight: 400; + font-size: 16px; + color: #fff; + background-color: #76cfa6; + width: auto; + margin: auto; + padding: 7px; + padding-left: 1.5em; + padding-right: 1.5em; + cursor: pointer; +} + +.mx_UserSettings h2 { + clear: both; + margin-top: 32px; + margin-bottom: 8px; + margin-left: 63px; + padding-bottom: 6px; + border-bottom: 1px solid #eee; +} + +.mx_UserSettings_section { + margin-left: 63px; + margin-top: 28px; + margin-bottom: 28px; +} + +.mx_UserSettings_profileTable, +.mx_UserSettings_notifTable +{ + display: table; +} + +.mx_UserSettings_profileTableRow, +.mx_UserSettings_notifTableRow +{ + display: table-row; +} + +.mx_UserSettings_profileLabelCell +{ + padding-bottom: 21px; + display: table-cell; + font-weight: bold; + padding-right: 24px; +} + +.mx_UserSettings_profileInputCell { + display: table-cell; + padding-bottom: 21px; + width: 240px; +} + +.mx_UserSettings_profileInputCell input { + border: 0px; + border-bottom: 1px solid rgba(151, 151, 151, 0.5); + padding: 0px; + width: 240px; + color: rgba(74, 74, 74, 0.9); + font-family: 'Myriad Pro', Helvetica, Arial, Sans-Serif; + font-size: 16px; +} + +.mx_UserSettings_notifInputCell { + display: table-cell; + padding-bottom: 21px; + padding-right: 8px; + width: 16px; +} + +.mx_UserSettings_notifLabelCell +{ + padding-bottom: 21px; + width: 270px; + display: table-cell; +} + +.mx_UserSettings_logout, +.mx_UserSettings_save { + float: right; + margin-right: 24px; + margin-bottom: 24px; +} \ No newline at end of file diff --git a/src/skins/vector/views/molecules/RoomHeader.js b/src/skins/vector/views/molecules/RoomHeader.js index cc43b1cd0..47ac9cbea 100644 --- a/src/skins/vector/views/molecules/RoomHeader.js +++ b/src/skins/vector/views/molecules/RoomHeader.js @@ -48,10 +48,15 @@ module.exports = React.createClass({ var header; if (this.props.simpleHeader) { + var cancel; + if (this.props.onCancelClick) { + cancel = Close + } header =
{ this.props.simpleHeader } + { cancel }
} diff --git a/src/skins/vector/views/organisms/UserSettings.js b/src/skins/vector/views/organisms/UserSettings.js index ab376ea47..5e1574f18 100644 --- a/src/skins/vector/views/organisms/UserSettings.js +++ b/src/skins/vector/views/organisms/UserSettings.js @@ -15,15 +15,142 @@ limitations under the License. var React = require('react'); var sdk = require('matrix-react-sdk') +var dis = require('matrix-react-sdk/lib/dispatcher') var MatrixClientPeg = require('matrix-react-sdk/lib/MatrixClientPeg'); +var q = require('q'); -var UserSettingsController = require('matrix-react-sdk/lib/controllers/organisms/UserSettings') +var version = require('../../../../../package.json').version; var Modal = require('matrix-react-sdk/lib/Modal'); +var UserSettingsStore = require('matrix-react-sdk/lib/UserSettingsStore'); module.exports = React.createClass({ displayName: 'UserSettings', - mixins: [UserSettingsController], + + Phases: { + Loading: "loading", + Saving: "saving", + Display: "display", + }, + + getInitialState: function() { + return { + avatarUrl: null, + displayName: null, + threePids: [], + clientVersion: version, + phase: this.Phases.Loading, + }; + }, + + componentWillMount: function() { + var self = this; + + var profilePromise = UserSettingsStore.loadProfileInfo(); + var threepidPromise = UserSettingsStore.loadThreePids(); + + q.all([profilePromise, threepidPromise]).then( + function(resps) { + self.setState({ + avatarUrl: resps[0].avatar_url, + displayName: resps[0].displayname, + threepids: resps[1].threepids, + phase: self.Phases.Display, + }); + + // keep a copy of the original state in order to track changes + self.setState({ + originalState: self.state + }); + }, + function(error) { + var ErrorDialog = sdk.getComponent("organisms.ErrorDialog"); + Modal.createDialog(ErrorDialog, { + title: "Can't load user settings", + description: error.toString() + }); + } + ); + }, + + componentDidMount: function() { + this.dispatcherRef = dis.register(this.onAction); + }, + + componentWillUnmount: function() { + dis.unregister(this.dispatcherRef); + }, + + onSaveClicked: function(ev) { + var self = this; + var savePromises = []; + + // XXX: this is managed in ChangeAvatar.js, although could be moved out here in order + // to allow for the change to be staged alongside the rest of the form. + // + // if (this.state.originalState.avatarUrl !== this.state.avatarUrl) { + // savePromises.push( UserSettingsStore.saveAvatarUrl(this.state.avatarUrl) ); + // } + + if (this.state.originalState.displayName !== this.state.displayName) { + savePromises.push( UserSettingsStore.saveDisplayName(this.state.displayName) ); + } + + if (this.state.originalState.threepids.length !== this.state.threepids.length || + this.state.originalState.threepids.every(function(element, index) { + return element === this.state.threepids[index]; + })) + { + savePromises.push( UserSettingsStore.saveThreePids(this.state.threepids) ); + } + + self.setState({ + phase: self.Phases.Saving, + }); + + q.all(savePromises).then( + function(resps) { + self.setState({ + phase: self.Phases.Display, + }); + self.onClose(); + }, + function(error) { + self.setState({ + phase: self.Phases.Display, + }); + var ErrorDialog = sdk.getComponent("organisms.ErrorDialog"); + Modal.createDialog(ErrorDialog, { + title: "Can't save user settings", + description: error.toString() + }); + } + ); + }, + + onClose: function(ev) { + // XXX: use browser history instead to find the previous room? + if (this.props.roomId) { + dis.dispatch({ + action: 'view_room', + room_id: this.props.roomId, + }); + } + else { + dis.dispatch({ + action: 'view_indexed_room', + roomIndex: 0, + }); + } + }, + + onAction: function(payload) { + if (payload.action === "notifier_enabled") { + this.setState({ + enableNotifications : UserSettingsStore.getEnableNotifications() + }); + } + }, editAvatar: function() { var url = MatrixClientPeg.get().mxcUrlToHttp(this.state.avatarUrl); @@ -39,20 +166,11 @@ module.exports = React.createClass({ this.avatarDialog = Modal.createDialogWithElement(avatarDialog); }, - addEmail: function() { - + onAvatarDialogCancel: function() { + this.avatarDialog.close(); }, - editDisplayName: function() { - this.refs.displayname.edit(); - }, - - changePassword: function() { - var ChangePassword = sdk.getComponent('molecules.ChangePassword'); - Modal.createDialog(ChangePassword); - }, - - onLogoutClicked: function(ev) { + onLogoutClicked: function(event) { var LogoutPrompt = sdk.getComponent('organisms.LogoutPrompt'); this.logoutModal = Modal.createDialog(LogoutPrompt, {onCancel: this.onLogoutPromptCancel}); }, @@ -61,62 +179,115 @@ module.exports = React.createClass({ this.logoutModal.closeDialog(); }, - onAvatarDialogCancel: function() { - this.avatarDialog.close(); + onDisplayNameChange: function(event) { + this.setState({ displayName: event.target.value }); + }, + + onEnableNotificationsChange: function(event) { + // don't bother waiting for Save to be clicked, as that'd be silly + UserSettingsStore.setEnableNotifications( this.refs.enableNotifications.value ); + + this.setState({ + enableNotifications : UserSettingsStore.getEnableNotifications() + }); }, render: function() { - var Loader = sdk.getComponent("atoms.Spinner"); + var Loader = sdk.getComponent("atoms.Spinner"); + var saving; switch (this.state.phase) { case this.Phases.Loading: return + case this.Phases.Saving: + saving = case this.Phases.Display: - var ChangeDisplayName = sdk.getComponent('molecules.ChangeDisplayName'); - var EnableNotificationsButton = sdk.getComponent('atoms.EnableNotificationsButton'); + var RoomHeader = sdk.getComponent('molecules.RoomHeader'); return (
-
-

User Settings

-
-
-
-
Profile Photo
-
Edit
+ + +

Profile

+ +
+
+
+
+ +
+
+ +
-
- -
Edit
+ {this.state.threepids.map(function(val) { + var id = "email-" + val.address; + return ( +
+
+ +
+
+ +
+
+ ); + })} + +
+
+ +
+
+ +
+
+
+
+ +
+
+ +
-
- {this.state.threepids.map(function(val) { - return
{val.address}
; - })} -
+
-
Add email
+
+
-
-

Global Settings

-
-
-
- Change Password -
-
- Version {this.state.clientVersion} -
-
- -
-
- +
+
Log out
+
+ +

Notifications

+ +
+
+
+
+ +
+
+ +
+ +

Advanced

+ +
+
+ Version {this.state.clientVersion} +
+
+ +
+
{ saving }
+
Save and close
+
); } diff --git a/src/skins/vector/views/pages/MatrixChat.js b/src/skins/vector/views/pages/MatrixChat.js index 0553c25a1..8083902ce 100644 --- a/src/skins/vector/views/pages/MatrixChat.js +++ b/src/skins/vector/views/pages/MatrixChat.js @@ -111,7 +111,7 @@ module.exports = React.createClass({ right_panel = break; case this.PageTypes.UserSettings: - page_element = + page_element = right_panel = break; case this.PageTypes.CreateRoom: