diff --git a/autogpt_platform/frontend/pnpm-lock.yaml b/autogpt_platform/frontend/pnpm-lock.yaml index 54843fc589..7d39b68468 100644 --- a/autogpt_platform/frontend/pnpm-lock.yaml +++ b/autogpt_platform/frontend/pnpm-lock.yaml @@ -13011,7 +13011,7 @@ snapshots: minimatch: 3.1.2 node-abort-controller: 3.1.1 schema-utils: 3.3.0 - semver: 7.7.2 + semver: 7.7.3 tapable: 2.2.3 typescript: 5.9.3 webpack: 5.101.3(esbuild@0.25.9) diff --git a/autogpt_platform/frontend/src/components/layout/Navbar/Navbar.tsx b/autogpt_platform/frontend/src/components/layout/Navbar/Navbar.tsx index 1441cbfb65..c5e9cabd63 100644 --- a/autogpt_platform/frontend/src/components/layout/Navbar/Navbar.tsx +++ b/autogpt_platform/frontend/src/components/layout/Navbar/Navbar.tsx @@ -1,13 +1,157 @@ +"use client"; + +import { useGetV2GetUserProfile } from "@/app/api/__generated__/endpoints/store/store"; +import { okData } from "@/app/api/helpers"; +import { IconAutoGPTLogo, IconType } from "@/components/__legacy__/ui/icons"; +import { PreviewBanner } from "@/components/layout/Navbar/components/PreviewBanner/PreviewBanner"; +import { useBreakpoint } from "@/lib/hooks/useBreakpoint"; +import { useSupabase } from "@/lib/supabase/hooks/useSupabase"; import { environment } from "@/services/environment"; +import { Flag, useGetFlag } from "@/services/feature-flags/use-get-flag"; +import { AccountMenu } from "./components/AccountMenu/AccountMenu"; +import { AgentActivityDropdown } from "./components/AgentActivityDropdown/AgentActivityDropdown"; +import { LoginButton } from "./components/LoginButton"; +import { MobileNavBar } from "./components/MobileNavbar/MobileNavBar"; +import { NavbarLink } from "./components/NavbarLink"; +import { NavbarLoading } from "./components/NavbarLoading"; +import { Wallet } from "./components/Wallet/Wallet"; +import { getAccountMenuItems, loggedInLinks, loggedOutLinks } from "./helpers"; -import { NavbarView } from "./components/NavbarView"; -import { getNavbarAccountData } from "./data"; - -export async function Navbar() { - const { isLoggedIn } = await getNavbarAccountData(); +export function Navbar() { + const { user, isLoggedIn, isUserLoading } = useSupabase(); + const breakpoint = useBreakpoint(); + const isSmallScreen = breakpoint === "sm" || breakpoint === "base"; + const dynamicMenuItems = getAccountMenuItems(user?.role); + const isChatEnabled = useGetFlag(Flag.CHAT); const previewBranchName = environment.getPreviewStealingDev(); + const { data: profile, isLoading: isProfileLoading } = useGetV2GetUserProfile( + { + query: { + select: okData, + enabled: isLoggedIn && !!user, + // Include user ID in query key to ensure cache invalidation when user changes + queryKey: ["/api/store/profile", user?.id], + }, + }, + ); + + const isLoadingProfile = isProfileLoading || isUserLoading; + + const shouldShowPreviewBanner = Boolean(isLoggedIn && previewBranchName); + + const actualLoggedInLinks = + isChatEnabled === true + ? loggedInLinks.concat([{ name: "Chat", href: "/chat" }]) + : loggedInLinks; + + if (isUserLoading) { + return ; + } + return ( - + <> +
+ {shouldShowPreviewBanner && previewBranchName ? ( + + ) : null} + +
+ {/* Mobile Navbar - Adjust positioning */} + <> + {isLoggedIn && isSmallScreen ? ( +
+ + { + if (link.name === "Chat" && !isChatEnabled) { + return null; + } + + return { + icon: + link.name === "Marketplace" + ? IconType.Marketplace + : link.name === "Library" + ? IconType.Library + : link.name === "Build" + ? IconType.Builder + : link.name === "Chat" + ? IconType.Chat + : link.name === "Monitor" + ? IconType.Library + : IconType.LayoutDashboard, + text: link.name, + href: link.href, + }; + }) + .filter((item) => item !== null) as Array<{ + icon: IconType; + text: string; + href: string; + }>, + }, + ...dynamicMenuItems, + ]} + userEmail={profile?.name} + avatarSrc={profile?.avatar_url ?? ""} + /> +
+ ) : null} + + ); } diff --git a/autogpt_platform/frontend/src/components/layout/Navbar/components/AccountMenu/components/AccountLogoutOption.tsx b/autogpt_platform/frontend/src/components/layout/Navbar/components/AccountMenu/components/AccountLogoutOption.tsx index b0061ec2c9..570f05ca89 100644 --- a/autogpt_platform/frontend/src/components/layout/Navbar/components/AccountMenu/components/AccountLogoutOption.tsx +++ b/autogpt_platform/frontend/src/components/layout/Navbar/components/AccountMenu/components/AccountLogoutOption.tsx @@ -6,45 +6,42 @@ import { useSupabase } from "@/lib/supabase/hooks/useSupabase"; import { cn } from "@/lib/utils"; import * as Sentry from "@sentry/nextjs"; import { useRouter } from "next/navigation"; -import { useState } from "react"; +import { useTransition } from "react"; export function AccountLogoutOption() { - const [isLoggingOut, setIsLoggingOut] = useState(false); + const [isPending, startTransition] = useTransition(); const supabase = useSupabase(); const router = useRouter(); const { toast } = useToast(); - async function handleLogout() { - setIsLoggingOut(true); - try { - await supabase.logOut(); - router.push("/login"); - } catch (e) { - Sentry.captureException(e); - toast({ - title: "Error logging out", - description: - "Something went wrong when logging out. Please try again. If the problem persists, please contact support.", - variant: "destructive", - }); - } finally { - setTimeout(() => { - setIsLoggingOut(false); - }, 3000); - } + function handleLogout() { + startTransition(async () => { + try { + await supabase.logOut(); + router.replace("/login"); + } catch (e) { + Sentry.captureException(e); + toast({ + title: "Error logging out", + description: + "Something went wrong when logging out. Please try again. If the problem persists, please contact support.", + variant: "destructive", + }); + } + }); } return (
- {isLoggingOut ? ( + {isPending ? ( ) : ( <> diff --git a/autogpt_platform/frontend/src/components/layout/Navbar/components/NavbarLoading.tsx b/autogpt_platform/frontend/src/components/layout/Navbar/components/NavbarLoading.tsx index 42362d24d4..322574fdb0 100644 --- a/autogpt_platform/frontend/src/components/layout/Navbar/components/NavbarLoading.tsx +++ b/autogpt_platform/frontend/src/components/layout/Navbar/components/NavbarLoading.tsx @@ -5,16 +5,15 @@ export function NavbarLoading() { return ( ); diff --git a/autogpt_platform/frontend/src/components/layout/Navbar/components/NavbarView.tsx b/autogpt_platform/frontend/src/components/layout/Navbar/components/NavbarView.tsx deleted file mode 100644 index 863b9f601f..0000000000 --- a/autogpt_platform/frontend/src/components/layout/Navbar/components/NavbarView.tsx +++ /dev/null @@ -1,144 +0,0 @@ -"use client"; - -import { useGetV2GetUserProfile } from "@/app/api/__generated__/endpoints/store/store"; -import { IconAutoGPTLogo, IconType } from "@/components/__legacy__/ui/icons"; -import { PreviewBanner } from "@/components/layout/Navbar/components/PreviewBanner/PreviewBanner"; -import { useBreakpoint } from "@/lib/hooks/useBreakpoint"; -import { useSupabase } from "@/lib/supabase/hooks/useSupabase"; -import { Flag, useGetFlag } from "@/services/feature-flags/use-get-flag"; -import { useMemo } from "react"; -import { okData } from "@/app/api/helpers"; -import { getAccountMenuItems, loggedInLinks, loggedOutLinks } from "../helpers"; -import { AccountMenu } from "./AccountMenu/AccountMenu"; -import { AgentActivityDropdown } from "./AgentActivityDropdown/AgentActivityDropdown"; -import { LoginButton } from "./LoginButton"; -import { MobileNavBar } from "./MobileNavbar/MobileNavBar"; -import { NavbarLink } from "./NavbarLink"; -import { Wallet } from "./Wallet/Wallet"; -interface NavbarViewProps { - isLoggedIn: boolean; - previewBranchName?: string | null; -} - -export function NavbarView({ isLoggedIn, previewBranchName }: NavbarViewProps) { - const { user } = useSupabase(); - const breakpoint = useBreakpoint(); - const isSmallScreen = breakpoint === "sm" || breakpoint === "base"; - const dynamicMenuItems = getAccountMenuItems(user?.role); - const isChatEnabled = useGetFlag(Flag.CHAT); - - const { data: profile, isLoading: isProfileLoading } = useGetV2GetUserProfile( - { - query: { - select: okData, - enabled: isLoggedIn && !!user, - // Include user ID in query key to ensure cache invalidation when user changes - queryKey: ["/api/store/profile", user?.id], - }, - }, - ); - - const { isUserLoading } = useSupabase(); - const isLoadingProfile = isProfileLoading || isUserLoading; - - const linksWithChat = useMemo(() => { - const chatLink = { name: "Chat", href: "/chat" }; - return isChatEnabled ? [...loggedInLinks, chatLink] : loggedInLinks; - }, [isChatEnabled]); - - const shouldShowPreviewBanner = Boolean(isLoggedIn && previewBranchName); - - return ( - <> -
- {shouldShowPreviewBanner && previewBranchName ? ( - - ) : null} - -
- {/* Mobile Navbar - Adjust positioning */} - <> - {isLoggedIn && isSmallScreen ? ( -
- - ({ - icon: - link.name === "Marketplace" - ? IconType.Marketplace - : link.name === "Library" - ? IconType.Library - : link.name === "Build" - ? IconType.Builder - : link.name === "Chat" - ? IconType.Chat - : link.name === "Monitor" - ? IconType.Library - : IconType.LayoutDashboard, - text: link.name, - href: link.href, - })), - }, - ...dynamicMenuItems, - ]} - userEmail={profile?.name} - avatarSrc={profile?.avatar_url ?? ""} - /> -
- ) : null} - - - ); -} diff --git a/autogpt_platform/frontend/src/components/layout/Navbar/data.ts b/autogpt_platform/frontend/src/components/layout/Navbar/data.ts deleted file mode 100644 index 0d07cef78b..0000000000 --- a/autogpt_platform/frontend/src/components/layout/Navbar/data.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { prefetchGetV2GetUserProfileQuery } from "@/app/api/__generated__/endpoints/store/store"; -import { getQueryClient } from "@/lib/react-query/queryClient"; -import { getServerUser } from "@/lib/supabase/server/getServerUser"; - -export async function getNavbarAccountData() { - const { user } = await getServerUser(); - const isLoggedIn = Boolean(user); - const queryClient = getQueryClient(); - - if (!isLoggedIn) { - return { - profile: null, - isLoggedIn, - }; - } - try { - await prefetchGetV2GetUserProfileQuery(queryClient); - } catch (error) { - console.error("Error fetching profile:", error); - } - - return { - isLoggedIn, - }; -} diff --git a/autogpt_platform/frontend/src/services/feature-flags/use-get-flag.ts b/autogpt_platform/frontend/src/services/feature-flags/use-get-flag.ts index e80adeb7b5..f05d7c68a4 100644 --- a/autogpt_platform/frontend/src/services/feature-flags/use-get-flag.ts +++ b/autogpt_platform/frontend/src/services/feature-flags/use-get-flag.ts @@ -2,7 +2,6 @@ import { DEFAULT_SEARCH_TERMS } from "@/app/(platform)/marketplace/components/HeroSection/helpers"; import { useFlags } from "launchdarkly-react-client-sdk"; -import { environment } from "../environment"; export enum Flag { BETA_BLOCKS = "beta-blocks", @@ -40,7 +39,7 @@ const mockFlags = { [Flag.BETA_BLOCKS]: [], [Flag.NEW_BLOCK_MENU]: false, [Flag.NEW_AGENT_RUNS]: false, - [Flag.GRAPH_SEARCH]: true, + [Flag.GRAPH_SEARCH]: false, [Flag.ENABLE_ENHANCED_OUTPUT_HANDLING]: false, [Flag.NEW_FLOW_EDITOR]: false, [Flag.BUILDER_VIEW_SWITCH]: false, @@ -48,17 +47,20 @@ const mockFlags = { [Flag.AGENT_FAVORITING]: false, [Flag.MARKETPLACE_SEARCH_TERMS]: DEFAULT_SEARCH_TERMS, [Flag.ENABLE_PLATFORM_PAYMENT]: false, - [Flag.CHAT]: true, + [Flag.CHAT]: false, }; export function useGetFlag(flag: T): FlagValues[T] | null { const currentFlags = useFlags(); const flagValue = currentFlags[flag]; - const isCloud = environment.isCloud(); - if ((isPwMockEnabled && !isCloud) || flagValue === undefined) { + const envEnabled = process.env.NEXT_PUBLIC_LAUNCHDARKLY_ENABLED === "true"; + const clientId = process.env.NEXT_PUBLIC_LAUNCHDARKLY_CLIENT_ID; + const isLaunchDarklyConfigured = envEnabled && clientId; + + if (!isLaunchDarklyConfigured || isPwMockEnabled) { return mockFlags[flag]; } - return flagValue; + return flagValue ?? mockFlags[flag]; }