diff --git a/src/common/MenuLayout.tsx b/src/common/MenuLayout.tsx index 567587b4..87a4a58f 100644 --- a/src/common/MenuLayout.tsx +++ b/src/common/MenuLayout.tsx @@ -11,6 +11,11 @@ import NotFound from './NotFound'; import { AsideMenuProps } from './AsideMenu'; import './MenuLayout.scss'; +interface MenuLayoutProps { + sidebarRendered: Function; + sidebarNotRendered: Function; +} + const MenuLayout = ( TagsList: FC, ShortUrlsList: FC, @@ -24,13 +29,19 @@ const MenuLayout = ( Overview: FC, EditShortUrl: FC, ManageDomains: FC, -) => withSelectedServer(({ selectedServer }) => { +) => withSelectedServer(({ selectedServer, sidebarNotRendered, sidebarRendered }) => { const location = useLocation(); const [ sidebarVisible, toggleSidebar, showSidebar, hideSidebar ] = useToggle(); + const showContent = isReachableServer(selectedServer); useEffect(() => hideSidebar(), [ location ]); + useEffect(() => { + showContent && sidebarRendered(); - if (!isReachableServer(selectedServer)) { + return () => sidebarNotRendered(); + }, []); + + if (!showContent) { return ; } diff --git a/src/common/ShlinkVersions.tsx b/src/common/ShlinkVersions.tsx index 188f8f8d..50277ab0 100644 --- a/src/common/ShlinkVersions.tsx +++ b/src/common/ShlinkVersions.tsx @@ -1,13 +1,13 @@ import { pipe } from 'ramda'; import { ExternalLink } from 'react-external-link'; import { versionToPrintable, versionToSemVer } from '../utils/helpers/version'; -import { isReachableServer } from '../servers/data'; -import { ShlinkVersionsContainerProps } from './ShlinkVersionsContainer'; +import { isReachableServer, SelectedServer } from '../servers/data'; const SHLINK_WEB_CLIENT_VERSION = '%_VERSION_%'; const normalizeVersion = pipe(versionToSemVer(), versionToPrintable); -export interface ShlinkVersionsProps extends ShlinkVersionsContainerProps { +export interface ShlinkVersionsProps { + selectedServer: SelectedServer; clientVersion?: string; } diff --git a/src/common/ShlinkVersionsContainer.scss b/src/common/ShlinkVersionsContainer.scss index 296731cf..0ad96872 100644 --- a/src/common/ShlinkVersionsContainer.scss +++ b/src/common/ShlinkVersionsContainer.scss @@ -1,6 +1,6 @@ @import '../utils/base'; -.shlink-versions-container--with-server { +.shlink-versions-container--with-sidebar { margin-left: 0; @media (min-width: $mdMin) { diff --git a/src/common/ShlinkVersionsContainer.tsx b/src/common/ShlinkVersionsContainer.tsx index be3b9d74..419e77e4 100644 --- a/src/common/ShlinkVersionsContainer.tsx +++ b/src/common/ShlinkVersionsContainer.tsx @@ -1,15 +1,17 @@ import classNames from 'classnames'; -import { isReachableServer, SelectedServer } from '../servers/data'; +import { SelectedServer } from '../servers/data'; import ShlinkVersions from './ShlinkVersions'; +import { Sidebar } from './reducers/sidebar'; import './ShlinkVersionsContainer.scss'; export interface ShlinkVersionsContainerProps { selectedServer: SelectedServer; + sidebar: Sidebar; } -const ShlinkVersionsContainer = ({ selectedServer }: ShlinkVersionsContainerProps) => { +const ShlinkVersionsContainer = ({ selectedServer, sidebar }: ShlinkVersionsContainerProps) => { const classes = classNames('text-center', { - 'shlink-versions-container--with-server': isReachableServer(selectedServer), + 'shlink-versions-container--with-sidebar': sidebar.hasSidebar, }); return ( diff --git a/src/common/reducers/sidebar.ts b/src/common/reducers/sidebar.ts new file mode 100644 index 00000000..7e05686f --- /dev/null +++ b/src/common/reducers/sidebar.ts @@ -0,0 +1,27 @@ +import { Action } from 'redux'; +import { buildActionCreator, buildReducer } from '../../utils/helpers/redux'; + +/* eslint-disable padding-line-between-statements */ +export const SIDEBAR_RENDERED = 'shlink/common/SIDEBAR_RENDERED'; +export const SIDEBAR_NOT_RENDERED = 'shlink/common/SIDEBAR_NOT_RENDERED'; +/* eslint-enable padding-line-between-statements */ + +export interface Sidebar { + hasSidebar: boolean; +} + +type SidebarRenderedAction = Action; +type SidebarNotRenderedAction = Action; + +const initialState: Sidebar = { + hasSidebar: false, +}; + +export default buildReducer({ + [SIDEBAR_RENDERED]: () => ({ hasSidebar: true }), + [SIDEBAR_NOT_RENDERED]: () => ({ hasSidebar: false }), +}, initialState); + +export const sidebarRendered = buildActionCreator(SIDEBAR_RENDERED); + +export const sidebarNotRendered = buildActionCreator(SIDEBAR_NOT_RENDERED); diff --git a/src/common/services/provideServices.ts b/src/common/services/provideServices.ts index 8c7cc2af..354c08af 100644 --- a/src/common/services/provideServices.ts +++ b/src/common/services/provideServices.ts @@ -9,6 +9,7 @@ import ErrorHandler from '../ErrorHandler'; import ShlinkVersionsContainer from '../ShlinkVersionsContainer'; import { ConnectDecorator } from '../../container/types'; import { withoutSelectedServer } from '../../servers/helpers/withoutSelectedServer'; +import { sidebarNotRendered, sidebarRendered } from '../reducers/sidebar'; import { ImageDownloader } from './ImageDownloader'; const provideServices = (bottle: Bottle, connect: ConnectDecorator) => { @@ -44,14 +45,18 @@ const provideServices = (bottle: Bottle, connect: ConnectDecorator) => { 'EditShortUrl', 'ManageDomains', ); - bottle.decorator('MenuLayout', connect([ 'selectedServer' ], [ 'selectServer' ])); + bottle.decorator('MenuLayout', connect([ 'selectedServer' ], [ 'selectServer', 'sidebarRendered', 'sidebarNotRendered' ])); bottle.serviceFactory('AsideMenu', AsideMenu, 'DeleteServerButton'); bottle.serviceFactory('ShlinkVersionsContainer', () => ShlinkVersionsContainer); - bottle.decorator('ShlinkVersionsContainer', connect([ 'selectedServer' ])); + bottle.decorator('ShlinkVersionsContainer', connect([ 'selectedServer', 'sidebar' ])); bottle.serviceFactory('ErrorHandler', ErrorHandler, 'window', 'console'); + + // Actions + bottle.serviceFactory('sidebarRendered', () => sidebarRendered); + bottle.serviceFactory('sidebarNotRendered', () => sidebarNotRendered); }; export default provideServices; diff --git a/src/container/types.ts b/src/container/types.ts index 284ab00b..aeb4a8b5 100644 --- a/src/container/types.ts +++ b/src/container/types.ts @@ -14,6 +14,7 @@ import { TagVisits } from '../visits/reducers/tagVisits'; import { DomainsList } from '../domains/reducers/domainsList'; import { VisitsOverview } from '../visits/reducers/visitsOverview'; import { VisitsInfo } from '../visits/types'; +import { Sidebar } from '../common/reducers/sidebar'; export interface ShlinkState { servers: ServersMap; @@ -35,6 +36,7 @@ export interface ShlinkState { domainsList: DomainsList; visitsOverview: VisitsOverview; appUpdated: boolean; + sidebar: Sidebar; } export type ConnectDecorator = (props: string[] | null, actions?: string[]) => any; diff --git a/src/reducers/index.ts b/src/reducers/index.ts index a42e8814..c6573632 100644 --- a/src/reducers/index.ts +++ b/src/reducers/index.ts @@ -18,6 +18,7 @@ import settingsReducer from '../settings/reducers/settings'; import domainsListReducer from '../domains/reducers/domainsList'; import visitsOverviewReducer from '../visits/reducers/visitsOverview'; import appUpdatesReducer from '../app/reducers/appUpdates'; +import sidebarReducer from '../common/reducers/sidebar'; import { ShlinkState } from '../container/types'; export default combineReducers({ @@ -40,4 +41,5 @@ export default combineReducers({ domainsList: domainsListReducer, visitsOverview: visitsOverviewReducer, appUpdated: appUpdatesReducer, + sidebar: sidebarReducer, }); diff --git a/src/servers/services/provideServices.ts b/src/servers/services/provideServices.ts index 5dd8327e..6d25c6fd 100644 --- a/src/servers/services/provideServices.ts +++ b/src/servers/services/provideServices.ts @@ -43,7 +43,6 @@ const provideServices = (bottle: Bottle, connect: ConnectDecorator) => { bottle.decorator('CreateServer', connect([ 'selectedServer', 'servers' ], [ 'createServer', 'resetSelectedServer' ])); bottle.serviceFactory('EditServer', EditServer, 'ServerError'); - bottle.decorator('EditServer', withoutSelectedServer); bottle.decorator('EditServer', connect([ 'selectedServer' ], [ 'editServer', 'selectServer', 'resetSelectedServer' ])); bottle.serviceFactory('ServersDropdown', () => ServersDropdown); diff --git a/test/common/MenuLayout.test.tsx b/test/common/MenuLayout.test.tsx index 98306335..4e79a36e 100644 --- a/test/common/MenuLayout.test.tsx +++ b/test/common/MenuLayout.test.tsx @@ -20,7 +20,14 @@ describe('', () => { const createWrapper = (selectedServer: SelectedServer) => { (useParams as any).mockReturnValue({ serverId: 'abc123' }); - wrapper = shallow(); + wrapper = shallow( + , + ); return wrapper; }; diff --git a/test/common/ShlinkVersionsContainer.test.tsx b/test/common/ShlinkVersionsContainer.test.tsx index 5d86bdc7..b0994453 100644 --- a/test/common/ShlinkVersionsContainer.test.tsx +++ b/test/common/ShlinkVersionsContainer.test.tsx @@ -1,13 +1,14 @@ import { shallow, ShallowWrapper } from 'enzyme'; import { Mock } from 'ts-mockery'; import ShlinkVersionsContainer from '../../src/common/ShlinkVersionsContainer'; -import { NonReachableServer, NotFoundServer, ReachableServer, SelectedServer } from '../../src/servers/data'; +import { SelectedServer } from '../../src/servers/data'; +import { Sidebar } from '../../src/common/reducers/sidebar'; describe('', () => { let wrapper: ShallowWrapper; - const createWrapper = (selectedServer: SelectedServer) => { - wrapper = shallow(); + const createWrapper = (sidebar: Sidebar) => { + wrapper = shallow(()} sidebar={sidebar} />); return wrapper; }; @@ -15,12 +16,10 @@ describe('', () => { afterEach(() => wrapper?.unmount()); it.each([ - [ null, 'text-center' ], - [ Mock.of({ serverNotFound: true }), 'text-center' ], - [ Mock.of({ serverNotReachable: true }), 'text-center' ], - [ 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); + [{ hasSidebar: false }, 'text-center' ], + [{ hasSidebar: true }, 'text-center shlink-versions-container--with-sidebar' ], + ])('renders proper col classes based on sidebar status', (sidebar, expectedClasses) => { + const wrapper = createWrapper(sidebar); expect(wrapper.find('div').prop('className')).toEqual(`${expectedClasses}`); });