rename setReferrerPending and Error

bump lbryinc
improve invite states
register channels with apis
fix duplicate subscriptions
This commit is contained in:
jessop 2020-01-09 22:50:47 -05:00 committed by Sean Yesmunt
parent b16688754b
commit d1c4e96d60
9 changed files with 126 additions and 42 deletions

View file

@ -129,7 +129,7 @@
"json-loader": "^0.5.4",
"lbry-format": "https://github.com/lbryio/lbry-format.git",
"lbry-redux": "lbryio/lbry-redux#a2be979986dc93be4c2c596846109f5394f64fa1",
"lbryinc": "lbryio/lbryinc#6042c6f7bbf5fe7c6db2bd169f5b1c4558485c4c",
"lbryinc": "lbryio/lbryinc#018d149fb493615c7179d1ea3c497f07b9c8aed6",
"lint-staged": "^7.0.2",
"localforage": "^1.7.1",
"lodash-es": "^4.17.14",

View file

@ -41,7 +41,6 @@ type Props = {
fetchChannelListMine: () => void,
signIn: () => void,
requestDownloadUpgrade: () => void,
fetchChannelListMine: () => void,
onSignedIn: () => void,
setLanguage: string => void,
isUpgradeAvailable: boolean,

View file

@ -7,7 +7,13 @@ import {
selectUserInviteReferralCode,
doUserInviteNew,
} from 'lbryinc';
import { selectMyChannelClaims, selectFetchingMyChannels, doFetchChannelListMine } from 'lbry-redux';
import {
selectMyChannelClaims,
selectFetchingMyChannels,
doFetchChannelListMine,
doResolveUris,
selectResolvingUris,
} from 'lbry-redux';
import InviteNew from './view';
const select = state => ({
@ -18,11 +24,13 @@ const select = state => ({
isPending: selectUserInviteNewIsPending(state),
channels: selectMyChannelClaims(state),
fetchingChannels: selectFetchingMyChannels(state),
resolvingUris: selectResolvingUris(state),
});
const perform = dispatch => ({
inviteNew: email => dispatch(doUserInviteNew(email)),
fetchChannelListMine: () => dispatch(doFetchChannelListMine()),
resolveUris: uris => dispatch(doResolveUris(uris)),
});
export default connect(

View file

@ -6,6 +6,7 @@ import CopyableText from 'component/copyableText';
import Card from 'component/common/card';
import { URL } from 'config';
import SelectChannel from 'component/selectChannel';
import analytics from 'analytics';
import I18nMessage from 'component/i18nMessage';
type Props = {
@ -15,14 +16,42 @@ type Props = {
referralLink: string,
referralCode: string,
channels: any,
fetchChannelListMine: () => void,
fetchingChannels: boolean,
resolvingUris: Array<string>,
resolveUris: (Array<string>) => void,
};
function InviteNew(props: Props) {
const { inviteNew, fetchChannelListMine, errorMessage, isPending, referralCode, channels } = props;
const { inviteNew, errorMessage, isPending, referralCode = '', channels, resolveUris, resolvingUris } = props;
// Email
const [email, setEmail] = useState('');
function handleSubmit() {
inviteNew(email);
}
function handleEmailChanged(event: any) {
setEmail(event.target.value);
}
// Referral link
const [referralSource, setReferralSource] = useState(referralCode);
/* Canonical Referral links
* We need to make sure our channels are resolved so that canonical_url is present
*/
function handleReferralChange(code) {
setReferralSource(code);
// TODO: keep track of this in an array?
if (code !== referralCode) {
analytics.apiLogPublish(channels.find(ch => ch.name === code));
}
}
const [resolveStarted, setResolveStarted] = useState(false);
const [hasResolved, setHasResolved] = useState(false);
// join them so that useEffect doesn't update on new objects
const uris = channels && channels.map(channel => channel.permanent_url).join(',');
const channelCount = channels && channels.length;
const resolvingCount = resolvingUris && resolvingUris.length;
const topChannel =
channels &&
@ -31,32 +60,36 @@ function InviteNew(props: Props) {
);
const referralString =
channels && channels.length && referralSource !== referralCode
? getUrlFromName(referralSource, channels)
? lookupUrlByClaimName(referralSource, channels)
: referralSource;
const referral = `${URL}/$/invite/${referralString}`;
const referral = `${URL}/$/invite/${referralString.replace('#', ':')}`;
useEffect(() => {
// check emailverified and is_web?
fetchChannelListMine();
}, []);
useEffect(() => {
if (topChannel) {
setReferralSource(topChannel.name);
// resolve once, after we have channel list
if (!hasResolved && !resolveStarted && channelCount) {
setResolveStarted(true);
resolveUris(uris.split(','));
}
}, [topChannel]);
}, [channelCount, resolveStarted, hasResolved, resolvingCount, uris]);
function handleEmailChanged(event: any) {
setEmail(event.target.value);
}
useEffect(() => {
// once resolving count is 0, we know we're done
if (resolveStarted && !hasResolved && resolvingCount === 0) {
setHasResolved(true);
}
}, [resolveStarted, hasResolved, resolvingCount]);
function handleSubmit() {
inviteNew(email);
}
useEffect(() => {
// set default channel
if (topChannel && hasResolved) {
handleReferralChange(topChannel.name);
}
}, [topChannel, hasResolved]);
function getUrlFromName(name, channels) {
function lookupUrlByClaimName(name, channels) {
const claim = channels.find(channel => channel.name === name);
return claim ? claim.permanent_url.replace('lbry://', '') : name;
return claim ? claim.canonical_url.replace('lbry://', '') : name;
}
return (
@ -68,7 +101,7 @@ function InviteNew(props: Props) {
<Form onSubmit={handleSubmit}>
<SelectChannel
channel={referralSource}
onChannelChange={channel => setReferralSource(channel)}
onChannelChange={channel => handleReferralChange(channel)}
label={'Code or Channel'}
injected={[referralCode]}
/>

View file

@ -7,6 +7,7 @@ import {
selectSetReferrerPending,
selectSetReferrerError,
rewards as REWARDS,
selectUnclaimedRewards,
} from 'lbryinc';
import { doChannelSubscribe } from 'redux/actions/subscriptions';
import Invited from './view';
@ -14,8 +15,9 @@ import { withRouter } from 'react-router';
const select = state => ({
user: selectUser(state),
setReferrerPending: selectSetReferrerPending(state),
setReferrerError: selectSetReferrerError(state),
referrerSetPending: selectSetReferrerPending(state),
referrerSetError: selectSetReferrerError(state),
rewards: selectUnclaimedRewards(state),
});
const perform = dispatch => ({

View file

@ -6,16 +6,18 @@ import Button from 'component/button';
import ClaimPreview from 'component/claimPreview';
import Card from 'component/common/card';
import { parseURI } from 'lbry-redux';
import { rewards as REWARDS, ERRORS } from 'lbryinc';
type Props = {
user: any,
fetchUser: () => void,
claimReward: () => void,
setReferrer: string => void,
setReferrerPending: boolean,
setReferrerError: string,
referrerSetPending: boolean,
referrerSetError: string,
channelSubscribe: (sub: Subscription) => void,
history: { push: string => void },
rewards: Array<Reward>,
};
function Invited(props: Props) {
@ -24,10 +26,11 @@ function Invited(props: Props) {
fetchUser,
claimReward,
setReferrer,
setReferrerPending,
setReferrerError,
referrerSetPending,
referrerSetError,
channelSubscribe,
history,
rewards,
} = props;
// useParams requires react-router-dom ^v5.1.0
@ -36,16 +39,17 @@ function Invited(props: Props) {
const referrerIsChannel = parseURI(refUri).isChannel;
const rewardsApproved = user && user.is_reward_approved;
const hasVerifiedEmail = user && user.has_verified_email;
const referredRewardAvailable = rewards && rewards.some(reward => reward.reward_type === REWARDS.TYPE_REFEREE);
useEffect(() => {
fetchUser();
}, []);
useEffect(() => {
if (!setReferrerPending && hasVerifiedEmail) {
if (!referrerSetPending && hasVerifiedEmail) {
claimReward();
}
}, [setReferrerPending, hasVerifiedEmail]);
}, [referrerSetPending, hasVerifiedEmail]);
useEffect(() => {
if (referrer) {
@ -53,6 +57,16 @@ function Invited(props: Props) {
}
}, [referrer]);
// if they land here due to a referrer but already claimed, make them follow anyway
useEffect(() => {
if (!referredRewardAvailable && referrerIsChannel) {
channelSubscribe({
channelName: parseURI(refUri).claimName,
uri: refUri,
});
}
}, [referredRewardAvailable, referrerIsChannel]);
function handleDone() {
if (hasVerifiedEmail && referrerIsChannel) {
channelSubscribe({
@ -63,18 +77,43 @@ function Invited(props: Props) {
history.push(`/$/${PAGES.DISCOVER}`);
}
if (setReferrerError) {
if (referrerSetError === ERRORS.ALREADY_CLAIMED) {
return (
<Card
title={__(`Welcome!`)}
subtitle={referrerIsChannel ? __(`We've followed your referrer for you. Check it out!`) : __(`Congrats!`)}
actions={
<>
{referrerIsChannel && (
<div key={refUri} className="claim-preview--channel">
<ClaimPreview key={refUri} uri={refUri} actions={''} type={'small'} />
</div>
)}
<div className="card__actions">
<Button button="primary" label={__('Done!')} onClick={handleDone} />
</div>
</>
}
/>
);
}
if (referrerSetError && referredRewardAvailable) {
return (
<Card
title={__(`Welcome!`)}
subtitle={__(
`Something went wrong with this referral link. Take a look around. You can get earn rewards by setting your referrer later.`
`Something went wrong with your referral link. You can set and claim your referral reward after signing in.`
)}
actions={
<>
<p className="error-text">{__('Not a valid referral')}</p>
<p className="error-text">{setReferrerError}</p>
<div className="card__actions">
<Button
button="primary"
label={hasVerifiedEmail ? __('Verify') : __('Sign in')}
navigate={`/$/${PAGES.AUTH}?redirect=/$/${PAGES.REWARDS}`}
/>
<Button button="primary" label={__('Explore')} onClick={handleDone} />
</div>
</>
@ -112,7 +151,7 @@ function Invited(props: Props) {
return (
<Card
title={__(`Welcome!`)}
subtitle={__(`You can visit your referrer, or discover new stuff.`)}
subtitle={referrerIsChannel ? __(`We've followed your referrer for you. Check it out!`) : __(`Congrats!`)}
actions={
<>
{referrerIsChannel && (

View file

@ -4,8 +4,8 @@ import { doUserSetReferrer, selectSetReferrerError, selectSetReferrerPending } f
import ModalSetReferrer from './view';
const select = state => ({
setReferrerPending: selectSetReferrerPending(state),
setReferrerError: selectSetReferrerError(state),
referrerSetPending: selectSetReferrerPending(state),
referrerSetError: selectSetReferrerError(state),
});
const perform = dispatch => ({

View file

@ -9,8 +9,8 @@ type Props = {
error: ?string,
rewardIsPending: boolean,
setReferrer: (string, boolean) => void,
setReferrerPending: boolean,
setReferrerError?: string,
referrerSetPending: boolean,
referrerSetError?: string,
};
type State = {

View file

@ -21,7 +21,10 @@ export default handleActions(
[ACTIONS.CHANNEL_SUBSCRIBE]: (state: SubscriptionState, action: DoChannelSubscribe): SubscriptionState => {
const newSubscription: Subscription = action.data;
const newSubscriptions: Array<Subscription> = state.subscriptions.slice();
newSubscriptions.unshift(newSubscription);
// prevent duplicates in the sidebar
if (!newSubscriptions.some(sub => sub.uri === newSubscription.uri)) {
newSubscriptions.unshift(newSubscription);
}
return {
...state,