Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: nft list getting cut off #1829

Merged
merged 15 commits into from
Feb 12, 2025
5 changes: 5 additions & 0 deletions .changeset/rotten-toes-glow.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"fuels-wallet": patch
---

fix: nft list getting cut off
Original file line number Diff line number Diff line change
@@ -1,20 +1,30 @@
import { cssObj } from '@fuel-ui/css';
import { Accordion, Badge, Box, Copyable, VStack } from '@fuel-ui/react';
import { Accordion, Badge, Box, Copyable } from '@fuel-ui/react';
import type { CoinAsset } from '@fuel-wallet/types';
import { useMemo } from 'react';
import { memo, useMemo } from 'react';
import { NFTImageLoading } from '~/systems/Account/components/BalanceNFTs/NFTImageLoading';
import { AssetList } from '~/systems/Asset';
import { AssetListEmpty } from '~/systems/Asset/components/AssetList/AssetListEmpty';
import { shortAddress } from '~/systems/Core';
import { NFTImage } from './NFTImage';
import { NFTListItemLoading } from './NFTListItemLoading';
import { NFTTitleLoading } from './NFTTitleLoading';
import {
UNKNOWN_COLLECTION_TITLE,
groupNFTsByCollection,
} from './groupNFTsByCollection';

interface BalanceNFTsProps {
balances: CoinAsset[] | undefined;
isLoading?: boolean;
}

