Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor right panel header buttons #5117

Merged
merged 5 commits into from
Sep 25, 2017
Merged
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
165 changes: 93 additions & 72 deletions src/components/structures/RightPanel.js
Original file line number Diff line number Diff line change
@@ -17,17 +17,65 @@ limitations under the License.
*/

import React from 'react';
import PropTypes from 'prop-types';
import { _t } from 'matrix-react-sdk/lib/languageHandler';
import sdk from 'matrix-react-sdk';
import Matrix from "matrix-js-sdk";
import dis from 'matrix-react-sdk/lib/dispatcher';
import MatrixClientPeg from 'matrix-react-sdk/lib/MatrixClientPeg';
import Analytics from 'matrix-react-sdk/lib/Analytics';
import rate_limited_func from 'matrix-react-sdk/lib/ratelimitedfunc';
import Modal from 'matrix-react-sdk/lib/Modal';
import AccessibleButton from 'matrix-react-sdk/lib/components/views/elements/AccessibleButton';
import { showGroupInviteDialog } from 'matrix-react-sdk/lib/GroupInvite';

class HeaderButton extends React.Component {
constructor() {
super();
this.onClick = this.onClick.bind(this);
}

onClick(ev) {
Analytics.trackEvent(...this.props.analytics);
dis.dispatch({
action: 'view_right_panel_phase',
phase: this.props.clickPhase,
});
}

render() {
const TintableSvg = sdk.getComponent("elements.TintableSvg");
const AccessibleButton = sdk.getComponent("elements.AccessibleButton");
const isHighlighted = this.props.phases.includes(this.props.currentPhase);

return <AccessibleButton
className="mx_RightPanel_headerButton"
key={this.props.key}
onClick={ this.onClick }
>
<div className="mx_RightPanel_headerButton_badge">
{ this.props.badge ? this.props.badge : <span>&nbsp;</span>}
</div>
<TintableSvg src={this.props.iconSrc} width="25" height="25"/>
{ isHighlighted ? <div className="mx_RightPanel_headerButton_highlight"></div> : <div/> }
</AccessibleButton>;
}
}

HeaderButton.propTypes = {
// If currentPhase is one of the specified phases, the button will be highlighted
phases: PropTypes.arrayOf(PropTypes.string).isRequired,
// The currentPhase of the RightPanel
currentPhase: PropTypes.string.isRequired,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there likely to be any need for the button to know the actual phases it represents or what the current phase is? Could we just pass in whether it should be highlighted or not?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we just pass in whether it should be highlighted or not?

I was hoping to abstract this logic away such that, for example, we can't get two buttons highlighted at once. It's probably overkill but if every single header button is going to embody this logic, it seems inefficient to dupe it for each one.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, it needs to know for the dispatch so 🤷‍♂️

// The phase to swap to when the button is clicked
clickPhase: PropTypes.string.isRequired,
// The source file of the icon to display
iconSrc: PropTypes.string.isRequired,

// The badge to display above the icon
badge: PropTypes.node,
// The parameters to track the click event
analytics: PropTypes.arrayOf(PropTypes.string).isRequired,
};

