From 418420e104e0a297208ae6b2e6e4eb3e4d8e756e Mon Sep 17 00:00:00 2001 From: Urjit Chakraborty <135136842+urjitc@users.noreply.github.com> Date: Thu, 29 Jan 2026 18:32:14 -0500 Subject: [PATCH 1/6] feat: simplify session --- src/components/home/WorkspaceGrid.tsx | 40 ++++++++++++++++++- src/components/layout/SessionHandler.tsx | 49 +++++------------------- src/proxy.ts | 4 +- 3 files changed, 51 insertions(+), 42 deletions(-) diff --git a/src/components/home/WorkspaceGrid.tsx b/src/components/home/WorkspaceGrid.tsx index aeeb32df..cb926813 100644 --- a/src/components/home/WorkspaceGrid.tsx +++ b/src/components/home/WorkspaceGrid.tsx @@ -1,9 +1,10 @@ "use client"; -import { useState } from "react"; +import { useState, useEffect } from "react"; import { FolderPlus, MoreVertical } from "lucide-react"; import { useUIStore } from "@/lib/stores/ui-store"; import { useWorkspaceContext } from "@/contexts/WorkspaceContext"; +import { useSession } from "@/lib/auth-client"; import { IconRenderer } from "@/hooks/use-icon-picker"; import { cn } from "@/lib/utils"; import WorkspaceSettingsModal from "@/components/workspace/WorkspaceSettingsModal"; @@ -13,8 +14,37 @@ import { getCardColorCSS, getCardAccentColor, type CardColor } from "@/lib/works export function WorkspaceGrid() { const { setShowCreateWorkspaceModal } = useUIStore(); const { workspaces, switchWorkspace, loadWorkspaces } = useWorkspaceContext(); + const { data: session } = useSession(); const [showSettingsModal, setShowSettingsModal] = useState(false); const [settingsWorkspace, setSettingsWorkspace] = useState(null); + const [isCreatingWorkspace, setIsCreatingWorkspace] = useState(false); + + // Lazy workspace creation for anonymous users + useEffect(() => { + const createWelcomeWorkspace = async () => { + if (!session?.user?.isAnonymous) return; + if (workspaces.length > 0) return; // Already has workspaces + if (isCreatingWorkspace) return; // Already creating + + setIsCreatingWorkspace(true); + try { + const res = await fetch("/api/guest/create-welcome-workspace", { + method: "POST", + }); + + if (res.ok) { + // Reload workspaces to show the newly created one + await loadWorkspaces(); + } + } catch (error) { + console.error("Failed to create welcome workspace:", error); + } finally { + setIsCreatingWorkspace(false); + } + }; + + createWelcomeWorkspace(); + }, [session, workspaces.length, isCreatingWorkspace, loadWorkspaces]); // Format date helper const formatDate = (dateString: string | null | undefined) => { @@ -87,6 +117,14 @@ export function WorkspaceGrid() { + {/* Loading state for anonymous users creating first workspace */} + {session?.user?.isAnonymous && workspaces.length === 0 && isCreatingWorkspace && ( +
+
+

Setting up your workspace...

