remove reward/verify components
This commit is contained in:
parent
4c40b5a07f
commit
df6be2ac8f
36 changed files with 96 additions and 1549 deletions
|
@ -2314,5 +2314,6 @@
|
|||
"Apply": "Apply",
|
||||
"24-hour clock": "24-hour clock",
|
||||
"Disable background": "Disable background",
|
||||
"Odysee Connect --[Section in Help Page]--": "Odysee Connect",
|
||||
"--end--": "--end--"
|
||||
}
|
||||
|
|
|
@ -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);
|
|
@ -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;
|
|
@ -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);
|
|
@ -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;
|
|
@ -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);
|
|
@ -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;
|
|
@ -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);
|
|
@ -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;
|
|
@ -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);
|
|
@ -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;
|
|
@ -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 |
|
@ -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;
|
|
@ -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>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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);
|
|
@ -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;
|
|
@ -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);
|
|
@ -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;
|
|
@ -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);
|
|
@ -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;
|
|
@ -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';
|
||||
|
|
|
@ -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);
|
|
@ -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;
|
|
@ -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);
|
|
@ -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;
|
|
@ -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:
|
||||
|
|
|
@ -1,9 +0,0 @@
|
|||
import { connect } from 'react-redux';
|
||||
import FourOhFourPage from './view';
|
||||
|
||||
const select = state => ({});
|
||||
|
||||
export default connect(
|
||||
select,
|
||||
null
|
||||
)(FourOhFourPage);
|
|
@ -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;
|
|
@ -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>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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);
|
|
@ -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;
|
|
@ -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);
|
|
@ -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;
|
|
@ -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);
|
|
@ -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>
|
||||
);
|
||||
}
|
Loading…
Reference in a new issue