Added modal to select token chain

This commit is contained in:
juan 2021-03-10 11:36:22 -05:00
parent 979a369f6a
commit b3a0dabf4b
5 changed files with 137 additions and 61 deletions

View File

@ -1,12 +1,9 @@
import React, { useState } from 'react'; import React, { useState } from 'react';
import { NumericInput } from '@oyster/common'; import { NumericInput } from '@oyster/common';
import { Card, Select } from 'antd'; import { Card } from 'antd';
import './style.less'; import './style.less';
import { useEthereum } from '../../contexts';
import { TokenDisplay } from '../TokenDisplay';
import { ASSET_CHAIN } from '../../models/bridge/constants'; import { ASSET_CHAIN } from '../../models/bridge/constants';
import { TokenSelectModal } from '../TokenSelectModal';
const { Option } = Select;
export function Input(props: { export function Input(props: {
title: string; title: string;
@ -18,33 +15,6 @@ export function Input(props: {
onInputChange: (value: number | undefined) => void; onInputChange: (value: number | undefined) => void;
}) { }) {
const [lastAmount, setLastAmount] = useState<string>(''); const [lastAmount, setLastAmount] = useState<string>('');
const { tokens } = useEthereum();
const renderReserveAccounts = tokens
.filter(t => (t.tags?.indexOf('longList') || -1) < 0)
.map(token => {
const mint = token.address;
return (
<Option
key={mint}
className="multichain-option"
value={mint}
name={token.symbol}
title={token.name}
>
<div className="multichain-option-content">
<TokenDisplay
asset={props.asset}
token={token}
chain={props.chain}
/>
<div className="multichain-option-name">
<span className={'token-name'}>{token.symbol}</span>
</div>
</div>
</Option>
);
});
return ( return (
<Card <Card
@ -58,7 +28,9 @@ export function Input(props: {
{!!props.balance && ( {!!props.balance && (
<div <div
className="ccy-input-header-right" className="ccy-input-header-right"
onClick={() => props.onInputChange && props.onInputChange(props.balance)} onClick={() =>
props.onInputChange && props.onInputChange(props.balance)
}
> >
Balance: {props.balance.toFixed(6)} Balance: {props.balance.toFixed(6)}
</div> </div>
@ -90,21 +62,11 @@ export function Input(props: {
placeholder="0.00" placeholder="0.00"
/> />
<div className="ccy-input-header-right" style={{ display: 'flex' }}> <div className="ccy-input-header-right" style={{ display: 'flex' }}>
<Select <TokenSelectModal
size="large" onSelectToken={token => props.setAsset(token)}
showSearch asset={props.asset}
style={{ minWidth: 150 }} chain={props.chain}
placeholder="CCY" />
value={props.asset}
onChange={(item: string) => {
props.setAsset(item);
}}
filterOption={(input, option) =>
option?.name?.toLowerCase().indexOf(input.toLowerCase()) >= 0
}
>
{renderReserveAccounts}
</Select>
</div> </div>
</div> </div>
</Card> </Card>

View File

@ -0,0 +1,104 @@
import React, { useMemo, useState } from 'react';
import './style.less';
import { Modal, Input } from 'antd';
import { useEthereum } from '../../contexts';
import { TokenDisplay } from '../TokenDisplay';
import { ASSET_CHAIN } from '../../models/bridge/constants';
export const TokenSelectModal = (props: {
onSelectToken: (token: string) => void;
asset?: string;
chain?: ASSET_CHAIN;
}) => {
const { tokens } = useEthereum();
const [isModalVisible, setIsModalVisible] = useState<boolean>(false);
const [selected, setSelected] = useState<string>('');
const [search, setSearch] = useState<string>('');
const showModal = () => {
setIsModalVisible(true);
};
const hideModal = () => {
setIsModalVisible(false);
};
const firstToken = useMemo(() => {
if (!selected) {
return tokens.find(el => el.address === props.asset);
}
return tokens.find(el => el.address === selected);
}, [selected, tokens, props.asset]);
const renderTokensChain = useMemo(() => {
return tokens
.filter(
t =>
(t.tags?.indexOf('longList') || -1) < 0 &&
search &&
search.length >= 3 &&
t.symbol.includes(search.toUpperCase()),
)
.map(token => {
const mint = token.address;
return (
<div
key={mint}
className="multichain-option"
title={token.name}
onClick={() => {
props.onSelectToken(mint);
setSelected(mint);
hideModal();
}}
style={{ cursor: 'pointer' }}
>
<div className="multichain-option-content">
<TokenDisplay
asset={props.asset}
token={token}
chain={props.chain}
/>
<div className="multichain-option-name">
<span className={'token-name'}>{token.symbol}</span>
</div>
</div>
</div>
);
});
}, [search, tokens]);
return (
<>
{firstToken ? (
<div
key={firstToken.address}
className="multichain-option"
title={firstToken.name}
onClick={() => showModal()}
style={{ cursor: 'pointer' }}
>
<div className="multichain-option-content">
<TokenDisplay
asset={props.asset}
token={firstToken}
chain={props.chain}
/>
</div>
</div>
) : null}
<Modal
visible={isModalVisible}
onCancel={() => hideModal()}
footer={null}
>
<Input
className={'input-token-search'}
placeholder={'ETH, SOL, ... etc'}
value={search}
onChange={e => setSearch(e.target.value)}
/>
<div className={'assets-scroll'}>{[...renderTokensChain]}</div>
</Modal>
</>
);
};

View File

@ -0,0 +1,7 @@
.input-token-search {
margin: 20px 0 20px 0;
}
.assets-scroll {
height: 60vh;
overflow: auto;
}

View File

@ -46,13 +46,13 @@ export const Transfer = () => {
}); });
useEffect(() => { useEffect(() => {
if(tokens && !request.asset) { if (tokens && !request.asset) {
setRequest({ setRequest({
...request, ...request,
asset: tokens?.[0]?.address, asset: tokens?.[0]?.address,
}); });
} }
}, [request, tokens, setRequest]) }, [request, tokens, setRequest]);
const setAssetInformation = async (asset: string) => { const setAssetInformation = async (asset: string) => {
setRequest({ setRequest({
@ -63,7 +63,7 @@ export const Transfer = () => {
useEffect(() => { useEffect(() => {
const asset = request.asset; const asset = request.asset;
if(!asset || asset === request?.info?.address) { if (!asset || asset === request?.info?.address) {
return; return;
} }
@ -87,9 +87,10 @@ export const Transfer = () => {
address: asset, address: asset,
name: symbol, name: symbol,
balance: balance, balance: balance,
balanceAsNumber: (new BN(balance.toString()) balanceAsNumber:
.div(new BN(10).pow(new BN(decimals - 2))) new BN(balance.toString())
.toNumber()) / 100, .div(new BN(10).pow(new BN(decimals - 2)))
.toNumber() / 100,
allowance: allowance, allowance: allowance,
decimals: decimals, decimals: decimals,
isWrapped: false, isWrapped: false,
@ -103,7 +104,10 @@ export const Transfer = () => {
let isWrapped = await b.isWrappedAsset(asset); let isWrapped = await b.isWrappedAsset(asset);
if (isWrapped) { if (isWrapped) {
info.chainID = await e.assetChain(); info.chainID = await e.assetChain();
info.assetAddress = Buffer.from((await e.assetAddress()).slice(2), 'hex'); info.assetAddress = Buffer.from(
(await e.assetAddress()).slice(2),
'hex',
);
info.isWrapped = true; info.isWrapped = true;
} }
@ -113,7 +117,7 @@ export const Transfer = () => {
info, info,
}); });
})(); })();
}, [request, provider]) }, [request, provider]);
return ( return (
<> <>
@ -122,7 +126,7 @@ export const Transfer = () => {
title={`From ${chainToName(request.from)}`} title={`From ${chainToName(request.from)}`}
asset={request.asset} asset={request.asset}
chain={request.from} chain={request.from}
balance={request.info?.balanceAsNumber || 0 } balance={request.info?.balanceAsNumber || 0}
setAsset={asset => setAssetInformation(asset)} setAsset={asset => setAssetInformation(asset)}
amount={request.amount} amount={request.amount}
onInputChange={amount => { onInputChange={amount => {
@ -179,7 +183,7 @@ export const Transfer = () => {
(async () => { (async () => {
let steps: ProgressUpdate[] = []; let steps: ProgressUpdate[] = [];
try { try {
if(request.toChain === ASSET_CHAIN.Solana) { if (request.toChain === ASSET_CHAIN.Solana) {
await toSolana( await toSolana(
connection, connection,
wallet, wallet,
@ -211,8 +215,7 @@ export const Transfer = () => {
request.toChain, request.toChain,
)} Mainnet`}</h5> )} Mainnet`}</h5>
<h2> <h2>
{request.amount?.toString()}{' '} {request.amount?.toString()} {request.info?.name}
{request.info?.name}
</h2> </h2>
</div> </div>
<div <div

View File

@ -93,7 +93,7 @@ export const EthereumProvider: FunctionComponent = ({ children }) => {
window.ethereum.enable(); window.ethereum.enable();
// @ts-ignore // @ts-ignore
const provider = new ethers.providers.Web3Provider( const provider = new ethers.providers.Web3Provider(
(window as any).ethereum , (window as any).ethereum,
); );
const signer = provider.getSigner(); const signer = provider.getSigner();
signer.getAddress().then(account => setAccounts([account])); signer.getAddress().then(account => setAccounts([account]));