module.exports = React.createClass({
displayName: 'RightPanel',

@@ -73,21 +121,6 @@ module.exports = React.createClass({
}
},

onMemberListButtonClick: function() {
Analytics.trackEvent('Right Panel', 'Member List Button', 'click');
this.setState({ phase: this.Phase.RoomMemberList });
},

onFileListButtonClick: function() {
Analytics.trackEvent('Right Panel', 'File List Button', 'click');
this.setState({ phase: this.Phase.FilePanel });
},

onNotificationListButtonClick: function() {
Analytics.trackEvent('Right Panel', 'Notification List Button', 'click');
this.setState({ phase: this.Phase.NotificationPanel });
},

onCollapseClick: function() {
dis.dispatch({
action: 'hide_right_panel',
@@ -140,7 +173,7 @@ module.exports = React.createClass({
} else {
if (this.props.roomId) {
this.setState({
phase: this.Phase.RoomMemberList
phase: this.Phase.RoomMemberList,
});
} else if (this.props.groupId) {
this.setState({
@@ -164,7 +197,11 @@ module.exports = React.createClass({
});
} else if (payload.action === "view_room") {
this.setState({
phase: this.Phase.RoomMemberList
phase: this.Phase.RoomMemberList,
});
} else if (payload.action === "view_right_panel_phase") {
this.setState({
phase: payload.phase,
});
}
},
@@ -176,36 +213,22 @@ module.exports = React.createClass({
const FilePanel = sdk.getComponent('structures.FilePanel');
const TintableSvg = sdk.getComponent("elements.TintableSvg");
let inviteGroup;
let panel;

let filesHighlight;
let membersHighlight;
let notificationsHighlight;
if (!this.props.collapsed) {
if (this.state.phase == this.Phase.RoomMemberList || this.state.phase === this.Phase.RoomMemberInfo) {
membersHighlight = <div className="mx_RightPanel_headerButton_highlight"></div>;
}
else if (this.state.phase == this.Phase.FilePanel) {
filesHighlight = <div className="mx_RightPanel_headerButton_highlight"></div>;
}
else if (this.state.phase == this.Phase.NotificationPanel) {
notificationsHighlight = <div className="mx_RightPanel_headerButton_highlight"></div>;
}
}

let membersBadge;
if ((this.state.phase == this.Phase.RoomMemberList || this.state.phase === this.Phase.RoomMemberInfo) && this.props.roomId) {
if ((this.state.phase == this.Phase.RoomMemberList || this.state.phase === this.Phase.RoomMemberInfo)
&& this.props.roomId
) {
const cli = MatrixClientPeg.get();
const room = cli.getRoom(this.props.roomId);
let user_is_in_room;
let userIsInRoom;
if (room) {
membersBadge = room.getJoinedMembers().length;
user_is_in_room = room.hasMembershipState(
MatrixClientPeg.get().credentials.userId, 'join'
userIsInRoom = room.hasMembershipState(
MatrixClientPeg.get().credentials.userId, 'join',
);
}

if (user_is_in_room) {
if (userIsInRoom) {
inviteGroup =
<AccessibleButton className="mx_RightPanel_invite" onClick={ this.onInviteButtonClick } >
<div className="mx_RightPanel_icon" >
@@ -214,37 +237,31 @@ module.exports = React.createClass({
<div className="mx_RightPanel_message">{ _t('Invite to this room') }</div>
</AccessibleButton>;
}

}

let headerButtons = [];
if (this.props.roomId) {
headerButtons.push(
<AccessibleButton className="mx_RightPanel_headerButton" key="_membersButton"
title={ _t('Members') } onClick={ this.onMemberListButtonClick }>
<div className="mx_RightPanel_headerButton_badge">{ membersBadge ? membersBadge : <span>&nbsp;</span>}</div>
<TintableSvg src="img/icons-people.svg" width="25" height="25"/>
{ membersHighlight }
</AccessibleButton>
);
headerButtons.push(
<AccessibleButton
className="mx_RightPanel_headerButton mx_RightPanel_filebutton" key="_filesButton"
title={ _t('Files') } onClick={ this.onFileListButtonClick }>
<div className="mx_RightPanel_headerButton_badge">&nbsp;</div>
<TintableSvg src="img/icons-files.svg" width="25" height="25"/>
{ filesHighlight }
</AccessibleButton>
);
headerButtons.push(
<AccessibleButton
className="mx_RightPanel_headerButton mx_RightPanel_notificationbutton" key="_notifsButton"
title={ _t('Notifications') } onClick={ this.onNotificationListButtonClick }>
<div className="mx_RightPanel_headerButton_badge">&nbsp;</div>
<TintableSvg src="img/icons-notifications.svg" width="25" height="25"/>
{ notificationsHighlight }
</AccessibleButton>
);
headerButtons = [
<HeaderButton key="_membersButton" title={_t('Members')} iconSrc="img/icons-people.svg"
phases={[this.Phase.RoomMemberList, this.Phase.RoomMemberInfo]}
clickPhase={this.Phase.RoomMemberList}
currentPhase={this.state.phase}
badge={membersBadge}
analytics={['Right Panel', 'Member List Button', 'click']}
/>,
<HeaderButton key="_filesButton" title={_t('Files')} iconSrc="img/icons-files.svg"
phases={[this.Phase.FilePanel]}
clickPhase={this.Phase.FilePanel}
currentPhase={this.state.phase}
analytics={['Right Panel', 'File List Button', 'click']}
/>,
<HeaderButton key="_notifsButton" title={_t('Notifications')} iconSrc="img/icons-notifications.svg"
phases={[this.Phase.NotificationPanel]}
clickPhase={this.Phase.NotificationPanel}
currentPhase={this.state.phase}
analytics={['Right Panel', 'Notification List Button', 'click']}
/>,
];
}

if (this.props.roomId || this.props.groupId) {
@@ -256,13 +273,14 @@ module.exports = React.createClass({
title={ _t("Hide panel") } onClick={ this.onCollapseClick }
>
<TintableSvg src="img/minimise.svg" width="10" height="16"/>
</div>
</div>,
);
}

let panel = <div />;
if (!this.props.collapsed) {
if (this.props.roomId && this.state.phase == this.Phase.RoomMemberList) {
panel = <MemberList roomId={this.props.roomId} key={this.props.roomId} />
panel = <MemberList roomId={this.props.roomId} key={this.props.roomId} />;
} else if (this.props.groupId && this.state.phase == this.Phase.GroupMemberList) {
panel = <GroupMemberList groupId={this.props.groupId} key={this.props.groupId} />;
inviteGroup = (
@@ -275,10 +293,13 @@ module.exports = React.createClass({
);
} else if (this.state.phase == this.Phase.RoomMemberInfo) {
const MemberInfo = sdk.getComponent('rooms.MemberInfo');
panel = <MemberInfo member={this.state.member} key={this.props.roomId || this.state.member.userId} />
panel = <MemberInfo member={this.state.member} key={this.props.roomId || this.state.member.userId} />;
} else if (this.state.phase == this.Phase.GroupMemberInfo) {
const GroupMemberInfo = sdk.getComponent('groups.GroupMemberInfo');
panel = <GroupMemberInfo groupMember={this.state.member} groupId={this.props.groupId} key={this.state.member.user_id} />;
panel = <GroupMemberInfo
groupMember={this.state.member}
groupId={this.props.groupId}
key={this.state.member.user_id} />;
} else if (this.state.phase == this.Phase.NotificationPanel) {
panel = <NotificationPanel />;
} else if (this.state.phase == this.Phase.FilePanel) {
@@ -308,5 +329,5 @@ module.exports = React.createClass({
</div>
</aside>
);
}
},
});