/ src / modules / reserve-overview / AddTokenDropdown.tsx
AddTokenDropdown.tsx
  1  import { Trans } from '@lingui/macro';
  2  import { Box, Menu, MenuItem, Typography } from '@mui/material';
  3  import * as React from 'react';
  4  import { useEffect, useState } from 'react';
  5  import { CircleIcon } from 'src/components/CircleIcon';
  6  import { WalletIcon } from 'src/components/icons/WalletIcon';
  7  import { Base64Token, TokenIcon } from 'src/components/primitives/TokenIcon';
  8  import { ComputedReserveData } from 'src/hooks/app-data-provider/useAppDataProvider';
  9  import { ERC20TokenType } from 'src/libs/web3-data-provider/Web3Provider';
 10  import { useRootStore } from 'src/store/root';
 11  import { RESERVE_DETAILS } from 'src/utils/mixPanelEvents';
 12  
 13  interface AddTokenDropdownProps {
 14    poolReserve: ComputedReserveData;
 15    downToSM: boolean;
 16    switchNetwork: (chainId: number) => Promise<void>;
 17    addERC20Token: (args: ERC20TokenType) => Promise<boolean>;
 18    currentChainId: number;
 19    connectedChainId: number;
 20    hideAToken?: boolean;
 21  }
 22  
 23  export const AddTokenDropdown = ({
 24    poolReserve,
 25    downToSM,
 26    switchNetwork,
 27    addERC20Token,
 28    currentChainId,
 29    connectedChainId,
 30    hideAToken,
 31  }: AddTokenDropdownProps) => {
 32    const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null);
 33    const [changingNetwork, setChangingNetwork] = useState(false);
 34    const [underlyingBase64, setUnderlyingBase64] = useState('');
 35    const [aTokenBase64, setATokenBase64] = useState('');
 36    const open = Boolean(anchorEl);
 37    const trackEvent = useRootStore((store) => store.trackEvent);
 38  
 39    const handleClick = (event: React.MouseEvent<HTMLDivElement>) => {
 40      setAnchorEl(event.currentTarget);
 41    };
 42    const handleClose = () => {
 43      setAnchorEl(null);
 44    };
 45  
 46    // The switchNetwork function has no return type, so to detect if a user successfully switched networks before adding token to wallet, check the selected vs connected chain id
 47    useEffect(() => {
 48      if (changingNetwork && currentChainId === connectedChainId) {
 49        addERC20Token({
 50          address: poolReserve.underlyingAsset,
 51          decimals: poolReserve.decimals,
 52          symbol: poolReserve.symbol,
 53          image: !/_/.test(poolReserve.iconSymbol) ? underlyingBase64 : undefined,
 54        });
 55        setChangingNetwork(false);
 56      }
 57    }, [
 58      currentChainId,
 59      connectedChainId,
 60      changingNetwork,
 61      addERC20Token,
 62      poolReserve?.underlyingAsset,
 63      poolReserve?.decimals,
 64      poolReserve?.symbol,
 65      poolReserve?.iconSymbol,
 66      underlyingBase64,
 67    ]);
 68  
 69    if (!poolReserve) {
 70      return null;
 71    }
 72  
 73    return (
 74      <>
 75        {/* Load base64 token symbol for adding underlying and aTokens to wallet */}
 76        {poolReserve?.symbol && !/_/.test(poolReserve.symbol) && (
 77          <>
 78            <Base64Token
 79              symbol={poolReserve.iconSymbol}
 80              onImageGenerated={setUnderlyingBase64}
 81              aToken={false}
 82            />
 83            {!hideAToken && (
 84              <Base64Token
 85                symbol={poolReserve.iconSymbol}
 86                onImageGenerated={setATokenBase64}
 87                aToken={true}
 88              />
 89            )}
 90          </>
 91        )}
 92        <Box onClick={handleClick}>
 93          <CircleIcon tooltipText="Add token to wallet" downToSM={downToSM}>
 94            <Box
 95              onClick={() => {
 96                trackEvent(RESERVE_DETAILS.ADD_TOKEN_TO_WALLET_DROPDOWN, {
 97                  asset: poolReserve.underlyingAsset,
 98                  assetName: poolReserve.name,
 99                });
100              }}
101              sx={{
102                display: 'inline-flex',
103                alignItems: 'center',
104                '&:hover': {
105                  '.Wallet__icon': { opacity: '0 !important' },
106                  '.Wallet__iconHover': { opacity: '1 !important' },
107                },
108                cursor: 'pointer',
109              }}
110            >
111              <WalletIcon sx={{ width: '14px', height: '14px', '&:hover': { stroke: '#F1F1F3' } }} />
112            </Box>
113          </CircleIcon>
114        </Box>
115        <Menu
116          anchorEl={anchorEl}
117          open={open}
118          onClose={handleClose}
119          MenuListProps={{
120            'aria-labelledby': 'basic-button',
121          }}
122          keepMounted={true}
123          data-cy="addToWaletSelector"
124        >
125          <Box sx={{ px: 4, pt: 3, pb: 2 }}>
126            <Typography variant="secondary12" color="text.secondary">
127              <Trans>Underlying token</Trans>
128            </Typography>
129          </Box>
130  
131          <MenuItem
132            key="underlying"
133            value="underlying"
134            divider
135            onClick={() => {
136              if (currentChainId !== connectedChainId) {
137                switchNetwork(currentChainId).then(() => {
138                  setChangingNetwork(true);
139                });
140              } else {
141                trackEvent(RESERVE_DETAILS.ADD_TO_WALLET, {
142                  type: 'Underlying token',
143                  asset: poolReserve.underlyingAsset,
144                  assetName: poolReserve.name,
145                });
146  
147                addERC20Token({
148                  address: poolReserve.underlyingAsset,
149                  decimals: poolReserve.decimals,
150                  symbol: poolReserve.symbol,
151                  image: !/_/.test(poolReserve.symbol) ? underlyingBase64 : undefined,
152                });
153              }
154              handleClose();
155            }}
156          >
157            <TokenIcon symbol={poolReserve.iconSymbol} sx={{ fontSize: '20px' }} />
158            <Typography variant="subheader1" sx={{ ml: 3 }} noWrap data-cy={`assetName`}>
159              {poolReserve.symbol}
160            </Typography>
161          </MenuItem>
162          {!hideAToken && (
163            <Box>
164              <Box sx={{ px: 4, pt: 3, pb: 2 }}>
165                <Typography variant="secondary12" color="text.secondary">
166                  <Trans>Aave aToken</Trans>
167                </Typography>
168              </Box>
169              <MenuItem
170                key="atoken"
171                value="atoken"
172                onClick={() => {
173                  if (currentChainId !== connectedChainId) {
174                    switchNetwork(currentChainId).then(() => {
175                      setChangingNetwork(true);
176                    });
177                  } else {
178                    trackEvent(RESERVE_DETAILS.ADD_TO_WALLET, {
179                      asset: poolReserve.underlyingAsset,
180                      assetName: poolReserve.name,
181                    });
182  
183                    addERC20Token({
184                      address: poolReserve.aTokenAddress,
185                      decimals: poolReserve.decimals,
186                      symbol: '',
187                      image: !/_/.test(poolReserve.symbol) ? aTokenBase64 : undefined,
188                    });
189                  }
190                  handleClose();
191                }}
192              >
193                <TokenIcon symbol={poolReserve.iconSymbol} sx={{ fontSize: '20px' }} aToken={true} />
194                <Typography variant="subheader1" sx={{ ml: 3 }} noWrap data-cy={`assetName`}>
195                  {`a${poolReserve.symbol}`}
196                </Typography>
197              </MenuItem>
198            </Box>
199          )}
200        </Menu>
201      </>
202    );
203  };