Skip to content

Commit

Permalink
feat: made search results reopen whenever the search field is clicked…
Browse files Browse the repository at this point in the history
… again and has a search term

Ticket: MEN-6894
Changelog: Title
Signed-off-by: Manuel Zedel <manuel.zedel@northern.tech>
  • Loading branch information
mzedel committed Sep 2, 2024
1 parent ce58bb8 commit c36eb96
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 5 deletions.
36 changes: 31 additions & 5 deletions frontend/src/js/components/common/search.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,27 +49,51 @@ export const ControlledSearch = ({ isSearching, name = 'search', onSearch, place
const { classes } = useStyles();
const { control, watch } = useFormContext();
const inputRef = useRef();
const focusLockRef = useRef(true);
const timer = useRef(); // this + the above focusLock are needed to work around the focus being reassigned to the input field which would cause runaway search triggers
const triggerDebounceRef = useRef(false); // this is needed to reject the search triggered through the recreation of the onSearch callback

const searchValue = watch('search', '');

const debouncedSearchTerm = useDebounce(searchValue, TIMEOUTS.debounceDefault);

const focusAndLock = () => {
focusLockRef.current = false;
inputRef.current.focus();
clearTimeout(timer.current);
triggerDebounceRef.current = false;
timer.current = setTimeout(() => (focusLockRef.current = true), TIMEOUTS.oneSecond);
};

useEffect(() => {
return () => {
clearTimeout(timer.current);
};
}, []);

useEffect(() => {
if (debouncedSearchTerm.length < MINIMUM_SEARCH_LENGTH) {
if (debouncedSearchTerm.length < MINIMUM_SEARCH_LENGTH || triggerDebounceRef.current) {
return;
}
onSearch(debouncedSearchTerm).then(() => inputRef.current.focus());
triggerDebounceRef.current = true;
onSearch(debouncedSearchTerm).then(focusAndLock);
}, [debouncedSearchTerm, onSearch]);

const onTriggerSearch = useCallback(
({ key }) => {
if (key === 'Enter' && (!debouncedSearchTerm || debouncedSearchTerm.length >= MINIMUM_SEARCH_LENGTH)) {
onSearch(debouncedSearchTerm).then(() => inputRef.current.focus());
onSearch(debouncedSearchTerm).then(focusAndLock);
}
},
[debouncedSearchTerm, onSearch]
);

const onFocus = useCallback(() => {
if (focusLockRef.current && debouncedSearchTerm.length >= MINIMUM_SEARCH_LENGTH) {
onSearch(debouncedSearchTerm).then(focusAndLock);
}
}, [debouncedSearchTerm, onSearch]);

const adornments = isSearching ? { startAdornment, endAdornment } : { startAdornment };
return (
<Controller
Expand All @@ -79,7 +103,8 @@ export const ControlledSearch = ({ isSearching, name = 'search', onSearch, place
<TextField
className={classes.root}
InputProps={adornments}
onKeyPress={onTriggerSearch}
onKeyUp={onTriggerSearch}
onFocus={onFocus}
placeholder={placeholder}
inputRef={inputRef}
size="small"
Expand All @@ -97,10 +122,11 @@ const Search = props => {
const { searchTerm, onSearch, trigger } = props;
const methods = useForm({ mode: 'onChange', defaultValues: { search: searchTerm ?? '' } });
const { handleSubmit } = methods;
const onSubmit = useCallback(search => onSearch(search, !trigger), [onSearch, trigger]);
return (
<FormProvider {...methods}>
<form noValidate onSubmit={handleSubmit(({ search }) => onSearch(search, !trigger))}>
<ControlledSearch {...props} />
<ControlledSearch {...props} onSearch={onSubmit} />
<input className="hidden" type="submit" />
</form>
</FormProvider>
Expand Down
1 change: 1 addition & 0 deletions frontend/src/js/components/search-result.js
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ export const SearchResult = ({ onToggleSearchResult, open = true }) => {
anchor="top"
classes={classes}
disableEnforceFocus
disableRestoreFocus
open={open}
ModalProps={{ className: classes.drawerOffset, BackdropProps: { className: classes.drawerOffset } }}
PaperProps={{ className: `${classes.drawerOffset} ${classes.paper}` }}
Expand Down

0 comments on commit c36eb96

Please sign in to comment.