diff --git a/web/cashtab/extension/src/components/App.js b/web/cashtab/extension/src/components/App.js index f15e27ca6..342811698 100644 --- a/web/cashtab/extension/src/components/App.js +++ b/web/cashtab/extension/src/components/App.js @@ -1,316 +1,316 @@ import React, { useState } from 'react'; import 'antd/dist/antd.less'; import { Spin } from 'antd'; import { CashLoadingIcon } from '@components/Common/CustomIcons'; import '../index.css'; import styled, { ThemeProvider, createGlobalStyle } from 'styled-components'; import { theme } from '@assets/styles/theme'; import { FolderOpenFilled, CaretRightOutlined, SettingFilled, AppstoreAddOutlined, } from '@ant-design/icons'; import Wallet from '@components/Wallet/Wallet'; import Tokens from '@components/Tokens/Tokens'; import Send from '@components/Send/Send'; import SendToken from '@components/Send/SendToken'; import Configure from '@components/Configure/Configure'; import NotFound from '@components/NotFound'; import CashTab from '@assets/cashtab_xec.png'; import './App.css'; import { WalletContext } from '@utils/context'; import { isValidStoredWallet } from '@utils/cashMethods'; import WalletLabel from '@components/Common/WalletLabel.js'; import { Route, Redirect, Switch, useLocation, useHistory, } from 'react-router-dom'; // Extension-only import used for open in new tab link import PopOut from '@assets/popout.svg'; const GlobalStyle = createGlobalStyle` .ant-modal-wrap > div > div.ant-modal-content > div > div > div.ant-modal-confirm-btns > button, .ant-modal > button, .ant-modal-confirm-btns > button, .ant-modal-footer > button { border-radius: 8px; background-color: ${props => props.theme.modals.buttons.background}; color: ${props => props.theme.wallet.text.secondary}; font-weight: bold; } .ant-modal-wrap > div > div.ant-modal-content > div > div > div.ant-modal-confirm-btns > button:hover,.ant-modal-confirm-btns > button:hover, .ant-modal-footer > button:hover { color: ${props => props.theme.primary}; transition: color 0.3s; background-color: ${props => props.theme.modals.buttons.background}; } .selectedCurrencyOption { text-align: left; color: ${props => props.theme.wallet.text.secondary} !important; background-color: ${props => props.theme.contrast} !important; } .cashLoadingIcon { color: ${props => props.theme.primary} !important font-size: 48px !important; } .selectedCurrencyOption:hover { color: ${props => props.theme.contrast} !important; background-color: ${props => props.theme.primary} !important; } #addrSwitch { .ant-switch-checked { background-color: white !important; } } #addrSwitch.ant-switch-checked { background-image: ${props => props.theme.buttons.primary.backgroundImage} !important; } `; const CustomApp = styled.div` text-align: center; font-family: 'Gilroy', sans-serif; background-color: ${props => props.theme.app.background}; `; const Footer = styled.div` z-index: 2; background-color: ${props => props.theme.footer.background}; border-radius: 20px; position: fixed; bottom: 0; width: 500px; @media (max-width: 768px) { width: 100%; } border-top: 1px solid ${props => props.theme.wallet.borders.color}; `; export const NavButton = styled.button` :focus, :active { outline: none; } cursor: pointer; padding: 24px 12px 12px 12px; margin: 0 28px; @media (max-width: 475px) { margin: 0 20px; } @media (max-width: 420px) { margin: 0 12px; } @media (max-width: 350px) { margin: 0 8px; } background-color: ${props => props.theme.footer.background}; border: none; font-size: 12px; font-weight: bold; .anticon { display: block; color: ${props => props.theme.footer.navIconInactive}; font-size: 24px; margin-bottom: 6px; } ${({ active, ...props }) => active && ` color: ${props.theme.primary}; .anticon { color: ${props.theme.primary}; } `} `; export const WalletBody = styled.div` display: flex; align-items: center; justify-content: center; width: 100%; min-height: 100vh; background-image: ${props => props.theme.app.sidebars}; background-attachment: fixed; `; export const WalletCtn = styled.div` position: relative; width: 500px; background-color: ${props => props.theme.footerBackground}; min-height: 100vh; padding: 10px 30px 120px 30px; background: ${props => props.theme.wallet.background}; -webkit-box-shadow: 0px 0px 24px 1px ${props => props.theme.wallet.shadow}; -moz-box-shadow: 0px 0px 24px 1px ${props => props.theme.wallet.shadow}; box-shadow: 0px 0px 24px 1px ${props => props.theme.wallet.shadow}; @media (max-width: 768px) { width: 100%; -webkit-box-shadow: none; -moz-box-shadow: none; box-shadow: none; } `; export const HeaderCtn = styled.div` display: flex; align-items: center; justify-content: center; width: 100%; padding: 20px 0 30px; margin-bottom: 20px; justify-content: space-between; border-bottom: 1px solid ${props => props.theme.wallet.borders.color}; a { color: ${props => props.theme.wallet.text.secondary}; :hover { color: ${props => props.theme.primary}; } } @media (max-width: 768px) { a { font-size: 12px; } padding: 10px 0 20px; } `; export const CashTabLogo = styled.img` width: 120px; @media (max-width: 768px) { width: 110px; } `; // Extension only styled components const OpenInTabBtn = styled.button` background: none; border: none; `; const ExtTabImg = styled.img` max-width: 20px; `; const App = () => { const ContextValue = React.useContext(WalletContext); const { wallet, loading } = ContextValue; const [loadingUtxosAfterSend, setLoadingUtxosAfterSend] = useState(false); // 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 const validWallet = isValidStoredWallet(wallet); const location = useLocation(); const history = useHistory(); const selectedKey = location && location.pathname ? location.pathname.substr(1) : ''; // openInTab is an extension-only method const openInTab = () => { window.open(`index.html#/${selectedKey}`); }; return ( {/*Begin extension-only components*/} openInTab()} > {/*End extension-only components*/} ( )} /> {wallet ? ( ) : null} ); }; export default App; diff --git a/web/cashtab/src/components/App.js b/web/cashtab/src/components/App.js index acac127eb..38746a88a 100644 --- a/web/cashtab/src/components/App.js +++ b/web/cashtab/src/components/App.js @@ -1,381 +1,381 @@ import React, { useState, useEffect } from 'react'; import 'antd/dist/antd.less'; import { Modal, Spin } from 'antd'; import { CashLoadingIcon } from '@components/Common/CustomIcons'; import '../index.css'; import styled, { ThemeProvider, createGlobalStyle } from 'styled-components'; import { theme } from '@assets/styles/theme'; import { FolderOpenFilled, CaretRightOutlined, SettingFilled, AppstoreAddOutlined, } from '@ant-design/icons'; import Wallet from '@components/Wallet/Wallet'; import Tokens from '@components/Tokens/Tokens'; import Send from '@components/Send/Send'; import SendToken from '@components/Send/SendToken'; import Configure from '@components/Configure/Configure'; import NotFound from '@components/NotFound'; import CashTab from '@assets/cashtab_xec.png'; import './App.css'; import { WalletContext } from '@utils/context'; import { isValidStoredWallet } from '@utils/cashMethods'; import WalletLabel from '@components/Common/WalletLabel.js'; import { Route, Redirect, Switch, useLocation, useHistory, } from 'react-router-dom'; // Easter egg imports not used in extension/src/components/App.js import TabCash from '@assets/tabcash.png'; import ABC from '@assets/logo_topright.png'; import { checkForTokenById } from '@utils/tokenMethods.js'; import { currency } from './Common/Ticker'; const GlobalStyle = createGlobalStyle` .ant-modal-wrap > div > div.ant-modal-content > div > div > div.ant-modal-confirm-btns > button, .ant-modal > button, .ant-modal-confirm-btns > button, .ant-modal-footer > button { border-radius: 8px; background-color: ${props => props.theme.modals.buttons.background}; color: ${props => props.theme.wallet.text.secondary}; font-weight: bold; } .ant-modal-wrap > div > div.ant-modal-content > div > div > div.ant-modal-confirm-btns > button:hover,.ant-modal-confirm-btns > button:hover, .ant-modal-footer > button:hover { color: ${props => props.theme.primary}; transition: color 0.3s; background-color: ${props => props.theme.modals.buttons.background}; } .selectedCurrencyOption { text-align: left; color: ${props => props.theme.wallet.text.secondary} !important; background-color: ${props => props.theme.contrast} !important; } .cashLoadingIcon { color: ${props => props.theme.primary} !important font-size: 48px !important; } .selectedCurrencyOption:hover { color: ${props => props.theme.contrast} !important; background-color: ${props => props.theme.primary} !important; } #addrSwitch { .ant-switch-checked { background-color: white !important; } } #addrSwitch.ant-switch-checked { background-image: ${props => props.theme.buttons.primary.backgroundImage} !important; } `; const CustomApp = styled.div` text-align: center; font-family: 'Gilroy', sans-serif; background-color: ${props => props.theme.app.background}; `; const Footer = styled.div` z-index: 2; background-color: ${props => props.theme.footer.background}; border-radius: 20px; position: fixed; bottom: 0; width: 500px; @media (max-width: 768px) { width: 100%; } border-top: 1px solid ${props => props.theme.wallet.borders.color}; `; export const NavButton = styled.button` :focus, :active { outline: none; } cursor: pointer; padding: 24px 12px 12px 12px; margin: 0 28px; @media (max-width: 475px) { margin: 0 20px; } @media (max-width: 420px) { margin: 0 12px; } @media (max-width: 350px) { margin: 0 8px; } background-color: ${props => props.theme.footer.background}; border: none; font-size: 12px; font-weight: bold; .anticon { display: block; color: ${props => props.theme.footer.navIconInactive}; font-size: 24px; margin-bottom: 6px; } ${({ active, ...props }) => active && ` color: ${props.theme.primary}; .anticon { color: ${props.theme.primary}; } `} `; export const WalletBody = styled.div` display: flex; align-items: center; justify-content: center; width: 100%; min-height: 100vh; background-image: ${props => props.theme.app.sidebars}; background-attachment: fixed; `; export const WalletCtn = styled.div` position: relative; width: 500px; background-color: ${props => props.theme.footerBackground}; min-height: 100vh; padding: 10px 30px 120px 30px; background: ${props => props.theme.wallet.background}; -webkit-box-shadow: 0px 0px 24px 1px ${props => props.theme.wallet.shadow}; -moz-box-shadow: 0px 0px 24px 1px ${props => props.theme.wallet.shadow}; box-shadow: 0px 0px 24px 1px ${props => props.theme.wallet.shadow}; @media (max-width: 768px) { width: 100%; -webkit-box-shadow: none; -moz-box-shadow: none; box-shadow: none; } `; export const HeaderCtn = styled.div` display: flex; align-items: center; justify-content: center; width: 100%; padding: 20px 0 30px; margin-bottom: 20px; justify-content: space-between; border-bottom: 1px solid ${props => props.theme.wallet.borders.color}; a { color: ${props => props.theme.wallet.text.secondary}; :hover { color: ${props => props.theme.primary}; } } @media (max-width: 768px) { a { font-size: 12px; } padding: 10px 0 20px; } `; export const CashTabLogo = styled.img` width: 120px; @media (max-width: 768px) { width: 110px; } `; // AbcLogo styled component not included in extension, replaced by open in new tab link export const AbcLogo = styled.img` width: 150px; @media (max-width: 768px) { width: 120px; } `; // Easter egg styled component not used in extension/src/components/App.js export const EasterEgg = styled.img` position: fixed; bottom: -195px; margin: 0; right: 10%; transition-property: bottom; transition-duration: 1.5s; transition-timing-function: ease-out; :hover { bottom: 0; } @media screen and (max-width: 1250px) { display: none; } `; const App = () => { const ContextValue = React.useContext(WalletContext); const { wallet, loading } = ContextValue; const [loadingUtxosAfterSend, setLoadingUtxosAfterSend] = useState(false); // 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 const validWallet = isValidStoredWallet(wallet); const location = useLocation(); const history = useHistory(); const selectedKey = location && location.pathname ? location.pathname.substr(1) : ''; // Easter egg boolean not used in extension/src/components/App.js const hasTab = validWallet ? checkForTokenById( wallet.state.tokens, '50d8292c6255cda7afc6c8566fed3cf42a2794e9619740fe8f4c95431271410e', ) : false; useEffect(() => { // If URL is not as specified in currency.appURL in Ticker.js, show a popup const currentUrl = window.location.hostname; if (currentUrl !== currency.appUrl) { console.log( `Loaded URL ${currentUrl} does not match app URL ${currency.appUrl}!`, ); Modal.warning({ title: 'Cashtab is moving!', content: (

