diff --git a/extras/lbryinc/index.js b/extras/lbryinc/index.js index 1b23baae0..2d86de5fd 100644 --- a/extras/lbryinc/index.js +++ b/extras/lbryinc/index.js @@ -50,9 +50,12 @@ export { export { selectFilteredOutpoints, selectFilteredOutpointMap } from './redux/selectors/filtered'; export { selectViewCount, - makeSelectViewCountForUri, - makeSelectSubCountForUri, + selectViewCountForUri, + // makeSelectViewCountForUri, // deprecated + selectSubCountForUri, + // makeSelectSubCountForUri, // deprecated } from './redux/selectors/stats'; +export { selectBanStateForUri } from './redux/selectors/ban'; export { selectHasSyncedWallet, selectSyncData, diff --git a/extras/lbryinc/redux/selectors/ban.js b/extras/lbryinc/redux/selectors/ban.js new file mode 100644 index 000000000..ee0e2b0a0 --- /dev/null +++ b/extras/lbryinc/redux/selectors/ban.js @@ -0,0 +1,68 @@ +// @flow + +// TODO: This should be in 'redux/selectors/claim.js'. Temporarily putting it +// here to get past importing issues with 'lbryinc', which the real fix might +// involve moving it from 'extras' to 'ui' (big change). + +import { createCachedSelector } from 're-reselect'; +import { selectClaimForUri } from 'redux/selectors/claims'; +import { selectMutedChannels } from 'redux/selectors/blocked'; +import { selectModerationBlockList } from 'redux/selectors/comments'; +import { selectBlacklistedOutpointMap, selectFilteredOutpointMap } from 'lbryinc'; +import { getChannelFromClaim } from 'util/claim'; +import { isURIEqual } from 'util/lbryURI'; + +export const selectBanStateForUri = createCachedSelector( + selectClaimForUri, + selectBlacklistedOutpointMap, + selectFilteredOutpointMap, + selectMutedChannels, + selectModerationBlockList, + (claim, blackListedOutpointMap, filteredOutpointMap, mutedChannelUris, personalBlocklist) => { + const banState = {}; + + if (!claim) { + return banState; + } + + const channelClaim = getChannelFromClaim(claim); + + // This will be replaced once blocking is done at the wallet server level. + if (blackListedOutpointMap) { + if ( + (channelClaim && blackListedOutpointMap[`${channelClaim.txid}:${channelClaim.nout}`]) || + blackListedOutpointMap[`${claim.txid}:${claim.nout}`] + ) { + banState['blacklisted'] = true; + } + } + + // We're checking to see if the stream outpoint or signing channel outpoint + // is in the filter list. + if (filteredOutpointMap) { + if ( + (channelClaim && filteredOutpointMap[`${channelClaim.txid}:${channelClaim.nout}`]) || + filteredOutpointMap[`${claim.txid}:${claim.nout}`] + ) { + banState['filtered'] = true; + } + } + + // block stream claims + // block channel claims if we can't control for them in claim search + if (mutedChannelUris.length && channelClaim) { + if (mutedChannelUris.some((blockedUri) => isURIEqual(blockedUri, channelClaim.permanent_url))) { + banState['muted'] = true; + } + } + + // Commentron blocklist + if (personalBlocklist.length && channelClaim) { + if (personalBlocklist.some((blockedUri) => isURIEqual(blockedUri, channelClaim.permanent_url))) { + banState['blocked'] = true; + } + } + + return banState; + } +)((state, uri) => String(uri)); diff --git a/extras/lbryinc/redux/selectors/stats.js b/extras/lbryinc/redux/selectors/stats.js index 2b2065285..755402c07 100644 --- a/extras/lbryinc/redux/selectors/stats.js +++ b/extras/lbryinc/redux/selectors/stats.js @@ -1,20 +1,20 @@ +// @flow import { createSelector } from 'reselect'; -import { makeSelectClaimForUri } from 'redux/selectors/claims'; +import { selectClaimIdForUri } from 'redux/selectors/claims'; +type State = { claims: any }; const selectState = state => state.stats || {}; export const selectViewCount = createSelector(selectState, state => state.viewCountById); export const selectSubCount = createSelector(selectState, state => state.subCountById); -export const makeSelectViewCountForUri = uri => - createSelector( - makeSelectClaimForUri(uri), - selectViewCount, - (claim, viewCountById) => (claim ? viewCountById[claim.claim_id] || 0 : 0) - ); +export const selectViewCountForUri = (state: State, uri: string) => { + const claimId = selectClaimIdForUri(state, uri); + const viewCountById = selectViewCount(state); + return claimId ? viewCountById[claimId] || 0 : 0; +}; -export const makeSelectSubCountForUri = uri => - createSelector( - makeSelectClaimForUri(uri), - selectSubCount, - (claim, subCountById) => (claim ? subCountById[claim.claim_id] || 0 : 0) - ); +export const selectSubCountForUri = (state: State, uri: string) => { + const claimId = selectClaimIdForUri(state, uri); + const subCountById = selectSubCount(state); + return claimId ? subCountById[claimId] || 0 : 0; +}; diff --git a/static/app-strings.json b/static/app-strings.json index 515bb7550..0d2718541 100644 --- a/static/app-strings.json +++ b/static/app-strings.json @@ -2235,5 +2235,8 @@ "Network Data Hosting allows the p2p network to store blobs unrelated to your browsing.": "Network Data Hosting allows the p2p network to store blobs unrelated to your browsing.", "Content: Limit (GB)": "Content: Limit (GB)", "Network: Allow (GB)": "Network: Allow (GB)", + "Failed to view lbry://@Destiny#6/destiny-crashes-conservative-panel-w#a, please try again. If this problem persists, visit https://lbry.com/faq/support for support.": "Failed to view lbry://@Destiny#6/destiny-crashes-conservative-panel-w#a, please try again. If this problem persists, visit https://lbry.com/faq/support for support.", + "A channel is required to repost on LBRY": "A channel is required to repost on LBRY", + "Failed to view lbry://@gatogalactico#9/gato-galactico-e-as-estrelas-ninja-dos#1, please try again. If this problem persists, visit https://lbry.com/faq/support for support.": "Failed to view lbry://@gatogalactico#9/gato-galactico-e-as-estrelas-ninja-dos#1, please try again. If this problem persists, visit https://lbry.com/faq/support for support.", "--end--": "--end--" } diff --git a/ui/component/channelBlockButton/index.js b/ui/component/channelBlockButton/index.js index 9852404d7..4018ebcc6 100644 --- a/ui/component/channelBlockButton/index.js +++ b/ui/component/channelBlockButton/index.js @@ -1,5 +1,5 @@ import { connect } from 'react-redux'; -import { makeSelectClaimIdForUri } from 'redux/selectors/claims'; +import { selectClaimIdForUri } from 'redux/selectors/claims'; import { doCommentModUnBlock, doCommentModBlock, @@ -43,7 +43,7 @@ const select = (state, props) => { isBlocked, isToggling, isBlockingOrUnBlocking: makeSelectUriIsBlockingOrUnBlocking(props.uri)(state), - creatorId: makeSelectClaimIdForUri(props.creatorUri)(state), + creatorId: selectClaimIdForUri(state, props.creatorUri), }; }; diff --git a/ui/component/channelContent/index.js b/ui/component/channelContent/index.js index fc1a349f0..46e9b29eb 100644 --- a/ui/component/channelContent/index.js +++ b/ui/component/channelContent/index.js @@ -3,9 +3,9 @@ import { PAGE_SIZE } from 'constants/claim'; import { makeSelectClaimsInChannelForPage, makeSelectFetchingChannelClaims, - makeSelectClaimIsMine, + selectClaimIsMine, makeSelectTotalPagesInChannelSearch, - makeSelectClaimForUri, + selectClaimForUri, } from 'redux/selectors/claims'; import { doResolveUris } from 'redux/actions/claims'; import * as SETTINGS from 'constants/settings'; @@ -20,13 +20,15 @@ const select = (state, props) => { const { search } = props.location; const urlParams = new URLSearchParams(search); const page = urlParams.get('page') || 0; + const claim = props.uri && selectClaimForUri(state, props.uri); + return { pageOfClaimsInChannel: makeSelectClaimsInChannelForPage(props.uri, page)(state), fetching: makeSelectFetchingChannelClaims(props.uri)(state), totalPages: makeSelectTotalPagesInChannelSearch(props.uri, PAGE_SIZE)(state), - channelIsMine: makeSelectClaimIsMine(props.uri)(state), + channelIsMine: selectClaimIsMine(state, claim), channelIsBlocked: makeSelectChannelIsMuted(props.uri)(state), - claim: props.uri && makeSelectClaimForUri(props.uri)(state), + claim, isAuthenticated: selectUserVerifiedEmail(state), showMature: selectShowMatureContent(state), tileLayout: makeSelectClientSetting(SETTINGS.TILE_LAYOUT)(state), diff --git a/ui/component/channelStakedIndicator/index.js b/ui/component/channelStakedIndicator/index.js index d217012a4..3a1a41107 100644 --- a/ui/component/channelStakedIndicator/index.js +++ b/ui/component/channelStakedIndicator/index.js @@ -1,15 +1,15 @@ import { connect } from 'react-redux'; import { makeSelectClaimForUri, - makeSelectStakedLevelForChannelUri, - makeSelectTotalStakedAmountForChannelUri, + selectTotalStakedAmountForChannelUri, + selectStakedLevelForChannelUri, } from 'redux/selectors/claims'; import ChannelStakedIndicator from './view'; const select = (state, props) => ({ channelClaim: makeSelectClaimForUri(props.uri)(state), - amount: makeSelectTotalStakedAmountForChannelUri(props.uri)(state), - level: makeSelectStakedLevelForChannelUri(props.uri)(state), + amount: selectTotalStakedAmountForChannelUri(state, props.uri), + level: selectStakedLevelForChannelUri(state, props.uri), }); export default connect(select)(ChannelStakedIndicator); diff --git a/ui/component/claimMenuList/index.js b/ui/component/claimMenuList/index.js index 2f00b8766..847270381 100644 --- a/ui/component/claimMenuList/index.js +++ b/ui/component/claimMenuList/index.js @@ -1,5 +1,5 @@ import { connect } from 'react-redux'; -import { makeSelectClaimForUri, makeSelectClaimIsMine } from 'redux/selectors/claims'; +import { selectClaimForUri, selectClaimIsMine } from 'redux/selectors/claims'; import { doCollectionEdit, doFetchItemsInCollection } from 'redux/actions/collections'; import { doPrepareEdit } from 'redux/actions/publish'; import { @@ -34,7 +34,7 @@ import ClaimPreview from './view'; import fs from 'fs'; const select = (state, props) => { - const claim = makeSelectClaimForUri(props.uri, false)(state); + const claim = selectClaimForUri(state, props.uri, false); // @KP test no repost! const collectionId = props.collectionId; const repostedClaim = claim && claim.reposted_claim; const contentClaim = repostedClaim || claim; @@ -51,7 +51,7 @@ const select = (state, props) => { contentClaim, contentSigningChannel, contentChannelUri, - claimIsMine: makeSelectClaimIsMine(props.uri)(state), + claimIsMine: selectClaimIsMine(state, claim), hasClaimInWatchLater: makeSelectCollectionForIdHasClaimUrl( COLLECTIONS_CONSTS.WATCH_LATER_ID, contentPermanentUri @@ -92,7 +92,7 @@ const perform = (dispatch) => ({ doChannelUnmute: (channelUri) => dispatch(doChannelUnmute(channelUri)), doCommentModBlock: (channelUri) => dispatch(doCommentModBlock(channelUri)), doCommentModUnBlock: (channelUri) => dispatch(doCommentModUnBlock(channelUri)), - doCommentModBlockAsAdmin: (commenterUri, blockerId) => dispatch(doCommentModBlockAsAdmin(commenterUri, blockerId)), + doCommentModBlockAsAdmin: (a, b, c) => dispatch(doCommentModBlockAsAdmin(a, b, c)), doCommentModUnBlockAsAdmin: (commenterUri, blockerId) => dispatch(doCommentModUnBlockAsAdmin(commenterUri, blockerId)), doChannelSubscribe: (subscription) => dispatch(doChannelSubscribe(subscription)), diff --git a/ui/component/claimPreview/index.js b/ui/component/claimPreview/index.js index 25ab46a8b..65efab5d6 100644 --- a/ui/component/claimPreview/index.js +++ b/ui/component/claimPreview/index.js @@ -2,7 +2,7 @@ import { connect } from 'react-redux'; import { selectClaimForUri, makeSelectIsUriResolving, - makeSelectClaimIsMine, + selectClaimIsMine, makeSelectClaimIsPending, makeSelectClaimIsNsfw, makeSelectReflectingClaimForUri, @@ -20,12 +20,10 @@ import { import { doResolveUri } from 'redux/actions/claims'; import { doCollectionEdit } from 'redux/actions/collections'; import { doFileGet } from 'redux/actions/file'; -import { selectMutedChannels, makeSelectChannelIsMuted } from 'redux/selectors/blocked'; -import { selectBlackListedOutpoints, selectFilteredOutpoints } from 'lbryinc'; +import { selectBanStateForUri } from 'lbryinc'; import { selectShowMatureContent } from 'redux/selectors/settings'; import { makeSelectHasVisitedUri } from 'redux/selectors/content'; import { makeSelectIsSubscribed } from 'redux/selectors/subscriptions'; -import { selectModerationBlockList } from 'redux/selectors/comments'; import ClaimPreview from './view'; import formatMediaDuration from 'util/formatMediaDuration'; @@ -42,16 +40,12 @@ const select = (state, props) => { pending: props.uri && makeSelectClaimIsPending(props.uri)(state), reflectingProgress: props.uri && makeSelectReflectingClaimForUri(props.uri)(state), obscureNsfw: selectShowMatureContent(state) === false, - claimIsMine: props.uri && makeSelectClaimIsMine(props.uri)(state), + claimIsMine: props.uri && selectClaimIsMine(state, claim), isResolvingUri: props.uri && makeSelectIsUriResolving(props.uri)(state), isResolvingRepost: props.uri && makeSelectIsUriResolving(props.repostUrl)(state), nsfw: props.uri && makeSelectClaimIsNsfw(props.uri)(state), - blackListedOutpoints: selectBlackListedOutpoints(state), - filteredOutpoints: selectFilteredOutpoints(state), - mutedUris: selectMutedChannels(state), - blockedUris: selectModerationBlockList(state), + banState: selectBanStateForUri(state, props.uri), hasVisitedUri: props.uri && makeSelectHasVisitedUri(props.uri)(state), - channelIsBlocked: props.uri && makeSelectChannelIsMuted(props.uri)(state), isSubscribed: props.uri && makeSelectIsSubscribed(props.uri, true)(state), streamingUrl: props.uri && makeSelectStreamingUrlForUri(props.uri)(state), wasPurchased: props.uri && makeSelectClaimWasPurchased(props.uri)(state), diff --git a/ui/component/claimPreview/view.jsx b/ui/component/claimPreview/view.jsx index 8903c28c2..b85ce32aa 100644 --- a/ui/component/claimPreview/view.jsx +++ b/ui/component/claimPreview/view.jsx @@ -4,7 +4,7 @@ import React, { useEffect, forwardRef } from 'react'; import { NavLink, withRouter } from 'react-router-dom'; import { isEmpty } from 'util/object'; import classnames from 'classnames'; -import { isURIEqual, isURIValid } from 'util/lbryURI'; +import { isURIValid } from 'util/lbryURI'; import * as COLLECTIONS_CONSTS from 'constants/collections'; import { formatLbryUrlForWeb } from 'util/url'; import { formatClaimPreviewTitle } from 'util/formatAriaLabel'; @@ -46,17 +46,8 @@ type Props = { nsfw: boolean, placeholder: string, type: string, + banState: { blacklisted?: boolean, filtered?: boolean, muted?: boolean, blocked?: boolean }, hasVisitedUri: boolean, - blackListedOutpoints: Array<{ - txid: string, - nout: number, - }>, - filteredOutpoints: Array<{ - txid: string, - nout: number, - }>, - mutedUris: Array, - blockedUris: Array, channelIsBlocked: boolean, actions: boolean | Node | string | number, properties: boolean | Node | string | number | ((Claim) => Node), @@ -131,10 +122,7 @@ const ClaimPreview = forwardRef((props: Props, ref: any) => { properties, onClick, actions, - mutedUris, - blockedUris, - blackListedOutpoints, - filteredOutpoints, + banState, includeSupportAction, renderActions, hideMenu = false, @@ -236,28 +224,13 @@ const ClaimPreview = forwardRef((props: Props, ref: any) => { ((abandoned && !showUnresolvedClaim) || (!claimIsMine && obscureNsfw && nsfw)); // This will be replaced once blocking is done at the wallet server level - if (claim && !claimIsMine && !shouldHide && blackListedOutpoints) { - shouldHide = blackListedOutpoints.some( - (outpoint) => - (signingChannel && outpoint.txid === signingChannel.txid && outpoint.nout === signingChannel.nout) || - (outpoint.txid === claim.txid && outpoint.nout === claim.nout) - ); - } - // We're checking to see if the stream outpoint - // or signing channel outpoint is in the filter list - if (claim && !claimIsMine && !shouldHide && filteredOutpoints) { - shouldHide = filteredOutpoints.some( - (outpoint) => - (signingChannel && outpoint.txid === signingChannel.txid && outpoint.nout === signingChannel.nout) || - (outpoint.txid === claim.txid && outpoint.nout === claim.nout) - ); + if (claim && !claimIsMine && (banState.blacklisted || banState.filtered)) { + shouldHide = true; } + // block stream claims - if (claim && !shouldHide && !showUserBlocked && mutedUris.length && signingChannel) { - shouldHide = mutedUris.some((blockedUri) => isURIEqual(blockedUri, signingChannel.permanent_url)); - } - if (claim && !shouldHide && !showUserBlocked && blockedUris.length && signingChannel) { - shouldHide = blockedUris.some((blockedUri) => isURIEqual(blockedUri, signingChannel.permanent_url)); + if (!shouldHide && !showUserBlocked && (banState.muted || banState.blocked)) { + shouldHide = true; } if (!shouldHide && customShouldHide && claim) { diff --git a/ui/component/claimPreviewTile/index.js b/ui/component/claimPreviewTile/index.js index eaf64a865..7d1e558d4 100644 --- a/ui/component/claimPreviewTile/index.js +++ b/ui/component/claimPreviewTile/index.js @@ -11,7 +11,7 @@ import { import { doFileGet } from 'redux/actions/file'; import { doResolveUri } from 'redux/actions/claims'; import { selectMutedChannels } from 'redux/selectors/blocked'; -import { makeSelectViewCountForUri, selectBlackListedOutpoints, selectFilteredOutpoints } from 'lbryinc'; +import { selectViewCountForUri, selectBanStateForUri } from 'lbryinc'; import { selectShowMatureContent } from 'redux/selectors/settings'; import ClaimPreviewTile from './view'; import formatMediaDuration from 'util/formatMediaDuration'; @@ -29,12 +29,11 @@ const select = (state, props) => { isResolvingUri: props.uri && makeSelectIsUriResolving(props.uri)(state), thumbnail: props.uri && makeSelectThumbnailForUri(props.uri)(state), title: props.uri && makeSelectTitleForUri(props.uri)(state), - blackListedOutpoints: selectBlackListedOutpoints(state), - filteredOutpoints: selectFilteredOutpoints(state), + banState: selectBanStateForUri(state, props.uri), blockedChannelUris: selectMutedChannels(state), showMature: selectShowMatureContent(state), isMature: makeSelectClaimIsNsfw(props.uri)(state), - viewCount: makeSelectViewCountForUri(props.uri)(state), + viewCount: selectViewCountForUri(state, props.uri), }; }; diff --git a/ui/component/claimPreviewTile/view.jsx b/ui/component/claimPreviewTile/view.jsx index 1c921f64e..f68fc1c22 100644 --- a/ui/component/claimPreviewTile/view.jsx +++ b/ui/component/claimPreviewTile/view.jsx @@ -12,7 +12,7 @@ import SubscribeButton from 'component/subscribeButton'; import useGetThumbnail from 'effects/use-get-thumbnail'; import { formatLbryUrlForWeb, generateListSearchUrlParams } from 'util/url'; import { formatClaimPreviewTitle } from 'util/formatAriaLabel'; -import { parseURI, isURIEqual } from 'util/lbryURI'; +import { parseURI } from 'util/lbryURI'; import PreviewOverlayProperties from 'component/previewOverlayProperties'; import FileDownloadLink from 'component/fileDownloadLink'; import FileWatchLaterLink from 'component/fileWatchLaterLink'; @@ -33,15 +33,7 @@ type Props = { thumbnail: string, title: string, placeholder: boolean, - blackListedOutpoints: Array<{ - txid: string, - nout: number, - }>, - filteredOutpoints: Array<{ - txid: string, - nout: number, - }>, - blockedChannelUris: Array, + banState: { blacklisted?: boolean, filtered?: boolean, muted?: boolean, blocked?: boolean }, getFile: (string) => void, streamingUrl: string, isMature: boolean, @@ -64,11 +56,9 @@ function ClaimPreviewTile(props: Props) { resolveUri, claim, placeholder, - blackListedOutpoints, - filteredOutpoints, + banState, getFile, streamingUrl, - blockedChannelUris, isMature, showMature, showHiddenByUser, @@ -139,34 +129,9 @@ function ClaimPreviewTile(props: Props) { // Unfortunately needed until this is resolved // https://github.com/lbryio/lbry-sdk/issues/2785 shouldHide = true; - } - - // This will be replaced once blocking is done at the wallet server level - if (claim && !shouldHide && blackListedOutpoints) { - shouldHide = blackListedOutpoints.some( - (outpoint) => - (signingChannel && outpoint.txid === signingChannel.txid && outpoint.nout === signingChannel.nout) || - (outpoint.txid === claim.txid && outpoint.nout === claim.nout) - ); - } - // We're checking to see if the stream outpoint - // or signing channel outpoint is in the filter list - if (claim && !shouldHide && filteredOutpoints) { - shouldHide = filteredOutpoints.some( - (outpoint) => - (signingChannel && outpoint.txid === signingChannel.txid && outpoint.nout === signingChannel.nout) || - (outpoint.txid === claim.txid && outpoint.nout === claim.nout) - ); - } - - // block stream claims - if (claim && !shouldHide && !showHiddenByUser && blockedChannelUris.length && signingChannel) { - shouldHide = blockedChannelUris.some((blockedUri) => isURIEqual(blockedUri, signingChannel.permanent_url)); - } - // block channel claims if we can't control for them in claim search - // e.g. fetchRecommendedSubscriptions - if (claim && isChannel && !shouldHide && !showHiddenByUser && blockedChannelUris.length && signingChannel) { - shouldHide = blockedChannelUris.some((blockedUri) => isURIEqual(blockedUri, signingChannel.permanent_url)); + } else { + shouldHide = + banState.blacklisted || banState.filtered || (!showHiddenByUser && (banState.muted || banState.blocked)); } if (shouldHide) { @@ -280,34 +245,4 @@ function ClaimPreviewTile(props: Props) { ); } -export default React.memo(withRouter(ClaimPreviewTile), areEqual); - -const BLOCKLIST_KEYS = ['blackListedOutpoints', 'filteredOutpoints', 'blockedChannelUris']; -const HANDLED_KEYS = [...BLOCKLIST_KEYS, 'date']; - -function areEqual(prev: Props, next: Props) { - for (let i = 0; i < BLOCKLIST_KEYS.length; ++i) { - const key = BLOCKLIST_KEYS[i]; - const a = prev[key]; - const b = next[key]; - - if (((!a || !b) && a !== b) || (a && b && a.length !== b.length)) { - // The arrays are huge, so just compare the length instead of each entry. - return false; - } - } - - if (Number(prev.date) !== Number(next.date)) { - return false; - } - - const propKeys = Object.keys(next); - for (let i = 0; i < propKeys.length; ++i) { - const pk = propKeys[i]; - if (!HANDLED_KEYS.includes(pk) && prev[pk] !== next[pk]) { - return false; - } - } - - return true; -} +export default withRouter(ClaimPreviewTile); diff --git a/ui/component/claimProperties/index.js b/ui/component/claimProperties/index.js index 574ceb0e1..3b5f3edf6 100644 --- a/ui/component/claimProperties/index.js +++ b/ui/component/claimProperties/index.js @@ -1,12 +1,16 @@ import { connect } from 'react-redux'; -import { makeSelectClaimIsMine, makeSelectClaimForUri } from 'redux/selectors/claims'; +import { selectClaimIsMine, selectClaimForUri } from 'redux/selectors/claims'; import { makeSelectIsSubscribed } from 'redux/selectors/subscriptions'; import ClaimProperties from './view'; -const select = (state, props) => ({ - claim: makeSelectClaimForUri(props.uri)(state), - isSubscribed: makeSelectIsSubscribed(props.uri)(state), - claimIsMine: makeSelectClaimIsMine(props.uri)(state), -}); +const select = (state, props) => { + const claim = selectClaimForUri(state, props.uri); + + return { + claim, + isSubscribed: makeSelectIsSubscribed(props.uri)(state), + claimIsMine: selectClaimIsMine(state, claim), + }; +}; export default connect(select, null)(ClaimProperties); diff --git a/ui/component/collectionContentSidebar/index.js b/ui/component/collectionContentSidebar/index.js index e07304052..e65f79f84 100644 --- a/ui/component/collectionContentSidebar/index.js +++ b/ui/component/collectionContentSidebar/index.js @@ -1,6 +1,6 @@ import { connect } from 'react-redux'; import CollectionContent from './view'; -import { makeSelectClaimForUri, makeSelectClaimIsMine } from 'redux/selectors/claims'; +import { selectClaimForUri, selectClaimIsMine } from 'redux/selectors/claims'; import { makeSelectUrlsForCollectionId, makeSelectNameForCollectionId, @@ -12,7 +12,7 @@ import { doToggleLoopList, doToggleShuffleList } from 'redux/actions/content'; const select = (state, props) => { const playingUri = selectPlayingUri(state); const playingUrl = playingUri && playingUri.uri; - const claim = makeSelectClaimForUri(playingUrl)(state); + const claim = selectClaimForUri(state, playingUrl); const url = claim && claim.permanent_url; const loopList = selectListLoop(state); const loop = loopList && loopList.collectionId === props.id && loopList.loop; @@ -24,7 +24,7 @@ const select = (state, props) => { collection: makeSelectCollectionForId(props.id)(state), collectionUrls: makeSelectUrlsForCollectionId(props.id)(state), collectionName: makeSelectNameForCollectionId(props.id)(state), - isMine: makeSelectClaimIsMine(url)(state), + isMine: selectClaimIsMine(state, claim), loop, shuffle, }; diff --git a/ui/component/collectionPreviewOverlay/index.js b/ui/component/collectionPreviewOverlay/index.js index 8c04f7020..caee0c5c9 100644 --- a/ui/component/collectionPreviewOverlay/index.js +++ b/ui/component/collectionPreviewOverlay/index.js @@ -1,5 +1,5 @@ import { connect } from 'react-redux'; -import { makeSelectIsUriResolving, makeSelectClaimIdForUri, makeSelectClaimForClaimId } from 'redux/selectors/claims'; +import { makeSelectIsUriResolving, selectClaimIdForUri, makeSelectClaimForClaimId } from 'redux/selectors/claims'; import { makeSelectUrlsForCollectionId, makeSelectNameForCollectionId, @@ -10,7 +10,7 @@ import { doFetchItemsInCollection } from 'redux/actions/collections'; import CollectionPreviewOverlay from './view'; const select = (state, props) => { - const collectionId = props.collectionId || (props.uri && makeSelectClaimIdForUri(props.uri)(state)); + const collectionId = props.collectionId || (props.uri && selectClaimIdForUri(state, props.uri)); const claim = props.collectionId && makeSelectClaimForClaimId(props.collectionId)(state); const collectionUri = props.uri || (claim && (claim.canonical_url || claim.permanent_url)) || null; diff --git a/ui/component/collectionPreviewTile/index.js b/ui/component/collectionPreviewTile/index.js index c3a5cc65b..706cd974d 100644 --- a/ui/component/collectionPreviewTile/index.js +++ b/ui/component/collectionPreviewTile/index.js @@ -5,7 +5,7 @@ import { makeSelectTitleForUri, makeSelectChannelForClaimUri, makeSelectClaimIsNsfw, - makeSelectClaimIdForUri, + selectClaimIdForUri, makeSelectClaimForClaimId, } from 'redux/selectors/claims'; import { @@ -24,7 +24,7 @@ import { selectShowMatureContent } from 'redux/selectors/settings'; import CollectionPreviewTile from './view'; const select = (state, props) => { - const collectionId = props.collectionId || (props.uri && makeSelectClaimIdForUri(props.uri)(state)); + const collectionId = props.collectionId || (props.uri && selectClaimIdForUri(state, props.uri)); const claim = props.collectionId && makeSelectClaimForClaimId(props.collectionId)(state); const collectionUri = props.uri || (claim && (claim.canonical_url || claim.permanent_url)) || null; diff --git a/ui/component/comment/index.js b/ui/component/comment/index.js index ffe06dd37..b5c336522 100644 --- a/ui/component/comment/index.js +++ b/ui/component/comment/index.js @@ -1,6 +1,6 @@ import { connect } from 'react-redux'; import { - makeSelectStakedLevelForChannelUri, + selectTotalStakedAmountForChannelUri, makeSelectClaimForUri, makeSelectThumbnailForUri, selectMyChannelClaims, @@ -33,7 +33,7 @@ const select = (state, props) => { activeChannelClaim, myChannels: selectMyChannelClaims(state), playingUri: selectPlayingUri(state), - stakedLevel: makeSelectStakedLevelForChannelUri(props.authorUri)(state), + stakedLevel: selectTotalStakedAmountForChannelUri(state, props.authorUri), linkedCommentAncestors: selectLinkedCommentAncestors(state), totalReplyPages: makeSelectTotalReplyPagesForParentId(props.commentId)(state), }; diff --git a/ui/component/commentCreate/index.js b/ui/component/commentCreate/index.js index 61d209e5d..ff760c3e3 100644 --- a/ui/component/commentCreate/index.js +++ b/ui/component/commentCreate/index.js @@ -1,8 +1,8 @@ import { connect } from 'react-redux'; import { - makeSelectClaimForUri, - makeSelectClaimIsMine, - selectMyChannelClaims, + selectClaimForUri, + selectClaimIsMine, + selectHasChannels, selectFetchingMyChannels, makeSelectTagInClaimOrChannelForUri, } from 'redux/selectors/claims'; @@ -14,15 +14,18 @@ import { CommentCreate } from './view'; import { doToast } from 'redux/actions/notifications'; import { DISABLE_SUPPORT_TAG } from 'constants/tags'; -const select = (state, props) => ({ - claim: makeSelectClaimForUri(props.uri)(state), - channels: selectMyChannelClaims(state), - isFetchingChannels: selectFetchingMyChannels(state), - activeChannelClaim: selectActiveChannelClaim(state), - claimIsMine: makeSelectClaimIsMine(props.uri)(state), - settingsByChannelId: selectSettingsByChannelId(state), - supportDisabled: makeSelectTagInClaimOrChannelForUri(props.uri, DISABLE_SUPPORT_TAG)(state), -}); +const select = (state, props) => { + const claim = selectClaimForUri(state, props.uri); + return { + activeChannelClaim: selectActiveChannelClaim(state), + hasChannels: selectHasChannels(state), + claim, + claimIsMine: selectClaimIsMine(state, claim), + isFetchingChannels: selectFetchingMyChannels(state), + settingsByChannelId: selectSettingsByChannelId(state), + supportDisabled: makeSelectTagInClaimOrChannelForUri(props.uri, DISABLE_SUPPORT_TAG)(state), + }; +}; const perform = (dispatch, ownProps) => ({ createComment: (comment, claimId, parentId, txid, payment_intent_id, environment) => diff --git a/ui/component/commentMenuList/index.js b/ui/component/commentMenuList/index.js index 62ddf4c8b..ce91b592d 100644 --- a/ui/component/commentMenuList/index.js +++ b/ui/component/commentMenuList/index.js @@ -4,24 +4,22 @@ import { doCommentPin, doCommentModAddDelegate } from 'redux/actions/comments'; import { doOpenModal } from 'redux/actions/app'; import { doSetPlayingUri } from 'redux/actions/content'; import { doToast } from 'redux/actions/notifications'; -import { - makeSelectChannelPermUrlForClaimUri, - makeSelectClaimIsMine, - makeSelectClaimForUri, -} from 'redux/selectors/claims'; +import { selectClaimIsMine, selectClaimForUri } from 'redux/selectors/claims'; import { selectActiveChannelClaim } from 'redux/selectors/app'; import { selectModerationDelegatorsById } from 'redux/selectors/comments'; import { selectPlayingUri } from 'redux/selectors/content'; import CommentMenuList from './view'; -const select = (state, props) => ({ - claim: makeSelectClaimForUri(props.uri)(state), - claimIsMine: makeSelectClaimIsMine(props.uri)(state), - contentChannelPermanentUrl: makeSelectChannelPermUrlForClaimUri(props.uri)(state), - activeChannelClaim: selectActiveChannelClaim(state), - playingUri: selectPlayingUri(state), - moderationDelegatorsById: selectModerationDelegatorsById(state), -}); +const select = (state, props) => { + const claim = selectClaimForUri(state, props.uri); + return { + claim, + claimIsMine: selectClaimIsMine(state, claim), + activeChannelClaim: selectActiveChannelClaim(state), + playingUri: selectPlayingUri(state), + moderationDelegatorsById: selectModerationDelegatorsById(state), + }; +}; const perform = (dispatch) => ({ openModal: (modal, props) => dispatch(doOpenModal(modal, props)), diff --git a/ui/component/commentReactions/index.js b/ui/component/commentReactions/index.js index b2de27008..86dfcdd4f 100644 --- a/ui/component/commentReactions/index.js +++ b/ui/component/commentReactions/index.js @@ -1,6 +1,6 @@ import { connect } from 'react-redux'; import Comment from './view'; -import { makeSelectClaimIsMine, makeSelectClaimForUri } from 'redux/selectors/claims'; +import { selectClaimIsMine, selectClaimForUri } from 'redux/selectors/claims'; import { doResolveUri } from 'redux/actions/claims'; import { doToast } from 'redux/actions/notifications'; import { selectMyReactsForComment, selectOthersReactsForComment } from 'redux/selectors/comments'; @@ -11,10 +11,11 @@ const select = (state, props) => { const activeChannelClaim = selectActiveChannelClaim(state); const activeChannelId = activeChannelClaim && activeChannelClaim.claim_id; const reactionKey = activeChannelId ? `${props.commentId}:${activeChannelId}` : props.commentId; + const claim = selectClaimForUri(state, props.uri); return { - claim: makeSelectClaimForUri(props.uri)(state), - claimIsMine: makeSelectClaimIsMine(props.uri)(state), + claim, + claimIsMine: selectClaimIsMine(state, claim), myReacts: selectMyReactsForComment(state, reactionKey), othersReacts: selectOthersReactsForComment(state, reactionKey), activeChannelId, diff --git a/ui/component/commentsList/index.js b/ui/component/commentsList/index.js index 4b09b9b4f..53712cf93 100644 --- a/ui/component/commentsList/index.js +++ b/ui/component/commentsList/index.js @@ -1,10 +1,11 @@ import { connect } from 'react-redux'; import { doResolveUris } from 'redux/actions/claims'; import { + selectClaimForUri, makeSelectClaimForUri, - makeSelectClaimIsMine, + selectClaimIsMine, selectFetchingMyChannels, - selectMyChannelClaims, + selectMyClaimIdsRaw, } from 'redux/selectors/claims'; import { selectTopLevelCommentsForUri, @@ -15,7 +16,7 @@ import { makeSelectTotalCommentsCountForUri, selectOthersReacts, selectMyReacts, - makeSelectCommentIdsForUri, + selectCommentIdsForUri, selectSettingsByChannelId, selectPinnedCommentsForUri, } from 'redux/selectors/comments'; @@ -24,6 +25,7 @@ import { selectActiveChannelClaim } from 'redux/selectors/app'; import CommentsList from './view'; const select = (state, props) => { + const claim = selectClaimForUri(state, props.uri); const activeChannelClaim = selectActiveChannelClaim(state); const topLevelComments = selectTopLevelCommentsForUri(state, props.uri); @@ -35,13 +37,13 @@ const select = (state, props) => { return { topLevelComments, resolvedComments, - myChannels: selectMyChannelClaims(state), - allCommentIds: makeSelectCommentIdsForUri(props.uri)(state), + myChannelIds: selectMyClaimIdsRaw(state), + allCommentIds: selectCommentIdsForUri(state, props.uri), pinnedComments: selectPinnedCommentsForUri(state, props.uri), topLevelTotalPages: makeSelectTopLevelTotalPagesForUri(props.uri)(state), totalComments: makeSelectTotalCommentsCountForUri(props.uri)(state), - claim: makeSelectClaimForUri(props.uri)(state), - claimIsMine: makeSelectClaimIsMine(props.uri)(state), + claim, + claimIsMine: selectClaimIsMine(state, claim), isFetchingComments: selectIsFetchingComments(state), isFetchingCommentsById: selectIsFetchingCommentsById(state), isFetchingReacts: selectIsFetchingReacts(state), diff --git a/ui/component/fileActions/index.js b/ui/component/fileActions/index.js index 3fe529ce9..78d76d263 100644 --- a/ui/component/fileActions/index.js +++ b/ui/component/fileActions/index.js @@ -1,8 +1,8 @@ import { connect } from 'react-redux'; import { - makeSelectClaimIsMine, - makeSelectClaimForUri, - selectMyChannelClaims, + selectClaimIsMine, + selectClaimForUri, + selectHasChannels, makeSelectTagInClaimOrChannelForUri, } from 'redux/selectors/claims'; import { makeSelectStreamingUrlForUri, makeSelectFileInfoForUri } from 'redux/selectors/file_info'; @@ -16,16 +16,20 @@ import fs from 'fs'; import FileActions from './view'; import { makeSelectFileRenderModeForUri } from 'redux/selectors/content'; -const select = (state, props) => ({ - claim: makeSelectClaimForUri(props.uri)(state), - claimIsMine: makeSelectClaimIsMine(props.uri)(state), - fileInfo: makeSelectFileInfoForUri(props.uri)(state), - renderMode: makeSelectFileRenderModeForUri(props.uri)(state), - costInfo: makeSelectCostInfoForUri(props.uri)(state), - myChannels: selectMyChannelClaims(state), - reactionsDisabled: makeSelectTagInClaimOrChannelForUri(props.uri, DISABLE_COMMENTS_TAG)(state), - streamingUrl: makeSelectStreamingUrlForUri(props.uri)(state), -}); +const select = (state, props) => { + const claim = selectClaimForUri(state, props.uri); + + return { + claim, + claimIsMine: selectClaimIsMine(state, claim), + fileInfo: makeSelectFileInfoForUri(props.uri)(state), + renderMode: makeSelectFileRenderModeForUri(props.uri)(state), + costInfo: makeSelectCostInfoForUri(props.uri)(state), + hasChannels: selectHasChannels(state), + reactionsDisabled: makeSelectTagInClaimOrChannelForUri(props.uri, DISABLE_COMMENTS_TAG)(state), + streamingUrl: makeSelectStreamingUrlForUri(props.uri)(state), + }; +}; const perform = (dispatch) => ({ openModal: (modal, props) => dispatch(doOpenModal(modal, props)), diff --git a/ui/component/fileDescription/index.js b/ui/component/fileDescription/index.js index 5004b7220..d8a119c37 100644 --- a/ui/component/fileDescription/index.js +++ b/ui/component/fileDescription/index.js @@ -1,23 +1,27 @@ import { connect } from 'react-redux'; import { - makeSelectClaimForUri, + selectClaimForUri, makeSelectMetadataForUri, + selectClaimIsMine, makeSelectTagsForUri, - makeSelectClaimIsMine, } from 'redux/selectors/claims'; import { makeSelectPendingAmountByUri } from 'redux/selectors/wallet'; import { doOpenModal } from 'redux/actions/app'; import { selectUser } from 'redux/selectors/user'; import FileDescription from './view'; -const select = (state, props) => ({ - claim: makeSelectClaimForUri(props.uri)(state), - claimIsMine: makeSelectClaimIsMine(props.uri)(state), - metadata: makeSelectMetadataForUri(props.uri)(state), - user: selectUser(state), - tags: makeSelectTagsForUri(props.uri)(state), - pendingAmount: makeSelectPendingAmountByUri(props.uri)(state), -}); +const select = (state, props) => { + const claim = selectClaimForUri(state, props.uri); + + return { + claim, + claimIsMine: selectClaimIsMine(state, claim), + metadata: makeSelectMetadataForUri(props.uri)(state), + user: selectUser(state), + pendingAmount: makeSelectPendingAmountByUri(props.uri)(state), + tags: makeSelectTagsForUri(props.uri)(state), + }; +}; export default connect(select, { doOpenModal, diff --git a/ui/component/fileDownloadLink/index.js b/ui/component/fileDownloadLink/index.js index 41e32d044..bf4ad34d3 100644 --- a/ui/component/fileDownloadLink/index.js +++ b/ui/component/fileDownloadLink/index.js @@ -1,5 +1,5 @@ import { connect } from 'react-redux'; -import { makeSelectClaimIsMine, makeSelectClaimForUri, makeSelectClaimWasPurchased } from 'redux/selectors/claims'; +import { selectClaimIsMine, selectClaimForUri, makeSelectClaimWasPurchased } from 'redux/selectors/claims'; import { makeSelectFileInfoForUri, makeSelectDownloadingForUri, @@ -11,16 +11,20 @@ import { doOpenModal, doAnalyticsView } from 'redux/actions/app'; import { doSetPlayingUri, doPlayUri } from 'redux/actions/content'; import FileDownloadLink from './view'; -const select = (state, props) => ({ - fileInfo: makeSelectFileInfoForUri(props.uri)(state), - downloading: makeSelectDownloadingForUri(props.uri)(state), - loading: makeSelectLoadingForUri(props.uri)(state), - claimIsMine: makeSelectClaimIsMine(props.uri)(state), - claim: makeSelectClaimForUri(props.uri)(state), - costInfo: makeSelectCostInfoForUri(props.uri)(state), - claimWasPurchased: makeSelectClaimWasPurchased(props.uri)(state), - streamingUrl: makeSelectStreamingUrlForUri(props.uri)(state), -}); +const select = (state, props) => { + const claim = selectClaimForUri(state, props.uri); + + return { + fileInfo: makeSelectFileInfoForUri(props.uri)(state), + downloading: makeSelectDownloadingForUri(props.uri)(state), + loading: makeSelectLoadingForUri(props.uri)(state), + claimIsMine: selectClaimIsMine(state, claim), + claim, + costInfo: makeSelectCostInfoForUri(props.uri)(state), + claimWasPurchased: makeSelectClaimWasPurchased(props.uri)(state), + streamingUrl: makeSelectStreamingUrlForUri(props.uri)(state), + }; +}; const perform = (dispatch) => ({ openModal: (modal, props) => dispatch(doOpenModal(modal, props)), diff --git a/ui/component/filePrice/index.js b/ui/component/filePrice/index.js index d795184c5..560f38b96 100644 --- a/ui/component/filePrice/index.js +++ b/ui/component/filePrice/index.js @@ -1,18 +1,18 @@ import { connect } from 'react-redux'; -import { makeSelectClaimForUri, makeSelectClaimWasPurchased, makeSelectClaimIsMine } from 'redux/selectors/claims'; +import { selectClaimForUri, makeSelectClaimWasPurchased, selectClaimIsMine } from 'redux/selectors/claims'; import { makeSelectCostInfoForUri, doFetchCostInfoForUri, makeSelectFetchingCostInfoForUri } from 'lbryinc'; import FilePrice from './view'; -const select = (state, props) => ({ - costInfo: makeSelectCostInfoForUri(props.uri)(state), - fetching: makeSelectFetchingCostInfoForUri(props.uri)(state), - claim: makeSelectClaimForUri(props.uri)(state), - claimWasPurchased: makeSelectClaimWasPurchased(props.uri)(state), - claimIsMine: makeSelectClaimIsMine(props.uri)(state), -}); +const select = (state, props) => { + const claim = selectClaimForUri(state, props.uri); -const perform = (dispatch) => ({ - fetchCostInfo: (uri) => dispatch(doFetchCostInfoForUri(uri)), -}); + return { + claim, + claimIsMine: selectClaimIsMine(state, claim), + claimWasPurchased: makeSelectClaimWasPurchased(props.uri)(state), + costInfo: makeSelectCostInfoForUri(props.uri)(state), + fetching: makeSelectFetchingCostInfoForUri(props.uri)(state), + }; +}; -export default connect(select, perform)(FilePrice); +export default connect(select, { doFetchCostInfoForUri })(FilePrice); diff --git a/ui/component/filePrice/view.jsx b/ui/component/filePrice/view.jsx index 3f9b1f626..352064d80 100644 --- a/ui/component/filePrice/view.jsx +++ b/ui/component/filePrice/view.jsx @@ -8,7 +8,7 @@ import Icon from 'component/common/icon'; type Props = { showFullPrice: boolean, costInfo: ?{ includesData: boolean, cost: number }, - fetchCostInfo: string => void, + doFetchCostInfoForUri: (string) => void, uri: string, fetching: boolean, claim: ?{}, @@ -35,10 +35,10 @@ class FilePrice extends React.PureComponent { } fetchCost = (props: Props) => { - const { costInfo, fetchCostInfo, uri, fetching, claim } = props; + const { costInfo, doFetchCostInfoForUri, uri, fetching, claim } = props; if (costInfo === undefined && !fetching && claim) { - fetchCostInfo(uri); + doFetchCostInfoForUri(uri); } }; diff --git a/ui/component/fileTitleSection/index.js b/ui/component/fileTitleSection/index.js index 0e9f3a4f9..b012111f5 100644 --- a/ui/component/fileTitleSection/index.js +++ b/ui/component/fileTitleSection/index.js @@ -1,5 +1,5 @@ import { connect } from 'react-redux'; -import { doFetchSubCount, makeSelectSubCountForUri } from 'lbryinc'; +import { doFetchSubCount, selectSubCountForUri } from 'lbryinc'; import { makeSelectTitleForUri, makeSelectClaimForUri } from 'redux/selectors/claims'; import { makeSelectInsufficientCreditsForUri } from 'redux/selectors/content'; import FileTitleSection from './view'; @@ -8,7 +8,7 @@ const select = (state, props) => { const claim = makeSelectClaimForUri(props.uri)(state); const channelClaimId = claim && claim.signing_channel ? claim.signing_channel.claim_id : undefined; const channelUri = claim && claim.signing_channel ? claim.signing_channel.canonical_url : undefined; - const subCount = channelUri && makeSelectSubCountForUri(channelUri)(state); + const subCount = channelUri && selectSubCountForUri(state, channelUri); return { isInsufficientCredits: makeSelectInsufficientCreditsForUri(props.uri)(state), diff --git a/ui/component/fileValues/index.js b/ui/component/fileValues/index.js index 8fe82ba56..a3994d7c3 100644 --- a/ui/component/fileValues/index.js +++ b/ui/component/fileValues/index.js @@ -1,9 +1,9 @@ import { connect } from 'react-redux'; import { - makeSelectClaimForUri, + selectClaimForUri, makeSelectContentTypeForUri, makeSelectMetadataForUri, - makeSelectClaimIsMine, + selectClaimIsMine, } from 'redux/selectors/claims'; import { makeSelectPendingAmountByUri } from 'redux/selectors/wallet'; import { makeSelectFileInfoForUri } from 'redux/selectors/file_info'; @@ -12,15 +12,19 @@ import { doOpenModal } from 'redux/actions/app'; import FileValues from './view'; -const select = (state, props) => ({ - claim: makeSelectClaimForUri(props.uri)(state), - contentType: makeSelectContentTypeForUri(props.uri)(state), - fileInfo: makeSelectFileInfoForUri(props.uri)(state), - metadata: makeSelectMetadataForUri(props.uri)(state), - user: selectUser(state), - pendingAmount: makeSelectPendingAmountByUri(props.uri)(state), - claimIsMine: makeSelectClaimIsMine(props.uri)(state), -}); +const select = (state, props) => { + const claim = selectClaimForUri(state, props.uri); + + return { + claim, + contentType: makeSelectContentTypeForUri(props.uri)(state), + fileInfo: makeSelectFileInfoForUri(props.uri)(state), + metadata: makeSelectMetadataForUri(props.uri)(state), + user: selectUser(state), + pendingAmount: makeSelectPendingAmountByUri(props.uri)(state), + claimIsMine: selectClaimIsMine(state, claim), + }; +}; const perform = (dispatch) => ({ openModal: (modal, props) => dispatch(doOpenModal(modal, props)), diff --git a/ui/component/fileViewCount/index.js b/ui/component/fileViewCount/index.js index e4c5e64d5..d1cec539a 100644 --- a/ui/component/fileViewCount/index.js +++ b/ui/component/fileViewCount/index.js @@ -1,12 +1,12 @@ import { connect } from 'react-redux'; -import { makeSelectClaimForUri } from 'redux/selectors/claims'; -import { doFetchViewCount, makeSelectViewCountForUri } from 'lbryinc'; +import { selectClaimForUri } from 'redux/selectors/claims'; +import { doFetchViewCount, selectViewCountForUri } from 'lbryinc'; import { doAnalyticsView } from 'redux/actions/app'; import FileViewCount from './view'; const select = (state, props) => ({ - claim: makeSelectClaimForUri(props.uri)(state), - viewCount: makeSelectViewCountForUri(props.uri)(state), + claim: selectClaimForUri(state, props.uri), + viewCount: selectViewCountForUri(state, props.uri), }); const perform = (dispatch) => ({ diff --git a/ui/component/fileViewCountInline/index.js b/ui/component/fileViewCountInline/index.js index 0f9f2c1e6..36fdabf98 100644 --- a/ui/component/fileViewCountInline/index.js +++ b/ui/component/fileViewCountInline/index.js @@ -1,13 +1,13 @@ import { connect } from 'react-redux'; -import { makeSelectClaimForUri } from 'redux/selectors/claims'; -import { makeSelectViewCountForUri } from 'lbryinc'; +import { selectClaimForUri } from 'redux/selectors/claims'; +import { selectViewCountForUri } from 'lbryinc'; import { selectLanguage } from 'redux/selectors/settings'; import FileViewCountInline from './view'; const select = (state, props) => { return { - claim: makeSelectClaimForUri(props.uri)(state), - viewCount: makeSelectViewCountForUri(props.uri)(state), + claim: selectClaimForUri(state, props.uri), + viewCount: selectViewCountForUri(state, props.uri), lang: selectLanguage(state), }; }; diff --git a/ui/component/previewLink/index.js b/ui/component/previewLink/index.js index 17493a0ed..9d93d2c63 100644 --- a/ui/component/previewLink/index.js +++ b/ui/component/previewLink/index.js @@ -1,9 +1,9 @@ import { connect } from 'react-redux'; import { - makeSelectClaimIsMine, + selectClaimIsMine, makeSelectTitleForUri, makeSelectThumbnailForUri, - makeSelectClaimForUri, + selectClaimForUri, makeSelectIsUriResolving, makeSelectMetadataItemForUri, } from 'redux/selectors/claims'; @@ -12,13 +12,15 @@ import { selectBlackListedOutpoints } from 'lbryinc'; import PreviewLink from './view'; const select = (state, props) => { + const claim = selectClaimForUri(state, props.uri); + return { uri: props.uri, - claim: makeSelectClaimForUri(props.uri)(state), + claim, title: makeSelectTitleForUri(props.uri)(state), thumbnail: makeSelectThumbnailForUri(props.uri)(state), description: makeSelectMetadataItemForUri(props.uri, 'description')(state), - channelIsMine: makeSelectClaimIsMine(props.uri)(state), + channelIsMine: selectClaimIsMine(state, claim), isResolvingUri: makeSelectIsUriResolving(props.uri)(state), blackListedOutpoints: selectBlackListedOutpoints(state), }; diff --git a/ui/component/previewOverlayProperties/index.js b/ui/component/previewOverlayProperties/index.js index 622fb642b..aa0938a0c 100644 --- a/ui/component/previewOverlayProperties/index.js +++ b/ui/component/previewOverlayProperties/index.js @@ -1,19 +1,20 @@ import { connect } from 'react-redux'; -import { makeSelectClaimIsMine, makeSelectClaimForUri } from 'redux/selectors/claims'; +import { selectClaimIsMine, selectClaimForUri } from 'redux/selectors/claims'; import { makeSelectFilePartlyDownloaded } from 'redux/selectors/file_info'; import { makeSelectEditedCollectionForId } from 'redux/selectors/collections'; import { makeSelectIsSubscribed } from 'redux/selectors/subscriptions'; import PreviewOverlayProperties from './view'; const select = (state, props) => { - const claim = makeSelectClaimForUri(props.uri)(state); + const claim = selectClaimForUri(state, props.uri); const claimId = claim && claim.claim_id; + return { claim, editedCollection: makeSelectEditedCollectionForId(claimId)(state), downloaded: makeSelectFilePartlyDownloaded(props.uri)(state), isSubscribed: makeSelectIsSubscribed(props.uri)(state), - claimIsMine: makeSelectClaimIsMine(props.uri)(state), + claimIsMine: selectClaimIsMine(state, claim), }; }; diff --git a/ui/modal/modalConfirmTransaction/index.js b/ui/modal/modalConfirmTransaction/index.js index c59a746dd..5a5493099 100644 --- a/ui/modal/modalConfirmTransaction/index.js +++ b/ui/modal/modalConfirmTransaction/index.js @@ -1,12 +1,12 @@ import { connect } from 'react-redux'; import { doSendDraftTransaction, doSendTip } from 'redux/actions/wallet'; -import { makeSelectClaimForUri } from 'redux/selectors/claims'; +import { selectClaimForUri } from 'redux/selectors/claims'; import { doHideModal } from 'redux/actions/app'; import ModalConfirmTransaction from './view'; import { selectActiveChannelClaim, selectIncognito } from 'redux/selectors/app'; const select = (state, props) => ({ - claim: makeSelectClaimForUri(props.destination)(state), + claim: selectClaimForUri(state, props.destination)(state), activeChannelClaim: selectActiveChannelClaim(state), incognito: selectIncognito(state), }); diff --git a/ui/modal/modalRemoveFile/index.js b/ui/modal/modalRemoveFile/index.js index bc0fdd321..2a9228f39 100644 --- a/ui/modal/modalRemoveFile/index.js +++ b/ui/modal/modalRemoveFile/index.js @@ -2,7 +2,7 @@ import { connect } from 'react-redux'; import { doDeleteFileAndMaybeGoBack } from 'redux/actions/file'; import { makeSelectTitleForUri, - makeSelectClaimForUri, + selectClaimForUri, makeSelectIsAbandoningClaimForUri, makeSelectClaimIsMine, } from 'redux/selectors/claims'; @@ -13,7 +13,7 @@ import ModalRemoveFile from './view'; const select = (state, props) => ({ claimIsMine: makeSelectClaimIsMine(props.uri)(state), title: makeSelectTitleForUri(props.uri)(state), - claim: makeSelectClaimForUri(props.uri)(state), + claim: selectClaimForUri(state, props.uri), isAbandoning: makeSelectIsAbandoningClaimForUri(props.uri)(state), }); diff --git a/ui/page/channel/index.js b/ui/page/channel/index.js index 049d0f0ea..4576586d3 100644 --- a/ui/page/channel/index.js +++ b/ui/page/channel/index.js @@ -1,15 +1,15 @@ import { connect } from 'react-redux'; import { - makeSelectClaimIsMine, + selectClaimIsMine, makeSelectTitleForUri, makeSelectThumbnailForUri, makeSelectCoverForUri, selectCurrentChannelPage, - makeSelectClaimForUri, + selectClaimForUri, makeSelectClaimIsPending, } from 'redux/selectors/claims'; import { selectMyUnpublishedCollections } from 'redux/selectors/collections'; -import { selectBlackListedOutpoints, doFetchSubCount, makeSelectSubCountForUri } from 'lbryinc'; +import { selectBlackListedOutpoints, doFetchSubCount, selectSubCountForUri } from 'lbryinc'; // ban state import { selectYoutubeChannels } from 'redux/selectors/user'; import { makeSelectIsSubscribed } from 'redux/selectors/subscriptions'; import { selectModerationBlockList } from 'redux/selectors/comments'; @@ -17,22 +17,26 @@ import { selectMutedChannels } from 'redux/selectors/blocked'; import { doOpenModal } from 'redux/actions/app'; import ChannelPage from './view'; -const select = (state, props) => ({ - title: makeSelectTitleForUri(props.uri)(state), - thumbnail: makeSelectThumbnailForUri(props.uri)(state), - cover: makeSelectCoverForUri(props.uri)(state), - channelIsMine: makeSelectClaimIsMine(props.uri)(state), - page: selectCurrentChannelPage(state), - claim: makeSelectClaimForUri(props.uri)(state), - isSubscribed: makeSelectIsSubscribed(props.uri, true)(state), - blackListedOutpoints: selectBlackListedOutpoints(state), - subCount: makeSelectSubCountForUri(props.uri)(state), - pending: makeSelectClaimIsPending(props.uri)(state), - youtubeChannels: selectYoutubeChannels(state), - blockedChannels: selectModerationBlockList(state), - mutedChannels: selectMutedChannels(state), - unpublishedCollections: selectMyUnpublishedCollections(state), -}); +const select = (state, props) => { + const claim = selectClaimForUri(state, props.uri); + + return { + title: makeSelectTitleForUri(props.uri)(state), + thumbnail: makeSelectThumbnailForUri(props.uri)(state), + cover: makeSelectCoverForUri(props.uri)(state), + channelIsMine: selectClaimIsMine(state, claim), + page: selectCurrentChannelPage(state), + claim, + isSubscribed: makeSelectIsSubscribed(props.uri, true)(state), + blackListedOutpoints: selectBlackListedOutpoints(state), + subCount: selectSubCountForUri(state, props.uri), + pending: makeSelectClaimIsPending(props.uri)(state), + youtubeChannels: selectYoutubeChannels(state), + blockedChannels: selectModerationBlockList(state), // banlist + mutedChannels: selectMutedChannels(state), + unpublishedCollections: selectMyUnpublishedCollections(state), + }; +}; const perform = (dispatch) => ({ openModal: (modal, props) => dispatch(doOpenModal(modal, props)), diff --git a/ui/page/collection/index.js b/ui/page/collection/index.js index b6705e674..62585eafe 100644 --- a/ui/page/collection/index.js +++ b/ui/page/collection/index.js @@ -5,7 +5,7 @@ import CollectionPage from './view'; import { makeSelectTitleForUri, makeSelectThumbnailForUri, - makeSelectClaimIsMine, + selectClaimIsMine, makeSelectClaimIsPending, makeSelectClaimForClaimId, makeSelectChannelForClaimUri, @@ -20,11 +20,7 @@ import { makeSelectEditedCollectionForId, } from 'redux/selectors/collections'; -import { - doFetchItemsInCollection, - doCollectionDelete, - doCollectionEdit, -} from 'redux/actions/collections'; +import { doFetchItemsInCollection, doCollectionDelete, doCollectionEdit } from 'redux/actions/collections'; import { selectUser } from 'redux/selectors/user'; const select = (state, props) => { @@ -44,7 +40,7 @@ const select = (state, props) => { isResolvingCollection: makeSelectIsResolvingCollectionForId(collectionId)(state), title: makeSelectTitleForUri(uri)(state), thumbnail: makeSelectThumbnailForUri(uri)(state), - isMyClaim: makeSelectClaimIsMine(uri)(state), // or collection is mine? + isMyClaim: selectClaimIsMine(state, claim), // or collection is mine? isMyCollection: makeSelectCollectionIsMine(collectionId)(state), claimIsPending: makeSelectClaimIsPending(uri)(state), collectionHasEdits: Boolean(makeSelectEditedCollectionForId(collectionId)(state)), diff --git a/ui/page/discover/index.js b/ui/page/discover/index.js index 0d0823b74..55890537e 100644 --- a/ui/page/discover/index.js +++ b/ui/page/discover/index.js @@ -1,7 +1,7 @@ import * as CS from 'constants/claim_search'; import { connect } from 'react-redux'; import { doResolveUri } from 'redux/actions/claims'; -import { makeSelectClaimForUri } from 'redux/selectors/claims'; +import { selectClaimForUri } from 'redux/selectors/claims'; import * as SETTINGS from 'constants/settings'; import { selectUserVerifiedEmail } from 'redux/selectors/user'; import { selectFollowedTags } from 'redux/selectors/tags'; @@ -17,7 +17,7 @@ const select = (state, props) => { return { followedTags: selectFollowedTags(state), repostedUri: repostedUri, - repostedClaim: repostedUri ? makeSelectClaimForUri(repostedUri)(state) : null, + repostedClaim: repostedUri ? selectClaimForUri(state, repostedUri) : null, isAuthenticated: selectUserVerifiedEmail(state), tileLayout: makeSelectClientSetting(SETTINGS.TILE_LAYOUT)(state), }; diff --git a/ui/page/show/index.js b/ui/page/show/index.js index 5f1ca151d..8c174e058 100644 --- a/ui/page/show/index.js +++ b/ui/page/show/index.js @@ -4,11 +4,11 @@ import { connect } from 'react-redux'; import { withRouter } from 'react-router'; import { PAGE_SIZE } from 'constants/claim'; import { - makeSelectClaimForUri, + selectClaimForUri, makeSelectIsUriResolving, makeSelectTotalPagesForChannel, makeSelectTitleForUri, - makeSelectClaimIsMine, + selectClaimIsMine, makeSelectClaimIsPending, } from 'redux/selectors/claims'; import { @@ -62,7 +62,7 @@ const select = (state, props) => { props.history.replace(`/${path.slice(0, match.index)}`); } } - const claim = makeSelectClaimForUri(uri)(state); + const claim = selectClaimForUri(state, uri); const collectionId = urlParams.get(COLLECTIONS_CONSTS.COLLECTION_ID) || (claim && claim.value_type === 'collection' && claim.claim_id) || @@ -76,7 +76,7 @@ const select = (state, props) => { totalPages: makeSelectTotalPagesForChannel(uri, PAGE_SIZE)(state), isSubscribed: makeSelectChannelInSubscriptions(uri)(state), title: makeSelectTitleForUri(uri)(state), - claimIsMine: makeSelectClaimIsMine(uri)(state), + claimIsMine: selectClaimIsMine(state, claim), claimIsPending: makeSelectClaimIsPending(uri)(state), collection: makeSelectCollectionForId(collectionId)(state), collectionId: collectionId, diff --git a/ui/redux/actions/app.js b/ui/redux/actions/app.js index 84da06b75..3420c9b69 100644 --- a/ui/redux/actions/app.js +++ b/ui/redux/actions/app.js @@ -9,7 +9,7 @@ import * as SHARED_PREFERENCES from 'constants/shared_preferences'; import { DOMAIN } from 'config'; import Lbry from 'lbry'; import { doFetchChannelListMine, doFetchCollectionListMine, doCheckPendingClaims } from 'redux/actions/claims'; -import { makeSelectClaimForUri, makeSelectClaimIsMine, selectMyChannelClaims } from 'redux/selectors/claims'; +import { selectClaimForUri, selectClaimIsMineForUri, selectMyChannelClaims } from 'redux/selectors/claims'; import { doFetchFileInfos } from 'redux/actions/file_info'; import { doClearSupport, doBalanceSubscribe } from 'redux/actions/wallet'; import { doClearPublish } from 'redux/actions/publish'; @@ -434,8 +434,9 @@ export function doToggleSearchExpanded() { export function doAnalyticsView(uri, timeToStart) { return (dispatch, getState) => { const state = getState(); - const { txid, nout, claim_id: claimId } = makeSelectClaimForUri(uri)(state); - const claimIsMine = makeSelectClaimIsMine(uri)(state); + const claim = selectClaimForUri(state, uri); + const { txid, nout, claim_id: claimId } = claim; + const claimIsMine = selectClaimIsMineForUri(state, claim); const outpoint = `${txid}:${nout}`; if (claimIsMine) { @@ -449,13 +450,13 @@ export function doAnalyticsView(uri, timeToStart) { export function doAnalyticsBuffer(uri, bufferData) { return (dispatch, getState) => { const state = getState(); - const claim = makeSelectClaimForUri(uri)(state); + const claim = selectClaimForUri(state, uri); const user = selectUser(state); const { value: { video, audio, source }, } = claim; - const timeAtBuffer = parseInt(bufferData.currentTime * 1000); - const bufferDuration = parseInt(bufferData.secondsToLoad * 1000); + const timeAtBuffer = parseInt(bufferData.currentTime ? bufferData.currentTime * 1000 : 0); + const bufferDuration = parseInt(bufferData.secondsToLoad ? bufferData.secondsToLoad * 1000 : 0); const fileDurationInSeconds = (video && video.duration) || (audio && audio.duration); const fileSize = source.size; // size in bytes const fileSizeInBits = fileSize * 8; @@ -501,7 +502,7 @@ export function doSignIn() { return (dispatch, getState) => { const state = getState(); const user = selectUser(state); - const notificationsEnabled = user.experimental_ui; // what is notifications? + const notificationsEnabled = user.experimental_ui; dispatch(doNotificationSocketConnect(notificationsEnabled)); diff --git a/ui/redux/actions/content.js b/ui/redux/actions/content.js index 045987665..f8d593082 100644 --- a/ui/redux/actions/content.js +++ b/ui/redux/actions/content.js @@ -5,7 +5,12 @@ import * as MODALS from 'constants/modal_types'; import { ipcRenderer } from 'electron'; // @endif import { doOpenModal } from 'redux/actions/app'; -import { makeSelectClaimForUri, makeSelectClaimIsMine, makeSelectClaimWasPurchased } from 'redux/selectors/claims'; +import { + makeSelectClaimForUri, + selectClaimForUri, + makeSelectClaimIsMine, + makeSelectClaimWasPurchased, +} from 'redux/selectors/claims'; import { makeSelectFileInfoForUri, selectFileInfosByOutpoint, @@ -216,7 +221,7 @@ export function doPlayUri( export function savePosition(uri: string, position: number) { return (dispatch: Dispatch, getState: () => any) => { const state = getState(); - const claim = makeSelectClaimForUri(uri)(state); + const claim = selectClaimForUri(state, uri)(state); const { claim_id: claimId, txid, nout } = claim; const outpoint = `${txid}:${nout}`; diff --git a/ui/redux/actions/file.js b/ui/redux/actions/file.js index 41cf1a2bb..e73177e35 100644 --- a/ui/redux/actions/file.js +++ b/ui/redux/actions/file.js @@ -5,7 +5,7 @@ import * as ABANDON_STATES from 'constants/abandon_states'; import { shell } from 'electron'; // @endif import Lbry from 'lbry'; -import { makeSelectClaimForUri } from 'redux/selectors/claims'; +import { selectClaimForUri } from 'redux/selectors/claims'; import { doAbandonClaim } from 'redux/actions/claims'; import { batchActions } from 'util/batch-actions'; @@ -71,7 +71,7 @@ export function doDeleteFileAndMaybeGoBack( const state = getState(); const playingUri = selectPlayingUri(state); const { outpoint } = makeSelectFileInfoForUri(uri)(state) || ''; - const { nout, txid } = makeSelectClaimForUri(uri)(state); + const { nout, txid } = selectClaimForUri(state, uri); const claimOutpoint = `${txid}:${nout}`; const actions = []; @@ -105,7 +105,7 @@ export function doDeleteFileAndMaybeGoBack( export function doFileGet(uri: string, saveFile: boolean = true, onSuccess?: (GetResponse) => any) { return (dispatch: Dispatch, getState: () => any) => { const state = getState(); - const { nout, txid } = makeSelectClaimForUri(uri)(state); + const { nout, txid } = selectClaimForUri(state, uri); const outpoint = `${txid}:${nout}`; dispatch({ diff --git a/ui/redux/actions/reactions.js b/ui/redux/actions/reactions.js index 51d2ac1a4..8c3d90eb3 100644 --- a/ui/redux/actions/reactions.js +++ b/ui/redux/actions/reactions.js @@ -3,7 +3,7 @@ import { Lbryio } from 'lbryinc'; import * as ACTIONS from 'constants/action_types'; import * as REACTION_TYPES from 'constants/reactions'; import { makeSelectMyReactionForUri } from 'redux/selectors/reactions'; -import { makeSelectClaimForUri } from 'redux/selectors/claims'; +import { selectClaimForUri } from 'redux/selectors/claims'; export const doFetchReactions = (claimId: string) => (dispatch: Dispatch) => { dispatch({ type: ACTIONS.REACTIONS_LIST_STARTED }); @@ -20,7 +20,7 @@ export const doFetchReactions = (claimId: string) => (dispatch: Dispatch) => { export const doReactionLike = (uri: string) => (dispatch: Dispatch, getState: GetState) => { const state = getState(); const myReaction = makeSelectMyReactionForUri(uri)(state); - const claim = makeSelectClaimForUri(uri)(state); + const claim = selectClaimForUri(state, uri); const claimId = claim.claim_id; const shouldRemove = myReaction === REACTION_TYPES.LIKE; @@ -46,7 +46,7 @@ export const doReactionLike = (uri: string) => (dispatch: Dispatch, getState: Ge export const doReactionDislike = (uri: string) => (dispatch: Dispatch, getState: GetState) => { const state = getState(); const myReaction = makeSelectMyReactionForUri(uri)(state); - const claim = makeSelectClaimForUri(uri)(state); + const claim = selectClaimForUri(state, uri); const claimId = claim.claim_id; const shouldRemove = myReaction === REACTION_TYPES.DISLIKE; diff --git a/ui/redux/actions/search.js b/ui/redux/actions/search.js index 2a3de1afe..dfd9c724a 100644 --- a/ui/redux/actions/search.js +++ b/ui/redux/actions/search.js @@ -1,7 +1,7 @@ // @flow import * as ACTIONS from 'constants/action_types'; import { selectShowMatureContent } from 'redux/selectors/settings'; -import { makeSelectClaimForUri, makeSelectClaimIsNsfw } from 'redux/selectors/claims'; +import { selectClaimForUri, makeSelectClaimIsNsfw } from 'redux/selectors/claims'; import { doResolveUris } from 'redux/actions/claims'; import { buildURI, isURIValid } from 'util/lbryURI'; import { batchActions } from 'util/batch-actions'; @@ -131,7 +131,7 @@ export const doUpdateSearchOptions = (newOptions: SearchOptions, additionalOptio export const doFetchRecommendedContent = (uri: string) => (dispatch: Dispatch, getState: GetState) => { const state = getState(); - const claim = makeSelectClaimForUri(uri)(state); + const claim = selectClaimForUri(state, uri); const matureEnabled = selectShowMatureContent(state); const claimIsMature = makeSelectClaimIsNsfw(uri)(state); diff --git a/ui/redux/actions/user.js b/ui/redux/actions/user.js index 701c36e5a..0935027d3 100644 --- a/ui/redux/actions/user.js +++ b/ui/redux/actions/user.js @@ -1,5 +1,5 @@ import Lbry from 'lbry'; -import { makeSelectClaimForUri } from 'redux/selectors/claims'; +import { selectClaimForUri } from 'redux/selectors/claims'; import { doFetchChannelListMine } from 'redux/actions/claims'; import { isURIValid, normalizeURI } from 'util/lbryURI'; import { batchActions } from 'util/batch-actions'; @@ -657,7 +657,7 @@ export function doUserSetReferrer(referrer, shouldClaim) { const isValid = isURIValid(referrer); if (isValid) { const uri = normalizeURI(referrer); - claim = makeSelectClaimForUri(uri)(getState()); + claim = selectClaimForUri(getState(), uri); if (!claim) { try { const response = await Lbry.resolve({ urls: [uri] }); diff --git a/ui/redux/selectors/app.js b/ui/redux/selectors/app.js index daea35ac1..aef96c158 100644 --- a/ui/redux/selectors/app.js +++ b/ui/redux/selectors/app.js @@ -1,5 +1,5 @@ import { createSelector } from 'reselect'; -import { selectClaimsById, selectMyChannelClaims, makeSelectStakedLevelForChannelUri } from 'redux/selectors/claims'; +import { selectClaimsById, selectMyChannelClaims, selectTotalStakedAmountForChannelUri } from 'redux/selectors/claims'; export const selectState = (state) => state.app || {}; @@ -127,7 +127,7 @@ export const selectActiveChannelStakedLevel = createSelector( } const uri = activeChannelClaim.permanent_url; - const stakedLevel = makeSelectStakedLevelForChannelUri(uri)(state); + const stakedLevel = selectTotalStakedAmountForChannelUri(state, uri)(state); return stakedLevel; } diff --git a/ui/redux/selectors/claims.js b/ui/redux/selectors/claims.js index 45f12936e..fb986fe1f 100644 --- a/ui/redux/selectors/claims.js +++ b/ui/redux/selectors/claims.js @@ -8,7 +8,7 @@ import * as CLAIM from 'constants/claim'; type State = { claims: any }; -const selectState = (state) => state.claims || {}; +const selectState = (state: State) => state.claims || {}; export const selectById = (state: State) => selectState(state).byId || {}; export const selectPendingClaimsById = (state: State) => selectState(state).pendingById || {}; @@ -18,16 +18,11 @@ export const selectClaimsById = createSelector(selectById, selectPendingClaimsBy }); export const selectClaimIdsByUri = (state: State) => selectState(state).claimsByUri || {}; - -export const selectCurrentChannelPage = createSelector(selectState, (state) => state.currentChannelPage || 1); - -export const selectCreatingChannel = createSelector(selectState, (state) => state.creatingChannel); - -export const selectCreateChannelError = createSelector(selectState, (state) => state.createChannelError); - -export const selectRepostLoading = createSelector(selectState, (state) => state.repostLoading); - -export const selectRepostError = createSelector(selectState, (state) => state.repostError); +export const selectCurrentChannelPage = (state: State) => selectState(state).currentChannelPage || 1; +export const selectCreatingChannel = (state: State) => selectState(state).creatingChannel; +export const selectCreateChannelError = (state: State) => selectState(state).createChannelError; +export const selectRepostLoading = (state: State) => selectState(state).repostLoading; +export const selectRepostError = (state: State) => selectState(state).repostError; export const selectClaimsByUri = createSelector(selectClaimIdsByUri, selectClaimsById, (byUri, byId) => { const claims = {}; @@ -48,6 +43,21 @@ export const selectClaimsByUri = createSelector(selectClaimIdsByUri, selectClaim return claims; }); +/** + * Returns the claim with the specified ID. The claim could be undefined if does + * not exist or have not fetched. Take note of the second parameter, which means + * an inline function or helper would be required when used as an input to + * 'createSelector'. + * + * @param state + * @param claimId + * @returns {*} + */ +export const selectClaimWithId = (state: State, claimId: string) => { + const byId = selectClaimsById(state); + return byId[claimId]; +}; + export const selectAllClaimsByChannel = createSelector(selectState, (state) => state.paginatedClaimsByChannel || {}); export const selectPendingIds = createSelector(selectState, (state) => Object.keys(state.pendingById) || []); @@ -69,10 +79,9 @@ export const makeSelectClaimIdIsPending = (claimId: string) => return Boolean(pendingById[claimId]); }); -export const makeSelectClaimIdForUri = (uri: string) => - createSelector(selectClaimIdsByUri, (claimIds) => claimIds[uri]); +export const selectClaimIdForUri = (state: State, uri: string) => selectClaimIdsByUri(state)[uri]; -export const selectReflectingById = createSelector(selectState, (state) => state.reflectingById); +export const selectReflectingById = (state: State) => selectState(state).reflectingById; export const makeSelectClaimForClaimId = (claimId: string) => createSelector(selectClaimsById, (byId) => byId[claimId]); @@ -85,7 +94,8 @@ export const selectClaimForUri = createCachedSelector( const validUri = isURIValid(uri); if (validUri && byUri) { - const claimId = uri && byUri[normalizeURI(uri)]; + const normalizedUri = normalizeURI(uri); + const claimId = uri && byUri[normalizedUri]; const claim = byId[claimId]; // Make sure to return the claim as is so apps can check if it's been resolved before (null) or still needs to be resolved (undefined) @@ -102,7 +112,7 @@ export const selectClaimForUri = createCachedSelector( return { ...repostedClaim, - repost_url: normalizeURI(uri), + repost_url: normalizedUri, repost_channel_url: channelUrl, repost_bid_amount: claim && claim.meta && claim.meta.effective_amount, }; @@ -111,14 +121,16 @@ export const selectClaimForUri = createCachedSelector( } } } -)((state, uri, returnRepost = true) => `${uri}:${returnRepost ? '1' : '0'}`); +)((state, uri, returnRepost = true) => `${String(uri)}:${returnRepost ? '1' : '0'}`); +// Note: this is deprecated. Use "selectClaimForUri(state, uri)" instead. export const makeSelectClaimForUri = (uri: string, returnRepost: boolean = true) => createSelector(selectClaimIdsByUri, selectClaimsById, (byUri, byId) => { const validUri = isURIValid(uri); if (validUri && byUri) { - const claimId = uri && byUri[normalizeURI(uri)]; + const normalizedUri = normalizeURI(uri); + const claimId = uri && byUri[normalizedUri]; const claim = byId[claimId]; // Make sure to return the claim as is so apps can check if it's been resolved before (null) or still needs to be resolved (undefined) @@ -135,7 +147,7 @@ export const makeSelectClaimForUri = (uri: string, returnRepost: boolean = true) return { ...repostedClaim, - repost_url: normalizeURI(uri), + repost_url: normalizedUri, repost_channel_url: channelUrl, repost_bid_amount: claim && claim.meta && claim.meta.effective_amount, }; @@ -145,6 +157,9 @@ export const makeSelectClaimForUri = (uri: string, returnRepost: boolean = true) } }); +// Returns your claim IDs without handling pending and abandoned claims. +export const selectMyClaimIdsRaw = (state: State) => selectState(state).myClaims; + export const selectMyClaimsRaw = createSelector(selectState, selectClaimsById, (state, byId) => { const ids = state.myClaims; if (!ids) { @@ -161,7 +176,10 @@ export const selectMyClaimsRaw = createSelector(selectState, selectClaimsById, ( return claims; }); -export const selectAbandoningIds = createSelector(selectState, (state) => Object.keys(state.abandoningById || {})); +export const selectAbandoningById = (state: State) => selectState(state).abandoningById || {}; +export const selectAbandoningIds = createSelector(selectAbandoningById, (abandoningById) => + Object.keys(abandoningById) +); export const makeSelectAbandoningClaimById = (claimId: string) => createSelector(selectAbandoningIds, (ids) => ids.includes(claimId)); @@ -173,12 +191,63 @@ export const makeSelectIsAbandoningClaimForUri = (uri: string) => }); export const selectMyActiveClaims = createSelector( - selectMyClaimsRaw, + selectMyClaimIdsRaw, selectAbandoningIds, - (claims, abandoningIds) => - new Set(claims && claims.map((claim) => claim.claim_id).filter((claimId) => !abandoningIds.includes(claimId))) + (myClaimIds, abandoningIds) => { + return new Set(myClaimIds && myClaimIds.filter((claimId) => !abandoningIds.includes(claimId))); + } ); +// Helper for 'selectClaimIsMineForUri'. +// Returns undefined string if unable to normalize or is not valid. +const selectNormalizedAndVerifiedUri = createCachedSelector( + (state, rawUri) => rawUri, + (rawUri) => { + try { + const uri = normalizeURI(rawUri); + if (isURIValid(uri)) { + return uri; + } + } catch (e) {} + + return undefined; + } +)((state, rawUri) => String(rawUri)); + +export const selectClaimIsMine = (state: State, claim: ?Claim) => { + if (claim) { + // The original code seems to imply that 'is_my_output' could be false even + // when it is yours and there is a need to double-check with 'myActiveClaims'. + // I'm retaining that logic. Otherwise, we could have just return + // is_my_output directly when it is defined and skip the fallback. + if (claim.is_my_output) { + return true; + } else { + // 'is_my_output' is false or undefined. + const myActiveClaims = selectMyActiveClaims(state); + return claim.claim_id && myActiveClaims.has(claim.claim_id); + } + } else { + return false; + } +}; + +export const selectClaimIsMineForUri = (state: State, rawUri: string) => { + // Not memoizing this selector because: + // (1) The workload is somewhat lightweight. + // (2) Since it depends on 'selectClaimsByUri', memoization won't work anyway + // because the array is constantly invalidated. + + const uri = selectNormalizedAndVerifiedUri(state, rawUri); + if (!uri) { + return false; + } + + const claimsByUri = selectClaimsByUri(state); + return selectClaimIsMine(state, claimsByUri && claimsByUri[uri]); +}; + +// DEPRECATED - use selectClaimIsMineForUri instead. export const makeSelectClaimIsMine = (rawUri: string) => { let uri; try { @@ -198,15 +267,11 @@ export const makeSelectClaimIsMine = (rawUri: string) => { }); }; -export const selectMyPurchases = createSelector(selectState, (state) => state.myPurchases); - -export const selectPurchaseUriSuccess = createSelector(selectState, (state) => state.purchaseUriSuccess); - -export const selectMyPurchasesCount = createSelector(selectState, (state) => state.myPurchasesPageTotalResults); - -export const selectIsFetchingMyPurchases = createSelector(selectState, (state) => state.fetchingMyPurchases); - -export const selectFetchingMyPurchasesError = createSelector(selectState, (state) => state.fetchingMyPurchasesError); +export const selectMyPurchases = (state: State) => selectState(state).myPurchases; +export const selectPurchaseUriSuccess = (state: State) => selectState(state).purchaseUriSuccess; +export const selectMyPurchasesCount = (state: State) => selectState(state).myPurchasesPageTotalResults; +export const selectIsFetchingMyPurchases = (state: State) => selectState(state).fetchingMyPurchases; +export const selectFetchingMyPurchasesError = (state: State) => selectState(state).fetchingMyPurchasesError; export const makeSelectMyPurchasesForPage = (query: ?string, page: number = 1) => createSelector( @@ -270,7 +335,7 @@ export const makeSelectTotalPagesInChannelSearch = (uri: string) => export const selectMetadataForUri = createCachedSelector(selectClaimForUri, (claim, uri) => { const metadata = claim && claim.value; return metadata || (claim === undefined ? undefined : null); -})((state, uri) => uri); +})((state, uri) => String(uri)); export const makeSelectMetadataForUri = (uri: string) => createSelector(makeSelectClaimForUri(uri), (claim) => { @@ -303,7 +368,7 @@ export const selectDateForUri = createCachedSelector( const dateObj = new Date(timestamp); return dateObj; } -)((state, uri) => uri); +)((state, uri) => String(uri)); export const makeSelectAmountForUri = (uri: string) => createSelector(makeSelectClaimForUri(uri), (claim) => { @@ -335,7 +400,7 @@ export const makeSelectCoverForUri = (uri: string) => return cover && cover.url ? cover.url.trim().replace(/^http:\/\//i, 'https://') : undefined; }); -export const selectIsFetchingClaimListMine = createSelector(selectState, (state) => state.isFetchingClaimListMine); +export const selectIsFetchingClaimListMine = (state: State) => selectState(state).isFetchingClaimListMine; export const selectMyClaimsPage = createSelector(selectState, (state) => state.myClaimsPageResults || []); @@ -346,12 +411,8 @@ export const selectMyClaimsPageNumber = createSelector( (state) => (state.txoPage && state.txoPage.page) || 1 ); -export const selectMyClaimsPageItemCount = createSelector(selectState, (state) => state.myClaimsPageTotalResults || 1); - -export const selectFetchingMyClaimsPageError = createSelector( - selectState, - (state) => state.fetchingClaimListMinePageError -); +export const selectMyClaimsPageItemCount = (state: State) => selectState(state).myClaimsPageTotalResults || 1; +export const selectFetchingMyClaimsPageError = (state: State) => selectState(state).fetchingClaimListMinePageError; export const selectMyClaims = createSelector( selectMyActiveClaims, @@ -403,18 +464,31 @@ export const selectMyClaimsOutpoints = createSelector(selectMyClaims, (myClaims) return outpoints; }); -export const selectFetchingMyChannels = createSelector(selectState, (state) => state.fetchingMyChannels); +export const selectFetchingMyChannels = (state: State) => selectState(state).fetchingMyChannels; +export const selectFetchingMyCollections = (state: State) => selectState(state).fetchingMyCollections; -export const selectFetchingMyCollections = createSelector(selectState, (state) => state.fetchingMyCollections); +export const selectMyChannelClaimIds = (state: State) => selectState(state).myChannelClaims; -export const selectMyChannelClaims = createSelector(selectState, selectClaimsById, (state, byId) => { - const ids = state.myChannelClaims; - if (!ids) { - return ids; +export const selectMyChannelClaims = createSelector(selectMyChannelClaimIds, (myChannelClaimIds) => { + if (!myChannelClaimIds) { + return myChannelClaimIds; } + if (!window || !window.store) { + return undefined; + } + + // Note: Grabbing the store and running the selector this way is anti-pattern, + // but it is _needed_ and works only because we know for sure that 'byId[]' + // will be populated with the same claims as when 'myChannelClaimIds' is populated. + // If we put 'state' or 'byId' as the input selector, it essentially + // recalculates every time. Putting 'state' as input to createSelector() is + // always wrong from a memoization standpoint. + const state = window.store.getState(); + const byId = selectClaimsById(state); + const claims = []; - ids.forEach((id) => { + myChannelClaimIds.forEach((id) => { if (byId[id]) { // I'm not sure why this check is necessary, but it ought to be a quick fix for https://github.com/lbryio/lbry-desktop/issues/544 claims.push(byId[id]); @@ -428,16 +502,21 @@ export const selectMyChannelUrls = createSelector(selectMyChannelClaims, (claims claims ? claims.map((claim) => claim.canonical_url || claim.permanent_url) : undefined ); -export const selectMyCollectionIds = createSelector(selectState, (state) => state.myCollectionClaims); +export const selectHasChannels = (state: State) => { + const myChannelClaimIds = selectMyChannelClaimIds(state); + return myChannelClaimIds ? myChannelClaimIds.length > 0 : false; +}; + +export const selectMyCollectionIds = (state: State) => selectState(state).myCollectionClaims; export const selectResolvingUris = createSelector(selectState, (state) => state.resolvingUris || []); -export const selectChannelImportPending = createSelector(selectState, (state) => state.pendingChannelImport); +export const selectChannelImportPending = (state: State) => selectState(state).pendingChannelImport; export const makeSelectIsUriResolving = (uri: string) => createSelector(selectResolvingUris, (resolvingUris) => resolvingUris && resolvingUris.indexOf(uri) !== -1); -export const selectPlayingUri = createSelector(selectState, (state) => state.playingUri); +export const selectPlayingUri = (state: State) => selectState(state).playingUri; export const selectChannelClaimCounts = createSelector(selectState, (state) => state.channelClaimCounts || {}); @@ -541,7 +620,7 @@ export const makeSelectMyChannelPermUrlForName = (name: string) => export const selectTagsForUri = createCachedSelector(selectMetadataForUri, (metadata: ?GenericMetadata) => { return (metadata && metadata.tags) || []; -})((state, uri) => uri); +})((state, uri) => String(uri)); export const makeSelectTagsForUri = (uri: string) => createSelector(makeSelectMetadataForUri(uri), (metadata: ?GenericMetadata) => { @@ -592,9 +671,8 @@ export const makeSelectSupportsForUri = (uri: string) => return total; }); -export const selectUpdatingChannel = createSelector(selectState, (state) => state.updatingChannel); - -export const selectUpdateChannelError = createSelector(selectState, (state) => state.updateChannelError); +export const selectUpdatingChannel = (state: State) => selectState(state).updatingChannel; +export const selectUpdateChannelError = (state: State) => selectState(state).updateChannelError; export const makeSelectReflectingClaimForUri = (uri: string) => createSelector(selectClaimIdsByUri, selectReflectingById, (claimIdsByUri, reflectingById) => { @@ -638,39 +716,34 @@ export const makeSelectClaimIsStreamPlaceholder = (uri: string) => return Boolean(claim.value_type === 'stream' && !claim.value.source); }); -export const makeSelectTotalStakedAmountForChannelUri = (uri: string) => - createSelector(makeSelectClaimForUri(uri), (claim) => { - if (!claim || !claim.amount || !claim.meta || !claim.meta.support_amount) { - return 0; - } +export const selectTotalStakedAmountForChannelUri = createCachedSelector(selectClaimForUri, (claim) => { + if (!claim || !claim.amount || !claim.meta || !claim.meta.support_amount) { + return 0; + } - return parseFloat(claim.amount) + parseFloat(claim.meta.support_amount) || 0; - }); + return parseFloat(claim.amount) + parseFloat(claim.meta.support_amount) || 0; +})((state, uri) => String(uri)); -export const makeSelectStakedLevelForChannelUri = (uri: string) => - createSelector(makeSelectTotalStakedAmountForChannelUri(uri), (amount) => { - let level = 1; - switch (true) { - case amount >= CLAIM.LEVEL_2_STAKED_AMOUNT && amount < CLAIM.LEVEL_3_STAKED_AMOUNT: - level = 2; - break; - case amount >= CLAIM.LEVEL_3_STAKED_AMOUNT && amount < CLAIM.LEVEL_4_STAKED_AMOUNT: - level = 3; - break; - case amount >= CLAIM.LEVEL_4_STAKED_AMOUNT && amount < CLAIM.LEVEL_5_STAKED_AMOUNT: - level = 4; - break; - case amount >= CLAIM.LEVEL_5_STAKED_AMOUNT: - level = 5; - break; - } - return level; - }); +export const selectStakedLevelForChannelUri = createCachedSelector(selectTotalStakedAmountForChannelUri, (amount) => { + let level = 1; + switch (true) { + case amount >= CLAIM.LEVEL_2_STAKED_AMOUNT && amount < CLAIM.LEVEL_3_STAKED_AMOUNT: + level = 2; + break; + case amount >= CLAIM.LEVEL_3_STAKED_AMOUNT && amount < CLAIM.LEVEL_4_STAKED_AMOUNT: + level = 3; + break; + case amount >= CLAIM.LEVEL_4_STAKED_AMOUNT && amount < CLAIM.LEVEL_5_STAKED_AMOUNT: + level = 4; + break; + case amount >= CLAIM.LEVEL_5_STAKED_AMOUNT: + level = 5; + break; + } + return level; +})((state, uri) => String(uri)); -export const selectUpdatingCollection = createSelector(selectState, (state) => state.updatingCollection); - -export const selectUpdateCollectionError = createSelector(selectState, (state) => state.updateCollectionError); - -export const selectCreatingCollection = createSelector(selectState, (state) => state.creatingCollection); - -export const selectCreateCollectionError = createSelector(selectState, (state) => state.createCollectionError); +export const selectUpdatingCollection = (state: State) => selectState(state).updatingCollection; +export const selectUpdateCollectionError = (state: State) => selectState(state).updateCollectionError; +export const selectCreatingCollection = (state: State) => selectState(state).creatingCollection; +export const selectCreateCollectionError = (state: State) => selectState(state).createCollectionError; diff --git a/ui/redux/selectors/comments.js b/ui/redux/selectors/comments.js index bc53eb785..4ced61c4f 100644 --- a/ui/redux/selectors/comments.js +++ b/ui/redux/selectors/comments.js @@ -4,14 +4,15 @@ import { createCachedSelector } from 're-reselect'; import { selectMutedChannels } from 'redux/selectors/blocked'; import { selectShowMatureContent } from 'redux/selectors/settings'; import { selectBlacklistedOutpointMap, selectFilteredOutpointMap } from 'lbryinc'; -import { selectClaimsById, selectMyActiveClaims } from 'redux/selectors/claims'; +import { selectClaimsById, selectMyActiveClaims, selectClaimIdForUri } from 'redux/selectors/claims'; import { isClaimNsfw } from 'util/claim'; -type State = { comments: CommentsState }; +type State = { comments: CommentsState, claims: any }; const selectState = (state) => state.comments || {}; export const selectCommentsById = (state: State) => selectState(state).commentById || {}; +export const selectCommentIdsByClaimId = (state: State) => selectState(state).byId; export const selectIsFetchingComments = (state: State) => selectState(state).isLoading; export const selectIsFetchingCommentsById = (state: State) => selectState(state).isLoadingById; export const selectIsFetchingCommentsByParentId = (state: State) => selectState(state).isLoadingByParentId; @@ -173,6 +174,12 @@ export const selectRepliesByParentId = createSelector(selectState, selectComment export const selectLinkedCommentAncestors = (state: State) => selectState(state).linkedCommentAncestors; +export const selectCommentIdsForUri = (state: State, uri: string) => { + const claimId = selectClaimIdForUri(state, uri); + const commentIdsByClaimId = selectCommentIdsByClaimId(state); + return commentIdsByClaimId[claimId]; +}; + export const makeSelectCommentIdsForUri = (uri: string) => createSelector(selectState, selectCommentsByUri, selectClaimsById, (state, byUri) => { const claimId = byUri[uri];