From f88769d1f2ba7f2097e9a545e18fb0c5eb4ea2e9 Mon Sep 17 00:00:00 2001 From: Saturnino Abril Date: Tue, 9 May 2017 21:54:45 +0900 Subject: [PATCH] [PLT-6363-1] Create PostFlagIcon component and add flag IDs to posts (#6271) * [UI-AUTO] add IDs to last 10 posts' text * create FlagPost component and add flag IDs for posts at center, RHS and search results --- webapp/components/common/post_flag_icon.jsx | 87 +++++++++++++++++++ .../components/post_view/components/post.jsx | 1 + .../post_view/components/post_header.jsx | 2 + .../post_view/components/post_info.jsx | 76 ++++------------ webapp/components/rhs_comment.jsx | 80 ++++------------- webapp/components/rhs_root_post.jsx | 62 ++----------- webapp/components/rhs_thread.jsx | 15 ++-- webapp/components/search_results.jsx | 6 +- webapp/components/search_results_item.jsx | 67 +++----------- 9 files changed, 158 insertions(+), 238 deletions(-) create mode 100644 webapp/components/common/post_flag_icon.jsx diff --git a/webapp/components/common/post_flag_icon.jsx b/webapp/components/common/post_flag_icon.jsx new file mode 100644 index 0000000000..5f714f76ba --- /dev/null +++ b/webapp/components/common/post_flag_icon.jsx @@ -0,0 +1,87 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See License.txt for license information. + +import React from 'react'; +import {FormattedMessage} from 'react-intl'; +import {Tooltip, OverlayTrigger} from 'react-bootstrap'; + +import {flagPost, unflagPost} from 'actions/post_actions.jsx'; +import Constants from 'utils/constants.jsx'; +import * as Utils from 'utils/utils.jsx'; + +function flagToolTip(isFlagged) { + return ( + + + + ); +} + +function flagIcon() { + return ( + + ); +} + +export default function PostFlagIcon(props) { + function onFlagPost(e) { + e.preventDefault(); + flagPost(props.postId); + } + + function onUnflagPost(e) { + e.preventDefault(); + unflagPost(props.postId); + } + + const flagFunc = props.isFlagged ? onUnflagPost : onFlagPost; + const flagVisible = props.isFlagged ? 'visible' : ''; + + let flagIconId = null; + if (props.idCount > -1) { + flagIconId = Utils.createSafeId(props.idPrefix + props.idCount); + } + + if (!props.isEphemeral) { + return ( + + + {flagIcon()} + + + ); + } + + return ''; +} + +PostFlagIcon.propTypes = { + idPrefix: React.PropTypes.string.isRequired, + idCount: React.PropTypes.number, + postId: React.PropTypes.string.isRequired, + isFlagged: React.PropTypes.bool.isRequired, + isEphemeral: React.PropTypes.bool +}; + +PostFlagIcon.defaultProps = { + idCount: -1, + postId: '', + isFlagged: false, + isEphemeral: false +}; diff --git a/webapp/components/post_view/components/post.jsx b/webapp/components/post_view/components/post.jsx index 1959d5cad3..38f95a85b6 100644 --- a/webapp/components/post_view/components/post.jsx +++ b/webapp/components/post_view/components/post.jsx @@ -292,6 +292,7 @@ export default class Post extends Component { ref='header' post={post} sameRoot={this.props.sameRoot} + lastPostCount={this.props.lastPostCount} commentCount={this.props.commentCount} handleCommentClick={this.handleCommentClick} handleDropdownOpened={this.handleDropdownOpened} diff --git a/webapp/components/post_view/components/post_header.jsx b/webapp/components/post_view/components/post_header.jsx index 9de0b7e798..eccd092b58 100644 --- a/webapp/components/post_view/components/post_header.jsx +++ b/webapp/components/post_view/components/post_header.jsx @@ -79,6 +79,7 @@ export default class PostHeader extends React.Component {
  • = 0 && this.props.lastPostCount < Constants.TEST_ID_COUNT) { + idCount = this.props.lastPostCount; + } this.canDelete = PostUtils.canDeletePost(post); this.canEdit = PostUtils.canEditPost(post, this.editDisableAction); @@ -420,64 +425,6 @@ export default class PostInfo extends React.Component { } } - let flag; - let flagFunc; - let flagVisible = ''; - let flagTooltip = ( - - - - ); - if (this.props.isFlagged) { - flagVisible = 'visible'; - flag = ( - - ); - flagFunc = this.unflagPost; - flagTooltip = ( - - - - ); - } else { - flag = ( - - ); - flagFunc = this.flagPost; - } - - let flagTrigger; - if (!isEphemeral) { - flagTrigger = ( - - - {flag} - - - ); - } - let pinnedBadge; if (post.is_pinned) { pinnedBadge = ( @@ -502,7 +449,13 @@ export default class PostInfo extends React.Component { /> {pinnedBadge} {this.state.showEmojiPicker} - {flagTrigger} +
  • {options} @@ -518,6 +471,7 @@ PostInfo.defaultProps = { }; PostInfo.propTypes = { post: React.PropTypes.object.isRequired, + lastPostCount: React.PropTypes.number, commentCount: React.PropTypes.number.isRequired, isLastComment: React.PropTypes.bool.isRequired, handleCommentClick: React.PropTypes.func.isRequired, diff --git a/webapp/components/rhs_comment.jsx b/webapp/components/rhs_comment.jsx index fb09728043..88e8c1ca66 100644 --- a/webapp/components/rhs_comment.jsx +++ b/webapp/components/rhs_comment.jsx @@ -8,6 +8,7 @@ import PostMessageContainer from 'components/post_view/components/post_message_c import ProfilePicture from 'components/profile_picture.jsx'; import ReactionListContainer from 'components/post_view/components/reaction_list_container.jsx'; import RhsDropdown from 'components/rhs_dropdown.jsx'; +import PostFlagIcon from 'components/common/post_flag_icon.jsx'; import * as GlobalActions from 'actions/global_actions.jsx'; import {flagPost, unflagPost, pinPost, unpinPost, addReaction} from 'actions/post_actions.jsx'; @@ -19,7 +20,7 @@ import * as PostUtils from 'utils/post_utils.jsx'; import Constants from 'utils/constants.jsx'; import DelayedAction from 'utils/delayed_action.jsx'; -import {Tooltip, OverlayTrigger, Overlay} from 'react-bootstrap'; +import {Overlay} from 'react-bootstrap'; import {FormattedMessage} from 'react-intl'; @@ -128,6 +129,10 @@ export default class RhsComment extends React.Component { return true; } + if (nextProps.lastPostCount !== this.props.lastPostCount) { + return true; + } + return false; } @@ -384,9 +389,13 @@ export default class RhsComment extends React.Component { render() { const post = this.props.post; - const flagIcon = Constants.FLAG_ICON_SVG; 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 isPending = post.state === Constants.POST_FAILED || post.state === Constants.POST_LOADING; const isSystemMessage = PostUtils.isSystemMessage(post); @@ -523,64 +532,6 @@ export default class RhsComment extends React.Component { ); } - let flag; - let flagFunc; - let flagVisible = ''; - let flagTooltip = ( - - - - ); - if (this.props.isFlagged) { - flagVisible = 'visible'; - flag = ( - - ); - flagFunc = this.unflagPost; - flagTooltip = ( - - - - ); - } else { - flag = ( - - ); - flagFunc = this.flagPost; - } - - let flagTrigger; - if (!isEphemeral) { - flagTrigger = ( - - - {flag} - - - ); - } - let react; let reactOverlay; @@ -668,7 +619,13 @@ export default class RhsComment extends React.Component {
  • {this.renderTimeTag(post, timeOptions)} {pinnedBadge} - {flagTrigger} +
  • {options} @@ -689,6 +646,7 @@ export default class RhsComment extends React.Component { RhsComment.propTypes = { post: React.PropTypes.object, + lastPostCount: React.PropTypes.number, user: React.PropTypes.object.isRequired, currentUser: React.PropTypes.object.isRequired, compactDisplay: React.PropTypes.bool, diff --git a/webapp/components/rhs_root_post.jsx b/webapp/components/rhs_root_post.jsx index 65bc52f730..bf97486366 100644 --- a/webapp/components/rhs_root_post.jsx +++ b/webapp/components/rhs_root_post.jsx @@ -8,6 +8,7 @@ import FileAttachmentListContainer from './file_attachment_list_container.jsx'; import ProfilePicture from 'components/profile_picture.jsx'; import ReactionListContainer from 'components/post_view/components/reaction_list_container.jsx'; import RhsDropdown from 'components/rhs_dropdown.jsx'; +import PostFlagIcon from 'components/common/post_flag_icon.jsx'; import ChannelStore from 'stores/channel_store.jsx'; import UserStore from 'stores/user_store.jsx'; @@ -24,7 +25,7 @@ import ReactDOM from 'react-dom'; import Constants from 'utils/constants.jsx'; import DelayedAction from 'utils/delayed_action.jsx'; -import {Tooltip, OverlayTrigger, Overlay} from 'react-bootstrap'; +import {Overlay} from 'react-bootstrap'; import {FormattedMessage} from 'react-intl'; @@ -203,7 +204,6 @@ export default class RhsRootPost extends React.Component { const mattermostLogo = Constants.MATTERMOST_ICON_SVG; var timestamp = user ? user.last_picture_update : 0; var channel = ChannelStore.get(post.channel_id); - const flagIcon = Constants.FLAG_ICON_SVG; this.canDelete = PostUtils.canDeletePost(post); this.canEdit = PostUtils.canEditPost(post, this.editDisableAction); @@ -530,44 +530,6 @@ export default class RhsRootPost extends React.Component { const profilePicContainer = (
    {profilePic}
    ); - let flag; - let flagFunc; - let flagVisible = ''; - let flagTooltip = ( - - - - ); - if (this.props.isFlagged) { - flagVisible = 'visible'; - flag = ( - - ); - flagFunc = this.unflagPost; - flagTooltip = ( - - - - ); - } else { - flag = ( - - ); - flagFunc = this.flagPost; - } - let pinnedBadge; if (post.is_pinned) { pinnedBadge = ( @@ -601,20 +563,11 @@ export default class RhsRootPost extends React.Component {
  • {this.renderTimeTag(post, timeOptions)} {pinnedBadge} - - - {flag} - - +
  • {reactOverlay} @@ -645,6 +598,7 @@ RhsRootPost.defaultProps = { }; RhsRootPost.propTypes = { post: React.PropTypes.object.isRequired, + lastPostCount: React.PropTypes.number, user: React.PropTypes.object.isRequired, currentUser: React.PropTypes.object.isRequired, commentCount: React.PropTypes.number, diff --git a/webapp/components/rhs_thread.jsx b/webapp/components/rhs_thread.jsx index 174799878c..82e54f6ffb 100644 --- a/webapp/components/rhs_thread.jsx +++ b/webapp/components/rhs_thread.jsx @@ -352,7 +352,8 @@ export default class RhsThread extends React.Component { let previousPostDay = rootPostDay; const commentsLists = []; - for (let i = 0; i < postsArray.length; i++) { + const postsLength = postsArray.length; + for (let i = 0; i < postsLength; i++) { const comPost = postsArray[i]; let p; if (UserStore.getCurrentId() === comPost.user_id) { @@ -371,10 +372,7 @@ export default class RhsThread extends React.Component { status = this.state.statuses[p.id] || 'offline'; } - const keyPrefix = comPost.id ? comPost.id : comPost.pending_post_id; - const currentPostDay = Utils.getDateForUnixTicks(comPost.create_at); - if (currentPostDay.toDateString() !== previousPostDay.toDateString()) { previousPostDay = currentPostDay; commentsLists.push( @@ -383,11 +381,14 @@ export default class RhsThread extends React.Component { />); } + const keyPrefix = comPost.id ? comPost.id : comPost.pending_post_id; + const reverseCount = postsLength - i - 1; commentsLists.push(
    = 0 && reverseCount < Constants.TEST_ID_COUNT) ? reverseCount : -1} user={p} currentUser={this.props.currentUser} compactDisplay={this.state.compactDisplay} @@ -431,12 +432,12 @@ export default class RhsThread extends React.Component { className='post-right__scroll' > 0 ? postsArray[postsArray.length - 1].id : selected.id} + latestPostId={postsLength > 0 ? postsArray[postsLength - 1].id : selected.id} />
    diff --git a/webapp/components/search_results.jsx b/webapp/components/search_results.jsx index 682b04e2a1..64e5a7c935 100644 --- a/webapp/components/search_results.jsx +++ b/webapp/components/search_results.jsx @@ -267,7 +267,7 @@ export default class SearchResults extends React.Component { ); } else { - ctls = results.order.map(function mymap(id) { + ctls = results.order.map(function searchResults(id, idx, arr) { const post = results.posts[id]; let profile; if (UserStore.getCurrentId() === post.user_id) { @@ -285,12 +285,16 @@ export default class SearchResults extends React.Component { if (this.state.flaggedPosts) { isFlagged = this.state.flaggedPosts.get(post.id) === 'true'; } + + const reverseCount = arr.length - idx - 1; + return ( = 0 && reverseCount < Constants.TEST_ID_COUNT) ? reverseCount : -1} user={profile} term={searchTerm} isMentionSearch={this.props.isMentionSearch} diff --git a/webapp/components/search_results_item.jsx b/webapp/components/search_results_item.jsx index 09ea8c427d..9e0eb51b0b 100644 --- a/webapp/components/search_results_item.jsx +++ b/webapp/components/search_results_item.jsx @@ -13,12 +13,12 @@ import UserStore from 'stores/user_store.jsx'; import AppDispatcher from '../dispatcher/app_dispatcher.jsx'; import * as GlobalActions from 'actions/global_actions.jsx'; import {flagPost, unflagPost} from 'actions/post_actions.jsx'; +import PostFlagIcon from 'components/common/post_flag_icon.jsx'; import * as Utils from 'utils/utils.jsx'; import * as PostUtils from 'utils/post_utils.jsx'; import Constants from 'utils/constants.jsx'; -import {Tooltip, OverlayTrigger} from 'react-bootstrap'; const ActionTypes = Constants.ActionTypes; import React from 'react'; @@ -114,7 +114,11 @@ export default class SearchResultsItem extends React.Component { const timestamp = UserStore.getCurrentUser().last_picture_update; const user = this.props.user || {}; const post = this.props.post; - const flagIcon = Constants.FLAG_ICON_SVG; + + let idCount = -1; + if (this.props.lastPostCount >= 0 && this.props.lastPostCount < Constants.TEST_ID_COUNT) { + idCount = this.props.lastPostCount; + } if (channel) { channelName = channel.display_name; @@ -185,59 +189,13 @@ export default class SearchResultsItem extends React.Component {

    ); } else { - let flag; - let flagFunc; - let flagVisible = ''; - let flagTooltip = ( - - - - ); - - if (this.props.isFlagged) { - flagVisible = 'visible'; - flagTooltip = ( - - - - ); - flagFunc = this.unflagPost; - flag = ( - - ); - } else { - flag = ( - - ); - flagFunc = this.flagPost; - } - flagContent = ( - - - {flag} - - + ); rhsControls = ( @@ -364,6 +322,7 @@ export default class SearchResultsItem extends React.Component { SearchResultsItem.propTypes = { post: React.PropTypes.object, + lastPostCount: React.PropTypes.number, user: React.PropTypes.object, channel: React.PropTypes.object, compactDisplay: React.PropTypes.bool,