remove reward/verify components

This commit is contained in:
zeppi 2022-06-28 11:49:34 -04:00
parent fbd9131b91
commit f87ce8e517
36 changed files with 96 additions and 1549 deletions

View file

@ -2315,5 +2315,6 @@
"Disable background": "Disable background",
"Installing, please wait...": "Installing, please wait...",
"There was an error during installation. Please, try again.": "There was an error during installation. Please, try again.",
"Odysee Connect --[Section in Help Page]--": "Odysee Connect",
"--end--": "--end--"
}

View file

@ -1,9 +0,0 @@
import { connect } from 'react-redux';
import { selectUnclaimedRewardValue } from 'redux/selectors/rewards';
import RewardAuthIntro from './view';
const select = state => ({
totalRewardValue: selectUnclaimedRewardValue(state),
});
export default connect(select, null)(RewardAuthIntro);

View file

@ -1,46 +0,0 @@
// @flow
import { SITE_NAME } from 'config';
import * as PAGES from 'constants/pages';
import React from 'react';
import CreditAmount from 'component/common/credit-amount';
import Button from 'component/button';
import Card from 'component/common/card';
import I18nMessage from 'component/i18nMessage';
type Props = {
balance: number,
totalRewardValue: number,
title?: string,
};
function RewardAuthIntro(props: Props) {
const { totalRewardValue, title } = props;
const totalRewardRounded = Math.floor(totalRewardValue / 10) * 10;
return (
<Card
title={title || __('Log in to %SITE_NAME% to earn rewards', { SITE_NAME })}
subtitle={
<I18nMessage
tokens={{
credit_amount: <CreditAmount inheritStyle amount={totalRewardRounded} />,
site_name: SITE_NAME,
}}
>
A %site_name% account allows you to earn more than %credit_amount% in rewards, backup your data, and get
content and security updates.
</I18nMessage>
}
actions={
<Button
requiresAuth
button="primary"
navigate={`/$/${PAGES.REWARDS_VERIFY}?redirect=/$/${PAGES.REWARDS}`}
label={__('Unlock Rewards')}
/>
}
/>
);
}
export default RewardAuthIntro;

View file

@ -1,17 +0,0 @@
import { connect } from 'react-redux';
import { makeSelectRewardByClaimCode, makeSelectIsRewardClaimPending } from 'redux/selectors/rewards';
import { doClaimRewardType } from 'redux/actions/rewards';
import RewardLink from './view';
const select = (state, props) => ({
isPending: makeSelectIsRewardClaimPending()(state, props),
reward: makeSelectRewardByClaimCode()(state, props.claim_code),
});
const perform = dispatch => ({
claimReward: reward =>
dispatch(doClaimRewardType(reward.reward_type, { notifyError: true, params: { claim_code: reward.claim_code } })),
});
export default connect(select, perform)(RewardLink);

View file

@ -1,48 +0,0 @@
// @flow
import React from 'react';
import Button from 'component/button';
import LbcMessage from 'component/common/lbc-message';
type Reward = {
reward_amount: number,
reward_range: string,
};
type Props = {
isPending: boolean,
label: ?string,
reward: Reward,
button: ?boolean,
disabled: boolean,
claimReward: (Reward) => void,
};
const RewardLink = (props: Props) => {
const { reward, claimReward, label, isPending, button, disabled = false } = props;
let displayLabel = label;
if (isPending) {
displayLabel = __('Claiming...');
} else if (label) {
displayLabel = label;
} else if (reward && reward.reward_range && reward.reward_range.includes('-')) {
displayLabel = __('Claim %range% LBC', { range: reward.reward_range });
} else if (reward && reward.reward_amount > 0) {
displayLabel = __('Claim %amount% LBC', { amount: reward.reward_amount });
} else {
displayLabel = __('Claim ??? LBC');
}
return !reward ? null : (
<Button
button={button ? 'primary' : 'link'}
disabled={disabled || isPending}
label={<LbcMessage>{displayLabel}</LbcMessage>}
aria-label={displayLabel}
onClick={() => {
claimReward(reward);
}}
/>
);
};
export default RewardLink;

View file

@ -1,9 +0,0 @@
import { connect } from 'react-redux';
import { selectClaimedRewards } from 'redux/selectors/rewards';
import RewardListClaimed from './view';
const select = state => ({
rewards: selectClaimedRewards(state),
});
export default connect(select, null)(RewardListClaimed);

View file

@ -1,68 +0,0 @@
// @flow
import React from 'react';
import ButtonTransaction from 'component/common/transaction-link';
import moment from 'moment';
import LbcSymbol from 'component/common/lbc-symbol';
import Card from 'component/common/card';
type Reward = {
id: string,
reward_title: string,
reward_amount: number,
transaction_id: string,
created_at: string,
};
type Props = {
rewards: Array<Reward>,
};
const RewardListClaimed = (props: Props) => {
const { rewards } = props;
if (!rewards || !rewards.length) {
return null;
}
return (
<Card
title={<div className="table__header-text">{__('Claimed Rewards')}</div>}
subtitle={
<div className="table__header-text">
{__(
'Reward history is tied to your email. In case of lost or multiple wallets, your balance may differ from the amounts claimed'
)}
</div>
}
isBodyList
body={
<div className="table__wrapper">
<table className="table table--rewards">
<thead>
<tr>
<th>{__('Title')}</th>
<th>
<LbcSymbol size={20} />
</th>
<th>{__('Transaction')}</th>
<th>{__('Date')}</th>
</tr>
</thead>
<tbody>
{rewards.reverse().map(reward => (
<tr key={reward.id}>
<td>{reward.reward_title}</td>
<td>{reward.reward_amount}</td>
<td>{reward.transaction_id && <ButtonTransaction id={reward.transaction_id} />}</td>
<td>{moment(reward.created_at).format('LLL')}</td>
</tr>
))}
</tbody>
</table>
</div>
}
/>
);
};
export default RewardListClaimed;

