additional rewards page changes and new verification flow #542
29 changed files with 893 additions and 65 deletions
|
@ -11,6 +11,7 @@ import SettingsPage from 'page/settings';
|
||||||
import SplashScreen from 'page/splash';
|
import SplashScreen from 'page/splash';
|
||||||
import SubscriptionsPage from 'page/subscriptions';
|
import SubscriptionsPage from 'page/subscriptions';
|
||||||
import TransactionHistoryPage from 'page/transactionHistory';
|
import TransactionHistoryPage from 'page/transactionHistory';
|
||||||
|
import VerificationScreen from 'page/verification';
|
||||||
import WalletPage from 'page/wallet';
|
import WalletPage from 'page/wallet';
|
||||||
import SearchInput from 'component/searchInput';
|
import SearchInput from 'component/searchInput';
|
||||||
import {
|
import {
|
||||||
|
@ -212,10 +213,19 @@ const mainStackNavigator = new createStackNavigator({
|
||||||
},
|
},
|
||||||
Main: {
|
Main: {
|
||||||
screen: drawer
|
screen: drawer
|
||||||
|
},
|
||||||
|
Verification: {
|
||||||
|
screen: VerificationScreen,
|
||||||
|
navigationOptions: {
|
||||||
|
drawerLockMode: 'locked-closed'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
headerMode: 'none'
|
headerMode: 'none'
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export const AppNavigator = mainStackNavigator;
|
export const AppNavigator = mainStackNavigator;
|
||||||
export const reactNavigationMiddleware = createReactNavigationReduxMiddleware(
|
export const reactNavigationMiddleware = createReactNavigationReduxMiddleware(
|
||||||
state => state.nav,
|
state => state.nav,
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { doFetchBlock, makeSelectBlockDate } from 'lbry-redux';
|
import { makeSelectDateForUri } from 'lbry-redux';
|
||||||
import DateTime from './view';
|
import DateTime from './view';
|
||||||
|
|
||||||
const select = (state, props) => ({
|
const select = (state, props) => ({
|
||||||
date: !props.date && props.block ? makeSelectBlockDate(props.block)(state) : props.date,
|
date: props.date || makeSelectDateForUri(props.uri)(state),
|
||||||
});
|
});
|
||||||
|
|
||||||
const perform = dispatch => ({
|
const perform = dispatch => ({
|
||||||
|
|
|
@ -90,7 +90,7 @@ class FileItem extends React.PureComponent {
|
||||||
<Link style={discoverStyle.channelName} text={channelName} onPress={() => {
|
<Link style={discoverStyle.channelName} text={channelName} onPress={() => {
|
||||||
navigateToUri(navigation, normalizeURI(fullChannelUri));
|
navigateToUri(navigation, normalizeURI(fullChannelUri));
|
||||||
}} />}
|
}} />}
|
||||||
<DateTime style={discoverStyle.dateTime} textStyle={discoverStyle.dateTimeText} timeAgo block={height} />
|
<DateTime style={discoverStyle.dateTime} textStyle={discoverStyle.dateTimeText} timeAgo uri={uri} />
|
||||||
</View>}
|
</View>}
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
{obscureNsfw && <NsfwOverlay onPress={() => navigation.navigate({ routeName: 'Settings', key: 'settingsPage' })} />}
|
{obscureNsfw && <NsfwOverlay onPress={() => navigation.navigate({ routeName: 'Settings', key: 'settingsPage' })} />}
|
||||||
|
|
|
@ -107,7 +107,7 @@ class FileListItem extends React.PureComponent {
|
||||||
|
|
||||||
<View style={fileListStyle.info}>
|
<View style={fileListStyle.info}>
|
||||||
{fileInfo && <Text style={fileListStyle.infoText}>{this.getStorageForFileInfo(fileInfo)}</Text>}
|
{fileInfo && <Text style={fileListStyle.infoText}>{this.getStorageForFileInfo(fileInfo)}</Text>}
|
||||||
<DateTime style={fileListStyle.publishInfo} textStyle={fileListStyle.infoText} timeAgo block={height} />
|
<DateTime style={fileListStyle.publishInfo} textStyle={fileListStyle.infoText} timeAgo uri={uri} />
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
{fileInfo &&
|
{fileInfo &&
|
||||||
|
|
|
@ -1,11 +1,14 @@
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { selectTotalBalance } from 'lbry-redux';
|
import { makeSelectClientSetting } from 'redux/selectors/settings';
|
||||||
|
import { selectBalance } from 'lbry-redux';
|
||||||
import { selectUnclaimedRewardValue } from 'lbryinc';
|
import { selectUnclaimedRewardValue } from 'lbryinc';
|
||||||
|
import Constants from 'constants';
|
||||||
import FloatingWalletBalance from './view';
|
import FloatingWalletBalance from './view';
|
||||||
|
|
||||||
const select = state => ({
|
const select = state => ({
|
||||||
balance: selectTotalBalance(state),
|
balance: selectBalance(state),
|
||||||
unclaimedRewardAmount: selectUnclaimedRewardValue(state),
|
unclaimedRewardAmount: selectUnclaimedRewardValue(state),
|
||||||
|
rewardsNotInterested: makeSelectClientSetting(Constants.SETTING_REWARDS_NOT_INTERESTED)(state),
|
||||||
});
|
});
|
||||||
|
|
||||||
export default connect(select, null)(FloatingWalletBalance);
|
export default connect(select, null)(FloatingWalletBalance);
|
||||||
|
|
|
@ -14,11 +14,11 @@ type Props = {
|
||||||
|
|
||||||
class FloatingWalletBalance extends React.PureComponent<Props> {
|
class FloatingWalletBalance extends React.PureComponent<Props> {
|
||||||
render() {
|
render() {
|
||||||
const { balance, navigation, unclaimedRewardAmount } = this.props;
|
const { balance, navigation, rewardsNotInterested, unclaimedRewardAmount } = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={[floatingButtonStyle.view, floatingButtonStyle.bottomRight]}>
|
<View style={[floatingButtonStyle.view, floatingButtonStyle.bottomRight]}>
|
||||||
{unclaimedRewardAmount > 0 &&
|
{(!rewardsNotInterested && unclaimedRewardAmount > 0) &&
|
||||||
<TouchableOpacity style={floatingButtonStyle.pendingContainer}
|
<TouchableOpacity style={floatingButtonStyle.pendingContainer}
|
||||||
onPress={() => navigation && navigation.navigate({ routeName: 'Rewards' })} >
|
onPress={() => navigation && navigation.navigate({ routeName: 'Rewards' })} >
|
||||||
<Icon name="award" size={18} style={floatingButtonStyle.rewardIcon} />
|
<Icon name="award" size={18} style={floatingButtonStyle.rewardIcon} />
|
||||||
|
|
|
@ -72,16 +72,7 @@ class RewardCard extends React.PureComponent<Props> {
|
||||||
}
|
}
|
||||||
}}>
|
}}>
|
||||||
<View style={rewardStyle.leftCol}>
|
<View style={rewardStyle.leftCol}>
|
||||||
{!isPending && <TouchableOpacity onPress={() => {
|
|
||||||
if (!claimed) {
|
|
||||||
this.onClaimPress();
|
|
||||||
}
|
|
||||||
}}>
|
|
||||||
<Icon name={claimed ? "check-circle" : "circle"}
|
|
||||||
style={claimed ? rewardStyle.claimed : (canClaim ? rewardStyle.unclaimed : rewardStyle.disabled)}
|
|
||||||
size={20} />
|
|
||||||
</TouchableOpacity>}
|
|
||||||
{isPending && <ActivityIndicator size="small" color={Colors.LbryGreen} />}
|
|
||||||
</View>
|
</View>
|
||||||
<View style={rewardStyle.midCol}>
|
<View style={rewardStyle.midCol}>
|
||||||
<Text style={rewardStyle.rewardTitle}>{reward.reward_title}</Text>
|
<Text style={rewardStyle.rewardTitle}>{reward.reward_title}</Text>
|
||||||
|
@ -92,6 +83,16 @@ class RewardCard extends React.PureComponent<Props> {
|
||||||
error={'The transaction URL could not be opened'} />}
|
error={'The transaction URL could not be opened'} />}
|
||||||
</View>
|
</View>
|
||||||
<View style={rewardStyle.rightCol}>
|
<View style={rewardStyle.rightCol}>
|
||||||
|
{!isPending && <TouchableOpacity onPress={() => {
|
||||||
|
if (!claimed) {
|
||||||
|
this.onClaimPress();
|
||||||
|
}
|
||||||
|
}}>
|
||||||
|
<Icon name={claimed ? "check-circle" : "circle"}
|
||||||
|
style={claimed ? rewardStyle.claimed : (canClaim ? rewardStyle.unclaimed : rewardStyle.disabled)}
|
||||||
|
size={20} />
|
||||||
|
</TouchableOpacity>}
|
||||||
|
{isPending && <ActivityIndicator size="small" color={Colors.LbryGreen} />}
|
||||||
<Text style={rewardStyle.rewardAmount}>{reward.reward_amount}</Text>
|
<Text style={rewardStyle.rewardAmount}>{reward.reward_amount}</Text>
|
||||||
<Text style={rewardStyle.rewardCurrency}>LBC</Text>
|
<Text style={rewardStyle.rewardCurrency}>LBC</Text>
|
||||||
</View>
|
</View>
|
||||||
|
|
19
app/src/component/rewardEnrolment/index.js
Normal file
19
app/src/component/rewardEnrolment/index.js
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
import { doToast } from 'lbry-redux';
|
||||||
|
import { doSetClientSetting } from 'redux/actions/settings';
|
||||||
|
import { doRewardList, selectUnclaimedRewardValue, selectFetchingRewards, selectUser } from 'lbryinc';
|
||||||
|
import RewardEnrolment from './view';
|
||||||
|
|
||||||
|
const select = state => ({
|
||||||
|
unclaimedRewardAmount: selectUnclaimedRewardValue(state),
|
||||||
|
fetching: selectFetchingRewards(state),
|
||||||
|
user: selectUser(state)
|
||||||
|
});
|
||||||
|
|
||||||
|
const perform = dispatch => ({
|
||||||
|
fetchRewards: () => dispatch(doRewardList()),
|
||||||
|
notify: data => dispatch(doToast(data)),
|
||||||
|
setClientSetting: (key, value) => dispatch(doSetClientSetting(key, value)),
|
||||||
|
});
|
||||||
|
|
||||||
|
export default connect(select, perform)(RewardEnrolment);
|
53
app/src/component/rewardEnrolment/view.js
Normal file
53
app/src/component/rewardEnrolment/view.js
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
import React from 'react';
|
||||||
|
import { NativeModules, Text, TouchableOpacity, View } from 'react-native';
|
||||||
|
import AsyncStorage from '@react-native-community/async-storage';
|
||||||
|
import Button from 'component/button';
|
||||||
|
import Constants from 'constants';
|
||||||
|
import Link from 'component/link';
|
||||||
|
import Colors from 'styles/colors';
|
||||||
|
import Icon from 'react-native-vector-icons/FontAwesome5';
|
||||||
|
import rewardStyle from 'styles/reward';
|
||||||
|
|
||||||
|
class RewardEnrolment extends React.Component {
|
||||||
|
componentDidMount() {
|
||||||
|
this.props.fetchRewards();
|
||||||
|
}
|
||||||
|
|
||||||
|
onNotInterestedPressed = () => {
|
||||||
|
const { navigation, setClientSetting } = this.props;
|
||||||
|
setClientSetting(Constants.SETTING_REWARDS_NOT_INTERESTED, true);
|
||||||
|
navigation.navigate({ routeName: 'DiscoverStack' });
|
||||||
|
}
|
||||||
|
|
||||||
|
onEnrollPressed = () => {
|
||||||
|
const { navigation } = this.props;
|
||||||
|
navigation.navigate({ routeName: 'Verification' })
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { fetching, navigation, unclaimedRewardAmount, user } = this.props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View style={rewardStyle.enrollContainer} onPress>
|
||||||
|
<View style={rewardStyle.summaryRow}>
|
||||||
|
<Icon name="award" size={36} color={Colors.White} />
|
||||||
|
<Text style={rewardStyle.summaryText}>
|
||||||
|
{unclaimedRewardAmount} unclaimed credits
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<View style={rewardStyle.onboarding}>
|
||||||
|
<Text style={rewardStyle.enrollDescText}>LBRY credits allow you to purchase content, publish content, and influence the network. You can start earning credits by watching videos on LBRY.</Text>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<View style={rewardStyle.buttonRow}>
|
||||||
|
<Link style={rewardStyle.notInterestedLink} text={"Not interested"} onPress={this.onNotInterestedPressed} />
|
||||||
|
<Button style={rewardStyle.enrollButton} theme={"light"} text={"Enroll"} onPress={this.onEnrollPressed} />
|
||||||
|
</View>
|
||||||
|
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default RewardEnrolment;
|
|
@ -1,9 +1,9 @@
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { selectTotalBalance } from 'lbry-redux';
|
import { selectBalance } from 'lbry-redux';
|
||||||
import WalletBalance from './view';
|
import WalletBalance from './view';
|
||||||
|
|
||||||
const select = state => ({
|
const select = state => ({
|
||||||
balance: selectTotalBalance(state),
|
balance: selectBalance(state),
|
||||||
});
|
});
|
||||||
|
|
||||||
export default connect(select, null)(WalletBalance);
|
export default connect(select, null)(WalletBalance);
|
||||||
|
|
6
app/src/component/walletRewardsDriver/index.js
Normal file
6
app/src/component/walletRewardsDriver/index.js
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
import WalletRewardsDriver from './view';
|
||||||
|
|
||||||
|
const select = state => ({});
|
||||||
|
|
||||||
|
export default connect(select, null)(WalletRewardsDriver);
|
17
app/src/component/walletRewardsDriver/view.js
Normal file
17
app/src/component/walletRewardsDriver/view.js
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
import React from 'react';
|
||||||
|
import { Text, TouchableOpacity } from 'react-native';
|
||||||
|
import walletStyle from 'styles/wallet';
|
||||||
|
|
||||||
|
class WalletRewardsDriver extends React.PureComponent<Props> {
|
||||||
|
render() {
|
||||||
|
const { navigation } = this.props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TouchableOpacity style={walletStyle.rewardDriverCard} onPress={() => navigation.navigate('Rewards')}>
|
||||||
|
<Text style={walletStyle.rewardDriverText}>Earn credits while using the LBRY app. Tap to get started.</Text>
|
||||||
|
</TouchableOpacity>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default WalletRewardsDriver;
|
|
@ -4,6 +4,12 @@ const Constants = {
|
||||||
FIRST_RUN_PAGE_WALLET: "wallet",
|
FIRST_RUN_PAGE_WALLET: "wallet",
|
||||||
FIRST_RUN_PAGE_SKIP_ACCOUNT: "skip-account",
|
FIRST_RUN_PAGE_SKIP_ACCOUNT: "skip-account",
|
||||||
|
|
||||||
|
VERIFY_PAGE_EMAIL: "email-verify",
|
||||||
|
VERIFY_PAGE_PHONE_NUMBER: "phone-number-verify",
|
||||||
|
|
||||||
|
PHASE_COLLECTION: "collection",
|
||||||
|
PHASE_VERIFICATION: "verification",
|
||||||
|
|
||||||
CONTENT_TAB: "content",
|
CONTENT_TAB: "content",
|
||||||
ABOUT_TAB: "about",
|
ABOUT_TAB: "about",
|
||||||
|
|
||||||
|
@ -16,6 +22,8 @@ const Constants = {
|
||||||
SETTING_SUBSCRIPTIONS_VIEW_MODE: "subscriptionsViewMode",
|
SETTING_SUBSCRIPTIONS_VIEW_MODE: "subscriptionsViewMode",
|
||||||
SETTING_RATING_REMINDER_LAST_SHOWN: "ratingReminderLastShown",
|
SETTING_RATING_REMINDER_LAST_SHOWN: "ratingReminderLastShown",
|
||||||
SETTING_RATING_REMINDER_DISABLED: "ratingReminderDisabled",
|
SETTING_RATING_REMINDER_DISABLED: "ratingReminderDisabled",
|
||||||
|
SETTING_BACKUP_DISMISSED: "backupDismissed",
|
||||||
|
SETTING_REWARDS_NOT_INTERESTED: "rewardsNotInterested",
|
||||||
|
|
||||||
ACTION_DELETE_COMPLETED_BLOBS: "DELETE_COMPLETED_BLOBS",
|
ACTION_DELETE_COMPLETED_BLOBS: "DELETE_COMPLETED_BLOBS",
|
||||||
ACTION_FIRST_RUN_PAGE_CHANGED: "FIRST_RUN_PAGE_CHANGED",
|
ACTION_FIRST_RUN_PAGE_CHANGED: "FIRST_RUN_PAGE_CHANGED",
|
||||||
|
|
|
@ -601,7 +601,7 @@ class FilePage extends React.PureComponent {
|
||||||
<DateTime
|
<DateTime
|
||||||
style={filePageStyle.publishDate}
|
style={filePageStyle.publishDate}
|
||||||
textStyle={filePageStyle.publishDateText}
|
textStyle={filePageStyle.publishDateText}
|
||||||
block={height}
|
uri={uri}
|
||||||
formatOptions={{ day: 'numeric', month: 'long', year: 'numeric' }}
|
formatOptions={{ day: 'numeric', month: 'long', year: 'numeric' }}
|
||||||
show={DateTime.SHOW_DATE} />
|
show={DateTime.SHOW_DATE} />
|
||||||
</View>
|
</View>
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import {
|
import {
|
||||||
|
doClaimRewardType,
|
||||||
doRewardList,
|
doRewardList,
|
||||||
selectEmailVerifyErrorMessage,
|
selectEmailVerifyErrorMessage,
|
||||||
selectEmailVerifyIsPending,
|
selectEmailVerifyIsPending,
|
||||||
|
@ -23,6 +24,7 @@ const select = state => ({
|
||||||
});
|
});
|
||||||
|
|
||||||
const perform = dispatch => ({
|
const perform = dispatch => ({
|
||||||
|
claimReward: reward => dispatch(doClaimRewardType(reward.reward_type, true)),
|
||||||
fetchRewards: () => dispatch(doRewardList()),
|
fetchRewards: () => dispatch(doRewardList()),
|
||||||
notify: data => dispatch(doToast(data)),
|
notify: data => dispatch(doToast(data)),
|
||||||
pushDrawerStack: () => dispatch(doPushDrawerStack(Constants.DRAWER_ROUTE_REWARDS))
|
pushDrawerStack: () => dispatch(doPushDrawerStack(Constants.DRAWER_ROUTE_REWARDS))
|
||||||
|
|
|
@ -14,6 +14,7 @@ import PhoneNumberRewardSubcard from 'component/phoneNumberRewardSubcard';
|
||||||
import EmailRewardSubcard from 'component/emailRewardSubcard';
|
import EmailRewardSubcard from 'component/emailRewardSubcard';
|
||||||
import PageHeader from 'component/pageHeader';
|
import PageHeader from 'component/pageHeader';
|
||||||
import RewardCard from 'component/rewardCard';
|
import RewardCard from 'component/rewardCard';
|
||||||
|
import RewardEnrolment from 'component/rewardEnrolment';
|
||||||
import RewardSummary from 'component/rewardSummary';
|
import RewardSummary from 'component/rewardSummary';
|
||||||
import UriBar from 'component/uriBar';
|
import UriBar from 'component/uriBar';
|
||||||
import rewardStyle from 'styles/reward';
|
import rewardStyle from 'styles/reward';
|
||||||
|
@ -24,7 +25,8 @@ class RewardsPage extends React.PureComponent {
|
||||||
isIdentityVerified: false,
|
isIdentityVerified: false,
|
||||||
isRewardApproved: false,
|
isRewardApproved: false,
|
||||||
verifyRequestStarted: false,
|
verifyRequestStarted: false,
|
||||||
revealVerification: false
|
revealVerification: true,
|
||||||
|
firstRewardClaimed: false
|
||||||
};
|
};
|
||||||
|
|
||||||
scrollView = null;
|
scrollView = null;
|
||||||
|
@ -43,7 +45,8 @@ class RewardsPage extends React.PureComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillReceiveProps(nextProps) {
|
componentWillReceiveProps(nextProps) {
|
||||||
const { emailVerifyErrorMessage, emailVerifyPending, user } = nextProps;
|
const { emailVerifyErrorMessage, emailVerifyPending, rewards, user } = nextProps;
|
||||||
|
const { claimReward } = this.props;
|
||||||
if (emailVerifyPending) {
|
if (emailVerifyPending) {
|
||||||
this.setState({ verifyRequestStarted: true });
|
this.setState({ verifyRequestStarted: true });
|
||||||
}
|
}
|
||||||
|
@ -63,6 +66,17 @@ class RewardsPage extends React.PureComponent {
|
||||||
isRewardApproved: (user && user.is_reward_approved)
|
isRewardApproved: (user && user.is_reward_approved)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (rewards && rewards.length && this.state.isRewardApproved && !this.state.firstRewardClaimed) {
|
||||||
|
// claim new_user and new_mobile rewards
|
||||||
|
for (let i = 0; i < rewards.length; i++) {
|
||||||
|
const { reward_type: type } = rewards[i];
|
||||||
|
if ('new_user' === type || 'new_mobile' === type) {
|
||||||
|
claimReward(rewards[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.setState({ firstRewardClaimed: true });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
renderVerification() {
|
renderVerification() {
|
||||||
|
@ -70,23 +84,12 @@ class RewardsPage extends React.PureComponent {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.state.isEmailVerified || !this.state.isIdentityVerified) {
|
|
||||||
return (
|
|
||||||
<View style={[rewardStyle.card, rewardStyle.verification]}>
|
|
||||||
<Text style={rewardStyle.title}>Humans Only</Text>
|
|
||||||
<Text style={rewardStyle.text}>Rewards are for human beings only. You'll have to prove you're one of us before you can claim any rewards.</Text>
|
|
||||||
{!this.state.isEmailVerified && <EmailRewardSubcard />}
|
|
||||||
{this.state.isEmailVerified && !this.state.isIdentityVerified && <PhoneNumberRewardSubcard />}
|
|
||||||
</View>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.state.isEmailVerified && this.state.isIdentityVerified && !this.state.isRewardApproved) {
|
if (this.state.isEmailVerified && this.state.isIdentityVerified && !this.state.isRewardApproved) {
|
||||||
return (
|
return (
|
||||||
<View style={[rewardStyle.card, rewardStyle.verification]}>
|
<View style={[rewardStyle.card, rewardStyle.verification]}>
|
||||||
<Text style={rewardStyle.title}>Manual Reward Verification</Text>
|
<Text style={rewardStyle.title}>Manual Reward Verification</Text>
|
||||||
<Text style={rewardStyle.text}>
|
<Text style={rewardStyle.text}>
|
||||||
You need to be manually verified before you can start claiming rewards. Please request to be verified on the <Link style={rewardStyle.textLink} href="https://discordapp.com/invite/Z3bERWA" text="LBRY Discord server" />.
|
You need to be manually verified before you can start claiming rewards. Please request to be verified on the <Link style={rewardStyle.greenLink} href="https://discordapp.com/invite/Z3bERWA" text="LBRY Discord server" />.
|
||||||
</Text>
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
|
@ -153,16 +156,18 @@ class RewardsPage extends React.PureComponent {
|
||||||
return (
|
return (
|
||||||
<View style={rewardStyle.container}>
|
<View style={rewardStyle.container}>
|
||||||
<UriBar navigation={navigation} />
|
<UriBar navigation={navigation} />
|
||||||
|
{(!this.state.isEmailVerified || !this.state.isIdentityVerified || !this.state.isRewardApproved) &&
|
||||||
|
<RewardEnrolment navigation={navigation} />}
|
||||||
|
|
||||||
|
{(this.state.isEmailVerified && this.state.isIdentityVerified && this.state.isRewardApproved) &&
|
||||||
<ScrollView
|
<ScrollView
|
||||||
ref={ref => this.scrollView = ref}
|
ref={ref => this.scrollView = ref}
|
||||||
keyboardShouldPersistTaps={'handled'}
|
keyboardShouldPersistTaps={'handled'}
|
||||||
style={rewardStyle.scrollContainer}
|
style={rewardStyle.scrollContainer}
|
||||||
contentContainerStyle={rewardStyle.scrollContentContainer}>
|
contentContainerStyle={rewardStyle.scrollContentContainer}>
|
||||||
<RewardSummary navigation={navigation} showVerification={this.showVerification} />
|
|
||||||
{this.state.revealVerification && this.renderVerification()}
|
|
||||||
{this.renderUnclaimedRewards()}
|
{this.renderUnclaimedRewards()}
|
||||||
{this.renderClaimedRewards()}
|
{this.renderClaimedRewards()}
|
||||||
</ScrollView>
|
</ScrollView>}
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { doTotalBalanceSubscribe, doUpdateBlockHeight, doToast } from 'lbry-redux';
|
import { doBalanceSubscribe, doUpdateBlockHeight, doToast } from 'lbry-redux';
|
||||||
import {
|
import {
|
||||||
doAuthenticate,
|
doAuthenticate,
|
||||||
doBlackListedOutpointsSubscribe,
|
doBlackListedOutpointsSubscribe,
|
||||||
|
@ -23,7 +23,7 @@ const select = state => ({
|
||||||
|
|
||||||
const perform = dispatch => ({
|
const perform = dispatch => ({
|
||||||
authenticate: (appVersion, os) => dispatch(doAuthenticate(appVersion, os)),
|
authenticate: (appVersion, os) => dispatch(doAuthenticate(appVersion, os)),
|
||||||
totalBalanceSubscribe: () => dispatch(doTotalBalanceSubscribe()),
|
balanceSubscribe: () => dispatch(doBalanceSubscribe()),
|
||||||
blacklistedOutpointsSubscribe: () => dispatch(doBlackListedOutpointsSubscribe()),
|
blacklistedOutpointsSubscribe: () => dispatch(doBlackListedOutpointsSubscribe()),
|
||||||
checkSubscriptionsInit: () => dispatch(doCheckSubscriptionsInit()),
|
checkSubscriptionsInit: () => dispatch(doCheckSubscriptionsInit()),
|
||||||
deleteCompleteBlobs: () => dispatch(doDeleteCompleteBlobs()),
|
deleteCompleteBlobs: () => dispatch(doDeleteCompleteBlobs()),
|
||||||
|
|
|
@ -137,7 +137,7 @@ class SplashScreen extends React.PureComponent {
|
||||||
finishSplashScreen = () => {
|
finishSplashScreen = () => {
|
||||||
const {
|
const {
|
||||||
authenticate,
|
authenticate,
|
||||||
totalBalanceSubscribe,
|
balanceSubscribe,
|
||||||
blacklistedOutpointsSubscribe,
|
blacklistedOutpointsSubscribe,
|
||||||
checkSubscriptionsInit,
|
checkSubscriptionsInit,
|
||||||
updateBlockHeight,
|
updateBlockHeight,
|
||||||
|
@ -147,7 +147,7 @@ class SplashScreen extends React.PureComponent {
|
||||||
|
|
||||||
Lbry.resolve({ urls: 'lbry://one' }).then(() => {
|
Lbry.resolve({ urls: 'lbry://one' }).then(() => {
|
||||||
// Leave the splash screen
|
// Leave the splash screen
|
||||||
totalBalanceSubscribe();
|
balanceSubscribe();
|
||||||
blacklistedOutpointsSubscribe();
|
blacklistedOutpointsSubscribe();
|
||||||
checkSubscriptionsInit();
|
checkSubscriptionsInit();
|
||||||
updateBlockHeight();
|
updateBlockHeight();
|
||||||
|
|
42
app/src/page/verification/index.js
Normal file
42
app/src/page/verification/index.js
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
import { doToast } from 'lbry-redux';
|
||||||
|
import {
|
||||||
|
doUserEmailNew,
|
||||||
|
doUserEmailToVerify,
|
||||||
|
doUserResendVerificationEmail,
|
||||||
|
doUserPhoneNew,
|
||||||
|
doUserPhoneVerify,
|
||||||
|
selectPhoneNewErrorMessage,
|
||||||
|
selectPhoneNewIsPending,
|
||||||
|
selectPhoneToVerify,
|
||||||
|
selectPhoneVerifyIsPending,
|
||||||
|
selectPhoneVerifyErrorMessage,
|
||||||
|
selectEmailNewErrorMessage,
|
||||||
|
selectEmailNewIsPending,
|
||||||
|
selectEmailToVerify,
|
||||||
|
selectUser,
|
||||||
|
} from 'lbryinc';
|
||||||
|
import Verification from './view';
|
||||||
|
|
||||||
|
const select = (state) => ({
|
||||||
|
emailToVerify: selectEmailToVerify(state),
|
||||||
|
emailNewErrorMessage: selectEmailNewErrorMessage(state),
|
||||||
|
emailNewPending: selectEmailNewIsPending(state),
|
||||||
|
user: selectUser(state),
|
||||||
|
phoneVerifyErrorMessage: selectPhoneVerifyErrorMessage(state),
|
||||||
|
phoneVerifyIsPending: selectPhoneVerifyIsPending(state),
|
||||||
|
phone: selectPhoneToVerify(state),
|
||||||
|
phoneNewErrorMessage: selectPhoneNewErrorMessage(state),
|
||||||
|
phoneNewIsPending: selectPhoneNewIsPending(state),
|
||||||
|
});
|
||||||
|
|
||||||
|
const perform = dispatch => ({
|
||||||
|
addUserEmail: email => dispatch(doUserEmailNew(email)),
|
||||||
|
addUserPhone: (phone, country_code) => dispatch(doUserPhoneNew(phone, country_code)),
|
||||||
|
verifyPhone: (verificationCode) => dispatch(doUserPhoneVerify(verificationCode)),
|
||||||
|
notify: data => dispatch(doToast(data)),
|
||||||
|
setEmailToVerify: email => dispatch(doUserEmailToVerify(email)),
|
||||||
|
resendVerificationEmail: email => dispatch(doUserResendVerificationEmail(email))
|
||||||
|
});
|
||||||
|
|
||||||
|
export default connect(select, perform)(Verification);
|
132
app/src/page/verification/internal/email-verify-page.js
Normal file
132
app/src/page/verification/internal/email-verify-page.js
Normal file
|
@ -0,0 +1,132 @@
|
||||||
|
import React from 'react';
|
||||||
|
import { Lbry } from 'lbry-redux';
|
||||||
|
import { ActivityIndicator, View, Text, TextInput } from 'react-native';
|
||||||
|
import AsyncStorage from '@react-native-community/async-storage';
|
||||||
|
import Button from 'component/button';
|
||||||
|
import Link from 'component/link';
|
||||||
|
import Colors from 'styles/colors';
|
||||||
|
import Constants from 'constants';
|
||||||
|
import firstRunStyle from 'styles/firstRun';
|
||||||
|
import rewardStyle from 'styles/reward';
|
||||||
|
|
||||||
|
class EmailVerifyPage extends React.PureComponent {
|
||||||
|
state = {
|
||||||
|
email: null,
|
||||||
|
phase: Constants.PHASE_COLLECTION,
|
||||||
|
placeholder: 'you@example.com',
|
||||||
|
verifyStarted: false,
|
||||||
|
previousEmail: null
|
||||||
|
}
|
||||||
|
|
||||||
|
handleChangeText = (text) => {
|
||||||
|
this.setState({ email: text });
|
||||||
|
AsyncStorage.setItem(Constants.KEY_FIRST_RUN_EMAIL, text);
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillReceiveProps(nextProps) {
|
||||||
|
const { emailNewErrorMessage, emailNewPending, emailToVerify } = nextProps;
|
||||||
|
const { notify } = this.props;
|
||||||
|
|
||||||
|
if (this.state.verifyStarted && !emailNewPending) {
|
||||||
|
if (emailNewErrorMessage) {
|
||||||
|
notify({ message: String(emailNewErrorMessage), isError: true });
|
||||||
|
this.setState({ verifyStarted: false });
|
||||||
|
} else {
|
||||||
|
this.setState({ phase: Constants.PHASE_VERIFICATION });
|
||||||
|
//notify({ message: 'Please follow the instructions in the email sent to your address to continue.' });
|
||||||
|
AsyncStorage.setItem(Constants.KEY_EMAIL_VERIFY_PENDING, 'true');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onSendVerificationPressed = () => {
|
||||||
|
const { addUserEmail, emailNewPending, notify, resendVerificationEmail } = this.props;
|
||||||
|
|
||||||
|
if (emailNewPending) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { email } = this.state;
|
||||||
|
if (!email || email.trim().length === 0 || email.indexOf('@') === -1) {
|
||||||
|
return notify({
|
||||||
|
message: 'Please provide a valid email address to continue.',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.state.previousEmail === this.state.email) {
|
||||||
|
// resend
|
||||||
|
resendVerificationEmail(this.state.email);
|
||||||
|
AsyncStorage.setItem(Constants.KEY_EMAIL_VERIFY_PENDING, 'true');
|
||||||
|
this.setState({ verifyStarted: true, phase: Constants.PHASE_VERIFICATION });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setState({ verifyStarted: true });
|
||||||
|
addUserEmail(email);
|
||||||
|
}
|
||||||
|
|
||||||
|
onResendPressed = () => {
|
||||||
|
const { resendVerificationEmail, notify } = this.props;
|
||||||
|
// resend verification email if there was one previously set (and it wasn't changed)
|
||||||
|
resendVerificationEmail(this.state.email);
|
||||||
|
AsyncStorage.setItem(Constants.KEY_EMAIL_VERIFY_PENDING, 'true');
|
||||||
|
notify({ message: 'Please follow the instructions in the email sent to your address to continue.' });
|
||||||
|
}
|
||||||
|
|
||||||
|
onEditPressed = () => {
|
||||||
|
this.setState({ verifyStarted: false, phase: Constants.PHASE_COLLECTION, previousEmail: this.state.email });
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { emailNewPending } = this.props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View style={firstRunStyle.container}>
|
||||||
|
<Text style={rewardStyle.verificationTitle}>{(Constants.PHASE_COLLECTION === this.state.phase) ? 'Email' : 'Verify Email'}</Text>
|
||||||
|
{(Constants.PHASE_COLLECTION === this.state.phase) &&
|
||||||
|
<View>
|
||||||
|
<Text style={firstRunStyle.paragraph}>Please provide an email address.</Text>
|
||||||
|
<TextInput style={firstRunStyle.emailInput}
|
||||||
|
placeholder={this.state.placeholder}
|
||||||
|
underlineColorAndroid="transparent"
|
||||||
|
value={this.state.email}
|
||||||
|
onChangeText={text => this.handleChangeText(text)}
|
||||||
|
onFocus={() => {
|
||||||
|
if (!this.state.email || this.state.email.length === 0) {
|
||||||
|
this.setState({ placeholder: '' });
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
onBlur={() => {
|
||||||
|
if (!this.state.email || this.state.email.length === 0) {
|
||||||
|
this.setState({ placeholder: 'you@example.com' });
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<View style={rewardStyle.buttonContainer}>
|
||||||
|
{!this.state.verifyStarted &&
|
||||||
|
<Button
|
||||||
|
style={rewardStyle.verificationButton}
|
||||||
|
theme={"light"}
|
||||||
|
text={"Send verification email"}
|
||||||
|
onPress={this.onSendVerificationPressed} />}
|
||||||
|
{this.state.verifyStarted && emailNewPending &&
|
||||||
|
<ActivityIndicator size={"small"} color={Colors.White} style={rewardStyle.loading} />}
|
||||||
|
</View>
|
||||||
|
</View>}
|
||||||
|
|
||||||
|
{(Constants.PHASE_VERIFICATION === this.state.phase) &&
|
||||||
|
<View>
|
||||||
|
<Text style={firstRunStyle.paragraph}>An email has been sent to {this.state.email}. Please follow the instructions in the message to verify your email address.</Text>
|
||||||
|
|
||||||
|
<View style={rewardStyle.buttonContainer}>
|
||||||
|
<Button style={rewardStyle.verificationButton} theme={"light"} text={"Resend"} onPress={this.onResendPressed} />
|
||||||
|
<Link style={rewardStyle.verificationLink} text={"Edit"} onPress={this.onEditPressed} />
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
}
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default EmailVerifyPage;
|
23
app/src/page/verification/internal/manual-verify-page.js
Normal file
23
app/src/page/verification/internal/manual-verify-page.js
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
import React from 'react';
|
||||||
|
import { Lbry } from 'lbry-redux';
|
||||||
|
import { ActivityIndicator, View, Text, TextInput } from 'react-native';
|
||||||
|
import AsyncStorage from '@react-native-community/async-storage';
|
||||||
|
import Button from 'component/button';
|
||||||
|
import Link from 'component/link';
|
||||||
|
import Colors from 'styles/colors';
|
||||||
|
import Constants from 'constants';
|
||||||
|
import firstRunStyle from 'styles/firstRun';
|
||||||
|
import rewardStyle from 'styles/reward';
|
||||||
|
|
||||||
|
class ManualVerifyPage extends React.PureComponent {
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<View style={firstRunStyle.container}>
|
||||||
|
<Text style={rewardStyle.verificationTitle}>Manual Reward Verification</Text>
|
||||||
|
<Text style={firstRunStyle.paragraph}>You need to be manually verified before you can start claiming rewards. Please request to be verified on the <Link style={rewardStyle.underlinedTextLink} href="https://discordapp.com/invite/Z3bERWA" text="LBRY Discord server" />.</Text>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ManualVerifyPage;
|
235
app/src/page/verification/internal/phone-verify-page.js
Normal file
235
app/src/page/verification/internal/phone-verify-page.js
Normal file
|
@ -0,0 +1,235 @@
|
||||||
|
// @flow
|
||||||
|
import React from 'react';
|
||||||
|
import {
|
||||||
|
ActivityIndicator,
|
||||||
|
DeviceEventEmitter,
|
||||||
|
NativeModules,
|
||||||
|
StyleSheet,
|
||||||
|
Text,
|
||||||
|
TextInput,
|
||||||
|
TouchableOpacity,
|
||||||
|
View
|
||||||
|
} from 'react-native';
|
||||||
|
import AsyncStorage from '@react-native-community/async-storage';
|
||||||
|
import Button from 'component/button';
|
||||||
|
import Colors from 'styles/colors';
|
||||||
|
import Constants from 'constants';
|
||||||
|
import CountryPicker from 'react-native-country-picker-modal';
|
||||||
|
import Icon from 'react-native-vector-icons/FontAwesome5';
|
||||||
|
import Link from 'component/link';
|
||||||
|
import PhoneInput from 'react-native-phone-input';
|
||||||
|
import firstRunStyle from 'styles/firstRun';
|
||||||
|
import rewardStyle from 'styles/reward';
|
||||||
|
|
||||||
|
class PhoneVerifyPage extends React.PureComponent {
|
||||||
|
phoneInput = null;
|
||||||
|
|
||||||
|
picker = null;
|
||||||
|
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
canReceiveSms: false,
|
||||||
|
cca2: 'US',
|
||||||
|
codeVerifyStarted: false,
|
||||||
|
codeVerifySuccessful: false,
|
||||||
|
countryCode: null,
|
||||||
|
newPhoneAdded: false,
|
||||||
|
number: null,
|
||||||
|
phoneVerifyFailed: false,
|
||||||
|
verificationCode: null,
|
||||||
|
phase: Constants.PHASE_COLLECTION
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
const { phone } = this.props;
|
||||||
|
if (phone && String(phone).trim().length > 0) {
|
||||||
|
this.setState({ newPhoneAdded: true, phase: Constants.PHASE_VERIFICATION });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidUpdate(prevProps) {
|
||||||
|
const {
|
||||||
|
phoneVerifyIsPending,
|
||||||
|
phoneVerifyErrorMessage,
|
||||||
|
notify,
|
||||||
|
phoneNewErrorMessage,
|
||||||
|
phoneNewIsPending,
|
||||||
|
onPhoneVerifySuccessful
|
||||||
|
} = this.props;
|
||||||
|
|
||||||
|
if (!phoneNewIsPending && (phoneNewIsPending !== prevProps.phoneNewIsPending)) {
|
||||||
|
if (phoneNewErrorMessage) {
|
||||||
|
notify({ message: String(phoneNewErrorMessage) });
|
||||||
|
this.setState({ phoneVerifyFailed: true });
|
||||||
|
} else {
|
||||||
|
this.setState({ newPhoneAdded: true, phase: Constants.PHASE_VERIFICATION, phoneVerifyFailed: false });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!phoneVerifyIsPending && (phoneVerifyIsPending !== prevProps.phoneVerifyIsPending)) {
|
||||||
|
if (phoneVerifyErrorMessage) {
|
||||||
|
notify({ message: String(phoneVerifyErrorMessage) });
|
||||||
|
this.setState({ codeVerifyStarted: false, phoneVerifyFailed: true });
|
||||||
|
} else {
|
||||||
|
notify({ message: 'Your phone number was successfully verified.' });
|
||||||
|
this.setState({ codeVerifySuccessful: true, phoneVerifyFailed: false });
|
||||||
|
if (onPhoneVerifySuccessful) {
|
||||||
|
onPhoneVerifySuccessful();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onEditPressed = () => {
|
||||||
|
this.setState({ newPhoneAdded: false, phase: Constants.PHASE_COLLECTION, phoneVerifyFailed: false });
|
||||||
|
}
|
||||||
|
|
||||||
|
receiveVerificationCode = (evt) => {
|
||||||
|
if (!this.state.newPhoneAdded || this.state.codeVerifySuccessful) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { verifyPhone } = this.props;
|
||||||
|
this.setState({ codeVerifyStarted: true });
|
||||||
|
verifyPhone(evt.code);
|
||||||
|
}
|
||||||
|
|
||||||
|
onSendTextPressed = () => {
|
||||||
|
const { addUserPhone, notify } = this.props;
|
||||||
|
|
||||||
|
if (!this.phoneInput.isValidNumber()) {
|
||||||
|
return notify({
|
||||||
|
message: 'Please provide a valid telephone number.',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setState({ phoneVerifyFailed: false });
|
||||||
|
const countryCode = this.phoneInput.getCountryCode();
|
||||||
|
const number = this.phoneInput.getValue().replace('+' + countryCode, '');
|
||||||
|
this.setState({ countryCode, number });
|
||||||
|
addUserPhone(number, countryCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
onVerifyPressed = () => {
|
||||||
|
if (this.state.codeVerifyStarted) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { verifyPhone } = this.props;
|
||||||
|
this.setState({ codeVerifyStarted: true, phoneVerifyFailed: false });
|
||||||
|
verifyPhone(this.state.verificationCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
onPressFlag = () => {
|
||||||
|
if (this.picker) {
|
||||||
|
this.picker.openModal();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
selectCountry(country) {
|
||||||
|
this.phoneInput.selectCountry(country.cca2.toLowerCase());
|
||||||
|
this.setState({ cca2: country.cca2 });
|
||||||
|
}
|
||||||
|
|
||||||
|
handleChangeText = (text) => {
|
||||||
|
this.setState({ verificationCode: text });
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const {
|
||||||
|
phoneVerifyIsPending,
|
||||||
|
phoneVerifyErrorMessage,
|
||||||
|
phone,
|
||||||
|
phoneErrorMessage,
|
||||||
|
phoneNewIsPending
|
||||||
|
} = this.props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View style={firstRunStyle.container}>
|
||||||
|
<Text style={rewardStyle.verificationTitle}>{this.state.phase === Constants.PHASE_VERIFICATION ? 'Verify ' : '' }Phone Number</Text>
|
||||||
|
|
||||||
|
<View style={rewardStyle.phoneVerificationContainer}>
|
||||||
|
{this.state.phase == Constants.PHASE_COLLECTION &&
|
||||||
|
<View>
|
||||||
|
<Text style={[rewardStyle.bottomMarginMedium, firstRunStyle.paragraph]}>Please provide a phone number to prevent fraud.</Text>
|
||||||
|
<PhoneInput
|
||||||
|
ref={(ref) => { this.phoneInput = ref; }}
|
||||||
|
style={StyleSheet.flatten(rewardStyle.phoneInput)}
|
||||||
|
textProps={{ placeholder: '(phone number)' }}
|
||||||
|
textStyle={StyleSheet.flatten(rewardStyle.phoneInputText)}
|
||||||
|
onPressFlag={this.onPressFlag} />
|
||||||
|
|
||||||
|
<View style={rewardStyle.buttonContainer}>
|
||||||
|
{!phoneNewIsPending &&
|
||||||
|
<Button
|
||||||
|
style={[rewardStyle.verificationButton, rewardStyle.topMarginMedium]}
|
||||||
|
theme={"light"}
|
||||||
|
text={"Send verification text"}
|
||||||
|
onPress={this.onSendTextPressed} />}
|
||||||
|
{phoneNewIsPending &&
|
||||||
|
<ActivityIndicator
|
||||||
|
style={[rewardStyle.loading, rewardStyle.topMarginMedium]}
|
||||||
|
size="small"
|
||||||
|
color={Colors.White} />}
|
||||||
|
</View>
|
||||||
|
</View>}
|
||||||
|
|
||||||
|
{this.state.phase === Constants.PHASE_VERIFICATION &&
|
||||||
|
<View>
|
||||||
|
{!phoneVerifyIsPending && !this.codeVerifyStarted &&
|
||||||
|
<View>
|
||||||
|
<Text style={[rewardStyle.bottomMarginSmall, firstRunStyle.paragraph]}>
|
||||||
|
Please enter the verification code sent to {phone}.
|
||||||
|
</Text>
|
||||||
|
<TextInput
|
||||||
|
style={rewardStyle.verificationCodeInput}
|
||||||
|
keyboardType="numeric"
|
||||||
|
placeholder="0000"
|
||||||
|
underlineColorAndroid="transparent"
|
||||||
|
value={this.state.verificationCode}
|
||||||
|
onChangeText={text => this.handleChangeText(text)}
|
||||||
|
/>
|
||||||
|
<View style={rewardStyle.buttonContainer}>
|
||||||
|
<Button
|
||||||
|
style={[rewardStyle.verificationButton, rewardStyle.topMarginSmall]}
|
||||||
|
theme={"light"}
|
||||||
|
text={"Verify"}
|
||||||
|
onPress={this.onVerifyPressed} />
|
||||||
|
<Link style={rewardStyle.verificationLink} text={"Edit"} onPress={this.onEditPressed} />
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
}
|
||||||
|
{phoneVerifyIsPending &&
|
||||||
|
<View>
|
||||||
|
<Text style={firstRunStyle.paragraph}>Verifying your phone number...</Text>
|
||||||
|
<ActivityIndicator
|
||||||
|
color={Colors.White}
|
||||||
|
size="small"
|
||||||
|
style={[rewardStyle.loading, rewardStyle.topMarginMedium, rewardStyle.leftRightMargin]} />
|
||||||
|
</View>}
|
||||||
|
</View>
|
||||||
|
}
|
||||||
|
{this.state.phoneVerifyFailed &&
|
||||||
|
<View style={rewardStyle.failureFootnote}>
|
||||||
|
<Text style={rewardStyle.paragraphText}>
|
||||||
|
Sorry, we were unable to verify your phone number. Please go to <Link style={rewardStyle.textLink} href="http://chat.lbry.com" text="chat.lbry.com" /> for manual verification if this keeps happening.
|
||||||
|
</Text>
|
||||||
|
</View>}
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<CountryPicker
|
||||||
|
ref={(picker) => { this.picker = picker; }}
|
||||||
|
cca2={this.state.cca2}
|
||||||
|
filterable={true}
|
||||||
|
onChange={value => this.selectCountry(value)}
|
||||||
|
showCallingCode={true}
|
||||||
|
translation="eng">
|
||||||
|
<View />
|
||||||
|
</CountryPicker>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export default PhoneVerifyPage;
|
140
app/src/page/verification/view.js
Normal file
140
app/src/page/verification/view.js
Normal file
|
@ -0,0 +1,140 @@
|
||||||
|
import React from 'react';
|
||||||
|
import { Lbry } from 'lbry-redux';
|
||||||
|
import {
|
||||||
|
ActivityIndicator,
|
||||||
|
Linking,
|
||||||
|
NativeModules,
|
||||||
|
Text,
|
||||||
|
TouchableOpacity,
|
||||||
|
View
|
||||||
|
} from 'react-native';
|
||||||
|
import { NavigationActions, StackActions } from 'react-navigation';
|
||||||
|
import AsyncStorage from '@react-native-community/async-storage';
|
||||||
|
import Colors from 'styles/colors';
|
||||||
|
import Constants from 'constants';
|
||||||
|
import EmailVerifyPage from './internal/email-verify-page';
|
||||||
|
import ManualVerifyPage from './internal/manual-verify-page';
|
||||||
|
import PhoneVerifyPage from './internal/phone-verify-page';
|
||||||
|
import firstRunStyle from 'styles/firstRun';
|
||||||
|
|
||||||
|
class VerificationScreen extends React.PureComponent {
|
||||||
|
state = {
|
||||||
|
currentPage: null,
|
||||||
|
emailSubmitted: false,
|
||||||
|
isFirstRun: false,
|
||||||
|
launchUrl: null,
|
||||||
|
showSkip: false,
|
||||||
|
skipAccountConfirmed: false,
|
||||||
|
showBottomContainer: true,
|
||||||
|
walletPassword: null,
|
||||||
|
isEmailVerified: false,
|
||||||
|
isIdentityVerified: false,
|
||||||
|
isRewardApproved: false
|
||||||
|
};
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
const { user } = this.props;
|
||||||
|
this.checkVerificationStatus(user);
|
||||||
|
}
|
||||||
|
|
||||||
|
checkVerificationStatus = (user) => {
|
||||||
|
const { navigation } = this.props;
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
isEmailVerified: (user && user.primary_email && user.has_verified_email),
|
||||||
|
isIdentityVerified: (user && user.is_identity_verified),
|
||||||
|
isRewardApproved: (user && user.is_reward_approved)
|
||||||
|
}, () => {
|
||||||
|
if (!this.state.isEmailVerified) {
|
||||||
|
this.setState({ currentPage: 'emailVerify' });
|
||||||
|
}
|
||||||
|
if (this.state.isEmailVerified && !this.state.isIdentityVerified) {
|
||||||
|
this.setState({ currentPage: 'phoneVerify' });
|
||||||
|
}
|
||||||
|
if (this.state.isEmailVerified && this.state.isIdentityVerified && !this.state.isRewardApproved) {
|
||||||
|
this.setState({ currentPage: 'manualVerify' });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.state.isEmailVerified && this.state.isIdentityVerified && this.state.isRewardApproved) {
|
||||||
|
// verification steps already completed
|
||||||
|
// simply navigate back to the rewards page
|
||||||
|
navigation.goBack();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillReceiveProps(nextProps) {
|
||||||
|
const { user } = nextProps;
|
||||||
|
this.checkVerificationStatus(user);
|
||||||
|
}
|
||||||
|
|
||||||
|
onCloseButtonPressed = () => {
|
||||||
|
const { navigation } = this.props;
|
||||||
|
navigation.goBack();
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const {
|
||||||
|
addUserEmail,
|
||||||
|
emailNewErrorMessage,
|
||||||
|
emailNewPending,
|
||||||
|
emailToVerify,
|
||||||
|
navigation,
|
||||||
|
notify,
|
||||||
|
addUserPhone,
|
||||||
|
phone,
|
||||||
|
phoneVerifyIsPending,
|
||||||
|
phoneVerifyErrorMessage,
|
||||||
|
phoneNewIsPending,
|
||||||
|
phoneNewErrorMessage,
|
||||||
|
resendVerificationEmail,
|
||||||
|
verifyPhone
|
||||||
|
} = this.props;
|
||||||
|
|
||||||
|
let page = null;
|
||||||
|
switch (this.state.currentPage) {
|
||||||
|
case 'emailVerify':
|
||||||
|
page = (
|
||||||
|
<EmailVerifyPage
|
||||||
|
addUserEmail={addUserEmail}
|
||||||
|
emailNewErrorMessage={emailNewErrorMessage}
|
||||||
|
emailNewPending={emailNewPending}
|
||||||
|
emailToVerify={emailToVerify}
|
||||||
|
notify={notify}
|
||||||
|
resendVerificationEmail={resendVerificationEmail}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
case 'phoneVerify':
|
||||||
|
page = (
|
||||||
|
<PhoneVerifyPage
|
||||||
|
addUserPhone={addUserPhone}
|
||||||
|
phone={phone}
|
||||||
|
phoneVerifyIsPending={phoneVerifyIsPending}
|
||||||
|
phoneVerifyErrorMessage={phoneVerifyErrorMessage}
|
||||||
|
phoneNewIsPending={phoneNewIsPending}
|
||||||
|
phoneNewErrorMessage={phoneNewErrorMessage}
|
||||||
|
notify={notify}
|
||||||
|
verifyPhone={verifyPhone}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
case 'manualVerify':
|
||||||
|
page = (
|
||||||
|
<ManualVerifyPage />
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View style={firstRunStyle.screenContainer}>
|
||||||
|
{page}
|
||||||
|
|
||||||
|
<TouchableOpacity style={firstRunStyle.closeButton} onPress={this.onCloseButtonPressed}>
|
||||||
|
<Text style={firstRunStyle.closeButtonText}>x</Text>
|
||||||
|
</TouchableOpacity>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default VerificationScreen;
|
|
@ -2,13 +2,17 @@ import { connect } from 'react-redux';
|
||||||
import { doSetClientSetting } from 'redux/actions/settings';
|
import { doSetClientSetting } from 'redux/actions/settings';
|
||||||
import { makeSelectClientSetting } from 'redux/selectors/settings';
|
import { makeSelectClientSetting } from 'redux/selectors/settings';
|
||||||
import { doPushDrawerStack } from 'redux/actions/drawer';
|
import { doPushDrawerStack } from 'redux/actions/drawer';
|
||||||
|
import { selectBalance } from 'lbry-redux';
|
||||||
import { doGetSync, selectUser } from 'lbryinc';
|
import { doGetSync, selectUser } from 'lbryinc';
|
||||||
import Constants from 'constants';
|
import Constants from 'constants';
|
||||||
import WalletPage from './view';
|
import WalletPage from './view';
|
||||||
|
|
||||||
const select = state => ({
|
const select = state => ({
|
||||||
user: selectUser(state),
|
user: selectUser(state),
|
||||||
|
balance: selectBalance(state),
|
||||||
understandsRisks: makeSelectClientSetting(Constants.SETTING_ALPHA_UNDERSTANDS_RISKS)(state),
|
understandsRisks: makeSelectClientSetting(Constants.SETTING_ALPHA_UNDERSTANDS_RISKS)(state),
|
||||||
|
backupDismissed: makeSelectClientSetting(Constants.SETTING_BACKUP_DISMISSED)(state),
|
||||||
|
rewardsNotInterested: makeSelectClientSetting(Constants.SETTING_REWARDS_NOT_INTERESTED)(state),
|
||||||
});
|
});
|
||||||
|
|
||||||
const perform = dispatch => ({
|
const perform = dispatch => ({
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { NativeModules, ScrollView, Text, View } from 'react-native';
|
import { NativeModules, ScrollView, Text, View } from 'react-native';
|
||||||
import TransactionListRecent from 'component/transactionListRecent';
|
import TransactionListRecent from 'component/transactionListRecent';
|
||||||
|
import WalletRewardsDriver from 'component/walletRewardsDriver';
|
||||||
import WalletAddress from 'component/walletAddress';
|
import WalletAddress from 'component/walletAddress';
|
||||||
import WalletBalance from 'component/walletBalance';
|
import WalletBalance from 'component/walletBalance';
|
||||||
import WalletSend from 'component/walletSend';
|
import WalletSend from 'component/walletSend';
|
||||||
|
@ -20,8 +21,20 @@ class WalletPage extends React.PureComponent {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onDismissBackupPressed = () => {
|
||||||
|
const { setClientSetting } = this.props;
|
||||||
|
setClientSetting(Constants.SETTING_BACKUP_DISMISSED, true);
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { understandsRisks, setClientSetting, navigation } = this.props;
|
const {
|
||||||
|
balance,
|
||||||
|
backupDismissed,
|
||||||
|
rewardsNotInterested,
|
||||||
|
understandsRisks,
|
||||||
|
setClientSetting,
|
||||||
|
navigation
|
||||||
|
} = this.props;
|
||||||
|
|
||||||
if (!understandsRisks) {
|
if (!understandsRisks) {
|
||||||
return (
|
return (
|
||||||
|
@ -41,17 +54,20 @@ class WalletPage extends React.PureComponent {
|
||||||
return (
|
return (
|
||||||
<View style={walletStyle.container}>
|
<View style={walletStyle.container}>
|
||||||
<UriBar navigation={navigation} />
|
<UriBar navigation={navigation} />
|
||||||
<ScrollView keyboardShouldPersistTaps={'handled'}>
|
<ScrollView style={walletStyle.scrollContainer} keyboardShouldPersistTaps={'handled'}>
|
||||||
|
{!backupDismissed &&
|
||||||
<View style={walletStyle.warningCard}>
|
<View style={walletStyle.warningCard}>
|
||||||
<Text style={walletStyle.warningText}>
|
<Text style={walletStyle.warningText}>
|
||||||
Please backup your wallet file using the instructions at <Link style={walletStyle.warningText} text="https://lbry.com/faq/how-to-backup-wallet#android" href="https://lbry.com/faq/how-to-backup-wallet#android" />.
|
Please backup your wallet file using the instructions at <Link style={walletStyle.warningText} text="https://lbry.com/faq/how-to-backup-wallet#android" href="https://lbry.com/faq/how-to-backup-wallet#android" />.
|
||||||
</Text>
|
</Text>
|
||||||
</View>
|
<Button text={'Dismiss'} style={walletStyle.button} onPress={this.onDismissBackupPressed} />
|
||||||
|
</View>}
|
||||||
|
|
||||||
|
{(!rewardsNotInterested) && (!balance || balance === 0) && <WalletRewardsDriver navigation={navigation} />}
|
||||||
<WalletBalance />
|
<WalletBalance />
|
||||||
<WalletAddress />
|
<WalletAddress />
|
||||||
<WalletSend />
|
<WalletSend />
|
||||||
<TransactionListRecent navigation={this.props.navigation} />
|
<TransactionListRecent navigation={navigation} />
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
|
|
|
@ -129,6 +129,20 @@ const firstRunStyle = StyleSheet.create({
|
||||||
},
|
},
|
||||||
titleIcon: {
|
titleIcon: {
|
||||||
marginTop: 8
|
marginTop: 8
|
||||||
|
},
|
||||||
|
closeButton: {
|
||||||
|
position: 'absolute',
|
||||||
|
top: 8,
|
||||||
|
right: 8,
|
||||||
|
width: 48,
|
||||||
|
height: 48,
|
||||||
|
borderRadius: 48,
|
||||||
|
justifyContent: 'center'
|
||||||
|
},
|
||||||
|
closeButtonText: {
|
||||||
|
alignSelf: 'center',
|
||||||
|
color: Colors.White,
|
||||||
|
fontSize: 16
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,24 @@ const rewardStyle = StyleSheet.create({
|
||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
flexDirection: 'row'
|
flexDirection: 'row'
|
||||||
},
|
},
|
||||||
|
enrollContainer: {
|
||||||
|
flex: 1,
|
||||||
|
marginTop: 76,
|
||||||
|
marginLeft: 16,
|
||||||
|
marginRight: 16,
|
||||||
|
marginBottom: 16,
|
||||||
|
padding: 24,
|
||||||
|
backgroundColor: Colors.LbryGreen
|
||||||
|
},
|
||||||
|
onboarding: {
|
||||||
|
marginTop: 36
|
||||||
|
},
|
||||||
|
enrollDescText: {
|
||||||
|
fontFamily: 'Inter-UI-Regular',
|
||||||
|
fontSize: 18,
|
||||||
|
lineHeight: 28,
|
||||||
|
color: Colors.White
|
||||||
|
},
|
||||||
rewardsContainer: {
|
rewardsContainer: {
|
||||||
flex: 1
|
flex: 1
|
||||||
},
|
},
|
||||||
|
@ -101,21 +119,32 @@ const rewardStyle = StyleSheet.create({
|
||||||
bottomMarginLarge: {
|
bottomMarginLarge: {
|
||||||
marginBottom: 24
|
marginBottom: 24
|
||||||
},
|
},
|
||||||
|
leftRightMargin: {
|
||||||
|
marginLeft: 32,
|
||||||
|
marginRight: 32
|
||||||
|
},
|
||||||
link: {
|
link: {
|
||||||
color: Colors.LbryGreen,
|
color: Colors.LbryGreen,
|
||||||
fontFamily: 'Inter-UI-Regular',
|
fontFamily: 'Inter-UI-Regular',
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
},
|
},
|
||||||
textLink: {
|
textLink: {
|
||||||
|
color: Colors.White
|
||||||
|
},
|
||||||
|
underlinedTextLink: {
|
||||||
|
color: Colors.White,
|
||||||
|
textDecorationLine: 'underline'
|
||||||
|
},
|
||||||
|
greenLink: {
|
||||||
color: Colors.LbryGreen
|
color: Colors.LbryGreen
|
||||||
},
|
},
|
||||||
leftCol: {
|
leftCol: {
|
||||||
width: '15%',
|
width: '5%',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
paddingLeft: 6
|
paddingLeft: 6
|
||||||
},
|
},
|
||||||
midCol: {
|
midCol: {
|
||||||
width: '65%'
|
width: '75%'
|
||||||
},
|
},
|
||||||
rightCol: {
|
rightCol: {
|
||||||
width: '18%',
|
width: '18%',
|
||||||
|
@ -178,12 +207,14 @@ const rewardStyle = StyleSheet.create({
|
||||||
paddingRight: 4
|
paddingRight: 4
|
||||||
},
|
},
|
||||||
phoneInput: {
|
phoneInput: {
|
||||||
marginLeft: 8
|
marginLeft: 32,
|
||||||
|
marginRight: 32
|
||||||
},
|
},
|
||||||
phoneInputText: {
|
phoneInputText: {
|
||||||
fontFamily: 'Inter-UI-Regular',
|
fontFamily: 'Inter-UI-Regular',
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
letterSpacing: 1.3
|
letterSpacing: 1.3,
|
||||||
|
color: Colors.White
|
||||||
},
|
},
|
||||||
verifyingText: {
|
verifyingText: {
|
||||||
fontFamily: 'Inter-UI-Regular',
|
fontFamily: 'Inter-UI-Regular',
|
||||||
|
@ -193,8 +224,11 @@ const rewardStyle = StyleSheet.create({
|
||||||
},
|
},
|
||||||
verificationCodeInput: {
|
verificationCodeInput: {
|
||||||
fontFamily: 'Inter-UI-Regular',
|
fontFamily: 'Inter-UI-Regular',
|
||||||
|
color: Colors.White,
|
||||||
fontSize: 24,
|
fontSize: 24,
|
||||||
letterSpacing: 12
|
letterSpacing: 12,
|
||||||
|
marginLeft: 32,
|
||||||
|
marginRight: 32
|
||||||
},
|
},
|
||||||
loading: {
|
loading: {
|
||||||
alignSelf: 'flex-start'
|
alignSelf: 'flex-start'
|
||||||
|
@ -202,12 +236,24 @@ const rewardStyle = StyleSheet.create({
|
||||||
smsPermissionContainer: {
|
smsPermissionContainer: {
|
||||||
marginBottom: 32
|
marginBottom: 32
|
||||||
},
|
},
|
||||||
dismissButton: {
|
buttonRow: {
|
||||||
alignSelf: 'flex-end',
|
width: '100%',
|
||||||
|
position: 'absolute',
|
||||||
|
alignItems: 'center',
|
||||||
|
left: 24,
|
||||||
|
bottom: 24,
|
||||||
|
flexDirection: 'row',
|
||||||
|
justifyContent: 'space-between'
|
||||||
|
},
|
||||||
|
notInterestedLink: {
|
||||||
|
fontSize: 14,
|
||||||
|
fontFamily: 'Inter-UI-Regular',
|
||||||
|
color: Colors.White
|
||||||
|
},
|
||||||
|
enrollButton: {
|
||||||
backgroundColor: Colors.White,
|
backgroundColor: Colors.White,
|
||||||
paddingLeft: 16,
|
paddingLeft: 16,
|
||||||
paddingRight: 16,
|
paddingRight: 16
|
||||||
marginTop: 8,
|
|
||||||
},
|
},
|
||||||
customCodeInput: {
|
customCodeInput: {
|
||||||
fontFamily: 'Inter-UI-Regular',
|
fontFamily: 'Inter-UI-Regular',
|
||||||
|
@ -221,7 +267,41 @@ const rewardStyle = StyleSheet.create({
|
||||||
backgroundColor: Colors.LbryGreen
|
backgroundColor: Colors.LbryGreen
|
||||||
},
|
},
|
||||||
failureFootnote: {
|
failureFootnote: {
|
||||||
marginTop: 12
|
marginTop: 32,
|
||||||
|
marginLeft: 32,
|
||||||
|
marginRight: 32
|
||||||
|
},
|
||||||
|
buttonContainer: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'space-between',
|
||||||
|
width: '100%',
|
||||||
|
paddingLeft: 32,
|
||||||
|
paddingRight: 32,
|
||||||
|
marginTop: 16
|
||||||
|
},
|
||||||
|
verificationTitle: {
|
||||||
|
fontSize: 32,
|
||||||
|
color: Colors.White,
|
||||||
|
fontFamily: 'Inter-UI-Regular',
|
||||||
|
marginLeft: 32,
|
||||||
|
marginRight: 32,
|
||||||
|
marginBottom: 24
|
||||||
|
},
|
||||||
|
verificationButton: {
|
||||||
|
backgroundColor: Colors.White,
|
||||||
|
paddingLeft: 16,
|
||||||
|
paddingRight: 16
|
||||||
|
},
|
||||||
|
verificationLink: {
|
||||||
|
color: Colors.White,
|
||||||
|
fontSize: 14
|
||||||
|
},
|
||||||
|
paragraphText: {
|
||||||
|
fontFamily: 'Inter-UI-Regular',
|
||||||
|
color: Colors.White,
|
||||||
|
fontSize: 12,
|
||||||
|
lineHeight: 16
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,9 @@ const walletStyle = StyleSheet.create({
|
||||||
container: {
|
container: {
|
||||||
backgroundColor: Colors.PageBackground
|
backgroundColor: Colors.PageBackground
|
||||||
},
|
},
|
||||||
|
scrollContainer: {
|
||||||
|
marginTop: 60
|
||||||
|
},
|
||||||
row: {
|
row: {
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
justifyContent: 'space-between',
|
justifyContent: 'space-between',
|
||||||
|
@ -40,7 +43,7 @@ const walletStyle = StyleSheet.create({
|
||||||
backgroundColor: Colors.Orange,
|
backgroundColor: Colors.Orange,
|
||||||
padding: 16,
|
padding: 16,
|
||||||
marginLeft: 16,
|
marginLeft: 16,
|
||||||
marginTop: 76,
|
marginTop: 16,
|
||||||
marginRight: 16
|
marginRight: 16
|
||||||
},
|
},
|
||||||
transactionsCard: {
|
transactionsCard: {
|
||||||
|
@ -142,7 +145,8 @@ const walletStyle = StyleSheet.create({
|
||||||
color: Colors.White,
|
color: Colors.White,
|
||||||
fontFamily: 'Inter-UI-Regular',
|
fontFamily: 'Inter-UI-Regular',
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
lineHeight: 24
|
lineHeight: 24,
|
||||||
|
marginBottom: 8
|
||||||
},
|
},
|
||||||
understand: {
|
understand: {
|
||||||
marginLeft: 16,
|
marginLeft: 16,
|
||||||
|
@ -168,6 +172,19 @@ const walletStyle = StyleSheet.create({
|
||||||
},
|
},
|
||||||
transactionHistoryScroll: {
|
transactionHistoryScroll: {
|
||||||
marginTop: 60
|
marginTop: 60
|
||||||
|
},
|
||||||
|
rewardDriverCard: {
|
||||||
|
padding: 16,
|
||||||
|
backgroundColor: Colors.LbryGreen,
|
||||||
|
marginLeft: 16,
|
||||||
|
marginTop: 16,
|
||||||
|
marginRight: 16
|
||||||
|
},
|
||||||
|
rewardDriverText: {
|
||||||
|
color: Colors.White,
|
||||||
|
fontFamily: 'Inter-UI-Regular',
|
||||||
|
fontSize: 14,
|
||||||
|
lineHeight: 16
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -55,6 +55,7 @@ public class FirebaseModule extends ReactContextBaseJavaModule {
|
||||||
@ReactMethod
|
@ReactMethod
|
||||||
public void logException(boolean fatal, String message, ReadableMap payload) {
|
public void logException(boolean fatal, String message, ReadableMap payload) {
|
||||||
Bundle bundle = new Bundle();
|
Bundle bundle = new Bundle();
|
||||||
|
bundle.putString("message", message);
|
||||||
if (payload != null) {
|
if (payload != null) {
|
||||||
HashMap<String, Object> payloadMap = payload.toHashMap();
|
HashMap<String, Object> payloadMap = payload.toHashMap();
|
||||||
for (Map.Entry<String, Object> entry : payloadMap.entrySet()) {
|
for (Map.Entry<String, Object> entry : payloadMap.entrySet()) {
|
||||||
|
|
Loading…
Reference in a new issue