Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactoring filter setup #1296

Merged
merged 20 commits into from
Jun 4, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
76d6ded
Update filter components: they parse and format url params
Gnito Jun 1, 2020
6d1f7f0
Utility functions for search filters
Gnito Jun 1, 2020
8e06d8f
Update filter and sort configurations
Gnito Jun 1, 2020
d10d6a5
Update SortBy component
Gnito Jun 1, 2020
05381ee
Add FilterComponent that chooses correct filter based on config
Gnito Jun 1, 2020
7894893
Fix loading text positioning with missing relative.
Gnito Jun 1, 2020
a4ea030
Remove filters from UI containers: SearchFilters, SearchFiltersMobile…
Gnito Jun 1, 2020
c57c49c
Update MainPanel to add FilterComponent(s) and SortBy
Gnito Jun 1, 2020
a6433e6
Update SearchPage.helpers.js to work with new config
Gnito Jun 1, 2020
7368c82
Update SearchPage to work with new marketplace-custom-config
Gnito Jun 1, 2020
19916c4
Update EditListingFeaturesForm to work with new marketplace-custom-co…
Gnito Jun 1, 2020
de6d66b
Update EditListingDescriptionPanel to work with new marketplace-custo…
Gnito Jun 1, 2020
07b3f50
Update ListingPage to work with new marketplace-custom-config
Gnito Jun 1, 2020
1f7f2e0
Add some padding to error message styles on SearchPage
Gnito Jun 1, 2020
8a9b84b
Rename SearchFiltersPanel -> SearchFiltersSecondary
Gnito Jun 2, 2020
dcc1e53
Rename SearchFilters -> SearchFiltersPrimary
Gnito Jun 2, 2020
0eca669
Fix translations for SearchFiltersMobile
Gnito Jun 2, 2020
79c6e2f
Update SearchPage/README.md
Gnito Jun 2, 2020
1133d9a
Fix: sort did reset itself after filter update
Gnito Jun 2, 2020
f8292d5
Update Changelog
Gnito Jun 4, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,26 @@ way to update this template, but currently, we follow a pattern:

## Upcoming version 2020-XX-XX

- [change] Streamlining filter setup. Everyone who customizes FTW-templates, needs to update filters
and unfortunately the related code has been spread out in multiple UI containers.

Now, filters are more configurable through marketplace-custom-config.js. You can just add new
filter configs to `filters` array in there - and that should be enough for creating new filters
for extended data.

If your are creating a totally new filter component, you can take it into use in a single file:
src/containers/SearchPage/FilterComponent.js

In addition, we have renamed couple of container components:

- SearchFilters -> SearchFiltersPrimary
- SearchFiltersPanel -> SearchFiltersSecondary (SearchFiltersMobile has kept its name.)

SortBy filter's state is also tracked similarly as filters. From now on, the state is kept in
MainPanel and not in those 3 different UI containers.

