refactor(web): consume runtime config in auth and dashboard flows

This commit is contained in:
Anish Sarkar 2026-06-16 01:39:32 +05:30
parent 9ef2c6a60e
commit c5dd55e964
9 changed files with 74 additions and 61 deletions

View file

@ -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);

View file

@ -0,0 +1,5 @@
import { RuntimeConfig } from "@/components/providers/runtime-config.server";
export default function LoginLayout({ children }: { children: React.ReactNode }) {
return <RuntimeConfig>{children}</RuntimeConfig>;
}

View file

@ -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<string | null>(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 <GoogleLoginButton />;

View file

@ -0,0 +1,5 @@
import { RuntimeConfig } from "@/components/providers/runtime-config.server";
export default function RegisterLayout({ children }: { children: React.ReactNode }) {
return <RuntimeConfig>{children}</RuntimeConfig>;
}

View file

@ -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();

View file

@ -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 (
<div className="h-full flex flex-col ">
<div className="flex-1 min-h-0">{children}</div>
</div>
);
}

View file

@ -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 (
<div className="h-full flex flex-col ">
<div className="flex-1 min-h-0">{children}</div>
</div>
<RuntimeConfig>
<DashboardShell>{children}</DashboardShell>
</RuntimeConfig>
);
}

View file

@ -0,0 +1,5 @@
import { RuntimeConfig } from "@/components/providers/runtime-config.server";
export default function DesktopLoginLayout({ children }: { children: React.ReactNode }) {
return <RuntimeConfig>{children}</RuntimeConfig>;
}

View file

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