View file

@ -1,10 +0,0 @@
import { connect } from 'react-redux';
import { selectUnclaimedRewardValue, selectFetchingRewards } from 'redux/selectors/rewards';
import RewardSummary from './view';
const select = state => ({
unclaimedRewardAmount: selectUnclaimedRewardValue(state),
fetching: selectFetchingRewards(state),
});
export default connect(select, null)(RewardSummary);

View file

@ -1,52 +0,0 @@
// @flow
import * as React from 'react';
import Button from 'component/button';
import CreditAmount from 'component/common/credit-amount';
import I18nMessage from 'component/i18nMessage';
import Card from 'component/common/card';
type Props = {
unclaimedRewardAmount: number,
fetching: boolean,
};
class RewardSummary extends React.Component<Props> {
render() {
const { unclaimedRewardAmount, fetching } = this.props;
const hasRewards = unclaimedRewardAmount > 0;
return (
<Card
title={__('Available rewards')}
subtitle={
<React.Fragment>
{fetching && __('You have...')}
{!fetching && hasRewards ? (
<I18nMessage
tokens={{
credit_amount: <CreditAmount inheritStyle amount={unclaimedRewardAmount} precision={8} />,
}}
f
>
You have %credit_amount% in unclaimed rewards.
</I18nMessage>
) : (
__('You have no rewards available.')
)}
</React.Fragment>
}
actions={
<React.Fragment>
<Button
button="primary"
navigate="/$/rewards"
label={hasRewards ? __('Claim Rewards') : __('View Rewards')}
/>
<Button button="link" label={__('Learn more')} href="https://lbry.com/faq/rewards" />
</React.Fragment>
}
/>
);
}
}
export default RewardSummary;

View file

@ -1,15 +0,0 @@
import * as MODALS from 'constants/modal_types';
import { connect } from 'react-redux';
import { doOpenModal } from 'redux/actions/app';
import { selectUser } from 'redux/selectors/user';
import RewardTile from './view';
const select = state => ({
user: selectUser(state),
});
const perform = dispatch => ({
openRewardCodeModal: () => dispatch(doOpenModal(MODALS.REWARD_GENERATED_CODE)),
openSetReferrerModal: () => dispatch(doOpenModal(MODALS.SET_REFERRER)),
});
export default connect(select, perform)(RewardTile);

View file

@ -1,78 +0,0 @@
// @flow
import * as ICONS from 'constants/icons';
import React from 'react';
import Icon from 'component/common/icon';
import RewardLink from 'component/rewardLink';
import Button from 'component/button';
import Card from 'component/common/card';
import rewards from 'rewards';
import LbcMessage from 'component/common/lbc-message';
type Props = {
openRewardCodeModal: () => void,
openSetReferrerModal: () => void,
reward: {
id: string,
reward_title: string,
reward_amount: number,
reward_range?: string,
transaction_id: string,
created_at: string,
reward_description: string,
reward_type: string,
claim_code: string,
},
user: User,
disabled: boolean,
};
const RewardTile = (props: Props) => {
const { reward, openRewardCodeModal, openSetReferrerModal, user, disabled = false } = props;
const referrerSet = user && user.invited_by_id;
const claimed = !!reward.transaction_id;
const customActionsRewards = [rewards.TYPE_REFERRAL, rewards.TYPE_REFEREE];
return (
<Card
title={__(reward.reward_title)}
subtitle={<LbcMessage>{reward.reward_description}</LbcMessage>}
actions={
<div className="section__actions">
{reward.reward_type === rewards.TYPE_GENERATED_CODE && (
<Button button="primary" onClick={openRewardCodeModal} label={__('Enter Code')} disabled={disabled} />
)}
{reward.reward_type === rewards.TYPE_REFERRAL && (
<Button
button="primary"
navigate="/$/invite"
label={__('Go To Invites')}
aria-hidden={disabled}
tabIndex={disabled ? -1 : 0}
/>
)}
{reward.reward_type === rewards.TYPE_REFEREE && (
<>
{referrerSet && <RewardLink button reward_type={reward.reward_type} disabled={disabled} />}
<Button
button={referrerSet ? 'link' : 'primary'}
onClick={openSetReferrerModal}
label={referrerSet ? __('Change Inviter') : __('Set Inviter')}
disabled={disabled}
/>
</>
)}
{!customActionsRewards.some((i) => i === reward.reward_type) &&
(claimed ? (
<span>
<Icon icon={ICONS.COMPLETED} /> {__('Reward claimed.')}
</span>
) : (
<RewardLink button claim_code={reward.claim_code} disabled={disabled} />
))}
</div>
}
/>
);
};
export default RewardTile;

