Ensured versions footer has proper classes based on sidebar status, not selected server

This commit is contained in:
Alejandro Celaya 2022-03-11 16:03:15 +01:00
parent 4f731d9de8
commit 73d4707420
11 changed files with 76 additions and 22 deletions

View file

@ -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<MenuLayoutProps>(({ 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 <ServerError />;
}

View file

@ -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;
}

View file

@ -1,6 +1,6 @@
@import '../utils/base';
.shlink-versions-container--with-server {
.shlink-versions-container--with-sidebar {
margin-left: 0;
@media (min-width: $mdMin) {

View file

@ -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 (

View file

@ -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<string>;
type SidebarNotRenderedAction = Action<string>;
const initialState: Sidebar = {
hasSidebar: false,
};
export default buildReducer<Sidebar, SidebarRenderedAction & SidebarNotRenderedAction>({
[SIDEBAR_RENDERED]: () => ({ hasSidebar: true }),
[SIDEBAR_NOT_RENDERED]: () => ({ hasSidebar: false }),
}, initialState);
export const sidebarRendered = buildActionCreator(SIDEBAR_RENDERED);
export const sidebarNotRendered = buildActionCreator(SIDEBAR_NOT_RENDERED);

View file

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

View file

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

View file

@ -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<ShlinkState>({
@ -40,4 +41,5 @@ export default combineReducers<ShlinkState>({
domainsList: domainsListReducer,
visitsOverview: visitsOverviewReducer,
appUpdated: appUpdatesReducer,
sidebar: sidebarReducer,
});

View file

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

View file

@ -20,7 +20,14 @@ describe('<MenuLayout />', () => {
const createWrapper = (selectedServer: SelectedServer) => {
(useParams as any).mockReturnValue({ serverId: 'abc123' });
wrapper = shallow(<MenuLayout selectServer={jest.fn()} selectedServer={selectedServer} />);
wrapper = shallow(
<MenuLayout
sidebarNotRendered={jest.fn()}
sidebarRendered={jest.fn}
selectServer={jest.fn()}
selectedServer={selectedServer}
/>,
);
return wrapper;
};

View file

@ -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('<ShlinkVersionsContainer />', () => {
let wrapper: ShallowWrapper;
const createWrapper = (selectedServer: SelectedServer) => {
wrapper = shallow(<ShlinkVersionsContainer selectedServer={selectedServer} />);
const createWrapper = (sidebar: Sidebar) => {
wrapper = shallow(<ShlinkVersionsContainer selectedServer={Mock.all<SelectedServer>()} sidebar={sidebar} />);
return wrapper;
};
@ -15,12 +16,10 @@ describe('<ShlinkVersionsContainer />', () => {
afterEach(() => wrapper?.unmount());
it.each([
[ null, 'text-center' ],
[ Mock.of<NotFoundServer>({ serverNotFound: true }), 'text-center' ],
[ Mock.of<NonReachableServer>({ serverNotReachable: true }), 'text-center' ],
[ Mock.of<ReachableServer>({ 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}`);
});