diff --git a/web/cashtab/src/components/App.css b/web/cashtab/src/components/App.css
index 09680624d..63140c657 100644
--- a/web/cashtab/src/components/App.css
+++ b/web/cashtab/src/components/App.css
@@ -1,40 +1,51 @@
@import '~antd/dist/antd.less';
@import '~@fortawesome/fontawesome-free/css/all.css';
@import url('https://fonts.googleapis.com/css?family=Khula&display=swap&.css');
+/* Hide scrollbars but keep functionality*/
+/* Hide scrollbar for Chrome, Safari and Opera */
+body::-webkit-scrollbar {
+ display: none;
+}
+
+/* Hide scrollbar for IE, Edge and Firefox */
+body {
+ -ms-overflow-style: none; /* IE and Edge */
+ scrollbar-width: none; /* Firefox */
+}
/* Hide up and down arros on input type="number" */
/* Chrome, Safari, Edge, Opera */
input::-webkit-outer-spin-button,
input::-webkit-inner-spin-button {
-webkit-appearance: none;
margin: 0;
}
/* Hide up and down arros on input type="number" */
/* Firefox */
input[type='number'] {
-moz-appearance: textfield;
}
html,
body {
max-width: 100%;
overflow-x: hidden;
}
/* Hide scroll bars on antd modals*/
.ant-modal-wrap.ant-modal-centered::-webkit-scrollbar {
display: none;
}
/* ITEMS BELOW TO BE MOVED TO STYLED COMPONENTS*/
/* useWallet.js, useBCH.js */
@media (max-width: 768px) {
.ant-notification {
width: 100%;
top: 20px !important;
max-width: unset;
margin-right: 0;
}
}
diff --git a/web/cashtab/src/components/Wallet/TokenList.js b/web/cashtab/src/components/Wallet/TokenList.js
index bb0c7e2d2..3c1388ef6 100644
--- a/web/cashtab/src/components/Wallet/TokenList.js
+++ b/web/cashtab/src/components/Wallet/TokenList.js
@@ -1,29 +1,22 @@
import React from 'react';
-import styled from 'styled-components';
import TokenListItem from './TokenListItem';
import { Link } from 'react-router-dom';
-import { currency } from '@components/Common/Ticker.js';
import { formatBalance } from '@utils/cashMethods';
-export const TokenTitle = styled.h2`
- color: ${props => props.theme.wallet.text.secondary};
-`;
-
const TokenList = ({ tokens }) => {
return (
- {currency.tokenTicker} Tokens
{tokens.map(token => (
))}
);
};
export default TokenList;
diff --git a/web/cashtab/src/components/Wallet/Tx.js b/web/cashtab/src/components/Wallet/Tx.js
index 417546f81..54a425e15 100644
--- a/web/cashtab/src/components/Wallet/Tx.js
+++ b/web/cashtab/src/components/Wallet/Tx.js
@@ -1,114 +1,114 @@
import React from 'react';
import styled from 'styled-components';
-import { UpCircleOutlined, DownCircleOutlined } from '@ant-design/icons';
+import { ArrowUpOutlined, ArrowDownOutlined } from '@ant-design/icons';
import { currency } from '@components/Common/Ticker';
-const SentTx = styled(UpCircleOutlined)`
+const SentTx = styled(ArrowUpOutlined)`
color: ${props => props.theme.secondary} !important;
`;
-const ReceivedTx = styled(DownCircleOutlined)`
+const ReceivedTx = styled(ArrowDownOutlined)`
color: ${props => props.theme.primary} !important;
`;
const DateType = styled.div`
text-align: left;
padding: 12px;
@media screen and (max-width: 500px) {
font-size: 0.8rem;
}
`;
const SentLabel = styled.span`
font-weight: bold;
color: ${props => props.theme.secondary} !important;
`;
const ReceivedLabel = styled.span`
font-weight: bold;
color: ${props => props.theme.primary} !important;
`;
const TxIcon = styled.div`
svg {
width: 32px;
height: 32px;
}
height: 32px;
width: 32px;
@media screen and (max-width: 500px) {
svg {
width: 24px;
height: 24px;
}
height: 24px;
width: 24px;
}
`;
const TxInfo = styled.div`
padding: 12px;
font-size: 1rem;
color: ${props =>
props.outgoing ? props.theme.secondary : props.theme.primary};
@media screen and (max-width: 500px) {
font-size: 0.8rem;
}
`;
const TxWrapper = styled.div`
display: grid;
grid-template-columns: 36px 30% 50%;
@media screen and (max-width: 500px) {
grid-template-columns: 24px 30% 50%;
}
justify-content: space-between;
align-items: center;
padding: 15px 25px;
border-radius: 3px;
background: ${props => props.theme.tokenListItem.background};
margin-bottom: 3px;
box-shadow: ${props => props.theme.tokenListItem.boxShadow};
border: 1px solid ${props => props.theme.tokenListItem.border};
:hover {
border-color: ${props => props.theme.primary};
}
`;
const Tx = ({ data }) => {
const txDate =
typeof data.blocktime === 'undefined'
? new Date().toLocaleDateString()
: new Date(data.blocktime * 1000).toLocaleDateString();
return (
{data.outgoingTx ? : }
{data.outgoingTx ? (
Sent
) : (
Received
)}
{txDate}
{data.tokenTx ? (
Token Tx
) : (
<>
{data.outgoingTx
? `- ${data.amountSent.toFixed(8)} ${
currency.ticker
}`
: `+ ${data.amountReceived.toFixed(8)} ${
currency.ticker
}`}
>
)}
);
};
export default Tx;
diff --git a/web/cashtab/src/components/Wallet/TxHistory.js b/web/cashtab/src/components/Wallet/TxHistory.js
index 28bbd3965..bf105c82e 100644
--- a/web/cashtab/src/components/Wallet/TxHistory.js
+++ b/web/cashtab/src/components/Wallet/TxHistory.js
@@ -1,28 +1,24 @@
import React from 'react';
import styled from 'styled-components';
import Tx from './Tx';
-export const TxTitle = styled.h2`
- color: ${props => props.theme.wallet.text.secondary};
-`;
export const TxLink = styled.a``;
const TxHistory = ({ txs }) => {
return (
- Transactions
{txs.map(tx => (
))}
);
};
export default TxHistory;
diff --git a/web/cashtab/src/components/Wallet/Wallet.js b/web/cashtab/src/components/Wallet/Wallet.js
index 60e09fa01..a53c47acb 100644
--- a/web/cashtab/src/components/Wallet/Wallet.js
+++ b/web/cashtab/src/components/Wallet/Wallet.js
@@ -1,292 +1,369 @@
import React from 'react';
import styled from 'styled-components';
import { LinkOutlined, LoadingOutlined } from '@ant-design/icons';
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 { CashLoader } from '@components/Common/CustomIcons';
import { formatBalance } from '@utils/cashMethods';
export const LoadingCtn = styled.div`
width: 100%;
display: flex;
align-items: center;
justify-content: center;
height: 400px;
flex-direction: column;
svg {
width: 50px;
height: 50px;
fill: ${props => props.theme.primary};
}
`;
export const BalanceHeader = styled.div`
color: ${props => props.theme.wallet.text.primary};
width: 100%;
font-size: 30px;
font-weight: bold;
@media (max-width: 768px) {
font-size: 23px;
}
`;
export const BalanceHeaderFiat = styled.div`
color: ${props => props.theme.wallet.text.secondary};
width: 100%;
font-size: 18px;
margin-bottom: 20px;
font-weight: bold;
@media (max-width: 768px) {
font-size: 16px;
}
`;
export const ZeroBalanceHeader = styled.div`
color: ${props => props.theme.wallet.text.primary};
width: 100%;
font-size: 14px;
margin-bottom: 5px;
`;
+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%;
+
+ ${({ left, ...props }) =>
+ left &&
+ `
+ margin-left: 1%
+ width: 69%;
+ `}
+`;
+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;
}
`;
const WalletInfo = () => {
const ContextValue = React.useContext(WalletContext);
const {
wallet,
fiatPrice,
balances,
+ tokens,
parsedTxHistory,
apiError,
} = ContextValue;
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
0 {currency.ticker}
>
) : (
<>
{formatBalance(balances.totalBalance)} {currency.ticker}
{fiatPrice !== null && !isNaN(balances.totalBalance) && (
${(balances.totalBalance * fiatPrice).toFixed(2)}{' '}
USD
)}
>
)}
{apiError && (
<>
An error occured on our end.
Re-establishing connection...
>
)}
{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 && (
-
- )}
- {balances.totalBalance ? (
<>
-
- More transactions
-
+
+ setActiveTab('txHistory')}
+ >
+ Transaction History
+
+ setActiveTab('tokens')}
+ >
+ Tokens
+
+
+
+
+
+
+
+ More transactions
+
+
+
+ {tokens && tokens.length > 0 ? (
+
+ ) : (
+
+ Tokens sent to your {currency.tokenTicker}{' '}
+ address will appear here
+
+ )}
+
>
- ) : null}
+ )}
>
);
};
const Wallet = () => {
const ContextValue = React.useContext(WalletContext);
- const { wallet, tokens, loading } = ContextValue;
+ const { wallet, loading } = ContextValue;
return (
<>
- {loading && (
+ {loading ? (
+ ) : (
+ <>{wallet.Path1899 ? : }>
)}
- {!loading && wallet.Path245 && }
-
- {!loading && wallet.Path245 && tokens && tokens.length > 0 && (
-
- )}
- {!loading && !wallet.Path245 ? : null}
>
);
};
export default Wallet;
diff --git a/web/cashtab/src/components/Wallet/__tests__/__snapshots__/Wallet.test.js.snap b/web/cashtab/src/components/Wallet/__tests__/__snapshots__/Wallet.test.js.snap
index 641205c3a..a8376bbce 100644
--- a/web/cashtab/src/components/Wallet/__tests__/__snapshots__/Wallet.test.js.snap
+++ b/web/cashtab/src/components/Wallet/__tests__/__snapshots__/Wallet.test.js.snap
@@ -1,514 +1,409 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Wallet with BCH balances 1`] = `
Array [
0.06047469
BCHA
,
$
NaN
USD
,
,
,
-
-
-
-
- More transactions
- ,
]
`;
exports[`Wallet with BCH balances and tokens 1`] = `
Array [
0.06047469
BCHA
,
$
NaN
USD
,
,
,
-
-
-
-
- More transactions
- ,
- ,
]
`;
exports[`Wallet without BCH balance 1`] = `
Array [
🎉
Congratulations on your new wallet!
🎉
Start using the wallet immediately to receive
BCHA
payments, or load it up with
BCHA
to send to others
,
0
BCHA
,
,
,
]
`;
exports[`Without wallet defined 1`] = `
Array [
Welcome to Cashtab!
,
Cashtab is an
open source,
non-custodial web wallet for
Bitcoin ABC
.
Want to learn more?
Check out the Cashtab documentation.
,
,
,
]
`;