Skip to content
This repository has been archived by the owner on Dec 30, 2022. It is now read-only.

Commit

Permalink
fix(connectRange): handle boundaries on first call
Browse files Browse the repository at this point in the history
* fix(connectRange): handle boundaries on first call

* chore(RangeInput): add stories

* refactor(connectRange): inline min/max condition in getCurrentRefinement

* fix(connectRange): use lodash isFinite instead of isFinite

* refactor(connectRange): compute currentRange from getProvidedProps

* refactor(connectRange.test): avoid to pre-bind getMetadata function

* refactor(connectRange): return items from getMetadata only when values are different from range

* refactor(connectRange): use default parameter on getCurrentRange

* fix(connectRange): use undefined as default range
  • Loading branch information
samouss authored and mthuret committed Oct 13, 2017
1 parent 35d668a commit 9f14dc0
Show file tree
Hide file tree
Showing 3 changed files with 280 additions and 94 deletions.
148 changes: 90 additions & 58 deletions packages/react-instantsearch/src/connectors/connectRange.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import PropTypes from 'prop-types';
import { isFinite as _isFinite } from 'lodash';
import {
cleanUpValue,
getIndex,
Expand Down Expand Up @@ -31,8 +32,33 @@ function getId(props) {

const namespace = 'range';

function getCurrentRange(boundaries, stats) {
let min;
if (_isFinite(boundaries.min)) {
min = boundaries.min;
} else if (_isFinite(stats.min)) {
min = stats.min;
} else {
min = undefined;
}

let max;
if (_isFinite(boundaries.max)) {
max = boundaries.max;
} else if (_isFinite(stats.max)) {
max = stats.max;
} else {
max = undefined;
}

return {
min,
max,
};
}

function getCurrentRefinement(props, searchState, context) {
return getCurrentRefinementValue(
const refinement = getCurrentRefinementValue(
props,
searchState,
context,
Expand All @@ -49,10 +75,23 @@ function getCurrentRefinement(props, searchState, context) {
return { min, max };
}
);

if (props.min !== undefined && refinement.min === undefined) {
refinement.min = props.min;
}

if (props.max !== undefined && refinement.max === undefined) {
refinement.max = props.max;
}

return refinement;
}

function refine(props, searchState, nextRefinement, context) {
if (!isFinite(nextRefinement.min) || !isFinite(nextRefinement.max)) {
if (
!_isFinite(parseFloat(nextRefinement.min)) ||
!_isFinite(parseFloat(nextRefinement.max))
) {
throw new Error(
"You can't provide non finite values to the range connector"
);
Expand Down Expand Up @@ -82,57 +121,45 @@ export default createConnector({
},

getProvidedProps(props, searchState, searchResults) {
const { attributeName } = props;
let { min, max } = props;

const hasMin = typeof min !== 'undefined';
const hasMax = typeof max !== 'undefined';

const { attributeName, min: minBound, max: maxBound } = props;
const results = getResults(searchResults, this.context);

if (!hasMin || !hasMax) {
if (!results) {
return {
canRefine: false,
};
}

const stats = results.getFacetByName(attributeName)
? results.getFacetStats(attributeName)
: null;
if (!stats) {
return {
canRefine: false,
};
}

if (!hasMin) {
min = stats.min;
}
if (!hasMax) {
max = stats.max;
}
}

const stats = results ? results.getFacetStats(attributeName) || {} : {};
const count = results
? results.getFacetValues(attributeName).map(v => ({
value: v.name,
count: v.count,
}))
: [];

const { min: valueMin = min, max: valueMax = max } = getCurrentRefinement(
const { min: rangeMin, max: rangeMax } = getCurrentRange(
{ min: minBound, max: maxBound },
stats
);

const { min: valueMin, max: valueMax } = getCurrentRefinement(
props,
searchState,
this.context
);

// The searchState is not always in sync with the helper state. For example
// when we set boundaries on the first render the searchState don't have
// the correct refinement. If this behaviour change in the upcoming version
// we could store the range inside the searchState instead of rely on `this`.
this._currentRange = {
min: rangeMin,
max: rangeMax,
};

return {
min,
max,
currentRefinement: { min: valueMin, max: valueMax },
count,
min: rangeMin,
max: rangeMax,
canRefine: count.length > 0,
currentRefinement: {
min: valueMin === undefined ? rangeMin : valueMin,
max: valueMax === undefined ? rangeMax : valueMax,
},
count,
};
},

Expand Down Expand Up @@ -165,36 +192,41 @@ export default createConnector({
},

getMetadata(props, searchState) {
const id = getId(props);
const currentRefinement = getCurrentRefinement(
const { min: minRange, max: maxRange } = this._currentRange;
const { min: minValue, max: maxValue } = getCurrentRefinement(
props,
searchState,
this.context
);
let item;
const hasMin = typeof currentRefinement.min !== 'undefined';
const hasMax = typeof currentRefinement.max !== 'undefined';
if (hasMin || hasMax) {
let itemLabel = '';
if (hasMin) {
itemLabel += `${currentRefinement.min} <= `;
}
itemLabel += props.attributeName;
if (hasMax) {
itemLabel += ` <= ${currentRefinement.max}`;
}
item = {
label: itemLabel,
currentRefinement,

const items = [];
const hasMin = minValue !== undefined;
const hasMax = maxValue !== undefined;
const shouldDisplayMinLabel = hasMin && minValue !== minRange;
const shouldDisplayMaxLabel = hasMax && maxValue !== maxRange;

if (shouldDisplayMinLabel || shouldDisplayMaxLabel) {
const fragments = [
hasMin ? `${minValue} <= ` : '',
props.attributeName,
hasMax ? ` <= ${maxValue}` : '',
];

items.push({
label: fragments.join(''),
attributeName: props.attributeName,
value: nextState => cleanUp(props, nextState, this.context),
};
currentRefinement: {
min: minValue,
max: maxValue,
},
});
}

return {
id,
id: getId(props),
index: getIndex(this.context),
items: item ? [item] : [],
items,
};
},
});
Loading

0 comments on commit 9f14dc0

Please sign in to comment.