cache claim search results by query

This commit is contained in:
Sean Yesmunt 2019-07-17 16:50:58 -04:00
parent 49e57e8ba0
commit b87e2f92f3
14 changed files with 189 additions and 107 deletions

124
dist/bundle.es.js vendored
View file

@ -7,6 +7,8 @@ function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'defau
require('proxy-polyfill');
var reselect = require('reselect');
var uuid = _interopDefault(require('uuid/v4'));
var formatCredits$1 = require('util/formatCredits');
require('util/batchActions');
var fs = _interopDefault(require('fs'));
var path = _interopDefault(require('path'));
@ -1308,12 +1310,14 @@ const makeSelectClaimForUri = uri => reselect.createSelector(selectClaimsByUri,
// Check if a claim is pending first
// It won't be in claimsByUri because resolving it will return nothing
let valid;
let claimId;
try {
({ claimId } = parseURI(uri));
valid = true;
} catch (e) {}
if (claimId) {
if (valid) {
const pendingClaim = pendingById[claimId];
if (pendingClaim) {
@ -1551,7 +1555,7 @@ const makeSelectTagsForUri = uri => reselect.createSelector(makeSelectMetadataFo
const selectFetchingClaimSearch = reselect.createSelector(selectState$1, state => state.fetchingClaimSearch);
const selectLastClaimSearchUris = reselect.createSelector(selectState$1, state => state.lastClaimSearchUris);
const selectClaimSearchByQuery = reselect.createSelector(selectState$1, state => state.claimSearchSearchByQuery || {});
const makeSelectShortUrlForUri = uri => reselect.createSelector(makeSelectClaimForUri(uri), claim => claim && claim.short_url);
@ -1702,34 +1706,6 @@ const selectCurrentHeight = reselect.createSelector(selectState$2, state => stat
const selectTransactionListFilter = reselect.createSelector(selectState$2, state => state.transactionListFilter || '');
function formatCredits(amount, precision) {
if (Number.isNaN(parseFloat(amount))) return '0';
return parseFloat(amount).toFixed(precision || 1).replace(/\.?0+$/, '');
}
function formatFullPrice(amount, precision = 1) {
let formated = '';
const quantity = amount.toString().split('.');
const fraction = quantity[1];
if (fraction) {
const decimals = fraction.split('');
const first = decimals.filter(number => number !== '0')[0];
const index = decimals.indexOf(first);
// Set format fraction
formated = `.${fraction.substring(0, index + precision)}`;
}
return parseFloat(quantity[0] + formated);
}
function creditsToString(amount) {
const creditString = parseFloat(amount).toFixed(8);
return creditString;
}
function doUpdateBalance() {
return (dispatch, getState) => {
const {
@ -1902,7 +1878,7 @@ function doSendDraftTransaction(address, amount) {
lbryProxy.account_send({
addresses: [address],
amount: creditsToString(amount)
amount: formatCredits$1.creditsToString(amount)
}).then(successCallback, errorCallback);
};
}
@ -1977,7 +1953,7 @@ function doSendTip(amount, claimId, successCallback, errorCallback) {
lbryProxy.support_create({
claim_id: claimId,
amount: creditsToString(amount),
amount: formatCredits$1.creditsToString(amount),
tip: isSupport ? false : true
}).then(success, error);
};
@ -2084,6 +2060,17 @@ function doUpdateBlockHeight() {
});
}
function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; }
//
function buildClaimSearchCacheQuery(options) {
// Ignore page because we don't care what the last page searched was, we want everything
// Ignore release_time because that will change depending on when you call claim_search ex: release_time: ">12344567"
const rest = _objectWithoutProperties(options, ["page", "release_time"]);
const query = JSON.stringify(rest);
return query;
}
var _extends$3 = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
function doResolveUris(uris, returnCachedClaims = false) {
@ -2291,7 +2278,7 @@ function doCreateChannel(name, amount) {
return lbryProxy.channel_create({
name,
bid: creditsToString(amount)
bid: formatCredits$1.creditsToString(amount)
})
// outputs[0] is the certificate
// outputs[1] is the change from the tx, not in the app currently
@ -2317,7 +2304,7 @@ function doUpdateChannel(params) {
});
const updateParams = {
claim_id: params.claim_id,
bid: creditsToString(params.amount),
bid: formatCredits$1.creditsToString(params.amount),
title: params.title,
cover_url: params.cover,
thumbnail_url: params.thumbnail,
@ -2367,6 +2354,8 @@ function doFetchChannelListMine() {
}
function doClaimSearch(options = {}) {
const query = buildClaimSearchCacheQuery(options);
return dispatch => {
dispatch({
type: CLAIM_SEARCH_STARTED
@ -2382,7 +2371,7 @@ function doClaimSearch(options = {}) {
dispatch({
type: CLAIM_SEARCH_COMPLETED,
data: { resolveInfo, uris, append: options.page && options.page !== 1 }
data: { resolveInfo, uris, query, append: options.page && options.page !== 1 }
});
};
@ -2788,12 +2777,40 @@ function batchActions(...actions) {
};
}
function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; }
function formatCredits(amount, precision) {
if (Number.isNaN(parseFloat(amount))) return '0';
return parseFloat(amount).toFixed(precision || 1).replace(/\.?0+$/, '');
}
function formatFullPrice(amount, precision = 1) {
let formated = '';
const quantity = amount.toString().split('.');
const fraction = quantity[1];
if (fraction) {
const decimals = fraction.split('');
const first = decimals.filter(number => number !== '0')[0];
const index = decimals.indexOf(first);
// Set format fraction
formated = `.${fraction.substring(0, index + precision)}`;
}
return parseFloat(quantity[0] + formated);
}
function creditsToString(amount) {
const creditString = parseFloat(amount).toFixed(8);
return creditString;
}
function _objectWithoutProperties$1(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; }
const selectState$5 = state => state.publish || {};
const selectPublishFormValues = reselect.createSelector(selectState$5, state => {
const formValues = _objectWithoutProperties(state, ['pendingPublish']);
const formValues = _objectWithoutProperties$1(state, ['pendingPublish']);
return formValues;
});
const makeSelectPublishFormValue = item => reselect.createSelector(selectState$5, state => state[item]);
@ -3475,6 +3492,7 @@ const defaultState = {
fetchingMyChannels: false,
abandoningById: {},
pendingById: {},
claimSearchError: undefined,
fetchingClaimSearch: false,
claimSearchUrisByTags: {},
fetchingClaimSearchByTags: {},
@ -3709,27 +3727,34 @@ reducers[RESOLVE_URIS_STARTED] = (state, action) => {
reducers[CLAIM_SEARCH_STARTED] = state => {
return Object.assign({}, state, {
fetchingClaimSearch: true
fetchingClaimSearch: true,
claimSearchError: false
});
};
reducers[CLAIM_SEARCH_COMPLETED] = (state, action) => {
const { lastClaimSearchUris } = state;
let newClaimSearchUris = [];
if (action.data.append) {
newClaimSearchUris = lastClaimSearchUris.concat(action.data.uris);
reducers[CLAIM_SEARCH_COMPLETED] = (state, action) => {
const { claimSearchSearchByQuery } = state;
const { uris, query, append } = action.data;
let newClaimSearch = _extends$5({}, claimSearchSearchByQuery);
if (!uris) {
newClaimSearch[query] = null;
} else if (append && newClaimSearch[query]) {
newClaimSearch[query] = newClaimSearch[query].concat(uris);
} else {
newClaimSearchUris = action.data.uris;
newClaimSearch[query] = uris;
}
return _extends$5({}, handleClaimAction(state, action), {
fetchingClaimSearch: false,
lastClaimSearchUris: newClaimSearchUris
claimSearchSearchByQuery: newClaimSearch
});
};
reducers[CLAIM_SEARCH_FAILED] = state => {
return Object.assign({}, state, {
fetchingClaimSearch: false
fetchingClaimSearch: false,
claimSearchError: true
});
};
@ -4209,7 +4234,7 @@ const notificationsReducer = handleActions({
var _extends$b = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
function _objectWithoutProperties$1(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; }
function _objectWithoutProperties$2(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; }
const defaultState$6 = {
editingURI: undefined,
@ -4259,7 +4284,7 @@ const publishReducer = handleActions({
publishSuccess: true
}),
[DO_PREPARE_EDIT]: (state, action) => {
const publishData = _objectWithoutProperties$1(action.data, []);
const publishData = _objectWithoutProperties$2(action.data, []);
const { channel, name, uri } = publishData;
// The short uri is what is presented to the user
@ -4761,6 +4786,7 @@ exports.SORT_OPTIONS = sort_options;
exports.THUMBNAIL_STATUSES = thumbnail_upload_statuses;
exports.TRANSACTIONS = transaction_types;
exports.batchActions = batchActions;
exports.buildClaimSearchCacheQuery = buildClaimSearchCacheQuery;
exports.buildURI = buildURI;
exports.claimsReducer = claimsReducer;
exports.commentReducer = commentReducer;
@ -4883,6 +4909,7 @@ exports.selectAllMyClaimsByOutpoint = selectAllMyClaimsByOutpoint;
exports.selectBalance = selectBalance;
exports.selectBlocks = selectBlocks;
exports.selectChannelClaimCounts = selectChannelClaimCounts;
exports.selectClaimSearchByQuery = selectClaimSearchByQuery;
exports.selectClaimSearchUrisByTags = selectClaimSearchUrisByTags;
exports.selectClaimsById = selectClaimsById;
exports.selectClaimsByUri = selectClaimsByUri;
@ -4914,7 +4941,6 @@ exports.selectIsResolvingPublishUris = selectIsResolvingPublishUris;
exports.selectIsSearching = selectIsSearching;
exports.selectIsSendingSupport = selectIsSendingSupport;
exports.selectIsStillEditing = selectIsStillEditing;
exports.selectLastClaimSearchUris = selectLastClaimSearchUris;
exports.selectLastPurchasedUri = selectLastPurchasedUri;
exports.selectMyActiveClaims = selectMyActiveClaims;
exports.selectMyChannelClaims = selectMyChannelClaims;

View file

@ -113,10 +113,11 @@ export { doToggleTagFollow, doAddTag, doDeleteTag } from 'redux/actions/tags';
export { doCommentList, doCommentCreate } from 'redux/actions/comments';
// utils
export { batchActions } from 'util/batchActions';
export { parseQueryParams, toQueryString } from 'util/query_params';
export { formatCredits, formatFullPrice, creditsToString } from 'util/formatCredits';
export { batchActions } from 'util/batch-actions';
export { parseQueryParams, toQueryString } from 'util/query-params';
export { formatCredits, formatFullPrice, creditsToString } from 'util/format-credits';
export { isClaimNsfw } from 'util/claim';
export { buildClaimSearchCacheQuery } from 'util/claim-search';
// reducers
export { claimsReducer } from 'redux/reducers/claims';
@ -193,11 +194,11 @@ export {
selectChannelClaimCounts,
selectCurrentChannelPage,
selectFetchingClaimSearch,
selectLastClaimSearchUris,
selectFetchingClaimSearchByTags,
selectClaimSearchUrisByTags,
makeSelectFetchingClaimSearchForTags,
makeSelectClaimSearchUrisForTags,
selectClaimSearchByQuery,
} from 'redux/selectors/claims';
export { makeSelectCommentsForUri } from 'redux/selectors/comments';

View file

@ -9,6 +9,7 @@ import { selectSupportsByOutpoint } from 'redux/selectors/wallet';
import { creditsToString } from 'util/formatCredits';
import { batchActions } from 'util/batchActions';
import { createNormalizedTagKey } from 'util/claim';
import { buildClaimSearchCacheQuery } from 'util/claim-search';
export function doResolveUris(uris: Array<string>, returnCachedClaims: boolean = false) {
return (dispatch: Dispatch, getState: GetState) => {
@ -314,7 +315,9 @@ export function doFetchChannelListMine() {
};
}
export function doClaimSearch(options: { page_size?: number, page?: number } = {}) {
export function doClaimSearch(options: { page?: number, release_time?: string } = {}) {
const query = buildClaimSearchCacheQuery(options);
return (dispatch: Dispatch) => {
dispatch({
type: ACTIONS.CLAIM_SEARCH_STARTED,
@ -330,7 +333,7 @@ export function doClaimSearch(options: { page_size?: number, page?: number } = {
dispatch({
type: ACTIONS.CLAIM_SEARCH_COMPLETED,
data: { resolveInfo, uris, append: options.page && options.page !== 1 },
data: { resolveInfo, uris, query, append: options.page && options.page !== 1 },
});
};

View file

@ -3,8 +3,8 @@ import { CC_LICENSES, COPYRIGHT, OTHER, NONE, PUBLIC_DOMAIN } from 'constants/li
import * as ACTIONS from 'constants/action_types';
import * as THUMBNAIL_STATUSES from 'constants/thumbnail_upload_statuses';
import Lbry from 'lbry';
import { batchActions } from 'util/batchActions';
import { creditsToString } from 'util/formatCredits';
import { batchActions } from 'util/batch-actions';
import { creditsToString } from 'util/format-credits';
import { doError } from 'redux/actions/notifications';
import { isClaimNsfw } from 'util/claim';
import {
@ -118,12 +118,12 @@ export const doUploadThumbnail = (
.then(json =>
json.success
? dispatch({
type: ACTIONS.UPDATE_PUBLISH_FORM,
data: {
uploadThumbnailStatus: THUMBNAIL_STATUSES.COMPLETE,
thumbnail: `${json.data.url}${fileExt}`,
},
})
type: ACTIONS.UPDATE_PUBLISH_FORM,
data: {
uploadThumbnailStatus: THUMBNAIL_STATUSES.COMPLETE,
thumbnail: `${json.data.url}${fileExt}`,
},
})
: uploadError(json.message)
)
.catch(err => uploadError(err.message));
@ -157,12 +157,12 @@ export const doUploadThumbnail = (
.then(json =>
json.success
? dispatch({
type: ACTIONS.UPDATE_PUBLISH_FORM,
data: {
uploadThumbnailStatus: THUMBNAIL_STATUSES.COMPLETE,
thumbnail: `${json.data.url}${fileExt}`,
},
})
type: ACTIONS.UPDATE_PUBLISH_FORM,
data: {
uploadThumbnailStatus: THUMBNAIL_STATUSES.COMPLETE,
thumbnail: `${json.data.url}${fileExt}`,
},
})
: uploadError(json.message)
)
.catch(err => uploadError(err.message));

View file

@ -8,7 +8,7 @@ import {
makeSelectQueryWithOptions,
selectSearchValue,
} from 'redux/selectors/search';
import { batchActions } from 'util/batchActions';
import { batchActions } from 'util/batch-actions';
import debounce from 'util/debounce';
import handleFetchResponse from 'util/handle-fetch';

View file

@ -230,7 +230,9 @@ export function doSendTip(amount, claimId, successCallback, errorCallback) {
const success = () => {
dispatch(
doToast({
message: isSupport ? __(`You deposited ${amount} LBC as a support!`) : __(`You sent ${amount} LBC as a tip, Mahalo!`),
message: isSupport
? __(`You deposited ${amount} LBC as a support!`)
: __(`You sent ${amount} LBC as a tip, Mahalo!`),
linkText: __('History'),
linkTarget: __('/wallet'),
})

View file

@ -46,6 +46,7 @@ const defaultState = {
fetchingMyChannels: false,
abandoningById: {},
pendingById: {},
claimSearchError: undefined,
fetchingClaimSearch: false,
claimSearchUrisByTags: {},
fetchingClaimSearchByTags: {},
@ -292,27 +293,34 @@ reducers[ACTIONS.RESOLVE_URIS_STARTED] = (state: State, action: any): State => {
reducers[ACTIONS.CLAIM_SEARCH_STARTED] = (state: State): State => {
return Object.assign({}, state, {
fetchingClaimSearch: true,
claimSearchError: false,
});
};
reducers[ACTIONS.CLAIM_SEARCH_COMPLETED] = (state: State, action: any): State => {
const { lastClaimSearchUris } = state;
let newClaimSearchUris = [];
if (action.data.append) {
newClaimSearchUris = lastClaimSearchUris.concat(action.data.uris);
reducers[ACTIONS.CLAIM_SEARCH_COMPLETED] = (state: State, action: any): State => {
const { claimSearchSearchByQuery } = state;
const { uris, query, append } = action.data;
let newClaimSearch = { ...claimSearchSearchByQuery };
if (!uris) {
newClaimSearch[query] = null;
} else if (append && newClaimSearch[query]) {
newClaimSearch[query] = newClaimSearch[query].concat(uris);
} else {
newClaimSearchUris = action.data.uris;
newClaimSearch[query] = uris;
}
return {
...handleClaimAction(state, action),
fetchingClaimSearch: false,
lastClaimSearchUris: newClaimSearchUris,
claimSearchSearchByQuery: newClaimSearch,
};
};
reducers[ACTIONS.CLAIM_SEARCH_FAILED] = (state: State): State => {
return Object.assign({}, state, {
fetchingClaimSearch: false,
claimSearchError: true,
});
};
@ -321,7 +329,7 @@ reducers[ACTIONS.CLAIM_SEARCH_BY_TAGS_STARTED] = (state: State, action: any): St
fetchingClaimSearchByTags[action.data.tags] = true;
return Object.assign({}, state, {
fetchingClaimSearchByTags
fetchingClaimSearchByTags,
});
};
reducers[ACTIONS.CLAIM_SEARCH_BY_TAGS_COMPLETED] = (state: State, action: any): State => {
@ -331,8 +339,10 @@ reducers[ACTIONS.CLAIM_SEARCH_BY_TAGS_COMPLETED] = (state: State, action: any):
if (action.data.append) {
// todo: check for duplicate uris when concatenating?
claimSearchUrisByTags[tags] = claimSearchUrisByTags[tags] && claimSearchUrisByTags[tags].length ?
claimSearchUrisByTags[tags].concat(uris) : uris;
claimSearchUrisByTags[tags] =
claimSearchUrisByTags[tags] && claimSearchUrisByTags[tags].length
? claimSearchUrisByTags[tags].concat(uris)
: uris;
} else {
claimSearchUrisByTags[tags] = uris;
}

View file

@ -3,7 +3,7 @@ import { normalizeURI, buildURI, parseURI } from 'lbryURI';
import { selectSearchUrisByQuery } from 'redux/selectors/search';
import { createSelector } from 'reselect';
import { isClaimNsfw, createNormalizedTagKey } from 'util/claim';
import { getSearchQueryString } from 'util/query_params';
import { getSearchQueryString } from 'util/query-params';
const selectState = state => state.claims || {};
@ -88,12 +88,14 @@ export const makeSelectClaimForUri = (uri: string) =>
// Check if a claim is pending first
// It won't be in claimsByUri because resolving it will return nothing
let valid;
let claimId;
try {
({ claimId } = parseURI(uri));
valid = true;
} catch (e) {}
if (claimId) {
if (valid) {
const pendingClaim = pendingById[claimId];
if (pendingClaim) {
@ -253,7 +255,9 @@ export const makeSelectThumbnailForUri = (uri: string) =>
makeSelectClaimForUri(uri),
claim => {
const thumbnail = claim && claim.value && claim.value.thumbnail;
return thumbnail && thumbnail.url && thumbnail.url.trim().length > 0 ? thumbnail.url : undefined;
return thumbnail && thumbnail.url && thumbnail.url.trim().length > 0
? thumbnail.url
: undefined;
}
);
@ -499,9 +503,9 @@ export const selectFetchingClaimSearch = createSelector(
state => state.fetchingClaimSearch
);
export const selectLastClaimSearchUris = createSelector(
export const selectClaimSearchByQuery = createSelector(
selectState,
state => state.lastClaimSearchUris
state => state.claimSearchSearchByQuery || {}
);
export const makeSelectShortUrlForUri = (uri: string) =>

View file

@ -1,40 +1,65 @@
import { createSelector } from 'reselect';
import { parseQueryParams } from 'util/query_params';
import { parseQueryParams } from 'util/query-params';
export const selectState = state => state.navigation || {};
export const selectCurrentPath = createSelector(selectState, state => state.currentPath);
export const selectCurrentPath = createSelector(
selectState,
state => state.currentPath
);
export const computePageFromPath = path => (path ? path.replace(/^\//, '').split('?')[0] : '');
export const selectCurrentPage = createSelector(selectCurrentPath, path =>
computePageFromPath(path)
export const selectCurrentPage = createSelector(
selectCurrentPath,
path => computePageFromPath(path)
);
export const selectCurrentParams = createSelector(selectCurrentPath, path => {
if (path === undefined) return {};
if (!path.match(/\?/)) return {};
export const selectCurrentParams = createSelector(
selectCurrentPath,
path => {
if (path === undefined) return {};
if (!path.match(/\?/)) return {};
return parseQueryParams(path.split('?')[1]);
});
return parseQueryParams(path.split('?')[1]);
}
);
export const makeSelectCurrentParam = param =>
createSelector(selectCurrentParams, params => (params ? params[param] : undefined));
createSelector(
selectCurrentParams,
params => (params ? params[param] : undefined)
);
export const selectPathAfterAuth = createSelector(selectState, state => state.pathAfterAuth);
export const selectPathAfterAuth = createSelector(
selectState,
state => state.pathAfterAuth
);
export const selectIsBackDisabled = createSelector(selectState, state => state.index === 0);
export const selectIsBackDisabled = createSelector(
selectState,
state => state.index === 0
);
export const selectIsForwardDisabled = createSelector(
selectState,
state => state.index === state.stack.length - 1
);
export const selectIsHome = createSelector(selectCurrentPage, page => page === 'discover');
export const selectIsHome = createSelector(
selectCurrentPage,
page => page === 'discover'
);
export const selectHistoryIndex = createSelector(selectState, state => state.index);
export const selectHistoryIndex = createSelector(
selectState,
state => state.index
);
export const selectHistoryStack = createSelector(selectState, state => state.stack);
export const selectHistoryStack = createSelector(
selectState,
state => state.stack
);
// returns current page attributes (scrollY, path)
export const selectActiveHistoryEntry = createSelector(
@ -42,9 +67,12 @@ export const selectActiveHistoryEntry = createSelector(
state => state.stack[state.index]
);
export const selectPageTitle = createSelector(selectCurrentPage, page => {
switch (page) {
default:
return '';
export const selectPageTitle = createSelector(
selectCurrentPage,
page => {
switch (page) {
default:
return '';
}
}
});
);

View file

@ -1,6 +1,6 @@
// @flow
import { SEARCH_TYPES, SEARCH_OPTIONS } from 'constants/search';
import { getSearchQueryString } from 'util/query_params';
import { getSearchQueryString } from 'util/query-params';
import { normalizeURI, parseURI } from 'lbryURI';
import { createSelector } from 'reselect';

8
src/util/claim-search.js Normal file
View file

@ -0,0 +1,8 @@
// @flow
export function buildClaimSearchCacheQuery(options: { page?: number, release_time?: string }) {
// Ignore page because we don't care what the last page searched was, we want everything
// Ignore release_time because that will change depending on when you call claim_search ex: release_time: ">12344567"
const { page: optionToIgnoreForQuery, release_time: anotherToIgnore, ...rest } = options;
const query = JSON.stringify(rest);
return query;
}