Unverified Commit 89a9571c authored by Akinwale Ariwodola's avatar Akinwale Ariwodola Committed by GitHub
Browse files

Display USD (#135)

* show usd values for lbc on wallet and rewards pages
* link to publish page
* update phrasing
* don't show rewards nag if user is not interested
parent 689e30a5
Pipeline #1890 passed with stage
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { doToast, selectMyChannelClaims } from 'lbry-redux'; import { doToast, selectBalance, selectMyChannelClaims } from 'lbry-redux';
import { selectUser } from 'lbryinc'; import { selectUnclaimedRewardValue, selectUser } from 'lbryinc';
import { selectSdkReady } from 'redux/selectors/settings'; import { selectSdkReady } from 'redux/selectors/settings';
import DrawerContent from './view'; import DrawerContent from './view';
const select = state => ({ const select = state => ({
balance: selectBalance(state),
channels: selectMyChannelClaims(state), channels: selectMyChannelClaims(state),
sdkReady: selectSdkReady(state), sdkReady: selectSdkReady(state),
unclaimedRewardAmount: selectUnclaimedRewardValue(state),
user: selectUser(state), user: selectUser(state),
}); });
......
...@@ -6,6 +6,8 @@ import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api ...@@ -6,6 +6,8 @@ import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api
import Icon from 'react-native-vector-icons/FontAwesome5'; import Icon from 'react-native-vector-icons/FontAwesome5';
import channelIconStyle from 'styles/channelIcon'; import channelIconStyle from 'styles/channelIcon';
import discoverStyle from 'styles/discover'; import discoverStyle from 'styles/discover';
import { Lbryio } from 'lbryinc';
import { formatUsd } from 'utils/helper';
const groupedMenuItems = { const groupedMenuItems = {
'Find content': [ 'Find content': [
...@@ -42,6 +44,18 @@ const routesRequiringSdkReady = [ ...@@ -42,6 +44,18 @@ const routesRequiringSdkReady = [
]; ];
class DrawerContent extends React.PureComponent { class DrawerContent extends React.PureComponent {
state = {
usdExchangeRate: 0,
};
componentDidMount() {
Lbryio.getExchangeRates().then(rates => {
if (!isNaN(rates.LBC_USD)) {
this.setState({ usdExchangeRate: rates.LBC_USD });
}
});
}
getAvatarImageUrl = () => { getAvatarImageUrl = () => {
const { channels = [] } = this.props; const { channels = [] } = this.props;
if (channels) { if (channels) {
...@@ -82,7 +96,7 @@ class DrawerContent extends React.PureComponent { ...@@ -82,7 +96,7 @@ class DrawerContent extends React.PureComponent {
}; };
render() { render() {
const { activeTintColor, navigation, user, onItemPress } = this.props; const { activeTintColor, balance, navigation, unclaimedRewardAmount, user, onItemPress } = this.props;
const { state } = navigation; const { state } = navigation;
const activeItemKey = state.routes[state.index] ? state.routes[state.index].key : null; const activeItemKey = state.routes[state.index] ? state.routes[state.index].key : null;
...@@ -189,6 +203,15 @@ class DrawerContent extends React.PureComponent { ...@@ -189,6 +203,15 @@ class DrawerContent extends React.PureComponent {
</View> </View>
<Text style={[discoverStyle.menuItem, focused ? discoverStyle.menuItemFocused : null]}> <Text style={[discoverStyle.menuItem, focused ? discoverStyle.menuItemFocused : null]}>
{__(item.label)} {__(item.label)}
{item.label === 'Wallet' && this.state.usdExchangeRate > 0 && (
<Text> ({formatUsd(parseFloat(balance) * parseFloat(this.state.usdExchangeRate))})</Text>
)}
{item.label === 'Rewards' && this.state.usdExchangeRate > 0 && (
<Text>
{' '}
({formatUsd(parseFloat(unclaimedRewardAmount) * parseFloat(this.state.usdExchangeRate))})
</Text>
)}
</Text> </Text>
</TouchableOpacity> </TouchableOpacity>
); );
......
...@@ -2,7 +2,7 @@ import { connect } from 'react-redux'; ...@@ -2,7 +2,7 @@ import { connect } from 'react-redux';
import { makeSelectClientSetting } from 'redux/selectors/settings'; import { makeSelectClientSetting } from 'redux/selectors/settings';
import { selectBalance } from 'lbry-redux'; import { selectBalance } from 'lbry-redux';
import { selectUnclaimedRewardValue } from 'lbryinc'; import { selectUnclaimedRewardValue } from 'lbryinc';
import Constants from 'constants'; import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api
import FloatingWalletBalance from './view'; import FloatingWalletBalance from './view';
const select = state => ({ const select = state => ({
...@@ -11,7 +11,4 @@ const select = state => ({ ...@@ -11,7 +11,4 @@ const select = state => ({
rewardsNotInterested: makeSelectClientSetting(Constants.SETTING_REWARDS_NOT_INTERESTED)(state), rewardsNotInterested: makeSelectClientSetting(Constants.SETTING_REWARDS_NOT_INTERESTED)(state),
}); });
export default connect( export default connect(select, null)(FloatingWalletBalance);
select,
null
)(FloatingWalletBalance);
// @flow // @flow
import React from 'react'; import React from 'react';
import { ActivityIndicator, Text, TouchableOpacity, View } from 'react-native'; import { ActivityIndicator, Text, TouchableOpacity, View } from 'react-native';
import Colors from '../../styles/colors'; import { formatUsd } from 'utils/helper';
import Colors from 'styles/colors';
import Icon from 'react-native-vector-icons/FontAwesome5'; import Icon from 'react-native-vector-icons/FontAwesome5';
import Link from '../link'; import Link from 'component/link';
import rewardStyle from '../../styles/reward'; import rewardStyle from 'styles/reward';
type Props = { type Props = {
canClaim: boolean, canClaim: boolean,
...@@ -61,7 +62,7 @@ class RewardCard extends React.PureComponent<Props> { ...@@ -61,7 +62,7 @@ class RewardCard extends React.PureComponent<Props> {
if (reward) { if (reward) {
const claimed = !!reward.transaction_id; const claimed = !!reward.transaction_id;
if (!claimed && reward.reward_range && reward.reward_range.includes('-')) { if (!claimed && reward.reward_range && reward.reward_range.includes('-')) {
return reward.reward_range.split('-')[0] + '+'; // ex: 5+ return reward.reward_range.split('-')[1];
} else if (reward.reward_amount > 0) { } else if (reward.reward_amount > 0) {
return reward.reward_amount; return reward.reward_amount;
} }
...@@ -72,7 +73,7 @@ class RewardCard extends React.PureComponent<Props> { ...@@ -72,7 +73,7 @@ class RewardCard extends React.PureComponent<Props> {
}; };
render() { render() {
const { canClaim, isPending, onClaimPress, reward } = this.props; const { canClaim, isPending, onClaimPress, reward, usdExchangeRate } = this.props;
const claimed = !!reward.transaction_id; const claimed = !!reward.transaction_id;
return ( return (
...@@ -117,8 +118,16 @@ class RewardCard extends React.PureComponent<Props> { ...@@ -117,8 +118,16 @@ class RewardCard extends React.PureComponent<Props> {
)} )}
</View> </View>
<View style={rewardStyle.rightCol}> <View style={rewardStyle.rightCol}>
{reward.reward_range && reward.reward_range.indexOf('-') > -1 && (
<Text style={rewardStyle.rightColHeader}>{__('up to')}</Text>
)}
<Text style={rewardStyle.rewardAmount}>{this.getDisplayAmount()}</Text> <Text style={rewardStyle.rewardAmount}>{this.getDisplayAmount()}</Text>
<Text style={rewardStyle.rewardCurrency}>LBC</Text> <Text style={rewardStyle.rewardCurrency}>LBC</Text>
{usdExchangeRate > 0 && (
<Text style={rewardStyle.rewardUsd}>
&asymp;{formatUsd(parseFloat(this.getDisplayAmount()) * parseFloat(usdExchangeRate))}
</Text>
)}
</View> </View>
</TouchableOpacity> </TouchableOpacity>
); );
......
...@@ -7,6 +7,7 @@ import Link from 'component/link'; ...@@ -7,6 +7,7 @@ import Link from 'component/link';
import Colors from 'styles/colors'; import Colors from 'styles/colors';
import Icon from 'react-native-vector-icons/FontAwesome5'; import Icon from 'react-native-vector-icons/FontAwesome5';
import rewardStyle from 'styles/reward'; import rewardStyle from 'styles/reward';
import { formatUsd } from '../../utils/helper';
class RewardEnrolment extends React.Component { class RewardEnrolment extends React.Component {
componentDidMount() { componentDidMount() {
...@@ -29,7 +30,7 @@ class RewardEnrolment extends React.Component { ...@@ -29,7 +30,7 @@ class RewardEnrolment extends React.Component {
}; };
render() { render() {
const { fetching, navigation, unclaimedRewardAmount, user } = this.props; const { unclaimedRewardAmount, usdExchangeRate } = this.props;
return ( return (
<View style={rewardStyle.enrollContainer}> <View style={rewardStyle.enrollContainer}>
...@@ -43,9 +44,11 @@ class RewardEnrolment extends React.Component { ...@@ -43,9 +44,11 @@ class RewardEnrolment extends React.Component {
<View style={rewardStyle.onboarding}> <View style={rewardStyle.onboarding}>
<Text style={rewardStyle.enrollDescText}> <Text style={rewardStyle.enrollDescText}>
{__('LBRY credits allow you to purchase content, publish content, and influence the network.')} {__('LBRY credits allow you to publish or purchase content.')}
{'\n\n'} {'\n\n'}
{__('You get credits for free for providing an email address and taking other basic actions.')} {__('You can obtain free credits worth %amount% after you provide an email address.', {
amount: formatUsd(parseFloat(unclaimedRewardAmount) * parseFloat(usdExchangeRate)),
})}
{'\n\n'} {'\n\n'}
<Link style={rewardStyle.learnMoreLink} text={__('Learn more')} onPress={this.onLearnMorePressed} />. <Link style={rewardStyle.learnMoreLink} text={__('Learn more')} onPress={this.onLearnMorePressed} />.
</Text> </Text>
......
...@@ -58,7 +58,7 @@ class SuggestedSubscriptionsGrid extends React.PureComponent { ...@@ -58,7 +58,7 @@ class SuggestedSubscriptionsGrid extends React.PureComponent {
const uris = claimSearchByQuery[claimSearchKey]; const uris = claimSearchByQuery[claimSearchKey];
if ( if (
lastPageReached[claimSearchKey] || lastPageReached[claimSearchKey] ||
((uris.length > 0 && uris.length < suggestedPageSize) || uris.length >= softLimit) (uris.length > 0 && uris.length < suggestedPageSize) || uris.length >= softLimit
) { ) {
return; return;
} }
...@@ -81,7 +81,7 @@ class SuggestedSubscriptionsGrid extends React.PureComponent { ...@@ -81,7 +81,7 @@ class SuggestedSubscriptionsGrid extends React.PureComponent {
} }
render() { render() {
const { claimSearchByQuery, suggested, inModal, navigation } = this.props; const { claimSearchByQuery, inModal, navigation } = this.props;
const options = this.buildClaimSearchOptions(); const options = this.buildClaimSearchOptions();
const claimSearchKey = createNormalizedClaimSearchKey(options); const claimSearchKey = createNormalizedClaimSearchKey(options);
const claimSearchUris = claimSearchByQuery[claimSearchKey]; const claimSearchUris = claimSearchByQuery[claimSearchKey];
...@@ -92,7 +92,7 @@ class SuggestedSubscriptionsGrid extends React.PureComponent { ...@@ -92,7 +92,7 @@ class SuggestedSubscriptionsGrid extends React.PureComponent {
maxToRenderPerBatch={48} maxToRenderPerBatch={48}
removeClippedSubviews removeClippedSubviews
itemDimension={120} itemDimension={120}
spacing={2} spacing={1}
items={claimSearchUris} items={claimSearchUris}
style={inModal ? subscriptionsStyle.modalScrollContainer : subscriptionsStyle.scrollContainer} style={inModal ? subscriptionsStyle.modalScrollContainer : subscriptionsStyle.scrollContainer}
contentContainerStyle={ contentContainerStyle={
......
...@@ -6,7 +6,4 @@ const select = state => ({ ...@@ -6,7 +6,4 @@ const select = state => ({
balance: selectBalance(state), balance: selectBalance(state),
}); });
export default connect( export default connect(select, null)(WalletBalance);
select,
null
)(WalletBalance);
// @flow // @flow
import React from 'react'; import React from 'react';
import { Image, Text, View } from 'react-native'; import { Image, Text, View } from 'react-native';
import { Lbry, formatCredits } from 'lbry-redux'; import { formatCredits } from 'lbry-redux';
import Address from 'component/address'; import { Lbryio } from 'lbryinc';
import Button from 'component/button'; import { formatUsd } from 'utils/helper';
import walletStyle from 'styles/wallet'; import walletStyle from 'styles/wallet';
type Props = { type Props = {
...@@ -11,6 +11,18 @@ type Props = { ...@@ -11,6 +11,18 @@ type Props = {
}; };
class WalletBalance extends React.PureComponent<Props> { class WalletBalance extends React.PureComponent<Props> {
state = {
usdExchangeRate: 0,
};
componentDidMount() {
Lbryio.getExchangeRates().then(rates => {
if (!isNaN(rates.LBC_USD)) {
this.setState({ usdExchangeRate: rates.LBC_USD });
}
});
}
render() { render() {
const { balance } = this.props; const { balance } = this.props;
return ( return (
...@@ -21,6 +33,13 @@ class WalletBalance extends React.PureComponent<Props> { ...@@ -21,6 +33,13 @@ class WalletBalance extends React.PureComponent<Props> {
<Text style={walletStyle.balance}> <Text style={walletStyle.balance}>
{(balance || balance === 0) && formatCredits(parseFloat(balance), 2) + ' LBC'} {(balance || balance === 0) && formatCredits(parseFloat(balance), 2) + ' LBC'}
</Text> </Text>
<Text style={walletStyle.usdBalance}>
{this.state.usdExchangeRate > 0 && (
<Text>
&asymp;{formatUsd(isNaN(balance) ? 0 : parseFloat(balance) * parseFloat(this.state.usdExchangeRate))}
</Text>
)}
</Text>
</View> </View>
); );
} }
......
// @flow // @flow
import React from 'react'; import React from 'react';
import { Image, Text, View } from 'react-native'; import { Text, View } from 'react-native';
import { Lbry, formatCredits } from 'lbry-redux'; import { formatCredits } from 'lbry-redux';
import Address from 'component/address'; import { Lbryio } from 'lbryinc';
import Button from 'component/button'; import { formatUsd } from 'utils/helper';
import Colors from 'styles/colors'; import Colors from 'styles/colors';
import Icon from 'react-native-vector-icons/FontAwesome5'; import Icon from 'react-native-vector-icons/FontAwesome5';
import Link from 'component/link'; import Link from 'component/link';
import walletStyle from 'styles/wallet'; import walletStyle from 'styles/wallet';
import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api
type Props = { type Props = {
claimsBalance: number, claimsBalance: number,
...@@ -16,25 +17,37 @@ type Props = { ...@@ -16,25 +17,37 @@ type Props = {
}; };
class WalletBalanceExtra extends React.PureComponent<Props> { class WalletBalanceExtra extends React.PureComponent<Props> {
state = {
usdExchangeRate: 0,
};
componentDidMount() {
Lbryio.getExchangeRates().then(rates => {
if (!isNaN(rates.LBC_USD)) {
this.setState({ usdExchangeRate: rates.LBC_USD });
}
});
}
render() { render() {
const { claimsBalance, deviceWalletSynced, supportsBalance, tipsBalance } = this.props; const { claimsBalance, deviceWalletSynced, navigation, supportsBalance, tipsBalance } = this.props;
return ( return (
<View style={walletStyle.balanceExtra}> <View style={walletStyle.balanceExtra}>
<View style={walletStyle.syncDriverCustody}> <View style={walletStyle.usdInfoCard}>
<Text style={walletStyle.syncInfoText}> <Text style={walletStyle.usdInfoText}>
{deviceWalletSynced You can convert your credits to USD and withdraw the converted amount using an exchange.{' '}
? __('A backup of your wallet is synced with lbry.tv') <Link
: __('Your wallet is not currently synced with lbry.tv. You are responsible for backing up your wallet.')} style={walletStyle.usdConvertFaqLink}
href={'https://lbry.com/faq/exchanges'}
text={__('Learn more')}
/>
.
</Text> </Text>
<Link <Link
text={__('What does this mean?')} style={walletStyle.usdConvertLink}
href={ href={'https://bittrex.com/Account/Register?referralCode=4M1-P30-BON'}
deviceWalletSynced text={__('Convert credits to USD on Bittrex')}
? 'https://lbry.com/faq/account-sync'
: 'https://lbry.com/faq/how-to-backup-wallet#android'
}
style={walletStyle.syncInfoLink}
/> />
</View> </View>
...@@ -47,7 +60,18 @@ class WalletBalanceExtra extends React.PureComponent<Props> { ...@@ -47,7 +60,18 @@ class WalletBalanceExtra extends React.PureComponent<Props> {
<Text style={walletStyle.walletExtraBalance}>{formatCredits(parseFloat(tipsBalance), 2)}</Text> <Text style={walletStyle.walletExtraBalance}>{formatCredits(parseFloat(tipsBalance), 2)}</Text>
<Text style={walletStyle.walletExtraCurrency}>LBC</Text> <Text style={walletStyle.walletExtraCurrency}>LBC</Text>
</View> </View>
<Text style={walletStyle.usdWalletExtraBalance}>
&asymp;{formatUsd(parseFloat(tipsBalance) * parseFloat(this.state.usdExchangeRate))}
</Text>
<Text style={walletStyle.text}>{__('in tips')}</Text> <Text style={walletStyle.text}>{__('in tips')}</Text>
<Link
style={walletStyle.earnTipsLink}
onPress={() => {
navigation.navigate({ routeName: Constants.DRAWER_ROUTE_PUBLISH });
}}
text={__('Earn more tips by uploading cool videos')}
/>
</View> </View>
<View style={walletStyle.walletExtraCol}> <View style={walletStyle.walletExtraCol}>
...@@ -66,6 +90,23 @@ class WalletBalanceExtra extends React.PureComponent<Props> { ...@@ -66,6 +90,23 @@ class WalletBalanceExtra extends React.PureComponent<Props> {
</View> </View>
</View> </View>
</View> </View>
<View style={walletStyle.syncDriverCustody}>
<Text style={walletStyle.syncInfoText}>
{deviceWalletSynced
? __('A backup of your wallet is synced with lbry.tv')
: __('Your wallet is not currently synced with lbry.tv. You are responsible for backing up your wallet.')}
</Text>
<Link
text={__('What does this mean?')}
href={
deviceWalletSynced
? 'https://lbry.com/faq/account-sync'
: 'https://lbry.com/faq/how-to-backup-wallet#android'
}
style={walletStyle.syncInfoLink}
/>
</View>
</View> </View>
); );
} }
......
import React from 'react'; import React from 'react';
import { Lbry } from 'lbry-redux'; import { Lbryio } from 'lbryinc';
import { ActivityIndicator, NativeModules, ScrollView, Text, View } from 'react-native'; import { ActivityIndicator, NativeModules, ScrollView, Text, View } from 'react-native';
import Colors from 'styles/colors'; import Colors from 'styles/colors';
import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api
...@@ -17,13 +17,14 @@ const FILTER_CLAIMED = 'claimed'; ...@@ -17,13 +17,14 @@ const FILTER_CLAIMED = 'claimed';
class RewardsPage extends React.PureComponent { class RewardsPage extends React.PureComponent {
state = { state = {
currentFilter: FILTER_AVAILABLE,
firstRewardClaimed: false,
isEmailVerified: false, isEmailVerified: false,
isIdentityVerified: false, isIdentityVerified: false,
isRewardApproved: false, isRewardApproved: false,
verifyRequestStarted: false,
revealVerification: true, revealVerification: true,
firstRewardClaimed: false, usdExchangeRate: 0,
currentFilter: FILTER_AVAILABLE, verifyRequestStarted: false,
}; };
scrollView = null; scrollView = null;
...@@ -48,6 +49,12 @@ class RewardsPage extends React.PureComponent { ...@@ -48,6 +49,12 @@ class RewardsPage extends React.PureComponent {
setPlayerVisible(); setPlayerVisible();
NativeModules.Firebase.setCurrentScreen('Rewards'); NativeModules.Firebase.setCurrentScreen('Rewards');
Lbryio.getExchangeRates().then(rates => {
if (!isNaN(rates.LBC_USD)) {
this.setState({ usdExchangeRate: rates.LBC_USD });
}
});
fetchRewards(); fetchRewards();
this.setState({ this.setState({
...@@ -158,6 +165,7 @@ class RewardsPage extends React.PureComponent { ...@@ -158,6 +165,7 @@ class RewardsPage extends React.PureComponent {
canClaim={!isNotEligible} canClaim={!isNotEligible}
reward={reward} reward={reward}
reward_type={reward.reward_type} reward_type={reward.reward_type}
usdExchangeRate={this.state.usdExchangeRate}
/> />
))} ))}
<CustomRewardCard canClaim={!isNotEligible} showVerification={this.showVerification} /> <CustomRewardCard canClaim={!isNotEligible} showVerification={this.showVerification} />
...@@ -211,7 +219,9 @@ class RewardsPage extends React.PureComponent { ...@@ -211,7 +219,9 @@ 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.isRewardApproved) && <RewardEnrolment navigation={navigation} />} {(!this.state.isEmailVerified || !this.state.isRewardApproved) && (
<RewardEnrolment usdExchangeRate={this.state.usdExchangeRate} navigation={navigation} />
)}
{this.state.isEmailVerified && this.state.isRewardApproved && ( {this.state.isEmailVerified && this.state.isRewardApproved && (
<ScrollView <ScrollView
......
...@@ -12,6 +12,7 @@ import { ...@@ -12,6 +12,7 @@ import {
selectViewMode, selectViewMode,
selectFirstRunCompleted, selectFirstRunCompleted,
selectShowSuggestedSubs, selectShowSuggestedSubs,
selectUnclaimedRewardValue,
selectUser, selectUser,
} from 'lbryinc'; } from 'lbryinc';
import { doToast, selectFetchingClaimSearch } from 'lbry-redux'; import { doToast, selectFetchingClaimSearch } from 'lbry-redux';
...@@ -33,9 +34,11 @@ const select = state => ({ ...@@ -33,9 +34,11 @@ const select = state => ({
unreadSubscriptions: selectUnreadSubscriptions(state), unreadSubscriptions: selectUnreadSubscriptions(state),
viewMode: selectViewMode(state), viewMode: selectViewMode(state),
firstRunCompleted: selectFirstRunCompleted(state), firstRunCompleted: selectFirstRunCompleted(state),
rewardsNotInterested: makeSelectClientSetting(Constants.SETTING_REWARDS_NOT_INTERESTED)(state),