View file

@ -1,16 +0,0 @@
import { connect } from 'react-redux';
import { selectUnclaimedRewardValue, selectFetchingRewards, selectClaimedRewards } from 'redux/selectors/rewards';
import { doRewardList } from 'redux/actions/rewards';
import RewardSummary from './view';
const select = state => ({
unclaimedRewardAmount: selectUnclaimedRewardValue(state),
fetching: selectFetchingRewards(state),
rewards: selectClaimedRewards(state),
});
const perform = dispatch => ({
fetchRewards: () => dispatch(doRewardList()),
});
export default connect(select, perform)(RewardSummary);

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

View file

@ -1,26 +0,0 @@
// @flow
import React from 'react';
import TotalBackground from './total-background.png';
import useTween from 'effects/use-tween';
import I18nMessage from 'component/i18nMessage';
import LbcSymbol from 'component/common/lbc-symbol';
type Props = {
rewards: Array<Reward>,
};
function RewardTotal(props: Props) {
const { rewards } = props;
const rewardTotal = rewards.reduce((acc, val) => acc + val.reward_amount, 0);
const modifier = rewardTotal > 500 ? 1 : 15; // used to tweak the reward count speed
const total = useTween(rewardTotal * modifier);
const integer = Math.round(total * rewardTotal);
return (
<section className="card card--section card--reward-total" style={{ backgroundImage: `url(${TotalBackground})` }}>
<I18nMessage tokens={{ amount: integer, lbc: <LbcSymbol /> }}>%amount% %lbc% earned from rewards</I18nMessage>
</section>
);
}
export default RewardTotal;

View file

@ -37,7 +37,6 @@ import ChannelsPage from 'page/channels';
import CreatorDashboard from 'page/creatorDashboard';
import DiscoverPage from 'page/discover';
import FileListPublished from 'page/fileListPublished';
import FourOhFourPage from 'page/fourOhFour';
import HelpPage from 'page/help';
import LibraryPage from 'page/library';
import ListBlockedPage from 'page/listBlocked';
@ -279,7 +278,6 @@ function AppRouter(props: Props) {
{/* Below need to go at the end to make sure we don't match any of our pages first */}
<Route path="/:claimName" exact component={ShowPage} />
<Route path="/:claimName/:streamName" exact component={ShowPage} />
<Route path="/*" component={FourOhFourPage} />
</Switch>
);
}

View file

@ -1,14 +0,0 @@
import { connect } from 'react-redux';
import { selectPhoneNewErrorMessage } from 'redux/selectors/user';
import { doUserPhoneNew } from 'redux/actions/user';
import UserPhoneNew from './view';
const select = state => ({
phoneErrorMessage: selectPhoneNewErrorMessage(state),
});
const perform = dispatch => ({
addUserPhone: (phone, countryCode) => dispatch(doUserPhoneNew(phone, countryCode)),
});
export default connect(select, perform)(UserPhoneNew);

View file

@ -1,124 +0,0 @@
// @flow
import * as React from 'react';
import { Form, FormField, Submit } from 'component/common/form';
import Card from 'component/common/card';
const os = require('os').type();
const countryCodes = require('country-data')
.callingCountries.all.filter(_ => _.emoji)
.reduce((acc, cur) => acc.concat(cur.countryCallingCodes.map(_ => ({ ...cur, countryCallingCode: _ }))), [])
.sort((a, b) => {
if (a.countryCallingCode < b.countryCallingCode) {
return -1;
}
if (a.countryCallingCode > b.countryCallingCode) {
return 1;
}
return 0;
});
type Props = {
addUserPhone: (string, string) => void,
cancelButton: React.Node,
phoneErrorMessage: ?string,
isPending: boolean,
};
type State = {
phone: string,
countryCode: string,
};
class UserPhoneNew extends React.PureComponent<Props, State> {
constructor(props: Props) {
super(props);
this.state = {
phone: '',
countryCode: '+1',
};
(this: any).formatPhone = this.formatPhone.bind(this);
(this: any).handleSubmit = this.handleSubmit.bind(this);
(this: any).handleSelect = this.handleSelect.bind(this);
}
formatPhone(value: string) {
const { countryCode } = this.state;
const formattedNumber = value.replace(/\D/g, '');
if (countryCode === '+1') {
if (!formattedNumber) {
return '';
} else if (formattedNumber.length < 4) {
return formattedNumber;
} else if (formattedNumber.length < 7) {
return `(${formattedNumber.substring(0, 3)}) ${formattedNumber.substring(3)}`;
}
const fullNumber = `(${formattedNumber.substring(0, 3)}) ${formattedNumber.substring(
3,
6
)}-${formattedNumber.substring(6)}`;
return fullNumber.length <= 14 ? fullNumber : fullNumber.substring(0, 14);
}
return formattedNumber;
}
handleChanged(event: SyntheticInputEvent<*>) {
this.setState({
phone: this.formatPhone(event.target.value),
});
}
handleSelect(event: SyntheticInputEvent<*>) {
this.setState({ countryCode: event.target.value });
}
handleSubmit() {
const { phone, countryCode } = this.state;
this.props.addUserPhone(phone.replace(/\D/g, ''), countryCode.substring(1));
}
render() {
const { cancelButton, phoneErrorMessage, isPending } = this.props;
return (
<Card
title={__('Enter your phone number')}
subtitle={__(
'Enter your phone number and we will send you a verification code. We will not share your phone number with third parties.'
)}
actions={
<Form onSubmit={this.handleSubmit}>
<fieldset-group class="fieldset-group--smushed">
<FormField label={__('Country')} type="select" name="country-codes" onChange={this.handleSelect}>
{countryCodes.map((country, index) => (
<option key={index} value={country.countryCallingCode}>
{os === 'Darwin' ? country.emoji : `(${country.alpha2})`} {country.countryCallingCode}
</option>
))}
</FormField>
<FormField
type="text"
label={__('Number')}
placeholder={this.state.countryCode === '+1' ? '(555) 555-5555' : '5555555555'}
name="phone"
value={this.state.phone}
error={phoneErrorMessage}
onChange={event => {
this.handleChanged(event);
}}
/>
</fieldset-group>
<div className="card__actions">
<Submit label="Submit" disabled={isPending} />
{cancelButton}
</div>
</Form>
}
/>
);
}
}
export default UserPhoneNew;

