Search improves (#67)

* ESC should go back from search
using direct onKeyDown here as react-keydown does not trigger within an input

* Addressable search urls
This commit is contained in:
Tom Moor
2017-05-21 23:02:53 -07:00
committed by GitHub
parent 87adccb816
commit 3353eb913a
5 changed files with 55 additions and 21 deletions

View File

@ -79,6 +79,7 @@ render(
<Route exact path="/d/:id/new" component={DocumentNewChild} /> <Route exact path="/d/:id/new" component={DocumentNewChild} />
<Route exact path="/search" component={Search} /> <Route exact path="/search" component={Search} />
<Route exact path="/search/:query" component={Search} />
<Route exact path="/settings" component={Settings} /> <Route exact path="/settings" component={Settings} />
<Route exact path="/auth/slack" component={SlackAuth} /> <Route exact path="/auth/slack" component={SlackAuth} />

View File

@ -3,6 +3,8 @@ import React from 'react';
import { observer } from 'mobx-react'; import { observer } from 'mobx-react';
import _ from 'lodash'; import _ from 'lodash';
import { Flex } from 'reflexbox'; import { Flex } from 'reflexbox';
import { withRouter } from 'react-router';
import { searchUrl } from 'utils/routeHelpers';
import SearchField from './components/SearchField'; import SearchField from './components/SearchField';
import styles from './Search.scss'; import styles from './Search.scss';
@ -13,6 +15,8 @@ import CenteredContent from 'components/CenteredContent';
import DocumentPreview from 'components/DocumentPreview'; import DocumentPreview from 'components/DocumentPreview';
type Props = { type Props = {
history: Object,
match: Object,
notFound: ?boolean, notFound: ?boolean,
}; };
@ -23,12 +27,31 @@ type Props = {
constructor(props: Props) { constructor(props: Props) {
super(props); super(props);
this.store = new SearchStore(); this.store = new SearchStore();
this.updateSearchResults();
} }
render() { componentDidUpdate(prevProps) {
const search = _.debounce(searchTerm => { if (prevProps.match.params.query !== this.props.match.params.query) {
this.store.search(searchTerm); this.updateSearchResults();
}
}
handleKeyDown = ev => {
if (ev.which === 27) {
ev.preventDefault();
this.props.history.goBack();
}
};
updateSearchResults = _.debounce(() => {
this.store.search(this.props.match.params.query);
}, 250); }, 250);
updateQuery = query => {
this.props.history.replace(searchUrl(query));
};
render() {
const title = <Title content="Search" />; const title = <Title content="Search" />;
return ( return (
@ -55,15 +78,13 @@ type Props = {
/> />
<SearchField <SearchField
searchTerm={this.store.searchTerm} searchTerm={this.store.searchTerm}
onChange={search} onKeyDown={this.handleKeyDown}
onChange={this.updateQuery}
/> />
</Flex> </Flex>
{this.store.documents && {this.store.documents.map(document => (
this.store.documents.map(document => {
return (
<DocumentPreview key={document.id} document={document} /> <DocumentPreview key={document.id} document={document} />
); ))}
})}
</Flex> </Flex>
</CenteredContent> </CenteredContent>
</Layout> </Layout>
@ -71,4 +92,4 @@ type Props = {
} }
} }
export default Search; export default withRouter(Search);

View File

@ -5,7 +5,7 @@ import { client } from 'utils/ApiClient';
import type { Document } from 'types'; import type { Document } from 'types';
class SearchStore { class SearchStore {
@observable documents: ?(Document[]); @observable documents: Array<Document> = [];
@observable searchTerm: ?string = null; @observable searchTerm: ?string = null;
@observable isFetching = false; @observable isFetching = false;
@ -28,7 +28,7 @@ class SearchStore {
console.error('Something went wrong'); console.error('Something went wrong');
} }
} else { } else {
this.documents = null; this.documents = [];
} }
this.isFetching = false; this.isFetching = false;

View File

@ -1,15 +1,13 @@
// @flow // @flow
import React, { PropTypes } from 'react'; import React, { Component } from 'react';
import { observer } from 'mobx-react';
import styles from './SearchField.scss'; import styles from './SearchField.scss';
@observer class SearchField extends React.Component { class SearchField extends Component {
static propTypes = { props: {
onChange: PropTypes.func, onChange: Function,
}; };
onChange = (event: SyntheticEvent) => { handleChange = (event: SyntheticEvent) => {
event.currentTarget.value && this.props.onChange(event.currentTarget.value); event.currentTarget.value && this.props.onChange(event.currentTarget.value);
}; };
@ -17,7 +15,8 @@ import styles from './SearchField.scss';
return ( return (
<div className={styles.container}> <div className={styles.container}>
<input <input
onChange={this.onChange} {...this.props}
onChange={this.handleChange}
className={styles.field} className={styles.field}
placeholder="Search" placeholder="Search"
autoFocus autoFocus

View File

@ -0,0 +1,13 @@
// @flow
export function homeUrl() {
return '/dashboard';
}
export function newCollectionUrl() {
return '/collections/new';
}
export function searchUrl(query: string) {
return `/search/${query}`;
}