Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions src/frontend/src/components/AuthBroadcastListener/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,21 @@ import { authBroadcast } from "@/utils/auth-broadcast";
import { useQueryClient } from "@tanstack/react-query";
import { useCallback, useEffect } from "react";
import { useLocation } from "react-router-dom";
import { Cookies } from "react-cookie";
import {
LANGFLOW_ACCESS_TOKEN,
LANGFLOW_AUTO_LOGIN_OPTION,
} from "@/constants/constants";
import { getAuthCookie } from "@/utils/utils";

export function AuthBroadcastListener() {
const queryClient = useQueryClient();
const navigate = useCustomNavigate();
const location = useLocation();
const logout = useAuthStore((state) => state.logout);
const setIsAuthenticated = useAuthStore((state) => state.setIsAuthenticated);
const setAccessToken = useAuthStore((state) => state.setAccessToken);
const setAutoLogin = useAuthStore((state) => state.setAutoLogin);
const { signOut } = IS_CLERK_AUTH ? useClerk() : { signOut: async () => {} };

/**
Expand Down Expand Up @@ -126,9 +135,37 @@ export function AuthBroadcastListener() {
handleCrossTabLogout();
});

const unsubscribeLogin = authBroadcast.onLogin(async () => {
// Another tab logged in — refresh local auth state and redirect if needed
const cookies = new Cookies();
const accessToken = getAuthCookie(cookies, LANGFLOW_ACCESS_TOKEN);

if (accessToken) {
setIsAuthenticated(true);
setAccessToken(accessToken);
// Derive autoLogin from cookie set during login (defaults to manual)
const autoLoginCookie = getAuthCookie(
cookies,
LANGFLOW_AUTO_LOGIN_OPTION,
);
setAutoLogin(autoLoginCookie === "auto");

const currentPath = location.pathname;
const isLoginPage = currentPath.includes("login");
const isOrgPage = currentPath.includes("organization");

if (isLoginPage || isOrgPage) {
const urlParams = new URLSearchParams(window.location.search);
const redirectPath = urlParams.get("redirect");
navigate(redirectPath || "/flows", { replace: true });
}
}
});

// Cleanup on unmount
return () => {
unsubscribe();
unsubscribeLogin();
};
} catch (error) {
console.error("[AuthBroadcast] Failed to register listener:", error);
Expand Down
3 changes: 3 additions & 0 deletions src/frontend/src/contexts/authContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
import { useGetUserData } from "@/controllers/API/queries/auth";
import { useGetGlobalVariablesMutation } from "@/controllers/API/queries/variables/use-get-mutation-global-variables";
import useAuthStore from "@/stores/authStore";
import { authBroadcast } from "@/utils/auth-broadcast";
import { setLocalStorage } from "@/utils/local-storage-util";
import { getAuthCookie, setAuthCookie } from "@/utils/utils";
import { useStoreStore } from "../stores/storeStore";
Expand Down Expand Up @@ -92,6 +93,8 @@ export function AuthProvider({ children }): React.ReactElement {
}
setAccessToken(newAccessToken);
setIsAuthenticated(true);
// Notify other tabs that a manual login has completed
authBroadcast.broadcastLogin();
getUser();
getGlobalVariables();
}
Expand Down
24 changes: 0 additions & 24 deletions src/new-landingpage/src/App.tsx

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two issues:

1

Once I go to Organisation, it is not directly going to /flows, it is going to /dashboard for a few seconds and then to /flows. We need to go to /flows directly from /organization

What we need is
/organization->/flows instead of /organization->/dashboard(for few seconds) ->/flows

2

⚠️ Note
This behavior exists in the old frontend and must be fully replicated in the new frontend. You can check for the Dashboard button and logout button in the old frontend and replicate its style in the new frontend


Post-Login Routing & Header Behavior

(Parity with Old Frontend)


Root (/) behavior after login

  • After a user has logged in, opening / in a new tab should remain on /.
  • Currently, / incorrectly redirects to /flows.
    This must be fixed.

Restricted routes after login

Once a user is logged in:

  • Visiting /login must redirect to /flows
  • Visiting /organization must redirect to /flows

Header actions on / after login

On the / page, after login:

  • The “Login” button (top-right) should change to “Dashboard”
  • Clicking Dashboard should navigate to /flows

Sign-out behavior on / after login

On the / page, after login:

  • The “Book a Demo” button (top-right) should change to “Sign Out”
  • Clicking Sign Out should properly log the user out

Original file line number Diff line number Diff line change
@@ -1,36 +1,12 @@
import { useAuth } from "@clerk/clerk-react";
import { BrowserRouter, Navigate, Route, Routes } from "react-router-dom";
import { LANDING_BASENAME } from "./landingRoutes";
import NewLandingPageLogin from "./NewLandingPageLogin";
import OrganizationOnboarding from "./OrganizationOnboarding";
import "./App.css";
import DashboardPage from "./DashboardPage";
import { useCookies } from "react-cookie";
import LandingPage from "./LandingPage";
import {
hasWorkspaceSession,
LANGFLOW_ACCESS_TOKEN,
LANGFLOW_REFRESH_TOKEN,
} from "./session";

function RootRoute() {
const { isSignedIn } = useAuth();
const [cookies] = useCookies([LANGFLOW_ACCESS_TOKEN, LANGFLOW_REFRESH_TOKEN]);

console.log("[App] RootRoute render", { isSignedIn });

if (isSignedIn) {
const workspaceReady = hasWorkspaceSession(cookies);
const destination = workspaceReady ? "/dashboard" : "/organization";

console.log("[App] Redirecting signed-in user from root", {
workspaceReady,
destination,
});

return <Navigate to={destination} replace />;
}

return <LandingPage />;
}

Expand Down
21 changes: 16 additions & 5 deletions src/new-landingpage/src/LandingPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import { AnimatePresence, motion, type SVGMotionProps } from "framer-motion";
import { useState, type SVGProps } from "react";
import { useCookies } from "react-cookie";
import { useAuth } from "@clerk/clerk-react";
import { Link } from "react-router-dom";
import VisualWorkflow from "./new-assets/VisualWorkflow.webp";
import demoWalkthrough from "./new-assets/demo-walkthrough.webp";
import logoicon from "./new-assets/visualailogo.png";
Expand Down Expand Up @@ -55,7 +54,7 @@ function AnimatedArrowIcon(props: SVGMotionProps<SVGSVGElement>) {
export default function LandingPage(): JSX.Element {
const [isMenuOpen, setIsMenuOpen] = useState(false);
const { isSignedIn, signOut } = useAuth();
const [, , removeCookie] = useCookies([
const [cookies, , removeCookie] = useCookies([
LANGFLOW_ACCESS_TOKEN,
LANGFLOW_REFRESH_TOKEN,
]);
Expand All @@ -71,6 +70,17 @@ export default function LandingPage(): JSX.Element {
window.location.assign("/flows");
};

const handleLoginClick = () => {
const token = cookies[LANGFLOW_ACCESS_TOKEN];

if (token) {
window.location.assign("/flows");
return;
}

window.location.assign("/login");
};

/* -------------------- UI (copied structure from second file) -------------------- */

return (
Expand Down Expand Up @@ -155,12 +165,13 @@ export default function LandingPage(): JSX.Element {
Book a Demo
</a>

<Link
to="/login"
<button
onClick={handleLoginClick}
className="whitespace-nowrap rounded-xl bg-white px-4 py-2 text-sm font-semibold text-neutral-900 transition hover:opacity-90"
type="button"
>
Log in
</Link>
</button>
</>
)}
</div>
Expand Down
20 changes: 12 additions & 8 deletions src/new-landingpage/src/NewLandingPageLogin.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { SignIn, SignedIn, SignedOut, useAuth } from "@clerk/clerk-react";
import { useEffect } from "react";
import { useNavigate } from "react-router-dom";
import { useCookies } from "react-cookie";
import { LANDING_BASENAME } from "./landingRoutes";
import {
clearStoredOrgSelection,
hasWorkspaceSession,
LANGFLOW_ACCESS_TOKEN,
LANGFLOW_REFRESH_TOKEN,
} from "./session";
import { useCookies } from "react-cookie";

export default function NewLandingPageLogin() {
const { isSignedIn, isLoaded } = useAuth();
Expand All @@ -26,14 +26,18 @@ export default function NewLandingPageLogin() {
useEffect(() => {
if (isLoaded && isSignedIn) {
const workspaceReady = hasWorkspaceSession(cookies);
const destination = workspaceReady ? "/dashboard" : "/organization";
const destination = workspaceReady ? "/flows" : "/organization";

console.log(
"[NewLandingPageLogin] User signed in, redirecting based on session",
{ workspaceReady, destination },
);
console.log("[NewLandingPageLogin] User signed in, redirecting", {
workspaceReady,
destination,
});

navigate(destination, { replace: true });
if (workspaceReady) {
window.location.assign(destination);
} else {
navigate("/organization", { replace: true });
}
}
}, [cookies, isLoaded, isSignedIn, navigate]);

Expand All @@ -55,7 +59,7 @@ export default function NewLandingPageLogin() {
/>
</SignedOut>
<SignedIn>
<div style={{ textAlign: "center" }}>Redirecting you to your organization list…</div>
<div style={{ textAlign: "center" }}>Redirecting you to your workspace…</div>
</SignedIn>
</div>
</div>
Expand Down
Loading
Loading