From 9250e0c45118237a94884bb762790efcaec9d0f4 Mon Sep 17 00:00:00 2001 From: Akinwale Ariwodola Date: Sun, 5 Jan 2020 12:58:44 +0100 Subject: [PATCH 1/5] add doResolvedSearch actions which returns resolved search results --- dist/bundle.es.js | 85 ++++++++++++++++++++++++++++++++++- dist/flow-typed/Search.js | 20 +++++++++ flow-typed/Search.js | 20 +++++++++ src/constants/action_types.js | 3 ++ src/index.js | 3 ++ src/redux/actions/search.js | 64 ++++++++++++++++++++++++++ src/redux/reducers/search.js | 25 +++++++++++ src/redux/selectors/search.js | 16 +++++++ 8 files changed, 235 insertions(+), 1 deletion(-) diff --git a/dist/bundle.es.js b/dist/bundle.es.js index 035f91c..a1c23ad 100644 --- a/dist/bundle.es.js +++ b/dist/bundle.es.js @@ -162,6 +162,9 @@ const DELETE_PURCHASED_URI = 'DELETE_PURCHASED_URI'; const SEARCH_START = 'SEARCH_START'; const SEARCH_SUCCESS = 'SEARCH_SUCCESS'; const SEARCH_FAIL = 'SEARCH_FAIL'; +const RESOLVED_SEARCH_START = 'RESOLVED_SEARCH_START'; +const RESOLVED_SEARCH_SUCCESS = 'RESOLVED_SEARCH_SUCCESS'; +const RESOLVED_SEARCH_FAIL = 'RESOLVED_SEARCH_FAIL'; const UPDATE_SEARCH_QUERY = 'UPDATE_SEARCH_QUERY'; const UPDATE_SEARCH_OPTIONS = 'UPDATE_SEARCH_OPTIONS'; const UPDATE_SEARCH_SUGGESTIONS = 'UPDATE_SEARCH_SUGGESTIONS'; @@ -401,6 +404,9 @@ var action_types = /*#__PURE__*/Object.freeze({ SEARCH_START: SEARCH_START, SEARCH_SUCCESS: SEARCH_SUCCESS, SEARCH_FAIL: SEARCH_FAIL, + RESOLVED_SEARCH_START: RESOLVED_SEARCH_START, + RESOLVED_SEARCH_SUCCESS: RESOLVED_SEARCH_SUCCESS, + RESOLVED_SEARCH_FAIL: RESOLVED_SEARCH_FAIL, UPDATE_SEARCH_QUERY: UPDATE_SEARCH_QUERY, UPDATE_SEARCH_OPTIONS: UPDATE_SEARCH_OPTIONS, UPDATE_SEARCH_SUGGESTIONS: UPDATE_SEARCH_SUGGESTIONS, @@ -1330,6 +1336,12 @@ const makeSelectSearchUris = query => // replace statement below is kind of ugly, and repeated in doSearch action reselect.createSelector(selectSearchUrisByQuery, byQuery => byQuery[query ? query.replace(/^lbry:\/\//i, '').replace(/\//, ' ') : query]); +const selectResolvedSearchResultsByQuery = reselect.createSelector(selectState, state => state.resolvedResultsByQuery); + +const makeSelectResolvedSearchResults = query => +// replace statement below is kind of ugly, and repeated in doSearch action +reselect.createSelector(selectResolvedSearchResultsByQuery, byQuery => byQuery[query ? query.replace(/^lbry:\/\//i, '').replace(/\//, ' ') : query]); + const selectSearchBarFocused = reselect.createSelector(selectState, state => state.focused); const selectSearchSuggestions = reselect.createSelector(selectSearchValue, selectSuggestions, (query, suggestions) => { @@ -3995,6 +4007,57 @@ from, isBackgroundSearch = false, options = {}, resolveResults = true) => (dispa }); }; +const doResolvedSearch = (rawQuery, size, // only pass in if you don't want to use the users setting (ex: related content) +from, isBackgroundSearch = false, options = {}) => (dispatch, getState) => { + const query = rawQuery.replace(/^lbry:\/\//i, '').replace(/\//, ' '); + + if (!query) { + dispatch({ + type: RESOLVED_SEARCH_FAIL + }); + return; + } + + const state = getState(); + let queryWithOptions = makeSelectQueryWithOptions(query, size, from, isBackgroundSearch, options)(state); + + // If we have already searched for something, we don't need to do anything + const resultsForQuery = makeSelectResolvedSearchResults(queryWithOptions)(state); + if (resultsForQuery && !!resultsForQuery.length) { + return; + } + + dispatch({ + type: RESOLVED_SEARCH_START + }); + + if (!state.search.searchQuery && !isBackgroundSearch) { + dispatch(doUpdateSearchQuery(query)); + } + + fetch(`${CONNECTION_STRING}search?resolve=true&${queryWithOptions}`).then(handleFetchResponse).then(data => { + const results = []; + + data.forEach(result => { + if (result) { + results.push(result); + } + }); + + dispatch({ + type: RESOLVED_SEARCH_SUCCESS, + data: { + query: queryWithOptions, + results + } + }); + }).catch(e => { + dispatch({ + type: RESOLVED_SEARCH_FAIL + }); + }); +}; + const doFocusSearchInput = () => dispatch => dispatch({ type: SEARCH_FOCUS }); @@ -4999,7 +5062,8 @@ const defaultState$7 = { [SEARCH_OPTIONS.MEDIA_APPLICATION]: true }, suggestions: {}, - urisByQuery: {} + urisByQuery: {}, + resolvedResultsByQuery: {} }; const searchReducer = handleActions({ @@ -5019,6 +5083,22 @@ const searchReducer = handleActions({ searching: false }), + [RESOLVED_SEARCH_START]: state => _extends$c({}, state, { + searching: true + }), + [RESOLVED_SEARCH_SUCCESS]: (state, action) => { + const { query, results } = action.data; + + return _extends$c({}, state, { + searching: false, + resolvedResultsByQuery: Object.assign({}, state.resolvedResultsByQuery, { [query]: results }) + }); + }, + + [RESOLVED_SEARCH_FAIL]: state => _extends$c({}, state, { + searching: false + }), + [UPDATE_SEARCH_QUERY]: (state, action) => _extends$c({}, state, { searchQuery: action.data.query, isActive: true @@ -5587,6 +5667,7 @@ exports.doPurchaseUri = doPurchaseUri; exports.doResetThumbnailStatus = doResetThumbnailStatus; exports.doResolveUri = doResolveUri; exports.doResolveUris = doResolveUris; +exports.doResolvedSearch = doResolvedSearch; exports.doSearch = doSearch; exports.doSendDraftTransaction = doSendDraftTransaction; exports.doSendTip = doSendTip; @@ -5655,6 +5736,7 @@ exports.makeSelectPermanentUrlForUri = makeSelectPermanentUrlForUri; exports.makeSelectPublishFormValue = makeSelectPublishFormValue; exports.makeSelectQueryWithOptions = makeSelectQueryWithOptions; exports.makeSelectRecommendedContentForUri = makeSelectRecommendedContentForUri; +exports.makeSelectResolvedSearchResults = makeSelectResolvedSearchResults; exports.makeSelectSearchDownloadUrlsCount = makeSelectSearchDownloadUrlsCount; exports.makeSelectSearchDownloadUrlsForPage = makeSelectSearchDownloadUrlsForPage; exports.makeSelectSearchUris = makeSelectSearchUris; @@ -5747,6 +5829,7 @@ exports.selectPurchasedUris = selectPurchasedUris; exports.selectReceiveAddress = selectReceiveAddress; exports.selectRecentTransactions = selectRecentTransactions; exports.selectReservedBalance = selectReservedBalance; +exports.selectResolvedSearchResultsByQuery = selectResolvedSearchResultsByQuery; exports.selectResolvingUris = selectResolvingUris; exports.selectSearchBarFocused = selectSearchBarFocused; exports.selectSearchOptions = selectSearchOptions; diff --git a/dist/flow-typed/Search.js b/dist/flow-typed/Search.js index 5fad710..9b5c909 100644 --- a/dist/flow-typed/Search.js +++ b/dist/flow-typed/Search.js @@ -28,6 +28,7 @@ declare type SearchState = { options: SearchOptions, suggestions: { [string]: Array }, urisByQuery: {}, + resolvedResultsByQuery: {}, }; declare type SearchSuccess = { @@ -57,3 +58,22 @@ declare type UpdateSearchOptions = { type: ACTIONS.UPDATE_SEARCH_OPTIONS, data: SearchOptions, }; + +declare type ResolvedSearchResult = { + channel: string, + channel_claim_id: string, + claimId: string, + fee: number, + name: string, + release_time: string, + thumbnail_url: string, + title: string, +}; + +declare type ResolvedSearchSuccess = { + type: ACTIONS.RESOLVED_SEARCH_SUCCESS, + data: { + query: string, + results: Array, + }, +}; diff --git a/flow-typed/Search.js b/flow-typed/Search.js index 5fad710..9b5c909 100644 --- a/flow-typed/Search.js +++ b/flow-typed/Search.js @@ -28,6 +28,7 @@ declare type SearchState = { options: SearchOptions, suggestions: { [string]: Array }, urisByQuery: {}, + resolvedResultsByQuery: {}, }; declare type SearchSuccess = { @@ -57,3 +58,22 @@ declare type UpdateSearchOptions = { type: ACTIONS.UPDATE_SEARCH_OPTIONS, data: SearchOptions, }; + +declare type ResolvedSearchResult = { + channel: string, + channel_claim_id: string, + claimId: string, + fee: number, + name: string, + release_time: string, + thumbnail_url: string, + title: string, +}; + +declare type ResolvedSearchSuccess = { + type: ACTIONS.RESOLVED_SEARCH_SUCCESS, + data: { + query: string, + results: Array, + }, +}; diff --git a/src/constants/action_types.js b/src/constants/action_types.js index ac23374..42cf987 100644 --- a/src/constants/action_types.js +++ b/src/constants/action_types.js @@ -139,6 +139,9 @@ export const DELETE_PURCHASED_URI = 'DELETE_PURCHASED_URI'; export const SEARCH_START = 'SEARCH_START'; export const SEARCH_SUCCESS = 'SEARCH_SUCCESS'; export const SEARCH_FAIL = 'SEARCH_FAIL'; +export const RESOLVED_SEARCH_START = 'RESOLVED_SEARCH_START'; +export const RESOLVED_SEARCH_SUCCESS = 'RESOLVED_SEARCH_SUCCESS'; +export const RESOLVED_SEARCH_FAIL = 'RESOLVED_SEARCH_FAIL'; export const UPDATE_SEARCH_QUERY = 'UPDATE_SEARCH_QUERY'; export const UPDATE_SEARCH_OPTIONS = 'UPDATE_SEARCH_OPTIONS'; export const UPDATE_SEARCH_SUGGESTIONS = 'UPDATE_SEARCH_SUGGESTIONS'; diff --git a/src/index.js b/src/index.js index 65f1db9..be0a3d0 100644 --- a/src/index.js +++ b/src/index.js @@ -90,6 +90,7 @@ export { export { doSearch, + doResolvedSearch, doUpdateSearchQuery, doFocusSearchInput, doBlurSearchInput, @@ -265,9 +266,11 @@ export { export { selectSearchState }; export { makeSelectSearchUris, + makeSelectResolvedSearchResults, selectSearchValue, selectSearchOptions, selectIsSearching, + selectResolvedSearchResultsByQuery, selectSearchUrisByQuery, selectSearchBarFocused, selectSearchSuggestions, diff --git a/src/redux/actions/search.js b/src/redux/actions/search.js index 3cd3a47..ccab1c3 100644 --- a/src/redux/actions/search.js +++ b/src/redux/actions/search.js @@ -4,6 +4,7 @@ import { buildURI } from 'lbryURI'; import { doResolveUri } from 'redux/actions/claims'; import { makeSelectSearchUris, + makeSelectResolvedSearchResults, selectSuggestions, makeSelectQueryWithOptions, selectSearchValue, @@ -159,6 +160,69 @@ export const doSearch = ( }); }; +export const doResolvedSearch = ( + rawQuery: string, + size: ?number, // only pass in if you don't want to use the users setting (ex: related content) + from: ?number, + isBackgroundSearch: boolean = false, + options: { + related_to?: string, + } = {} +) => (dispatch: Dispatch, getState: GetState) => { + const query = rawQuery.replace(/^lbry:\/\//i, '').replace(/\//, ' '); + + if (!query) { + dispatch({ + type: ACTIONS.RESOLVED_SEARCH_FAIL, + }); + return; + } + + const state = getState(); + let queryWithOptions = makeSelectQueryWithOptions(query, size, from, isBackgroundSearch, options)( + state + ); + + // If we have already searched for something, we don't need to do anything + const resultsForQuery = makeSelectResolvedSearchResults(queryWithOptions)(state); + if (resultsForQuery && !!resultsForQuery.length) { + return; + } + + dispatch({ + type: ACTIONS.RESOLVED_SEARCH_START, + }); + + if (!state.search.searchQuery && !isBackgroundSearch) { + dispatch(doUpdateSearchQuery(query)); + } + + fetch(`${CONNECTION_STRING}search?resolve=true&${queryWithOptions}`) + .then(handleFetchResponse) + .then((data: Array) => { + const results = []; + + data.forEach(result => { + if (result) { + results.push(result); + } + }); + + dispatch({ + type: ACTIONS.RESOLVED_SEARCH_SUCCESS, + data: { + query: queryWithOptions, + results, + }, + }); + }) + .catch(e => { + dispatch({ + type: ACTIONS.RESOLVED_SEARCH_FAIL, + }); + }); +}; + export const doFocusSearchInput = () => (dispatch: Dispatch) => dispatch({ type: ACTIONS.SEARCH_FOCUS, diff --git a/src/redux/reducers/search.js b/src/redux/reducers/search.js index ee0bd8b..fe5a443 100644 --- a/src/redux/reducers/search.js +++ b/src/redux/reducers/search.js @@ -18,6 +18,7 @@ const defaultState = { }, suggestions: {}, urisByQuery: {}, + resolvedResultsByQuery: {}, }; export const searchReducer = handleActions( @@ -41,6 +42,30 @@ export const searchReducer = handleActions( searching: false, }), + [ACTIONS.RESOLVED_SEARCH_START]: (state: SearchState): SearchState => ({ + ...state, + searching: true, + }), + [ACTIONS.RESOLVED_SEARCH_SUCCESS]: ( + state: SearchState, + action: ResolvedSearchSuccess + ): SearchState => { + const { query, results } = action.data; + + return { + ...state, + searching: false, + resolvedResultsByQuery: Object.assign({}, state.resolvedResultsByQuery, { + [query]: results, + }), + }; + }, + + [ACTIONS.RESOLVED_SEARCH_FAIL]: (state: SearchState): SearchState => ({ + ...state, + searching: false, + }), + [ACTIONS.UPDATE_SEARCH_QUERY]: ( state: SearchState, action: UpdateSearchQuery diff --git a/src/redux/selectors/search.js b/src/redux/selectors/search.js index d556602..2dc006a 100644 --- a/src/redux/selectors/search.js +++ b/src/redux/selectors/search.js @@ -44,6 +44,22 @@ export const makeSelectSearchUris = (query: string): ((state: State) => Array byQuery[query ? query.replace(/^lbry:\/\//i, '').replace(/\//, ' ') : query] ); +export const selectResolvedSearchResultsByQuery: ( + state: State +) => { [string]: Array } = createSelector( + selectState, + state => state.resolvedResultsByQuery +); + +export const makeSelectResolvedSearchResults = ( + query: string +): ((state: State) => Array) => + // replace statement below is kind of ugly, and repeated in doSearch action + createSelector( + selectResolvedSearchResultsByQuery, + byQuery => byQuery[query ? query.replace(/^lbry:\/\//i, '').replace(/\//, ' ') : query] + ); + export const selectSearchBarFocused: boolean = createSelector( selectState, state => state.focused -- 2.45.2 From 6ef2f9dde9167f3217fde2d7d3fed97282bdb0dc Mon Sep 17 00:00:00 2001 From: Akinwale Ariwodola Date: Sun, 5 Jan 2020 13:40:48 +0100 Subject: [PATCH 2/5] add recommended content selector --- dist/bundle.es.js | 33 +++++++++++++++++++++++++++- src/index.js | 1 + src/redux/selectors/claims.js | 41 ++++++++++++++++++++++++++++++++++- 3 files changed, 73 insertions(+), 2 deletions(-) diff --git a/dist/bundle.es.js b/dist/bundle.es.js index a1c23ad..1fb9212 100644 --- a/dist/bundle.es.js +++ b/dist/bundle.es.js @@ -2277,6 +2277,34 @@ const makeSelectMyStreamUrlsForPage = (page = 1) => reselect.createSelector(sele const selectMyStreamUrlsCount = reselect.createSelector(selectMyClaimUrisWithoutChannels, channels => channels.length); +const makeSelectResolvedRecommendedContentForUri = (uri, size) => reselect.createSelector(makeSelectClaimForUri(uri), selectResolvedSearchResultsByQuery, (claim, resolvedResultsByQuery) => { + const atVanityURI = !uri.includes('#'); + + let recommendedContent; + if (claim) { + // always grab full URL - this can change once search returns canonical + const currentUri = buildURI({ streamClaimId: claim.claim_id, streamName: claim.name }); + + const { title } = claim.value; + + if (!title) { + return; + } + + const searchQuery = getSearchQueryString(title.replace(/\//, ' '), { size }, undefined, { + related_to: claim.claim_id + }); + + let results = resolvedResultsByQuery[searchQuery]; + if (results) { + results = results.filter(result => buildURI({ streamClaimId: result.claimId, streamName: result.name }) !== currentUri); + recommendedContent = results; + } + } + + return recommendedContent; +}); + function numberWithCommas(x) { var parts = x.toString().split('.'); parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ','); @@ -5091,7 +5119,9 @@ const searchReducer = handleActions({ return _extends$c({}, state, { searching: false, - resolvedResultsByQuery: Object.assign({}, state.resolvedResultsByQuery, { [query]: results }) + resolvedResultsByQuery: Object.assign({}, state.resolvedResultsByQuery, { + [query]: results + }) }); }, @@ -5736,6 +5766,7 @@ exports.makeSelectPermanentUrlForUri = makeSelectPermanentUrlForUri; exports.makeSelectPublishFormValue = makeSelectPublishFormValue; exports.makeSelectQueryWithOptions = makeSelectQueryWithOptions; exports.makeSelectRecommendedContentForUri = makeSelectRecommendedContentForUri; +exports.makeSelectResolvedRecommendedContentForUri = makeSelectResolvedRecommendedContentForUri; exports.makeSelectResolvedSearchResults = makeSelectResolvedSearchResults; exports.makeSelectSearchDownloadUrlsCount = makeSelectSearchDownloadUrlsCount; exports.makeSelectSearchDownloadUrlsForPage = makeSelectSearchDownloadUrlsForPage; diff --git a/src/index.js b/src/index.js index be0a3d0..fceec98 100644 --- a/src/index.js +++ b/src/index.js @@ -184,6 +184,7 @@ export { makeSelectOmittedCountForChannel, makeSelectClaimIsNsfw, makeSelectRecommendedContentForUri, + makeSelectResolvedRecommendedContentForUri, makeSelectFirstRecommendedFileForUri, makeSelectChannelForClaimUri, makeSelectClaimIsPending, diff --git a/src/redux/selectors/claims.js b/src/redux/selectors/claims.js index e825188..6adf368 100644 --- a/src/redux/selectors/claims.js +++ b/src/redux/selectors/claims.js @@ -1,6 +1,9 @@ // @flow import { normalizeURI, buildURI, parseURI } from 'lbryURI'; -import { selectSearchUrisByQuery } from 'redux/selectors/search'; +import { + selectResolvedSearchResultsByQuery, + selectSearchUrisByQuery, +} from 'redux/selectors/search'; import { selectSupportsByOutpoint } from 'redux/selectors/wallet'; import { createSelector } from 'reselect'; import { isClaimNsfw, createNormalizedClaimSearchKey } from 'util/claim'; @@ -639,3 +642,39 @@ export const selectMyStreamUrlsCount = createSelector( selectMyClaimUrisWithoutChannels, channels => channels.length ); + +export const makeSelectResolvedRecommendedContentForUri = (uri: string, size: number) => + createSelector( + makeSelectClaimForUri(uri), + selectResolvedSearchResultsByQuery, + (claim, resolvedResultsByQuery) => { + const atVanityURI = !uri.includes('#'); + + let recommendedContent; + if (claim) { + // always grab full URL - this can change once search returns canonical + const currentUri = buildURI({ streamClaimId: claim.claim_id, streamName: claim.name }); + + const { title } = claim.value; + + if (!title) { + return; + } + + const searchQuery = getSearchQueryString(title.replace(/\//, ' '), { size }, undefined, { + related_to: claim.claim_id, + }); + + let results = resolvedResultsByQuery[searchQuery]; + if (results) { + results = results.filter( + result => + buildURI({ streamClaimId: result.claimId, streamName: result.name }) !== currentUri + ); + recommendedContent = results; + } + } + + return recommendedContent; + } + ); -- 2.45.2 From e8f29f1c47b136669df265babb109d2488a37db0 Mon Sep 17 00:00:00 2001 From: Akinwale Ariwodola Date: Sun, 5 Jan 2020 17:56:08 +0100 Subject: [PATCH 3/5] update ResolvedSearchResult type --- dist/flow-typed/Search.js | 2 ++ flow-typed/Search.js | 2 ++ 2 files changed, 4 insertions(+) diff --git a/dist/flow-typed/Search.js b/dist/flow-typed/Search.js index 9b5c909..b099a47 100644 --- a/dist/flow-typed/Search.js +++ b/dist/flow-typed/Search.js @@ -63,8 +63,10 @@ declare type ResolvedSearchResult = { channel: string, channel_claim_id: string, claimId: string, + duration: number, fee: number, name: string, + nsfw: boolean, release_time: string, thumbnail_url: string, title: string, diff --git a/flow-typed/Search.js b/flow-typed/Search.js index 9b5c909..b099a47 100644 --- a/flow-typed/Search.js +++ b/flow-typed/Search.js @@ -63,8 +63,10 @@ declare type ResolvedSearchResult = { channel: string, channel_claim_id: string, claimId: string, + duration: number, fee: number, name: string, + nsfw: boolean, release_time: string, thumbnail_url: string, title: string, -- 2.45.2 From c910cd2b80b165843a81fdf6ce96094429b94ec8 Mon Sep 17 00:00:00 2001 From: Akinwale Ariwodola Date: Wed, 8 Jan 2020 09:09:45 +0100 Subject: [PATCH 4/5] support for multiple pages of resolved search results --- dist/bundle.es.js | 46 +++++++++++++++++++++++++++-------- dist/flow-typed/Search.js | 5 +++- flow-typed/Search.js | 5 +++- src/index.js | 2 ++ src/redux/actions/search.js | 16 +++++++++--- src/redux/reducers/search.js | 26 +++++++++++++++++--- src/redux/selectors/search.js | 16 ++++++++++++ 7 files changed, 96 insertions(+), 20 deletions(-) diff --git a/dist/bundle.es.js b/dist/bundle.es.js index 1fb9212..5e8dd3c 100644 --- a/dist/bundle.es.js +++ b/dist/bundle.es.js @@ -1338,10 +1338,16 @@ reselect.createSelector(selectSearchUrisByQuery, byQuery => byQuery[query ? quer const selectResolvedSearchResultsByQuery = reselect.createSelector(selectState, state => state.resolvedResultsByQuery); +const selectResolvedSearchResultsByQueryLastPageReached = reselect.createSelector(selectState, state => state.resolvedResultsByQueryLastPageReached); + const makeSelectResolvedSearchResults = query => // replace statement below is kind of ugly, and repeated in doSearch action reselect.createSelector(selectResolvedSearchResultsByQuery, byQuery => byQuery[query ? query.replace(/^lbry:\/\//i, '').replace(/\//, ' ') : query]); +const makeSelectResolvedSearchResultsLastPageReached = query => +// replace statement below is kind of ugly, and repeated in doSearch action +reselect.createSelector(selectResolvedSearchResultsByQueryLastPageReached, byQuery => byQuery[query ? query.replace(/^lbry:\/\//i, '').replace(/\//, ' ') : query]); + const selectSearchBarFocused = reselect.createSelector(selectState, state => state.focused); const selectSearchSuggestions = reselect.createSelector(selectSearchValue, selectSuggestions, (query, suggestions) => { @@ -4049,11 +4055,15 @@ from, isBackgroundSearch = false, options = {}) => (dispatch, getState) => { const state = getState(); let queryWithOptions = makeSelectQueryWithOptions(query, size, from, isBackgroundSearch, options)(state); + // make from null so that we can maintain a reference to the same query for multiple pages and simply append the found results + let queryWithoutFrom = makeSelectQueryWithOptions(query, size, null, isBackgroundSearch, options)(state); + // If we have already searched for something, we don't need to do anything - const resultsForQuery = makeSelectResolvedSearchResults(queryWithOptions)(state); - if (resultsForQuery && !!resultsForQuery.length) { + // TODO: Tweak this check for multiple page results + /* const resultsForQuery = makeSelectResolvedSearchResults(queryWithOptions)(state); + if (resultsForQuery && resultsForQuery.length && resultsForQuery.length > (from * size)) { return; - } + } */ dispatch({ type: RESOLVED_SEARCH_START @@ -4075,8 +4085,10 @@ from, isBackgroundSearch = false, options = {}) => (dispatch, getState) => { dispatch({ type: RESOLVED_SEARCH_SUCCESS, data: { - query: queryWithOptions, - results + query: queryWithoutFrom, + results, + pageSize: size, + append: parseInt(from, 10) > parseInt(size, 10) - 1 } }); }).catch(e => { @@ -5091,7 +5103,8 @@ const defaultState$7 = { }, suggestions: {}, urisByQuery: {}, - resolvedResultsByQuery: {} + resolvedResultsByQuery: {}, + resolvedResultsByQueryLastPageReached: {} }; const searchReducer = handleActions({ @@ -5115,13 +5128,24 @@ const searchReducer = handleActions({ searching: true }), [RESOLVED_SEARCH_SUCCESS]: (state, action) => { - const { query, results } = action.data; + const resolvedResultsByQuery = Object.assign({}, state.resolvedResultsByQuery); + const resolvedResultsByQueryLastPageReached = Object.assign({}, state.resolvedResultsByQueryLastPageReached); + const { append, query, results, pageSize } = action.data; + + if (append) { + // todo: check for duplicates when concatenating? + resolvedResultsByQuery[query] = resolvedResultsByQuery[query] && resolvedResultsByQuery[query].length ? resolvedResultsByQuery[query].concat(results) : results; + } else { + resolvedResultsByQuery[query] = results; + } + + // the returned number of urls is less than the page size, so we're on the last page + resolvedResultsByQueryLastPageReached[query] = results.length < pageSize; return _extends$c({}, state, { searching: false, - resolvedResultsByQuery: Object.assign({}, state.resolvedResultsByQuery, { - [query]: results - }) + resolvedResultsByQuery, + resolvedResultsByQueryLastPageReached }); }, @@ -5768,6 +5792,7 @@ exports.makeSelectQueryWithOptions = makeSelectQueryWithOptions; exports.makeSelectRecommendedContentForUri = makeSelectRecommendedContentForUri; exports.makeSelectResolvedRecommendedContentForUri = makeSelectResolvedRecommendedContentForUri; exports.makeSelectResolvedSearchResults = makeSelectResolvedSearchResults; +exports.makeSelectResolvedSearchResultsLastPageReached = makeSelectResolvedSearchResultsLastPageReached; exports.makeSelectSearchDownloadUrlsCount = makeSelectSearchDownloadUrlsCount; exports.makeSelectSearchDownloadUrlsForPage = makeSelectSearchDownloadUrlsForPage; exports.makeSelectSearchUris = makeSelectSearchUris; @@ -5861,6 +5886,7 @@ exports.selectReceiveAddress = selectReceiveAddress; exports.selectRecentTransactions = selectRecentTransactions; exports.selectReservedBalance = selectReservedBalance; exports.selectResolvedSearchResultsByQuery = selectResolvedSearchResultsByQuery; +exports.selectResolvedSearchResultsByQueryLastPageReached = selectResolvedSearchResultsByQueryLastPageReached; exports.selectResolvingUris = selectResolvingUris; exports.selectSearchBarFocused = selectSearchBarFocused; exports.selectSearchOptions = selectSearchOptions; diff --git a/dist/flow-typed/Search.js b/dist/flow-typed/Search.js index b099a47..2a2152e 100644 --- a/dist/flow-typed/Search.js +++ b/dist/flow-typed/Search.js @@ -29,6 +29,7 @@ declare type SearchState = { suggestions: { [string]: Array }, urisByQuery: {}, resolvedResultsByQuery: {}, + resolvedResultsByQueryLastPageReached: {}, }; declare type SearchSuccess = { @@ -75,7 +76,9 @@ declare type ResolvedSearchResult = { declare type ResolvedSearchSuccess = { type: ACTIONS.RESOLVED_SEARCH_SUCCESS, data: { - query: string, + append: boolean, + pageSize: number, results: Array, + query: string, }, }; diff --git a/flow-typed/Search.js b/flow-typed/Search.js index b099a47..2a2152e 100644 --- a/flow-typed/Search.js +++ b/flow-typed/Search.js @@ -29,6 +29,7 @@ declare type SearchState = { suggestions: { [string]: Array }, urisByQuery: {}, resolvedResultsByQuery: {}, + resolvedResultsByQueryLastPageReached: {}, }; declare type SearchSuccess = { @@ -75,7 +76,9 @@ declare type ResolvedSearchResult = { declare type ResolvedSearchSuccess = { type: ACTIONS.RESOLVED_SEARCH_SUCCESS, data: { - query: string, + append: boolean, + pageSize: number, results: Array, + query: string, }, }; diff --git a/src/index.js b/src/index.js index fceec98..b9d554f 100644 --- a/src/index.js +++ b/src/index.js @@ -268,10 +268,12 @@ export { selectSearchState }; export { makeSelectSearchUris, makeSelectResolvedSearchResults, + makeSelectResolvedSearchResultsLastPageReached, selectSearchValue, selectSearchOptions, selectIsSearching, selectResolvedSearchResultsByQuery, + selectResolvedSearchResultsByQueryLastPageReached, selectSearchUrisByQuery, selectSearchBarFocused, selectSearchSuggestions, diff --git a/src/redux/actions/search.js b/src/redux/actions/search.js index ccab1c3..e00d7ba 100644 --- a/src/redux/actions/search.js +++ b/src/redux/actions/search.js @@ -183,11 +183,17 @@ export const doResolvedSearch = ( state ); + // make from null so that we can maintain a reference to the same query for multiple pages and simply append the found results + let queryWithoutFrom = makeSelectQueryWithOptions(query, size, null, isBackgroundSearch, options)( + state + ); + // If we have already searched for something, we don't need to do anything - const resultsForQuery = makeSelectResolvedSearchResults(queryWithOptions)(state); - if (resultsForQuery && !!resultsForQuery.length) { + // TODO: Tweak this check for multiple page results + /* const resultsForQuery = makeSelectResolvedSearchResults(queryWithOptions)(state); + if (resultsForQuery && resultsForQuery.length && resultsForQuery.length > (from * size)) { return; - } + } */ dispatch({ type: ACTIONS.RESOLVED_SEARCH_START, @@ -211,8 +217,10 @@ export const doResolvedSearch = ( dispatch({ type: ACTIONS.RESOLVED_SEARCH_SUCCESS, data: { - query: queryWithOptions, + query: queryWithoutFrom, results, + pageSize: size, + append: parseInt(from, 10) > parseInt(size, 10) - 1, }, }); }) diff --git a/src/redux/reducers/search.js b/src/redux/reducers/search.js index fe5a443..27e1013 100644 --- a/src/redux/reducers/search.js +++ b/src/redux/reducers/search.js @@ -19,6 +19,7 @@ const defaultState = { suggestions: {}, urisByQuery: {}, resolvedResultsByQuery: {}, + resolvedResultsByQueryLastPageReached: {}, }; export const searchReducer = handleActions( @@ -50,14 +51,31 @@ export const searchReducer = handleActions( state: SearchState, action: ResolvedSearchSuccess ): SearchState => { - const { query, results } = action.data; + const resolvedResultsByQuery = Object.assign({}, state.resolvedResultsByQuery); + const resolvedResultsByQueryLastPageReached = Object.assign( + {}, + state.resolvedResultsByQueryLastPageReached + ); + const { append, query, results, pageSize } = action.data; + + if (append) { + // todo: check for duplicates when concatenating? + resolvedResultsByQuery[query] = + resolvedResultsByQuery[query] && resolvedResultsByQuery[query].length + ? resolvedResultsByQuery[query].concat(results) + : results; + } else { + resolvedResultsByQuery[query] = results; + } + + // the returned number of urls is less than the page size, so we're on the last page + resolvedResultsByQueryLastPageReached[query] = results.length < pageSize; return { ...state, searching: false, - resolvedResultsByQuery: Object.assign({}, state.resolvedResultsByQuery, { - [query]: results, - }), + resolvedResultsByQuery, + resolvedResultsByQueryLastPageReached, }; }, diff --git a/src/redux/selectors/search.js b/src/redux/selectors/search.js index 2dc006a..48dca04 100644 --- a/src/redux/selectors/search.js +++ b/src/redux/selectors/search.js @@ -51,6 +51,13 @@ export const selectResolvedSearchResultsByQuery: ( state => state.resolvedResultsByQuery ); +export const selectResolvedSearchResultsByQueryLastPageReached: ( + state: State +) => { [string]: Array } = createSelector( + selectState, + state => state.resolvedResultsByQueryLastPageReached +); + export const makeSelectResolvedSearchResults = ( query: string ): ((state: State) => Array) => @@ -60,6 +67,15 @@ export const makeSelectResolvedSearchResults = ( byQuery => byQuery[query ? query.replace(/^lbry:\/\//i, '').replace(/\//, ' ') : query] ); +export const makeSelectResolvedSearchResultsLastPageReached = ( + query: string +): ((state: State) => boolean) => + // replace statement below is kind of ugly, and repeated in doSearch action + createSelector( + selectResolvedSearchResultsByQueryLastPageReached, + byQuery => byQuery[query ? query.replace(/^lbry:\/\//i, '').replace(/\//, ' ') : query] + ); + export const selectSearchBarFocused: boolean = createSelector( selectState, state => state.focused -- 2.45.2 From acbbc66b78566da11faa0fa8c65b44a8d4302c5e Mon Sep 17 00:00:00 2001 From: Akinwale Ariwodola Date: Mon, 3 Feb 2020 07:25:44 +0100 Subject: [PATCH 5/5] add nsfw flag --- dist/bundle.es.js | 5 +++-- src/redux/actions/search.js | 8 ++++++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/dist/bundle.es.js b/dist/bundle.es.js index 0549d59..1c85e26 100644 --- a/dist/bundle.es.js +++ b/dist/bundle.es.js @@ -4055,7 +4055,7 @@ from, isBackgroundSearch = false, options = {}, resolveResults = true) => (dispa }; const doResolvedSearch = (rawQuery, size, // only pass in if you don't want to use the users setting (ex: related content) -from, isBackgroundSearch = false, options = {}) => (dispatch, getState) => { +from, isBackgroundSearch = false, options = {}, nsfw) => (dispatch, getState) => { const query = rawQuery.replace(/^lbry:\/\//i, '').replace(/\//, ' '); if (!query) { @@ -4086,7 +4086,8 @@ from, isBackgroundSearch = false, options = {}) => (dispatch, getState) => { dispatch(doUpdateSearchQuery(query)); } - fetch(`${CONNECTION_STRING}search?resolve=true&${queryWithOptions}`).then(handleFetchResponse).then(data => { + const fetchUrl = nsfw ? `${CONNECTION_STRING}search?resolve=true&${queryWithOptions}` : `${CONNECTION_STRING}search?resolve=true&nsfw=false&${queryWithOptions}`; + fetch(fetchUrl).then(handleFetchResponse).then(data => { const results = []; data.forEach(result => { diff --git a/src/redux/actions/search.js b/src/redux/actions/search.js index e00d7ba..fc17b4b 100644 --- a/src/redux/actions/search.js +++ b/src/redux/actions/search.js @@ -167,7 +167,8 @@ export const doResolvedSearch = ( isBackgroundSearch: boolean = false, options: { related_to?: string, - } = {} + } = {}, + nsfw: boolean ) => (dispatch: Dispatch, getState: GetState) => { const query = rawQuery.replace(/^lbry:\/\//i, '').replace(/\//, ' '); @@ -203,7 +204,10 @@ export const doResolvedSearch = ( dispatch(doUpdateSearchQuery(query)); } - fetch(`${CONNECTION_STRING}search?resolve=true&${queryWithOptions}`) + const fetchUrl = nsfw + ? `${CONNECTION_STRING}search?resolve=true&${queryWithOptions}` + : `${CONNECTION_STRING}search?resolve=true&nsfw=false&${queryWithOptions}`; + fetch(fetchUrl) .then(handleFetchResponse) .then((data: Array) => { const results = []; -- 2.45.2