mirror of https://github.com/vector-im/riot-web
Start on editing groups
parent
ce0f9e8803
commit
381f685013
|
@ -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}
|
||||||
|
|
|
@ -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 />
|
||||||
);
|
);
|
||||||
|
|
Loading…
Reference in New Issue