Skip to content

Commit

Permalink
feat(menu): implement getRenderState and getWidgetRenderState (#4540
Browse files Browse the repository at this point in the history
)

* feat(menu): implement `getRenderState` and `getWidgetRenderState`

* Removed duplicated declaration of `jsHelper`, moved `cachedToggleShowMore` binding to `init` to avoid it happens more than once
  • Loading branch information
shortcuts authored and Haroenv committed Nov 30, 2020
1 parent 33300c7 commit 8135cc6
Show file tree
Hide file tree
Showing 2 changed files with 180 additions and 53 deletions.
116 changes: 116 additions & 0 deletions src/connectors/menu/__tests__/connectMenu-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,13 @@ import jsHelper, {
SearchResults,
SearchParameters,
} from 'algoliasearch-helper';
import { createSearchClient } from '../../../../test/mock/createSearchClient';
import { createSingleSearchResponse } from '../../../../test/mock/createAPIResponse';
import { createInstantSearch } from '../../../../test/mock/createInstantSearch';
import {
createInitOptions,
createRenderOptions,
} from '../../../../test/mock/createWidget';
import connectMenu from '../connectMenu';

describe('connectMenu', () => {
Expand Down Expand Up @@ -437,6 +442,117 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/menu/js/#co
expect(() => widget.dispose({ helper, state: helper.state })).not.toThrow();
});

describe('getRenderState', () => {
test('returns the render state', () => {
const renderFn = jest.fn();
const unmountFn = jest.fn();
const createMenu = connectMenu(renderFn, unmountFn);
const menu = createMenu({
attribute: 'brand',
});
const helper = jsHelper(
createSearchClient(),
'indexName',
menu.getWidgetSearchParameters(new SearchParameters(), { uiState: {} })
);

const renderState1 = menu.getRenderState(
{ menu: {} },
createInitOptions({ helper })
);

expect(renderState1.menu).toEqual({
items: [],
createURL: undefined,
refine: undefined,
canRefine: false,
isShowingMore: false,
toggleShowMore: expect.any(Function),
canToggleShowMore: false,
widgetParams: { attribute: 'brand' },
});
});

test('returns the render state with results', () => {
const renderFn = jest.fn();
const unmountFn = jest.fn();
const createMenu = connectMenu(renderFn, unmountFn);
const menu = createMenu({
attribute: 'brand',
});
const helper = jsHelper(
createSearchClient(),
'indexName',
menu.getWidgetSearchParameters(new SearchParameters(), {
uiState: {},
})
);

menu.init(createInitOptions({ helper }));

expect(
menu.getRenderState(
{},
createRenderOptions({
helper,
results: new SearchResults(helper.state, [
createSingleSearchResponse({
hits: [],
facets: {
brand: 300,
},
}),
]),
})
)
).toEqual({
menu: {
items: [],
canRefine: false,
refine: expect.any(Function),
sendEvent: expect.any(Function),
createURL: expect.any(Function),
widgetParams: { attribute: 'brand' },
isShowingMore: false,
toggleShowMore: expect.any(Function),
canToggleShowMore: false,
},
});
});
});

describe('getWidgetRenderState', () => {
test('returns the widget render state', () => {
const renderFn = jest.fn();
const unmountFn = jest.fn();
const createMenu = connectMenu(renderFn, unmountFn);
const menu = createMenu({
attribute: 'brand',
});
const helper = jsHelper(
createSearchClient(),
'indexName',
menu.getWidgetSearchParameters(new SearchParameters(), { uiState: {} })
);

const renderState1 = menu.getWidgetRenderState(
{},
createInitOptions({ helper })
);

expect(renderState1).toEqual({
items: [],
createURL: undefined,
refine: undefined,
canRefine: false,
isShowingMore: false,
toggleShowMore: expect.any(Function),
canToggleShowMore: false,
widgetParams: { attribute: 'brand' },
});
});
});

