bridge_ui: transfer confirmation dialog

Change-Id: I232f60354388b0b88ba3ab43d9bbd9cb5ceb255e
This commit is contained in:
Evan Gray 2021-10-15 15:33:59 -04:00
parent 6cd43fdbc8
commit e5642a788d
5 changed files with 183 additions and 29 deletions

View File

@ -24,10 +24,22 @@ import KeyAndBalance from "../KeyAndBalance";
import ShowTx from "../ShowTx";
import StepDescription from "../StepDescription";
import TransactionProgress from "../TransactionProgress";
import SendConfirmationDialog from "./SendConfirmationDialog";
import WaitingForWalletMessage from "./WaitingForWalletMessage";
function Send() {
const { handleClick, disabled, showLoader } = useHandleTransfer();
const [isConfirmOpen, setIsConfirmOpen] = useState(false);
const handleTransferClick = useCallback(() => {
setIsConfirmOpen(true);
}, []);
const handleConfirmClick = useCallback(() => {
handleClick();
setIsConfirmOpen(false);
}, [handleClick]);
const handleConfirmClose = useCallback(() => {
setIsConfirmOpen(false);
}, []);
const sourceChain = useSelector(selectTransferSourceChain);
const sourceAsset = useSelector(selectTransferSourceAsset);
@ -143,14 +155,21 @@ function Send() {
</ButtonWithLoader>
</>
) : (
<ButtonWithLoader
disabled={isDisabled}
onClick={handleClick}
showLoader={showLoader}
error={errorMessage}
>
Transfer
</ButtonWithLoader>
<>
<ButtonWithLoader
disabled={isDisabled}
onClick={handleTransferClick}
showLoader={showLoader}
error={errorMessage}
>
Transfer
</ButtonWithLoader>
<SendConfirmationDialog
open={isConfirmOpen}
onClick={handleConfirmClick}
onClose={handleConfirmClose}
/>
</>
)}
<WaitingForWalletMessage />
{transferTx ? <ShowTx chainId={sourceChain} tx={transferTx} /> : null}

View File

@ -0,0 +1,93 @@
import {
Button,
Dialog,
DialogActions,
DialogContent,
DialogTitle,
Typography,
} from "@material-ui/core";
import { ArrowDownward } from "@material-ui/icons";
import { Alert } from "@material-ui/lab";
import { useSelector } from "react-redux";
import {
selectTransferSourceChain,
selectTransferSourceParsedTokenAccount,
} from "../../store/selectors";
import { CHAINS_BY_ID } from "../../utils/consts";
import SmartAddress from "../SmartAddress";
import { useTargetInfo } from "./Target";
function SendConfirmationContent() {
const sourceChain = useSelector(selectTransferSourceChain);
const sourceParsedTokenAccount = useSelector(
selectTransferSourceParsedTokenAccount
);
const { targetChain, targetAsset, symbol, tokenName, logo } = useTargetInfo();
return (
<>
{targetAsset ? (
<div style={{ textAlign: "center" }}>
<SmartAddress
variant="h6"
chainId={sourceChain}
parsedTokenAccount={sourceParsedTokenAccount}
/>
<div>
<Typography variant="caption">
{CHAINS_BY_ID[sourceChain].name}
</Typography>
</div>
<div style={{ paddingTop: 4 }}>
<ArrowDownward fontSize="inherit" />
</div>
<SmartAddress
variant="h6"
chainId={targetChain}
address={targetAsset}
symbol={symbol}
tokenName={tokenName}
logo={logo}
/>
<div>
<Typography variant="caption">
{CHAINS_BY_ID[targetChain].name}
</Typography>
</div>
</div>
) : null}
<Alert severity="warning" variant="outlined" style={{ marginTop: 8 }}>
Once the transfer transaction is submitted, the transfer must be
completed by redeeming the tokens on the target chain. Please ensure
that the token listed above is the desired token and confirm that
markets exist on the target chain.
</Alert>
</>
);
}
export default function SendConfirmationDialog({
open,
onClick,
onClose,
}: {
open: boolean;
onClick: () => void;
onClose: () => void;
}) {
return (
<Dialog open={open} onClose={onClose}>
<DialogTitle>Are you sure?</DialogTitle>
<DialogContent>
<SendConfirmationContent />
</DialogContent>
<DialogActions>
<Button variant="outlined" onClick={onClose}>
Cancel
</Button>
<Button variant="contained" color="primary" onClick={onClick}>
Confirm
</Button>
</DialogActions>
</Dialog>
);
}

