mirror of
https://github.com/shlinkio/shlink-web-client.git
synced 2026-03-17 04:53:49 +00:00
Do not inject appupdated state or actions
This commit is contained in:
@@ -14,11 +14,7 @@ import { useLoadRemoteServers } from '../servers/reducers/remoteServers';
|
|||||||
import { useSettings } from '../settings/reducers/settings';
|
import { useSettings } from '../settings/reducers/settings';
|
||||||
import { Settings } from '../settings/Settings';
|
import { Settings } from '../settings/Settings';
|
||||||
import { forceUpdate } from '../utils/helpers/sw';
|
import { forceUpdate } from '../utils/helpers/sw';
|
||||||
|
import { useAppUpdated } from './reducers/appUpdates';
|
||||||
export type AppProps = {
|
|
||||||
resetAppUpdate: () => void;
|
|
||||||
appUpdated: boolean;
|
|
||||||
};
|
|
||||||
|
|
||||||
type AppDeps = {
|
type AppDeps = {
|
||||||
Home: FC;
|
Home: FC;
|
||||||
@@ -27,7 +23,8 @@ type AppDeps = {
|
|||||||
ManageServers: FC;
|
ManageServers: FC;
|
||||||
};
|
};
|
||||||
|
|
||||||
const App: FCWithDeps<AppProps, AppDeps> = ({ appUpdated, resetAppUpdate }) => {
|
const App: FCWithDeps<any, AppDeps> = () => {
|
||||||
|
const { appUpdated, resetAppUpdate } = useAppUpdated();
|
||||||
const {
|
const {
|
||||||
Home,
|
Home,
|
||||||
ShlinkWebComponentContainer,
|
ShlinkWebComponentContainer,
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
import { createSlice } from '@reduxjs/toolkit';
|
import { createSlice } from '@reduxjs/toolkit';
|
||||||
|
import { useCallback } from 'react';
|
||||||
|
import { useAppDispatch, useAppSelector } from '../../store';
|
||||||
|
|
||||||
const { actions, reducer } = createSlice({
|
const { actions, reducer } = createSlice({
|
||||||
name: 'shlink/appUpdates',
|
name: 'shlink/appUpdates',
|
||||||
@@ -12,3 +14,12 @@ const { actions, reducer } = createSlice({
|
|||||||
export const { appUpdateAvailable, resetAppUpdate } = actions;
|
export const { appUpdateAvailable, resetAppUpdate } = actions;
|
||||||
|
|
||||||
export const appUpdatesReducer = reducer;
|
export const appUpdatesReducer = reducer;
|
||||||
|
|
||||||
|
export const useAppUpdated = () => {
|
||||||
|
const dispatch = useAppDispatch();
|
||||||
|
const appUpdateAvailable = useCallback(() => dispatch(actions.appUpdateAvailable()), [dispatch]);
|
||||||
|
const resetAppUpdate = useCallback(() => dispatch(actions.resetAppUpdate()), [dispatch]);
|
||||||
|
const appUpdated = useAppSelector((state) => state.appUpdated);
|
||||||
|
|
||||||
|
return { appUpdated, appUpdateAvailable, resetAppUpdate };
|
||||||
|
};
|
||||||
|
|||||||
@@ -1,14 +1,7 @@
|
|||||||
import type Bottle from 'bottlejs';
|
import type Bottle from 'bottlejs';
|
||||||
import type { ConnectDecorator } from '../../container/types';
|
|
||||||
import { AppFactory } from '../App';
|
import { AppFactory } from '../App';
|
||||||
import { appUpdateAvailable, resetAppUpdate } from '../reducers/appUpdates';
|
|
||||||
|
|
||||||
export const provideServices = (bottle: Bottle, connect: ConnectDecorator) => {
|
export const provideServices = (bottle: Bottle) => {
|
||||||
// Components
|
// Components
|
||||||
bottle.factory('App', AppFactory);
|
bottle.factory('App', AppFactory);
|
||||||
bottle.decorator('App', connect(['appUpdated'], ['resetAppUpdate']));
|
|
||||||
|
|
||||||
// Actions
|
|
||||||
bottle.serviceFactory('appUpdateAvailable', () => appUpdateAvailable);
|
|
||||||
bottle.serviceFactory('resetAppUpdate', () => resetAppUpdate);
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,39 +1,15 @@
|
|||||||
import type { IContainer } from 'bottlejs';
|
|
||||||
import Bottle from 'bottlejs';
|
import Bottle from 'bottlejs';
|
||||||
import { connect as reduxConnect } from 'react-redux';
|
|
||||||
import { provideServices as provideApiServices } from '../api/services/provideServices';
|
import { provideServices as provideApiServices } from '../api/services/provideServices';
|
||||||
import { provideServices as provideAppServices } from '../app/services/provideServices';
|
import { provideServices as provideAppServices } from '../app/services/provideServices';
|
||||||
import { provideServices as provideCommonServices } from '../common/services/provideServices';
|
import { provideServices as provideCommonServices } from '../common/services/provideServices';
|
||||||
import { provideServices as provideServersServices } from '../servers/services/provideServices';
|
import { provideServices as provideServersServices } from '../servers/services/provideServices';
|
||||||
import { provideServices as provideUtilsServices } from '../utils/services/provideServices';
|
import { provideServices as provideUtilsServices } from '../utils/services/provideServices';
|
||||||
import type { ConnectDecorator } from './types';
|
|
||||||
|
|
||||||
type LazyActionMap = Record<string, (...args: unknown[]) => unknown>;
|
|
||||||
|
|
||||||
const bottle = new Bottle();
|
const bottle = new Bottle();
|
||||||
|
|
||||||
export const { container } = bottle;
|
export const { container } = bottle;
|
||||||
|
|
||||||
const lazyService = <T extends (...args: unknown[]) => unknown, K>(cont: IContainer, serviceName: string) =>
|
provideAppServices(bottle);
|
||||||
(...args: any[]) => (cont[serviceName] as T)(...args) as K;
|
|
||||||
|
|
||||||
const mapActionService = (map: LazyActionMap, actionName: string): LazyActionMap => ({
|
|
||||||
...map,
|
|
||||||
// Wrap actual action service in a function so that it is lazily created the first time it is called
|
|
||||||
[actionName]: lazyService(container, actionName),
|
|
||||||
});
|
|
||||||
|
|
||||||
const pickProps = (propsToPick: string[]) => (obj: any) => Object.fromEntries(
|
|
||||||
propsToPick.map((key) => [key, obj[key]]),
|
|
||||||
);
|
|
||||||
|
|
||||||
const connect: ConnectDecorator = (propsFromState: string[] | null, actionServiceNames: string[] = []) =>
|
|
||||||
reduxConnect(
|
|
||||||
propsFromState ? pickProps(propsFromState) : null,
|
|
||||||
actionServiceNames.reduce(mapActionService, {}),
|
|
||||||
);
|
|
||||||
|
|
||||||
provideAppServices(bottle, connect);
|
|
||||||
provideCommonServices(bottle);
|
provideCommonServices(bottle);
|
||||||
provideApiServices(bottle);
|
provideApiServices(bottle);
|
||||||
provideServersServices(bottle);
|
provideServersServices(bottle);
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
export type ConnectDecorator = (props: string[] | null, actions?: string[]) => any;
|
|
||||||
@@ -2,6 +2,7 @@ import { createRoot } from 'react-dom/client';
|
|||||||
import { Provider } from 'react-redux';
|
import { Provider } from 'react-redux';
|
||||||
import { BrowserRouter } from 'react-router';
|
import { BrowserRouter } from 'react-router';
|
||||||
import pack from '../package.json';
|
import pack from '../package.json';
|
||||||
|
import { appUpdateAvailable } from './app/reducers/appUpdates';
|
||||||
import { ErrorHandler } from './common/ErrorHandler';
|
import { ErrorHandler } from './common/ErrorHandler';
|
||||||
import { ScrollToTop } from './common/ScrollToTop';
|
import { ScrollToTop } from './common/ScrollToTop';
|
||||||
import { container } from './container';
|
import { container } from './container';
|
||||||
@@ -11,7 +12,7 @@ import { setUpStore } from './store';
|
|||||||
import './tailwind.css';
|
import './tailwind.css';
|
||||||
|
|
||||||
const store = setUpStore();
|
const store = setUpStore();
|
||||||
const { App, appUpdateAvailable } = container;
|
const { App } = container;
|
||||||
|
|
||||||
createRoot(document.getElementById('root')!).render(
|
createRoot(document.getElementById('root')!).render(
|
||||||
<ContainerProvider value={container}>
|
<ContainerProvider value={container}>
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ describe('<App />', () => {
|
|||||||
<ContainerProvider
|
<ContainerProvider
|
||||||
value={fromPartial({ HttpClient: fromPartial<HttpClient>({}), buildShlinkApiClient: vi.fn() })}
|
value={fromPartial({ HttpClient: fromPartial<HttpClient>({}), buildShlinkApiClient: vi.fn() })}
|
||||||
>
|
>
|
||||||
<App appUpdated={false} resetAppUpdate={() => {}} />
|
<App />
|
||||||
</ContainerProvider>
|
</ContainerProvider>
|
||||||
</MemoryRouter>,
|
</MemoryRouter>,
|
||||||
{
|
{
|
||||||
@@ -32,6 +32,7 @@ describe('<App />', () => {
|
|||||||
def456: fromPartial<ServerWithId>({ id: 'def456', name: 'def456 server' }),
|
def456: fromPartial<ServerWithId>({ id: 'def456', name: 'def456 server' }),
|
||||||
},
|
},
|
||||||
settings: fromPartial({}),
|
settings: fromPartial({}),
|
||||||
|
appUpdated: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
));
|
));
|
||||||
|
|||||||
Reference in New Issue
Block a user