import { User } from "../../models/user";
export interface MainAppBarMenuItem {
- label: string
+ label: string;
}
export interface MainAppBarMenuItems {
}
interface MainAppBarDataProps {
- searchQuery: string,
- breadcrumbs: Breadcrumb[],
- user?: User,
- menuItems: MainAppBarMenuItems
+ searchText: string;
+ searchDebounce?: number;
+ breadcrumbs: Breadcrumb[];
+ user?: User;
+ menuItems: MainAppBarMenuItems;
}
export interface MainAppBarActionProps {
- actions: {
- onSearchQueryChange: (searchQuery: string) => void,
- onSearchQuerySubmit: () => void,
- onBreadcrumbClick: (breadcrumb: Breadcrumb) => void,
- onMenuItemClick: (menuItem: MainAppBarMenuItem) => void
- }
+ onSearch: (searchText: string) => void,
+ onBreadcrumbClick: (breadcrumb: Breadcrumb) => void,
+ onMenuItemClick: (menuItem: MainAppBarMenuItem) => void
}
type MainAppBarProps = MainAppBarDataProps & MainAppBarActionProps & WithStyles<CssRules>;
export class MainAppBar extends React.Component<MainAppBarProps> {
render() {
- const { classes, searchQuery, breadcrumbs } = this.props
+ const { classes, searchText, breadcrumbs, searchDebounce } = this.props
return <AppBar className={classes.appBar} position="static">
<Toolbar>
<Grid
<Grid item xs={6} container alignItems="center">
{
this.props.user && <SearchBar
- value={searchQuery}
- onChange={this.props.actions.onSearchQueryChange}
- onSubmit={this.props.actions.onSearchQuerySubmit}
+ value={searchText}
+ onSearch={this.props.onSearch}
+ debounce={searchDebounce}
/>
}
</Grid>
</Toolbar>
{
this.props.user && <Toolbar>
- <Breadcrumbs items={breadcrumbs} onClick={this.props.actions.onBreadcrumbClick} />
+ <Breadcrumbs items={breadcrumbs} onClick={this.props.onBreadcrumbClick} />
</Toolbar>
}
</AppBar>
}
renderMenuForUser = () => {
- const { user, actions } = this.props
+ const { user } = this.props
return (
<>
<IconButton color="inherit">
renderMenuForAnonymous = () => {
return this.props.menuItems.anonymousMenu.map((item, index) => (
- <Button color="inherit" onClick={() => this.props.actions.onMenuItemClick(item)}>{item.label}</Button>
+ <Button color="inherit" onClick={() => this.props.onMenuItemClick(item)}>{item.label}</Button>
))
}
renderMenuItems = (menuItems: MainAppBarMenuItem[]) => {
return menuItems.map((item, index) => (
- <MenuItem key={index} onClick={() => this.props.actions.onMenuItemClick(item)}>{item.label}</MenuItem>
+ <MenuItem key={index} onClick={() => this.props.onMenuItemClick(item)}>{item.label}</MenuItem>
))
}
}
interface SearchBarActionProps {
- onChange: (value: string) => any;
- onSubmit: () => any;
+ onSearch: (value: string) => any;
+ debounce?: number;
}
type SearchBarProps = SearchBarDataProps & SearchBarActionProps & WithStyles<CssRules>
+interface SearchBarState {
+ value: string;
+ prevValue: string;
+}
+
+const DEFAULT_SEARCH_DEBOUNCE = 1000;
+
class SearchBar extends React.Component<SearchBarProps> {
+
+ state: SearchBarState = {
+ value: "",
+ prevValue: ""
+ }
+
+ timeout: NodeJS.Timer;
+
render() {
const { classes } = this.props
return <Paper className={classes.container}>
className={classes.input}
onChange={this.handleChange}
placeholder="Search"
- value={this.props.value}
+ value={this.state.value}
/>
<IconButton className={classes.button}>
<SearchIcon />
</Paper>
}
+ componentWillReceiveProps(nextProps: SearchBarProps) {
+ if (nextProps.value !== this.props.value) {
+ this.setState({ value: nextProps.value });
+ }
+ }
+
handleSubmit = (event: React.FormEvent<HTMLFormElement>) => {
event.preventDefault();
- this.props.onSubmit();
+ clearTimeout(this.timeout);
+ this.props.onSearch(this.state.value);
}
handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
- this.props.onChange(event.target.value);
+ clearTimeout(this.timeout);
+ this.setState({ value: event.target.value });
+ this.timeout = setTimeout(
+ () => this.props.onSearch(this.state.value),
+ this.props.debounce || DEFAULT_SEARCH_DEBOUNCE
+ );
+
}
}
interface WorkbenchState {
anchorEl: any;
breadcrumbs: NavBreadcrumb[];
- searchQuery: string;
+ searchText: string;
menuItems: {
accountMenu: NavMenuItem[],
helpMenu: NavMenuItem[],
class Workbench extends React.Component<WorkbenchProps, WorkbenchState> {
state = {
anchorEl: null,
- searchQuery: "",
+ searchText: "",
breadcrumbs: [
{
label: "Projects",
mainAppBarActions: MainAppBarActionProps = {
- actions: {
- onBreadcrumbClick: (breadcrumb: NavBreadcrumb) => this.props.dispatch(push(breadcrumb.path)),
- onSearchQueryChange: searchQuery => this.setState({ searchQuery }),
- onSearchQuerySubmit: () => this.props.dispatch(push(`/search?q=${this.state.searchQuery}`)),
- onMenuItemClick: (menuItem: NavMenuItem) => menuItem.action()
- }
+ onBreadcrumbClick: (breadcrumb: NavBreadcrumb) => this.props.dispatch(push(breadcrumb.path)),
+ onSearch: searchText => {
+ this.setState({ searchText });
+ this.props.dispatch(push(`/search?q=${searchText}`));
+ },
+ onMenuItemClick: (menuItem: NavMenuItem) => menuItem.action()
}
render() {
<div className={classes.appBar}>
<MainAppBar
breadcrumbs={this.state.breadcrumbs}
- searchQuery={this.state.searchQuery}
+ searchText={this.state.searchText}
user={this.props.user}
menuItems={this.state.menuItems}
- actions={this.mainAppBarActions.actions}
+ {...this.mainAppBarActions}
/>
</div>
{user &&