bridge_ui: max button for number inputs
Change-Id: I4fdbb2b3191a012cbdf02df4ad6292c78eed5bb7
This commit is contained in:
parent
5ecdde62e1
commit
cff4d928b6
|
@ -1,10 +1,5 @@
|
||||||
import { ChainId } from "@certusone/wormhole-sdk";
|
import { ChainId } from "@certusone/wormhole-sdk";
|
||||||
import {
|
import { CircularProgress, makeStyles, Typography } from "@material-ui/core";
|
||||||
CircularProgress,
|
|
||||||
makeStyles,
|
|
||||||
TextField,
|
|
||||||
Typography,
|
|
||||||
} from "@material-ui/core";
|
|
||||||
import { Alert } from "@material-ui/lab";
|
import { Alert } from "@material-ui/lab";
|
||||||
import { parseUnits } from "ethers/lib/utils";
|
import { parseUnits } from "ethers/lib/utils";
|
||||||
import { useSnackbar } from "notistack";
|
import { useSnackbar } from "notistack";
|
||||||
|
@ -14,6 +9,7 @@ import useEthereumMigratorInformation from "../../hooks/useEthereumMigratorInfor
|
||||||
import useIsWalletReady from "../../hooks/useIsWalletReady";
|
import useIsWalletReady from "../../hooks/useIsWalletReady";
|
||||||
import ButtonWithLoader from "../ButtonWithLoader";
|
import ButtonWithLoader from "../ButtonWithLoader";
|
||||||
import EthereumSignerKey from "../EthereumSignerKey";
|
import EthereumSignerKey from "../EthereumSignerKey";
|
||||||
|
import NumberTextField from "../NumberTextField";
|
||||||
import ShowTx from "../ShowTx";
|
import ShowTx from "../ShowTx";
|
||||||
import SmartAddress from "../SmartAddress";
|
import SmartAddress from "../SmartAddress";
|
||||||
|
|
||||||
|
@ -49,6 +45,7 @@ export default function EvmWorkflow({
|
||||||
signerAddress,
|
signerAddress,
|
||||||
toggleRefresh
|
toggleRefresh
|
||||||
);
|
);
|
||||||
|
const fromWalletBalance = poolInfo.data?.fromWalletBalance;
|
||||||
|
|
||||||
const [migrationAmount, setMigrationAmount] = useState("");
|
const [migrationAmount, setMigrationAmount] = useState("");
|
||||||
const [migrationIsProcessing, setMigrationIsProcessing] = useState(false);
|
const [migrationIsProcessing, setMigrationIsProcessing] = useState(false);
|
||||||
|
@ -69,9 +66,9 @@ export default function EvmWorkflow({
|
||||||
const hasRequisiteData = poolInfo.data;
|
const hasRequisiteData = poolInfo.data;
|
||||||
const amountGreaterThanZero = fromParse(migrationAmount) > BigInt(0);
|
const amountGreaterThanZero = fromParse(migrationAmount) > BigInt(0);
|
||||||
const sufficientFromTokens =
|
const sufficientFromTokens =
|
||||||
poolInfo.data?.fromWalletBalance &&
|
fromWalletBalance &&
|
||||||
migrationAmount &&
|
migrationAmount &&
|
||||||
fromParse(migrationAmount) <= fromParse(poolInfo.data.fromWalletBalance);
|
fromParse(migrationAmount) <= fromParse(fromWalletBalance);
|
||||||
const sufficientPoolBalance =
|
const sufficientPoolBalance =
|
||||||
poolInfo.data?.toPoolBalance &&
|
poolInfo.data?.toPoolBalance &&
|
||||||
migrationAmount &&
|
migrationAmount &&
|
||||||
|
@ -106,6 +103,11 @@ export default function EvmWorkflow({
|
||||||
(event) => setMigrationAmount(event.target.value),
|
(event) => setMigrationAmount(event.target.value),
|
||||||
[setMigrationAmount]
|
[setMigrationAmount]
|
||||||
);
|
);
|
||||||
|
const handleMaxClick = useCallback(() => {
|
||||||
|
if (fromWalletBalance) {
|
||||||
|
setMigrationAmount(fromWalletBalance);
|
||||||
|
}
|
||||||
|
}, [fromWalletBalance]);
|
||||||
|
|
||||||
const migrateTokens = useCallback(async () => {
|
const migrateTokens = useCallback(async () => {
|
||||||
if (!poolInfo.data) {
|
if (!poolInfo.data) {
|
||||||
|
@ -170,8 +172,7 @@ export default function EvmWorkflow({
|
||||||
<div>
|
<div>
|
||||||
<Typography>This action will convert</Typography>
|
<Typography>This action will convert</Typography>
|
||||||
<Typography variant="h6">
|
<Typography variant="h6">
|
||||||
{fromTokenPretty}{" "}
|
{fromTokenPretty} {`(Balance: ${fromWalletBalance || ""})`}
|
||||||
{`(Balance: ${poolInfo.data?.fromWalletBalance || ""})`}
|
|
||||||
</Typography>
|
</Typography>
|
||||||
<div className={classes.spacer} />
|
<div className={classes.spacer} />
|
||||||
<Typography>to</Typography>
|
<Typography>to</Typography>
|
||||||
|
@ -190,14 +191,14 @@ export default function EvmWorkflow({
|
||||||
<>
|
<>
|
||||||
{explainerContent}
|
{explainerContent}
|
||||||
<div className={classes.spacer} />
|
<div className={classes.spacer} />
|
||||||
<TextField
|
<NumberTextField
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
value={migrationAmount}
|
value={migrationAmount}
|
||||||
type="number"
|
|
||||||
onChange={handleAmountChange}
|
onChange={handleAmountChange}
|
||||||
label={"Amount"}
|
label={"Amount"}
|
||||||
disabled={!!migrationIsProcessing || !!transaction}
|
disabled={!!migrationIsProcessing || !!transaction}
|
||||||
></TextField>
|
onMaxClick={fromWalletBalance ? handleMaxClick : undefined}
|
||||||
|
/>
|
||||||
|
|
||||||
{!transaction && (
|
{!transaction && (
|
||||||
<ButtonWithLoader
|
<ButtonWithLoader
|
||||||
|
|
|
@ -2,7 +2,7 @@ import { CHAIN_ID_SOLANA } from "@certusone/wormhole-sdk";
|
||||||
import migrateTokensTx from "@certusone/wormhole-sdk/lib/migration/migrateTokens";
|
import migrateTokensTx from "@certusone/wormhole-sdk/lib/migration/migrateTokens";
|
||||||
import getPoolAddress from "@certusone/wormhole-sdk/lib/migration/poolAddress";
|
import getPoolAddress from "@certusone/wormhole-sdk/lib/migration/poolAddress";
|
||||||
import getToCustodyAddress from "@certusone/wormhole-sdk/lib/migration/toCustodyAddress";
|
import getToCustodyAddress from "@certusone/wormhole-sdk/lib/migration/toCustodyAddress";
|
||||||
import { makeStyles, TextField, Typography } from "@material-ui/core";
|
import { makeStyles, Typography } from "@material-ui/core";
|
||||||
import {
|
import {
|
||||||
ASSOCIATED_TOKEN_PROGRAM_ID,
|
ASSOCIATED_TOKEN_PROGRAM_ID,
|
||||||
Token,
|
Token,
|
||||||
|
@ -19,6 +19,7 @@ import { COLORS } from "../../muiTheme";
|
||||||
import { MIGRATION_PROGRAM_ADDRESS, SOLANA_HOST } from "../../utils/consts";
|
import { MIGRATION_PROGRAM_ADDRESS, SOLANA_HOST } from "../../utils/consts";
|
||||||
import { getMultipleAccounts, signSendAndConfirm } from "../../utils/solana";
|
import { getMultipleAccounts, signSendAndConfirm } from "../../utils/solana";
|
||||||
import ButtonWithLoader from "../ButtonWithLoader";
|
import ButtonWithLoader from "../ButtonWithLoader";
|
||||||
|
import NumberTextField from "../NumberTextField";
|
||||||
import ShowTx from "../ShowTx";
|
import ShowTx from "../ShowTx";
|
||||||
import SmartAddress from "../SmartAddress";
|
import SmartAddress from "../SmartAddress";
|
||||||
import SolanaCreateAssociatedAddress, {
|
import SolanaCreateAssociatedAddress, {
|
||||||
|
@ -358,6 +359,11 @@ export default function Workflow({
|
||||||
(event) => setMigrationAmount(event.target.value),
|
(event) => setMigrationAmount(event.target.value),
|
||||||
[setMigrationAmount]
|
[setMigrationAmount]
|
||||||
);
|
);
|
||||||
|
const handleMaxClick = useCallback(() => {
|
||||||
|
if (fromTokenAccountBalance) {
|
||||||
|
setMigrationAmount(fromTokenAccountBalance);
|
||||||
|
}
|
||||||
|
}, [fromTokenAccountBalance]);
|
||||||
|
|
||||||
const getMetadata = (address: string) => {
|
const getMetadata = (address: string) => {
|
||||||
const tokenMapItem = solanaTokenMap.data?.find(
|
const tokenMapItem = solanaTokenMap.data?.find(
|
||||||
|
@ -459,14 +465,14 @@ export default function Workflow({
|
||||||
</>
|
</>
|
||||||
) : null}
|
) : null}
|
||||||
<div className={classes.spacer} />
|
<div className={classes.spacer} />
|
||||||
<TextField
|
<NumberTextField
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
value={migrationAmount}
|
value={migrationAmount}
|
||||||
type="number"
|
|
||||||
onChange={handleAmountChange}
|
onChange={handleAmountChange}
|
||||||
label={"Amount"}
|
label={"Amount"}
|
||||||
disabled={!!migrationIsProcessing || !!transaction}
|
disabled={!!migrationIsProcessing || !!transaction}
|
||||||
></TextField>
|
onMaxClick={fromTokenAccountBalance ? handleMaxClick : undefined}
|
||||||
|
/>
|
||||||
|
|
||||||
{!transaction && (
|
{!transaction && (
|
||||||
<ButtonWithLoader
|
<ButtonWithLoader
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
import {
|
||||||
|
Button,
|
||||||
|
InputAdornment,
|
||||||
|
TextField,
|
||||||
|
TextFieldProps,
|
||||||
|
} from "@material-ui/core";
|
||||||
|
|
||||||
|
export default function NumberTextField(
|
||||||
|
props: TextFieldProps & { onMaxClick?: () => void }
|
||||||
|
) {
|
||||||
|
return (
|
||||||
|
<TextField
|
||||||
|
type="number"
|
||||||
|
{...props}
|
||||||
|
InputProps={{
|
||||||
|
endAdornment: props.onMaxClick ? (
|
||||||
|
<InputAdornment position="end">
|
||||||
|
<Button
|
||||||
|
onClick={props.onMaxClick}
|
||||||
|
disabled={props.disabled}
|
||||||
|
variant="outlined"
|
||||||
|
>
|
||||||
|
Max
|
||||||
|
</Button>
|
||||||
|
</InputAdornment>
|
||||||
|
) : undefined,
|
||||||
|
...(props?.InputProps || {}),
|
||||||
|
}}
|
||||||
|
></TextField>
|
||||||
|
);
|
||||||
|
}
|
|
@ -4,7 +4,7 @@ import {
|
||||||
CHAIN_ID_SOLANA,
|
CHAIN_ID_SOLANA,
|
||||||
} from "@certusone/wormhole-sdk";
|
} from "@certusone/wormhole-sdk";
|
||||||
import { getAddress } from "@ethersproject/address";
|
import { getAddress } from "@ethersproject/address";
|
||||||
import { Button, makeStyles, TextField } from "@material-ui/core";
|
import { Button, makeStyles } from "@material-ui/core";
|
||||||
import { useCallback } from "react";
|
import { useCallback } from "react";
|
||||||
import { useDispatch, useSelector } from "react-redux";
|
import { useDispatch, useSelector } from "react-redux";
|
||||||
import { useHistory } from "react-router";
|
import { useHistory } from "react-router";
|
||||||
|
@ -33,6 +33,7 @@ import ButtonWithLoader from "../ButtonWithLoader";
|
||||||
import ChainSelect from "../ChainSelect";
|
import ChainSelect from "../ChainSelect";
|
||||||
import KeyAndBalance from "../KeyAndBalance";
|
import KeyAndBalance from "../KeyAndBalance";
|
||||||
import LowBalanceWarning from "../LowBalanceWarning";
|
import LowBalanceWarning from "../LowBalanceWarning";
|
||||||
|
import NumberTextField from "../NumberTextField";
|
||||||
import StepDescription from "../StepDescription";
|
import StepDescription from "../StepDescription";
|
||||||
import { TokenSelector } from "../TokenSelectors/SourceTokenSelector";
|
import { TokenSelector } from "../TokenSelectors/SourceTokenSelector";
|
||||||
import TokenWarning from "./TokenWarning";
|
import TokenWarning from "./TokenWarning";
|
||||||
|
@ -95,6 +96,11 @@ function Source() {
|
||||||
},
|
},
|
||||||
[dispatch]
|
[dispatch]
|
||||||
);
|
);
|
||||||
|
const handleMaxClick = useCallback(() => {
|
||||||
|
if (uiAmountString) {
|
||||||
|
dispatch(setAmount(uiAmountString));
|
||||||
|
}
|
||||||
|
}, [dispatch, uiAmountString]);
|
||||||
const handleNextClick = useCallback(() => {
|
const handleNextClick = useCallback(() => {
|
||||||
dispatch(incrementStep());
|
dispatch(incrementStep());
|
||||||
}, [dispatch]);
|
}, [dispatch]);
|
||||||
|
@ -136,15 +142,15 @@ function Source() {
|
||||||
/>
|
/>
|
||||||
<LowBalanceWarning chainId={sourceChain} />
|
<LowBalanceWarning chainId={sourceChain} />
|
||||||
{hasParsedTokenAccount ? (
|
{hasParsedTokenAccount ? (
|
||||||
<TextField
|
<NumberTextField
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
label="Amount"
|
label="Amount"
|
||||||
type="number"
|
|
||||||
fullWidth
|
fullWidth
|
||||||
className={classes.transferField}
|
className={classes.transferField}
|
||||||
value={amount}
|
value={amount}
|
||||||
onChange={handleAmountChange}
|
onChange={handleAmountChange}
|
||||||
disabled={shouldLockFields}
|
disabled={shouldLockFields}
|
||||||
|
onMaxClick={uiAmountString ? handleMaxClick : undefined}
|
||||||
/>
|
/>
|
||||||
) : null}
|
) : null}
|
||||||
<ButtonWithLoader
|
<ButtonWithLoader
|
||||||
|
|
Loading…
Reference in New Issue