11"use client" ;
22
3- import React , { useState , useEffect } from 'react' ;
3+ import React , { useState , useEffect , useCallback , useRef } from 'react' ;
44import { useProjectsContext } from '@/context/ProjectsContext' ;
55import { getProjectDocs , regenerateProjectDocs , modifyDocsWithQna , getDocsQnaHistory , createDocsShare , revokeDocsShare , getDocsShare , deleteDocsQnaRecord , deleteAllDocsQnaHistory } from '@/lib/actions' ;
66import { Card , CardContent , CardDescription , CardHeader , CardTitle } from '@/components/ui/card' ;
@@ -99,6 +99,7 @@ function DocsPage() {
9999 const [ qnaQuestion , setQnaQuestion ] = useState ( '' ) ;
100100 const [ isProcessingQna , setIsProcessingQna ] = useState ( false ) ;
101101 const [ activeTab , setActiveTab ] = useState ( 'preview' ) ;
102+ const qnaInputRef = useRef < HTMLTextAreaElement > ( null ) ;
102103 const [ shareToken , setShareToken ] = useState < string | null > ( null ) ;
103104 const [ isCreatingShare , setIsCreatingShare ] = useState ( false ) ;
104105 const [ isRevokingShare , setIsRevokingShare ] = useState ( false ) ;
@@ -215,13 +216,15 @@ function DocsPage() {
215216 } ;
216217
217218 const handleQnaSubmit = async ( ) => {
218- if ( ! selectedProjectId || ! qnaQuestion . trim ( ) ) return ;
219+ // Get value from ref if available, otherwise use state
220+ const questionValue = qnaInputRef . current ?. value || qnaQuestion ;
221+ if ( ! selectedProjectId || ! questionValue . trim ( ) ) return ;
219222
220223 setIsProcessingQna ( true ) ;
221224 setError ( null ) ;
222225
223226 try {
224- const result = await modifyDocsWithQna ( selectedProjectId , qnaQuestion ) ;
227+ const result = await modifyDocsWithQna ( selectedProjectId , questionValue ) ;
225228 setDocsData ( result . docs ) ;
226229 if ( result . docs . content ) {
227230 setMetadata ( parseDocsMetadata ( result . docs . content ) ) ;
@@ -230,6 +233,9 @@ function DocsPage() {
230233 // Add to Q&A history
231234 setQnaHistory ( prev => [ result . qnaRecord , ...prev ] ) ;
232235 setQnaQuestion ( '' ) ;
236+ if ( qnaInputRef . current ) {
237+ qnaInputRef . current . value = '' ;
238+ }
233239
234240 // Switch to preview tab to show the updated docs
235241 setActiveTab ( 'preview' ) ;
@@ -249,6 +255,16 @@ function DocsPage() {
249255 }
250256 } ;
251257
258+ // Optimized onChange handler to prevent lag - debounced state update for button disabled state
259+ const handleQnaQuestionChange = useCallback ( ( e : React . ChangeEvent < HTMLTextAreaElement > ) => {
260+ const value = e . target . value ;
261+ // Update state with a small delay to prevent blocking the input
262+ // The input itself updates immediately (uncontrolled), state syncs for button logic
263+ setTimeout ( ( ) => {
264+ setQnaQuestion ( value ) ;
265+ } , 0 ) ;
266+ } , [ ] ) ;
267+
252268 const fetchQnaHistory = async ( ) => {
253269 if ( ! selectedProjectId ) return ;
254270
@@ -529,6 +545,16 @@ function DocsPage() {
529545 </ div >
530546 </ div >
531547
548+ { /* Regenerating Status Indicator */ }
549+ { isRegenerating && (
550+ < div className = "mx-2 sm:mx-4 mb-4 sm:mb-6" >
551+ < div className = "bg-white/10 border border-white/20 rounded-lg px-3 sm:px-4 py-2 sm:py-3 flex items-center gap-2 sm:gap-3" >
552+ < Loader2 className = "h-4 w-4 sm:h-5 sm:w-5 text-white animate-spin flex-shrink-0" />
553+ < span className = "text-white text-sm sm:text-base mobile-no-truncate" > Regenerating documentation...</ span >
554+ </ div >
555+ </ div >
556+ ) }
557+
532558 { metadata && (
533559 < div className = "px-2 sm:px-4 mb-4 sm:mb-6" >
534560 < div className = "flex flex-wrap gap-1 sm:gap-2 md:gap-3" >
@@ -731,8 +757,9 @@ function DocsPage() {
731757 < div className = "pb-4 sm:pb-6 border-b border-white/10" >
732758 < div className = "space-y-4 sm:space-y-6" >
733759 < textarea
734- value = { qnaQuestion }
735- onChange = { ( e ) => setQnaQuestion ( e . target . value ) }
760+ ref = { qnaInputRef }
761+ defaultValue = { qnaQuestion }
762+ onChange = { handleQnaQuestionChange }
736763 placeholder = "Which file contains authentication logic?"
737764 className = "w-full h-[60px] sm:h-[80px] p-2 sm:p-3 bg-black/30 border border-white/20 rounded-lg resize-none text-sm sm:text-base text-white placeholder:text-white/50 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent mobile-no-truncate"
738765 onKeyDown = { ( e ) => {
@@ -741,10 +768,14 @@ function DocsPage() {
741768 handleQnaSubmit ( ) ;
742769 }
743770 } }
771+ autoComplete = "off"
772+ autoCorrect = "off"
773+ autoCapitalize = "off"
774+ spellCheck = "false"
744775 />
745776 < Button
746777 onClick = { handleQnaSubmit }
747- disabled = { isProcessingQna || ! qnaQuestion . trim ( ) }
778+ disabled = { isProcessingQna || ! ( qnaInputRef . current ?. value || qnaQuestion ) . trim ( ) }
748779 className = "w-full bg-red-600 hover:bg-red-700 text-white py-2 sm:py-3 rounded-lg transition-colors h-[40px] sm:h-[48px] text-sm sm:text-base font-medium"
749780 >
750781 { isProcessingQna ? (
@@ -866,8 +897,8 @@ function DocsPage() {
866897 >
867898 { isRegenerating ? (
868899 < >
869- < Loader2 className = "h-5 w-5 mr-2 animate-spin" />
870- Generating Documentation...
900+ < Loader2 className = "h-5 w-5 mr-2 animate-spin flex-shrink-0 " />
901+ < span > Generating Documentation...</ span >
871902 </ >
872903 ) : (
873904 < >
0 commit comments