Cashtab is moving to a new home at{' '} Cashtab.com

Please write down your wallet 12-word seed and import it at the new domain.

At the end of the month, cashtabapp.com will auto-fwd to cashtab.com after one minute.

), }); } }, []); return ( {/*Begin component not included in extension as desktop only*/} {hasTab && ( )} {/*End component not included in extension as desktop only*/} {/*Begin component not included in extension as replaced by open in tab link*/} {/*Begin component not included in extension as replaced by open in tab link*/} ( )} /> {wallet ? ( ) : null} ); }; export default App; diff --git a/web/cashtab/src/components/Tokens/CreateTokenForm.js b/web/cashtab/src/components/Tokens/CreateTokenForm.js index 36bf36a5c..15ffb1e79 100644 --- a/web/cashtab/src/components/Tokens/CreateTokenForm.js +++ b/web/cashtab/src/components/Tokens/CreateTokenForm.js @@ -1,385 +1,385 @@ import React, { useState } from 'react'; import PropTypes from 'prop-types'; import { AntdFormWrapper } from '@components/Common/EnhancedInputs'; import { TokenCollapse } from '@components/Common/StyledCollapse'; import { currency } from '@components/Common/Ticker.js'; import { WalletContext } from '@utils/context'; import { isValidTokenName, isValidTokenTicker, isValidTokenDecimals, isValidTokenInitialQty, isValidTokenDocumentUrl, } from '@utils/validation'; import { PlusSquareOutlined } from '@ant-design/icons'; import { SmartButton } from '@components/Common/PrimaryButton'; import { Collapse, Form, Input, Modal, notification } from 'antd'; const { Panel } = Collapse; import Paragraph from 'antd/lib/typography/Paragraph'; import { TokenParamLabel } from '@components/Common/Atoms'; import { TokenReceivedNotificationIcon } from '@components/Common/CustomIcons'; const CreateTokenForm = ({ BCH, getRestUrl, createToken, disabled, passLoadingStatus, }) => { const { wallet } = React.useContext(WalletContext); // New Token Name const [newTokenName, setNewTokenName] = useState(''); const [newTokenNameIsValid, setNewTokenNameIsValid] = useState(null); const handleNewTokenNameInput = e => { const { value } = e.target; // validation setNewTokenNameIsValid(isValidTokenName(value)); setNewTokenName(value); }; // New Token Ticker const [newTokenTicker, setNewTokenTicker] = useState(''); const [newTokenTickerIsValid, setNewTokenTickerIsValid] = useState(null); const handleNewTokenTickerInput = e => { const { value } = e.target; // validation setNewTokenTickerIsValid(isValidTokenTicker(value)); setNewTokenTicker(value); }; // New Token Decimals const [newTokenDecimals, setNewTokenDecimals] = useState(0); const [newTokenDecimalsIsValid, setNewTokenDecimalsIsValid] = useState(true); const handleNewTokenDecimalsInput = e => { const { value } = e.target; // validation setNewTokenDecimalsIsValid(isValidTokenDecimals(value)); // Also validate the supply here if it has not yet been set if (newTokenInitialQtyIsValid !== null) { setNewTokenInitialQtyIsValid( isValidTokenInitialQty(value, newTokenDecimals), ); } setNewTokenDecimals(value); }; // New Token Initial Quantity const [newTokenInitialQty, setNewTokenInitialQty] = useState(''); const [newTokenInitialQtyIsValid, setNewTokenInitialQtyIsValid] = useState(null); const handleNewTokenInitialQtyInput = e => { const { value } = e.target; // validation setNewTokenInitialQtyIsValid( isValidTokenInitialQty(value, newTokenDecimals), ); setNewTokenInitialQty(value); }; // New Token document URL const [newTokenDocumentUrl, setNewTokenDocumentUrl] = useState(''); // Start with this as true, field is not required const [newTokenDocumentUrlIsValid, setNewTokenDocumentUrlIsValid] = useState(true); const handleNewTokenDocumentUrlInput = e => { const { value } = e.target; // validation setNewTokenDocumentUrlIsValid(isValidTokenDocumentUrl(value)); setNewTokenDocumentUrl(value); }; // New Token fixed supply // Only allow creation of fixed supply tokens until Minting support is added // New Token document hash // Do not include this; questionable value to casual users and requires significant complication // Only enable CreateToken button if all form entries are valid let tokenGenesisDataIsValid = newTokenNameIsValid && newTokenTickerIsValid && newTokenDecimalsIsValid && newTokenInitialQtyIsValid && newTokenDocumentUrlIsValid; // Modal settings const [showConfirmCreateToken, setShowConfirmCreateToken] = useState(false); const createPreviewedToken = async () => { passLoadingStatus(true); // If data is for some reason not valid here, bail out if (!tokenGenesisDataIsValid) { return; } // data must be valid and user reviewed to get here const configObj = { name: newTokenName, ticker: newTokenTicker, documentUrl: newTokenDocumentUrl === '' ? 'https://cashtabapp.com/' : newTokenDocumentUrl, decimals: newTokenDecimals, initialQty: newTokenInitialQty, documentHash: '', }; // create token with data in state fields try { const link = await createToken( BCH, wallet, currency.defaultFee, configObj, ); notification.success({ message: 'Success', description: ( Token created! Click to view in block explorer. ), icon: , style: { width: '100%' }, }); } catch (e) { // Set loading to false here as well, as balance may not change depending on where error occured in try loop passLoadingStatus(false); let message; if (!e.error && !e.message) { message = `Transaction failed: no response from ${getRestUrl()}.`; } else if ( /Could not communicate with full node or other external service/.test( e.error, ) ) { message = 'Could not communicate with API. Please try again.'; } else if ( e.error && e.error.includes( 'too-long-mempool-chain, too many unconfirmed ancestors [limit: 50] (code 64)', ) ) { message = `The ${currency.ticker} you are trying to send has too many unconfirmed ancestors to send (limit 50). Sending will be possible after a block confirmation. Try again in about 10 minutes.`; } else { message = e.message || e.error || JSON.stringify(e); } notification.error({ message: 'Error', description: message, duration: 5, }); console.error(e); } // Hide the modal setShowConfirmCreateToken(false); // Stop spinner passLoadingStatus(false); }; return ( <> setShowConfirmCreateToken(false)} > Name: {newTokenName}
Ticker: {newTokenTicker}
Decimals: {newTokenDecimals}
Supply: {newTokenInitialQty}
Document URL:{' '} {newTokenDocumentUrl === '' ? 'https://cashtabapp.com/' : newTokenDocumentUrl}
<> - +
handleNewTokenNameInput(e) } /> handleNewTokenTickerInput(e) } /> handleNewTokenDecimalsInput(e) } /> handleNewTokenInitialQtyInput(e) } /> handleNewTokenDocumentUrlInput(e) } />
setShowConfirmCreateToken(true)} disabled={!tokenGenesisDataIsValid} > -  Create Token +  Create eToken
); }; /* passLoadingStatus must receive a default prop that is a function in order to pass the rendering unit test in CreateTokenForm.test.js status => {console.log(status)} is an arbitrary stub function */ CreateTokenForm.defaultProps = { passLoadingStatus: status => { console.log(status); }, }; CreateTokenForm.propTypes = { BCH: PropTypes.object, getRestUrl: PropTypes.func, createToken: PropTypes.func, disabled: PropTypes.bool, passLoadingStatus: PropTypes.func, }; export default CreateTokenForm; diff --git a/web/cashtab/src/components/Tokens/__tests__/__snapshots__/CreateTokenForm.test.js.snap b/web/cashtab/src/components/Tokens/__tests__/__snapshots__/CreateTokenForm.test.js.snap index 55d691d4a..e1c0b2ca6 100644 --- a/web/cashtab/src/components/Tokens/__tests__/__snapshots__/CreateTokenForm.test.js.snap +++ b/web/cashtab/src/components/Tokens/__tests__/__snapshots__/CreateTokenForm.test.js.snap @@ -1,47 +1,47 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP @generated exports[`Wallet with BCH balances and tokens and state field 1`] = `
- Create Token + Create eToken
`; diff --git a/web/cashtab/src/components/Tokens/__tests__/__snapshots__/Tokens.test.js.snap b/web/cashtab/src/components/Tokens/__tests__/__snapshots__/Tokens.test.js.snap index 9c28a2bba..759f4a4b0 100644 --- a/web/cashtab/src/components/Tokens/__tests__/__snapshots__/Tokens.test.js.snap +++ b/web/cashtab/src/components/Tokens/__tests__/__snapshots__/Tokens.test.js.snap @@ -1,419 +1,419 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP @generated exports[`Wallet with BCH balances 1`] = ` Array [
You need some XEC in your wallet to create tokens.
,
0 XEC
,
- Create Token + Create eToken
,

You need at least 5.5 XEC ( $ NaN USD ) to create a token

, "No ", "eToken", " tokens in this wallet", ] `; exports[`Wallet with BCH balances and tokens 1`] = ` Array [
You need some XEC in your wallet to create tokens.
,
0 XEC
,
- Create Token + Create eToken
,

You need at least 5.5 XEC ( $ NaN USD ) to create a token

, "No ", "eToken", " tokens in this wallet", ] `; exports[`Wallet with BCH balances and tokens and state field 1`] = ` Array [
0.06047469 XEC
,
$ NaN USD
,
- Create Token + Create eToken
,
identicon of tokenId bd1acc4c986de57af8d6d2a64aecad8c30ee80f37ae9d066d758923732ddc9ba
6.001 TBS
, ] `; exports[`Wallet without BCH balance 1`] = ` Array [
You need some XEC in your wallet to create tokens.
,
0 XEC
,
- Create Token + Create eToken
,

You need at least 5.5 XEC ( $ NaN USD ) to create a token

, "No ", "eToken", " tokens in this wallet", ] `; exports[`Without wallet defined 1`] = ` Array [
You need some XEC in your wallet to create tokens.
,
0 XEC
,
- Create Token + Create eToken
,

You need at least 5.5 XEC ( $ NaN USD ) to create a token

, "No ", "eToken", " tokens in this wallet", ] `; diff --git a/web/cashtab/src/components/Wallet/Wallet.js b/web/cashtab/src/components/Wallet/Wallet.js index da342b9fd..aa88f78b0 100644 --- a/web/cashtab/src/components/Wallet/Wallet.js +++ b/web/cashtab/src/components/Wallet/Wallet.js @@ -1,335 +1,335 @@ import React from 'react'; import styled from 'styled-components'; import { WalletContext } from '@utils/context'; import OnBoarding from '@components/OnBoarding/OnBoarding'; import { QRCode } from '@components/Common/QRCode'; import { currency } from '@components/Common/Ticker.js'; import { Link } from 'react-router-dom'; import TokenList from './TokenList'; import TxHistory from './TxHistory'; import ApiError from '@components/Common/ApiError'; import BalanceHeader from '@components/Common/BalanceHeader'; import BalanceHeaderFiat from '@components/Common/BalanceHeaderFiat'; import { LoadingCtn, ZeroBalanceHeader } from '@components/Common/Atoms'; import { getWalletState } from '@utils/cashMethods'; export const Tabs = styled.div` margin: auto; margin-bottom: 12px; display: inline-block; text-align: center; `; export const TabLabel = styled.button` :focus, :active { outline: none; } border: none; background: none; font-size: 20px; cursor: pointer; @media (max-width: 400px) { font-size: 16px; } ${({ active, ...props }) => active && ` color: ${props.theme.primary}; `} `; export const TabLine = styled.div` margin: auto; transition: margin-left 0.5s ease-in-out, width 0.5s 0.1s; height: 4px; border-radius: 5px; background-color: ${props => props.theme.primary}; pointer-events: none; - margin-left: 72%; - width: 28%; + margin-left: 69.5%; + width: 29%; ${({ left, ...props }) => left && ` - margin-left: 1% - width: 69%; + margin-left: 3% + width: 63%; `} `; export const TabPane = styled.div` ${({ active }) => !active && ` display: none; `} `; export const SwitchBtnCtn = styled.div` display: flex; align-items: center; justify-content: center; align-content: space-between; margin-bottom: 15px; .nonactiveBtn { color: ${props => props.theme.wallet.text.secondary}; background: ${props => props.theme.wallet.switch.inactive.background} !important; box-shadow: none !important; } .slpActive { background: ${props => props.theme.wallet.switch.activeToken.background} !important; box-shadow: ${props => props.theme.wallet.switch.activeToken.shadow} !important; } `; export const SwitchBtn = styled.div` font-weight: bold; display: inline-block; cursor: pointer; color: ${props => props.theme.contrast}; font-size: 14px; padding: 6px 0; width: 100px; margin: 0 1px; text-decoration: none; background: ${props => props.theme.primary}; box-shadow: ${props => props.theme.wallet.switch.activeCash.shadow}; user-select: none; :first-child { border-radius: 100px 0 0 100px; } :nth-child(2) { border-radius: 0 100px 100px 0; } `; export const Links = styled(Link)` color: ${props => props.theme.wallet.text.secondary}; width: 100%; font-size: 16px; margin: 10px 0 20px 0; border: 1px solid ${props => props.theme.wallet.text.secondary}; padding: 14px 0; display: inline-block; border-radius: 3px; transition: all 200ms ease-in-out; svg { fill: ${props => props.theme.wallet.text.secondary}; } :hover { color: ${props => props.theme.primary}; border-color: ${props => props.theme.primary}; svg { fill: ${props => props.theme.primary}; } } @media (max-width: 768px) { padding: 10px 0; font-size: 14px; } `; export const ExternalLink = styled.a` color: ${props => props.theme.wallet.text.secondary}; width: 100%; font-size: 16px; margin: 0 0 20px 0; border: 1px solid ${props => props.theme.wallet.text.secondary}; padding: 14px 0; display: inline-block; border-radius: 3px; transition: all 200ms ease-in-out; svg { fill: ${props => props.theme.wallet.text.secondary}; transition: all 200ms ease-in-out; } :hover { color: ${props => props.theme.primary}; border-color: ${props => props.theme.primary}; svg { fill: ${props => props.theme.primary}; } } @media (max-width: 768px) { padding: 10px 0; font-size: 14px; } `; export const AddrSwitchContainer = styled.div` text-align: center; padding: 6px 0 12px 0; `; const WalletInfo = () => { const ContextValue = React.useContext(WalletContext); const { wallet, fiatPrice, apiError, cashtabSettings } = ContextValue; const walletState = getWalletState(wallet); const { balances, parsedTxHistory, tokens } = walletState; const [address, setAddress] = React.useState('cashAddress'); const [activeTab, setActiveTab] = React.useState('txHistory'); const hasHistory = parsedTxHistory && parsedTxHistory.length > 0; const handleChangeAddress = () => { setAddress(address === 'cashAddress' ? 'slpAddress' : 'cashAddress'); }; return ( <> {!balances.totalBalance && !apiError && !hasHistory ? ( <> 🎉 Congratulations on your new wallet!{' '} 🎉
Start using the wallet immediately to receive{' '} {currency.ticker} payments, or load it up with{' '} {currency.ticker} to send to others
) : ( <> {fiatPrice !== null && !isNaN(balances.totalBalance) && ( )} )} {apiError && } {wallet && ((wallet.Path245 && wallet.Path145) || wallet.Path1899) && ( <> {wallet.Path1899 ? ( <> ) : ( <> )} )} handleChangeAddress()} className={ address !== 'cashAddress' ? 'nonactiveBtn' : null } > {currency.ticker} handleChangeAddress()} className={ address === 'cashAddress' ? 'nonactiveBtn' : 'slpActive' } > {currency.tokenTicker} {hasHistory && parsedTxHistory && ( <> setActiveTab('txHistory')} > Transaction History setActiveTab('tokens')} > - Tokens + eTokens {tokens && tokens.length > 0 ? ( ) : (

Tokens sent to your {currency.tokenTicker}{' '} address will appear here

)}
)} ); }; const Wallet = () => { const ContextValue = React.useContext(WalletContext); const { wallet, previousWallet, loading } = ContextValue; return ( <> {loading ? ( ) : ( <> {(wallet && wallet.Path1899) || (previousWallet && previousWallet.path1899) ? ( ) : ( )} )} ); }; export default Wallet;