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);