MM-55251 - Updating reply count on thread post (#26142)

* MM-55251 - Updating reply count on thread post

* Updating reply count fetch

* Fixing lint errors

---------

Co-authored-by: Mattermost Build <build@mattermost.com>
This commit is contained in:
Asaad Mahmood 2024-03-12 14:24:47 +05:00 committed by GitHub
parent 2cc2bad1b3
commit 76bab25199
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 70 additions and 15 deletions

View File

@ -60,6 +60,7 @@ function ThreadFooter({
channel_id: channelId,
},
} = thread;
const participantIds = useMemo(() => (participants || []).map(({id}) => id).reverse(), [participants]);
const handleReply = useCallback((e) => {

View File

@ -32,6 +32,7 @@ describe('components/threading/ThreadViewer', () => {
user_id: post.user_id,
channel_id: post.channel_id,
message: post.message,
reply_count: 3,
};
const channel: Channel = TestHelper.getChannelMock({

View File

@ -22,6 +22,7 @@ import Reply from './reply';
type Props = {
a11yIndex: number;
currentUserId: string;
replyCount: number;
isRootPost: boolean;
isLastPost: boolean;
listId: string;
@ -40,6 +41,7 @@ function ThreadViewerRow({
isRootPost,
isLastPost,
listId,
replyCount,
onCardClick,
previousPostId,
timestampProps,
@ -70,13 +72,20 @@ function ThreadViewerRow({
case isRootPost:
return (
<PostComponent
postId={listId}
isLastPost={isLastPost}
handleCardClick={onCardClick}
timestampProps={timestampProps}
location={Locations.RHS_ROOT}
/>
<>
<PostComponent
postId={listId}
isLastPost={isLastPost}
handleCardClick={onCardClick}
timestampProps={timestampProps}
location={Locations.RHS_ROOT}
/>
{replyCount > 0 && (
<div className='root-post__divider'>
<div>{`${replyCount} Replies`}</div>
</div>
)}
</>
);
case PostListUtils.isCombinedUserActivityPost(listId): {
return (

View File

@ -26,6 +26,7 @@ function getBasePropsAndState(): [Props, DeepPartial<GlobalState>] {
const currentUser = TestHelper.getUserMock({roles: 'role'});
const post = TestHelper.getPostMock({
channel_id: channel.id,
reply_count: 0,
});
const directTeammate: UserProfile = TestHelper.getUserMock();

View File

@ -3,14 +3,17 @@
import {DynamicSizeList} from 'dynamic-virtualized-list';
import type {OnScrollArgs, OnItemsRenderedArgs} from 'dynamic-virtualized-list';
import React, {PureComponent} from 'react';
import React, {PureComponent, useMemo} from 'react';
import type {RefObject} from 'react';
import {useSelector} from 'react-redux';
import AutoSizer from 'react-virtualized-auto-sizer';
import type {Channel} from '@mattermost/types/channels';
import type {Post} from '@mattermost/types/posts';
import type {UserProfile} from '@mattermost/types/users';
import {getPost} from 'mattermost-redux/selectors/entities/posts';
import {makeGetThreadOrSynthetic} from 'mattermost-redux/selectors/entities/threads';
import {isDateLine, isStartOfNewMessages, isCreateComment} from 'mattermost-redux/utils/post_list';
import NewRepliesBanner from 'components/new_replies_banner';
@ -22,6 +25,7 @@ import DelayedAction from 'utils/delayed_action';
import {getNewMessageIndex, getPreviousPostId, getLatestPostId} from 'utils/post_utils';
import * as Utils from 'utils/utils';
import type {GlobalState} from 'types/store';
import type {PluginComponent} from 'types/store/plugins';
import type {FakePost} from 'types/store/rhs';
@ -350,6 +354,14 @@ class ThreadViewerVirtualized extends PureComponent<Props, State> {
const isLastPost = itemId === this.props.lastPost.id;
const isRootPost = itemId === this.props.selected.id;
const post = useSelector((state: GlobalState) => getPost(state, this.props.selected.id));
const getThreadOrSynthetic = useMemo(makeGetThreadOrSynthetic, []);
const totalReplies = useSelector((state: GlobalState) => {
const thread = getThreadOrSynthetic(state, post);
return thread.reply_count || 0;
});
if (!isDateLine(itemId) && !isStartOfNewMessages(itemId) && !isCreateComment(itemId) && !isRootPost) {
a11yIndex++;
}
@ -379,6 +391,7 @@ class ThreadViewerVirtualized extends PureComponent<Props, State> {
isRootPost={isRootPost}
isLastPost={isLastPost}
listId={itemId}
replyCount={totalReplies}
onCardClick={this.props.onCardClick}
previousPostId={getPreviousPostId(data, index)}
timestampProps={this.props.useRelativeTimestamp ? THREADING_TIME : undefined}

View File

@ -38,9 +38,37 @@
display: none;
}
.root-post__divider {
position: relative;
display: flex;
height: 28px;
align-items: center;
margin: 0 0 4px 30px;
div {
z-index: 1;
padding: 0 12px;
margin-left: 34px;
background: rgba(v(center-channel-bg-rgb), 1);
color: rgba(v(center-channel-color-rgb), 0.72);
font-size: 12px;
font-weight: 600;
}
&::before {
position: absolute;
top: calc(50% - 1px);
left: 0;
display: block;
width: 100%;
border-top: 1px solid rgba(var(--center-channel-color-rgb), 0.12);
content: "";
}
}
.post {
&.post--root {
padding-top: 2rem;
padding-top: 16px;
.post__body {
background: transparent !important;
@ -52,9 +80,9 @@
}
.post-pre-header__icons-container {
width: 60px; // If the width of post__img changes, this needs to be adjusted accordingly
padding-right: 12px; // If the padding of post__img changes, this needs to be adjusted accordingly
margin-left: 0; // if left margin of post__content changes, this needs to be adjusted accordingly
width: 54px; // If the width of post__img changes, this needs to be adjusted accordingly;
padding-right: 12px; // If the padding of post__img changes, this needs to be adjusted accordingly;
margin-left: 0; // if left margin of post__content changes, this needs to be adjusted accordingly;
}
.post__header {
@ -119,8 +147,8 @@
}
.post__img {
width: 60px; // if this changes, the width of post-pre-header__icons-container needs to be adjusted accordingly
padding: 2px 12px 0 0; // if the right padding changes, the padding of post-pre-header__icons-container needs to be adjusted accordingly
width: 54px; // if this changes, the width of post-pre-header__icons-container needs to be adjusted accordingly;
padding: 2px 12px 0 0; // if the right padding changes, the padding of post-pre-header__icons-container needs to be adjusted accordingly;
}
.post-body {

View File

@ -440,7 +440,7 @@
.post {
&.post--thread {
.post-pre-header__icons-container {
width: 60px; // If the width of post__img changes, this needs to be adjusted accordingly
width: 44px; // If the width of post__img changes, this needs to be adjusted accordingly
padding-right: 12px; // If the padding of post__img changes, this needs to be adjusted accordingly
margin-left: 0; // if left margin of post__content changes, this needs to be adjusted accordingly
}

View File

@ -94,6 +94,7 @@ export const getSelectedPost = createSelector(
message: localizeMessage('rhs_thread.rootPostDeletedMessage.body', 'Part of this thread has been deleted due to a data retention policy. You can no longer reply to this thread.'),
channel_id: selectedPostChannelId,
user_id: currentUserId,
reply_count: 0,
};
},
);

View File

@ -16,6 +16,7 @@ export type FakePost = {
exists: boolean;
type: PostType;
message: string;
reply_count: number;
channel_id: Channel['id'];
user_id: UserProfile['id'];
};