diff --git a/static/app-strings.json b/static/app-strings.json index a7e83a936..896dd1b96 100644 --- a/static/app-strings.json +++ b/static/app-strings.json @@ -2090,6 +2090,8 @@ "Expand Comments": "Expand Comments", "Expand": "Expand", "Load More": "Load More", + "%channelSubCount% Followers": "%channelSubCount% Followers", + "%channelSubCount% Follower": "%channelSubCount% Follower", "Collection": "Collection", "%channelName% isn't live right now, but the chat is! Check back later to watch the stream.": "%channelName% isn't live right now, but the chat is! Check back later to watch the stream.", "Review": "Review", diff --git a/ui/component/claimAuthor/view.jsx b/ui/component/claimAuthor/view.jsx index 0301c5b4d..c8a6fd292 100644 --- a/ui/component/claimAuthor/view.jsx +++ b/ui/component/claimAuthor/view.jsx @@ -5,13 +5,21 @@ import ClaimPreview from 'component/claimPreview'; type Props = { channelUri: string, hideActions?: boolean, + channelSubCount?: number, }; function ClaimAuthor(props: Props) { - const { channelUri, hideActions } = props; + const { channelUri, hideActions, channelSubCount } = props; return channelUri ? ( - + ) : (
{__('Anonymous')}
); diff --git a/ui/component/claimPreview/view.jsx b/ui/component/claimPreview/view.jsx index 00e153930..650839952 100644 --- a/ui/component/claimPreview/view.jsx +++ b/ui/component/claimPreview/view.jsx @@ -91,6 +91,7 @@ type Props = { date?: any, containerId?: string, // ID or name of the container (e.g. ClaimList, HOC, etc.) that this is in. indexInContainer?: number, // The index order of this component within 'containerId'. + channelSubCount?: number, }; const ClaimPreview = forwardRef((props: Props, ref: any) => { @@ -154,6 +155,7 @@ const ClaimPreview = forwardRef((props: Props, ref: any) => { disableNavigation, containerId, indexInContainer, + channelSubCount, } = props; const isCollection = claim && claim.value_type === 'collection'; const collectionClaimId = isCollection && claim && claim.claim_id; @@ -166,6 +168,18 @@ const ClaimPreview = forwardRef((props: Props, ref: any) => { const shouldHideActions = hideActions || isMyCollection || type === 'small' || type === 'tooltip'; const canonicalUrl = claim && claim.canonical_url; const lastCollectionIndex = collectionUris ? collectionUris.length - 1 : 0; + const channelSubscribers = React.useMemo(() => { + if (channelSubCount === undefined) { + return ; + } + return ( + + {channelSubCount === 1 + ? __('%channelSubCount% Follower', { channelSubCount }) + : __('%channelSubCount% Followers', { channelSubCount })} + + ); + }, [channelSubCount]); let isValid = false; if (uri) { try { @@ -399,6 +413,7 @@ const ClaimPreview = forwardRef((props: Props, ref: any) => { {(pending || !!reflectingProgress) && } + {channelSubscribers} {type !== 'small' && (
diff --git a/ui/component/fileTitleSection/index.js b/ui/component/fileTitleSection/index.js index a6a79fd5f..7af998148 100644 --- a/ui/component/fileTitleSection/index.js +++ b/ui/component/fileTitleSection/index.js @@ -1,4 +1,5 @@ import { connect } from 'react-redux'; +import { doFetchSubCount, makeSelectSubCountForUri } from 'lbryinc'; import { makeSelectTitleForUri, makeSelectClaimForUri } from 'lbry-redux'; import { makeSelectInsufficientCreditsForUri } from 'redux/selectors/content'; import { makeSelectViewersForId } from 'redux/selectors/livestream'; @@ -7,11 +8,21 @@ import FileTitleSection from './view'; const select = (state, props) => { const claim = makeSelectClaimForUri(props.uri)(state); const viewers = claim && makeSelectViewersForId(claim.claim_id)(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); + return { viewers, isInsufficientCredits: makeSelectInsufficientCreditsForUri(props.uri)(state), title: makeSelectTitleForUri(props.uri)(state), + channelClaimId, + subCount, }; }; -export default connect(select)(FileTitleSection); +const perform = (dispatch) => ({ + fetchSubCount: (claimId) => dispatch(doFetchSubCount(claimId)), +}); + +export default connect(select, perform)(FileTitleSection); diff --git a/ui/component/fileTitleSection/view.jsx b/ui/component/fileTitleSection/view.jsx index eb4fa2e7a..3b641a133 100644 --- a/ui/component/fileTitleSection/view.jsx +++ b/ui/component/fileTitleSection/view.jsx @@ -23,12 +23,32 @@ type Props = { livestream?: boolean, isLive?: boolean, viewers?: number, + subCount: number, + channelClaimId?: string, + fetchSubCount: (string) => void, }; function FileTitleSection(props: Props) { - const { title, uri, nsfw, isNsfwBlocked, livestream = false, isLive = false, viewers } = props; + const { + title, + uri, + nsfw, + isNsfwBlocked, + livestream = false, + isLive = false, + viewers, + subCount, + channelClaimId, + fetchSubCount, + } = props; const [hasAcknowledgedSec, setHasAcknowledgedSec] = usePersistedState('sec-nag', false); + React.useEffect(() => { + if (channelClaimId) { + fetchSubCount(channelClaimId); + } + }, [channelClaimId, fetchSubCount]); + return ( <> {!hasAcknowledgedSec && ( @@ -108,7 +128,7 @@ function FileTitleSection(props: Props) {
) : (
- +
) diff --git a/ui/scss/component/_claim-list.scss b/ui/scss/component/_claim-list.scss index a7215f379..dc963bd6b 100644 --- a/ui/scss/component/_claim-list.scss +++ b/ui/scss/component/_claim-list.scss @@ -276,6 +276,11 @@ color: var(--color-text); } +.claim-preview__channel-sub-count { + color: var(--color-text-subtitle); + font-size: var(--font-small); +} + .claim-preview__custom-properties { text-align: right; display: flex;