show total balance on wallet page/header

This commit is contained in:
Sean Yesmunt 2021-01-12 10:25:51 -05:00
parent 2f1fae23cf
commit 5420a6a887
15 changed files with 145 additions and 148 deletions

View file

@ -502,8 +502,9 @@
"Access to these files are equivalent to having access to your Credits, channels, and publishes. Keep any copies you make of your wallet in a secure place. For more details on backing up and best practices %helpLink%.": "Access to these files are equivalent to having access to your Credits, channels, and publishes. Keep any copies you make of your wallet in a secure place. For more details on backing up and best practices %helpLink%.", "Access to these files are equivalent to having access to your Credits, channels, and publishes. Keep any copies you make of your wallet in a secure place. For more details on backing up and best practices %helpLink%.": "Access to these files are equivalent to having access to your Credits, channels, and publishes. Keep any copies you make of your wallet in a secure place. For more details on backing up and best practices %helpLink%.",
"Your channels": "Your channels", "Your channels": "Your channels",
"Add Tags": "Add Tags", "Add Tags": "Add Tags",
"Available Balance": "Available Balance", "available balance": "available balance",
"Earned and bound in tips": "Earned and bound in tips", "currently in use": "currently in use",
"... earned and bound in tips": "... earned and bound in tips",
"... in your publishes": "... in your publishes", "... in your publishes": "... in your publishes",
"... in your supports": "... in your supports", "... in your supports": "... in your supports",
"Add a tag": "Add a tag", "Add a tag": "Add a tag",
@ -582,8 +583,8 @@
"settings": "settings", "settings": "settings",
"Content may be hidden on this %type% because of your %settings%.": "Content may be hidden on this %type% because of your %settings%.", "Content may be hidden on this %type% because of your %settings%.": "Content may be hidden on this %type% because of your %settings%.",
"Sync": "Sync", "Sync": "Sync",
"earned and bound in tips": "earned and bound in tips", "%lbc_amount% earned and bound in tips": "%lbc_amount% earned and bound in tips",
"currently staked": "currently staked", "%lbc_amount% currently staked": "%lbc_amount% currently staked",
"Sync balance and preferences across devices.": "Sync balance and preferences across devices.", "Sync balance and preferences across devices.": "Sync balance and preferences across devices.",
"By creating an account, you agree to our %terms% and confirm you're over the age of 13.": "By creating an account, you agree to our %terms% and confirm you're over the age of 13.", "By creating an account, you agree to our %terms% and confirm you're over the age of 13.": "By creating an account, you agree to our %terms% and confirm you're over the age of 13.",
"Advanced Editor": "Advanced Editor", "Advanced Editor": "Advanced Editor",
@ -701,7 +702,7 @@
"Unlock Rewards": "Unlock Rewards", "Unlock Rewards": "Unlock Rewards",
"Log in to %SITE_NAME% to earn rewards": "Log in to %SITE_NAME% to earn rewards", "Log in to %SITE_NAME% to earn rewards": "Log in to %SITE_NAME% to earn rewards",
"A %site_name% account allows you to earn more than %credit_amount% in rewards, backup your data, and get content and security updates.": "A %site_name% account allows you to earn more than %credit_amount% in rewards, backup your data, and get content and security updates.", "A %site_name% account allows you to earn more than %credit_amount% in rewards, backup your data, and get content and security updates.": "A %site_name% account allows you to earn more than %credit_amount% in rewards, backup your data, and get content and security updates.",
"Deposit cannot be higher than your balance": "Deposit cannot be higher than your balance", "Deposit cannot be higher than your available balance": "Deposit cannot be higher than your available balance",
"Your deposit must be higher": "Your deposit must be higher", "Your deposit must be higher": "Your deposit must be higher",
"1 view": "1 view", "1 view": "1 view",
"%view_count% views": "%view_count% views", "%view_count% views": "%view_count% views",

View file

