Changeset View
Changeset View
Standalone View
Standalone View
web/cashtab/src/components/Tokens/Tokens.js
import React from 'react'; | import React from 'react'; | ||||
import { LoadingOutlined } from '@ant-design/icons'; | |||||
import { CashLoader } from '@components/Common/CustomIcons'; | import { CashLoader } from '@components/Common/CustomIcons'; | ||||
import { WalletContext } from '@utils/context'; | import { WalletContext } from '@utils/context'; | ||||
import { | import { fromSmallestDenomination, getWalletState } from '@utils/cashMethods'; | ||||
isValidStoredWallet, | |||||
fromSmallestDenomination, | |||||
} from '@utils/cashMethods'; | |||||
import CreateTokenForm from '@components/Tokens/CreateTokenForm'; | import CreateTokenForm from '@components/Tokens/CreateTokenForm'; | ||||
import { currency } from '@components/Common/Ticker.js'; | import { currency } from '@components/Common/Ticker.js'; | ||||
import TokenList from '@components/Wallet/TokenList'; | import TokenList from '@components/Wallet/TokenList'; | ||||
import useBCH from '@hooks/useBCH'; | import useBCH from '@hooks/useBCH'; | ||||
import { BalanceHeader } from '@components/Common/BalanceHeader'; | import { BalanceHeader } from '@components/Common/BalanceHeader'; | ||||
import { BalanceHeaderFiat } from '@components/Common/BalanceHeaderFiat'; | import { BalanceHeaderFiat } from '@components/Common/BalanceHeaderFiat'; | ||||
import { | import { ZeroBalanceHeader, AlertMsg } from '@components/Common/Atoms'; | ||||
LoadingCtn, | |||||
ZeroBalanceHeader, | |||||
AlertMsg, | |||||
} from '@components/Common/Atoms'; | |||||
const Tokens = ({ jestBCH }) => { | const Tokens = ({ jestBCH }) => { | ||||
/* | /* | ||||
Dev note | Dev note | ||||
This is the first new page created after the wallet migration to include state in storage | This is the first new page created after the wallet migration to include state in storage | ||||
As such, it will only load this type of wallet | As such, it will only load this type of wallet | ||||
If any user is still migrating at this point, this page will display a loading spinner until | If any user is still migrating at this point, this page will display a loading spinner until | ||||
their wallet has updated (ETA within 10 seconds) | their wallet has updated (ETA within 10 seconds) | ||||
Going forward, this approach will be the model for Wallet, Send, and SendToken, as the legacy | Going forward, this approach will be the model for Wallet, Send, and SendToken, as the legacy | ||||
wallet state parameters not stored in the wallet object are deprecated | wallet state parameters not stored in the wallet object are deprecated | ||||
*/ | */ | ||||
const { | const { wallet, apiError, fiatPrice, cashtabSettings } = React.useContext( | ||||
loading, | WalletContext, | ||||
wallet, | ); | ||||
apiError, | const walletState = getWalletState(wallet); | ||||
fiatPrice, | const { balances, tokens } = walletState; | ||||
cashtabSettings, | |||||
} = React.useContext(WalletContext); | |||||
// If wallet is unmigrated, do not show page until it has migrated | |||||
// An invalid wallet will be validated/populated after the next API call, ETA 10s | |||||
let validWallet = isValidStoredWallet(wallet); | |||||
// Get wallet state variables | |||||
let balances, tokens; | |||||
if (validWallet) { | |||||
balances = wallet.state.balances; | |||||
tokens = wallet.state.tokens; | |||||
} | |||||
const { getBCH, getRestUrl, createToken } = useBCH(); | const { getBCH, getRestUrl, createToken } = useBCH(); | ||||
// Support using locally installed bchjs for unit tests | // Support using locally installed bchjs for unit tests | ||||
const BCH = jestBCH ? jestBCH : getBCH(); | const BCH = jestBCH ? jestBCH : getBCH(); | ||||
return ( | return ( | ||||
<> | <> | ||||
{loading || !validWallet ? ( | |||||
<LoadingCtn> | |||||
<LoadingOutlined /> | |||||
</LoadingCtn> | |||||
) : ( | |||||
<> | |||||
{!balances.totalBalance ? ( | {!balances.totalBalance ? ( | ||||
<> | <> | ||||
<ZeroBalanceHeader> | <ZeroBalanceHeader> | ||||
You need some {currency.ticker} in your wallet | You need some {currency.ticker} in your wallet to create | ||||
to create tokens. | tokens. | ||||
</ZeroBalanceHeader> | </ZeroBalanceHeader> | ||||
<BalanceHeader | <BalanceHeader balance={0} ticker={currency.ticker} /> | ||||
balance={0} | |||||
ticker={currency.ticker} | |||||
/> | |||||
</> | </> | ||||
) : ( | ) : ( | ||||
<> | <> | ||||
<BalanceHeader | <BalanceHeader | ||||
balance={balances.totalBalance} | balance={balances.totalBalance} | ||||
ticker={currency.ticker} | ticker={currency.ticker} | ||||
/> | /> | ||||
{fiatPrice !== null && | {fiatPrice !== null && !isNaN(balances.totalBalance) && ( | ||||
!isNaN(balances.totalBalance) && ( | |||||
<BalanceHeaderFiat | <BalanceHeaderFiat | ||||
balance={balances.totalBalance} | balance={balances.totalBalance} | ||||
settings={cashtabSettings} | settings={cashtabSettings} | ||||
fiatPrice={fiatPrice} | fiatPrice={fiatPrice} | ||||
/> | /> | ||||
)} | )} | ||||
</> | </> | ||||
)} | )} | ||||
{apiError && ( | {apiError && ( | ||||
<> | <> | ||||
<p | <p | ||||
style={{ | style={{ | ||||
color: 'red', | color: 'red', | ||||
}} | }} | ||||
> | > | ||||
<b>An error occurred on our end.</b> | <b>An error occurred on our end.</b> | ||||
<br></br> Re-establishing connection... | <br></br> Re-establishing connection... | ||||
</p> | </p> | ||||
<CashLoader /> | <CashLoader /> | ||||
</> | </> | ||||
)} | )} | ||||
<CreateTokenForm | <CreateTokenForm | ||||
BCH={BCH} | BCH={BCH} | ||||
getRestUrl={getRestUrl} | getRestUrl={getRestUrl} | ||||
createToken={createToken} | createToken={createToken} | ||||
disabled={ | disabled={balances.totalBalanceInSatoshis < currency.dustSats} | ||||
balances.totalBalanceInSatoshis < currency.dustSats | |||||
} | |||||
/> | /> | ||||
{balances.totalBalanceInSatoshis < currency.dustSats && ( | {balances.totalBalanceInSatoshis < currency.dustSats && ( | ||||
<AlertMsg> | <AlertMsg> | ||||
You need at least{' '} | You need at least{' '} | ||||
{fromSmallestDenomination( | {fromSmallestDenomination(currency.dustSats).toString()}{' '} | ||||
currency.dustSats, | |||||
).toString()}{' '} | |||||
{currency.ticker} ( | {currency.ticker} ( | ||||
{cashtabSettings | {cashtabSettings | ||||
? `${ | ? `${ | ||||
currency.fiatCurrencies[ | currency.fiatCurrencies[ | ||||
cashtabSettings.fiatCurrency | cashtabSettings.fiatCurrency | ||||
].symbol | ].symbol | ||||
} ` | } ` | ||||
: '$ '} | : '$ '} | ||||
{( | {( | ||||
fromSmallestDenomination( | fromSmallestDenomination(currency.dustSats).toString() * | ||||
currency.dustSats, | fiatPrice | ||||
).toString() * fiatPrice | |||||
).toFixed(4)}{' '} | ).toFixed(4)}{' '} | ||||
{cashtabSettings | {cashtabSettings | ||||
? `${currency.fiatCurrencies[ | ? `${currency.fiatCurrencies[ | ||||
cashtabSettings.fiatCurrency | cashtabSettings.fiatCurrency | ||||
].slug.toUpperCase()} ` | ].slug.toUpperCase()} ` | ||||
: 'USD'} | : 'USD'} | ||||
) to create a token | ) to create a token | ||||
</AlertMsg> | </AlertMsg> | ||||
)} | )} | ||||
{tokens && tokens.length > 0 ? ( | {tokens && tokens.length > 0 ? ( | ||||
<> | <> | ||||
<TokenList | <TokenList tokens={tokens} /> | ||||
wallet={wallet} | |||||
tokens={tokens} | |||||
jestBCH={false} | |||||
/> | |||||
</> | </> | ||||
) : ( | ) : ( | ||||
<>No {currency.tokenTicker} tokens in this wallet</> | <>No {currency.tokenTicker} tokens in this wallet</> | ||||
)} | )} | ||||
</> | </> | ||||
)} | |||||
</> | |||||
); | ); | ||||
}; | }; | ||||
export default Tokens; | export default Tokens; |