Optionally use Link header for search pagination
This commit is contained in:
parent
82ff60efaa
commit
a985348bf1
2 changed files with 35 additions and 17 deletions
|
@ -1,4 +1,4 @@
|
|||
import api from '../api';
|
||||
import api, { getLinks } from '../api';
|
||||
|
||||
import { fetchRelationships } from './accounts';
|
||||
import { importFetchedAccounts, importFetchedStatuses } from './importer';
|
||||
|
@ -83,7 +83,9 @@ const submitSearch = (filter?: SearchFilter) =>
|
|||
dispatch(importFetchedStatuses(response.data.statuses));
|
||||
}
|
||||
|
||||
dispatch(fetchSearchSuccess(response.data, value, type));
|
||||
const next = getLinks(response).refs.find(link => link.rel === 'next');
|
||||
|
||||
dispatch(fetchSearchSuccess(response.data, value, type, next ? next.uri : null));
|
||||
dispatch(fetchRelationships(response.data.accounts.map((item: APIEntity) => item.id)));
|
||||
}).catch(error => {
|
||||
dispatch(fetchSearchFail(error));
|
||||
|
@ -95,11 +97,12 @@ const fetchSearchRequest = (value: string) => ({
|
|||
value,
|
||||
});
|
||||
|
||||
const fetchSearchSuccess = (results: APIEntity[], searchTerm: string, searchType: SearchFilter) => ({
|
||||
const fetchSearchSuccess = (results: APIEntity[], searchTerm: string, searchType: SearchFilter, next: string | null) => ({
|
||||
type: SEARCH_FETCH_SUCCESS,
|
||||
results,
|
||||
searchTerm,
|
||||
searchType,
|
||||
next,
|
||||
});
|
||||
|
||||
const fetchSearchFail = (error: AxiosError) => ({
|
||||
|
@ -125,17 +128,26 @@ const expandSearch = (type: SearchFilter) => (dispatch: AppDispatch, getState: (
|
|||
|
||||
dispatch(expandSearchRequest(type));
|
||||
|
||||
const params: Record<string, any> = {
|
||||
q: value,
|
||||
type,
|
||||
offset,
|
||||
};
|
||||
let url = getState().search.next as string;
|
||||
let params: Record<string, any> = {};
|
||||
|
||||
if (accountId) params.account_id = accountId;
|
||||
// if no URL was extracted from the Link header,
|
||||
// fall back on querying with the offset
|
||||
if (!url) {
|
||||
url = '/api/v2/search';
|
||||
params = {
|
||||
q: value,
|
||||
type,
|
||||
offset,
|
||||
};
|
||||
if (accountId) params.account_id = accountId;
|
||||
}
|
||||
|
||||
api(getState).get('/api/v2/search', {
|
||||
api(getState).get(url, {
|
||||
params,
|
||||
}).then(({ data }) => {
|
||||
}).then(response => {
|
||||
const data = response.data;
|
||||
|
||||
if (data.accounts) {
|
||||
dispatch(importFetchedAccounts(data.accounts));
|
||||
}
|
||||
|
@ -144,7 +156,9 @@ const expandSearch = (type: SearchFilter) => (dispatch: AppDispatch, getState: (
|
|||
dispatch(importFetchedStatuses(data.statuses));
|
||||
}
|
||||
|
||||
dispatch(expandSearchSuccess(data, value, type));
|
||||
const next = getLinks(response).refs.find(link => link.rel === 'next');
|
||||
|
||||
dispatch(expandSearchSuccess(data, value, type, next ? next.uri : null));
|
||||
dispatch(fetchRelationships(data.accounts.map((item: APIEntity) => item.id)));
|
||||
}).catch(error => {
|
||||
dispatch(expandSearchFail(error));
|
||||
|
@ -156,11 +170,12 @@ const expandSearchRequest = (searchType: SearchFilter) => ({
|
|||
searchType,
|
||||
});
|
||||
|
||||
const expandSearchSuccess = (results: APIEntity[], searchTerm: string, searchType: SearchFilter) => ({
|
||||
const expandSearchSuccess = (results: APIEntity[], searchTerm: string, searchType: SearchFilter, next: string | null) => ({
|
||||
type: SEARCH_EXPAND_SUCCESS,
|
||||
results,
|
||||
searchTerm,
|
||||
searchType,
|
||||
next,
|
||||
});
|
||||
|
||||
const expandSearchFail = (error: AxiosError) => ({
|
||||
|
|
|
@ -47,6 +47,7 @@ const ReducerRecord = ImmutableRecord({
|
|||
results: ResultsRecord(),
|
||||
filter: 'accounts' as SearchFilter,
|
||||
accountId: null as string | null,
|
||||
next: null as string | null,
|
||||
});
|
||||
|
||||
type State = ReturnType<typeof ReducerRecord>;
|
||||
|
@ -57,7 +58,7 @@ const toIds = (items: APIEntities = []) => {
|
|||
return ImmutableOrderedSet(items.map(item => item.id));
|
||||
};
|
||||
|
||||
const importResults = (state: State, results: APIEntity, searchTerm: string, searchType: SearchFilter) => {
|
||||
const importResults = (state: State, results: APIEntity, searchTerm: string, searchType: SearchFilter, next: string | null) => {
|
||||
return state.withMutations(state => {
|
||||
if (state.value === searchTerm && state.filter === searchType) {
|
||||
state.set('results', ResultsRecord({
|
||||
|
@ -76,15 +77,17 @@ const importResults = (state: State, results: APIEntity, searchTerm: string, sea
|
|||
}));
|
||||
|
||||
state.set('submitted', true);
|
||||
state.set('next', next);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const paginateResults = (state: State, searchType: SearchFilter, results: APIEntity, searchTerm: string) => {
|
||||
const paginateResults = (state: State, searchType: SearchFilter, results: APIEntity, searchTerm: string, next: string | null) => {
|
||||
return state.withMutations(state => {
|
||||
if (state.value === searchTerm) {
|
||||
state.setIn(['results', `${searchType}HasMore`], results[searchType].length >= 20);
|
||||
state.setIn(['results', `${searchType}Loaded`], true);
|
||||
state.set('next', next);
|
||||
state.updateIn(['results', searchType], items => {
|
||||
const data = results[searchType];
|
||||
// Hashtags are a list of maps. Others are IDs.
|
||||
|
@ -129,13 +132,13 @@ export default function search(state = ReducerRecord(), action: AnyAction) {
|
|||
case SEARCH_FETCH_REQUEST:
|
||||
return handleSubmitted(state, action.value);
|
||||
case SEARCH_FETCH_SUCCESS:
|
||||
return importResults(state, action.results, action.searchTerm, action.searchType);
|
||||
return importResults(state, action.results, action.searchTerm, action.searchType, action.next);
|
||||
case SEARCH_FILTER_SET:
|
||||
return state.set('filter', action.value);
|
||||
case SEARCH_EXPAND_REQUEST:
|
||||
return state.setIn(['results', `${action.searchType}Loaded`], false);
|
||||
case SEARCH_EXPAND_SUCCESS:
|
||||
return paginateResults(state, action.searchType, action.results, action.searchTerm);
|
||||
return paginateResults(state, action.searchType, action.results, action.searchTerm, action.next);
|
||||
case SEARCH_ACCOUNT_SET:
|
||||
if (!action.accountId) return state.merge({
|
||||
results: ResultsRecord(),
|
||||
|
|
Loading…
Reference in a new issue