[#1296](https://github.com/sharetribe/ftw-daily/pull/1296)

## [v4.5.0] 2020-06-01

- [fix] In some situations, ProfileMenu has began to overflow on TopbarDesktop.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ export const BookingDateRangeFilterPopup = {
component: BookingDateRangeFilterWrapper,
props: {
id: 'BookingDateRangeFilterPopupExample',
urlParam: URL_PARAM,
queryParamNames: [URL_PARAM],
liveEdit: false,
showAsPopup: true,
contentPlacementOffset: -14,
Expand All @@ -62,7 +62,7 @@ export const BookingDateRangeFilterPlain = {
component: BookingDateRangeFilterWrapper,
props: {
id: 'BookingDateRangeFilterPlainExample',
urlParam: URL_PARAM,
queryParamNames: [URL_PARAM],
liveEdit: true,
showAsPopup: false,
contentPlacementOffset: -14,
Expand Down
66 changes: 52 additions & 14 deletions src/components/BookingDateRangeFilter/BookingDateRangeFilter.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,36 @@
import React, { Component } from 'react';
import { bool, func, number, object, string } from 'prop-types';
import { arrayOf, bool, func, node, number, object, string } from 'prop-types';
import { injectIntl, intlShape } from '../../util/reactIntl';
import { parseDateFromISO8601, stringifyDateToISO8601 } from '../../util/dates';

import { FieldDateRangeController, FilterPopup, FilterPlain } from '../../components';
import css from './BookingDateRangeFilter.css';

const getDatesQueryParamName = queryParamNames => {
return Array.isArray(queryParamNames)
? queryParamNames[0]
: typeof queryParamNames === 'string'
? queryParamNames
: 'dates';
};

// Parse query parameter, which should look like "2020-05-28,2020-05-31"
const parseValue = value => {
const rawValuesFromParams = value ? value.split(',') : [];
const [startDate, endDate] = rawValuesFromParams.map(v => parseDateFromISO8601(v));
return value && startDate && endDate ? { dates: { startDate, endDate } } : { dates: null };
};
// Format dateRange value for the query. It's given by FieldDateRangeInput:
// { dates: { startDate, endDate } }
const formatValue = (dateRange, queryParamName) => {
const hasDates = dateRange && dateRange.dates;
const { startDate, endDate } = hasDates ? dateRange.dates : {};
const start = startDate ? stringifyDateToISO8601(startDate) : null;
const end = endDate ? stringifyDateToISO8601(endDate) : null;
const value = start && end ? `${start},${end}` : null;
return { [queryParamName]: value };
};

export class BookingDateRangeFilterComponent extends Component {
constructor(props) {
super(props);
Expand All @@ -18,20 +44,25 @@ export class BookingDateRangeFilterComponent extends Component {
className,
rootClassName,
showAsPopup,
initialValues: initialValuesRaw,
initialValues,
id,
contentPlacementOffset,
onSubmit,
urlParam,
queryParamNames,
label,
intl,
...rest
} = this.props;

const isSelected = !!initialValuesRaw && !!initialValuesRaw.dates;
const initialValues = isSelected ? initialValuesRaw : { dates: null };
const datesQueryParamName = getDatesQueryParamName(queryParamNames);
const initialDates =
initialValues && initialValues[datesQueryParamName]
? parseValue(initialValues[datesQueryParamName])
: { dates: null };

const startDate = isSelected ? initialValues.dates.startDate : null;
const endDate = isSelected ? initialValues.dates.endDate : null;
const isSelected = !!initialDates.dates;
const startDate = isSelected ? initialDates.dates.startDate : null;
const endDate = isSelected ? initialDates.dates.endDate : null;

const format = {
month: 'short',
Expand All @@ -48,6 +79,8 @@ export class BookingDateRangeFilterComponent extends Component {
dates: `${formattedStartDate} - ${formattedEndDate}`,
}
)
: label
? label
: intl.formatMessage({ id: 'BookingDateRangeFilter.labelPlain' });

const labelForPopup = isSelected
Expand All @@ -57,8 +90,14 @@ export class BookingDateRangeFilterComponent extends Component {
dates: `${formattedStartDate} - ${formattedEndDate}`,
}
)
: label
? label
: intl.formatMessage({ id: 'BookingDateRangeFilter.labelPopup' });

const handleSubmit = values => {
onSubmit(formatValue(values, datesQueryParamName));
};

const onClearPopupMaybe =
this.popupControllerRef && this.popupControllerRef.onReset
? { onClear: () => this.popupControllerRef.onReset(null, null) }
Expand All @@ -84,11 +123,10 @@ export class BookingDateRangeFilterComponent extends Component {
id={`${id}.popup`}
showAsPopup
contentPlacementOffset={contentPlacementOffset}
onSubmit={onSubmit}
onSubmit={handleSubmit}
{...onClearPopupMaybe}
{...onCancelPopupMaybe}
initialValues={initialValues}
urlParam={urlParam}
initialValues={initialDates}
{...rest}
>
<FieldDateRangeController
Expand All @@ -107,10 +145,9 @@ export class BookingDateRangeFilterComponent extends Component {
id={`${id}.plain`}
liveEdit
contentPlacementOffset={contentPlacementOffset}
onSubmit={onSubmit}
onSubmit={handleSubmit}
{...onClearPlainMaybe}
initialValues={initialValues}
urlParam={urlParam}
initialValues={initialDates}
{...rest}
>
<FieldDateRangeController
Expand All @@ -137,9 +174,10 @@ BookingDateRangeFilterComponent.propTypes = {
rootClassName: string,
className: string,
id: string.isRequired,
label: node,
showAsPopup: bool,
liveEdit: bool,
urlParam: string.isRequired,
queryParamNames: arrayOf(string).isRequired,
onSubmit: func.isRequired,
initialValues: object,
contentPlacementOffset: number,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ describe('BookingDateRangeFilter', () => {
const tree = renderShallow(
<BookingDateRangeFilterComponent
id="BookingDateRangeFilter"
urlParam="dates"
queryParamNames={['dates']}
liveEdit={false}
showAsPopup={true}
contentPlacementOffset={-14}
Expand All @@ -29,7 +29,7 @@ describe('BookingDateRangeFilter', () => {
const tree = renderShallow(
<BookingDateRangeFilterComponent
id="BookingDateRangeFilter"
urlParam="dates"
queryParamNames={['dates']}
liveEdit={true}
showAsPopup={false}
contentPlacementOffset={-14}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ exports[`BookingDateRangeFilter matches plain snapshot 1`] = `
liveEdit={true}
onSubmit={[Function]}
rootClassName={null}
urlParam="dates"
>
<FieldDateRangeController
className={null}
Expand All @@ -42,7 +41,6 @@ exports[`BookingDateRangeFilter matches popup snapshot 1`] = `
onSubmit={[Function]}
rootClassName={null}
showAsPopup={true}
urlParam="dates"
>
<FieldDateRangeController
className={null}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ import { bool, func, object, string } from 'prop-types';
import classNames from 'classnames';
import { FormattedMessage } from '../../util/reactIntl';
import { ensureOwnListing } from '../../util/data';
import { ListingLink } from '../../components';
import { findOptionsForSelectFilter } from '../../util/search';
import { LISTING_STATE_DRAFT } from '../../util/types';
import { ListingLink } from '../../components';
import { EditListingDescriptionForm } from '../../forms';
import config from '../../config';

Expand Down Expand Up @@ -39,6 +40,7 @@ const EditListingDescriptionPanel = props => {
<FormattedMessage id="EditListingDescriptionPanel.createListingTitle" />
);

const categoryOptions = findOptionsForSelectFilter('category', config.custom.filters);
return (
<div className={classes}>
<h1 className={css.title}>{panelTitle}</h1>
Expand All @@ -62,7 +64,7 @@ const EditListingDescriptionPanel = props => {
updated={panelUpdated}
updateInProgress={updateInProgress}
fetchErrors={errors}
categories={config.custom.categories}
categories={categoryOptions}
/>
</div>
);
Expand Down
8 changes: 4 additions & 4 deletions src/components/FilterPlain/FilterPlain.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,18 @@ class FilterPlainComponent extends Component {
}

handleChange(values) {
const { onSubmit, urlParam } = this.props;
onSubmit(urlParam, values);
const { onSubmit } = this.props;
onSubmit(values);
}

handleClear() {
const { onSubmit, onClear, urlParam } = this.props;
const { onSubmit, onClear } = this.props;

if (onClear) {
onClear();
}

onSubmit(urlParam, null);
onSubmit(null);
}

toggleIsOpen() {
Expand Down
13 changes: 6 additions & 7 deletions src/components/FilterPopup/FilterPopup.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,31 +27,31 @@ class FilterPopup extends Component {
}

handleSubmit(values) {
const { onSubmit, urlParam } = this.props;
const { onSubmit } = this.props;
this.setState({ isOpen: false });
onSubmit(urlParam, values);
onSubmit(values);
}

handleClear() {
const { onSubmit, onClear, urlParam } = this.props;
const { onSubmit, onClear } = this.props;
this.setState({ isOpen: false });

if (onClear) {
onClear();
}

onSubmit(urlParam, null);
onSubmit(null);
}

handleCancel() {
const { onSubmit, onCancel, initialValues, urlParam } = this.props;
const { onSubmit, onCancel, initialValues } = this.props;
this.setState({ isOpen: false });

if (onCancel) {
onCancel();
}

onSubmit(urlParam, initialValues);
onSubmit(initialValues);
}

handleBlur() {
Expand Down Expand Up @@ -182,7 +182,6 @@ FilterPopup.propTypes = {
className: string,
popupClassName: string,
id: string.isRequired,
urlParam: string.isRequired,
onSubmit: func.isRequired,
initialValues: object,
keepDirtyOnReinitialize: bool,
Expand Down
18 changes: 9 additions & 9 deletions src/components/KeywordFilter/KeywordFilter.example.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ import { stringify, parse } from '../../util/urlHelpers';

const URL_PARAM = 'keywords';

const handleSubmit = (urlParam, values, history) => {
const handleSubmit = (values, history) => {
console.log('Submitting values', values);
const queryParams = values ? `?${stringify({ [urlParam]: values })}` : '';
const queryParams = values ? `?${stringify(values)}` : '';
history.push(`${window.location.pathname}${queryParams}`);
};

Expand All @@ -16,15 +16,15 @@ const KeywordFilterPopup = withRouter(props => {

const params = parse(location.search);
const keyword = params[URL_PARAM];
const initialValues = !!keyword ? keyword : '';
const initialValues = !!keyword ? { [URL_PARAM]: keyword } : { [URL_PARAM]: null };

return (
<KeywordFilter
id="KeywordFilterPopupExample"
name="keyword"
urlParam={URL_PARAM}
queryParamNames={[URL_PARAM]}
label="Keyword"
onSubmit={(urlParam, values) => handleSubmit(urlParam, values, history)}
onSubmit={values => handleSubmit(values, history)}
showAsPopup={true}
liveEdit={false}
initialValues={initialValues}
Expand All @@ -44,16 +44,16 @@ const KeywordFilterPlain = withRouter(props => {

const params = parse(location.search);
const keyword = params[URL_PARAM];
const initialValues = !!keyword ? keyword : '';
const initialValues = !!keyword ? { [URL_PARAM]: keyword } : { [URL_PARAM]: null };

return (
<KeywordFilter
id="KeywordFilterPlainExample"
name="keyword"
urlParam={URL_PARAM}
queryParamNames={[URL_PARAM]}
label="Keyword"
onSubmit={(urlParam, values) => {
handleSubmit(urlParam, values, history);
onSubmit={values => {
handleSubmit(values, history);
}}
showAsPopup={false}
liveEdit={true}
Expand Down
Loading