diff --git a/web/cashtab/src/components/Home/Tx.js b/web/cashtab/src/components/Home/Tx.js index 339abc263..090f84d71 100644 --- a/web/cashtab/src/components/Home/Tx.js +++ b/web/cashtab/src/components/Home/Tx.js @@ -1,855 +1,856 @@ import React from 'react'; import { Link } from 'react-router-dom'; import PropTypes from 'prop-types'; import styled from 'styled-components'; import { SendIcon, ReceiveIcon, GenesisIcon, UnparsedIcon, ThemedContactsOutlined, } from 'components/Common/CustomIcons'; import { currency } from 'components/Common/Ticker'; import { fromLegacyDecimals } from 'utils/cashMethods'; import { formatBalance, formatDate } from 'utils/formatting'; import TokenIcon from 'components/Tokens/TokenIcon'; import { Collapse } from 'antd'; import CopyToClipboard from 'components/Common/CopyToClipboard'; import { ThemedCopySolid, ThemedLinkSolid, ThemedPdfSolid, } from 'components/Common/CustomIcons'; const TxIcon = styled.div` svg { width: 20px; height: 20px; } height: 40px; width: 40px; border: 1px solid #fff; display: flex; align-items: center; justify-content: center; border-radius: 100px; `; const AddToContacts = styled.span` max-height: 200px; text-align: left; `; const SentTx = styled(TxIcon)` svg { margin-right: -3px; } fill: ${props => props.theme.contrast}; `; const ReceivedTx = styled(TxIcon)` svg { fill: ${props => props.theme.eCashBlue}; } border-color: ${props => props.theme.eCashBlue}; `; const GenesisTx = styled(TxIcon)` border-color: ${props => props.theme.genesisGreen}; svg { fill: ${props => props.theme.genesisGreen}; } `; const UnparsedTx = styled(TxIcon)` color: ${props => props.theme.eCashBlue} !important; `; const DateType = styled.div` text-align: left; padding: 12px; @media screen and (max-width: 500px) { font-size: 0.8rem; } `; +const GenesisHeader = styled.h3``; +const ReceivedHeader = styled.h3``; + const LeftTextCtn = styled.div` text-align: left; display: flex; align-items: left; flex-direction: column; margin-left: 10px; h3 { color: ${props => props.theme.contrast}; font-size: 14px; font-weight: 700; margin: 0; } - .genesis { + ${GenesisHeader} { color: ${props => props.theme.genesisGreen}; } - .received { + ${ReceivedHeader} { color: ${props => props.theme.eCashBlue}; } h4 { font-size: 12px; color: ${props => props.theme.lightWhite}; margin: 0; } `; const RightTextCtn = styled.div` text-align: right; display: flex; align-items: left; flex-direction: column; margin-left: 10px; h3 { color: ${props => props.theme.contrast}; font-size: 14px; font-weight: 700; margin: 0; } h4 { font-size: 12px; color: ${props => props.theme.lightWhite}; margin: 0; } `; const OpReturnType = styled.div` text-align: right; width: 100%; padding: 10px; border-radius: 5px; background: ${props => props.theme.sentMessage}; margin-top: 15px; h4 { color: ${props => props.theme.lightWhite}; margin: 0; font-size: 12px; display: inline-block; } p { color: ${props => props.theme.contrast}; margin: 0; font-size: 14px; margin-bottom: 10px; overflow-wrap: break-word; } a { color: ${props => props.theme.contrast}; margin: 0; font-size: 10px; border: 1px solid ${props => props.theme.contrast}; border-radius: 5px; padding: 2px 10px; opacity: 0.6; } a:hover { opacity: 1; border-color: ${props => props.theme.eCashBlue}; color: ${props => props.theme.contrast}; background: ${props => props.theme.eCashBlue}; } ${({ received, ...props }) => received && ` text-align: left; background: ${props.theme.receivedMessage}; `} `; const ReceivedLabel = styled.span` font-weight: bold; color: ${props => props.theme.eCashBlue} !important; `; const EncryptionMessageLabel = styled.span` font-weight: bold; font-size: 12px; color: ${props => props.theme.encryptionRed}; white-space: nowrap; `; const UnauthorizedDecryptionMessage = styled.span` text-align: left; color: ${props => props.theme.encryptionRed}; white-space: nowrap; font-style: italic; `; const TxInfo = styled.div` text-align: right; display: flex; align-items: left; flex-direction: column; margin-left: 10px; flex-grow: 2; h3 { color: ${props => props.theme.contrast}; font-size: 14px; font-weight: 700; margin: 0; } h4 { font-size: 12px; color: ${props => props.theme.lightWhite}; margin: 0; } @media screen and (max-width: 500px) { font-size: 0.8rem; } `; const TokenInfo = styled.div` display: flex; flex-grow: 1; justify-content: flex-end; color: ${props => props.outgoing ? props.theme.secondary : props.theme.eCashBlue}; @media screen and (max-width: 500px) { font-size: 0.8rem; grid-template-columns: 16px auto; } `; const TxTokenIcon = styled.div` img { height: 24px; width: 24px; } @media screen and (max-width: 500px) { img { height: 16px; width: 16px; } } grid-column-start: 1; grid-column-end: span 1; grid-row-start: 1; grid-row-end: span 2; align-self: center; `; const TokenTxAmt = styled.h3` text-align: right; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; `; const TokenTxAmtGenesis = styled(TokenTxAmt)` color: ${props => props.theme.genesisGreen} !important; `; const TokenTxAmtReceived = styled(TokenTxAmt)` color: ${props => props.theme.eCashBlue} !important; `; const TokenName = styled.h4` text-align: right; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; `; const TxWrapper = styled.div` display: flex; align-items: center; border-top: 1px solid rgba(255, 255, 255, 0.12); color: ${props => props.theme.contrast}; padding: 10px 0; flex-wrap: wrap; width: 100%; `; const AntdContextCollapseWrapper = styled.div` .ant-collapse { border: none !important; background-color: transparent !important; } .ant-collapse-item { border: none !important; } .ant-collapse-header { padding: 0 !important; color: ${props => props.theme.forms.text} !important; } border-radius: 16px; .ant-collapse-content-box { padding-right: 0 !important; } @media screen and (max-width: 500px) { grid-template-columns: 24px 30% 50%; } `; const Panel = Collapse.Panel; const DropdownIconWrapper = styled.div` display: flex; align-items: center; gap: 4px; `; const TextLayer = styled.div` font-size: 12px; color: ${props => props.theme.contrast}; white-space: nowrap; `; const DropdownButton = styled.button` display: flex; justify-content: flex-end; position: relative; background-color: ${props => props.theme.walletBackground}; border: none; cursor: pointer; padding: 0; &:hover { div { color: ${props => props.theme.eCashBlue}!important; } svg { fill: ${props => props.theme.eCashBlue}!important; } } `; const PanelCtn = styled.div` display: flex; align-items: center; justify-content: flex-end; right: 0; gap: 8px; @media (max-width: 500px) { flex-wrap: wrap; } `; const TxLink = styled.a` color: ${props => props.theme.primary}; `; const NotInContactsAlert = styled.h4` color: ${props => props.theme.forms.error} !important; font-style: italic; `; const ReceivedFromCtn = styled.div` display: flex; align-items: center; justify-content: center; gap: 3px; h4 { margin-top: 2.5px; } `; const Tx = ({ data, fiatPrice, fiatCurrency, addressesInContactList, contactList, }) => { const txDate = typeof data.blocktime === 'undefined' ? formatDate() : formatDate(data.blocktime, navigator.language); // if data only includes height and txid, then the tx could not be parsed by cashtab // render as such but keep link to block explorer let unparsedTx = false; if (!Object.keys(data).includes('outgoingTx')) { unparsedTx = true; } return ( <> {unparsedTx ? ( Unparsed
{txDate}
Open in Explorer
) : ( - + {data.outgoingTx ? ( <> {data.tokenTx && data.tokenInfo .transactionType === 'GENESIS' ? ( ) : ( )} ) : ( )} {data.outgoingTx ? ( <> {data.tokenTx && data.tokenInfo .transactionType === 'GENESIS' ? ( -

+ Genesis -

+ ) : ( -

- Sent -

+

Sent

)} ) : ( -

+ Received -

+ {addressesInContactList.includes( data.replyAddress, ) && ( <>

from

{contactList.map( ( contact, index, ) => { let result; const contactAddress = contact.address; const dataAddress = data.replyAddress; if ( contactAddress === dataAddress ) { result = contact.name; } else { result = ''; } return (

{ result }

); }, )} )}
)}

{txDate}

{data.tokenTx ? ( {data.tokenTx && data.tokenInfo ? ( <> {data.outgoingTx ? ( {data.tokenInfo .transactionType === 'GENESIS' ? ( <> +{' '} {data.tokenInfo.qtyReceived.toString()}   { data .tokenInfo .tokenTicker } { data .tokenInfo .tokenName } ) : ( <> -{' '} {data.tokenInfo.qtySent.toString()}   { data .tokenInfo .tokenTicker } { data .tokenInfo .tokenName } )} ) : ( +{' '} {data.tokenInfo.qtyReceived.toString()}   { data .tokenInfo .tokenTicker } { data .tokenInfo .tokenName } )} ) : ( Token Tx )} ) : ( <> {data.outgoingTx ? ( <>

- {formatBalance( fromLegacyDecimals( data.amountSent, ), )}{' '} { currency.ticker }

{fiatPrice !== null && !isNaN( data.amountSent, ) && (

- { currency .fiatCurrencies[ fiatCurrency ] .symbol } {( fromLegacyDecimals( data.amountSent, ) * fiatPrice ).toFixed( 2, )}{' '} { currency .fiatCurrencies .fiatCurrency }

)} ) : ( <> + {formatBalance( fromLegacyDecimals( data.amountReceived, ), )}{' '} { currency.ticker } {fiatPrice !== null && !isNaN( data.amountReceived, ) && (

+ { currency .fiatCurrencies[ fiatCurrency ] .symbol } {( fromLegacyDecimals( data.amountReceived, ) * fiatPrice ).toFixed( 2, )}{' '} { currency .fiatCurrencies .fiatCurrency }

)} )}
)} {data.opReturnMessage && ( <> {!data.outgoingTx && !addressesInContactList.includes( data.replyAddress, ) && ( Warning: This sender is not in your contact list. Beware of scams. )} {data.isCashtabMessage ? (

Cashtab Message{' '}

) : (

External Message

)} {data.isEncryptedMessage ? (  - Encrypted ) : ( '' )}
{/*unencrypted OP_RETURN Message*/} {data.opReturnMessage && !data.isEncryptedMessage ? (

{ data.opReturnMessage }

) : ( '' )} {/*encrypted and wallet is authorized to view OP_RETURN Message*/} {data.opReturnMessage && data.isEncryptedMessage && data.decryptionSuccess ? (

{ data.opReturnMessage }

) : ( '' )} {/*encrypted but wallet is not authorized to view OP_RETURN Message*/} {data.opReturnMessage && data.isEncryptedMessage && !data.decryptionSuccess ? ( { data.opReturnMessage } ) : ( '' )} {!data.outgoingTx && data.replyAddress ? ( Reply ) : ( '' )}
)}
} > Txid {data.opReturnMessage && ( Msg )} View on be.cash Receipt {!data.outgoingTx && data.replyAddress && !addressesInContactList.includes( data.replyAddress, ) && ( Add to contacts )}
)} ); }; Tx.propTypes = { data: PropTypes.object, fiatPrice: PropTypes.number, fiatCurrency: PropTypes.string, addressesInContactList: PropTypes.arrayOf(PropTypes.string), contactList: PropTypes.arrayOf( PropTypes.shape({ address: PropTypes.string, name: PropTypes.string, }), ), }; export default Tx; diff --git a/web/cashtab/src/components/Home/__tests__/__snapshots__/Home.test.js.snap b/web/cashtab/src/components/Home/__tests__/__snapshots__/Home.test.js.snap index d7b84b49e..6bcc3079e 100644 --- a/web/cashtab/src/components/Home/__tests__/__snapshots__/Home.test.js.snap +++ b/web/cashtab/src/components/Home/__tests__/__snapshots__/Home.test.js.snap @@ -1,449 +1,449 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP @generated exports[`Wallet with BCH balances 1`] = ` Array [

MigrationTestAlpha

0 XEC
,
🎉 Congratulations on your new wallet! 🎉
Start using the wallet immediately to receive XEC payments, or load it up with XEC to send to others
Create eToken

Tokens sent to your eToken address will appear here

, ] `; exports[`Wallet with BCH balances and tokens 1`] = ` Array [

MigrationTestAlpha

0 XEC
,
🎉 Congratulations on your new wallet! 🎉
Start using the wallet immediately to receive XEC payments, or load it up with XEC to send to others
Create eToken

Tokens sent to your eToken address will appear here

, ] `; exports[`Wallet with BCH balances and tokens and state field 1`] = ` Array [

MigrationTestAlpha

0.06 XEC
,
🎉 Congratulations on your new wallet! 🎉
Start using the wallet immediately to receive XEC payments, or load it up with XEC to send to others
, ] `; exports[`Wallet without BCH balance 1`] = ` Array [

MigrationTestAlpha

0 XEC
,
🎉 Congratulations on your new wallet! 🎉
Start using the wallet immediately to receive XEC payments, or load it up with XEC to send to others
Create eToken

Tokens sent to your eToken address will appear here

, ] `; exports[`Without wallet defined 1`] = `

Welcome to Cashtab!

Cashtab is an open source, non-custodial web wallet for eCash .

Want to learn more? Check out the Cashtab documentation.

`;