diff --git a/packages/adena-extension/src/App/use-app.ts b/packages/adena-extension/src/App/use-app.ts index f7257596..1472934b 100644 --- a/packages/adena-extension/src/App/use-app.ts +++ b/packages/adena-extension/src/App/use-app.ts @@ -4,6 +4,7 @@ import { useLocation } from 'react-router-dom'; import { useAccountName } from '@hooks/use-account-name'; import { useWalletContext } from '@hooks/use-context'; import { useCurrentAccount } from '@hooks/use-current-account'; +import { useLoadImages } from '@hooks/use-load-images'; import { useNetwork } from '@hooks/use-network'; import useScrollHistory from '@hooks/use-scroll-history'; import { useTokenMetainfo } from '@hooks/use-token-metainfo'; @@ -14,6 +15,7 @@ const useApp = (): void => { const { currentAccount } = useCurrentAccount(); const { currentNetwork, checkNetworkState } = useNetwork(); const { initTokenMetainfos } = useTokenMetainfo(); + const { clear: clearLoadingImages } = useLoadImages(); const { pathname, key } = useLocation(); const { scrollMove } = useScrollHistory(); @@ -34,6 +36,7 @@ const useApp = (): void => { return; } + clearLoadingImages(); initTokenMetainfos(); }, [currentAccount?.id, currentNetwork.networkId]); diff --git a/packages/adena-extension/src/common/provider/wallet/wallet-provider.tsx b/packages/adena-extension/src/common/provider/wallet/wallet-provider.tsx index e7e88594..2356d775 100644 --- a/packages/adena-extension/src/common/provider/wallet/wallet-provider.tsx +++ b/packages/adena-extension/src/common/provider/wallet/wallet-provider.tsx @@ -22,8 +22,7 @@ export interface WalletContextProps { export const WalletContext = createContext(null); export const WalletProvider: React.FC> = ({ children }) => { - const { walletService, balanceService, accountService, chainService, tokenService } = - useAdenaContext(); + const { walletService, accountService, chainService } = useAdenaContext(); const [gnoProvider, setGnoProvider] = useState(); @@ -31,7 +30,7 @@ export const WalletProvider: React.FC> = ({ chi const [walletStatus, setWalletStatus] = useRecoilState(WalletState.state); - const [tokenMetainfos, setTokenMetainfos] = useRecoilState(TokenState.tokenMetainfos); + const [tokenMetainfos] = useRecoilState(TokenState.tokenMetainfos); const [networkMetainfos, setNetworkMetainfos] = useRecoilState(NetworkState.networkMetainfos); @@ -95,7 +94,6 @@ export const WalletProvider: React.FC> = ({ chi if (currentAccount) { setCurrentAccount(currentAccount); await accountService.changeCurrentAccount(currentAccount); - await initTokenMetainfos(currentAccount.id); } return true; } @@ -124,13 +122,6 @@ export const WalletProvider: React.FC> = ({ chi return true; } - async function initTokenMetainfos(accountId: string): Promise { - await tokenService.initAccountTokenMetainfos(accountId); - const tokenMetainfos = await tokenService.getTokenMetainfosByAccountId(accountId); - setTokenMetainfos(tokenMetainfos); - balanceService.setTokenMetainfos(tokenMetainfos); - } - async function changeNetwork(networkMetainfo: NetworkMetainfo): Promise { const rpcUrl = networkMetainfo.rpcUrl; const gnoProvider = new GnoProvider(rpcUrl, networkMetainfo.networkId); diff --git a/packages/adena-extension/src/components/pages/wallet-main/token-list-item/token-list-item.spec.tsx b/packages/adena-extension/src/components/pages/wallet-main/token-list-item/token-list-item.spec.tsx index 62b72d7b..63034861 100644 --- a/packages/adena-extension/src/components/pages/wallet-main/token-list-item/token-list-item.spec.tsx +++ b/packages/adena-extension/src/components/pages/wallet-main/token-list-item/token-list-item.spec.tsx @@ -20,6 +20,9 @@ describe('TokenListItem Component', () => { it('TokenListItem render', () => { const args: TokenListItemProps = { token, + completeImageLoading: () => { + return; + }, onClickTokenItem: () => { return; }, diff --git a/packages/adena-extension/src/components/pages/wallet-main/token-list-item/token-list-item.tsx b/packages/adena-extension/src/components/pages/wallet-main/token-list-item/token-list-item.tsx index b1fbe5c2..eefc39f5 100644 --- a/packages/adena-extension/src/components/pages/wallet-main/token-list-item/token-list-item.tsx +++ b/packages/adena-extension/src/components/pages/wallet-main/token-list-item/token-list-item.tsx @@ -1,20 +1,37 @@ -import React from 'react'; -import { TokenListItemWrapper } from './token-list-item.styles'; import TokenListItemBalance from '@components/pages/wallet-main/token-list-item-balance/token-list-item-balance'; import { MainToken } from '@types'; +import React from 'react'; +import { TokenListItemWrapper } from './token-list-item.styles'; export interface TokenListItemProps { token: MainToken; + completeImageLoading: (imageUrl: string) => void; onClickTokenItem: (tokenId: string) => void; } -const TokenListItem: React.FC = ({ token, onClickTokenItem }) => { +const TokenListItem: React.FC = ({ + token, + completeImageLoading, + onClickTokenItem, +}) => { const { tokenId, logo, name, balanceAmount } = token; + const onLoadImage = (): void => { + completeImageLoading(logo); + }; + return ( onClickTokenItem(tokenId)}>
- token img + token img
diff --git a/packages/adena-extension/src/components/pages/wallet-main/token-list/token-list.spec.tsx b/packages/adena-extension/src/components/pages/wallet-main/token-list/token-list.spec.tsx index 53e85722..ac4de565 100644 --- a/packages/adena-extension/src/components/pages/wallet-main/token-list/token-list.spec.tsx +++ b/packages/adena-extension/src/components/pages/wallet-main/token-list/token-list.spec.tsx @@ -31,6 +31,9 @@ describe('TokenList Component', () => { it('TokenList render', () => { const args: TokenListProps = { tokens, + completeImageLoading: () => { + return; + }, onClickTokenItem: () => { return; }, diff --git a/packages/adena-extension/src/components/pages/wallet-main/token-list/token-list.tsx b/packages/adena-extension/src/components/pages/wallet-main/token-list/token-list.tsx index 43558455..e2e12041 100644 --- a/packages/adena-extension/src/components/pages/wallet-main/token-list/token-list.tsx +++ b/packages/adena-extension/src/components/pages/wallet-main/token-list/token-list.tsx @@ -1,18 +1,28 @@ +import { MainToken } from '@types'; import React from 'react'; -import { TokenListWrapper } from './token-list.styles'; import TokenListItem from '../token-list-item/token-list-item'; -import { MainToken } from '@types'; +import { TokenListWrapper } from './token-list.styles'; export interface TokenListProps { tokens: Array; + completeImageLoading: (imageUrl: string) => void; onClickTokenItem: (tokenId: string) => void; } -const TokenList: React.FC = ({ tokens, onClickTokenItem }) => { +const TokenList: React.FC = ({ + tokens, + completeImageLoading, + onClickTokenItem, +}) => { return ( {tokens.map((token, index) => ( - + ))} ); diff --git a/packages/adena-extension/src/hooks/use-load-images.tsx b/packages/adena-extension/src/hooks/use-load-images.tsx new file mode 100644 index 00000000..7df05f92 --- /dev/null +++ b/packages/adena-extension/src/hooks/use-load-images.tsx @@ -0,0 +1,38 @@ +import { useRecoilState } from 'recoil'; + +import { CommonState } from '@states'; +import { useMemo } from 'react'; + +export type UseLoadAccountsReturn = { + isLoading: boolean; + addLoadingImages: (imageUrls: string[]) => void; + completeImageLoading: (imageUrl: string) => void; + clear: () => void; +}; + +export const useLoadImages = (): UseLoadAccountsReturn => { + const [loadingImageUrls, setLoadingImageUrls] = useRecoilState(CommonState.loadingImageUrls); + const [loadedImageUrls, setLoadedImageUrls] = useRecoilState(CommonState.loadedImageUrls); + + const isLoading = useMemo(() => { + if (loadedImageUrls.length === 0) { + return true; + } + return loadedImageUrls.length < loadingImageUrls.length; + }, [loadedImageUrls, loadingImageUrls]); + + const addLoadingImages = (imageUrls: string[]): void => { + setLoadingImageUrls([...new Set(imageUrls.filter((url) => !!url))]); + }; + + const completeImageLoading = (imageUrl: string): void => { + setLoadedImageUrls((prev) => [...new Set([...prev, imageUrl])]); + }; + + const clear = (): void => { + setLoadingImageUrls([]); + setLoadedImageUrls([]); + }; + + return { isLoading, addLoadingImages, completeImageLoading, clear }; +}; diff --git a/packages/adena-extension/src/pages/popup/wallet/wallet-main/index.tsx b/packages/adena-extension/src/pages/popup/wallet/wallet-main/index.tsx index 6624d835..0ac2e7b1 100644 --- a/packages/adena-extension/src/pages/popup/wallet/wallet-main/index.tsx +++ b/packages/adena-extension/src/pages/popup/wallet/wallet-main/index.tsx @@ -1,28 +1,29 @@ -import React, { useCallback, useEffect, useMemo } from 'react'; -import styled from 'styled-components'; -import { useRecoilState } from 'recoil'; -import BigNumber from 'bignumber.js'; import { isAirgapAccount } from 'adena-module'; +import BigNumber from 'bignumber.js'; +import { useCallback, useEffect, useMemo } from 'react'; +import { useRecoilState } from 'recoil'; +import styled from 'styled-components'; -import { RoutePath } from '@types'; -import { useTokenBalance } from '@hooks/use-token-balance'; +import UnknownTokenIcon from '@assets/common-unknown-token.svg'; +import { Button, Row, Text } from '@components/atoms'; +import IconThunder from '@components/atoms/icon/icon-assets/icon-thunder'; +import LoadingButton from '@components/atoms/loading-button/loading-button'; +import MainManageTokenButton from '@components/pages/main/main-manage-token-button/main-manage-token-button'; +import MainNetworkLabel from '@components/pages/main/main-network-label/main-network-label'; import MainTokenBalance from '@components/pages/main/main-token-balance/main-token-balance'; import TokenList from '@components/pages/wallet-main/token-list/token-list'; -import MainManageTokenButton from '@components/pages/main/main-manage-token-button/main-manage-token-button'; -import UnknownTokenIcon from '@assets/common-unknown-token.svg'; -import { useCurrentAccount } from '@hooks/use-current-account'; -import { WalletState } from '@states'; -import { usePreventHistoryBack } from '@hooks/use-prevent-history-back'; import useAppNavigate from '@hooks/use-app-navigate'; -import { useNetwork } from '@hooks/use-network'; -import MainNetworkLabel from '@components/pages/main/main-network-label/main-network-label'; -import { Button, Row, Text } from '@components/atoms'; -import mixins from '@styles/mixins'; +import { useCurrentAccount } from '@hooks/use-current-account'; import { useFaucet } from '@hooks/use-faucet'; +import { useLoadImages } from '@hooks/use-load-images'; +import { useNetwork } from '@hooks/use-network'; +import { usePreventHistoryBack } from '@hooks/use-prevent-history-back'; import { useToast } from '@hooks/use-toast'; -import LoadingButton from '@components/atoms/loading-button/loading-button'; -import IconThunder from '@components/atoms/icon/icon-assets/icon-thunder'; +import { useTokenBalance } from '@hooks/use-token-balance'; import { useTokenMetainfo } from '@hooks/use-token-metainfo'; +import { WalletState } from '@states'; +import mixins from '@styles/mixins'; +import { RoutePath } from '@types'; const Wrapper = styled.main` padding-top: 37px; @@ -74,6 +75,8 @@ export const WalletMain = (): JSX.Element => { const { isSupported: supportedFaucet, isLoading: isFaucetLoading, faucet } = useFaucet(); const { show } = useToast(); + const { addLoadingImages, completeImageLoading } = useLoadImages(); + const onClickFaucetButton = (): void => { if (isFaucetLoading) { return; @@ -119,6 +122,10 @@ export const WalletMain = (): JSX.Element => { }); }, [currentBalances, getTokenImage]); + const tokenImages = useMemo(() => { + return tokens.map((token) => token.logo); + }, [tokens]); + const onClickTokenListItem = useCallback( (tokenId: string) => { const tokenBalance = currentBalances.find((tokenBalance) => tokenBalance.tokenId === tokenId); @@ -137,6 +144,10 @@ export const WalletMain = (): JSX.Element => { navigate(RoutePath.ManageToken); }, [navigate]); + useEffect(() => { + addLoadingImages(tokenImages); + }, [tokenImages.length]); + return (
@@ -175,7 +186,11 @@ export const WalletMain = (): JSX.Element => {
- +
diff --git a/packages/adena-extension/src/router/popup/loading-main.tsx b/packages/adena-extension/src/router/popup/loading-main.tsx index dbf1dde6..46630560 100644 --- a/packages/adena-extension/src/router/popup/loading-main.tsx +++ b/packages/adena-extension/src/router/popup/loading-main.tsx @@ -1,16 +1,17 @@ -import React, { ReactElement, useMemo } from 'react'; +import { ReactElement, useMemo } from 'react'; +import { useMatch } from 'react-router-dom'; import { useRecoilState } from 'recoil'; import styled from 'styled-components'; -import { useMatch } from 'react-router-dom'; import { Loading, SkeletonBoxStyle } from '@components/atoms'; -import { RoutePath } from '@types'; +import { GhostButtons } from '@components/molecules'; +import { useLoadImages } from '@hooks/use-load-images'; +import { useNetwork } from '@hooks/use-network'; import { useTokenBalance } from '@hooks/use-token-balance'; import { WalletState } from '@states'; -import { useNetwork } from '@hooks/use-network'; -import { GhostButtons } from '@components/molecules'; -import { getTheme } from '@styles/theme'; import mixins from '@styles/mixins'; +import { getTheme } from '@styles/theme'; +import { RoutePath } from '@types'; const Wrapper = styled.main` ${mixins.flex({ justify: 'stretch' })}; @@ -49,6 +50,7 @@ const LoadingMain = (): ReactElement => { const { currentBalances } = useTokenBalance(); const isNotMatch = useMatch('/approve/wallet/*'); const isPopupMatch = useMatch('/popup/*'); + const { isLoading: isLoadingImage } = useLoadImages(); const loading = useMemo(() => { if (isApproveHardwarePath || isNotMatch || isPopupMatch) { @@ -57,6 +59,9 @@ const LoadingMain = (): ReactElement => { if (state === 'CREATE' || state === 'LOGIN') { return false; } + if (isLoadingImage) { + return true; + } if (state === 'FINISH') { // If `failedNetwork` is null, it is loading. if (failedNetwork) { @@ -69,7 +74,15 @@ const LoadingMain = (): ReactElement => { } } return true; - }, [isPopupMatch, state, currentBalances, failedNetwork, currentNetwork.id, useMatch]); + }, [ + isPopupMatch, + state, + currentBalances, + failedNetwork, + currentNetwork.id, + isLoadingImage, + useMatch, + ]); return loading ? ( diff --git a/packages/adena-extension/src/states/common.ts b/packages/adena-extension/src/states/common.ts index b95bc265..a28f3e0b 100644 --- a/packages/adena-extension/src/states/common.ts +++ b/packages/adena-extension/src/states/common.ts @@ -48,3 +48,13 @@ export const windowSizeType = atom({ key: 'common/windowSizeType', default: 'DEFAULT', }); + +export const loadingImageUrls = atom({ + key: 'common/loadingImageUrls', + default: [], +}); + +export const loadedImageUrls = atom({ + key: 'common/loadedImageUrls', + default: [], +});