View file

@ -1,17 +0,0 @@
import { connect } from 'react-redux';
import { doUserPhoneVerify, doUserPhoneReset } from 'redux/actions/user';
import { selectPhoneToVerify, selectPhoneVerifyErrorMessage, selectUserCountryCode } from 'redux/selectors/user';
import UserPhoneVerify from './view';
const select = state => ({
phone: selectPhoneToVerify(state),
countryCode: selectUserCountryCode(state),
phoneErrorMessage: selectPhoneVerifyErrorMessage(state),
});
const perform = dispatch => ({
resetPhone: () => dispatch(doUserPhoneReset()),
verifyUserPhone: code => dispatch(doUserPhoneVerify(code)),
});
export default connect(select, perform)(UserPhoneVerify);

View file

@ -1,90 +0,0 @@
// @flow
import * as React from 'react';
import Button from 'component/button';
import { Form, FormField, Submit } from 'component/common/form';
import I18nMessage from 'component/i18nMessage';
import Card from 'component/common/card';
import { SITE_HELP_EMAIL } from 'config';
type Props = {
verifyUserPhone: (string) => void,
resetPhone: () => void,
phoneErrorMessage: string,
phone: string,
countryCode: string,
};
type State = {
code: string,
};
class UserPhoneVerify extends React.PureComponent<Props, State> {
constructor(props: Props) {
super(props);
this.state = {
code: '',
};
}
handleCodeChanged(event: SyntheticInputEvent<*>) {
this.setState({
code: String(event.target.value).trim(),
});
}
handleSubmit() {
const { code } = this.state;
this.props.verifyUserPhone(code);
}
reset() {
const { resetPhone } = this.props;
resetPhone();
}
render() {
const { phoneErrorMessage, phone, countryCode } = this.props;
return (
<Card
title={__('Enter the verification code')}
subtitle={
<>
{__(`Please enter the verification code sent to +${countryCode}${phone}. Didn't receive it? `)}
<Button button="link" onClick={this.reset.bind(this)} label={__('Go back.')} />
</>
}
actions={
<>
<Form onSubmit={this.handleSubmit.bind(this)}>
<FormField
type="text"
name="code"
placeholder="1234"
value={this.state.code}
onChange={(event) => {
this.handleCodeChanged(event);
}}
label={__('Verification Code')}
error={phoneErrorMessage}
inputButton={<Submit label={__('Verify')} />}
/>
</Form>
<p className="help">
<I18nMessage
tokens={{
help_link: <Button button="link" href={`mailto:${SITE_HELP_EMAIL}`} label={`${SITE_HELP_EMAIL}`} />,
chat_link: <Button button="link" href="https://chat.lbry.com" label={__('chat')} />,
}}
>
Email %help_link% or join our %chat_link% if you encounter any trouble with your code.
</I18nMessage>
</p>
</>
}
/>
);
}
}
export default UserPhoneVerify;

View file

@ -1,26 +0,0 @@
import * as MODALS from 'constants/modal_types';
import { connect } from 'react-redux';
import { doOpenModal } from 'redux/actions/app';
import { doUserIdentityVerify, doUserFetch } from 'redux/actions/user';
import { makeSelectRewardByType } from 'redux/selectors/rewards';
import rewards from 'rewards';
import { selectIdentityVerifyIsPending, selectIdentityVerifyErrorMessage } from 'redux/selectors/user';
import UserVerify from './view';
const select = state => {
const selectReward = makeSelectRewardByType();
return {
isPending: selectIdentityVerifyIsPending(state),
errorMessage: selectIdentityVerifyErrorMessage(state),
reward: selectReward(state, rewards.TYPE_NEW_USER),
};
};
const perform = dispatch => ({
verifyUserIdentity: token => dispatch(doUserIdentityVerify(token)),
verifyPhone: () => dispatch(doOpenModal(MODALS.PHONE_COLLECTION)),
fetchUser: () => dispatch(doUserFetch()),
});
export default connect(select, perform)(UserVerify);

View file

