Skip to content

Commit

Permalink
feat(MultiRange): add an all range (#1959)
Browse files Browse the repository at this point in the history
BREAKING CHANGE:
- MultiRange/connectMultiRange: will add a "All" range to allow unselection of range without the usage of CurrentRefinements. This range can be either filtered or ramove via CSS if not needed. The label can be changed by using our translations system.
  • Loading branch information
mthuret authored and bobylito committed Feb 10, 2017
1 parent f93af74 commit a3dc950
Show file tree
Hide file tree
Showing 6 changed files with 260 additions and 66 deletions.
14 changes: 9 additions & 5 deletions packages/react-instantsearch/src/components/MultiRange.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React, {PropTypes, Component} from 'react';
import List from './List';
import classNames from './classNames.js';
import translatable from '../core/translatable';

const cx = classNames('MultiRange');

Expand All @@ -15,6 +16,7 @@ class MultiRange extends Component {
refine: PropTypes.func.isRequired,
transformItems: PropTypes.func,
canRefine: PropTypes.bool.isRequired,
translate: PropTypes.func.isRequired,
};

static contextTypes = {
Expand All @@ -30,10 +32,10 @@ class MultiRange extends Component {
}

renderItem = item => {
const {refine} = this.props;

const {refine, translate} = this.props;
const label = item.value === '' ? translate('all') : item.label;
return (
<label>
<label {...cx(item.value === '' && 'itemAll')}>
<input
{...cx('itemRadio', item.isRefined && 'itemRadioSelected')}
type="radio"
Expand All @@ -43,7 +45,7 @@ class MultiRange extends Component {
/>
<span {...cx('itemBox', 'itemBox', item.isRefined && 'itemBoxSelected')}></span>
<span {...cx('itemLabel', 'itemLabel', item.isRefined && 'itemLabelSelected')}>
{item.label}
{label}
</span>
</label>
);
Expand All @@ -64,4 +66,6 @@ class MultiRange extends Component {
}
}

export default MultiRange;
export default translatable({
all: 'All',
})(MultiRange);
22 changes: 21 additions & 1 deletion packages/react-instantsearch/src/components/MultiRange.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ describe('MultiRange', () => {
{label: 'label2', value: '10:20', isRefined: false, noRefinement: false},
{label: 'label3', value: '20:30', isRefined: false, noRefinement: false},
{label: 'label4', value: '30:', isRefined: false, noRefinement: false},
{label: 'All', value: '', isRefined: true, noRefinement: false},
]}
canRefine={true}
/>
Expand All @@ -34,6 +35,25 @@ describe('MultiRange', () => {
{label: 'label2', value: '10:20', isRefined: true, noRefinement: false},
{label: 'label3', value: '20:30', isRefined: false, noRefinement: false},
{label: 'label4', value: '30:', isRefined: false, noRefinement: false},
{label: 'All', value: '', isRefined: false, noRefinement: false},
]}
canRefine={true}
/>
).toJSON();
expect(tree).toMatchSnapshot();
});

