From c565152c1317991e94ac5c8fbdafc75666ed8ef6 Mon Sep 17 00:00:00 2001 From: Evan Gray Date: Mon, 27 Sep 2021 15:18:45 -0400 Subject: [PATCH] bridge_ui: token picker styling imrpovements fixes https://github.com/certusone/wormhole/issues/484 fixes https://github.com/certusone/wormhole/issues/490 fixes https://github.com/certusone/wormhole/issues/487 Change-Id: I7405e17371dfde2921e63604d8353ebffed975c9 --- .../EthereumSourceTokenSelector.tsx | 51 +++++-- .../SolanaSourceTokenSelector.tsx | 135 ++++++++++++------ .../TerraSourceTokenSelector.tsx | 25 +++- bridge_ui/src/utils/sort.ts | 17 +++ 4 files changed, 163 insertions(+), 65 deletions(-) create mode 100644 bridge_ui/src/utils/sort.ts diff --git a/bridge_ui/src/components/TokenSelectors/EthereumSourceTokenSelector.tsx b/bridge_ui/src/components/TokenSelectors/EthereumSourceTokenSelector.tsx index 03f20e67e..13a9345a8 100644 --- a/bridge_ui/src/components/TokenSelectors/EthereumSourceTokenSelector.tsx +++ b/bridge_ui/src/components/TokenSelectors/EthereumSourceTokenSelector.tsx @@ -7,7 +7,7 @@ import { Typography, } from "@material-ui/core"; import { Autocomplete, createFilterOptions } from "@material-ui/lab"; -import React, { useCallback, useEffect, useState } from "react"; +import React, { useCallback, useEffect, useMemo, useState } from "react"; import { useEthereumProvider } from "../../contexts/EthereumProviderContext"; import { CovalentData } from "../../hooks/useGetSourceParsedTokenAccounts"; import { DataWrapper } from "../../store/helpers"; @@ -28,18 +28,34 @@ import NFTViewer from "./NFTViewer"; import { useDebounce } from "use-debounce/lib"; import RefreshButtonWrapper from "./RefreshButtonWrapper"; import { CHAIN_ID_ETH } from "@certusone/wormhole-sdk"; +import { sortParsedTokenAccounts } from "../../utils/sort"; -const useStyles = makeStyles(() => +const useStyles = makeStyles((theme) => createStyles({ selectInput: { minWidth: "10rem" }, tokenOverviewContainer: { display: "flex", + width: "100%", + alignItems: "center", "& div": { - margin: ".5rem", + margin: theme.spacing(1), + flexBasis: "33%", + "&$tokenImageContainer": { + maxWidth: 40, + }, + "&:last-child": { + textAlign: "right", + }, }, }, + tokenImageContainer: { + display: "flex", + alignItems: "center", + justifyContent: "center", + width: 40, + }, tokenImage: { - maxHeight: "2.5rem", + maxHeight: "2.5rem", //Eyeballing this based off the text size }, }) ); @@ -86,7 +102,7 @@ const renderAccount = ( const symbol = getSymbol(account) || "Unknown"; return (
-
+
{uri && }
@@ -119,7 +135,7 @@ const renderNFTAccount = ( const name = account.name || "Unknown"; return (
-
+
{uri && }
@@ -437,9 +453,19 @@ export default function EthereumSourceTokenSelector( setAdvancedMode(!advancedMode); }; - const handleAutocompleteChange = (newValue: ParsedTokenAccount | null) => { - setAutocompleteHolder(newValue); - }; + const handleAutocompleteChange = useCallback( + (event, newValue: ParsedTokenAccount | null) => { + setAutocompleteHolder(newValue); + }, + [] + ); + + const tokenAccountsData = tokenAccounts?.data; + const sortedOptions = useMemo(() => { + const options = tokenAccountsData || []; + options.sort(sortParsedTokenAccounts); + return options; + }, [tokenAccountsData]); const isLoading = props.covalent?.isFetching || props.tokenAccounts?.isFetching; @@ -449,22 +475,19 @@ export default function EthereumSourceTokenSelector( { - handleAutocompleteChange(newValue); - }} + onChange={handleAutocompleteChange} disabled={disabled} noOptionsText={ nft ? "No ERC-721 tokens found at the moment." : "No ERC-20 tokens found at the moment." } - options={tokenAccounts?.data || []} + options={sortedOptions} renderInput={(params) => ( )} diff --git a/bridge_ui/src/components/TokenSelectors/SolanaSourceTokenSelector.tsx b/bridge_ui/src/components/TokenSelectors/SolanaSourceTokenSelector.tsx index cf18b5cb1..5333aaabe 100644 --- a/bridge_ui/src/components/TokenSelectors/SolanaSourceTokenSelector.tsx +++ b/bridge_ui/src/components/TokenSelectors/SolanaSourceTokenSelector.tsx @@ -1,6 +1,11 @@ import { CHAIN_ID_SOLANA } from "@certusone/wormhole-sdk"; -import { CircularProgress, TextField, Typography } from "@material-ui/core"; -import { createStyles, makeStyles, Theme } from "@material-ui/core/styles"; +import { + CircularProgress, + TextField, + Typography, + createStyles, + makeStyles, +} from "@material-ui/core"; import { Alert, Autocomplete } from "@material-ui/lab"; import { createFilterOptions } from "@material-ui/lab/Autocomplete"; import { TokenInfo } from "@solana/spl-token-registry"; @@ -15,21 +20,46 @@ import { WORMHOLE_V1_MINT_AUTHORITY, } from "../../utils/consts"; import { ExtractedMintInfo, shortenAddress } from "../../utils/solana"; +import { sortParsedTokenAccounts } from "../../utils/sort"; import NFTViewer from "./NFTViewer"; import RefreshButtonWrapper from "./RefreshButtonWrapper"; -const useStyles = makeStyles((theme: Theme) => +const useStyles = makeStyles((theme) => createStyles({ selectInput: { minWidth: "10rem" }, tokenOverviewContainer: { display: "flex", + width: "100%", + alignItems: "center", "& div": { - margin: ".5rem", + margin: theme.spacing(1), + flexBasis: "33%", + "&$tokenImageContainer": { + maxWidth: 40, + }, + "&:last-child": { + textAlign: "right", + }, }, }, + tokenImageContainer: { + display: "flex", + alignItems: "center", + justifyContent: "center", + width: 40, + }, tokenImage: { maxHeight: "2.5rem", //Eyeballing this based off the text size }, + v1Warning: { + width: "100%", + }, + migrationAlert: { + width: "100%", + "& .MuiAlert-message": { + width: "100%", + }, + }, }) ); @@ -169,39 +199,39 @@ export default function SolanaSourceTokenSelector( const name = getName(account) || "--"; const content = ( - <> -
-
- {uri && } -
-
- {symbol} - {name} -
-
- {account.isNativeAsset ? ( - {"Native"} - ) : ( - <> - - {"Mint : " + mintPrettyString} - - - {"Account :" + accountAddressPrettyString} - - - )} -
+
+
+ {uri && } +
+
+ {symbol} + {name} +
+
+ {account.isNativeAsset ? ( + {"Native"} + ) : ( + <> + + {"Mint : " + mintPrettyString} + + + {"Account :" + accountAddressPrettyString} + + + )} +
+ {nft ? null : (
{"Balance"} {account.uiAmountString}
-
- + )} +
); const v1Warning = ( -
+
Wormhole v1 tokens are not eligible for transfer. @@ -210,7 +240,7 @@ export default function SolanaSourceTokenSelector( ); const migrationRender = ( -
+
This is a legacy asset eligible for migration. @@ -226,7 +256,15 @@ export default function SolanaSourceTokenSelector( ? v1Warning : content; }, - [getLogo, getSymbol, getName, classes, isWormholev1, isMigrationEligible] + [ + getLogo, + getSymbol, + getName, + classes, + isWormholev1, + isMigrationEligible, + nft, + ] ); //The autocomplete doesn't rerender the option label unless the value changes. @@ -244,18 +282,26 @@ export default function SolanaSourceTokenSelector( //This exists to remove NFTs from the list of potential options. It requires reading the metaplex data, so it would be //difficult to do before this point. const filteredOptions = useMemo(() => { - return props.accounts.filter((x) => { - const zeroBalance = x.amount === "0"; - if (zeroBalance) { - return false; - } - const isNFT = - x.decimals === 0 && - metaplex.data?.get(x.mintKey)?.data?.uri && - mintAccounts?.data?.get(x.mintKey)?.supply === "1"; - return nft ? isNFT : !isNFT; - }); - }, [mintAccounts?.data, metaplex.data, nft, props.accounts]); + const tokenList = props.accounts + .filter((x) => { + const zeroBalance = x.amount === "0"; + if (zeroBalance) { + return false; + } + const isNFT = + x.decimals === 0 && + metaplex.data?.get(x.mintKey)?.data?.uri && + mintAccounts?.data?.get(x.mintKey)?.supply === "1"; + return nft ? isNFT : !isNFT; + }) + .map((account) => ({ + ...account, + symbol: account.symbol || getSymbol(account) || undefined, + })); + tokenList.sort(sortParsedTokenAccounts); + return tokenList; + }, [mintAccounts?.data, metaplex.data, nft, props.accounts, getSymbol]); + console.log(filteredOptions); const isOptionDisabled = useMemo(() => { return (value: ParsedTokenAccount) => { @@ -314,7 +360,6 @@ export default function SolanaSourceTokenSelector( +const useStyles = makeStyles((theme) => createStyles({ selectInput: { minWidth: "10rem" }, tokenOverviewContainer: { display: "flex", + width: "100%", + alignItems: "center", "& div": { - margin: ".5rem", + margin: theme.spacing(1), + "&$tokenImageContainer": { + maxWidth: 40, + }, }, }, + tokenImageContainer: { + display: "flex", + alignItems: "center", + justifyContent: "center", + width: 40, + }, tokenImage: { - maxHeight: "2.5rem", + maxHeight: "2.5rem", //Eyeballing this based off the text size + }, + tokenSymbolContainer: { + flexBasis: 112, }, }) ); @@ -168,10 +182,10 @@ export default function TerraSourceTokenSelector( const renderOption = (option: TerraTokenMetadata) => { return (
-
+
-
+
{option.symbol} {option.protocol}
@@ -200,7 +214,6 @@ export default function TerraSourceTokenSelector( + a.isNativeAsset && !b.isNativeAsset + ? -1 + : !a.isNativeAsset && b.isNativeAsset + ? 1 + : a.symbol && b.symbol + ? a.symbol.localeCompare(b.symbol) + : a.symbol + ? -1 + : b.symbol + ? 1 + : 0;