Skip to content

Commit

Permalink
Rework Gene Autocomplete
Browse files Browse the repository at this point in the history
  • Loading branch information
jpfisher72 committed Nov 1, 2024
1 parent 1489e88 commit 1ab4d1d
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 33 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,7 @@ export function GeneExpression(props: {
<MenuItem value={"mm10"}>mm10</MenuItem>
</Select>
<GeneAutocomplete
key={assembly} //force reset of component state when assembly changes. Without this, the value of the component is old gene when toggling to ortholog
assembly={assembly}
slotProps={{
autocompleteProps: {
Expand Down
76 changes: 46 additions & 30 deletions screen2.0/src/app/search/_geneAutocomplete/GeneAutocomplete.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useState, useEffect, useMemo } from "react"
import React, { useState, useEffect, useMemo, useCallback } from "react"
import Box from "@mui/material/Box"
import Grid from "@mui/material/Grid2"
import Typography from "@mui/material/Typography"
Expand All @@ -24,20 +24,18 @@ export const GeneAutocomplete = (
slotProps,
endIcon = 'search',
CustomEndIcon,
// onIconClick,
onTextBoxClick,
onGeneSelected,
onGeneSubmitted,
renderOption,
colorTheme
} = props;

const [inputValue, setInputValue] = useState("")
const [value, setValue] = useState<GeneInfo>(props.slotProps?.autocompleteProps?.defaultValue)
const [inputValue, setInputValue] = useState<string>("")
const [options, setOptions] = useState<GeneInfo[]>([])
const [descriptions, setDescriptions] = useState<{ name: string; desc: string }[]>([])
const [loadingOptions, setLoadingOptions] = useState<boolean>(false)

//Fetch gene desciptions
//Fetch and set gene desciptions. Descriptions should probably not be it's own state variable, but rather added to options
useEffect(() => {
const fetchData = async () => {
const descriptions = await Promise.all(
Expand All @@ -62,6 +60,7 @@ export const GeneAutocomplete = (
if (options) fetchData()
}, [options])

//handles setting options on search change
const onSearchChange = async (value: string, assembly: string) => {
setOptions([])
setLoadingOptions(true)
Expand Down Expand Up @@ -91,15 +90,14 @@ export const GeneAutocomplete = (
}
}
})
setOptions(g)
setOptions(g.sort((a, b) => a.name.localeCompare(b.name)))
} else if (genesSuggestion && genesSuggestion.length === 0) {
setOptions([])
}
setLoadingOptions(false)
}

const debounceFn = useMemo(() => debounce(onSearchChange, 500), [])

const debounceOnSearchChange = useMemo(() => debounce(onSearchChange, 500), [])

// Merge the ListboxProps
const mergedListboxProps = {
Expand Down Expand Up @@ -141,39 +139,57 @@ export const GeneAutocomplete = (
...slotProps?.inputTextFieldProps?.sx
}
}

//changes to text input
const handleInputChange = (
_,
value: string,
) => {
if (value != "") { debounceOnSearchChange(value, assembly) } //fetch new gene suggestions
setInputValue(value)
}

const attemptSubmit = (inputVal: string) => {
const gene = options.find(x => x.name.toLowerCase() === inputVal.toLowerCase())
if (gene) {
setInputValue(gene.name)
if (onGeneSubmitted) onGeneSubmitted(gene)
}
//changes to value of component
const handleChange = (
_,
value: GeneInfo,
) => {
setValue(value)
if (onGeneSelected) onGeneSelected(value)
}

//checks for enter key and tries to match with listed options
const handleKeyDown = useCallback((
event: React.KeyboardEvent<HTMLDivElement> & { defaultMuiPrevented?: boolean;}
) => {
if (event.key === "Enter") {
const matchingGene = options.find(x => x.name.toLowerCase() === inputValue.toLowerCase())
if (matchingGene) {
setValue(matchingGene)
if (onGeneSubmitted) onGeneSubmitted(matchingGene)
}
}
}, [inputValue, onGeneSubmitted, options])

const handleIconClick = useCallback(() => {
if (onGeneSubmitted && value) onGeneSubmitted(value)
}, [onGeneSubmitted, value])

return (
<Stack direction="row" spacing={2} {...slotProps?.stackProps}>
<Autocomplete
multiple={false} //How can I easily support this
ListboxProps={mergedListboxProps}
options={options.sort((a, b) => a.name.localeCompare(b.name))} //How do I type this properly?
options={options}
value={value}
inputValue={inputValue}
onInputChange={(_, newInputValue) => {
if (newInputValue != "") {
debounceFn(newInputValue, assembly) // This triggers sending new request for genes
}
setInputValue(newInputValue)
}}
onChange={(_, value) => onGeneSelected && onGeneSelected(value)} //Should I just expose the whole onChange function?
onKeyDown={(event) => {
if (event.key === "Enter") {
attemptSubmit(inputValue)
}
}}
onInputChange={handleInputChange}
onChange={handleChange} //Should I just expose the whole onChange function?
onKeyDown={handleKeyDown}
noOptionsText={loadingOptions ? "Loading..." : "No Genes Found"} //Maybe expose?
renderInput={(params) => (
<i>
<TextField
onClick={onTextBoxClick}
{...params}
{...mergedTextFieldProps}
/>
Expand Down Expand Up @@ -207,7 +223,7 @@ export const GeneAutocomplete = (
<IconButton
aria-label="Search"
type="submit"
onClick={() => attemptSubmit(inputValue)}
onClick={handleIconClick}
{...mergedIconProps}
>
{CustomEndIcon ?
Expand Down
2 changes: 0 additions & 2 deletions screen2.0/src/app/search/_geneAutocomplete/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,6 @@ endIcon?: 'search' | 'add' | 'none'
CustomEndIcon?: OverridableComponent<SvgIconTypeMap<{}, "svg">> & {
muiName: string;
}
// onIconClick?: React.MouseEventHandler<HTMLButtonElement>
onTextBoxClick?: React.MouseEventHandler<HTMLDivElement>
/**
*
* Callback fired when a gene is selected from the dropdown options. Not fired on submission (enter, clicking endIcon)
Expand Down
2 changes: 1 addition & 1 deletion screen2.0/src/app/search/mainresultsfilters.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -919,9 +919,9 @@ export function MainResultsFilters(
null,
getOptionDisabled: option => !linkedGenesWithNums.find(x => x.geneName === option.name),
},
inputTextFieldProps: {onClick: () => !dataLinkedGenes && !loadingLinkedGenes && getLinkedGenes()},
stackProps: { mt: 1 }
}}
onTextBoxClick={() => !dataLinkedGenes && !loadingLinkedGenes && getLinkedGenes()}
endIcon="none"
colorTheme="light"
onGeneSelected={(gene) =>
Expand Down

0 comments on commit 1ab4d1d

Please sign in to comment.