mirror of
https://github.com/mattermost/mattermost.git
synced 2025-02-25 18:55:24 -06:00
Move logic to track mobile view into its own component (#24272)
* Move logic to track mobile view into its own component * Address feedback
This commit is contained in:
parent
17ff2049ec
commit
0fb6e5169d
17
webapp/channels/src/components/mobile_view_watcher/index.ts
Normal file
17
webapp/channels/src/components/mobile_view_watcher/index.ts
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||||
|
// See LICENSE.txt for license information.
|
||||||
|
|
||||||
|
import {connect} from 'react-redux';
|
||||||
|
import type {ConnectedProps} from 'react-redux';
|
||||||
|
|
||||||
|
import {emitBrowserWindowResized} from 'actions/views/browser';
|
||||||
|
|
||||||
|
import MobileViewWatcher from './mobile_view_watcher';
|
||||||
|
|
||||||
|
const mapDispatchToProps = {
|
||||||
|
emitBrowserWindowResized,
|
||||||
|
};
|
||||||
|
|
||||||
|
const connector = connect(null, mapDispatchToProps);
|
||||||
|
export type PropsFromRedux = ConnectedProps<typeof connector>;
|
||||||
|
export default connector(MobileViewWatcher);
|
@ -0,0 +1,68 @@
|
|||||||
|
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||||
|
// See LICENSE.txt for license information.
|
||||||
|
|
||||||
|
import {render} from '@testing-library/react';
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import matchMedia from 'tests/helpers/match_media.mock';
|
||||||
|
import Constants, {WindowSizes} from 'utils/constants';
|
||||||
|
|
||||||
|
import MobileViewWatcher from './mobile_view_watcher';
|
||||||
|
|
||||||
|
describe('window.matchMedia', () => {
|
||||||
|
const baseProps = {
|
||||||
|
emitBrowserWindowResized: jest.fn(),
|
||||||
|
};
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
matchMedia.clear();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should update redux when the desktop media query matches', () => {
|
||||||
|
render(<MobileViewWatcher {...baseProps}/>);
|
||||||
|
|
||||||
|
expect(baseProps.emitBrowserWindowResized).toBeCalledTimes(0);
|
||||||
|
|
||||||
|
matchMedia.useMediaQuery(`(min-width: ${Constants.DESKTOP_SCREEN_WIDTH + 1}px)`);
|
||||||
|
|
||||||
|
expect(baseProps.emitBrowserWindowResized).toBeCalledTimes(1);
|
||||||
|
|
||||||
|
expect(baseProps.emitBrowserWindowResized.mock.calls[0][0]).toBe(WindowSizes.DESKTOP_VIEW);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should update redux when the small desktop media query matches', () => {
|
||||||
|
render(<MobileViewWatcher {...baseProps}/>);
|
||||||
|
|
||||||
|
expect(baseProps.emitBrowserWindowResized).toBeCalledTimes(0);
|
||||||
|
|
||||||
|
matchMedia.useMediaQuery(`(min-width: ${Constants.TABLET_SCREEN_WIDTH + 1}px) and (max-width: ${Constants.DESKTOP_SCREEN_WIDTH}px)`);
|
||||||
|
|
||||||
|
expect(baseProps.emitBrowserWindowResized).toBeCalledTimes(1);
|
||||||
|
|
||||||
|
expect(baseProps.emitBrowserWindowResized.mock.calls[0][0]).toBe(WindowSizes.SMALL_DESKTOP_VIEW);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should update redux when the tablet media query matches', () => {
|
||||||
|
render(<MobileViewWatcher {...baseProps}/>);
|
||||||
|
|
||||||
|
expect(baseProps.emitBrowserWindowResized).toBeCalledTimes(0);
|
||||||
|
|
||||||
|
matchMedia.useMediaQuery(`(min-width: ${Constants.MOBILE_SCREEN_WIDTH + 1}px) and (max-width: ${Constants.TABLET_SCREEN_WIDTH}px)`);
|
||||||
|
|
||||||
|
expect(baseProps.emitBrowserWindowResized).toBeCalledTimes(1);
|
||||||
|
|
||||||
|
expect(baseProps.emitBrowserWindowResized.mock.calls[0][0]).toBe(WindowSizes.TABLET_VIEW);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should update redux when the mobile media query matches', () => {
|
||||||
|
render(<MobileViewWatcher {...baseProps}/>);
|
||||||
|
|
||||||
|
expect(baseProps.emitBrowserWindowResized).toBeCalledTimes(0);
|
||||||
|
|
||||||
|
matchMedia.useMediaQuery(`(max-width: ${Constants.MOBILE_SCREEN_WIDTH}px)`);
|
||||||
|
|
||||||
|
expect(baseProps.emitBrowserWindowResized).toBeCalledTimes(1);
|
||||||
|
|
||||||
|
expect(baseProps.emitBrowserWindowResized.mock.calls[0][0]).toBe(WindowSizes.MOBILE_VIEW);
|
||||||
|
});
|
||||||
|
});
|
@ -0,0 +1,55 @@
|
|||||||
|
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||||
|
// See LICENSE.txt for license information.
|
||||||
|
|
||||||
|
import {useCallback, useEffect, useLayoutEffect, useRef} from 'react';
|
||||||
|
|
||||||
|
import Constants, {WindowSizes} from 'utils/constants';
|
||||||
|
|
||||||
|
import type {PropsFromRedux} from './index';
|
||||||
|
|
||||||
|
type Props = PropsFromRedux;
|
||||||
|
|
||||||
|
export default function MobileViewWatcher(props: Props) {
|
||||||
|
const desktopMediaQuery = useRef(window.matchMedia(`(min-width: ${Constants.DESKTOP_SCREEN_WIDTH + 1}px)`));
|
||||||
|
const smallDesktopMediaQuery = useRef(window.matchMedia(`(min-width: ${Constants.TABLET_SCREEN_WIDTH + 1}px) and (max-width: ${Constants.DESKTOP_SCREEN_WIDTH}px)`));
|
||||||
|
const tabletMediaQuery = useRef(window.matchMedia(`(min-width: ${Constants.MOBILE_SCREEN_WIDTH + 1}px) and (max-width: ${Constants.TABLET_SCREEN_WIDTH}px)`));
|
||||||
|
const mobileMediaQuery = useRef(window.matchMedia(`(max-width: ${Constants.MOBILE_SCREEN_WIDTH}px)`));
|
||||||
|
|
||||||
|
const updateWindowSize = useCallback(() => {
|
||||||
|
if (desktopMediaQuery.current.matches) {
|
||||||
|
props.emitBrowserWindowResized(WindowSizes.DESKTOP_VIEW);
|
||||||
|
} else if (smallDesktopMediaQuery.current.matches) {
|
||||||
|
props.emitBrowserWindowResized(WindowSizes.SMALL_DESKTOP_VIEW);
|
||||||
|
} else if (tabletMediaQuery.current.matches) {
|
||||||
|
props.emitBrowserWindowResized(WindowSizes.TABLET_VIEW);
|
||||||
|
} else if (mobileMediaQuery.current.matches) {
|
||||||
|
props.emitBrowserWindowResized(WindowSizes.MOBILE_VIEW);
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useLayoutEffect(() => {
|
||||||
|
updateWindowSize();
|
||||||
|
}, [updateWindowSize]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const handleMediaQueryChangeEvent = (e: MediaQueryListEvent) => {
|
||||||
|
if (e.matches) {
|
||||||
|
updateWindowSize();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
desktopMediaQuery.current.addEventListener('change', handleMediaQueryChangeEvent);
|
||||||
|
smallDesktopMediaQuery.current.addEventListener('change', handleMediaQueryChangeEvent);
|
||||||
|
tabletMediaQuery.current.addEventListener('change', handleMediaQueryChangeEvent);
|
||||||
|
mobileMediaQuery.current.addEventListener('change', handleMediaQueryChangeEvent);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
desktopMediaQuery.current.removeEventListener('change', handleMediaQueryChangeEvent);
|
||||||
|
smallDesktopMediaQuery.current.removeEventListener('change', handleMediaQueryChangeEvent);
|
||||||
|
tabletMediaQuery.current.removeEventListener('change', handleMediaQueryChangeEvent);
|
||||||
|
mobileMediaQuery.current.removeEventListener('change', handleMediaQueryChangeEvent);
|
||||||
|
};
|
||||||
|
}, [updateWindowSize]);
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
exports[`components/Root Routes Should mount public product routes 1`] = `
|
exports[`components/Root Routes Should mount public product routes 1`] = `
|
||||||
<RootProvider>
|
<RootProvider>
|
||||||
|
<Connect(MobileViewWatcher) />
|
||||||
<Switch>
|
<Switch>
|
||||||
<Route
|
<Route
|
||||||
component={[Function]}
|
component={[Function]}
|
||||||
|
@ -15,7 +15,6 @@ import {shouldShowTermsOfService, getCurrentUserId} from 'mattermost-redux/selec
|
|||||||
import type {Action} from 'mattermost-redux/types/actions';
|
import type {Action} from 'mattermost-redux/types/actions';
|
||||||
|
|
||||||
import {migrateRecentEmojis} from 'actions/emoji_actions';
|
import {migrateRecentEmojis} from 'actions/emoji_actions';
|
||||||
import {emitBrowserWindowResized} from 'actions/views/browser';
|
|
||||||
import {loadConfigAndMe, registerCustomPostRenderer} from 'actions/views/root';
|
import {loadConfigAndMe, registerCustomPostRenderer} from 'actions/views/root';
|
||||||
import {getShowLaunchingWorkspace} from 'selectors/onboarding';
|
import {getShowLaunchingWorkspace} from 'selectors/onboarding';
|
||||||
import {shouldShowAppBar} from 'selectors/plugins';
|
import {shouldShowAppBar} from 'selectors/plugins';
|
||||||
@ -65,7 +64,6 @@ function mapDispatchToProps(dispatch: Dispatch) {
|
|||||||
return {
|
return {
|
||||||
actions: bindActionCreators<ActionCreatorsMapObject<Action>, Actions>({
|
actions: bindActionCreators<ActionCreatorsMapObject<Action>, Actions>({
|
||||||
loadConfigAndMe,
|
loadConfigAndMe,
|
||||||
emitBrowserWindowResized,
|
|
||||||
getFirstAdminSetupComplete,
|
getFirstAdminSetupComplete,
|
||||||
getProfiles,
|
getProfiles,
|
||||||
migrateRecentEmojis,
|
migrateRecentEmojis,
|
||||||
|
@ -1,9 +1,6 @@
|
|||||||
// 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.
|
||||||
|
|
||||||
// side-effect necessary before other imports
|
|
||||||
import matchMedia from 'tests/helpers/match_media.mock'; // eslint-disable-line import/order
|
|
||||||
|
|
||||||
import {shallow} from 'enzyme';
|
import {shallow} from 'enzyme';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import type {RouteComponentProps} from 'react-router-dom';
|
import type {RouteComponentProps} from 'react-router-dom';
|
||||||
@ -20,7 +17,7 @@ import store from 'stores/redux_store.jsx';
|
|||||||
|
|
||||||
import Root from 'components/root/root';
|
import Root from 'components/root/root';
|
||||||
|
|
||||||
import Constants, {StoragePrefixes, WindowSizes} from 'utils/constants';
|
import {StoragePrefixes} from 'utils/constants';
|
||||||
|
|
||||||
import type {ProductComponent} from 'types/store/plugins';
|
import type {ProductComponent} from 'types/store/plugins';
|
||||||
|
|
||||||
@ -67,7 +64,6 @@ describe('components/Root', () => {
|
|||||||
data: false,
|
data: false,
|
||||||
});
|
});
|
||||||
}),
|
}),
|
||||||
emitBrowserWindowResized: () => {},
|
|
||||||
getFirstAdminSetupComplete: jest.fn(() => Promise.resolve({
|
getFirstAdminSetupComplete: jest.fn(() => Promise.resolve({
|
||||||
type: GeneralTypes.FIRST_ADMIN_COMPLETE_SETUP_RECEIVED,
|
type: GeneralTypes.FIRST_ADMIN_COMPLETE_SETUP_RECEIVED,
|
||||||
data: true,
|
data: true,
|
||||||
@ -270,88 +266,6 @@ describe('components/Root', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('window.matchMedia', () => {
|
|
||||||
afterEach(() => {
|
|
||||||
matchMedia.clear();
|
|
||||||
});
|
|
||||||
|
|
||||||
test('should update redux when the desktop media query matches', () => {
|
|
||||||
const props = {
|
|
||||||
...baseProps,
|
|
||||||
actions: {
|
|
||||||
...baseProps.actions,
|
|
||||||
emitBrowserWindowResized: jest.fn(),
|
|
||||||
},
|
|
||||||
};
|
|
||||||
const wrapper = shallow(<Root {...props}/>);
|
|
||||||
|
|
||||||
matchMedia.useMediaQuery(`(min-width: ${Constants.DESKTOP_SCREEN_WIDTH + 1}px)`);
|
|
||||||
|
|
||||||
expect(props.actions.emitBrowserWindowResized).toBeCalledTimes(1);
|
|
||||||
|
|
||||||
expect(props.actions.emitBrowserWindowResized.mock.calls[0][0]).toBe(WindowSizes.DESKTOP_VIEW);
|
|
||||||
|
|
||||||
wrapper.unmount();
|
|
||||||
});
|
|
||||||
|
|
||||||
test('should update redux when the small desktop media query matches', () => {
|
|
||||||
const props = {
|
|
||||||
...baseProps,
|
|
||||||
actions: {
|
|
||||||
...baseProps.actions,
|
|
||||||
emitBrowserWindowResized: jest.fn(),
|
|
||||||
},
|
|
||||||
};
|
|
||||||
const wrapper = shallow(<Root {...props}/>);
|
|
||||||
|
|
||||||
matchMedia.useMediaQuery(`(min-width: ${Constants.TABLET_SCREEN_WIDTH + 1}px) and (max-width: ${Constants.DESKTOP_SCREEN_WIDTH}px)`);
|
|
||||||
|
|
||||||
expect(props.actions.emitBrowserWindowResized).toBeCalledTimes(1);
|
|
||||||
|
|
||||||
expect(props.actions.emitBrowserWindowResized.mock.calls[0][0]).toBe(WindowSizes.SMALL_DESKTOP_VIEW);
|
|
||||||
|
|
||||||
wrapper.unmount();
|
|
||||||
});
|
|
||||||
|
|
||||||
test('should update redux when the tablet media query matches', () => {
|
|
||||||
const props = {
|
|
||||||
...baseProps,
|
|
||||||
actions: {
|
|
||||||
...baseProps.actions,
|
|
||||||
emitBrowserWindowResized: jest.fn(),
|
|
||||||
},
|
|
||||||
};
|
|
||||||
const wrapper = shallow(<Root {...props}/>);
|
|
||||||
|
|
||||||
matchMedia.useMediaQuery(`(min-width: ${Constants.MOBILE_SCREEN_WIDTH + 1}px) and (max-width: ${Constants.TABLET_SCREEN_WIDTH}px)`);
|
|
||||||
|
|
||||||
expect(props.actions.emitBrowserWindowResized).toBeCalledTimes(1);
|
|
||||||
|
|
||||||
expect(props.actions.emitBrowserWindowResized.mock.calls[0][0]).toBe(WindowSizes.TABLET_VIEW);
|
|
||||||
|
|
||||||
wrapper.unmount();
|
|
||||||
});
|
|
||||||
|
|
||||||
test('should update redux when the mobile media query matches', () => {
|
|
||||||
const props = {
|
|
||||||
...baseProps,
|
|
||||||
actions: {
|
|
||||||
...baseProps.actions,
|
|
||||||
emitBrowserWindowResized: jest.fn(),
|
|
||||||
},
|
|
||||||
};
|
|
||||||
const wrapper = shallow(<Root {...props}/>);
|
|
||||||
|
|
||||||
matchMedia.useMediaQuery(`(max-width: ${Constants.MOBILE_SCREEN_WIDTH}px)`);
|
|
||||||
|
|
||||||
expect(props.actions.emitBrowserWindowResized).toBeCalledTimes(1);
|
|
||||||
|
|
||||||
expect(props.actions.emitBrowserWindowResized.mock.calls[0][0]).toBe(WindowSizes.MOBILE_VIEW);
|
|
||||||
|
|
||||||
wrapper.unmount();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('Routes', () => {
|
describe('Routes', () => {
|
||||||
test('Should mount public product routes', () => {
|
test('Should mount public product routes', () => {
|
||||||
const mainComponent = () => (<p>{'TestMainComponent'}</p>);
|
const mainComponent = () => (<p>{'TestMainComponent'}</p>);
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
|
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import deepEqual from 'fast-deep-equal';
|
import deepEqual from 'fast-deep-equal';
|
||||||
import throttle from 'lodash/throttle';
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import {Route, Switch, Redirect} from 'react-router-dom';
|
import {Route, Switch, Redirect} from 'react-router-dom';
|
||||||
import type {RouteComponentProps} from 'react-router-dom';
|
import type {RouteComponentProps} from 'react-router-dom';
|
||||||
@ -27,7 +26,7 @@ import {loadRecentlyUsedCustomEmojis} from 'actions/emoji_actions';
|
|||||||
import * as GlobalActions from 'actions/global_actions';
|
import * as GlobalActions from 'actions/global_actions';
|
||||||
import {measurePageLoadTelemetry, trackEvent, trackSelectorMetrics} from 'actions/telemetry_actions.jsx';
|
import {measurePageLoadTelemetry, trackEvent, trackSelectorMetrics} from 'actions/telemetry_actions.jsx';
|
||||||
import BrowserStore from 'stores/browser_store';
|
import BrowserStore from 'stores/browser_store';
|
||||||
import store from 'stores/redux_store.jsx';
|
import store from 'stores/redux_store';
|
||||||
|
|
||||||
import AccessProblem from 'components/access_problem';
|
import AccessProblem from 'components/access_problem';
|
||||||
import AnnouncementBarController from 'components/announcement_bar';
|
import AnnouncementBarController from 'components/announcement_bar';
|
||||||
@ -40,6 +39,7 @@ import OpenPricingModalPost from 'components/custom_open_pricing_modal_post_rend
|
|||||||
import GlobalHeader from 'components/global_header/global_header';
|
import GlobalHeader from 'components/global_header/global_header';
|
||||||
import {HFRoute} from 'components/header_footer_route/header_footer_route';
|
import {HFRoute} from 'components/header_footer_route/header_footer_route';
|
||||||
import {HFTRoute, LoggedInHFTRoute} from 'components/header_footer_template_route';
|
import {HFTRoute, LoggedInHFTRoute} from 'components/header_footer_template_route';
|
||||||
|
import MobileViewWatcher from 'components/mobile_view_watcher';
|
||||||
import ModalController from 'components/modal_controller';
|
import ModalController from 'components/modal_controller';
|
||||||
import LaunchingWorkspace, {LAUNCHING_WORKSPACE_FULLSCREEN_Z_INDEX} from 'components/preparing_workspace/launching_workspace';
|
import LaunchingWorkspace, {LAUNCHING_WORKSPACE_FULLSCREEN_Z_INDEX} from 'components/preparing_workspace/launching_workspace';
|
||||||
import {Animations} from 'components/preparing_workspace/steps';
|
import {Animations} from 'components/preparing_workspace/steps';
|
||||||
@ -53,7 +53,7 @@ import webSocketClient from 'client/web_websocket_client.jsx';
|
|||||||
import {initializePlugins} from 'plugins';
|
import {initializePlugins} from 'plugins';
|
||||||
import Pluggable from 'plugins/pluggable';
|
import Pluggable from 'plugins/pluggable';
|
||||||
import A11yController from 'utils/a11y_controller';
|
import A11yController from 'utils/a11y_controller';
|
||||||
import Constants, {StoragePrefixes, WindowSizes} from 'utils/constants';
|
import {StoragePrefixes} from 'utils/constants';
|
||||||
import {EmojiIndicesByAlias} from 'utils/emoji';
|
import {EmojiIndicesByAlias} from 'utils/emoji';
|
||||||
import {getSiteURL} from 'utils/url';
|
import {getSiteURL} from 'utils/url';
|
||||||
import * as UserAgent from 'utils/user_agent';
|
import * as UserAgent from 'utils/user_agent';
|
||||||
@ -134,7 +134,6 @@ function LoggedInRoute<T>(props: LoggedInRouteProps<T>) {
|
|||||||
const noop = () => {};
|
const noop = () => {};
|
||||||
|
|
||||||
export type Actions = {
|
export type Actions = {
|
||||||
emitBrowserWindowResized: (size?: string) => void;
|
|
||||||
getFirstAdminSetupComplete: () => Promise<ActionResult>;
|
getFirstAdminSetupComplete: () => Promise<ActionResult>;
|
||||||
getProfiles: (page?: number, pageSize?: number, options?: Record<string, any>) => Promise<ActionResult>;
|
getProfiles: (page?: number, pageSize?: number, options?: Record<string, any>) => Promise<ActionResult>;
|
||||||
migrateRecentEmojis: () => void;
|
migrateRecentEmojis: () => void;
|
||||||
@ -165,10 +164,6 @@ interface State {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default class Root extends React.PureComponent<Props, State> {
|
export default class Root extends React.PureComponent<Props, State> {
|
||||||
private desktopMediaQuery: MediaQueryList;
|
|
||||||
private smallDesktopMediaQuery: MediaQueryList;
|
|
||||||
private tabletMediaQuery: MediaQueryList;
|
|
||||||
private mobileMediaQuery: MediaQueryList;
|
|
||||||
private mounted: boolean;
|
private mounted: boolean;
|
||||||
|
|
||||||
// The constructor adds a bunch of event listeners,
|
// The constructor adds a bunch of event listeners,
|
||||||
@ -211,14 +206,6 @@ export default class Root extends React.PureComponent<Props, State> {
|
|||||||
|
|
||||||
this.a11yController = new A11yController();
|
this.a11yController = new A11yController();
|
||||||
|
|
||||||
// set initial window size state
|
|
||||||
this.desktopMediaQuery = window.matchMedia(`(min-width: ${Constants.DESKTOP_SCREEN_WIDTH + 1}px)`);
|
|
||||||
this.smallDesktopMediaQuery = window.matchMedia(`(min-width: ${Constants.TABLET_SCREEN_WIDTH + 1}px) and (max-width: ${Constants.DESKTOP_SCREEN_WIDTH}px)`);
|
|
||||||
this.tabletMediaQuery = window.matchMedia(`(min-width: ${Constants.MOBILE_SCREEN_WIDTH + 1}px) and (max-width: ${Constants.TABLET_SCREEN_WIDTH}px)`);
|
|
||||||
this.mobileMediaQuery = window.matchMedia(`(max-width: ${Constants.MOBILE_SCREEN_WIDTH}px)`);
|
|
||||||
|
|
||||||
this.updateWindowSize();
|
|
||||||
|
|
||||||
store.subscribe(() => applyLuxonDefaults(store.getState()));
|
store.subscribe(() => applyLuxonDefaults(store.getState()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -436,20 +423,6 @@ export default class Root extends React.PureComponent<Props, State> {
|
|||||||
this.props.actions.registerCustomPostRenderer('custom_up_notification', OpenPricingModalPost, 'upgrade_post_message_renderer');
|
this.props.actions.registerCustomPostRenderer('custom_up_notification', OpenPricingModalPost, 'upgrade_post_message_renderer');
|
||||||
this.props.actions.registerCustomPostRenderer('custom_pl_notification', OpenPluginInstallPost, 'plugin_install_post_message_renderer');
|
this.props.actions.registerCustomPostRenderer('custom_pl_notification', OpenPluginInstallPost, 'plugin_install_post_message_renderer');
|
||||||
|
|
||||||
if (this.desktopMediaQuery.addEventListener) {
|
|
||||||
this.desktopMediaQuery.addEventListener('change', this.handleMediaQueryChangeEvent);
|
|
||||||
this.smallDesktopMediaQuery.addEventListener('change', this.handleMediaQueryChangeEvent);
|
|
||||||
this.tabletMediaQuery.addEventListener('change', this.handleMediaQueryChangeEvent);
|
|
||||||
this.mobileMediaQuery.addEventListener('change', this.handleMediaQueryChangeEvent);
|
|
||||||
} else if (this.desktopMediaQuery.addListener) {
|
|
||||||
this.desktopMediaQuery.addListener(this.handleMediaQueryChangeEvent);
|
|
||||||
this.smallDesktopMediaQuery.addListener(this.handleMediaQueryChangeEvent);
|
|
||||||
this.tabletMediaQuery.addListener(this.handleMediaQueryChangeEvent);
|
|
||||||
this.mobileMediaQuery.addListener(this.handleMediaQueryChangeEvent);
|
|
||||||
} else {
|
|
||||||
window.addEventListener('resize', this.handleWindowResizeEvent);
|
|
||||||
}
|
|
||||||
|
|
||||||
measurePageLoadTelemetry();
|
measurePageLoadTelemetry();
|
||||||
trackSelectorMetrics();
|
trackSelectorMetrics();
|
||||||
}
|
}
|
||||||
@ -457,20 +430,6 @@ export default class Root extends React.PureComponent<Props, State> {
|
|||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
this.mounted = false;
|
this.mounted = false;
|
||||||
window.removeEventListener('storage', this.handleLogoutLoginSignal);
|
window.removeEventListener('storage', this.handleLogoutLoginSignal);
|
||||||
|
|
||||||
if (this.desktopMediaQuery.removeEventListener) {
|
|
||||||
this.desktopMediaQuery.removeEventListener('change', this.handleMediaQueryChangeEvent);
|
|
||||||
this.smallDesktopMediaQuery.removeEventListener('change', this.handleMediaQueryChangeEvent);
|
|
||||||
this.tabletMediaQuery.removeEventListener('change', this.handleMediaQueryChangeEvent);
|
|
||||||
this.mobileMediaQuery.removeEventListener('change', this.handleMediaQueryChangeEvent);
|
|
||||||
} else if (this.desktopMediaQuery.removeListener) {
|
|
||||||
this.desktopMediaQuery.removeListener(this.handleMediaQueryChangeEvent);
|
|
||||||
this.smallDesktopMediaQuery.removeListener(this.handleMediaQueryChangeEvent);
|
|
||||||
this.tabletMediaQuery.removeListener(this.handleMediaQueryChangeEvent);
|
|
||||||
this.mobileMediaQuery.removeListener(this.handleMediaQueryChangeEvent);
|
|
||||||
} else {
|
|
||||||
window.removeEventListener('resize', this.handleWindowResizeEvent);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
handleLogoutLoginSignal = (e: StorageEvent) => {
|
handleLogoutLoginSignal = (e: StorageEvent) => {
|
||||||
@ -498,16 +457,6 @@ export default class Root extends React.PureComponent<Props, State> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
handleWindowResizeEvent = throttle(() => {
|
|
||||||
this.props.actions.emitBrowserWindowResized();
|
|
||||||
}, 100);
|
|
||||||
|
|
||||||
handleMediaQueryChangeEvent = (e: MediaQueryListEvent) => {
|
|
||||||
if (e.matches) {
|
|
||||||
this.updateWindowSize();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
setRootMeta = () => {
|
setRootMeta = () => {
|
||||||
const root = document.getElementById('root')!;
|
const root = document.getElementById('root')!;
|
||||||
|
|
||||||
@ -520,23 +469,6 @@ export default class Root extends React.PureComponent<Props, State> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
updateWindowSize = () => {
|
|
||||||
switch (true) {
|
|
||||||
case this.desktopMediaQuery.matches:
|
|
||||||
this.props.actions.emitBrowserWindowResized(WindowSizes.DESKTOP_VIEW);
|
|
||||||
break;
|
|
||||||
case this.smallDesktopMediaQuery.matches:
|
|
||||||
this.props.actions.emitBrowserWindowResized(WindowSizes.SMALL_DESKTOP_VIEW);
|
|
||||||
break;
|
|
||||||
case this.tabletMediaQuery.matches:
|
|
||||||
this.props.actions.emitBrowserWindowResized(WindowSizes.TABLET_VIEW);
|
|
||||||
break;
|
|
||||||
case this.mobileMediaQuery.matches:
|
|
||||||
this.props.actions.emitBrowserWindowResized(WindowSizes.MOBILE_VIEW);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
if (!this.state.configLoaded) {
|
if (!this.state.configLoaded) {
|
||||||
return <div/>;
|
return <div/>;
|
||||||
@ -544,6 +476,7 @@ export default class Root extends React.PureComponent<Props, State> {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<RootProvider>
|
<RootProvider>
|
||||||
|
<MobileViewWatcher/>
|
||||||
<Switch>
|
<Switch>
|
||||||
<Route
|
<Route
|
||||||
path={'/error'}
|
path={'/error'}
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
// See LICENSE.txt for license information.
|
// See LICENSE.txt for license information.
|
||||||
|
|
||||||
import throttle from 'lodash/throttle';
|
import throttle from 'lodash/throttle';
|
||||||
import {useCallback, useEffect} from 'react';
|
import {useCallback, useEffect, useRef} from 'react';
|
||||||
import {useDispatch} from 'react-redux';
|
import {useDispatch} from 'react-redux';
|
||||||
|
|
||||||
import {setLhsSize} from 'actions/views/lhs';
|
import {setLhsSize} from 'actions/views/lhs';
|
||||||
@ -12,14 +12,14 @@ import {SidebarSize} from 'components/resizable_sidebar/constants';
|
|||||||
|
|
||||||
import Constants from 'utils/constants';
|
import Constants from 'utils/constants';
|
||||||
|
|
||||||
const smallSidebarMediaQuery = window.matchMedia(`(max-width: ${Constants.SMALL_SIDEBAR_BREAKPOINT}px)`);
|
|
||||||
const mediumSidebarMediaQuery = window.matchMedia(`(min-width: ${Constants.SMALL_SIDEBAR_BREAKPOINT + 1}px) and (max-width: ${Constants.MEDIUM_SIDEBAR_BREAKPOINT}px)`);
|
|
||||||
const largeSidebarMediaQuery = window.matchMedia(`(min-width: ${Constants.MEDIUM_SIDEBAR_BREAKPOINT + 1}px) and (max-width: ${Constants.LARGE_SIDEBAR_BREAKPOINT}px)`);
|
|
||||||
const xLargeSidebarMediaQuery = window.matchMedia(`(min-width: ${Constants.LARGE_SIDEBAR_BREAKPOINT + 1}px)`);
|
|
||||||
|
|
||||||
function WindowSizeObserver() {
|
function WindowSizeObserver() {
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
|
|
||||||
|
const smallSidebarMediaQuery = useRef(window.matchMedia(`(max-width: ${Constants.SMALL_SIDEBAR_BREAKPOINT}px)`)).current;
|
||||||
|
const mediumSidebarMediaQuery = useRef(window.matchMedia(`(min-width: ${Constants.SMALL_SIDEBAR_BREAKPOINT + 1}px) and (max-width: ${Constants.MEDIUM_SIDEBAR_BREAKPOINT}px)`)).current;
|
||||||
|
const largeSidebarMediaQuery = useRef(window.matchMedia(`(min-width: ${Constants.MEDIUM_SIDEBAR_BREAKPOINT + 1}px) and (max-width: ${Constants.LARGE_SIDEBAR_BREAKPOINT}px)`)).current;
|
||||||
|
const xLargeSidebarMediaQuery = useRef(window.matchMedia(`(min-width: ${Constants.LARGE_SIDEBAR_BREAKPOINT + 1}px)`)).current;
|
||||||
|
|
||||||
const updateSidebarSize = useCallback(() => {
|
const updateSidebarSize = useCallback(() => {
|
||||||
switch (true) {
|
switch (true) {
|
||||||
case xLargeSidebarMediaQuery.matches:
|
case xLargeSidebarMediaQuery.matches:
|
||||||
|
Loading…
Reference in New Issue
Block a user