mirror of
https://github.com/shlinkio/shlink-web-client.git
synced 2024-12-23 09:30:31 +03:00
Added banner to be displayed when the service worker has updated the app in the background
This commit is contained in:
parent
4546b74b6f
commit
5caa648112
9 changed files with 90 additions and 20 deletions
16
src/App.scss
16
src/App.scss
|
@ -1,4 +1,5 @@
|
|||
@import './utils/base';
|
||||
@import './utils/mixins/horizontal-align';
|
||||
|
||||
.app-container {
|
||||
height: 100%;
|
||||
|
@ -24,3 +25,18 @@
|
|||
padding: 0 15px;
|
||||
}
|
||||
}
|
||||
|
||||
.app__update-banner.app__update-banner {
|
||||
@include horizontal-align();
|
||||
|
||||
position: fixed;
|
||||
top: $headerHeight - 25px;
|
||||
padding: 0 4rem 0 0;
|
||||
z-index: 1040;
|
||||
margin: 0;
|
||||
color: var(--text-color);
|
||||
text-align: center;
|
||||
width: 700px;
|
||||
max-width: calc(100% - 30px);
|
||||
box-shadow: 0 0 1rem var(--brand-color);
|
||||
}
|
||||
|
|
19
src/App.tsx
19
src/App.tsx
|
@ -1,15 +1,19 @@
|
|||
import { useEffect, FC } from 'react';
|
||||
import { Route, Switch } from 'react-router-dom';
|
||||
import { Alert } from 'reactstrap';
|
||||
import NotFound from './common/NotFound';
|
||||
import { ServersMap } from './servers/data';
|
||||
import { Settings } from './settings/reducers/settings';
|
||||
import { changeThemeInMarkup } from './utils/theme';
|
||||
import { SimpleCard } from './utils/SimpleCard';
|
||||
import './App.scss';
|
||||
|
||||
interface AppProps {
|
||||
fetchServers: Function;
|
||||
fetchServers: () => void;
|
||||
servers: ServersMap;
|
||||
settings: Settings;
|
||||
resetAppUpdate: () => void;
|
||||
appUpdated: boolean;
|
||||
}
|
||||
|
||||
const App = (
|
||||
|
@ -20,7 +24,7 @@ const App = (
|
|||
EditServer: FC,
|
||||
Settings: FC,
|
||||
ShlinkVersionsContainer: FC,
|
||||
) => ({ fetchServers, servers, settings }: AppProps) => {
|
||||
) => ({ fetchServers, servers, settings, appUpdated, resetAppUpdate }: AppProps) => {
|
||||
useEffect(() => {
|
||||
// On first load, try to fetch the remote servers if the list is empty
|
||||
if (Object.keys(servers).length === 0) {
|
||||
|
@ -50,6 +54,17 @@ const App = (
|
|||
<ShlinkVersionsContainer />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Alert
|
||||
className="app__update-banner"
|
||||
tag={SimpleCard}
|
||||
color="secondary"
|
||||
isOpen={appUpdated}
|
||||
toggle={resetAppUpdate}
|
||||
>
|
||||
<h4 className="mb-4">This app has just been updated!</h4>
|
||||
<p className="mb-0">Restart it to enjoy the new features.</p>
|
||||
</Alert>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
18
src/app/reducers/appUpdates.ts
Normal file
18
src/app/reducers/appUpdates.ts
Normal file
|
@ -0,0 +1,18 @@
|
|||
import { Action } from 'redux';
|
||||
import { buildActionCreator, buildReducer } from '../../utils/helpers/redux';
|
||||
|
||||
/* eslint-disable padding-line-between-statements */
|
||||
export const APP_UPDATE_AVAILABLE = 'shlink/appUpdates/APP_UPDATE_AVAILABLE';
|
||||
export const RESET_APP_UPDATE = 'shlink/appUpdates/RESET_APP_UPDATE';
|
||||
/* eslint-enable padding-line-between-statements */
|
||||
|
||||
const initialState = false;
|
||||
|
||||
export default buildReducer<boolean, Action<string>>({
|
||||
[APP_UPDATE_AVAILABLE]: () => true,
|
||||
[RESET_APP_UPDATE]: () => false,
|
||||
}, initialState);
|
||||
|
||||
export const appUpdateAvailable = buildActionCreator(APP_UPDATE_AVAILABLE);
|
||||
|
||||
export const resetAppUpdate = buildActionCreator(RESET_APP_UPDATE);
|
26
src/app/services/provideServices.ts
Normal file
26
src/app/services/provideServices.ts
Normal file
|
@ -0,0 +1,26 @@
|
|||
import Bottle from 'bottlejs';
|
||||
import { appUpdateAvailable, resetAppUpdate } from '../reducers/appUpdates';
|
||||
import App from '../../App';
|
||||
import { ConnectDecorator } from '../../container/types';
|
||||
|
||||
const provideServices = (bottle: Bottle, connect: ConnectDecorator) => {
|
||||
// Components
|
||||
bottle.serviceFactory(
|
||||
'App',
|
||||
App,
|
||||
'MainHeader',
|
||||
'Home',
|
||||
'MenuLayout',
|
||||
'CreateServer',
|
||||
'EditServer',
|
||||
'Settings',
|
||||
'ShlinkVersionsContainer',
|
||||
);
|
||||
bottle.decorator('App', connect([ 'servers', 'settings', 'appUpdated' ], [ 'fetchServers', 'resetAppUpdate' ]));
|
||||
|
||||
// Actions
|
||||
bottle.serviceFactory('appUpdateAvailable', () => appUpdateAvailable);
|
||||
bottle.serviceFactory('resetAppUpdate', () => resetAppUpdate);
|
||||
};
|
||||
|
||||
export default provideServices;
|
|
@ -3,9 +3,9 @@ import { Link } from 'react-router-dom';
|
|||
import { Card, Row } from 'reactstrap';
|
||||
import { ExternalLink } from 'react-external-link';
|
||||
import ServersListGroup from '../servers/ServersListGroup';
|
||||
import './Home.scss';
|
||||
import { ServersMap } from '../servers/data';
|
||||
import { ShlinkLogo } from './img/ShlinkLogo';
|
||||
import './Home.scss';
|
||||
|
||||
export interface HomeProps {
|
||||
servers: ServersMap;
|
||||
|
|
|
@ -2,7 +2,6 @@ import Bottle, { IContainer } from 'bottlejs';
|
|||
import { withRouter } from 'react-router-dom';
|
||||
import { connect as reduxConnect } from 'react-redux';
|
||||
import { pick } from 'ramda';
|
||||
import App from '../App';
|
||||
import provideApiServices from '../api/services/provideServices';
|
||||
import provideCommonServices from '../common/services/provideServices';
|
||||
import provideShortUrlsServices from '../short-urls/services/provideServices';
|
||||
|
@ -13,6 +12,7 @@ import provideUtilsServices from '../utils/services/provideServices';
|
|||
import provideMercureServices from '../mercure/services/provideServices';
|
||||
import provideSettingsServices from '../settings/services/provideServices';
|
||||
import provideDomainsServices from '../domains/services/provideServices';
|
||||
import provideAppServices from '../app/services/provideServices';
|
||||
import { ConnectDecorator } from './types';
|
||||
|
||||
type LazyActionMap = Record<string, Function>;
|
||||
|
@ -33,19 +33,7 @@ const connect: ConnectDecorator = (propsFromState: string[] | null, actionServic
|
|||
actionServiceNames.reduce(mapActionService, {}),
|
||||
);
|
||||
|
||||
bottle.serviceFactory(
|
||||
'App',
|
||||
App,
|
||||
'MainHeader',
|
||||
'Home',
|
||||
'MenuLayout',
|
||||
'CreateServer',
|
||||
'EditServer',
|
||||
'Settings',
|
||||
'ShlinkVersionsContainer',
|
||||
);
|
||||
bottle.decorator('App', connect([ 'servers', 'settings' ], [ 'fetchServers' ]));
|
||||
|
||||
provideAppServices(bottle, connect);
|
||||
provideCommonServices(bottle, connect, withRouter);
|
||||
provideApiServices(bottle);
|
||||
provideShortUrlsServices(bottle, connect);
|
||||
|
|
|
@ -35,6 +35,7 @@ export interface ShlinkState {
|
|||
settings: Settings;
|
||||
domainsList: DomainsList;
|
||||
visitsOverview: VisitsOverview;
|
||||
appUpdated: boolean;
|
||||
}
|
||||
|
||||
export type ConnectDecorator = (props: string[] | null, actions?: string[]) => any;
|
||||
|
|
|
@ -5,7 +5,7 @@ import { homepage } from '../package.json';
|
|||
import container from './container';
|
||||
import store from './container/store';
|
||||
import { fixLeafletIcons } from './utils/helpers/leaflet';
|
||||
import * as serviceWorkerRegistration from './serviceWorkerRegistration';
|
||||
import { register as registerServiceWorker } from './serviceWorkerRegistration';
|
||||
import 'react-datepicker/dist/react-datepicker.css';
|
||||
import 'leaflet/dist/leaflet.css';
|
||||
import './index.scss';
|
||||
|
@ -13,7 +13,7 @@ import './index.scss';
|
|||
// This overwrites icons used for leaflet maps, fixing some issues caused by webpack while processing the CSS
|
||||
fixLeafletIcons();
|
||||
|
||||
const { App, ScrollToTop, ErrorHandler } = container;
|
||||
const { App, ScrollToTop, ErrorHandler, appUpdateAvailable } = container;
|
||||
|
||||
render(
|
||||
<Provider store={store}>
|
||||
|
@ -31,4 +31,8 @@ render(
|
|||
// If you want your app to work offline and load faster, you can change
|
||||
// unregister() to register() below. Note this comes with some pitfalls.
|
||||
// Learn more about service workers: https://cra.link/PWA
|
||||
serviceWorkerRegistration.register();
|
||||
registerServiceWorker({
|
||||
onUpdate() {
|
||||
store.dispatch(appUpdateAvailable()); // eslint-disable-line @typescript-eslint/no-unsafe-call
|
||||
},
|
||||
});
|
||||
|
|
|
@ -17,6 +17,7 @@ import mercureInfoReducer from '../mercure/reducers/mercureInfo';
|
|||
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 { ShlinkState } from '../container/types';
|
||||
|
||||
export default combineReducers<ShlinkState>({
|
||||
|
@ -38,4 +39,5 @@ export default combineReducers<ShlinkState>({
|
|||
settings: settingsReducer,
|
||||
domainsList: domainsListReducer,
|
||||
visitsOverview: visitsOverviewReducer,
|
||||
appUpdated: appUpdatesReducer,
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue