diff options
author | Joram Wilander <jwawilander@gmail.com> | 2017-06-18 14:42:32 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-06-18 14:42:32 -0400 |
commit | ab67f6e257f6e8f08145a02a7b93550f99641be4 (patch) | |
tree | d33d1c58a3d229f7e37db58bc2c397ac3806c503 /webapp/components/post_view/post_info | |
parent | 0231e95f1c5a8c42ba97875f0d2301815f552974 (diff) | |
download | chat-ab67f6e257f6e8f08145a02a7b93550f99641be4.tar.gz chat-ab67f6e257f6e8f08145a02a7b93550f99641be4.tar.bz2 chat-ab67f6e257f6e8f08145a02a7b93550f99641be4.zip |
PLT-6215 Major post list refactor (#6501)
* Major post list refactor
* Fix post and thread deletion
* Fix preferences not selecting correctly
* Fix military time displaying
* Fix UP key for editing posts
* Fix ESLint error
* Various fixes and updates per feedback
* Fix for permalink view
* Revert to old scrolling method and various fixes
* Add floating timestamp, new message indicator, scroll arrows
* Update post loading for focus mode and add visibility limit
* Fix pinning posts and a react warning
* Add loading UI updates from Asaad
* Fix refreshing loop
* Temporarily bump post visibility limit
* Update infinite scrolling
* Remove infinite scrolling
Diffstat (limited to 'webapp/components/post_view/post_info')
-rw-r--r-- | webapp/components/post_view/post_info/index.js | 31 | ||||
-rw-r--r-- | webapp/components/post_view/post_info/post_info.jsx | 243 |
2 files changed, 274 insertions, 0 deletions
diff --git a/webapp/components/post_view/post_info/index.js b/webapp/components/post_view/post_info/index.js new file mode 100644 index 000000000..749ec5aba --- /dev/null +++ b/webapp/components/post_view/post_info/index.js @@ -0,0 +1,31 @@ +// Copyright (c) 2017 Mattermost, Inc. All Rights Reserved. +// See License.txt for license information. + +import {connect} from 'react-redux'; +import {bindActionCreators} from 'redux'; +import {removePost, addReaction} from 'mattermost-redux/actions/posts'; + +import {getBool} from 'mattermost-redux/selectors/entities/preferences'; + +import {Preferences} from 'utils/constants.jsx'; + +import PostInfo from './post_info.jsx'; + +function mapStateToProps(state, ownProps) { + return { + ...ownProps, + useMilitaryTime: getBool(state, Preferences.CATEGORY_DISPLAY_SETTINGS, Preferences.USE_MILITARY_TIME, false), + isFlagged: getBool(state, Preferences.CATEGORY_FLAGGED_POST, ownProps.post.id) + }; +} + +function mapDispatchToProps(dispatch) { + return { + actions: bindActionCreators({ + removePost, + addReaction + }, dispatch) + }; +} + +export default connect(mapStateToProps, mapDispatchToProps)(PostInfo); diff --git a/webapp/components/post_view/post_info/post_info.jsx b/webapp/components/post_view/post_info/post_info.jsx new file mode 100644 index 000000000..f037bf03b --- /dev/null +++ b/webapp/components/post_view/post_info/post_info.jsx @@ -0,0 +1,243 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See License.txt for license information. + +import PostTime from 'components/post_view/post_time.jsx'; +import PostFlagIcon from 'components/post_view/post_flag_icon.jsx'; +import CommentIcon from 'components/common/comment_icon.jsx'; +import EmojiPickerOverlay from 'components/emoji_picker/emoji_picker_overlay.jsx'; +import DotMenu from 'components/dot_menu'; + +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 {FormattedMessage} from 'react-intl'; + +export default class PostInfo extends React.PureComponent { + static propTypes = { + + /* + * The post to render the info for + */ + post: PropTypes.object.isRequired, + + /* + * Function called when the comment icon is clicked + */ + handleCommentClick: PropTypes.func.isRequired, + + /* + * Funciton called when the post options dropdown is opened + */ + handleDropdownOpened: PropTypes.func.isRequired, + + /* + * Set to display in 24 hour format + */ + useMilitaryTime: PropTypes.bool.isRequired, + + /* + * Set to mark the post as flagged + */ + isFlagged: PropTypes.bool, + + /* + * The number of replies in the same thread as this post + */ + replyCount: PropTypes.number, + + /* + * Post identifiers for selenium tests + */ + lastPostCount: PropTypes.number, + + /** + * Function to get the post list HTML element + */ + getPostList: PropTypes.func.isRequired, + + actions: PropTypes.shape({ + + /* + * Function to remove the post + */ + removePost: PropTypes.func.isRequired, + + /* + * Function to add a reaction to the post + */ + addReaction: PropTypes.func.isRequired + }).isRequired + } + + constructor(props) { + super(props); + + this.removePost = this.removePost.bind(this); + this.reactEmojiClick = this.reactEmojiClick.bind(this); + + this.state = { + showEmojiPicker: false, + reactionPickerOffset: 21, + canEdit: PostUtils.canEditPost(props.post, this.editDisableAction) + }; + } + + toggleEmojiPicker = () => { + const showEmojiPicker = !this.state.showEmojiPicker; + + this.setState({showEmojiPicker}); + this.props.handleDropdownOpened(showEmojiPicker); + } + + hideEmojiPicker = () => { + this.setState({showEmojiPicker: false}); + this.props.handleDropdownOpened(false); + } + + removePost() { + this.props.actions.removePost(this.props.post); + } + + createRemovePostButton() { + return ( + <a + href='#' + className='post__remove theme' + type='button' + onClick={this.removePost} + > + {'×'} + </a> + ); + } + + reactEmojiClick(emoji) { + const pickerOffset = 21; + this.setState({showEmojiPicker: false, reactionPickerOffset: pickerOffset}); + const emojiName = emoji.name || emoji.aliases[0]; + this.props.actions.addReaction(this.props.post.id, emojiName); + } + + getDotMenu = () => { + return this.refs.dotMenu; + } + + render() { + const post = this.props.post; + + 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); + + let comments = null; + let react = null; + if (!isEphemeral && !post.failed && !isSystemMessage) { + comments = ( + <CommentIcon + idPrefix='commentIcon' + idCount={idCount} + handleCommentClick={this.props.handleCommentClick} + commentCount={this.props.replyCount} + id={post.channel_id + '_' + post.id} + /> + ); + + if (Utils.isFeatureEnabled(Constants.PRE_RELEASE_FEATURES.EMOJI_PICKER_PREVIEW)) { + react = ( + <span> + <EmojiPickerOverlay + show={this.state.showEmojiPicker} + container={this.props.getPostList} + target={this.getDotMenu} + onHide={this.hideEmojiPicker} + onEmojiClick={this.reactEmojiClick} + /> + <a + href='#' + className='reacticon__container' + onClick={this.toggleEmojiPicker} + > + <i className='fa fa-smile-o'/> + </a> + </span> + + ); + } + } + + let options; + if (isEphemeral) { + options = ( + <div className='col col__remove'> + {this.createRemovePostButton()} + </div> + ); + } else if (!post.failed) { + const dotMenu = ( + <DotMenu + idPrefix={Constants.CENTER} + idCount={idCount} + post={this.props.post} + commentCount={this.props.replyCount} + isFlagged={this.props.isFlagged} + handleCommentClick={this.props.handleCommentClick} + handleDropdownOpened={this.props.handleDropdownOpened} + /> + ); + + if (dotMenu) { + options = ( + <div + ref='dotMenu' + className='col col__reply' + > + {dotMenu} + {react} + {comments} + </div> + ); + } + } + + let pinnedBadge; + if (post.is_pinned) { + pinnedBadge = ( + <span className='post__pinned-badge'> + <FormattedMessage + id='post_info.pinned' + defaultMessage='Pinned' + /> + </span> + ); + } + + return ( + <div className='post__header--info'> + <div className='col'> + <PostTime + eventTime={post.create_at} + useMilitaryTime={this.props.useMilitaryTime} + postId={post.id} + /> + {pinnedBadge} + {this.state.showEmojiPicker} + <PostFlagIcon + idPrefix={'centerPostFlag'} + idCount={idCount} + postId={post.id} + isFlagged={this.props.isFlagged} + isEphemeral={isEphemeral} + /> + </div> + {options} + </div> + ); + } +} |