Skip to content

Commit

Permalink
fix: fallback icon for custom token import step (#7429)
Browse files Browse the repository at this point in the history
* chore: zerion market data wip

* chore: wire up token price on import

* chore: filter by alchemy supported chainIds

* chore: hide fiat on input when not available

* chore: handle no fiat data in quote tag

* chore: more missing fiat handling

* chore: even more missing fiat handling

* feat: handle custom asset view

* fix: asset selection

* fix: market data selector

* feat: handle JIT market data fetching

* chore: first pass address review feedback

* chore: first pass kevs review feedback

* chore: 2nd pass kevs review feedback

* fix: build lint

* chore: remove JIT market data logic

* chore: remove custom asset prop

* chore: lint

* fix: ratio calc without market data

* feat: improve `<AssetIcon />` types

* fix: derp

* fix: more derp

* fix: more more derp

* fix: derpy derp derp

* fix: last derp?

* fix: actually last derp fix

* feat: pre-rebase mergefixes

---------

Co-authored-by: Apotheosis <[email protected]>
Co-authored-by: Apotheosis <[email protected]>
  • Loading branch information
3 people committed Jul 28, 2024
1 parent 1e991eb commit c3bac3d
Show file tree
Hide file tree
Showing 12 changed files with 86 additions and 60 deletions.
93 changes: 59 additions & 34 deletions src/components/AssetIcon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import type { AvatarProps } from '@chakra-ui/react'
import { Avatar, Center, Flex, useColorModeValue } from '@chakra-ui/react'
import type { AssetId } from '@shapeshiftoss/caip'
import { fromAssetId } from '@shapeshiftoss/caip'
import type { Asset } from '@shapeshiftoss/types'
import { memo, useMemo } from 'react'
import { getChainAdapterManager } from 'context/PluginProvider/chainAdapterSingleton'
import { selectAssetById, selectFeeAssetById } from 'state/slices/selectors'
Expand All @@ -23,34 +24,58 @@ export const sansNotchBottom =
'polygon( 29.875% 95.781%,29.875% 95.781%,32.106% 96.7%,34.39% 97.513%,36.724% 98.218%,39.105% 98.81%,41.529% 99.287%,43.995% 99.646%,46.498% 99.882%,49.036% 99.994%,51.605% 99.977%,54.203% 99.828%,54.203% 99.828%,61.486% 98.674%,68.384% 96.495%,74.816% 93.377%,80.7% 89.403%,85.955% 84.66%,90.5% 79.232%,94.254% 73.203%,97.135% 66.658%,99.062% 59.682%,99.953% 52.359%,99.953% 52.359%,100.006% 49.623%,99.913% 46.921%,99.679% 44.257%,99.307% 41.634%,98.801% 39.057%,98.164% 36.528%,97.401% 34.053%,96.516% 31.635%,95.511% 29.277%,94.391% 26.984%,94.391% 26.984%,94.286% 26.814%,94.163% 26.66%,94.022% 26.523%,93.867% 26.405%,93.699% 26.307%,93.521% 26.23%,93.335% 26.175%,93.143% 26.143%,92.947% 26.137%,92.75% 26.156%,92.75% 26.156%,82.77% 28.407%,73.334% 31.927%,64.536% 36.619%,56.474% 42.387%,49.244% 49.135%,42.943% 56.766%,37.667% 65.185%,33.512% 74.295%,30.575% 84%,28.953% 94.203%,28.953% 94.203%,28.947% 94.403%,28.967% 94.6%,29.01% 94.791%,29.076% 94.973%,29.164% 95.146%,29.273% 95.308%,29.401% 95.456%,29.547% 95.588%,29.711% 95.702%,29.891% 95.797%,29.875% 95.781% );'

type AssetIconProps = {
assetId?: AssetId
// Show the network icon instead of the asset icon e.g OP icon instead of ETH for Optimism native asset
showNetworkIcon?: boolean
} & AvatarProps
} & (
| {
assetId: AssetId
asset?: undefined
src?: undefined
icon?: undefined
}
| {
asset: Asset
assetId?: undefined
src?: undefined
icon?: undefined
}
| {
src: string | undefined
assetId?: undefined
asset?: undefined
icon?: undefined
}
| {
icon: JSX.Element
src?: undefined
assetId?: undefined
asset?: undefined
}
) &
AvatarProps

