PremiumBadge
: retrieve membership db internally instead of from parent (#1764)
* DRY up membership selector Selectors should be chained up, not copy/pasted. * PremiumBadge: retrieve membership db internally instead of from parent ## Ticket 1753 odyseeMembershipByUri function causing unnecessary renders ## Issue While the rendering issue in the ticket is due to the way the props are defined, it also surfaced a prop-drilling issue with PremiumBadge. Instead of asking the parent for the membership db, it can retrieve from Redux itself. This prevents the prop from polluting 2 levels of components and causing unnecessary renders. ## Approach - Make `PremiumBadge` accept `uri` like most other components. - I still leave the `membership` prop as (i.e. parent can still pass it directly). In some cases (e.g. `livestreamComment`, `page/odyseeMembership`), the parent itself needs the same data, so we don't need to derive it twice.
This commit is contained in:
parent
6ceb0d7d8f
commit
dbb9ee7ac6
20 changed files with 46 additions and 85 deletions
|
@ -1,5 +1,5 @@
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { selectMyChannelClaims, selectClaimsByUri, selectOdyseeMembershipForUri } from 'redux/selectors/claims';
|
import { selectMyChannelClaims, selectClaimsByUri } from 'redux/selectors/claims';
|
||||||
import { selectActiveChannelClaim, selectIncognito } from 'redux/selectors/app';
|
import { selectActiveChannelClaim, selectIncognito } from 'redux/selectors/app';
|
||||||
import { doSetActiveChannel, doSetIncognito } from 'redux/actions/app';
|
import { doSetActiveChannel, doSetIncognito } from 'redux/actions/app';
|
||||||
import { doFetchUserMemberships } from 'redux/actions/user';
|
import { doFetchUserMemberships } from 'redux/actions/user';
|
||||||
|
@ -16,7 +16,6 @@ const select = (state, props) => {
|
||||||
channels: selectMyChannelClaims(state),
|
channels: selectMyChannelClaims(state),
|
||||||
activeChannelClaim: storeSelection ? defaultChannelClaim : activeChannelClaim,
|
activeChannelClaim: storeSelection ? defaultChannelClaim : activeChannelClaim,
|
||||||
incognito: selectIncognito(state),
|
incognito: selectIncognito(state),
|
||||||
odyseeMembershipByUri: (uri) => selectOdyseeMembershipForUri(state, uri),
|
|
||||||
claimsByUri: selectClaimsByUri(state),
|
claimsByUri: selectClaimsByUri(state),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -9,7 +9,7 @@ import ChannelTitle from 'component/channelTitle';
|
||||||
import Icon from 'component/common/icon';
|
import Icon from 'component/common/icon';
|
||||||
import { useHistory } from 'react-router';
|
import { useHistory } from 'react-router';
|
||||||
import useGetUserMemberships from 'effects/use-get-user-memberships';
|
import useGetUserMemberships from 'effects/use-get-user-memberships';
|
||||||
import PremiumBadge from 'component/common/premium-badge';
|
import PremiumBadge from 'component/premiumBadge';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
selectedChannelUrl: string, // currently selected channel
|
selectedChannelUrl: string, // currently selected channel
|
||||||
|
@ -138,13 +138,10 @@ type ListItemProps = {
|
||||||
isSelected?: boolean,
|
isSelected?: boolean,
|
||||||
claimsByUri: { [string]: any },
|
claimsByUri: { [string]: any },
|
||||||
doFetchUserMemberships: (claimIdCsv: string) => void,
|
doFetchUserMemberships: (claimIdCsv: string) => void,
|
||||||
odyseeMembershipByUri: (uri: string) => string,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
function ChannelListItem(props: ListItemProps) {
|
function ChannelListItem(props: ListItemProps) {
|
||||||
const { uri, isSelected = false, claimsByUri, doFetchUserMemberships, odyseeMembershipByUri } = props;
|
const { uri, isSelected = false, claimsByUri, doFetchUserMemberships } = props;
|
||||||
|
|
||||||
const membership = odyseeMembershipByUri(uri);
|
|
||||||
|
|
||||||
const shouldFetchUserMemberships = true;
|
const shouldFetchUserMemberships = true;
|
||||||
useGetUserMemberships(shouldFetchUserMemberships, [uri], claimsByUri, doFetchUserMemberships, [uri]);
|
useGetUserMemberships(shouldFetchUserMemberships, [uri], claimsByUri, doFetchUserMemberships, [uri]);
|
||||||
|
@ -153,7 +150,7 @@ function ChannelListItem(props: ListItemProps) {
|
||||||
<div className={classnames('channel__list-item', { 'channel__list-item--selected': isSelected })}>
|
<div className={classnames('channel__list-item', { 'channel__list-item--selected': isSelected })}>
|
||||||
<ChannelThumbnail uri={uri} hideStakedIndicator xsmall noLazyLoad />
|
<ChannelThumbnail uri={uri} hideStakedIndicator xsmall noLazyLoad />
|
||||||
<ChannelTitle uri={uri} />
|
<ChannelTitle uri={uri} />
|
||||||
<PremiumBadge membership={membership} />
|
<PremiumBadge uri={uri} />
|
||||||
{isSelected && <Icon icon={ICONS.DOWN} />}
|
{isSelected && <Icon icon={ICONS.DOWN} />}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -4,7 +4,6 @@ import {
|
||||||
selectClaimForUri,
|
selectClaimForUri,
|
||||||
selectIsUriResolving,
|
selectIsUriResolving,
|
||||||
selectClaimsByUri,
|
selectClaimsByUri,
|
||||||
selectOdyseeMembershipForUri,
|
|
||||||
} from 'redux/selectors/claims';
|
} from 'redux/selectors/claims';
|
||||||
import { doResolveUri } from 'redux/actions/claims';
|
import { doResolveUri } from 'redux/actions/claims';
|
||||||
import { doFetchUserMemberships } from 'redux/actions/user';
|
import { doFetchUserMemberships } from 'redux/actions/user';
|
||||||
|
@ -14,7 +13,6 @@ const select = (state, props) => ({
|
||||||
thumbnail: selectThumbnailForUri(state, props.uri),
|
thumbnail: selectThumbnailForUri(state, props.uri),
|
||||||
claim: selectClaimForUri(state, props.uri),
|
claim: selectClaimForUri(state, props.uri),
|
||||||
isResolving: selectIsUriResolving(state, props.uri),
|
isResolving: selectIsUriResolving(state, props.uri),
|
||||||
odyseeMembership: selectOdyseeMembershipForUri(state, props.uri),
|
|
||||||
claimsByUri: selectClaimsByUri(state),
|
claimsByUri: selectClaimsByUri(state),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ import FreezeframeWrapper from 'component/fileThumbnail/FreezeframeWrapper';
|
||||||
import OptimizedImage from 'component/optimizedImage';
|
import OptimizedImage from 'component/optimizedImage';
|
||||||
import { AVATAR_DEFAULT } from 'config';
|
import { AVATAR_DEFAULT } from 'config';
|
||||||
import useGetUserMemberships from 'effects/use-get-user-memberships';
|
import useGetUserMemberships from 'effects/use-get-user-memberships';
|
||||||
import PremiumBadge from 'component/common/premium-badge';
|
import PremiumBadge from 'component/premiumBadge';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
thumbnail: ?string,
|
thumbnail: ?string,
|
||||||
|
@ -29,7 +29,6 @@ type Props = {
|
||||||
setThumbUploadError: (boolean) => void,
|
setThumbUploadError: (boolean) => void,
|
||||||
ThumbUploadError: boolean,
|
ThumbUploadError: boolean,
|
||||||
claimsByUri: { [string]: any },
|
claimsByUri: { [string]: any },
|
||||||
odyseeMembership: string,
|
|
||||||
doFetchUserMemberships: (claimIdCsv: string) => void,
|
doFetchUserMemberships: (claimIdCsv: string) => void,
|
||||||
showMemberBadge?: boolean,
|
showMemberBadge?: boolean,
|
||||||
isChannel?: boolean,
|
isChannel?: boolean,
|
||||||
|
@ -55,7 +54,6 @@ function ChannelThumbnail(props: Props) {
|
||||||
setThumbUploadError,
|
setThumbUploadError,
|
||||||
ThumbUploadError,
|
ThumbUploadError,
|
||||||
claimsByUri,
|
claimsByUri,
|
||||||
odyseeMembership,
|
|
||||||
doFetchUserMemberships,
|
doFetchUserMemberships,
|
||||||
showMemberBadge,
|
showMemberBadge,
|
||||||
isChannel,
|
isChannel,
|
||||||
|
@ -71,7 +69,7 @@ function ChannelThumbnail(props: Props) {
|
||||||
const showThumb = (!obscure && !!thumbnail) || thumbnailPreview;
|
const showThumb = (!obscure && !!thumbnail) || thumbnailPreview;
|
||||||
|
|
||||||
const badgeProps = {
|
const badgeProps = {
|
||||||
membership: odyseeMembership,
|
uri,
|
||||||
linkPage: isChannel,
|
linkPage: isChannel,
|
||||||
placement: isChannel ? 'bottom' : undefined,
|
placement: isChannel ? 'bottom' : undefined,
|
||||||
hideTooltip,
|
hideTooltip,
|
||||||
|
|
|
@ -46,7 +46,7 @@ import OptimizedImage from 'component/optimizedImage';
|
||||||
import { getChannelFromClaim } from 'util/claim';
|
import { getChannelFromClaim } from 'util/claim';
|
||||||
import { parseSticker } from 'util/comments';
|
import { parseSticker } from 'util/comments';
|
||||||
import { useIsMobile } from 'effects/use-screensize';
|
import { useIsMobile } from 'effects/use-screensize';
|
||||||
import PremiumBadge from 'component/common/premium-badge';
|
import PremiumBadge from 'component/premiumBadge';
|
||||||
import Spinner from 'component/spinner';
|
import Spinner from 'component/spinner';
|
||||||
|
|
||||||
const AUTO_EXPAND_ALL_REPLIES = false;
|
const AUTO_EXPAND_ALL_REPLIES = false;
|
||||||
|
|
|
@ -17,7 +17,7 @@ import Icon from 'component/common/icon';
|
||||||
import MarkdownPreview from 'component/common/markdown-preview';
|
import MarkdownPreview from 'component/common/markdown-preview';
|
||||||
import OptimizedImage from 'component/optimizedImage';
|
import OptimizedImage from 'component/optimizedImage';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PremiumBadge from 'component/common/premium-badge';
|
import PremiumBadge from 'component/premiumBadge';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
comment: Comment,
|
comment: Comment,
|
||||||
|
|
9
ui/component/premiumBadge/index.js
Normal file
9
ui/component/premiumBadge/index.js
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
import PremiumBadge from './view';
|
||||||
|
import { selectOdyseeMembershipForUri } from 'redux/selectors/claims';
|
||||||
|
|
||||||
|
const select = (state, props) => ({
|
||||||
|
membership: props.uri ? selectOdyseeMembershipForUri(state, props.uri) : props.membership,
|
||||||
|
});
|
||||||
|
|
||||||
|
export default connect(select)(PremiumBadge);
|
|
@ -1,14 +1,15 @@
|
||||||
// @flow
|
// @flow
|
||||||
import 'scss/component/_comment-badge.scss';
|
import 'scss/component/_comment-badge.scss';
|
||||||
|
|
||||||
|
import React from 'react';
|
||||||
import * as ICONS from 'constants/icons';
|
import * as ICONS from 'constants/icons';
|
||||||
import * as PAGES from 'constants/pages';
|
import * as PAGES from 'constants/pages';
|
||||||
import React from 'react';
|
import CommentBadge from 'component/common/comment-badge';
|
||||||
import CommentBadge from './comment-badge';
|
|
||||||
import Button from 'component/button';
|
import Button from 'component/button';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
membership: ?string,
|
uri?: string,
|
||||||
|
membership: ?string, // Retrieved from redux if `uri` is provided; else uses the given `membership` directly.
|
||||||
linkPage?: boolean,
|
linkPage?: boolean,
|
||||||
placement?: string,
|
placement?: string,
|
||||||
className?: string,
|
className?: string,
|
|
@ -8,7 +8,7 @@ import { selectUserVerifiedEmail, selectUser, selectOdyseeMembershipName } from
|
||||||
import { selectHomepageData } from 'redux/selectors/settings';
|
import { selectHomepageData } from 'redux/selectors/settings';
|
||||||
import { doSignOut } from 'redux/actions/app';
|
import { doSignOut } from 'redux/actions/app';
|
||||||
import { selectUnseenNotificationCount } from 'redux/selectors/notifications';
|
import { selectUnseenNotificationCount } from 'redux/selectors/notifications';
|
||||||
import { selectPurchaseUriSuccess, selectOdyseeMembershipForUri } from 'redux/selectors/claims';
|
import { selectPurchaseUriSuccess } from 'redux/selectors/claims';
|
||||||
|
|
||||||
import SideNavigation from './view';
|
import SideNavigation from './view';
|
||||||
|
|
||||||
|
@ -22,7 +22,6 @@ const select = (state) => ({
|
||||||
user: selectUser(state),
|
user: selectUser(state),
|
||||||
homepageData: selectHomepageData(state),
|
homepageData: selectHomepageData(state),
|
||||||
odyseeMembership: selectOdyseeMembershipName(state),
|
odyseeMembership: selectOdyseeMembershipName(state),
|
||||||
odyseeMembershipByUri: (uri) => selectOdyseeMembershipForUri(state, uri),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export default connect(select, {
|
export default connect(select, {
|
||||||
|
|
|
@ -17,7 +17,7 @@ import { useIsMobile, useIsLargeScreen } from 'effects/use-screensize';
|
||||||
import { GetLinksData } from 'util/buildHomepage';
|
import { GetLinksData } from 'util/buildHomepage';
|
||||||
import { platform } from 'util/platform';
|
import { platform } from 'util/platform';
|
||||||
import { DOMAIN, ENABLE_UI_NOTIFICATIONS, ENABLE_NO_SOURCE_CLAIMS } from 'config';
|
import { DOMAIN, ENABLE_UI_NOTIFICATIONS, ENABLE_NO_SOURCE_CLAIMS } from 'config';
|
||||||
import PremiumBadge from 'component/common/premium-badge';
|
import PremiumBadge from 'component/premiumBadge';
|
||||||
|
|
||||||
const touch = platform.isTouch();
|
const touch = platform.isTouch();
|
||||||
|
|
||||||
|
@ -146,7 +146,6 @@ type Props = {
|
||||||
homepageData: any,
|
homepageData: any,
|
||||||
doClearClaimSearch: () => void,
|
doClearClaimSearch: () => void,
|
||||||
odyseeMembership: ?string,
|
odyseeMembership: ?string,
|
||||||
odyseeMembershipByUri: (uri: string) => string,
|
|
||||||
doFetchLastActiveSubs: (force?: boolean, count?: number) => void,
|
doFetchLastActiveSubs: (force?: boolean, count?: number) => void,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -168,7 +167,6 @@ function SideNavigation(props: Props) {
|
||||||
followedTags,
|
followedTags,
|
||||||
doClearClaimSearch,
|
doClearClaimSearch,
|
||||||
odyseeMembership,
|
odyseeMembership,
|
||||||
odyseeMembershipByUri,
|
|
||||||
doFetchLastActiveSubs,
|
doFetchLastActiveSubs,
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
|
@ -352,11 +350,7 @@ function SideNavigation(props: Props) {
|
||||||
</li>
|
</li>
|
||||||
)}
|
)}
|
||||||
{displayedSubscriptions.map((subscription) => (
|
{displayedSubscriptions.map((subscription) => (
|
||||||
<SubscriptionListItem
|
<SubscriptionListItem key={subscription.uri} subscription={subscription} />
|
||||||
key={subscription.uri}
|
|
||||||
subscription={subscription}
|
|
||||||
odyseeMembershipByUri={odyseeMembershipByUri}
|
|
||||||
/>
|
|
||||||
))}
|
))}
|
||||||
{!!subscriptionFilter && !displayedSubscriptions.length && (
|
{!!subscriptionFilter && !displayedSubscriptions.length && (
|
||||||
<li>
|
<li>
|
||||||
|
@ -577,15 +571,12 @@ function SideNavigation(props: Props) {
|
||||||
|
|
||||||
type SubItemProps = {
|
type SubItemProps = {
|
||||||
subscription: Subscription,
|
subscription: Subscription,
|
||||||
odyseeMembershipByUri: (uri: string) => string,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
function SubscriptionListItem(props: SubItemProps) {
|
function SubscriptionListItem(props: SubItemProps) {
|
||||||
const { subscription, odyseeMembershipByUri } = props;
|
const { subscription } = props;
|
||||||
const { uri, channelName } = subscription;
|
const { uri, channelName } = subscription;
|
||||||
|
|
||||||
const membership = odyseeMembershipByUri(uri);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<li className="navigation-link__wrapper navigation__subscription">
|
<li className="navigation-link__wrapper navigation__subscription">
|
||||||
<Button
|
<Button
|
||||||
|
@ -598,7 +589,7 @@ function SubscriptionListItem(props: SubItemProps) {
|
||||||
<ClaimPreviewTitle uri={uri} />
|
<ClaimPreviewTitle uri={uri} />
|
||||||
<span dir="auto" className="channel-name">
|
<span dir="auto" className="channel-name">
|
||||||
{channelName}
|
{channelName}
|
||||||
<PremiumBadge membership={membership} />
|
<PremiumBadge uri={uri} />
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</Button>
|
</Button>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { selectClaimForUri, selectOdyseeMembershipForUri } from 'redux/selectors/claims';
|
import { selectClaimForUri } from 'redux/selectors/claims';
|
||||||
import TextareaSuggestionsItem from './view';
|
import TextareaSuggestionsItem from './view';
|
||||||
import { formatLbryChannelName } from 'util/url';
|
import { formatLbryChannelName } from 'util/url';
|
||||||
import { getClaimTitle } from 'util/claim';
|
import { getClaimTitle } from 'util/claim';
|
||||||
|
@ -12,7 +12,6 @@ const select = (state, props) => {
|
||||||
return {
|
return {
|
||||||
claimLabel: claim && formatLbryChannelName(claim.canonical_url),
|
claimLabel: claim && formatLbryChannelName(claim.canonical_url),
|
||||||
claimTitle: claim && getClaimTitle(claim),
|
claimTitle: claim && getClaimTitle(claim),
|
||||||
odyseeMembershipByUri: selectOdyseeMembershipForUri(state, uri),
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,18 +1,17 @@
|
||||||
// @flow
|
// @flow
|
||||||
import ChannelThumbnail from 'component/channelThumbnail';
|
import ChannelThumbnail from 'component/channelThumbnail';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PremiumBadge from 'component/common/premium-badge';
|
import PremiumBadge from 'component/premiumBadge';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
claimLabel?: string,
|
claimLabel?: string,
|
||||||
claimTitle?: string,
|
claimTitle?: string,
|
||||||
emote?: any,
|
emote?: any,
|
||||||
uri?: string,
|
uri?: string,
|
||||||
odyseeMembershipByUri: ?string,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function TextareaSuggestionsItem(props: Props) {
|
export default function TextareaSuggestionsItem(props: Props) {
|
||||||
const { claimLabel, claimTitle, emote, uri, odyseeMembershipByUri, ...autocompleteProps } = props;
|
const { claimLabel, claimTitle, emote, uri, ...autocompleteProps } = props;
|
||||||
|
|
||||||
if (emote) {
|
if (emote) {
|
||||||
const { name: value, url, unicode } = emote;
|
const { name: value, url, unicode } = emote;
|
||||||
|
@ -41,7 +40,7 @@ export default function TextareaSuggestionsItem(props: Props) {
|
||||||
<span className="textarea-suggestion__title">{claimTitle || value}</span>
|
<span className="textarea-suggestion__title">{claimTitle || value}</span>
|
||||||
<span className="textarea-suggestion__value">
|
<span className="textarea-suggestion__value">
|
||||||
{value}
|
{value}
|
||||||
<PremiumBadge membership={odyseeMembershipByUri} />
|
<PremiumBadge uri={uri} />
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { normalizeURI } from 'util/lbryURI';
|
import { normalizeURI } from 'util/lbryURI';
|
||||||
import { doResolveUri } from 'redux/actions/claims';
|
import { doResolveUri } from 'redux/actions/claims';
|
||||||
import { selectIsUriResolving, selectClaimForUri, selectOdyseeMembershipForUri } from 'redux/selectors/claims';
|
import { selectIsUriResolving, selectClaimForUri } from 'redux/selectors/claims';
|
||||||
import UriIndicator from './view';
|
import UriIndicator from './view';
|
||||||
|
|
||||||
const select = (state, props) => {
|
const select = (state, props) => {
|
||||||
|
@ -14,7 +14,6 @@ const select = (state, props) => {
|
||||||
claim: selectClaimForUri(state, props.uri),
|
claim: selectClaimForUri(state, props.uri),
|
||||||
isResolvingUri: selectIsUriResolving(state, props.uri),
|
isResolvingUri: selectIsUriResolving(state, props.uri),
|
||||||
uri,
|
uri,
|
||||||
odyseeMembership: selectOdyseeMembershipForUri(state, props.uri),
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ import type { Node } from 'react';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import classnames from 'classnames';
|
import classnames from 'classnames';
|
||||||
import Button from 'component/button';
|
import Button from 'component/button';
|
||||||
import PremiumBadge from 'component/common/premium-badge';
|
import PremiumBadge from 'component/premiumBadge';
|
||||||
import { stripLeadingAtSign } from 'util/string';
|
import { stripLeadingAtSign } from 'util/string';
|
||||||
|
|
||||||
type ChannelInfo = { uri: string, name: string, title: string };
|
type ChannelInfo = { uri: string, name: string, title: string };
|
||||||
|
@ -23,7 +23,6 @@ type Props = {
|
||||||
// --- redux ---
|
// --- redux ---
|
||||||
claim: ?Claim,
|
claim: ?Claim,
|
||||||
isResolvingUri: boolean,
|
isResolvingUri: boolean,
|
||||||
odyseeMembership: string,
|
|
||||||
comment?: boolean,
|
comment?: boolean,
|
||||||
resolveUri: (string) => void,
|
resolveUri: (string) => void,
|
||||||
};
|
};
|
||||||
|
@ -94,7 +93,6 @@ class UriIndicator extends React.PureComponent<Props> {
|
||||||
hideAnonymous = false,
|
hideAnonymous = false,
|
||||||
showAtSign,
|
showAtSign,
|
||||||
className,
|
className,
|
||||||
odyseeMembership,
|
|
||||||
comment,
|
comment,
|
||||||
showMemberBadge = true,
|
showMemberBadge = true,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
@ -127,7 +125,7 @@ class UriIndicator extends React.PureComponent<Props> {
|
||||||
const inner = (
|
const inner = (
|
||||||
<span dir="auto" className={classnames('channel-name', { 'channel-name--inline': inline })}>
|
<span dir="auto" className={classnames('channel-name', { 'channel-name--inline': inline })}>
|
||||||
<p>{showAtSign ? channelName : stripLeadingAtSign(channelTitle)}</p>
|
<p>{showAtSign ? channelName : stripLeadingAtSign(channelTitle)}</p>
|
||||||
{!comment && showMemberBadge && <PremiumBadge membership={odyseeMembership} />}
|
{!comment && showMemberBadge && <PremiumBadge uri={uri} />}
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,5 @@
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import {
|
import { selectClaimForUri, selectGeoRestrictionForUri, selectIsUriResolving } from 'redux/selectors/claims';
|
||||||
selectClaimForUri,
|
|
||||||
selectGeoRestrictionForUri,
|
|
||||||
selectIsUriResolving,
|
|
||||||
selectOdyseeMembershipForUri,
|
|
||||||
} from 'redux/selectors/claims';
|
|
||||||
import WunderbarSuggestion from './view';
|
import WunderbarSuggestion from './view';
|
||||||
|
|
||||||
const select = (state, props) => {
|
const select = (state, props) => {
|
||||||
|
@ -14,7 +9,6 @@ const select = (state, props) => {
|
||||||
claim: selectClaimForUri(state, uri),
|
claim: selectClaimForUri(state, uri),
|
||||||
isResolvingUri: selectIsUriResolving(state, uri),
|
isResolvingUri: selectIsUriResolving(state, uri),
|
||||||
geoRestriction: selectGeoRestrictionForUri(state, props.uri),
|
geoRestriction: selectGeoRestrictionForUri(state, props.uri),
|
||||||
odyseeMembership: selectOdyseeMembershipForUri(state, uri),
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -6,18 +6,17 @@ import FileThumbnail from 'component/fileThumbnail';
|
||||||
import ChannelThumbnail from 'component/channelThumbnail';
|
import ChannelThumbnail from 'component/channelThumbnail';
|
||||||
import FileProperties from 'component/previewOverlayProperties';
|
import FileProperties from 'component/previewOverlayProperties';
|
||||||
import ClaimProperties from 'component/claimProperties';
|
import ClaimProperties from 'component/claimProperties';
|
||||||
import PremiumBadge from 'component/common/premium-badge';
|
import PremiumBadge from 'component/premiumBadge';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
claim: ?Claim,
|
claim: ?Claim,
|
||||||
uri: string,
|
uri: string,
|
||||||
isResolvingUri: boolean,
|
isResolvingUri: boolean,
|
||||||
geoRestriction: ?GeoRestriction,
|
geoRestriction: ?GeoRestriction,
|
||||||
odyseeMembership: ?string,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function WunderbarSuggestion(props: Props) {
|
export default function WunderbarSuggestion(props: Props) {
|
||||||
const { claim, uri, isResolvingUri, odyseeMembership, geoRestriction } = props;
|
const { claim, uri, isResolvingUri, geoRestriction } = props;
|
||||||
|
|
||||||
if (isResolvingUri) {
|
if (isResolvingUri) {
|
||||||
return (
|
return (
|
||||||
|
@ -69,7 +68,7 @@ export default function WunderbarSuggestion(props: Props) {
|
||||||
<div className="wunderbar__suggestion-title">{claim.value.title}</div>
|
<div className="wunderbar__suggestion-title">{claim.value.title}</div>
|
||||||
<div className="wunderbar__suggestion-name">
|
<div className="wunderbar__suggestion-name">
|
||||||
{isChannel ? claim.name : (claim.signing_channel && claim.signing_channel.name) || __('Anonymous')}
|
{isChannel ? claim.name : (claim.signing_channel && claim.signing_channel.name) || __('Anonymous')}
|
||||||
<PremiumBadge membership={odyseeMembership} />
|
<PremiumBadge uri={uri} />
|
||||||
</div>
|
</div>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -6,7 +6,6 @@ import {
|
||||||
selectCurrentChannelPage,
|
selectCurrentChannelPage,
|
||||||
selectClaimForUri,
|
selectClaimForUri,
|
||||||
makeSelectClaimIsPending,
|
makeSelectClaimIsPending,
|
||||||
selectOdyseeMembershipForChannelId,
|
|
||||||
} from 'redux/selectors/claims';
|
} from 'redux/selectors/claims';
|
||||||
import { selectMyUnpublishedCollections } from 'redux/selectors/collections';
|
import { selectMyUnpublishedCollections } from 'redux/selectors/collections';
|
||||||
import { selectBlacklistedOutpointMap, doFetchSubCount, selectSubCountForUri } from 'lbryinc';
|
import { selectBlacklistedOutpointMap, doFetchSubCount, selectSubCountForUri } from 'lbryinc';
|
||||||
|
@ -38,7 +37,6 @@ const select = (state, props) => {
|
||||||
mutedChannels: selectMutedChannels(state),
|
mutedChannels: selectMutedChannels(state),
|
||||||
unpublishedCollections: selectMyUnpublishedCollections(state),
|
unpublishedCollections: selectMyUnpublishedCollections(state),
|
||||||
lang: selectLanguage(state),
|
lang: selectLanguage(state),
|
||||||
odyseeMembership: selectOdyseeMembershipForChannelId(state, claim.claim_id),
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,7 @@ import TruncatedText from 'component/common/truncated-text';
|
||||||
import PlaceholderTx from 'static/img/placeholderTx.gif';
|
import PlaceholderTx from 'static/img/placeholderTx.gif';
|
||||||
import Tooltip from 'component/common/tooltip';
|
import Tooltip from 'component/common/tooltip';
|
||||||
import { toCompactNotation } from 'util/string';
|
import { toCompactNotation } from 'util/string';
|
||||||
import PremiumBadge from 'component/common/premium-badge';
|
import PremiumBadge from 'component/premiumBadge';
|
||||||
|
|
||||||
export const PAGE_VIEW_QUERY = `view`;
|
export const PAGE_VIEW_QUERY = `view`;
|
||||||
export const DISCUSSION_PAGE = `discussion`;
|
export const DISCUSSION_PAGE = `discussion`;
|
||||||
|
@ -61,7 +61,6 @@ type Props = {
|
||||||
mutedChannels: Array<string>,
|
mutedChannels: Array<string>,
|
||||||
unpublishedCollections: CollectionGroup,
|
unpublishedCollections: CollectionGroup,
|
||||||
lang: string,
|
lang: string,
|
||||||
odyseeMembership: string,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
function ChannelPage(props: Props) {
|
function ChannelPage(props: Props) {
|
||||||
|
@ -82,7 +81,6 @@ function ChannelPage(props: Props) {
|
||||||
mutedChannels,
|
mutedChannels,
|
||||||
unpublishedCollections,
|
unpublishedCollections,
|
||||||
lang,
|
lang,
|
||||||
odyseeMembership,
|
|
||||||
} = props;
|
} = props;
|
||||||
const {
|
const {
|
||||||
push,
|
push,
|
||||||
|
@ -251,7 +249,7 @@ function ChannelPage(props: Props) {
|
||||||
<TruncatedText lines={2} showTooltip>
|
<TruncatedText lines={2} showTooltip>
|
||||||
{title || (channelName && '@' + channelName)}
|
{title || (channelName && '@' + channelName)}
|
||||||
</TruncatedText>
|
</TruncatedText>
|
||||||
<PremiumBadge membership={odyseeMembership} />
|
<PremiumBadge uri={uri} />
|
||||||
</h1>
|
</h1>
|
||||||
<div className="channel__meta">
|
<div className="channel__meta">
|
||||||
<Tooltip title={formattedSubCount} followCursor placement="top">
|
<Tooltip title={formattedSubCount} followCursor placement="top">
|
||||||
|
|
|
@ -14,7 +14,7 @@ import Card from 'component/common/card';
|
||||||
import MembershipSplash from 'component/membershipSplash';
|
import MembershipSplash from 'component/membershipSplash';
|
||||||
import Button from 'component/button';
|
import Button from 'component/button';
|
||||||
import ChannelSelector from 'component/channelSelector';
|
import ChannelSelector from 'component/channelSelector';
|
||||||
import PremiumBadge from 'component/common/premium-badge';
|
import PremiumBadge from 'component/premiumBadge';
|
||||||
import I18nMessage from 'component/i18nMessage';
|
import I18nMessage from 'component/i18nMessage';
|
||||||
import useGetUserMemberships from 'effects/use-get-user-memberships';
|
import useGetUserMemberships from 'effects/use-get-user-memberships';
|
||||||
import usePersistedState from 'effects/use-persisted-state';
|
import usePersistedState from 'effects/use-persisted-state';
|
||||||
|
|
|
@ -820,41 +820,26 @@ export const selectIsMyChannelCountOverLimit = createSelector(
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Given a uri of a channel, check if there an Odysee membership value
|
* Given a uri of a channel, check if there is an Odysee membership value.
|
||||||
* @param state
|
* @param state
|
||||||
* @param uri
|
* @param uri
|
||||||
* @returns {*}
|
* @returns {*}
|
||||||
*/
|
*/
|
||||||
export const selectOdyseeMembershipForUri = (state: State, uri: string) => {
|
export const selectOdyseeMembershipForUri = (state: State, uri: string) => {
|
||||||
const claim = selectClaimForUri(state, uri);
|
const claim = selectClaimForUri(state, uri);
|
||||||
|
const channelId = getChannelIdFromClaim(claim);
|
||||||
const uploaderChannelClaimId = getChannelIdFromClaim(claim);
|
return channelId ? selectOdyseeMembershipForChannelId(state, channelId) : undefined;
|
||||||
|
|
||||||
// looks for the uploader id
|
|
||||||
if (uploaderChannelClaimId) {
|
|
||||||
const matchingMembershipOfUser =
|
|
||||||
state.user &&
|
|
||||||
state.user.odyseeMembershipsPerClaimIds &&
|
|
||||||
state.user.odyseeMembershipsPerClaimIds[uploaderChannelClaimId];
|
|
||||||
|
|
||||||
return matchingMembershipOfUser;
|
|
||||||
}
|
|
||||||
|
|
||||||
return undefined;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Given a uri of a channel, check if there an Odysee membership value
|
* Given a channel ID, check if there is an Odysee membership value.
|
||||||
* @param state
|
* @param state
|
||||||
* @param channelId
|
* @param channelId
|
||||||
* @returns {*}
|
* @returns {*}
|
||||||
*/
|
*/
|
||||||
export const selectOdyseeMembershipForChannelId = (state: State, channelId: string) => {
|
export const selectOdyseeMembershipForChannelId = (state: State, channelId: string) => {
|
||||||
// looks for the uploader id
|
// TODO: should access via selector, not from `state` directly.
|
||||||
const matchingMembershipOfUser =
|
return state.user && state.user.odyseeMembershipsPerClaimIds && state.user.odyseeMembershipsPerClaimIds[channelId];
|
||||||
state.user && state.user.odyseeMembershipsPerClaimIds && state.user.odyseeMembershipsPerClaimIds[channelId];
|
|
||||||
|
|
||||||
return matchingMembershipOfUser;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const selectGeoRestrictionForUri = createCachedSelector(
|
export const selectGeoRestrictionForUri = createCachedSelector(
|
||||||
|
|
Loading…
Reference in a new issue