From 57b8db4cff92e62afc5b1cc3bc633c7f58a85a8c Mon Sep 17 00:00:00 2001 From: Taylor Ho Date: Sat, 1 Aug 2026 21:39:53 -0700 Subject: [PATCH] fix(desktop): stabilize onboarding route navigation Co-authored-by: Taylor Ho Signed-off-by: Taylor Ho --- desktop/src/app/routeTree.gen.ts | 21 +++++++++++++++++++ desktop/src/app/routes/onboarding.tsx | 2 +- .../onboarding/ui/CommunityOnboardingFlow.tsx | 21 +++++++++++-------- 3 files changed, 34 insertions(+), 10 deletions(-) diff --git a/desktop/src/app/routeTree.gen.ts b/desktop/src/app/routeTree.gen.ts index 2bc2c8ddb6..7f545708d8 100644 --- a/desktop/src/app/routeTree.gen.ts +++ b/desktop/src/app/routeTree.gen.ts @@ -14,6 +14,7 @@ import { Route as agentsRouteImport } from "./routes/agents"; import { Route as indexRouteImport } from "./routes/index"; import { Route as workflowsDotworkflowIdRouteImport } from "./routes/workflows.$workflowId"; import { Route as projectsDotprojectIdRouteImport } from "./routes/projects.$projectId"; +import { Route as onboardingRouteImport } from "./routes/onboarding"; import { Route as messagesDotnewRouteImport } from "./routes/messages.new"; import { Route as channelsDotchannelIdRouteImport } from "./routes/channels.$channelId"; import { Route as channelsDotchannelIdDotpostsDotpostIdRouteImport } from "./routes/channels.$channelId.posts.$postId"; @@ -63,6 +64,11 @@ const projectsDotprojectIdRoute = projectsDotprojectIdRouteImport.update({ path: "/projects/$projectId", getParentRoute: () => rootRouteImport, } as any); +const onboardingRoute = onboardingRouteImport.update({ + id: "/onboarding/$step", + path: "/onboarding/$step", + getParentRoute: () => rootRouteImport, +} as any); const messagesDotnewRoute = messagesDotnewRouteImport.update({ id: "/messages/new", path: "/messages/new", @@ -90,6 +96,7 @@ export interface FileRoutesByFullPath { "/workflows": typeof workflowsRoute; "/channels/$channelId": typeof channelsDotchannelIdRoute; "/messages/new": typeof messagesDotnewRoute; + "/onboarding/$step": typeof onboardingRoute; "/projects/$projectId": typeof projectsDotprojectIdRoute; "/workflows/$workflowId": typeof workflowsDotworkflowIdRoute; "/channels/$channelId/posts/$postId": typeof channelsDotchannelIdDotpostsDotpostIdRoute; @@ -104,6 +111,7 @@ export interface FileRoutesByTo { "/workflows": typeof workflowsRoute; "/channels/$channelId": typeof channelsDotchannelIdRoute; "/messages/new": typeof messagesDotnewRoute; + "/onboarding/$step": typeof onboardingRoute; "/projects/$projectId": typeof projectsDotprojectIdRoute; "/workflows/$workflowId": typeof workflowsDotworkflowIdRoute; "/channels/$channelId/posts/$postId": typeof channelsDotchannelIdDotpostsDotpostIdRoute; @@ -119,6 +127,7 @@ export interface FileRoutesById { "/workflows": typeof workflowsRoute; "/channels/$channelId": typeof channelsDotchannelIdRoute; "/messages/new": typeof messagesDotnewRoute; + "/onboarding/$step": typeof onboardingRoute; "/projects/$projectId": typeof projectsDotprojectIdRoute; "/workflows/$workflowId": typeof workflowsDotworkflowIdRoute; "/channels/$channelId/posts/$postId": typeof channelsDotchannelIdDotpostsDotpostIdRoute; @@ -135,6 +144,7 @@ export interface FileRouteTypes { | "/workflows" | "/channels/$channelId" | "/messages/new" + | "/onboarding/$step" | "/projects/$projectId" | "/workflows/$workflowId" | "/channels/$channelId/posts/$postId"; @@ -149,6 +159,7 @@ export interface FileRouteTypes { | "/workflows" | "/channels/$channelId" | "/messages/new" + | "/onboarding/$step" | "/projects/$projectId" | "/workflows/$workflowId" | "/channels/$channelId/posts/$postId"; @@ -163,6 +174,7 @@ export interface FileRouteTypes { | "/workflows" | "/channels/$channelId" | "/messages/new" + | "/onboarding/$step" | "/projects/$projectId" | "/workflows/$workflowId" | "/channels/$channelId/posts/$postId"; @@ -178,6 +190,7 @@ export interface RootRouteChildren { workflowsRoute: typeof workflowsRoute; channelsDotchannelIdRoute: typeof channelsDotchannelIdRoute; messagesDotnewRoute: typeof messagesDotnewRoute; + onboardingRoute: typeof onboardingRoute; projectsDotprojectIdRoute: typeof projectsDotprojectIdRoute; workflowsDotworkflowIdRoute: typeof workflowsDotworkflowIdRoute; channelsDotchannelIdDotpostsDotpostIdRoute: typeof channelsDotchannelIdDotpostsDotpostIdRoute; @@ -248,6 +261,13 @@ declare module "@tanstack/react-router" { preLoaderRoute: typeof projectsDotprojectIdRouteImport; parentRoute: typeof rootRouteImport; }; + "/onboarding/$step": { + id: "/onboarding/$step"; + path: "/onboarding/$step"; + fullPath: "/onboarding/$step"; + preLoaderRoute: typeof onboardingRouteImport; + parentRoute: typeof rootRouteImport; + }; "/messages/new": { id: "/messages/new"; path: "/messages/new"; @@ -282,6 +302,7 @@ const rootRouteChildren: RootRouteChildren = { workflowsRoute: workflowsRoute, channelsDotchannelIdRoute: channelsDotchannelIdRoute, messagesDotnewRoute: messagesDotnewRoute, + onboardingRoute: onboardingRoute, projectsDotprojectIdRoute: projectsDotprojectIdRoute, workflowsDotworkflowIdRoute: workflowsDotworkflowIdRoute, channelsDotchannelIdDotpostsDotpostIdRoute: diff --git a/desktop/src/app/routes/onboarding.tsx b/desktop/src/app/routes/onboarding.tsx index 484e1e51cf..95af34416a 100644 --- a/desktop/src/app/routes/onboarding.tsx +++ b/desktop/src/app/routes/onboarding.tsx @@ -3,7 +3,7 @@ import { createFileRoute, redirect } from "@tanstack/react-router"; // Onboarding is rendered by startup gates before RouterProvider mounts. If a // stale session-only onboarding URL reaches the normal app router, repair it // instead of rendering onboarding without its required in-memory state. -export const Route = createFileRoute("/onboarding/$step" as never)({ +export const Route = createFileRoute("/onboarding/$step")({ beforeLoad: () => { throw redirect({ to: "/", replace: true }); }, diff --git a/desktop/src/features/onboarding/ui/CommunityOnboardingFlow.tsx b/desktop/src/features/onboarding/ui/CommunityOnboardingFlow.tsx index 726496d376..0bc41f9460 100644 --- a/desktop/src/features/onboarding/ui/CommunityOnboardingFlow.tsx +++ b/desktop/src/features/onboarding/ui/CommunityOnboardingFlow.tsx @@ -299,10 +299,19 @@ export function CommunityOnboardingFlow({ }, [finish, isPending, onboardingHistory, queryClient, relayUrl, update]); const backToProfile = React.useCallback(() => { - if (isPending) return; + if (isPending || !transaction) return; setStarterChannelFailureCount(0); + update({ stage: "profile", error: undefined }, transaction.id); onboardingHistory.back("profile"); - }, [isPending, onboardingHistory]); + }, [isPending, onboardingHistory, transaction, update]); + + const backToCommunitySetup = React.useCallback(() => { + if (isPending || !transaction) return; + onboardingHistory.back( + routeForFirstCommunityPage(transaction.firstCommunityPage), + ); + void onCancel(); + }, [isPending, onboardingHistory, onCancel, transaction]); const isProfileStage = transaction?.stage === "profile"; React.useEffect(() => { @@ -671,13 +680,7 @@ export function CommunityOnboardingFlow({ className="h-9 w-20 rounded-full bg-foreground/10 px-6 hover:bg-foreground/15" data-testid="community-profile-back" disabled={isPending || isUploadingAvatar} - onClick={() => - onboardingHistory.back( - routeForFirstCommunityPage( - transaction.firstCommunityPage, - ), - ) - } + onClick={backToCommunitySetup} type="button" variant="ghost" >