mirror of
https://github.com/shlinkio/shlink-web-client.git
synced 2024-12-23 09:30:31 +03:00
Merge pull request #523 from acelaya-forks/feature/home-alignment
Updated landing page to be vertically aligned on mobile devices
This commit is contained in:
commit
7db9974e8d
6 changed files with 67 additions and 25 deletions
17
CHANGELOG.md
17
CHANGELOG.md
|
@ -4,6 +4,23 @@ All notable changes to this project will be documented in this file.
|
|||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org).
|
||||
|
||||
## [Unreleased]
|
||||
### Added
|
||||
* [#520](https://github.com/shlinkio/shlink-web-client/issues/520) Allowed to select "all visits" as the default interval for visits.
|
||||
|
||||
### Changed
|
||||
* Moved ci workflow to external repo and reused
|
||||
|
||||
### Deprecated
|
||||
* *Nothing*
|
||||
|
||||
### Removed
|
||||
* *Nothing*
|
||||
|
||||
### Fixed
|
||||
* *Nothing*
|
||||
|
||||
|
||||
## [3.4.0] - 2021-11-11
|
||||
### Added
|
||||
* [#496](https://github.com/shlinkio/shlink-web-client/issues/496) Allowed to select "all visits" as the default interval for visits.
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import { useEffect, FC } from 'react';
|
||||
import { Route, Switch } from 'react-router-dom';
|
||||
import { Route, RouteChildrenProps, Switch } from 'react-router-dom';
|
||||
import classNames from 'classnames';
|
||||
import NotFound from '../common/NotFound';
|
||||
import { ServersMap } from '../servers/data';
|
||||
import { Settings } from '../settings/reducers/settings';
|
||||
|
@ -8,7 +9,7 @@ import { AppUpdateBanner } from '../common/AppUpdateBanner';
|
|||
import { forceUpdate } from '../utils/helpers/sw';
|
||||
import './App.scss';
|
||||
|
||||
interface AppProps {
|
||||
interface AppProps extends RouteChildrenProps {
|
||||
fetchServers: () => void;
|
||||
servers: ServersMap;
|
||||
settings: Settings;
|
||||
|
@ -25,7 +26,9 @@ const App = (
|
|||
Settings: FC,
|
||||
ManageServers: FC,
|
||||
ShlinkVersionsContainer: FC,
|
||||
) => ({ fetchServers, servers, settings, appUpdated, resetAppUpdate }: AppProps) => {
|
||||
) => ({ fetchServers, servers, settings, appUpdated, resetAppUpdate, location }: AppProps) => {
|
||||
const isHome = location.pathname === '/';
|
||||
|
||||
useEffect(() => {
|
||||
// On first load, try to fetch the remote servers if the list is empty
|
||||
if (Object.keys(servers).length === 0) {
|
||||
|
@ -40,7 +43,7 @@ const App = (
|
|||
<MainHeader />
|
||||
|
||||
<div className="app">
|
||||
<div className="shlink-wrapper">
|
||||
<div className={classNames('shlink-wrapper', { 'd-flex d-md-block align-items-center': isHome })}>
|
||||
<Switch>
|
||||
<Route exact path="/" component={Home} />
|
||||
<Route exact path="/settings" component={Settings} />
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import Bottle from 'bottlejs';
|
||||
import Bottle, { Decorator } from 'bottlejs';
|
||||
import { appUpdateAvailable, resetAppUpdate } from '../reducers/appUpdates';
|
||||
import App from '../App';
|
||||
import { ConnectDecorator } from '../../container/types';
|
||||
|
||||
const provideServices = (bottle: Bottle, connect: ConnectDecorator) => {
|
||||
const provideServices = (bottle: Bottle, connect: ConnectDecorator, withRouter: Decorator) => {
|
||||
// Components
|
||||
bottle.serviceFactory(
|
||||
'App',
|
||||
|
@ -18,6 +18,7 @@ const provideServices = (bottle: Bottle, connect: ConnectDecorator) => {
|
|||
'ShlinkVersionsContainer',
|
||||
);
|
||||
bottle.decorator('App', connect([ 'servers', 'settings', 'appUpdated' ], [ 'fetchServers', 'resetAppUpdate' ]));
|
||||
bottle.decorator('App', withRouter);
|
||||
|
||||
// Actions
|
||||
bottle.serviceFactory('appUpdateAvailable', () => appUpdateAvailable);
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
.home {
|
||||
position: relative;
|
||||
padding-top: 15px;
|
||||
width: 100%;
|
||||
|
||||
@media (min-width: $mdMin) {
|
||||
padding-top: 0;
|
||||
|
|
|
@ -33,7 +33,7 @@ const connect: ConnectDecorator = (propsFromState: string[] | null, actionServic
|
|||
actionServiceNames.reduce(mapActionService, {}),
|
||||
);
|
||||
|
||||
provideAppServices(bottle, connect);
|
||||
provideAppServices(bottle, connect, withRouter);
|
||||
provideCommonServices(bottle, connect, withRouter);
|
||||
provideApiServices(bottle);
|
||||
provideShortUrlsServices(bottle, connect, withRouter);
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
import { shallow, ShallowWrapper } from 'enzyme';
|
||||
import { Route } from 'react-router-dom';
|
||||
import { Mock } from 'ts-mockery';
|
||||
import { match } from 'react-router';
|
||||
import { History, Location } from 'history';
|
||||
import { Settings } from '../../src/settings/reducers/settings';
|
||||
import appFactory from '../../src/app/App';
|
||||
import { AppUpdateBanner } from '../../src/common/AppUpdateBanner';
|
||||
|
@ -9,19 +11,17 @@ describe('<App />', () => {
|
|||
let wrapper: ShallowWrapper;
|
||||
const MainHeader = () => null;
|
||||
const ShlinkVersions = () => null;
|
||||
|
||||
beforeEach(() => {
|
||||
const App = appFactory(
|
||||
MainHeader,
|
||||
() => null,
|
||||
() => null,
|
||||
() => null,
|
||||
() => null,
|
||||
() => null,
|
||||
() => null,
|
||||
ShlinkVersions,
|
||||
);
|
||||
|
||||
const App = appFactory(
|
||||
MainHeader,
|
||||
() => null,
|
||||
() => null,
|
||||
() => null,
|
||||
() => null,
|
||||
() => null,
|
||||
() => null,
|
||||
ShlinkVersions,
|
||||
);
|
||||
const createWrapper = (pathname = '') => {
|
||||
wrapper = shallow(
|
||||
<App
|
||||
fetchServers={() => {}}
|
||||
|
@ -29,18 +29,27 @@ describe('<App />', () => {
|
|||
settings={Mock.all<Settings>()}
|
||||
appUpdated={false}
|
||||
resetAppUpdate={() => {}}
|
||||
match={Mock.all<match>()}
|
||||
history={Mock.all<History>()}
|
||||
location={Mock.of<Location>({ pathname })}
|
||||
/>,
|
||||
);
|
||||
});
|
||||
|
||||
return wrapper;
|
||||
};
|
||||
|
||||
afterEach(() => wrapper.unmount());
|
||||
|
||||
it('renders a header', () => expect(wrapper.find(MainHeader)).toHaveLength(1));
|
||||
it('renders children components', () => {
|
||||
const wrapper = createWrapper();
|
||||
|
||||
it('renders versions', () => expect(wrapper.find(ShlinkVersions)).toHaveLength(1));
|
||||
|
||||
it('renders an update banner', () => expect(wrapper.find(AppUpdateBanner)).toHaveLength(1));
|
||||
expect(wrapper.find(MainHeader)).toHaveLength(1);
|
||||
expect(wrapper.find(ShlinkVersions)).toHaveLength(1);
|
||||
expect(wrapper.find(AppUpdateBanner)).toHaveLength(1);
|
||||
});
|
||||
|
||||
it('renders app main routes', () => {
|
||||
const wrapper = createWrapper();
|
||||
const routes = wrapper.find(Route);
|
||||
const expectedPaths = [
|
||||
'/',
|
||||
|
@ -57,4 +66,15 @@ describe('<App />', () => {
|
|||
expect(routes.at(index).prop('path')).toEqual(path);
|
||||
});
|
||||
});
|
||||
|
||||
it.each([
|
||||
[ '/foo', 'shlink-wrapper' ],
|
||||
[ '/bar', 'shlink-wrapper' ],
|
||||
[ '/', 'shlink-wrapper d-flex d-md-block align-items-center' ],
|
||||
])('renders expected classes on shlink-wrapper based on current pathname', (pathname, expectedClasses) => {
|
||||
const wrapper = createWrapper(pathname);
|
||||
const shlinkWrapper = wrapper.find('.shlink-wrapper');
|
||||
|
||||
expect(shlinkWrapper.prop('className')).toEqual(expectedClasses);
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue