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

Commit

Permalink
feat(infiniteHits): add previous button (#2296)
Browse files Browse the repository at this point in the history
  • Loading branch information
Yannick Croissant authored Apr 25, 2019
1 parent 5c53bad commit 010a69a
Show file tree
Hide file tree
Showing 7 changed files with 422 additions and 28 deletions.
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -130,19 +130,19 @@
},
{
"path": "packages/react-instantsearch/dist/umd/Connectors.min.js",
"maxSize": "40.50 kB"
"maxSize": "40.75 kB"
},
{
"path": "packages/react-instantsearch/dist/umd/Dom.min.js",
"maxSize": "63.00 kB"
},
{
"path": "packages/react-instantsearch-core/dist/umd/ReactInstantSearchCore.min.js",
"maxSize": "41.25 kB"
"maxSize": "41.50 kB"
},
{
"path": "packages/react-instantsearch-dom/dist/umd/ReactInstantSearchDOM.min.js",
"maxSize": "62.75 kB"
"maxSize": "63.00 kB"
},
{
"path": "packages/react-instantsearch-dom-maps/dist/umd/ReactInstantSearchDOMMaps.min.js",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@ describe('connectInfiniteHits', () => {
context: {
ais: {
mainTargetedIndex: 'index',
onInternalStateUpdate: jest.fn(),
},
},
refine: jest.fn(),
});

it('provides the current hits to the component', () => {
Expand All @@ -23,7 +25,10 @@ describe('connectInfiniteHits', () => {

expect(props).toEqual({
hits: hits.map(hit => expect.objectContaining(hit)),
hasPrevious: false,
hasMore: true,
refinePrevious: expect.any(Function),
refineNext: expect.any(Function),
});
});

Expand Down Expand Up @@ -55,6 +60,43 @@ describe('connectInfiniteHits', () => {
expect(res2.hasMore).toBe(true);
});

it('prepend hits internally', () => {
const context = createSingleIndexContext();
const getProvidedProps = connect.getProvidedProps.bind(context);

const initialPageHits = [{}, {}];
const previousPageHits = [{}, {}];
const initialPageProps = getProvidedProps(null, null, {
results: {
hits: initialPageHits,
page: 1,
hitsPerPage: 2,
nbPages: 3,
},
});

expect(initialPageProps.hits).toEqual(
initialPageHits.map(hit => expect.objectContaining(hit))
);
expect(initialPageProps.hasPrevious).toBe(true);

const previousPageProps = getProvidedProps(null, null, {
results: {
hits: previousPageHits,
page: 0,
hitsPerPage: 2,
nbPages: 3,
},
});

expect(previousPageProps.hits).toEqual(
[...previousPageHits, ...initialPageHits].map(hit =>
expect.objectContaining(hit)
)
);
expect(previousPageProps.hasPrevious).toBe(false);
});

it('accumulate hits internally while changing hitsPerPage configuration', () => {
const context = createSingleIndexContext();
const getProvidedProps = connect.getProvidedProps.bind(context);
Expand Down Expand Up @@ -373,7 +415,59 @@ describe('connectInfiniteHits', () => {
expect(props.hasMore).toBe(false);
});

it('adds 1 to page when calling refine', () => {
it('calls refine with next page when calling refineNext', () => {
const context = createSingleIndexContext();
const getProvidedProps = connect.getProvidedProps.bind(context);

const hits = [{}, {}];
const event = new Event('click');

const props = getProvidedProps(
{},
{},
{
results: {
hits,
page: 2,
hitsPerPage: 2,
nbPages: 3,
},
}
);

props.refineNext.apply(context, [event]);

expect(context.refine).toHaveBeenCalledTimes(1);
expect(context.refine).toHaveBeenLastCalledWith(event, 3);
});

it('calls refine with previous page when calling refinePrevious', () => {
const context = createSingleIndexContext();
const getProvidedProps = connect.getProvidedProps.bind(context);

const hits = [{}, {}];
const event = new Event('click');

const props = getProvidedProps(
{},
{},
{
results: {
hits,
page: 2,
hitsPerPage: 2,
nbPages: 3,
},
}
);

props.refinePrevious.apply(context, [event]);

expect(context.refine).toHaveBeenCalledTimes(1);
expect(context.refine).toHaveBeenLastCalledWith(event, 1);
});

it('adds 1 to page when calling refine without index', () => {
const context = createSingleIndexContext();
const refine = connect.refine.bind(context);

Expand All @@ -387,6 +481,20 @@ describe('connectInfiniteHits', () => {
expect(state2).toEqual({ page: 3 });
});

it('set page to the corresponding index', () => {
const context = createSingleIndexContext();
const refine = connect.refine.bind(context);

const props = {};
const state0 = {};
const event = new Event('click');
const index = 5;

const state1 = refine(props, state0, event, index);
// `index` is indexed from 0 but page number is indexed from 1
expect(state1).toEqual({ page: 6 });
});

it('automatically converts String state to Number', () => {
const context = createSingleIndexContext();
const refine = connect.refine.bind(context);
Expand Down Expand Up @@ -418,7 +526,10 @@ describe('connectInfiniteHits', () => {

const expectation = {
hits: [{}, {}, {}].map(hit => expect.objectContaining(hit)),
hasPrevious: true,
hasMore: true,
refinePrevious: expect.any(Function),
refineNext: expect.any(Function),
};

const actual = getProvidedProps(props, searchState, searchResults);
Expand Down Expand Up @@ -450,7 +561,10 @@ describe('connectInfiniteHits', () => {

expect(props).toEqual({
hits: hits.map(hit => expect.objectContaining(hit)),
hasPrevious: false,
hasMore: true,
refinePrevious: expect.any(Function),
refineNext: expect.any(Function),
});
});

Expand Down Expand Up @@ -480,6 +594,47 @@ describe('connectInfiniteHits', () => {
expect(res2.hasMore).toBe(true);
});

it('prepend hits internally', () => {
const context = createMultiIndexContext();
const getProvidedProps = connect.getProvidedProps.bind(context);

const initialPageHits = [{}, {}];
const previousPageHits = [{}, {}];
const initialPageProps = getProvidedProps(null, null, {
results: {
second: {
hits: initialPageHits,
page: 1,
hitsPerPage: 2,
nbPages: 3,
},
},
});

expect(initialPageProps.hits).toEqual(
initialPageHits.map(hit => expect.objectContaining(hit))
);
expect(initialPageProps.hasPrevious).toBe(true);

const previousPageProps = getProvidedProps(null, null, {
results: {
second: {
hits: previousPageHits,
page: 0,
hitsPerPage: 2,
nbPages: 3,
},
},
});

expect(previousPageProps.hits).toEqual(
[...previousPageHits, ...initialPageHits].map(hit =>
expect.objectContaining(hit)
)
);
expect(previousPageProps.hasPrevious).toBe(false);
});

it('accumulate hits internally while changing hitsPerPage configuration', () => {
const context = createMultiIndexContext();
const getProvidedProps = connect.getProvidedProps.bind(context);
Expand Down Expand Up @@ -530,6 +685,44 @@ describe('connectInfiniteHits', () => {
expect(res3.hasMore).toBe(true);
});

it('should not accumulate hits internally while changing query', () => {
const context = createMultiIndexContext();
const getProvidedProps = connect.getProvidedProps.bind(context);

const hits = [{}, {}, {}, {}, {}, {}];
const hits2 = [{}, {}, {}, {}, {}, {}];

const res1 = getProvidedProps(null, null, {
results: {
second: {
hits,
page: 0,
hitsPerPage: 6,
nbPages: 10,
_state: { page: 0, query: 'a' },
},
},
});

expect(res1.hits).toEqual(hits.map(hit => expect.objectContaining(hit)));
expect(res1.hasMore).toBe(true);

const res2 = getProvidedProps(null, null, {
results: {
second: {
hits: hits2,
page: 0,
hitsPerPage: 6,
nbPages: 10,
_state: { page: 0, query: 'b' },
},
},
});

expect(res2.hits).toEqual(hits2.map(hit => expect.objectContaining(hit)));
expect(res2.hasMore).toBe(true);
});

it('should not reset while accumulating results', () => {
const context = createMultiIndexContext();
const getProvidedProps = connect.getProvidedProps.bind(context);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { isEqual } from 'lodash';

import createConnector from '../core/createConnector';
import {
getCurrentRefinementValue,
Expand Down Expand Up @@ -45,39 +47,63 @@ export default createConnector({
const results = getResults(searchResults, this.context);

this._allResults = this._allResults || [];
this._previousPage = this._previousPage || 0;
this._prevState = this._prevState || {};

if (!results) {
return {
hits: [],
hasPrevious: false,
hasMore: false,
refine: () => {},
refinePrevious: () => {},
refineNext: () => {},
};
}

const { hits, hitsPerPage, page, nbPages } = results;
const {
page,
hits,
hitsPerPage,
nbPages,
_state: { page: p, ...currentState } = {},
} = results;

const hitsWithPositions = addAbsolutePositions(hits, hitsPerPage, page);
const hitsWithPositionsAndQueryID = addQueryID(
hitsWithPositions,
results.queryID
);

if (page === 0) {
this._allResults = hitsWithPositionsAndQueryID;
} else if (page > this._previousPage) {
if (
this._firstReceivedPage === undefined ||
!isEqual(currentState, this._prevState)
) {
this._allResults = [...hitsWithPositionsAndQueryID];
this._firstReceivedPage = page;
this._lastReceivedPage = page;
} else if (this._lastReceivedPage < page) {
this._allResults = [...this._allResults, ...hitsWithPositionsAndQueryID];
} else if (page < this._previousPage) {
this._allResults = hitsWithPositionsAndQueryID;
this._lastReceivedPage = page;
} else if (this._firstReceivedPage > page) {
this._allResults = [...hitsWithPositionsAndQueryID, ...this._allResults];
this._firstReceivedPage = page;
}

this._prevState = currentState;

const hasPrevious = this._firstReceivedPage > 0;
const lastPageIndex = nbPages - 1;
const hasMore = page < lastPageIndex;

this._previousPage = page;
const refinePrevious = event =>
this.refine(event, this._firstReceivedPage - 1);
const refineNext = event => this.refine(event, this._lastReceivedPage + 1);

return {
hits: this._allResults,
hasPrevious,
hasMore,
refinePrevious,
refineNext,
};
},

Expand All @@ -87,10 +113,14 @@ export default createConnector({
});
},

refine(props, searchState) {
refine(props, searchState, event, index) {
if (index === undefined && this._lastReceivedPage !== undefined) {
index = this._lastReceivedPage + 1;
} else if (index === undefined) {
index = getCurrentRefinement(props, searchState, this.context);
}
const id = getId();
const nextPage = getCurrentRefinement(props, searchState, this.context) + 1;
const nextValue = { [id]: nextPage };
const nextValue = { [id]: index + 1 }; // `index` is indexed from 0 but page number is indexed from 1
const resetPage = false;
return refineValue(searchState, nextValue, this.context, resetPage);
},
Expand Down
Loading

0 comments on commit 010a69a

Please sign in to comment.