MM-50577 Replaced makeCreateAriaLabelForPost with better memoized usePostAriaLabel (#22833)
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
024a5472ff
Коммит
21b72c7607
@@ -1,36 +1,24 @@
|
|||||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||||
// See LICENSE.txt for license information.
|
// See LICENSE.txt for license information.
|
||||||
|
|
||||||
import React, {useRef} from 'react';
|
import React from 'react';
|
||||||
import {useSelector} from 'react-redux';
|
|
||||||
import {useIntl} from 'react-intl';
|
|
||||||
|
|
||||||
import {Post} from '@mattermost/types/posts';
|
import {Post} from '@mattermost/types/posts';
|
||||||
|
|
||||||
import {GlobalState} from 'types/store';
|
import {usePostAriaLabel} from 'utils/post_utils';
|
||||||
|
|
||||||
import {makeCreateAriaLabelForPost} from 'utils/post_utils';
|
|
||||||
|
|
||||||
export type Props = React.HTMLProps<HTMLDivElement> & {
|
export type Props = React.HTMLProps<HTMLDivElement> & {
|
||||||
labelPrefix?: string;
|
|
||||||
post: Post;
|
post: Post;
|
||||||
}
|
}
|
||||||
|
|
||||||
const PostAriaLabelDiv = React.forwardRef((props: Props, ref: React.Ref<HTMLDivElement>) => {
|
const PostAriaLabelDiv = React.forwardRef((props: Props, ref: React.Ref<HTMLDivElement>) => {
|
||||||
const {
|
const {
|
||||||
children,
|
children,
|
||||||
labelPrefix,
|
|
||||||
post,
|
post,
|
||||||
...otherProps
|
...otherProps
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
const intl = useIntl();
|
const ariaLabel = usePostAriaLabel(post);
|
||||||
|
|
||||||
const createAriaLabelForPost = useRef(makeCreateAriaLabelForPost());
|
|
||||||
let ariaLabel = useSelector<GlobalState, string>((state) => createAriaLabelForPost.current(state, post)(intl));
|
|
||||||
if (labelPrefix) {
|
|
||||||
ariaLabel = labelPrefix + ariaLabel;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
|
|||||||
@@ -77,4 +77,18 @@ describe('LatestPostReader', () => {
|
|||||||
expect(span.prop('children')).toContain(author.username);
|
expect(span.prop('children')).toContain(author.username);
|
||||||
expect(span.prop('children')).toContain('enero');
|
expect(span.prop('children')).toContain('enero');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('should be able to handle an empty post array', () => {
|
||||||
|
const {mountOptions} = mockStore(baseState);
|
||||||
|
|
||||||
|
const props = {
|
||||||
|
...baseProps,
|
||||||
|
postIds: [],
|
||||||
|
};
|
||||||
|
|
||||||
|
const wrapper = mount(<LatestPostReader {...props}/>, mountOptions);
|
||||||
|
const span = wrapper.childAt(0);
|
||||||
|
|
||||||
|
expect(span.prop('children')).toEqual('');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||||
// See LICENSE.txt for license information.
|
// See LICENSE.txt for license information.
|
||||||
|
|
||||||
import React, {useMemo, useRef} from 'react';
|
import React, {useMemo} from 'react';
|
||||||
import {useIntl} from 'react-intl';
|
|
||||||
import {useSelector} from 'react-redux';
|
import {useSelector} from 'react-redux';
|
||||||
|
|
||||||
import {getPost} from 'mattermost-redux/selectors/entities/posts';
|
import {getPost} from 'mattermost-redux/selectors/entities/posts';
|
||||||
@@ -11,27 +10,18 @@ import {Post} from '@mattermost/types/posts';
|
|||||||
|
|
||||||
import {GlobalState} from 'types/store';
|
import {GlobalState} from 'types/store';
|
||||||
|
|
||||||
import {getLatestPostId, makeCreateAriaLabelForPost} from 'utils/post_utils';
|
import {getLatestPostId, usePostAriaLabel} from 'utils/post_utils';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
postIds?: string[];
|
postIds?: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
const LatestPostReader = (props: Props): JSX.Element => {
|
const LatestPostReader = (props: Props): JSX.Element => {
|
||||||
const intl = useIntl();
|
|
||||||
|
|
||||||
const {postIds} = props;
|
const {postIds} = props;
|
||||||
const latestPostId = useMemo(() => getLatestPostId(postIds || []), [postIds]);
|
const latestPostId = useMemo(() => getLatestPostId(postIds || []), [postIds]);
|
||||||
const latestPost = useSelector<GlobalState, Post>((state) => getPost(state, latestPostId));
|
const latestPost = useSelector<GlobalState, Post>((state) => getPost(state, latestPostId));
|
||||||
|
|
||||||
const createAriaLabelForPost = useRef(makeCreateAriaLabelForPost());
|
const ariaLabel = usePostAriaLabel(latestPost);
|
||||||
const ariaLabel = useSelector<GlobalState, string>((state) => {
|
|
||||||
if (!latestPost) {
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
|
|
||||||
return createAriaLabelForPost.current(state, latestPost)(intl);
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<span
|
<span
|
||||||
|
|||||||
@@ -71,13 +71,13 @@ export function getReactionsForPosts(state: GlobalState): RelationOneToOne<Post,
|
|||||||
|
|
||||||
export function makeGetReactionsForPost(): (state: GlobalState, postId: Post['id']) => {
|
export function makeGetReactionsForPost(): (state: GlobalState, postId: Post['id']) => {
|
||||||
[x: string]: Reaction;
|
[x: string]: Reaction;
|
||||||
} | undefined | null {
|
} | undefined {
|
||||||
return createSelector('makeGetReactionsForPost', getReactionsForPosts, (state: GlobalState, postId: string) => postId, (reactions, postId) => {
|
return createSelector('makeGetReactionsForPost', getReactionsForPosts, (state: GlobalState, postId: string) => postId, (reactions, postId) => {
|
||||||
if (reactions[postId]) {
|
if (reactions[postId]) {
|
||||||
return reactions[postId];
|
return reactions[postId];
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return undefined;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,11 @@
|
|||||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||||
// See LICENSE.txt for license information.
|
// See LICENSE.txt for license information.
|
||||||
|
|
||||||
import {IntlShape} from 'react-intl';
|
import {IntlShape, useIntl} from 'react-intl';
|
||||||
|
|
||||||
|
import {useMemo} from 'react';
|
||||||
|
|
||||||
|
import {useSelector} from 'react-redux';
|
||||||
|
|
||||||
import {createSelector} from 'reselect';
|
import {createSelector} from 'reselect';
|
||||||
|
|
||||||
@@ -17,6 +21,8 @@ import {haveIChannelPermission} from 'mattermost-redux/selectors/entities/roles'
|
|||||||
import {getCurrentTeamId, getTeam} from 'mattermost-redux/selectors/entities/teams';
|
import {getCurrentTeamId, getTeam} from 'mattermost-redux/selectors/entities/teams';
|
||||||
import {makeGetDisplayName, getCurrentUserId, getUser, UserMentionKey, getUsersByUsername} from 'mattermost-redux/selectors/entities/users';
|
import {makeGetDisplayName, getCurrentUserId, getUser, UserMentionKey, getUsersByUsername} from 'mattermost-redux/selectors/entities/users';
|
||||||
|
|
||||||
|
import {memoizeResult} from 'mattermost-redux/utils/helpers';
|
||||||
|
|
||||||
import {Channel} from '@mattermost/types/channels';
|
import {Channel} from '@mattermost/types/channels';
|
||||||
import {ClientConfig, ClientLicense} from '@mattermost/types/config';
|
import {ClientConfig, ClientLicense} from '@mattermost/types/config';
|
||||||
import {ServerError} from '@mattermost/types/errors';
|
import {ServerError} from '@mattermost/types/errors';
|
||||||
@@ -42,8 +48,8 @@ import {allAtMentions} from 'utils/text_formatting';
|
|||||||
import {isMobile} from 'utils/user_agent';
|
import {isMobile} from 'utils/user_agent';
|
||||||
import * as Utils from 'utils/utils';
|
import * as Utils from 'utils/utils';
|
||||||
|
|
||||||
import * as Emoticons from './emoticons';
|
|
||||||
import EmojiMap from './emoji_map';
|
import EmojiMap from './emoji_map';
|
||||||
|
import * as Emoticons from './emoticons';
|
||||||
|
|
||||||
const CHANNEL_SWITCH_IGNORE_ENTER_THRESHOLD_MS = 500;
|
const CHANNEL_SWITCH_IGNORE_ENTER_THRESHOLD_MS = 500;
|
||||||
|
|
||||||
@@ -443,27 +449,41 @@ export function makeGetMentionsFromMessage(): (state: GlobalState, post: Post) =
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function makeCreateAriaLabelForPost(): (state: GlobalState, post: Post) => (intl: IntlShape) => string {
|
export function usePostAriaLabel(post: Post | undefined) {
|
||||||
const getReactionsForPost = makeGetUniqueReactionsToPost();
|
const intl = useIntl();
|
||||||
const getDisplayName = makeGetDisplayName();
|
|
||||||
const getMentionsFromMessage = makeGetMentionsFromMessage();
|
|
||||||
|
|
||||||
return createSelector(
|
const getDisplayName = useMemo(makeGetDisplayName, []);
|
||||||
'makeCreateAriaLabelForPost',
|
const getReactionsForPost = useMemo(makeGetReactionsForPost, []);
|
||||||
(state: GlobalState, post: Post) => post,
|
const getMentionsFromMessage = useMemo(makeGetMentionsFromMessage, []);
|
||||||
(state: GlobalState, post: Post) => getDisplayName(state, post.user_id),
|
|
||||||
(state: GlobalState, post: Post) => getReactionsForPost(state, post.id),
|
const createAriaLabelMemoized = memoizeResult(createAriaLabelForPost);
|
||||||
(state: GlobalState, post: Post) => get(state, Preferences.CATEGORY_FLAGGED_POST, post.id, null) != null,
|
|
||||||
getEmojiMap,
|
return useSelector((state: GlobalState) => {
|
||||||
(state: GlobalState, post: Post) => getMentionsFromMessage(state, post),
|
if (!post) {
|
||||||
(state: GlobalState) => getTeammateNameDisplaySetting(state),
|
return '';
|
||||||
(post, author, reactions, isFlagged, emojiMap, mentions, teammateNameDisplaySetting) => {
|
}
|
||||||
return (intl: IntlShape) => createAriaLabelForPost(post, author, isFlagged, reactions ?? {}, intl, emojiMap, mentions, teammateNameDisplaySetting);
|
|
||||||
},
|
const authorDisplayName = getDisplayName(state, post.user_id);
|
||||||
|
const reactions = getReactionsForPost(state, post?.id);
|
||||||
|
const isFlagged = get(state, Preferences.CATEGORY_FLAGGED_POST, post.id, null) != null;
|
||||||
|
const emojiMap = getEmojiMap(state);
|
||||||
|
const mentions = getMentionsFromMessage(state, post);
|
||||||
|
const teammateNameDisplaySetting = getTeammateNameDisplaySetting(state);
|
||||||
|
|
||||||
|
return createAriaLabelMemoized(
|
||||||
|
post,
|
||||||
|
authorDisplayName,
|
||||||
|
isFlagged,
|
||||||
|
reactions,
|
||||||
|
intl,
|
||||||
|
emojiMap,
|
||||||
|
mentions,
|
||||||
|
teammateNameDisplaySetting,
|
||||||
);
|
);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createAriaLabelForPost(post: Post, author: string, isFlagged: boolean, reactions: Record<string, Reaction>, intl: IntlShape, emojiMap: EmojiMap, mentions: Record<string, UserProfile>, teammateNameDisplaySetting: string): string {
|
export function createAriaLabelForPost(post: Post, author: string, isFlagged: boolean, reactions: Record<string, Reaction> | undefined, intl: IntlShape, emojiMap: EmojiMap, mentions: Record<string, UserProfile>, teammateNameDisplaySetting: string): string {
|
||||||
const {formatMessage, formatTime, formatDate} = intl;
|
const {formatMessage, formatTime, formatDate} = intl;
|
||||||
|
|
||||||
let message = post.state === Posts.POST_DELETED ? formatMessage({
|
let message = post.state === Posts.POST_DELETED ? formatMessage({
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user