MM-49862 - remove no longer needed webapp calls to action and pulsating dots (#22699)

* MM-49862 - remove no longer needed webapp calls to action and pulsating dots

* fix snapshots

* improve function logic based on pr comments

* fix unit tests

---------

Co-authored-by: Mattermost Build <build@mattermost.com>
Этот коммит содержится в:
Pablo Andrés Vélez Vidal
2023-04-04 18:04:06 +02:00
коммит произвёл GitHub
родитель 9736304633
Коммит 6919761122
19 изменённых файлов: 94 добавлений и 361 удалений

Просмотреть файл

@@ -39,7 +39,6 @@ exports[`components/actions_menu/ActionsMenu has actions - marketplace disabled
className="post-menu__item post-menu__item--active"
id="center_actions_button_post_id_1"
key="more-actions-button"
onClick={[Function]}
type="button"
>
<i
@@ -107,7 +106,6 @@ exports[`components/actions_menu/ActionsMenu has actions - marketplace enabled a
className="post-menu__item post-menu__item--active"
id="center_actions_button_post_id_1"
key="more-actions-button"
onClick={[Function]}
type="button"
>
<i
@@ -194,7 +192,6 @@ exports[`components/actions_menu/ActionsMenu no actions - sysadmin - menu should
className="post-menu__item post-menu__item--active"
id="center_actions_button_post_id_1"
key="more-actions-button"
onClick={[Function]}
type="button"
>
<i

Просмотреть файл

@@ -38,12 +38,7 @@ describe('components/actions_menu/ActionsMenu', () => {
isSysAdmin: true,
pluginMenuItems: [],
post: TestHelper.getPostMock({id: 'post_id_1', is_pinned: false, type: '' as PostType}),
showTutorialTip: false,
components: {},
handleOpenTip: jest.fn(),
handleNextTip: jest.fn(),
handleDismissTip: jest.fn(),
showPulsatingDot: false,
location: 'center',
canOpenMarketplace: false,
actions: {

Просмотреть файл

@@ -17,7 +17,6 @@ import {AppCallResponseTypes} from 'mattermost-redux/constants/apps';
import {HandleBindingClick, PostEphemeralCallResponseForPost, OpenAppsModal} from 'types/apps';
import {Locations, Constants, ModalIdentifiers} from 'utils/constants';
import Permissions from 'mattermost-redux/constants/permissions';
import {ActionsTutorialTip} from 'components/actions_menu/actions_menu_tutorial_tip';
import {ModalData} from 'types/actions';
import MarketplaceModal, {OpenedFromType} from 'components/plugin_marketplace/marketplace_modal';
import OverlayTrigger from 'components/overlay_trigger';
@@ -44,11 +43,6 @@ export type Props = {
pluginMenuItems?: PluginComponent[];
post: Post;
teamId: string;
handleOpenTip: () => void;
handleNextTip: (e: React.MouseEvent) => void;
handleDismissTip: () => void;
showPulsatingDot?: boolean;
showTutorialTip: boolean;
canOpenMarketplace: boolean;
/**
@@ -236,14 +230,6 @@ export class ActionMenuClass extends React.PureComponent<Props, State> {
);
}
handleActionsIconClick = (e: React.MouseEvent) => {
if (this.props.showPulsatingDot || this.props.showTutorialTip) {
this.props.handleOpenTip();
e.preventDefault();
e.stopPropagation();
}
};
renderDivider = (suffix: string): React.ReactNode => {
return (
<li
@@ -413,17 +399,8 @@ export class ActionMenuClass extends React.PureComponent<Props, State> {
})}
type='button'
aria-expanded='false'
onClick={this.handleActionsIconClick}
>
<i className={'icon icon-apps'}/>
{this.props.showPulsatingDot &&
<ActionsTutorialTip
showTip={this.props.showTutorialTip}
handleNext={this.props.handleNextTip}
handleOpen={this.props.handleOpenTip}
handleDismiss={this.props.handleDismissTip}
/>
}
</button>
</OverlayTrigger>
<Menu

Просмотреть файл

@@ -37,11 +37,6 @@ describe('components/actions_menu/ActionsMenu returning empty ("")', () => {
},
appBindings: [],
pluginMenuItems: [],
handleOpenTip: jest.fn(),
handleNextTip: jest.fn(),
handleDismissTip: jest.fn(),
showPulsatingDot: false,
showTutorialTip: false,
appsEnabled: false,
isSysAdmin: true,
canOpenMarketplace: false,

Просмотреть файл

@@ -37,11 +37,6 @@ describe('components/actions_menu/ActionsMenu on mobile view', () => {
},
appBindings: [],
pluginMenuItems: [],
handleOpenTip: jest.fn(),
handleNextTip: jest.fn(),
handleDismissTip: jest.fn(),
showPulsatingDot: false,
showTutorialTip: false,
appsEnabled: false,
isSysAdmin: true,
canOpenMarketplace: false,

Просмотреть файл

@@ -107,113 +107,6 @@ Object {
}
`;
exports[`components/dot_menu/DotMenu should match snapshot, hide "New" badge on forward post 1`] = `
Object {
"asFragment": [Function],
"baseElement": <body>
<div>
<button
aria-controls="CENTER_dropdown_post_id_1"
aria-expanded="false"
aria-haspopup="true"
aria-label="Actions"
class="post-menu__item"
data-testid="PostDotMenu-Button-post_id_1"
id="CENTER_button_post_id_1"
>
<svg
fill="currentColor"
height="16"
version="1.1"
viewBox="0 0 24 24"
width="16"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M16,12A2,2 0 0,1 18,10A2,2 0 0,1 20,12A2,2 0 0,1 18,14A2,2 0 0,1 16,12M10,12A2,2 0 0,1 12,10A2,2 0 0,1 14,12A2,2 0 0,1 12,14A2,2 0 0,1 10,12M4,12A2,2 0 0,1 6,10A2,2 0 0,1 8,12A2,2 0 0,1 6,14A2,2 0 0,1 4,12Z"
/>
</svg>
</button>
</div>
</body>,
"container": <div>
<button
aria-controls="CENTER_dropdown_post_id_1"
aria-expanded="false"
aria-haspopup="true"
aria-label="Actions"
class="post-menu__item"
data-testid="PostDotMenu-Button-post_id_1"
id="CENTER_button_post_id_1"
>
<svg
fill="currentColor"
height="16"
version="1.1"
viewBox="0 0 24 24"
width="16"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M16,12A2,2 0 0,1 18,10A2,2 0 0,1 20,12A2,2 0 0,1 18,14A2,2 0 0,1 16,12M10,12A2,2 0 0,1 12,10A2,2 0 0,1 14,12A2,2 0 0,1 12,14A2,2 0 0,1 10,12M4,12A2,2 0 0,1 6,10A2,2 0 0,1 8,12A2,2 0 0,1 6,14A2,2 0 0,1 4,12Z"
/>
</svg>
</button>
</div>,
"debug": [Function],
"findAllByAltText": [Function],
"findAllByDisplayValue": [Function],
"findAllByLabelText": [Function],
"findAllByPlaceholderText": [Function],
"findAllByRole": [Function],
"findAllByTestId": [Function],
"findAllByText": [Function],
"findAllByTitle": [Function],
"findByAltText": [Function],
"findByDisplayValue": [Function],
"findByLabelText": [Function],
"findByPlaceholderText": [Function],
"findByRole": [Function],
"findByTestId": [Function],
"findByText": [Function],
"findByTitle": [Function],
"getAllByAltText": [Function],
"getAllByDisplayValue": [Function],
"getAllByLabelText": [Function],
"getAllByPlaceholderText": [Function],
"getAllByRole": [Function],
"getAllByTestId": [Function],
"getAllByText": [Function],
"getAllByTitle": [Function],
"getByAltText": [Function],
"getByDisplayValue": [Function],
"getByLabelText": [Function],
"getByPlaceholderText": [Function],
"getByRole": [Function],
"getByTestId": [Function],
"getByText": [Function],
"getByTitle": [Function],
"queryAllByAltText": [Function],
"queryAllByDisplayValue": [Function],
"queryAllByLabelText": [Function],
"queryAllByPlaceholderText": [Function],
"queryAllByRole": [Function],
"queryAllByTestId": [Function],
"queryAllByText": [Function],
"queryAllByTitle": [Function],
"queryByAltText": [Function],
"queryByDisplayValue": [Function],
"queryByLabelText": [Function],
"queryByPlaceholderText": [Function],
"queryByRole": [Function],
"queryByTestId": [Function],
"queryByText": [Function],
"queryByTitle": [Function],
"rerender": [Function],
"unmount": [Function],
}
`;
exports[`components/dot_menu/DotMenu should match snapshot, on Center 1`] = `
<Menu
menu={
@@ -483,110 +376,3 @@ exports[`components/dot_menu/DotMenu should match snapshot, on Center 1`] = `
/>
</Menu>
`;
exports[`components/dot_menu/DotMenu should match snapshot, show "New" badge on forward post 1`] = `
Object {
"asFragment": [Function],
"baseElement": <body>
<div>
<button
aria-controls="CENTER_dropdown_post_id_1"
aria-expanded="false"
aria-haspopup="true"
aria-label="Actions"
class="post-menu__item"
data-testid="PostDotMenu-Button-post_id_1"
id="CENTER_button_post_id_1"
>
<svg
fill="currentColor"
height="16"
version="1.1"
viewBox="0 0 24 24"
width="16"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M16,12A2,2 0 0,1 18,10A2,2 0 0,1 20,12A2,2 0 0,1 18,14A2,2 0 0,1 16,12M10,12A2,2 0 0,1 12,10A2,2 0 0,1 14,12A2,2 0 0,1 12,14A2,2 0 0,1 10,12M4,12A2,2 0 0,1 6,10A2,2 0 0,1 8,12A2,2 0 0,1 6,14A2,2 0 0,1 4,12Z"
/>
</svg>
</button>
</div>
</body>,
"container": <div>
<button
aria-controls="CENTER_dropdown_post_id_1"
aria-expanded="false"
aria-haspopup="true"
aria-label="Actions"
class="post-menu__item"
data-testid="PostDotMenu-Button-post_id_1"
id="CENTER_button_post_id_1"
>
<svg
fill="currentColor"
height="16"
version="1.1"
viewBox="0 0 24 24"
width="16"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M16,12A2,2 0 0,1 18,10A2,2 0 0,1 20,12A2,2 0 0,1 18,14A2,2 0 0,1 16,12M10,12A2,2 0 0,1 12,10A2,2 0 0,1 14,12A2,2 0 0,1 12,14A2,2 0 0,1 10,12M4,12A2,2 0 0,1 6,10A2,2 0 0,1 8,12A2,2 0 0,1 6,14A2,2 0 0,1 4,12Z"
/>
</svg>
</button>
</div>,
"debug": [Function],
"findAllByAltText": [Function],
"findAllByDisplayValue": [Function],
"findAllByLabelText": [Function],
"findAllByPlaceholderText": [Function],
"findAllByRole": [Function],
"findAllByTestId": [Function],
"findAllByText": [Function],
"findAllByTitle": [Function],
"findByAltText": [Function],
"findByDisplayValue": [Function],
"findByLabelText": [Function],
"findByPlaceholderText": [Function],
"findByRole": [Function],
"findByTestId": [Function],
"findByText": [Function],
"findByTitle": [Function],
"getAllByAltText": [Function],
"getAllByDisplayValue": [Function],
"getAllByLabelText": [Function],
"getAllByPlaceholderText": [Function],
"getAllByRole": [Function],
"getAllByTestId": [Function],
"getAllByText": [Function],
"getAllByTitle": [Function],
"getByAltText": [Function],
"getByDisplayValue": [Function],
"getByLabelText": [Function],
"getByPlaceholderText": [Function],
"getByRole": [Function],
"getByTestId": [Function],
"getByText": [Function],
"getByTitle": [Function],
"queryAllByAltText": [Function],
"queryAllByDisplayValue": [Function],
"queryAllByLabelText": [Function],
"queryAllByPlaceholderText": [Function],
"queryAllByRole": [Function],
"queryAllByTestId": [Function],
"queryAllByText": [Function],
"queryAllByTitle": [Function],
"queryByAltText": [Function],
"queryByDisplayValue": [Function],
"queryByLabelText": [Function],
"queryByPlaceholderText": [Function],
"queryByRole": [Function],
"queryByTestId": [Function],
"queryByText": [Function],
"queryByTitle": [Function],
"rerender": [Function],
"unmount": [Function],
}
`;

Просмотреть файл

@@ -146,7 +146,6 @@ describe('components/dot_menu/DotMenu', () => {
threadReplyCount: 0,
userId: 'user_id_1',
isMilitaryTime: false,
showForwardPostNewLabel: false,
};
test('should match snapshot, on Center', () => {
@@ -181,32 +180,6 @@ describe('components/dot_menu/DotMenu', () => {
expect(wrapper).toMatchSnapshot();
});
test('should match snapshot, show "New" badge on forward post', () => {
const props = {
...baseProps,
showForwardPostNewLabel: true,
};
const wrapper = renderWithIntlAndStore(
<DotMenu {...props}/>,
initialState,
);
expect(wrapper).toMatchSnapshot();
});
test('should match snapshot, hide "New" badge on forward post', () => {
const props = {
...baseProps,
showForwardPostNewLabel: false,
};
const wrapper = renderWithIntlAndStore(
<DotMenu {...props}/>,
initialState,
);
expect(wrapper).toMatchSnapshot();
});
test('should show mark as unread when channel is not archived', () => {
const props = {
...baseProps,

Просмотреть файл

@@ -25,7 +25,7 @@ import {
import Permissions from 'mattermost-redux/constants/permissions';
import {Locations, ModalIdentifiers, Constants, TELEMETRY_LABELS, Preferences} from 'utils/constants';
import {Locations, ModalIdentifiers, Constants, TELEMETRY_LABELS} from 'utils/constants';
import DeletePostModal from 'components/delete_post_modal';
import DelayedAction from 'utils/delayed_action';
import * as PostUtils from 'utils/post_utils';
@@ -33,12 +33,10 @@ import * as Menu from 'components/menu';
import * as Utils from 'utils/utils';
import ChannelPermissionGate from 'components/permissions_gates/channel_permission_gate';
import {ModalData} from 'types/actions';
import {PluginComponent} from 'types/store/plugins';
import {UserThread} from '@mattermost/types/threads';
import {Post} from '@mattermost/types/posts';
import ForwardPostModal from '../forward_post_modal';
import Tag from '../widgets/tag/tag';
import {ChangeEvent, trackDotMenuEvent} from './utils';
@@ -70,20 +68,11 @@ type Props = {
postEditTimeLimit?: string; // TechDebt: Made non-mandatory while converting to typescript
enableEmojiPicker?: boolean; // TechDebt: Made non-mandatory while converting to typescript
channelIsArchived?: boolean; // TechDebt: Made non-mandatory while converting to typescript
currentTeamUrl?: string; // TechDebt: Made non-mandatory while converting to typescript
teamUrl?: string; // TechDebt: Made non-mandatory while converting to typescript
isMobileView: boolean;
showForwardPostNewLabel: boolean;
timezone?: string;
isMilitaryTime: boolean;
/**
* Components for overriding provided by plugins
*/
components: {
[componentName: string]: PluginComponent[];
};
actions: {
/**
@@ -292,9 +281,6 @@ export class DotMenuClass extends React.PureComponent<Props, State> {
},
};
if (this.props.showForwardPostNewLabel) {
this.props.actions.setGlobalItem(Preferences.FORWARD_POST_VIEWED, false);
}
this.props.actions.openModal(forwardPostModalData);
}
@@ -441,15 +427,6 @@ export class DotMenuClass extends React.PureComponent<Props, State> {
id='forward_post_button.label'
defaultMessage='Forward'
/>
{this.props.showForwardPostNewLabel && (
<Tag
variant='success'
text={formatMessage({
id: 'tag.default.new',
defaultMessage: 'NEW',
})}
/>
)}
</span>
);
@@ -519,12 +496,12 @@ export class DotMenuClass extends React.PureComponent<Props, State> {
class: classNames('post-menu__item', {
'post-menu__item--active': this.props.isMenuOpen,
}),
'aria-label': this.props.intl.formatMessage({id: 'post_info.dot_menu.tooltip.more_actions', defaultMessage: 'Actions'}),
'aria-label': formatMessage({id: 'post_info.dot_menu.tooltip.more_actions', defaultMessage: 'Actions'}),
children: <DotsHorizontalIcon size={16}/>,
}}
menu={{
id: `${this.props.location}_dropdown_${this.props.post.id}`,
'aria-label': this.props.intl.formatMessage({id: 'post_info.menuAriaLabel', defaultMessage: 'Post extra options'}),
'aria-label': formatMessage({id: 'post_info.menuAriaLabel', defaultMessage: 'Post extra options'}),
onKeyDown: this.onShortcutKeyDown,
width: '264px',
onToggle: this.handleMenuToggle,
@@ -532,7 +509,7 @@ export class DotMenuClass extends React.PureComponent<Props, State> {
}}
menuButtonTooltip={{
id: `PostDotMenu-ButtonTooltip-${this.props.post.id}`,
text: this.props.intl.formatMessage({id: 'post_info.dot_menu.tooltip.more_actions', defaultMessage: 'More'}),
text: formatMessage({id: 'post_info.dot_menu.tooltip.more_actions', defaultMessage: 'More'}),
class: 'hidden-xs',
}}
>

Просмотреть файл

@@ -59,7 +59,6 @@ describe('components/dot_menu/DotMenu returning empty ("")', () => {
threadId: 'post_id_1',
userId: 'user_id_1',
isMilitaryTime: false,
showForwardPostNewLabel: false,
};
const wrapper = shallow(

Просмотреть файл

@@ -59,7 +59,6 @@ describe('components/dot_menu/DotMenu on mobile view', () => {
threadId: 'post_id_1',
userId: 'user_id_1',
isMilitaryTime: false,
showForwardPostNewLabel: false,
};
const wrapper = shallow(

Просмотреть файл

@@ -44,7 +44,6 @@ import {matchUserMentionTriggersWithMessageMentions} from 'utils/post_utils';
import {Post} from '@mattermost/types/posts';
import {setGlobalItem} from '../../actions/storage';
import {getGlobalItem} from '../../selectors/storage';
import DotMenu from './dot_menu';
@@ -110,8 +109,6 @@ function makeMapStateToProps() {
}
}
const showForwardPostNewLabel = getGlobalItem(state, Preferences.FORWARD_POST_VIEWED, true);
return {
channelIsArchived: isArchivedChannel(channel),
components: state.plugins.components,
@@ -129,7 +126,6 @@ function makeMapStateToProps() {
isCollapsedThreadsEnabled: collapsedThreads,
threadReplyCount,
isMobileView: getIsMobileView(state),
showForwardPostNewLabel,
timezone: getCurrentUserTimezone(state),
isMilitaryTime,
};

Просмотреть файл

@@ -4,7 +4,6 @@
import {connect, ConnectedProps} from 'react-redux';
import {AnyAction, bindActionCreators, Dispatch} from 'redux';
import {showActionsDropdownPulsatingDot} from 'selectors/actions_menu';
import {setActionsMenuInitialisationState} from 'mattermost-redux/actions/preferences';
import {getConfig} from 'mattermost-redux/selectors/entities/general';
import {getPost, makeGetCommentCountForPost, makeIsPostCommentMention, isPostAcknowledgementsEnabled, isPostPriorityEnabled, UserActivityPost} from 'mattermost-redux/selectors/entities/posts';
@@ -13,7 +12,6 @@ import {
get,
getBool,
isCollapsedThreadsEnabled,
onboardingTourTipsEnabled,
} from 'mattermost-redux/selectors/entities/preferences';
import {getCurrentTeam, getCurrentTeamId, getTeam, getTeamMemberships} from 'mattermost-redux/selectors/entities/teams';
import {getCurrentUserId, getUser} from 'mattermost-redux/selectors/entities/users';
@@ -129,8 +127,7 @@ function makeMapStateToProps() {
const user = getUser(state, post.user_id);
const isBot = Boolean(user && user.is_bot);
const highlightedPostId = getHighlightedPostId(state);
const showActionsMenuPulsatingDot = showActionsDropdownPulsatingDot(state);
const tourTipsEnabled = onboardingTourTipsEnabled(state);
const selectedCard = getSelectedPostCard(state);
let emojis: Emoji[] = [];
@@ -203,8 +200,7 @@ function makeMapStateToProps() {
compactDisplay: get(state, Preferences.CATEGORY_DISPLAY_SETTINGS, Preferences.MESSAGE_DISPLAY, Preferences.MESSAGE_DISPLAY_DEFAULT) === Preferences.MESSAGE_DISPLAY_COMPACT,
colorizeUsernames: get(state, Preferences.CATEGORY_DISPLAY_SETTINGS, Preferences.COLORIZE_USERNAMES, Preferences.COLORIZE_USERNAMES_DEFAULT) === 'true',
shouldShowActionsMenu: shouldShowActionsMenu(state, post),
showActionsMenuPulsatingDot,
tourTipsEnabled,
shortcutReactToLastPostEmittedFrom,
isBot,
collapsedThreadsEnabled: isCollapsedThreadsEnabled(state),

Просмотреть файл

@@ -114,8 +114,6 @@ export type Props = {
isPostAcknowledgementsEnabled: boolean;
isPostPriorityEnabled: boolean;
isCardOpen?: boolean;
shouldShowDotMenu: boolean;
tourTipsEnabled: boolean;
};
const PostComponent = (props: Props): JSX.Element => {

Просмотреть файл

@@ -5,7 +5,7 @@ import React, {ReactNode, useEffect, useRef, useState} from 'react';
import {FormattedMessage} from 'react-intl';
import {Posts, Preferences} from 'mattermost-redux/constants/index';
import {Posts} from 'mattermost-redux/constants/index';
import {isPostEphemeral} from 'mattermost-redux/utils/post_utils';
import {Locations} from 'utils/constants';
@@ -34,8 +34,6 @@ type Props = {
handleDropdownOpened?: (e: boolean) => void;
collapsedThreadsEnabled?: boolean;
shouldShowActionsMenu?: boolean;
showActionsMenuPulsatingDot?: boolean;
tourTipsEnabled: boolean;
oneClickReactionsEnabled?: boolean;
recentEmojis: Emoji[];
isExpanded?: boolean;
@@ -51,7 +49,6 @@ type Props = {
shortcutReactToLastPostEmittedFrom?: string;
isPostHeaderVisible?: boolean | null;
isPostBeingEdited?: boolean;
shouldShowDotMenu: boolean;
actions: {
emitShortcutReactToLastPostFrom: (emittedFrom: 'CENTER' | 'RHS_ROOT' | 'NO_WHERE') => void;
};
@@ -63,7 +60,6 @@ const PostOptions = (props: Props): JSX.Element => {
const [showEmojiPicker, setShowEmojiPicker] = useState(false);
const [showDotMenu, setShowDotMenu] = useState(false);
const [showActionsMenu, setShowActionsMenu] = useState(false);
const [showActionTip, setShowActionTip] = useState(false);
useEffect(() => {
if (props.isLastPost &&
@@ -80,8 +76,6 @@ const PostOptions = (props: Props): JSX.Element => {
isReadOnly,
post,
oneClickReactionsEnabled,
showActionsMenuPulsatingDot,
tourTipsEnabled,
isMobileView,
} = props;
@@ -102,34 +96,14 @@ const PostOptions = (props: Props): JSX.Element => {
};
const handleActionsMenuOpened = (open: boolean) => {
if (tourTipsEnabled && showActionsMenuPulsatingDot) {
setShowActionTip(true);
return;
}
setShowActionsMenu(open);
props.handleDropdownOpened!(open);
};
const handleActionsMenuTipOpened = () => {
setShowActionTip(true);
props.handleDropdownOpened!(true);
};
const handleActionsMenuGotItClick = () => {
props.setActionsMenuInitialisationState?.(({[Preferences.ACTIONS_MENU_VIEWED]: true}));
setShowActionTip(false);
props.handleDropdownOpened!(false);
};
const handleTipDismissed = () => {
setShowActionTip(false);
props.handleDropdownOpened!(false);
};
const getDotMenuRef = () => dotMenuRef.current;
const isPostDeleted = post && post.state === Posts.POST_DELETED;
const hoverLocal = props.hover || showEmojiPicker || showDotMenu || showActionsMenu || showActionTip;
const hoverLocal = props.hover || showEmojiPicker || showDotMenu || showActionsMenu;
const showCommentIcon = isFromAutoResponder || (!systemMessage && (isMobileView ||
hoverLocal || (!post.root_id && Boolean(props.hasReplies)) ||
props.isFirstReply) && props.location === Locations.CENTER);
@@ -197,11 +171,6 @@ const PostOptions = (props: Props): JSX.Element => {
location={props.location}
handleDropdownOpened={handleActionsMenuOpened}
isMenuOpen={showActionsMenu}
showPulsatingDot={tourTipsEnabled && showActionsMenuPulsatingDot}
showTutorialTip={tourTipsEnabled && showActionTip}
handleOpenTip={handleActionsMenuTipOpened}
handleNextTip={handleActionsMenuGotItClick}
handleDismissTip={handleTipDismissed}
/>
);
const dotMenu = (
@@ -231,7 +200,7 @@ const PostOptions = (props: Props): JSX.Element => {
</button>
</div>
);
} else if (isPostDeleted || !props.shouldShowDotMenu) {
} else if (isPostDeleted) {
options = null;
} else if (props.location === Locations.SEARCH) {
const hasCRTFooter = props.collapsedThreadsEnabled && !post.root_id && (post.reply_count > 0 || post.is_following);

Просмотреть файл

@@ -27,7 +27,6 @@ type Props = {
previousPostId: string;
teamId: string;
timestampProps?: Partial<TimestampProps>;
lastPost: Post;
};
function noop() {}

Просмотреть файл

@@ -403,7 +403,6 @@ class ThreadViewerVirtualized extends PureComponent<Props, State> {
previousPostId={getPreviousPostId(data, index)}
teamId={this.props.teamId}
timestampProps={this.props.useRelativeTimestamp ? THREADING_TIME : undefined}
lastPost={this.props.lastPost}
/>
</div>
);

Просмотреть файл

@@ -11,6 +11,7 @@ import {makeGetCustomStatus, getRecentCustomStatuses, isCustomStatusEnabled, sho
import {TestHelper} from 'utils/test_helper';
import {CustomStatusDuration} from '@mattermost/types/users';
import {addTimeToTimestamp, TimeInformation} from 'utils/utils';
jest.mock('mattermost-redux/selectors/entities/users');
jest.mock('mattermost-redux/selectors/entities/general');
@@ -86,6 +87,7 @@ describe('isCustomStatusEnabled', () => {
});
describe('showStatusDropdownPulsatingDot and showPostHeaderUpdateStatusButton', () => {
const user = TestHelper.getUserMock();
const preference = {
myPreference: {
value: '',
@@ -104,4 +106,31 @@ describe('showStatusDropdownPulsatingDot and showPostHeaderUpdateStatusButton',
(PreferenceSelectors.get as jest.Mock).mockReturnValue(preference.myPreference.value);
expect(showPostHeaderUpdateStatusButton(store.getState())).toBeFalsy();
});
it('should return false if user was created less than seven days before from today', async () => {
const store = await configureStore();
(PreferenceSelectors.get as jest.Mock).mockReturnValue(preference.myPreference.value);
const todayTimestamp = new Date().getTime();
// set the user create date to 6 days in the past from today
const todayMinusSixDays = addTimeToTimestamp(todayTimestamp, TimeInformation.DAYS, 6, TimeInformation.PAST);
const newUser = {...user, create_at: todayMinusSixDays};
newUser.props.customStatus = JSON.stringify(customStatus);
(UserSelectors.getCurrentUser as jest.Mock).mockReturnValue(newUser);
expect(showStatusDropdownPulsatingDot(store.getState())).toBeFalsy();
});
it('should return true if user was created more than seven days before from today', async () => {
const store = await configureStore();
preference.myPreference.value = JSON.stringify({[Preferences.CUSTOM_STATUS_MODAL_VIEWED]: false});
(PreferenceSelectors.get as jest.Mock).mockReturnValue(preference.myPreference.value);
const todayTimestamp = new Date().getTime();
// set the user create date to 8 days in the past from today
const todayMinusEightDays = addTimeToTimestamp(todayTimestamp, TimeInformation.DAYS, 8, TimeInformation.PAST);
const newUser = {...user, create_at: todayMinusEightDays};
newUser.props.customStatus = JSON.stringify(customStatus);
(UserSelectors.getCurrentUser as jest.Mock).mockReturnValue(newUser);
expect(showStatusDropdownPulsatingDot(store.getState())).toBeTruthy();
});
});

Просмотреть файл

@@ -12,6 +12,8 @@ import {get} from 'mattermost-redux/selectors/entities/preferences';
import {Preferences} from 'mattermost-redux/constants';
import {CustomStatusDuration, UserCustomStatus} from '@mattermost/types/users';
import {isDateWithinDaysRange, TimeInformation} from 'utils/utils';
import {GlobalState} from 'types/store';
import {getCurrentUserTimezone} from 'selectors/general';
import {getCurrentMomentForTimezone} from 'utils/timezone';
@@ -56,9 +58,12 @@ export function isCustomStatusEnabled(state: GlobalState) {
}
function showCustomStatusPulsatingDotAndPostHeader(state: GlobalState) {
// only show this for users after the first seven days
const currentUser = getCurrentUser(state);
const hasUserCreationMoreThanSevenDays = isDateWithinDaysRange(currentUser?.create_at, 7, TimeInformation.FUTURE);
const customStatusTutorialState = get(state, Preferences.CATEGORY_CUSTOM_STATUS, Preferences.NAME_CUSTOM_STATUS_TUTORIAL_STATE);
const modalAlreadyViewed = customStatusTutorialState && JSON.parse(customStatusTutorialState)[Preferences.CUSTOM_STATUS_MODAL_VIEWED];
return !modalAlreadyViewed;
return !modalAlreadyViewed && hasUserCreationMoreThanSevenDays;
}
export function showStatusDropdownPulsatingDot(state: GlobalState) {

Просмотреть файл

@@ -90,6 +90,23 @@ const CLICKABLE_ELEMENTS = [
'audio',
'video',
];
const MS_PER_SECOND = 1000;
const MS_PER_MINUTE = 60 * MS_PER_SECOND;
const MS_PER_HOUR = 60 * MS_PER_MINUTE;
const MS_PER_DAY = 24 * MS_PER_HOUR;
export enum TimeInformation {
MILLISECONDS = 'm',
SECONDS = 's',
MINUTES = 'x',
HOURS = 'h',
DAYS = 'd',
FUTURE = 'f',
PAST = 'p'
}
export type TimeUnit = Exclude<TimeInformation, TimeInformation.FUTURE | TimeInformation.PAST>;
export type TimeDirection = TimeInformation.FUTURE | TimeInformation.PAST;
export function isMac() {
return navigator.platform.toUpperCase().indexOf('MAC') >= 0;
@@ -256,7 +273,6 @@ export function getTimestamp(): number {
}
export function getRemainingDaysFromFutureTimestamp(timestamp?: number): number {
const MS_PER_DAY = 24 * 60 * 60 * 1000;
const futureDate = new Date(timestamp as number);
const utcFuture = Date.UTC(futureDate.getFullYear(), futureDate.getMonth(), futureDate.getDate());
const today = new Date();
@@ -265,6 +281,39 @@ export function getRemainingDaysFromFutureTimestamp(timestamp?: number): number
return Math.floor((utcFuture - utcToday) / MS_PER_DAY);
}
export function addTimeToTimestamp(timestamp: number, type: TimeUnit, diff: number, timeline: TimeDirection) {
let modifier = 1;
switch (type) {
case TimeInformation.SECONDS:
modifier = MS_PER_SECOND;
break;
case TimeInformation.MINUTES:
modifier = MS_PER_MINUTE;
break;
case TimeInformation.HOURS:
modifier = MS_PER_HOUR;
break;
case TimeInformation.DAYS:
modifier = MS_PER_DAY;
break;
}
return timeline === TimeInformation.FUTURE ? timestamp + (diff * modifier) : timestamp - (diff * modifier);
}
/**
* Verifies if a date is in a particular given range of days from today
* @param timestamp date you want to check is in the range of the provided number of days from today
* @param days number of days you want to check your date against to
* @param timeline 'f' represents future, 'p' represents past
* @returns boolean, true if your date is in the range of the provided number of days
*/
export function isDateWithinDaysRange(timestamp: number, days: number, timeline: TimeDirection): boolean {
const today = new Date().getTime();
const daysSince = Math.round((today - timestamp) / MS_PER_DAY);
return timeline === TimeInformation.PAST ? daysSince <= days : daysSince >= days;
}
export function getLocaleDateFromUTC(timestamp: number, format = 'YYYY/MM/DD HH:mm:ss', userTimezone = '') {
if (!timestamp) {
return moment.now();