@ -1,164 +0,0 @@
// @flow
import { SITE_NAME } from 'config';
import * as ICONS from 'constants/icons';
import React, { Fragment } from 'react';
import Button from 'component/button';
import CardVerify from 'component/cardVerify';
import { Lbryio } from 'lbryinc';
import Card from 'component/common/card';
import I18nMessage from 'component/i18nMessage';
import LbcSymbol from 'component/common/lbc-symbol';
type Props = {
errorMessage: ?string,
isPending: boolean,
verifyUserIdentity: (string) => void,
verifyPhone: () => void,
fetchUser: () => void,
skipLink?: string,
onSkip: () => void,
};
class UserVerify extends React.PureComponent<Props> {
constructor() {
super();
(this: any).onToken = this.onToken.bind(this);
}
onToken(data: { id: string }) {
this.props.verifyUserIdentity(data.id);
}
render() {
const { errorMessage, isPending, verifyPhone, fetchUser, onSkip } = this.props;
const skipButtonProps = {
onClick: onSkip,
};
return (
<div className="main__auth-content">
<section className="section__header">
<h1 className="section__title--large">
{''}
<I18nMessage
tokens={{
lbc: <LbcSymbol size={48} />,
}}
>
Verify to earn %lbc%
</I18nMessage>
</h1>
<p>
<I18nMessage
tokens={{
rewards_program: (
<Button button="link" label={__('other rewards')} href="https://lbry.com/faq/rewards" />
),
Refresh: <Button onClick={() => fetchUser()} button="link" label={__('Refresh')} />,
Skip: <Button {...skipButtonProps} button="link" label={__('Skip')} />,
SITE_NAME,
}}
>
Verified accounts are eligible to earn LBRY Credits for views, watching and reposting content, sharing
invite links etc. Verifying also helps us keep the %SITE_NAME% community safe too! %Refresh% or %Skip%.
</I18nMessage>
</p>
<p className="help">
{__('This step is not mandatory and not required in order for you to use %SITE_NAME%.', { SITE_NAME })}
</p>
</section>
<div className="section">
<Card
icon={ICONS.PHONE}
title={__('Verify phone number')}
subtitle={__(
'You will receive an SMS text message confirming your phone number is valid. May not be available in all regions.'
)}
actions={
<Fragment>
<Button
onClick={() => {
verifyPhone();
}}
button="primary"
label={__('Verify Via Text')}
/>
<p className="help">
{__('Standard messaging rates apply. Having trouble?')}{' '}
<Button button="link" href="https://lbry.com/faq/phone" label={__('Read more')} />.
</p>
</Fragment>
}
/>
<div className="section__divider">
<hr />
<p>{__('OR')}</p>
</div>
<Card
icon={ICONS.WALLET}
title={__('Verify via credit card')}
subtitle={__('Your card information will not be stored or charged, now or in the future.')}
actions={
<Fragment>
{errorMessage && <p className="error__text">{errorMessage}</p>}
<CardVerify
label={__('Verify Card')}
disabled={isPending}
token={this.onToken}
stripeKey={Lbryio.getStripeToken()}
/>
<p className="help">
{__('A $1 authorization may temporarily appear with your provider.')}{' '}
<Button button="link" href="https://lbry.com/faq/identity-requirements" label={__('Read more')} />.
</p>
</Fragment>
}
/>
<div className="section__divider">
<hr />
<p>{__('OR')}</p>
</div>
<Card
icon={ICONS.CHAT}
title={__('Verify via chat')}
subtitle={
<>
<p>
{__(
'A moderator can approve you within our discord server. Please review the instructions within #rewards-approval carefully.'
)}
</p>
<p>{__('You will be asked to provide proof of identity.')}</p>
</>
}
actions={<Button href="https://chat.lbry.com" button="primary" label={__('Join LBRY Chat')} />}
/>
<div className="section__divider">
<hr />
<p>{__('OR')}</p>
</div>
<Card
icon={ICONS.REMOVE}
title={__('Skip')}
subtitle={__("Verifying is optional. If you skip this, it just means you can't earn LBRY Credits.")}
actions={
<Fragment>
<Button {...skipButtonProps} button="primary" label={__('Continue Without Verifying')} />
</Fragment>
}
/>
</div>
</div>
);
}
}
export default UserVerify;

View file

@ -37,7 +37,6 @@ export const SET_REFERRER = 'set_referrer';
export const SIGN_OUT = 'sign_out';
export const LIQUIDATE_SUPPORTS = 'liquidate_supports';
export const MASS_TIP_UNLOCK = 'mass_tip_unlock';
export const CONFIRM_AGE = 'confirm_age';
export const SYNC_ENABLE = 'SYNC_ENABLE';
export const IMAGE_UPLOAD = 'image_upload';
export const MOBILE_SEARCH = 'mobile_search';

View file

@ -1,9 +0,0 @@
import { connect } from 'react-redux';
import { doHideModal } from 'redux/actions/app';
import { doSetClientSetting } from 'redux/actions/settings';
import ModalAffirmPurchase from './view';
export default connect(null, {
doHideModal,
doSetClientSetting,
})(ModalAffirmPurchase);

View file