@ -64,7 +64,7 @@ class ChannelCreate extends React.PureComponent<Props, State> {
} else if (newChannelBid === balance) { } else if (newChannelBid === balance) {
newChannelBidError = __('Please decrease your deposit to account for transaction fees'); newChannelBidError = __('Please decrease your deposit to account for transaction fees');
} else if (newChannelBid > balance) { } else if (newChannelBid > balance) {
newChannelBidError = __('Deposit cannot be higher than your balance'); newChannelBidError = __('Deposit cannot be higher than your available balance');
} else if (newChannelBid < MINIMUM_PUBLISH_BID) { } else if (newChannelBid < MINIMUM_PUBLISH_BID) {
newChannelBidError = __('Your deposit must be higher'); newChannelBidError = __('Your deposit must be higher');
} }

View file

@ -138,7 +138,7 @@ function ChannelForm(props: Props) {
if (bid <= 0.0 || isNaN(bid)) { if (bid <= 0.0 || isNaN(bid)) {
setBidError(__('Deposit cannot be 0')); setBidError(__('Deposit cannot be 0'));
} else if (totalAvailableBidAmount < bid) { } else if (totalAvailableBidAmount < bid) {
setBidError(__('Deposit cannot be higher than your balance')); setBidError(__('Deposit cannot be higher than your available balance'));
} else if (totalAvailableBidAmount - bid < ESTIMATED_FEE) { } else if (totalAvailableBidAmount - bid < ESTIMATED_FEE) {
setBidError(__('Please decrease your deposit to account for transaction fees')); setBidError(__('Please decrease your deposit to account for transaction fees'));
} else if (bid < MINIMUM_PUBLISH_BID) { } else if (bid < MINIMUM_PUBLISH_BID) {

View file

@ -42,7 +42,7 @@ function FileReactions(props: Props) {
requiresAuth={IS_WEB} requiresAuth={IS_WEB}
authSrc="filereaction_like" authSrc="filereaction_like"
className={classnames('button--file-action')} className={classnames('button--file-action')}
label={formatNumberWithCommas(likeCount)} label={formatNumberWithCommas(likeCount, 0)}
iconSize={18} iconSize={18}
icon={ICONS.UPVOTE} icon={ICONS.UPVOTE}
onClick={() => doReactionLike(uri)} onClick={() => doReactionLike(uri)}
@ -52,7 +52,7 @@ function FileReactions(props: Props) {
authSrc={'filereaction_dislike'} authSrc={'filereaction_dislike'}
title={__('I dislike this')} title={__('I dislike this')}
className={classnames('button--file-action')} className={classnames('button--file-action')}
label={formatNumberWithCommas(dislikeCount)} label={formatNumberWithCommas(dislikeCount, 0)}
iconSize={18} iconSize={18}
icon={ICONS.DOWNVOTE} icon={ICONS.DOWNVOTE}
onClick={() => doReactionDislike(uri)} onClick={() => doReactionDislike(uri)}

View file

@ -1,6 +1,6 @@
import * as MODALS from 'constants/modal_types'; import * as MODALS from 'constants/modal_types';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { selectBalance, formatCredits, selectMyChannelClaims, SETTINGS } from 'lbry-redux'; import { selectTotalBalance, formatCredits, selectMyChannelClaims, SETTINGS } from 'lbry-redux';
import { selectGetSyncErrorMessage } from 'redux/selectors/sync'; import { selectGetSyncErrorMessage } from 'redux/selectors/sync';
import { selectUserVerifiedEmail, selectUserEmail, selectEmailToVerify, selectUser } from 'redux/selectors/user'; import { selectUserVerifiedEmail, selectUserEmail, selectEmailToVerify, selectUser } from 'redux/selectors/user';
import { doClearEmailEntry, doClearPasswordEntry } from 'redux/actions/user'; import { doClearEmailEntry, doClearPasswordEntry } from 'redux/actions/user';
@ -12,9 +12,8 @@ import Header from './view';
import { selectHasNavigated } from 'redux/selectors/app'; import { selectHasNavigated } from 'redux/selectors/app';
const select = state => ({ const select = state => ({
balance: selectBalance(state),
language: selectLanguage(state), language: selectLanguage(state),
roundedBalance: formatCredits(selectBalance(state), 2, true), roundedBalance: formatCredits(selectTotalBalance(state), 2, true),
currentTheme: makeSelectClientSetting(SETTINGS.THEME)(state), currentTheme: makeSelectClientSetting(SETTINGS.THEME)(state),
automaticDarkModeEnabled: makeSelectClientSetting(SETTINGS.AUTOMATIC_DARK_MODE_ENABLED)(state), automaticDarkModeEnabled: makeSelectClientSetting(SETTINGS.AUTOMATIC_DARK_MODE_ENABLED)(state),
hideBalance: makeSelectClientSetting(SETTINGS.HIDE_BALANCE)(state), hideBalance: makeSelectClientSetting(SETTINGS.HIDE_BALANCE)(state),

View file

@ -88,7 +88,7 @@ function PublishName(props: Props) {
} else if (bid < MINIMUM_PUBLISH_BID) { } else if (bid < MINIMUM_PUBLISH_BID) {
bidError = __('Your deposit must be higher'); bidError = __('Your deposit must be higher');
} else if (totalAvailableBidAmount < bid) { } else if (totalAvailableBidAmount < bid) {
bidError = __('Deposit cannot be higher than your balance'); bidError = __('Deposit cannot be higher than your available balance');
} else if (totalAvailableBidAmount <= bid + 0.05) { } else if (totalAvailableBidAmount <= bid + 0.05) {
bidError = __('Please decrease your deposit to account for transaction fees or acquire more LBRY Credits.'); bidError = __('Please decrease your deposit to account for transaction fees or acquire more LBRY Credits.');
} }

View file

@ -210,7 +210,7 @@ function RepostCreate(props: Props) {
} else if (balance === repostBid) { } else if (balance === repostBid) {
rBidError = __('Please decrease your deposit to account for transaction fees'); rBidError = __('Please decrease your deposit to account for transaction fees');
} else if (balance < repostBid) { } else if (balance < repostBid) {
rBidError = __('Deposit cannot be higher than your balance'); rBidError = __('Deposit cannot be higher than your available balance');
} else if (repostBid < MINIMUM_PUBLISH_BID) { } else if (repostBid < MINIMUM_PUBLISH_BID) {
rBidError = __('Your deposit must be higher'); rBidError = __('Your deposit must be higher');
} }

View file

@ -5,11 +5,11 @@ import * as PAGES from 'constants/pages';
import React from 'react'; import React from 'react';
import CreditAmount from 'component/common/credit-amount'; import CreditAmount from 'component/common/credit-amount';
import Button from 'component/button'; import Button from 'component/button';
import Icon from 'component/common/icon';
import HelpLink from 'component/common/help-link'; import HelpLink from 'component/common/help-link';
import Card from 'component/common/card'; import Card from 'component/common/card';
import LbcSymbol from 'component/common/lbc-symbol'; import LbcSymbol from 'component/common/lbc-symbol';
import I18nMessage from 'component/i18nMessage'; import I18nMessage from 'component/i18nMessage';
import { formatNumberWithCommas } from 'util/number';
type Props = { type Props = {
balance: number, balance: number,
@ -44,24 +44,82 @@ const WalletBalance = (props: Props) => {
consolidatingUtxos, consolidatingUtxos,
utxoCounts, utxoCounts,
} = props; } = props;
const [detailsExpanded, setDetailsExpanded] = React.useState(false);
const { other: otherCount = 0 } = utxoCounts || {}; const { other: otherCount = 0 } = utxoCounts || {};
const totalBalance = balance + tipsBalance + supportsBalance + claimsBalance;
React.useEffect(() => { React.useEffect(() => {
if (balance > LARGE_WALLET_BALANCE) { if (balance > LARGE_WALLET_BALANCE) {
doFetchUtxoCounts(); doFetchUtxoCounts();
} }
}, [doFetchUtxoCounts, balance]); }, [doFetchUtxoCounts, balance]);
return ( return (
<React.Fragment>
<section className="columns">
<div>
<div className="section">
<Card <Card
title={<LbcSymbol postfix={balance} isTitle />} title={<LbcSymbol postfix={formatNumberWithCommas(totalBalance)} isTitle />}
subtitle={__('Available Balance')} subtitle={
<I18nMessage tokens={{ lbc: <LbcSymbol /> }}>
This is your total balance. Some of the %lbc% is in use on your channels and content right now.
</I18nMessage>
}
actions={ actions={
<> <>
<div className="section__actions--between"> <h2 className="section__title--small">
<I18nMessage tokens={{ lbc_amount: <CreditAmount amount={balance} precision={8} /> }}>
%lbc_amount% available balance
</I18nMessage>
</h2>
<h2 className="section__title--small">
<I18nMessage
tokens={{
lbc_amount: <CreditAmount amount={tipsBalance + claimsBalance + supportsBalance} precision={8} />,
}}
>
%lbc_amount% currently in use
</I18nMessage>
<Button
button="link"
label={detailsExpanded ? __('View less') : __('View more')}
iconRight={detailsExpanded ? ICONS.UP : ICONS.DOWN}
onClick={() => setDetailsExpanded(!detailsExpanded)}
/>
</h2>
{detailsExpanded && (
<div className="section__subtitle">
<dl>
<dt>{__('... earned and bound in tips')}</dt>
<dd>
<CreditAmount amount={tipsBalance} precision={8} />
</dd>
<dt>{__('... in your publishes')}</dt>
<dd>
<CreditAmount amount={claimsBalance} precision={8} />
</dd>
<dt>{__('... in your supports')}</dt>
<dd>
<CreditAmount amount={supportsBalance} precision={8} />
</dd>
</dl>
</div>
)}
{/* @if TARGET='app' */}
{!hasSynced ? (
<p className="section help">
{__('A backup of your wallet is synced with lbry.tv.')}
<HelpLink href="https://lbry.com/faq/account-sync" />
</p>
) : (
<p className="help--warning">
{__('Your wallet is not currently synced with lbry.tv. You are in control of backing up your wallet.')}
<HelpLink navigate={`/$/${PAGES.BACKUP}`} />
</p>
)}
{/* @endif */}
<div className="section__actions"> <div className="section__actions">
<Button button="primary" label={__('Buy')} icon={ICONS.BUY} navigate={`/$/${PAGES.BUY}`} /> <Button button="primary" label={__('Buy')} icon={ICONS.BUY} navigate={`/$/${PAGES.BUY}`} />
<Button <Button
@ -77,7 +135,6 @@ const WalletBalance = (props: Props) => {
onClick={() => doOpenModal(MODALS.WALLET_SEND)} onClick={() => doOpenModal(MODALS.WALLET_SEND)}
/> />
</div> </div>
</div>
{(otherCount > WALLET_CONSOLIDATE_UTXOS || pendingUtxoConsolidating.length || consolidatingUtxos) && ( {(otherCount > WALLET_CONSOLIDATE_UTXOS || pendingUtxoConsolidating.length || consolidatingUtxos) && (
<p className="help"> <p className="help">
<I18nMessage <I18nMessage
@ -97,87 +154,14 @@ const WalletBalance = (props: Props) => {
help: <HelpLink href="https://lbry.com/faq/transaction-types" />, help: <HelpLink href="https://lbry.com/faq/transaction-types" />,
}} }}
> >
Your wallet has a lot of change lying around. Consolidating will speed up your transactions. Your wallet has a lot of change lying around. Consolidating will speed up your transactions. This could
This could take some time. %now%%help% take some time. %now%%help%
</I18nMessage> </I18nMessage>
</p> </p>
)} )}
</> </>
} }
/> />
</div>
</div>
<div>
<React.Fragment>
{/* @if TARGET='app' */}
{hasSynced ? (
<div className="section">
<div className="section__flex">
<Icon sectionIcon icon={ICONS.LOCK} />
<h2 className="section__title--small">
{__('A backup of your wallet is synced with lbry.tv.')}
<HelpLink href="https://lbry.com/faq/account-sync" />
</h2>
</div>
</div>
) : (
<div className="section">
<div className="section__flex">
<Icon sectionIcon icon={ICONS.UNLOCK} />
<h2 className="section__title--small">
{__(
'Your wallet is not currently synced with lbry.tv. You are in control of backing up your wallet.'
)}
<HelpLink navigate={`/$/${PAGES.BACKUP}`} />
</h2>
</div>
</div>
)}
{/* @endif */}
<div className="section">
<div className="section__flex">
<Icon sectionIcon icon={ICONS.SUPPORT} />
<h2 className="section__title--small">
<strong>
<CreditAmount amount={tipsBalance} precision={8} />
</strong>{' '}
{__('earned and bound in tips')}
</h2>
</div>
</div>
<div className="section">
<div className="section__flex">
<Icon sectionIcon icon={ICONS.LOCK} />
<div>
<h2 className="section__title--small">
<strong>
<CreditAmount amount={claimsBalance + supportsBalance} precision={8} />
</strong>{' '}
{__('currently staked')}
</h2>
<div className="section__subtitle">
<dl>
<dt>{__('... in your publishes')}</dt>
<dd>
<CreditAmount amount={claimsBalance} precision={8} />
</dd>
<dt>{__('... in your supports')}</dt>
<dd>
<CreditAmount amount={supportsBalance} precision={8} />
</dd>
</dl>
</div>
</div>
</div>
</div>
</React.Fragment>
</div>
</section>
</React.Fragment>
); );
}; };

View file

@ -56,7 +56,7 @@ function ModalRepost(props: Props) {
} else if (balance === repostBid) { } else if (balance === repostBid) {
repostBidError = __('Please decrease your deposit to account for transaction fees'); repostBidError = __('Please decrease your deposit to account for transaction fees');
} else if (balance < repostBid) { } else if (balance < repostBid) {
repostBidError = __('Deposit cannot be higher than your balance'); repostBidError = __('Deposit cannot be higher than your available balance');
} else if (repostBid < MINIMUM_PUBLISH_BID) { } else if (repostBid < MINIMUM_PUBLISH_BID) {
repostBidError = __('Your deposit must be higher'); repostBidError = __('Your deposit must be higher');
} }

View file

@ -31,10 +31,10 @@ const WalletPage = (props: Props) => {
{showIntro ? ( {showIntro ? (
<YrblWalletEmpty includeWalletLink /> <YrblWalletEmpty includeWalletLink />
) : ( ) : (
<> <div className="card-stack">
<WalletBalance /> <WalletBalance />
<TxoList search={search} /> <TxoList search={search} />
</> </div>
)} )}
</> </>
)} )}

