From fe604cf7dbb4535b04ba2e8595f679edade85aec Mon Sep 17 00:00:00 2001 From: jinoosss <112360739+jinoosss@users.noreply.github.com> Date: Mon, 11 Nov 2024 19:41:25 +0900 Subject: [PATCH] fix: handle invalid image paths (#634) --- .../manage-token-list-item.tsx | 13 +++++-- .../nft-card-image/nft-card-image.tsx | 23 ++++++++++-- .../transaction-history-list-item.tsx | 34 ++++++++++++++++-- .../pages/popup/wallet/manage-token/index.tsx | 6 ++-- .../popup/wallet/transaction-detail/index.tsx | 36 ++++++++++++++++--- 5 files changed, 97 insertions(+), 15 deletions(-) diff --git a/packages/adena-extension/src/components/molecules/manage-token-list/manage-token-list-item.tsx b/packages/adena-extension/src/components/molecules/manage-token-list/manage-token-list-item.tsx index 82f68340..31ecf3e1 100644 --- a/packages/adena-extension/src/components/molecules/manage-token-list/manage-token-list-item.tsx +++ b/packages/adena-extension/src/components/molecules/manage-token-list/manage-token-list-item.tsx @@ -1,4 +1,4 @@ -import React, { useMemo } from 'react'; +import React, { useMemo, useState } from 'react'; import IconEmptyImage from '@assets/icon-empty-image.svg'; import Toggle from '@components/atoms/toggle'; @@ -34,6 +34,7 @@ const ManageTokenListItem: React.FC = ({ onToggleActiveItem, }) => { const theme = useTheme(); + const [hasLogoError, setHasLogoError] = useState(false); const isTokenInfo = isManageTokenInfo(token); const tokenUriResponse = !isTokenInfo && token.isTokenUri && queryGRC721TokenUri @@ -45,6 +46,10 @@ const ManageTokenListItem: React.FC = ({ : null; const grc721CollectionImage = useMemo(() => { + if (!hasLogoError) { + return null; + } + if (!tokenUriResponse) { return null; } @@ -77,11 +82,15 @@ const ManageTokenListItem: React.FC = ({ return `${balanceBN.toFormat()} Item`; }, [token]); + const handleLogoError = (): void => { + setHasLogoError(true); + }; + if (isTokenInfo) { return (
- token img + token img
diff --git a/packages/adena-extension/src/components/molecules/nft-card-image/nft-card-image.tsx b/packages/adena-extension/src/components/molecules/nft-card-image/nft-card-image.tsx index 3cd5f4f9..4d04aea9 100644 --- a/packages/adena-extension/src/components/molecules/nft-card-image/nft-card-image.tsx +++ b/packages/adena-extension/src/components/molecules/nft-card-image/nft-card-image.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { useState } from 'react'; import IconEmptyImage from '@assets/icon-empty-image.svg'; import { Loading } from '@components/atoms'; @@ -11,6 +11,17 @@ export interface NFTCardImageProps { } const NFTCardImage: React.FC = ({ isFetched, image, hasBadge = false }) => { + const [hasError, setHasError] = useState(false); + const [loaded, setLoaded] = useState(false); + + const handleLoad = (): void => { + setLoaded(true); + }; + + const handleError = (): void => { + setHasError(true); + }; + if (!isFetched) { return ( @@ -19,7 +30,7 @@ const NFTCardImage: React.FC = ({ isFetched, image, hasBadge ); } - if (!image) { + if (!image || !loaded || hasError) { return ( empty image @@ -29,7 +40,13 @@ const NFTCardImage: React.FC = ({ isFetched, image, hasBadge return ( - + nft image ); }; diff --git a/packages/adena-extension/src/components/molecules/transaction-history/transaction-history-list-item/transaction-history-list-item.tsx b/packages/adena-extension/src/components/molecules/transaction-history/transaction-history-list-item/transaction-history-list-item.tsx index 22325cae..f2b8d105 100644 --- a/packages/adena-extension/src/components/molecules/transaction-history/transaction-history-list-item/transaction-history-list-item.tsx +++ b/packages/adena-extension/src/components/molecules/transaction-history/transaction-history-list-item/transaction-history-list-item.tsx @@ -5,7 +5,7 @@ import FailedIcon from '@assets/failed.svg'; import SuccessIcon from '@assets/success.svg'; import { TokenBalance } from '@components/molecules'; import { UseQueryOptions, UseQueryResult } from '@tanstack/react-query'; -import React, { useCallback, useMemo } from 'react'; +import React, { useCallback, useMemo, useState } from 'react'; import { TransactionHistoryListItemWrapper } from './transaction-history-list-item.styles'; export interface TransactionHistoryListItemProps { @@ -43,6 +43,8 @@ const TransactionHistoryListItem: React.FC = (a queryGRC721TokenUri, onClickItem, } = args; + const [hasLogoError, setHasLogoError] = useState(false); + const [isLoadedLogo, setIsLoadedLogo] = useState(false); const tokenUriQuery = type === 'TRANSFER_GRC721' && queryGRC721TokenUri !== undefined @@ -50,24 +52,44 @@ const TransactionHistoryListItem: React.FC = (a : null; const logoImage = useMemo(() => { + if (hasLogoError) { + return `${UnknownTokenIcon}`; + } + if (type === 'TRANSFER_GRC721' && tokenUriQuery) { + if (!isLoadedLogo) { + return `${UnknownTokenIcon}`; + } + return tokenUriQuery?.data || `${UnknownTokenIcon}`; } if (type === 'ADD_PACKAGE') { return `${AddPackageIcon}`; } + if (type === 'CONTRACT_CALL') { return `${ContractIcon}`; } + if (type === 'MULTI_CONTRACT_CALL') { return `${ContractIcon}`; } + if (!logo) { return `${UnknownTokenIcon}`; } + return `${logo}`; - }, [type, logo, tokenUriQuery]); + }, [isLoadedLogo, hasLogoError, type, logo, tokenUriQuery]); + + const handleLogoError = (): void => { + setHasLogoError(true); + }; + + const handleLoadLogo = (): void => { + setIsLoadedLogo(true); + }; const getValueTypeClassName = useCallback(() => { if (valueType === 'ACTIVE') { @@ -82,7 +104,13 @@ const TransactionHistoryListItem: React.FC = (a return ( onClickItem(hash)}>
- logo image + logo image { @@ -14,6 +15,7 @@ const ManageTokenSearchContainer: React.FC = () => { const [searchKeyword, setSearchKeyword] = useState(''); const [isClose, setIsClose] = useState(false); const { currentAccount } = useCurrentAccount(); + const { tokenLogoMap } = useTokenMetainfo(); const { currentBalances, toggleDisplayOption } = useTokenBalance(); useEffect(() => { @@ -39,11 +41,11 @@ const ManageTokenSearchContainer: React.FC = () => { value: BigNumber(metainfo.amount.value).toFormat(), denom: metainfo.amount.denom, }, - logo: metainfo.image || `${UnknownTokenIcon}`, + logo: tokenLogoMap[metainfo.tokenId] || `${UnknownTokenIcon}`, }; }); return filteredTokens; - }, [searchKeyword, currentBalances]); + }, [searchKeyword, currentBalances, tokenLogoMap]); const moveTokenAddedPage = useCallback(() => { navigate(RoutePath.ManageTokenAdded); diff --git a/packages/adena-extension/src/pages/popup/wallet/transaction-detail/index.tsx b/packages/adena-extension/src/pages/popup/wallet/transaction-detail/index.tsx index 438a703e..f76fefe4 100644 --- a/packages/adena-extension/src/pages/popup/wallet/transaction-detail/index.tsx +++ b/packages/adena-extension/src/pages/popup/wallet/transaction-detail/index.tsx @@ -1,4 +1,4 @@ -import { useCallback } from 'react'; +import { useMemo, useState } from 'react'; import styled from 'styled-components'; import AddPackageIcon from '@assets/addpkg.svg'; @@ -24,35 +24,55 @@ interface DLProps { } export const TransactionDetail = (): JSX.Element => { + const [hasLogoError, setHasLogoError] = useState(false); + const [isLoadedLogo, setIsLoadedLogo] = useState(false); + const { openLink } = useLink(); const { convertDenom } = useTokenMetainfo(); const { currentNetwork, scannerParameters } = useNetwork(); const { goBack, params } = useAppNavigate(); + const transactionItem = params.transactionInfo; const tokenUriQuery = transactionItem?.type === 'TRANSFER_GRC721' ? useGetGRC721TokenUri(transactionItem.logo, '0') : null; - const getLogoImage = useCallback(() => { - if (transactionItem?.type === 'TRANSFER_GRC721') { + const logoImage = useMemo(() => { + if (transactionItem?.type === 'TRANSFER_GRC721' && tokenUriQuery) { + if (!isLoadedLogo || hasLogoError) { + return `${UnknownTokenIcon}`; + } + return tokenUriQuery?.data || `${UnknownTokenIcon}`; } if (transactionItem?.type === 'ADD_PACKAGE') { return `${AddPackageIcon}`; } + if (transactionItem?.type === 'CONTRACT_CALL') { return `${ContractIcon}`; } + if (transactionItem?.type === 'MULTI_CONTRACT_CALL') { return `${ContractIcon}`; } + if (!transactionItem?.logo) { return `${UnknownTokenIcon}`; } + return `${transactionItem?.logo}`; - }, [transactionItem]); + }, [isLoadedLogo, hasLogoError, transactionItem?.type, transactionItem?.logo, tokenUriQuery]); + + const handleLoadLogo = (): void => { + setIsLoadedLogo(true); + }; + + const handleLogoError = (): void => { + setHasLogoError(true); + }; const handleLinkClick = (hash: string): void => { const scannerUrl = currentNetwork.linkUrl || SCANNER_URL; @@ -70,7 +90,13 @@ export const TransactionDetail = (): JSX.Element => { alt='status icon' /> - logo image + logo image {transactionItem.type === 'TRANSFER' ? (