export const BalanceNFTs = ({ balances = [] }: BalanceNFTsProps) => {
const EMPTY_ARRAY: CoinAsset[] = [];

export const BalanceNFTs = ({
balances = EMPTY_ARRAY,
isLoading,
}: BalanceNFTsProps) => {
const { collections, defaultValue } = useMemo(() => {
const collections = groupNFTsByCollection(balances);
const defaultValue = collections
Expand All @@ -27,21 +37,31 @@ export const BalanceNFTs = ({ balances = [] }: BalanceNFTsProps) => {
};
}, [balances]);

if (collections.length === 0) {
return (
<AssetListEmpty
text="You don't have any NFTs"
supportText="To add NFTs, simply send them to your Fuel address."
hideFaucet
/>
);
}

return (
<Box css={styles.root}>
<Accordion type="multiple" defaultValue={defaultValue}>
{collections.map((collection) => {
return (
{isLoading && !collections.length && (
<Box css={styles.titleLoading}>
<NFTTitleLoading />
<Box css={styles.gridLoading}>
<NFTListItemLoading />
<NFTListItemLoading />
<NFTListItemLoading />
<NFTListItemLoading />
<NFTListItemLoading />
<NFTListItemLoading />
</Box>
</Box>
)}
{!isLoading && !collections?.length && (
<AssetListEmpty
text="You don't have any NFTs"
supportText="To add NFTs, simply send them to your Fuel address."
hideFaucet
/>
)}
{!!collections.length && (
<Accordion type="multiple" defaultValue={defaultValue}>
{collections.map((collection) => (
<Accordion.Item key={collection.name} value={collection.name}>
<Accordion.Trigger>
<Badge variant="ghost" color="gray" as="span">
Expand All @@ -64,9 +84,9 @@ export const BalanceNFTs = ({ balances = [] }: BalanceNFTsProps) => {
</Box>
</Accordion.Content>
</Accordion.Item>
);
})}
</Accordion>
))}
</Accordion>
)}
</Box>
);
};
Expand Down Expand Up @@ -102,7 +122,6 @@ const styles = {

svg: {
width: '$3',
height: '$3',
},
},
'.fuel_Accordion-content': {
Expand All @@ -128,6 +147,17 @@ const styles = {
gridTemplateColumns: 'repeat(3, 1fr)',
gap: '$3',
}),
gridLoading: cssObj({
display: 'grid',
gridTemplateColumns: 'repeat(3, 1fr)',
gap: '$3',
marginTop: '14px',
paddingLeft: '$5',
paddingRight: '$2',
}),
titleLoading: cssObj({
marginTop: '16px',
}),
name: cssObj({
marginTop: '$1',
gap: '$0',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,23 @@
import { cssObj } from '@fuel-ui/css';
import { Box, ContentLoader, Icon } from '@fuel-ui/react';
import { useEffect, useRef, useState } from 'react';
import { Box, ContentLoader, Icon, Image } from '@fuel-ui/react';
import { memo, useEffect, useRef, useState } from 'react';
import { NFTImageLoading } from '~/systems/Account/components/BalanceNFTs/NFTImageLoading';
import { shortAddress } from '~/systems/Core';

interface NFTImageProps {
assetId: string;
image: string | undefined;
}

export const NFTImage = ({ assetId, image }: NFTImageProps) => {
function Empty() {
return (
<Box css={styles.noImage}>
<Icon icon={Icon.is('FileOff')} />
</Box>
);
}

const _NFTImage = ({ assetId, image }: NFTImageProps) => {
const imgRef = useRef<HTMLImageElement>(null);

const [fallback, setFallback] = useState(false);
Expand All @@ -25,31 +34,22 @@ export const NFTImage = ({ assetId, image }: NFTImageProps) => {
}
}, []);

if (image && !fallback) {
return (
<Box css={styles.item}>
{isLoading && (
<ContentLoader width="100%" height="100%" viewBox="0 0 22 22">
<rect x="0" y="0" rx="0" ry="0" width="22" height="22" />
</ContentLoader>
)}
<img
if (!image || !!fallback) return <Empty />;

return (
<Box css={styles.item}>
{image && !fallback && isLoading && <NFTImageLoading />}
{image && !fallback && (
<Image
ref={imgRef}
src={image}
alt={shortAddress(assetId)}
data-loading={isLoading}
style={cssObj({ visibility: isLoading ? 'hidden' : 'visible' })}
arthurgeron marked this conversation as resolved.
Show resolved Hide resolved
onLoad={() => setLoading(false)}
onError={() => {
setFallback(true);
}}
onError={() => setFallback(true)}
/>
</Box>
);
}

return (
<Box css={styles.noImage}>
<Icon icon={Icon.is('FileOff')} />
)}
</Box>
);
};
Expand All @@ -59,7 +59,7 @@ const styles = {
aspectRatio: '1 / 1',
borderRadius: '12px',
overflow: 'hidden',

minHeight: '89px',
img: {
width: '100%',
objectFit: 'cover',
Expand All @@ -79,3 +79,7 @@ const styles = {
alignItems: 'center',
}),
};

export const NFTImage = memo(_NFTImage, (a, b) => {
return a.assetId === b.assetId && a.image === b.image;
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { cssObj } from '@fuel-ui/css';
import { Box, ContentLoader } from '@fuel-ui/react';

export function NFTImageLoading({ size = 89 }: { size?: number }) {
return (
<Box
css={cssObj({
overflow: 'hidden',
borderRadius: '10px',
width: `${size}px`,
height: `${size}px`,
})}
>
<ContentLoader width={size} height={size} viewBox={`0 0 ${size} ${size}`}>
<rect x="0" y="0" rx="0" ry="0" width={size} height={size} />
</ContentLoader>
</Box>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { cssObj } from '@fuel-ui/css';
import { Box } from '@fuel-ui/react';
import { NFTImageLoading } from './NFTImageLoading';
import { NFTTitleLoading } from './NFTTitleLoading';

export function NFTListItemLoading() {
return (
<Box
css={cssObj({
display: 'flex',
flexDirection: 'column',
gap: '8px',
})}
>
<NFTImageLoading />
<NFTTitleLoading />
</Box>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { cssObj } from '@fuel-ui/css';
import { Box, ContentLoader } from '@fuel-ui/react';

export function NFTTitleLoading({ height = 18 }: { height?: number }) {
return (
<Box
css={cssObj({
overflow: 'hidden',
borderRadius: '6px',
width: '89px',
height: `${height}px`,
})}
>
<ContentLoader
width="89px"
height={height ?? '100%'}
viewBox={`0 0 89 ${height}`}
>
<rect x="0" y="0" rx="0" ry="0" width="89" height="18" />
</ContentLoader>
</Box>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const BALANCE_NFTS_TAB_HEIGHT = 244;
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { cssObj } from '@fuel-ui/css';
import { Button, Card, Heading, Icon, Text } from '@fuel-ui/react';
import { Box, Button, Card, Heading, Icon, Text } from '@fuel-ui/react';
import { BALANCE_NFTS_TAB_HEIGHT } from '~/systems/Account/components/BalanceNFTs/constants';
import { useFundWallet } from '~/systems/FundWallet';

export type AssetListEmptyProps = {
Expand All @@ -17,29 +18,34 @@ export function AssetListEmpty({
const showFund = hasFaucet || hasBridge;

return (
<Card css={styles.empty}>
<Card.Body>
{!!text && <Heading as="h5">{text}</Heading>}
{!!supportText && <Text fontSize="sm">{supportText}</Text>}
{showFund && !hideFaucet && (
/**
* TODO: need to add right faucet icon on @fuel-ui
*/
<Button
size="sm"
intent="primary"
leftIcon={hasFaucet ? Icon.is('Wand') : Icon.is('Coins')}
onPress={open}
>
{hasFaucet ? 'Faucet' : 'Bridge to Fuel'}
</Button>
)}
</Card.Body>
</Card>
<Box css={styles.container}>
<Card css={styles.empty}>
<Card.Body>
{!!text && <Heading as="h5">{text}</Heading>}
{!!supportText && <Text fontSize="sm">{supportText}</Text>}
{showFund && !hideFaucet && (
/**
* TODO: need to add right faucet icon on @fuel-ui
*/
<Button
size="sm"
intent="primary"
leftIcon={hasFaucet ? Icon.is('Wand') : Icon.is('Coins')}
onPress={open}
>
{hasFaucet ? 'Faucet' : 'Bridge to Fuel'}
</Button>
)}
</Card.Body>
</Card>
</Box>
);
}

const styles = {
container: cssObj({
minHeight: BALANCE_NFTS_TAB_HEIGHT,
}),
empty: cssObj({
h5: {
margin: 0,
Expand Down
6 changes: 3 additions & 3 deletions packages/app/src/systems/Home/pages/Home/Home.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { useBalanceVisibility } from '~/systems/Core/hooks/useVisibility';

import { BalanceAssets } from '~/systems/Account/components/BalanceAssets/BalanceAssets';
import { BalanceNFTs } from '~/systems/Account/components/BalanceNFTs/BalanceNFTs';
import { BALANCE_NFTS_TAB_HEIGHT } from '~/systems/Account/components/BalanceNFTs/constants';
import { QuickAccountConnect } from '~/systems/Account/components/QuickAccountConnect/QuickAccountConnect';
import { HomeActions } from '../../components';

Expand Down Expand Up @@ -52,7 +53,7 @@ export function Home() {
<BalanceAssets balances={account?.balances} isLoading={isLoading} />
</Tabs.Content>
<Tabs.Content value="nft" css={styles.assetsList}>
<BalanceNFTs balances={account?.balances} />
<BalanceNFTs balances={account?.balances} isLoading={isLoading} />
</Tabs.Content>
</Tabs>
</Layout.Content>
Expand All @@ -69,8 +70,7 @@ const styles = {
},
}),
assetsList: cssObj({
maxHeight: 200,
paddingBottom: '$4',
height: BALANCE_NFTS_TAB_HEIGHT,
...scrollable(),
overflowY: 'scroll !important',
}),
Expand Down
Loading