mirror of https://github.com/certusone/oyster.git
Merge pull request #18 from yamijuan/transfer-ui
Added virtualized list and debounce search on token modal
This commit is contained in:
commit
4b7176302d
|
@ -20,6 +20,7 @@
|
||||||
"@types/chart.js": "^2.9.29",
|
"@types/chart.js": "^2.9.29",
|
||||||
"@types/echarts": "^4.9.0",
|
"@types/echarts": "^4.9.0",
|
||||||
"@types/react-router-dom": "^5.1.6",
|
"@types/react-router-dom": "^5.1.6",
|
||||||
|
"@types/react-virtualized": "^9.21.11",
|
||||||
"@types/testing-library__react": "^10.2.0",
|
"@types/testing-library__react": "^10.2.0",
|
||||||
"@uniswap/token-lists": "^1.0.0-beta.19",
|
"@uniswap/token-lists": "^1.0.0-beta.19",
|
||||||
"@walletconnect/client": "^1.3.6",
|
"@walletconnect/client": "^1.3.6",
|
||||||
|
@ -52,6 +53,7 @@
|
||||||
"react-router-dom": "^5.2.0",
|
"react-router-dom": "^5.2.0",
|
||||||
"react-scripts": "3.4.3",
|
"react-scripts": "3.4.3",
|
||||||
"react-three-fiber": "^5.3.18",
|
"react-three-fiber": "^5.3.18",
|
||||||
|
"react-virtualized": "^9.22.3",
|
||||||
"three": "^0.125.2",
|
"three": "^0.125.2",
|
||||||
"typescript": "^4.1.3",
|
"typescript": "^4.1.3",
|
||||||
"use-wallet": "^0.8.1"
|
"use-wallet": "^0.8.1"
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
|
|
||||||
.multichain-option-name {
|
.multichain-option-name {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ccy-input {
|
.ccy-input {
|
||||||
|
|
|
@ -1,4 +1,7 @@
|
||||||
import React, { useMemo, useState } from 'react';
|
import React, { useMemo, useState } from 'react';
|
||||||
|
import List from 'react-virtualized/dist/commonjs/List';
|
||||||
|
import AutoSizer from 'react-virtualized/dist/commonjs/AutoSizer';
|
||||||
|
import _ from 'lodash';
|
||||||
import './style.less';
|
import './style.less';
|
||||||
import { Modal, Input } from 'antd';
|
import { Modal, Input } from 'antd';
|
||||||
import { useEthereum } from '../../contexts';
|
import { useEthereum } from '../../contexts';
|
||||||
|
@ -15,6 +18,18 @@ export const TokenSelectModal = (props: {
|
||||||
const [selected, setSelected] = useState<string>('');
|
const [selected, setSelected] = useState<string>('');
|
||||||
const [search, setSearch] = useState<string>('');
|
const [search, setSearch] = useState<string>('');
|
||||||
|
|
||||||
|
const tokenList = useMemo(() => {
|
||||||
|
if (tokens && search) {
|
||||||
|
return tokens.filter(token => {
|
||||||
|
return (
|
||||||
|
(token.tags?.indexOf('longList') || -1) < 0 &&
|
||||||
|
token.symbol.includes(search.toUpperCase())
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return tokens;
|
||||||
|
}, [tokens, search]);
|
||||||
|
|
||||||
const showModal = () => {
|
const showModal = () => {
|
||||||
setIsModalVisible(true);
|
setIsModalVisible(true);
|
||||||
};
|
};
|
||||||
|
@ -29,43 +44,38 @@ export const TokenSelectModal = (props: {
|
||||||
return tokens.find(el => el.address === selected);
|
return tokens.find(el => el.address === selected);
|
||||||
}, [selected, tokens, props.asset]);
|
}, [selected, tokens, props.asset]);
|
||||||
|
|
||||||
const renderTokensChain = useMemo(() => {
|
const delayedSearchChange = _.debounce(val => {
|
||||||
return tokens
|
setSearch(val);
|
||||||
.filter(
|
});
|
||||||
t =>
|
|
||||||
(t.tags?.indexOf('longList') || -1) < 0 &&
|
const rowRender = (rowProps: { index: number; key: string; style: any }) => {
|
||||||
search &&
|
const token = tokenList[rowProps.index];
|
||||||
search.length >= 3 &&
|
const mint = token.address;
|
||||||
t.symbol.includes(search.toUpperCase()),
|
return (
|
||||||
)
|
<div
|
||||||
.map(token => {
|
key={rowProps.key}
|
||||||
const mint = token.address;
|
className="multichain-option"
|
||||||
return (
|
title={token.name}
|
||||||
|
onClick={() => {
|
||||||
|
props.onSelectToken(mint);
|
||||||
|
setSelected(mint);
|
||||||
|
hideModal();
|
||||||
|
}}
|
||||||
|
style={{ ...rowProps.style, cursor: 'pointer' }}
|
||||||
|
>
|
||||||
|
<div className="multichain-option-content">
|
||||||
|
<TokenDisplay asset={props.asset} token={token} chain={props.chain} />
|
||||||
<div
|
<div
|
||||||
key={mint}
|
className="multichain-option-name"
|
||||||
className="multichain-option"
|
style={{ marginLeft: '20px' }}
|
||||||
title={token.name}
|
|
||||||
onClick={() => {
|
|
||||||
props.onSelectToken(mint);
|
|
||||||
setSelected(mint);
|
|
||||||
hideModal();
|
|
||||||
}}
|
|
||||||
style={{ cursor: 'pointer' }}
|
|
||||||
>
|
>
|
||||||
<div className="multichain-option-content">
|
<em className={'token-symbol'}>{token.symbol}</em>
|
||||||
<TokenDisplay
|
<span className={'token-name'}>{token.name}</span>
|
||||||
asset={props.asset}
|
|
||||||
token={token}
|
|
||||||
chain={props.chain}
|
|
||||||
/>
|
|
||||||
<div className="multichain-option-name">
|
|
||||||
<span className={'token-name'}>{token.symbol}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
</div>
|
||||||
});
|
</div>
|
||||||
}, [search, tokens]);
|
);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
@ -93,11 +103,28 @@ export const TokenSelectModal = (props: {
|
||||||
>
|
>
|
||||||
<Input
|
<Input
|
||||||
className={'input-token-search'}
|
className={'input-token-search'}
|
||||||
placeholder={'ETH, SOL, ... etc'}
|
placeholder={'SOL, SRM, ... etc'}
|
||||||
value={search}
|
value={search}
|
||||||
onChange={e => setSearch(e.target.value)}
|
onChange={e => {
|
||||||
|
e.persist();
|
||||||
|
delayedSearchChange(e.target.value);
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
<div className={'assets-scroll'}>{[...renderTokensChain]}</div>
|
<div style={{ height: '90%' }}>
|
||||||
|
<AutoSizer>
|
||||||
|
{({ width, height }) => (
|
||||||
|
<List
|
||||||
|
ref="List"
|
||||||
|
height={height}
|
||||||
|
rowHeight={70}
|
||||||
|
rowCount={tokenList.length || 0}
|
||||||
|
rowRenderer={rowRender}
|
||||||
|
width={width}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</AutoSizer>
|
||||||
|
</div>
|
||||||
|
{/*<div className={'assets-scroll'}>{[...renderTokensChain]}</div>*/}
|
||||||
</Modal>
|
</Modal>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|
|
@ -5,3 +5,21 @@
|
||||||
height: 60vh;
|
height: 60vh;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.ant-modal-body {
|
||||||
|
height: 80vh;
|
||||||
|
::-webkit-scrollbar-track {
|
||||||
|
border-radius: 5px;
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
::-webkit-scrollbar {
|
||||||
|
width: 7px;
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
::-webkit-scrollbar-thumb {
|
||||||
|
border-radius: 5px;
|
||||||
|
height: 50px;
|
||||||
|
-webkit-box-shadow: inset 0 0 30px rgba(0,0,0,.3);
|
||||||
|
background-color: #555;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -53,7 +53,7 @@ export const EthereumProvider: FunctionComponent = ({ children }) => {
|
||||||
fetch('https://gateway.ipfs.io/ipns/tokens.uniswap.org').then(_ =>
|
fetch('https://gateway.ipfs.io/ipns/tokens.uniswap.org').then(_ =>
|
||||||
_.json(),
|
_.json(),
|
||||||
),
|
),
|
||||||
fetch('https://tokenlist.aave.eth.link/').then(_ => _.json()),
|
//fetch('https://tokenlist.aave.eth.link/').then(_ => _.json()),
|
||||||
fetch('https://tokens.coingecko.com/uniswap/all.json').then(_ =>
|
fetch('https://tokens.coingecko.com/uniswap/all.json').then(_ =>
|
||||||
_.json(),
|
_.json(),
|
||||||
),
|
),
|
||||||
|
|
Loading…
Reference in New Issue