Start on editing groups

pull/21833/head
David Baker 2017-07-13 18:41:51 +01:00
parent ce0f9e8803
commit 381f685013
2 changed files with 189 additions and 54 deletions

View File

@ -212,7 +212,20 @@ export default React.createClass({
}, },
_onSettingsClick: function() { _onSettingsClick: function() {
this.setState({editing: true}); this.setState({
editing: true,
profileForm: Object.assign({}, this.state.summary.profile),
});
},
_onCancelClick: function() {
this.setState({
editing: false,
profileForm: null,
});
},
_onSaveClick: function() {
}, },
_getFeaturedRoomsNode() { _getFeaturedRoomsNode() {
@ -295,61 +308,162 @@ export default React.createClass({
const GroupAvatar = sdk.getComponent("avatars.GroupAvatar"); const GroupAvatar = sdk.getComponent("avatars.GroupAvatar");
const Loader = sdk.getComponent("elements.Spinner"); const Loader = sdk.getComponent("elements.Spinner");
const TintableSvg = sdk.getComponent("elements.TintableSvg"); const TintableSvg = sdk.getComponent("elements.TintableSvg");
const ChangeAvatar = sdk.getComponent("settings.ChangeAvatar");
if (this.state.summary === null && this.state.error === null) { if (this.state.summary === null && this.state.error === null) {
return <Loader />; return <Loader />;
} else if (this.state.editing) { } else if (false && this.state.editing) {
return <div />; const summary = this.state.summary;
const avatarEdit = (
<div className="mx_GroupView_avatarPicker">
<div onClick={this.onAvatarPickerClick}>
<ChangeAvatar ref={this._collectChangeAvatar}
groupId={this.props.groupId}
initialAvatarUrl={this.state.summary.profile.avatar_url}
setAvatar={false} onAvatar={this._onAvatarChange}
showUploadSection={false} width={48} height={48}
/>
</div>
<div className="mx_GroupView_avatarPicker_edit">
<label htmlFor="avatarInput" ref="file_label">
<img src="img/camera.svg"
alt={ _t("Upload avatar") } title={ _t("Upload avatar") }
width="17" height="15" />
</label>
<input id="avatarInput" className="mx_GroupView_uploadInput" type="file" onChange={this._onAvatarSelected}/>
</div>
</div>
);
return <div>
{avatarEdit}
<input type="text"
value={this.state.profileForm.name}
onChange={this._onNameChange}
placeholder={_t('Group Name')}
/>
<input type="text"
value={this.state.profileForm.short_description}
onChange={this._onShortDescChange}
placeholder={_t('Description')}
/>
<AccessibleButton className="mx_GroupView_saveButton" onClick={this._onSaveClick}>
{_t('Save')}
</AccessibleButton>
<AccessibleButton className='mx_GroupView_cancelButton' onClick={this._onCancelClick}>
<img src="img/cancel.svg" className='mx_filterFlipColor'
width="18" height="18" alt={_t("Cancel")}/>
</AccessibleButton>
<textarea value={this.state.profileForm.long_description}
onChange={this._onLongDescChange}
/>
</div>;
} else if (this.state.summary) { } else if (this.state.summary) {
const summary = this.state.summary; const summary = this.state.summary;
let description = null;
if (summary.profile && summary.profile.long_description) {
description = sanitizedHtmlNode(summary.profile.long_description);
}
const roomBody = <div>
<div className="mx_GroupView_groupDesc">{description}</div>
{this._getFeaturedRoomsNode()}
{this._getFeaturedUsersNode()}
</div>;
let avatarNode;
let nameNode; let nameNode;
let shortDescNode;
let rightButtons;
let roomBody;
if (this.state.editing) {
avatarNode = (
<div className="mx_GroupView_avatarPicker">
<div onClick={this.onAvatarPickerClick}>
<ChangeAvatar ref={this._collectChangeAvatar}
groupId={this.props.groupId}
initialAvatarUrl={this.state.summary.profile.avatar_url}
setAvatar={false} onAvatar={this._onAvatarChange}
showUploadSection={false} width={48} height={48}
/>
</div>
<div className="mx_GroupView_avatarPicker_edit">
<label htmlFor="avatarInput" ref="file_label">
<img src="img/camera.svg"
alt={ _t("Upload avatar") } title={ _t("Upload avatar") }
width="17" height="15" />
</label>
<input id="avatarInput" className="mx_GroupView_uploadInput" type="file" onChange={this._onAvatarSelected}/>
</div>
</div>
);
nameNode = <input type="text"
value={this.state.profileForm.name}
onChange={this._onNameChange}
placeholder={_t('Group Name')}
/>
shortDescNode = <input type="text"
value={this.state.profileForm.short_description}
onChange={this._onShortDescChange}
placeholder={_t('Description')}
/>
roomBody = <div>
<textarea value={this.state.profileForm.long_description}
onChange={this._onLongDescChange}
/>
</div>;
rightButtons = <div>
<AccessibleButton className="mx_GroupView_saveButton" onClick={this._onSaveClick}>
{_t('Save')}
</AccessibleButton>
<AccessibleButton className='mx_GroupView_cancelButton' onClick={this._onCancelClick}>
<img src="img/cancel.svg" className='mx_filterFlipColor'
width="18" height="18" alt={_t("Cancel")}/>
</AccessibleButton>
</div>;
} else {
const groupAvatarUrl = summary.profile ? summary.profile.avatar_url : null;
avatarNode = <GroupAvatar
groupId={this.props.groupId}
groupAvatarUrl={groupAvatarUrl}
width={48} height={48}
/>;
if (summary.profile && summary.profile.name) { if (summary.profile && summary.profile.name) {
nameNode = <div className="mx_RoomHeader_name"> nameNode = <div>
<span>{summary.profile.name}</span> <span>{summary.profile.name}</span>
<span className="mx_GroupView_header_groupid"> <span className="mx_GroupView_header_groupid">
({this.props.groupId}) ({this.props.groupId})
</span> </span>
</div>; </div>;
} else { } else {
nameNode = <div className="mx_RoomHeader_name"> nameNode = <span>{this.props.groupId}</span>;
<span>{this.props.groupId}</span> }
shortDescNode = <div className="mx_RoomHeader_topic">
{summary.profile.short_description}
</div>; </div>;
let description = null;
if (summary.profile && summary.profile.long_description) {
description = sanitizedHtmlNode(summary.profile.long_description);
}
roomBody = <div>
<div className="mx_GroupView_groupDesc">{description}</div>
{this._getFeaturedRoomsNode()}
{this._getFeaturedUsersNode()}
</div>;
rightButtons = <AccessibleButton className="mx_RoomHeader_button" onClick={this._onSettingsClick} title={_t("Settings")}>
<TintableSvg src="img/icons-settings-room.svg" width="16" height="16"/>
</AccessibleButton>;
} }
const groupAvatarUrl = summary.profile ? summary.profile.avatar_url : null;
// settings button is display: none until settings is wired up
return ( return (
<div className="mx_GroupView"> <div className="mx_GroupView">
<div className="mx_RoomHeader"> <div className="mx_GroupView_header">
<div className="mx_RoomHeader_wrapper"> <div className="mx_GroupView_header_leftCol">
<div className="mx_RoomHeader_avatar"> <div className="mx_GroupView_header_avatar">
<GroupAvatar {avatarNode}
groupId={this.props.groupId}
groupAvatarUrl={groupAvatarUrl}
width={48} height={48}
/>
</div> </div>
<div className="mx_RoomHeader_info"> <div className="mx_GroupView_header_info">
<div className="mx_GroupView_header_name">
{nameNode} {nameNode}
<div className="mx_RoomHeader_topic"> </div>
{summary.profile.short_description} <div className="mx_GroupView_header_shortDesc">
{shortDescNode}
</div> </div>
</div> </div>
<AccessibleButton className="mx_RoomHeader_button" onClick={this._onSettingsClick} title={_t("Settings")} style={{display: 'none'}}> </div>
<TintableSvg src="img/icons-settings-room.svg" width="16" height="16"/> <div className="mx_GroupView_header_rightCol">
</AccessibleButton> {rightButtons}
</div> </div>
</div> </div>
{roomBody} {roomBody}

View File

@ -24,11 +24,21 @@ module.exports = React.createClass({
propTypes: { propTypes: {
initialAvatarUrl: React.PropTypes.string, initialAvatarUrl: React.PropTypes.string,
room: React.PropTypes.object, room: React.PropTypes.object,
// if set, set initialAvatarUrl to the current avatar, if it has one
groupId: React.PropTypes.string,
// if false, you need to call changeAvatar.onFileSelected yourself. // if false, you need to call changeAvatar.onFileSelected yourself.
showUploadSection: React.PropTypes.bool, showUploadSection: React.PropTypes.bool,
width: React.PropTypes.number, width: React.PropTypes.number,
height: React.PropTypes.number, height: React.PropTypes.number,
className: React.PropTypes.string className: React.PropTypes.string,
// If true, set the room / user avatar once the image is uploaded.
// Ignored for groups.
setAvatar: React.PropTypes.bool,
// Called after the avatar is uploaded
onAvatar: React.PropTypes.func,
}, },
Phases: { Phases: {
@ -43,6 +53,7 @@ module.exports = React.createClass({
className: "", className: "",
width: 80, width: 80,
height: 80, height: 80,
setAvatar: true,
}; };
}, },
@ -72,6 +83,10 @@ module.exports = React.createClass({
var self = this; var self = this;
var httpPromise = MatrixClientPeg.get().uploadContent(file).then(function(url) { var httpPromise = MatrixClientPeg.get().uploadContent(file).then(function(url) {
newUrl = url; newUrl = url;
if (this.props.onAvatar) {
this.props.onAvatar(url);
}
if (this.props.setAvatar) {
if (self.props.room) { if (self.props.room) {
return MatrixClientPeg.get().sendStateEvent( return MatrixClientPeg.get().sendStateEvent(
self.props.room.roomId, self.props.room.roomId,
@ -82,6 +97,7 @@ module.exports = React.createClass({
} else { } else {
return MatrixClientPeg.get().setAvatarUrl(url); return MatrixClientPeg.get().setAvatarUrl(url);
} }
}
}); });
httpPromise.done(function() { httpPromise.done(function() {
@ -111,20 +127,25 @@ module.exports = React.createClass({
}, },
render: function() { render: function() {
var avatarImg; let avatarImg;
// Having just set an avatar we just display that since it will take a little // Having just set an avatar we just display that since it will take a little
// time to propagate through to the RoomAvatar. // time to propagate through to the RoomAvatar.
if (this.props.room && !this.avatarSet) { if (this.props.room && !this.avatarSet) {
var RoomAvatar = sdk.getComponent('avatars.RoomAvatar'); const RoomAvatar = sdk.getComponent('avatars.RoomAvatar');
avatarImg = <RoomAvatar room={this.props.room} width={ this.props.width } height={ this.props.height } resizeMethod='crop' />; avatarImg = <RoomAvatar room={this.props.room} width={ this.props.width } height={ this.props.height } resizeMethod='crop' />;
} else if (this.props.groupId) {
const GroupAvatar = sdk.getComponent('avatars.GroupAvatar');
avatarImg = <GroupAvatar groupId={this.props.groupId} groupAvatarUrl={this.props.initialAvatarUrl}
width={this.props.width} height={this.props.height} resizeMethod='crop'
/>;
} else { } else {
var BaseAvatar = sdk.getComponent("avatars.BaseAvatar"); const BaseAvatar = sdk.getComponent("avatars.BaseAvatar");
// XXX: FIXME: once we track in the JS what our own displayname is(!) then use it here rather than ? // XXX: FIXME: once we track in the JS what our own displayname is(!) then use it here rather than ?
avatarImg = <BaseAvatar width={this.props.width} height={this.props.height} resizeMethod='crop' avatarImg = <BaseAvatar width={this.props.width} height={this.props.height} resizeMethod='crop'
name='?' idName={ MatrixClientPeg.get().getUserIdLocalpart() } url={this.state.avatarUrl} />; name='?' idName={ MatrixClientPeg.get().getUserIdLocalpart() } url={this.state.avatarUrl} />;
} }
var uploadSection; let uploadSection;
if (this.props.showUploadSection) { if (this.props.showUploadSection) {
uploadSection = ( uploadSection = (
<div className={this.props.className}> <div className={this.props.className}>
@ -147,7 +168,7 @@ module.exports = React.createClass({
</div> </div>
); );
case this.Phases.Uploading: case this.Phases.Uploading:
var Loader = sdk.getComponent("elements.Spinner"); const Loader = sdk.getComponent("elements.Spinner");
return ( return (
<Loader /> <Loader />
); );