View file

@ -48,8 +48,15 @@
.section__title--small { .section__title--small {
@extend .section__title; @extend .section__title;
font-size: var(--font-body); font-size: var(--font-body);
.button {
margin-left: var(--spacing-s);
}
&:not(:first-of-type) {
margin-top: var(--spacing-m); margin-top: var(--spacing-m);
} }
}
.section__title--large { .section__title--large {
@extend .section__title; @extend .section__title;

View file

@ -231,7 +231,11 @@ textarea {
.help--warning { .help--warning {
@extend .help; @extend .help;
color: var(--color-text-help-warning); padding: var(--spacing-s);
color: var(--color-black);
border-radius: var(--border-radius);
background-color: var(--color-help-warning-bg);
color: var(--color-help-warning-text);
margin-bottom: var(--spacing-s); margin-bottom: var(--spacing-s);
} }

View file

@ -63,7 +63,8 @@
// Text // Text
--color-text: #d8d8d8; --color-text: #d8d8d8;
--color-text-error: #f5748c; --color-text-error: #f5748c;
--color-text-help-warning: #f5ec74; --color-help-warning-bg: #fbbf2450;
--color-help-warning-text: white;
--color-text-empty: var(--color-text-subtitle); --color-text-empty: var(--color-text-subtitle);
--color-text-help: #bbbbbb; --color-text-help: #bbbbbb;

View file

@ -43,7 +43,8 @@
--color-text-help: #999999; --color-text-help: #999999;
--color-text-subtitle: #767676; --color-text-subtitle: #767676;
--color-text-warning: #212529; --color-text-warning: #212529;
--color-text-help-warning: #989b20; --color-help-warning-bg: #fef3c7;
--color-help-warning-text: black;
--color-text-warning--background: var(--lbry-yellow-1); --color-text-warning--background: var(--lbry-yellow-1);
--color-blockquote: var(--color-gray-3); --color-blockquote: var(--color-gray-3);
--color-blockquote-bg: var(--color-gray-1); --color-blockquote-bg: var(--color-gray-1);

View file

@ -1,5 +1,5 @@
// @flow // @flow
export function formatNumberWithCommas(num: number): string { export function formatNumberWithCommas(num: number, numberOfDigits?: number): string {
return num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ','); return num.toLocaleString('en', { minimumFractionDigits: numberOfDigits !== undefined ? numberOfDigits : 8 });
} }