diff --git a/skins/base/views/organisms/UserSettings.js b/skins/base/views/organisms/UserSettings.js
new file mode 100644
index 0000000000..5bce0a036e
--- /dev/null
+++ b/skins/base/views/organisms/UserSettings.js
@@ -0,0 +1,97 @@
+/*
+Copyright 2015 OpenMarket Ltd
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+ http://www.apache.org/licenses/LICENSE-2.0
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+'use strict';
+
+var React = require('react');
+var ComponentBroker = require('../../../../src/ComponentBroker');
+var MatrixClientPeg = require("../../../../src/MatrixClientPeg");
+
+var UserSettingsController = require("../../../../src/controllers/organisms/UserSettings");
+
+var EditableText = ComponentBroker.get('atoms/EditableText');
+var ChangeAvatar = ComponentBroker.get('molecules/ChangeAvatar');
+var ChangePassword = ComponentBroker.get('molecules/ChangePassword');
+var Loader = require("react-loader");
+
+var Modal = require("../../../../src/Modal")
+
+module.exports = React.createClass({
+ displayName: 'UserSettings',
+ mixins: [UserSettingsController],
+
+ editAvatar: function() {
+ var url = MatrixClientPeg.get().mxcUrlToHttp(this.state.avatarUrl);
+ Modal.createDialog(ChangeAvatar, {initialAvatarUrl: url});
+ },
+
+ addEmail: function() {
+
+ },
+
+ editDisplayName: function() {
+ this.refs.displayname.edit();
+ },
+
+ changePassword: function() {
+ Modal.createDialog(ChangePassword);
+ },
+
+ render: function() {
+ switch (this.state.phase) {
+ case this.Phases.Loading:
+ return
+ case this.Phases.Display:
+ return (
+
+
+
User Settings
+
+
+
+
+
+
+
+ {this.state.threepids.map(function(val) {
+ return
{val.address}
;
+ })}
+
+
+
Add email
+
+
+
+
+
Global Settings
+
+
+
+ Change Password
+
+
+ Version {this.state.clientVersion}
+
+
+
+
+ );
+ }
+ }
+});
diff --git a/skins/base/views/pages/MatrixChat.js b/skins/base/views/pages/MatrixChat.js
index b9b5a1a946..27d1a1151a 100644
--- a/skins/base/views/pages/MatrixChat.js
+++ b/skins/base/views/pages/MatrixChat.js
@@ -23,6 +23,7 @@ var LeftPanel = ComponentBroker.get('organisms/LeftPanel');
var RoomView = ComponentBroker.get('organisms/RoomView');
var RightPanel = ComponentBroker.get('organisms/RightPanel');
var Login = ComponentBroker.get('templates/Login');
+var UserSettings = ComponentBroker.get('organisms/UserSettings');
var Register = ComponentBroker.get('templates/Register');
var MatrixChatController = require("../../../../src/controllers/pages/MatrixChat");
@@ -37,11 +38,24 @@ module.exports = React.createClass({
render: function() {
if (this.state.logged_in && this.state.ready) {
+
+ var page_element;
+ var right_panel = "";
+
+ if (this.state.page_type == this.PageTypes.RoomView) {
+ page_element =
+ right_panel =
+ } else if (this.state.page_type == this.PageTypes.UserSettings) {
+ page_element =
+ }
+
return (
-
-
+
+ {page_element}
+
+ {right_panel}
);
} else if (this.state.logged_in) {
@@ -63,4 +77,3 @@ module.exports = React.createClass({
}
}
});
-
diff --git a/src/ComponentBroker.js b/src/ComponentBroker.js
index 32587c628c..dfbcf2e217 100644
--- a/src/ComponentBroker.js
+++ b/src/ComponentBroker.js
@@ -89,6 +89,9 @@ require('../skins/base/views/templates/Register');
require('../skins/base/views/organisms/Notifier');
require('../skins/base/views/organisms/CreateRoom');
require('../skins/base/views/molecules/UserSelector');
+require('../skins/base/views/organisms/UserSettings');
+require('../skins/base/views/molecules/ChangeAvatar');
+require('../skins/base/views/molecules/ChangePassword');
// new for vector
require('../skins/base/views/organisms/LeftPanel');
require('../skins/base/views/organisms/RightPanel');
diff --git a/src/Modal.js b/src/Modal.js
new file mode 100644
index 0000000000..ca11a2101b
--- /dev/null
+++ b/src/Modal.js
@@ -0,0 +1,58 @@
+/*
+Copyright 2015 OpenMarket Ltd
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+
+'use strict';
+
+var React = require('react');
+var q = require('q');
+
+module.exports = {
+ DialogContainerId: "mx_Dialog_Container",
+
+ getOrCreateContainer: function() {
+ var container = document.getElementById(this.DialogContainerId);
+
+ if (!container) {
+ container = document.createElement("div");
+ container.id = this.DialogContainerId;
+ document.body.appendChild(container);
+ }
+
+ return container;
+ },
+
+ createDialog: function (Element, props) {
+ var self = this;
+
+ var closeDialog = function() {
+ React.unmountComponentAtNode(self.getOrCreateContainer());
+
+ if (props && props.onFinished) props.onFinished.apply(arguments);
+ };
+
+ var dialog = (
+
+ );
+
+ React.render(dialog, this.getOrCreateContainer());
+ },
+};
diff --git a/src/controllers/atoms/EditableText.js b/src/controllers/atoms/EditableText.js
index ac46973613..d9155a5cb9 100644
--- a/src/controllers/atoms/EditableText.js
+++ b/src/controllers/atoms/EditableText.js
@@ -22,6 +22,7 @@ module.exports = {
propTypes: {
onValueChanged: React.PropTypes.func,
initalValue: React.PropTypes.string,
+ placeHolder: React.PropTypes.string,
},
Phases: {
@@ -33,6 +34,7 @@ module.exports = {
return {
onValueChanged: function() {},
initalValue: '',
+ placeHolder: 'Click to set',
};
},
@@ -51,9 +53,13 @@ module.exports = {
this.setState({
value: val,
phase: this.Phases.Display,
- });
+ }, this.onValueChanged);
+ },
- this.onValueChanged();
+ edit: function() {
+ this.setState({
+ phase: this.Phases.Edit,
+ });
},
cancelEdit: function() {
diff --git a/src/controllers/molecules/ChangeAvatar.js b/src/controllers/molecules/ChangeAvatar.js
new file mode 100644
index 0000000000..2dd492b6e2
--- /dev/null
+++ b/src/controllers/molecules/ChangeAvatar.js
@@ -0,0 +1,52 @@
+/*
+Copyright 2015 OpenMarket Ltd
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+'use strict';
+
+var React = require('react');
+var MatrixClientPeg = require("../../MatrixClientPeg");
+
+var dis = require("../../dispatcher");
+
+module.exports = {
+ propTypes: {
+ onFinished: React.PropTypes.func,
+ initialAvatarUrl: React.PropTypes.string.isRequired,
+ },
+
+ Phases: {
+ Display: "display",
+ Uploading: "uploading",
+ Error: "error",
+ },
+
+ getDefaultProps: function() {
+ return {
+ onFinished: function() {},
+ };
+ },
+
+ getInitialState: function() {
+ return {
+ avatarUrl: this.props.initialAvatarUrl,
+ phase: this.Phases.Display,
+ }
+ },
+
+ uploadNewAvatar: function() {
+
+ },
+}
diff --git a/src/controllers/molecules/ChangePassword.js b/src/controllers/molecules/ChangePassword.js
new file mode 100644
index 0000000000..5cc73c5def
--- /dev/null
+++ b/src/controllers/molecules/ChangePassword.js
@@ -0,0 +1,78 @@
+/*
+Copyright 2015 OpenMarket Ltd
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+'use strict';
+
+var React = require('react');
+var MatrixClientPeg = require("../../MatrixClientPeg");
+
+var dis = require("../../dispatcher");
+
+module.exports = {
+ propTypes: {
+ onFinished: React.PropTypes.func,
+ },
+
+ Phases: {
+ Edit: "edit",
+ Uploading: "uploading",
+ Error: "error",
+ Success: "Success"
+ },
+
+ getDefaultProps: function() {
+ return {
+ onFinished: function() {},
+ };
+ },
+
+ getInitialState: function() {
+ return {
+ phase: this.Phases.Edit,
+ errorString: ''
+ }
+ },
+
+ changePassword: function(old_password, new_password) {
+ var cli = MatrixClientPeg.get();
+
+ var authDict = {
+ type: 'm.login.password',
+ user: cli.credentials.userId,
+ password: old_password
+ };
+
+ this.setState({
+ phase: this.Phases.Uploading,
+ errorString: '',
+ })
+
+ var d = cli.setPassword(authDict, new_password);
+
+ var self = this;
+ d.then(function() {
+ self.setState({
+ phase: self.Phases.Success,
+ errorString: '',
+ })
+ }, function(err) {
+ self.setState({
+ phase: self.Phases.Error,
+ errorString: err.toString()
+ })
+ });
+ },
+}
diff --git a/src/controllers/organisms/UserSettings.js b/src/controllers/organisms/UserSettings.js
new file mode 100644
index 0000000000..80056b2366
--- /dev/null
+++ b/src/controllers/organisms/UserSettings.js
@@ -0,0 +1,82 @@
+/*
+Copyright 2015 OpenMarket Ltd
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+'use strict';
+
+var MatrixClientPeg = require("../../MatrixClientPeg");
+var React = require("react");
+var q = require('q');
+var dis = require("../../dispatcher");
+var version = require('../../../package.json').version;
+
+var ComponentBroker = require('../../ComponentBroker');
+
+module.exports = {
+ Phases: {
+ Loading: "loading",
+ Display: "display",
+ },
+
+ getInitialState: function() {
+ return {
+ displayName: null,
+ avatarUrl: null,
+ threePids: [],
+ clientVersion: version,
+ phase: this.Phases.Loading,
+ };
+ },
+
+ changeDisplayname: function(new_displayname) {
+ if (this.state.displayName == new_displayname) return;
+
+ var self = this;
+ return MatrixClientPeg.get().setDisplayName(new_displayname).then(
+ function() { self.setState({displayName: new_displayname}); },
+ function(err) { console.err(err); }
+ );
+ },
+
+ changeAvatarUrl: function(new_avatar_url) {
+ if (this.state.avatarUrl == new_avatar_url) return;
+
+ var self = this;
+ return MatrixClientPeg.get().setAvatarUrl(new_avatar_url).then(
+ function() { self.setState({displayName: new_displayname}); },
+ function(err) { console.err(err); }
+ );
+ },
+
+ componentWillMount: function() {
+ var self = this;
+ var cli = MatrixClientPeg.get();
+
+ var profile_d = cli.getProfileInfo(cli.credentials.userId);
+ var threepid_d = cli.getThreePids();
+
+ q.all([profile_d, threepid_d]).then(
+ function(resps) {
+ self.setState({
+ displayName: resps[0].displayname,
+ avatarUrl: resps[0].avatar_url,
+ threepids: resps[1].threepids,
+ phase: self.Phases.Display,
+ });
+ },
+ function(err) { console.err(err); }
+ );
+ },
+}
diff --git a/src/controllers/pages/MatrixChat.js b/src/controllers/pages/MatrixChat.js
index 44a4df0752..9367872b2a 100644
--- a/src/controllers/pages/MatrixChat.js
+++ b/src/controllers/pages/MatrixChat.js
@@ -29,10 +29,16 @@ var ComponentBroker = require('../../ComponentBroker');
var Notifier = ComponentBroker.get('organisms/Notifier');
module.exports = {
+ PageTypes: {
+ RoomView: "room_view",
+ UserSettings: "user_settings",
+ },
+
getInitialState: function() {
return {
logged_in: !!(MatrixClientPeg.get() && MatrixClientPeg.get().credentials),
- ready: false
+ ready: false,
+ page_type: this.PageTypes.RoomView,
};
},
@@ -110,7 +116,8 @@ module.exports = {
case 'view_room':
this.focusComposer = true;
this.setState({
- currentRoom: payload.room_id
+ currentRoom: payload.room_id,
+ page_type: this.PageTypes.RoomView,
});
break;
case 'view_prev_room':
@@ -131,6 +138,11 @@ module.exports = {
currentRoom: allRooms[roomIndex].roomId
});
break;
+ case 'view_user_settings':
+ this.setState({
+ page_type: this.PageTypes.UserSettings,
+ });
+ break;
}
},
@@ -199,4 +211,3 @@ module.exports = {
}
}
};
-