Skip to content

Commit

Permalink
feat(connectors): connectStarRating (iteration2)
Browse files Browse the repository at this point in the history
  • Loading branch information
iam4x committed Mar 21, 2017
1 parent 589454c commit 7ef7b6b
Show file tree
Hide file tree
Showing 6 changed files with 235 additions and 195 deletions.
44 changes: 14 additions & 30 deletions src/connectors/star-rating/__tests__/connectStarRating-test.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@


import sinon from 'sinon';

import jsHelper from 'algoliasearch-helper';
Expand Down Expand Up @@ -44,11 +42,8 @@ describe('connectStarRating', () => {
expect(isFirstRendering).toBe(true);

// should provide good values for the first rendering
const {containerNode, facetValues, collapsible, shouldAutoHideContainer} = rendering.lastCall.args[0];
expect(containerNode).toBe(container);
const {facetValues} = rendering.lastCall.args[0];
expect(facetValues).toEqual([]);
expect(collapsible).toBe(false);
expect(shouldAutoHideContainer).toBe(true);
}

widget.render({
Expand All @@ -68,32 +63,25 @@ describe('connectStarRating', () => {
expect(isFirstRendering).toBe(false);

// should provide good values after the first search
const {containerNode, facetValues, collapsible, shouldAutoHideContainer} = rendering.lastCall.args[0];
expect(containerNode).toBe(container);
const {facetValues} = rendering.lastCall.args[0];
expect(facetValues).toEqual([
{
count: 1000, isRefined: false,
labels: {andUp: '& Up'}, name: '4',
count: 1000, isRefined: false, name: '4',
stars: [true, true, true, true, false],
},
{
count: 1050, isRefined: false,
labels: {andUp: '& Up'}, name: '3',
count: 1050, isRefined: false, name: '3',
stars: [true, true, true, false, false],
},
{
count: 1070, isRefined: false,
labels: {andUp: '& Up'}, name: '2',
count: 1070, isRefined: false, name: '2',
stars: [true, true, false, false, false],
},
{
count: 1080, isRefined: false,
labels: {andUp: '& Up'}, name: '1',
count: 1080, isRefined: false, name: '1',
stars: [true, false, false, false, false],
},
]);
expect(collapsible).toBe(false);
expect(shouldAutoHideContainer).toBe(false);
}
});

Expand Down Expand Up @@ -122,10 +110,10 @@ describe('connectStarRating', () => {

{ // first rendering
const renderOptions = rendering.lastCall.args[0];
const {toggleRefinement, facetValues} = renderOptions;
const {refine, facetValues} = renderOptions;
expect(facetValues).toEqual([]);
expect(helper.getRefinements(attributeName)).toEqual([]);
toggleRefinement('3');
refine('3');
expect(helper.getRefinements(attributeName)).toEqual([
{type: 'disjunctive', value: '3'},
{type: 'disjunctive', value: '4'},
Expand All @@ -151,26 +139,22 @@ describe('connectStarRating', () => {

{ // Second rendering
const renderOptions = rendering.lastCall.args[0];
const {toggleRefinement, facetValues} = renderOptions;
const {refine, facetValues} = renderOptions;
expect(facetValues).toEqual([
{
count: 1000, isRefined: false,
labels: {andUp: '& Up'}, name: '4',
count: 1000, isRefined: false, name: '4',
stars: [true, true, true, true, false],
},
{
count: 1050, isRefined: true,
labels: {andUp: '& Up'}, name: '3',
count: 1050, isRefined: true, name: '3',
stars: [true, true, true, false, false],
},
{
count: 1070, isRefined: false,
labels: {andUp: '& Up'}, name: '2',
count: 1070, isRefined: false, name: '2',
stars: [true, true, false, false, false],
},
{
count: 1080, isRefined: false,
labels: {andUp: '& Up'}, name: '1',
count: 1080, isRefined: false, name: '1',
stars: [true, false, false, false, false],
},
]);
Expand All @@ -179,7 +163,7 @@ describe('connectStarRating', () => {
{type: 'disjunctive', value: '4'},
{type: 'disjunctive', value: '5'},
]);
toggleRefinement('4');
refine('4');
expect(helper.getRefinements(attributeName)).toEqual([
{type: 'disjunctive', value: '4'},
{type: 'disjunctive', value: '5'},
Expand Down
238 changes: 101 additions & 137 deletions src/connectors/star-rating/connectStarRating.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,4 @@
import {
bemHelper,
prepareTemplateProps,
getContainerNode,
} from '../../lib/utils.js';
import cx from 'classnames';
import defaultTemplates from './defaultTemplates.js';
import defaultLabels from './defaultLabels.js';

const bem = bemHelper('ais-star-rating');
import {checkRendering} from '../../lib/utils.js';

/**
* Instantiate a list of refinements based on a rating attribute
Expand Down Expand Up @@ -42,144 +33,117 @@ const bem = bemHelper('ais-star-rating');
* @return {Object}
*/
const usage = `Usage:
starRating({
container,
attributeName,
[ max=5 ],
[ cssClasses.{root,header,body,footer,list,item,active,link,disabledLink,star,emptyStar,count} ],
[ templates.{header,item,footer} ],
[ transformData.{item} ],
[ labels.{andUp} ],
[ autoHideContainer=true ],
[ collapsible=false ]
})`;
const connectStarRating = starRatingRendering => ({
container,
var customStarRating = connectStarRating(function render(params, isFirstRendering) {
// params = {
// facetValues,
// createURL,
// instantSearchInstance,
// results,
// }
});
search.addWidget(
customStarRatingI({
attributeName,
[ max=5 ],
});
);
Full documentation available at https://community.algolia.com/instantsearch.js/connectors/connectStarRating.html
`;
export default function connectStarRating(renderFn) {
checkRendering(renderFn, usage);

return ({
attributeName,
max = 5,
cssClasses: userCssClasses = {},
labels = defaultLabels,
templates = defaultTemplates,
collapsible = false,
transformData,
autoHideContainer = true,
}) => {
const containerNode = getContainerNode(container);
if (!attributeName) {
throw new Error(usage);
}

if (!container || !attributeName) {
throw new Error(usage);
}
return {
getConfiguration() {
return {disjunctiveFacets: [attributeName]};
},

const cssClasses = {
root: cx(bem(null), userCssClasses.root),
header: cx(bem('header'), userCssClasses.header),
body: cx(bem('body'), userCssClasses.body),
footer: cx(bem('footer'), userCssClasses.footer),
list: cx(bem('list'), userCssClasses.list),
item: cx(bem('item'), userCssClasses.item),
link: cx(bem('link'), userCssClasses.link),
disabledLink: cx(bem('link', 'disabled'), userCssClasses.disabledLink),
count: cx(bem('count'), userCssClasses.count),
star: cx(bem('star'), userCssClasses.star),
emptyStar: cx(bem('star', 'empty'), userCssClasses.emptyStar),
active: cx(bem('item', 'active'), userCssClasses.active),
};
init({helper, createURL, instantSearchInstance}) {
this._instantSearchInstance = instantSearchInstance;
this._toggleRefinement = this._toggleRefinement.bind(this, helper);
this._createURL = state => facetValue => createURL(state.toggleRefinement(attributeName, facetValue));

return {
getConfiguration: () => ({disjunctiveFacets: [attributeName]}),
renderFn({
instantSearchInstance: this._instantSearchInstance,
facetValues: [],
nbHits: 0,
refine: this._toggleRefinement,
createURL: this._createURL(helper.state),
}, true);
},

init({templatesConfig, helper, createURL}) {
this._templateProps = prepareTemplateProps({
transformData,
defaultTemplates,
templatesConfig,
templates,
});
this._toggleRefinement = this._toggleRefinement.bind(this, helper);
this._createURL = state => facetValue => createURL(state.toggleRefinement(attributeName, facetValue));

starRatingRendering({
collapsible,
createURL: this._createURL(helper.state),
cssClasses,
facetValues: [],
shouldAutoHideContainer: autoHideContainer,
templateProps: this._templateProps,
toggleRefinement: this._toggleRefinement,
containerNode,
}, true);
},

render({helper, results, state}) {
const facetValues = [];
const allValues = {};
for (let v = max; v >= 0; --v) {
allValues[v] = 0;
}
results.getFacetValues(attributeName).forEach(facet => {
const val = Math.round(facet.name);
if (!val || val > max) {
return;
}
for (let v = val; v >= 1; --v) {
allValues[v] += facet.count;
render({helper, results, state}) {
const facetValues = [];
const allValues = {};
for (let v = max; v >= 0; --v) {
allValues[v] = 0;
}
});
const refinedStar = this._getRefinedStar(helper);
for (let star = max - 1; star >= 1; --star) {
const count = allValues[star];
if (refinedStar && star !== refinedStar && count === 0) {
// skip count==0 when at least 1 refinement is enabled
// eslint-disable-next-line no-continue
continue;
}
const stars = [];
for (let i = 1; i <= max; ++i) {
stars.push(i <= star);
}
facetValues.push({
stars,
name: String(star),
count,
isRefined: refinedStar === star,
labels,
results.getFacetValues(attributeName).forEach(facet => {
const val = Math.round(facet.name);
if (!val || val > max) {
return;
}
for (let v = val; v >= 1; --v) {
allValues[v] += facet.count;
}
});
}
const refinedStar = this._getRefinedStar(helper);
for (let star = max - 1; star >= 1; --star) {
const count = allValues[star];
if (refinedStar && star !== refinedStar && count === 0) {
// skip count==0 when at least 1 refinement is enabled
// eslint-disable-next-line no-continue
continue;
}
const stars = [];
for (let i = 1; i <= max; ++i) {
stars.push(i <= star);
}
facetValues.push({
stars,
name: String(star),
count,
isRefined: refinedStar === star,
});
}

starRatingRendering({
collapsible,
createURL: this._createURL(state),
cssClasses,
facetValues,
shouldAutoHideContainer: autoHideContainer && results.nbHits === 0,
templateProps: this._templateProps,
toggleRefinement: this._toggleRefinement,
containerNode,
}, false);
},
renderFn({
instantSearchInstance: this._instantSearchInstance,
facetValues,
nbHits: results.nbHits,
refine: this._toggleRefinement,
createURL: this._createURL(state),
}, false);
},

_toggleRefinement(helper, facetValue) {
const isRefined = this._getRefinedStar(helper) === Number(facetValue);
helper.clearRefinements(attributeName);
if (!isRefined) {
for (let val = Number(facetValue); val <= max; ++val) {
helper.addDisjunctiveFacetRefinement(attributeName, val);
_toggleRefinement(helper, facetValue) {
const isRefined = this._getRefinedStar(helper) === Number(facetValue);
helper.clearRefinements(attributeName);
if (!isRefined) {
for (let val = Number(facetValue); val <= max; ++val) {
helper.addDisjunctiveFacetRefinement(attributeName, val);
}
}
}
helper.search();
},
helper.search();
},

_getRefinedStar(helper) {
let refinedStar = undefined;
const refinements = helper.getRefinements(attributeName);
refinements.forEach(r => {
if (!refinedStar || Number(r.value) < refinedStar) {
refinedStar = Number(r.value);
}
});
return refinedStar;
},
_getRefinedStar(helper) {
let refinedStar = undefined;
const refinements = helper.getRefinements(attributeName);
refinements.forEach(r => {
if (!refinedStar || Number(r.value) < refinedStar) {
refinedStar = Number(r.value);
}
});
return refinedStar;
},
};
};
};

export default connectStarRating;
}
6 changes: 3 additions & 3 deletions src/widgets/star-rating/__tests__/star-rating-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import sinon from 'sinon';
import expect from 'expect';
import expectJSX from 'expect-jsx';
expect.extend(expectJSX);
import defaultTemplates from '../../../connectors/star-rating/defaultTemplates.js';
import defaultLabels from '../../../connectors/star-rating/defaultLabels.js';
import defaultTemplates from '../../../widgets/star-rating/defaultTemplates.js';
import defaultLabels from '../../../widgets/star-rating/defaultLabels.js';
import starRating from '../star-rating.js';
import RefinementList from '../../../components/RefinementList/RefinementList.js';

Expand Down Expand Up @@ -39,7 +39,7 @@ describe('starRating()', () => {
hits: [],
};
createURL = () => '#';
widget.init({helper});
widget.init({helper, instantSearchInstance: {templatesConfig: undefined}});
});

it('configures the underlying disjunctive facet', () => {
Expand Down
File renamed without changes.
File renamed without changes.
Loading

0 comments on commit 7ef7b6b

Please sign in to comment.