Skip to content

Commit

Permalink
Merge pull request #1275 from sharetribe/reorganize-default-search-fi…
Browse files Browse the repository at this point in the history
…lters

Reorganize default search filters
  • Loading branch information
kpuputti committed Mar 25, 2020
2 parents 4790b98 + 6bb749a commit 2ea7ffa
Show file tree
Hide file tree
Showing 7 changed files with 87 additions and 117 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ way to update this template, but currently, we follow a pattern:

## Upcoming version 2020-XX-XX

- [change] Move category and amenities search filters from primary filters to secondary filters. [#1275](https://github.com/sharetribe/ftw-daily/pull/1275)

## [v4.3.0] 2020-03-16

- [change] Redirect user back to Stripe during Connect Onboarding Flow when user is returned to
Expand Down
82 changes: 1 addition & 81 deletions src/components/SearchFilters/SearchFilters.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,7 @@ import classNames from 'classnames';
import { withRouter } from 'react-router-dom';
import omit from 'lodash/omit';

import {
BookingDateRangeFilter,
SelectSingleFilter,
SelectMultipleFilter,
PriceFilter,
KeywordFilter,
} from '../../components';
import { BookingDateRangeFilter, PriceFilter, KeywordFilter } from '../../components';
import routeConfiguration from '../../routeConfiguration';
import { parseDateFromISO8601, stringifyDateToISO8601 } from '../../util/dates';
import { createResourceLocatorString } from '../../util/routes';
Expand All @@ -28,11 +22,6 @@ const initialValue = (queryParams, paramName) => {
return queryParams[paramName];
};

// resolve initial values for a multi value filter
const initialValues = (queryParams, paramName) => {
return !!queryParams[paramName] ? queryParams[paramName].split(',') : [];
};

const initialPriceRangeValue = (queryParams, paramName) => {
const price = queryParams[paramName];
const valuesFromParams = !!price ? price.split(',').map(v => Number.parseInt(v, RADIX)) : [];
Expand Down Expand Up @@ -67,8 +56,6 @@ const SearchFiltersComponent = props => {
listingsAreLoaded,
resultsCount,
searchInProgress,
categoryFilter,
amenitiesFilter,
priceFilter,
dateRangeFilter,
keywordFilter,
Expand All @@ -82,26 +69,10 @@ const SearchFiltersComponent = props => {
const hasNoResult = listingsAreLoaded && resultsCount === 0;
const classes = classNames(rootClassName || css.root, { [css.longInfo]: hasNoResult }, className);

const categoryLabel = intl.formatMessage({
id: 'SearchFilters.categoryLabel',
});

const amenitiesLabel = intl.formatMessage({
id: 'SearchFilters.amenitiesLabel',
});

const keywordLabel = intl.formatMessage({
id: 'SearchFilters.keywordLabel',
});

const initialAmenities = amenitiesFilter
? initialValues(urlQueryParams, amenitiesFilter.paramName)
: null;

const initialCategory = categoryFilter
? initialValue(urlQueryParams, categoryFilter.paramName)
: null;

const initialPriceRange = priceFilter
? initialPriceRangeValue(urlQueryParams, priceFilter.paramName)
: null;
Expand All @@ -114,25 +85,6 @@ const SearchFiltersComponent = props => {
? initialValue(urlQueryParams, keywordFilter.paramName)
: null;

const handleSelectOptions = (urlParam, options) => {
const queryParams =
options && options.length > 0
? { ...urlQueryParams, [urlParam]: options.join(',') }
: omit(urlQueryParams, urlParam);

history.push(createResourceLocatorString('SearchPage', routeConfiguration(), {}, queryParams));
};

const handleSelectOption = (urlParam, option) => {
// query parameters after selecting the option
// if no option is passed, clear the selection for the filter
const queryParams = option
? { ...urlQueryParams, [urlParam]: option }
: omit(urlQueryParams, urlParam);

history.push(createResourceLocatorString('SearchPage', routeConfiguration(), {}, queryParams));
};

const handlePrice = (urlParam, range) => {
const { minPrice, maxPrice } = range || {};
const queryParams =
Expand Down Expand Up @@ -165,32 +117,6 @@ const SearchFiltersComponent = props => {
history.push(createResourceLocatorString('SearchPage', routeConfiguration(), {}, queryParams));
};

const categoryFilterElement = categoryFilter ? (
<SelectSingleFilter
urlParam={categoryFilter.paramName}
label={categoryLabel}
onSelect={handleSelectOption}
showAsPopup
options={categoryFilter.options}
initialValue={initialCategory}
contentPlacementOffset={FILTER_DROPDOWN_OFFSET}
/>
) : null;

const amenitiesFilterElement = amenitiesFilter ? (
<SelectMultipleFilter
id={'SearchFilters.amenitiesFilter'}
name="amenities"
urlParam={amenitiesFilter.paramName}
label={amenitiesLabel}
onSubmit={handleSelectOptions}
showAsPopup
options={amenitiesFilter.options}
initialValues={initialAmenities}
contentPlacementOffset={FILTER_DROPDOWN_OFFSET}
/>
) : null;

const priceFilterElement = priceFilter ? (
<PriceFilter
id="SearchFilters.priceFilter"
Expand Down Expand Up @@ -249,8 +175,6 @@ const SearchFiltersComponent = props => {
return (
<div className={classes}>
<div className={css.filters}>
{categoryFilterElement}
{amenitiesFilterElement}
{priceFilterElement}
{dateRangeFilterElement}
{keywordFilterElement}
Expand Down Expand Up @@ -285,8 +209,6 @@ SearchFiltersComponent.defaultProps = {
className: null,
resultsCount: null,
searchingInProgress: false,
categoryFilter: null,
amenitiesFilter: null,
priceFilter: null,
dateRangeFilter: null,
isSearchFiltersPanelOpen: false,
Expand All @@ -302,8 +224,6 @@ SearchFiltersComponent.propTypes = {
resultsCount: number,
searchingInProgress: bool,
onManageDisableScrolling: func.isRequired,
categoriesFilter: propTypes.filterConfig,
amenitiesFilter: propTypes.filterConfig,
priceFilter: propTypes.filterConfig,
dateRangeFilter: propTypes.filterConfig,
isSearchFiltersPanelOpen: bool,
Expand Down
51 changes: 47 additions & 4 deletions src/components/SearchFiltersPanel/SearchFiltersPanel.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,12 @@ import omit from 'lodash/omit';

import routeConfiguration from '../../routeConfiguration';
import { createResourceLocatorString } from '../../util/routes';
import { InlineTextButton } from '../../components';
import { SelectSingleFilter, SelectMultipleFilter, InlineTextButton } from '../../components';
import css from './SearchFiltersPanel.css';

// Dropdown container can have a positional offset (in pixels)
const FILTER_DROPDOWN_OFFSET = -14;

class SearchFiltersPanelComponent extends Component {
constructor(props) {
super(props);
Expand Down Expand Up @@ -101,7 +104,7 @@ class SearchFiltersPanelComponent extends Component {
// if no option is passed, clear the selection for the filter
const currentQueryParams = option
? { ...mergedQueryParams, [urlParam]: option }
: omit(mergedQueryParams, urlParam);
: { ...mergedQueryParams, [urlParam]: null };

return { currentQueryParams };
});
Expand Down Expand Up @@ -151,12 +154,52 @@ class SearchFiltersPanelComponent extends Component {
}

render() {
const { rootClassName, className } = this.props;
const { rootClassName, className, intl, categoryFilter, amenitiesFilter } = this.props;
const classes = classNames(rootClassName || css.root, className);

const initialCategory = this.initialValue(categoryFilter.paramName);
const initialAmenities = this.initialValues(amenitiesFilter.paramName);

const categoryLabel = intl.formatMessage({
id: 'SearchFiltersPanel.categoryLabel',
});

const amenitiesLabel = intl.formatMessage({
id: 'SearchFiltersPanel.amenitiesLabel',
});

const categoryFilterElement = categoryFilter ? (
<SelectSingleFilter
urlParam={categoryFilter.paramName}
label={categoryLabel}
onSelect={this.handleSelectSingle}
liveEdit
options={categoryFilter.options}
initialValue={initialCategory}
contentPlacementOffset={FILTER_DROPDOWN_OFFSET}
/>
) : null;

const amenitiesFilterElement = amenitiesFilter ? (
<SelectMultipleFilter
id={'SearchFiltersPanel.amenitiesFilter'}
name="amenities"
urlParam={amenitiesFilter.paramName}
label={amenitiesLabel}
onSubmit={this.handleSelectMultiple}
liveEdit
options={amenitiesFilter.options}
initialValues={initialAmenities}
contentPlacementOffset={FILTER_DROPDOWN_OFFSET}
/>
) : null;

return (
<div className={classes}>
<div className={css.filtersWrapper}>{/* Add filters here */}</div>
<div className={css.filtersWrapper}>
{categoryFilterElement}
{amenitiesFilterElement}
</div>
<div className={css.footer}>
<InlineTextButton rootClassName={css.resetAllButton} onClick={this.resetAll}>
<FormattedMessage id={'SearchFiltersPanel.resetAll'} />
Expand Down
2 changes: 1 addition & 1 deletion src/containers/SearchPage/MainPanel.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ class MainPanel extends Component {

const isSearchFiltersPanelOpen = !!secondaryFilters && this.state.isSearchFiltersPanelOpen;

const filters = merge(primaryFilters, secondaryFilters);
const filters = merge({}, primaryFilters, secondaryFilters);
const selectedFilters = validFilterParams(urlQueryParams, filters);
const selectedFiltersCount = Object.keys(selectedFilters).length;

Expand Down
6 changes: 4 additions & 2 deletions src/containers/SearchPage/SearchPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -226,12 +226,14 @@ export class SearchPageComponent extends Component {
searchParamsForPagination={parse(location.search)}
showAsModalMaxWidth={MODAL_BREAKPOINT}
primaryFilters={{
categoryFilter: filters.categoryFilter,
amenitiesFilter: filters.amenitiesFilter,
priceFilter: filters.priceFilter,
dateRangeFilter: filters.dateRangeFilter,
keywordFilter: filters.keywordFilter,
}}
secondaryFilters={{
categoryFilter: filters.categoryFilter,
amenitiesFilter: filters.amenitiesFilter,
}}
/>
<ModalInMobile
className={css.mapPanel}
Expand Down
57 changes: 30 additions & 27 deletions src/containers/SearchPage/__snapshots__/SearchPage.test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -40,32 +40,6 @@ exports[`SearchPageComponent matches snapshot 1`] = `
}
primaryFilters={
Object {
"amenitiesFilter": Object {
"options": Array [
Object {
"key": "dog1",
"label": "Dog 1",
},
Object {
"key": "dog2",
"label": "Dog 2",
},
],
"paramName": "pub_amenities",
},
"categoryFilter": Object {
"options": Array [
Object {
"key": "cat1",
"label": "Cat 1",
},
Object {
"key": "cat2",
"label": "Cat 2",
},
],
"paramName": "pub_category",
},
"dateRangeFilter": Object {
"config": Object {
"active": true,
Expand Down Expand Up @@ -94,7 +68,36 @@ exports[`SearchPageComponent matches snapshot 1`] = `
searchListingsError={null}
searchParamsAreInSync={true}
searchParamsForPagination={Object {}}
secondaryFilters={null}
secondaryFilters={
Object {
"amenitiesFilter": Object {
"options": Array [
Object {
"key": "dog1",
"label": "Dog 1",
},
Object {
"key": "dog2",
"label": "Dog 2",
},
],
"paramName": "pub_amenities",
},
"categoryFilter": Object {
"options": Array [
Object {
"key": "cat1",
"label": "Cat 1",
},
Object {
"key": "cat2",
"label": "Cat 2",
},
],
"paramName": "pub_category",
},
}
}
showAsModalMaxWidth={768}
urlQueryParams={Object {}}
/>
Expand Down
4 changes: 2 additions & 2 deletions src/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -696,8 +696,6 @@
"SavedCardDetails.replaceCardTitle": "Use another payment method",
"SavedCardDetails.savedPaymentMethodPlaceholderDesktop": "•••• •••• •••• {last4Digits}",
"SavedCardDetails.savedPaymentMethodPlaceholderMobile": "…{last4Digits}",
"SearchFilters.amenitiesLabel": "Amenities",
"SearchFilters.categoryLabel": "Category",
"SearchFilters.filtersButtonLabel": "Filters",
"SearchFilters.foundResults": "{count, number} {count, plural, one {result} other {results}}",
"SearchFilters.keywordLabel": "Keyword",
Expand All @@ -714,8 +712,10 @@
"SearchFiltersMobile.keywordLabel": "Keyword",
"SearchFiltersMobile.resetAll": "Reset all",
"SearchFiltersMobile.showListings": "Show {count, number} {count, plural, one {sauna} other {saunas}}",
"SearchFiltersPanel.amenitiesLabel": "Amenities",
"SearchFiltersPanel.apply": "Apply",
"SearchFiltersPanel.cancel": "Cancel",
"SearchFiltersPanel.categoryLabel": "Category",
"SearchFiltersPanel.resetAll": "Reset all",
"SearchMapInfoCard.noImage": "No image",
"SearchPage.schemaDescription": "Showing search results",
Expand Down

0 comments on commit 2ea7ffa

Please sign in to comment.