Refactor SelectMultipleFilter to use FilterPopup and FilterPlain

This commit is contained in:
Jenni Nurmi 2018-11-21 11:50:36 +02:00 committed by Vesa Luusua
parent b31656791c
commit 4c6435e569
7 changed files with 125 additions and 98 deletions

View file

@ -164,7 +164,8 @@ const SearchFiltersComponent = props => {
name="amenities"
urlParam={amenitiesFilter.paramName}
label={amenitiesLabel}
onSelect={handleSelectOptions}
onSubmit={handleSelectOptions}
showAsPopup
options={amenitiesFilter.options}
initialValues={initialAmenities}
contentPlacementOffset={FILTER_DROPDOWN_OFFSET}

View file

@ -14,7 +14,7 @@ import {
Button,
PriceFilter,
SelectSingleFilterPlain,
SelectMultipleFilterPlain,
SelectMultipleFilter,
BookingDateRangeFilter,
} from '../../components';
import { propTypes } from '../../util/types';
@ -236,12 +236,13 @@ class SearchFiltersMobileComponent extends Component {
const initialAmenities = this.initialValues(amenitiesFilter.paramName);
const amenitiesFilterElement = amenitiesFilter ? (
<SelectMultipleFilterPlain
<SelectMultipleFilter
id="SearchFiltersMobile.amenitiesFilter"
name="amenities"
urlParam={amenitiesFilter.paramName}
label={amenitiesLabel}
onSelect={this.handleSelectMultiple}
onSubmit={this.handleSelectMultiple}
liveEdit
options={amenitiesFilter.options}
initialValues={initialAmenities}
/>

View file

@ -13,16 +13,16 @@
* const initialNewFilterValues = this.initialValues(newFilter.paramName);
*
* const newFilterElement = newFilter ? (
* <SelectMultipleFilterPlain
* <SelectMultipleFilter
* id="SearchFiltersPanel.newFilter"
* name="newFilter"
* urlParam={newFilter.paramName}
* label={this.props.intl.formatMessage({ id: 'SearchFiltersPanel.newFilterLabel' })}
* onSelect={this.handleSelectMultiple}
* onSubmit={this.handleSelectMultiple}
* liveEdit
* options={multiSelectFilterXFromProps}
* initialValues={initialNewFilterValues}
* twoColumns
* />
* />
* ) : null;
*/

View file

@ -41,3 +41,8 @@
border: 1px solid var(--marketplaceColorDark);
}
}
.fieldGroupPlain {
padding-left: 20px;
padding-bottom: 30px;
}

View file

@ -41,11 +41,12 @@ const options = [
];
const handleSubmit = (urlParam, values, history) => {
console.log('Submitting values', values);
const queryParams = values ? `?${stringify({ [urlParam]: values.join(',') })}` : '';
history.push(`${window.location.pathname}${queryParams}`);
};
const AmenitiesFilterComponent = withRouter(props => {
const AmenitiesFilterPopup = withRouter(props => {
const { history, location } = props;
const params = parse(location.search);
@ -54,11 +55,13 @@ const AmenitiesFilterComponent = withRouter(props => {
return (
<SelectMultipleFilter
id="SelectMultipleFilterExample"
id="SelectMultipleFilterPopupExample"
name="amenities"
urlParam={URL_PARAM}
label="Amenities"
onSelect={(urlParam, values) => handleSubmit(urlParam, values, history)}
onSubmit={(urlParam, values) => handleSubmit(urlParam, values, history)}
showAsPopup={true}
liveEdit={false}
options={options}
initialValues={initialValues}
contentPlacementOffset={-14}
@ -66,8 +69,38 @@ const AmenitiesFilterComponent = withRouter(props => {
);
});
export const AmenitiesFilter = {
component: AmenitiesFilterComponent,
export const AmenitiesFilterPopupExample = {
component: AmenitiesFilterPopup,
props: {},
group: 'misc',
group: 'filters',
};
const AmenitiesFilterPlain = withRouter(props => {
const { history, location } = props;
const params = parse(location.search);
const amenities = params[URL_PARAM];
const initialValues = !!amenities ? amenities.split(',') : [];
return (
<SelectMultipleFilter
id="SelectMultipleFilterPlainExample"
name="amenities"
urlParam={URL_PARAM}
label="Amenities"
onSubmit={(urlParam, values) => {
handleSubmit(urlParam, values, history);
}}
showAsPopup={false}
liveEdit={true}
options={options}
initialValues={initialValues}
/>
);
});
export const AmenitiesFilterPlainExample = {
component: AmenitiesFilterPlain,
props: {},
group: 'filters',
};

View file

@ -2,71 +2,21 @@ import React, { Component } from 'react';
import { array, arrayOf, func, number, string } from 'prop-types';
import classNames from 'classnames';
import { injectIntl, intlShape } from 'react-intl';
import { FieldCheckboxGroup } from '../../components';
import { SelectMultipleFilterForm } from '../../forms';
import { FilterPopup, FilterPlain } from '../../components';
import css from './SelectMultipleFilter.css';
const KEY_CODE_ESCAPE = 27;
class SelectMultipleFilter extends Component {
constructor(props) {
super(props);
this.state = { isOpen: false };
this.filter = null;
this.filterContent = null;
this.handleSubmit = this.handleSubmit.bind(this);
this.handleClear = this.handleClear.bind(this);
this.handleCancel = this.handleCancel.bind(this);
this.handleBlur = this.handleBlur.bind(this);
this.handleKeyDown = this.handleKeyDown.bind(this);
this.toggleOpen = this.toggleOpen.bind(this);
this.positionStyleForContent = this.positionStyleForContent.bind(this);
}
handleSubmit(values) {
const { name, onSelect, urlParam } = this.props;
const paramValues = values[name];
this.setState({ isOpen: false });
onSelect(urlParam, paramValues);
}
handleClear() {
const { onSelect, urlParam } = this.props;
this.setState({ isOpen: false });
onSelect(urlParam, null);
}
handleCancel() {
const { onSelect, initialValues, urlParam } = this.props;
this.setState({ isOpen: false });
onSelect(urlParam, initialValues);
}
handleBlur(event) {
// FocusEvent is fired faster than the link elements native click handler
// gets its own event. Therefore, we need to check the origin of this FocusEvent.
if (!this.filter.contains(event.relatedTarget)) {
this.setState({ isOpen: false });
}
}
handleKeyDown(e) {
// Gather all escape presses to close menu
if (e.keyCode === KEY_CODE_ESCAPE) {
this.toggleOpen(false);
}
}
toggleOpen(enforcedState) {
if (enforcedState) {
this.setState({ isOpen: enforcedState });
} else {
this.setState(prevState => ({ isOpen: !prevState.isOpen }));
}
}
positionStyleForContent() {
if (this.filter && this.filterContent) {
// Render the filter content to the right from the menu
@ -91,54 +41,94 @@ class SelectMultipleFilter extends Component {
}
render() {
const { rootClassName, className, id, name, label, options, initialValues, intl } = this.props;
const {
rootClassName,
className,
id,
name,
label,
options,
initialValues,
contentPlacementOffset,
onSubmit,
urlParam,
intl,
showAsPopup,
...rest
} = this.props;
const classes = classNames(rootClassName || css.root, className);
const hasInitialValues = initialValues.length > 0;
const labelStyles = hasInitialValues ? css.labelSelected : css.label;
const buttonLabel = hasInitialValues
const labelForPopup = hasInitialValues
? intl.formatMessage(
{ id: 'SelectMultipleFilter.labelSelected' },
{ labelText: label, count: initialValues.length }
)
: label;
const labelForPlain = hasInitialValues
? intl.formatMessage(
{ id: 'SelectMultipleFilterPlainForm.labelSelected' },
{ labelText: label, count: initialValues.length }
)
: label;
const contentStyle = this.positionStyleForContent();
// pass the initial values with the name key so that
// they can be passed to the correct field
const namedInitialValues = { [name]: initialValues };
return (
<div
const handleSubmit = (urlParam, values) => {
const usedValue = values ? values[name] : values;
onSubmit(urlParam, usedValue);
};
return showAsPopup ? (
<FilterPopup
className={classes}
onBlur={this.handleBlur}
onKeyDown={this.handleKeyDown}
ref={node => {
this.filter = node;
}}
rootClassName={rootClassName}
popupClassName={css.popupSize}
name={name}
label={labelForPopup}
isSelected={hasInitialValues}
id={`${id}.popup`}
showAsPopup
contentPlacementOffset={contentPlacementOffset}
onSubmit={handleSubmit}
initialValues={namedInitialValues}
urlParam={urlParam}
{...rest}
>
<button className={labelStyles} onClick={() => this.toggleOpen()}>
{buttonLabel}
</button>
<SelectMultipleFilterForm
id={id}
onSubmit={this.handleSubmit}
initialValues={namedInitialValues}
enableReinitialize={true}
<FieldCheckboxGroup
className={css.fieldGroup}
name={name}
onClear={this.handleClear}
onCancel={this.handleCancel}
id={`${id}-checkbox-group`}
options={options}
isOpen={this.state.isOpen}
intl={intl}
contentRef={node => {
this.filterContent = node;
}}
style={contentStyle}
/>
</div>
</FilterPopup>
) : (
<FilterPlain
className={className}
rootClassName={rootClassName}
label={labelForPlain}
isSelected={hasInitialValues}
id={`${id}.plain`}
liveEdit
contentPlacementOffset={contentStyle}
onSubmit={handleSubmit}
initialValues={namedInitialValues}
urlParam={urlParam}
{...rest}
>
<FieldCheckboxGroup
className={css.fieldGroupPlain}
name={name}
id={`${id}-checkbox-group`}
options={options}
/>
</FilterPlain>
);
}
}
@ -157,7 +147,7 @@ SelectMultipleFilter.propTypes = {
name: string.isRequired,
urlParam: string.isRequired,
label: string.isRequired,
onSelect: func.isRequired,
onSubmit: func.isRequired,
options: array.isRequired,
initialValues: arrayOf(string),
contentPlacementOffset: number,

View file

@ -689,9 +689,6 @@
"SectionLocations.listingsInLocation": "Saunas in {location}",
"SectionLocations.title": "Explore exotic locations in Finland",
"SelectMultipleFilter.labelSelected": "{labelText} • {count}",
"SelectMultipleFilterForm.cancel": "Cancel",
"SelectMultipleFilterForm.clear": "Clear",
"SelectMultipleFilterForm.submit": "Apply",
"SelectMultipleFilterPlainForm.clear": "Clear",
"SelectMultipleFilterPlainForm.labelSelected": "{labelText} • {count}",
"SelectSingleFilter.clear": "Clear",