diff --git a/src/components/SearchFiltersPanel/SearchFiltersPanel.js b/src/components/SearchFiltersPanel/SearchFiltersPanel.js index 103df60c..2d6f019c 100644 --- a/src/components/SearchFiltersPanel/SearchFiltersPanel.js +++ b/src/components/SearchFiltersPanel/SearchFiltersPanel.js @@ -41,10 +41,6 @@ import { createResourceLocatorString } from '../../util/routes'; import { InlineTextButton } from '../../components'; import css from './SearchFiltersPanel.css'; -// Create constants from url params and uset them in FILTERS array and while adding actual filters -// e.g. const MULTI_SELECT_URL_PARAM = 'pub_filterX'; -const FILTERS = []; - class SearchFiltersPanelComponent extends Component { constructor(props) { super(props); @@ -82,9 +78,9 @@ class SearchFiltersPanelComponent extends Component { // Reset all filter query parameters resetAll(e) { - const { urlQueryParams, history, onClosePanel } = this.props; + const { urlQueryParams, customURLParamToConfig, history, onClosePanel } = this.props; - const queryParams = omit(urlQueryParams, FILTERS); + const queryParams = omit(urlQueryParams, Object.keys(customURLParamToConfig)); history.push(createResourceLocatorString('SearchPage', routeConfiguration(), {}, queryParams)); // Ensure that panel closes (if now changes have been made) @@ -161,6 +157,7 @@ SearchFiltersPanelComponent.propTypes = { rootClassName: string, className: string, urlQueryParams: object.isRequired, + customURLParamToConfig: object.isRequired, onClosePanel: func.isRequired, // from injectIntl diff --git a/src/containers/SearchPage/MainPanel.js b/src/containers/SearchPage/MainPanel.js new file mode 100644 index 00000000..c13fc815 --- /dev/null +++ b/src/containers/SearchPage/MainPanel.js @@ -0,0 +1,157 @@ +import React, { Component } from 'react'; +import { array, bool, func, object, number, string } from 'prop-types'; +import { FormattedMessage } from 'react-intl'; +import classNames from 'classnames'; +import { propTypes } from '../../util/types'; +import { + SearchResultsPanel, + SearchFilters, + SearchFiltersMobile, + SearchFiltersPanel, +} from '../../components'; + +import css from './SearchPage.css'; + +class MainPanel extends Component { + constructor(props) { + super(props); + this.state = { isSearchFiltersPanelOpen: false }; + } + + render() { + const { + className, + rootClassName, + urlQueryParams, + listings, + searchInProgress, + searchListingsError, + searchParamsAreInSync, + onActivateListing, + onManageDisableScrolling, + onMapIconClick, + pagination, + searchParamsForPagination, + showAsModalMaxWidth, + customURLParamToConfig, + primaryFilters, + secondaryFilters, + } = this.props; + + const isSearchFiltersPanelOpen = !!secondaryFilters && this.state.isSearchFiltersPanelOpen; + const searchFiltersPanelSelectedCount = !secondaryFilters + ? 0 + : Object.keys(customURLParamToConfig) + .map(key => urlQueryParams[key]) + .filter(param => !!param).length; + + const searchFiltersPanelProps = !!secondaryFilters + ? { + isSearchFiltersPanelOpen: this.state.isSearchFiltersPanelOpen, + toggleSearchFiltersPanel: isOpen => { + this.setState({ isSearchFiltersPanelOpen: isOpen }); + }, + searchFiltersPanelSelectedCount, + } + : {}; + + const hasPaginationInfo = !!pagination && pagination.totalItems != null; + const totalItems = searchParamsAreInSync && hasPaginationInfo ? pagination.totalItems : 0; + const listingsAreLoaded = !searchInProgress && searchParamsAreInSync && hasPaginationInfo; + + const classes = classNames(rootClassName || css.searchResultContainer, className); + + return ( +
+ + + {isSearchFiltersPanelOpen ? ( +
+ this.setState({ isSearchFiltersPanelOpen: false })} + {...secondaryFilters} + /> +
+ ) : ( +
+ {searchListingsError ? ( +

+ +

+ ) : null} + +
+ )} +
+ ); + } +} + +MainPanel.defaultProps = { + className: null, + rootClassName: null, + listings: [], + resultsCount: 0, + pagination: null, + searchParamsForPagination: {}, + primaryFilters: null, + secondaryFilters: null, +}; + +MainPanel.propTypes = { + className: string, + rootClassName: string, + + urlQueryParams: object.isRequired, + listings: array, + searchInProgress: bool.isRequired, + searchListingsError: propTypes.error, + searchParamsAreInSync: bool.isRequired, + onActivateListing: func.isRequired, + onManageDisableScrolling: func.isRequired, + onMapIconClick: func.isRequired, + pagination: propTypes.pagination, + searchParamsForPagination: object, + showAsModalMaxWidth: number.isRequired, + customURLParamToConfig: object.isRequired, + primaryFilters: object, + secondaryFilters: object, +}; + +export default MainPanel; diff --git a/src/containers/SearchPage/README.md b/src/containers/SearchPage/README.md new file mode 100644 index 00000000..1c358224 --- /dev/null +++ b/src/containers/SearchPage/README.md @@ -0,0 +1,71 @@ +# SearchPage + +SearchPage component has roughly 3 sections inside its layout: +Topbar, MainPanel (for results and filters), and Map + +So, rough JSX presentation is something like: +```jsx + + + + + +``` + +Searches can be made by each of these components. + +* Topbar contains location search (LocationAutocompleteInput) +* MainPanel has Filters that can fine-tune current location search +* SearchMap can create new location searches when the map's bounding box changes + (i.e. moving, zooming, etc.) + +## Topbar + +In contrast to other pages, Topbar gets `currentSearchParams` among other props. This makes it +possible for Topbar to take current filters into account. + +## MainPanel + +MainPanel has two functions: showing searchResults and showing filters. There are two sets of +filters that can be passed to it: `primaryFilters`, `secondaryFilters`. + +Primary filters are filters that are shown always on top of SearchResults as dropdown-selections. +We recommend that only 1 - 3 primary filters are passed in since they start to take too much space +on narrow screens. + +Secondary filters create one more button to the space containing primary filters: *More filters*. +This more-filters button opens up a SearchFiltersPanel component that can be changed to show those +extra filters passed to it. +**Note:** Currently, it doesn't contain any filter components by default, even if you pass in some +filter data. Creating those filter components is part of the customization process. + +On the mobile layout, all the filters are shown in separate mobile filters panel. + +## SearchMap + +SearchMap listens to 'idle' event and SearchPage function `onIndle` can create a new location search if +SearchMap's bounds have changed enough. + +## Other things to consider + +### URL Params vs marketplace-custom-config.js + +Filter handling needs some mapping between configured extended data. For example, +*marketplace-custom-config.js* defines all the categories used by the app, but that data needs to be in +format `pub_category=selectedCategory` when we talk with the API. (We also use this format in URL.) + +This mapping is done at the beginning of the file: +``` +const CATEGORY_URL_PARAM = 'pub_category'; +const AMENITIES_URL_PARAM = 'pub_amenities'; + +const customURLParamToConfig = { + [CATEGORY_URL_PARAM]: 'categories', + [AMENITIES_URL_PARAM]: 'amenities', +}; +``` + +### SeachPage schema / SEO + +Schema is created inside `createSearchResultSchema` in *SearchPage.helpers.js*. It needs listings +and address to make meaningful JSON-LD presentation for search engines. diff --git a/src/containers/SearchPage/SearchPage.helpers.js b/src/containers/SearchPage/SearchPage.helpers.js new file mode 100644 index 00000000..d42d2487 --- /dev/null +++ b/src/containers/SearchPage/SearchPage.helpers.js @@ -0,0 +1,98 @@ +import { intersection } from 'lodash'; +import config from '../../config'; +import { createResourceLocatorString } from '../../util/routes'; +import { createSlug } from '../../util/urlHelpers'; +import routeConfiguration from '../../routeConfiguration'; + +// customURLParams +export const validURLParamForExtendedData = (paramKey, urlParams, customConfigKeys) => { + const configKey = customConfigKeys[paramKey]; + const value = urlParams[paramKey]; + const valueArray = value ? value.split(',') : []; + + if (configKey && valueArray.length > 0) { + const allowedValues = config.custom[configKey].map(a => a.key); + const validValues = intersection(valueArray, allowedValues).join(','); + return validValues.length > 0 ? { [paramKey]: validValues } : {}; + } + return {}; +}; + +// validate filter params +export const validURLParamsForExtendedData = (params, customURLParams, customURLParamToConfig) => { + const paramKeys = Object.keys(params); + return paramKeys.reduce((validParams, paramKey) => { + return customURLParams.includes(paramKey) + ? { + ...validParams, + ...validURLParamForExtendedData(paramKey, params, customURLParamToConfig), + } + : { ...validParams, [paramKey]: params[paramKey] }; + }, {}); +}; + +// extract search parameters, including a custom URL params +// which are validated by mapping the values to marketplace custom config. +export const pickSearchParamsOnly = (params, customURLParams, customURLParamToConfig) => { + const { address, origin, bounds, country, ...rest } = params || {}; + const boundsMaybe = bounds ? { bounds } : {}; + const originMaybe = config.sortSearchByDistance && origin ? { origin } : {}; + + const customSearchParamKeys = Object.keys(rest); + const customSearchParams = customSearchParamKeys.reduce((validParams, paramKey) => { + return customURLParams.includes(paramKey) + ? { ...validParams, ...validURLParamForExtendedData(paramKey, rest, customURLParamToConfig) } + : { ...validParams }; + }, {}); + + return { + ...boundsMaybe, + ...originMaybe, + ...customSearchParams, + }; +}; + +export const createSearchResultSchema = (listings, address, intl) => { + // Schema for search engines (helps them to understand what this page is about) + // http://schema.org + // We are using JSON-LD format + const siteTitle = config.siteTitle; + const searchAddress = address || intl.formatMessage({ id: 'SearchPage.schemaMapSearch' }); + const schemaDescription = intl.formatMessage({ id: 'SearchPage.schemaDescription' }); + const schemaTitle = intl.formatMessage( + { id: 'SearchPage.schemaTitle' }, + { searchAddress, siteTitle } + ); + + const schemaListings = listings.map((l, i) => { + const title = l.attributes.title; + const pathToItem = createResourceLocatorString('ListingPage', routeConfiguration(), { + id: l.id.uuid, + slug: createSlug(title), + }); + return { + '@type': 'ListItem', + position: i, + url: `${config.canonicalRootURL}${pathToItem}`, + name: title, + }; + }); + + const schemaMainEntity = JSON.stringify({ + '@type': 'ItemList', + name: searchAddress, + itemListOrder: 'http://schema.org/ItemListOrderAscending', + itemListElement: schemaListings, + }); + return { + title: schemaTitle, + description: schemaDescription, + schema: { + '@context': 'http://schema.org', + '@type': 'SearchResultsPage', + description: schemaDescription, + name: schemaTitle, + mainEntity: [schemaMainEntity], + }, + }; +}; diff --git a/src/containers/SearchPage/SearchPage.js b/src/containers/SearchPage/SearchPage.js index 6d1bacf1..ccd92167 100644 --- a/src/containers/SearchPage/SearchPage.js +++ b/src/containers/SearchPage/SearchPage.js @@ -1,10 +1,10 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; -import { FormattedMessage, injectIntl, intlShape } from 'react-intl'; +import { injectIntl, intlShape } from 'react-intl'; import { connect } from 'react-redux'; import { compose } from 'redux'; import { withRouter } from 'react-router-dom'; -import { debounce, intersection, isEqual, unionWith } from 'lodash'; +import { debounce, isEqual, unionWith } from 'lodash'; import classNames from 'classnames'; import config from '../../config'; import routeConfiguration from '../../routeConfiguration'; @@ -15,85 +15,37 @@ import { hasSameSDKBounds, } from '../../util/googleMaps'; import { createResourceLocatorString } from '../../util/routes'; -import { createSlug, parse, stringify } from '../../util/urlHelpers'; +import { parse, stringify } from '../../util/urlHelpers'; import { propTypes } from '../../util/types'; import { getListingsById } from '../../ducks/marketplaceData.duck'; import { manageDisableScrolling, isScrollingDisabled } from '../../ducks/UI.duck'; -import { - SearchMap, - ModalInMobile, - Page, - SearchResultsPanel, - SearchFilters, - SearchFiltersMobile, - SearchFiltersPanel, -} from '../../components'; +import { SearchMap, ModalInMobile, Page } from '../../components'; import { TopbarContainer } from '../../containers'; -import { searchListings, searchMapListings, setActiveListing } from './SearchPage.duck'; +import { searchListings, searchMapListings, setActiveListing } from './SearchPage.duck'; +import { + pickSearchParamsOnly, + validURLParamForExtendedData, + validURLParamsForExtendedData, + createSearchResultSchema, +} from './SearchPage.helpers'; +import MainPanel from './MainPanel'; import css from './SearchPage.css'; // Pagination page size might need to be dynamic on responsive page layouts // Current design has max 3 columns 12 is divisible by 2 and 3 // So, there's enough cards to fill all columns on full pagination pages const RESULT_PAGE_SIZE = 24; -const MAX_SEARCH_RESULT_PAGE_SIZE_ON_MAP = 80; // max page size is 100 in API -const MAX_SEARCH_RESULT_PAGES_ON_MAP = 1; // page size * n pages = number of listings shown on a map. const MODAL_BREAKPOINT = 768; // Search is in modal on mobile layout const SEARCH_WITH_MAP_DEBOUNCE = 300; // Little bit of debounce before search is initiated. const BOUNDS_FIXED_PRECISION = 8; const CATEGORY_URL_PARAM = 'pub_category'; const AMENITIES_URL_PARAM = 'pub_amenities'; -const USE_SEARCH_FILTER_PANEL = false; -// Find correct extended data key from config.custom -// e.g. 'pub_category' -> 'categories'. -const customConfigKey = paramKey => { - switch (paramKey) { - case CATEGORY_URL_PARAM: - return 'categories'; - case AMENITIES_URL_PARAM: - return 'amenities'; - default: - return null; - } -}; - -const validURLParamForExtendedData = (paramKey, urlParams) => { - const configKey = customConfigKey(paramKey); - const value = urlParams[paramKey]; - const valueArray = value ? value.split(',') : []; - - if (configKey && valueArray.length > 0) { - const allowedValues = config.custom[configKey].map(a => a.key); - const validValues = intersection(valueArray, allowedValues).join(','); - return validValues.length > 0 ? { [paramKey]: validValues } : {}; - } - return {}; -}; - -// validate filter params -const validURLParamsForExtendedData = params => { - const { [CATEGORY_URL_PARAM]: category, [AMENITIES_URL_PARAM]: amenities, ...rest } = params; - return { - ...rest, - ...validURLParamForExtendedData(CATEGORY_URL_PARAM, params), - ...validURLParamForExtendedData(AMENITIES_URL_PARAM, params), - }; -}; - -// extract search parameters, including a custom attribute named category -const pickSearchParamsOnly = params => { - const { address, origin, bounds, country, ...rest } = params || {}; - const boundsMaybe = bounds ? { bounds } : {}; - const originMaybe = config.sortSearchByDistance && origin ? { origin } : {}; - return { - ...boundsMaybe, - ...originMaybe, - ...validURLParamForExtendedData(CATEGORY_URL_PARAM, rest), - ...validURLParamForExtendedData(AMENITIES_URL_PARAM, rest), - }; +const customURLParamToConfig = { + [CATEGORY_URL_PARAM]: 'categories', + [AMENITIES_URL_PARAM]: 'amenities', }; export class SearchPageComponent extends Component { @@ -103,7 +55,6 @@ export class SearchPageComponent extends Component { this.state = { isSearchMapOpenOnMobile: props.tab === 'map', isMobileModalOpen: false, - isSearchFiltersPanelOpen: false, }; // Initiating map creates 'bounds_changes' event @@ -116,19 +67,12 @@ export class SearchPageComponent extends Component { this.searchMapListingsInProgress = false; this.onIdle = debounce(this.onIdle.bind(this), SEARCH_WITH_MAP_DEBOUNCE); - this.fetchMoreListingsToMap = this.fetchMoreListingsToMap.bind(this); this.onOpenMobileModal = this.onOpenMobileModal.bind(this); this.onCloseMobileModal = this.onCloseMobileModal.bind(this); } - componentDidMount() { - this.fetchMoreListingsToMap(this.props.location); - } - componentWillReceiveProps(nextProps) { if (!isEqual(this.props.location, nextProps.location)) { - this.fetchMoreListingsToMap(nextProps.location); - // If no mapSearch url parameter is given, this is original location search const { mapSearch } = parse(nextProps.location.search, { latlng: ['origin'], @@ -175,8 +119,8 @@ export class SearchPageComponent extends Component { bounds: viewportBounds, country, mapSearch: true, - ...validURLParamForExtendedData(CATEGORY_URL_PARAM, rest), - ...validURLParamForExtendedData(AMENITIES_URL_PARAM, rest), + ...validURLParamForExtendedData(CATEGORY_URL_PARAM, rest, customURLParamToConfig), + ...validURLParamForExtendedData(AMENITIES_URL_PARAM, rest, customURLParamToConfig), }; this.viewportBounds = viewportBounds; history.push( @@ -188,52 +132,6 @@ export class SearchPageComponent extends Component { } } - fetchMoreListingsToMap(location) { - // TODO Remove this function. - // Temporarily just return immediately to avoid merge conflicts. - return; - - // eslint-disable-next-line no-unreachable - const { onSearchMapListings } = this.props; - const searchInURL = parse(location.search, { - latlng: ['origin'], - latlngBounds: ['bounds'], - }); - - const perPage = MAX_SEARCH_RESULT_PAGE_SIZE_ON_MAP; - const page = 1; - const { address, country, origin, ...rest } = searchInURL; - const originMaybe = config.sortSearchByDistance ? { origin } : {}; - const searchParamsForMapResults = { - ...rest, - ...originMaybe, - include: ['images'], - page, - perPage, - 'fields.image': ['variants.landscape-crop', 'variants.landscape-crop2x'], - 'limit.images': 1, - }; - this.searchMapListingsInProgress = true; - - // Search more listings for map - onSearchMapListings(searchParamsForMapResults) - .then(response => { - const hasNextPage = - page < response.data.meta.totalPages && page < MAX_SEARCH_RESULT_PAGES_ON_MAP; - if (hasNextPage) { - onSearchMapListings({ ...searchParamsForMapResults, page: page + 1 }); - } else { - this.searchMapListingsInProgress = false; - } - }) - .catch(error => { - // In case of error, stop recursive loop and report error. - // TODO: Show and error in the listings column - // eslint-disable-next-line no-console - console.error(`An error (${error} occured while trying to retrieve map listings`); - }); - } - // Invoked when a modal is opened from a child component, // for example when a filter modal is opened in mobile view onOpenMobileModal() { @@ -271,77 +169,33 @@ export class SearchPageComponent extends Component { // urlQueryParams doesn't contain page specific url params // like mapSearch, page or origin (origin depends on config.sortSearchByDistance) - const urlQueryParams = pickSearchParamsOnly(searchInURL); + const urlQueryParams = pickSearchParamsOnly( + searchInURL, + [AMENITIES_URL_PARAM, CATEGORY_URL_PARAM], + customURLParamToConfig + ); // Page transition might initially use values from previous search const urlQueryString = stringify(urlQueryParams); - const paramsQueryString = stringify(pickSearchParamsOnly(searchParams)); - const searchParamsMatch = urlQueryString === paramsQueryString; + const paramsQueryString = stringify( + pickSearchParamsOnly( + searchParams, + [AMENITIES_URL_PARAM, CATEGORY_URL_PARAM], + customURLParamToConfig + ) + ); + const searchParamsAreInSync = urlQueryString === paramsQueryString; - const { address, bounds, origin } = searchInURL || {}; - - const hasPaginationInfo = !!pagination && pagination.totalItems != null; - const totalItems = searchParamsMatch && hasPaginationInfo ? pagination.totalItems : 0; - const listingsAreLoaded = !searchInProgress && searchParamsMatch && hasPaginationInfo; - - const validQueryParams = validURLParamsForExtendedData(searchInURL); - - const searchError = ( -

