From 9e66639d814765152aa3b686ed3032cd444403cc Mon Sep 17 00:00:00 2001 From: Aleksander <170264518+t-aleksander@users.noreply.github.com> Date: Wed, 4 Feb 2026 14:28:12 +0100 Subject: [PATCH 1/3] restore wizard routing --- web/src/routes/__root.tsx | 46 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 44 insertions(+), 2 deletions(-) diff --git a/web/src/routes/__root.tsx b/web/src/routes/__root.tsx index fbefa9a574..07975bd9c1 100644 --- a/web/src/routes/__root.tsx +++ b/web/src/routes/__root.tsx @@ -1,7 +1,14 @@ import type { QueryClient } from '@tanstack/react-query'; -import { createRootRouteWithContext, Outlet, redirect } from '@tanstack/react-router'; +import { + createRootRouteWithContext, + Outlet, + type ParsedLocation, + redirect, +} from '@tanstack/react-router'; import { AppLoaderPage } from '../pages/AppLoaderPage/AppLoaderPage'; +import { useSetupWizardStore } from '../pages/SetupPage/useSetupWizardStore'; import { SnackbarManager } from '../shared/defguard-ui/providers/snackbar/SnackbarManager'; +import { useApp } from '../shared/hooks/useApp'; import { useAuth } from '../shared/hooks/useAuth'; import { getUserMeQueryOptions } from '../shared/query'; @@ -9,18 +16,53 @@ interface RouterContext { queryClient: QueryClient; } +// Handles the initial wizard redirect. +// All routes should redirect to the setup wizard if the initial setup is not completed. +const handleWizardRedirect = async (location: ParsedLocation) => { + const settingsEssentials = useApp((s) => s.settingsEssentials); + + // Tries to access any route but setup is not completed + const setupNotCompletedAnyAccess = + !settingsEssentials.initial_setup_completed && + !location.pathname.startsWith('/setup-wizard'); + + // Tries to access setup wizard but setup is already completed + const setupCompletedButAccessingWizard = + settingsEssentials.initial_setup_completed && + location.pathname.startsWith('/setup-wizard'); + + if (setupNotCompletedAnyAccess) { + useSetupWizardStore.getState().reset(); + throw redirect({ to: '/setup-wizard', replace: true }); + } else if (setupCompletedButAccessingWizard) { + throw redirect({ to: '/vpn-overview', replace: true }); + } +}; + export const Route = createRootRouteWithContext()({ component: RootComponent, beforeLoad: async ({ location, context }) => { - if (location.pathname.startsWith('/auth')) { + await handleWizardRedirect(location); + + if ( + location.pathname.startsWith('/auth') || + location.pathname.startsWith('/setup-wizard') + ) { return; } + try { const user = ( await ( await context.queryClient.ensureQueryData(getUserMeQueryOptions) )() ).data; + + // Invalid user object + if (!user.id) { + throw redirect({ to: '/auth/login', replace: true }); + } + useAuth.getState().setUser(user); } catch (_) { useAuth.getState().reset(); From c95ecfe4baa5a241b6035a027ded66c185d49228 Mon Sep 17 00:00:00 2001 From: Aleksander <170264518+t-aleksander@users.noreply.github.com> Date: Wed, 4 Feb 2026 14:59:06 +0100 Subject: [PATCH 2/3] fix --- web/src/routes/__root.tsx | 25 ++++++++++++++++++++----- web/src/shared/query.ts | 11 +++++++++++ 2 files changed, 31 insertions(+), 5 deletions(-) diff --git a/web/src/routes/__root.tsx b/web/src/routes/__root.tsx index 07975bd9c1..180727c5b2 100644 --- a/web/src/routes/__root.tsx +++ b/web/src/routes/__root.tsx @@ -8,9 +8,11 @@ import { import { AppLoaderPage } from '../pages/AppLoaderPage/AppLoaderPage'; import { useSetupWizardStore } from '../pages/SetupPage/useSetupWizardStore'; import { SnackbarManager } from '../shared/defguard-ui/providers/snackbar/SnackbarManager'; -import { useApp } from '../shared/hooks/useApp'; import { useAuth } from '../shared/hooks/useAuth'; -import { getUserMeQueryOptions } from '../shared/query'; +import { + getSettingsEssentialsQueryOptions, + getUserMeQueryOptions, +} from '../shared/query'; interface RouterContext { queryClient: QueryClient; @@ -18,8 +20,18 @@ interface RouterContext { // Handles the initial wizard redirect. // All routes should redirect to the setup wizard if the initial setup is not completed. -const handleWizardRedirect = async (location: ParsedLocation) => { - const settingsEssentials = useApp((s) => s.settingsEssentials); +const handleWizardRedirect = async ({ + location, + context, +}: { + location: ParsedLocation; + context: RouterContext; +}) => { + const settingsEssentials = ( + await ( + await context.queryClient.ensureQueryData(getSettingsEssentialsQueryOptions) + )() + ).data; // Tries to access any route but setup is not completed const setupNotCompletedAnyAccess = @@ -42,7 +54,10 @@ const handleWizardRedirect = async (location: ParsedLocation) => { export const Route = createRootRouteWithContext()({ component: RootComponent, beforeLoad: async ({ location, context }) => { - await handleWizardRedirect(location); + await handleWizardRedirect({ + location, + context, + }); if ( location.pathname.startsWith('/auth') || diff --git a/web/src/shared/query.ts b/web/src/shared/query.ts index 401db9b28d..68fa20f71e 100644 --- a/web/src/shared/query.ts +++ b/web/src/shared/query.ts @@ -168,3 +168,14 @@ export const getActivityLogStreamsQueryOptions = queryOptions({ queryKey: ['activity_log_stream'], select: (resp) => resp.data, }); + +export const getSettingsEssentialsQueryOptions = queryOptions({ + queryFn: () => api.settings.getSettingsEssentials, + queryKey: ['settings-essentials'], + throwOnError: false, + retry: false, + refetchOnWindowFocus: false, + refetchOnMount: true, + refetchOnReconnect: true, + staleTime: 60_000, +}); From 8751900bb6a3f8eebde576dfae11b88d318536e4 Mon Sep 17 00:00:00 2001 From: Aleksander <170264518+t-aleksander@users.noreply.github.com> Date: Wed, 4 Feb 2026 16:12:59 +0100 Subject: [PATCH 3/3] redirect to login --- web/src/routes/__root.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/src/routes/__root.tsx b/web/src/routes/__root.tsx index 180727c5b2..5227977542 100644 --- a/web/src/routes/__root.tsx +++ b/web/src/routes/__root.tsx @@ -47,7 +47,7 @@ const handleWizardRedirect = async ({ useSetupWizardStore.getState().reset(); throw redirect({ to: '/setup-wizard', replace: true }); } else if (setupCompletedButAccessingWizard) { - throw redirect({ to: '/vpn-overview', replace: true }); + throw redirect({ to: '/auth/login', replace: true }); } };