feat(client): use url query param on search page
This commit is contained in:
committed by
Mrugesh Mohapatra
parent
aee2f5e536
commit
84c46750e8
@@ -132,7 +132,6 @@ class DefaultLayout extends Component {
|
||||
isSignedIn,
|
||||
landingPage,
|
||||
navigationMenu,
|
||||
pathname,
|
||||
removeFlashMessage,
|
||||
showFooter = true
|
||||
} = this.props;
|
||||
@@ -151,7 +150,7 @@ class DefaultLayout extends Component {
|
||||
>
|
||||
<style>{fontawesome.dom.css()}</style>
|
||||
</Helmet>
|
||||
<WithInstantSearch pathname={pathname}>
|
||||
<WithInstantSearch>
|
||||
<Header
|
||||
disableSettings={landingPage}
|
||||
navigationMenu={navigationMenu}
|
||||
|
@@ -1,7 +1,9 @@
|
||||
import React, { Component } from 'react';
|
||||
import { Location } from '@reach/router';
|
||||
import PropTypes from 'prop-types';
|
||||
import { connect } from 'react-redux';
|
||||
import { InstantSearch, Configure } from 'react-instantsearch-dom';
|
||||
import qs from 'query-string';
|
||||
|
||||
import {
|
||||
isSearchDropdownEnabledSelector,
|
||||
@@ -15,7 +17,7 @@ import { createSelector } from 'reselect';
|
||||
const propTypes = {
|
||||
children: PropTypes.any,
|
||||
isDropdownEnabled: PropTypes.bool,
|
||||
pathname: PropTypes.string.isRequired,
|
||||
location: PropTypes.object.isRequired,
|
||||
query: PropTypes.string,
|
||||
toggleSearchDropdown: PropTypes.func.isRequired,
|
||||
updateSearchQuery: PropTypes.func.isRequired
|
||||
@@ -31,33 +33,71 @@ const mapDispatchToProps = {
|
||||
updateSearchQuery
|
||||
};
|
||||
|
||||
class WithInstantSearch extends Component {
|
||||
const searchStateToUrl = ({ pathname }, query) =>
|
||||
`${pathname}${query ? `?${qs.stringify({ query })}` : ''}`;
|
||||
|
||||
const urlToSearchState = ({ search }) => qs.parse(search.slice(1));
|
||||
|
||||
class InstantSearchRoot extends Component {
|
||||
componentDidMount() {
|
||||
const { toggleSearchDropdown } = this.props;
|
||||
toggleSearchDropdown(this.getSearchEnableDropdown());
|
||||
toggleSearchDropdown(!this.isSearchPage());
|
||||
this.setQueryFromURL();
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
const { pathname, toggleSearchDropdown, isDropdownEnabled } = this.props;
|
||||
const { pathname: prevPathname } = prevProps;
|
||||
const enableDropdown = this.getSearchEnableDropdown();
|
||||
if (pathname !== prevPathname || isDropdownEnabled !== enableDropdown) {
|
||||
const { location, toggleSearchDropdown, isDropdownEnabled } = this.props;
|
||||
|
||||
const enableDropdown = !this.isSearchPage();
|
||||
if (isDropdownEnabled !== enableDropdown) {
|
||||
toggleSearchDropdown(enableDropdown);
|
||||
}
|
||||
const { query, updateSearchQuery } = this.props;
|
||||
if (query && pathname !== prevPathname && enableDropdown) {
|
||||
updateSearchQuery('');
|
||||
|
||||
if (location !== prevProps.location) {
|
||||
const { query, updateSearchQuery } = this.props;
|
||||
if (this.isSearchPage()) {
|
||||
this.setQueryFromURL();
|
||||
} else if (query) {
|
||||
updateSearchQuery('');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getSearchEnableDropdown = () => !this.props.pathname.startsWith('/search');
|
||||
isSearchPage = () => this.props.location.pathname.startsWith('/search');
|
||||
|
||||
setQueryFromURL = () => {
|
||||
if (this.isSearchPage()) {
|
||||
const { updateSearchQuery, location, query } = this.props;
|
||||
const { query: queryFromURL } = urlToSearchState(location);
|
||||
if (query !== queryFromURL) {
|
||||
updateSearchQuery(queryFromURL);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
onSearchStateChange = ({ query }) => {
|
||||
const { updateSearchQuery, query: propsQuery } = this.props;
|
||||
if (propsQuery === query || typeof query === 'undefined') {
|
||||
return null;
|
||||
return;
|
||||
}
|
||||
updateSearchQuery(query);
|
||||
this.updateBrowserHistory(query);
|
||||
};
|
||||
|
||||
updateBrowserHistory = query => {
|
||||
if (this.isSearchPage()) {
|
||||
clearTimeout(this.debouncedSetState);
|
||||
|
||||
this.debouncedSetState = setTimeout(() => {
|
||||
if (this.isSearchPage()) {
|
||||
window.history.pushState(
|
||||
{ query },
|
||||
null,
|
||||
searchStateToUrl(this.props.location, query)
|
||||
);
|
||||
}
|
||||
}, 400);
|
||||
}
|
||||
return updateSearchQuery(query);
|
||||
};
|
||||
|
||||
render() {
|
||||
@@ -77,10 +117,25 @@ class WithInstantSearch extends Component {
|
||||
}
|
||||
}
|
||||
|
||||
WithInstantSearch.displayName = 'WithInstantSearch';
|
||||
WithInstantSearch.propTypes = propTypes;
|
||||
InstantSearchRoot.displayName = 'InstantSearchRoot';
|
||||
InstantSearchRoot.propTypes = propTypes;
|
||||
|
||||
export default connect(
|
||||
const InstantSearchRootConnected = connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(WithInstantSearch);
|
||||
)(InstantSearchRoot);
|
||||
|
||||
const WithInstantSearch = ({ children }) => (
|
||||
<Location>
|
||||
{({ location }) => (
|
||||
<InstantSearchRootConnected location={location}>
|
||||
{children}
|
||||
</InstantSearchRootConnected>
|
||||
)}
|
||||
</Location>
|
||||
);
|
||||
|
||||
WithInstantSearch.displayName = 'WithInstantSearch';
|
||||
WithInstantSearch.propTypes = { children: PropTypes.any };
|
||||
|
||||
export default WithInstantSearch;
|
||||
|
@@ -85,7 +85,7 @@ class SearchBar extends Component {
|
||||
if (query) {
|
||||
updateSearchQuery(query);
|
||||
}
|
||||
return navigate('/search');
|
||||
return navigate(`/search${query ? `?query=${query}` : ''}`);
|
||||
}
|
||||
|
||||
render() {
|
||||
|
@@ -1,5 +1,6 @@
|
||||
import React, { Fragment, Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import Helmet from 'react-helmet';
|
||||
import { connect } from 'react-redux';
|
||||
import { Index, PoweredBy } from 'react-instantsearch-dom';
|
||||
import { Grid, Row, Col } from '@freecodecamp/react-bootstrap';
|
||||
@@ -18,6 +19,7 @@ class SearchPage extends Component {
|
||||
render() {
|
||||
return (
|
||||
<Fragment>
|
||||
<Helmet title='Search | freeCodeCamp.org' />
|
||||
<Index indexName='challenges' />
|
||||
<Index indexName='guides' />
|
||||
<Index indexName='youtube' />
|
||||
|
Reference in New Issue
Block a user