diff --git a/src/skins/vector/css/molecules/RoomHeader.css b/src/skins/vector/css/molecules/RoomHeader.css
index 5519c14de5..e033d735cd 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 2b0aca3d0f..6511439cac 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 cc43b1cd01..47ac9cbeaf 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 =
+ }
header =
{ this.props.simpleHeader }
+ { cancel }
}
diff --git a/src/skins/vector/views/organisms/UserSettings.js b/src/skins/vector/views/organisms/UserSettings.js
index ab376ea476..5e1574f185 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}
-
-
-
-
-
-
+
+
+
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 0553c25a1c..8083902ce7 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: