b2c95a9379a04f24454d315ecc37e12b58fa7c3e
[arvados-workbench2.git] / src / components / main-app-bar / search-bar / search-bar.tsx
1 // Copyright (C) The Arvados Authors. All rights reserved.
2 //
3 // SPDX-License-Identifier: AGPL-3.0
4
5 import * as React from 'react';
6 import { AppBar, Toolbar, Typography, Grid, IconButton, Badge, Paper, Input, StyleRulesCallback, withStyles, WithStyles } from '@material-ui/core';
7 import NotificationsIcon from '@material-ui/icons/Notifications';
8 import PersonIcon from '@material-ui/icons/Person';
9 import HelpIcon from '@material-ui/icons/Help';
10 import SearchIcon from '@material-ui/icons/Search';
11 import { AppBarProps } from '@material-ui/core/AppBar';
12
13 interface SearchBarDataProps {
14     value: string;
15 }
16
17 interface SearchBarActionProps {
18     onSearch: (value: string) => any;
19     debounce?: number;
20 }
21
22 type SearchBarProps = SearchBarDataProps & SearchBarActionProps & WithStyles<CssRules>
23
24 interface SearchBarState {
25     value: string;
26     prevValue: string;
27 }
28
29 const DEFAULT_SEARCH_DEBOUNCE = 1000;
30
31 class SearchBar extends React.Component<SearchBarProps> {
32
33     state: SearchBarState = {
34         value: "",
35         prevValue: ""
36     }
37
38     timeout: NodeJS.Timer;
39
40     render() {
41         const { classes } = this.props
42         return <Paper className={classes.container}>
43             <form onSubmit={this.handleSubmit}>
44                 <input
45                     className={classes.input}
46                     onChange={this.handleChange}
47                     placeholder="Search"
48                     value={this.state.value}
49                 />
50                 <IconButton className={classes.button}>
51                     <SearchIcon />
52                 </IconButton>
53             </form>
54         </Paper>
55     }
56
57     componentWillReceiveProps(nextProps: SearchBarProps) {
58         if (nextProps.value !== this.props.value) {
59             this.setState({ value: nextProps.value });
60         }
61     }
62
63     handleSubmit = (event: React.FormEvent<HTMLFormElement>) => {
64         event.preventDefault();
65         clearTimeout(this.timeout);
66         this.props.onSearch(this.state.value);
67     }
68
69     handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
70         clearTimeout(this.timeout);
71         this.setState({ value: event.target.value });
72         this.timeout = setTimeout(
73             () => this.props.onSearch(this.state.value),
74             this.props.debounce || DEFAULT_SEARCH_DEBOUNCE
75         );
76
77     }
78
79 }
80
81 type CssRules = 'container' | 'input' | 'button'
82
83 const styles: StyleRulesCallback<CssRules> = theme => {
84     const { unit } = theme.spacing
85     return {
86         container: {
87             position: 'relative',
88             width: '100%'
89         },
90         input: {
91             border: 'none',
92             borderRadius: unit / 4,
93             boxSizing: 'border-box',
94             padding: unit,
95             paddingRight: unit * 4,
96             width: '100%',
97         },
98         button: {
99             position: 'absolute',
100             top: unit / 2,
101             right: unit / 2,
102             width: unit * 3,
103             height: unit * 3
104         }
105     }
106 }
107
108 export default withStyles(styles)(SearchBar)