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 { fetchRelationships } from './accounts';
|
||||||
import { importFetchedAccounts, importFetchedStatuses } from './importer';
|
import { importFetchedAccounts, importFetchedStatuses } from './importer';
|
||||||
|
@ -83,7 +83,9 @@ const submitSearch = (filter?: SearchFilter) =>
|
||||||
dispatch(importFetchedStatuses(response.data.statuses));
|
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)));
|
dispatch(fetchRelationships(response.data.accounts.map((item: APIEntity) => item.id)));
|
||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
dispatch(fetchSearchFail(error));
|
dispatch(fetchSearchFail(error));
|
||||||
|
@ -95,11 +97,12 @@ const fetchSearchRequest = (value: string) => ({
|
||||||
value,
|
value,
|
||||||
});
|
});
|
||||||
|
|
||||||
const fetchSearchSuccess = (results: APIEntity[], searchTerm: string, searchType: SearchFilter) => ({
|
const fetchSearchSuccess = (results: APIEntity[], searchTerm: string, searchType: SearchFilter, next: string | null) => ({
|
||||||
type: SEARCH_FETCH_SUCCESS,
|
type: SEARCH_FETCH_SUCCESS,
|
||||||
results,
|
results,
|
||||||
searchTerm,
|
searchTerm,
|
||||||
searchType,
|
searchType,
|
||||||
|
next,
|
||||||
});
|
});
|
||||||
|
|
||||||
const fetchSearchFail = (error: AxiosError) => ({
|
const fetchSearchFail = (error: AxiosError) => ({
|
||||||
|
@ -125,17 +128,26 @@ const expandSearch = (type: SearchFilter) => (dispatch: AppDispatch, getState: (
|
||||||
|
|
||||||
dispatch(expandSearchRequest(type));
|
dispatch(expandSearchRequest(type));
|
||||||
|
|
||||||
const params: Record<string, any> = {
|
let url = getState().search.next as string;
|
||||||
|
let params: Record<string, any> = {};
|
||||||
|
|
||||||
|
// 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,
|
q: value,
|
||||||
type,
|
type,
|
||||||
offset,
|
offset,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (accountId) params.account_id = accountId;
|
if (accountId) params.account_id = accountId;
|
||||||
|
}
|
||||||
|
|
||||||
api(getState).get('/api/v2/search', {
|
api(getState).get(url, {
|
||||||
params,
|
params,
|
||||||
}).then(({ data }) => {
|
}).then(response => {
|
||||||
|
const data = response.data;
|
||||||
|
|
||||||
if (data.accounts) {
|
if (data.accounts) {
|
||||||
dispatch(importFetchedAccounts(data.accounts));
|
dispatch(importFetchedAccounts(data.accounts));
|
||||||
}
|
}
|
||||||
|
@ -144,7 +156,9 @@ const expandSearch = (type: SearchFilter) => (dispatch: AppDispatch, getState: (
|
||||||
dispatch(importFetchedStatuses(data.statuses));
|
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)));
|
dispatch(fetchRelationships(data.accounts.map((item: APIEntity) => item.id)));
|
||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
dispatch(expandSearchFail(error));
|
dispatch(expandSearchFail(error));
|
||||||
|
@ -156,11 +170,12 @@ const expandSearchRequest = (searchType: SearchFilter) => ({
|
||||||
searchType,
|
searchType,
|
||||||
});
|
});
|
||||||
|
|
||||||
const expandSearchSuccess = (results: APIEntity[], searchTerm: string, searchType: SearchFilter) => ({
|
const expandSearchSuccess = (results: APIEntity[], searchTerm: string, searchType: SearchFilter, next: string | null) => ({
|
||||||
type: SEARCH_EXPAND_SUCCESS,
|
type: SEARCH_EXPAND_SUCCESS,
|
||||||
results,
|
results,
|
||||||
searchTerm,
|
searchTerm,
|
||||||
searchType,
|
searchType,
|
||||||
|
next,
|
||||||
});
|
});
|
||||||
|
|
||||||
const expandSearchFail = (error: AxiosError) => ({
|
const expandSearchFail = (error: AxiosError) => ({
|
||||||
|
|
|
@ -47,6 +47,7 @@ const ReducerRecord = ImmutableRecord({
|
||||||
results: ResultsRecord(),
|
results: ResultsRecord(),
|
||||||
filter: 'accounts' as SearchFilter,
|
filter: 'accounts' as SearchFilter,
|
||||||
accountId: null as string | null,
|
accountId: null as string | null,
|
||||||
|
next: null as string | null,
|
||||||
});
|
});
|
||||||
|
|
||||||
type State = ReturnType<typeof ReducerRecord>;
|
type State = ReturnType<typeof ReducerRecord>;
|
||||||
|
@ -57,7 +58,7 @@ const toIds = (items: APIEntities = []) => {
|
||||||
return ImmutableOrderedSet(items.map(item => item.id));
|
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 => {
|
return state.withMutations(state => {
|
||||||
if (state.value === searchTerm && state.filter === searchType) {
|
if (state.value === searchTerm && state.filter === searchType) {
|
||||||
state.set('results', ResultsRecord({
|
state.set('results', ResultsRecord({
|
||||||
|
@ -76,15 +77,17 @@ const importResults = (state: State, results: APIEntity, searchTerm: string, sea
|
||||||
}));
|
}));
|
||||||
|
|
||||||
state.set('submitted', true);
|
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 => {
|
return state.withMutations(state => {
|
||||||
if (state.value === searchTerm) {
|
if (state.value === searchTerm) {
|
||||||
state.setIn(['results', `${searchType}HasMore`], results[searchType].length >= 20);
|
state.setIn(['results', `${searchType}HasMore`], results[searchType].length >= 20);
|
||||||
state.setIn(['results', `${searchType}Loaded`], true);
|
state.setIn(['results', `${searchType}Loaded`], true);
|
||||||
|
state.set('next', next);
|
||||||
state.updateIn(['results', searchType], items => {
|
state.updateIn(['results', searchType], items => {
|
||||||
const data = results[searchType];
|
const data = results[searchType];
|
||||||
// Hashtags are a list of maps. Others are IDs.
|
// 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:
|
case SEARCH_FETCH_REQUEST:
|
||||||
return handleSubmitted(state, action.value);
|
return handleSubmitted(state, action.value);
|
||||||
case SEARCH_FETCH_SUCCESS:
|
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:
|
case SEARCH_FILTER_SET:
|
||||||
return state.set('filter', action.value);
|
return state.set('filter', action.value);
|
||||||
case SEARCH_EXPAND_REQUEST:
|
case SEARCH_EXPAND_REQUEST:
|
||||||
return state.setIn(['results', `${action.searchType}Loaded`], false);
|
return state.setIn(['results', `${action.searchType}Loaded`], false);
|
||||||
case SEARCH_EXPAND_SUCCESS:
|
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:
|
case SEARCH_ACCOUNT_SET:
|
||||||
if (!action.accountId) return state.merge({
|
if (!action.accountId) return state.merge({
|
||||||
results: ResultsRecord(),
|
results: ResultsRecord(),
|
||||||
|
|
Loading…
Reference in a new issue