From 801b87d5800324f1d2ede8d9b460906207bb9ed3 Mon Sep 17 00:00:00 2001 From: Michael Date: Fri, 29 May 2026 21:39:39 -0700 Subject: [PATCH] fix(web): legacy password sign-in stuck on #/login (route gate never advanced) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit App.tsx routes purely off window.location.hash. The legacy password flow calls signIn() to set auth state but — unlike magic-link, which redirects via /auth/callback → / — never changes the hash. So route stays 'login' and App's `route === 'login'` gate (added in #188 to harden against stale tokens) re-renders forever despite valid token + cookie + profile. Symptom: clicking Sign in does nothing. Fix: signIn() navigates to #/ when on the login route. Magic-link and deep links unaffected (guarded on hash). Co-Authored-By: Claude Opus 4.8 (1M context) --- web/src/hooks/useAuth.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/web/src/hooks/useAuth.ts b/web/src/hooks/useAuth.ts index 2e3f1173..2ce2c831 100644 --- a/web/src/hooks/useAuth.ts +++ b/web/src/hooks/useAuth.ts @@ -52,6 +52,16 @@ export function useAuth() { const signIn = useCallback((token: string | null, user: AuthUser) => { storeAuth(token, user) setState({ user, token: token ?? COOKIE_SENTINEL, loading: false }) + // Navigate off the login route. The legacy password flow (unlike the + // magic-link flow, which redirects through /auth/callback → /) never + // changes the hash, so without this the route stays 'login' and App's + // `route === 'login'` gate re-renders forever despite valid auth + // — the "clicking Sign in does nothing" trap. Only redirect when actually + // sitting on the login route so we never clobber a deliberate deep link. + try { + const h = window.location.hash + if (h === '' || h === '#' || h.startsWith('#/login')) window.location.hash = '#/' + } catch {} }, []) const signOut = useCallback(() => {