feat(frontend): display submitted question below input (sub-phase 2.2)

Show submitted question as italic text below the input area after clicking submit. Clears when user starts typing a new question.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
Woody 2026-04-24 15:56:35 +08:00
parent 0ba8ff2e24
commit 87acb8816a
2 changed files with 66 additions and 8 deletions

View File

@ -7,12 +7,14 @@ export interface QueryInputProps {
export const QueryInput: React.FC<QueryInputProps> = ({ onSubmit, isLoading }) => {
const [question, setQuestion] = useState<string>('')
const [submittedQuestion, setSubmittedQuestion] = useState<string | null>(null)
const handleSubmit = (e: FormEvent): void => {
e.preventDefault()
const trimmed = question.trim()
if (trimmed && !isLoading) {
onSubmit(trimmed)
setSubmittedQuestion(trimmed)
setQuestion('')
}
}
@ -24,26 +26,40 @@ export const QueryInput: React.FC<QueryInputProps> = ({ onSubmit, isLoading }) =
}
}
const handleChange = (e: React.ChangeEvent<HTMLTextAreaElement>): void => {
setQuestion(e.target.value)
if (e.target.value.trim() !== '') {
setSubmittedQuestion(null)
}
}
const isDisabled = isLoading || question.trim() === ''
return (
<form onSubmit={handleSubmit} className="space-y-3">
<textarea
value={question}
onChange={(e) => setQuestion(e.target.value)}
onChange={handleChange}
onKeyDown={handleKeyDown}
placeholder="Ask a question about your documents..."
disabled={isLoading}
rows={3}
className="w-full rounded border border-gray-300 px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent disabled:bg-gray-100 disabled:cursor-not-allowed"
/>
<button
type="submit"
disabled={isDisabled}
className="px-4 py-2 bg-blue-600 text-white font-medium rounded hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 disabled:opacity-50 disabled:cursor-not-allowed disabled:hover:bg-blue-600 transition-all duration-200"
>
{isLoading ? 'Processing...' : 'Submit'}
</button>
<div className="flex items-start gap-3">
<button
type="submit"
disabled={isDisabled}
className="px-4 py-2 bg-blue-600 text-white font-medium rounded hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 disabled:opacity-50 disabled:cursor-not-allowed disabled:hover:bg-blue-600 transition-all duration-200"
>
{isLoading ? 'Processing...' : 'Submit'}
</button>
</div>
{submittedQuestion && (
<p data-testid="submitted-question" className="text-sm text-gray-500 italic">
Your question: &ldquo;{submittedQuestion}&rdquo;
</p>
)}
</form>
)
}

View File

@ -111,4 +111,46 @@ describe('QueryInput', () => {
expect(mockOnSubmit).not.toHaveBeenCalled()
})
it('shows submitted question after clicking submit', () => {
render(<QueryInput onSubmit={mockOnSubmit} isLoading={false} />)
const textarea = screen.getByPlaceholderText('Ask a question about your documents...')
const button = screen.getByRole('button', { name: /submit/i })
fireEvent.change(textarea, { target: { value: 'What is NEC4?' } })
fireEvent.click(button)
expect(screen.getByTestId('submitted-question')).toHaveTextContent('What is NEC4?')
})
it('clears submitted question when user starts typing a new question', () => {
render(<QueryInput onSubmit={mockOnSubmit} isLoading={false} />)
const textarea = screen.getByPlaceholderText('Ask a question about your documents...')
const button = screen.getByRole('button', { name: /submit/i })
fireEvent.change(textarea, { target: { value: 'First question' } })
fireEvent.click(button)
expect(screen.getByTestId('submitted-question')).toBeInTheDocument()
fireEvent.change(textarea, { target: { value: 'New question' } })
expect(screen.queryByTestId('submitted-question')).not.toBeInTheDocument()
})
it('does not show submitted question before any submission', () => {
render(<QueryInput onSubmit={mockOnSubmit} isLoading={false} />)
expect(screen.queryByTestId('submitted-question')).not.toBeInTheDocument()
})
it('does not clear submitted question when typing only whitespace', () => {
render(<QueryInput onSubmit={mockOnSubmit} isLoading={false} />)
const textarea = screen.getByPlaceholderText('Ask a question about your documents...')
const button = screen.getByRole('button', { name: /submit/i })
fireEvent.change(textarea, { target: { value: 'My question' } })
fireEvent.click(button)
expect(screen.getByTestId('submitted-question')).toBeInTheDocument()
fireEvent.change(textarea, { target: { value: ' ' } })
expect(screen.getByTestId('submitted-question')).toBeInTheDocument()
})
})