fix: composer send attempt while signed out reopens login instead of dead-ending - #1905
fix: composer send attempt while signed out reopens login instead of dead-ending#1905sweetmantech wants to merge 1 commit into
Conversation
…dead-ending A signed-out visitor who dismisses the Privy login modal could type in the composer but never send: the workspace never provisions without auth, so the send button stayed permanently disabled and Enter was a silent no-op (form.requestSubmit() bails on a disabled default submit). Extract the decision into lib/chat/getComposerSubmitAction (send | prompt-login | disabled, auth checked before workspace blockers) and branch in ChatInput's submit handler: a signed-out send attempt calls Privy login() instead. The draft survives the auth flow because it lives in useVercelChat's input state under the modal overlay. Part of #1902 (C4). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Bugbot is not enabled for your account, so this pull request was not reviewed. Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs. |
|
Warning Review limit reached
Next review available in: 55 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (2)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
2 issues found across 3 files
Confidence score: 3/5
- In
lib/chat/getComposerSubmitAction.ts, file-only messages are currently classified as empty, so users can’t send attachment-only messages even though downstream handling supports files; this is a concrete send-path regression for attachment workflows — include non-pending attachments in the content check (or align the emptiness predicate with the content contract). - In
components/VercelChat/ChatInput.tsx, when Privy is still initializing, existing-chat drafts can show an enabled Send button whilesubmitActionis actually"disabled", leading to no-op submits and confusing UX — map this disabled state into the button/interaction gating so the UI matches runtime behavior.
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="components/VercelChat/ChatInput.tsx">
<violation number="1" location="components/VercelChat/ChatInput.tsx:55">
P2: While Privy is initializing, an existing-chat draft leaves the Send button enabled but submitting it does nothing because `submitAction` is `"disabled"` and the UI only maps workspace blockers to `disabled`. Reflect the auth-ready gate in the button state so users cannot hit this temporary dead end, while preserving the existing stop action.</violation>
</file>
<file name="lib/chat/getComposerSubmitAction.ts">
<violation number="1" location="lib/chat/getComposerSubmitAction.ts:7">
P2: File-only messages are treated as empty and cannot be sent: the content contract omits binary attachments even though the chat handler supports them. Include non-pending file attachments in the content predicate (or pass a separate `hasFileAttachments` flag) so an attachment-only draft can reach `send`.</violation>
</file>
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
| const isSendDisabled = | ||
| submitAction === "prompt-login" ? false : isSendBlocked; |
There was a problem hiding this comment.
P2: While Privy is initializing, an existing-chat draft leaves the Send button enabled but submitting it does nothing because submitAction is "disabled" and the UI only maps workspace blockers to disabled. Reflect the auth-ready gate in the button state so users cannot hit this temporary dead end, while preserving the existing stop action.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At components/VercelChat/ChatInput.tsx, line 55:
<comment>While Privy is initializing, an existing-chat draft leaves the Send button enabled but submitting it does nothing because `submitAction` is `"disabled"` and the UI only maps workspace blockers to `disabled`. Reflect the auth-ready gate in the button state so users cannot hit this temporary dead end, while preserving the existing stop action.</comment>
<file context>
@@ -29,15 +31,29 @@ export function ChatInput() {
+ // The workspace never provisions for signed-out visitors, so Send must
+ // stay clickable for them once they have a draft: the attempt reopens
+ // the Privy login modal instead of dead-ending (chat#1902 C4).
+ const isSendDisabled =
+ submitAction === "prompt-login" ? false : isSendBlocked;
</file context>
| const isSendDisabled = | |
| submitAction === "prompt-login" ? false : isSendBlocked; | |
| const isSendDisabled = | |
| (!authReady && !isGeneratingResponse) || | |
| (submitAction !== "prompt-login" && isSendBlocked); |
| /** Privy has finished initializing — login() must never fire before this. */ | ||
| authReady: boolean; | ||
| authenticated: boolean; | ||
| /** Typed input or text attachments present. */ |
There was a problem hiding this comment.
P2: File-only messages are treated as empty and cannot be sent: the content contract omits binary attachments even though the chat handler supports them. Include non-pending file attachments in the content predicate (or pass a separate hasFileAttachments flag) so an attachment-only draft can reach send.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At lib/chat/getComposerSubmitAction.ts, line 7:
<comment>File-only messages are treated as empty and cannot be sent: the content contract omits binary attachments even though the chat handler supports them. Include non-pending file attachments in the content predicate (or pass a separate `hasFileAttachments` flag) so an attachment-only draft can reach `send`.</comment>
<file context>
@@ -0,0 +1,32 @@
+ /** Privy has finished initializing — login() must never fire before this. */
+ authReady: boolean;
+ authenticated: boolean;
+ /** Typed input or text attachments present. */
+ hasContent: boolean;
+ /** Pending uploads, signed-url loading, or workspace not ready. */
</file context>
What
On chat.recoupable.dev, a signed-out visitor who dismisses the Privy login modal can type in the composer but can never send: the workspace never provisions without auth, so the send button stays permanently disabled and Enter is a silent no-op (
form.requestSubmit()bails when the default submit button is disabled). This PR turns that dead end into a login reprompt: any send attempt (button click or Enter) while unauthenticated reopens the Privy login modal viausePrivy().login().Part of #1902 (item C4).
How
lib/chat/getComposerSubmitAction.ts: pure decision function returning"send" | "prompt-login" | "disabled". Auth is checked before workspace blockers, because the workspace never provisions for anonymous visitors; without that ordering the signed-out state is permanently "disabled".components/VercelChat/ChatInput.tsx: computes the action fromusePrivy()(ready,authenticated,login) plus the existing context flags. When the action isprompt-loginthe send button stays enabled and the submit handler callslogin()instead ofhandleSendMessage. Signed-in behavior (workspace gating, stop-while-generating, empty-input no-op) is unchanged. The button also gains a state-accuratearia-label("Sign in to send" / "Send message" / "Stop response").login()is never called before Privy finishes initializing (readygate in the decision function).Draft persistence: the composer draft is React state (
useState("")inhooks/useVercelChat.ts) inside the<Chat>instance, whichNewChatBootstrapkeeps mounted with a stable ref-based id across the provisioning transition. The Privy modal is an overlay, so nothing unmounts: the drafted text survives dismissing and reopening the modal and the full auth flow, and sends normally once the workspace provisions after login.How to test
Tests:
pnpm exec vitest run(282 passed, incl. 6 new forgetComposerSubmitAction);pnpm exec tsc --noEmitclean for the changed files.Preview verification to follow in a PR comment.
🤖 Generated with Claude Code
Summary by cubic
Fixes the signed-out composer dead end: pressing Send or Enter now reopens the Privy login modal and preserves the draft. Addresses #1902 (C4).
getComposerSubmitActionto decide between "send" | "prompt-login" | "disabled", checking auth before workspace blockers.VercelChat/ChatInputto callusePrivy().login()from@privy-io/react-authon unauthenticated send, keep Send enabled with correct aria-labels, and guard until Privy is ready; drafts persist and signed-in behavior is unchanged.Written for commit 2e99f7f. Summary will update on new commits.