+
+ )} + {/* Existing Workspaces */} {workspaces.map((workspace) => { const color = workspace.color as CardColor | undefined; diff --git a/src/components/layout/SessionHandler.tsx b/src/components/layout/SessionHandler.tsx index 09f461ff..f85fe644 100644 --- a/src/components/layout/SessionHandler.tsx +++ b/src/components/layout/SessionHandler.tsx @@ -1,56 +1,27 @@ "use client"; import { useEffect } from "react"; -import { useRouter } from "next/navigation"; -import { Loader2 } from "lucide-react"; -import { useSession } from "@/lib/auth-client"; -import { AuthPageBackground } from "@/components/auth/AuthPageBackground"; +import { useSession, signIn } from "@/lib/auth-client"; import { SidebarProvider } from "@/components/ui/sidebar"; /** - * Handles anonymous session checking and redirects to guest-setup if no session. - * Shows a loading state while checking the session. + * Handles anonymous session creation and workspace access. + * Creates anonymous session if needed, workspace creation happens lazily in WorkspaceGrid. + * No loading screen - renders children immediately. */ export function AnonymousSessionHandler({ children }: { children: React.ReactNode }) { const { data: session, isPending } = useSession(); - const router = useRouter(); useEffect(() => { - // If no session and not loading, redirect to guest-setup + // If no session and not loading, create anonymous session if (!isPending && !session) { - router.replace("/guest-setup"); - return; + signIn.anonymous().catch((error) => { + console.error("Failed to create anonymous session:", error); + }); } - }, [session, isPending, router]); - - // Show loading while checking session - if (isPending) { - return ( -
- {/* Background with grid and cards - same as auth page */} - - - {/* Content */} -
-
- -
-

- Setting up your workspace... -

-

- This will only take a moment -

-
-
- ); - } - - // Don't render children if no session (will redirect) - if (!session) { - return null; - } + }, [session, isPending]); + // Always render children - no loading screen return <>{children}; } diff --git a/src/proxy.ts b/src/proxy.ts index dd5c8934..c78a19b0 100644 --- a/src/proxy.ts +++ b/src/proxy.ts @@ -18,8 +18,8 @@ export async function proxy(request: NextRequest) { const sessionCookie = getSessionCookie(request); const { pathname } = request.nextUrl; - // Redirect authenticated users from root to home - if (sessionCookie && pathname === "/") { + // Send all users from root to home - session handling happens there + if (pathname === "/") { return NextResponse.redirect(new URL("/home", request.url)); } From 700d9abe19e10c7618ce3e2009159789f102266d Mon Sep 17 00:00:00 2001 From: Urjit Chakraborty <135136842+urjitc@users.noreply.github.com> Date: Thu, 29 Jan 2026 18:35:45 -0500 Subject: [PATCH 2/6] remove: guest setup page --- src/app/guest-setup/page.tsx | 105 ----------------------------------- 1 file changed, 105 deletions(-) delete mode 100644 src/app/guest-setup/page.tsx diff --git a/src/app/guest-setup/page.tsx b/src/app/guest-setup/page.tsx deleted file mode 100644 index 57db8ab7..00000000 --- a/src/app/guest-setup/page.tsx +++ /dev/null @@ -1,105 +0,0 @@ -"use client"; - -import { useEffect, useRef, useState } from "react"; -import { useRouter } from "next/navigation"; -import { Loader2 } from "lucide-react"; -import { AuthPageBackground } from "@/components/auth/AuthPageBackground"; -import { signIn, useSession } from "@/lib/auth-client"; - -/** - * Guest Setup page for anonymous users - * - * This page: - * 1. Creates an anonymous session if one doesn't exist - * 2. Creates a welcome workspace for the anonymous user - * 3. Redirects to home once ready - */ -export default function GuestSetupPage() { - const router = useRouter(); - const { data: session } = useSession(); - const [errorMessage, setErrorMessage] = useState(null); - const hasStartedRef = useRef(false); - - useEffect(() => { - // Run only once on mount - if (hasStartedRef.current) return; - hasStartedRef.current = true; - - const setupGuest = async () => { - try { - // Step 1: Check if already authenticated (not anonymous) - if (session && !session.user.isAnonymous) { - router.replace("/home"); - return; - } - - // Step 2: Create anonymous session if needed (no delay - cookie is set immediately) - if (!session) { - await signIn.anonymous(); - // No delay needed - cookie is set synchronously by Better Auth - } - - // Step 3: Create welcome workspace - const res = await fetch("/api/guest/create-welcome-workspace", { - method: "POST", - }); - - if (!res.ok) { - const errorData = await res.json().catch(() => ({})); - throw new Error(errorData.error || "Failed to create welcome workspace"); - } - - const data = await res.json(); - - // Step 4: Redirect to home (workspace is created but user goes to home) - router.replace("/home"); - } catch (error) { - console.error("Guest setup error:", error); - setErrorMessage((error as Error).message || "Something went wrong"); - } - }; - - setupGuest(); - // No cleanup needed - we run once and don't abort - }, []); // Empty deps - run once on mount only - - - return ( -
- {/* Background with grid and cards - same as auth page */} - - - {/* Content */} -
- {!errorMessage ? ( - <> -
- -
-

- Setting up your workspace... -

-

- This will only take a moment -

- - ) : ( - <> -

- Something went wrong -

-

- {errorMessage} -

- - - )} -
-
- ); -} From 83d81462d51fe53f75c33c9ee22a3980a2166bbc Mon Sep 17 00:00:00 2001 From: Urjit Chakraborty <135136842+urjitc@users.noreply.github.com> Date: Thu, 29 Jan 2026 18:36:00 -0500 Subject: [PATCH 3/6] remove: create welcome workspace --- .../guest/create-welcome-workspace/route.ts | 57 ------------------- 1 file changed, 57 deletions(-) delete mode 100644 src/app/api/guest/create-welcome-workspace/route.ts diff --git a/src/app/api/guest/create-welcome-workspace/route.ts b/src/app/api/guest/create-welcome-workspace/route.ts deleted file mode 100644 index 8b8e4020..00000000 --- a/src/app/api/guest/create-welcome-workspace/route.ts +++ /dev/null @@ -1,57 +0,0 @@ -import { NextResponse } from "next/server"; -import { headers } from "next/headers"; -import { auth } from "@/lib/auth"; -import { db, workspaces } from "@/lib/db/client"; -import { cloneDemoWorkspace } from "@/lib/workspace/clone-demo"; -import { eq } from "drizzle-orm"; - -/** - * POST /api/guest/create-welcome-workspace - * Create a welcome workspace for anonymous users - */ -export async function POST() { - try { - const session = await auth.api.getSession({ - headers: await headers(), - }); - - if (!session) { - return NextResponse.json({ error: "Unauthorized" }, { status: 401 }); - } - - // Only allow anonymous users - if (!session.user.isAnonymous) { - return NextResponse.json({ error: "This endpoint is for anonymous users only" }, { status: 403 }); - } - - const userId = session.user.id; - - // Check if user already has workspaces - const existingWorkspaces = await db - .select() - .from(workspaces) - .where(eq(workspaces.userId, userId)) - .limit(1); - - if (existingWorkspaces.length > 0) { - // User already has a workspace, return the first one - const workspace = existingWorkspaces[0]; - return NextResponse.json({ - workspaceId: workspace.id, - slug: workspace.slug || workspace.id, - }); - } - - // Clone demo workspace using shared utility - const userName = session.user.name || session.user.email || undefined; - const result = await cloneDemoWorkspace(userId, userName); - - return NextResponse.json(result); - } catch (error) { - console.error("Error creating welcome workspace for anonymous user:", error); - return NextResponse.json( - { error: "Failed to create welcome workspace" }, - { status: 500 } - ); - } -} From 8ab6b560bf73992d55ad0cfe1f6ada5f7446e42e Mon Sep 17 00:00:00 2001 From: Urjit Chakraborty <135136842+urjitc@users.noreply.github.com> Date: Thu, 29 Jan 2026 18:36:36 -0500 Subject: [PATCH 4/6] fix: landing page cta redirect --- src/components/landing/FinalCTA.tsx | 2 +- src/components/landing/Hero.tsx | 2 +- src/components/landing/Navbar.tsx | 4 ++-- src/components/landing/Pricing.tsx | 4 ++-- src/contexts/WorkspaceContext.tsx | 4 ++-- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/components/landing/FinalCTA.tsx b/src/components/landing/FinalCTA.tsx index 66aafa3b..edc13330 100644 --- a/src/components/landing/FinalCTA.tsx +++ b/src/components/landing/FinalCTA.tsx @@ -39,7 +39,7 @@ export function FinalCTA() { size="lg" className="h-12 rounded-md bg-foreground px-8 text-base font-medium text-background transition-all hover:bg-foreground/90" > - + Get Started diff --git a/src/components/landing/Hero.tsx b/src/components/landing/Hero.tsx index 473663b4..ad4ea190 100644 --- a/src/components/landing/Hero.tsx +++ b/src/components/landing/Hero.tsx @@ -93,7 +93,7 @@ export function Hero() { size="lg" className="h-12 rounded-md bg-foreground px-8 text-base font-medium text-background transition-all hover:bg-foreground/90" > - + Try for Free diff --git a/src/components/landing/Navbar.tsx b/src/components/landing/Navbar.tsx index 62c0288c..b988f1a8 100644 --- a/src/components/landing/Navbar.tsx +++ b/src/components/landing/Navbar.tsx @@ -147,7 +147,7 @@ export function Navbar() { size="default" className="rounded-md bg-foreground font-medium text-background transition-all hover:bg-foreground/90" > - + Get Started @@ -246,7 +246,7 @@ export function Navbar() { posthog.capture('navbar-get-started-clicked', { location: 'mobile' })} className="cursor-pointer" > diff --git a/src/components/landing/Pricing.tsx b/src/components/landing/Pricing.tsx index 83f5b0df..0ea60354 100644 --- a/src/components/landing/Pricing.tsx +++ b/src/components/landing/Pricing.tsx @@ -31,7 +31,7 @@ const pricingTiers: PricingTier[] = [ "Collaborative sharing", ], cta: "Get Started", - ctaLink: "/guest-setup", + ctaLink: "/home", }, { name: "Pro", @@ -45,7 +45,7 @@ const pricingTiers: PricingTier[] = [ "Early access to new features", ], cta: "Start Free", - ctaLink: "/guest-setup", + ctaLink: "/home", highlighted: true, }, ]; diff --git a/src/contexts/WorkspaceContext.tsx b/src/contexts/WorkspaceContext.tsx index bf761e94..63a44d9c 100644 --- a/src/contexts/WorkspaceContext.tsx +++ b/src/contexts/WorkspaceContext.tsx @@ -104,8 +104,8 @@ export function WorkspaceProvider({ children }: { children: React.ReactNode }) { loadWorkspaces(); }, [loadWorkspaces]); - // Note: Welcome workspace creation is now handled by /guest-setup page - // This prevents jarring dashboard flash + // Note: Welcome workspace creation is now handled lazily in WorkspaceGrid + // This prevents jarring dashboard flash and provides better UX // Switch workspace const switchWorkspace = useCallback( From 549ba86a18e5f64774af194625c11722a1640954 Mon Sep 17 00:00:00 2001 From: Urjit Chakraborty <135136842+urjitc@users.noreply.github.com> Date: Thu, 29 Jan 2026 18:37:22 -0500 Subject: [PATCH 5/6] fix: race condition --- src/components/home/WorkspaceGrid.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/home/WorkspaceGrid.tsx b/src/components/home/WorkspaceGrid.tsx index cb926813..5c059e26 100644 --- a/src/components/home/WorkspaceGrid.tsx +++ b/src/components/home/WorkspaceGrid.tsx @@ -44,7 +44,7 @@ export function WorkspaceGrid() { }; createWelcomeWorkspace(); - }, [session, workspaces.length, isCreatingWorkspace, loadWorkspaces]); + }, [session, workspaces.length, loadWorkspaces]); // Format date helper const formatDate = (dateString: string | null | undefined) => { From 4e6a67b99f28fecb915a9479fb96abff57ad4a45 Mon Sep 17 00:00:00 2001 From: Urjit Chakraborty <135136842+urjitc@users.noreply.github.com> Date: Thu, 29 Jan 2026 18:44:57 -0500 Subject: [PATCH 6/6] fix: retry logic --- src/components/home/WorkspaceGrid.tsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/components/home/WorkspaceGrid.tsx b/src/components/home/WorkspaceGrid.tsx index 5c059e26..bcdecc65 100644 --- a/src/components/home/WorkspaceGrid.tsx +++ b/src/components/home/WorkspaceGrid.tsx @@ -1,6 +1,6 @@ "use client"; -import { useState, useEffect } from "react"; +import { useState, useEffect, useRef } from "react"; import { FolderPlus, MoreVertical } from "lucide-react"; import { useUIStore } from "@/lib/stores/ui-store"; import { useWorkspaceContext } from "@/contexts/WorkspaceContext"; @@ -18,6 +18,7 @@ export function WorkspaceGrid() { const [showSettingsModal, setShowSettingsModal] = useState(false); const [settingsWorkspace, setSettingsWorkspace] = useState(null); const [isCreatingWorkspace, setIsCreatingWorkspace] = useState(false); + const hasAttemptedWelcomeWorkspace = useRef(false); // Lazy workspace creation for anonymous users useEffect(() => { @@ -25,8 +26,10 @@ export function WorkspaceGrid() { if (!session?.user?.isAnonymous) return; if (workspaces.length > 0) return; // Already has workspaces if (isCreatingWorkspace) return; // Already creating + if (hasAttemptedWelcomeWorkspace.current) return; // Avoid retry loop setIsCreatingWorkspace(true); + hasAttemptedWelcomeWorkspace.current = true; try { const res = await fetch("/api/guest/create-welcome-workspace", { method: "POST",