diff --git a/src/common/MenuLayout.tsx b/src/common/MenuLayout.tsx
index 7528a860..57bd1189 100644
--- a/src/common/MenuLayout.tsx
+++ b/src/common/MenuLayout.tsx
@@ -1,11 +1,10 @@
import { FC, useEffect } from 'react';
import { Redirect, Route, Switch } from 'react-router-dom';
-import { useSwipeable } from 'react-swipeable';
import { faBars as burgerIcon } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import classNames from 'classnames';
import { withSelectedServer } from '../servers/helpers/withSelectedServer';
-import { useToggle } from '../utils/helpers/hooks';
+import { useSwipeable, useToggle } from '../utils/helpers/hooks';
import { versionMatch } from '../utils/helpers/version';
import { isReachableServer } from '../servers/data';
import NotFound from './NotFound';
@@ -33,25 +32,8 @@ const MenuLayout = (
const addTagsVisitsRoute = versionMatch(selectedServer.version, { minVersion: '2.2.0' });
const addOrphanVisitsRoute = versionMatch(selectedServer.version, { minVersion: '2.6.0' });
- const burgerClasses = classNames('menu-layout__burger-icon', {
- 'menu-layout__burger-icon--active': sidebarVisible,
- });
- const swipeMenuIfNoModalExists = (callback: () => void) => (e: any) => {
- const swippedOnVisitsTable = (e.event.composedPath() as HTMLElement[]).some(
- ({ classList }) => classList?.contains('visits-table'),
- );
-
- if (swippedOnVisitsTable || document.querySelector('.modal')) {
- return;
- }
-
- callback();
- };
- const swipeableProps = useSwipeable({
- delta: 40,
- onSwipedLeft: swipeMenuIfNoModalExists(hideSidebar),
- onSwipedRight: swipeMenuIfNoModalExists(showSidebar),
- });
+ const burgerClasses = classNames('menu-layout__burger-icon', { 'menu-layout__burger-icon--active': sidebarVisible });
+ const swipeableProps = useSwipeable(showSidebar, hideSidebar);
return (
<>
diff --git a/src/servers/data/index.ts b/src/servers/data/index.ts
index 22294143..32c8a75a 100644
--- a/src/servers/data/index.ts
+++ b/src/servers/data/index.ts
@@ -34,7 +34,7 @@ export const isServerWithId = (server: SelectedServer | ServerWithId): server is
!!server?.hasOwnProperty('id');
export const isReachableServer = (server: SelectedServer): server is ReachableServer =>
- !!server?.hasOwnProperty('printableVersion');
+ !!server?.hasOwnProperty('version');
export const isNotFoundServer = (server: SelectedServer): server is NotFoundServer =>
!!server?.hasOwnProperty('serverNotFound');
diff --git a/src/utils/helpers/hooks.ts b/src/utils/helpers/hooks.ts
index 3eadd866..a44b4c20 100644
--- a/src/utils/helpers/hooks.ts
+++ b/src/utils/helpers/hooks.ts
@@ -1,4 +1,5 @@
import { useState, useRef } from 'react';
+import { useSwipeable as useReactSwipeable } from 'react-swipeable';
const DEFAULT_DELAY = 2000;
@@ -30,3 +31,23 @@ export const useToggle = (initialValue = false): ToggleResult => {
return [ flag, () => setFlag(!flag), () => setFlag(true), () => setFlag(false) ];
};
+
+export const useSwipeable = (showSidebar: () => void, hideSidebar: () => void) => {
+ const swipeMenuIfNoModalExists = (callback: () => void) => (e: any) => {
+ const swippedOnVisitsTable = (e.event.composedPath() as HTMLElement[]).some(
+ ({ classList }) => classList?.contains('visits-table'),
+ );
+
+ if (swippedOnVisitsTable || document.querySelector('.modal')) {
+ return;
+ }
+
+ callback();
+ };
+
+ return useReactSwipeable({
+ delta: 40,
+ onSwipedLeft: swipeMenuIfNoModalExists(hideSidebar),
+ onSwipedRight: swipeMenuIfNoModalExists(showSidebar),
+ });
+};
diff --git a/test/common/MenuLayout.test.tsx b/test/common/MenuLayout.test.tsx
new file mode 100644
index 00000000..85cbc109
--- /dev/null
+++ b/test/common/MenuLayout.test.tsx
@@ -0,0 +1,63 @@
+import { shallow, ShallowWrapper } from 'enzyme';
+import { History, Location } from 'history';
+import { match } from 'react-router'; // eslint-disable-line @typescript-eslint/no-unused-vars
+import { Route } from 'react-router-dom';
+import { Mock } from 'ts-mockery';
+import createMenuLayout from '../../src/common/MenuLayout';
+import { NonReachableServer, NotFoundServer, ReachableServer, SelectedServer } from '../../src/servers/data';
+import NoMenuLayout from '../../src/common/NoMenuLayout';
+
+describe('', () => {
+ const ServerError = jest.fn();
+ const C = jest.fn();
+ const MenuLayout = createMenuLayout(C, C, C, C, C, C, C, ServerError, C);
+ let wrapper: ShallowWrapper;
+ const createWrapper = (selectedServer: SelectedServer) => {
+ wrapper = shallow(
+ ()}
+ location={Mock.all()}
+ match={Mock.of>({
+ params: { serverId: 'abc123' },
+ })}
+ />,
+ );
+
+ return wrapper;
+ };
+
+ afterEach(() => wrapper?.unmount());
+
+ it.each([
+ [ null, NoMenuLayout ],
+ [ Mock.of({ serverNotFound: true }), ServerError ],
+ ])('returns error when server is not found', (selectedServer, ExpectedComp) => {
+ const wrapper = createWrapper(selectedServer);
+ const comp = wrapper.find(ExpectedComp);
+
+ expect(comp).toHaveLength(1);
+ });
+
+ it('returns error if server is not reachable', () => {
+ const wrapper = createWrapper(Mock.of()).dive();
+ const serverError = wrapper.find(ServerError);
+
+ expect(serverError).toHaveLength(1);
+ });
+
+ it.each([
+ [ '2.1.0', 6 ],
+ [ '2.2.0', 7 ],
+ [ '2.5.0', 7 ],
+ [ '2.6.0', 8 ],
+ [ '2.7.0', 8 ],
+ ])('has expected amount of routes based on selected server\'s version', (version, expectedAmountOfRoutes) => {
+ const selectedServer = Mock.of({ version });
+ const wrapper = createWrapper(selectedServer).dive();
+ const routes = wrapper.find(Route);
+
+ expect(routes).toHaveLength(expectedAmountOfRoutes);
+ });
+});
diff --git a/test/common/ShlinkVersions.test.tsx b/test/common/ShlinkVersions.test.tsx
index b16e4105..0a97010f 100644
--- a/test/common/ShlinkVersions.test.tsx
+++ b/test/common/ShlinkVersions.test.tsx
@@ -14,11 +14,11 @@ describe('', () => {
afterEach(() => wrapper?.unmount());
it.each([
- [ '1.2.3', Mock.of({ printableVersion: 'foo' }), 'v1.2.3', 'foo' ],
- [ 'foo', Mock.of({ printableVersion: '1.2.3' }), 'latest', '1.2.3' ],
- [ 'latest', Mock.of({ printableVersion: 'latest' }), 'latest', 'latest' ],
- [ '5.5.0', Mock.of({ printableVersion: '0.2.8' }), 'v5.5.0', '0.2.8' ],
- [ 'not-semver', Mock.of({ printableVersion: 'something' }), 'latest', 'something' ],
+ [ '1.2.3', Mock.of({ version: '', printableVersion: 'foo' }), 'v1.2.3', 'foo' ],
+ [ 'foo', Mock.of({ version: '', printableVersion: '1.2.3' }), 'latest', '1.2.3' ],
+ [ 'latest', Mock.of({ version: '', printableVersion: 'latest' }), 'latest', 'latest' ],
+ [ '5.5.0', Mock.of({ version: '', printableVersion: '0.2.8' }), 'v5.5.0', '0.2.8' ],
+ [ 'not-semver', Mock.of({ version: '', printableVersion: 'something' }), 'latest', 'something' ],
])(
'displays expected versions when selected server is reachable',
(clientVersion, selectedServer, expectedClientVersion, expectedServerVersion) => {
diff --git a/test/common/ShlinkVersionsContainer.test.tsx b/test/common/ShlinkVersionsContainer.test.tsx
index ba4bec86..534972af 100644
--- a/test/common/ShlinkVersionsContainer.test.tsx
+++ b/test/common/ShlinkVersionsContainer.test.tsx
@@ -18,7 +18,7 @@ describe('', () => {
[ null, 'text-center' ],
[ Mock.of({ serverNotFound: true }), 'text-center' ],
[ Mock.of({ serverNotReachable: true }), 'text-center' ],
- [ Mock.of({ printableVersion: 'v1.0.0' }), 'text-center shlink-versions-container--with-server' ],
+ [ Mock.of({ version: '1.0.0' }), 'text-center shlink-versions-container--with-server' ],
])('renders proper col classes based on type of selected server', (selectedServer, expectedClasses) => {
const wrapper = createWrapper(selectedServer);