diff --git a/src/components/ConnectionRequired.tsx b/src/components/ConnectionRequired.tsx index 9c5f402b0a..59e680e219 100644 --- a/src/components/ConnectionRequired.tsx +++ b/src/components/ConnectionRequired.tsx @@ -1,4 +1,4 @@ -import React, { FunctionComponent, useEffect, useState } from 'react'; +import React, { FunctionComponent, useCallback, useEffect, useState } from 'react'; import { Outlet, useLocation, useNavigate } from 'react-router-dom'; import type { ConnectResponse } from 'jellyfin-apiclient'; @@ -35,116 +35,119 @@ const ConnectionRequired: FunctionComponent = ({ const [ isLoading, setIsLoading ] = useState(true); - useEffect(() => { - const bounce = async (connectionResponse: ConnectResponse) => { - switch (connectionResponse.State) { - case ConnectionState.SignedIn: - // Already logged in, bounce to the home page - console.debug('[ConnectionRequired] already logged in, redirecting to home'); - navigate(BounceRoutes.Home); - return; - case ConnectionState.ServerSignIn: - // Bounce to the login page - if (location.pathname === BounceRoutes.Login) { - setIsLoading(false); - } else { - console.debug('[ConnectionRequired] not logged in, redirecting to login page'); - navigate(`${BounceRoutes.Login}?serverid=${connectionResponse.ApiClient.serverId()}`); - } - return; - case ConnectionState.ServerSelection: - // Bounce to select server page - console.debug('[ConnectionRequired] redirecting to select server page'); - navigate(BounceRoutes.SelectServer); - return; - case ConnectionState.ServerUpdateNeeded: - // Show update needed message and bounce to select server page - try { - await alert({ - text: globalize.translate('ServerUpdateNeeded', 'https://github.com/jellyfin/jellyfin'), - html: globalize.translate('ServerUpdateNeeded', 'https://github.com/jellyfin/jellyfin') - }); - } catch (ex) { - console.warn('[ConnectionRequired] failed to show alert', ex); - } - console.debug('[ConnectionRequired] server update required, redirecting to select server page'); - navigate(BounceRoutes.SelectServer); - return; - } - - console.warn('[ConnectionRequired] unhandled connection state', connectionResponse.State); - }; - - const validateConnection = async () => { - // Check connection status on initial page load - const firstConnection = appRouter.firstConnectionResult; - appRouter.firstConnectionResult = null; - - if (firstConnection && firstConnection.State !== ConnectionState.SignedIn) { - if (firstConnection.State === ConnectionState.ServerSignIn) { - // Verify the wizard is complete - try { - const infoResponse = await fetch(`${firstConnection.ApiClient.serverAddress()}/System/Info/Public`); - if (!infoResponse.ok) { - throw new Error('Public system info request failed'); - } - const systemInfo = await infoResponse.json(); - if (!systemInfo?.StartupWizardCompleted) { - // Update the current ApiClient - // TODO: Is there a better place to handle this? - ServerConnections.setLocalApiClient(firstConnection.ApiClient); - // Bounce to the wizard - console.info('[ConnectionRequired] startup wizard is not complete, redirecting there'); - navigate(BounceRoutes.StartWizard); - return; - } - } catch (ex) { - console.error('[ConnectionRequired] checking wizard status failed', ex); - return; - } + const bounce = useCallback(async (connectionResponse: ConnectResponse) => { + switch (connectionResponse.State) { + case ConnectionState.SignedIn: + // Already logged in, bounce to the home page + console.debug('[ConnectionRequired] already logged in, redirecting to home'); + navigate(BounceRoutes.Home); + return; + case ConnectionState.ServerSignIn: + // Bounce to the login page + if (location.pathname === BounceRoutes.Login) { + setIsLoading(false); + } else { + console.debug('[ConnectionRequired] not logged in, redirecting to login page'); + navigate(`${BounceRoutes.Login}?serverid=${connectionResponse.ApiClient.serverId()}`); } + return; + case ConnectionState.ServerSelection: + // Bounce to select server page + console.debug('[ConnectionRequired] redirecting to select server page'); + navigate(BounceRoutes.SelectServer); + return; + case ConnectionState.ServerUpdateNeeded: + // Show update needed message and bounce to select server page + try { + await alert({ + text: globalize.translate('ServerUpdateNeeded', 'https://github.com/jellyfin/jellyfin'), + html: globalize.translate('ServerUpdateNeeded', 'https://github.com/jellyfin/jellyfin') + }); + } catch (ex) { + console.warn('[ConnectionRequired] failed to show alert', ex); + } + console.debug('[ConnectionRequired] server update required, redirecting to select server page'); + navigate(BounceRoutes.SelectServer); + return; + } - // Bounce to the correct page in the login flow - bounce(firstConnection); + console.warn('[ConnectionRequired] unhandled connection state', connectionResponse.State); + }, [location.pathname, navigate]); + + const handleIncompleteWizard = useCallback(async (firstConnection: ConnectResponse) => { + if (firstConnection.State === ConnectionState.ServerSignIn) { + // Verify the wizard is complete + try { + const infoResponse = await fetch(`${firstConnection.ApiClient.serverAddress()}/System/Info/Public`); + if (!infoResponse.ok) { + throw new Error('Public system info request failed'); + } + const systemInfo = await infoResponse.json(); + if (!systemInfo?.StartupWizardCompleted) { + // Update the current ApiClient + // TODO: Is there a better place to handle this? + ServerConnections.setLocalApiClient(firstConnection.ApiClient); + // Bounce to the wizard + console.info('[ConnectionRequired] startup wizard is not complete, redirecting there'); + navigate(BounceRoutes.StartWizard); + return; + } + } catch (ex) { + console.error('[ConnectionRequired] checking wizard status failed', ex); return; } + } - // TODO: appRouter will call appHost.exit() if navigating back when you are already at the default route. - // This case will need to be handled elsewhere before appRouter can be killed. + // Bounce to the correct page in the login flow + bounce(firstConnection); + }, [bounce, navigate]); - const client = ServerConnections.currentApiClient(); + const validateUserAccess = useCallback(async () => { + const client = ServerConnections.currentApiClient(); - // If this is a user route, ensure a user is logged in - if ((isAdminRequired || isUserRequired) && !client?.isLoggedIn()) { - try { - console.warn('[ConnectionRequired] unauthenticated user attempted to access user route'); + // If this is a user route, ensure a user is logged in + if ((isAdminRequired || isUserRequired) && !client?.isLoggedIn()) { + try { + console.warn('[ConnectionRequired] unauthenticated user attempted to access user route'); + bounce(await ServerConnections.connect()); + } catch (ex) { + console.warn('[ConnectionRequired] error bouncing from user route', ex); + } + return; + } + + // If this is an admin route, ensure the user has access + if (isAdminRequired) { + try { + const user = await client?.getCurrentUser(); + if (!user?.Policy?.IsAdministrator) { + console.warn('[ConnectionRequired] normal user attempted to access admin route'); bounce(await ServerConnections.connect()); - } catch (ex) { - console.warn('[ConnectionRequired] error bouncing from user route', ex); - } - return; - } - - // If this is an admin route, ensure the user has access - if (isAdminRequired) { - try { - const user = await client?.getCurrentUser(); - if (!user?.Policy?.IsAdministrator) { - console.warn('[ConnectionRequired] normal user attempted to access admin route'); - bounce(await ServerConnections.connect()); - return; - } - } catch (ex) { - console.warn('[ConnectionRequired] error bouncing from admin route', ex); return; } + } catch (ex) { + console.warn('[ConnectionRequired] error bouncing from admin route', ex); + return; } + } - setIsLoading(false); - }; + setIsLoading(false); + }, [bounce, isAdminRequired, isUserRequired]); - validateConnection(); - }, [ isAdminRequired, isUserRequired, location.pathname, navigate ]); + useEffect(() => { + // TODO: appRouter will call appHost.exit() if navigating back when you are already at the default route. + // This case will need to be handled elsewhere before appRouter can be killed. + + // Check connection status on initial page load + const firstConnection = appRouter.firstConnectionResult; + appRouter.firstConnectionResult = null; + + if (firstConnection && firstConnection.State !== ConnectionState.SignedIn) { + handleIncompleteWizard(firstConnection); + } else { + validateUserAccess(); + } + }, [handleIncompleteWizard, validateUserAccess]); if (isLoading) { return ;