Merge pull request #33 from matrix-org/matthew/settings
WIP experiment of turning UserSettings controller into UserSettingsStorepull/21833/head
commit
b941904078
|
@ -0,0 +1,67 @@
|
||||||
|
/*
|
||||||
|
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 Notifier = require("./Notifier");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TODO: Make things use this. This is all WIP - see UserSettings.js for usage.
|
||||||
|
*/
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
|
||||||
|
loadProfileInfo: function() {
|
||||||
|
var cli = MatrixClientPeg.get();
|
||||||
|
return cli.getProfileInfo(cli.credentials.userId);
|
||||||
|
},
|
||||||
|
|
||||||
|
saveDisplayName: function(newDisplayname) {
|
||||||
|
return MatrixClientPeg.get().setDisplayName(newDisplayname);
|
||||||
|
},
|
||||||
|
|
||||||
|
loadThreePids: function() {
|
||||||
|
return MatrixClientPeg.get().getThreePids();
|
||||||
|
},
|
||||||
|
|
||||||
|
saveThreePids: function(threePids) {
|
||||||
|
// TODO
|
||||||
|
},
|
||||||
|
|
||||||
|
getEnableNotifications: function() {
|
||||||
|
return Notifier.isEnabled();
|
||||||
|
},
|
||||||
|
|
||||||
|
setEnableNotifications: function(enable) {
|
||||||
|
if (!Notifier.supportsDesktopNotifications()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Notifier.setEnabled(enable);
|
||||||
|
},
|
||||||
|
|
||||||
|
changePassword: function(old_password, new_password) {
|
||||||
|
var cli = MatrixClientPeg.get();
|
||||||
|
|
||||||
|
var authDict = {
|
||||||
|
type: 'm.login.password',
|
||||||
|
user: cli.credentials.userId,
|
||||||
|
password: old_password
|
||||||
|
};
|
||||||
|
|
||||||
|
return cli.setPassword(authDict, new_password);
|
||||||
|
},
|
||||||
|
};
|
|
@ -628,6 +628,22 @@ module.exports = React.createClass({
|
||||||
this.showScreen("settings");
|
this.showScreen("settings");
|
||||||
},
|
},
|
||||||
|
|
||||||
|
onUserSettingsClose: function() {
|
||||||
|
// XXX: use browser history instead to find the previous room?
|
||||||
|
if (this.state.currentRoom) {
|
||||||
|
dis.dispatch({
|
||||||
|
action: 'view_room',
|
||||||
|
room_id: this.state.currentRoom,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
dis.dispatch({
|
||||||
|
action: 'view_indexed_room',
|
||||||
|
roomIndex: 0,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
render: function() {
|
render: function() {
|
||||||
var LeftPanel = sdk.getComponent('structures.LeftPanel');
|
var LeftPanel = sdk.getComponent('structures.LeftPanel');
|
||||||
var RoomView = sdk.getComponent('structures.RoomView');
|
var RoomView = sdk.getComponent('structures.RoomView');
|
||||||
|
@ -660,7 +676,7 @@ module.exports = React.createClass({
|
||||||
right_panel = <RightPanel roomId={this.state.currentRoom} collapsed={this.state.collapse_rhs} />
|
right_panel = <RightPanel roomId={this.state.currentRoom} collapsed={this.state.collapse_rhs} />
|
||||||
break;
|
break;
|
||||||
case this.PageTypes.UserSettings:
|
case this.PageTypes.UserSettings:
|
||||||
page_element = <UserSettings />
|
page_element = <UserSettings onClose={this.onUserSettingsClose} />
|
||||||
right_panel = <RightPanel collapsed={this.state.collapse_rhs}/>
|
right_panel = <RightPanel collapsed={this.state.collapse_rhs}/>
|
||||||
break;
|
break;
|
||||||
case this.PageTypes.CreateRoom:
|
case this.PageTypes.CreateRoom:
|
||||||
|
|
|
@ -17,14 +17,22 @@ var React = require('react');
|
||||||
var sdk = require('../../index');
|
var sdk = require('../../index');
|
||||||
var MatrixClientPeg = require("../../MatrixClientPeg");
|
var MatrixClientPeg = require("../../MatrixClientPeg");
|
||||||
var Modal = require('../../Modal');
|
var Modal = require('../../Modal');
|
||||||
|
var dis = require("../../dispatcher");
|
||||||
var q = require('q');
|
var q = require('q');
|
||||||
var version = require('../../../package.json').version;
|
var version = require('../../../package.json').version;
|
||||||
|
var UserSettingsStore = require('../../UserSettingsStore');
|
||||||
|
|
||||||
module.exports = React.createClass({
|
module.exports = React.createClass({
|
||||||
displayName: 'UserSettings',
|
displayName: 'UserSettings',
|
||||||
Phases: {
|
|
||||||
Loading: "loading",
|
propTypes: {
|
||||||
Display: "display",
|
onClose: React.PropTypes.func
|
||||||
|
},
|
||||||
|
|
||||||
|
getDefaultProps: function() {
|
||||||
|
return {
|
||||||
|
onClose: function() {}
|
||||||
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
getInitialState: function() {
|
getInitialState: function() {
|
||||||
|
@ -32,131 +40,227 @@ module.exports = React.createClass({
|
||||||
avatarUrl: null,
|
avatarUrl: null,
|
||||||
threePids: [],
|
threePids: [],
|
||||||
clientVersion: version,
|
clientVersion: version,
|
||||||
phase: this.Phases.Loading,
|
phase: "UserSettings.LOADING", // LOADING, DISPLAY
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
componentWillMount: function() {
|
componentWillMount: function() {
|
||||||
var self = this;
|
var self = this;
|
||||||
var cli = MatrixClientPeg.get();
|
this._refreshFromServer();
|
||||||
|
|
||||||
var profile_d = cli.getProfileInfo(cli.credentials.userId);
|
|
||||||
var threepid_d = cli.getThreePids();
|
|
||||||
|
|
||||||
q.all([profile_d, threepid_d]).then(
|
|
||||||
function(resps) {
|
|
||||||
self.setState({
|
|
||||||
avatarUrl: resps[0].avatar_url,
|
|
||||||
threepids: resps[1].threepids,
|
|
||||||
phase: self.Phases.Display,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
function(err) { console.err(err); }
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
editAvatar: function() {
|
componentDidMount: function() {
|
||||||
var url = MatrixClientPeg.get().mxcUrlToHttp(this.state.avatarUrl);
|
this.dispatcherRef = dis.register(this.onAction);
|
||||||
var ChangeAvatar = sdk.getComponent('settings.ChangeAvatar');
|
this._me = MatrixClientPeg.get().credentials.userId;
|
||||||
var avatarDialog = (
|
|
||||||
<div>
|
|
||||||
<ChangeAvatar initialAvatarUrl={url} />
|
|
||||||
<div className="mx_Dialog_buttons">
|
|
||||||
<button onClick={this.onAvatarDialogCancel}>Cancel</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
this.avatarDialog = Modal.createDialogWithElement(avatarDialog);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
addEmail: function() {
|
componentWillUnmount: function() {
|
||||||
|
dis.unregister(this.dispatcherRef);
|
||||||
},
|
},
|
||||||
|
|
||||||
editDisplayName: function() {
|
_refreshFromServer: function() {
|
||||||
this.refs.displayname.edit();
|
var self = this;
|
||||||
|
q.all([
|
||||||
|
UserSettingsStore.loadProfileInfo(), UserSettingsStore.loadThreePids()
|
||||||
|
]).done(function(resps) {
|
||||||
|
self.setState({
|
||||||
|
avatarUrl: resps[0].avatar_url,
|
||||||
|
threepids: resps[1].threepids,
|
||||||
|
phase: "UserSettings.DISPLAY",
|
||||||
|
});
|
||||||
|
}, function(error) {
|
||||||
|
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
||||||
|
Modal.createDialog(ErrorDialog, {
|
||||||
|
title: "Can't load user settings",
|
||||||
|
description: error.toString()
|
||||||
|
});
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
changePassword: function() {
|
onAction: function(payload) {
|
||||||
var ChangePassword = sdk.getComponent('settings.ChangePassword');
|
if (payload.action === "notifier_enabled") {
|
||||||
Modal.createDialog(ChangePassword);
|
this.forceUpdate();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
onAvatarSelected: function(ev) {
|
||||||
|
var self = this;
|
||||||
|
var changeAvatar = this.refs.changeAvatar;
|
||||||
|
if (!changeAvatar) {
|
||||||
|
console.error("No ChangeAvatar found to upload image to!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
changeAvatar.onFileSelected(ev).done(function() {
|
||||||
|
// dunno if the avatar changed, re-check it.
|
||||||
|
self._refreshFromServer();
|
||||||
|
}, function(err) {
|
||||||
|
var errMsg = (typeof err === "string") ? err : (err.error || "");
|
||||||
|
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
||||||
|
Modal.createDialog(ErrorDialog, {
|
||||||
|
title: "Error",
|
||||||
|
description: "Failed to set avatar. " + errMsg
|
||||||
|
});
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
onLogoutClicked: function(ev) {
|
onLogoutClicked: function(ev) {
|
||||||
var LogoutPrompt = sdk.getComponent('dialogs.LogoutPrompt');
|
var LogoutPrompt = sdk.getComponent('dialogs.LogoutPrompt');
|
||||||
this.logoutModal = Modal.createDialog(LogoutPrompt, {onCancel: this.onLogoutPromptCancel});
|
this.logoutModal = Modal.createDialog(
|
||||||
|
LogoutPrompt, {onCancel: this.onLogoutPromptCancel}
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
onPasswordChangeError: function(err) {
|
||||||
|
var errMsg = err.error || "";
|
||||||
|
if (err.httpStatus === 403) {
|
||||||
|
errMsg = "Failed to change password. Is your password correct?";
|
||||||
|
}
|
||||||
|
else if (err.httpStatus) {
|
||||||
|
errMsg += ` (HTTP status ${err.httpStatus})`;
|
||||||
|
}
|
||||||
|
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
||||||
|
Modal.createDialog(ErrorDialog, {
|
||||||
|
title: "Error",
|
||||||
|
description: errMsg
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
onPasswordChanged: function() {
|
||||||
|
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
||||||
|
Modal.createDialog(ErrorDialog, {
|
||||||
|
title: "Success",
|
||||||
|
description: `Your password was successfully changed. You will not
|
||||||
|
receive push notifications on other devices until you
|
||||||
|
log back in to them.`
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
onLogoutPromptCancel: function() {
|
onLogoutPromptCancel: function() {
|
||||||
this.logoutModal.closeDialog();
|
this.logoutModal.closeDialog();
|
||||||
},
|
},
|
||||||
|
|
||||||
onAvatarDialogCancel: function() {
|
onEnableNotificationsChange: function(event) {
|
||||||
this.avatarDialog.close();
|
UserSettingsStore.setEnableNotifications(event.target.checked);
|
||||||
},
|
},
|
||||||
|
|
||||||
render: function() {
|
render: function() {
|
||||||
var Loader = sdk.getComponent("elements.Spinner");
|
switch (this.state.phase) {
|
||||||
if (this.state.phase === this.Phases.Loading) {
|
case "UserSettings.LOADING":
|
||||||
return <Loader />
|
var Loader = sdk.getComponent("elements.Spinner");
|
||||||
|
return (
|
||||||
|
<Loader />
|
||||||
|
);
|
||||||
|
case "UserSettings.DISPLAY":
|
||||||
|
break; // quit the switch to return the common state
|
||||||
|
default:
|
||||||
|
throw new Error("Unknown state.phase => " + this.state.phase);
|
||||||
}
|
}
|
||||||
else if (this.state.phase === this.Phases.Display) {
|
// can only get here if phase is UserSettings.DISPLAY
|
||||||
var ChangeDisplayName = sdk.getComponent('settings.ChangeDisplayName');
|
var RoomHeader = sdk.getComponent('rooms.RoomHeader');
|
||||||
var EnableNotificationsButton = sdk.getComponent('settings.EnableNotificationsButton');
|
var ChangeDisplayName = sdk.getComponent("views.settings.ChangeDisplayName");
|
||||||
return (
|
var ChangePassword = sdk.getComponent("views.settings.ChangePassword");
|
||||||
|
var ChangeAvatar = sdk.getComponent('settings.ChangeAvatar');
|
||||||
|
var avatarUrl = (
|
||||||
|
this.state.avatarUrl ? MatrixClientPeg.get().mxcUrlToHttp(this.state.avatarUrl) : null
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
<div className="mx_UserSettings">
|
<div className="mx_UserSettings">
|
||||||
<div className="mx_UserSettings_User">
|
<RoomHeader simpleHeader="Settings" />
|
||||||
<h1>User Settings</h1>
|
|
||||||
<hr/>
|
<h2>Profile</h2>
|
||||||
<div className="mx_UserSettings_User_Inner">
|
|
||||||
<div className="mx_UserSettings_Avatar">
|
<div className="mx_UserSettings_section">
|
||||||
<div className="mx_UserSettings_Avatar_Text">
|
<div className="mx_UserSettings_profileTable">
|
||||||
Profile Photo
|
<div className="mx_UserSettings_profileTableRow">
|
||||||
|
<div className="mx_UserSettings_profileLabelCell">
|
||||||
|
<label htmlFor="displayName">Display name</label>
|
||||||
</div>
|
</div>
|
||||||
<div className="mx_UserSettings_Avatar_Edit" onClick={this.editAvatar}>
|
<div className="mx_UserSettings_profileInputCell">
|
||||||
Edit
|
<ChangeDisplayName />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="mx_UserSettings_DisplayName">
|
{this.state.threepids.map(function(val, pidIndex) {
|
||||||
<ChangeDisplayName ref="displayname" />
|
var id = "email-" + val.address;
|
||||||
<div className="mx_UserSettings_DisplayName_Edit" onClick={this.editDisplayName}>
|
return (
|
||||||
Edit
|
<div className="mx_UserSettings_profileTableRow" key={pidIndex}>
|
||||||
</div>
|
<div className="mx_UserSettings_profileLabelCell">
|
||||||
</div>
|
<label htmlFor={id}>Email</label>
|
||||||
|
</div>
|
||||||
|
<div className="mx_UserSettings_profileInputCell">
|
||||||
|
<input key={val.address} id={id} value={val.address} disabled />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
|
||||||
<div className="mx_UserSettings_3pids">
|
<div className="mx_UserSettings_avatarPicker">
|
||||||
{this.state.threepids.map(function(val) {
|
<ChangeAvatar ref="changeAvatar" initialAvatarUrl={avatarUrl}
|
||||||
return <div key={val.address}>{val.address}</div>;
|
showUploadSection={false} className="mx_UserSettings_avatarPicker_img"/>
|
||||||
})}
|
<div className="mx_UserSettings_avatarPicker_edit">
|
||||||
</div>
|
<label htmlFor="avatarInput">
|
||||||
|
<img src="img/upload.svg"
|
||||||
<div className="mx_UserSettings_Add3pid" onClick={this.addEmail}>
|
alt="Upload avatar" title="Upload avatar"
|
||||||
Add email
|
width="19" height="24" />
|
||||||
|
</label>
|
||||||
|
<input id="avatarInput" type="file" onChange={this.onAvatarSelected}/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="mx_UserSettings_Global">
|
<h2>Account</h2>
|
||||||
<h1>Global Settings</h1>
|
|
||||||
<hr/>
|
<div className="mx_UserSettings_section">
|
||||||
<div className="mx_UserSettings_Global_Inner">
|
<ChangePassword
|
||||||
<div className="mx_UserSettings_ChangePassword" onClick={this.changePassword}>
|
className="mx_UserSettings_accountTable"
|
||||||
Change Password
|
rowClassName="mx_UserSettings_profileTableRow"
|
||||||
</div>
|
rowLabelClassName="mx_UserSettings_profileLabelCell"
|
||||||
<div className="mx_UserSettings_ClientVersion">
|
rowInputClassName="mx_UserSettings_profileInputCell"
|
||||||
Version {this.state.clientVersion}
|
buttonClassName="mx_UserSettings_button"
|
||||||
</div>
|
onError={this.onPasswordChangeError}
|
||||||
<div className="mx_UserSettings_EnableNotifications">
|
onFinished={this.onPasswordChanged} />
|
||||||
<EnableNotificationsButton />
|
</div>
|
||||||
</div>
|
|
||||||
<div className="mx_UserSettings_Logout">
|
<div className="mx_UserSettings_logout">
|
||||||
<button onClick={this.onLogoutClicked}>Sign Out</button>
|
<div className="mx_UserSettings_button" onClick={this.onLogoutClicked}>
|
||||||
|
Log out
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h2>Notifications</h2>
|
||||||
|
|
||||||
|
<div className="mx_UserSettings_section">
|
||||||
|
<div className="mx_UserSettings_notifTable">
|
||||||
|
<div className="mx_UserSettings_notifTableRow">
|
||||||
|
<div className="mx_UserSettings_notifInputCell">
|
||||||
|
<input id="enableNotifications"
|
||||||
|
ref="enableNotifications"
|
||||||
|
type="checkbox"
|
||||||
|
checked={ UserSettingsStore.getEnableNotifications() }
|
||||||
|
onChange={ this.onEnableNotificationsChange } />
|
||||||
|
</div>
|
||||||
|
<div className="mx_UserSettings_notifLabelCell">
|
||||||
|
<label htmlFor="enableNotifications">
|
||||||
|
Enable desktop notifications
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<h2>Advanced</h2>
|
||||||
|
|
||||||
|
<div className="mx_UserSettings_section">
|
||||||
|
<div className="mx_UserSettings_advanced">
|
||||||
|
Logged in as {this._me}
|
||||||
|
</div>
|
||||||
|
<div className="mx_UserSettings_advanced">
|
||||||
|
Version {this.state.clientVersion}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -113,6 +113,10 @@ module.exports = React.createClass({
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
onBlur: function() {
|
||||||
|
this.cancelEdit();
|
||||||
|
},
|
||||||
|
|
||||||
render: function() {
|
render: function() {
|
||||||
var editable_el;
|
var editable_el;
|
||||||
|
|
||||||
|
@ -125,7 +129,8 @@ module.exports = React.createClass({
|
||||||
} else if (this.state.phase == this.Phases.Edit) {
|
} else if (this.state.phase == this.Phases.Edit) {
|
||||||
editable_el = (
|
editable_el = (
|
||||||
<div>
|
<div>
|
||||||
<input type="text" defaultValue={this.state.value} onKeyUp={this.onKeyUp} onFocus={this.onFocus} onBlur={this.onFinish} placeholder={this.props.placeHolder} autoFocus/>
|
<input type="text" defaultValue={this.state.value}
|
||||||
|
onKeyUp={this.onKeyUp} onFocus={this.onFocus} onBlur={this.onBlur} placeholder={this.props.placeHolder} autoFocus/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,10 +73,15 @@ module.exports = React.createClass({
|
||||||
|
|
||||||
var header;
|
var header;
|
||||||
if (this.props.simpleHeader) {
|
if (this.props.simpleHeader) {
|
||||||
|
var cancel;
|
||||||
|
if (this.props.onCancelClick) {
|
||||||
|
cancel = <img className="mx_RoomHeader_simpleHeaderCancel" src="img/cancel-black.png" onClick={ this.props.onCancelClick } alt="Close" width="18" height="18"/>
|
||||||
|
}
|
||||||
header =
|
header =
|
||||||
<div className="mx_RoomHeader_wrapper">
|
<div className="mx_RoomHeader_wrapper">
|
||||||
<div className="mx_RoomHeader_simpleHeader">
|
<div className="mx_RoomHeader_simpleHeader">
|
||||||
{ this.props.simpleHeader }
|
{ this.props.simpleHeader }
|
||||||
|
{ cancel }
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,9 @@ module.exports = React.createClass({
|
||||||
propTypes: {
|
propTypes: {
|
||||||
initialAvatarUrl: React.PropTypes.string,
|
initialAvatarUrl: React.PropTypes.string,
|
||||||
room: React.PropTypes.object,
|
room: React.PropTypes.object,
|
||||||
|
// if false, you need to call changeAvatar.onFileSelected yourself.
|
||||||
|
showUploadSection: React.PropTypes.bool,
|
||||||
|
className: React.PropTypes.string
|
||||||
},
|
},
|
||||||
|
|
||||||
Phases: {
|
Phases: {
|
||||||
|
@ -31,6 +34,13 @@ module.exports = React.createClass({
|
||||||
Error: "error",
|
Error: "error",
|
||||||
},
|
},
|
||||||
|
|
||||||
|
getDefaultProps: function() {
|
||||||
|
return {
|
||||||
|
showUploadSection: true,
|
||||||
|
className: "mx_Dialog_content" // FIXME - shouldn't be this by default
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
getInitialState: function() {
|
getInitialState: function() {
|
||||||
return {
|
return {
|
||||||
avatarUrl: this.props.initialAvatarUrl,
|
avatarUrl: this.props.initialAvatarUrl,
|
||||||
|
@ -55,7 +65,7 @@ module.exports = React.createClass({
|
||||||
phase: this.Phases.Uploading
|
phase: this.Phases.Uploading
|
||||||
});
|
});
|
||||||
var self = this;
|
var self = this;
|
||||||
MatrixClientPeg.get().uploadContent(file).then(function(url) {
|
var httpPromise = MatrixClientPeg.get().uploadContent(file).then(function(url) {
|
||||||
newUrl = url;
|
newUrl = url;
|
||||||
if (self.props.room) {
|
if (self.props.room) {
|
||||||
return MatrixClientPeg.get().sendStateEvent(
|
return MatrixClientPeg.get().sendStateEvent(
|
||||||
|
@ -67,7 +77,9 @@ module.exports = React.createClass({
|
||||||
} else {
|
} else {
|
||||||
return MatrixClientPeg.get().setAvatarUrl(url);
|
return MatrixClientPeg.get().setAvatarUrl(url);
|
||||||
}
|
}
|
||||||
}).done(function() {
|
});
|
||||||
|
|
||||||
|
httpPromise.done(function() {
|
||||||
self.setState({
|
self.setState({
|
||||||
phase: self.Phases.Display,
|
phase: self.Phases.Display,
|
||||||
avatarUrl: MatrixClientPeg.get().mxcUrlToHttp(newUrl)
|
avatarUrl: MatrixClientPeg.get().mxcUrlToHttp(newUrl)
|
||||||
|
@ -78,11 +90,13 @@ module.exports = React.createClass({
|
||||||
});
|
});
|
||||||
self.onError(error);
|
self.onError(error);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
return httpPromise;
|
||||||
},
|
},
|
||||||
|
|
||||||
onFileSelected: function(ev) {
|
onFileSelected: function(ev) {
|
||||||
this.avatarSet = true;
|
this.avatarSet = true;
|
||||||
this.setAvatarFromFile(ev.target.files[0]);
|
return this.setAvatarFromFile(ev.target.files[0]);
|
||||||
},
|
},
|
||||||
|
|
||||||
onError: function(error) {
|
onError: function(error) {
|
||||||
|
@ -106,19 +120,26 @@ module.exports = React.createClass({
|
||||||
avatarImg = <img src={this.state.avatarUrl} style={style} />;
|
avatarImg = <img src={this.state.avatarUrl} style={style} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var uploadSection;
|
||||||
|
if (this.props.showUploadSection) {
|
||||||
|
uploadSection = (
|
||||||
|
<div className={this.props.className}>
|
||||||
|
Upload new:
|
||||||
|
<input type="file" onChange={this.onFileSelected}/>
|
||||||
|
{this.state.errorText}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
switch (this.state.phase) {
|
switch (this.state.phase) {
|
||||||
case this.Phases.Display:
|
case this.Phases.Display:
|
||||||
case this.Phases.Error:
|
case this.Phases.Error:
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<div className="mx_Dialog_content">
|
<div className={this.props.className}>
|
||||||
{avatarImg}
|
{avatarImg}
|
||||||
</div>
|
</div>
|
||||||
<div className="mx_Dialog_content">
|
{uploadSection}
|
||||||
Upload new:
|
|
||||||
<input type="file" onChange={this.onFileSelected}/>
|
|
||||||
{this.state.errorText}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
case this.Phases.Uploading:
|
case this.Phases.Uploading:
|
||||||
|
|
|
@ -98,7 +98,9 @@ module.exports = React.createClass({
|
||||||
} else {
|
} else {
|
||||||
var EditableText = sdk.getComponent('elements.EditableText');
|
var EditableText = sdk.getComponent('elements.EditableText');
|
||||||
return (
|
return (
|
||||||
<EditableText ref="displayname_edit" initialValue={this.state.displayName} label="Click to set display name." onValueChanged={this.onValueChanged}/>
|
<EditableText ref="displayname_edit" initialValue={this.state.displayName}
|
||||||
|
label="Click to set display name."
|
||||||
|
onValueChanged={this.onValueChanged} />
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,30 +18,47 @@ limitations under the License.
|
||||||
|
|
||||||
var React = require('react');
|
var React = require('react');
|
||||||
var MatrixClientPeg = require("../../../MatrixClientPeg");
|
var MatrixClientPeg = require("../../../MatrixClientPeg");
|
||||||
|
var sdk = require("../../../index");
|
||||||
|
|
||||||
module.exports = React.createClass({
|
module.exports = React.createClass({
|
||||||
displayName: 'ChangePassword',
|
displayName: 'ChangePassword',
|
||||||
propTypes: {
|
propTypes: {
|
||||||
onFinished: React.PropTypes.func,
|
onFinished: React.PropTypes.func,
|
||||||
|
onError: React.PropTypes.func,
|
||||||
|
onCheckPassword: React.PropTypes.func,
|
||||||
|
rowClassName: React.PropTypes.string,
|
||||||
|
rowLabelClassName: React.PropTypes.string,
|
||||||
|
rowInputClassName: React.PropTypes.string,
|
||||||
|
buttonClassName: React.PropTypes.string
|
||||||
},
|
},
|
||||||
|
|
||||||
Phases: {
|
Phases: {
|
||||||
Edit: "edit",
|
Edit: "edit",
|
||||||
Uploading: "uploading",
|
Uploading: "uploading",
|
||||||
Error: "error",
|
Error: "error"
|
||||||
Success: "Success"
|
|
||||||
},
|
},
|
||||||
|
|
||||||
getDefaultProps: function() {
|
getDefaultProps: function() {
|
||||||
return {
|
return {
|
||||||
onFinished: function() {},
|
onFinished: function() {},
|
||||||
|
onError: function() {},
|
||||||
|
onCheckPassword: function(oldPass, newPass, confirmPass) {
|
||||||
|
if (newPass !== confirmPass) {
|
||||||
|
return {
|
||||||
|
error: "New passwords don't match."
|
||||||
|
};
|
||||||
|
} else if (!newPass || newPass.length === 0) {
|
||||||
|
return {
|
||||||
|
error: "Passwords can't be empty"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
getInitialState: function() {
|
getInitialState: function() {
|
||||||
return {
|
return {
|
||||||
phase: this.Phases.Edit,
|
phase: this.Phases.Edit
|
||||||
errorString: ''
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -55,60 +72,72 @@ module.exports = React.createClass({
|
||||||
};
|
};
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
phase: this.Phases.Uploading,
|
phase: this.Phases.Uploading
|
||||||
errorString: '',
|
});
|
||||||
})
|
|
||||||
|
|
||||||
var d = cli.setPassword(authDict, new_password);
|
|
||||||
|
|
||||||
var self = this;
|
var self = this;
|
||||||
d.then(function() {
|
cli.setPassword(authDict, new_password).then(function() {
|
||||||
self.setState({
|
self.props.onFinished();
|
||||||
phase: self.Phases.Success,
|
|
||||||
errorString: '',
|
|
||||||
})
|
|
||||||
}, function(err) {
|
}, function(err) {
|
||||||
|
self.props.onError(err);
|
||||||
|
}).finally(function() {
|
||||||
self.setState({
|
self.setState({
|
||||||
phase: self.Phases.Error,
|
phase: self.Phases.Edit
|
||||||
errorString: err.toString()
|
});
|
||||||
})
|
}).done();
|
||||||
});
|
|
||||||
},
|
},
|
||||||
|
|
||||||
onClickChange: function() {
|
onClickChange: function() {
|
||||||
var old_password = this.refs.old_input.value;
|
var old_password = this.refs.old_input.value;
|
||||||
var new_password = this.refs.new_input.value;
|
var new_password = this.refs.new_input.value;
|
||||||
var confirm_password = this.refs.confirm_input.value;
|
var confirm_password = this.refs.confirm_input.value;
|
||||||
if (new_password != confirm_password) {
|
var err = this.props.onCheckPassword(
|
||||||
this.setState({
|
old_password, new_password, confirm_password
|
||||||
state: this.Phases.Error,
|
);
|
||||||
errorString: "Passwords don't match"
|
if (err) {
|
||||||
});
|
this.props.onError(err);
|
||||||
} else if (new_password == '' || old_password == '') {
|
}
|
||||||
this.setState({
|
else {
|
||||||
state: this.Phases.Error,
|
|
||||||
errorString: "Passwords can't be empty"
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
this.changePassword(old_password, new_password);
|
this.changePassword(old_password, new_password);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
render: function() {
|
render: function() {
|
||||||
|
var rowClassName = this.props.rowClassName;
|
||||||
|
var rowLabelClassName = this.props.rowLabelClassName;
|
||||||
|
var rowInputClassName = this.props.rowInputClassName
|
||||||
|
var buttonClassName = this.props.buttonClassName;
|
||||||
|
|
||||||
switch (this.state.phase) {
|
switch (this.state.phase) {
|
||||||
case this.Phases.Edit:
|
case this.Phases.Edit:
|
||||||
case this.Phases.Error:
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div className={this.props.className}>
|
||||||
<div className="mx_Dialog_content">
|
<div className={rowClassName}>
|
||||||
<div>{this.state.errorString}</div>
|
<div className={rowLabelClassName}>
|
||||||
<div><label>Old password <input type="password" ref="old_input"/></label></div>
|
<label htmlFor="passwordold">Current password</label>
|
||||||
<div><label>New password <input type="password" ref="new_input"/></label></div>
|
</div>
|
||||||
<div><label>Confirm password <input type="password" ref="confirm_input"/></label></div>
|
<div className={rowInputClassName}>
|
||||||
|
<input id="passwordold" type="password" ref="old_input" />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="mx_Dialog_buttons">
|
<div className={rowClassName}>
|
||||||
<button onClick={this.onClickChange}>Change Password</button>
|
<div className={rowLabelClassName}>
|
||||||
<button onClick={this.props.onFinished}>Cancel</button>
|
<label htmlFor="password1">New password</label>
|
||||||
|
</div>
|
||||||
|
<div className={rowInputClassName}>
|
||||||
|
<input id="password1" type="password" ref="new_input" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className={rowClassName}>
|
||||||
|
<div className={rowLabelClassName}>
|
||||||
|
<label htmlFor="password2">Confirm password</label>
|
||||||
|
</div>
|
||||||
|
<div className={rowInputClassName}>
|
||||||
|
<input id="password2" type="password" ref="confirm_input" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className={buttonClassName} onClick={this.onClickChange}>
|
||||||
|
Change Password
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -119,17 +148,6 @@ module.exports = React.createClass({
|
||||||
<Loader />
|
<Loader />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
case this.Phases.Success:
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<div className="mx_Dialog_content">
|
|
||||||
Success!
|
|
||||||
</div>
|
|
||||||
<div className="mx_Dialog_buttons">
|
|
||||||
<button onClick={this.props.onFinished}>Ok</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue