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