mirror of
https://github.com/LBRYFoundation/lbry-desktop.git
synced 2025-09-01 09:45:10 +00:00
rename setReferrerPending and Error
bump lbryinc improve invite states register channels with apis fix duplicate subscriptions
This commit is contained in:
parent
b16688754b
commit
d1c4e96d60
9 changed files with 126 additions and 42 deletions
|
@ -129,7 +129,7 @@
|
||||||
"json-loader": "^0.5.4",
|
"json-loader": "^0.5.4",
|
||||||
"lbry-format": "https://github.com/lbryio/lbry-format.git",
|
"lbry-format": "https://github.com/lbryio/lbry-format.git",
|
||||||
"lbry-redux": "lbryio/lbry-redux#a2be979986dc93be4c2c596846109f5394f64fa1",
|
"lbry-redux": "lbryio/lbry-redux#a2be979986dc93be4c2c596846109f5394f64fa1",
|
||||||
"lbryinc": "lbryio/lbryinc#6042c6f7bbf5fe7c6db2bd169f5b1c4558485c4c",
|
"lbryinc": "lbryio/lbryinc#018d149fb493615c7179d1ea3c497f07b9c8aed6",
|
||||||
"lint-staged": "^7.0.2",
|
"lint-staged": "^7.0.2",
|
||||||
"localforage": "^1.7.1",
|
"localforage": "^1.7.1",
|
||||||
"lodash-es": "^4.17.14",
|
"lodash-es": "^4.17.14",
|
||||||
|
|
|
@ -41,7 +41,6 @@ type Props = {
|
||||||
fetchChannelListMine: () => void,
|
fetchChannelListMine: () => void,
|
||||||
signIn: () => void,
|
signIn: () => void,
|
||||||
requestDownloadUpgrade: () => void,
|
requestDownloadUpgrade: () => void,
|
||||||
fetchChannelListMine: () => void,
|
|
||||||
onSignedIn: () => void,
|
onSignedIn: () => void,
|
||||||
setLanguage: string => void,
|
setLanguage: string => void,
|
||||||
isUpgradeAvailable: boolean,
|
isUpgradeAvailable: boolean,
|
||||||
|
|
|
@ -7,7 +7,13 @@ import {
|
||||||
selectUserInviteReferralCode,
|
selectUserInviteReferralCode,
|
||||||
doUserInviteNew,
|
doUserInviteNew,
|
||||||
} from 'lbryinc';
|
} from 'lbryinc';
|
||||||
import { selectMyChannelClaims, selectFetchingMyChannels, doFetchChannelListMine } from 'lbry-redux';
|
import {
|
||||||
|
selectMyChannelClaims,
|
||||||
|
selectFetchingMyChannels,
|
||||||
|
doFetchChannelListMine,
|
||||||
|
doResolveUris,
|
||||||
|
selectResolvingUris,
|
||||||
|
} from 'lbry-redux';
|
||||||
import InviteNew from './view';
|
import InviteNew from './view';
|
||||||
|
|
||||||
const select = state => ({
|
const select = state => ({
|
||||||
|
@ -18,11 +24,13 @@ const select = state => ({
|
||||||
isPending: selectUserInviteNewIsPending(state),
|
isPending: selectUserInviteNewIsPending(state),
|
||||||
channels: selectMyChannelClaims(state),
|
channels: selectMyChannelClaims(state),
|
||||||
fetchingChannels: selectFetchingMyChannels(state),
|
fetchingChannels: selectFetchingMyChannels(state),
|
||||||
|
resolvingUris: selectResolvingUris(state),
|
||||||
});
|
});
|
||||||
|
|
||||||
const perform = dispatch => ({
|
const perform = dispatch => ({
|
||||||
inviteNew: email => dispatch(doUserInviteNew(email)),
|
inviteNew: email => dispatch(doUserInviteNew(email)),
|
||||||
fetchChannelListMine: () => dispatch(doFetchChannelListMine()),
|
fetchChannelListMine: () => dispatch(doFetchChannelListMine()),
|
||||||
|
resolveUris: uris => dispatch(doResolveUris(uris)),
|
||||||
});
|
});
|
||||||
|
|
||||||
export default connect(
|
export default connect(
|
||||||
|
|
|
@ -6,6 +6,7 @@ import CopyableText from 'component/copyableText';
|
||||||
import Card from 'component/common/card';
|
import Card from 'component/common/card';
|
||||||
import { URL } from 'config';
|
import { URL } from 'config';
|
||||||
import SelectChannel from 'component/selectChannel';
|
import SelectChannel from 'component/selectChannel';
|
||||||
|
import analytics from 'analytics';
|
||||||
import I18nMessage from 'component/i18nMessage';
|
import I18nMessage from 'component/i18nMessage';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
|
@ -15,14 +16,42 @@ type Props = {
|
||||||
referralLink: string,
|
referralLink: string,
|
||||||
referralCode: string,
|
referralCode: string,
|
||||||
channels: any,
|
channels: any,
|
||||||
fetchChannelListMine: () => void,
|
resolvingUris: Array<string>,
|
||||||
fetchingChannels: boolean,
|
resolveUris: (Array<string>) => void,
|
||||||
};
|
};
|
||||||
|
|
||||||
function InviteNew(props: Props) {
|
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('');
|
const [email, setEmail] = useState('');
|
||||||
|
function handleSubmit() {
|
||||||
|
inviteNew(email);
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleEmailChanged(event: any) {
|
||||||
|
setEmail(event.target.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Referral link
|
||||||
const [referralSource, setReferralSource] = useState(referralCode);
|
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 =
|
const topChannel =
|
||||||
channels &&
|
channels &&
|
||||||
|
@ -31,32 +60,36 @@ function InviteNew(props: Props) {
|
||||||
);
|
);
|
||||||
const referralString =
|
const referralString =
|
||||||
channels && channels.length && referralSource !== referralCode
|
channels && channels.length && referralSource !== referralCode
|
||||||
? getUrlFromName(referralSource, channels)
|
? lookupUrlByClaimName(referralSource, channels)
|
||||||
: referralSource;
|
: referralSource;
|
||||||
const referral = `${URL}/$/invite/${referralString}`;
|
|
||||||
|
const referral = `${URL}/$/invite/${referralString.replace('#', ':')}`;
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// check emailverified and is_web?
|
// resolve once, after we have channel list
|
||||||
fetchChannelListMine();
|
if (!hasResolved && !resolveStarted && channelCount) {
|
||||||
}, []);
|
setResolveStarted(true);
|
||||||
|
resolveUris(uris.split(','));
|
||||||
useEffect(() => {
|
|
||||||
if (topChannel) {
|
|
||||||
setReferralSource(topChannel.name);
|
|
||||||
}
|
}
|
||||||
}, [topChannel]);
|
}, [channelCount, resolveStarted, hasResolved, resolvingCount, uris]);
|
||||||
|
|
||||||
function handleEmailChanged(event: any) {
|
useEffect(() => {
|
||||||
setEmail(event.target.value);
|
// once resolving count is 0, we know we're done
|
||||||
}
|
if (resolveStarted && !hasResolved && resolvingCount === 0) {
|
||||||
|
setHasResolved(true);
|
||||||
|
}
|
||||||
|
}, [resolveStarted, hasResolved, resolvingCount]);
|
||||||
|
|
||||||
function handleSubmit() {
|
useEffect(() => {
|
||||||
inviteNew(email);
|
// 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);
|
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 (
|
return (
|
||||||
|
@ -68,7 +101,7 @@ function InviteNew(props: Props) {
|
||||||
<Form onSubmit={handleSubmit}>
|
<Form onSubmit={handleSubmit}>
|
||||||
<SelectChannel
|
<SelectChannel
|
||||||
channel={referralSource}
|
channel={referralSource}
|
||||||
onChannelChange={channel => setReferralSource(channel)}
|
onChannelChange={channel => handleReferralChange(channel)}
|
||||||
label={'Code or Channel'}
|
label={'Code or Channel'}
|
||||||
injected={[referralCode]}
|
injected={[referralCode]}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -7,6 +7,7 @@ import {
|
||||||
selectSetReferrerPending,
|
selectSetReferrerPending,
|
||||||
selectSetReferrerError,
|
selectSetReferrerError,
|
||||||
rewards as REWARDS,
|
rewards as REWARDS,
|
||||||
|
selectUnclaimedRewards,
|
||||||
} from 'lbryinc';
|
} from 'lbryinc';
|
||||||
import { doChannelSubscribe } from 'redux/actions/subscriptions';
|
import { doChannelSubscribe } from 'redux/actions/subscriptions';
|
||||||
import Invited from './view';
|
import Invited from './view';
|
||||||
|
@ -14,8 +15,9 @@ import { withRouter } from 'react-router';
|
||||||
|
|
||||||
const select = state => ({
|
const select = state => ({
|
||||||
user: selectUser(state),
|
user: selectUser(state),
|
||||||
setReferrerPending: selectSetReferrerPending(state),
|
referrerSetPending: selectSetReferrerPending(state),
|
||||||
setReferrerError: selectSetReferrerError(state),
|
referrerSetError: selectSetReferrerError(state),
|
||||||
|
rewards: selectUnclaimedRewards(state),
|
||||||
});
|
});
|
||||||
|
|
||||||
const perform = dispatch => ({
|
const perform = dispatch => ({
|
||||||
|
|
|
@ -6,16 +6,18 @@ import Button from 'component/button';
|
||||||
import ClaimPreview from 'component/claimPreview';
|
import ClaimPreview from 'component/claimPreview';
|
||||||
import Card from 'component/common/card';
|
import Card from 'component/common/card';
|
||||||
import { parseURI } from 'lbry-redux';
|
import { parseURI } from 'lbry-redux';
|
||||||
|
import { rewards as REWARDS, ERRORS } from 'lbryinc';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
user: any,
|
user: any,
|
||||||
fetchUser: () => void,
|
fetchUser: () => void,
|
||||||
claimReward: () => void,
|
claimReward: () => void,
|
||||||
setReferrer: string => void,
|
setReferrer: string => void,
|
||||||
setReferrerPending: boolean,
|
referrerSetPending: boolean,
|
||||||
setReferrerError: string,
|
referrerSetError: string,
|
||||||
channelSubscribe: (sub: Subscription) => void,
|
channelSubscribe: (sub: Subscription) => void,
|
||||||
history: { push: string => void },
|
history: { push: string => void },
|
||||||
|
rewards: Array<Reward>,
|
||||||
};
|
};
|
||||||
|
|
||||||
function Invited(props: Props) {
|
function Invited(props: Props) {
|
||||||
|
@ -24,10 +26,11 @@ function Invited(props: Props) {
|
||||||
fetchUser,
|
fetchUser,
|
||||||
claimReward,
|
claimReward,
|
||||||
setReferrer,
|
setReferrer,
|
||||||
setReferrerPending,
|
referrerSetPending,
|
||||||
setReferrerError,
|
referrerSetError,
|
||||||
channelSubscribe,
|
channelSubscribe,
|
||||||
history,
|
history,
|
||||||
|
rewards,
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
// useParams requires react-router-dom ^v5.1.0
|
// useParams requires react-router-dom ^v5.1.0
|
||||||
|
@ -36,16 +39,17 @@ function Invited(props: Props) {
|
||||||
const referrerIsChannel = parseURI(refUri).isChannel;
|
const referrerIsChannel = parseURI(refUri).isChannel;
|
||||||
const rewardsApproved = user && user.is_reward_approved;
|
const rewardsApproved = user && user.is_reward_approved;
|
||||||
const hasVerifiedEmail = user && user.has_verified_email;
|
const hasVerifiedEmail = user && user.has_verified_email;
|
||||||
|
const referredRewardAvailable = rewards && rewards.some(reward => reward.reward_type === REWARDS.TYPE_REFEREE);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fetchUser();
|
fetchUser();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!setReferrerPending && hasVerifiedEmail) {
|
if (!referrerSetPending && hasVerifiedEmail) {
|
||||||
claimReward();
|
claimReward();
|
||||||
}
|
}
|
||||||
}, [setReferrerPending, hasVerifiedEmail]);
|
}, [referrerSetPending, hasVerifiedEmail]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (referrer) {
|
if (referrer) {
|
||||||
|
@ -53,6 +57,16 @@ function Invited(props: Props) {
|
||||||
}
|
}
|
||||||
}, [referrer]);
|
}, [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() {
|
function handleDone() {
|
||||||
if (hasVerifiedEmail && referrerIsChannel) {
|
if (hasVerifiedEmail && referrerIsChannel) {
|
||||||
channelSubscribe({
|
channelSubscribe({
|
||||||
|
@ -63,18 +77,43 @@ function Invited(props: Props) {
|
||||||
history.push(`/$/${PAGES.DISCOVER}`);
|
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 (
|
return (
|
||||||
<Card
|
<Card
|
||||||
title={__(`Welcome!`)}
|
title={__(`Welcome!`)}
|
||||||
subtitle={__(
|
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={
|
actions={
|
||||||
<>
|
<>
|
||||||
<p className="error-text">{__('Not a valid referral')}</p>
|
<p className="error-text">{__('Not a valid referral')}</p>
|
||||||
<p className="error-text">{setReferrerError}</p>
|
|
||||||
<div className="card__actions">
|
<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} />
|
<Button button="primary" label={__('Explore')} onClick={handleDone} />
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
|
@ -112,7 +151,7 @@ function Invited(props: Props) {
|
||||||
return (
|
return (
|
||||||
<Card
|
<Card
|
||||||
title={__(`Welcome!`)}
|
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={
|
actions={
|
||||||
<>
|
<>
|
||||||
{referrerIsChannel && (
|
{referrerIsChannel && (
|
||||||
|
|
|
@ -4,8 +4,8 @@ import { doUserSetReferrer, selectSetReferrerError, selectSetReferrerPending } f
|
||||||
import ModalSetReferrer from './view';
|
import ModalSetReferrer from './view';
|
||||||
|
|
||||||
const select = state => ({
|
const select = state => ({
|
||||||
setReferrerPending: selectSetReferrerPending(state),
|
referrerSetPending: selectSetReferrerPending(state),
|
||||||
setReferrerError: selectSetReferrerError(state),
|
referrerSetError: selectSetReferrerError(state),
|
||||||
});
|
});
|
||||||
|
|
||||||
const perform = dispatch => ({
|
const perform = dispatch => ({
|
||||||
|
|
|
@ -9,8 +9,8 @@ type Props = {
|
||||||
error: ?string,
|
error: ?string,
|
||||||
rewardIsPending: boolean,
|
rewardIsPending: boolean,
|
||||||
setReferrer: (string, boolean) => void,
|
setReferrer: (string, boolean) => void,
|
||||||
setReferrerPending: boolean,
|
referrerSetPending: boolean,
|
||||||
setReferrerError?: string,
|
referrerSetError?: string,
|
||||||
};
|
};
|
||||||
|
|
||||||
type State = {
|
type State = {
|
||||||
|
|
|
@ -21,7 +21,10 @@ export default handleActions(
|
||||||
[ACTIONS.CHANNEL_SUBSCRIBE]: (state: SubscriptionState, action: DoChannelSubscribe): SubscriptionState => {
|
[ACTIONS.CHANNEL_SUBSCRIBE]: (state: SubscriptionState, action: DoChannelSubscribe): SubscriptionState => {
|
||||||
const newSubscription: Subscription = action.data;
|
const newSubscription: Subscription = action.data;
|
||||||
const newSubscriptions: Array<Subscription> = state.subscriptions.slice();
|
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 {
|
return {
|
||||||
...state,
|
...state,
|
||||||
|
|
Loading…
Add table
Reference in a new issue