diff --git a/webapp/channels/src/actions/views/rhs.ts b/webapp/channels/src/actions/views/rhs.ts index ebc34c5044..76f9699300 100644 --- a/webapp/channels/src/actions/views/rhs.ts +++ b/webapp/channels/src/actions/views/rhs.ts @@ -19,7 +19,7 @@ import { } from 'mattermost-redux/actions/search'; import {getCurrentChannelId, getCurrentChannelNameForSearchShortcut, getChannel as getChannelSelector} from 'mattermost-redux/selectors/entities/channels'; import {getConfig} from 'mattermost-redux/selectors/entities/general'; -import {getPost} from 'mattermost-redux/selectors/entities/posts'; +import {getLatestInteractablePostId, getPost} from 'mattermost-redux/selectors/entities/posts'; import {getCurrentTeamId} from 'mattermost-redux/selectors/entities/teams'; import {getCurrentTimezone} from 'mattermost-redux/selectors/entities/timezone'; import {getCurrentUser, getCurrentUserMentionKeys} from 'mattermost-redux/selectors/entities/users'; @@ -122,6 +122,14 @@ export function selectPostFromRightHandSideSearchByPostId(postId: string): Actio }; } +export function replyToLatestPostInChannel(channelId: string): ActionFuncAsync { + return async (dispatch, getState) => { + const state = getState(); + const postId = getLatestInteractablePostId(state, channelId); + return dispatch(selectPostFromRightHandSideSearchByPostId(postId)); + }; +} + export function updateSearchTerms(terms: string) { return { type: ActionTypes.UPDATE_RHS_SEARCH_TERMS, diff --git a/webapp/channels/src/components/advanced_text_editor/use_key_handler.tsx b/webapp/channels/src/components/advanced_text_editor/use_key_handler.tsx index 97d2c93d32..e5dabcdb95 100644 --- a/webapp/channels/src/components/advanced_text_editor/use_key_handler.tsx +++ b/webapp/channels/src/components/advanced_text_editor/use_key_handler.tsx @@ -5,12 +5,11 @@ import type React from 'react'; import {useCallback, useEffect, useRef} from 'react'; import {useDispatch, useSelector} from 'react-redux'; -import {getLatestReplyablePostId} from 'mattermost-redux/selectors/entities/posts'; import {getBool} from 'mattermost-redux/selectors/entities/preferences'; import {emitShortcutReactToLastPostFrom} from 'actions/post_actions'; import {editLatestPost} from 'actions/views/create_comment'; -import {selectPostFromRightHandSideSearchByPostId} from 'actions/views/rhs'; +import {replyToLatestPostInChannel} from 'actions/views/rhs'; import type {TextboxElement} from 'components/textbox'; import type TextboxClass from 'components/textbox/textbox'; @@ -59,7 +58,6 @@ const useKeyHandler = ( const lastChannelSwitchAt = useRef(0); const isNonFormattedPaste = useRef(false); - const latestReplyablePostId = useSelector((state: GlobalState) => (postId ? '' : getLatestReplyablePostId(state))); const replyToLastPost = useCallback((e: React.KeyboardEvent) => { if (postId) { return; @@ -70,10 +68,9 @@ const useKeyHandler = ( if (replyBox) { replyBox.focus(); } - if (latestReplyablePostId) { - dispatch(selectPostFromRightHandSideSearchByPostId(latestReplyablePostId)); - } - }, [latestReplyablePostId, dispatch, postId]); + + dispatch(replyToLatestPostInChannel(channelId)); + }, [dispatch, postId, channelId]); const onEditLatestPost = useCallback((e: React.KeyboardEvent) => { e.preventDefault(); diff --git a/webapp/channels/src/packages/mattermost-redux/src/selectors/entities/posts.ts b/webapp/channels/src/packages/mattermost-redux/src/selectors/entities/posts.ts index b39ededda1..79bffaef18 100644 --- a/webapp/channels/src/packages/mattermost-redux/src/selectors/entities/posts.ts +++ b/webapp/channels/src/packages/mattermost-redux/src/selectors/entities/posts.ts @@ -28,7 +28,7 @@ import {getMyPreferences} from 'mattermost-redux/selectors/entities/preferences' import {getCurrentTeamId} from 'mattermost-redux/selectors/entities/teams'; import {getUsers, getCurrentUserId, getUserStatuses} from 'mattermost-redux/selectors/entities/users'; import {createIdsSelector} from 'mattermost-redux/utils/helpers'; -import {isCombinedUserActivityPost, shouldShowJoinLeaveMessages} from 'mattermost-redux/utils/post_list'; +import {shouldShowJoinLeaveMessages} from 'mattermost-redux/utils/post_list'; import { isPostEphemeral, isSystemMessage, @@ -61,6 +61,18 @@ export function getPostsInThread(state: GlobalState): RelationOneToMany allPosts[v]).filter((v) => v); + const sortedPosts = threadPosts.sort(comparePosts); + return [...sortedPosts.map((v) => v.id), rootId]; +} + export function getReactionsForPosts(state: GlobalState): RelationOneToOne { @@ -269,8 +281,17 @@ function formatPostInChannel(post: Post, previousPost: Post | undefined | null, }; } +function isPostInteractable(post: Post | undefined) { + return post && + !post.delete_at && + !isPostEphemeral(post) && + !isSystemMessage(post) && + !isPostPendingOrFailed(post) && + post.state !== Posts.POST_DELETED; +} + export function getLatestInteractablePostId(state: GlobalState, channelId: string, rootId = '') { - const postsIds = rootId ? getPostsInThread(state)[rootId] : getPostIdsInChannel(state, channelId); + const postsIds = rootId ? getPostsInThreadOrdered(state, rootId) : getPostIdsInChannel(state, channelId); if (!postsIds) { return ''; } @@ -278,49 +299,31 @@ export function getLatestInteractablePostId(state: GlobalState, channelId: strin const allPosts = getAllPosts(state); for (const postId of postsIds) { - if (isCombinedUserActivityPost(postId)) { + if (!isPostInteractable(allPosts[postId])) { continue; } - - const post = allPosts[postId]; - if (!post) { - continue; - } - - if (post.delete_at) { - continue; - } - - if (isPostEphemeral(post)) { - continue; - } - - if (isSystemMessage(post)) { - continue; - } - return postId; } - if (rootId && allPosts[rootId] && !allPosts[rootId].delete_at) { - return rootId; - } - return ''; } export function getLatestPostToEdit(state: GlobalState, channelId: string, rootId = '') { - const postsIds = rootId ? getPostsInThread(state)[rootId] : getPostIdsInChannel(state, channelId); + const postsIds = rootId ? getPostsInThreadOrdered(state, rootId) : getPostIdsInChannel(state, channelId); if (!postsIds) { return ''; } + if (rootId) { + postsIds.push(rootId); + } + const allPosts = getAllPosts(state); const currentUserId = getCurrentUserId(state); for (const postId of postsIds) { const post = allPosts[postId]; - if (!post || post.user_id !== currentUserId || (post.props?.from_webhook) || post.state === Posts.POST_DELETED || isSystemMessage(post) || isPostEphemeral(post) || isPostPendingOrFailed(post)) { + if (post?.user_id !== currentUserId || !isPostInteractable(post)) { continue; }