experiment with trying to turn UserSettings into a controller-less 'wiring component' which wires together a series of smaller components (in this case, so small they're mainly <input/s>
This commit is contained in:
parent
88c5a5e074
commit
7b3eea0b58
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -48,10 +48,15 @@ module.exports = React.createClass({
|
|||
|
||||
var header;
|
||||
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 =
|
||||
<div className="mx_RoomHeader_wrapper">
|
||||
<div className="mx_RoomHeader_simpleHeader">
|
||||
{ this.props.simpleHeader }
|
||||
{ cancel }
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
|
|
@ -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 <Loader />
|
||||
case this.Phases.Saving:
|
||||
saving = <Loader />
|
||||
case this.Phases.Display:
|
||||
var ChangeDisplayName = sdk.getComponent('molecules.ChangeDisplayName');
|
||||
var EnableNotificationsButton = sdk.getComponent('atoms.EnableNotificationsButton');
|
||||
var RoomHeader = sdk.getComponent('molecules.RoomHeader');
|
||||
return (
|
||||
<div className="mx_UserSettings">
|
||||
<div className="mx_UserSettings_User">
|
||||
<h1>User Settings</h1>
|
||||
<hr/>
|
||||
<div className="mx_UserSettings_User_Inner">
|
||||
<div className="mx_UserSettings_Avatar">
|
||||
<div className="mx_UserSettings_Avatar_Text">Profile Photo</div>
|
||||
<div className="mx_UserSettings_Avatar_Edit" onClick={this.editAvatar}>Edit</div>
|
||||
<RoomHeader simpleHeader="Settings" onCancelClick={ this.onClose } />
|
||||
|
||||
<h2>Profile</h2>
|
||||
|
||||
<div className="mx_UserSettings_section">
|
||||
<div className="mx_UserSettings_profileTable">
|
||||
<div className="mx_UserSettings_profileTableRow">
|
||||
<div className="mx_UserSettings_profileLabelCell">
|
||||
<label htmlFor="displayName">Display name</label>
|
||||
</div>
|
||||
<div className="mx_UserSettings_profileInputCell">
|
||||
<input id="displayName" ref="displayName" value={ this.state.displayName } onChange={ this.onDisplayNameChange } />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mx_UserSettings_DisplayName">
|
||||
<ChangeDisplayName ref="displayname" />
|
||||
<div className="mx_UserSettings_DisplayName_Edit" onClick={this.editDisplayName}>Edit</div>
|
||||
{this.state.threepids.map(function(val) {
|
||||
var id = "email-" + val.address;
|
||||
return (
|
||||
<div className="mx_UserSettings_profileTableRow">
|
||||
<div className="mx_UserSettings_profileLabelCell">
|
||||
<label htmlFor={ id }>Email</label>
|
||||
</div>
|
||||
<div className="mx_UserSettings_profileInputCell">
|
||||
<input key={val.address} id={ id } value={ val.address } disabled />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
|
||||
<div className="mx_UserSettings_profileTableRow">
|
||||
<div className="mx_UserSettings_profileLabelCell">
|
||||
<label htmlFor="password1">New password</label>
|
||||
</div>
|
||||
<div className="mx_UserSettings_profileInputCell">
|
||||
<input id="password1" ref="password1" value={ this.state.password1 } />
|
||||
</div>
|
||||
</div>
|
||||
<div className="mx_UserSettings_profileTableRow">
|
||||
<div className="mx_UserSettings_profileLabelCell">
|
||||
<label htmlFor="password2">Confirm new password</label>
|
||||
</div>
|
||||
<div className="mx_UserSettings_profileInputCell">
|
||||
<input id="password2" ref="password2" value={ this.state.password2 } />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mx_UserSettings_3pids">
|
||||
{this.state.threepids.map(function(val) {
|
||||
return <div key={val.address}>{val.address}</div>;
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mx_UserSettings_Add3pid" onClick={this.addEmail}>Add email</div>
|
||||
<div className="mx_UserSettings_avatarPicker">
|
||||
<div className="mx_UserSettings_avatarPicker_edit" onClick={this.editAvatar}></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mx_UserSettings_Global">
|
||||
<h1>Global Settings</h1>
|
||||
<hr/>
|
||||
<div className="mx_UserSettings_Global_Inner">
|
||||
<div className="mx_UserSettings_ChangePassword" onClick={this.changePassword}>
|
||||
Change Password
|
||||
</div>
|
||||
<div className="mx_UserSettings_ClientVersion">
|
||||
Version {this.state.clientVersion}
|
||||
</div>
|
||||
<div className="mx_UserSettings_EnableNotifications">
|
||||
<EnableNotificationsButton />
|
||||
</div>
|
||||
<div className="mx_UserSettings_Logout">
|
||||
<button onClick={this.onLogoutClicked}>Sign Out</button>
|
||||
<div className="mx_UserSettings_logout">
|
||||
<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={ this.state.enableNotifications } onChange={ this.onEnableNotificationsChange } />
|
||||
</div>
|
||||
<div className="mx_UserSettings_notifLabelCell">
|
||||
<label htmlFor="enableNotifications">Enable desktop notifications</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h2>Advanced</h2>
|
||||
|
||||
<div className="mx_UserSettings_section">
|
||||
<div className="mx_UserSettings_advanced">
|
||||
Version {this.state.clientVersion}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mx_UserSettings_save">
|
||||
<div className="mx_UserSettings_spinner">{ saving }</div>
|
||||
<div className="mx_UserSettings_button" onClick={this.onSaveClicked}>Save and close</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -111,7 +111,7 @@ module.exports = React.createClass({
|
|||
right_panel = <RightPanel roomId={this.state.currentRoom} collapsed={this.state.collapse_rhs} />
|
||||
break;
|
||||
case this.PageTypes.UserSettings:
|
||||
page_element = <UserSettings />
|
||||
page_element = <UserSettings roomId={this.state.currentRoom} />
|
||||
right_panel = <RightPanel collapsed={this.state.collapse_rhs}/>
|
||||
break;
|
||||
case this.PageTypes.CreateRoom:
|
||||
|
|
Loading…
Reference in New Issue