"dependencies": {
"@material-ui/core": "3.1.2",
"@material-ui/icons": "3.0.1",
+ "@types/debounce": "3.0.0",
"@types/js-yaml": "3.11.2",
"@types/lodash": "4.14.116",
"@types/react-copy-to-clipboard": "4.2.6",
"axios": "0.18.0",
"classnames": "2.2.6",
"cwlts": "1.15.29",
+ "debounce": "1.2.0",
"js-yaml": "3.12.0",
"lodash": "4.17.11",
"react": "16.5.2",
import { snackbarActions, SnackbarKind } from '~/store/snackbar/snackbar-actions';
import { initialize } from 'redux-form';
import { SearchBarAdvanceFormData, PropertyValues } from '~/models/search-bar';
+import { debounce } from 'debounce';
export const searchBarActions = unionize({
SET_CURRENT_VIEW: ofType<string>(),
export const SEARCH_BAR_ADVANCE_FORM_PICKER_ID = 'searchBarAdvanceFormPickerId';
+export const DEFAULT_SEARCH_DEBOUNCE = 1000;
+
export const goToView = (currentView: string) => searchBarActions.SET_CURRENT_VIEW(currentView);
export const saveRecentQuery = (query: string) =>
};
+export const changeData = (searchValue: string) =>
+ (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
+ dispatch(searchBarActions.SET_SEARCH_VALUE(searchValue));
+ if (searchValue.length > 0) {
+ dispatch<any>(goToView(SearchView.AUTOCOMPLETE));
+ } else {
+ dispatch<any>(goToView(SearchView.BASIC));
+ }
+ debounceStartSearch(dispatch);
+ };
+
+const debounceStartSearch = debounce((dispatch: Dispatch) => dispatch<any>(startSearch()), DEFAULT_SEARCH_DEBOUNCE);
+
+const startSearch = () =>
+ (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
+ const searchValue = getState().searchBar.searchValue;
+ if (searchValue.length > 0) {
+ dispatch<any>(searchData(searchValue));
+ } else {
+ dispatch(searchBarActions.SET_SEARCH_VALUE(searchValue));
+ dispatch(searchBarActions.SET_SEARCH_RESULTS([]));
+ }
+ };
+
+export const submitData = (event: React.FormEvent<HTMLFormElement>) =>
+ (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
+ event.preventDefault();
+ const searchValue = getState().searchBar.searchValue;
+ dispatch<any>(saveRecentQuery(searchValue));
+ dispatch<any>(searchDataOnEnter(searchValue));
+ dispatch<any>(loadRecentQueries());
+ };
+
export const searchDataOnEnter = (searchValue: string) =>
async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
dispatch(searchBarActions.CLOSE_SEARCH_VIEW());
import { GroupContentsResource } from '~/services/groups-service/groups-service';
import Highlighter from "react-highlight-words";
-type CssRules = 'list' | 'searchView';
+type CssRules = 'searchView' | 'list' | 'listItem';
const styles: StyleRulesCallback<CssRules> = theme => {
return {
+ searchView: {
+ borderRadius: `0 0 ${theme.spacing.unit / 2}px ${theme.spacing.unit / 2}px`
+ },
list: {
padding: 0
},
- searchView: {
- borderRadius: `0 0 ${theme.spacing.unit / 2}px ${theme.spacing.unit / 2}px`
- }
+ listItem: {
+ paddingLeft: theme.spacing.unit,
+ paddingRight: theme.spacing.unit * 2,
+ },
+
};
};
<Paper className={classes.searchView}>
{searchResults && <List component="nav" className={classes.list}>
{searchResults.map((item: GroupContentsResource) =>
- <ListItem button key={item.uuid}>
+ <ListItem button key={item.uuid} className={classes.listItem}>
<ListItemText secondary={getFormattedText(item.name, searchValue)} onClick={() => navigateTo(item.uuid)} />
</ListItem>
)}
& SearchBarBasicViewDataProps;
interface SearchBarViewDataProps {
+ searchValue: string;
currentView: string;
isPopoverOpen: boolean;
debounce?: number;
& SearchBarBasicViewActionProps;
interface SearchBarViewActionProps {
- onSearch: (value: string) => any;
- searchDataOnEnter: (value: string) => void;
+ onChange: (event: React.ChangeEvent<HTMLInputElement>) => void;
+ onSubmit: (event: React.FormEvent<HTMLFormElement>) => void;
onSetView: (currentView: string) => void;
closeView: () => void;
openSearchView: () => void;
- saveRecentQuery: (query: string) => void;
loadRecentQueries: () => string[];
}
type SearchBarViewProps = SearchBarDataProps & SearchBarActionProps & WithStyles<CssRules>;
-interface SearchBarState {
- value: string;
-}
-
-export const DEFAULT_SEARCH_DEBOUNCE = 1000;
-
export const SearchBarView = withStyles(styles)(
- class extends React.Component<SearchBarViewProps> {
- state: SearchBarState = {
- value: ""
- };
-
- timeout: number;
-
- render() {
- const { classes, currentView, openSearchView, closeView, isPopoverOpen } = this.props;
- return <ClickAwayListener onClickAway={closeView}>
+ (props : SearchBarViewProps) => {
+ const { classes, isPopoverOpen, closeView, searchValue, openSearchView, onChange, onSubmit } = props;
+ return (
+ <ClickAwayListener onClickAway={closeView}>
<Paper className={isPopoverOpen ? classes.containerSearchViewOpened : classes.container} >
- <form onSubmit={this.handleSubmit}>
+ <form onSubmit={onSubmit}>
<Input
className={classes.input}
- onChange={this.handleChange}
+ onChange={onChange}
placeholder="Search"
- value={this.state.value}
+ value={searchValue}
fullWidth={true}
disableUnderline={true}
onClick={openSearchView}
} />
</form>
<div className={classes.view}>
- {isPopoverOpen && this.getView(currentView)}
+ {isPopoverOpen && getView({...props})}
</div>
</Paper >
- </ClickAwayListener>;
- }
-
- componentDidMount() {
- this.setState({ value: this.props.searchValue });
- }
-
- componentWillReceiveProps(nextProps: SearchBarViewProps) {
- if (nextProps.searchValue !== this.props.searchValue) {
- this.setState({ value: nextProps.searchValue });
- }
- }
-
- componentWillUnmount() {
- clearTimeout(this.timeout);
- }
-
- getView = (currentView: string) => {
- const { onSetView, loadRecentQueries, savedQueries, deleteSavedQuery, searchValue,
- searchResults, saveQuery, onSearch, navigateTo, editSavedQuery, tags } = this.props;
- switch (currentView) {
- case SearchView.AUTOCOMPLETE:
- return <SearchBarAutocompleteView
- navigateTo={navigateTo}
- searchResults={searchResults}
- searchValue={searchValue} />;
- case SearchView.ADVANCED:
- return <SearchBarAdvancedView
- onSetView={onSetView}
- saveQuery={saveQuery}
- tags={tags} />;
- default:
- return <SearchBarBasicView
- onSetView={onSetView}
- onSearch={onSearch}
- loadRecentQueries={loadRecentQueries}
- savedQueries={savedQueries}
- deleteSavedQuery={deleteSavedQuery}
- editSavedQuery={editSavedQuery} />;
- }
- }
-
- handleSubmit = (event: React.FormEvent<HTMLFormElement>) => {
- event.preventDefault();
- clearTimeout(this.timeout);
- this.props.saveRecentQuery(this.state.value);
- this.props.searchDataOnEnter(this.state.value);
- this.props.loadRecentQueries();
- }
-
- // ToDo: nie pokazywac autocomplete jezeli jestesmy w advance
- // currentView ze state.searchBar.currentView
- handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
- clearTimeout(this.timeout);
- this.setState({ value: event.target.value });
- this.timeout = window.setTimeout(
- () => this.props.onSearch(this.state.value),
- this.props.debounce || DEFAULT_SEARCH_DEBOUNCE
- );
- if (event.target.value.length > 0) {
- this.props.onSetView(SearchView.AUTOCOMPLETE);
- } else {
- this.props.onSetView(SearchView.BASIC);
- }
- }
+ </ClickAwayListener>
+ );
}
);
+
+const getView = (props: SearchBarViewProps) => {
+ const { onSetView, loadRecentQueries, savedQueries, deleteSavedQuery, searchValue,
+ searchResults, saveQuery, onSearch, navigateTo, editSavedQuery, tags, currentView } = props;
+ switch (currentView) {
+ case SearchView.AUTOCOMPLETE:
+ return <SearchBarAutocompleteView
+ navigateTo={navigateTo}
+ searchResults={searchResults}
+ searchValue={searchValue} />;
+ case SearchView.ADVANCED:
+ return <SearchBarAdvancedView
+ onSetView={onSetView}
+ saveQuery={saveQuery}
+ tags={tags} />;
+ default:
+ return <SearchBarBasicView
+ onSetView={onSetView}
+ onSearch={onSearch}
+ loadRecentQueries={loadRecentQueries}
+ savedQueries={savedQueries}
+ deleteSavedQuery={deleteSavedQuery}
+ editSavedQuery={editSavedQuery} />;
+ }
+};
closeSearchView,
navigateToItem,
editSavedQuery,
- searchDataOnEnter
+ searchDataOnEnter,
+ changeData,
+ submitData
} from '~/store/search-bar/search-bar-actions';
import { SearchBarView, SearchBarActionProps, SearchBarDataProps } from '~/views-components/search-bar/search-bar-view';
import { SearchBarAdvanceFormData } from '~/models/search-bar';
const mapDispatchToProps = (dispatch: Dispatch): SearchBarActionProps => ({
onSearch: (valueSearch: string) => dispatch<any>(searchData(valueSearch)),
+ onChange: (event: React.ChangeEvent<HTMLInputElement>) => dispatch<any>(changeData(event.target.value)),
onSetView: (currentView: string) => dispatch(goToView(currentView)),
+ onSubmit: (event: React.FormEvent<HTMLFormElement>) => dispatch<any>(submitData(event)),
closeView: () => dispatch<any>(closeSearchView()),
- saveRecentQuery: (query: string) => dispatch<any>(saveRecentQuery(query)),
loadRecentQueries: () => dispatch<any>(loadRecentQueries()),
saveQuery: (data: SearchBarAdvanceFormData) => dispatch<any>(saveQuery(data)),
deleteSavedQuery: (id: number) => dispatch<any>(deleteSavedQuery(id)),
openSearchView: () => dispatch<any>(openSearchView()),
navigateTo: (uuid: string) => dispatch<any>(navigateToItem(uuid)),
- editSavedQuery: (data: SearchBarAdvanceFormData) => dispatch<any>(editSavedQuery(data)),
- searchDataOnEnter: (searchValue: string) => dispatch<any>(searchDataOnEnter(searchValue))
+ editSavedQuery: (data: SearchBarAdvanceFormData) => dispatch<any>(editSavedQuery(data))
});
export const SearchBar = connect(mapStateToProps, mapDispatchToProps)(SearchBarView);
\ No newline at end of file
version "2.2.6"
resolved "https://registry.yarnpkg.com/@types/classnames/-/classnames-2.2.6.tgz#dbe8a666156d556ed018e15a4c65f08937c3f628"
+"@types/debounce@3.0.0":
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/@types/debounce/-/debounce-3.0.0.tgz#ea4290f6e2d7ab99464c93b4a69b843d0993b181"
+
"@types/enzyme-adapter-react-16@1.0.3":
version "1.0.3"
resolved "https://registry.yarnpkg.com/@types/enzyme-adapter-react-16/-/enzyme-adapter-react-16-1.0.3.tgz#0cf7025b036694ca8d596fe38f24162e7117acf1"
version "0.1.4"
resolved "https://registry.yarnpkg.com/date-now/-/date-now-0.1.4.tgz#eaf439fd4d4848ad74e5cc7dbef200672b9e345b"
-debounce@^1.1.0:
+debounce@1.2.0, debounce@^1.1.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/debounce/-/debounce-1.2.0.tgz#44a540abc0ea9943018dc0eaa95cce87f65cd131"