From e3e4ac908d69f5d540110172b9e7e49d8de7447c Mon Sep 17 00:00:00 2001 From: BilalG1 Date: Fri, 26 Jun 2026 13:43:48 -0700 Subject: [PATCH] Fix preview-mode logout when opening account settings (#1670) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Problem In **preview mode**, clicking the user profile → **Account settings** logs the user out and strands them on a sign-in page they can't get past. Root cause is a combination of three things: - Preview mode uses an **in-memory** token store (`tokenStore: "memory"`), so any full page reload wipes the session. - The account-settings menu item calls `app.redirectToAccountSettings()`, whose `redirectTo*` helpers fall through to `window.location.assign` on the client — a **hard reload**. - The `/handler/account-settings` route lives **outside** the `(protected)` layout that performs the preview auto-login, so nothing re-mints the preview session after the reload. Net effect: hard nav → in-memory session wiped → `useUser({ or: 'redirect' })` finds no user → redirect to sign-in, with no way back in (preview credentials are a throwaway UUID). In normal (cookie) mode this is harmless because the cookie survives the reload — the bug is preview-specific. ## Fix Soft-navigate from the menu item using `app.useNavigate()` (a `router.push` wrapper under the `"nextjs"` redirect method) instead of `redirectToAccountSettings()`. A soft client-side navigation does not re-evaluate the JS bundle, so the module-singleton app instance and its in-memory token store stay alive. The fix is scoped to the single dashboard call site rather than the shared SDK `redirectToAccountSettings()` method, which ships to all customers and intentionally hard-navigates for cross-domain / sign-out flows. ## Note / follow-up This covers navigation **from within the app**, which is the only in-app entry point to account settings. It does **not** cover a hard refresh or a direct link to `/handler/account-settings` in preview mode — those still wipe the in-memory session because the handler route has no auto-login. A fuller root-cause fix would bring the preview auto-login (or the `(protected)` layout) to the handler route. --- ## Summary by cubic Fixes preview-mode logout when opening Account settings by switching the dashboard menu to a soft client-side nav using `app.useNavigate()` instead of a hard reload. This preserves the in-memory session. - **Bug Fixes** - Soft-navigate to `/handler/account-settings` via `app.useNavigate()` to avoid wiping the preview token. - Change scoped to the dashboard menu; `redirectToAccountSettings()` in the SDK remains unchanged. Written for commit 0e0c3a1bab4e579921c2a5c73f63655c01db44b2. Summary will update on new commits. Review in cubic ## Summary by CodeRabbit * **Bug Fixes** * The “Account settings” menu now opens with smooth in-app navigation instead of a full page reload, making the experience faster and more seamless. --- apps/dashboard/src/components/dashboard-user-button.tsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/dashboard/src/components/dashboard-user-button.tsx b/apps/dashboard/src/components/dashboard-user-button.tsx index 4cc6382c7..401684555 100644 --- a/apps/dashboard/src/components/dashboard-user-button.tsx +++ b/apps/dashboard/src/components/dashboard-user-button.tsx @@ -88,6 +88,9 @@ export function DashboardUserButton(props: DashboardUserButtonProps) { function DashboardUserButtonInner(props: DashboardUserButtonProps) { const user = useUser(); const app = useStackApp(); + // Soft-navigate: redirectToAccountSettings() hard-reloads, which wipes preview mode's + // in-memory session and bounces the user to sign-in. router.push keeps the session alive. + const navigate = app.useNavigate(); const showUserInfo = props.showUserInfo === true; const displayName = user?.displayName ?? user?.primaryEmail ?? "Account"; const iconProps = { size: 16, className: menuIconClassName }; @@ -142,7 +145,7 @@ function DashboardUserButtonInner(props: DashboardUserButtonProps) { {user && ( await app.redirectToAccountSettings()} + onClick={() => navigate("/handler/account-settings")} icon={} /> )}