99} from "lucide-react" ;
1010import { SoftwareCard } from "../components/SoftwareCard" ;
1111import { getSuggestions , getSoftware } from "../lib/gemini" ;
12+ import debounce from "lodash/debounce" ;
1213
1314interface TaskDescriptionInputProps {
1415 taskDescription : string ;
@@ -32,7 +33,7 @@ const TaskDescriptionInput: React.FC<TaskDescriptionInputProps> = ({
3233} ) => {
3334 const [ showDescriptionSuggestions , setShowDescriptionSuggestions ] =
3435 useState ( false ) ;
35-
36+ const [ selectedIndex , setSelectedIndex ] = useState ( - 1 ) ;
3637 return (
3738 < div
3839 className = { `${ layout === "default" ? "" : "mb-8" } bg-white rounded-lg shadow p-6` }
@@ -57,12 +58,32 @@ const TaskDescriptionInput: React.FC<TaskDescriptionInputProps> = ({
5758 onChange = { ( e ) => {
5859 setTaskDescription ( e . target . value ) ;
5960 setShowDescriptionSuggestions ( true ) ;
61+ setSelectedIndex ( - 1 ) ;
6062 } }
6163 onFocus = { ( ) => setShowDescriptionSuggestions ( true ) }
64+ onBlur = { ( ) =>
65+ setTimeout ( ( ) => setShowDescriptionSuggestions ( false ) , 200 )
66+ }
6267 onKeyDown = { ( e ) => {
63- if ( e . key === "Enter" && taskDescription . trim ( ) ) {
68+ if ( e . key === "ArrowDown" ) {
69+ e . preventDefault ( ) ;
70+ setSelectedIndex ( ( prev ) =>
71+ prev < descriptionSuggestions . length - 1 ? prev + 1 : 0 ,
72+ ) ;
73+ } else if ( e . key === "ArrowUp" ) {
74+ e . preventDefault ( ) ;
75+ setSelectedIndex ( ( prev ) =>
76+ prev > 0 ? prev - 1 : descriptionSuggestions . length - 1 ,
77+ ) ;
78+ } else if ( e . key === "Enter" ) {
6479 e . preventDefault ( ) ;
65- handleSearch ( ) ;
80+ if ( selectedIndex >= 0 ) {
81+ setSelectedIndex ( - 1 ) ;
82+ setTaskDescription ( descriptionSuggestions [ selectedIndex ] ) ;
83+ setShowDescriptionSuggestions ( false ) ;
84+ } else if ( taskDescription . trim ( ) ) {
85+ handleSearch ( ) ;
86+ }
6687 }
6788 } }
6889 />
@@ -72,10 +93,14 @@ const TaskDescriptionInput: React.FC<TaskDescriptionInputProps> = ({
7293 { descriptionSuggestions . map ( ( suggestion , index ) => (
7394 < button
7495 key = { index }
75- className = "w-full text-left px-4 py-2 hover:bg-gray-100 first:rounded-t-md last:rounded-b-md"
76- onClick = { ( ) => {
96+ className = { `w-full text-left px-4 py-2 hover:bg-gray-100 first:rounded-t-md last:rounded-b-md ${
97+ selectedIndex === index ? "bg-gray-200" : ""
98+ } `}
99+ onMouseDown = { ( e ) => {
100+ e . preventDefault ( ) ;
77101 setTaskDescription ( suggestion ) ;
78102 setShowDescriptionSuggestions ( false ) ;
103+ setSelectedIndex ( - 1 ) ;
79104 } }
80105 >
81106 { suggestion }
@@ -135,15 +160,22 @@ export function Home({ hasSearched, setHasSearched }: HomeProps) {
135160 ) . sort ( ) ;
136161
137162 useEffect ( ( ) => {
138- if ( taskDescription . length >= 3 ) {
139- const getAutocompleteSuggestions = async ( ) => {
140- const suggestions = await getSuggestions ( taskDescription ) ;
141- setDescriptionSuggestions ( suggestions ?. suggestions ?? [ ] ) ;
142- } ;
143- getAutocompleteSuggestions ( ) ;
144- } else {
145- setDescriptionSuggestions ( [ ] ) ;
146- }
163+ const fetchSuggestions = debounce ( async ( ) => {
164+ if ( taskDescription . length >= 3 ) {
165+ try {
166+ const suggestions = await getSuggestions ( taskDescription ) ;
167+ setDescriptionSuggestions ( suggestions ?. suggestions ?? [ ] ) ;
168+ } catch ( error ) {
169+ console . error ( "Error fetching suggestions:" , error ) ;
170+ }
171+ } else {
172+ setDescriptionSuggestions ( [ ] ) ;
173+ }
174+ } , 500 ) ; // Wait 500ms before making the API request
175+
176+ fetchSuggestions ( ) ;
177+
178+ return ( ) => fetchSuggestions . cancel ( ) ; // Cleanup to prevent unnecessary calls
147179 } , [ taskDescription ] ) ;
148180
149181 const handleSearch = async ( ) => {
0 commit comments