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 (
+
+ );
+}
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}
+
);
}
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("");