diff --git a/package.json b/package.json index 8a08052..db5e6d2 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,9 @@ "bs58": "^4.0.1", "buffer-layout": "^1.2.0", "immutable-tuple": "^0.4.10", + "mdi-material-ui": "^6.17.0", "notistack": "^0.9.17", + "qrcode.react": "^1.0.0", "react": "^16.13.1", "react-dom": "^16.13.1", "react-scripts": "3.4.1", diff --git a/src/components/BalancesList.js b/src/components/BalancesList.js index 51c314d..071fae6 100644 --- a/src/components/BalancesList.js +++ b/src/components/BalancesList.js @@ -19,7 +19,7 @@ import { makeStyles } from '@material-ui/core/styles'; import { abbreviateAddress } from '../utils/utils'; import Button from '@material-ui/core/Button'; import SendIcon from '@material-ui/icons/Send'; -import ReceiveIcon from '@material-ui/icons/CallReceived'; +import ReceiveIcon from '@material-ui/icons/WorkOutline'; import AppBar from '@material-ui/core/AppBar'; import Toolbar from '@material-ui/core/Toolbar'; import AddIcon from '@material-ui/icons/Add'; @@ -28,6 +28,7 @@ import IconButton from '@material-ui/core/IconButton'; import Tooltip from '@material-ui/core/Tooltip'; import AddTokenDialog from './AddTokenDialog'; import SendDialog from './SendDialog'; +import DepositDialog from './DepositDialog'; import { refreshAccountInfo, useSolanaExplorerUrlSuffix, @@ -109,6 +110,7 @@ function BalanceListItem({ publicKey }) { const classes = useStyles(); const [open, setOpen] = useState(false); const [sendDialogOpen, setSendDialogOpen] = useState(false); + const [depositDialogOpen, setDepositDialogOpen] = useState(false); if (!balanceInfo) { return ; @@ -138,6 +140,7 @@ function BalanceListItem({ publicKey }) { variant="outlined" color="primary" startIcon={} + onClick={() => setDepositDialogOpen(true)} > Receive @@ -184,6 +187,12 @@ function BalanceListItem({ publicKey }) { balanceInfo={balanceInfo} publicKey={publicKey} /> + setDepositDialogOpen(false)} + balanceInfo={balanceInfo} + publicKey={publicKey} + /> ); } diff --git a/src/components/CopyableDisplay.js b/src/components/CopyableDisplay.js new file mode 100644 index 0000000..2615a91 --- /dev/null +++ b/src/components/CopyableDisplay.js @@ -0,0 +1,68 @@ +import React, { useRef } from 'react'; +import { Button, TextField } from '@material-ui/core'; +import CopyIcon from 'mdi-material-ui/ContentCopy'; +import { makeStyles } from '@material-ui/core/styles'; +import { useSnackbar } from 'notistack'; + +const useStyles = makeStyles((theme) => ({ + root: { + display: 'flex', + marginTop: theme.spacing(1), + marginBottom: theme.spacing(1), + }, + button: { + marginLeft: theme.spacing(3), + whiteSpace: 'nowrap', + marginTop: theme.spacing(2), + }, + buttonIcon: { + marginRight: theme.spacing(1), + }, +})); + +export default function CopyableDisplay({ + value, + label, + autoFocus, + buttonProps, +}) { + const { enqueueSnackbar } = useSnackbar(); + const textareaRef = useRef(); + const classes = useStyles(); + const copyLink = () => { + let textArea = textareaRef.current; + if (textArea) { + textArea.select(); + document.execCommand('copy'); + enqueueSnackbar('Address copied', { + variant: 'success', + autoHideDuration: 2500, + }); + } + }; + + return ( +
+ (textareaRef.current = ref)} + multiline + autoFocus={autoFocus} + value={value} + readOnly + onFocus={(e) => e.currentTarget.select()} + className={classes.textArea} + fullWidth + label={label} + spellCheck={false} + /> + +
+ ); +} diff --git a/src/components/DepositDialog.js b/src/components/DepositDialog.js new file mode 100644 index 0000000..5503532 --- /dev/null +++ b/src/components/DepositDialog.js @@ -0,0 +1,86 @@ +import React from 'react'; +import DialogTitle from '@material-ui/core/DialogTitle'; +import DialogContent from '@material-ui/core/DialogContent'; +import DialogForm from './DialogForm'; +import { abbreviateAddress } from '../utils/utils'; +import { Button, Typography } from '@material-ui/core'; +import CopyableDisplay from './CopyableDisplay'; +import { makeStyles } from '@material-ui/core/styles'; +import QrcodeIcon from 'mdi-material-ui/Qrcode'; +import QRCode from 'qrcode.react'; + +export default function DepositDialog({ + open, + onClose, + publicKey, + balanceInfo, +}) { + let { mint, tokenName, tokenSymbol, owner } = balanceInfo; + + return ( + + + Deposit {tokenName ?? abbreviateAddress(mint)} + {tokenSymbol ? ` (${tokenSymbol})` : null} + + + {publicKey.equals(owner) ? ( + + This address can only be used to receive SOL. Do not send other + tokens to this address. + + ) : ( + + This address can only be used to receive {tokenSymbol}. Do not send + SOL to this address. + + )} + + + + + ); +} + +const useQrCodeStyles = makeStyles((theme) => ({ + qrcodeButton: { + marginTop: theme.spacing(1), + marginBottom: theme.spacing(2), + }, + qrcodeIcon: { + marginRight: theme.spacing(1), + }, + qrcodeContainer: { + display: 'flex', + flexDirection: 'column', + alignItems: 'center', + marginBottom: theme.spacing(2), + }, +})); + +function Qrcode({ value }) { + const [showQrcode, setShowQrcode] = React.useState(false); + + const classes = useQrCodeStyles(); + return ( + <> + + {showQrcode && ( +
+ +
+ )} + + ); +} diff --git a/yarn.lock b/yarn.lock index 2fae508..6b2c3f5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7338,6 +7338,11 @@ md5.js@^1.3.4: inherits "^2.0.1" safe-buffer "^5.1.2" +mdi-material-ui@^6.17.0: + version "6.17.0" + resolved "https://registry.yarnpkg.com/mdi-material-ui/-/mdi-material-ui-6.17.0.tgz#da69f0b7d7c6fc2255e6007ed8b8ca858c1aede7" + integrity sha512-eOprRu31lklPIS1WGe3cM0G/8glKl1WKRvewxjDrgXH2Ryxxg7uQ+uwDUwUEONtLku0p2ZOLzgXUIy2uRy5rLg== + mdn-data@2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.4.tgz#699b3c38ac6f1d728091a64650b65d388502fd5b" @@ -9186,7 +9191,7 @@ prompts@^2.0.1: kleur "^3.0.3" sisteransi "^1.0.4" -prop-types@^15.6.2, prop-types@^15.7.2: +prop-types@^15.6.0, prop-types@^15.6.2, prop-types@^15.7.2: version "15.7.2" resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5" integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ== @@ -9270,6 +9275,20 @@ q@^1.1.2: resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" integrity sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc= +qr.js@0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/qr.js/-/qr.js-0.0.0.tgz#cace86386f59a0db8050fa90d9b6b0e88a1e364f" + integrity sha1-ys6GOG9ZoNuAUPqQ2baw6IoeNk8= + +qrcode.react@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/qrcode.react/-/qrcode.react-1.0.0.tgz#7e8889db3b769e555e8eb463d4c6de221c36d5de" + integrity sha512-jBXleohRTwvGBe1ngV+62QvEZ/9IZqQivdwzo9pJM4LQMoCM2VnvNBnKdjvGnKyDZ/l0nCDgsPod19RzlPvm/Q== + dependencies: + loose-envify "^1.4.0" + prop-types "^15.6.0" + qr.js "0.0.0" + qs@6.7.0: version "6.7.0" resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc"