diff --git a/ui/src/App.tsx b/ui/src/App.tsx index c2706cd2..00b8d5cd 100644 --- a/ui/src/App.tsx +++ b/ui/src/App.tsx @@ -1,17 +1,13 @@ -import React, {useEffect} from 'react'; +import React from 'react'; import {createHashRouter, RouterProvider} from 'react-router-dom'; import Applications from './application/Applications.tsx'; import Clients from './client/Clients.tsx'; import {checkAuthLoader} from './common/Auth.ts'; import Messages from './message/Messages.tsx'; -import {WebSocketStore} from './message/WebSocketStore.ts'; import PluginsRootLayout from './pages/plugins.tsx'; import RootLayout from './pages/root'; import PluginDetailView from './plugin/PluginDetailView.tsx'; import Plugins from './plugin/Plugins.tsx'; -import * as Notifications from './snack/browserNotification.ts'; -import {useAppDispatch, useAppSelector} from './store'; -import {messageActions} from './message/message-slice.ts'; import Login from './user/Login.tsx'; import Users from './user/Users.tsx'; @@ -71,46 +67,6 @@ const router = createHashRouter([ }, ]); -const ws = new WebSocketStore(); - -const App = () => { - const dispatch = useAppDispatch(); - const loggedIn = useAppSelector((state) => state.auth.loggedIn); - const reloadRequired = useAppSelector((state) => state.ui.reloadRequired); - - useEffect(() => { - if (loggedIn) { - ws.listen((message) => { - dispatch(messageActions.loading(true)); - dispatch(messageActions.add(message)); - Notifications.notifyNewMessage(message); - if (message.priority >= 4) { - const src = 'static/notification.ogg'; - const audio = new Audio(src); - audio.play(); - } - }); - window.onbeforeunload = () => { - ws.close(); - }; - } else { - ws.close(); - } - }, [dispatch, loggedIn, reloadRequired]); - - - return ( - - ); -}; +const App = () => (); export default App; - -/* - - {authenticating ? (} />) : null} - } /> - } /> - - -*/ diff --git a/ui/src/message/WebSocketStore.ts b/ui/src/message/WebSocketStore.ts index 8633874c..9b7dbce9 100644 --- a/ui/src/message/WebSocketStore.ts +++ b/ui/src/message/WebSocketStore.ts @@ -1,10 +1,13 @@ +import {Middleware} from '@reduxjs/toolkit'; import {AxiosError} from 'axios'; import {getAuthToken} from '../common/Auth.ts'; import * as config from '../config'; +import * as Notifications from '../snack/browserNotification.ts'; import {tryAuthenticate} from '../user/auth-actions.ts'; import {uiActions} from '../store/ui-slice.ts'; import {IMessage} from '../types'; -import state from '../store/index.ts'; +import state, {RootState} from '../store/index.ts'; +import {messageActions} from './message-slice.ts'; export class WebSocketStore { private wsActive = false; @@ -57,3 +60,38 @@ export class WebSocketStore { public close = () => this.ws?.close(1000, 'WebSocketStore#close'); } + +const ws = new WebSocketStore(); + +export const handleWebsocketMiddleware: Middleware<{}, RootState> = + (store) => (next) => (action) => { + const prevLoginStatus = store.getState().auth.loggedIn; + const prevReloadRequired = store.getState().ui.reloadRequired; + const result = next(action); + const nextLoginStatus = store.getState().auth.loggedIn; + const nextReloadRequired = store.getState().ui.reloadRequired; + + // Open websocket connection on login and if a reload is required + if ((action.type.startsWith('auth/login') && prevLoginStatus !== nextLoginStatus) + || (action.type.startsWith('ui/setReloadRequired') && prevReloadRequired !== nextReloadRequired && nextReloadRequired) + ) { + ws.listen((message) => { + store.dispatch(messageActions.loading(true)); + store.dispatch(messageActions.add(message)); + Notifications.notifyNewMessage(message); + if (message.priority >= 4) { + const src = 'static/notification.ogg'; + const audio = new Audio(src); + audio.play(); + } + }); + window.onbeforeunload = () => { + ws.close(); + }; + } + // Close websocket if the user logs out + if (action.type.startsWith('auth/logout') && prevLoginStatus !== nextLoginStatus && !nextLoginStatus) { + ws.close(); + } + return result; + }; diff --git a/ui/src/store/index.ts b/ui/src/store/index.ts index 5ce295d6..8ab8f41b 100644 --- a/ui/src/store/index.ts +++ b/ui/src/store/index.ts @@ -1,5 +1,6 @@ import {configureStore} from '@reduxjs/toolkit'; import {useDispatch, useSelector} from 'react-redux'; +import {handleWebsocketMiddleware} from '../message/WebSocketStore.ts'; import uiReducer from './ui-slice'; import authReducer from '../user/auth-slice'; @@ -21,7 +22,7 @@ const store = configureStore({ message: messageReducer, }, middleware: (getDefaultMiddleware) => - getDefaultMiddleware().concat(connectionErrorMiddleware), + getDefaultMiddleware().concat(handleWebsocketMiddleware, connectionErrorMiddleware), }); // Infer the `RootState` and `AppDispatch` types from the store itself