diff --git a/surfsense_web/app/(home)/login/LocalLoginForm.tsx b/surfsense_web/app/(home)/login/LocalLoginForm.tsx index 9692d35e1..108151512 100644 --- a/surfsense_web/app/(home)/login/LocalLoginForm.tsx +++ b/surfsense_web/app/(home)/login/LocalLoginForm.tsx @@ -7,10 +7,10 @@ import { useRouter } from "next/navigation"; import { useTranslations } from "next-intl"; import { useState } from "react"; import { loginMutationAtom } from "@/atoms/auth/auth-mutation.atoms"; +import { useRuntimeConfig } from "@/components/providers/runtime-config"; import { Button } from "@/components/ui/button"; import { Spinner } from "@/components/ui/spinner"; import { getAuthErrorDetails, isNetworkError } from "@/lib/auth-errors"; -import { AUTH_TYPE } from "@/lib/env-config"; import { ValidationError } from "@/lib/error"; import { trackLoginAttempt, trackLoginFailure, trackLoginSuccess } from "@/lib/posthog/events"; @@ -26,7 +26,7 @@ export function LocalLoginForm() { title: null, message: null, }); - const authType = AUTH_TYPE; + const { authType } = useRuntimeConfig(); const router = useRouter(); const [{ mutateAsync: login, isPending: isLoggingIn }] = useAtom(loginMutationAtom); diff --git a/surfsense_web/app/(home)/login/layout.tsx b/surfsense_web/app/(home)/login/layout.tsx new file mode 100644 index 000000000..e14aec239 --- /dev/null +++ b/surfsense_web/app/(home)/login/layout.tsx @@ -0,0 +1,5 @@ +import { RuntimeConfig } from "@/components/providers/runtime-config.server"; + +export default function LoginLayout({ children }: { children: React.ReactNode }) { + return {children}; +} diff --git a/surfsense_web/app/(home)/login/page.tsx b/surfsense_web/app/(home)/login/page.tsx index 42a9182e9..8f146f815 100644 --- a/surfsense_web/app/(home)/login/page.tsx +++ b/surfsense_web/app/(home)/login/page.tsx @@ -6,11 +6,10 @@ import { useTranslations } from "next-intl"; import { Suspense, useEffect, useState } from "react"; import { toast } from "sonner"; import { Logo } from "@/components/Logo"; +import { useRuntimeConfig } from "@/components/providers/runtime-config"; import { Button } from "@/components/ui/button"; -import { useGlobalLoadingEffect } from "@/hooks/use-global-loading"; import { getAuthErrorDetails, shouldRetry } from "@/lib/auth-errors"; import { setRedirectPath } from "@/lib/auth-utils"; -import { AUTH_TYPE } from "@/lib/env-config"; import { AmbientBackground } from "./AmbientBackground"; import { GoogleLoginButton } from "./GoogleLoginButton"; import { LocalLoginForm } from "./LocalLoginForm"; @@ -19,8 +18,7 @@ function LoginContent() { const t = useTranslations("auth"); const tCommon = useTranslations("common"); const router = useRouter(); - const [authType, setAuthType] = useState(null); - const [isLoading, setIsLoading] = useState(true); + const { authType } = useRuntimeConfig(); const [urlError, setUrlError] = useState<{ title: string; message: string } | null>(null); const searchParams = useSearchParams(); @@ -96,19 +94,7 @@ function LoginContent() { duration: 4000, }); } - - // Get the auth type from centralized config - setAuthType(AUTH_TYPE); - setIsLoading(false); - }, [searchParams, t, tCommon]); - - // Use global loading screen for auth type determination - spinner animation won't reset - useGlobalLoadingEffect(isLoading); - - // Show nothing while loading - the GlobalLoadingProvider handles the loading UI - if (isLoading) { - return null; - } + }, [router, searchParams, t, tCommon]); if (authType === "GOOGLE") { return ; diff --git a/surfsense_web/app/(home)/register/layout.tsx b/surfsense_web/app/(home)/register/layout.tsx new file mode 100644 index 000000000..361df85c1 --- /dev/null +++ b/surfsense_web/app/(home)/register/layout.tsx @@ -0,0 +1,5 @@ +import { RuntimeConfig } from "@/components/providers/runtime-config.server"; + +export default function RegisterLayout({ children }: { children: React.ReactNode }) { + return {children}; +} diff --git a/surfsense_web/app/(home)/register/page.tsx b/surfsense_web/app/(home)/register/page.tsx index 1fd1a4ecb..9421a0156 100644 --- a/surfsense_web/app/(home)/register/page.tsx +++ b/surfsense_web/app/(home)/register/page.tsx @@ -9,11 +9,11 @@ import { useEffect, useState } from "react"; import { type ExternalToast, toast } from "sonner"; import { registerMutationAtom } from "@/atoms/auth/auth-mutation.atoms"; import { Logo } from "@/components/Logo"; +import { useRuntimeConfig } from "@/components/providers/runtime-config"; import { Button } from "@/components/ui/button"; import { Spinner } from "@/components/ui/spinner"; import { getAuthErrorDetails, isNetworkError, shouldRetry } from "@/lib/auth-errors"; import { getBearerToken } from "@/lib/auth-utils"; -import { AUTH_TYPE } from "@/lib/env-config"; import { AppError, ValidationError } from "@/lib/error"; import { trackRegistrationAttempt, @@ -25,6 +25,7 @@ import { AmbientBackground } from "../login/AmbientBackground"; export default function RegisterPage() { const t = useTranslations("auth"); const tCommon = useTranslations("common"); + const { authType } = useRuntimeConfig(); const [email, setEmail] = useState(""); const [password, setPassword] = useState(""); const [confirmPassword, setConfirmPassword] = useState(""); @@ -44,10 +45,10 @@ export default function RegisterPage() { router.replace("/dashboard"); return; } - if (AUTH_TYPE !== "LOCAL") { + if (authType !== "LOCAL") { router.push("/login"); } - }, [router]); + }, [authType, router]); const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); diff --git a/surfsense_web/app/dashboard/dashboard-shell.tsx b/surfsense_web/app/dashboard/dashboard-shell.tsx new file mode 100644 index 000000000..f84cd56eb --- /dev/null +++ b/surfsense_web/app/dashboard/dashboard-shell.tsx @@ -0,0 +1,42 @@ +"use client"; + +import { useEffect, useState } from "react"; +import { USER_QUERY_KEY } from "@/atoms/user/user-query.atoms"; +import { useGlobalLoadingEffect } from "@/hooks/use-global-loading"; +import { ensureTokensFromElectron, getBearerToken, redirectToLogin } from "@/lib/auth-utils"; +import { queryClient } from "@/lib/query-client/client"; + +export function DashboardShell({ children }: { children: React.ReactNode }) { + const [isCheckingAuth, setIsCheckingAuth] = useState(true); + + // Use the global loading screen - spinner animation won't reset + useGlobalLoadingEffect(isCheckingAuth); + + useEffect(() => { + async function checkAuth() { + let token = getBearerToken(); + if (!token) { + const synced = await ensureTokensFromElectron(); + if (synced) token = getBearerToken(); + } + if (!token) { + redirectToLogin(); + return; + } + queryClient.invalidateQueries({ queryKey: [...USER_QUERY_KEY] }); + setIsCheckingAuth(false); + } + checkAuth(); + }, []); + + // Return null while loading - the global provider handles the loading UI + if (isCheckingAuth) { + return null; + } + + return ( +
+
{children}
+
+ ); +} diff --git a/surfsense_web/app/dashboard/layout.tsx b/surfsense_web/app/dashboard/layout.tsx index 1f5481b15..6212c92e7 100644 --- a/surfsense_web/app/dashboard/layout.tsx +++ b/surfsense_web/app/dashboard/layout.tsx @@ -1,46 +1,14 @@ -"use client"; - -import { useEffect, useState } from "react"; -import { USER_QUERY_KEY } from "@/atoms/user/user-query.atoms"; -import { useGlobalLoadingEffect } from "@/hooks/use-global-loading"; -import { ensureTokensFromElectron, getBearerToken, redirectToLogin } from "@/lib/auth-utils"; -import { queryClient } from "@/lib/query-client/client"; +import { RuntimeConfig } from "@/components/providers/runtime-config.server"; +import { DashboardShell } from "./dashboard-shell"; interface DashboardLayoutProps { children: React.ReactNode; } export default function DashboardLayout({ children }: DashboardLayoutProps) { - const [isCheckingAuth, setIsCheckingAuth] = useState(true); - - // Use the global loading screen - spinner animation won't reset - useGlobalLoadingEffect(isCheckingAuth); - - useEffect(() => { - async function checkAuth() { - let token = getBearerToken(); - if (!token) { - const synced = await ensureTokensFromElectron(); - if (synced) token = getBearerToken(); - } - if (!token) { - redirectToLogin(); - return; - } - queryClient.invalidateQueries({ queryKey: [...USER_QUERY_KEY] }); - setIsCheckingAuth(false); - } - checkAuth(); - }, []); - - // Return null while loading - the global provider handles the loading UI - if (isCheckingAuth) { - return null; - } - return ( -
-
{children}
-
+ + {children} + ); } diff --git a/surfsense_web/app/desktop/login/layout.tsx b/surfsense_web/app/desktop/login/layout.tsx new file mode 100644 index 000000000..83556d314 --- /dev/null +++ b/surfsense_web/app/desktop/login/layout.tsx @@ -0,0 +1,5 @@ +import { RuntimeConfig } from "@/components/providers/runtime-config.server"; + +export default function DesktopLoginLayout({ children }: { children: React.ReactNode }) { + return {children}; +} diff --git a/surfsense_web/app/desktop/login/page.tsx b/surfsense_web/app/desktop/login/page.tsx index 41c956f3e..399da7434 100644 --- a/surfsense_web/app/desktop/login/page.tsx +++ b/surfsense_web/app/desktop/login/page.tsx @@ -8,6 +8,7 @@ import { useCallback, useEffect, useMemo, useRef, useState } from "react"; import { toast } from "sonner"; import { loginMutationAtom } from "@/atoms/auth/auth-mutation.atoms"; import { DEFAULT_SHORTCUTS, keyEventToAccelerator } from "@/components/desktop/shortcut-recorder"; +import { useIsGoogleAuth } from "@/components/providers/runtime-config"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; @@ -17,9 +18,8 @@ import { Spinner } from "@/components/ui/spinner"; import { useElectronAPI } from "@/hooks/use-platform"; import { searchSpacesApiService } from "@/lib/apis/search-spaces-api.service"; import { setBearerToken } from "@/lib/auth-utils"; -import { AUTH_TYPE, BACKEND_URL } from "@/lib/env-config"; +import { BACKEND_URL } from "@/lib/env-config"; -const isGoogleAuth = AUTH_TYPE === "GOOGLE"; type ShortcutKey = "generalAssist" | "quickAsk" | "screenshotAssist"; type ShortcutMap = typeof DEFAULT_SHORTCUTS; @@ -189,6 +189,7 @@ function HotkeyRow({ export default function DesktopLoginPage() { const router = useRouter(); const api = useElectronAPI(); + const isGoogleAuth = useIsGoogleAuth(); const [{ mutateAsync: login, isPending: isLoggingIn }] = useAtom(loginMutationAtom); const [email, setEmail] = useState("");