// @TODO: this will be replaced with whatever we do for icons later
// The icon prop is used as the placeholder while the icon loads, or if it fails to load.
// Either src or assetId can be passed, if both are passed src takes precedence
type AssetWithNetworkProps = {
assetId: AssetId
asset: Asset
showNetworkIcon?: boolean
} & AvatarProps

const AssetWithNetwork: React.FC<AssetWithNetworkProps> = ({
assetId,
asset,
icon,
src,
showNetworkIcon = true,
size,
...rest
}) => {
const asset = useAppSelector(state => selectAssetById(state, assetId ?? ''))
const feeAsset = useAppSelector(state => selectFeeAssetById(state, assetId))
const showNetwork = feeAsset?.networkIcon || asset?.assetId !== feeAsset?.assetId
const iconSrc = src ?? asset?.icon
const feeAsset = useAppSelector(state => selectFeeAssetById(state, asset.assetId))
const showNetwork = feeAsset?.networkIcon || asset.assetId !== feeAsset?.assetId
const iconSrc = src ?? asset.icon
// We should only show the fallback if the asset doesn't have an icon/icons
// Failure to check this means we would lose loading FOX icon functionality
const showFallback = !asset?.icon && !asset?.icons?.length
const showFallback = !asset.icon && !asset.icons?.length

return (
<Center>
Expand All @@ -70,7 +95,7 @@ const AssetWithNetwork: React.FC<AssetWithNetworkProps> = ({
)}
<Avatar
src={iconSrc}
name={showFallback ? asset?.symbol : undefined}
name={showFallback ? asset.symbol : undefined}
icon={icon}
border={0}
size={size}
Expand All @@ -82,22 +107,30 @@ const AssetWithNetwork: React.FC<AssetWithNetworkProps> = ({
)
}

export const AssetIcon = memo(({ assetId, showNetworkIcon, src, ...rest }: AssetIconProps) => {
const asset = useAppSelector(state => selectAssetById(state, assetId ?? ''))
const assetIconBg = useColorModeValue('gray.200', 'gray.700')
const assetIconColor = useColorModeValue('text.subtle', 'text.subtle')
export const AssetIcon = memo(
({ assetId: _assetId, asset: _asset, showNetworkIcon, src, ...rest }: AssetIconProps) => {
const asset = useAppSelector(state =>
_asset ? _asset : selectAssetById(state, _assetId ?? ''),
)
const assetId = _assetId ?? asset?.assetId
const assetIconBg = useColorModeValue('gray.200', 'gray.700')
const assetIconColor = useColorModeValue('text.subtle', 'text.subtle')

const chainAdapterManager = getChainAdapterManager()
const chainId = assetId && fromAssetId(assetId).chainId
const nativeAssetId = chainAdapterManager.get(chainId ?? '')?.getFeeAssetId()
const foxIcon = useMemo(() => <FoxIcon boxSize='16px' color={assetIconColor} />, [assetIconColor])
const chainAdapterManager = getChainAdapterManager()
const chainId = assetId && fromAssetId(assetId).chainId
const nativeAssetId = chainAdapterManager.get(chainId ?? '')?.getFeeAssetId()
const foxIcon = useMemo(
() => <FoxIcon boxSize='16px' color={assetIconColor} />,
[assetIconColor],
)

if (assetId === nativeAssetId && asset?.networkIcon && showNetworkIcon) {
return <Avatar src={asset.networkIcon} bg={assetIconBg} icon={foxIcon} {...rest} />
}
if (!asset) return <Avatar src={src} bg={assetIconBg} icon={foxIcon} {...rest} />

if (assetId) {
if (asset?.icons?.length) {
if (assetId === nativeAssetId && asset.networkIcon && showNetworkIcon) {
return <Avatar src={asset.networkIcon} bg={assetIconBg} icon={foxIcon} {...rest} />
}

if (asset.icons?.length) {
return (
<Flex flexDirection='row' alignItems='center'>
{asset.icons.map((iconSrc, i) => (
Expand All @@ -108,15 +141,7 @@ export const AssetIcon = memo(({ assetId, showNetworkIcon, src, ...rest }: Asset
}

return (
<AssetWithNetwork
assetId={assetId}
src={src}
icon={foxIcon}
showNetworkIcon={showNetworkIcon}
{...rest}
/>
<AssetWithNetwork asset={asset} icon={foxIcon} showNetworkIcon={showNetworkIcon} {...rest} />
)
}

return <Avatar src={src} bg={assetIconBg} icon={foxIcon} {...rest} />
})
},
)
9 changes: 4 additions & 5 deletions src/components/AssetSelection/components/AssetMenuButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,10 @@ export const AssetMenuButton = ({
const asset = useAppSelector(state => selectAssetById(state, assetId ?? ''))

const icon = useMemo(() => {
return asset?.icons ? (
<PairIcons icons={asset.icons} iconBoxSize='5' h='38px' p={1} borderRadius={8} />
) : (
<AssetIcon assetId={assetId} size='xs' showNetworkIcon={showNetworkIcon} />
)
if (asset?.icons)
return <PairIcons icons={asset.icons} iconBoxSize='5' h='38px' p={1} borderRadius={8} />
if (assetId) return <AssetIcon assetId={assetId} size='xs' showNetworkIcon={showNetworkIcon} />
return null
}, [asset?.icons, assetId, showNetworkIcon])

const handleAssetClick = useCallback(() => {
Expand Down
4 changes: 3 additions & 1 deletion src/components/ChainMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export type ChainMenuProps<T extends ChainId | 'All'> = {
onMenuOptionClick: (chainId: T) => void
}

export const ChainIcon = (props: { chainId: ChainId } & AvatarProps) => {
export const ChainIcon = (props: { chainId: ChainId } & Omit<AvatarProps, 'src' | 'icon'>) => {
const { chainId, avatarProps } = useMemo(() => {
const { chainId, ...avatarProps } = props
return { chainId, avatarProps }
Expand All @@ -43,6 +43,8 @@ export const ChainIcon = (props: { chainId: ChainId } & AvatarProps) => {
return feeAssetId
}, [chainId])

if (!feeAssetId) return null

return <AssetIcon showNetworkIcon assetId={feeAssetId} {...avatarProps} />
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,8 @@ export const AssetSummaryStep = ({
}, [asset.chainId])

const assetIcon = useMemo(() => {
return <AssetIcon src={asset.icon} boxSize='32px' />
}, [asset.icon])
return <AssetIcon assetId={asset.assetId} boxSize='32px' />
}, [asset.assetId])
return (
<StepperStep
title={amountCryptoFormatted}
Expand Down
1 change: 1 addition & 0 deletions src/components/TradeAssetSearch/Chains/ChainCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ type ChainCardProps = {

export const ChainCard: React.FC<ChainCardProps> = memo(({ chainId, isActive, onClick }) => {
const feeAssetId = chainIdToFeeAssetId(chainId)
if (!feeAssetId) throw new Error(`feeAssetId not found for chainId ${chainId}`)
const feeAsset = useAppSelector(state => selectAssetById(state, feeAssetId ?? ''))
if (!feeAsset) throw new Error(`Fee asset not found for AssetId ${feeAssetId}`)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ export const CustomAssetAcknowledgement: React.FC<CustomAssetAcknowledgementProp
flexDirection={flexDirection}
>
<Flex gap={4} alignItems='center' padding={4}>
<AssetIcon assetId={asset.assetId} size='sm' />
<AssetIcon asset={asset} size='sm' />
<Box textAlign='left'>
<Text
lineHeight='normal'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ export const GroupedAssetRow = ({
_focus={focus}
>
<Flex gap={4} alignItems='center'>
<AssetIcon assetId={asset.assetId} size='sm' />
<AssetIcon assetId={assetId} size='sm' />
<Box textAlign='left'>
<Text
lineHeight='normal'
Expand Down Expand Up @@ -124,6 +124,7 @@ export const GroupedAssetRow = ({
)
}, [
asset,
assetId,
color,
cryptoPrecisionBalance,
handleAssetClick,
Expand All @@ -147,7 +148,7 @@ export const GroupedAssetRow = ({
_focus={focus}
>
<Flex gap={4} alignItems='center'>
<AssetIcon assetId={asset.assetId} size='sm' />
<AssetIcon asset={asset} size='sm' />
<Box textAlign='left'>
<Text
lineHeight='normal'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ export const TransferColumn = (transfer: TransferColumnProps) => {
/>
<Row title='for' justifyContent='flex-start' flexDirection='column' alignItems='flex-start'>
<Stack direction='row' spacing={2} alignItems='center'>
<AssetIcon src={transfer.asset.icon} boxSize='4' />
<AssetIcon asset={transfer.asset} boxSize='4' />
<Amount
value={transfer.value}
precision={transfer.asset.precision}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ export const AssetTransfer: React.FC<AssetTransferProps> = ({ index, compactMode
direction={index === 0 ? 'row' : 'row-reverse'}
textAlign={index === 0 ? 'left' : 'right'}
>
<AssetIcon src={transfer.asset.icon} assetId={transfer.asset?.assetId} size={assetIconSize} />
<AssetIcon asset={transfer.asset} size={assetIconSize} />
<Box flex={1}>
<Amount.Crypto
color='inherit'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,11 +73,7 @@ export const AssetsTransfers: React.FC<AssetsTransfersProps> = ({
>
{singleAsset ? (
<>
<AssetIcon
src={transfers[0].asset.icon}
assetId={transfers[0].asset?.assetId}
size={assetIconSize}
/>
<AssetIcon asset={transfers[0].asset} size={assetIconSize} />
<Box flex={1}>
<Amount.Crypto
color='inherit'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,12 +59,14 @@ export const ThorchainSaversEmpty = ({ assetId, onClick }: ThorchainSaversEmptyP
)

const renderFooter = useMemo(() => {
if (!asset) return

return (
<Flex flexDir='column' gap={4} width='full'>
{bnOrZero(cryptoBalance).eq(0) && assetSupportsBuy}
<Alert status='info' justifyContent='space-between' borderRadius='xl'>
<Flex gap={2} alignItems='center'>
<AssetIcon assetId={asset?.assetId} size='sm' />
<AssetIcon assetId={asset.assetId} size='sm' />
<Text fontWeight='bold' letterSpacing='-0.02em' translation={needAssetTranslation} />
</Flex>
<Button variant='ghost' size='sm' colorScheme='blue' onClick={handleAssetBuyClick}>
Expand All @@ -85,14 +87,14 @@ export const ThorchainSaversEmpty = ({ assetId, onClick }: ThorchainSaversEmptyP
</Flex>
)
}, [
asset?.assetId,
assetSupportsBuy,
asset,
cryptoBalance,
handleAssetBuyClick,
assetSupportsBuy,
needAssetTranslation,
onClick,
handleAssetBuyClick,
translate,
hasAccounts,
onClick,
])

const emptyOverviewAssets = useMemo(() => (asset ? [asset] : []), [asset])
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -410,15 +410,15 @@ export const TransactionRow: React.FC<TransactionRowProps> = ({
<CardHeader gap={2} display='flex' flexDir='row' alignItems='center'>
<AssetIcon size='xs' assetId={asset.assetId} />
<Amount.Crypto fontWeight='bold' value={amountCryptoPrecision} symbol={asset.symbol} />{' '}
{isSymWithdraw && (
{isSymWithdraw && poolAsset && (
// Symmetrical withdrawals withdraw both asset amounts in a single TX.
// In this case, we want to show the pool asset amount in additional to the rune amount for the user
<>
<AssetIcon size='xs' assetId={poolAsset?.assetId} />
<AssetIcon size='xs' assetId={poolAsset.assetId} />
<Amount.Crypto
fontWeight='bold'
value={confirmedQuote.assetWithdrawAmountCryptoPrecision}
symbol={poolAsset?.symbol ?? ''}
symbol={poolAsset.symbol ?? ''}
/>{' '}
</>
)}
Expand Down

0 comments on commit c3bac3d

Please sign in to comment.