diff --git a/src/component/drawerContent/index.js b/src/component/drawerContent/index.js
index b2e48fb..e4a5531 100644
--- a/src/component/drawerContent/index.js
+++ b/src/component/drawerContent/index.js
@@ -1,12 +1,14 @@
import { connect } from 'react-redux';
-import { doToast, selectMyChannelClaims } from 'lbry-redux';
-import { selectUser } from 'lbryinc';
+import { doToast, selectBalance, selectMyChannelClaims } from 'lbry-redux';
+import { selectUnclaimedRewardValue, selectUser } from 'lbryinc';
import { selectSdkReady } from 'redux/selectors/settings';
import DrawerContent from './view';
const select = state => ({
+ balance: selectBalance(state),
channels: selectMyChannelClaims(state),
sdkReady: selectSdkReady(state),
+ unclaimedRewardAmount: selectUnclaimedRewardValue(state),
user: selectUser(state),
});
diff --git a/src/component/drawerContent/view.js b/src/component/drawerContent/view.js
index 5b26c22..cf224c2 100644
--- a/src/component/drawerContent/view.js
+++ b/src/component/drawerContent/view.js
@@ -6,6 +6,8 @@ import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api
import Icon from 'react-native-vector-icons/FontAwesome5';
import channelIconStyle from 'styles/channelIcon';
import discoverStyle from 'styles/discover';
+import { Lbryio } from 'lbryinc';
+import { formatUsd } from 'utils/helper';
const groupedMenuItems = {
'Find content': [
@@ -42,6 +44,18 @@ const routesRequiringSdkReady = [
];
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 = () => {
const { channels = [] } = this.props;
if (channels) {
@@ -82,7 +96,7 @@ class DrawerContent extends React.PureComponent {
};
render() {
- const { activeTintColor, navigation, user, onItemPress } = this.props;
+ const { activeTintColor, balance, navigation, unclaimedRewardAmount, user, onItemPress } = this.props;
const { state } = navigation;
const activeItemKey = state.routes[state.index] ? state.routes[state.index].key : null;
@@ -189,6 +203,15 @@ class DrawerContent extends React.PureComponent {
{__(item.label)}
+ {item.label === 'Wallet' && this.state.usdExchangeRate > 0 && (
+ ({formatUsd(parseFloat(balance) * parseFloat(this.state.usdExchangeRate))})
+ )}
+ {item.label === 'Rewards' && this.state.usdExchangeRate > 0 && (
+
+ {' '}
+ ({formatUsd(parseFloat(unclaimedRewardAmount) * parseFloat(this.state.usdExchangeRate))})
+
+ )}
);
diff --git a/src/component/rewardCard/view.js b/src/component/rewardCard/view.js
index 87eceaa..eab3b70 100644
--- a/src/component/rewardCard/view.js
+++ b/src/component/rewardCard/view.js
@@ -1,10 +1,11 @@
// @flow
import React from 'react';
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 Link from '../link';
-import rewardStyle from '../../styles/reward';
+import Link from 'component/link';
+import rewardStyle from 'styles/reward';
type Props = {
canClaim: boolean,
@@ -61,7 +62,7 @@ class RewardCard extends React.PureComponent {
if (reward) {
const claimed = !!reward.transaction_id;
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) {
return reward.reward_amount;
}
@@ -72,7 +73,7 @@ class RewardCard extends React.PureComponent {
};
render() {
- const { canClaim, isPending, onClaimPress, reward } = this.props;
+ const { canClaim, isPending, onClaimPress, reward, usdExchangeRate } = this.props;
const claimed = !!reward.transaction_id;
return (
@@ -117,8 +118,16 @@ class RewardCard extends React.PureComponent {
)}
+ {reward.reward_range && reward.reward_range.indexOf('-') > -1 && (
+ {__('up to')}
+ )}
{this.getDisplayAmount()}
LBC
+ {usdExchangeRate > 0 && (
+
+ ≈{formatUsd(parseFloat(this.getDisplayAmount()) * parseFloat(usdExchangeRate))}
+
+ )}
);
diff --git a/src/component/rewardEnrolment/view.js b/src/component/rewardEnrolment/view.js
index a010ca9..c91e754 100644
--- a/src/component/rewardEnrolment/view.js
+++ b/src/component/rewardEnrolment/view.js
@@ -7,6 +7,7 @@ import Link from 'component/link';
import Colors from 'styles/colors';
import Icon from 'react-native-vector-icons/FontAwesome5';
import rewardStyle from 'styles/reward';
+import { formatUsd } from '../../utils/helper';
class RewardEnrolment extends React.Component {
componentDidMount() {
@@ -29,7 +30,7 @@ class RewardEnrolment extends React.Component {
};
render() {
- const { fetching, navigation, unclaimedRewardAmount, user } = this.props;
+ const { unclaimedRewardAmount, usdExchangeRate } = this.props;
return (
@@ -43,9 +44,11 @@ class RewardEnrolment extends React.Component {
- {__('LBRY credits allow you to purchase content, publish content, and influence the network.')}
+ {__('LBRY credits allow you to purchase or publish content.')}
{'\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'}
.
diff --git a/src/component/suggestedSubscriptionsGrid/view.js b/src/component/suggestedSubscriptionsGrid/view.js
index a046392..d0d1e08 100644
--- a/src/component/suggestedSubscriptionsGrid/view.js
+++ b/src/component/suggestedSubscriptionsGrid/view.js
@@ -58,7 +58,7 @@ class SuggestedSubscriptionsGrid extends React.PureComponent {
const uris = claimSearchByQuery[claimSearchKey];
if (
lastPageReached[claimSearchKey] ||
- ((uris.length > 0 && uris.length < suggestedPageSize) || uris.length >= softLimit)
+ (uris.length > 0 && uris.length < suggestedPageSize) || uris.length >= softLimit
) {
return;
}
@@ -81,7 +81,7 @@ class SuggestedSubscriptionsGrid extends React.PureComponent {
}
render() {
- const { claimSearchByQuery, suggested, inModal, navigation } = this.props;
+ const { claimSearchByQuery, inModal, navigation } = this.props;
const options = this.buildClaimSearchOptions();
const claimSearchKey = createNormalizedClaimSearchKey(options);
const claimSearchUris = claimSearchByQuery[claimSearchKey];
@@ -92,7 +92,7 @@ class SuggestedSubscriptionsGrid extends React.PureComponent {
maxToRenderPerBatch={48}
removeClippedSubviews
itemDimension={120}
- spacing={2}
+ spacing={1}
items={claimSearchUris}
style={inModal ? subscriptionsStyle.modalScrollContainer : subscriptionsStyle.scrollContainer}
contentContainerStyle={
diff --git a/src/component/walletBalance/index.js b/src/component/walletBalance/index.js
index 6e136f1..9f69e65 100644
--- a/src/component/walletBalance/index.js
+++ b/src/component/walletBalance/index.js
@@ -6,7 +6,4 @@ const select = state => ({
balance: selectBalance(state),
});
-export default connect(
- select,
- null
-)(WalletBalance);
+export default connect(select, null)(WalletBalance);
diff --git a/src/component/walletBalance/view.js b/src/component/walletBalance/view.js
index 3ef9bf0..f620e9a 100644
--- a/src/component/walletBalance/view.js
+++ b/src/component/walletBalance/view.js
@@ -1,9 +1,9 @@
// @flow
import React from 'react';
import { Image, Text, View } from 'react-native';
-import { Lbry, formatCredits } from 'lbry-redux';
-import Address from 'component/address';
-import Button from 'component/button';
+import { formatCredits } from 'lbry-redux';
+import { Lbryio } from 'lbryinc';
+import { formatUsd } from 'utils/helper';
import walletStyle from 'styles/wallet';
type Props = {
@@ -11,6 +11,18 @@ type Props = {
};
class WalletBalance extends React.PureComponent {
+ state = {
+ usdExchangeRate: 0,
+ };
+
+ componentDidMount() {
+ Lbryio.getExchangeRates().then(rates => {
+ if (!isNaN(rates.LBC_USD)) {
+ this.setState({ usdExchangeRate: rates.LBC_USD });
+ }
+ });
+ }
+
render() {
const { balance } = this.props;
return (
@@ -21,6 +33,13 @@ class WalletBalance extends React.PureComponent {
{(balance || balance === 0) && formatCredits(parseFloat(balance), 2) + ' LBC'}
+
+ {this.state.usdExchangeRate > 0 && (
+
+ ≈{formatUsd(isNaN(balance) ? 0 : parseFloat(balance) * parseFloat(this.state.usdExchangeRate))}
+
+ )}
+
);
}
diff --git a/src/component/walletBalanceExtra/view.js b/src/component/walletBalanceExtra/view.js
index 564ef90..7ee9fda 100644
--- a/src/component/walletBalanceExtra/view.js
+++ b/src/component/walletBalanceExtra/view.js
@@ -1,9 +1,9 @@
// @flow
import React from 'react';
-import { Image, Text, View } from 'react-native';
-import { Lbry, formatCredits } from 'lbry-redux';
-import Address from 'component/address';
-import Button from 'component/button';
+import { Text, View } from 'react-native';
+import { formatCredits } from 'lbry-redux';
+import { Lbryio } from 'lbryinc';
+import { formatUsd } from 'utils/helper';
import Colors from 'styles/colors';
import Icon from 'react-native-vector-icons/FontAwesome5';
import Link from 'component/link';
@@ -16,25 +16,37 @@ type Props = {
};
class WalletBalanceExtra extends React.PureComponent {
+ state = {
+ usdExchangeRate: 0,
+ };
+
+ componentDidMount() {
+ Lbryio.getExchangeRates().then(rates => {
+ if (!isNaN(rates.LBC_USD)) {
+ this.setState({ usdExchangeRate: rates.LBC_USD });
+ }
+ });
+ }
+
render() {
const { claimsBalance, deviceWalletSynced, supportsBalance, tipsBalance } = this.props;
return (
-
-
- {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.')}
+
+
+ You can convert your credits to USD and withdraw the converted amount using an exchange.{' '}
+
+ .
@@ -47,7 +59,18 @@ class WalletBalanceExtra extends React.PureComponent {
{formatCredits(parseFloat(tipsBalance), 2)}
LBC
+
+ ≈{formatUsd(parseFloat(tipsBalance) * parseFloat(this.state.usdExchangeRate))}
+
{__('in tips')}
+
+ {
+ // navigation.navigate({ })
+ }}
+ text={__('Earn more tips by uploading cool videos')}
+ />
@@ -66,6 +89,23 @@ class WalletBalanceExtra extends React.PureComponent {
+
+
+
+ {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.')}
+
+
+
);
}
diff --git a/src/page/rewards/view.js b/src/page/rewards/view.js
index 7bad9ac..4edec91 100644
--- a/src/page/rewards/view.js
+++ b/src/page/rewards/view.js
@@ -1,5 +1,5 @@
import React from 'react';
-import { Lbry } from 'lbry-redux';
+import { Lbryio } from 'lbryinc';
import { ActivityIndicator, NativeModules, ScrollView, Text, View } from 'react-native';
import Colors from 'styles/colors';
import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api
@@ -17,13 +17,14 @@ const FILTER_CLAIMED = 'claimed';
class RewardsPage extends React.PureComponent {
state = {
+ currentFilter: FILTER_AVAILABLE,
+ firstRewardClaimed: false,
isEmailVerified: false,
isIdentityVerified: false,
isRewardApproved: false,
- verifyRequestStarted: false,
revealVerification: true,
- firstRewardClaimed: false,
- currentFilter: FILTER_AVAILABLE,
+ usdExchangeRate: 0,
+ verifyRequestStarted: false,
};
scrollView = null;
@@ -48,6 +49,12 @@ class RewardsPage extends React.PureComponent {
setPlayerVisible();
NativeModules.Firebase.setCurrentScreen('Rewards');
+ Lbryio.getExchangeRates().then(rates => {
+ if (!isNaN(rates.LBC_USD)) {
+ this.setState({ usdExchangeRate: rates.LBC_USD });
+ }
+ });
+
fetchRewards();
this.setState({
@@ -158,6 +165,7 @@ class RewardsPage extends React.PureComponent {
canClaim={!isNotEligible}
reward={reward}
reward_type={reward.reward_type}
+ usdExchangeRate={this.state.usdExchangeRate}
/>
))}
@@ -211,7 +219,9 @@ class RewardsPage extends React.PureComponent {
return (
- {(!this.state.isEmailVerified || !this.state.isRewardApproved) && }
+ {(!this.state.isEmailVerified || !this.state.isRewardApproved) && (
+
+ )}
{this.state.isEmailVerified && this.state.isRewardApproved && (
({
showSuggestedSubs: selectShowSuggestedSubs(state),
timeItem: selectTimeItem(state),
sdkReady: selectSdkReady(state),
+ unclaimedRewardAmount: selectUnclaimedRewardValue(state),
user: selectUser(state),
});
diff --git a/src/page/subscriptions/view.js b/src/page/subscriptions/view.js
index f087914..dd6e88f 100644
--- a/src/page/subscriptions/view.js
+++ b/src/page/subscriptions/view.js
@@ -11,7 +11,7 @@ import {
View,
} from 'react-native';
import { buildURI, parseURI } from 'lbry-redux';
-import { getOrderBy } from 'utils/helper';
+import { formatUsd, getOrderBy } from 'utils/helper';
import AsyncStorage from '@react-native-community/async-storage';
import moment from 'moment';
import Button from 'component/button';
@@ -31,17 +31,21 @@ import SuggestedSubscriptions from 'component/suggestedSubscriptions';
import SuggestedSubscriptionsGrid from 'component/suggestedSubscriptionsGrid';
import UriBar from 'component/uriBar';
import SdkLoadingStatus from 'component/sdkLoadingStatus';
+import Snackbar from 'react-native-snackbar';
+import { Lbryio } from 'lbryinc';
class SubscriptionsPage extends React.PureComponent {
state = {
+ currentSortByItem: Constants.CLAIM_SEARCH_SORT_BY_ITEMS[1], // should always default to sorting subscriptions by new
+ filteredChannels: [],
+ orderBy: ['release_time'],
+ showRewardsNag: true,
showingSuggestedSubs: false,
showSortPicker: false,
showTimePicker: false,
showModalSuggestedSubs: false,
+ usdExchangeRate: 0,
userEmailVerified: false,
- orderBy: ['release_time'],
- filteredChannels: [],
- currentSortByItem: Constants.CLAIM_SEARCH_SORT_BY_ITEMS[1], // should always default to sorting subscriptions by new
};
didFocusListener;
@@ -58,15 +62,25 @@ class SubscriptionsPage extends React.PureComponent {
}
onComponentFocused = () => {
- const { currentRoute, doFetchMySubscriptions, pushDrawerStack, setPlayerVisible, user } = this.props;
+ const { currentRoute, doFetchMySubscriptions, pushDrawerStack, sdkReady, setPlayerVisible, user } = this.props;
if (currentRoute === Constants.DRAWER_ROUTE_SUBSCRIPTIONS) {
pushDrawerStack();
}
setPlayerVisible();
NativeModules.Firebase.setCurrentScreen('Subscriptions');
- this.setState({ userEmailVerified: user && user.has_verified_email });
+ Lbryio.getExchangeRates().then(rates => {
+ if (!isNaN(rates.LBC_USD)) {
+ this.setState({ usdExchangeRate: rates.LBC_USD }, () => {
+ if (sdkReady) {
+ this.showRewardsAvailable();
+ }
+ });
+ }
+ });
+
+ this.setState({ userEmailVerified: user && user.has_verified_email });
doFetchMySubscriptions();
};
@@ -75,7 +89,7 @@ class SubscriptionsPage extends React.PureComponent {
}
componentWillReceiveProps(nextProps) {
- const { currentRoute, user } = nextProps;
+ const { currentRoute, user, sdkReady } = nextProps;
const { currentRoute: prevRoute, doFetchMySubscriptions } = this.props;
if (Constants.DRAWER_ROUTE_SUBSCRIPTIONS === currentRoute && currentRoute !== prevRoute) {
this.onComponentFocused();
@@ -88,9 +102,32 @@ class SubscriptionsPage extends React.PureComponent {
});
}
+ if (sdkReady && this.state.showRewardsNag && user && !user.is_reward_approved) {
+ this.showRewardsAvailable();
+ }
+
this.unsubscribeShortChannelUrls();
}
+ showRewardsAvailable = () => {
+ const { navigation, unclaimedRewardAmount } = this.props;
+ this.setState({ showRewardsNag: false }, () => {
+ Snackbar.show({
+ title: __('Did you know that you can earn free credits worth up to %amount%?', {
+ amount: formatUsd(parseFloat(this.state.usdExchangeRate) * parseFloat(unclaimedRewardAmount)),
+ }),
+ duration: Snackbar.LENGTH_LONG,
+ action: {
+ title: __('SHOW ME'),
+ color: Colors.LbryGreen,
+ onPress: () => {
+ navigation.navigate({ routeName: Constants.DRAWER_ROUTE_REWARDS });
+ },
+ },
+ });
+ });
+ };
+
handleSortByItemSelected = item => {
this.setState({ currentSortByItem: item, orderBy: getOrderBy(item), showSortPicker: false });
};
diff --git a/src/styles/reward.js b/src/styles/reward.js
index f4b1178..aa5d603 100644
--- a/src/styles/reward.js
+++ b/src/styles/reward.js
@@ -147,6 +147,10 @@ const rewardStyle = StyleSheet.create({
width: '18%',
alignItems: 'center',
},
+ rightColHeader: {
+ fontFamily: 'Inter-Regular',
+ fontSize: 12,
+ },
rewardAmount: {
fontFamily: 'Inter-Regular',
fontSize: 26,
@@ -154,6 +158,7 @@ const rewardStyle = StyleSheet.create({
},
rewardCurrency: {
fontFamily: 'Inter-Regular',
+ fontSize: 12,
},
rewardTitle: {
fontFamily: 'Inter-Regular',
@@ -322,6 +327,12 @@ const rewardStyle = StyleSheet.create({
activeFilterLink: {
fontFamily: 'Inter-SemiBold',
},
+ rewardUsd: {
+ fontFamily: 'Inter-Regular',
+ fontSize: 12,
+ color: Colors.DescriptionGrey,
+ marginTop: 6,
+ },
});
export default rewardStyle;
diff --git a/src/styles/subscriptions.js b/src/styles/subscriptions.js
index 2a3a47d..5c03cc2 100644
--- a/src/styles/subscriptions.js
+++ b/src/styles/subscriptions.js
@@ -192,8 +192,6 @@ const subscriptionsStyle = StyleSheet.create({
suggestedItem: {
alignItems: 'center',
marginBottom: 16,
- marginLeft: 16,
- marginRight: 16,
height: 140,
},
suggestedItemThumbnailContainer: {
@@ -209,8 +207,8 @@ const subscriptionsStyle = StyleSheet.create({
height: '100%',
},
suggestedItemDetails: {
- marginLeft: 16,
- marginRight: 16,
+ marginLeft: 8,
+ marginRight: 8,
alignItems: 'center',
},
suggestedItemSubscribe: {
@@ -229,7 +227,7 @@ const subscriptionsStyle = StyleSheet.create({
suggestedItemTitle: {
fontFamily: 'Inter-Regular',
textAlign: 'center',
- fontSize: 14,
+ fontSize: 13,
marginTop: 4,
marginBottom: 2,
},
diff --git a/src/styles/tag.js b/src/styles/tag.js
index e028410..15bee52 100644
--- a/src/styles/tag.js
+++ b/src/styles/tag.js
@@ -23,7 +23,7 @@ const tagStyle = StyleSheet.create({
},
text: {
fontFamily: 'Inter-Regular',
- fontSize: 14,
+ fontSize: 12,
marginRight: 8,
},
tagResultsList: {
diff --git a/src/styles/wallet.js b/src/styles/wallet.js
index 63bc0c7..a2fef03 100644
--- a/src/styles/wallet.js
+++ b/src/styles/wallet.js
@@ -137,6 +137,13 @@ const walletStyle = StyleSheet.create({
fontFamily: 'Inter-Bold',
fontSize: 36,
marginLeft: 16,
+ },
+ usdBalance: {
+ color: Colors.White,
+ fontFamily: 'Inter-Regular',
+ fontSize: 20,
+ marginLeft: 16,
+ marginTop: 2,
marginBottom: 16,
},
balanceFocus: {
@@ -402,6 +409,11 @@ const walletStyle = StyleSheet.create({
fontFamily: 'Inter-SemiBold',
fontSize: 28,
},
+ usdWalletExtraBalance: {
+ fontFamily: 'Inter-Regular',
+ fontSize: 16,
+ color: Colors.DescriptionGrey,
+ },
balanceRow: {
flexDirection: 'row',
alignItems: 'center',
@@ -424,6 +436,33 @@ const walletStyle = StyleSheet.create({
left: 0,
top: 0,
},
+ usdInfoCard: {
+ backgroundColor: Colors.White,
+ padding: 16,
+ borderBottomColor: Colors.VeryLightGrey,
+ borderBottomWidth: 1,
+ },
+ usdInfoText: {
+ fontFamily: 'Inter-Regular',
+ fontSize: 14,
+ marginBottom: 8,
+ },
+ usdConvertLink: {
+ fontFamily: 'Inter-Regular',
+ fontSize: 16,
+ color: Colors.LbryGreen,
+ },
+ usdConvertFaqLink: {
+ fontFamily: 'Inter-Regular',
+ fontSize: 14,
+ color: Colors.LbryGreen,
+ },
+ earnTipsLink: {
+ fontFamily: 'Inter-Regular',
+ fontSize: 14,
+ color: Colors.LbryGreen,
+ marginTop: 12,
+ },
});
export default walletStyle;
diff --git a/src/utils/helper.js b/src/utils/helper.js
index 756826c..66d2e2a 100644
--- a/src/utils/helper.js
+++ b/src/utils/helper.js
@@ -436,3 +436,10 @@ export function fetchReferralCode(successCallback, errorCallback) {
export function decode(value) {
return decodeURIComponent(value).replace(/\+/g, ' ');
}
+
+export function formatUsd(value) {
+ if (isNaN(parseFloat(value))) {
+ value = 0;
+ }
+ return '$' + parseFloat(value).toFixed(2);
+}