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,140 +44,124 @@ 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> <Card
<section className="columns"> title={<LbcSymbol postfix={formatNumberWithCommas(totalBalance)} isTitle />}
<div> subtitle={
<div className="section"> <I18nMessage tokens={{ lbc: <LbcSymbol /> }}>
<Card This is your total balance. Some of the %lbc% is in use on your channels and content right now.
title={<LbcSymbol postfix={balance} isTitle />} </I18nMessage>
subtitle={__('Available Balance')} }
actions={ actions={
<> <>
<div className="section__actions--between"> <h2 className="section__title--small">
<div className="section__actions"> <I18nMessage tokens={{ lbc_amount: <CreditAmount amount={balance} precision={8} /> }}>
<Button button="primary" label={__('Buy')} icon={ICONS.BUY} navigate={`/$/${PAGES.BUY}`} /> %lbc_amount% available balance
<Button </I18nMessage>
button="secondary" </h2>
label={__('Receive')}
icon={ICONS.RECEIVE} <h2 className="section__title--small">
onClick={() => doOpenModal(MODALS.WALLET_RECEIVE)} <I18nMessage
/> tokens={{
<Button lbc_amount: <CreditAmount amount={tipsBalance + claimsBalance + supportsBalance} precision={8} />,
button="secondary" }}
label={__('Send')} >
icon={ICONS.SEND} %lbc_amount% currently in use
onClick={() => doOpenModal(MODALS.WALLET_SEND)} </I18nMessage>
/> <Button
</div> button="link"
</div> label={detailsExpanded ? __('View less') : __('View more')}
{(otherCount > WALLET_CONSOLIDATE_UTXOS || pendingUtxoConsolidating.length || consolidatingUtxos) && ( iconRight={detailsExpanded ? ICONS.UP : ICONS.DOWN}
<p className="help"> onClick={() => setDetailsExpanded(!detailsExpanded)}
<I18nMessage />
tokens={{ </h2>
now: ( {detailsExpanded && (
<Button <div className="section__subtitle">
button="link" <dl>
onClick={() => doUtxoConsolidate()} <dt>{__('... earned and bound in tips')}</dt>
disabled={pendingUtxoConsolidating.length || consolidatingUtxos} <dd>
label={ <CreditAmount amount={tipsBalance} precision={8} />
pendingUtxoConsolidating.length || consolidatingUtxos </dd>
? __('Consolidating')
: __('Consolidate Now') <dt>{__('... in your publishes')}</dt>
} <dd>
/> <CreditAmount amount={claimsBalance} precision={8} />
), </dd>
help: <HelpLink href="https://lbry.com/faq/transaction-types" />,
}} <dt>{__('... in your supports')}</dt>
> <dd>
Your wallet has a lot of change lying around. Consolidating will speed up your transactions. <CreditAmount amount={supportsBalance} precision={8} />
This could take some time. %now%%help% </dd>
</I18nMessage> </dl>
</p> </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">
<Button button="primary" label={__('Buy')} icon={ICONS.BUY} navigate={`/$/${PAGES.BUY}`} />
<Button
button="secondary"
label={__('Receive')}
icon={ICONS.RECEIVE}
onClick={() => doOpenModal(MODALS.WALLET_RECEIVE)}
/>
<Button
button="secondary"
label={__('Send')}
icon={ICONS.SEND}
onClick={() => doOpenModal(MODALS.WALLET_SEND)}
/> />
</div> </div>
</div> {(otherCount > WALLET_CONSOLIDATE_UTXOS || pendingUtxoConsolidating.length || consolidatingUtxos) && (
<p className="help">
<div> <I18nMessage
<React.Fragment> tokens={{
{/* @if TARGET='app' */} now: (
{hasSynced ? ( <Button
<div className="section"> button="link"
<div className="section__flex"> onClick={() => doUtxoConsolidate()}
<Icon sectionIcon icon={ICONS.LOCK} /> disabled={pendingUtxoConsolidating.length || consolidatingUtxos}
<h2 className="section__title--small"> label={
{__('A backup of your wallet is synced with lbry.tv.')} pendingUtxoConsolidating.length || consolidatingUtxos
<HelpLink href="https://lbry.com/faq/account-sync" /> ? __('Consolidating')
</h2> : __('Consolidate Now')
</div> }
</div> />
) : ( ),
<div className="section"> help: <HelpLink href="https://lbry.com/faq/transaction-types" />,
<div className="section__flex"> }}
<Icon sectionIcon icon={ICONS.UNLOCK} /> >
<h2 className="section__title--small"> Your wallet has a lot of change lying around. Consolidating will speed up your transactions. This could
{__( take some time. %now%%help%
'Your wallet is not currently synced with lbry.tv. You are in control of backing up your wallet.' </I18nMessage>
)} </p>
<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,7 +48,14 @@
.section__title--small { .section__title--small {
@extend .section__title; @extend .section__title;
font-size: var(--font-body); font-size: var(--font-body);
margin-top: var(--spacing-m);
.button {
margin-left: var(--spacing-s);
}
&:not(:first-of-type) {
margin-top: var(--spacing-m);
}
} }
.section__title--large { .section__title--large {

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 });
} }