fix: recommended subscriptions

This commit is contained in:
Sean Yesmunt 2019-07-08 13:06:42 -04:00
parent e7af386608
commit 23f073de3f
7 changed files with 103 additions and 128 deletions

View file

@ -14,7 +14,6 @@ import FileListPublished from 'page/fileListPublished';
import TransactionHistoryPage from 'page/transactionHistory'; import TransactionHistoryPage from 'page/transactionHistory';
import AuthPage from 'page/auth'; import AuthPage from 'page/auth';
import InvitePage from 'page/invite'; import InvitePage from 'page/invite';
import SubscriptionsPage from 'page/subscriptions';
import SearchPage from 'page/search'; import SearchPage from 'page/search';
import LibraryPage from 'page/library'; import LibraryPage from 'page/library';
import WalletPage from 'page/wallet'; import WalletPage from 'page/wallet';
@ -56,8 +55,7 @@ export default function AppRouter() {
<Route path={`/$/${PAGES.ACCOUNT}`} exact component={AccountPage} /> <Route path={`/$/${PAGES.ACCOUNT}`} exact component={AccountPage} />
<Route path={`/$/${PAGES.LIBRARY}/all`} exact component={NavigationHistory} /> <Route path={`/$/${PAGES.LIBRARY}/all`} exact component={NavigationHistory} />
<Route path={`/$/${PAGES.TAGS}`} exact component={TagsPage} /> <Route path={`/$/${PAGES.TAGS}`} exact component={TagsPage} />
<Route path={`/$/${PAGES.FOLLOWING}`} exact component={SubscriptionsPage} /> <Route path={`/$/${PAGES.FOLLOWING}`} exact component={FollowingPage} />
<Route path={`/$/${PAGES.FOLLOWING}/customize`} exact component={FollowingPage} />
<Route path={`/$/${PAGES.WALLET}`} exact component={WalletPage} /> <Route path={`/$/${PAGES.WALLET}`} exact component={WalletPage} />
{/* Below need to go at the end to make sure we don't match any of our pages first */} {/* Below need to go at the end to make sure we don't match any of our pages first */}
<Route path="/:claimName" exact component={ShowPage} /> <Route path="/:claimName" exact component={ShowPage} />

View file

@ -1,4 +1,5 @@
// @flow // @flow
import * as PAGES from 'constants/pages';
import React from 'react'; import React from 'react';
import ClaimListDiscover from 'component/claimListDiscover'; import ClaimListDiscover from 'component/claimListDiscover';
import TagsSelect from 'component/tagsSelect'; import TagsSelect from 'component/tagsSelect';
@ -17,7 +18,7 @@ function DiscoverPage(props: Props) {
<ClaimListDiscover <ClaimListDiscover
personal personal
tags={followedTags.map(tag => tag.name)} tags={followedTags.map(tag => tag.name)}
meta={<Button button="link" label={__('Customize')} navigate="/$/following/customize" />} meta={<Button button="link" label={__('Customize')} navigate={`/$/${PAGES.FOLLOWING}`} />}
injectedItem={<TagsSelect showClose title={__('Customize Your Homepage')} />} injectedItem={<TagsSelect showClose title={__('Customize Your Homepage')} />}
/> />
</Page> </Page>

View file

@ -1,16 +1,19 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { selectFollowedTags } from 'lbry-redux'; import { selectFollowedTags } from 'lbry-redux';
import { selectSubscriptions } from 'redux/selectors/subscriptions'; import { selectSubscriptions, selectSuggestedChannels } from 'redux/selectors/subscriptions';
import { doFetchRecommendedSubscriptions } from 'redux/actions/subscriptions';
import TagsEdit from './view'; import TagsEdit from './view';
const select = state => ({ const select = state => ({
followedTags: selectFollowedTags(state), followedTags: selectFollowedTags(state),
subscribedChannels: selectSubscriptions(state), subscribedChannels: selectSubscriptions(state),
suggestedSubscriptions: selectSuggestedChannels(state),
}); });
const perform = {};
export default connect( export default connect(
select, select,
perform {
doFetchRecommendedSubscriptions,
}
)(TagsEdit); )(TagsEdit);

View file

@ -1,26 +1,61 @@
// @flow // @flow
import React from 'react'; import * as PAGES from 'constants/pages';
import React, { useEffect } from 'react';
import Page from 'component/page'; import Page from 'component/page';
import TagsSelect from 'component/tagsSelect'; import TagsSelect from 'component/tagsSelect';
import ClaimList from 'component/claimList'; import ClaimList from 'component/claimList';
import Button from 'component/button';
type Props = { type Props = {
subscribedChannels: Array<Subscription>, subscribedChannels: Array<Subscription>,
location: { search: string },
history: { push: string => void },
doFetchRecommendedSubscriptions: () => void,
suggestedSubscriptions: Array<{ uri: string }>,
}; };
function FollowingEditPage(props: Props) { function FollowingPage(props: Props) {
const { subscribedChannels } = props; const { subscribedChannels, location, history, doFetchRecommendedSubscriptions, suggestedSubscriptions } = props;
const hasSubscriptions = !!subscribedChannels.length;
const channelUris = subscribedChannels.map(({ uri }) => uri); const channelUris = subscribedChannels.map(({ uri }) => uri);
const { search } = location;
const urlParams = new URLSearchParams(search);
const viewingSuggestedSubs = urlParams.get('view') || !hasSubscriptions;
function onClick() {
let url = `/$/${PAGES.FOLLOWING}`;
if (!viewingSuggestedSubs) {
url += '?view=discover';
}
history.push(url);
}
useEffect(() => {
doFetchRecommendedSubscriptions();
}, [doFetchRecommendedSubscriptions]);
return ( return (
<Page> <Page>
<div className="card"> <div className="card">
<TagsSelect showClose={false} title={__('Customize Your Tags')} /> <TagsSelect showClose={false} title={__('Customize Your Tags')} />
</div> </div>
<div className="card"> <div className="card">
<ClaimList header={<h1>{__('Channels You Follow')}</h1>} uris={channelUris} /> <ClaimList
header={<h1>{viewingSuggestedSubs ? __('Discover New Channels') : __('Channels You Follow')}</h1>}
headerAltControls={
<Button
button="link"
label={viewingSuggestedSubs ? hasSubscriptions && __('View Your Channels') : __('Find New Channels')}
onClick={() => onClick()}
/>
}
uris={viewingSuggestedSubs ? suggestedSubscriptions.map(sub => sub.uri) : channelUris}
/>
</div> </div>
</Page> </Page>
); );
} }
export default FollowingEditPage; export default FollowingPage;

View file

@ -1,26 +0,0 @@
import { connect } from 'react-redux';
import {
selectSubscriptions,
selectSubscriptionsBeingFetched,
selectIsFetchingSubscriptions,
selectSuggestedChannels,
} from 'redux/selectors/subscriptions';
import { doFetchMySubscriptions, doFetchRecommendedSubscriptions } from 'redux/actions/subscriptions';
import { selectLastClaimSearchUris, doClaimSearch } from 'lbry-redux';
import SubscriptionsPage from './view';
const select = state => ({
loading: selectIsFetchingSubscriptions(state) || Boolean(Object.keys(selectSubscriptionsBeingFetched(state)).length),
subscribedChannels: selectSubscriptions(state),
suggestedSubscriptions: selectSuggestedChannels(state),
uris: selectLastClaimSearchUris(state),
});
export default connect(
select,
{
doFetchMySubscriptions,
doFetchRecommendedSubscriptions,
doClaimSearch,
}
)(SubscriptionsPage);

View file

@ -1,87 +0,0 @@
// @flow
import * as PAGES from 'constants/pages';
import React, { useEffect, useState } from 'react';
import Page from 'component/page';
import ClaimList from 'component/claimList';
import ClaimPreview from 'component/claimPreview';
import Button from 'component/button';
type Props = {
subscribedChannels: Array<{ uri: string }>, // The channels a user is subscribed to
suggestedSubscriptions: Array<{ uri: string }>,
loading: boolean,
doFetchMySubscriptions: () => void,
doFetchRecommendedSubscriptions: () => void,
location: { search: string },
history: { push: string => void },
doClaimSearch: (number, {}) => void,
uris: Array<string>,
};
export default function SubscriptionsPage(props: Props) {
const {
subscribedChannels,
doFetchMySubscriptions,
doFetchRecommendedSubscriptions,
suggestedSubscriptions,
loading,
location,
history,
doClaimSearch,
uris,
} = props;
const [page, setPage] = useState(1);
const hasSubscriptions = !!subscribedChannels.length;
const { search } = location;
const urlParams = new URLSearchParams(search);
const viewingSuggestedSubs = urlParams.get('view');
function onClick() {
let url = `/$/${PAGES.FOLLOWING}`;
if (!viewingSuggestedSubs) {
url += '?view=discover';
}
history.push(url);
}
useEffect(() => {
doFetchMySubscriptions();
doFetchRecommendedSubscriptions();
}, [doFetchMySubscriptions, doFetchRecommendedSubscriptions]);
const idString = subscribedChannels.map(channel => channel.uri.split('#')[1]).join(',');
useEffect(() => {
const ids = idString.split(',');
const options = {
page,
channel_ids: ids,
order_by: ['release_time'],
};
doClaimSearch(20, options);
}, [idString, doClaimSearch, page]);
return (
<Page>
<div className="card">
<ClaimList
loading={loading}
header={
<h1>{viewingSuggestedSubs ? __('Discover New Channels') : __("Latest From Who You're Following")}</h1>
}
headerAltControls={
<Button
button="link"
label={viewingSuggestedSubs ? hasSubscriptions && __('View Your Feed') : __('Find New Channels')}
onClick={() => onClick()}
/>
}
uris={viewingSuggestedSubs ? suggestedSubscriptions.map(sub => sub.uri) : uris}
onScrollBottom={() => console.log('scroll bottom') || setPage(page + 1)}
/>
{loading && page > 1 && new Array(20).fill(1).map((x, i) => <ClaimPreview key={i} placeholder />)}
</div>
</Page>
);
}

View file

@ -480,5 +480,56 @@
"Got it!": "Got it!", "Got it!": "Got it!",
"Filter": "Filter", "Filter": "Filter",
"Rendering document.": "Rendering document.", "Rendering document.": "Rendering document.",
"Sorry, looks like we can't load the document.": "Sorry, looks like we can't load the document." "Sorry, looks like we can't load the document.": "Sorry, looks like we can't load the document.",
"Tag Search": "Tag Search",
"Disabled": "Disabled",
"Rewards are currently disabled for your account. Turn on diagnostic data sharing, in": "Rewards are currently disabled for your account. Turn on diagnostic data sharing, in",
", in order to re-enable them.": ", in order to re-enable them.",
"Humans Only": "Humans Only",
"Rewards are for human beings only.": "Rewards are for human beings only.",
"You'll have to prove you're one of us before you can claim any rewards.": "You'll have to prove you're one of us before you can claim any rewards.",
"Rewawrds ": "Rewawrds ",
"Verification For Rewards": "Verification For Rewards",
"Fetching rewards": "Fetching rewards",
"This is optional.": "This is optional.",
"Verify Your Email": "Verify Your Email",
"Final Human Proof": "Final Human Proof",
"1) Proof via Credit": "1) Proof via Credit",
"If you have a valid credit or debit card, you can use it to instantly prove your humanity.": "If you have a valid credit or debit card, you can use it to instantly prove your humanity.",
"LBRY does not store your credit card information. There is no charge at all for this, now or in the future.": "LBRY does not store your credit card information. There is no charge at all for this, now or in the future.",
"Perform Card Verification": "Perform Card Verification",
"A $1 authorization may temporarily appear with your provider.": "A $1 authorization may temporarily appear with your provider.",
"Read more about why we do this.": "Read more about why we do this.",
"2) Proof via Phone": "2) Proof via Phone",
"You will receive an SMS text message confirming that your phone number is correct.": "You will receive an SMS text message confirming that your phone number is correct.",
"Submit Phone Number": "Submit Phone Number",
"Standard messaging rates apply. Having trouble?": "Standard messaging rates apply. Having trouble?",
"Read more.": "Read more.",
"3) Proof via Chat": "3) Proof via Chat",
"A moderator capable of approving you is typically available in the discord server. Check out the #rewards-approval channel for more information.": "A moderator capable of approving you is typically available in the discord server. Check out the #rewards-approval channel for more information.",
"This process will likely involve providing proof of a stable and established online or real-life identity.": "This process will likely involve providing proof of a stable and established online or real-life identity.",
"Join LBRY Chat": "Join LBRY Chat",
"Or, Skip It Entirely": "Or, Skip It Entirely",
"You can continue without this step, but you will not be eligible to earn rewards.": "You can continue without this step, but you will not be eligible to earn rewards.",
"Skip Rewards": "Skip Rewards",
"Waiting For Verification": "Waiting For Verification",
"An email was sent to": "An email was sent to",
"Follow the link and you will be good to go. This will update automatically.": "Follow the link and you will be good to go. This will update automatically.",
"Resend verification email": "Resend verification email",
"if you encounter any trouble verifying.": "if you encounter any trouble verifying.",
"Blockchain Sync": "Blockchain Sync",
"Catching up with the blockchain": "Catching up with the blockchain",
"No Rewards Available": "No Rewards Available",
"There are no rewards available at this time, please check back later.": "There are no rewards available at this time, please check back later.",
"Confirm Identity": "Confirm Identity",
"Not following any channels": "Not following any channels",
"Subscriptions 101": "Subscriptions 101",
"You just subscribed to your first channel. Awesome!": "You just subscribed to your first channel. Awesome!",
"A few quick things to know:": "A few quick things to know:",
"1) This app will automatically download new free content from channels you are subscribed to. You may configure this in Settings or on the Subscriptions page.": "1) This app will automatically download new free content from channels you are subscribed to. You may configure this in Settings or on the Subscriptions page.",
"2) If we have your email address, we will send you notifications related to new content. You may configure these emails from the Help page.": "2) If we have your email address, we will send you notifications related to new content. You may configure these emails from the Help page.",
"Got it": "Got it",
"View Your Feed": "View Your Feed",
"View Your Channels": "View Your Channels",
"Unfollow": "Unfollow"
} }