feat(dashboard): connect wallet without signing in - #2086
Conversation
Delegating, voting and publishing a proposal are settled on-chain by the wallet's own transaction signature, so they only ever needed a connected account. They were routed through the sign-in modal instead, forcing a SIWE message on anyone who just wanted to act on-chain. Connecting and signing in are now separate: - useWalletPrompt always opens the wallet picker, never the sign-in modal - LoginProvider no longer force-disconnects a wallet that has no session, and no longer re-opens the sign-in modal when the account changes - the header connect buttons (Anticapture and whitelabel) open the wallet picker directly - the sign-in modal, still raised by the surfaces that need a server session (proposal drafts, API keys), labels its wallet option "Sign in with wallet" Wallet-born sessions stay bound to their wallet: disconnecting or switching accounts still signs them out, it just never prompts again. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
1 Skipped Deployment
|
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: bcd09f1772
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| @@ -82,19 +85,8 @@ export function LoginProvider({ | |||
| address.toLowerCase() !== sessionAddress | |||
| ) { | |||
| void authClient.signOut(); | |||
There was a problem hiding this comment.
Block gated actions while switching wallet accounts
When a SIWE-authenticated user switches from wallet A to wallet B, this starts signOut() asynchronously but leaves A's session usable while the request is pending—and indefinitely if it fails. During that interval the UI displays wallet B, while useDrafts and ApiKeysManager still treat A as authenticated, so saving a draft or creating/revoking an API key can mutate A's account. Keep the session-gated surfaces blocked or treat the session as invalid as soon as the address mismatch is detected, rather than relying solely on the eventual sign-out response.
Useful? React with 👍 / 👎.
🎨 UI Review
Header — Connect Wallet button (Anticapture + Whitelabel)Question for author — header no longer offers a wallet sign-in path, which the linked spec says it should
Component statesNice-to-have — "connected, no session" now looks identical to "signed in" in the header
Design-system adherenceNo issues — the diff only reconfigures existing MobileNo mobile-specific surface changed in this diff — the same header components render responsively as before; nothing new to check here. Scope noteThis is a UI-only review (visual fidelity, DS adherence, UX, copy, responsive behavior) — architecture, hook structure, and other code-quality concerns are left to the code reviewer. Generated by Claude Code |
|
🔍 Vercel preview: https://anticapture-hp5a75g8u-ful.vercel.app |
|
🚅 Deployed to the anticapture-pr-2086 environment in anticapture-infra
|
…anges Switching accounts on a SIWE session fired signOut() and left the old session usable while the request was in flight, and indefinitely if it failed: the header showed wallet B while drafts and API keys still acted for wallet A. Sign-out is now the cleanup, not the gate. isWalletSessionStale derives the broken binding synchronously from wallet state, and useAuthSession serves the session through it, so a mismatched or disconnected wallet reads as no session from the render it happens. The API-key create and delete modals live outside the auth branch, so they close on the account change instead of submitting against the previous account. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 160230f74a
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| setSessionTokens({}); | ||
| setLastCreated(null); | ||
| setCreated(null); | ||
| setCreateOpen(false); |
There was a problem hiding this comment.
Discard previous-account mutation completions
When a user submits an API-key creation and switches or disconnects the wallet before the request completes, this effect clears and closes the current state, but it does not cancel or invalidate the mutation's per-call callback. A successful response can subsequently run onSuccess, repopulate created and sessionTokens, and show wallet A's plaintext key after wallet B has signed in. Associate the mutation with the initiating user ID and ignore late completions after that ID changes.
Useful? React with 👍 / 👎.
Problem
Delegating, voting and publishing a proposal are settled on-chain by the wallet's own transaction signature, so they only ever needed a connected account. They were routed through the sign-in modal instead, which forced a SIWE message on anyone who just wanted to act on-chain.
A harder blocker sat in
LoginProvider: an effect that calleddisconnect()on any connected wallet without a session. Being connected but not signed in was simply not a reachable state.Applies to both Anticapture and whitelabel.
What changed
Connecting a wallet and signing in are now separate actions.
shared/services/auth/useWalletPrompt.tsshared/services/auth/LoginProvider.tsxshared/services/auth/LoginProvider.tsxshared/components/wallet/ConnectWallet.tsxshared/components/wallet/WhitelabelConnectWallet.tsxNo copy changes: the sign-in modal keeps its "Connect wallet" button.
Wallet-born sessions stay bound to their wallet: disconnecting or switching accounts still signs them out, it just never prompts again.
The remaining
openLogin()call sites are only where a server session is genuinely required: API keys, saving or sharing a draft, and opening the proposal editor. None on the delegate or vote path.Verification
tsc --noEmitclean andeslintat 0 errors, with no warnings in the touched files (the 83 warnings in the app are pre-existing).Not verified: the wallet flows in a browser. That needs a real wallet extension plus the full local stack, so please confirm manually that Delegate and Vote open MetaMask without asking for a signature, on both Anticapture and a whitelabel deployment.
Worth a look during review
With the header becoming a pure connect affordance, email and Google lose their visible entry point. They now surface only when the user hits a session-gated action (draft, API key). If that is not the intent, the alternative is two separate affordances ("Connect wallet" and "Sign in"), which needs design.
🤖 Generated with Claude Code