@ -1,52 +0,0 @@
// @flow
import * as SETTINGS from 'constants/settings';
import React from 'react';
import { Modal } from 'modal/modal';
import Card from 'component/common/card';
import Button from 'component/button';
import { FormField } from 'component/common/form';
type Props = {
doHideModal: () => void,
doSetClientSetting: (string, any) => void,
};
function ModalAffirmPurchase(props: Props) {
const { doHideModal, doSetClientSetting } = props;
const [confirmed, setConfirmed] = React.useState(false);
function handleConfirmAge() {
doSetClientSetting(SETTINGS.SHOW_MATURE, true);
doHideModal();
}
const title = __('Confirm Your Age');
return (
<Modal type="card" isOpen contentLabel={title} onAborted={doHideModal}>
<Card
title={title}
actions={
<>
<div className="section">
<FormField
name="age-confirmation"
type="checkbox"
label={__('I confirm I am over 18 years old.')}
helper={__('This is only for regulatory compliance and the data will not be stored.')}
checked={confirmed}
onChange={() => setConfirmed(!confirmed)}
/>
</div>
<div className="section__actions">
<Button button="primary" label={'Confirm'} onClick={handleConfirmAge} disabled={!confirmed} />
<Button button="link" label={__('Cancel')} onClick={doHideModal} />
</div>
</>
}
/>
</Modal>
);
}
export default ModalAffirmPurchase;

View file

@ -1,15 +0,0 @@
import { connect } from 'react-redux';
import { doHideModal } from 'redux/actions/app';
import { selectPhoneToVerify, selectUser } from 'redux/selectors/user';
import ModalPhoneCollection from './view';
const select = state => ({
phone: selectPhoneToVerify(state),
user: selectUser(state),
});
const perform = dispatch => () => ({
closeModal: () => dispatch(doHideModal()),
});
export default connect(select, perform)(ModalPhoneCollection);

View file

@ -1,50 +0,0 @@
// @flow
import React from 'react';
import { Modal } from 'modal/modal';
import Button from 'component/button';
import UserPhoneVerify from 'component/userPhoneVerify';
import UserPhoneNew from 'component/userPhoneNew';
import { Redirect } from 'react-router';
type Props = {
phone: ?number,
user: {
is_identity_verified: boolean,
},
closeModal: () => void,
history: { push: string => void },
};
class ModalPhoneCollection extends React.PureComponent<Props> {
renderInner() {
const { closeModal, phone, user } = this.props;
const cancelButton = <Button button="link" onClick={closeModal} label={__('Not Now')} />;
if (!user.is_identity_verified && !phone) {
return <UserPhoneNew cancelButton={cancelButton} />;
} else if (!user.is_identity_verified) {
return <UserPhoneVerify cancelButton={cancelButton} />;
}
closeModal();
return <Redirect to="/$/rewards" />;
}
render() {
const { user, closeModal } = this.props;
// this shouldn't happen
if (!user) {
return null;
}
return (
<Modal type="card" isOpen contentLabel="Phone" onAborted={closeModal}>
{this.renderInner()}
</Modal>
);
}
}
export default ModalPhoneCollection;

View file

