Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 9 additions & 3 deletions apps/next/src/hooks/useAllTokensFromEnabledNetworks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,14 @@ import { useNetworkContext } from '@core/ui';
import { useAllTokens } from './useAllTokens';

// TODO: Currently the hook is using favoriteNetwork. It should be changed to enabledNetworks once added.
export const useAllTokensFromEnabledNetworks = () => {
const { favoriteNetworks } = useNetworkContext();
export const useAllTokensFromEnabledNetworks = (
onlyTokensWithBalances?: boolean,
hideMalicious?: boolean,
) => {
const { enabledNetworks } = useNetworkContext();
const tokens = useAllTokens(enabledNetworks, hideMalicious);

return useAllTokens(favoriteNetworks, false);
return !onlyTokensWithBalances
? tokens
: tokens.filter((token) => token.balance);
};
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import { useAllTokensFromEnabledNetworks } from '@/hooks/useAllTokensFromEnabledNetworks';
import { Box } from '@avalabs/k2-alpine';
import { TokenType } from '@avalabs/vm-module-types';
import { isTokenMalicious } from '@core/common';
import { FungibleTokenBalance } from '@core/types';
import { FC, useMemo } from 'react';
import { FixedSizeList, ListChildComponentProps } from 'react-window';
Expand All @@ -16,41 +14,29 @@ interface Props {

export const TokenSwitchList: FC<Props> = ({ filter, spam }) => {
const [height, containerRef] = useContainerHeight<HTMLDivElement>(400);
const tokensWithBalances = useAllTokensFromEnabledNetworks();
const tokensWithBalances = useAllTokensFromEnabledNetworks(false, !spam);

const nonNative = useMemo(() => {
return tokensWithBalances.filter(
(token) => token.type !== TokenType.NATIVE,
);
}, [tokensWithBalances]);

const spamless = useMemo(
() =>
spam ? nonNative : nonNative.filter((token) => !isTokenMalicious(token)),
[spam, nonNative],
);

const filtered = useMemo(
const filteredTokensList = useMemo(
() =>
filter
? spamless.filter((token) => {
? tokensWithBalances.filter((token) => {
const normalizedFilter = filter.toLowerCase();
return (
token.name.toLowerCase().includes(normalizedFilter) ||
token.symbol.toLowerCase().includes(normalizedFilter)
);
})
: spamless,
[filter, spamless],
: tokensWithBalances,
[filter, tokensWithBalances],
);

return (
<Box height={1} ref={containerRef}>
<FixedSizeList
height={height}
width="100%"
itemData={filtered}
itemCount={filtered.length}
itemData={filteredTokensList}
itemCount={filteredTokensList.length}
itemSize={54}
overscanCount={5}
style={{ overflow: 'auto', scrollbarWidth: 'none' }}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import { Avatar, Box, Stack, Typography } from '@avalabs/k2-alpine';
import { ProfitAndLoss } from './ProfitAndLoss';
import { FungibleTokenBalance } from '@core/types';

interface AssetCardProps {
asset: FungibleTokenBalance;
last?: boolean;
}

export const AssetCard = ({ asset, last }: AssetCardProps) => {
console.log('asset: ', asset);
return (
<Stack
width="100%"
direction="row"
alignItems="center"
justifyContent="space-between"
pt={1}
>
{/* Left side - Avatar */}
<Box position="relative" sx={{ transform: 'translateY(-4px)' }}>
<Avatar
alt={asset.symbol}
src={asset.logoUri || undefined}
sx={{ width: 36, height: 36 }}
>
{asset.symbol}
</Avatar>
</Box>
<Stack
direction="row"
alignItems="center"
justifyContent="space-between"
gap={2}
flexGrow={1}
ml={2}
pb={1}
borderBottom={last ? undefined : '1px solid'}
borderColor={last ? undefined : 'divider'}
width={`calc(100% - 52px)`} // 36px (avatar) + 16px (gaps)
>
{/* Middle left side - Token info */}
<Stack flexGrow={1} minWidth={0}>
<Typography variant="body3" noWrap>
{asset.name}
</Typography>
<Typography color="text.secondary" variant="body3" noWrap>
{asset.balanceDisplayValue} {asset.symbol}
</Typography>
</Stack>

<Stack
justifyContent="space-between"
alignItems="center"
flexGrow={1}
direction="row"
columnGap={1.5}
>
<Box
alignItems="flex-end"
ml="auto"
display="flex"
justifyContent="flex-end"
>
<Stack alignItems="flex-end">
<ProfitAndLoss
// percentage={asset.priceChanges?.percentage}
// value={asset.balanceCurrencyDisplayValue}
asset={asset}
/>
</Stack>
</Box>
</Stack>
</Stack>
</Stack>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,18 @@ import {
} from '@avalabs/k2-alpine';
import { FC } from 'react';
import { useTranslation } from 'react-i18next';
import { MdCurrencyBitcoin, MdKeyboardArrowDown } from 'react-icons/md';
import { MdKeyboardArrowDown } from 'react-icons/md';
import { useHistory } from 'react-router-dom';
import { UnderConstruction } from './UnderConstruction';
import { useAllTokensFromEnabledNetworks } from '@/hooks/useAllTokensFromEnabledNetworks';
import { TrendingTokenBanner } from '@/pages/TrendingTokens/components/banner/TrendingTokenBanner';

import { AssetCard } from './AssetCard';

export const AssetsTab: FC = () => {
const { t } = useTranslation();
const { push } = useHistory();
const assets = useAllTokensFromEnabledNetworks(true, true);
console.log('assets: ', assets);
return (
<Stack direction="column" gap={1.25} height={1}>
<Box bgcolor="background.paper" borderRadius={2} px={2}>
Expand All @@ -40,11 +44,21 @@ export const AssetsTab: FC = () => {
</StyledButton>
</Box>
</Stack>
<UnderConstruction
{/* <UnderConstruction
title="Assets"
description="Your assets will be displayed here. We're working hard to bring you this feature soon!"
icon={<MdCurrencyBitcoin size={24} />}
/>
/> */}
<Stack width="100%" flexGrow={1}>
{assets.map((token, index) => (
<AssetCard
key={token.name}
asset={token}
last={index === assets.length - 1}
// network={network}
/>
))}
</Stack>
</Stack>
);
};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {
BridgeIcon,
SendIcon,
Slide,
SquareButton,
Stack,
SwapIcon,
Expand All @@ -27,32 +28,40 @@ const ICON_SIZE = 19.2;
export const PortfolioActionButtons = () => {
const { push } = useHistory();
return (
<Stack direction="row" gap={1}>
<SquareButton
variant="extension"
icon={<SendIcon size={ICON_SIZE} />}
label="Send"
onClick={() => push(getSendPath())}
/>

<SquareButton
variant="extension"
icon={<SwapIcon size={ICON_SIZE} />}
label="Swap"
onClick={() => push(getSwapPath())}
/>
<SquareButton
variant="extension"
icon={<MdAdd size={ICON_SIZE} />}
label="Buy"
onClick={onNotImplementedClick}
/>
<SquareButton
variant="extension"
icon={<BridgeIcon size={ICON_SIZE} />}
label="Bridge"
onClick={onNotImplementedClick}
/>
<Stack direction="row" gap={1} width="100%">
{/* TODO: create the proper animation */}
<Slide direction="left" in timeout={300} easing="ease-out">
<SquareButton
variant="extension"
icon={<SendIcon size={ICON_SIZE} />}
label="Send"
onClick={() => push(getSendPath())}
/>
</Slide>
<Slide direction="left" in timeout={600} easing="ease-out">
<SquareButton
variant="extension"
icon={<SwapIcon size={ICON_SIZE} />}
label="Swap"
onClick={() => push(getSwapPath())}
/>
</Slide>
<Slide direction="left" in timeout={900} easing="ease-out">
<SquareButton
variant="extension"
icon={<MdAdd size={ICON_SIZE} />}
label="Buy"
onClick={onNotImplementedClick}
/>
</Slide>
<Slide direction="left" in timeout={1200} easing="ease-out">
<SquareButton
variant="extension"
icon={<BridgeIcon size={ICON_SIZE} />}
label="Bridge"
onClick={onNotImplementedClick}
/>
</Slide>
</Stack>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import {
Stack,
TriangleDownIcon,
TriangleUpIcon,
Typography,
useTheme,
} from '@avalabs/k2-alpine';
import {
FungibleTokenBalance,
getUnconfirmedBalanceInCurrency,
} from '@core/types';
import { useSettingsContext } from '@core/ui';
import { useMemo } from 'react';

export enum Trend {
Up = 'up',
Down = 'down',
NoChange = 'no-change',
}

interface ProfitAndLossProps {
// value?: number;
// percentage?: number;
// showPercentage?: boolean;
// size?: 'big';
asset: FungibleTokenBalance;
}

export const ProfitAndLoss = ({
// value,
// percentage,
// size,
// showPercentage,
// balanceInCurrency,
asset,
}: ProfitAndLossProps) => {
const { currencyFormatter } = useSettingsContext();
const theme = useTheme();

const trend =
asset.priceChanges?.percentage && asset.priceChanges?.percentage > 0
? Trend.Up
: Trend.Down;

const color = useMemo(() => {
if (trend === Trend.Up) {
return theme.palette.success.main;
}
if (trend === Trend.Down) {
return theme.palette.error.light;
}
return theme.palette.text.secondary;
}, [
theme.palette.error.light,
theme.palette.success.main,
theme.palette.text.secondary,
trend,
]);

const Icon = () => {
if (trend === Trend.Up) {
return <TriangleUpIcon size={8} />;
}
if (trend === Trend.Down) {
return <TriangleDownIcon size={8} />;
}
};

if (
!asset.priceChanges?.percentage ||
!asset.priceChanges?.value ||
!asset.balanceInCurrency
) {
return <></>;
}

return (
<Stack>
{/* <ProfitAndLoss
value={currencyFormatter(value)}
percentage={
showPercentage
? `${percentage.toFixed(DEFAULT_DECIMALS)}%`
: undefined
}
trend={trend}
size={size}
/> */}
<Stack sx={{ gap: 0.5 }}>
<>
<Typography sx={{ color: theme.palette.text.secondary }}>
{/* {`${percentage.toFixed(DEFAULT_DECIMALS)}%`} */}
{currencyFormatter(
asset.balanceInCurrency +
(getUnconfirmedBalanceInCurrency(asset) ?? 0),
)}
</Typography>
</>

<Stack
sx={{ flexDirection: 'row', color, alignItems: 'center', gap: 0.5 }}
>
<Typography>{currencyFormatter(asset.priceChanges.value)}</Typography>
<Icon />
</Stack>
</Stack>
</Stack>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ export const NetworkToggleList = ({ networks }: NetworkToggleListProps) => {
useNetworkContext();
const history = useHistory();

const enabledNetworksArray = enabledNetworks || [];
const enabledNetworksArray =
enabledNetworks.map((network) => network.chainId) || [];

return (
<Stack
Expand Down
Loading
Loading