describe('showMore', () => {
it('should set `maxValuesPerFacet` by default', () => {
const widget = makeWidget({
Expand Down
117 changes: 64 additions & 53 deletions src/connectors/menu/connectMenu.js
Original file line number Diff line number Diff line change
Expand Up @@ -140,84 +140,49 @@ export default function connectMenu(renderFn, unmountFn = noop) {
return this.isShowingMore ? showMoreLimit : limit;
},

refine(helper) {
return facetValue => {
const [refinedItem] = helper.getHierarchicalFacetBreadcrumb(
attribute
);
sendEvent('click', facetValue ? facetValue : refinedItem);
helper
.toggleRefinement(attribute, facetValue ? facetValue : refinedItem)
.search();
};
},
init(initOptions) {
const { helper, createURL, instantSearchInstance } = initOptions;

init({ helper, createURL, instantSearchInstance }) {
sendEvent = createSendEventForFacet({
instantSearchInstance,
helper,
attribute,
widgetType: this.$$type,
});

this.cachedToggleShowMore = this.cachedToggleShowMore.bind(this);

this._createURL = facetValue =>
createURL(helper.state.toggleRefinement(attribute, facetValue));

this._refine = this.refine(helper);
this._refine = function(facetValue) {
const [refinedItem] = helper.getHierarchicalFacetBreadcrumb(
attribute
);
sendEvent('click', facetValue ? facetValue : refinedItem);
helper
.toggleRefinement(attribute, facetValue ? facetValue : refinedItem)
.search();
};

this.cachedToggleShowMore = this.cachedToggleShowMore.bind(this);

renderFn(
{
items: [],
createURL: this._createURL,
refine: this._refine,
sendEvent,
...this.getWidgetRenderState(initOptions),
instantSearchInstance,
canRefine: false,
widgetParams,
isShowingMore: this.isShowingMore,
toggleShowMore: this.cachedToggleShowMore,
canToggleShowMore: false,
},
true
);
},

render({ results, instantSearchInstance }) {
const facetValues = results.getFacetValues(attribute, { sortBy });
const facetItems =
facetValues && facetValues.data ? facetValues.data : [];

const items = transformItems(
facetItems
.slice(0, this.getLimit())
.map(({ name: label, path: value, ...item }) => ({
...item,
label,
value,
}))
);
render(renderOptions) {
const { instantSearchInstance } = renderOptions;

this.toggleShowMore = this.createToggleShowMore({
results,
instantSearchInstance,
});
this.toggleShowMore = this.createToggleShowMore(renderOptions);

renderFn(
{
items,
createURL: this._createURL,
refine: this._refine,
sendEvent,
...this.getWidgetRenderState(renderOptions),
instantSearchInstance,
canRefine: items.length > 0,
widgetParams,
isShowingMore: this.isShowingMore,
toggleShowMore: this.cachedToggleShowMore,
canToggleShowMore:
showMore &&
(this.isShowingMore || facetItems.length > this.getLimit()),
},
false
);
Expand All @@ -231,6 +196,52 @@ export default function connectMenu(renderFn, unmountFn = noop) {
.setQueryParameter('maxValuesPerFacet', undefined);
},

getRenderState(renderState, renderOptions) {
return {
...renderState,
menu: this.getWidgetRenderState(renderOptions),
};
},

getWidgetRenderState(widgetOptions) {
let items = [];
let canToggleShowMore = false;

if (widgetOptions.results) {
const facetValues = widgetOptions.results.getFacetValues(attribute, {
sortBy,
});
const facetItems =
facetValues && facetValues.data ? facetValues.data : [];

canToggleShowMore =
showMore &&
(this.isShowingMore || facetItems.length > this.getLimit());

items = transformItems(
facetItems
.slice(0, this.getLimit())
.map(({ name: label, path: value, ...item }) => ({
...item,
label,
value,
}))
);
}

return {
items,
createURL: this._createURL,
refine: this._refine,
sendEvent,
canRefine: items.length > 0,
widgetParams,
isShowingMore: this.isShowingMore,
toggleShowMore: this.cachedToggleShowMore,
canToggleShowMore,
};
},

getWidgetUiState(uiState, { searchParameters }) {
const [value] = searchParameters.getHierarchicalFacetBreadcrumb(
attribute
Expand Down

0 comments on commit 8135cc6

Please sign in to comment.