add youtube sync to first run
This commit is contained in:
parent
dec63d7a2e
commit
bc89d774ba
18 changed files with 348 additions and 56 deletions
|
@ -508,10 +508,10 @@
|
|||
"Policies": "Policies",
|
||||
"Confirm your account": "Confirm your account",
|
||||
"Start Over": "Start Over",
|
||||
"Your YouTube Channel": "Your YouTube Channel",
|
||||
"Your YouTube Channels": "Your YouTube Channels",
|
||||
"Your YouTube channel": "Your YouTube channel",
|
||||
"Your YouTube channels": "Your YouTube channels",
|
||||
"Your videos are currently being transferred. There is nothing else for you to do.": "Your videos are currently being transferred. There is nothing else for you to do.",
|
||||
"Please check back later.": "Please check back later.",
|
||||
"Please check back later. This may take up to 1 week.": "Please check back later. This may take up to 1 week.",
|
||||
"%channelName% is not yet ready to be transferred. Please allow up to one week, though it is frequently faster.": "%channelName% is not yet ready to be transferred. Please allow up to one week, though it is frequently faster.",
|
||||
"here": "here",
|
||||
"%channelName% is not ready to be transferred. You can check the status %statusLink% or check back later.": "%channelName% is not ready to be transferred. You can check the status %statusLink% or check back later.",
|
||||
|
|
|
@ -739,6 +739,7 @@ export const icons = {
|
|||
<polyline points="22 4 12 14.01 9 11.01" />
|
||||
</g>
|
||||
),
|
||||
[ICONS.NOT_COMPLETED]: buildIcon(<circle cx="12" cy="12" r="10" />),
|
||||
[ICONS.PINNED]: buildIcon(
|
||||
<g>
|
||||
<path d="M21.44 11.05l-9.19 9.19a6 6 0 0 1-8.49-8.49l9.19-9.19a4 4 0 0 1 5.66 5.66l-9.2 9.19a2 2 0 0 1-2.83-2.83l8.49-8.48" />
|
||||
|
@ -819,4 +820,10 @@ export const icons = {
|
|||
<path d="M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5z" />
|
||||
</g>
|
||||
),
|
||||
[ICONS.YOUTUBE]: buildIcon(
|
||||
<g>
|
||||
<path d="M22.54 6.42a2.78 2.78 0 0 0-1.94-2C18.88 4 12 4 12 4s-6.88 0-8.6.46a2.78 2.78 0 0 0-1.94 2A29 29 0 0 0 1 11.75a29 29 0 0 0 .46 5.33A2.78 2.78 0 0 0 3.4 19c1.72.46 8.6.46 8.6.46s6.88 0 8.6-.46a2.78 2.78 0 0 0 1.94-2 29 29 0 0 0 .46-5.25 29 29 0 0 0-.46-5.33z" />
|
||||
<polygon points="9.75 15.02 15.5 11.75 9.75 8.48 9.75 15.02" />
|
||||
</g>
|
||||
),
|
||||
};
|
||||
|
|
|
@ -177,7 +177,7 @@ const Header = (props: Props) => {
|
|||
label={(backLabel && backLabel) || __('Cancel')}
|
||||
icon={ICONS.ARROW_LEFT}
|
||||
/>
|
||||
{backTitle && <h1 className={'card__title'}>{isMobile ? simpleBackTitle || backTitle : backTitle}</h1>}
|
||||
{backTitle && <h1 className="header__auth-title">{isMobile ? simpleBackTitle || backTitle : backTitle}</h1>}
|
||||
<Button
|
||||
aria-label={__('Your wallet')}
|
||||
navigate={`/$/${PAGES.WALLET}`}
|
||||
|
|
|
@ -19,7 +19,7 @@ function RewardAuthIntro(props: Props) {
|
|||
|
||||
return (
|
||||
<Card
|
||||
title={title || __('Log in to %SITE_NAME% to Earn Rewards', { SITE_NAME })}
|
||||
title={title || __('Log in to %SITE_NAME% to earn rewards', { SITE_NAME })}
|
||||
subtitle={
|
||||
<I18nMessage
|
||||
tokens={{
|
||||
|
|
|
@ -46,6 +46,7 @@ import ChannelNew from 'page/channelNew';
|
|||
import BuyPage from 'page/buy';
|
||||
import NotificationsPage from 'page/notifications';
|
||||
import SignInWalletPasswordPage from 'page/signInWalletPassword';
|
||||
import YoutubeSyncPage from 'page/youtubeSync';
|
||||
import { LINKED_COMMENT_QUERY_PARAM } from 'constants/comment';
|
||||
import { parseURI } from 'lbry-redux';
|
||||
import { SITE_TITLE, WELCOME_VERSION } from 'config';
|
||||
|
@ -190,6 +191,7 @@ function AppRouter(props: Props) {
|
|||
<Route path={`/$/${PAGES.AUTH}`} exact component={SignUpPage} />
|
||||
<Route path={`/$/${PAGES.AUTH}/*`} exact component={SignUpPage} />
|
||||
<Route path={`/$/${PAGES.WELCOME}`} exact component={Welcome} />
|
||||
<Route path={`/$/${PAGES.YOUTUBE_SYNC}`} exact component={YoutubeSyncPage} />
|
||||
|
||||
<Route path={`/$/${PAGES.HELP}`} exact component={HelpPage} />
|
||||
{/* @if TARGET='app' */}
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
// @flow
|
||||
import * as PAGES from 'constants/pages';
|
||||
import React, { useState } from 'react';
|
||||
import { isNameValid } from 'lbry-redux';
|
||||
import Button from 'component/button';
|
||||
import { Form, FormField } from 'component/common/form';
|
||||
import { INVALID_NAME_ERROR } from 'constants/claim';
|
||||
import Card from 'component/common/card';
|
||||
import I18nMessage from 'component/i18nMessage';
|
||||
export const DEFAULT_BID_FOR_FIRST_CHANNEL = 0.01;
|
||||
|
||||
type Props = {
|
||||
|
@ -78,6 +80,21 @@ function UserFirstChannel(props: Props) {
|
|||
label={creatingChannel || claimingReward ? __('Creating') : __('Create')}
|
||||
/>
|
||||
</div>
|
||||
<div className="help--card-actions">
|
||||
<I18nMessage
|
||||
tokens={{
|
||||
sync_channel: (
|
||||
<Button
|
||||
button="link"
|
||||
label={__('Sync it and skip this step')}
|
||||
navigate={`/$/${PAGES.YOUTUBE_SYNC}`}
|
||||
/>
|
||||
),
|
||||
}}
|
||||
>
|
||||
Have a YouTube channel? %sync_channel%.
|
||||
</I18nMessage>
|
||||
</div>
|
||||
</Form>
|
||||
}
|
||||
/>
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
// @flow
|
||||
import * as PAGES from 'constants/pages';
|
||||
import * as ICONS from 'constants/icons';
|
||||
import * as React from 'react';
|
||||
import classnames from 'classnames';
|
||||
import Button from 'component/button';
|
||||
import ClaimPreview from 'component/claimPreview';
|
||||
import Card from 'component/common/card';
|
||||
import { YOUTUBE_STATUSES } from 'lbryinc';
|
||||
import { buildURI } from 'lbry-redux';
|
||||
import I18nMessage from 'component/i18nMessage';
|
||||
|
||||
const STATUS_URL = 'https://lbry.com/youtube/status/';
|
||||
import Spinner from 'component/spinner';
|
||||
import Icon from 'component/common/icon';
|
||||
|
||||
type Props = {
|
||||
youtubeChannels: Array<any>,
|
||||
|
@ -17,7 +17,8 @@ type Props = {
|
|||
updateUser: () => void,
|
||||
checkYoutubeTransfer: () => void,
|
||||
videosImported: ?Array<number>, // [currentAmountImported, totalAmountToImport]
|
||||
hideChannelLink: boolean,
|
||||
alwaysShow: boolean,
|
||||
addNewChannel?: boolean,
|
||||
};
|
||||
|
||||
export default function YoutubeTransferStatus(props: Props) {
|
||||
|
@ -28,15 +29,21 @@ export default function YoutubeTransferStatus(props: Props) {
|
|||
videosImported,
|
||||
checkYoutubeTransfer,
|
||||
updateUser,
|
||||
hideChannelLink = false,
|
||||
alwaysShow = false,
|
||||
addNewChannel,
|
||||
} = props;
|
||||
const hasChannels = youtubeChannels && youtubeChannels.length;
|
||||
const hasChannels = youtubeChannels && youtubeChannels.length > 0;
|
||||
const transferEnabled = youtubeChannels.some(status => status.transferable);
|
||||
const hasPendingTransfers = youtubeChannels.some(
|
||||
status => status.transfer_state === YOUTUBE_STATUSES.PENDING_TRANSFER
|
||||
status => status.transfer_state === YOUTUBE_STATUSES.YOUTUBE_SYNC_PENDING_TRANSFER
|
||||
);
|
||||
const isYoutubeTransferComplete =
|
||||
hasChannels && youtubeChannels.every(channel => channel.transfer_state === YOUTUBE_STATUSES.COMPLETED_TRANSFER);
|
||||
hasChannels &&
|
||||
youtubeChannels.every(
|
||||
channel =>
|
||||
channel.transfer_state === YOUTUBE_STATUSES.YOUTUBE_SYNC_COMPLETED_TRANSFER ||
|
||||
channel.sync_status === YOUTUBE_STATUSES.YOUTUBE_SYNC_ABANDONDED
|
||||
);
|
||||
|
||||
let total;
|
||||
let complete;
|
||||
|
@ -49,12 +56,14 @@ export default function YoutubeTransferStatus(props: Props) {
|
|||
const { transferable, transfer_state: transferState, sync_status: syncStatus } = channel;
|
||||
if (!transferable) {
|
||||
switch (transferState) {
|
||||
case YOUTUBE_STATUSES.NOT_TRANSFERRED:
|
||||
case YOUTUBE_STATUSES.YOUTUBE_SYNC_NOT_TRANSFERRED:
|
||||
return syncStatus[0].toUpperCase() + syncStatus.slice(1);
|
||||
case YOUTUBE_STATUSES.PENDING_TRANSFER:
|
||||
case YOUTUBE_STATUSES.YOUTUBE_SYNC_PENDING_TRANSFER:
|
||||
return __('Transfer in progress');
|
||||
case YOUTUBE_STATUSES.COMPLETED_TRANSFER:
|
||||
case YOUTUBE_STATUSES.YOUTUBE_SYNC_COMPLETED_TRANSFER:
|
||||
return __('Completed transfer');
|
||||
case YOUTUBE_STATUSES.YOUTUBE_SYNC_ABANDONDED:
|
||||
return __('This channel not eligible to by synced');
|
||||
}
|
||||
} else {
|
||||
return __('Ready to transfer');
|
||||
|
@ -74,28 +83,36 @@ export default function YoutubeTransferStatus(props: Props) {
|
|||
return () => {
|
||||
clearInterval(interval);
|
||||
};
|
||||
} else {
|
||||
updateUser();
|
||||
}
|
||||
}, [hasPendingTransfers, checkYoutubeTransfer, updateUser]);
|
||||
}, [hasPendingTransfers, checkYoutubeTransfer, updateUser, updateUser]);
|
||||
|
||||
return (
|
||||
hasChannels &&
|
||||
!isYoutubeTransferComplete && (
|
||||
(alwaysShow || (hasChannels && !isYoutubeTransferComplete)) && (
|
||||
<Card
|
||||
title={youtubeChannels.length > 1 ? __('Your YouTube Channels') : __('Your YouTube Channel')}
|
||||
title={youtubeChannels.length > 1 ? __('Your YouTube channels') : __('Your YouTube channel')}
|
||||
subtitle={
|
||||
<span>
|
||||
{hasPendingTransfers &&
|
||||
__('Your videos are currently being transferred. There is nothing else for you to do.')}
|
||||
{transferEnabled && !hasPendingTransfers && __('Your videos are ready to be transferred.')}
|
||||
{!transferEnabled && !hasPendingTransfers && __('Please check back later.')}
|
||||
{!transferEnabled && !hasPendingTransfers && __('Please check back later. This may take up to 1 week.')}
|
||||
</span>
|
||||
}
|
||||
body={
|
||||
<section>
|
||||
{youtubeChannels.map((channel, index) => {
|
||||
const { lbry_channel_name: channelName, channel_claim_id: claimId, status_token: statusToken } = channel;
|
||||
const { lbry_channel_name: channelName, channel_claim_id: claimId, sync_status: syncStatus } = channel;
|
||||
const url = buildURI({ channelName, channelClaimId: claimId });
|
||||
const transferState = getMessage(channel);
|
||||
const isWaitingForSync =
|
||||
syncStatus === YOUTUBE_STATUSES.YOUTUBE_SYNC_QUEUED ||
|
||||
syncStatus === YOUTUBE_STATUSES.YOUTUBE_SYNC_PENDINGUPGRADE ||
|
||||
syncStatus === YOUTUBE_STATUSES.YOUTUBE_SYNC_SYNCING;
|
||||
|
||||
const isNotEligible = syncStatus === YOUTUBE_STATUSES.YOUTUBE_SYNC_ABANDONDED;
|
||||
|
||||
return (
|
||||
<div key={url} className="card--inline">
|
||||
{claimId ? (
|
||||
|
@ -106,26 +123,32 @@ export default function YoutubeTransferStatus(props: Props) {
|
|||
/>
|
||||
) : (
|
||||
<div className="section--padded">
|
||||
<p>
|
||||
<I18nMessage
|
||||
tokens={{
|
||||
channelName,
|
||||
}}
|
||||
>
|
||||
%channelName% is not yet ready to be transferred. Please allow up to one week, though it is
|
||||
frequently faster.
|
||||
</I18nMessage>
|
||||
</p>
|
||||
<p className="help">
|
||||
<I18nMessage
|
||||
tokens={{
|
||||
statusLink: <Button button="link" href={STATUS_URL + statusToken} label={__('here')} />,
|
||||
faqLink: <Button button="link" label={__('FAQ')} href="https://lbry.com/faq/youtube" />,
|
||||
}}
|
||||
>
|
||||
You can check your status %statusLink%. This %faqLink% explains the program in more detail.
|
||||
</I18nMessage>
|
||||
</p>
|
||||
{isNotEligible ? (
|
||||
<div>{__('%channelName% is not eligible to be synced', { channelName })}</div>
|
||||
) : (
|
||||
<div className="progress">
|
||||
<div className="progress__item">
|
||||
{__('Claim your handle %handle%', { handle: channelName })}
|
||||
<Icon icon={ICONS.COMPLETED} className="progress__complete-icon--completed" />
|
||||
</div>
|
||||
<div className="progress__item">
|
||||
{__('Agree to sync')}{' '}
|
||||
<Icon icon={ICONS.COMPLETED} className="progress__complete-icon--completed" />
|
||||
</div>
|
||||
<div className="progress__item">
|
||||
{__('Wait for your videos to be synced')}
|
||||
{isWaitingForSync ? (
|
||||
<Spinner type="small" />
|
||||
) : (
|
||||
<Icon icon={ICONS.COMPLETED} className="progress__complete-icon--completed" />
|
||||
)}
|
||||
</div>
|
||||
<div className="progress__item">
|
||||
{__('Claim your channel')}
|
||||
<Icon icon={ICONS.NOT_COMPLETED} className={classnames('progress__complete-icon')} />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
@ -137,23 +160,30 @@ export default function YoutubeTransferStatus(props: Props) {
|
|||
</section>
|
||||
}
|
||||
actions={
|
||||
transferEnabled ? (
|
||||
<div className="card__actions">
|
||||
<>
|
||||
<div className="section__actions">
|
||||
<Button
|
||||
button="primary"
|
||||
disabled={youtubeImportPending}
|
||||
disabled={youtubeImportPending || !transferEnabled}
|
||||
onClick={claimChannels}
|
||||
label={youtubeChannels.length > 1 ? __('Claim Channels') : __('Claim Channel')}
|
||||
/>
|
||||
<Button button="link" label={__('Learn more')} href="https://lbry.com/faq/youtube#transfer" />
|
||||
</div>
|
||||
) : !hideChannelLink ? (
|
||||
<div className="card__actions">
|
||||
<Button button="primary" navigate={`/$/${PAGES.CHANNELS}`} label={__('View your channels')} />
|
||||
</div>
|
||||
{addNewChannel ? (
|
||||
<Button button="link" label={__('Add Another Channel')} onClick={addNewChannel} />
|
||||
) : (
|
||||
false
|
||||
)
|
||||
<Button button="link" label={__('Learn More')} href="https://lbry.com/faq/youtube#transfer" />
|
||||
)}
|
||||
</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" />
|
||||
)}
|
||||
</p>
|
||||
</>
|
||||
}
|
||||
/>
|
||||
)
|
||||
|
|
|
@ -30,6 +30,7 @@ export const WALLET = 'List';
|
|||
export const PHONE = 'Phone';
|
||||
export const COMPLETE = 'Check';
|
||||
export const COMPLETED = 'CheckCircle';
|
||||
export const NOT_COMPLETED = 'Circle';
|
||||
export const SUBSCRIBE = 'Heart';
|
||||
export const UNSUBSCRIBE = 'BrokenHeart';
|
||||
export const UNLOCK = 'Unlock';
|
||||
|
@ -115,3 +116,4 @@ export const LBRY_STATUS = 'BarChart';
|
|||
export const NOTIFICATION = 'Bell';
|
||||
export const LAYOUT = 'Layout';
|
||||
export const REPLY = 'Reply';
|
||||
export const YOUTUBE = 'Youtube';
|
||||
|
|
|
@ -46,3 +46,4 @@ exports.CODE_2257 = '2257';
|
|||
exports.BUY = 'buy';
|
||||
exports.CHANNEL_NEW = 'channel/new';
|
||||
exports.NOTIFICATIONS = 'notifications';
|
||||
exports.YOUTUBE_SYNC = 'youtube';
|
||||
|
|
|
@ -10,6 +10,7 @@ import {
|
|||
} from 'lbry-redux';
|
||||
import { selectChannelIsBlocked } from 'redux/selectors/blocked';
|
||||
import { selectBlackListedOutpoints, doFetchSubCount, makeSelectSubCountForUri } from 'lbryinc';
|
||||
import { selectYoutubeChannels } from 'redux/selectors/user';
|
||||
import { makeSelectIsSubscribed } from 'redux/selectors/subscriptions';
|
||||
import { doOpenModal } from 'redux/actions/app';
|
||||
import ChannelPage from './view';
|
||||
|
@ -26,6 +27,7 @@ const select = (state, props) => ({
|
|||
blackListedOutpoints: selectBlackListedOutpoints(state),
|
||||
subCount: makeSelectSubCountForUri(props.uri)(state),
|
||||
pending: makeSelectClaimIsPending(props.uri)(state),
|
||||
youtubeChannels: selectYoutubeChannels(state),
|
||||
});
|
||||
|
||||
const perform = dispatch => ({
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
// @flow
|
||||
import * as ICONS from 'constants/icons';
|
||||
import * as PAGES from 'constants/pages';
|
||||
import React from 'react';
|
||||
import { parseURI } from 'lbry-redux';
|
||||
import { YOUTUBE_STATUSES } from 'lbryinc';
|
||||
import Page from 'component/page';
|
||||
import SubscribeButton from 'component/subscribeButton';
|
||||
import BlockButton from 'component/blockButton';
|
||||
|
@ -43,6 +45,7 @@ type Props = {
|
|||
fetchSubCount: string => void,
|
||||
subCount: number,
|
||||
pending: boolean,
|
||||
youtubeChannels: ?Array<{ channel_claim_id: string, sync_status: string, transfer_state: string }>,
|
||||
};
|
||||
|
||||
function ChannelPage(props: Props) {
|
||||
|
@ -59,6 +62,7 @@ function ChannelPage(props: Props) {
|
|||
fetchSubCount,
|
||||
subCount,
|
||||
pending,
|
||||
youtubeChannels,
|
||||
} = props;
|
||||
const {
|
||||
push,
|
||||
|
@ -73,6 +77,18 @@ function ChannelPage(props: Props) {
|
|||
const { permanent_url: permanentUrl } = claim;
|
||||
const claimId = claim.claim_id;
|
||||
const formattedSubCount = Number(subCount).toLocaleString();
|
||||
const isMyYouTubeChannel =
|
||||
claim &&
|
||||
youtubeChannels &&
|
||||
youtubeChannels.some(({ channel_claim_id, sync_status, transfer_state }) => {
|
||||
if (
|
||||
channel_claim_id === claim.claim_id &&
|
||||
sync_status !== YOUTUBE_STATUSES.YOUTUBE_SYNC_ABANDONDED &&
|
||||
transfer_state !== YOUTUBE_STATUSES.YOUTUBE_SYNC_COMPLETED_TRANSFER
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
let channelIsBlackListed = false;
|
||||
|
||||
if (claim && blackListedOutpoints) {
|
||||
|
@ -131,6 +147,14 @@ function ChannelPage(props: Props) {
|
|||
<YoutubeBadge channelClaimId={claimId} />
|
||||
<header className="channel-cover">
|
||||
<div className="channel__quick-actions">
|
||||
{isMyYouTubeChannel && (
|
||||
<Button
|
||||
button="alt"
|
||||
label={__('Claim Your Channel')}
|
||||
icon={ICONS.YOUTUBE}
|
||||
navigate={`/$/${PAGES.CHANNELS}`}
|
||||
/>
|
||||
)}
|
||||
{!channelIsBlocked && !channelIsBlackListed && <ShareButton uri={uri} />}
|
||||
{!channelIsBlocked && <ClaimSupportButton uri={uri} />}
|
||||
{!channelIsBlocked && (!channelIsBlackListed || isSubscribed) && <SubscribeButton uri={permanentUrl} />}
|
||||
|
|
|
@ -33,7 +33,7 @@ class InvitePage extends React.PureComponent<Props> {
|
|||
<Page>
|
||||
{!authenticated ? (
|
||||
<RewardAuthIntro
|
||||
title={__('Log in to %SITE_NAME% to Earn Rewards From Inviting Your Friends', { SITE_NAME })}
|
||||
title={__('Log in to %SITE_NAME% to earn rewards From Inviting Your Friends', { SITE_NAME })}
|
||||
/>
|
||||
) : (
|
||||
<React.Fragment>
|
||||
|
|
12
ui/page/youtubeSync/index.js
Normal file
12
ui/page/youtubeSync/index.js
Normal file
|
@ -0,0 +1,12 @@
|
|||
import { connect } from 'react-redux';
|
||||
import { selectYoutubeChannels } from 'redux/selectors/user';
|
||||
import { doUserFetch } from 'redux/actions/user';
|
||||
import CreatorDashboardPage from './view';
|
||||
|
||||
const select = state => ({
|
||||
youtubeChannels: selectYoutubeChannels(state),
|
||||
});
|
||||
|
||||
export default connect(select, {
|
||||
doUserFetch,
|
||||
})(CreatorDashboardPage);
|
168
ui/page/youtubeSync/view.jsx
Normal file
168
ui/page/youtubeSync/view.jsx
Normal file
|
@ -0,0 +1,168 @@
|
|||
// @flow
|
||||
import { SITE_NAME, DOMAIN } from 'config';
|
||||
import * as PAGES from 'constants/pages';
|
||||
import React from 'react';
|
||||
import Page from 'component/page';
|
||||
import Button from 'component/button';
|
||||
import Card from 'component/common/card';
|
||||
import I18nMessage from 'component/i18nMessage';
|
||||
import { Form, FormField } from 'component/common/form';
|
||||
import { INVALID_NAME_ERROR } from 'constants/claim';
|
||||
import { isNameValid } from 'lbry-redux';
|
||||
import { Lbryio } from 'lbryinc';
|
||||
import { useHistory } from 'react-router';
|
||||
import YoutubeTransferStatus from 'component/youtubeTransferStatus';
|
||||
import Nag from 'component/common/nag';
|
||||
|
||||
const STATUS_TOKEN_PARAM = 'status_token';
|
||||
const ERROR_MESSAGE_PARAM = 'error_message';
|
||||
const NEW_CHANNEL_PARAM = 'new_channel';
|
||||
|
||||
type Props = {
|
||||
youtubeChannels: ?Array<{ transfer_state: string, sync_status: string }>,
|
||||
doUserFetch: () => void,
|
||||
};
|
||||
|
||||
export default function YoutubeSync(props: Props) {
|
||||
const { youtubeChannels, doUserFetch } = props;
|
||||
const {
|
||||
location: { search, pathname },
|
||||
push,
|
||||
} = useHistory();
|
||||
const urlParams = new URLSearchParams(search);
|
||||
const statusToken = urlParams.get(STATUS_TOKEN_PARAM);
|
||||
const errorMessage = urlParams.get(ERROR_MESSAGE_PARAM);
|
||||
const newChannelParam = urlParams.get(NEW_CHANNEL_PARAM);
|
||||
const [channel, setChannel] = React.useState('');
|
||||
const [nameError, setNameError] = React.useState(undefined);
|
||||
const [acknowledgedTerms, setAcknowledgedTerms] = React.useState(false);
|
||||
const [addingNewChannel, setAddingNewChannel] = React.useState(newChannelParam);
|
||||
const hasYoutubeChannels = youtubeChannels && youtubeChannels.length > 0;
|
||||
|
||||
React.useEffect(() => {
|
||||
if (statusToken && !hasYoutubeChannels) {
|
||||
doUserFetch();
|
||||
}
|
||||
}, [statusToken, hasYoutubeChannels, doUserFetch]);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (!newChannelParam) {
|
||||
setAddingNewChannel(false);
|
||||
}
|
||||
}, [newChannelParam]);
|
||||
|
||||
function handleCreateChannel() {
|
||||
Lbryio.call('yt', 'new', {
|
||||
type: 'sync',
|
||||
immediate_sync: true,
|
||||
desired_lbry_channel_name: `@${channel}`,
|
||||
return_url: `https://${DOMAIN}/$/${PAGES.YOUTUBE_SYNC}`,
|
||||
}).then(ytAuthUrl => {
|
||||
// react-router isn't needed since it's a different domain
|
||||
window.location.href = ytAuthUrl;
|
||||
});
|
||||
}
|
||||
|
||||
function handleChannelChange(e) {
|
||||
const { value } = e.target;
|
||||
setChannel(value);
|
||||
if (!isNameValid(value, 'false')) {
|
||||
setNameError(INVALID_NAME_ERROR);
|
||||
} else {
|
||||
setNameError();
|
||||
}
|
||||
}
|
||||
|
||||
function handleNewChannel() {
|
||||
urlParams.append('new_channel', 'true');
|
||||
push(`${pathname}?${urlParams.toString()}`);
|
||||
setAddingNewChannel(true);
|
||||
}
|
||||
|
||||
return (
|
||||
<Page noSideNavigation authPage>
|
||||
<div className="main__channel-creation">
|
||||
{hasYoutubeChannels && !addingNewChannel ? (
|
||||
<YoutubeTransferStatus alwaysShow addNewChannel={handleNewChannel} />
|
||||
) : (
|
||||
<Card
|
||||
title={__('Connect with your fans while earning rewards')}
|
||||
subtitle={__('Get your YouTube videos in front of the %site_name% audience.', {
|
||||
site_name: IS_WEB ? SITE_NAME : 'LBRY',
|
||||
})}
|
||||
actions={
|
||||
<Form onSubmit={handleCreateChannel}>
|
||||
<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')}
|
||||
</label>
|
||||
<div className="form-field__prefix">@</div>
|
||||
</fieldset-section>
|
||||
|
||||
<FormField
|
||||
autoFocus
|
||||
placeholder={__('channel')}
|
||||
type="text"
|
||||
name="yt_sync_channel"
|
||||
className="form-field--short"
|
||||
value={channel}
|
||||
onChange={handleChannelChange}
|
||||
/>
|
||||
</fieldset-group>
|
||||
<FormField
|
||||
type="checkbox"
|
||||
name="yt_sync_terms"
|
||||
checked={acknowledgedTerms}
|
||||
onChange={() => setAcknowledgedTerms(!acknowledgedTerms)}
|
||||
label={
|
||||
<I18nMessage
|
||||
tokens={{
|
||||
terms: (
|
||||
<Button button="link" label={__('these terms')} href="https://lbry.com/faq/youtube-terms" />
|
||||
),
|
||||
faq: (
|
||||
<Button
|
||||
button="link"
|
||||
label={__('how the program works')}
|
||||
href="https://lbry.com/faq/youtube"
|
||||
/>
|
||||
),
|
||||
}}
|
||||
>
|
||||
I want to sync my content to the LBRY network and agree to %terms%. I have also read and
|
||||
understand %faq%.
|
||||
</I18nMessage>
|
||||
}
|
||||
/>
|
||||
|
||||
<div className="section__actions">
|
||||
<Button
|
||||
button="primary"
|
||||
type="submit"
|
||||
disabled={nameError || !channel || !acknowledgedTerms}
|
||||
label={__('Claim Now')}
|
||||
/>
|
||||
|
||||
{errorMessage && <Button button="link" label={__('Skip')} navigate={`/$/${PAGES.REWARDS}`} />}
|
||||
</div>
|
||||
<div className="help--card-actions">
|
||||
<I18nMessage
|
||||
tokens={{
|
||||
learn_more: <Button button="link" label={__('Learn more')} href="https://lbry.com/faq/youtube" />,
|
||||
}}
|
||||
>
|
||||
This will verify you are an active YouTuber. Channel names cannot be changed once chosen, please be
|
||||
extra careful. Additional instructions will be emailed to you after you verify your email on the
|
||||
next page. %learn_more%.
|
||||
</I18nMessage>
|
||||
</div>
|
||||
</Form>
|
||||
}
|
||||
nag={errorMessage && <Nag message={errorMessage} type="error" relative />}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</Page>
|
||||
);
|
||||
}
|
|
@ -40,6 +40,7 @@
|
|||
@import 'component/pagination';
|
||||
@import 'component/purchase';
|
||||
@import 'component/placeholder';
|
||||
@import 'component/progress';
|
||||
@import 'component/search';
|
||||
@import 'component/claim-search';
|
||||
@import 'component/section';
|
||||
|
|
|
@ -388,7 +388,10 @@ fieldset-group {
|
|||
}
|
||||
|
||||
.form-field--short {
|
||||
width: 100%;
|
||||
@media (min-width: $breakpoint-small) {
|
||||
width: 25em;
|
||||
}
|
||||
}
|
||||
|
||||
.form-field--price-amount {
|
||||
|
|
|
@ -186,3 +186,9 @@
|
|||
justify-content: center;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.header__auth-title {
|
||||
@media (min-width: $breakpoint-small) {
|
||||
font-size: var(--font-large);
|
||||
}
|
||||
}
|
||||
|
|
17
ui/scss/component/_progress.scss
Normal file
17
ui/scss/component/_progress.scss
Normal file
|
@ -0,0 +1,17 @@
|
|||
.progress__item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
&:not(:first-of-type) {
|
||||
margin-top: var(--spacing-s);
|
||||
}
|
||||
}
|
||||
|
||||
.progress__complete-icon {
|
||||
margin-left: var(--spacing-s);
|
||||
}
|
||||
|
||||
.progress__complete-icon--completed {
|
||||
@extend .progress__complete-icon;
|
||||
stroke: var(--color-primary);
|
||||
}
|
Loading…
Reference in a new issue