MM-49393 Remove Utils.isMobile (#24271)

* Switch Utils.isMobile to getIsMobileView in most places

* Copy Utils.isMobile into menu widgets

* Actually remove Utils.isMobile

* Remove pointless checkAndSetMobileView action

* Fix incorrect import of UserProfile

* Fix unit test
This commit is contained in:
Harrison Healey 2023-09-01 12:20:45 -04:00 committed by GitHub
parent 47e18ea829
commit b17daf79b1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
30 changed files with 143 additions and 143 deletions

View File

@ -273,8 +273,6 @@ export class ActionMenuClass extends React.PureComponent<Props, State> {
return null;
}
// const isMobile = this.props.isMobileView TODO;
const pluginItems = this.props.pluginMenuItems?.
filter((item) => {
return item.filter ? item.filter(this.props.post.id) : item;

View File

@ -15,10 +15,9 @@ import {ActionFunc} from 'mattermost-redux/types/actions';
import {GlobalState} from 'types/store';
import {isMobile} from 'utils/utils';
import {getNavigationBlocked} from 'selectors/views/admin';
import {getAdminDefinition, getConsoleAccess} from 'selectors/admin_console';
import {getNavigationBlocked} from 'selectors/views/admin';
import {getIsMobileView} from 'selectors/views/browser';
import {OnboardingTaskCategory, OnboardingTaskList} from 'components/onboarding_tasks';
@ -33,7 +32,7 @@ function mapStateToProps(state: GlobalState) {
const consoleAccess = getConsoleAccess(state);
const taskListStatus = getBool(state, OnboardingTaskCategory, OnboardingTaskList.ONBOARDING_TASK_LIST_SHOW);
const isUserFirstAdmin = isFirstAdmin(state);
const isMobileView = isMobile();
const isMobileView = getIsMobileView(state);
const showTaskList = isUserFirstAdmin && taskListStatus && !isMobileView;
const subscriptionProduct = getSubscriptionProduct(state);

View File

@ -107,6 +107,11 @@ const initialState = {
config: {PostEditTimeLimit: -1},
},
},
views: {
browser: {
windowSize: '',
},
},
};
describe('channel_info_rhs/about_area_gm', () => {

View File

@ -160,14 +160,14 @@ export default class LinkingLandingPage extends PureComponent<Props, State> {
renderGoNativeAppMessage = () => {
return (
<a
href={Utils.isMobile() ? '#' : this.state.nativeLocation}
href={UserAgent.isMobile() ? '#' : this.state.nativeLocation}
onMouseDown={() => {
this.setPreference(LandingPreferenceTypes.MATTERMOSTAPP, true);
}}
onClick={() => {
this.setPreference(LandingPreferenceTypes.MATTERMOSTAPP, true);
this.setState({redirectPage: true, navigating: true});
if (Utils.isMobile()) {
if (UserAgent.isMobile()) {
if (UserAgent.isAndroidWeb()) {
const timeout = setTimeout(() => {
window.location.replace(this.getDownloadLink()!);

View File

@ -22,14 +22,6 @@ const suggestionProviders = [
new SearchUserProvider(jest.fn()),
];
jest.mock('utils/utils', () => {
const original = jest.requireActual('utils/utils');
return {
...original,
isMobile: jest.fn(() => false),
};
});
const wrapIntl = (component: JSX.Element) => (
<IntlProvider
locale={'en'}

View File

@ -8,6 +8,7 @@ import {getConfig} from 'mattermost-redux/selectors/entities/general';
import {getCurrentTeam} from 'mattermost-redux/selectors/entities/teams';
import {openMenu as openRhsMenu} from 'actions/views/rhs';
import {getIsRhsMenuOpen} from 'selectors/rhs';
import {getIsMobileView} from 'selectors/views/browser';
import {GlobalState} from 'types/store';
@ -23,6 +24,7 @@ function mapStateToProps(state: GlobalState) {
return {
teamDisplayName: currentTeam && currentTeam.display_name,
isMobileView: getIsMobileView(state),
isOpen: getIsRhsMenuOpen(state),
siteName,
};

View File

@ -8,7 +8,6 @@ import {CSSTransition} from 'react-transition-group';
import * as GlobalActions from 'actions/global_actions';
import {Constants} from 'utils/constants';
import * as Utils from 'utils/utils';
import MainMenu from 'components/main_menu';
@ -17,6 +16,7 @@ type Action = {
}
type Props = {
isMobileView: boolean;
isOpen: boolean;
teamDisplayName?: string;
siteName?: string;
@ -42,7 +42,7 @@ export default class SidebarRightMenu extends React.PureComponent<Props> {
return (
<div
className={classNames('sidebar--menu', {'move--left': this.props.isOpen && Utils.isMobile()})}
className={classNames('sidebar--menu', {'move--left': this.props.isOpen && this.props.isMobileView})}
id='sidebar-menu'
>
<div className='team__header theme'>
@ -56,7 +56,7 @@ export default class SidebarRightMenu extends React.PureComponent<Props> {
<div className='nav-pills__container mobile-main-menu'>
<CSSTransition
in={this.props.isOpen && Utils.isMobile()}
in={this.props.isOpen && this.props.isMobileView}
classNames='MobileRightSidebarMenu'
enter={true}
exit={true}

View File

@ -10,6 +10,8 @@ import {Permissions} from 'mattermost-redux/constants';
import {haveITeamPermission} from 'mattermost-redux/selectors/entities/roles';
import {ActionResult, GenericAction} from 'mattermost-redux/types/actions';
import {getIsMobileView} from 'selectors/views/browser';
import {GlobalState} from 'types/store/index';
import {Team} from '@mattermost/types/teams';
@ -33,6 +35,7 @@ function mapStateToProps(state: GlobalState, ownProps: OwnProps) {
return {
maxFileSize,
canInviteTeamMembers,
isMobileView: getIsMobileView(state),
};
}

View File

@ -30,6 +30,7 @@ describe('components/TeamSettings', () => {
collapseModal: jest.fn(),
actions: baseActions,
canInviteTeamMembers: true,
isMobileView: false,
};
test('should handle bad updateTeamIcon function call', () => {

View File

@ -5,7 +5,7 @@ import React, {ChangeEvent, MouseEvent, ReactNode} from 'react';
import {FormattedMessage, FormattedDate} from 'react-intl';
import Constants from 'utils/constants';
import {imageURLForTeam, isMobile, localizeMessage, moveCursorToEnd} from 'utils/utils';
import {imageURLForTeam, localizeMessage, moveCursorToEnd} from 'utils/utils';
import {t} from 'utils/i18n';
import SettingItemMax from 'components/setting_item_max';
@ -390,7 +390,7 @@ export default class GeneralTab extends React.PureComponent<Props, State> {
if (this.props.activeSection === 'name') {
const inputs = [];
const teamNameLabel = isMobile() ? '' : (
const teamNameLabel = this.props.isMobileView ? '' : (
<FormattedMessage
id='general_tab.teamName'
defaultMessage='Team Name'
@ -449,7 +449,7 @@ export default class GeneralTab extends React.PureComponent<Props, State> {
if (this.props.activeSection === 'description') {
const inputs = [];
const teamDescriptionLabel = isMobile() ? '' : (
const teamDescriptionLabel = this.props.isMobileView ? '' : (
<FormattedMessage
id='general_tab.teamDescription'
defaultMessage='Team Description'
@ -557,7 +557,7 @@ export default class GeneralTab extends React.PureComponent<Props, State> {
/>
);
} else {
minMessage = isMobile() ? localizeMessage('general_tab.teamIconEditHintMobile', 'Click to upload an image') : localizeMessage('general_tab.teamIconEditHint', 'Click \'Edit\' to upload an image.');
minMessage = this.props.isMobileView ? localizeMessage('general_tab.teamIconEditHintMobile', 'Click to upload an image') : localizeMessage('general_tab.teamIconEditHint', 'Click \'Edit\' to upload an image.');
}
teamIconSection = (

View File

@ -13,9 +13,10 @@ import {Post} from '@mattermost/types/posts';
import {FakePost} from 'types/store/rhs';
import {getIsMobileView} from 'selectors/views/browser';
import {makePrepareReplyIdsForThreadViewer, makeGetThreadLastViewedAt} from 'selectors/views/threads';
import {GlobalState} from 'types/store';
import type {GlobalState} from 'types/store';
import ThreadViewerVirtualized from './virtualized_thread_viewer';
@ -51,6 +52,7 @@ function makeMapStateToProps() {
return {
currentUserId,
directTeammate,
isMobileView: getIsMobileView(state),
lastPost,
replyListIds,
lastViewedAt,

View File

@ -54,7 +54,6 @@ describe('components/threading/VirtualizedThreadViewer', () => {
socketConnectionStatus: true,
actions,
directTeammate,
isCollapsedThreadsEnabled: false,
posts: [post],
lastPost: post,
onCardClick: () => {},
@ -62,6 +61,7 @@ describe('components/threading/VirtualizedThreadViewer', () => {
replyListIds: [],
teamId: '',
useRelativeTimestamp: true,
isMobileView: false,
isThreadView: true,
lastViewedAt: 0,
newMessagesSeparatorActions: [],

View File

@ -36,6 +36,7 @@ type Props = {
replyListIds: string[];
selected: Post | FakePost;
useRelativeTimestamp: boolean;
isMobileView: boolean;
isThreadView: boolean;
lastViewedAt: number;
newMessagesSeparatorActions: PluginComponent[];
@ -43,7 +44,6 @@ type Props = {
type State = {
createCommentHeight: number;
isMobile: boolean;
isScrolling: boolean;
topRhsPostId?: string;
userScrolled: boolean;
@ -96,7 +96,6 @@ class ThreadViewerVirtualized extends PureComponent<Props, State> {
super(props);
const postIndex = this.getInitialPostIndex();
const isMobile = Utils.isMobile();
this.initRangeToRender = [
Math.max(postIndex - 30, 0),
@ -110,7 +109,6 @@ class ThreadViewerVirtualized extends PureComponent<Props, State> {
this.state = {
createCommentHeight: 0,
isMobile,
isScrolling: false,
userScrolled: false,
userScrolledToBottom: false,
@ -125,12 +123,10 @@ class ThreadViewerVirtualized extends PureComponent<Props, State> {
componentDidMount() {
this.mounted = true;
window.addEventListener('resize', this.handleWindowResize);
}
componentWillUnmount() {
this.mounted = false;
window.removeEventListener('resize', this.handleWindowResize);
}
componentDidUpdate(prevProps: Props) {
@ -156,15 +152,6 @@ class ThreadViewerVirtualized extends PureComponent<Props, State> {
return Promise.resolve();
}
handleWindowResize = () => {
const isMobile = Utils.isMobile();
if (isMobile !== this.state.isMobile) {
this.setState({
isMobile,
});
}
};
initScrollToIndex = (): {index: number; position: string; offset?: number} => {
const {highlightedPostId, replyListIds} = this.props;
@ -207,7 +194,7 @@ class ThreadViewerVirtualized extends PureComponent<Props, State> {
updatedState.userScrolled = true;
updatedState.userScrolledToBottom = userScrolledToBottom;
if (this.state.isMobile) {
if (this.props.isMobileView) {
if (!this.state.isScrolling) {
updatedState.isScrolling = true;
}
@ -241,7 +228,7 @@ class ThreadViewerVirtualized extends PureComponent<Props, State> {
overscanStartIndex,
overscanStopIndex,
}: OnItemsRenderedArgs) => {
if (this.state.isMobile) {
if (this.props.isMobileView) {
this.updateFloatingTimestamp(visibleStartIndex);
}
this.setState({
@ -434,11 +421,11 @@ class ThreadViewerVirtualized extends PureComponent<Props, State> {
};
render() {
const {isMobile, topRhsPostId} = this.state;
const {topRhsPostId} = this.state;
return (
<>
{isMobile && topRhsPostId && !this.props.useRelativeTimestamp && (
{this.props.isMobileView && topRhsPostId && !this.props.useRelativeTimestamp && (
<FloatingTimestamp
isRhsPost={true}
isScrolling={this.state.isScrolling}

View File

@ -6,7 +6,8 @@ import {connect} from 'react-redux';
import {getUser, makeGetDisplayName} from 'mattermost-redux/selectors/entities/users';
import {getTheme} from 'mattermost-redux/selectors/entities/preferences';
import {GlobalState} from '@mattermost/types/store';
import {getIsMobileView} from 'selectors/views/browser';
import {GlobalState} from 'types/store';
import UserProfile from './user_profile';
@ -25,6 +26,7 @@ function makeMapStateToProps() {
displayName: getDisplayName(state, ownProps.userId, true),
user,
theme,
isMobileView: getIsMobileView(state),
isShared: Boolean(user && user.remote_id),
};
};

View File

@ -13,6 +13,7 @@ describe('components/UserProfile', () => {
const baseProps = {
displayName: 'nickname',
isBusy: false,
isMobileView: false,
user: {username: 'username'} as UserProfileType,
userId: 'user_id',
theme: Preferences.THEMES.onyx,

View File

@ -12,7 +12,7 @@ import {UserProfile as UserProfileType} from '@mattermost/types/users';
import {Theme} from 'mattermost-redux/selectors/entities/preferences';
import {isGuest} from 'mattermost-redux/utils/user_utils';
import {imageURLForUser, isMobile} from 'utils/utils';
import {imageURLForUser} from 'utils/utils';
import OverlayTrigger, {BaseOverlayTrigger} from 'components/overlay_trigger';
import ProfilePopover from 'components/profile_popover';
@ -34,6 +34,7 @@ export type UserProfileProps = {
colorize?: boolean;
hasMention?: boolean;
hideStatus?: boolean;
isMobileView: boolean;
isRHS?: boolean;
channelId?: string;
theme?: Theme;
@ -68,6 +69,7 @@ export default class UserProfile extends PureComponent<UserProfileProps> {
displayName,
displayUsername,
isBusy,
isMobileView,
isRHS,
isShared,
hasMention,
@ -110,7 +112,7 @@ export default class UserProfile extends PureComponent<UserProfileProps> {
}
let placement = 'right';
if (isRHS && !isMobile()) {
if (isRHS && !isMobileView) {
placement = 'left';
}

View File

@ -13,9 +13,12 @@ import {
import {clearErrors, logError} from 'mattermost-redux/actions/errors';
import {getConfig} from 'mattermost-redux/selectors/entities/general';
import {GlobalState} from '@mattermost/types/store';
import {ActionFunc} from 'mattermost-redux/types/actions';
import {getIsMobileView} from 'selectors/views/browser';
import type {GlobalState} from 'types/store';
import UserSettingsGeneralTab, {Props} from './user_settings_general';
function mapStateToProps(state: GlobalState) {
@ -34,6 +37,7 @@ function mapStateToProps(state: GlobalState) {
const ldapPictureAttributeSet = config.LdapPictureAttributeSet === 'true';
return {
isMobileView: getIsMobileView(state),
requireEmailVerification,
maxFileSize,
ldapFirstNameAttributeSet,

View File

@ -34,6 +34,7 @@ describe('components/user_settings/general/UserSettingsGeneral', () => {
activeSection: '',
closeModal: jest.fn(),
collapseModal: jest.fn(),
isMobileView: false,
actions: {
logError: jest.fn(),
clearErrors: jest.fn(),

View File

@ -101,6 +101,7 @@ export type Props = {
activeSection?: string;
closeModal: () => void;
collapseModal: () => void;
isMobileView: boolean;
maxFileSize: number;
actions: {
logError: ({message, type}: {message: any; type: string}, status: boolean) => void;
@ -934,7 +935,7 @@ export class UserSettingsGeneralTab extends React.Component<Props, State> {
defaultMessage="Click 'Edit' to add your full name"
/>
);
if (Utils.isMobile()) {
if (this.props.isMobileView) {
describe = (
<FormattedMessage
id='user.settings.general.mobile.emptyName'
@ -984,7 +985,7 @@ export class UserSettingsGeneralTab extends React.Component<Props, State> {
defaultMessage='Nickname'
/>
);
if (Utils.isMobile()) {
if (this.props.isMobileView) {
nicknameLabel = '';
}
@ -1046,7 +1047,7 @@ export class UserSettingsGeneralTab extends React.Component<Props, State> {
defaultMessage="Click 'Edit' to add a nickname"
/>
);
if (Utils.isMobile()) {
if (this.props.isMobileView) {
describe = (
<FormattedMessage
id='user.settings.general.mobile.emptyNickname'
@ -1086,7 +1087,7 @@ export class UserSettingsGeneralTab extends React.Component<Props, State> {
defaultMessage='Username'
/>
);
if (Utils.isMobile()) {
if (this.props.isMobileView) {
usernameLabel = '';
}
@ -1187,7 +1188,7 @@ export class UserSettingsGeneralTab extends React.Component<Props, State> {
defaultMessage='Position'
/>
);
if (Utils.isMobile()) {
if (this.props.isMobileView) {
positionLabel = '';
}
@ -1250,7 +1251,7 @@ export class UserSettingsGeneralTab extends React.Component<Props, State> {
defaultMessage="Click 'Edit' to add your job title / position"
/>
);
if (Utils.isMobile()) {
if (this.props.isMobileView) {
describe = (
<FormattedMessage
id='user.settings.general.mobile.emptyPosition'
@ -1332,7 +1333,7 @@ export class UserSettingsGeneralTab extends React.Component<Props, State> {
}
let minMessage: JSX.Element|string = formatMessage(holders.uploadImage);
if (Utils.isMobile()) {
if (this.props.isMobileView) {
minMessage = formatMessage(holders.uploadImageMobile);
}
if (user.last_picture_update > 0) {

View File

@ -0,0 +1,15 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {getIsMobileView} from 'selectors/views/browser';
import store from 'stores/redux_store';
/**
* @deprecated This is a horrible hack that shouldn't used done elsewhere because we shouldn't be accessing the global
* store directly, but it's too hard to get this value into these component properly without rewriting everything.
* These components will eventually be replaced by the newer components in `components/menu` anyway.
*/
export function isMobile() {
return getIsMobileView(store.getState());
}

View File

@ -171,3 +171,17 @@
}
}
}
.Menu__content {
&.openLeft {
right: 0;
left: inherit;
}
&.openUp {
@media screen and (min-width: 768px) {
top: auto;
bottom: 100%;
}
}
}

View File

@ -6,19 +6,15 @@ import {shallow} from 'enzyme';
import Menu from './menu';
jest.mock('./is_mobile_view_hack', () => ({
isMobile: jest.fn(() => false),
}));
(global as any).MutationObserver = class {
public disconnect() {}
public observe() {}
};
jest.mock('utils/utils', () => {
const original = jest.requireActual('utils/utils');
return {
...original,
isMobile: jest.fn(() => false),
};
});
describe('components/Menu', () => {
test('should match snapshot', () => {
const wrapper = shallow(<Menu ariaLabel='test-label'>{'text'}</Menu>);
@ -68,46 +64,7 @@ describe('components/Menu', () => {
`);
});
test('should match snapshot with openLeft and openUp when is mobile', () => {
const utils = require('utils/utils'); //eslint-disable-line global-require
utils.isMobile.mockReturnValue(true);
const wrapper = shallow(
<Menu
openLeft={true}
openUp={true}
ariaLabel='test-label'
>
{'text'}
</Menu>,
);
expect(wrapper).toMatchInlineSnapshot(`
<div
aria-label="test-label"
className="a11y__popup Menu"
role="menu"
>
<ul
className="Menu__content dropdown-menu"
onClick={[Function]}
style={
Object {
"left": "inherit",
"right": 0,
}
}
>
text
</ul>
</div>
`);
});
test('should match snapshot with openLeft and openUp', () => {
const utils = require('utils/utils'); //eslint-disable-line global-require
utils.isMobile.mockReturnValue(false);
const wrapper = shallow(
<Menu
openLeft={true}
@ -125,16 +82,9 @@ describe('components/Menu', () => {
role="menu"
>
<ul
className="Menu__content dropdown-menu"
className="Menu__content dropdown-menu openLeft openUp"
onClick={[Function]}
style={
Object {
"bottom": "100%",
"left": "inherit",
"right": 0,
"top": "auto",
}
}
style={Object {}}
>
text
</ul>
@ -143,8 +93,6 @@ describe('components/Menu', () => {
});
test('should hide the correct dividers', () => {
const utils = require('utils/utils'); //eslint-disable-line global-require
utils.isMobile.mockReturnValue(false);
const pseudoMenu = document.createElement('div');
const listOfItems = [
'menu-divider',
@ -255,8 +203,6 @@ describe('components/Menu', () => {
});
test('should hide the correct dividers on mobile', () => {
const utils = require('utils/utils'); //eslint-disable-line global-require
utils.isMobile.mockReturnValue(false);
const pseudoMenu = document.createElement('div');
const listOfItems = [
'mobile-menu-divider',

View File

@ -4,8 +4,6 @@
import React, {CSSProperties} from 'react';
import classNames from 'classnames';
import {isMobile} from 'utils/utils';
import SubMenuItem from './menu_items/submenu_item';
import MenuHeader from './menu_header';
@ -123,15 +121,6 @@ export default class Menu extends React.PureComponent<Props> {
let styles: CSSProperties = {};
if (customStyles) {
styles = customStyles;
} else {
if (openLeft) {
styles.left = 'inherit';
styles.right = 0;
}
if (openUp && !isMobile()) {
styles.bottom = '100%';
styles.top = 'auto';
}
}
return (
@ -145,7 +134,14 @@ export default class Menu extends React.PureComponent<Props> {
id={listId}
ref={this.node}
style={styles}
className={classNames('Menu__content dropdown-menu', this.props.className)}
className={classNames(
'Menu__content dropdown-menu',
{
openLeft,
openUp,
},
this.props.className,
)}
onClick={this.handleMenuClick}
>
{children}

View File

@ -8,6 +8,10 @@ import Constants from 'utils/constants';
import SubMenuItem from './submenu_item';
jest.mock('../is_mobile_view_hack', () => ({
isMobile: jest.fn(() => false),
}));
describe('components/widgets/menu/menu_items/submenu_item', () => {
test('empty subMenu should match snapshot', () => {
const wrapper = mount(

View File

@ -6,10 +6,13 @@ import classNames from 'classnames';
import * as Keyboard from 'utils/keyboard';
import * as Utils from 'utils/utils';
import {showMobileSubMenuModal} from 'actions/global_actions';
import type {Menu} from 'types/store/plugins';
import {isMobile as isMobileViewHack} from '../is_mobile_view_hack';
import './menu_item.scss';
import Constants from 'utils/constants';
@ -94,7 +97,7 @@ export default class SubMenuItem extends React.PureComponent<Props, State> {
private onClick = (event: React.SyntheticEvent<HTMLElement>) => {
event.preventDefault();
const {id, postId, subMenu, action, root, isHeader} = this.props;
const isMobile = Utils.isMobile();
const isMobile = isMobileViewHack();
if (isHeader) {
event.stopPropagation();
return;
@ -141,7 +144,7 @@ export default class SubMenuItem extends React.PureComponent<Props, State> {
public render() {
const {id, postId, text, selectedValueText, subMenu, icon, filter, ariaLabel, direction, styleSelectableItem, extraText, renderSelected, rightDecorator, tabIndex} = this.props;
const isMobile = Utils.isMobile();
const isMobile = isMobileViewHack();
if (filter && !filter(id)) {
return ('');

View File

@ -5,7 +5,11 @@ import React from 'react';
import {shallow, mount} from 'enzyme';
import {Modal} from 'react-bootstrap';
import SubMenuModal from 'components/widgets/menu/menu_modals/submenu_modal/submenu_modal';
import SubMenuModal from './submenu_modal';
jest.mock('../../is_mobile_view_hack', () => ({
isMobile: jest.fn(() => false),
}));
(global as any).MutationObserver = class {
public disconnect() {}

View File

@ -4,7 +4,7 @@
import React from 'react';
import {CSSTransition} from 'react-transition-group';
import {isMobile} from 'utils/utils';
import {isMobile} from './is_mobile_view_hack';
const ANIMATION_DURATION = 80;

View File

@ -35,6 +35,11 @@ describe('selectors/onboarding', () => {
profiles,
},
},
views: {
browser: {
windowSize: '',
},
},
} as unknown as GlobalState;
const [showTaskList, firstTimeOnboarding] = getShowTaskListBool(state);
@ -65,6 +70,11 @@ describe('selectors/onboarding', () => {
profiles,
},
},
views: {
browser: {
windowSize: '',
},
},
} as unknown as GlobalState;
const [showTaskList, firstTimeOnboarding] = getShowTaskListBool(state);
@ -95,6 +105,11 @@ describe('selectors/onboarding', () => {
profiles,
},
},
views: {
browser: {
windowSize: '',
},
},
} as unknown as GlobalState;
const [showTaskList, firstTimeOnboarding] = getShowTaskListBool(state);
@ -128,6 +143,11 @@ describe('selectors/onboarding', () => {
profiles,
},
},
views: {
browser: {
windowSize: '',
},
},
} as unknown as GlobalState;
const [showTaskList, firstTimeOnboarding] = getShowTaskListBool(state);
@ -165,6 +185,11 @@ describe('selectors/onboarding', () => {
profiles,
},
},
views: {
browser: {
windowSize: '',
},
},
} as unknown as GlobalState;
const [showTaskList, firstTimeOnboarding] = getShowTaskListBool(state);

View File

@ -1,14 +1,14 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {isMobile} from 'utils/utils';
import {createSelector} from 'mattermost-redux/selectors/create_selector';
import {makeGetCategory, getBool} from 'mattermost-redux/selectors/entities/preferences';
import {getCurrentUser, isFirstAdmin} from 'mattermost-redux/selectors/entities/users';
import {OnboardingTaskCategory, OnboardingTaskList} from 'components/onboarding_tasks';
import {getIsMobileView} from 'selectors/views/browser';
import {GlobalState} from 'types/store';
import {RecommendedNextStepsLegacy, Preferences} from 'utils/constants';
@ -125,9 +125,8 @@ export const getShowTaskListBool = createSelector(
(state: GlobalState) => state,
(state: GlobalState) => getCategory(state, OnboardingTaskCategory),
(state: GlobalState) => getCategory(state, Preferences.RECOMMENDED_NEXT_STEPS),
(state, onboardingPreferences, legacyStepsPreferences) => {
const isMobileView = isMobile();
getIsMobileView,
(state, onboardingPreferences, legacyStepsPreferences, isMobileView) => {
// conditions to validate scenario where users (initially first_admins) had already set any of the onboarding task list preferences values.
// We check wether the preference value exists meaning the onboarding tasks list already started no matter what the state of the process is
const hasUserStartedOnboardingTaskListProcess = onboardingPreferences?.some((pref) =>

View File

@ -47,12 +47,10 @@ import {searchForTerm} from 'actions/post_actions';
import {getHistory} from 'utils/browser_history';
import * as Keyboard from 'utils/keyboard';
import * as UserAgent from 'utils/user_agent';
import {isDesktopApp} from 'utils/user_agent';
import {t} from 'utils/i18n';
import store from 'stores/redux_store.jsx';
import {getCurrentLocale, getTranslations} from 'selectors/i18n';
import {getIsMobileView} from 'selectors/views/browser';
import {FileInfo} from '@mattermost/types/files';
import {Team} from '@mattermost/types/teams';
@ -890,10 +888,6 @@ export function isValidBotUsername(name: string) {
return error;
}
export function isMobile() {
return getIsMobileView(store.getState());
}
export function loadImage(
url: string,
onLoad: ((this: XMLHttpRequest, ev: ProgressEvent) => any) | null,
@ -1720,9 +1714,9 @@ const TrackFlowSources: Record<string, string> = {
};
function getTrackFlowSource() {
if (isMobile()) {
if (UserAgent.isMobile()) {
return TrackFlowSources.wm;
} else if (isDesktopApp()) {
} else if (UserAgent.isDesktopApp()) {
return TrackFlowSources.d;
}
return TrackFlowSources.wd;