it('no refinements', () => {
const tree = renderer.create(
<MultiRange
createURL={() => '#'}
refine={() => null}
items={[
{label: 'label1', value: '10:', isRefined: false, noRefinement: true},
{label: 'label2', value: '10:20', isRefined: false, noRefinement: true},
{label: 'label3', value: '20:30', isRefined: false, noRefinement: true},
{label: 'label4', value: '30:', isRefined: false, noRefinement: true},
{label: 'All', value: '', isRefined: true, noRefinement: false},
]}
canRefine={true}
/>
Expand All @@ -47,7 +67,7 @@ describe('MultiRange', () => {
<MultiRange
refine={refine}
items={[
{label: 'label', value: '10:', isRefined: false, noRefinement: false},
{label: 'label', value: '10:', isRefined: false, noRefinement: false},
{label: 'label', value: '10:20', isRefined: false, noRefinement: false},
{label: 'label', value: '20:30', isRefined: false, noRefinement: false},
{label: 'label', value: '30:', isRefined: false, noRefinement: false},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,111 @@
exports[`MultiRange no refinements 1`] = `
<div
className="ais-MultiRange__root">
<div
className="ais-MultiRange__items">
<div
className="ais-MultiRange__item ais-MultiRange__itemNoRefinement">
<label
className="">
<input
checked={false}
className="ais-MultiRange__itemRadio"
disabled={true}
onChange={[Function]}
type="radio" />
<span
className="ais-MultiRange__itemBox ais-MultiRange__itemBox" />
<span
className="ais-MultiRange__itemLabel ais-MultiRange__itemLabel">
label1
</span>
</label>
</div>
<div
className="ais-MultiRange__item ais-MultiRange__itemNoRefinement">
<label
className="">
<input
checked={false}
className="ais-MultiRange__itemRadio"
disabled={true}
onChange={[Function]}
type="radio" />
<span
className="ais-MultiRange__itemBox ais-MultiRange__itemBox" />
<span
className="ais-MultiRange__itemLabel ais-MultiRange__itemLabel">
label2
</span>
</label>
</div>
<div
className="ais-MultiRange__item ais-MultiRange__itemNoRefinement">
<label
className="">
<input
checked={false}
className="ais-MultiRange__itemRadio"
disabled={true}
onChange={[Function]}
type="radio" />
<span
className="ais-MultiRange__itemBox ais-MultiRange__itemBox" />
<span
className="ais-MultiRange__itemLabel ais-MultiRange__itemLabel">
label3
</span>
</label>
</div>
<div
className="ais-MultiRange__item ais-MultiRange__itemNoRefinement">
<label
className="">
<input
checked={false}
className="ais-MultiRange__itemRadio"
disabled={true}
onChange={[Function]}
type="radio" />
<span
className="ais-MultiRange__itemBox ais-MultiRange__itemBox" />
<span
className="ais-MultiRange__itemLabel ais-MultiRange__itemLabel">
label4
</span>
</label>
</div>
<div
className="ais-MultiRange__item ais-MultiRange__itemSelected">
<label
className="ais-MultiRange__itemAll">
<input
checked={true}
className="ais-MultiRange__itemRadio ais-MultiRange__itemRadioSelected"
disabled={false}
onChange={[Function]}
type="radio" />
<span
className="ais-MultiRange__itemBox ais-MultiRange__itemBox ais-MultiRange__itemBoxSelected" />
<span
className="ais-MultiRange__itemLabel ais-MultiRange__itemLabel ais-MultiRange__itemLabelSelected">
All
</span>
</label>
</div>
</div>
</div>
`;

exports[`MultiRange supports having a selected item 1`] = `
<div
className="ais-MultiRange__root">
<div
className="ais-MultiRange__items">
<div
className="ais-MultiRange__item">
<label>
<label
className="">
<input
checked={false}
className="ais-MultiRange__itemRadio"
Expand All @@ -22,7 +122,8 @@ exports[`MultiRange supports having a selected item 1`] = `
</div>
<div
className="ais-MultiRange__item ais-MultiRange__itemSelected">
<label>
<label
className="">
<input
checked={true}
className="ais-MultiRange__itemRadio ais-MultiRange__itemRadioSelected"
Expand All @@ -39,7 +140,8 @@ exports[`MultiRange supports having a selected item 1`] = `
</div>
<div
className="ais-MultiRange__item">
<label>
<label
className="">
<input
checked={false}
className="ais-MultiRange__itemRadio"
Expand All @@ -56,7 +158,8 @@ exports[`MultiRange supports having a selected item 1`] = `
</div>
<div
className="ais-MultiRange__item">
<label>
<label
className="">
<input
checked={false}
className="ais-MultiRange__itemRadio"
Expand All @@ -71,6 +174,24 @@ exports[`MultiRange supports having a selected item 1`] = `
</span>
</label>
</div>
<div
className="ais-MultiRange__item">
<label
className="ais-MultiRange__itemAll">
<input
checked={false}
className="ais-MultiRange__itemRadio"
disabled={false}
onChange={[Function]}
type="radio" />
<span
className="ais-MultiRange__itemBox ais-MultiRange__itemBox" />
<span
className="ais-MultiRange__itemLabel ais-MultiRange__itemLabel">
All
</span>
</label>
</div>
</div>
</div>
`;
Expand All @@ -82,7 +203,8 @@ exports[`MultiRange supports passing items values 1`] = `
className="ais-MultiRange__items">
<div
className="ais-MultiRange__item">
<label>
<label
className="">
<input
checked={false}
className="ais-MultiRange__itemRadio"
Expand All @@ -99,7 +221,8 @@ exports[`MultiRange supports passing items values 1`] = `
</div>
<div
className="ais-MultiRange__item">
<label>
<label
className="">
<input
checked={false}
className="ais-MultiRange__itemRadio"
Expand All @@ -116,7 +239,8 @@ exports[`MultiRange supports passing items values 1`] = `
</div>
<div
className="ais-MultiRange__item">
<label>
<label
className="">
<input
checked={false}
className="ais-MultiRange__itemRadio"
Expand All @@ -133,7 +257,8 @@ exports[`MultiRange supports passing items values 1`] = `
</div>
<div
className="ais-MultiRange__item">
<label>
<label
className="">
<input
checked={false}
className="ais-MultiRange__itemRadio"
Expand All @@ -148,6 +273,24 @@ exports[`MultiRange supports passing items values 1`] = `
</span>
</label>
</div>
<div
className="ais-MultiRange__item ais-MultiRange__itemSelected">
<label
className="ais-MultiRange__itemAll">
<input
checked={true}
className="ais-MultiRange__itemRadio ais-MultiRange__itemRadioSelected"
disabled={false}
onChange={[Function]}
type="radio" />
<span
className="ais-MultiRange__itemBox ais-MultiRange__itemBox ais-MultiRange__itemBoxSelected" />
<span
className="ais-MultiRange__itemLabel ais-MultiRange__itemLabel ais-MultiRange__itemLabelSelected">
All
</span>
</label>
</div>
</div>
</div>
`;
13 changes: 13 additions & 0 deletions packages/react-instantsearch/src/connectors/connectMultiRange.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ export default createConnector({
},

getProvidedProps(props, searchState, searchResults) {
const attributeName = props.attributeName;
const currentRefinement = getCurrentRefinement(props, searchState);
const items = props.items.map(item => {
const value = stringifyItem(item);
Expand All @@ -99,6 +100,18 @@ export default createConnector({
};
});

const stats = searchResults.results && searchResults.results.getFacetByName(attributeName) ?
searchResults.results.getFacetStats(attributeName) : null;
const refinedItem = find(items, item => item.isRefined === true);
if (!items.some(item => item.value === '')) {
items.push({
value: '',
isRefined: isEmpty(refinedItem),
noRefinement: !stats,
label: 'All',
});
}

return {
items: props.transformItems ? props.transformItems(items) : items,
currentRefinement,
Expand Down
Loading

0 comments on commit a3dc950

Please sign in to comment.