2016-01-18 18:19:49 +03:00
|
|
|
/*
|
|
|
|
Copyright 2015, 2016 OpenMarket Ltd
|
2018-03-19 19:47:12 +03:00
|
|
|
Copyright 2018 New Vector Ltd
|
2020-01-31 00:38:40 +03:00
|
|
|
Copyright 2020 The Matrix.org Foundation C.I.C.
|
2016-01-18 18:19:49 +03:00
|
|
|
|
|
|
|
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.
|
|
|
|
*/
|
|
|
|
|
2019-09-06 17:04:46 +03:00
|
|
|
import React from 'react';
|
2017-12-26 04:03:18 +03:00
|
|
|
import PropTypes from 'prop-types';
|
2019-09-06 17:04:46 +03:00
|
|
|
import createReactClass from 'create-react-class';
|
2019-12-20 04:19:56 +03:00
|
|
|
import * as sdk from '../../../index';
|
2017-01-25 01:41:52 +03:00
|
|
|
import AccessibleButton from '../elements/AccessibleButton';
|
2017-06-08 16:08:51 +03:00
|
|
|
import { _t } from '../../../languageHandler';
|
2019-03-08 00:55:17 +03:00
|
|
|
import classNames from "classnames";
|
2020-01-31 00:38:40 +03:00
|
|
|
import E2EIcon from './E2EIcon';
|
2016-01-18 18:19:49 +03:00
|
|
|
|
2017-10-11 19:56:17 +03:00
|
|
|
const PRESENCE_CLASS = {
|
2016-01-18 19:47:31 +03:00
|
|
|
"offline": "mx_EntityTile_offline",
|
|
|
|
"online": "mx_EntityTile_online",
|
2017-10-11 19:56:17 +03:00
|
|
|
"unavailable": "mx_EntityTile_unavailable",
|
2016-01-18 18:19:49 +03:00
|
|
|
};
|
|
|
|
|
2018-03-19 19:47:12 +03:00
|
|
|
function presenceClassForMember(presenceState, lastActiveAgo, showPresence) {
|
|
|
|
if (showPresence === false) {
|
|
|
|
return 'mx_EntityTile_online_beenactive';
|
|
|
|
}
|
|
|
|
|
2016-07-14 19:41:07 +03:00
|
|
|
// offline is split into two categories depending on whether we have
|
|
|
|
// a last_active_ago for them.
|
2016-07-14 20:18:44 +03:00
|
|
|
if (presenceState == 'offline') {
|
|
|
|
if (lastActiveAgo) {
|
2016-07-14 19:41:07 +03:00
|
|
|
return PRESENCE_CLASS['offline'] + '_beenactive';
|
|
|
|
} else {
|
|
|
|
return PRESENCE_CLASS['offline'] + '_neveractive';
|
|
|
|
}
|
2016-07-14 20:18:44 +03:00
|
|
|
} else if (presenceState) {
|
|
|
|
return PRESENCE_CLASS[presenceState];
|
2016-07-14 19:41:07 +03:00
|
|
|
} else {
|
2016-07-14 20:13:54 +03:00
|
|
|
return PRESENCE_CLASS['offline'] + '_neveractive';
|
2016-07-14 19:41:07 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-06 17:04:46 +03:00
|
|
|
const EntityTile = createReactClass({
|
2016-01-18 18:19:49 +03:00
|
|
|
displayName: 'EntityTile',
|
|
|
|
|
|
|
|
propTypes: {
|
2017-12-26 04:03:18 +03:00
|
|
|
name: PropTypes.string,
|
|
|
|
title: PropTypes.string,
|
|
|
|
avatarJsx: PropTypes.any, // <BaseAvatar />
|
|
|
|
className: PropTypes.string,
|
|
|
|
presenceState: PropTypes.string,
|
|
|
|
presenceLastActiveAgo: PropTypes.number,
|
|
|
|
presenceLastTs: PropTypes.number,
|
|
|
|
presenceCurrentlyActive: PropTypes.bool,
|
|
|
|
showInviteButton: PropTypes.bool,
|
|
|
|
shouldComponentUpdate: PropTypes.func,
|
|
|
|
onClick: PropTypes.func,
|
|
|
|
suppressOnHover: PropTypes.bool,
|
2018-03-19 19:47:12 +03:00
|
|
|
showPresence: PropTypes.bool,
|
2018-12-12 07:40:11 +03:00
|
|
|
subtextLabel: PropTypes.string,
|
2020-01-31 00:38:40 +03:00
|
|
|
e2eStatus: PropTypes.string,
|
2016-01-18 18:19:49 +03:00
|
|
|
},
|
|
|
|
|
|
|
|
getDefaultProps: function() {
|
|
|
|
return {
|
2016-01-21 18:57:59 +03:00
|
|
|
shouldComponentUpdate: function(nextProps, nextState) { return true; },
|
2016-01-18 18:19:49 +03:00
|
|
|
onClick: function() {},
|
|
|
|
presenceState: "offline",
|
2016-04-18 03:35:40 +03:00
|
|
|
presenceLastActiveAgo: 0,
|
|
|
|
presenceLastTs: 0,
|
2016-01-18 18:19:49 +03:00
|
|
|
showInviteButton: false,
|
2017-10-11 19:56:17 +03:00
|
|
|
suppressOnHover: false,
|
2018-03-19 19:47:12 +03:00
|
|
|
showPresence: true,
|
2016-01-18 18:19:49 +03:00
|
|
|
};
|
|
|
|
},
|
|
|
|
|
|
|
|
getInitialState: function() {
|
|
|
|
return {
|
2017-10-11 19:56:17 +03:00
|
|
|
hover: false,
|
2016-01-18 18:19:49 +03:00
|
|
|
};
|
|
|
|
},
|
|
|
|
|
|
|
|
shouldComponentUpdate: function(nextProps, nextState) {
|
|
|
|
if (this.state.hover !== nextState.hover) return true;
|
|
|
|
return this.props.shouldComponentUpdate(nextProps, nextState);
|
|
|
|
},
|
|
|
|
|
|
|
|
render: function() {
|
2019-03-08 00:55:17 +03:00
|
|
|
const mainClassNames = {
|
|
|
|
"mx_EntityTile": true,
|
|
|
|
"mx_EntityTile_noHover": this.props.suppressOnHover,
|
|
|
|
};
|
|
|
|
if (this.props.className) mainClassNames[this.props.className] = true;
|
|
|
|
|
2016-07-14 20:13:15 +03:00
|
|
|
const presenceClass = presenceClassForMember(
|
2018-03-19 19:47:12 +03:00
|
|
|
this.props.presenceState, this.props.presenceLastActiveAgo, this.props.showPresence,
|
2016-07-14 19:41:07 +03:00
|
|
|
);
|
2019-03-08 00:55:17 +03:00
|
|
|
mainClassNames[presenceClass] = true;
|
2016-07-14 19:41:07 +03:00
|
|
|
|
2017-10-11 19:56:17 +03:00
|
|
|
let nameEl;
|
2016-08-09 22:01:51 +03:00
|
|
|
const {name} = this.props;
|
2016-01-21 14:41:28 +03:00
|
|
|
|
2019-03-08 00:55:17 +03:00
|
|
|
if (!this.props.suppressOnHover) {
|
2017-10-11 19:56:17 +03:00
|
|
|
const activeAgo = this.props.presenceLastActiveAgo ?
|
2016-04-18 03:35:40 +03:00
|
|
|
(Date.now() - (this.props.presenceLastTs - this.props.presenceLastActiveAgo)) : -1;
|
|
|
|
|
2017-10-11 19:56:17 +03:00
|
|
|
const PresenceLabel = sdk.getComponent("rooms.PresenceLabel");
|
2018-03-19 19:47:12 +03:00
|
|
|
let presenceLabel = null;
|
|
|
|
if (this.props.showPresence) {
|
|
|
|
presenceLabel = <PresenceLabel activeAgo={activeAgo}
|
2018-12-13 04:18:43 +03:00
|
|
|
currentlyActive={this.props.presenceCurrentlyActive}
|
|
|
|
presenceState={this.props.presenceState} />;
|
2018-03-19 19:47:12 +03:00
|
|
|
}
|
2018-12-12 07:40:11 +03:00
|
|
|
if (this.props.subtextLabel) {
|
2018-12-12 22:57:48 +03:00
|
|
|
presenceLabel = <span className="mx_EntityTile_subtext">{this.props.subtextLabel}</span>;
|
2018-12-12 07:40:11 +03:00
|
|
|
}
|
2016-01-18 18:19:49 +03:00
|
|
|
nameEl = (
|
2016-01-18 19:47:31 +03:00
|
|
|
<div className="mx_EntityTile_details">
|
2019-05-19 17:23:43 +03:00
|
|
|
<div className="mx_EntityTile_name" dir="auto">
|
2018-12-13 04:18:43 +03:00
|
|
|
{ name }
|
2019-05-19 17:23:43 +03:00
|
|
|
</div>
|
2018-03-19 19:47:12 +03:00
|
|
|
{presenceLabel}
|
2016-01-18 18:19:49 +03:00
|
|
|
</div>
|
|
|
|
);
|
2018-12-12 07:40:11 +03:00
|
|
|
} else if (this.props.subtextLabel) {
|
|
|
|
nameEl = (
|
|
|
|
<div className="mx_EntityTile_details">
|
2019-05-19 17:23:43 +03:00
|
|
|
<div className="mx_EntityTile_name" dir="auto">
|
2018-12-12 07:40:11 +03:00
|
|
|
{name}
|
2019-05-19 17:23:43 +03:00
|
|
|
</div>
|
2018-12-12 22:57:48 +03:00
|
|
|
<span className="mx_EntityTile_subtext">{this.props.subtextLabel}</span>
|
2018-12-12 07:40:11 +03:00
|
|
|
</div>
|
|
|
|
);
|
2017-10-11 19:56:17 +03:00
|
|
|
} else {
|
2016-01-18 18:19:49 +03:00
|
|
|
nameEl = (
|
2019-05-19 17:23:43 +03:00
|
|
|
<div className="mx_EntityTile_name" dir="auto">{ name }</div>
|
2016-01-18 18:19:49 +03:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2017-10-11 19:56:17 +03:00
|
|
|
let inviteButton;
|
2016-01-18 19:47:31 +03:00
|
|
|
if (this.props.showInviteButton) {
|
|
|
|
inviteButton = (
|
|
|
|
<div className="mx_EntityTile_invite">
|
2019-01-11 04:37:28 +03:00
|
|
|
<img src={require("../../../../res/img/plus.svg")} width="16" height="16" />
|
2016-01-18 19:47:31 +03:00
|
|
|
</div>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2020-01-30 19:00:09 +03:00
|
|
|
let powerLabel;
|
2017-11-06 19:37:16 +03:00
|
|
|
const powerStatus = this.props.powerStatus;
|
|
|
|
if (powerStatus) {
|
2020-01-31 01:04:47 +03:00
|
|
|
const powerText = {
|
|
|
|
[EntityTile.POWER_STATUS_MODERATOR]: _t("Mod"),
|
2017-11-06 19:37:16 +03:00
|
|
|
[EntityTile.POWER_STATUS_ADMIN]: _t("Admin"),
|
|
|
|
}[powerStatus];
|
2020-01-31 01:04:47 +03:00
|
|
|
powerLabel = <div className="mx_EntityTile_power">{powerText}</div>;
|
2016-01-18 20:37:17 +03:00
|
|
|
}
|
2016-01-18 19:47:31 +03:00
|
|
|
|
2020-01-31 00:38:40 +03:00
|
|
|
let e2eIcon;
|
|
|
|
const { e2eStatus } = this.props;
|
|
|
|
if (e2eStatus) {
|
2020-07-14 02:52:03 +03:00
|
|
|
e2eIcon = <E2EIcon status={e2eStatus} isUser={true} bordered={true} />;
|
2020-01-31 00:38:40 +03:00
|
|
|
}
|
|
|
|
|
2017-10-11 19:56:17 +03:00
|
|
|
const BaseAvatar = sdk.getComponent('avatars.BaseAvatar');
|
2016-01-18 18:19:49 +03:00
|
|
|
|
2020-02-28 14:56:53 +03:00
|
|
|
const av = this.props.avatarJsx ||
|
|
|
|
<BaseAvatar name={this.props.name} width={36} height={36} aria-hidden="true" />;
|
2016-01-18 18:19:49 +03:00
|
|
|
|
2019-03-07 02:27:29 +03:00
|
|
|
// The wrapping div is required to make the magic mouse listener work, for some reason.
|
2016-01-18 18:19:49 +03:00
|
|
|
return (
|
2019-03-07 02:27:29 +03:00
|
|
|
<div ref={(c) => this.container = c} >
|
2019-03-08 00:55:17 +03:00
|
|
|
<AccessibleButton className={classNames(mainClassNames)} title={this.props.title}
|
|
|
|
onClick={this.props.onClick}>
|
2019-03-07 02:27:29 +03:00
|
|
|
<div className="mx_EntityTile_avatar">
|
|
|
|
{ av }
|
2020-01-31 00:38:40 +03:00
|
|
|
{ e2eIcon }
|
2019-03-07 02:27:29 +03:00
|
|
|
</div>
|
|
|
|
{ nameEl }
|
2020-01-31 01:04:47 +03:00
|
|
|
{ powerLabel }
|
2019-03-07 02:27:29 +03:00
|
|
|
{ inviteButton }
|
|
|
|
</AccessibleButton>
|
|
|
|
</div>
|
2016-01-18 18:19:49 +03:00
|
|
|
);
|
2017-10-11 19:56:17 +03:00
|
|
|
},
|
2016-01-18 18:19:49 +03:00
|
|
|
});
|
2017-11-06 19:37:16 +03:00
|
|
|
|
|
|
|
EntityTile.POWER_STATUS_MODERATOR = "moderator";
|
|
|
|
EntityTile.POWER_STATUS_ADMIN = "admin";
|
|
|
|
|
|
|
|
export default EntityTile;
|