19311: changed search component to a functional style
[arvados-workbench2.git] / src / components / search-input / search-input.tsx
1 // Copyright (C) The Arvados Authors. All rights reserved.
2 //
3 // SPDX-License-Identifier: AGPL-3.0
4
5 import React, {useState, useEffect} from 'react';
6 import { IconButton, StyleRulesCallback, withStyles, WithStyles, FormControl, InputLabel, Input, InputAdornment, Tooltip } from '@material-ui/core';
7 import SearchIcon from '@material-ui/icons/Search';
8
9 type CssRules = 'container' | 'input' | 'button';
10
11 const styles: StyleRulesCallback<CssRules> = theme => {
12     return {
13         container: {
14             position: 'relative',
15             width: '100%'
16         },
17         input: {
18             border: 'none',
19             borderRadius: theme.spacing.unit / 4,
20             boxSizing: 'border-box',
21             padding: theme.spacing.unit,
22             paddingRight: theme.spacing.unit * 4,
23             width: '100%',
24         },
25         button: {
26             position: 'absolute',
27             top: theme.spacing.unit / 2,
28             right: theme.spacing.unit / 2,
29             width: theme.spacing.unit * 3,
30             height: theme.spacing.unit * 3
31         }
32     };
33 };
34
35 interface SearchInputDataProps {
36     value: string;
37     label?: string;
38     selfClearProp: string;
39 }
40
41 interface SearchInputActionProps {
42     onSearch: (value: string) => any;
43     debounce?: number;
44 }
45
46 type SearchInputProps = SearchInputDataProps & SearchInputActionProps & WithStyles<CssRules>;
47
48 // interface SearchInputState {
49 //     value: string;
50 //     label: string;
51 // }
52
53 // let selfClearPropState = '';
54
55 export const DEFAULT_SEARCH_DEBOUNCE = 1000;
56
57 const SearchInputComponent = (props: SearchInputProps) => {
58     const [timeout, setTimeout] = useState(1);
59     const [value, setValue] = useState("");
60     const [label, setLabel] = useState("Search");
61     const [selfClearProp, setSelfClearProp] = useState("");
62
63     useEffect(() => {
64         if (props.value) {
65             setValue(props.value);
66         }
67         if (props.label) {
68             setLabel(props.label);
69         }
70
71         return () => {
72             setValue("");
73             clearTimeout(timeout);
74         };
75     }, [props.value, props.label]); // eslint-disable-line react-hooks/exhaustive-deps
76
77     useEffect(() => {
78         if (selfClearProp !== props.selfClearProp) {
79             setValue("");
80             setSelfClearProp(props.selfClearProp);
81             handleChange({ target: { value: "" } } as any);
82         }
83     }, [props.selfClearProp]); // eslint-disable-line react-hooks/exhaustive-deps
84
85     const handleSubmit = (event: React.FormEvent<HTMLElement>) => {
86         event.preventDefault();
87         clearTimeout(timeout);
88         props.onSearch(value);
89     };
90
91     const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
92         const { target: { value: eventValue } } = event;
93         clearTimeout(timeout);
94         setValue(eventValue);
95         setTimeout(window.setTimeout(
96             () => {
97                 props.onSearch(eventValue);
98             },
99             props.debounce || DEFAULT_SEARCH_DEBOUNCE
100         ));
101     };
102
103     return <form onSubmit={handleSubmit}>
104         <FormControl>
105             <InputLabel>{label}</InputLabel>
106             <Input
107                 type="text"
108                 data-cy="search-input"
109                 value={value}
110                 onChange={handleChange}
111                 endAdornment={
112                     <InputAdornment position="end">
113                         <Tooltip title='Search'>
114                             <IconButton
115                                 onClick={handleSubmit}>
116                                 <SearchIcon />
117                             </IconButton>
118                         </Tooltip>
119                     </InputAdornment>
120                 } />
121         </FormControl>
122     </form>;
123 }
124
125 export const SearchInput = withStyles(styles)(SearchInputComponent);