add reward rate + analytics link on channels page

This commit is contained in:
Sean Yesmunt 2020-10-12 17:12:46 -04:00
parent 65c39cbbc8
commit 4815aa9ff1
7 changed files with 87 additions and 3 deletions
ui
component
claimList
claimPreview
creatorAnalytics
page
channels
creatorDashboard
scss

View file

@ -36,6 +36,7 @@ type Props = {
injectedItem: ?Node, injectedItem: ?Node,
timedOutMessage?: Node, timedOutMessage?: Node,
tileLayout?: boolean, tileLayout?: boolean,
renderActions?: Claim => ?Node,
}; };
export default function ClaimList(props: Props) { export default function ClaimList(props: Props) {
@ -59,6 +60,7 @@ export default function ClaimList(props: Props) {
injectedItem, injectedItem,
timedOutMessage, timedOutMessage,
tileLayout = false, tileLayout = false,
renderActions,
} = props; } = props;
const [currentSort, setCurrentSort] = usePersistedState(persistedStorageKey, SORT_NEW); const [currentSort, setCurrentSort] = usePersistedState(persistedStorageKey, SORT_NEW);
@ -147,6 +149,7 @@ export default function ClaimList(props: Props) {
includeSupportAction={includeSupportAction} includeSupportAction={includeSupportAction}
showUnresolvedClaim={showUnresolvedClaims} showUnresolvedClaim={showUnresolvedClaims}
properties={renderProperties || (type !== 'small' ? undefined : false)} properties={renderProperties || (type !== 'small' ? undefined : false)}
renderActions={renderActions}
showUserBlocked={showHiddenByUser} showUserBlocked={showHiddenByUser}
hideBlock={hideBlock} hideBlock={hideBlock}
customShouldHide={(claim: StreamClaim) => { customShouldHide={(claim: StreamClaim) => {

View file

@ -59,6 +59,8 @@ type Props = {
customShouldHide?: Claim => boolean, customShouldHide?: Claim => boolean,
showUnresolvedClaim?: boolean, showUnresolvedClaim?: boolean,
includeSupportAction?: boolean, includeSupportAction?: boolean,
hideActions?: boolean,
renderActions?: Claim => ?Node,
}; };
const ClaimPreview = forwardRef<any, {}>((props: Props, ref: any) => { const ClaimPreview = forwardRef<any, {}>((props: Props, ref: any) => {
@ -91,12 +93,14 @@ const ClaimPreview = forwardRef<any, {}>((props: Props, ref: any) => {
customShouldHide, customShouldHide,
showUnresolvedClaim, showUnresolvedClaim,
includeSupportAction, includeSupportAction,
hideActions = false,
renderActions,
} = props; } = props;
const shouldFetch = const shouldFetch =
claim === undefined || (claim !== null && claim.value_type === 'channel' && isEmpty(claim.meta) && !pending); claim === undefined || (claim !== null && claim.value_type === 'channel' && isEmpty(claim.meta) && !pending);
const abandoned = !isResolvingUri && !claim; const abandoned = !isResolvingUri && !claim;
const showPublishLink = abandoned && !showUnresolvedClaim && placeholder === 'publish'; const showPublishLink = abandoned && !showUnresolvedClaim && placeholder === 'publish';
const hideActions = type === 'small' || type === 'tooltip'; const shouldHideActions = hideActions || type === 'small' || type === 'tooltip';
const canonicalUrl = claim && claim.canonical_url; const canonicalUrl = claim && claim.canonical_url;
let isValid = false; let isValid = false;
if (uri) { if (uri) {
@ -286,7 +290,8 @@ const ClaimPreview = forwardRef<any, {}>((props: Props, ref: any) => {
<div className="claim-preview__actions"> <div className="claim-preview__actions">
{!pending && ( {!pending && (
<> <>
{hideActions ? null : actions !== undefined ? ( {renderActions && claim && renderActions(claim)}
{shouldHideActions || renderActions ? null : actions !== undefined ? (
actions actions
) : ( ) : (
<div className="claim-preview__primary-actions"> <div className="claim-preview__primary-actions">

View file

@ -26,7 +26,7 @@ export default function CreatorAnalytics(props: Props) {
const history = useHistory(); const history = useHistory();
const [stats, setStats] = React.useState(); const [stats, setStats] = React.useState();
const [error, setError] = React.useState(); const [error, setError] = React.useState();
const [fetchingStats, setFetchingStats] = React.useState(false); const [fetchingStats, setFetchingStats] = React.useState(true);
const claimId = claim && claim.claim_id; const claimId = claim && claim.claim_id;
const channelHasClaims = claim && claim.meta && claim.meta.claims_in_channel && claim.meta.claims_in_channel > 0; const channelHasClaims = claim && claim.meta && claim.meta.claims_in_channel && claim.meta.claims_in_channel > 0;

View file

@ -1,12 +1,14 @@
// @flow // @flow
import * as ICONS from 'constants/icons'; import * as ICONS from 'constants/icons';
import React, { useEffect } from 'react'; import React, { useEffect } from 'react';
import { Lbryio } from 'lbryinc';
import ClaimList from 'component/claimList'; import ClaimList from 'component/claimList';
import Page from 'component/page'; import Page from 'component/page';
import Button from 'component/button'; import Button from 'component/button';
import YoutubeTransferStatus from 'component/youtubeTransferStatus'; import YoutubeTransferStatus from 'component/youtubeTransferStatus';
import Spinner from 'component/spinner'; import Spinner from 'component/spinner';
import Yrbl from 'component/yrbl'; import Yrbl from 'component/yrbl';
import LbcSymbol from 'component/common/lbc-symbol';
import * as PAGES from 'constants/pages'; import * as PAGES from 'constants/pages';
type Props = { type Props = {
@ -19,6 +21,7 @@ type Props = {
export default function ChannelsPage(props: Props) { export default function ChannelsPage(props: Props) {
const { channels, channelUrls, fetchChannelListMine, fetchingChannels, youtubeChannels } = props; const { channels, channelUrls, fetchChannelListMine, fetchingChannels, youtubeChannels } = props;
const [rewardData, setRewardData] = React.useState();
const hasYoutubeChannels = youtubeChannels && Boolean(youtubeChannels.length); const hasYoutubeChannels = youtubeChannels && Boolean(youtubeChannels.length);
const hasPendingChannels = channels && channels.some(channel => channel.confirmations < 0); const hasPendingChannels = channels && channels.some(channel => channel.confirmations < 0);
@ -26,6 +29,10 @@ export default function ChannelsPage(props: Props) {
fetchChannelListMine(); fetchChannelListMine();
}, [fetchChannelListMine, hasPendingChannels]); }, [fetchChannelListMine, hasPendingChannels]);
useEffect(() => {
Lbryio.call('user_rewards', 'view_rate').then(data => setRewardData(data));
}, [setRewardData]);
return ( return (
<Page> <Page>
<div className="card-stack"> <div className="card-stack">
@ -44,6 +51,44 @@ export default function ChannelsPage(props: Props) {
} }
loading={fetchingChannels} loading={fetchingChannels}
uris={channelUrls} uris={channelUrls}
renderActions={claim => {
const claimsInChannel = claim.meta.claims_in_channel;
return claimsInChannel === 0 ? (
<span />
) : (
<div className="section__actions">
<Button
button="alt"
icon={ICONS.ANALYTICS}
label={__('Analytics')}
navigate={`/$/${PAGES.CREATOR_DASHBOARD}?channel=${encodeURIComponent(claim.canonical_url)}`}
/>
</div>
);
}}
renderProperties={claim => {
const claimsInChannel = claim.meta.claims_in_channel;
if (!claim || claimsInChannel === 0) {
return null;
}
const channelRewardData =
rewardData &&
rewardData.rates.find(data => {
return data.channel_claim_id === claim.claim_id;
});
if (channelRewardData) {
return (
<span className="claim-preview__custom-properties">
<span className="help--inline">{__('Earnings per view')}</span>
<LbcSymbol postfix={channelRewardData.view_rate.toFixed(2)} />
</span>
);
} else {
return null;
}
}}
/> />
)} )}
</div> </div>

View file

@ -8,14 +8,23 @@ import CreatorAnalytics from 'component/creatorAnalytics';
import ChannelSelector from 'component/channelSelector'; import ChannelSelector from 'component/channelSelector';
import usePersistedState from 'effects/use-persisted-state'; import usePersistedState from 'effects/use-persisted-state';
import Yrbl from 'component/yrbl'; import Yrbl from 'component/yrbl';
import { useHistory } from 'react-router';
type Props = { type Props = {
channels: Array<ChannelClaim>, channels: Array<ChannelClaim>,
fetchingChannels: boolean, fetchingChannels: boolean,
}; };
const SELECTED_CHANNEL_QUERY_PARAM = 'channel';
export default function CreatorDashboardPage(props: Props) { export default function CreatorDashboardPage(props: Props) {
const { channels, fetchingChannels } = props; const { channels, fetchingChannels } = props;
const {
push,
location: { search, pathname },
} = useHistory();
const urlParams = new URLSearchParams(search);
const channelFromUrl = urlParams.get(SELECTED_CHANNEL_QUERY_PARAM);
const [selectedChannelUrl, setSelectedChannelUrl] = usePersistedState('analytics-selected-channel'); const [selectedChannelUrl, setSelectedChannelUrl] = usePersistedState('analytics-selected-channel');
const hasChannels = channels && channels.length > 0; const hasChannels = channels && channels.length > 0;
const firstChannel = hasChannels && channels[0]; const firstChannel = hasChannels && channels[0];
@ -33,6 +42,19 @@ export default function CreatorDashboardPage(props: Props) {
} }
}, [setSelectedChannelUrl, selectedChannelUrl, firstChannelUrl, channelFoundForSelectedChannelUrl]); }, [setSelectedChannelUrl, selectedChannelUrl, firstChannelUrl, channelFoundForSelectedChannelUrl]);
React.useEffect(() => {
if (channelFromUrl) {
const decodedChannel = decodeURIComponent(channelFromUrl);
setSelectedChannelUrl(decodedChannel);
}
}, [channelFromUrl, setSelectedChannelUrl]);
function updateUrl(channelUrl) {
const newUrlParams = new URLSearchParams();
newUrlParams.append(SELECTED_CHANNEL_QUERY_PARAM, encodeURIComponent(channelUrl));
push(`${pathname}?${newUrlParams.toString()}`);
}
return ( return (
<Page> <Page>
{fetchingChannels && ( {fetchingChannels && (
@ -59,6 +81,7 @@ export default function CreatorDashboardPage(props: Props) {
<ChannelSelector <ChannelSelector
selectedChannelUrl={selectedChannelUrl} selectedChannelUrl={selectedChannelUrl}
onChannelSelect={newChannelUrl => { onChannelSelect={newChannelUrl => {
updateUrl(newChannelUrl);
setSelectedChannelUrl(newChannelUrl); setSelectedChannelUrl(newChannelUrl);
}} }}
/> />

View file

@ -200,6 +200,10 @@
color: var(--color-text); color: var(--color-text);
} }
.claim-preview__custom-properties {
text-align: right;
}
.claim-preview-metadata { .claim-preview-metadata {
display: flex; display: flex;
flex-direction: column; flex-direction: column;

View file

@ -230,6 +230,10 @@ textarea {
@extend .help; @extend .help;
margin-top: 0; margin-top: 0;
margin-bottom: 0; margin-bottom: 0;
&:not(:last-child) {
margin-bottom: 0;
}
} }
.help--card-actions { .help--card-actions {