add yotube sync to initial sign up flow

This commit is contained in:
Sean Yesmunt 2020-09-04 16:11:28 -04:00
parent baafd60f4f
commit f547053ebc
11 changed files with 125 additions and 56 deletions

View file

@ -23,6 +23,8 @@ type Props = {
setShareDiagnosticData: boolean => void,
doSignUp: (string, ?string) => Promise<any>,
clearEmailEntry: () => void,
interestedInYoutubSync: boolean,
doToggleInterestedInYoutubeSync: () => void,
};
function UserEmailNew(props: Props) {
@ -35,6 +37,8 @@ function UserEmailNew(props: Props) {
setShareDiagnosticData,
clearEmailEntry,
emailExists,
interestedInYoutubSync,
doToggleInterestedInYoutubeSync,
} = props;
const { share_usage_data: shareUsageData } = daemonSettings;
const { push, location } = useHistory();
@ -113,6 +117,14 @@ function UserEmailNew(props: Props) {
onChange={e => setPassword(e.target.value)}
/>
<FormField
type="checkbox"
name="youtube_sync_checkbox"
label={__('Sync my YouTube channel')}
checked={interestedInYoutubSync}
onChange={() => doToggleInterestedInYoutubeSync()}
/>
{!IS_WEB && (
<FormField
type="checkbox"

View file

@ -1,5 +1,4 @@
// @flow
import * as PAGES from 'constants/pages';
import React, { useState } from 'react';
import { isNameValid } from 'lbry-redux';
import Button from 'component/button';
@ -15,10 +14,18 @@ type Props = {
createChannelError: string,
claimingReward: boolean,
user: User,
doToggleInterestedInYoutubeSync: () => void,
};
function UserFirstChannel(props: Props) {
const { createChannel, creatingChannel, claimingReward, user, createChannelError } = props;
const {
createChannel,
creatingChannel,
claimingReward,
user,
createChannelError,
doToggleInterestedInYoutubeSync,
} = props;
const { primary_email: primaryEmail } = user;
const initialChannel = primaryEmail ? primaryEmail.split('@')[0] : '';
const [channel, setChannel] = useState(initialChannel);
@ -87,7 +94,7 @@ function UserFirstChannel(props: Props) {
<Button
button="link"
label={__('Sync it and skip this step')}
navigate={`/$/${PAGES.YOUTUBE_SYNC}`}
onClick={() => doToggleInterestedInYoutubeSync()}
/>
),
}}

View file

@ -20,6 +20,8 @@ import {
SETTINGS,
} from 'lbry-redux';
import { makeSelectClientSetting } from 'redux/selectors/settings';
import { selectInterestedInYoutubeSync } from 'redux/selectors/app';
import { doToggleInterestedInYoutubeSync } from 'redux/actions/app';
import UserSignIn from './view';
const select = state => ({
@ -42,6 +44,7 @@ const select = state => ({
syncingWallet: selectGetSyncIsPending(state),
hasSynced: Boolean(selectSyncHash(state)),
creatingChannel: selectCreatingChannel(state),
interestedInYoutubeSync: selectInterestedInYoutubeSync(state),
});
const perform = dispatch => ({
@ -60,6 +63,7 @@ const perform = dispatch => ({
),
syncSettings: () => dispatch(doSyncClientSettings()),
setClientSetting: (setting, value) => dispatch(doSetClientSetting(setting, value)),
doToggleInterestedInYoutubeSync: () => dispatch(doToggleInterestedInYoutubeSync()),
});
export default connect(select, perform)(UserSignIn);

View file

@ -2,12 +2,13 @@
import * as PAGES from 'constants/pages';
import React from 'react';
import classnames from 'classnames';
import { withRouter } from 'react-router';
import { useHistory } from 'react-router';
import UserEmailNew from 'component/userEmailNew';
import UserEmailVerify from 'component/userEmailVerify';
import UserFirstChannel from 'component/userFirstChannel';
import UserChannelFollowIntro from 'component/userChannelFollowIntro';
import UserTagFollowIntro from 'component/userTagFollowIntro';
import YoutubeSync from 'page/youtubeSync';
import { DEFAULT_BID_FOR_FIRST_CHANNEL } from 'component/userFirstChannel/view';
import { YOUTUBE_STATUSES } from 'lbryinc';
import { SETTINGS } from 'lbry-redux';
@ -18,6 +19,10 @@ import YoutubeTransferStatus from 'component/youtubeTransferStatus';
import useFetched from 'effects/use-fetched';
import Confetti from 'react-confetti';
const REDIRECT_PARAM = 'redirect';
const REDIRECT_IMMEDIATELY_PARAM = 'immediate';
const STEP_PARAM = 'step';
type Props = {
user: ?User,
emailToVerify: ?string,
@ -29,8 +34,6 @@ type Props = {
claimNewUserReward: () => void,
fetchUser: () => void,
claimedRewards: Array<Reward>,
history: { replace: string => void },
location: { search: string },
youtubeChannels: Array<any>,
syncEnabled: boolean,
hasSynced: boolean,
@ -41,6 +44,8 @@ type Props = {
followingAcknowledged: boolean,
tagsAcknowledged: boolean,
rewardsAcknowledged: boolean,
interestedInYoutubeSync: boolean,
doToggleInterestedInYoutubeSync: () => void,
};
function UserSignUp(props: Props) {
@ -53,8 +58,6 @@ function UserSignUp(props: Props) {
claimConfirmEmailReward,
claimNewUserReward,
balance,
history,
location,
fetchUser,
youtubeChannels,
syncEnabled,
@ -67,12 +70,17 @@ function UserSignUp(props: Props) {
rewardsAcknowledged,
syncSettings,
setClientSetting,
interestedInYoutubeSync,
doToggleInterestedInYoutubeSync,
} = props;
const { search } = location;
const {
location: { search, pathname },
replace,
} = useHistory();
const urlParams = new URLSearchParams(search);
const redirect = urlParams.get('redirect');
const step = urlParams.get('step');
const shouldRedirectImmediately = urlParams.get('immediate');
const redirect = urlParams.get(REDIRECT_PARAM);
const step = urlParams.get(STEP_PARAM);
const shouldRedirectImmediately = urlParams.get(REDIRECT_IMMEDIATELY_PARAM);
const [initialSignInStep, setInitialSignInStep] = React.useState();
const hasVerifiedEmail = user && user.has_verified_email;
const rewardsApproved = user && user.is_reward_approved;
@ -97,11 +105,12 @@ function UserSignUp(props: Props) {
const showSyncPassword = syncEnabled && getSyncError;
const showChannelCreation =
hasVerifiedEmail &&
balance !== undefined &&
balance !== null &&
balance > DEFAULT_BID_FOR_FIRST_CHANNEL &&
channelCount === 0 &&
!hasYoutubeChannels;
((balance !== undefined &&
balance !== null &&
balance > DEFAULT_BID_FOR_FIRST_CHANNEL &&
channelCount === 0 &&
!hasYoutubeChannels) ||
interestedInYoutubeSync);
const showYoutubeTransfer = hasVerifiedEmail && hasYoutubeChannels && !isYoutubeTransferComplete;
const showFollowIntro = step === 'channels' || (hasVerifiedEmail && !followingAcknowledged);
const showTagsIntro = step === 'tags' || (hasVerifiedEmail && !tagsAcknowledged);
@ -150,7 +159,12 @@ function UserSignUp(props: Props) {
// Loop through this list from the end, until it finds a matching component
// If it never finds one, assume the user has completed every step and redirect them
const SIGN_IN_FLOW = [
showEmail && <UserEmailNew />,
showEmail && (
<UserEmailNew
interestedInYoutubSync={interestedInYoutubeSync}
doToggleInterestedInYoutubeSync={doToggleInterestedInYoutubeSync}
/>
),
showEmailVerification && <UserEmailVerify />,
showUserVerification && (
<UserVerify
@ -159,47 +173,48 @@ function UserSignUp(props: Props) {
}}
/>
),
showChannelCreation && <UserFirstChannel />,
showChannelCreation &&
(interestedInYoutubeSync ? (
<YoutubeSync inSignUpFlow />
) : (
<UserFirstChannel doToggleInterestedInYoutubeSync={doToggleInterestedInYoutubeSync} />
)),
showFollowIntro && (
<UserChannelFollowIntro
onContinue={() => {
let url = `/$/${PAGES.AUTH}?reset_scroll=1`;
if (redirect) {
url += `&redirect=${redirect}`;
}
if (shouldRedirectImmediately) {
url += `&immediate=true`;
if (urlParams.get('reset_scroll')) {
urlParams.delete('reset_scroll');
urlParams.append('reset_scroll', '2');
}
history.replace(url);
urlParams.delete(STEP_PARAM);
setSettingAndSync(SETTINGS.FOLLOWING_ACKNOWLEDGED, true);
replace(`${pathname}?${urlParams.toString()}`);
}}
onBack={() => {
let url = `/$/${PAGES.AUTH}?reset_scroll=1&step=tags`;
if (redirect) {
url += `&redirect=${redirect}`;
}
if (shouldRedirectImmediately) {
url += `&immediate=true`;
if (urlParams.get('reset_scroll')) {
urlParams.delete('reset_scroll');
urlParams.append('reset_scroll', '3');
}
history.replace(url);
setSettingAndSync(SETTINGS.FOLLOWING_ACKNOWLEDGED, false);
replace(`${pathname}?${urlParams.toString()}`);
}}
/>
),
showTagsIntro && (
<UserTagFollowIntro
onContinue={() => {
let url = `/$/${PAGES.AUTH}?reset_scroll=1&step=channels`;
let url = `/$/${PAGES.AUTH}?reset_scroll=1&${STEP_PARAM}=channels`;
if (redirect) {
url += `&redirect=${redirect}`;
url += `&${REDIRECT_PARAM}=${redirect}`;
}
if (shouldRedirectImmediately) {
url += `&immediate=true`;
url += `&${REDIRECT_IMMEDIATELY_PARAM}=true`;
}
history.replace(url);
replace(url);
setSettingAndSync(SETTINGS.TAGS_ACKNOWLEDGED, true);
}}
/>
@ -228,7 +243,7 @@ function UserSignUp(props: Props) {
if (!initialSignInStep) {
setInitialSignInStep(i);
} else if (i !== initialSignInStep && i !== SIGN_IN_FLOW.length - 1) {
history.replace(redirect);
replace(redirect);
}
}
@ -250,7 +265,7 @@ function UserSignUp(props: Props) {
}, [componentToRender, claimNewUserReward]);
if (!componentToRender) {
history.replace(redirect || '/');
replace(redirect || '/');
}
return (
@ -258,4 +273,4 @@ function UserSignUp(props: Props) {
);
}
export default withRouter(UserSignUp);
export default UserSignUp;

View file

@ -1,4 +1,5 @@
// @flow
import { SITE_NAME } from 'config';
import * as ICONS from 'constants/icons';
import * as React from 'react';
import classnames from 'classnames';
@ -168,20 +169,15 @@ export default function YoutubeTransferStatus(props: Props) {
onClick={claimChannels}
label={youtubeChannels.length > 1 ? __('Claim Channels') : __('Claim Channel')}
/>
{addNewChannel ? (
<Button button="link" label={__('Add Another Channel')} onClick={addNewChannel} />
) : (
<Button button="link" label={__('Learn More')} href="https://lbry.com/faq/youtube#transfer" />
)}
<Button button="link" label={__('Explore %SITE_NAME%', { SITE_NAME })} navigate="/" />
</div>
<p className="help">
{youtubeChannels.length > 1
? __('You will be able to claim your channels once they finish syncing.')
: __('You will be able to claim your channel once it has finished syncing.')}{' '}
{addNewChannel && (
<Button button="link" label={__('Learn More')} href="https://lbry.com/faq/youtube#transfer" />
)}
<Button button="link" label={__('Learn More')} href="https://lbry.com/faq/youtube#transfer" />{' '}
{addNewChannel && <Button button="link" label={__('Add Another Channel')} onClick={addNewChannel} />}
</p>
</>
}

View file

@ -28,6 +28,7 @@ export const SET_WELCOME_VERSION = 'SET_WELCOME_VERSION';
export const SET_ALLOW_ANALYTICS = 'SET_ALLOW_ANALYTICS';
export const SET_HAS_NAVIGATED = 'SET_HAS_NAVIGATED';
export const SET_SYNC_LOCK = 'SET_SYNC_LOCK';
export const TOGGLE_YOUTUBE_SYNC_INTEREST = 'TOGGLE_YOUTUBE_SYNC_INTEREST';
// Navigation
export const CHANGE_AFTER_AUTH_PATH = 'CHANGE_AFTER_AUTH_PATH';

View file

@ -21,10 +21,11 @@ const NEW_CHANNEL_PARAM = 'new_channel';
type Props = {
youtubeChannels: ?Array<{ transfer_state: string, sync_status: string }>,
doUserFetch: () => void,
inSignUpFlow?: boolean,
};
export default function YoutubeSync(props: Props) {
const { youtubeChannels, doUserFetch } = props;
const { youtubeChannels, doUserFetch, inSignUpFlow = false } = props;
const {
location: { search, pathname },
push,
@ -56,7 +57,7 @@ export default function YoutubeSync(props: Props) {
type: 'sync',
immediate_sync: true,
desired_lbry_channel_name: `@${channel}`,
return_url: `https://${DOMAIN}/$/${PAGES.YOUTUBE_SYNC}`,
return_url: `https://${DOMAIN}/$/${inSignUpFlow ? PAGES.AUTH : PAGES.YOUTUBE_SYNC}`,
}).then(ytAuthUrl => {
// react-router isn't needed since it's a different domain
window.location.href = ytAuthUrl;
@ -79,14 +80,24 @@ export default function YoutubeSync(props: Props) {
setAddingNewChannel(true);
}
const Wrapper = (props: { children: any }) => {
return inSignUpFlow ? (
<>{props.children}</>
) : (
<Page noSideNavigation authPage>
{props.children}
</Page>
);
};
return (
<Page noSideNavigation authPage>
<Wrapper>
<div className="main__channel-creation">
{hasYoutubeChannels && !addingNewChannel ? (
<YoutubeTransferStatus alwaysShow addNewChannel={handleNewChannel} />
) : (
<Card
title={__('Connect with your fans while earning rewards')}
title={__('Sync your YouTube channel to %site_name%', { site_name: IS_WEB ? SITE_NAME : 'LBRY' })}
subtitle={__('Get your YouTube videos in front of the %site_name% audience.', {
site_name: IS_WEB ? SITE_NAME : 'LBRY',
})}
@ -95,7 +106,11 @@ export default function YoutubeSync(props: Props) {
<fieldset-group class="fieldset-group--smushed fieldset-group--disabled-prefix">
<fieldset-section>
<label htmlFor="auth_first_channel">
{nameError ? <span className="error__text">{nameError}</span> : __('Your Channel')}
{nameError ? (
<span className="error__text">{nameError}</span>
) : (
__('Your %site_name% channel name', { site_name: IS_WEB ? SITE_NAME : 'LBRY' })
)}
</label>
<div className="form-field__prefix">@</div>
</fieldset-section>
@ -128,10 +143,11 @@ export default function YoutubeSync(props: Props) {
href="https://lbry.com/faq/youtube"
/>
),
site_name: SITE_NAME,
}}
>
I want to sync my content to the LBRY network and agree to %terms%. I have also read and
understand %faq%.
I want to sync my content to %site_name% and the LBRY network and agree to %terms%. I have also
read and understand %faq%.
</I18nMessage>
}
/>
@ -163,6 +179,6 @@ export default function YoutubeSync(props: Props) {
/>
)}
</div>
</Page>
</Wrapper>
);
}

View file

@ -667,3 +667,9 @@ export function doHandleSyncComplete(error, hasNewData) {
export function doSyncWithPreferences() {
return dispatch => dispatch(doSyncSubscribe());
}
export function doToggleInterestedInYoutubeSync() {
return {
type: ACTIONS.TOGGLE_YOUTUBE_SYNC_INTEREST,
};
}

View file

@ -43,6 +43,7 @@ export type AppState = {
allowAnalytics: boolean,
hasNavigated: boolean,
syncLocked: boolean,
interestedInYoutubeSync: boolean,
};
const defaultState: AppState = {
@ -78,6 +79,7 @@ const defaultState: AppState = {
allowAnalytics: false,
hasNavigated: false,
syncLocked: false,
interestedInYoutubeSync: false,
};
// @@router comes from react-router
@ -289,6 +291,13 @@ reducers[ACTIONS.TOGGLE_SEARCH_EXPANDED] = state =>
searchOptionsExpanded: !state.searchOptionsExpanded,
});
reducers[ACTIONS.TOGGLE_YOUTUBE_SYNC_INTEREST] = (state, action) => {
return {
...state,
interestedInYoutubeSync: !state.interestedInYoutubeSync,
};
};
reducers[LBRY_REDUX_ACTIONS.USER_STATE_POPULATE] = (state, action) => {
const { welcomeVersion, allowAnalytics } = action.data;
return {

View file

@ -82,3 +82,5 @@ export const selectScrollStartingPosition = createSelector(selectState, state =>
export const selectIsPasswordSaved = createSelector(selectState, state => state.isPasswordSaved);
export const selectSyncIsLocked = createSelector(selectState, state => state.syncLocked);
export const selectInterestedInYoutubeSync = createSelector(selectState, state => state.interestedInYoutubeSync);

View file

@ -56,6 +56,7 @@ const appFilter = createFilter('app', [
'muted',
'allowAnalytics',
'welcomeVersion',
'interestedInYoutubeSync',
]);
// We only need to persist the receiveAddress for the wallet
const walletFilter = createFilter('wallet', ['receiveAddress']);