View File

@ -1,6 +1,7 @@
import { makeStyles, Typography } from "@material-ui/core";
import { useSelector } from "react-redux";
import {
selectSourceWalletAddress,
selectTransferAmount,
selectTransferSourceChain,
selectTransferSourceParsedTokenAccount,
@ -21,6 +22,7 @@ export default function SourcePreview() {
const sourceParsedTokenAccount = useSelector(
selectTransferSourceParsedTokenAccount
);
const sourceWalletAddress = useSelector(selectSourceWalletAddress);
const sourceAmount = useSelector(selectTransferAmount);
const explainerContent =
@ -31,7 +33,13 @@ export default function SourcePreview() {
chainId={sourceChain}
parsedTokenAccount={sourceParsedTokenAccount}
/>
<span>from {CHAINS_BY_ID[sourceChain].name}</span>
{sourceWalletAddress ? (
<>
<span>from</span>
<SmartAddress chainId={sourceChain} address={sourceWalletAddress} />
</>
) : null}
<span>on {CHAINS_BY_ID[sourceChain].name}</span>
</>
) : (
""

View File

@ -43,15 +43,7 @@ const useStyles = makeStyles((theme) => ({
},
}));
function Target() {
const classes = useStyles();
const dispatch = useDispatch();
const isBeta = useBetaContext();
const sourceChain = useSelector(selectTransferSourceChain);
const chains = useMemo(
() => CHAINS.filter((c) => c.id !== sourceChain),
[sourceChain]
);
export const useTargetInfo = () => {
const targetChain = useSelector(selectTransferTargetChain);
const targetAddressHex = useSelector(selectTransferTargetAddressHex);
const targetAsset = useSelector(selectTransferTargetAsset);
@ -68,6 +60,36 @@ function Target() {
(targetAsset && metadata.data?.get(targetAsset)?.logo) || undefined;
const readableTargetAddress =
hexToNativeString(targetAddressHex, targetChain) || "";
return useMemo(
() => ({
targetChain,
targetAsset,
tokenName,
symbol,
logo,
readableTargetAddress,
}),
[targetChain, targetAsset, tokenName, symbol, logo, readableTargetAddress]
);
};
function Target() {
const classes = useStyles();
const dispatch = useDispatch();
const isBeta = useBetaContext();
const sourceChain = useSelector(selectTransferSourceChain);
const chains = useMemo(
() => CHAINS.filter((c) => c.id !== sourceChain),
[sourceChain]
);
const {
targetChain,
targetAsset,
tokenName,
symbol,
logo,
readableTargetAddress,
} = useTargetInfo();
const uiAmountString = useSelector(selectTransferTargetBalanceString);
const transferAmount = useSelector(selectTransferAmount);
const error = useSelector(selectTransferTargetError);

View File

@ -1,12 +1,7 @@
import { hexToNativeString } from "@certusone/wormhole-sdk";
import { makeStyles, Typography } from "@material-ui/core";
import { useSelector } from "react-redux";
import {
selectTransferTargetAddressHex,
selectTransferTargetChain,
} from "../../store/selectors";
import { CHAINS_BY_ID } from "../../utils/consts";
import SmartAddress from "../SmartAddress";
import { useTargetInfo } from "./Target";
const useStyles = makeStyles((theme) => ({
description: {
@ -16,15 +11,32 @@ const useStyles = makeStyles((theme) => ({
export default function TargetPreview() {
const classes = useStyles();
const targetChain = useSelector(selectTransferTargetChain);
const targetAddress = useSelector(selectTransferTargetAddressHex);
const targetAddressNative = hexToNativeString(targetAddress, targetChain);
const {
targetChain,
readableTargetAddress,
targetAsset,
symbol,
tokenName,
logo,
} = useTargetInfo();
const explainerContent =
targetChain && targetAddressNative ? (
targetChain && readableTargetAddress ? (
<>
{targetAsset ? (
<>
<span>and receive</span>
<SmartAddress
chainId={targetChain}
address={targetAsset}
symbol={symbol}
tokenName={tokenName}
logo={logo}
/>
</>
) : null}
<span>to</span>
<SmartAddress chainId={targetChain} address={targetAddressNative} />
<SmartAddress chainId={targetChain} address={readableTargetAddress} />
<span>on {CHAINS_BY_ID[targetChain].name}</span>
</>
) : (