parent
9f40680b64
commit
9e48d22d70
7 changed files with 296 additions and 12 deletions
|
@ -26,16 +26,15 @@ MATOMO_URL=https://analytics.lbry.com/
|
|||
MATOMO_ID=4
|
||||
|
||||
# OG
|
||||
OG_TITLE_SUFFIX=| lbry.com
|
||||
OG_HOMEPAGE_TITLE=lbry.com
|
||||
OG_TITLE_SUFFIX=| lbry.tv
|
||||
OG_HOMEPAGE_TITLE=lbry.tv
|
||||
OG_IMAGE_URL=
|
||||
SITE_CANONICAL_URL=https://lbry.com
|
||||
SITE_CANONICAL_URL=https://lbry.tv
|
||||
|
||||
# UI
|
||||
## Custom Site info
|
||||
DOMAIN=lbry.com
|
||||
CLOUD_DOMAIN=odysee.com
|
||||
URL=https://lbry.com
|
||||
DOMAIN=lbry.tv
|
||||
URL=https://lbry.tv
|
||||
SITE_TITLE=LBRY
|
||||
SITE_NAME=LBRY
|
||||
SITE_DESCRIPTION=Meet LBRY, an open, free, and community-controlled content wonderland.
|
||||
|
|
|
@ -21,7 +21,6 @@ const config = {
|
|||
WELCOME_VERSION: process.env.WELCOME_VERSION,
|
||||
DOMAIN: process.env.DOMAIN,
|
||||
SHARE_DOMAIN_URL: process.env.SHARE_DOMAIN_URL,
|
||||
CLOUD_DOMAIN: process.env.CLOUD_DOMAIN,
|
||||
URL: process.env.URL,
|
||||
THUMBNAIL_CDN_URL: process.env.THUMBNAIL_CDN_URL,
|
||||
SITE_TITLE: process.env.SITE_TITLE,
|
||||
|
|
|
@ -155,7 +155,10 @@ Lbryio.authenticate = (domain, language) => {
|
|||
.then(
|
||||
status =>
|
||||
new Promise((res, rej) => {
|
||||
const appId = status.installation_id;
|
||||
const appId =
|
||||
domain && domain !== 'lbry.tv'
|
||||
? (domain.replace(/[.]/gi, '') + status.installation_id).slice(0, 66)
|
||||
: status.installation_id;
|
||||
Lbryio.call(
|
||||
'user',
|
||||
'new',
|
||||
|
|
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);
|
216
ui/page/youtubeSync/view.jsx
Normal file
216
ui/page/youtubeSync/view.jsx
Normal file
|
@ -0,0 +1,216 @@
|
|||
// @flow
|
||||
import { SITE_NAME, DOMAIN } from 'config';
|
||||
import * as PAGES from 'constants/pages';
|
||||
import SUPPORTED_LANGUAGES from 'constants/supported_languages';
|
||||
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 'util/lbryURI';
|
||||
import { Lbryio } from 'lbryinc';
|
||||
import { useHistory } from 'react-router';
|
||||
import YoutubeTransferStatus from 'component/youtubeTransferStatus';
|
||||
import Nag from 'component/common/nag';
|
||||
import { getDefaultLanguage, sortLanguageMap } from 'util/default-languages';
|
||||
|
||||
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,
|
||||
inSignUpFlow?: boolean,
|
||||
doToggleInterestedInYoutubeSync: () => void,
|
||||
};
|
||||
|
||||
export default function YoutubeSync(props: Props) {
|
||||
const { youtubeChannels, doUserFetch, inSignUpFlow = false, doToggleInterestedInYoutubeSync } = props;
|
||||
const {
|
||||
location: { search, pathname },
|
||||
push,
|
||||
replace,
|
||||
} = 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 [language, setLanguage] = React.useState(getDefaultLanguage());
|
||||
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(() => {
|
||||
const urlParamsInEffect = new URLSearchParams(search);
|
||||
if (!urlParamsInEffect.get('reset_scroll')) {
|
||||
urlParamsInEffect.append('reset_scroll', 'youtube');
|
||||
}
|
||||
|
||||
replace(`?${urlParamsInEffect.toString()}`);
|
||||
}, [pathname, search]);
|
||||
|
||||
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,
|
||||
channel_language: language,
|
||||
desired_lbry_channel_name: `@${channel}`,
|
||||
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;
|
||||
});
|
||||
}
|
||||
|
||||
function handleChannelChange(e) {
|
||||
const { value } = e.target;
|
||||
setChannel(value);
|
||||
if (!isNameValid(value)) {
|
||||
setNameError(INVALID_NAME_ERROR);
|
||||
} else {
|
||||
setNameError();
|
||||
}
|
||||
}
|
||||
|
||||
function handleNewChannel() {
|
||||
urlParams.append('new_channel', 'true');
|
||||
push(`${pathname}?${urlParams.toString()}`);
|
||||
setAddingNewChannel(true);
|
||||
}
|
||||
|
||||
const Wrapper = (props: { children: any }) => {
|
||||
return inSignUpFlow ? (
|
||||
<>{props.children}</>
|
||||
) : (
|
||||
<Page noSideNavigation authPage>
|
||||
{props.children}
|
||||
</Page>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<Wrapper>
|
||||
<div className="main__channel-creation">
|
||||
{hasYoutubeChannels && !addingNewChannel ? (
|
||||
<YoutubeTransferStatus alwaysShow addNewChannel={handleNewChannel} />
|
||||
) : (
|
||||
<Card
|
||||
title={__('Sync your YouTube channel to %site_name%', { site_name: 'LBRY' })}
|
||||
subtitle={__('Get your YouTube videos in front of the %site_name% audience.', {
|
||||
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 %site_name% channel name', { site_name: 'LBRY' })
|
||||
)}
|
||||
</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
|
||||
name="language_select"
|
||||
type="select"
|
||||
label={__('Channel language')}
|
||||
onChange={(event) => setLanguage(event.target.value)}
|
||||
value={language}
|
||||
>
|
||||
{sortLanguageMap(SUPPORTED_LANGUAGES).map(([langKey, langName]) => (
|
||||
<option key={langKey} value={langKey}>
|
||||
{langName}
|
||||
</option>
|
||||
))}
|
||||
</FormField>
|
||||
<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"
|
||||
/>
|
||||
),
|
||||
site_name: SITE_NAME,
|
||||
}}
|
||||
>
|
||||
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>
|
||||
}
|
||||
/>
|
||||
|
||||
<div className="section__actions">
|
||||
<Button
|
||||
button="primary"
|
||||
type="submit"
|
||||
disabled={nameError || !channel || !acknowledgedTerms}
|
||||
label={__('Claim Now')}
|
||||
/>
|
||||
|
||||
{inSignUpFlow && !errorMessage && (
|
||||
<Button button="link" label={__('Skip')} onClick={() => doToggleInterestedInYoutubeSync()} />
|
||||
)}
|
||||
|
||||
{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>
|
||||
</Wrapper>
|
||||
);
|
||||
}
|
|
@ -7,7 +7,7 @@ import * as MODALS from 'constants/modal_types';
|
|||
import * as SETTINGS from 'constants/settings';
|
||||
import * as DAEMON_SETTINGS from 'constants/daemon_settings';
|
||||
import * as SHARED_PREFERENCES from 'constants/shared_preferences';
|
||||
import { CLOUD_DOMAIN } from 'config';
|
||||
import { DOMAIN } from 'config';
|
||||
import Lbry from 'lbry';
|
||||
import { doFetchChannelListMine, doFetchCollectionListMine, doCheckPendingClaims } from 'redux/actions/claims';
|
||||
import { selectClaimForUri, selectClaimIsMineForUri, selectMyChannelClaims } from 'redux/selectors/claims';
|
||||
|
@ -336,7 +336,7 @@ export function doDaemonReady() {
|
|||
}
|
||||
},
|
||||
undefined,
|
||||
CLOUD_DOMAIN
|
||||
DOMAIN
|
||||
)
|
||||
);
|
||||
dispatch({ type: ACTIONS.DAEMON_READY });
|
||||
|
|
|
@ -9,11 +9,42 @@ import { doClaimRewardType, doRewardList } from 'redux/actions/rewards';
|
|||
import { selectEmailToVerify, selectPhoneToVerify, selectUserCountryCode, selectUser } from 'redux/selectors/user';
|
||||
import rewards from 'rewards';
|
||||
import { Lbryio } from 'lbryinc';
|
||||
import { CLOUD_DOMAIN } from 'config';
|
||||
import { DOMAIN } from 'config';
|
||||
import { getDefaultLanguage } from 'util/default-languages';
|
||||
const AUTH_IN_PROGRESS = 'authInProgress';
|
||||
export let sessionStorageAvailable = false;
|
||||
|
||||
export function doFetchInviteStatus(shouldCallRewardList = true) {
|
||||
return (dispatch) => {
|
||||
dispatch({
|
||||
type: ACTIONS.USER_INVITE_STATUS_FETCH_STARTED,
|
||||
});
|
||||
|
||||
Promise.all([Lbryio.call('user', 'invite_status'), Lbryio.call('user_referral_code', 'list')])
|
||||
.then(([status, code]) => {
|
||||
if (shouldCallRewardList) {
|
||||
dispatch(doRewardList());
|
||||
}
|
||||
|
||||
dispatch({
|
||||
type: ACTIONS.USER_INVITE_STATUS_FETCH_SUCCESS,
|
||||
data: {
|
||||
invitesRemaining: status.invites_remaining ? status.invites_remaining : 0,
|
||||
invitees: status.invitees,
|
||||
referralLink: `${Lbryio.CONNECTION_STRING}user/refer?r=${code}`,
|
||||
referralCode: code,
|
||||
},
|
||||
});
|
||||
})
|
||||
.catch((error) => {
|
||||
dispatch({
|
||||
type: ACTIONS.USER_INVITE_STATUS_FETCH_FAILURE,
|
||||
data: { error },
|
||||
});
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export function doInstallNew(appVersion, os = null, firebaseToken = null, callbackForUsersWhoAreSharingData, domain) {
|
||||
const payload = { app_version: appVersion, domain };
|
||||
if (firebaseToken) {
|
||||
|
@ -39,6 +70,30 @@ export function doInstallNew(appVersion, os = null, firebaseToken = null, callba
|
|||
});
|
||||
}
|
||||
|
||||
export function doInstallNewWithParams(
|
||||
appVersion,
|
||||
installationId,
|
||||
nodeId,
|
||||
lbrynetVersion,
|
||||
os,
|
||||
platform,
|
||||
firebaseToken = null
|
||||
) {
|
||||
return () => {
|
||||
const payload = { app_version: appVersion };
|
||||
if (firebaseToken) {
|
||||
payload.firebase_token = firebaseToken;
|
||||
}
|
||||
|
||||
payload.app_id = installationId;
|
||||
payload.node_id = nodeId;
|
||||
payload.daemon_version = lbrynetVersion;
|
||||
payload.operating_system = os;
|
||||
payload.platform = platform;
|
||||
Lbryio.call('install', 'new', payload);
|
||||
};
|
||||
}
|
||||
|
||||
// TODO: Call doInstallNew separately so we don't have to pass appVersion and os_system params?
|
||||
export function doAuthenticate(
|
||||
appVersion,
|
||||
|
@ -53,7 +108,7 @@ export function doAuthenticate(
|
|||
dispatch({
|
||||
type: ACTIONS.AUTHENTICATION_STARTED,
|
||||
});
|
||||
return Lbryio.authenticate(CLOUD_DOMAIN, getDefaultLanguage()) // lbry.tv
|
||||
return Lbryio.authenticate(DOMAIN, getDefaultLanguage())
|
||||
.then((user) => {
|
||||
if (sessionStorageAvailable) window.sessionStorage.removeItem(AUTH_IN_PROGRESS);
|
||||
Lbryio.getAuthToken().then((token) => {
|
||||
|
|
Loading…
Reference in a new issue