@ -15,7 +15,6 @@ import ModalClaimCollectionAdd from 'modal/modalClaimCollectionAdd';
import ModalCommentAcknowledgement from 'modal/modalCommentAcknowledgement';
import ModalConfirmAge from 'modal/modalConfirmAge';
import ModalConfirmThumbnailUpload from 'modal/modalConfirmThumbnailUpload';
import ModalConfirmTransaction from 'modal/modalConfirmTransaction';
@ -39,8 +38,6 @@ import ModalOpenExternalResource from 'modal/modalOpenExternalResource';
import ModalPasswordUnsave from 'modal/modalPasswordUnsave';
import ModalPhoneCollection from 'modal/modalPhoneCollection';
import ModalPublish from 'modal/modalPublish';
import ModalPublishPreview from 'modal/modalPublishPreview';
@ -94,8 +91,7 @@ function getModal(id) {
return ModalAffirmPurchase;
case MODALS.CONFIRM_CLAIM_REVOKE:
return ModalRevokeClaim;
case MODALS.PHONE_COLLECTION:
return ModalPhoneCollection;
case MODALS.FIRST_SUBSCRIPTION:
return ModalFirstSubscription;
case MODALS.SEND_TIP:
@ -130,8 +126,6 @@ function getModal(id) {
return ModalSetReferrer;
case MODALS.SIGN_OUT:
return ModalSignOut;
case MODALS.CONFIRM_AGE:
return ModalConfirmAge;
case MODALS.FILE_SELECTION:
return ModalFileSelection;
case MODALS.LIQUIDATE_SUPPORTS:

View file

@ -1,9 +0,0 @@
import { connect } from 'react-redux';
import FourOhFourPage from './view';
const select = state => ({});
export default connect(
select,
null
)(FourOhFourPage);

View file

@ -1,16 +0,0 @@
import React from 'react';
import Page from 'component/page';
import Yrbl from 'component/yrbl';
const FourOhFourPage = () => (
<Page notcontained>
<div className="main main--empty">
<Yrbl type="sad" title={__('404')} subtitle={<p>{__('Page Not Found')}</p>} />
<p>{__('Four-Oh-Four-Oh-Four-Oh-Four! Four-Oh-Four!')}</p>
<p>{__('Four-Oh-Four, Oh, Four...')}</p>
<p>{__('Four-Oh-Four-Oh-Four-Oh-Four, Oh-Four, Oh-Four...')}</p>
</div>
</Page>
);
export default FourOhFourPage;

View file

@ -183,7 +183,6 @@ class HelpPage extends React.PureComponent<Props, State> {
}
/>
{/* @if TARGET='app' */}
<Card
title={__('View your log')}
subtitle={
@ -214,8 +213,58 @@ class HelpPage extends React.PureComponent<Props, State> {
/>
<WalletBackup />
{/* @endif */}
<>
<Card
title={__('Odysee Connect --[Section in Help Page]--')}
isBodyList
body={
<div className="table__wrapper">
<table className="table table--stretch">
<tbody>
<tr>
<td>{__('Connected Email')}</td>
<td>
{user && user.primary_email ? (
<React.Fragment>
{user.primary_email}{' '}
<Button
button="link"
navigate={`/$/${PAGES.SETTINGS_NOTIFICATIONS}`}
label={__('Update mailing preferences')}
/>
</React.Fragment>
) : (
<React.Fragment>
<span className="empty">{__('none')} </span>
<Button button="link" onClick={() => doAuth()} label={__('set email')} />
</React.Fragment>
)}
</td>
</tr>
<tr>
<td>{__('Reward Eligible')}</td>
<td>{user && user.is_reward_approved ? __('Yes') : __('No')}</td>
</tr>
<tr>
<td>{__('Access Token')}</td>
<td>
{this.state.accessTokenHidden && (
<Button button="link" label={__('View')} onClick={this.showAccessToken} />
)}
{!this.state.accessTokenHidden && accessToken && (
<div>
<p>{accessToken}</p>
<div className="help--warning">
{__('This is equivalent to a password. Do not post or share this.')}
</div>
</div>
)}
</td>
</tr>
</tbody>
</table>
</div>
}
/>
<Card
title={__('About --[About section in Help Page]--')}
subtitle={
@ -246,30 +295,6 @@ class HelpPage extends React.PureComponent<Props, State> {
<td>{__('Daemon (lbrynet)')}</td>
<td>{ver ? ver.lbrynet_version : __('Loading...')}</td>
</tr>
<tr>
<td>{__('Connected Email')}</td>
<td>
{user && user.primary_email ? (
<React.Fragment>
{user.primary_email}{' '}
<Button
button="link"
navigate={`/$/${PAGES.SETTINGS_NOTIFICATIONS}`}
label={__('Update mailing preferences')}
/>
</React.Fragment>
) : (
<React.Fragment>
<span className="empty">{__('none')} </span>
<Button button="link" onClick={() => doAuth()} label={__('set email')} />
</React.Fragment>
)}
</td>
</tr>
<tr>
<td>{__('Reward Eligible')}</td>
<td>{user && user.is_reward_approved ? __('Yes') : __('No')}</td>
</tr>
<tr>
<td>{__('Platform')}</td>
<td>{platform}</td>
@ -278,28 +303,11 @@ class HelpPage extends React.PureComponent<Props, State> {
<td>{__('Installation ID')}</td>
<td>{this.state.lbryId}</td>
</tr>
<tr>
<td>{__('Access Token')}</td>
<td>
{this.state.accessTokenHidden && (
<Button button="link" label={__('View')} onClick={this.showAccessToken} />
)}
{!this.state.accessTokenHidden && accessToken && (
<div>
<p>{accessToken}</p>
<div className="help--warning">
{__('This is equivalent to a password. Do not post or share this.')}
</div>
</div>
)}
</td>
</tr>
</tbody>
</table>
</div>
}
/>
</>
</Page>
);
}

View file

@ -1,22 +0,0 @@
import { connect } from 'react-redux';
import { selectUser } from 'redux/selectors/user';
import { selectFetchingRewards, selectUnclaimedRewards, selectClaimedRewards } from 'redux/selectors/rewards';
import { doUserFetch } from 'redux/actions/user';
import { doRewardList } from 'redux/actions/rewards';
import { selectDaemonSettings } from 'redux/selectors/settings';
import RewardsPage from './view';
const select = state => ({
daemonSettings: selectDaemonSettings(state),
fetching: selectFetchingRewards(state),
rewards: selectUnclaimedRewards(state),
claimed: selectClaimedRewards(state),
user: selectUser(state),
});
const perform = dispatch => ({
fetchRewards: () => dispatch(doRewardList()),
fetchUser: () => dispatch(doUserFetch()),
});
export default connect(select, perform)(RewardsPage);

View file

@ -1,185 +0,0 @@
// @flow
import * as PAGES from 'constants/pages';
import React, { PureComponent } from 'react';
import BusyIndicator from 'component/common/busy-indicator';
import RewardListClaimed from 'component/rewardListClaimed';
import RewardTile from 'component/rewardTile';
import Button from 'component/button';
import Page from 'component/page';
import classnames from 'classnames';
import REWARD_TYPES from 'rewards';
import RewardAuthIntro from 'component/rewardAuthIntro';
import Card from 'component/common/card';
import I18nMessage from 'component/i18nMessage';
import { SITE_HELP_EMAIL, SITE_NAME } from 'config';
type Props = {
doAuth: () => void,
fetchRewards: () => void,
fetchUser: () => void,
fetching: boolean,
rewards: Array<Reward>,
claimed: Array<Reward>,
user: ?{
is_identity_verified: boolean,
is_reward_approved: boolean,
primary_email: string,
has_verified_email: boolean,
},
daemonSettings: {
share_usage_data: boolean,
},
};
class RewardsPage extends PureComponent<Props> {
componentDidMount() {
const { user, fetchUser, fetchRewards } = this.props;
const rewardsApproved = user && user.is_reward_approved;
fetchRewards();
if (!rewardsApproved) {
fetchUser();
}
}
renderPageHeader() {
const { user, daemonSettings, fetchUser } = this.props;
const rewardsEnabled = daemonSettings && daemonSettings.share_usage_data;
if (user && !user.is_reward_approved && rewardsEnabled) {
if (!user.primary_email || !user.has_verified_email || !user.is_identity_verified) {
return (
<div className="section">
<RewardAuthIntro />
</div>
);
}
return (
<Card
className="section"
title={__('Reward validation pending')}
body={
<React.Fragment>
<p>
{__(
'This account must undergo review before you can participate in the rewards program. Not all users and regions may qualify.'
)}{' '}
{__('This can take anywhere from a few hours to several days. Please be patient.')}
</p>
<p>
{__(
'We apologize for this inconvenience, but have added this additional step to prevent abuse. Users on VPN or shared connections will continue to see this message and are not eligible for Rewards.'
)}
</p>
<p>
<I18nMessage
tokens={{
rewards_faq: <Button button="link" label={__('Rewards FAQ')} href="https://lbry.com/faq/support" />,
help_email: SITE_HELP_EMAIL,
site_name: SITE_NAME,
}}
>
Please review the %rewards_faq% for eligibility, and send us an email to %help_email% if you continue
to see this message. You can continue to use %site_name% without this feature.
</I18nMessage>
{`${__('Enjoy all the awesome free content in the meantime!')}`}
</p>
</React.Fragment>
}
actions={
<div className="section__actions">
<Button navigate="/" button="primary" label="Return Home" />
<Button onClick={() => fetchUser()} button="link" label="Refresh" />
</div>
}
/>
);
}
return null;
}
renderCustomRewardCode() {
const { user } = this.props;
const isNotEligible = !user || !user.primary_email || !user.has_verified_email || !user.is_reward_approved;
return (
<RewardTile
key={REWARD_TYPES.TYPE_GENERATED_CODE}
reward={{
reward_type: REWARD_TYPES.TYPE_GENERATED_CODE,
reward_title: __('Custom Code'),
reward_description: __('Are you a supermodel or rockstar that received a custom reward code? Claim it here.'),
}}
disabled={isNotEligible}
/>
);
}
renderUnclaimedRewards() {
const { fetching, rewards, user, daemonSettings, claimed } = this.props;
if (daemonSettings && !daemonSettings.share_usage_data) {
return (
<section className="card card--section">
<h2 className="card__title card__title--deprecated">{__('Rewards Disabled')}</h2>
<p className="error__text">
<I18nMessage tokens={{ settings: <Button button="link" navigate="/$/settings" label="Settings" /> }}>
Rewards are currently disabled for your account. Turn on diagnostic data sharing, in %settings%, to
re-enable them.
</I18nMessage>
</p>
</section>
);
} else if (fetching) {
return <BusyIndicator message={__('Fetching rewards')} />;
} else if (user === null) {
return (
<p className="help">{__('This application is unable to earn rewards due to an authentication failure.')}</p>
);
} else if (!rewards || rewards.length <= 0) {
return (
<Card
title={__('No rewards available')}
subtitle={
claimed && claimed.length
? __(
"You have claimed all available rewards! We're regularly adding more so be sure to check back later."
)
: __('There are no rewards available at this time, please check back later.')
}
actions={<Button button="primary" navigate={`/$/${PAGES.DISCOVER}`} label={__('Go Home')} />}
/>
);
}
const isNotEligible = !user || !user.primary_email || !user.has_verified_email || !user.is_reward_approved;
return (
<div
aria-hidden={isNotEligible}
className={classnames('card__list', {
'card--disabled': isNotEligible,
})}
>
{rewards.map((reward) => (
<RewardTile disabled={isNotEligible} key={reward.claim_code} reward={reward} />
))}
{this.renderCustomRewardCode()}
</div>
);
}
render() {
return (
<Page>
{this.renderPageHeader()}
<div className="section">{this.renderUnclaimedRewards()}</div>
<RewardListClaimed />
</Page>
);
}
}
export default RewardsPage;

View file

@ -1,9 +0,0 @@
import { connect } from 'react-redux';
import { selectUser } from 'redux/selectors/user';
import RewardsVerifyPage from './view';
const select = state => ({
user: selectUser(state),
});
export default connect(select, null)(RewardsVerifyPage);

View file

@ -1,29 +0,0 @@
// @flow
import React from 'react';
import UserVerify from 'component/userVerify';
import Page from 'component/page';
import { useHistory } from 'react-router-dom';
type Props = {
user: ?User,
};
function RewardsVerifyPage(props: Props) {
const { user } = props;
const { goBack } = useHistory();
const rewardsApproved = user && user.is_reward_approved;
React.useEffect(() => {
if (rewardsApproved) {
goBack();
}
}, [rewardsApproved]);
return (
<Page>
<UserVerify onSkip={() => goBack()} />
</Page>
);
}
export default RewardsVerifyPage;

View file

@ -1,12 +0,0 @@
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);

View file

@ -1,216 +0,0 @@
// @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>
);
}