diff --git a/src/app/App.tsx b/src/app/App.tsx index 9bd2d471..078fef99 100644 --- a/src/app/App.tsx +++ b/src/app/App.tsx @@ -14,11 +14,7 @@ import { useLoadRemoteServers } from '../servers/reducers/remoteServers'; import { useSettings } from '../settings/reducers/settings'; import { Settings } from '../settings/Settings'; import { forceUpdate } from '../utils/helpers/sw'; - -export type AppProps = { - resetAppUpdate: () => void; - appUpdated: boolean; -}; +import { useAppUpdated } from './reducers/appUpdates'; type AppDeps = { Home: FC; @@ -27,7 +23,8 @@ type AppDeps = { ManageServers: FC; }; -const App: FCWithDeps = ({ appUpdated, resetAppUpdate }) => { +const App: FCWithDeps = () => { + const { appUpdated, resetAppUpdate } = useAppUpdated(); const { Home, ShlinkWebComponentContainer, diff --git a/src/app/reducers/appUpdates.ts b/src/app/reducers/appUpdates.ts index 675b3959..2bf870d8 100644 --- a/src/app/reducers/appUpdates.ts +++ b/src/app/reducers/appUpdates.ts @@ -1,4 +1,6 @@ import { createSlice } from '@reduxjs/toolkit'; +import { useCallback } from 'react'; +import { useAppDispatch, useAppSelector } from '../../store'; const { actions, reducer } = createSlice({ name: 'shlink/appUpdates', @@ -12,3 +14,12 @@ const { actions, reducer } = createSlice({ export const { appUpdateAvailable, resetAppUpdate } = actions; 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 }; +}; diff --git a/src/app/services/provideServices.ts b/src/app/services/provideServices.ts index 80278b93..0d3e58b6 100644 --- a/src/app/services/provideServices.ts +++ b/src/app/services/provideServices.ts @@ -1,14 +1,7 @@ import type Bottle from 'bottlejs'; -import type { ConnectDecorator } from '../../container/types'; import { AppFactory } from '../App'; -import { appUpdateAvailable, resetAppUpdate } from '../reducers/appUpdates'; -export const provideServices = (bottle: Bottle, connect: ConnectDecorator) => { +export const provideServices = (bottle: Bottle) => { // Components bottle.factory('App', AppFactory); - bottle.decorator('App', connect(['appUpdated'], ['resetAppUpdate'])); - - // Actions - bottle.serviceFactory('appUpdateAvailable', () => appUpdateAvailable); - bottle.serviceFactory('resetAppUpdate', () => resetAppUpdate); }; diff --git a/src/container/index.ts b/src/container/index.ts index d7fa9606..81b5828e 100644 --- a/src/container/index.ts +++ b/src/container/index.ts @@ -1,39 +1,15 @@ -import type { IContainer } from 'bottlejs'; import Bottle from 'bottlejs'; -import { connect as reduxConnect } from 'react-redux'; import { provideServices as provideApiServices } from '../api/services/provideServices'; import { provideServices as provideAppServices } from '../app/services/provideServices'; import { provideServices as provideCommonServices } from '../common/services/provideServices'; import { provideServices as provideServersServices } from '../servers/services/provideServices'; import { provideServices as provideUtilsServices } from '../utils/services/provideServices'; -import type { ConnectDecorator } from './types'; - -type LazyActionMap = Record unknown>; const bottle = new Bottle(); export const { container } = bottle; -const lazyService = unknown, K>(cont: IContainer, serviceName: string) => - (...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); +provideAppServices(bottle); provideCommonServices(bottle); provideApiServices(bottle); provideServersServices(bottle); diff --git a/src/container/types.ts b/src/container/types.ts deleted file mode 100644 index 71b20fbd..00000000 --- a/src/container/types.ts +++ /dev/null @@ -1 +0,0 @@ -export type ConnectDecorator = (props: string[] | null, actions?: string[]) => any; diff --git a/src/index.tsx b/src/index.tsx index e3509a65..f7022a69 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -2,6 +2,7 @@ import { createRoot } from 'react-dom/client'; import { Provider } from 'react-redux'; import { BrowserRouter } from 'react-router'; import pack from '../package.json'; +import { appUpdateAvailable } from './app/reducers/appUpdates'; import { ErrorHandler } from './common/ErrorHandler'; import { ScrollToTop } from './common/ScrollToTop'; import { container } from './container'; @@ -11,7 +12,7 @@ import { setUpStore } from './store'; import './tailwind.css'; const store = setUpStore(); -const { App, appUpdateAvailable } = container; +const { App } = container; createRoot(document.getElementById('root')!).render( diff --git a/test/app/App.test.tsx b/test/app/App.test.tsx index 6f291b6e..694d12a9 100644 --- a/test/app/App.test.tsx +++ b/test/app/App.test.tsx @@ -22,7 +22,7 @@ describe('', () => { ({}), buildShlinkApiClient: vi.fn() })} > - {}} /> + , { @@ -32,6 +32,7 @@ describe('', () => { def456: fromPartial({ id: 'def456', name: 'def456 server' }), }, settings: fromPartial({}), + appUpdated: false, }, }, ));