From bd26d7ba441849cfe3ced3cfcbc8871178c5d70f Mon Sep 17 00:00:00 2001 From: Upsided Date: Thu, 28 Mar 2019 19:40:40 -0500 Subject: [PATCH 01/21] Allow unicode characters in claim names. See https://spec.lbry.com/#urls --- src/lbryURI.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/lbryURI.js b/src/lbryURI.js index fd07213..3415b26 100644 --- a/src/lbryURI.js +++ b/src/lbryURI.js @@ -1,7 +1,8 @@ const channelNameMinLength = 1; const claimIdMaxLength = 40; -export const regexInvalidURI = /[^A-Za-z0-9-]/g; +// see https://spec.lbry.com/#urls +const regexInvalidURI = (exports.regexInvalidURI = /[=&#:$@%?\u{0000}-\u{0008}\u{000b}-\u{000c}\u{000e}-\u{001F}\u{D800}-\u{DFFF}\u{FFFE}-\u{FFFF}]/u); export const regexAddress = /^(b|r)(?=[^0OIl]{32,33})[0-9A-Za-z]{32,33}$/; /** From b427ccfedea881bd5582f6e095d2d9f407691e74 Mon Sep 17 00:00:00 2001 From: Thomas Zarebczan Date: Sun, 2 Jun 2019 22:55:52 -0400 Subject: [PATCH 02/21] fix unicode regex Add /g option like before. Remove manual export. Actually use it in the isNameValid function. --- dist/bundle.es.js | 9 ++++----- src/index.js | 1 - src/lbryURI.js | 7 +++---- 3 files changed, 7 insertions(+), 10 deletions(-) diff --git a/dist/bundle.es.js b/dist/bundle.es.js index 2977116..fb5eae1 100644 --- a/dist/bundle.es.js +++ b/dist/bundle.es.js @@ -822,7 +822,8 @@ var _extends = Object.assign || function (target) { for (var i = 1; i < argument const channelNameMinLength = 1; const claimIdMaxLength = 40; -const regexInvalidURI = /[^A-Za-z0-9-]/g; +// see https://spec.lbry.com/#urls +const regexInvalidURI = exports.regexInvalidURI = /[=&#:$@%?\u{0000}-\u{0008}\u{000b}-\u{000c}\u{000e}-\u{001F}\u{D800}-\u{DFFF}\u{FFFE}-\u{FFFF}]/gu; const regexAddress = /^(b|r)(?=[^0OIl]{32,33})[0-9A-Za-z]{32,33}$/; /** @@ -990,9 +991,8 @@ function isURIValid(URI) { return parts && parts.claimName; } -function isNameValid(claimName, checkCase = true) { - const regexp = new RegExp('^[a-z0-9-]+$', checkCase ? '' : 'i'); - return regexp.test(claimName); +function isNameValid(claimName) { + return !regexInvalidURI.test(claimName); } function isURIClaimable(URI) { @@ -3766,7 +3766,6 @@ exports.notificationsReducer = notificationsReducer; exports.parseQueryParams = parseQueryParams; exports.parseURI = parseURI; exports.regexAddress = regexAddress; -exports.regexInvalidURI = regexInvalidURI; exports.savePosition = savePosition; exports.searchReducer = searchReducer; exports.selectAbandoningIds = selectAbandoningIds; diff --git a/src/index.js b/src/index.js index 848d0e5..a85a007 100644 --- a/src/index.js +++ b/src/index.js @@ -23,7 +23,6 @@ export { // common export { Lbry }; export { - regexInvalidURI, regexAddress, parseURI, buildURI, diff --git a/src/lbryURI.js b/src/lbryURI.js index 3415b26..8292606 100644 --- a/src/lbryURI.js +++ b/src/lbryURI.js @@ -2,7 +2,7 @@ const channelNameMinLength = 1; const claimIdMaxLength = 40; // see https://spec.lbry.com/#urls -const regexInvalidURI = (exports.regexInvalidURI = /[=&#:$@%?\u{0000}-\u{0008}\u{000b}-\u{000c}\u{000e}-\u{001F}\u{D800}-\u{DFFF}\u{FFFE}-\u{FFFF}]/u); +const regexInvalidURI = (exports.regexInvalidURI = /[=&#:$@%?\u{0000}-\u{0008}\u{000b}-\u{000c}\u{000e}-\u{001F}\u{D800}-\u{DFFF}\u{FFFE}-\u{FFFF}]/gu); export const regexAddress = /^(b|r)(?=[^0OIl]{32,33})[0-9A-Za-z]{32,33}$/; /** @@ -201,9 +201,8 @@ export function isURIValid(URI) { return parts && parts.claimName; } -export function isNameValid(claimName, checkCase = true) { - const regexp = new RegExp('^[a-z0-9-]+$', checkCase ? '' : 'i'); - return regexp.test(claimName); +export function isNameValid(claimName) { + return !regexInvalidURI.test(claimName); } export function isURIClaimable(URI) { From e883f8172203d77ab09d79679bea0256906ed9a5 Mon Sep 17 00:00:00 2001 From: Thomas Zarebczan Date: Mon, 3 Jun 2019 10:24:46 -0400 Subject: [PATCH 03/21] Fix export --- dist/bundle.es.js | 1 + src/index.js | 1 + src/lbryURI.js | 2 +- 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/dist/bundle.es.js b/dist/bundle.es.js index fb5eae1..7039cf4 100644 --- a/dist/bundle.es.js +++ b/dist/bundle.es.js @@ -3766,6 +3766,7 @@ exports.notificationsReducer = notificationsReducer; exports.parseQueryParams = parseQueryParams; exports.parseURI = parseURI; exports.regexAddress = regexAddress; +exports.regexInvalidURI = regexInvalidURI; exports.savePosition = savePosition; exports.searchReducer = searchReducer; exports.selectAbandoningIds = selectAbandoningIds; diff --git a/src/index.js b/src/index.js index a85a007..848d0e5 100644 --- a/src/index.js +++ b/src/index.js @@ -23,6 +23,7 @@ export { // common export { Lbry }; export { + regexInvalidURI, regexAddress, parseURI, buildURI, diff --git a/src/lbryURI.js b/src/lbryURI.js index 8292606..9b805f7 100644 --- a/src/lbryURI.js +++ b/src/lbryURI.js @@ -2,7 +2,7 @@ const channelNameMinLength = 1; const claimIdMaxLength = 40; // see https://spec.lbry.com/#urls -const regexInvalidURI = (exports.regexInvalidURI = /[=&#:$@%?\u{0000}-\u{0008}\u{000b}-\u{000c}\u{000e}-\u{001F}\u{D800}-\u{DFFF}\u{FFFE}-\u{FFFF}]/gu); +export const regexInvalidURI = (exports.regexInvalidURI = /[=&#:$@%?\u{0000}-\u{0008}\u{000b}-\u{000c}\u{000e}-\u{001F}\u{D800}-\u{DFFF}\u{FFFE}-\u{FFFF}]/gu); export const regexAddress = /^(b|r)(?=[^0OIl]{32,33})[0-9A-Za-z]{32,33}$/; /** From 1b98a1308270087cc1a8abac357d7f61ae35c587 Mon Sep 17 00:00:00 2001 From: Sean Yesmunt Date: Tue, 4 Jun 2019 12:06:19 -0400 Subject: [PATCH 04/21] changes for 38 --- dist/bundle.es.js | 35 ++++++++++++++++----------------- dist/flow-typed/Claim.js | 14 +++++++++++++ dist/flow-typed/Lbry.js | 4 +++- flow-typed/Claim.js | 14 +++++++++++++ flow-typed/Lbry.js | 4 +++- src/redux/actions/claims.js | 25 +++++++++++++++-------- src/redux/reducers/file_info.js | 10 ---------- 7 files changed, 68 insertions(+), 38 deletions(-) diff --git a/dist/bundle.es.js b/dist/bundle.es.js index 2977116..e706f2a 100644 --- a/dist/bundle.es.js +++ b/dist/bundle.es.js @@ -1975,13 +1975,22 @@ function doResolveUris(uris, returnCachedClaims = false) { // Flow has terrible Object.entries support // https://github.com/facebook/flow/issues/2221 - // $FlowFixMe - if (uriResolveInfo.error) { - resolveInfo[uri] = _extends$3({}, fallbackResolveInfo); - } else { - // $FlowFixMe - const { claim, certificate, claims_in_channel: claimsInChannel } = uriResolveInfo; - resolveInfo[uri] = { claim, certificate, claimsInChannel }; + if (uriResolveInfo) { + if (uriResolveInfo.error) { + resolveInfo[uri] = _extends$3({}, fallbackResolveInfo); + } else { + let result = {}; + if (uriResolveInfo.value_type === 'channel') { + result.certificate = uriResolveInfo; + // $FlowFixMe + result.claimsInChannel = uriResolveInfo.meta.claims_in_channel; + } else { + result.claim = uriResolveInfo; + } + + // $FlowFixMe + resolveInfo[uri] = result; + } } }); @@ -2095,7 +2104,7 @@ function doFetchClaimsByChannel(uri, page = 1) { data: { uri, page } }); - lbryProxy.claim_search({ channel_name: uri, page: page || 1, winning: true }).then(result => { + lbryProxy.claim_search({ channel: uri, controlling: true, page: page || 1 }).then(result => { const { items: claimsInChannel, page: returnedPage } = result; dispatch({ @@ -3155,16 +3164,6 @@ reducers$2[LOADING_VIDEO_FAILED] = (state, action) => { }); }; -reducers$2[FETCH_DATE] = (state, action) => { - const { time } = action.data; - if (time) { - return Object.assign({}, state, { - publishedDate: time - }); - } - return null; -}; - reducers$2[SET_FILE_LIST_SORT] = (state, action) => { const pageSortStates = { [PUBLISHED]: 'fileListPublishedSort', diff --git a/dist/flow-typed/Claim.js b/dist/flow-typed/Claim.js index 69ac31b..0cb2167 100644 --- a/dist/flow-typed/Claim.js +++ b/dist/flow-typed/Claim.js @@ -44,6 +44,20 @@ declare type GenericClaim = { type: 'claim' | 'update' | 'support', valid_at_height?: number, // BUG: this should always exist https://github.com/lbryio/lbry/issues/1728 value_type: 'stream' | 'channel', + meta: { + activation_height: number, + creation_height: number, + creation_timestamp: number, + effective_amount: string, + expiration_height: number, + is_controlling: boolean, + support_amount: string, + trending_global: number, + trending_group: number, + trending_local: number, + trending_mixed: number, + claims_in_channel?: number, + }, }; declare type GenericMetadata = { diff --git a/dist/flow-typed/Lbry.js b/dist/flow-typed/Lbry.js index 303de6f..d9ff6f3 100644 --- a/dist/flow-typed/Lbry.js +++ b/dist/flow-typed/Lbry.js @@ -67,7 +67,9 @@ declare type ResolveResponse = { // Keys are the url(s) passed to resolve [string]: | { error: {}, certificate: ChannelClaim, claims_in_channel: number } - | { error?: {}, claim: StreamClaim, certificate?: ChannelClaim }, + | StreamClaim + | ChannelClaim + | { error?: {} }, }; declare type GetResponse = FileListItem; diff --git a/flow-typed/Claim.js b/flow-typed/Claim.js index 69ac31b..0cb2167 100644 --- a/flow-typed/Claim.js +++ b/flow-typed/Claim.js @@ -44,6 +44,20 @@ declare type GenericClaim = { type: 'claim' | 'update' | 'support', valid_at_height?: number, // BUG: this should always exist https://github.com/lbryio/lbry/issues/1728 value_type: 'stream' | 'channel', + meta: { + activation_height: number, + creation_height: number, + creation_timestamp: number, + effective_amount: string, + expiration_height: number, + is_controlling: boolean, + support_amount: string, + trending_global: number, + trending_group: number, + trending_local: number, + trending_mixed: number, + claims_in_channel?: number, + }, }; declare type GenericMetadata = { diff --git a/flow-typed/Lbry.js b/flow-typed/Lbry.js index 303de6f..d9ff6f3 100644 --- a/flow-typed/Lbry.js +++ b/flow-typed/Lbry.js @@ -67,7 +67,9 @@ declare type ResolveResponse = { // Keys are the url(s) passed to resolve [string]: | { error: {}, certificate: ChannelClaim, claims_in_channel: number } - | { error?: {}, claim: StreamClaim, certificate?: ChannelClaim }, + | StreamClaim + | ChannelClaim + | { error?: {} }, }; declare type GetResponse = FileListItem; diff --git a/src/redux/actions/claims.js b/src/redux/actions/claims.js index 33dd119..51c2712 100644 --- a/src/redux/actions/claims.js +++ b/src/redux/actions/claims.js @@ -50,13 +50,22 @@ export function doResolveUris(uris: Array, returnCachedClaims: boolean = // Flow has terrible Object.entries support // https://github.com/facebook/flow/issues/2221 - // $FlowFixMe - if (uriResolveInfo.error) { - resolveInfo[uri] = { ...fallbackResolveInfo }; - } else { - // $FlowFixMe - const { claim, certificate, claims_in_channel: claimsInChannel } = uriResolveInfo; - resolveInfo[uri] = { claim, certificate, claimsInChannel }; + if (uriResolveInfo) { + if (uriResolveInfo.error) { + resolveInfo[uri] = { ...fallbackResolveInfo }; + } else { + let result = {}; + if (uriResolveInfo.value_type === 'channel') { + result.certificate = uriResolveInfo; + // $FlowFixMe + result.claimsInChannel = uriResolveInfo.meta.claims_in_channel; + } else { + result.claim = uriResolveInfo; + } + + // $FlowFixMe + resolveInfo[uri] = result; + } } }); @@ -182,7 +191,7 @@ export function doFetchClaimsByChannel(uri: string, page: number = 1) { data: { uri, page }, }); - Lbry.claim_search({ channel_name: uri, page: page || 1, winning: true }).then( + Lbry.claim_search({ channel: uri, controlling: true, page: page || 1 }).then( (result: ClaimSearchResponse) => { const { items: claimsInChannel, page: returnedPage } = result; diff --git a/src/redux/reducers/file_info.js b/src/redux/reducers/file_info.js index 1d9f950..dbc5e86 100644 --- a/src/redux/reducers/file_info.js +++ b/src/redux/reducers/file_info.js @@ -161,16 +161,6 @@ reducers[ACTIONS.LOADING_VIDEO_FAILED] = (state, action) => { }); }; -reducers[ACTIONS.FETCH_DATE] = (state, action) => { - const { time } = action.data; - if (time) { - return Object.assign({}, state, { - publishedDate: time, - }); - } - return null; -}; - reducers[ACTIONS.SET_FILE_LIST_SORT] = (state, action) => { const pageSortStates = { [PAGES.PUBLISHED]: 'fileListPublishedSort', From 5c8d3b414301f36e3af246e8093b988e3e81aa2f Mon Sep 17 00:00:00 2001 From: Thomas Zarebczan Date: Thu, 6 Jun 2019 12:02:43 -0400 Subject: [PATCH 05/21] fix: crash on blank title --- dist/bundle.es.js | 10 ++++++---- src/redux/selectors/file_info.js | 10 ++++++---- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/dist/bundle.es.js b/dist/bundle.es.js index e706f2a..96257e9 100644 --- a/dist/bundle.es.js +++ b/dist/bundle.es.js @@ -2270,10 +2270,12 @@ const selectSearchDownloadUris = query => reselect.createSelector(selectFileInfo return; } - const titleParts = title.toLowerCase().split(' '); - if (arrayContainsQueryPart(titleParts)) { - downloadResultsFromQuery.push(fileInfo); - return; + if (title) { + const titleParts = title.toLowerCase().split(' '); + if (arrayContainsQueryPart(titleParts)) { + downloadResultsFromQuery.push(fileInfo); + return; + } } if (author) { diff --git a/src/redux/selectors/file_info.js b/src/redux/selectors/file_info.js index ab941ea..4718cd8 100644 --- a/src/redux/selectors/file_info.js +++ b/src/redux/selectors/file_info.js @@ -164,10 +164,12 @@ export const selectSearchDownloadUris = query => return; } - const titleParts = title.toLowerCase().split(' '); - if (arrayContainsQueryPart(titleParts)) { - downloadResultsFromQuery.push(fileInfo); - return; + if (title) { + const titleParts = title.toLowerCase().split(' '); + if (arrayContainsQueryPart(titleParts)) { + downloadResultsFromQuery.push(fileInfo); + return; + } } if (author) { From b419a1bfa9a5833083b2a587eaad0672100d9e87 Mon Sep 17 00:00:00 2001 From: Thomas Zarebczan Date: Thu, 6 Jun 2019 17:37:36 -0400 Subject: [PATCH 06/21] fix: more 38 changes Fixed resolving by signed_channel, order for claim search and timestamp to use release date / creation date (to match sorting). We'll probably want to show updated_date somewhere in advanced section eventually. Needs some flow love --- dist/bundle.es.js | 48 +++++++++++++++------------ dist/flow-typed/Claim.js | 36 ++++++++------------- dist/flow-typed/Lbry.js | 13 ++++---- flow-typed/Claim.js | 36 ++++++++------------- flow-typed/Lbry.js | 13 ++++---- src/redux/actions/claims.js | 22 +++++++------ src/redux/reducers/claims.js | 61 ++++++++++++++++++----------------- src/redux/selectors/claims.js | 6 ++-- src/util/claim.js | 2 +- 9 files changed, 114 insertions(+), 123 deletions(-) diff --git a/dist/bundle.es.js b/dist/bundle.es.js index 96257e9..1e03922 100644 --- a/dist/bundle.es.js +++ b/dist/bundle.es.js @@ -1269,7 +1269,7 @@ const makeSelectMetadataItemForUri = (uri, key) => reselect.createSelector(makeS const makeSelectTitleForUri = uri => reselect.createSelector(makeSelectMetadataForUri(uri), metadata => metadata && metadata.title); const makeSelectDateForUri = uri => reselect.createSelector(makeSelectClaimForUri(uri), claim => { - const timestamp = claim && claim.timestamp ? claim.timestamp * 1000 : undefined; + const timestamp = claim && claim.value && (claim.value.release_time ? claim.value.release_time * 1000 : claim.value.meta.creation_timestamp * 1000); if (!timestamp) { return undefined; } @@ -1968,9 +1968,9 @@ function doResolveUris(uris, returnCachedClaims = false) { lbryProxy.resolve({ urls: urisToResolve }).then(result => { Object.entries(result).forEach(([uri, uriResolveInfo]) => { const fallbackResolveInfo = { - claim: null, + stream: null, claimsInChannel: null, - certificate: null + channel: null }; // Flow has terrible Object.entries support @@ -1981,11 +1981,15 @@ function doResolveUris(uris, returnCachedClaims = false) { } else { let result = {}; if (uriResolveInfo.value_type === 'channel') { - result.certificate = uriResolveInfo; + result.channel = uriResolveInfo; // $FlowFixMe result.claimsInChannel = uriResolveInfo.meta.claims_in_channel; } else { - result.claim = uriResolveInfo; + result.stream = uriResolveInfo; + if (uriResolveInfo.signing_channel) { + result.channel = uriResolveInfo.signing_channel; + result.claimsInChannel = uriResolveInfo.signing_channel.meta.claims_in_channel; + } } // $FlowFixMe @@ -2104,7 +2108,7 @@ function doFetchClaimsByChannel(uri, page = 1) { data: { uri, page } }); - lbryProxy.claim_search({ channel: uri, controlling: true, page: page || 1 }).then(result => { + lbryProxy.claim_search({ channel: uri, is_controlling: true, page: page || 1, order_by: ['release_time'] }).then(result => { const { items: claimsInChannel, page: returnedPage } = result; dispatch({ @@ -2708,34 +2712,36 @@ const defaultState = { }; reducers[RESOLVE_URIS_COMPLETED] = (state, action) => { - const { resolveInfo } = action.data; + const { + resolveInfo + } = action.data; const byUri = Object.assign({}, state.claimsByUri); const byId = Object.assign({}, state.byId); const channelClaimCounts = Object.assign({}, state.channelClaimCounts); Object.entries(resolveInfo).forEach(([uri, resolveResponse]) => { // $FlowFixMe - if (resolveResponse.certificate && !Number.isNaN(resolveResponse.claimsInChannel)) { + if (resolveResponse.claimsInChannel) { // $FlowFixMe channelClaimCounts[uri] = resolveResponse.claimsInChannel; } }); // $FlowFixMe - Object.entries(resolveInfo).forEach(([uri, { certificate, claim }]) => { - if (claim && !certificate) { - byId[claim.claim_id] = claim; - byUri[uri] = claim.claim_id; - } else if (claim && certificate) { - byId[claim.claim_id] = claim; - byUri[uri] = claim.claim_id; + Object.entries(resolveInfo).forEach(([uri, { channel, stream }]) => { + if (stream && !channel) { + byId[stream.claim_id] = stream; + byUri[uri] = stream.claim_id; + } else if (stream && channel) { + byId[stream.claim_id] = stream; + byUri[uri] = stream.claim_id; - byId[certificate.claim_id] = certificate; - const channelUri = `lbry://${certificate.name}#${certificate.claim_id}`; - byUri[channelUri] = certificate.claim_id; - } else if (!claim && certificate) { - byId[certificate.claim_id] = certificate; - byUri[uri] = certificate.claim_id; + byId[channel.claim_id] = channel; + const channelUri = channel.permanent_url; + byUri[channelUri] = channel.claim_id; + } else if (!stream && channel) { + byId[channel.claim_id] = channel; + byUri[uri] = channel.claim_id; } else { byUri[uri] = null; } diff --git a/dist/flow-typed/Claim.js b/dist/flow-typed/Claim.js index 0cb2167..e8744f5 100644 --- a/dist/flow-typed/Claim.js +++ b/dist/flow-typed/Claim.js @@ -1,51 +1,41 @@ // @flow -declare type ClaimWithPossibleCertificate = { - certificate?: ChannelClaim, - claim: StreamClaim, -}; +declare type Claim = StreamClaim | ChannelClaim; declare type ChannelClaim = GenericClaim & { + is_channel_signature_valid?: boolean, // we may have signed channels in the future, fixes some flow issues for now. + signing_channel?: ChannelMetadata, value: ChannelMetadata, }; declare type StreamClaim = GenericClaim & { is_channel_signature_valid?: boolean, - signing_channel?: { - claim_id: string, - name: string, - value: { - public_key: string, - }, - }, + signing_channel?: ChannelMetadata, value: StreamMetadata, }; declare type GenericClaim = { address: string, // address associated with tx - amount: number, // bid amount at time of tx + amount: string, // bid amount at time of tx + canonical_url: string, // URL with short id, includes channel with short id claim_id: string, // unique claim identifier - claim_sequence: number, + claim_sequence: number, // not being used currently claim_op: 'create' | 'update', - confirmations: number, // This isn't the most stable atm: https://github.com/lbryio/lbry/issues/2000 - decoded_claim: boolean, // claim made in accordance with sdk protobuf types - effective_amount: number, // bid amount + supports - timestamp?: number, // date of transaction - has_signature: boolean, + confirmations: number, + decoded_claim: boolean, // Not available currently https://github.com/lbryio/lbry/issues/2044 + timestamp?: number, // date of last transaction height: number, // block height the tx was confirmed - hex: string, // `value` hex encoded name: string, - channel_name?: string, normalized_name: string, // `name` normalized via unicode NFD spec, nout: number, // index number for an output of a tx permanent_url: string, // name + claim_id - supports: Array<{}>, // TODO: add support type once we start using it + short_url: string, // permanent_url with short id, no channel txid: string, // unique tx id type: 'claim' | 'update' | 'support', - valid_at_height?: number, // BUG: this should always exist https://github.com/lbryio/lbry/issues/1728 value_type: 'stream' | 'channel', meta: { activation_height: number, + claims_in_channel?: number, creation_height: number, creation_timestamp: number, effective_amount: string, @@ -56,7 +46,6 @@ declare type GenericClaim = { trending_group: number, trending_local: number, trending_mixed: number, - claims_in_channel?: number, }, }; @@ -73,6 +62,7 @@ declare type GenericMetadata = { declare type ChannelMetadata = GenericMetadata & { public_key: string, + public_key_id: string, cover_url?: string, email?: string, website_url?: string, diff --git a/dist/flow-typed/Lbry.js b/dist/flow-typed/Lbry.js index d9ff6f3..dae9168 100644 --- a/dist/flow-typed/Lbry.js +++ b/dist/flow-typed/Lbry.js @@ -66,9 +66,7 @@ declare type VersionResponse = { declare type ResolveResponse = { // Keys are the url(s) passed to resolve [string]: - | { error: {}, certificate: ChannelClaim, claims_in_channel: number } - | StreamClaim - | ChannelClaim + | Claim | { error?: {} }, }; @@ -88,18 +86,19 @@ declare type GenericTxResponse = { declare type PublishResponse = GenericTxResponse & { // Only first value in outputs is a claim // That's the only value we care about - outputs: Array, + outputs: Array, }; declare type ClaimSearchResponse = { - items: Array, + items: Array, page: number, page_size: number, - page_number: number, + total_items: number, + total_pages: number, }; declare type ClaimListResponse = { - claims: Array, + claims: Array, }; declare type ChannelCreateResponse = GenericTxResponse & { diff --git a/flow-typed/Claim.js b/flow-typed/Claim.js index 0cb2167..e8744f5 100644 --- a/flow-typed/Claim.js +++ b/flow-typed/Claim.js @@ -1,51 +1,41 @@ // @flow -declare type ClaimWithPossibleCertificate = { - certificate?: ChannelClaim, - claim: StreamClaim, -}; +declare type Claim = StreamClaim | ChannelClaim; declare type ChannelClaim = GenericClaim & { + is_channel_signature_valid?: boolean, // we may have signed channels in the future, fixes some flow issues for now. + signing_channel?: ChannelMetadata, value: ChannelMetadata, }; declare type StreamClaim = GenericClaim & { is_channel_signature_valid?: boolean, - signing_channel?: { - claim_id: string, - name: string, - value: { - public_key: string, - }, - }, + signing_channel?: ChannelMetadata, value: StreamMetadata, }; declare type GenericClaim = { address: string, // address associated with tx - amount: number, // bid amount at time of tx + amount: string, // bid amount at time of tx + canonical_url: string, // URL with short id, includes channel with short id claim_id: string, // unique claim identifier - claim_sequence: number, + claim_sequence: number, // not being used currently claim_op: 'create' | 'update', - confirmations: number, // This isn't the most stable atm: https://github.com/lbryio/lbry/issues/2000 - decoded_claim: boolean, // claim made in accordance with sdk protobuf types - effective_amount: number, // bid amount + supports - timestamp?: number, // date of transaction - has_signature: boolean, + confirmations: number, + decoded_claim: boolean, // Not available currently https://github.com/lbryio/lbry/issues/2044 + timestamp?: number, // date of last transaction height: number, // block height the tx was confirmed - hex: string, // `value` hex encoded name: string, - channel_name?: string, normalized_name: string, // `name` normalized via unicode NFD spec, nout: number, // index number for an output of a tx permanent_url: string, // name + claim_id - supports: Array<{}>, // TODO: add support type once we start using it + short_url: string, // permanent_url with short id, no channel txid: string, // unique tx id type: 'claim' | 'update' | 'support', - valid_at_height?: number, // BUG: this should always exist https://github.com/lbryio/lbry/issues/1728 value_type: 'stream' | 'channel', meta: { activation_height: number, + claims_in_channel?: number, creation_height: number, creation_timestamp: number, effective_amount: string, @@ -56,7 +46,6 @@ declare type GenericClaim = { trending_group: number, trending_local: number, trending_mixed: number, - claims_in_channel?: number, }, }; @@ -73,6 +62,7 @@ declare type GenericMetadata = { declare type ChannelMetadata = GenericMetadata & { public_key: string, + public_key_id: string, cover_url?: string, email?: string, website_url?: string, diff --git a/flow-typed/Lbry.js b/flow-typed/Lbry.js index d9ff6f3..dae9168 100644 --- a/flow-typed/Lbry.js +++ b/flow-typed/Lbry.js @@ -66,9 +66,7 @@ declare type VersionResponse = { declare type ResolveResponse = { // Keys are the url(s) passed to resolve [string]: - | { error: {}, certificate: ChannelClaim, claims_in_channel: number } - | StreamClaim - | ChannelClaim + | Claim | { error?: {} }, }; @@ -88,18 +86,19 @@ declare type GenericTxResponse = { declare type PublishResponse = GenericTxResponse & { // Only first value in outputs is a claim // That's the only value we care about - outputs: Array, + outputs: Array, }; declare type ClaimSearchResponse = { - items: Array, + items: Array, page: number, page_size: number, - page_number: number, + total_items: number, + total_pages: number, }; declare type ClaimListResponse = { - claims: Array, + claims: Array, }; declare type ChannelCreateResponse = GenericTxResponse & { diff --git a/src/redux/actions/claims.js b/src/redux/actions/claims.js index 51c2712..d7a0ff9 100644 --- a/src/redux/actions/claims.js +++ b/src/redux/actions/claims.js @@ -34,8 +34,8 @@ export function doResolveUris(uris: Array, returnCachedClaims: boolean = const resolveInfo: { [string]: { - claim: ?StreamClaim, - certificate: ?ChannelClaim, + stream: ?StreamClaim, + channel: ?ChannelClaim, claimsInChannel: ?number, }, } = {}; @@ -43,9 +43,9 @@ export function doResolveUris(uris: Array, returnCachedClaims: boolean = Lbry.resolve({ urls: urisToResolve }).then((result: ResolveResponse) => { Object.entries(result).forEach(([uri, uriResolveInfo]) => { const fallbackResolveInfo = { - claim: null, + stream: null, claimsInChannel: null, - certificate: null, + channel: null, }; // Flow has terrible Object.entries support @@ -55,12 +55,16 @@ export function doResolveUris(uris: Array, returnCachedClaims: boolean = resolveInfo[uri] = { ...fallbackResolveInfo }; } else { let result = {}; - if (uriResolveInfo.value_type === 'channel') { - result.certificate = uriResolveInfo; + if (uriResolveInfo.value_type === 'channel' ) { + result.channel = uriResolveInfo; // $FlowFixMe result.claimsInChannel = uriResolveInfo.meta.claims_in_channel; } else { - result.claim = uriResolveInfo; + result.stream = uriResolveInfo; + if (uriResolveInfo.signing_channel) { + result.channel = uriResolveInfo.signing_channel; + result.claimsInChannel = uriResolveInfo.signing_channel.meta.claims_in_channel; + } } // $FlowFixMe @@ -103,7 +107,7 @@ export function doAbandonClaim(txid: string, nout: number) { return (dispatch: Dispatch, getState: GetState) => { const state = getState(); - const myClaims: Array = selectMyClaimsRaw(state); + const myClaims: Array = selectMyClaimsRaw(state); const mySupports: { [string]: Support } = selectSupportsByOutpoint(state); // A user could be trying to abandon a support or one of their claims @@ -191,7 +195,7 @@ export function doFetchClaimsByChannel(uri: string, page: number = 1) { data: { uri, page }, }); - Lbry.claim_search({ channel: uri, controlling: true, page: page || 1 }).then( + Lbry.claim_search({ channel: uri, is_controlling: true, page: page || 1, order_by: ['release_time'] }).then( (result: ClaimSearchResponse) => { const { items: claimsInChannel, page: returnedPage } = result; diff --git a/src/redux/reducers/claims.js b/src/redux/reducers/claims.js index b4a81e9..59fb1b9 100644 --- a/src/redux/reducers/claims.js +++ b/src/redux/reducers/claims.js @@ -14,9 +14,9 @@ import { buildURI, parseURI } from 'lbryURI'; type State = { channelClaimCounts: { [string]: number }, claimsByUri: { [string]: string }, - byId: { [string]: StreamClaim | ChannelClaim }, + byId: { [string]: Claim }, resolvingUris: Array, - pendingById: { [string]: StreamClaim | ChannelClaim }, + pendingById: { [string]: Claim }, myChannelClaims: Set, abandoningById: { [string]: boolean }, fetchingChannelClaims: { [string]: number }, @@ -46,36 +46,42 @@ const defaultState = { }; reducers[ACTIONS.RESOLVE_URIS_COMPLETED] = (state: State, action: any): State => { - const { resolveInfo }: { [string]: ClaimWithPossibleCertificate } = action.data; + const { + resolveInfo, + }: { + [string]: { + stream: ?StreamClaim, + channel: ?ChannelClaim, + claimsInChannel: ?number, + }, + } = action.data; const byUri = Object.assign({}, state.claimsByUri); const byId = Object.assign({}, state.byId); const channelClaimCounts = Object.assign({}, state.channelClaimCounts); - Object.entries(resolveInfo).forEach( - ([uri: string, resolveResponse: ClaimWithPossibleCertificate]) => { + Object.entries(resolveInfo).forEach(([uri: string, resolveResponse: Claim]) => { + // $FlowFixMe + if (resolveResponse.claimsInChannel) { // $FlowFixMe - if (resolveResponse.certificate && !Number.isNaN(resolveResponse.claimsInChannel)) { - // $FlowFixMe - channelClaimCounts[uri] = resolveResponse.claimsInChannel; - } + channelClaimCounts[uri] = resolveResponse.claimsInChannel; } - ); + }); // $FlowFixMe - Object.entries(resolveInfo).forEach(([uri, { certificate, claim }]) => { - if (claim && !certificate) { - byId[claim.claim_id] = claim; - byUri[uri] = claim.claim_id; - } else if (claim && certificate) { - byId[claim.claim_id] = claim; - byUri[uri] = claim.claim_id; + Object.entries(resolveInfo).forEach(([uri, { channel, stream }]) => { + if (stream && !channel) { + byId[stream.claim_id] = stream; + byUri[uri] = stream.claim_id; + } else if (stream && channel) { + byId[stream.claim_id] = stream; + byUri[uri] = stream.claim_id; - byId[certificate.claim_id] = certificate; - const channelUri = `lbry://${certificate.name}#${certificate.claim_id}`; - byUri[channelUri] = certificate.claim_id; - } else if (!claim && certificate) { - byId[certificate.claim_id] = certificate; - byUri[uri] = certificate.claim_id; + byId[channel.claim_id] = channel; + const channelUri = channel.permanent_url; + byUri[channelUri] = channel.claim_id; + } else if (!stream && channel) { + byId[channel.claim_id] = channel; + byUri[uri] = channel.claim_id; } else { byUri[uri] = null; } @@ -95,15 +101,12 @@ reducers[ACTIONS.FETCH_CLAIM_LIST_MINE_STARTED] = (state: State): State => }); reducers[ACTIONS.FETCH_CLAIM_LIST_MINE_COMPLETED] = (state: State, action: any): State => { - const { claims }: { claims: Array } = action.data; + const { claims }: { claims: Array } = action.data; const byId = Object.assign({}, state.byId); const byUri = Object.assign({}, state.claimsByUri); - const pendingById: { [string]: StreamClaim | ChannelClaim } = Object.assign( - {}, - state.pendingById - ); + const pendingById: { [string]: Claim } = Object.assign({}, state.pendingById); - claims.forEach((claim: StreamClaim | ChannelClaim) => { + claims.forEach((claim: Claim) => { const uri = buildURI({ claimName: claim.name, claimId: claim.claim_id }); if (claim.type && claim.type.match(/claim|update/)) { diff --git a/src/redux/selectors/claims.js b/src/redux/selectors/claims.js index 7a1808f..da48735 100644 --- a/src/redux/selectors/claims.js +++ b/src/redux/selectors/claims.js @@ -190,7 +190,7 @@ export const makeSelectDateForUri = (uri: string) => createSelector( makeSelectClaimForUri(uri), claim => { - const timestamp = claim && claim.timestamp ? claim.timestamp * 1000 : undefined; + const timestamp = claim && claim.value && (claim.value.release_time ? claim.value.release_time * 1000 : claim.value.meta.creation_timestamp * 1000); if (!timestamp) { return undefined; } @@ -368,7 +368,7 @@ export const makeSelectClaimIsNsfw = (uri: string): boolean => // Or possibly come from users settings of what tags they want to hide // For now, there is just a hard coded list of tags inside `isClaimNsfw` // selectNaughtyTags(), - (claim: StreamClaim) => { + (claim: Claim) => { if (!claim) { return false; } @@ -418,7 +418,7 @@ export const makeSelectFirstRecommendedFileForUri = (uri: string) => export const makeSelectChannelForClaimUri = (uri: string, includePrefix: boolean = false) => createSelector( makeSelectClaimForUri(uri), - (claim: ?StreamClaim) => { + (claim: ?Claim) => { if (!claim || !claim.signing_channel) { return null; } diff --git a/src/util/claim.js b/src/util/claim.js index 0e56ce3..73adb7a 100644 --- a/src/util/claim.js +++ b/src/util/claim.js @@ -5,7 +5,7 @@ const naughtyTags = ['porn', 'nsfw', 'mature', 'xxx'].reduce( {} ); -export const isClaimNsfw = (claim: StreamClaim): boolean => { +export const isClaimNsfw = (claim: Claim): boolean => { if (!claim) { throw new Error('No claim passed to isClaimNsfw()'); } From 85c24ae37d09666d19c238be33ee836476e62a2b Mon Sep 17 00:00:00 2001 From: Thomas Zarebczan Date: Fri, 7 Jun 2019 13:16:50 -0400 Subject: [PATCH 07/21] fix: sorting param It's claim.meta, not claim.value.meta. --- dist/bundle.es.js | 2 +- src/redux/selectors/claims.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dist/bundle.es.js b/dist/bundle.es.js index 1e03922..15984e3 100644 --- a/dist/bundle.es.js +++ b/dist/bundle.es.js @@ -1269,7 +1269,7 @@ const makeSelectMetadataItemForUri = (uri, key) => reselect.createSelector(makeS const makeSelectTitleForUri = uri => reselect.createSelector(makeSelectMetadataForUri(uri), metadata => metadata && metadata.title); const makeSelectDateForUri = uri => reselect.createSelector(makeSelectClaimForUri(uri), claim => { - const timestamp = claim && claim.value && (claim.value.release_time ? claim.value.release_time * 1000 : claim.value.meta.creation_timestamp * 1000); + const timestamp = claim && claim.value && (claim.value.release_time ? claim.value.release_time * 1000 : claim.meta.creation_timestamp * 1000); if (!timestamp) { return undefined; } diff --git a/src/redux/selectors/claims.js b/src/redux/selectors/claims.js index da48735..7abe3c8 100644 --- a/src/redux/selectors/claims.js +++ b/src/redux/selectors/claims.js @@ -190,7 +190,7 @@ export const makeSelectDateForUri = (uri: string) => createSelector( makeSelectClaimForUri(uri), claim => { - const timestamp = claim && claim.value && (claim.value.release_time ? claim.value.release_time * 1000 : claim.value.meta.creation_timestamp * 1000); + const timestamp = claim && claim.value && (claim.value.release_time ? claim.value.release_time * 1000 : claim.meta.creation_timestamp * 1000); if (!timestamp) { return undefined; } From 50d1b166f50ca7db8e23832917c45542a26888e2 Mon Sep 17 00:00:00 2001 From: Sean Yesmunt Date: Sun, 9 Jun 2019 21:25:55 -0400 Subject: [PATCH 08/21] simplify claims resolve reducer --- flow-typed/Claim.js | 4 ++-- src/redux/actions/claims.js | 34 +++++++++++++++++++--------------- src/redux/reducers/claims.js | 17 ++++++----------- src/redux/selectors/claims.js | 9 +++++++-- 4 files changed, 34 insertions(+), 30 deletions(-) diff --git a/flow-typed/Claim.js b/flow-typed/Claim.js index e8744f5..f18b128 100644 --- a/flow-typed/Claim.js +++ b/flow-typed/Claim.js @@ -4,13 +4,13 @@ declare type Claim = StreamClaim | ChannelClaim; declare type ChannelClaim = GenericClaim & { is_channel_signature_valid?: boolean, // we may have signed channels in the future, fixes some flow issues for now. - signing_channel?: ChannelMetadata, + signing_channel?: ChannelClaim, value: ChannelMetadata, }; declare type StreamClaim = GenericClaim & { is_channel_signature_valid?: boolean, - signing_channel?: ChannelMetadata, + signing_channel?: ChannelClaim, value: StreamMetadata, }; diff --git a/src/redux/actions/claims.js b/src/redux/actions/claims.js index d7a0ff9..3cbffcd 100644 --- a/src/redux/actions/claims.js +++ b/src/redux/actions/claims.js @@ -55,7 +55,7 @@ export function doResolveUris(uris: Array, returnCachedClaims: boolean = resolveInfo[uri] = { ...fallbackResolveInfo }; } else { let result = {}; - if (uriResolveInfo.value_type === 'channel' ) { + if (uriResolveInfo.value_type === 'channel') { result.channel = uriResolveInfo; // $FlowFixMe result.claimsInChannel = uriResolveInfo.meta.claims_in_channel; @@ -63,7 +63,8 @@ export function doResolveUris(uris: Array, returnCachedClaims: boolean = result.stream = uriResolveInfo; if (uriResolveInfo.signing_channel) { result.channel = uriResolveInfo.signing_channel; - result.claimsInChannel = uriResolveInfo.signing_channel.meta.claims_in_channel; + result.claimsInChannel = + (uriResolveInfo.meta && uriResolveInfo.meta.claims_in_channel) || 0; } } @@ -195,20 +196,23 @@ export function doFetchClaimsByChannel(uri: string, page: number = 1) { data: { uri, page }, }); - Lbry.claim_search({ channel: uri, is_controlling: true, page: page || 1, order_by: ['release_time'] }).then( - (result: ClaimSearchResponse) => { - const { items: claimsInChannel, page: returnedPage } = result; + Lbry.claim_search({ + channel: uri, + is_controlling: true, + page: page || 1, + order_by: ['release_time'], + }).then((result: ClaimSearchResponse) => { + const { items: claimsInChannel, page: returnedPage } = result; - dispatch({ - type: ACTIONS.FETCH_CHANNEL_CLAIMS_COMPLETED, - data: { - uri, - claims: claimsInChannel || [], - page: returnedPage || undefined, - }, - }); - } - ); + dispatch({ + type: ACTIONS.FETCH_CHANNEL_CLAIMS_COMPLETED, + data: { + uri, + claims: claimsInChannel || [], + page: returnedPage || undefined, + }, + }); + }); }; } diff --git a/src/redux/reducers/claims.js b/src/redux/reducers/claims.js index 59fb1b9..cd50cd6 100644 --- a/src/redux/reducers/claims.js +++ b/src/redux/reducers/claims.js @@ -69,20 +69,15 @@ reducers[ACTIONS.RESOLVE_URIS_COMPLETED] = (state: State, action: any): State => // $FlowFixMe Object.entries(resolveInfo).forEach(([uri, { channel, stream }]) => { - if (stream && !channel) { + if (stream) { byId[stream.claim_id] = stream; byUri[uri] = stream.claim_id; - } else if (stream && channel) { - byId[stream.claim_id] = stream; - byUri[uri] = stream.claim_id; - + } + if (channel) { byId[channel.claim_id] = channel; - const channelUri = channel.permanent_url; - byUri[channelUri] = channel.claim_id; - } else if (!stream && channel) { - byId[channel.claim_id] = channel; - byUri[uri] = channel.claim_id; - } else { + byUri[stream ? channel.permanent_url : uri] = channel.claim_id; + } + if (!stream && !channel) { byUri[uri] = null; } }); diff --git a/src/redux/selectors/claims.js b/src/redux/selectors/claims.js index 7abe3c8..0cf4bdf 100644 --- a/src/redux/selectors/claims.js +++ b/src/redux/selectors/claims.js @@ -190,7 +190,12 @@ export const makeSelectDateForUri = (uri: string) => createSelector( makeSelectClaimForUri(uri), claim => { - const timestamp = claim && claim.value && (claim.value.release_time ? claim.value.release_time * 1000 : claim.meta.creation_timestamp * 1000); + const timestamp = + claim && + claim.value && + (claim.value.release_time + ? claim.value.release_time * 1000 + : claim.meta.creation_timestamp * 1000); if (!timestamp) { return undefined; } @@ -418,7 +423,7 @@ export const makeSelectFirstRecommendedFileForUri = (uri: string) => export const makeSelectChannelForClaimUri = (uri: string, includePrefix: boolean = false) => createSelector( makeSelectClaimForUri(uri), - (claim: ?Claim) => { + (claim: ?StreamClaim) => { if (!claim || !claim.signing_channel) { return null; } From c73ea0094179dfe3a2e5385ea03d771367e02d97 Mon Sep 17 00:00:00 2001 From: Thomas Zarebczan Date: Tue, 11 Jun 2019 12:22:44 -0400 Subject: [PATCH 09/21] fix: controlling and channel claim count meta Controlling means controlling claims, not channels. Added so we only return claims with valid signatures (safer for now, can add options to show invalid later). Also, the claim count in channel is in the signed channel meta object, not the high level one. --- dist/bundle.es.js | 26 +++++++++++++------------- dist/flow-typed/Claim.js | 4 ++-- src/redux/actions/claims.js | 6 ++++-- 3 files changed, 19 insertions(+), 17 deletions(-) diff --git a/dist/bundle.es.js b/dist/bundle.es.js index 87cf4e4..536e4f0 100644 --- a/dist/bundle.es.js +++ b/dist/bundle.es.js @@ -1997,7 +1997,7 @@ function doResolveUris(uris, returnCachedClaims = false) { result.stream = uriResolveInfo; if (uriResolveInfo.signing_channel) { result.channel = uriResolveInfo.signing_channel; - result.claimsInChannel = uriResolveInfo.signing_channel.meta.claims_in_channel; + result.claimsInChannel = uriResolveInfo.signing_channel.meta && uriResolveInfo.signing_channel.meta.claims_in_channel || 0; } } @@ -2117,7 +2117,12 @@ function doFetchClaimsByChannel(uri, page = 1) { data: { uri, page } }); - lbryProxy.claim_search({ channel: uri, is_controlling: true, page: page || 1, order_by: ['release_time'] }).then(result => { + lbryProxy.claim_search({ + channel: uri, + valid_channel_signatures: true, + page: page || 1, + order_by: ['release_time'] + }).then(result => { const { items: claimsInChannel, page: returnedPage } = result; dispatch({ @@ -2738,20 +2743,15 @@ reducers[RESOLVE_URIS_COMPLETED] = (state, action) => { // $FlowFixMe Object.entries(resolveInfo).forEach(([uri, { channel, stream }]) => { - if (stream && !channel) { + if (stream) { byId[stream.claim_id] = stream; byUri[uri] = stream.claim_id; - } else if (stream && channel) { - byId[stream.claim_id] = stream; - byUri[uri] = stream.claim_id; - + } + if (channel) { byId[channel.claim_id] = channel; - const channelUri = channel.permanent_url; - byUri[channelUri] = channel.claim_id; - } else if (!stream && channel) { - byId[channel.claim_id] = channel; - byUri[uri] = channel.claim_id; - } else { + byUri[stream ? channel.permanent_url : uri] = channel.claim_id; + } + if (!stream && !channel) { byUri[uri] = null; } }); diff --git a/dist/flow-typed/Claim.js b/dist/flow-typed/Claim.js index e8744f5..f18b128 100644 --- a/dist/flow-typed/Claim.js +++ b/dist/flow-typed/Claim.js @@ -4,13 +4,13 @@ declare type Claim = StreamClaim | ChannelClaim; declare type ChannelClaim = GenericClaim & { is_channel_signature_valid?: boolean, // we may have signed channels in the future, fixes some flow issues for now. - signing_channel?: ChannelMetadata, + signing_channel?: ChannelClaim, value: ChannelMetadata, }; declare type StreamClaim = GenericClaim & { is_channel_signature_valid?: boolean, - signing_channel?: ChannelMetadata, + signing_channel?: ChannelClaim, value: StreamMetadata, }; diff --git a/src/redux/actions/claims.js b/src/redux/actions/claims.js index 3cbffcd..5248309 100644 --- a/src/redux/actions/claims.js +++ b/src/redux/actions/claims.js @@ -64,7 +64,9 @@ export function doResolveUris(uris: Array, returnCachedClaims: boolean = if (uriResolveInfo.signing_channel) { result.channel = uriResolveInfo.signing_channel; result.claimsInChannel = - (uriResolveInfo.meta && uriResolveInfo.meta.claims_in_channel) || 0; + (uriResolveInfo.signing_channel.meta && + uriResolveInfo.signing_channel.meta.claims_in_channel) || + 0; } } @@ -198,7 +200,7 @@ export function doFetchClaimsByChannel(uri: string, page: number = 1) { Lbry.claim_search({ channel: uri, - is_controlling: true, + valid_channel_signatures: true, page: page || 1, order_by: ['release_time'], }).then((result: ClaimSearchResponse) => { From 8fba180923d5bf8c45ad98a82fa99db5f1d75d78 Mon Sep 17 00:00:00 2001 From: zxawry Date: Wed, 12 Jun 2019 15:30:08 +0100 Subject: [PATCH 10/21] set correct suggestion type for lbry URIs --- src/redux/selectors/search.js | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/redux/selectors/search.js b/src/redux/selectors/search.js index b519425..e2f1c1a 100644 --- a/src/redux/selectors/search.js +++ b/src/redux/selectors/search.js @@ -57,20 +57,21 @@ export const selectSearchSuggestions: Array = createSelector( return []; } - const queryIsPrefix = query === 'lbry:' || query === 'lbry:/' || query === 'lbry://'; + const queryIsPrefix = + query === 'lbry:' || query === 'lbry:/' || query === 'lbry://' || query === 'lbry://@'; - if (query.startsWith('lbry://') && query !== 'lbry://') { + if (queryIsPrefix) { + // If it is a prefix, wait until something else comes to figure out what to do + return []; + } else if (query.startsWith('lbry://')) { // If it starts with a prefix, don't show any autocomplete results // They are probably typing/pasting in a lbry uri return [ { value: query, - type: SEARCH_TYPES.FILE, + type: query[7] === '@' ? SEARCH_TYPES.CHANNEL : SEARCH_TYPES.FILE, }, ]; - } else if (queryIsPrefix) { - // If it is a prefix, wait until something else comes to figure out what to do - return []; } let searchSuggestions = []; From f435dc4600e0aa03a22f49d4f0a70cb9f85afc57 Mon Sep 17 00:00:00 2001 From: Sean Yesmunt Date: Tue, 18 Jun 2019 12:59:04 -0400 Subject: [PATCH 11/21] update build --- dist/bundle.es.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/dist/bundle.es.js b/dist/bundle.es.js index 536e4f0..b2f04b7 100644 --- a/dist/bundle.es.js +++ b/dist/bundle.es.js @@ -1044,18 +1044,18 @@ const selectSearchSuggestions = reselect.createSelector(selectSearchValue, selec return []; } - const queryIsPrefix = query === 'lbry:' || query === 'lbry:/' || query === 'lbry://'; + const queryIsPrefix = query === 'lbry:' || query === 'lbry:/' || query === 'lbry://' || query === 'lbry://@'; - if (query.startsWith('lbry://') && query !== 'lbry://') { + if (queryIsPrefix) { + // If it is a prefix, wait until something else comes to figure out what to do + return []; + } else if (query.startsWith('lbry://')) { // If it starts with a prefix, don't show any autocomplete results // They are probably typing/pasting in a lbry uri return [{ value: query, - type: SEARCH_TYPES.FILE + type: query[7] === '@' ? SEARCH_TYPES.CHANNEL : SEARCH_TYPES.FILE }]; - } else if (queryIsPrefix) { - // If it is a prefix, wait until something else comes to figure out what to do - return []; } let searchSuggestions = []; From a22d0270d08cc87f647bdc6eae61a14ff5bba2aa Mon Sep 17 00:00:00 2001 From: Sean Yesmunt Date: Sun, 9 Jun 2019 22:45:47 -0400 Subject: [PATCH 12/21] add tags --- .eslintrc.json | 1 + dist/bundle.es.js | 453 +++++++++++++++++++++++-------- dist/flow-typed/Tags.js | 30 ++ flow-typed/Claim.js | 3 +- flow-typed/Tags.js | 30 ++ src/constants/action_types.js | 25 +- src/constants/tags.js | 21 ++ src/index.js | 12 + src/redux/actions/claims.js | 47 +++- src/redux/actions/tags.js | 51 ++++ src/redux/reducers/claims.js | 20 +- src/redux/reducers/tags.js | 84 ++++++ src/redux/selectors/claims.js | 8 + src/redux/selectors/file_info.js | 6 + src/redux/selectors/tags.js | 47 ++++ 15 files changed, 705 insertions(+), 133 deletions(-) create mode 100644 dist/flow-typed/Tags.js create mode 100644 flow-typed/Tags.js create mode 100644 src/constants/tags.js create mode 100644 src/redux/actions/tags.js create mode 100644 src/redux/reducers/tags.js create mode 100644 src/redux/selectors/tags.js diff --git a/.eslintrc.json b/.eslintrc.json index 9ac4855..1860ea4 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -10,6 +10,7 @@ "__": true }, "rules": { + "camelcase": 0, "no-multi-spaces": 0, "new-cap": 0, "prefer-promise-reject-errors": 0, diff --git a/dist/bundle.es.js b/dist/bundle.es.js index b2f04b7..129ae72 100644 --- a/dist/bundle.es.js +++ b/dist/bundle.es.js @@ -98,6 +98,9 @@ const SET_CONTENT_POSITION = 'SET_CONTENT_POSITION'; const SET_CONTENT_LAST_VIEWED = 'SET_CONTENT_LAST_VIEWED'; const CLEAR_CONTENT_HISTORY_URI = 'CLEAR_CONTENT_HISTORY_URI'; const CLEAR_CONTENT_HISTORY_ALL = 'CLEAR_CONTENT_HISTORY_ALL'; +const CLAIM_SEARCH_STARTED = 'CLAIM_SEARCH_STARTED'; +const CLAIM_SEARCH_COMPLETED = 'CLAIM_SEARCH_COMPLETED'; +const CLAIM_SEARCH_FAILED = 'CLAIM_SEARCH_FAILED'; // Files const FILE_LIST_STARTED = 'FILE_LIST_STARTED'; @@ -187,21 +190,6 @@ const FETCH_REWARD_CONTENT_COMPLETED = 'FETCH_REWARD_CONTENT_COMPLETED'; const DOWNLOAD_LANGUAGE_SUCCEEDED = 'DOWNLOAD_LANGUAGE_SUCCEEDED'; const DOWNLOAD_LANGUAGE_FAILED = 'DOWNLOAD_LANGUAGE_FAILED'; -// ShapeShift -const GET_SUPPORTED_COINS_START = 'GET_SUPPORTED_COINS_START'; -const GET_SUPPORTED_COINS_SUCCESS = 'GET_SUPPORTED_COINS_SUCCESS'; -const GET_SUPPORTED_COINS_FAIL = 'GET_SUPPORTED_COINS_FAIL'; -const GET_COIN_STATS_START = 'GET_COIN_STATS_START'; -const GET_COIN_STATS_SUCCESS = 'GET_COIN_STATS_SUCCESS'; -const GET_COIN_STATS_FAIL = 'GET_COIN_STATS_FAIL'; -const PREPARE_SHAPE_SHIFT_START = 'PREPARE_SHAPE_SHIFT_START'; -const PREPARE_SHAPE_SHIFT_SUCCESS = 'PREPARE_SHAPE_SHIFT_SUCCESS'; -const PREPARE_SHAPE_SHIFT_FAIL = 'PREPARE_SHAPE_SHIFT_FAIL'; -const GET_ACTIVE_SHIFT_START = 'GET_ACTIVE_SHIFT_START'; -const GET_ACTIVE_SHIFT_SUCCESS = 'GET_ACTIVE_SHIFT_SUCCESS'; -const GET_ACTIVE_SHIFT_FAIL = 'GET_ACTIVE_SHIFT_FAIL'; -const CLEAR_SHAPE_SHIFT = 'CLEAR_SHAPE_SHIFT'; - // Subscriptions const CHANNEL_SUBSCRIBE = 'CHANNEL_SUBSCRIBE'; const CHANNEL_UNSUBSCRIBE = 'CHANNEL_UNSUBSCRIBE'; @@ -239,6 +227,13 @@ const FETCH_DATE = 'FETCH_DATE'; const FETCH_COST_INFO_STARTED = 'FETCH_COST_INFO_STARTED'; const FETCH_COST_INFO_COMPLETED = 'FETCH_COST_INFO_COMPLETED'; const FETCH_COST_INFO_FAILED = 'FETCH_COST_INFO_FAILED'; +// Tags +const TOGGLE_TAG_FOLLOW = 'TOGGLE_TAG_FOLLOW'; +const TAG_ADD = 'TAG_ADD'; +const TAG_DELETE = 'TAG_DELETE'; +const FETCH_TRENDING_STARTED = 'FETCH_TRENDING_STARTED'; +const FETCH_TRENDING_COMPLETED = 'FETCH_TRENDING_COMPLETED'; +const FETCH_TRENDING_FAILED = 'FETCH_TRENDING_FAILED'; var action_types = /*#__PURE__*/Object.freeze({ WINDOW_FOCUSED: WINDOW_FOCUSED, @@ -323,6 +318,9 @@ var action_types = /*#__PURE__*/Object.freeze({ SET_CONTENT_LAST_VIEWED: SET_CONTENT_LAST_VIEWED, CLEAR_CONTENT_HISTORY_URI: CLEAR_CONTENT_HISTORY_URI, CLEAR_CONTENT_HISTORY_ALL: CLEAR_CONTENT_HISTORY_ALL, + CLAIM_SEARCH_STARTED: CLAIM_SEARCH_STARTED, + CLAIM_SEARCH_COMPLETED: CLAIM_SEARCH_COMPLETED, + CLAIM_SEARCH_FAILED: CLAIM_SEARCH_FAILED, FILE_LIST_STARTED: FILE_LIST_STARTED, FILE_LIST_SUCCEEDED: FILE_LIST_SUCCEEDED, FETCH_FILE_INFO_STARTED: FETCH_FILE_INFO_STARTED, @@ -399,19 +397,6 @@ var action_types = /*#__PURE__*/Object.freeze({ FETCH_REWARD_CONTENT_COMPLETED: FETCH_REWARD_CONTENT_COMPLETED, DOWNLOAD_LANGUAGE_SUCCEEDED: DOWNLOAD_LANGUAGE_SUCCEEDED, DOWNLOAD_LANGUAGE_FAILED: DOWNLOAD_LANGUAGE_FAILED, - GET_SUPPORTED_COINS_START: GET_SUPPORTED_COINS_START, - GET_SUPPORTED_COINS_SUCCESS: GET_SUPPORTED_COINS_SUCCESS, - GET_SUPPORTED_COINS_FAIL: GET_SUPPORTED_COINS_FAIL, - GET_COIN_STATS_START: GET_COIN_STATS_START, - GET_COIN_STATS_SUCCESS: GET_COIN_STATS_SUCCESS, - GET_COIN_STATS_FAIL: GET_COIN_STATS_FAIL, - PREPARE_SHAPE_SHIFT_START: PREPARE_SHAPE_SHIFT_START, - PREPARE_SHAPE_SHIFT_SUCCESS: PREPARE_SHAPE_SHIFT_SUCCESS, - PREPARE_SHAPE_SHIFT_FAIL: PREPARE_SHAPE_SHIFT_FAIL, - GET_ACTIVE_SHIFT_START: GET_ACTIVE_SHIFT_START, - GET_ACTIVE_SHIFT_SUCCESS: GET_ACTIVE_SHIFT_SUCCESS, - GET_ACTIVE_SHIFT_FAIL: GET_ACTIVE_SHIFT_FAIL, - CLEAR_SHAPE_SHIFT: CLEAR_SHAPE_SHIFT, CHANNEL_SUBSCRIBE: CHANNEL_SUBSCRIBE, CHANNEL_UNSUBSCRIBE: CHANNEL_UNSUBSCRIBE, HAS_FETCHED_SUBSCRIPTIONS: HAS_FETCHED_SUBSCRIPTIONS, @@ -440,7 +425,13 @@ var action_types = /*#__PURE__*/Object.freeze({ FETCH_DATE: FETCH_DATE, FETCH_COST_INFO_STARTED: FETCH_COST_INFO_STARTED, FETCH_COST_INFO_COMPLETED: FETCH_COST_INFO_COMPLETED, - FETCH_COST_INFO_FAILED: FETCH_COST_INFO_FAILED + FETCH_COST_INFO_FAILED: FETCH_COST_INFO_FAILED, + TOGGLE_TAG_FOLLOW: TOGGLE_TAG_FOLLOW, + TAG_ADD: TAG_ADD, + TAG_DELETE: TAG_DELETE, + FETCH_TRENDING_STARTED: FETCH_TRENDING_STARTED, + FETCH_TRENDING_COMPLETED: FETCH_TRENDING_COMPLETED, + FETCH_TRENDING_FAILED: FETCH_TRENDING_FAILED }); const API_DOWN = 'apiDown'; @@ -1428,6 +1419,10 @@ const makeSelectChannelForClaimUri = (uri, includePrefix = false) => reselect.cr return includePrefix ? `lbry://${channel}` : channel; }); +const makeSelectTagsForUri = uri => reselect.createSelector(makeSelectMetadataForUri(uri), metadata => { + return metadata && metadata.tags || []; +}); + const selectState$2 = state => state.wallet || {}; const selectWalletState = selectState$2; @@ -1946,6 +1941,14 @@ function doUpdateBlockHeight() { }); } +// https://github.com/reactjs/redux/issues/911 +function batchActions(...actions) { + return { + type: 'BATCH_ACTIONS', + actions + }; +} + 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) { @@ -1997,10 +2000,13 @@ function doResolveUris(uris, returnCachedClaims = false) { result.stream = uriResolveInfo; if (uriResolveInfo.signing_channel) { result.channel = uriResolveInfo.signing_channel; +<<<<<<< HEAD result.claimsInChannel = uriResolveInfo.signing_channel.meta && uriResolveInfo.signing_channel.meta.claims_in_channel || 0; +======= + result.claimsInChannel = uriResolveInfo.meta && uriResolveInfo.meta.claims_in_channel || 0; +>>>>>>> add tags } } - // $FlowFixMe resolveInfo[uri] = result; } @@ -2119,7 +2125,11 @@ function doFetchClaimsByChannel(uri, page = 1) { lbryProxy.claim_search({ channel: uri, +<<<<<<< HEAD valid_channel_signatures: true, +======= + is_controlling: true, +>>>>>>> add tags page: page || 1, order_by: ['release_time'] }).then(result => { @@ -2181,6 +2191,46 @@ function doFetchChannelListMine() { }; } +function doClaimSearch(amount = 20, options = {}, cb) { + return dispatch => { + dispatch({ + type: CLAIM_SEARCH_STARTED + }); + + const success = data => { + const resolveInfo = {}; + const uris = []; + data.items.forEach(stream => { + resolveInfo[stream.permanent_url] = { stream }; + uris.push(stream.permanent_url); + }); + + dispatch({ + type: CLAIM_SEARCH_COMPLETED, + data: { resolveInfo } + }); + + if (cb) { + cb(null, uris); + } + }; + + const failure = err => { + dispatch({ + type: CLAIM_SEARCH_FAILED, + error: err + }); + if (cb) { + cb(err); + } + }; + + lbryProxy.claim_search(_extends$3({ + page_size: amount + }, options)).then(success, failure); + }; +} + const selectState$3 = state => state.fileInfo || {}; const selectFileInfosByOutpoint = reselect.createSelector(selectState$3, state => state.byOutpoint || {}); @@ -2344,6 +2394,10 @@ const selectFileListPublishedSort = reselect.createSelector(selectState$3, state const selectFileListDownloadedSort = reselect.createSelector(selectState$3, state => state.fileListDownloadedSort); +const selectDownloadedUris = reselect.createSelector(selectFileInfosDownloaded, +// We should use permament_url but it doesn't exist in file_list +info => info.map(claim => `lbry://${claim.claim_name}#${claim.claim_id}`)); + // const selectState$4 = state => state.file || {}; @@ -2522,14 +2576,6 @@ function doSetFileListSort(page, value) { }; } -// https://github.com/reactjs/redux/issues/911 -function batchActions(...actions) { - return { - type: 'BATCH_ACTIONS', - actions - }; -} - // Returns a function, that, as long as it continues to be invoked, will not // be triggered. The function will be called after it stops being called for // N milliseconds. If `immediate` is passed, trigger the function on the @@ -2709,6 +2755,55 @@ function savePosition(claimId, outpoint, position) { // +const doToggleTagFollow = name => ({ + type: TOGGLE_TAG_FOLLOW, + data: { + name + } +}); + +const doAddTag = name => ({ + type: TAG_ADD, + data: { + name + } +}); + +const doDeleteTag = name => ({ + type: TAG_DELETE, + data: { + name + } +}); + +const doFetchByTags = (amount = 10, options = {}) => { + return dispatch => { + dispatch({ + type: FETCH_TRENDING_STARTED + }); + + const callback = (error, uris = []) => { + if (error) { + return dispatch({ + type: FETCH_TRENDING_FAILED, + error + }); + } + + dispatch({ + type: FETCH_TRENDING_COMPLETED, + data: { + uris + } + }); + }; + + dispatch(doClaimSearch(amount, options, callback)); + }; +}; + +var _extends$4 = 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; }; + const reducers = {}; const defaultState = { byId: {}, @@ -2725,7 +2820,7 @@ const defaultState = { pendingById: {} }; -reducers[RESOLVE_URIS_COMPLETED] = (state, action) => { +function handleClaimAction(state, action) { const { resolveInfo } = action.data; @@ -2762,6 +2857,10 @@ reducers[RESOLVE_URIS_COMPLETED] = (state, action) => { channelClaimCounts, resolvingUris: (state.resolvingUris || []).filter(uri => !resolveInfo[uri]) }); +} + +reducers[RESOLVE_URIS_COMPLETED] = (state, action) => { + return handleClaimAction(state, action); }; reducers[FETCH_CLAIM_LIST_MINE_STARTED] = state => Object.assign({}, state, { @@ -2936,13 +3035,27 @@ reducers[RESOLVE_URIS_STARTED] = (state, action) => { }); }; +reducers[CLAIM_SEARCH_STARTED] = state => { + return Object.assign({}, state, { + fetchingClaimSearch: true + }); +}; +reducers[CLAIM_SEARCH_COMPLETED] = (state, action) => { + return _extends$4({}, handleClaimAction(state, action), { fetchingClaimSearch: false }); +}; +reducers[CLAIM_SEARCH_FAILED] = state => { + return Object.assign({}, state, { + fetchingClaimSearch: false + }); +}; + function claimsReducer(state = defaultState, action) { const handler = reducers[action.type]; if (handler) return handler(state, action); return state; } -var _extends$4 = 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; }; +var _extends$5 = 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; }; const reducers$1 = {}; const defaultState$1 = { @@ -2959,7 +3072,7 @@ reducers$1[PURCHASE_URI_STARTED] = (state, action) => { newFailedPurchaseUris.splice(newFailedPurchaseUris.indexOf(uri), 1); } - return _extends$4({}, state, { + return _extends$5({}, state, { failedPurchaseUris: newFailedPurchaseUris, purchaseUriErrorMessage: '' }); @@ -2981,7 +3094,7 @@ reducers$1[PURCHASE_URI_COMPLETED] = (state, action) => { newPurchasedStreamingUrls[uri] = streamingUrl; } - return _extends$4({}, state, { + return _extends$5({}, state, { failedPurchaseUris: newFailedPurchaseUris, purchasedUris: newPurchasedUris, purchasedStreamingUrls: newPurchasedStreamingUrls, @@ -2997,7 +3110,7 @@ reducers$1[PURCHASE_URI_FAILED] = (state, action) => { newFailedPurchaseUris.push(uri); } - return _extends$4({}, state, { + return _extends$5({}, state, { failedPurchaseUris: newFailedPurchaseUris, purchaseUriErrorMessage: error }); @@ -3010,7 +3123,7 @@ reducers$1[DELETE_PURCHASED_URI] = (state, action) => { newPurchasedUris.splice(newPurchasedUris.indexOf(uri), 1); } - return _extends$4({}, state, { + return _extends$5({}, state, { purchasedUris: newPurchasedUris }); }; @@ -3021,7 +3134,7 @@ function fileReducer(state = defaultState$1, action) { return state; } -var _extends$5 = 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; }; +var _extends$6 = 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; }; const reducers$2 = {}; const defaultState$2 = { @@ -3157,12 +3270,12 @@ reducers$2[LOADING_VIDEO_STARTED] = (state, action) => { const newLoading = Object.assign({}, state.urisLoading); newLoading[uri] = true; - const newErrors = _extends$5({}, state.errors); + const newErrors = _extends$6({}, state.errors); if (uri in newErrors) delete newErrors[uri]; return Object.assign({}, state, { urisLoading: newLoading, - errors: _extends$5({}, newErrors) + errors: _extends$6({}, newErrors) }); }; @@ -3172,12 +3285,12 @@ reducers$2[LOADING_VIDEO_FAILED] = (state, action) => { const newLoading = Object.assign({}, state.urisLoading); delete newLoading[uri]; - const newErrors = _extends$5({}, state.errors); + const newErrors = _extends$6({}, state.errors); newErrors[uri] = true; return Object.assign({}, state, { urisLoading: newLoading, - errors: _extends$5({}, newErrors) + errors: _extends$6({}, newErrors) }); }; @@ -3218,7 +3331,7 @@ const handleActions = (actionMap, defaultState) => (state = defaultState, action return state; }; -var _extends$6 = 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; }; +var _extends$7 = 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; }; const defaultState$3 = { notifications: [], @@ -3233,7 +3346,7 @@ const notificationsReducer = handleActions({ const newToasts = state.toasts.slice(); newToasts.push(toast); - return _extends$6({}, state, { + return _extends$7({}, state, { toasts: newToasts }); }, @@ -3241,7 +3354,7 @@ const notificationsReducer = handleActions({ const newToasts = state.toasts.slice(); newToasts.shift(); - return _extends$6({}, state, { + return _extends$7({}, state, { toasts: newToasts }); }, @@ -3252,7 +3365,7 @@ const notificationsReducer = handleActions({ const newNotifications = state.notifications.slice(); newNotifications.push(notification); - return _extends$6({}, state, { + return _extends$7({}, state, { notifications: newNotifications }); }, @@ -3263,7 +3376,7 @@ const notificationsReducer = handleActions({ notifications = notifications.map(pastNotification => pastNotification.id === notification.id ? notification : pastNotification); - return _extends$6({}, state, { + return _extends$7({}, state, { notifications }); }, @@ -3272,7 +3385,7 @@ const notificationsReducer = handleActions({ let newNotifications = state.notifications.slice(); newNotifications = newNotifications.filter(notification => notification.id !== id); - return _extends$6({}, state, { + return _extends$7({}, state, { notifications: newNotifications }); }, @@ -3283,7 +3396,7 @@ const notificationsReducer = handleActions({ const newErrors = state.errors.slice(); newErrors.push(error); - return _extends$6({}, state, { + return _extends$7({}, state, { errors: newErrors }); }, @@ -3291,13 +3404,13 @@ const notificationsReducer = handleActions({ const newErrors = state.errors.slice(); newErrors.shift(); - return _extends$6({}, state, { + return _extends$7({}, state, { errors: newErrors }); } }, defaultState$3); -var _extends$7 = 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; }; +var _extends$8 = 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; }; const defaultState$4 = { isActive: false, // does the user have any typed text in the search input @@ -3317,29 +3430,29 @@ const defaultState$4 = { }; const searchReducer = handleActions({ - [SEARCH_START]: state => _extends$7({}, state, { + [SEARCH_START]: state => _extends$8({}, state, { searching: true }), [SEARCH_SUCCESS]: (state, action) => { const { query, uris } = action.data; - return _extends$7({}, state, { + return _extends$8({}, state, { searching: false, urisByQuery: Object.assign({}, state.urisByQuery, { [query]: uris }) }); }, - [SEARCH_FAIL]: state => _extends$7({}, state, { + [SEARCH_FAIL]: state => _extends$8({}, state, { searching: false }), - [UPDATE_SEARCH_QUERY]: (state, action) => _extends$7({}, state, { + [UPDATE_SEARCH_QUERY]: (state, action) => _extends$8({}, state, { searchQuery: action.data.query, isActive: true }), - [UPDATE_SEARCH_SUGGESTIONS]: (state, action) => _extends$7({}, state, { - suggestions: _extends$7({}, state.suggestions, { + [UPDATE_SEARCH_SUGGESTIONS]: (state, action) => _extends$8({}, state, { + suggestions: _extends$8({}, state.suggestions, { [action.data.query]: action.data.suggestions }) }), @@ -3347,27 +3460,27 @@ const searchReducer = handleActions({ // sets isActive to false so the uri will be populated correctly if the // user is on a file page. The search query will still be present on any // other page - [DISMISS_NOTIFICATION]: state => _extends$7({}, state, { + [DISMISS_NOTIFICATION]: state => _extends$8({}, state, { isActive: false }), - [SEARCH_FOCUS]: state => _extends$7({}, state, { + [SEARCH_FOCUS]: state => _extends$8({}, state, { focused: true }), - [SEARCH_BLUR]: state => _extends$7({}, state, { + [SEARCH_BLUR]: state => _extends$8({}, state, { focused: false }), [UPDATE_SEARCH_OPTIONS]: (state, action) => { const { options: oldOptions } = state; const newOptions = action.data; - const options = _extends$7({}, oldOptions, newOptions); - return _extends$7({}, state, { + const options = _extends$8({}, oldOptions, newOptions); + return _extends$8({}, state, { options }); } }, defaultState$4); -var _extends$8 = 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; }; +var _extends$9 = 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; }; const buildDraftTransaction = () => ({ amount: undefined, @@ -3407,25 +3520,25 @@ const defaultState$5 = { }; const walletReducer = handleActions({ - [FETCH_TRANSACTIONS_STARTED]: state => _extends$8({}, state, { + [FETCH_TRANSACTIONS_STARTED]: state => _extends$9({}, state, { fetchingTransactions: true }), [FETCH_TRANSACTIONS_COMPLETED]: (state, action) => { - const byId = _extends$8({}, state.transactions); + const byId = _extends$9({}, state.transactions); const { transactions } = action.data; transactions.forEach(transaction => { byId[transaction.txid] = transaction; }); - return _extends$8({}, state, { + return _extends$9({}, state, { transactions: byId, fetchingTransactions: false }); }, - [FETCH_SUPPORTS_STARTED]: state => _extends$8({}, state, { + [FETCH_SUPPORTS_STARTED]: state => _extends$9({}, state, { fetchingSupports: true }), @@ -3438,7 +3551,7 @@ const walletReducer = handleActions({ byOutpoint[`${txid}:${nout}`] = transaction; }); - return _extends$8({}, state, { supports: byOutpoint, fetchingSupports: false }); + return _extends$9({}, state, { supports: byOutpoint, fetchingSupports: false }); }, [ABANDON_SUPPORT_STARTED]: (state, action) => { @@ -3447,7 +3560,7 @@ const walletReducer = handleActions({ currentlyAbandoning[outpoint] = true; - return _extends$8({}, state, { + return _extends$9({}, state, { abandoningSupportsByOutpoint: currentlyAbandoning }); }, @@ -3460,56 +3573,56 @@ const walletReducer = handleActions({ delete currentlyAbandoning[outpoint]; delete byOutpoint[outpoint]; - return _extends$8({}, state, { + return _extends$9({}, state, { supports: byOutpoint, abandoningSupportsById: currentlyAbandoning }); }, - [GET_NEW_ADDRESS_STARTED]: state => _extends$8({}, state, { + [GET_NEW_ADDRESS_STARTED]: state => _extends$9({}, state, { gettingNewAddress: true }), [GET_NEW_ADDRESS_COMPLETED]: (state, action) => { const { address } = action.data; - return _extends$8({}, state, { gettingNewAddress: false, receiveAddress: address }); + return _extends$9({}, state, { gettingNewAddress: false, receiveAddress: address }); }, - [UPDATE_BALANCE]: (state, action) => _extends$8({}, state, { + [UPDATE_BALANCE]: (state, action) => _extends$9({}, state, { balance: action.data.balance }), - [UPDATE_TOTAL_BALANCE]: (state, action) => _extends$8({}, state, { + [UPDATE_TOTAL_BALANCE]: (state, action) => _extends$9({}, state, { totalBalance: action.data.totalBalance }), - [CHECK_ADDRESS_IS_MINE_STARTED]: state => _extends$8({}, state, { + [CHECK_ADDRESS_IS_MINE_STARTED]: state => _extends$9({}, state, { checkingAddressOwnership: true }), - [CHECK_ADDRESS_IS_MINE_COMPLETED]: state => _extends$8({}, state, { + [CHECK_ADDRESS_IS_MINE_COMPLETED]: state => _extends$9({}, state, { checkingAddressOwnership: false }), [SET_DRAFT_TRANSACTION_AMOUNT]: (state, action) => { const oldDraft = state.draftTransaction; - const newDraft = _extends$8({}, oldDraft, { amount: parseFloat(action.data.amount) }); + const newDraft = _extends$9({}, oldDraft, { amount: parseFloat(action.data.amount) }); - return _extends$8({}, state, { draftTransaction: newDraft }); + return _extends$9({}, state, { draftTransaction: newDraft }); }, [SET_DRAFT_TRANSACTION_ADDRESS]: (state, action) => { const oldDraft = state.draftTransaction; - const newDraft = _extends$8({}, oldDraft, { address: action.data.address }); + const newDraft = _extends$9({}, oldDraft, { address: action.data.address }); - return _extends$8({}, state, { draftTransaction: newDraft }); + return _extends$9({}, state, { draftTransaction: newDraft }); }, [SEND_TRANSACTION_STARTED]: state => { - const newDraftTransaction = _extends$8({}, state.draftTransaction, { sending: true }); + const newDraftTransaction = _extends$9({}, state.draftTransaction, { sending: true }); - return _extends$8({}, state, { draftTransaction: newDraftTransaction }); + return _extends$9({}, state, { draftTransaction: newDraftTransaction }); }, [SEND_TRANSACTION_COMPLETED]: state => Object.assign({}, state, { @@ -3522,108 +3635,108 @@ const walletReducer = handleActions({ error: action.data.error }); - return _extends$8({}, state, { draftTransaction: newDraftTransaction }); + return _extends$9({}, state, { draftTransaction: newDraftTransaction }); }, - [SUPPORT_TRANSACTION_STARTED]: state => _extends$8({}, state, { + [SUPPORT_TRANSACTION_STARTED]: state => _extends$9({}, state, { sendingSupport: true }), - [SUPPORT_TRANSACTION_COMPLETED]: state => _extends$8({}, state, { + [SUPPORT_TRANSACTION_COMPLETED]: state => _extends$9({}, state, { sendingSupport: false }), - [SUPPORT_TRANSACTION_FAILED]: (state, action) => _extends$8({}, state, { + [SUPPORT_TRANSACTION_FAILED]: (state, action) => _extends$9({}, state, { error: action.data.error, sendingSupport: false }), - [WALLET_STATUS_COMPLETED]: (state, action) => _extends$8({}, state, { + [WALLET_STATUS_COMPLETED]: (state, action) => _extends$9({}, state, { walletIsEncrypted: action.result }), - [WALLET_ENCRYPT_START]: state => _extends$8({}, state, { + [WALLET_ENCRYPT_START]: state => _extends$9({}, state, { walletEncryptPending: true, walletEncryptSucceded: null, walletEncryptResult: null }), - [WALLET_ENCRYPT_COMPLETED]: (state, action) => _extends$8({}, state, { + [WALLET_ENCRYPT_COMPLETED]: (state, action) => _extends$9({}, state, { walletEncryptPending: false, walletEncryptSucceded: true, walletEncryptResult: action.result }), - [WALLET_ENCRYPT_FAILED]: (state, action) => _extends$8({}, state, { + [WALLET_ENCRYPT_FAILED]: (state, action) => _extends$9({}, state, { walletEncryptPending: false, walletEncryptSucceded: false, walletEncryptResult: action.result }), - [WALLET_DECRYPT_START]: state => _extends$8({}, state, { + [WALLET_DECRYPT_START]: state => _extends$9({}, state, { walletDecryptPending: true, walletDecryptSucceded: null, walletDecryptResult: null }), - [WALLET_DECRYPT_COMPLETED]: (state, action) => _extends$8({}, state, { + [WALLET_DECRYPT_COMPLETED]: (state, action) => _extends$9({}, state, { walletDecryptPending: false, walletDecryptSucceded: true, walletDecryptResult: action.result }), - [WALLET_DECRYPT_FAILED]: (state, action) => _extends$8({}, state, { + [WALLET_DECRYPT_FAILED]: (state, action) => _extends$9({}, state, { walletDecryptPending: false, walletDecryptSucceded: false, walletDecryptResult: action.result }), - [WALLET_UNLOCK_START]: state => _extends$8({}, state, { + [WALLET_UNLOCK_START]: state => _extends$9({}, state, { walletUnlockPending: true, walletUnlockSucceded: null, walletUnlockResult: null }), - [WALLET_UNLOCK_COMPLETED]: (state, action) => _extends$8({}, state, { + [WALLET_UNLOCK_COMPLETED]: (state, action) => _extends$9({}, state, { walletUnlockPending: false, walletUnlockSucceded: true, walletUnlockResult: action.result }), - [WALLET_UNLOCK_FAILED]: (state, action) => _extends$8({}, state, { + [WALLET_UNLOCK_FAILED]: (state, action) => _extends$9({}, state, { walletUnlockPending: false, walletUnlockSucceded: false, walletUnlockResult: action.result }), - [WALLET_LOCK_START]: state => _extends$8({}, state, { + [WALLET_LOCK_START]: state => _extends$9({}, state, { walletLockPending: false, walletLockSucceded: null, walletLockResult: null }), - [WALLET_LOCK_COMPLETED]: (state, action) => _extends$8({}, state, { + [WALLET_LOCK_COMPLETED]: (state, action) => _extends$9({}, state, { walletLockPending: false, walletLockSucceded: true, walletLockResult: action.result }), - [WALLET_LOCK_FAILED]: (state, action) => _extends$8({}, state, { + [WALLET_LOCK_FAILED]: (state, action) => _extends$9({}, state, { walletLockPending: false, walletLockSucceded: false, walletLockResult: action.result }), - [SET_TRANSACTION_LIST_FILTER]: (state, action) => _extends$8({}, state, { + [SET_TRANSACTION_LIST_FILTER]: (state, action) => _extends$9({}, state, { transactionListFilter: action.data }), - [UPDATE_CURRENT_HEIGHT]: (state, action) => _extends$8({}, state, { + [UPDATE_CURRENT_HEIGHT]: (state, action) => _extends$9({}, state, { latestBlock: action.data }) }, defaultState$5); -var _extends$9 = 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; }; +var _extends$a = 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; }; const reducers$3 = {}; const defaultState$6 = { @@ -3632,9 +3745,9 @@ const defaultState$6 = { reducers$3[SET_CONTENT_POSITION] = (state, action) => { const { claimId, outpoint, position } = action.data; - return _extends$9({}, state, { - positions: _extends$9({}, state.positions, { - [claimId]: _extends$9({}, state.positions[claimId], { + return _extends$a({}, state, { + positions: _extends$a({}, state.positions, { + [claimId]: _extends$a({}, state.positions[claimId], { [outpoint]: position }) }) @@ -3647,6 +3760,79 @@ function contentReducer(state = defaultState$6, action) { return state; } +const defaultFollowedTags = ['gaming', 'blockchain', 'news', 'learning', 'funny', 'technology', 'automotive', 'economics', 'sports', 'food', 'science', 'art', 'nature', 'beliefs', 'music', 'pop culture', 'weapons']; + +const defaultRecommendedTags = []; + +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 getDefaultRecommendedTags() { + return defaultFollowedTags.concat(defaultRecommendedTags).reduce((tagsMap, tag) => _extends$b({}, tagsMap, { + [tag]: { name: tag } + }), {}); +} + +const defaultState$7 = { + followedTags: defaultFollowedTags, + knownTags: getDefaultRecommendedTags(), + trending: [], + fetchingTrending: false +}; + +const tagsReducer = handleActions({ + [TOGGLE_TAG_FOLLOW]: (state, action) => { + const { followedTags } = state; + const { name } = action.data; + + let newFollowedTags = followedTags.slice(); + + if (newFollowedTags.includes(name)) { + newFollowedTags = newFollowedTags.filter(tag => tag !== name); + } else { + newFollowedTags.push(name); + } + + return _extends$b({}, state, { + followedTags: newFollowedTags + }); + }, + + [TAG_ADD]: (state, action) => { + const { knownTags } = state; + const { name } = action.data; + + let newKnownTags = _extends$b({}, knownTags); + newKnownTags[name] = { name }; + + return _extends$b({}, state, { + knownTags: newKnownTags + }); + }, + + [TAG_DELETE]: (state, action) => { + const { knownTags, followedTags } = state; + const { name } = action.data; + + let newKnownTags = _extends$b({}, knownTags); + delete newKnownTags[name]; + + return _extends$b({}, state, { + knownTags: newKnownTags + }); + }, + [FETCH_TRENDING_STARTED]: state => _extends$b({}, state, { + fetchingTrending: true + }), + [FETCH_TRENDING_COMPLETED]: (state, action) => _extends$b({}, state, { + trending: action.data.uris, + fetchingTrending: false + }), + [FETCH_TRENDING_FAILED]: state => _extends$b({}, state, { + trending: [], + fetchingTrending: false + }) +}, defaultState$7); + const selectState$5 = state => state.content || {}; const makeSelectContentPositionForUri = uri => reselect.createSelector(selectState$5, makeSelectClaimForUri(uri), (state, claim) => { @@ -3658,14 +3844,14 @@ const makeSelectContentPositionForUri = uri => reselect.createSelector(selectSta return state.positions[id] ? state.positions[id][outpoint] : null; }); -var _extends$a = 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; }; +var _extends$c = 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; }; const selectState$6 = state => state.notifications || {}; const selectToast = reselect.createSelector(selectState$6, state => { if (state.toasts.length) { const { id, params } = state.toasts[0]; - return _extends$a({ + return _extends$c({ id }, params); } @@ -3684,6 +3870,34 @@ const selectError = reselect.createSelector(selectState$6, state => { return null; }); +// + +const selectState$7 = state => state.tags || {}; + +const selectKnownTagsByName = reselect.createSelector(selectState$7, state => state.knownTags); + +const selectFollowedTagsList = reselect.createSelector(selectState$7, state => state.followedTags); + +const selectFollowedTags = reselect.createSelector(selectFollowedTagsList, followedTags => followedTags.map(tag => ({ name: tag }))); + +const selectUnfollowedTags = reselect.createSelector(selectKnownTagsByName, selectFollowedTagsList, (tagsByName, followedTags) => { + const followedTagsSet = new Set(followedTags); + let tagsToReturn = []; + + Object.keys(tagsByName).forEach(key => { + if (!followedTagsSet.has(key)) { + const { name } = tagsByName[key]; + tagsToReturn.push({ name }); + } + }); + + return tagsToReturn; +}); + +const selectTrendingUris = reselect.createSelector(selectState$7, state => state.trending || []); + +const selectFetchingTrending = reselect.createSelector(selectState$7, state => state.fetchingTrending); + exports.ACTIONS = action_types; exports.Lbry = lbryProxy; exports.PAGES = pages; @@ -3700,14 +3914,17 @@ exports.contentReducer = contentReducer; exports.convertToShareLink = convertToShareLink; exports.creditsToString = creditsToString; exports.doAbandonClaim = doAbandonClaim; +exports.doAddTag = doAddTag; exports.doBalanceSubscribe = doBalanceSubscribe; exports.doBlurSearchInput = doBlurSearchInput; exports.doCheckAddressIsMine = doCheckAddressIsMine; exports.doCreateChannel = doCreateChannel; exports.doDeletePurchasedUri = doDeletePurchasedUri; +exports.doDeleteTag = doDeleteTag; exports.doDismissError = doDismissError; exports.doDismissToast = doDismissToast; exports.doError = doError; +exports.doFetchByTags = doFetchByTags; exports.doFetchChannelListMine = doFetchChannelListMine; exports.doFetchClaimListMine = doFetchClaimListMine; exports.doFetchClaimsByChannel = doFetchClaimsByChannel; @@ -3729,6 +3946,7 @@ exports.doSetDraftTransactionAmount = doSetDraftTransactionAmount; exports.doSetFileListSort = doSetFileListSort; exports.doSetTransactionListFilter = doSetTransactionListFilter; exports.doToast = doToast; +exports.doToggleTagFollow = doToggleTagFollow; exports.doTotalBalanceSubscribe = doTotalBalanceSubscribe; exports.doUpdateBalance = doUpdateBalance; exports.doUpdateBlockHeight = doUpdateBlockHeight; @@ -3773,6 +3991,7 @@ exports.makeSelectQueryWithOptions = makeSelectQueryWithOptions; exports.makeSelectRecommendedContentForUri = makeSelectRecommendedContentForUri; exports.makeSelectSearchUris = makeSelectSearchUris; exports.makeSelectStreamingUrlForUri = makeSelectStreamingUrlForUri; +exports.makeSelectTagsForUri = makeSelectTagsForUri; exports.makeSelectThumbnailForUri = makeSelectThumbnailForUri; exports.makeSelectTitleForUri = makeSelectTitleForUri; exports.makeSelectTotalItemsForChannel = makeSelectTotalItemsForChannel; @@ -3795,6 +4014,7 @@ exports.selectChannelClaimCounts = selectChannelClaimCounts; exports.selectClaimsById = selectClaimsById; exports.selectClaimsByUri = selectClaimsByUri; exports.selectCurrentChannelPage = selectCurrentChannelPage; +exports.selectDownloadedUris = selectDownloadedUris; exports.selectDownloadingByOutpoint = selectDownloadingByOutpoint; exports.selectDownloadingFileInfos = selectDownloadingFileInfos; exports.selectDraftTransaction = selectDraftTransaction; @@ -3804,10 +4024,12 @@ exports.selectDraftTransactionError = selectDraftTransactionError; exports.selectError = selectError; exports.selectFailedPurchaseUris = selectFailedPurchaseUris; exports.selectFetchingMyChannels = selectFetchingMyChannels; +exports.selectFetchingTrending = selectFetchingTrending; exports.selectFileInfosByOutpoint = selectFileInfosByOutpoint; exports.selectFileInfosDownloaded = selectFileInfosDownloaded; exports.selectFileListDownloadedSort = selectFileListDownloadedSort; exports.selectFileListPublishedSort = selectFileListPublishedSort; +exports.selectFollowedTags = selectFollowedTags; exports.selectGettingNewAddress = selectGettingNewAddress; exports.selectHasTransactions = selectHasTransactions; exports.selectIsFetchingClaimListMine = selectIsFetchingClaimListMine; @@ -3846,6 +4068,8 @@ exports.selectTotalDownloadProgress = selectTotalDownloadProgress; exports.selectTransactionItems = selectTransactionItems; exports.selectTransactionListFilter = selectTransactionListFilter; exports.selectTransactionsById = selectTransactionsById; +exports.selectTrendingUris = selectTrendingUris; +exports.selectUnfollowedTags = selectUnfollowedTags; exports.selectUrisLoading = selectUrisLoading; exports.selectWalletDecryptPending = selectWalletDecryptPending; exports.selectWalletDecryptResult = selectWalletDecryptResult; @@ -3859,5 +4083,6 @@ exports.selectWalletUnlockPending = selectWalletUnlockPending; exports.selectWalletUnlockResult = selectWalletUnlockResult; exports.selectWalletUnlockSucceeded = selectWalletUnlockSucceeded; exports.setSearchApi = setSearchApi; +exports.tagsReducer = tagsReducer; exports.toQueryString = toQueryString; exports.walletReducer = walletReducer; diff --git a/dist/flow-typed/Tags.js b/dist/flow-typed/Tags.js new file mode 100644 index 0000000..d6b4510 --- /dev/null +++ b/dist/flow-typed/Tags.js @@ -0,0 +1,30 @@ +declare type TagState = { + followedTags: FollowedTags, + knownTags: KnownTags, + trending: Array, + fetchingTrending: boolean, +}; + +declare type Tag = { + name: string, +}; + +declare type KnownTags = { + [string]: Tag, +}; + +declare type FollowedTags = Array; + +declare type TagAction = { + type: string, + data: { + name: string, + }, +}; + +declare type TrendingTagAction = { + type: string, + data: { + uris: Array, + }, +}; diff --git a/flow-typed/Claim.js b/flow-typed/Claim.js index f18b128..d5ca709 100644 --- a/flow-typed/Claim.js +++ b/flow-typed/Claim.js @@ -3,8 +3,7 @@ declare type Claim = StreamClaim | ChannelClaim; declare type ChannelClaim = GenericClaim & { - is_channel_signature_valid?: boolean, // we may have signed channels in the future, fixes some flow issues for now. - signing_channel?: ChannelClaim, + is_channel_signature_valid?: boolean, // we may have signed channels in the future value: ChannelMetadata, }; diff --git a/flow-typed/Tags.js b/flow-typed/Tags.js new file mode 100644 index 0000000..d6b4510 --- /dev/null +++ b/flow-typed/Tags.js @@ -0,0 +1,30 @@ +declare type TagState = { + followedTags: FollowedTags, + knownTags: KnownTags, + trending: Array, + fetchingTrending: boolean, +}; + +declare type Tag = { + name: string, +}; + +declare type KnownTags = { + [string]: Tag, +}; + +declare type FollowedTags = Array; + +declare type TagAction = { + type: string, + data: { + name: string, + }, +}; + +declare type TrendingTagAction = { + type: string, + data: { + uris: Array, + }, +}; diff --git a/src/constants/action_types.js b/src/constants/action_types.js index cb1cdd0..7a303f9 100644 --- a/src/constants/action_types.js +++ b/src/constants/action_types.js @@ -88,6 +88,9 @@ export const SET_CONTENT_POSITION = 'SET_CONTENT_POSITION'; export const SET_CONTENT_LAST_VIEWED = 'SET_CONTENT_LAST_VIEWED'; export const CLEAR_CONTENT_HISTORY_URI = 'CLEAR_CONTENT_HISTORY_URI'; export const CLEAR_CONTENT_HISTORY_ALL = 'CLEAR_CONTENT_HISTORY_ALL'; +export const CLAIM_SEARCH_STARTED = 'CLAIM_SEARCH_STARTED'; +export const CLAIM_SEARCH_COMPLETED = 'CLAIM_SEARCH_COMPLETED'; +export const CLAIM_SEARCH_FAILED = 'CLAIM_SEARCH_FAILED'; // Files export const FILE_LIST_STARTED = 'FILE_LIST_STARTED'; @@ -177,21 +180,6 @@ export const FETCH_REWARD_CONTENT_COMPLETED = 'FETCH_REWARD_CONTENT_COMPLETED'; export const DOWNLOAD_LANGUAGE_SUCCEEDED = 'DOWNLOAD_LANGUAGE_SUCCEEDED'; export const DOWNLOAD_LANGUAGE_FAILED = 'DOWNLOAD_LANGUAGE_FAILED'; -// ShapeShift -export const GET_SUPPORTED_COINS_START = 'GET_SUPPORTED_COINS_START'; -export const GET_SUPPORTED_COINS_SUCCESS = 'GET_SUPPORTED_COINS_SUCCESS'; -export const GET_SUPPORTED_COINS_FAIL = 'GET_SUPPORTED_COINS_FAIL'; -export const GET_COIN_STATS_START = 'GET_COIN_STATS_START'; -export const GET_COIN_STATS_SUCCESS = 'GET_COIN_STATS_SUCCESS'; -export const GET_COIN_STATS_FAIL = 'GET_COIN_STATS_FAIL'; -export const PREPARE_SHAPE_SHIFT_START = 'PREPARE_SHAPE_SHIFT_START'; -export const PREPARE_SHAPE_SHIFT_SUCCESS = 'PREPARE_SHAPE_SHIFT_SUCCESS'; -export const PREPARE_SHAPE_SHIFT_FAIL = 'PREPARE_SHAPE_SHIFT_FAIL'; -export const GET_ACTIVE_SHIFT_START = 'GET_ACTIVE_SHIFT_START'; -export const GET_ACTIVE_SHIFT_SUCCESS = 'GET_ACTIVE_SHIFT_SUCCESS'; -export const GET_ACTIVE_SHIFT_FAIL = 'GET_ACTIVE_SHIFT_FAIL'; -export const CLEAR_SHAPE_SHIFT = 'CLEAR_SHAPE_SHIFT'; - // Subscriptions export const CHANNEL_SUBSCRIBE = 'CHANNEL_SUBSCRIBE'; export const CHANNEL_UNSUBSCRIBE = 'CHANNEL_UNSUBSCRIBE'; @@ -229,3 +217,10 @@ export const FETCH_DATE = 'FETCH_DATE'; export const FETCH_COST_INFO_STARTED = 'FETCH_COST_INFO_STARTED'; export const FETCH_COST_INFO_COMPLETED = 'FETCH_COST_INFO_COMPLETED'; export const FETCH_COST_INFO_FAILED = 'FETCH_COST_INFO_FAILED'; +// Tags +export const TOGGLE_TAG_FOLLOW = 'TOGGLE_TAG_FOLLOW'; +export const TAG_ADD = 'TAG_ADD'; +export const TAG_DELETE = 'TAG_DELETE'; +export const FETCH_TRENDING_STARTED = 'FETCH_TRENDING_STARTED'; +export const FETCH_TRENDING_COMPLETED = 'FETCH_TRENDING_COMPLETED'; +export const FETCH_TRENDING_FAILED = 'FETCH_TRENDING_FAILED'; diff --git a/src/constants/tags.js b/src/constants/tags.js new file mode 100644 index 0000000..7f00bd2 --- /dev/null +++ b/src/constants/tags.js @@ -0,0 +1,21 @@ +export const defaultFollowedTags = [ + 'gaming', + 'blockchain', + 'news', + 'learning', + 'funny', + 'technology', + 'automotive', + 'economics', + 'sports', + 'food', + 'science', + 'art', + 'nature', + 'beliefs', + 'music', + 'pop culture', + 'weapons', +]; + +export const defaultRecommendedTags = []; diff --git a/src/index.js b/src/index.js index 848d0e5..6e40213 100644 --- a/src/index.js +++ b/src/index.js @@ -87,6 +87,8 @@ export { doUpdateBlockHeight, } from 'redux/actions/wallet'; +export { doToggleTagFollow, doAddTag, doDeleteTag, doFetchByTags } from 'redux/actions/tags'; + // utils export { batchActions } from 'util/batchActions'; export { parseQueryParams, toQueryString } from 'util/query_params'; @@ -101,6 +103,7 @@ export { notificationsReducer } from 'redux/reducers/notifications'; export { searchReducer } from 'redux/reducers/search'; export { walletReducer } from 'redux/reducers/wallet'; export { contentReducer } from 'redux/reducers/content'; +export { tagsReducer } from 'redux/reducers/tags'; // selectors export { makeSelectContentPositionForUri } from 'redux/selectors/content'; @@ -127,6 +130,7 @@ export { makeSelectCoverForUri, makeSelectTitleForUri, makeSelectDateForUri, + makeSelectTagsForUri, makeSelectContentTypeForUri, makeSelectIsUriResolving, makeSelectTotalItemsForChannel, @@ -177,6 +181,7 @@ export { selectSearchDownloadUris, selectFileListDownloadedSort, selectFileListPublishedSort, + selectDownloadedUris, } from 'redux/selectors/file_info'; export { selectSearchState }; @@ -221,3 +226,10 @@ export { selectWalletUnlockResult, selectTransactionListFilter, } from 'redux/selectors/wallet'; + +export { + selectFollowedTags, + selectUnfollowedTags, + selectTrendingUris, + selectFetchingTrending, +} from 'redux/selectors/tags'; diff --git a/src/redux/actions/claims.js b/src/redux/actions/claims.js index 5248309..ea3da1f 100644 --- a/src/redux/actions/claims.js +++ b/src/redux/actions/claims.js @@ -7,6 +7,7 @@ import { selectMyClaimsRaw, selectResolvingUris, selectClaimsByUri } from 'redux import { doFetchTransactions } from 'redux/actions/wallet'; import { selectSupportsByOutpoint } from 'redux/selectors/wallet'; import { creditsToString } from 'util/formatCredits'; +import { batchActions } from 'util/batchActions'; export function doResolveUris(uris: Array, returnCachedClaims: boolean = false) { return (dispatch: Dispatch, getState: GetState) => { @@ -69,7 +70,6 @@ export function doResolveUris(uris: Array, returnCachedClaims: boolean = 0; } } - // $FlowFixMe resolveInfo[uri] = result; } @@ -264,3 +264,48 @@ export function doFetchChannelListMine() { Lbry.channel_list().then(callback); }; } + +export function doClaimSearch( + amount: number = 20, + options: {} = {}, + cb: (?Error, ?Array) => void +) { + return (dispatch: Dispatch) => { + dispatch({ + type: ACTIONS.CLAIM_SEARCH_STARTED, + }); + + const success = (data: ClaimSearchResponse) => { + const resolveInfo = {}; + const uris = []; + data.items.forEach((stream: Claim) => { + resolveInfo[stream.permanent_url] = { stream }; + uris.push(stream.permanent_url); + }); + + dispatch({ + type: ACTIONS.CLAIM_SEARCH_COMPLETED, + data: { resolveInfo }, + }); + + if (cb) { + cb(null, uris); + } + }; + + const failure = err => { + dispatch({ + type: ACTIONS.CLAIM_SEARCH_FAILED, + error: err, + }); + if (cb) { + cb(err); + } + }; + + Lbry.claim_search({ + page_size: amount, + ...options, + }).then(success, failure); + }; +} diff --git a/src/redux/actions/tags.js b/src/redux/actions/tags.js new file mode 100644 index 0000000..28bb7c8 --- /dev/null +++ b/src/redux/actions/tags.js @@ -0,0 +1,51 @@ +// @flow +import * as ACTIONS from 'constants/action_types'; +import Lbry from 'lbry'; +import { doClaimSearch } from 'redux/actions/claims'; + +export const doToggleTagFollow = (name: string) => ({ + type: ACTIONS.TOGGLE_TAG_FOLLOW, + data: { + name, + }, +}); + +export const doAddTag = (name: string) => ({ + type: ACTIONS.TAG_ADD, + data: { + name, + }, +}); + +export const doDeleteTag = (name: string) => ({ + type: ACTIONS.TAG_DELETE, + data: { + name, + }, +}); + +export const doFetchByTags = (amount: number = 10, options: Object = {}) => { + return (dispatch: Dispatch) => { + dispatch({ + type: ACTIONS.FETCH_TRENDING_STARTED, + }); + + const callback = (error: ?Error, uris: ?Array = []) => { + if (error) { + return dispatch({ + type: ACTIONS.FETCH_TRENDING_FAILED, + error, + }); + } + + dispatch({ + type: ACTIONS.FETCH_TRENDING_COMPLETED, + data: { + uris, + }, + }); + }; + + dispatch(doClaimSearch(amount, options, callback)); + }; +}; diff --git a/src/redux/reducers/claims.js b/src/redux/reducers/claims.js index cd50cd6..92c5f99 100644 --- a/src/redux/reducers/claims.js +++ b/src/redux/reducers/claims.js @@ -45,7 +45,7 @@ const defaultState = { pendingById: {}, }; -reducers[ACTIONS.RESOLVE_URIS_COMPLETED] = (state: State, action: any): State => { +function handleClaimAction(state: State, action: any): State { const { resolveInfo, }: { @@ -88,6 +88,10 @@ reducers[ACTIONS.RESOLVE_URIS_COMPLETED] = (state: State, action: any): State => channelClaimCounts, resolvingUris: (state.resolvingUris || []).filter(uri => !resolveInfo[uri]), }); +} + +reducers[ACTIONS.RESOLVE_URIS_COMPLETED] = (state: State, action: any): State => { + return handleClaimAction(state, action); }; reducers[ACTIONS.FETCH_CLAIM_LIST_MINE_STARTED] = (state: State): State => @@ -265,6 +269,20 @@ reducers[ACTIONS.RESOLVE_URIS_STARTED] = (state: State, action: any): State => { }); }; +reducers[ACTIONS.CLAIM_SEARCH_STARTED] = (state: State): State => { + return Object.assign({}, state, { + fetchingClaimSearch: true, + }); +}; +reducers[ACTIONS.CLAIM_SEARCH_COMPLETED] = (state: State, action: any): State => { + return { ...handleClaimAction(state, action), fetchingClaimSearch: false }; +}; +reducers[ACTIONS.CLAIM_SEARCH_FAILED] = (state: State): State => { + return Object.assign({}, state, { + fetchingClaimSearch: false, + }); +}; + export function claimsReducer(state: State = defaultState, action: any) { const handler = reducers[action.type]; if (handler) return handler(state, action); diff --git a/src/redux/reducers/tags.js b/src/redux/reducers/tags.js new file mode 100644 index 0000000..eb11692 --- /dev/null +++ b/src/redux/reducers/tags.js @@ -0,0 +1,84 @@ +// @flow +import * as ACTIONS from 'constants/action_types'; +import { handleActions } from 'util/redux-utils'; +import { defaultRecommendedTags, defaultFollowedTags } from 'constants/tags'; + +function getDefaultRecommendedTags() { + return defaultFollowedTags.concat(defaultRecommendedTags).reduce( + (tagsMap, tag) => ({ + ...tagsMap, + [tag]: { name: tag }, + }), + {} + ); +} + +const defaultState: TagState = { + followedTags: defaultFollowedTags, + knownTags: getDefaultRecommendedTags(), + trending: [], + fetchingTrending: false, +}; + +export const tagsReducer = handleActions( + { + [ACTIONS.TOGGLE_TAG_FOLLOW]: (state: TagState, action: TagAction): TagState => { + const { followedTags } = state; + const { name } = action.data; + + let newFollowedTags = followedTags.slice(); + + if (newFollowedTags.includes(name)) { + newFollowedTags = newFollowedTags.filter(tag => tag !== name); + } else { + newFollowedTags.push(name); + } + + return { + ...state, + followedTags: newFollowedTags, + }; + }, + + [ACTIONS.TAG_ADD]: (state: TagState, action: TagAction) => { + const { knownTags } = state; + const { name } = action.data; + + let newKnownTags = { ...knownTags }; + newKnownTags[name] = { name }; + + return { + ...state, + knownTags: newKnownTags, + }; + }, + + [ACTIONS.TAG_DELETE]: (state: TagState, action: TagAction) => { + const { knownTags, followedTags } = state; + const { name } = action.data; + + let newKnownTags = { ...knownTags }; + delete newKnownTags[name]; + + return { + ...state, + knownTags: newKnownTags, + }; + }, + [ACTIONS.FETCH_TRENDING_STARTED]: (state: TagState) => ({ + ...state, + fetchingTrending: true, + }), + [ACTIONS.FETCH_TRENDING_COMPLETED]: (state: TagState, action: TrendingTagAction) => ({ + ...state, + trending: action.data.uris, + fetchingTrending: false, + }), + [ACTIONS.FETCH_TRENDING_FAILED]: (state: TagState) => ({ + ...state, + trending: [], + fetchingTrending: false, + }), + }, + defaultState +); diff --git a/src/redux/selectors/claims.js b/src/redux/selectors/claims.js index 0cf4bdf..0a0efc3 100644 --- a/src/redux/selectors/claims.js +++ b/src/redux/selectors/claims.js @@ -433,3 +433,11 @@ export const makeSelectChannelForClaimUri = (uri: string, includePrefix: boolean return includePrefix ? `lbry://${channel}` : channel; } ); + +export const makeSelectTagsForUri = (uri: string) => + createSelector( + makeSelectMetadataForUri(uri), + (metadata: ?GenericMetadata) => { + return (metadata && metadata.tags) || []; + } + ); diff --git a/src/redux/selectors/file_info.js b/src/redux/selectors/file_info.js index 4718cd8..fbfc023 100644 --- a/src/redux/selectors/file_info.js +++ b/src/redux/selectors/file_info.js @@ -228,3 +228,9 @@ export const selectFileListDownloadedSort = createSelector( selectState, state => state.fileListDownloadedSort ); + +export const selectDownloadedUris = createSelector( + selectFileInfosDownloaded, + // We should use permament_url but it doesn't exist in file_list + info => info.map(claim => `lbry://${claim.claim_name}#${claim.claim_id}`) +); diff --git a/src/redux/selectors/tags.js b/src/redux/selectors/tags.js new file mode 100644 index 0000000..20f88f9 --- /dev/null +++ b/src/redux/selectors/tags.js @@ -0,0 +1,47 @@ +// @flow +import { createSelector } from 'reselect'; + +const selectState = (state: { tags: TagState }) => state.tags || {}; + +export const selectKnownTagsByName = createSelector( + selectState, + (state: TagState): KnownTags => state.knownTags +); + +export const selectFollowedTagsList = createSelector( + selectState, + (state: TagState): Array => state.followedTags +); + +export const selectFollowedTags = createSelector( + selectFollowedTagsList, + (followedTags: Array): Array => followedTags.map(tag => ({ name: tag })) +); + +export const selectUnfollowedTags = createSelector( + selectKnownTagsByName, + selectFollowedTagsList, + (tagsByName: KnownTags, followedTags: Array): Array => { + const followedTagsSet = new Set(followedTags); + let tagsToReturn = []; + + Object.keys(tagsByName).forEach(key => { + if (!followedTagsSet.has(key)) { + const { name } = tagsByName[key]; + tagsToReturn.push({ name }); + } + }); + + return tagsToReturn; + } +); + +export const selectTrendingUris = createSelector( + selectState, + state => state.trending || [] +); + +export const selectFetchingTrending = createSelector( + selectState, + state => state.fetchingTrending +); From 478251f9005f380ae4405f063ee7dbd39556af21 Mon Sep 17 00:00:00 2001 From: Sean Yesmunt Date: Mon, 10 Jun 2019 12:58:39 -0400 Subject: [PATCH 13/21] sort followed tags alphabetically --- dist/bundle.es.js | 2 +- src/redux/selectors/tags.js | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/dist/bundle.es.js b/dist/bundle.es.js index 129ae72..903f824 100644 --- a/dist/bundle.es.js +++ b/dist/bundle.es.js @@ -3878,7 +3878,7 @@ const selectKnownTagsByName = reselect.createSelector(selectState$7, state => st const selectFollowedTagsList = reselect.createSelector(selectState$7, state => state.followedTags); -const selectFollowedTags = reselect.createSelector(selectFollowedTagsList, followedTags => followedTags.map(tag => ({ name: tag }))); +const selectFollowedTags = reselect.createSelector(selectFollowedTagsList, followedTags => followedTags.map(tag => ({ name: tag })).sort((a, b) => a.name.localeCompare(b.name))); const selectUnfollowedTags = reselect.createSelector(selectKnownTagsByName, selectFollowedTagsList, (tagsByName, followedTags) => { const followedTagsSet = new Set(followedTags); diff --git a/src/redux/selectors/tags.js b/src/redux/selectors/tags.js index 20f88f9..c6b9889 100644 --- a/src/redux/selectors/tags.js +++ b/src/redux/selectors/tags.js @@ -15,7 +15,8 @@ export const selectFollowedTagsList = createSelector( export const selectFollowedTags = createSelector( selectFollowedTagsList, - (followedTags: Array): Array => followedTags.map(tag => ({ name: tag })) + (followedTags: Array): Array => + followedTags.map(tag => ({ name: tag })).sort((a, b) => a.name.localeCompare(b.name)) ); export const selectUnfollowedTags = createSelector( From 12f4c032b8c6d8d08da87a7e64412855e7b5ae40 Mon Sep 17 00:00:00 2001 From: Sean Yesmunt Date: Mon, 10 Jun 2019 14:38:53 -0400 Subject: [PATCH 14/21] unfollow tag on delete --- dist/bundle.es.js | 4 +++- src/redux/reducers/tags.js | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/dist/bundle.es.js b/dist/bundle.es.js index 903f824..64ae791 100644 --- a/dist/bundle.es.js +++ b/dist/bundle.es.js @@ -3815,9 +3815,11 @@ const tagsReducer = handleActions({ let newKnownTags = _extends$b({}, knownTags); delete newKnownTags[name]; + const newFollowedTags = followedTags.filter(tag => tag !== name); return _extends$b({}, state, { - knownTags: newKnownTags + knownTags: newKnownTags, + followedTags: newFollowedTags }); }, [FETCH_TRENDING_STARTED]: state => _extends$b({}, state, { diff --git a/src/redux/reducers/tags.js b/src/redux/reducers/tags.js index eb11692..38c3d09 100644 --- a/src/redux/reducers/tags.js +++ b/src/redux/reducers/tags.js @@ -59,10 +59,12 @@ export const tagsReducer = handleActions( let newKnownTags = { ...knownTags }; delete newKnownTags[name]; + const newFollowedTags = followedTags.filter(tag => tag !== name); return { ...state, knownTags: newKnownTags, + followedTags: newFollowedTags, }; }, [ACTIONS.FETCH_TRENDING_STARTED]: (state: TagState) => ({ From e8466bbeeca1778476e6c9b262ffa98882b45bb2 Mon Sep 17 00:00:00 2001 From: Sean Yesmunt Date: Tue, 11 Jun 2019 14:11:18 -0400 Subject: [PATCH 15/21] remove trending in favor of lastClaimSearchUris --- dist/bundle.es.js | 87 ++++++++--------------------------- dist/flow-typed/Claim.js | 2 +- dist/flow-typed/Tags.js | 9 ---- flow-typed/Claim.js | 2 +- flow-typed/Tags.js | 9 ---- src/constants/action_types.js | 3 -- src/index.js | 12 ++--- src/redux/actions/claims.js | 15 +----- src/redux/actions/tags.js | 27 ----------- src/redux/reducers/claims.js | 12 ++++- src/redux/reducers/tags.js | 16 ------- src/redux/selectors/claims.js | 10 ++++ src/redux/selectors/tags.js | 10 ---- 13 files changed, 49 insertions(+), 165 deletions(-) diff --git a/dist/bundle.es.js b/dist/bundle.es.js index 64ae791..2dd0112 100644 --- a/dist/bundle.es.js +++ b/dist/bundle.es.js @@ -231,9 +231,6 @@ const FETCH_COST_INFO_FAILED = 'FETCH_COST_INFO_FAILED'; const TOGGLE_TAG_FOLLOW = 'TOGGLE_TAG_FOLLOW'; const TAG_ADD = 'TAG_ADD'; const TAG_DELETE = 'TAG_DELETE'; -const FETCH_TRENDING_STARTED = 'FETCH_TRENDING_STARTED'; -const FETCH_TRENDING_COMPLETED = 'FETCH_TRENDING_COMPLETED'; -const FETCH_TRENDING_FAILED = 'FETCH_TRENDING_FAILED'; var action_types = /*#__PURE__*/Object.freeze({ WINDOW_FOCUSED: WINDOW_FOCUSED, @@ -428,10 +425,7 @@ var action_types = /*#__PURE__*/Object.freeze({ FETCH_COST_INFO_FAILED: FETCH_COST_INFO_FAILED, TOGGLE_TAG_FOLLOW: TOGGLE_TAG_FOLLOW, TAG_ADD: TAG_ADD, - TAG_DELETE: TAG_DELETE, - FETCH_TRENDING_STARTED: FETCH_TRENDING_STARTED, - FETCH_TRENDING_COMPLETED: FETCH_TRENDING_COMPLETED, - FETCH_TRENDING_FAILED: FETCH_TRENDING_FAILED + TAG_DELETE: TAG_DELETE }); const API_DOWN = 'apiDown'; @@ -1423,6 +1417,10 @@ const makeSelectTagsForUri = uri => reselect.createSelector(makeSelectMetadataFo return metadata && metadata.tags || []; }); +const selectFetchingClaimSearch = reselect.createSelector(selectState$1, state => state.fetchingClaimSearch); + +const selectLastClaimSearchUris = reselect.createSelector(selectState$1, state => state.lastClaimSearchUris); + const selectState$2 = state => state.wallet || {}; const selectWalletState = selectState$2; @@ -2191,7 +2189,7 @@ function doFetchChannelListMine() { }; } -function doClaimSearch(amount = 20, options = {}, cb) { +function doClaimSearch(amount = 20, options = {}) { return dispatch => { dispatch({ type: CLAIM_SEARCH_STARTED @@ -2207,12 +2205,8 @@ function doClaimSearch(amount = 20, options = {}, cb) { dispatch({ type: CLAIM_SEARCH_COMPLETED, - data: { resolveInfo } + data: { resolveInfo, uris } }); - - if (cb) { - cb(null, uris); - } }; const failure = err => { @@ -2220,9 +2214,6 @@ function doClaimSearch(amount = 20, options = {}, cb) { type: CLAIM_SEARCH_FAILED, error: err }); - if (cb) { - cb(err); - } }; lbryProxy.claim_search(_extends$3({ @@ -2776,32 +2767,6 @@ const doDeleteTag = name => ({ } }); -const doFetchByTags = (amount = 10, options = {}) => { - return dispatch => { - dispatch({ - type: FETCH_TRENDING_STARTED - }); - - const callback = (error, uris = []) => { - if (error) { - return dispatch({ - type: FETCH_TRENDING_FAILED, - error - }); - } - - dispatch({ - type: FETCH_TRENDING_COMPLETED, - data: { - uris - } - }); - }; - - dispatch(doClaimSearch(amount, options, callback)); - }; -}; - var _extends$4 = 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; }; const reducers = {}; @@ -2817,7 +2782,9 @@ const defaultState = { myChannelClaims: new Set(), fetchingMyChannels: false, abandoningById: {}, - pendingById: {} + pendingById: {}, + fetchingClaimSearch: false, + lastClaimSearchUris: [] }; function handleClaimAction(state, action) { @@ -2860,7 +2827,7 @@ function handleClaimAction(state, action) { } reducers[RESOLVE_URIS_COMPLETED] = (state, action) => { - return handleClaimAction(state, action); + return _extends$4({}, handleClaimAction(state, action)); }; reducers[FETCH_CLAIM_LIST_MINE_STARTED] = state => Object.assign({}, state, { @@ -3041,7 +3008,10 @@ reducers[CLAIM_SEARCH_STARTED] = state => { }); }; reducers[CLAIM_SEARCH_COMPLETED] = (state, action) => { - return _extends$4({}, handleClaimAction(state, action), { fetchingClaimSearch: false }); + return _extends$4({}, handleClaimAction(state, action), { + fetchingClaimSearch: false, + lastClaimSearchUris: action.data.uris + }); }; reducers[CLAIM_SEARCH_FAILED] = state => { return Object.assign({}, state, { @@ -3774,9 +3744,7 @@ function getDefaultRecommendedTags() { const defaultState$7 = { followedTags: defaultFollowedTags, - knownTags: getDefaultRecommendedTags(), - trending: [], - fetchingTrending: false + knownTags: getDefaultRecommendedTags() }; const tagsReducer = handleActions({ @@ -3821,18 +3789,7 @@ const tagsReducer = handleActions({ knownTags: newKnownTags, followedTags: newFollowedTags }); - }, - [FETCH_TRENDING_STARTED]: state => _extends$b({}, state, { - fetchingTrending: true - }), - [FETCH_TRENDING_COMPLETED]: (state, action) => _extends$b({}, state, { - trending: action.data.uris, - fetchingTrending: false - }), - [FETCH_TRENDING_FAILED]: state => _extends$b({}, state, { - trending: [], - fetchingTrending: false - }) + } }, defaultState$7); const selectState$5 = state => state.content || {}; @@ -3896,10 +3853,6 @@ const selectUnfollowedTags = reselect.createSelector(selectKnownTagsByName, sele return tagsToReturn; }); -const selectTrendingUris = reselect.createSelector(selectState$7, state => state.trending || []); - -const selectFetchingTrending = reselect.createSelector(selectState$7, state => state.fetchingTrending); - exports.ACTIONS = action_types; exports.Lbry = lbryProxy; exports.PAGES = pages; @@ -3920,13 +3873,13 @@ exports.doAddTag = doAddTag; exports.doBalanceSubscribe = doBalanceSubscribe; exports.doBlurSearchInput = doBlurSearchInput; exports.doCheckAddressIsMine = doCheckAddressIsMine; +exports.doClaimSearch = doClaimSearch; exports.doCreateChannel = doCreateChannel; exports.doDeletePurchasedUri = doDeletePurchasedUri; exports.doDeleteTag = doDeleteTag; exports.doDismissError = doDismissError; exports.doDismissToast = doDismissToast; exports.doError = doError; -exports.doFetchByTags = doFetchByTags; exports.doFetchChannelListMine = doFetchChannelListMine; exports.doFetchClaimListMine = doFetchClaimListMine; exports.doFetchClaimsByChannel = doFetchClaimsByChannel; @@ -4025,8 +3978,8 @@ exports.selectDraftTransactionAmount = selectDraftTransactionAmount; exports.selectDraftTransactionError = selectDraftTransactionError; exports.selectError = selectError; exports.selectFailedPurchaseUris = selectFailedPurchaseUris; +exports.selectFetchingClaimSearch = selectFetchingClaimSearch; exports.selectFetchingMyChannels = selectFetchingMyChannels; -exports.selectFetchingTrending = selectFetchingTrending; exports.selectFileInfosByOutpoint = selectFileInfosByOutpoint; exports.selectFileInfosDownloaded = selectFileInfosDownloaded; exports.selectFileListDownloadedSort = selectFileListDownloadedSort; @@ -4040,6 +3993,7 @@ exports.selectIsFetchingFileListDownloadedOrPublished = selectIsFetchingFileList exports.selectIsFetchingTransactions = selectIsFetchingTransactions; exports.selectIsSearching = selectIsSearching; exports.selectIsSendingSupport = selectIsSendingSupport; +exports.selectLastClaimSearchUris = selectLastClaimSearchUris; exports.selectLastPurchasedUri = selectLastPurchasedUri; exports.selectMyActiveClaims = selectMyActiveClaims; exports.selectMyChannelClaims = selectMyChannelClaims; @@ -4070,7 +4024,6 @@ exports.selectTotalDownloadProgress = selectTotalDownloadProgress; exports.selectTransactionItems = selectTransactionItems; exports.selectTransactionListFilter = selectTransactionListFilter; exports.selectTransactionsById = selectTransactionsById; -exports.selectTrendingUris = selectTrendingUris; exports.selectUnfollowedTags = selectUnfollowedTags; exports.selectUrisLoading = selectUrisLoading; exports.selectWalletDecryptPending = selectWalletDecryptPending; diff --git a/dist/flow-typed/Claim.js b/dist/flow-typed/Claim.js index f18b128..20b8ff0 100644 --- a/dist/flow-typed/Claim.js +++ b/dist/flow-typed/Claim.js @@ -10,7 +10,6 @@ declare type ChannelClaim = GenericClaim & { declare type StreamClaim = GenericClaim & { is_channel_signature_valid?: boolean, - signing_channel?: ChannelClaim, value: StreamMetadata, }; @@ -33,6 +32,7 @@ declare type GenericClaim = { txid: string, // unique tx id type: 'claim' | 'update' | 'support', value_type: 'stream' | 'channel', + signing_channel?: ChannelClaim, meta: { activation_height: number, claims_in_channel?: number, diff --git a/dist/flow-typed/Tags.js b/dist/flow-typed/Tags.js index d6b4510..01c58ac 100644 --- a/dist/flow-typed/Tags.js +++ b/dist/flow-typed/Tags.js @@ -1,8 +1,6 @@ declare type TagState = { followedTags: FollowedTags, knownTags: KnownTags, - trending: Array, - fetchingTrending: boolean, }; declare type Tag = { @@ -21,10 +19,3 @@ declare type TagAction = { name: string, }, }; - -declare type TrendingTagAction = { - type: string, - data: { - uris: Array, - }, -}; diff --git a/flow-typed/Claim.js b/flow-typed/Claim.js index d5ca709..1c61c10 100644 --- a/flow-typed/Claim.js +++ b/flow-typed/Claim.js @@ -9,7 +9,6 @@ declare type ChannelClaim = GenericClaim & { declare type StreamClaim = GenericClaim & { is_channel_signature_valid?: boolean, - signing_channel?: ChannelClaim, value: StreamMetadata, }; @@ -32,6 +31,7 @@ declare type GenericClaim = { txid: string, // unique tx id type: 'claim' | 'update' | 'support', value_type: 'stream' | 'channel', + signing_channel?: ChannelClaim, meta: { activation_height: number, claims_in_channel?: number, diff --git a/flow-typed/Tags.js b/flow-typed/Tags.js index d6b4510..01c58ac 100644 --- a/flow-typed/Tags.js +++ b/flow-typed/Tags.js @@ -1,8 +1,6 @@ declare type TagState = { followedTags: FollowedTags, knownTags: KnownTags, - trending: Array, - fetchingTrending: boolean, }; declare type Tag = { @@ -21,10 +19,3 @@ declare type TagAction = { name: string, }, }; - -declare type TrendingTagAction = { - type: string, - data: { - uris: Array, - }, -}; diff --git a/src/constants/action_types.js b/src/constants/action_types.js index 7a303f9..80acf3f 100644 --- a/src/constants/action_types.js +++ b/src/constants/action_types.js @@ -221,6 +221,3 @@ export const FETCH_COST_INFO_FAILED = 'FETCH_COST_INFO_FAILED'; export const TOGGLE_TAG_FOLLOW = 'TOGGLE_TAG_FOLLOW'; export const TAG_ADD = 'TAG_ADD'; export const TAG_DELETE = 'TAG_DELETE'; -export const FETCH_TRENDING_STARTED = 'FETCH_TRENDING_STARTED'; -export const FETCH_TRENDING_COMPLETED = 'FETCH_TRENDING_COMPLETED'; -export const FETCH_TRENDING_FAILED = 'FETCH_TRENDING_FAILED'; diff --git a/src/index.js b/src/index.js index 6e40213..6ed5cd7 100644 --- a/src/index.js +++ b/src/index.js @@ -45,6 +45,7 @@ export { doResolveUri, doFetchChannelListMine, doCreateChannel, + doClaimSearch, } from 'redux/actions/claims'; export { doDeletePurchasedUri, doPurchaseUri, doFileGet } from 'redux/actions/file'; @@ -87,7 +88,7 @@ export { doUpdateBlockHeight, } from 'redux/actions/wallet'; -export { doToggleTagFollow, doAddTag, doDeleteTag, doFetchByTags } from 'redux/actions/tags'; +export { doToggleTagFollow, doAddTag, doDeleteTag } from 'redux/actions/tags'; // utils export { batchActions } from 'util/batchActions'; @@ -164,6 +165,8 @@ export { selectPlayingUri, selectChannelClaimCounts, selectCurrentChannelPage, + selectFetchingClaimSearch, + selectLastClaimSearchUris, } from 'redux/selectors/claims'; export { @@ -227,9 +230,4 @@ export { selectTransactionListFilter, } from 'redux/selectors/wallet'; -export { - selectFollowedTags, - selectUnfollowedTags, - selectTrendingUris, - selectFetchingTrending, -} from 'redux/selectors/tags'; +export { selectFollowedTags, selectUnfollowedTags } from 'redux/selectors/tags'; diff --git a/src/redux/actions/claims.js b/src/redux/actions/claims.js index ea3da1f..4ad3728 100644 --- a/src/redux/actions/claims.js +++ b/src/redux/actions/claims.js @@ -265,11 +265,7 @@ export function doFetchChannelListMine() { }; } -export function doClaimSearch( - amount: number = 20, - options: {} = {}, - cb: (?Error, ?Array) => void -) { +export function doClaimSearch(amount: number = 20, options: {} = {}) { return (dispatch: Dispatch) => { dispatch({ type: ACTIONS.CLAIM_SEARCH_STARTED, @@ -285,12 +281,8 @@ export function doClaimSearch( dispatch({ type: ACTIONS.CLAIM_SEARCH_COMPLETED, - data: { resolveInfo }, + data: { resolveInfo, uris }, }); - - if (cb) { - cb(null, uris); - } }; const failure = err => { @@ -298,9 +290,6 @@ export function doClaimSearch( type: ACTIONS.CLAIM_SEARCH_FAILED, error: err, }); - if (cb) { - cb(err); - } }; Lbry.claim_search({ diff --git a/src/redux/actions/tags.js b/src/redux/actions/tags.js index 28bb7c8..cd7568b 100644 --- a/src/redux/actions/tags.js +++ b/src/redux/actions/tags.js @@ -1,7 +1,6 @@ // @flow import * as ACTIONS from 'constants/action_types'; import Lbry from 'lbry'; -import { doClaimSearch } from 'redux/actions/claims'; export const doToggleTagFollow = (name: string) => ({ type: ACTIONS.TOGGLE_TAG_FOLLOW, @@ -23,29 +22,3 @@ export const doDeleteTag = (name: string) => ({ name, }, }); - -export const doFetchByTags = (amount: number = 10, options: Object = {}) => { - return (dispatch: Dispatch) => { - dispatch({ - type: ACTIONS.FETCH_TRENDING_STARTED, - }); - - const callback = (error: ?Error, uris: ?Array = []) => { - if (error) { - return dispatch({ - type: ACTIONS.FETCH_TRENDING_FAILED, - error, - }); - } - - dispatch({ - type: ACTIONS.FETCH_TRENDING_COMPLETED, - data: { - uris, - }, - }); - }; - - dispatch(doClaimSearch(amount, options, callback)); - }; -}; diff --git a/src/redux/reducers/claims.js b/src/redux/reducers/claims.js index 92c5f99..fd57b99 100644 --- a/src/redux/reducers/claims.js +++ b/src/redux/reducers/claims.js @@ -43,6 +43,8 @@ const defaultState = { fetchingMyChannels: false, abandoningById: {}, pendingById: {}, + fetchingClaimSearch: false, + lastClaimSearchUris: [], }; function handleClaimAction(state: State, action: any): State { @@ -91,7 +93,9 @@ function handleClaimAction(state: State, action: any): State { } reducers[ACTIONS.RESOLVE_URIS_COMPLETED] = (state: State, action: any): State => { - return handleClaimAction(state, action); + return { + ...handleClaimAction(state, action), + }; }; reducers[ACTIONS.FETCH_CLAIM_LIST_MINE_STARTED] = (state: State): State => @@ -275,7 +279,11 @@ reducers[ACTIONS.CLAIM_SEARCH_STARTED] = (state: State): State => { }); }; reducers[ACTIONS.CLAIM_SEARCH_COMPLETED] = (state: State, action: any): State => { - return { ...handleClaimAction(state, action), fetchingClaimSearch: false }; + return { + ...handleClaimAction(state, action), + fetchingClaimSearch: false, + lastClaimSearchUris: action.data.uris, + }; }; reducers[ACTIONS.CLAIM_SEARCH_FAILED] = (state: State): State => { return Object.assign({}, state, { diff --git a/src/redux/reducers/tags.js b/src/redux/reducers/tags.js index 38c3d09..fb01577 100644 --- a/src/redux/reducers/tags.js +++ b/src/redux/reducers/tags.js @@ -16,8 +16,6 @@ function getDefaultRecommendedTags() { const defaultState: TagState = { followedTags: defaultFollowedTags, knownTags: getDefaultRecommendedTags(), - trending: [], - fetchingTrending: false, }; export const tagsReducer = handleActions( @@ -67,20 +65,6 @@ export const tagsReducer = handleActions( followedTags: newFollowedTags, }; }, - [ACTIONS.FETCH_TRENDING_STARTED]: (state: TagState) => ({ - ...state, - fetchingTrending: true, - }), - [ACTIONS.FETCH_TRENDING_COMPLETED]: (state: TagState, action: TrendingTagAction) => ({ - ...state, - trending: action.data.uris, - fetchingTrending: false, - }), - [ACTIONS.FETCH_TRENDING_FAILED]: (state: TagState) => ({ - ...state, - trending: [], - fetchingTrending: false, - }), }, defaultState ); diff --git a/src/redux/selectors/claims.js b/src/redux/selectors/claims.js index 0a0efc3..d699d0d 100644 --- a/src/redux/selectors/claims.js +++ b/src/redux/selectors/claims.js @@ -441,3 +441,13 @@ export const makeSelectTagsForUri = (uri: string) => return (metadata && metadata.tags) || []; } ); + +export const selectFetchingClaimSearch = createSelector( + selectState, + state => state.fetchingClaimSearch +); + +export const selectLastClaimSearchUris = createSelector( + selectState, + state => state.lastClaimSearchUris +); diff --git a/src/redux/selectors/tags.js b/src/redux/selectors/tags.js index c6b9889..e3bbe4c 100644 --- a/src/redux/selectors/tags.js +++ b/src/redux/selectors/tags.js @@ -36,13 +36,3 @@ export const selectUnfollowedTags = createSelector( return tagsToReturn; } ); - -export const selectTrendingUris = createSelector( - selectState, - state => state.trending || [] -); - -export const selectFetchingTrending = createSelector( - selectState, - state => state.fetchingTrending -); From 82a5f242d09685b9f3b7e4022e9b42833d3d3dfb Mon Sep 17 00:00:00 2001 From: Sean Yesmunt Date: Tue, 11 Jun 2019 14:36:01 -0400 Subject: [PATCH 16/21] add my publishes uri selector --- dist/bundle.es.js | 3 +++ src/index.js | 1 + src/redux/selectors/claims.js | 5 +++++ 3 files changed, 9 insertions(+) diff --git a/dist/bundle.es.js b/dist/bundle.es.js index 2dd0112..4b0de17 100644 --- a/dist/bundle.es.js +++ b/dist/bundle.es.js @@ -1302,6 +1302,8 @@ const selectMyClaims = reselect.createSelector(selectMyActiveClaims, selectClaim const selectMyClaimsWithoutChannels = reselect.createSelector(selectMyClaims, myClaims => myClaims.filter(claim => !claim.name.match(/^@/))); +const selectMyClaimUrisWithoutChannels = reselect.createSelector(selectMyClaimsWithoutChannels, myClaims => myClaims.map(claim => `lbry://${claim.name}#${claim.claim_id}`)); + const selectAllMyClaimsByOutpoint = reselect.createSelector(selectMyClaimsRaw, claims => new Set(claims && claims.length ? claims.map(claim => `${claim.txid}:${claim.nout}`) : null)); const selectMyClaimsOutpoints = reselect.createSelector(selectMyClaims, myClaims => { @@ -3997,6 +3999,7 @@ exports.selectLastClaimSearchUris = selectLastClaimSearchUris; exports.selectLastPurchasedUri = selectLastPurchasedUri; exports.selectMyActiveClaims = selectMyActiveClaims; exports.selectMyChannelClaims = selectMyChannelClaims; +exports.selectMyClaimUrisWithoutChannels = selectMyClaimUrisWithoutChannels; exports.selectMyClaims = selectMyClaims; exports.selectMyClaimsOutpoints = selectMyClaimsOutpoints; exports.selectMyClaimsRaw = selectMyClaimsRaw; diff --git a/src/index.js b/src/index.js index 6ed5cd7..e3d84b0 100644 --- a/src/index.js +++ b/src/index.js @@ -157,6 +157,7 @@ export { selectPendingClaims, selectMyClaims, selectMyClaimsWithoutChannels, + selectMyClaimUrisWithoutChannels, selectAllMyClaimsByOutpoint, selectMyClaimsOutpoints, selectFetchingMyChannels, diff --git a/src/redux/selectors/claims.js b/src/redux/selectors/claims.js index d699d0d..8fcfff6 100644 --- a/src/redux/selectors/claims.js +++ b/src/redux/selectors/claims.js @@ -259,6 +259,11 @@ export const selectMyClaimsWithoutChannels = createSelector( myClaims => myClaims.filter(claim => !claim.name.match(/^@/)) ); +export const selectMyClaimUrisWithoutChannels = createSelector( + selectMyClaimsWithoutChannels, + myClaims => myClaims.map(claim => `lbry://${claim.name}#${claim.claim_id}`) +); + export const selectAllMyClaimsByOutpoint = createSelector( selectMyClaimsRaw, claims => From ae2f720d1da430c6b931a02ee821799270dff5d7 Mon Sep 17 00:00:00 2001 From: Sean Yesmunt Date: Thu, 13 Jun 2019 12:10:27 -0400 Subject: [PATCH 17/21] allow apps to set their own default followed tags --- dist/bundle.es.js | 21 +------ src/constants/tags.js | 21 ------- src/index.js | 2 +- src/redux/reducers/tags.js | 115 ++++++++++++++++--------------------- 4 files changed, 54 insertions(+), 105 deletions(-) delete mode 100644 src/constants/tags.js diff --git a/dist/bundle.es.js b/dist/bundle.es.js index 4b0de17..bc5368f 100644 --- a/dist/bundle.es.js +++ b/dist/bundle.es.js @@ -3732,24 +3732,9 @@ function contentReducer(state = defaultState$6, action) { return state; } -const defaultFollowedTags = ['gaming', 'blockchain', 'news', 'learning', 'funny', 'technology', 'automotive', 'economics', 'sports', 'food', 'science', 'art', 'nature', 'beliefs', 'music', 'pop culture', 'weapons']; - -const defaultRecommendedTags = []; - 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 getDefaultRecommendedTags() { - return defaultFollowedTags.concat(defaultRecommendedTags).reduce((tagsMap, tag) => _extends$b({}, tagsMap, { - [tag]: { name: tag } - }), {}); -} - -const defaultState$7 = { - followedTags: defaultFollowedTags, - knownTags: getDefaultRecommendedTags() -}; - -const tagsReducer = handleActions({ +const tagsReducerBuilder = defaultState => handleActions({ [TOGGLE_TAG_FOLLOW]: (state, action) => { const { followedTags } = state; const { name } = action.data; @@ -3792,7 +3777,7 @@ const tagsReducer = handleActions({ followedTags: newFollowedTags }); } -}, defaultState$7); +}, defaultState); const selectState$5 = state => state.content || {}; @@ -4041,6 +4026,6 @@ exports.selectWalletUnlockPending = selectWalletUnlockPending; exports.selectWalletUnlockResult = selectWalletUnlockResult; exports.selectWalletUnlockSucceeded = selectWalletUnlockSucceeded; exports.setSearchApi = setSearchApi; -exports.tagsReducer = tagsReducer; +exports.tagsReducerBuilder = tagsReducerBuilder; exports.toQueryString = toQueryString; exports.walletReducer = walletReducer; diff --git a/src/constants/tags.js b/src/constants/tags.js deleted file mode 100644 index 7f00bd2..0000000 --- a/src/constants/tags.js +++ /dev/null @@ -1,21 +0,0 @@ -export const defaultFollowedTags = [ - 'gaming', - 'blockchain', - 'news', - 'learning', - 'funny', - 'technology', - 'automotive', - 'economics', - 'sports', - 'food', - 'science', - 'art', - 'nature', - 'beliefs', - 'music', - 'pop culture', - 'weapons', -]; - -export const defaultRecommendedTags = []; diff --git a/src/index.js b/src/index.js index e3d84b0..4ae019e 100644 --- a/src/index.js +++ b/src/index.js @@ -104,7 +104,7 @@ export { notificationsReducer } from 'redux/reducers/notifications'; export { searchReducer } from 'redux/reducers/search'; export { walletReducer } from 'redux/reducers/wallet'; export { contentReducer } from 'redux/reducers/content'; -export { tagsReducer } from 'redux/reducers/tags'; +export { tagsReducerBuilder } from 'redux/reducers/tags'; // selectors export { makeSelectContentPositionForUri } from 'redux/selectors/content'; diff --git a/src/redux/reducers/tags.js b/src/redux/reducers/tags.js index fb01577..aca5976 100644 --- a/src/redux/reducers/tags.js +++ b/src/redux/reducers/tags.js @@ -1,70 +1,55 @@ // @flow import * as ACTIONS from 'constants/action_types'; import { handleActions } from 'util/redux-utils'; -import { defaultRecommendedTags, defaultFollowedTags } from 'constants/tags'; -function getDefaultRecommendedTags() { - return defaultFollowedTags.concat(defaultRecommendedTags).reduce( - (tagsMap, tag) => ({ - ...tagsMap, - [tag]: { name: tag }, - }), - {} +export const tagsReducerBuilder = (defaultState: TagState) => + handleActions( + { + [ACTIONS.TOGGLE_TAG_FOLLOW]: (state: TagState, action: TagAction): TagState => { + const { followedTags } = state; + const { name } = action.data; + + let newFollowedTags = followedTags.slice(); + + if (newFollowedTags.includes(name)) { + newFollowedTags = newFollowedTags.filter(tag => tag !== name); + } else { + newFollowedTags.push(name); + } + + return { + ...state, + followedTags: newFollowedTags, + }; + }, + + [ACTIONS.TAG_ADD]: (state: TagState, action: TagAction) => { + const { knownTags } = state; + const { name } = action.data; + + let newKnownTags = { ...knownTags }; + newKnownTags[name] = { name }; + + return { + ...state, + knownTags: newKnownTags, + }; + }, + + [ACTIONS.TAG_DELETE]: (state: TagState, action: TagAction) => { + const { knownTags, followedTags } = state; + const { name } = action.data; + + let newKnownTags = { ...knownTags }; + delete newKnownTags[name]; + const newFollowedTags = followedTags.filter(tag => tag !== name); + + return { + ...state, + knownTags: newKnownTags, + followedTags: newFollowedTags, + }; + }, + }, + defaultState ); -} - -const defaultState: TagState = { - followedTags: defaultFollowedTags, - knownTags: getDefaultRecommendedTags(), -}; - -export const tagsReducer = handleActions( - { - [ACTIONS.TOGGLE_TAG_FOLLOW]: (state: TagState, action: TagAction): TagState => { - const { followedTags } = state; - const { name } = action.data; - - let newFollowedTags = followedTags.slice(); - - if (newFollowedTags.includes(name)) { - newFollowedTags = newFollowedTags.filter(tag => tag !== name); - } else { - newFollowedTags.push(name); - } - - return { - ...state, - followedTags: newFollowedTags, - }; - }, - - [ACTIONS.TAG_ADD]: (state: TagState, action: TagAction) => { - const { knownTags } = state; - const { name } = action.data; - - let newKnownTags = { ...knownTags }; - newKnownTags[name] = { name }; - - return { - ...state, - knownTags: newKnownTags, - }; - }, - - [ACTIONS.TAG_DELETE]: (state: TagState, action: TagAction) => { - const { knownTags, followedTags } = state; - const { name } = action.data; - - let newKnownTags = { ...knownTags }; - delete newKnownTags[name]; - const newFollowedTags = followedTags.filter(tag => tag !== name); - - return { - ...state, - knownTags: newKnownTags, - followedTags: newFollowedTags, - }; - }, - }, - defaultState -); From cfbf86e95d5e9183588015281f2eccc29003e24b Mon Sep 17 00:00:00 2001 From: Lex Berezhny Date: Mon, 24 Jun 2019 15:42:53 -0400 Subject: [PATCH 18/21] claim_search --valid_channel_signatures was renamed to --valid_channel_signature --- src/redux/actions/claims.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/redux/actions/claims.js b/src/redux/actions/claims.js index 4ad3728..518f02e 100644 --- a/src/redux/actions/claims.js +++ b/src/redux/actions/claims.js @@ -200,7 +200,7 @@ export function doFetchClaimsByChannel(uri: string, page: number = 1) { Lbry.claim_search({ channel: uri, - valid_channel_signatures: true, + valid_channel_signature: true, page: page || 1, order_by: ['release_time'], }).then((result: ClaimSearchResponse) => { From 9b6912e51f478382d2193ee0d55869c68ed9f23c Mon Sep 17 00:00:00 2001 From: Sean Yesmunt Date: Tue, 25 Jun 2019 02:37:31 -0400 Subject: [PATCH 19/21] run build --- dist/bundle.es.js | 10 +--------- dist/flow-typed/Claim.js | 3 +-- 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/dist/bundle.es.js b/dist/bundle.es.js index bc5368f..71bf2e5 100644 --- a/dist/bundle.es.js +++ b/dist/bundle.es.js @@ -2000,11 +2000,7 @@ function doResolveUris(uris, returnCachedClaims = false) { result.stream = uriResolveInfo; if (uriResolveInfo.signing_channel) { result.channel = uriResolveInfo.signing_channel; -<<<<<<< HEAD result.claimsInChannel = uriResolveInfo.signing_channel.meta && uriResolveInfo.signing_channel.meta.claims_in_channel || 0; -======= - result.claimsInChannel = uriResolveInfo.meta && uriResolveInfo.meta.claims_in_channel || 0; ->>>>>>> add tags } } // $FlowFixMe @@ -2125,11 +2121,7 @@ function doFetchClaimsByChannel(uri, page = 1) { lbryProxy.claim_search({ channel: uri, -<<<<<<< HEAD - valid_channel_signatures: true, -======= - is_controlling: true, ->>>>>>> add tags + valid_channel_signature: true, page: page || 1, order_by: ['release_time'] }).then(result => { diff --git a/dist/flow-typed/Claim.js b/dist/flow-typed/Claim.js index 20b8ff0..1c61c10 100644 --- a/dist/flow-typed/Claim.js +++ b/dist/flow-typed/Claim.js @@ -3,8 +3,7 @@ declare type Claim = StreamClaim | ChannelClaim; declare type ChannelClaim = GenericClaim & { - is_channel_signature_valid?: boolean, // we may have signed channels in the future, fixes some flow issues for now. - signing_channel?: ChannelClaim, + is_channel_signature_valid?: boolean, // we may have signed channels in the future value: ChannelMetadata, }; From 862ea676804708c46bf4ad59806c6ca8e5157c71 Mon Sep 17 00:00:00 2001 From: Jessop Breth Date: Tue, 11 Jun 2019 21:14:37 -0400 Subject: [PATCH 20/21] changes for comments --- dist/bundle.es.js | 184 +++++++++++++++++++++++++++++++- dist/flow-typed/Comment.js | 18 ++++ dist/flow-typed/Lbry.js | 6 ++ flow-typed/Comment.js | 18 ++++ flow-typed/Lbry.js | 6 ++ src/constants/action_types.js | 8 ++ src/index.js | 5 + src/lbry.js | 3 + src/redux/actions/comments.js | 82 ++++++++++++++ src/redux/reducers/comments.js | 66 ++++++++++++ src/redux/selectors/comments.js | 36 +++++++ 11 files changed, 429 insertions(+), 3 deletions(-) create mode 100644 dist/flow-typed/Comment.js create mode 100644 flow-typed/Comment.js create mode 100644 src/redux/actions/comments.js create mode 100644 src/redux/reducers/comments.js create mode 100644 src/redux/selectors/comments.js diff --git a/dist/bundle.es.js b/dist/bundle.es.js index 71bf2e5..e4cc141 100644 --- a/dist/bundle.es.js +++ b/dist/bundle.es.js @@ -102,6 +102,14 @@ const CLAIM_SEARCH_STARTED = 'CLAIM_SEARCH_STARTED'; const CLAIM_SEARCH_COMPLETED = 'CLAIM_SEARCH_COMPLETED'; const CLAIM_SEARCH_FAILED = 'CLAIM_SEARCH_FAILED'; +// Comments +const COMMENT_LIST_STARTED = 'COMMENT_LIST_STARTED'; +const COMMENT_LIST_COMPLETED = 'COMMENT_LIST_COMPLETED'; +const COMMENT_LIST_UPDATED = 'COMMENT_LIST_UPDATED'; +const COMMENT_CREATE_STARTED = 'COMMENT_CREATE_STARTED'; +const COMMENT_CREATE_COMPLETED = 'COMMENT_CREATE_COMPLETED'; +const COMMENT_CREATE_FAILED = 'COMMENT_CREATE_FAILED'; + // Files const FILE_LIST_STARTED = 'FILE_LIST_STARTED'; const FILE_LIST_SUCCEEDED = 'FILE_LIST_SUCCEEDED'; @@ -318,6 +326,12 @@ var action_types = /*#__PURE__*/Object.freeze({ CLAIM_SEARCH_STARTED: CLAIM_SEARCH_STARTED, CLAIM_SEARCH_COMPLETED: CLAIM_SEARCH_COMPLETED, CLAIM_SEARCH_FAILED: CLAIM_SEARCH_FAILED, + COMMENT_LIST_STARTED: COMMENT_LIST_STARTED, + COMMENT_LIST_COMPLETED: COMMENT_LIST_COMPLETED, + COMMENT_LIST_UPDATED: COMMENT_LIST_UPDATED, + COMMENT_CREATE_STARTED: COMMENT_CREATE_STARTED, + COMMENT_CREATE_COMPLETED: COMMENT_CREATE_COMPLETED, + COMMENT_CREATE_FAILED: COMMENT_CREATE_FAILED, FILE_LIST_STARTED: FILE_LIST_STARTED, FILE_LIST_SUCCEEDED: FILE_LIST_SUCCEEDED, FETCH_FILE_INFO_STARTED: FETCH_FILE_INFO_STARTED, @@ -676,6 +690,9 @@ const Lbry = { sync_hash: (params = {}) => daemonCallWithResult('sync_hash', params), sync_apply: (params = {}) => daemonCallWithResult('sync_apply', params), + // Comments + comment_list: (params = {}) => daemonCallWithResult('comment_list', params), + comment_create: (params = {}) => daemonCallWithResult('comment_create', params), // Connect to the sdk connect: () => { if (Lbry.connectPromise === null) { @@ -2761,6 +2778,74 @@ const doDeleteTag = name => ({ } }); +// + +function doCommentList(uri) { + return (dispatch, getState) => { + const state = getState(); + const claim = selectClaimsByUri(state)[uri]; + const claimId = claim ? claim.claim_id : null; + + dispatch({ + type: COMMENT_LIST_STARTED + }); + lbryProxy.comment_list({ + claim_id: claimId + }).then(results => { + dispatch({ + type: COMMENT_LIST_COMPLETED, + data: { + comments: results, + claimId: claimId, + uri: uri + } + }); + }).catch(error => { + console.log(error); + }); + }; +} + +function doCommentCreate(comment = '', claim_id = '', channel, parent_id) { + return (dispatch, getState) => { + const state = getState(); + dispatch({ + type: COMMENT_CREATE_STARTED + }); + const myChannels = selectMyChannelClaims(state); + const namedChannelClaim = myChannels.find(myChannel => myChannel.name === channel); + const channel_id = namedChannelClaim ? namedChannelClaim.claim_id : null; + return lbryProxy.comment_create({ + comment, + claim_id, + channel_id + }).then(result => { + dispatch({ + type: COMMENT_CREATE_COMPLETED, + data: { + response: result + } + }); + dispatch({ + type: COMMENT_LIST_UPDATED, + data: { + comment: result, + claimId: claim_id + } + }); + }).catch(error => { + dispatch({ + type: COMMENT_CREATE_FAILED, + data: error + }); + dispatch(doToast({ + message: 'Oops, someone broke comments.', + isError: true + })); + }); + }; +} + var _extends$4 = 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; }; const reducers = {}; @@ -3724,6 +3809,70 @@ function contentReducer(state = defaultState$6, action) { return state; } +// + +// TODO change to handleActions() +// const commentsReducer = handleActions( { +const reducers$4 = {}; + +const defaultState$7 = { + byId: {}, + commentsByUri: {}, + isLoading: false +}; + +reducers$4[COMMENT_CREATE_STARTED] = (state, action) => Object.assign({}, state, { + isLoading: true +}); + +reducers$4[COMMENT_CREATE_FAILED] = (state, action) => { + // TODO: handle error.. what else? + return state; +}; + +reducers$4[COMMENT_CREATE_COMPLETED] = (state, action) => { + const { comments } = action.data; + return state; +}; + +reducers$4[COMMENT_LIST_UPDATED] = (state, action) => { + const { comment, claimId } = action.data; + const byId = Object.assign({}, state.byId); + const comments = byId[claimId]; + const newComments = comments.slice(); + newComments.unshift(comment); + byId[claimId] = newComments; + return Object.assign({}, state, { + byId + }); +}; + +reducers$4[COMMENT_LIST_STARTED] = state => Object.assign({}, state, { + isLoading: true +}); + +reducers$4[COMMENT_LIST_COMPLETED] = (state, action) => { + const { comments, claimId, uri } = action.data; + const byId = Object.assign({}, state.byId); + const commentsByUri = Object.assign({}, state.commentsByUri); + + if (comments['items']) { + byId[claimId] = comments['items']; + commentsByUri[uri] = claimId; + } + return Object.assign({}, state, { + byId, + commentsByUri, + isLoading: false + }); +}; + +function commentReducer(state = defaultState$7, action) { + const handler = reducers$4[action.type]; + if (handler) return handler(state, action); + return state; +} + 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; }; const tagsReducerBuilder = defaultState => handleActions({ @@ -3810,11 +3959,36 @@ const selectError = reselect.createSelector(selectState$6, state => { // -const selectState$7 = state => state.tags || {}; +const selectState$7 = state => state.comments || {}; -const selectKnownTagsByName = reselect.createSelector(selectState$7, state => state.knownTags); +const selectCommentsById = reselect.createSelector(selectState$7, state => state.byId || {}); -const selectFollowedTagsList = reselect.createSelector(selectState$7, state => state.followedTags); +const selectCommentsByUri = reselect.createSelector(selectState$7, state => { + const byUri = state.commentsByUri || {}; + const comments = {}; + Object.keys(byUri).forEach(uri => { + const claimId = byUri[uri]; + if (claimId === null) { + comments[uri] = null; + } else { + comments[uri] = claimId; + } + }); + return comments; +}); + +const makeSelectCommentsForUri = uri => reselect.createSelector(selectCommentsById, selectCommentsByUri, (byId, byUri) => { + const claimId = byUri[uri]; + return byId && byId[claimId]; +}); + +// + +const selectState$8 = state => state.tags || {}; + +const selectKnownTagsByName = reselect.createSelector(selectState$8, state => state.knownTags); + +const selectFollowedTagsList = reselect.createSelector(selectState$8, state => state.followedTags); const selectFollowedTags = reselect.createSelector(selectFollowedTagsList, followedTags => followedTags.map(tag => ({ name: tag })).sort((a, b) => a.name.localeCompare(b.name))); @@ -3844,6 +4018,7 @@ exports.TRANSACTIONS = transaction_types; exports.batchActions = batchActions; exports.buildURI = buildURI; exports.claimsReducer = claimsReducer; +exports.commentReducer = commentReducer; exports.contentReducer = contentReducer; exports.convertToShareLink = convertToShareLink; exports.creditsToString = creditsToString; @@ -3853,6 +4028,8 @@ exports.doBalanceSubscribe = doBalanceSubscribe; exports.doBlurSearchInput = doBlurSearchInput; exports.doCheckAddressIsMine = doCheckAddressIsMine; exports.doClaimSearch = doClaimSearch; +exports.doCommentCreate = doCommentCreate; +exports.doCommentList = doCommentList; exports.doCreateChannel = doCreateChannel; exports.doDeletePurchasedUri = doDeletePurchasedUri; exports.doDeleteTag = doDeleteTag; @@ -3906,6 +4083,7 @@ exports.makeSelectClaimIsNsfw = makeSelectClaimIsNsfw; exports.makeSelectClaimIsPending = makeSelectClaimIsPending; exports.makeSelectClaimsInChannelForCurrentPageState = makeSelectClaimsInChannelForCurrentPageState; exports.makeSelectClaimsInChannelForPage = makeSelectClaimsInChannelForPage; +exports.makeSelectCommentsForUri = makeSelectCommentsForUri; exports.makeSelectContentPositionForUri = makeSelectContentPositionForUri; exports.makeSelectContentTypeForUri = makeSelectContentTypeForUri; exports.makeSelectCoverForUri = makeSelectCoverForUri; diff --git a/dist/flow-typed/Comment.js b/dist/flow-typed/Comment.js new file mode 100644 index 0000000..808dda8 --- /dev/null +++ b/dist/flow-typed/Comment.js @@ -0,0 +1,18 @@ +declare type Comment = { + author: string, + claim_index?: number, + comment_id?: number, + downvotes?: number, + message: string, + omitted?: number, + reply_count?: number, + time_posted?: number, + upvotes?: number, + parent_id?: number, +}; + +declare type CommentsState = { + byId: {}, + isLoading: boolean, + commentsByUri: { [string]: string }, +} diff --git a/dist/flow-typed/Lbry.js b/dist/flow-typed/Lbry.js index d67a17d..9931f68 100644 --- a/dist/flow-typed/Lbry.js +++ b/dist/flow-typed/Lbry.js @@ -105,6 +105,9 @@ declare type ChannelCreateResponse = GenericTxResponse & { outputs: Array, }; +declare type CommentCreateResponse = Comment; +declare type CommentListResponse = Array; + declare type ChannelListResponse = Array; declare type FileListResponse = Array; @@ -184,6 +187,9 @@ declare type LbryTypes = { blob_delete: (params: {}) => Promise, blob_list: (params: {}) => Promise, + // Commenting + comment_list: (params: {}) => Promise, + comment_create: (params: {}) => Promise, // Wallet utilities account_balance: (params: {}) => Promise, account_decrypt: (prams: {}) => Promise, diff --git a/flow-typed/Comment.js b/flow-typed/Comment.js new file mode 100644 index 0000000..808dda8 --- /dev/null +++ b/flow-typed/Comment.js @@ -0,0 +1,18 @@ +declare type Comment = { + author: string, + claim_index?: number, + comment_id?: number, + downvotes?: number, + message: string, + omitted?: number, + reply_count?: number, + time_posted?: number, + upvotes?: number, + parent_id?: number, +}; + +declare type CommentsState = { + byId: {}, + isLoading: boolean, + commentsByUri: { [string]: string }, +} diff --git a/flow-typed/Lbry.js b/flow-typed/Lbry.js index d67a17d..9931f68 100644 --- a/flow-typed/Lbry.js +++ b/flow-typed/Lbry.js @@ -105,6 +105,9 @@ declare type ChannelCreateResponse = GenericTxResponse & { outputs: Array, }; +declare type CommentCreateResponse = Comment; +declare type CommentListResponse = Array; + declare type ChannelListResponse = Array; declare type FileListResponse = Array; @@ -184,6 +187,9 @@ declare type LbryTypes = { blob_delete: (params: {}) => Promise, blob_list: (params: {}) => Promise, + // Commenting + comment_list: (params: {}) => Promise, + comment_create: (params: {}) => Promise, // Wallet utilities account_balance: (params: {}) => Promise, account_decrypt: (prams: {}) => Promise, diff --git a/src/constants/action_types.js b/src/constants/action_types.js index 80acf3f..c1427fb 100644 --- a/src/constants/action_types.js +++ b/src/constants/action_types.js @@ -92,6 +92,14 @@ export const CLAIM_SEARCH_STARTED = 'CLAIM_SEARCH_STARTED'; export const CLAIM_SEARCH_COMPLETED = 'CLAIM_SEARCH_COMPLETED'; export const CLAIM_SEARCH_FAILED = 'CLAIM_SEARCH_FAILED'; +// Comments +export const COMMENT_LIST_STARTED = 'COMMENT_LIST_STARTED'; +export const COMMENT_LIST_COMPLETED = 'COMMENT_LIST_COMPLETED'; +export const COMMENT_LIST_UPDATED = 'COMMENT_LIST_UPDATED'; +export const COMMENT_CREATE_STARTED = 'COMMENT_CREATE_STARTED'; +export const COMMENT_CREATE_COMPLETED = 'COMMENT_CREATE_COMPLETED'; +export const COMMENT_CREATE_FAILED = 'COMMENT_CREATE_FAILED'; + // Files export const FILE_LIST_STARTED = 'FILE_LIST_STARTED'; export const FILE_LIST_SUCCEEDED = 'FILE_LIST_SUCCEEDED'; diff --git a/src/index.js b/src/index.js index 4ae019e..0e88ed3 100644 --- a/src/index.js +++ b/src/index.js @@ -90,6 +90,8 @@ export { 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'; @@ -104,6 +106,7 @@ export { notificationsReducer } from 'redux/reducers/notifications'; export { searchReducer } from 'redux/reducers/search'; export { walletReducer } from 'redux/reducers/wallet'; export { contentReducer } from 'redux/reducers/content'; +export { commentReducer } from 'redux/reducers/comments'; export { tagsReducerBuilder } from 'redux/reducers/tags'; // selectors @@ -170,6 +173,8 @@ export { selectLastClaimSearchUris, } from 'redux/selectors/claims'; +export { makeSelectCommentsForUri } from 'redux/selectors/comments'; + export { makeSelectFileInfoForUri, makeSelectDownloadingForUri, diff --git a/src/lbry.js b/src/lbry.js index 3ac88ad..617b24b 100644 --- a/src/lbry.js +++ b/src/lbry.js @@ -100,6 +100,9 @@ const Lbry: LbryTypes = { sync_hash: (params = {}) => daemonCallWithResult('sync_hash', params), sync_apply: (params = {}) => daemonCallWithResult('sync_apply', params), + // Comments + comment_list: (params = {}) => daemonCallWithResult('comment_list', params), + comment_create: (params = {}) => daemonCallWithResult('comment_create', params), // Connect to the sdk connect: () => { if (Lbry.connectPromise === null) { diff --git a/src/redux/actions/comments.js b/src/redux/actions/comments.js new file mode 100644 index 0000000..6d48802 --- /dev/null +++ b/src/redux/actions/comments.js @@ -0,0 +1,82 @@ +// @flow +import * as ACTIONS from 'constants/action_types'; +import Lbry from 'lbry'; +import { selectClaimsByUri, selectMyChannelClaims } from 'redux/selectors/claims'; +import { doToast } from 'redux/actions/notifications'; + +export function doCommentList(uri: string) { + return (dispatch: Dispatch, getState: GetState) => { + const state = getState(); + const claim = selectClaimsByUri(state)[uri]; + const claimId = claim ? claim.claim_id : null; + + dispatch({ + type: ACTIONS.COMMENT_LIST_STARTED, + }); + Lbry.comment_list({ + claim_id: claimId, + }) + .then(results => { + dispatch({ + type: ACTIONS.COMMENT_LIST_COMPLETED, + data: { + comments: results, + claimId: claimId, + uri: uri, + }, + }); + }) + .catch(error => { + console.log(error); + }); + }; +} + +export function doCommentCreate( + comment: string = '', + claim_id: string = '', + channel: ?string, + parent_id?: number +) { + return (dispatch: Dispatch, getState: GetState) => { + const state = getState(); + dispatch({ + type: ACTIONS.COMMENT_CREATE_STARTED, + }); + const myChannels = selectMyChannelClaims(state); + const namedChannelClaim = myChannels.find(myChannel => myChannel.name === channel); + const channel_id = namedChannelClaim ? namedChannelClaim.claim_id : null; + return Lbry.comment_create({ + comment, + claim_id, + channel_id, + }) + .then((result: Comment) => { + dispatch({ + type: ACTIONS.COMMENT_CREATE_COMPLETED, + data: { + response: result, + }, + }); + dispatch({ + type: ACTIONS.COMMENT_LIST_UPDATED, + data: { + comment: result, + claimId: claim_id, + }, + }); + }) + .catch(error => { + dispatch({ + type: ACTIONS.COMMENT_CREATE_FAILED, + data: error, + }); + dispatch( + doToast({ + message: 'Oops, someone broke comments.', + isError: true, + }) + ); + }); + }; +} diff --git a/src/redux/reducers/comments.js b/src/redux/reducers/comments.js new file mode 100644 index 0000000..06895a3 --- /dev/null +++ b/src/redux/reducers/comments.js @@ -0,0 +1,66 @@ +// @flow +import * as ACTIONS from 'constants/action_types'; + +// TODO change to handleActions() +// const commentsReducer = handleActions( { +const reducers = {}; + +const defaultState: CommentsState = { + byId: {}, + commentsByUri: {}, + isLoading: false, +}; + +reducers[ACTIONS.COMMENT_CREATE_STARTED] = (state: CommentsState, action: any): CommentsState => + Object.assign({}, state, { + isLoading: true, + }); + +reducers[ACTIONS.COMMENT_CREATE_FAILED] = (state: CommentsState, action: any): CommentsState => { + // TODO: handle error.. what else? + return state; +}; + +reducers[ACTIONS.COMMENT_CREATE_COMPLETED] = (state: CommentsState, action: any): CommentsState => { + const { comments }: any = action.data; + return state; +}; + +reducers[ACTIONS.COMMENT_LIST_UPDATED] = (state: CommentsState, action: any): CommentsState => { + const { comment, claimId }: any = action.data; + const byId = Object.assign({}, state.byId); + const comments = byId[claimId]; + const newComments = comments.slice(); + newComments.unshift(comment); + byId[claimId] = newComments; + return Object.assign({}, state, { + byId, + }); +}; + +reducers[ACTIONS.COMMENT_LIST_STARTED] = state => + Object.assign({}, state, { + isLoading: true, + }); + +reducers[ACTIONS.COMMENT_LIST_COMPLETED] = (state: CommentsState, action: any) => { + const { comments, claimId, uri } = action.data; + const byId = Object.assign({}, state.byId); + const commentsByUri = Object.assign({}, state.commentsByUri); + + if (comments['items']) { + byId[claimId] = comments['items']; + commentsByUri[uri] = claimId; + } + return Object.assign({}, state, { + byId, + commentsByUri, + isLoading: false, + }); +}; + +export function commentReducer(state: CommentsState = defaultState, action: any) { + const handler = reducers[action.type]; + if (handler) return handler(state, action); + return state; +} diff --git a/src/redux/selectors/comments.js b/src/redux/selectors/comments.js new file mode 100644 index 0000000..c391a5c --- /dev/null +++ b/src/redux/selectors/comments.js @@ -0,0 +1,36 @@ +// @flow +import { createSelector } from 'reselect'; + +const selectState = state => state.comments || {}; + +export const selectCommentsById = createSelector( + selectState, + state => state.byId || {} +); + +export const selectCommentsByUri = createSelector( + selectState, + state => { + const byUri = state.commentsByUri || {}; + const comments = {}; + Object.keys(byUri).forEach(uri => { + const claimId = byUri[uri]; + if (claimId === null) { + comments[uri] = null; + } else { + comments[uri] = claimId; + } + }); + return comments; + } +); + +export const makeSelectCommentsForUri = (uri: string) => + createSelector( + selectCommentsById, + selectCommentsByUri, + (byId, byUri) => { + const claimId = byUri[uri]; + return byId && byId[claimId]; + } + ); From cd642e39a4e29811e0a5ee616a6104a34c7ac327 Mon Sep 17 00:00:00 2001 From: Sean Yesmunt Date: Wed, 26 Jun 2019 19:13:29 -0400 Subject: [PATCH 21/21] respond to PR comments --- dist/bundle.es.js | 126 +++++++++++++++------------------ src/constants/action_types.js | 2 +- src/redux/actions/comments.js | 12 ++-- src/redux/reducers/comments.js | 97 ++++++++++++------------- 4 files changed, 110 insertions(+), 127 deletions(-) diff --git a/dist/bundle.es.js b/dist/bundle.es.js index e4cc141..8abd424 100644 --- a/dist/bundle.es.js +++ b/dist/bundle.es.js @@ -105,7 +105,7 @@ const CLAIM_SEARCH_FAILED = 'CLAIM_SEARCH_FAILED'; // Comments const COMMENT_LIST_STARTED = 'COMMENT_LIST_STARTED'; const COMMENT_LIST_COMPLETED = 'COMMENT_LIST_COMPLETED'; -const COMMENT_LIST_UPDATED = 'COMMENT_LIST_UPDATED'; +const COMMENT_LIST_FAILED = 'COMMENT_LIST_FAILED'; const COMMENT_CREATE_STARTED = 'COMMENT_CREATE_STARTED'; const COMMENT_CREATE_COMPLETED = 'COMMENT_CREATE_COMPLETED'; const COMMENT_CREATE_FAILED = 'COMMENT_CREATE_FAILED'; @@ -328,7 +328,7 @@ var action_types = /*#__PURE__*/Object.freeze({ CLAIM_SEARCH_FAILED: CLAIM_SEARCH_FAILED, COMMENT_LIST_STARTED: COMMENT_LIST_STARTED, COMMENT_LIST_COMPLETED: COMMENT_LIST_COMPLETED, - COMMENT_LIST_UPDATED: COMMENT_LIST_UPDATED, + COMMENT_LIST_FAILED: COMMENT_LIST_FAILED, COMMENT_CREATE_STARTED: COMMENT_CREATE_STARTED, COMMENT_CREATE_COMPLETED: COMMENT_CREATE_COMPLETED, COMMENT_CREATE_FAILED: COMMENT_CREATE_FAILED, @@ -2802,6 +2802,10 @@ function doCommentList(uri) { }); }).catch(error => { console.log(error); + dispatch({ + type: COMMENT_LIST_FAILED, + data: error + }); }); }; } @@ -2822,12 +2826,6 @@ function doCommentCreate(comment = '', claim_id = '', channel, parent_id) { }).then(result => { dispatch({ type: COMMENT_CREATE_COMPLETED, - data: { - response: result - } - }); - dispatch({ - type: COMMENT_LIST_UPDATED, data: { comment: result, claimId: claim_id @@ -3809,11 +3807,7 @@ function contentReducer(state = defaultState$6, action) { return state; } -// - -// TODO change to handleActions() -// const commentsReducer = handleActions( { -const reducers$4 = {}; +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; }; const defaultState$7 = { byId: {}, @@ -3821,59 +3815,53 @@ const defaultState$7 = { isLoading: false }; -reducers$4[COMMENT_CREATE_STARTED] = (state, action) => Object.assign({}, state, { - isLoading: true -}); +const commentReducer = handleActions({ + [COMMENT_CREATE_STARTED]: (state, action) => _extends$b({}, state, { + isLoading: true + }), -reducers$4[COMMENT_CREATE_FAILED] = (state, action) => { - // TODO: handle error.. what else? - return state; -}; - -reducers$4[COMMENT_CREATE_COMPLETED] = (state, action) => { - const { comments } = action.data; - return state; -}; - -reducers$4[COMMENT_LIST_UPDATED] = (state, action) => { - const { comment, claimId } = action.data; - const byId = Object.assign({}, state.byId); - const comments = byId[claimId]; - const newComments = comments.slice(); - newComments.unshift(comment); - byId[claimId] = newComments; - return Object.assign({}, state, { - byId - }); -}; - -reducers$4[COMMENT_LIST_STARTED] = state => Object.assign({}, state, { - isLoading: true -}); - -reducers$4[COMMENT_LIST_COMPLETED] = (state, action) => { - const { comments, claimId, uri } = action.data; - const byId = Object.assign({}, state.byId); - const commentsByUri = Object.assign({}, state.commentsByUri); - - if (comments['items']) { - byId[claimId] = comments['items']; - commentsByUri[uri] = claimId; - } - return Object.assign({}, state, { - byId, - commentsByUri, + [COMMENT_CREATE_FAILED]: (state, action) => _extends$b({}, state, { isLoading: false - }); -}; + }), -function commentReducer(state = defaultState$7, action) { - const handler = reducers$4[action.type]; - if (handler) return handler(state, action); - return state; -} + [COMMENT_CREATE_COMPLETED]: (state, action) => { + const { comment, claimId } = action.data; + const byId = Object.assign({}, state.byId); + const comments = byId[claimId]; + const newComments = comments.slice(); -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; }; + newComments.unshift(comment); + byId[claimId] = newComments; + + return _extends$b({}, state, { + byId + }); + }, + + [COMMENT_LIST_STARTED]: state => _extends$b({}, state, { isLoading: true }), + + [COMMENT_LIST_COMPLETED]: (state, action) => { + const { comments, claimId, uri } = action.data; + const byId = Object.assign({}, state.byId); + const commentsByUri = Object.assign({}, state.commentsByUri); + + if (comments['items']) { + byId[claimId] = comments['items']; + commentsByUri[uri] = claimId; + } + return _extends$b({}, state, { + byId, + commentsByUri, + isLoading: false + }); + }, + + [COMMENT_LIST_FAILED]: (state, action) => _extends$b({}, state, { + isLoading: false + }) +}, defaultState$7); + +var _extends$c = 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; }; const tagsReducerBuilder = defaultState => handleActions({ [TOGGLE_TAG_FOLLOW]: (state, action) => { @@ -3888,7 +3876,7 @@ const tagsReducerBuilder = defaultState => handleActions({ newFollowedTags.push(name); } - return _extends$b({}, state, { + return _extends$c({}, state, { followedTags: newFollowedTags }); }, @@ -3897,10 +3885,10 @@ const tagsReducerBuilder = defaultState => handleActions({ const { knownTags } = state; const { name } = action.data; - let newKnownTags = _extends$b({}, knownTags); + let newKnownTags = _extends$c({}, knownTags); newKnownTags[name] = { name }; - return _extends$b({}, state, { + return _extends$c({}, state, { knownTags: newKnownTags }); }, @@ -3909,11 +3897,11 @@ const tagsReducerBuilder = defaultState => handleActions({ const { knownTags, followedTags } = state; const { name } = action.data; - let newKnownTags = _extends$b({}, knownTags); + let newKnownTags = _extends$c({}, knownTags); delete newKnownTags[name]; const newFollowedTags = followedTags.filter(tag => tag !== name); - return _extends$b({}, state, { + return _extends$c({}, state, { knownTags: newKnownTags, followedTags: newFollowedTags }); @@ -3931,14 +3919,14 @@ const makeSelectContentPositionForUri = uri => reselect.createSelector(selectSta return state.positions[id] ? state.positions[id][outpoint] : null; }); -var _extends$c = 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; }; +var _extends$d = 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; }; const selectState$6 = state => state.notifications || {}; const selectToast = reselect.createSelector(selectState$6, state => { if (state.toasts.length) { const { id, params } = state.toasts[0]; - return _extends$c({ + return _extends$d({ id }, params); } diff --git a/src/constants/action_types.js b/src/constants/action_types.js index c1427fb..3fa9547 100644 --- a/src/constants/action_types.js +++ b/src/constants/action_types.js @@ -95,7 +95,7 @@ export const CLAIM_SEARCH_FAILED = 'CLAIM_SEARCH_FAILED'; // Comments export const COMMENT_LIST_STARTED = 'COMMENT_LIST_STARTED'; export const COMMENT_LIST_COMPLETED = 'COMMENT_LIST_COMPLETED'; -export const COMMENT_LIST_UPDATED = 'COMMENT_LIST_UPDATED'; +export const COMMENT_LIST_FAILED = 'COMMENT_LIST_FAILED'; export const COMMENT_CREATE_STARTED = 'COMMENT_CREATE_STARTED'; export const COMMENT_CREATE_COMPLETED = 'COMMENT_CREATE_COMPLETED'; export const COMMENT_CREATE_FAILED = 'COMMENT_CREATE_FAILED'; diff --git a/src/redux/actions/comments.js b/src/redux/actions/comments.js index 6d48802..3de70e6 100644 --- a/src/redux/actions/comments.js +++ b/src/redux/actions/comments.js @@ -16,7 +16,7 @@ export function doCommentList(uri: string) { Lbry.comment_list({ claim_id: claimId, }) - .then(results => { + .then((results: CommentListResponse) => { dispatch({ type: ACTIONS.COMMENT_LIST_COMPLETED, data: { @@ -28,6 +28,10 @@ export function doCommentList(uri: string) { }) .catch(error => { console.log(error); + dispatch({ + type: ACTIONS.COMMENT_LIST_FAILED, + data: error, + }); }); }; } @@ -54,12 +58,6 @@ export function doCommentCreate( .then((result: Comment) => { dispatch({ type: ACTIONS.COMMENT_CREATE_COMPLETED, - data: { - response: result, - }, - }); - dispatch({ - type: ACTIONS.COMMENT_LIST_UPDATED, data: { comment: result, claimId: claim_id, diff --git a/src/redux/reducers/comments.js b/src/redux/reducers/comments.js index 06895a3..1f99467 100644 --- a/src/redux/reducers/comments.js +++ b/src/redux/reducers/comments.js @@ -1,9 +1,6 @@ // @flow import * as ACTIONS from 'constants/action_types'; - -// TODO change to handleActions() -// const commentsReducer = handleActions( { -const reducers = {}; +import { handleActions } from 'util/redux-utils'; const defaultState: CommentsState = { byId: {}, @@ -11,56 +8,56 @@ const defaultState: CommentsState = { isLoading: false, }; -reducers[ACTIONS.COMMENT_CREATE_STARTED] = (state: CommentsState, action: any): CommentsState => - Object.assign({}, state, { - isLoading: true, - }); +export const commentReducer = handleActions( + { + [ACTIONS.COMMENT_CREATE_STARTED]: (state: CommentsState, action: any): CommentsState => ({ + ...state, + isLoading: true, + }), -reducers[ACTIONS.COMMENT_CREATE_FAILED] = (state: CommentsState, action: any): CommentsState => { - // TODO: handle error.. what else? - return state; -}; + [ACTIONS.COMMENT_CREATE_FAILED]: (state: CommentsState, action: any) => ({ + ...state, + isLoading: false, + }), -reducers[ACTIONS.COMMENT_CREATE_COMPLETED] = (state: CommentsState, action: any): CommentsState => { - const { comments }: any = action.data; - return state; -}; + [ACTIONS.COMMENT_CREATE_COMPLETED]: (state: CommentsState, action: any): CommentsState => { + const { comment, claimId }: any = action.data; + const byId = Object.assign({}, state.byId); + const comments = byId[claimId]; + const newComments = comments.slice(); -reducers[ACTIONS.COMMENT_LIST_UPDATED] = (state: CommentsState, action: any): CommentsState => { - const { comment, claimId }: any = action.data; - const byId = Object.assign({}, state.byId); - const comments = byId[claimId]; - const newComments = comments.slice(); - newComments.unshift(comment); - byId[claimId] = newComments; - return Object.assign({}, state, { - byId, - }); -}; + newComments.unshift(comment); + byId[claimId] = newComments; -reducers[ACTIONS.COMMENT_LIST_STARTED] = state => - Object.assign({}, state, { - isLoading: true, - }); + return { + ...state, + byId, + }; + }, -reducers[ACTIONS.COMMENT_LIST_COMPLETED] = (state: CommentsState, action: any) => { - const { comments, claimId, uri } = action.data; - const byId = Object.assign({}, state.byId); - const commentsByUri = Object.assign({}, state.commentsByUri); + [ACTIONS.COMMENT_LIST_STARTED]: state => ({ ...state, isLoading: true }), - if (comments['items']) { - byId[claimId] = comments['items']; - commentsByUri[uri] = claimId; - } - return Object.assign({}, state, { - byId, - commentsByUri, - isLoading: false, - }); -}; + [ACTIONS.COMMENT_LIST_COMPLETED]: (state: CommentsState, action: any) => { + const { comments, claimId, uri } = action.data; + const byId = Object.assign({}, state.byId); + const commentsByUri = Object.assign({}, state.commentsByUri); -export function commentReducer(state: CommentsState = defaultState, action: any) { - const handler = reducers[action.type]; - if (handler) return handler(state, action); - return state; -} + if (comments['items']) { + byId[claimId] = comments['items']; + commentsByUri[uri] = claimId; + } + return { + ...state, + byId, + commentsByUri, + isLoading: false, + }; + }, + + [ACTIONS.COMMENT_LIST_FAILED]: (state: CommentsState, action: any) => ({ + ...state, + isLoading: false, + }), + }, + defaultState +);