feat(web): redirect logged-in users from root to /threads (opt-in)#950
Conversation
Not up to standards ⛔🔴 Issues
|
| Category | Results |
|---|---|
| ErrorProne | 3 high |
🟢 Metrics 8 complexity · 0 duplication
Metric Results Complexity 8 Duplication 0
NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.
Greptile SummaryThis PR lets logged-in users opt in (per-browser) to skip the marketing landing page and be redirected straight to
Confidence Score: 4/5The change is client-only with no backend impact; the worst-case failure is a redirect that doesn't persist across page reloads in private-mode browsers, with the existing The implementation is well-structured and follows existing patterns. The two issues — a duplicated magic string between the store and the middleware, and navigation proceeding after a failed localStorage write — are both narrow edge cases that affect only private-mode or storage-disabled browsers and degrade gracefully rather than breaking anything.
Important Files Changed
Sequence Diagram%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
participant U as User Browser
participant MW as redirectToThreads Middleware
participant LS as localStorage
participant IDX as index.vue (Landing Page)
participant PPOP as RedirectPromptPopover
participant STORE as redirectPreferenceStore
participant THR as /threads
Note over U,THR: First visit (opted-out)
U->>MW: Navigate to /
MW->>LS: getItem('httpsms_redirect_to_threads')
LS-->>MW: null
MW-->>IDX: Proceed (no redirect)
IDX->>PPOP: "Render popover (authUser != null)"
PPOP->>U: Show Skip this page next time?
Note over U,THR: User clicks Always open dashboard
U->>STORE: enable()
STORE->>LS: setItem('httpsms_redirect_to_threads', 'true')
STORE->>THR: "navigateTo('/threads', {replace: true})"
Note over U,THR: Subsequent visit (opted-in)
U->>MW: Navigate to /
MW->>LS: getItem('httpsms_redirect_to_threads')
LS-->>MW: 'true'
MW->>THR: "navigateTo('/threads', {replace: true})"
Note over U,THR: Logout
U->>STORE: resetState()
STORE->>LS: removeItem('httpsms_redirect_to_threads')
STORE-->>U: "enabled=false, dismissedThisSession=false"
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
participant U as User Browser
participant MW as redirectToThreads Middleware
participant LS as localStorage
participant IDX as index.vue (Landing Page)
participant PPOP as RedirectPromptPopover
participant STORE as redirectPreferenceStore
participant THR as /threads
Note over U,THR: First visit (opted-out)
U->>MW: Navigate to /
MW->>LS: getItem('httpsms_redirect_to_threads')
LS-->>MW: null
MW-->>IDX: Proceed (no redirect)
IDX->>PPOP: "Render popover (authUser != null)"
PPOP->>U: Show Skip this page next time?
Note over U,THR: User clicks Always open dashboard
U->>STORE: enable()
STORE->>LS: setItem('httpsms_redirect_to_threads', 'true')
STORE->>THR: "navigateTo('/threads', {replace: true})"
Note over U,THR: Subsequent visit (opted-in)
U->>MW: Navigate to /
MW->>LS: getItem('httpsms_redirect_to_threads')
LS-->>MW: 'true'
MW->>THR: "navigateTo('/threads', {replace: true})"
Note over U,THR: Logout
U->>STORE: resetState()
STORE->>LS: removeItem('httpsms_redirect_to_threads')
STORE-->>U: "enabled=false, dismissedThisSession=false"
Reviews (1): Last reviewed commit: "fix(web): use replace navigation in redi..." | Re-trigger Greptile |
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 6e6a8ddc-a5d6-49dc-99c9-f9b7fcbc00ce
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 6e6a8ddc-a5d6-49dc-99c9-f9b7fcbc00ce
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…Back button Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 6e6a8ddc-a5d6-49dc-99c9-f9b7fcbc00ce
pnpm 11.12.0 crashes pnpm/action-setup (pnpm/action-setup#276). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 6e6a8ddc-a5d6-49dc-99c9-f9b7fcbc00ce
Resolves Codacy type findings; removes gitignored docs/ files. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 6e6a8ddc-a5d6-49dc-99c9-f9b7fcbc00ce
935a985 to
859dc88
Compare
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 878f9e23-78ea-4f5d-aed2-c1381514107f
There was a problem hiding this comment.
Pull request overview
Adds an opt-in “skip landing page” behavior in the Nuxt web app so returning, logged-in users can be redirected from / to /threads based on a per-browser localStorage flag, with the preference cleared on logout.
Changes:
- Introduces a Pinia store to persist a “redirect to threads” preference in
localStorage. - Adds a route middleware on
/plus a small popover UI under the Dashboard button to enable/dismiss the preference. - Clears the preference during logout flows (settings + thread header) and pins pnpm to a specific version in CI.
Reviewed changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
web/app/stores/redirectPreference.ts |
Adds persisted redirect preference state + actions (enable/dismiss/reset). |
web/app/pages/settings/index.vue |
Clears redirect preference on logout from Settings. |
web/app/pages/index.vue |
Attaches redirect middleware to the marketing landing page route. |
web/app/middleware/redirectToThreads.ts |
Implements the optimistic client-side redirect based on localStorage. |
web/app/layouts/website.vue |
Adds the popover component next to the Dashboard CTA for logged-in users. |
web/app/components/RedirectPromptPopover.vue |
New UI component for opt-in/dismiss UX. |
web/app/components/MessageThreadHeader.vue |
Clears redirect preference on logout from the thread header. |
.github/workflows/web.yml |
Pins pnpm to a specific patch version for CI stability. |
On CTRL+R reload of /, Firebase restores the session asynchronously. The website layout rendered Login/Get Started while authUser was still null, hiding the Dashboard button until the state resolved. Wait for authStateChanged before showing any auth-dependent button, matching the default (dashboard) layout. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 878f9e23-78ea-4f5d-aed2-c1381514107f
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 878f9e23-78ea-4f5d-aed2-c1381514107f
What
Logged-in users can opt in (per-browser) to skip the marketing landing page and go straight to
/threads./reads alocalStorageflag synchronously and redirects to/threadsbefore the heavy landing page renders./threads' existing auth guard is the correctness backstop.localStorage(keyhttpsms_redirect_to_threads). No backend/API changes.localStorageflag, so a fresh login starts opted-out.Testing
pnpm lint(eslint + stylelint + prettier) — passpnpm run generate— pass (25 routes prerendered, 0 link errors)Design spec and implementation plan are included under
docs/superpowers/(force-added;docs/is gitignored).