Files
mattermost/webapp/components/rhs_comment.jsx

452 lines
14 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
import UserProfile from './user_profile.jsx';
import FileAttachmentListContainer from 'components/file_attachment_list';
import PostMessageContainer from 'components/post_view/post_message_view';
import ProfilePicture from 'components/profile_picture.jsx';
import ReactionListContainer from 'components/post_view/reaction_list';
import PostFlagIcon from 'components/post_view/post_flag_icon.jsx';
import FailedPostOptions from 'components/post_view/failed_post_options';
import DotMenu from 'components/dot_menu';
import EmojiPickerOverlay from 'components/emoji_picker/emoji_picker_overlay.jsx';
import {addReaction} from 'actions/post_actions.jsx';
import TeamStore from 'stores/team_store.jsx';
import * as Utils from 'utils/utils.jsx';
import * as PostUtils from 'utils/post_utils.jsx';
import Constants from 'utils/constants.jsx';
import React from 'react';
import PropTypes from 'prop-types';
import {Link} from 'react-router/es6';
import {FormattedMessage} from 'react-intl';
export default class RhsComment extends React.Component {
static propTypes = {
post: PropTypes.object,
lastPostCount: PropTypes.number,
user: PropTypes.object.isRequired,
currentUser: PropTypes.object.isRequired,
compactDisplay: PropTypes.bool,
useMilitaryTime: PropTypes.bool.isRequired,
isFlagged: PropTypes.bool,
status: PropTypes.string,
isBusy: PropTypes.bool,
removePost: PropTypes.func.isRequired
};
constructor(props) {
super(props);
this.removePost = this.removePost.bind(this);
this.reactEmojiClick = this.reactEmojiClick.bind(this);
this.handleDropdownOpened = this.handleDropdownOpened.bind(this);
this.state = {
currentTeamDisplayName: TeamStore.getCurrent().name,
width: '',
height: '',
showEmojiPicker: false,
dropdownOpened: false
};
}
componentDidMount() {
window.addEventListener('resize', () => {
Utils.updateWindowDimensions(this);
});
}
componentWillUnmount() {
window.removeEventListener('resize', () => {
Utils.updateWindowDimensions(this);
});
}
removePost() {
this.props.removePost(this.props.post);
}
createRemovePostButton() {
return (
<a
href='#'
className='post__remove theme'
type='button'
onClick={this.removePost}
>
{'×'}
</a>
);
}
shouldComponentUpdate(nextProps, nextState) {
if (nextProps.status !== this.props.status) {
return true;
}
if (nextProps.isBusy !== this.props.isBusy) {
return true;
}
if (nextProps.compactDisplay !== this.props.compactDisplay) {
return true;
}
if (nextProps.useMilitaryTime !== this.props.useMilitaryTime) {
return true;
}
if (nextProps.isFlagged !== this.props.isFlagged) {
return true;
}
if (!Utils.areObjectsEqual(nextProps.post, this.props.post)) {
return true;
}
if (!Utils.areObjectsEqual(nextProps.currentUser, this.props.currentUser)) {
return true;
}
if (this.state.showEmojiPicker !== nextState.showEmojiPicker) {
return true;
}
if (nextProps.lastPostCount !== this.props.lastPostCount) {
return true;
}
if (this.state.dropdownOpened !== nextState.dropdownOpened) {
return true;
}
return false;
}
timeTag(post, timeOptions) {
return (
<time
className='post__time'
dateTime={Utils.getDateForUnixTicks(post.create_at).toISOString()}
>
{Utils.getDateForUnixTicks(post.create_at).toLocaleString('en', timeOptions)}
</time>
);
}
renderTimeTag(post, timeOptions) {
return Utils.isMobile() ?
this.timeTag(post, timeOptions) :
(
<Link
to={`/${this.state.currentTeamDisplayName}/pl/${post.id}`}
target='_blank'
className='post__permalink'
>
{this.timeTag(post, timeOptions)}
</Link>
);
}
toggleEmojiPicker = () => {
const showEmojiPicker = !this.state.showEmojiPicker;
this.setState({
showEmojiPicker,
dropdownOpened: showEmojiPicker
});
}
reactEmojiClick(emoji) {
this.setState({showEmojiPicker: false});
const emojiName = emoji.name || emoji.aliases[0];
addReaction(this.props.post.channel_id, this.props.post.id, emojiName);
}
getClassName = (post, isSystemMessage) => {
let className = 'post post--thread';
if (this.props.currentUser.id === post.user_id) {
className += ' current--user';
}
if (isSystemMessage) {
className += ' post--system';
}
if (this.props.compactDisplay) {
className += ' post--compact';
}
if (post.is_pinned) {
className += ' post--pinned';
}
if (this.state.dropdownOpened) {
className += ' post--hovered';
}
return className;
}
handleDropdownOpened(isOpened) {
this.setState({
dropdownOpened: isOpened
});
}
render() {
const post = this.props.post;
const mattermostLogo = Constants.MATTERMOST_ICON_SVG;
let idCount = -1;
if (this.props.lastPostCount >= 0 && this.props.lastPostCount < Constants.TEST_ID_COUNT) {
idCount = this.props.lastPostCount;
}
const isEphemeral = Utils.isPostEphemeral(post);
const isSystemMessage = PostUtils.isSystemMessage(post);
var timestamp = this.props.currentUser.last_picture_update;
let status = this.props.status;
if (post.props && post.props.from_webhook === 'true') {
status = null;
}
let botIndicator;
let userProfile = (
<UserProfile
user={this.props.user}
status={status}
isBusy={this.props.isBusy}
/>
);
if (post.props && post.props.from_webhook) {
if (post.props.override_username && global.window.mm_config.EnablePostUsernameOverride === 'true') {
userProfile = (
<UserProfile
user={this.props.user}
overwriteName={post.props.override_username}
disablePopover={true}
/>
);
} else {
userProfile = (
<UserProfile
user={this.props.user}
disablePopover={true}
/>
);
}
botIndicator = <div className='col col__name bot-indicator'>{'BOT'}</div>;
} else if (isSystemMessage) {
userProfile = (
<UserProfile
user={{}}
overwriteName={
<FormattedMessage
id='post_info.system'
defaultMessage='System'
/>
}
overwriteImage={Constants.SYSTEM_MESSAGE_PROFILE_IMAGE}
disablePopover={true}
/>
);
}
let failedPostOptions;
let postClass = '';
if (post.failed) {
postClass += ' post-failed';
failedPostOptions = <FailedPostOptions post={this.props.post}/>;
}
if (PostUtils.isEdited(this.props.post)) {
postClass += ' post--edited';
}
let profilePic = (
<ProfilePicture
src={PostUtils.getProfilePicSrcForPost(post, timestamp)}
status={status}
width='36'
height='36'
user={this.props.user}
isBusy={this.props.isBusy}
/>
);
if (post.props && post.props.from_webhook) {
profilePic = (
<ProfilePicture
src={PostUtils.getProfilePicSrcForPost(post, timestamp)}
width='36'
height='36'
/>
);
}
if (isSystemMessage) {
profilePic = (
<span
className='icon'
dangerouslySetInnerHTML={{__html: mattermostLogo}}
/>
);
}
if (this.props.compactDisplay) {
if (post.props && post.props.from_webhook) {
profilePic = (
<ProfilePicture
src=''
/>
);
} else {
profilePic = (
<ProfilePicture
src=''
status={status}
user={this.props.user}
isBusy={this.props.isBusy}
/>
);
}
}
const profilePicContainer = (<div className='post__img'>{profilePic}</div>);
let fileAttachment = null;
if (post.file_ids && post.file_ids.length > 0) {
fileAttachment = (
<FileAttachmentListContainer
post={post}
compactDisplay={this.props.compactDisplay}
/>
);
}
let react;
if (!isEphemeral && !post.failed && !isSystemMessage && window.mm_config.EnableEmojiPicker === 'true') {
react = (
<span>
<EmojiPickerOverlay
show={this.state.showEmojiPicker}
onHide={this.toggleEmojiPicker}
target={() => this.refs.dotMenu}
onEmojiClick={this.reactEmojiClick}
rightOffset={15}
spaceRequiredAbove={342}
spaceRequiredBelow={342}
/>
<a
href='#'
className='reacticon__container reaction'
onClick={this.toggleEmojiPicker}
ref={'rhs_reacticon_' + post.id}
><i className='fa fa-smile-o'/>
</a>
</span>
);
}
let options;
if (isEphemeral) {
options = (
<div className='col col__remove'>
{this.createRemovePostButton()}
</div>
);
} else if (!isSystemMessage) {
const dotMenu = (
<DotMenu
idPrefix={Constants.RHS}
idCount={idCount}
post={this.props.post}
isFlagged={this.props.isFlagged}
handleDropdownOpened={this.handleDropdownOpened}
/>
);
options = (
<div
ref='dotMenu'
className='col col__reply'
>
{dotMenu}
{react}
</div>
);
}
let pinnedBadge;
if (post.is_pinned) {
pinnedBadge = (
<span className='post__pinned-badge'>
<FormattedMessage
id='post_info.pinned'
defaultMessage='Pinned'
/>
</span>
);
}
const timeOptions = {
hour: '2-digit',
minute: '2-digit',
hour12: !this.props.useMilitaryTime
};
return (
<div
ref={'post_body_' + post.id}
className={this.getClassName(post, isSystemMessage)}
>
<div className='post__content'>
{profilePicContainer}
<div>
<div className='post__header'>
<div className='col col__name'>
<strong>{userProfile}</strong>
</div>
{botIndicator}
<div className='col'>
{this.renderTimeTag(post, timeOptions)}
{pinnedBadge}
<PostFlagIcon
idPrefix={'rhsCommentFlag'}
idCount={idCount}
postId={post.id}
isFlagged={this.props.isFlagged}
isEphemeral={isEphemeral}
/>
</div>
{options}
</div>
<div className='post__body' >
<div className={postClass}>
{failedPostOptions}
<PostMessageContainer post={post}/>
</div>
{fileAttachment}
<ReactionListContainer post={post}/>
</div>
</div>
</div>
</div>
);
}
}