- -

+ const validQueryParams = validURLParamsForExtendedData( + searchInURL, + [AMENITIES_URL_PARAM, CATEGORY_URL_PARAM], + customURLParamToConfig ); - const searchMap = ( - { - onManageDisableScrolling('SearchPage.map', false); - }} - useLocationSearchBounds={!this.viewportBounds} - /> - ); - const showSearchMapInMobile = this.state.isSearchMapOpenOnMobile ? searchMap : null; const isWindowDefined = typeof window !== 'undefined'; - const searchMapMaybe = - isWindowDefined && window.innerWidth < MODAL_BREAKPOINT ? showSearchMapInMobile : searchMap; - - const searchParamsForPagination = parse(location.search); - - // Schema for search engines (helps them to understand what this page is about) - // http://schema.org - // We are using JSON-LD format - const siteTitle = config.siteTitle; - const searchAddress = address || intl.formatMessage({ id: 'SearchPage.schemaMapSearch' }); - const schemaTitle = intl.formatMessage( - { id: 'SearchPage.schemaTitle' }, - { searchAddress, siteTitle } - ); - const schemaDescription = intl.formatMessage({ id: 'SearchPage.schemaDescription' }); - const schemaListings = listings.map((l, i) => { - const title = l.attributes.title; - const pathToItem = createResourceLocatorString('ListingPage', routeConfiguration(), { - id: l.id.uuid, - slug: createSlug(title), - }); - return { - '@type': 'ListItem', - position: i, - url: `${config.canonicalRootURL}${pathToItem}`, - name: title, - }; - }); - const schemaMainEntity = JSON.stringify({ - '@type': 'ItemList', - name: searchAddress, - itemListOrder: 'http://schema.org/ItemListOrderAscending', - itemListElement: schemaListings, - }); + const isMobileLayout = isWindowDefined && window.innerWidth < MODAL_BREAKPOINT; + const shouldShowSearchMap = + !isMobileLayout || (isMobileLayout && this.state.isSearchMapOpenOnMobile); const onMapIconClick = () => { this.useLocationSearchBounds = true; @@ -349,51 +203,8 @@ export class SearchPageComponent extends Component { this.setState({ isSearchMapOpenOnMobile: true }); }; - const extraSearchFiltersPanelOrListings = - USE_SEARCH_FILTER_PANEL && this.state.isSearchFiltersPanelOpen ? ( -
- this.setState({ isSearchFiltersPanelOpen: false })} - /> -
- ) : ( -
- {searchListingsError ? searchError : null} - -
- ); - - // An example how to check how many filters are selected on SearchFilterPanel - // if it is in use. - // - // const searchFiltersPanelSelectedCount = [ - // validQueryParams[FILTER_1_URL_PARAM], - // validQueryParams[FILTER_2_URL_PARAM], - // ].filter(param => !!param).length - const searchFiltersPanelSelectedCount = 0; - const searchFiltersPanelProps = USE_SEARCH_FILTER_PANEL - ? { - isSearchFiltersPanelOpen: this.state.isSearchFiltersPanelOpen, - toggleSearchFiltersPanel: isOpen => { - this.setState({ isSearchFiltersPanelOpen: isOpen }); - }, - searchFiltersPanelSelectedCount, - } - : {}; + const { address, bounds, origin } = searchInURL || {}; + const { title, description, schema } = createSearchResultSchema(listings, address, intl); // Set topbar class based on if a modal is open in // a child component @@ -407,15 +218,9 @@ export class SearchPageComponent extends Component { return (
-
- - - {extraSearchFiltersPanelOrListings} -
+ -
{searchMapMaybe}
+
+ {shouldShowSearchMap ? ( + { + onManageDisableScrolling('SearchPage.map', false); + }} + useLocationSearchBounds={!this.viewportBounds} + /> + ) : null} +
@@ -487,6 +293,7 @@ const { array, bool, func, oneOf, object, shape, string } = PropTypes; SearchPageComponent.propTypes = { listings: array, mapListings: array, + onActivateListing: func.isRequired, onManageDisableScrolling: func.isRequired, onSearchMapListings: func.isRequired, pagination: propTypes.pagination, diff --git a/src/containers/SearchPage/SearchPage.test.js b/src/containers/SearchPage/SearchPage.test.js index aa38bfc9..9b7a35e4 100644 --- a/src/containers/SearchPage/SearchPage.test.js +++ b/src/containers/SearchPage/SearchPage.test.js @@ -36,6 +36,7 @@ describe('SearchPageComponent', () => { currentUserHasListings: false, intl: fakeIntl, isAuthenticated: false, + onActivateListing: noop, onLogout: noop, onManageDisableScrolling: noop, onSearchMapListings: noop, diff --git a/src/containers/SearchPage/__snapshots__/SearchPage.test.js.snap b/src/containers/SearchPage/__snapshots__/SearchPage.test.js.snap index 2c6d9c8f..df9d474c 100644 --- a/src/containers/SearchPage/__snapshots__/SearchPage.test.js.snap +++ b/src/containers/SearchPage/__snapshots__/SearchPage.test.js.snap @@ -22,10 +22,29 @@ exports[`SearchPageComponent matches snapshot 1`] = ` currentSearchParams={Object {}} />
-
- - -
- -
-
+ } + showAsModalMaxWidth={768} + urlQueryParams={Object {}} + />