From 426bc60853cb29a1bc2e3a4e84441e15530a2baf Mon Sep 17 00:00:00 2001 From: mimran-khan Date: Thu, 12 Nov 2026 00:28:42 +0530 Subject: [PATCH 1/2] fix: require a comment with every thumbs-down A down vote could be sent with an empty comment. Send stays disabled until the comment has text, and Enter does not submit a blank one. Signed-off-by: mimran-khan --- .../components/FeedbackButtons.test.tsx | 58 +++++++++++++++++++ src/frontend/components/FeedbackButtons.tsx | 19 ++++-- 2 files changed, 72 insertions(+), 5 deletions(-) create mode 100644 src/frontend/components/FeedbackButtons.test.tsx diff --git a/src/frontend/components/FeedbackButtons.test.tsx b/src/frontend/components/FeedbackButtons.test.tsx new file mode 100644 index 00000000..11de6d37 --- /dev/null +++ b/src/frontend/components/FeedbackButtons.test.tsx @@ -0,0 +1,58 @@ +import { fireEvent, render, screen } from '@testing-library/react'; +import { describe, expect, it, vi } from 'vitest'; + +import { FeedbackCommentBox, type FeedbackState } from './FeedbackButtons'; + +function commentState(comment: string): FeedbackState { + return { + existingFeedback: null, + isSubmitting: false, + showCommentInput: true, + comment, + disabled: false, + handleThumbsUp: vi.fn(), + handleThumbsDown: vi.fn(), + handleCommentSubmit: vi.fn(), + setComment: vi.fn(), + cancelComment: vi.fn(), + }; +} + +describe('FeedbackCommentBox', () => { + it('keeps Send disabled until the comment has text', () => { + const { rerender } = render(); + const send = screen.getByRole('button', { name: 'Send' }); + const comment = screen.getByRole('textbox', { name: 'What went wrong?' }); + + expect(comment).toBeRequired(); + expect(send).toBeDisabled(); + + rerender(); + expect(screen.getByRole('button', { name: 'Send' })).toBeDisabled(); + + rerender(); + expect(screen.getByRole('button', { name: 'Send' })).toBeEnabled(); + }); + + it('does not send a blank comment with Enter', () => { + const fb = commentState(' '); + render(); + + fireEvent.keyDown(screen.getByRole('textbox', { name: 'What went wrong?' }), { + key: 'Enter', + }); + + expect(fb.handleCommentSubmit).not.toHaveBeenCalled(); + }); + + it('sends when Enter is pressed on a real comment', () => { + const fb = commentState('The citation was wrong'); + render(); + + fireEvent.keyDown(screen.getByRole('textbox', { name: 'What went wrong?' }), { + key: 'Enter', + }); + + expect(fb.handleCommentSubmit).toHaveBeenCalledOnce(); + }); +}); diff --git a/src/frontend/components/FeedbackButtons.tsx b/src/frontend/components/FeedbackButtons.tsx index c3c2bc0f..f2d6a818 100644 --- a/src/frontend/components/FeedbackButtons.tsx +++ b/src/frontend/components/FeedbackButtons.tsx @@ -101,7 +101,9 @@ export function useFeedback({ }, [locked, isSubmitting]); const handleCommentSubmit = useCallback(() => { - void doSendFeedback('down', comment.trim() || undefined); + const text = comment.trim(); + if (!text) return; + void doSendFeedback('down', text); }, [doSendFeedback, comment]); const cancelComment = useCallback(() => { @@ -164,10 +166,13 @@ export function FeedbackButtons({ fb }: { fb: FeedbackState }) { export function FeedbackCommentBox({ fb }: { fb: FeedbackState }) { if (!fb.showCommentInput || !!fb.existingFeedback) return null; + const commentText = fb.comment.trim(); + const canSend = commentText.length > 0 && !fb.isSubmitting; + const handleKeyDown = (e: React.KeyboardEvent) => { if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); - fb.handleCommentSubmit(); + if (canSend) fb.handleCommentSubmit(); } else if (e.key === 'Escape') { fb.cancelComment(); } @@ -180,7 +185,10 @@ export function FeedbackCommentBox({ fb }: { fb: FeedbackState }) { value={fb.comment} onChange={(e) => fb.setComment(e.target.value)} onKeyDown={handleKeyDown} - placeholder="What went wrong? (optional)" + placeholder="What went wrong?" + aria-label="What went wrong?" + aria-required="true" + required className="w-full resize-none border-0 bg-transparent text-sm text-foreground placeholder:text-muted-foreground focus:outline-none" autoFocus rows={1} @@ -195,8 +203,9 @@ export function FeedbackCommentBox({ fb }: { fb: FeedbackState }) {