Skip to content

Commit e62d547

Browse files
authored
feat(next): CP-12485 account view (#519)
1 parent 6d70104 commit e62d547

File tree

32 files changed

+1018
-75
lines changed

32 files changed

+1018
-75
lines changed

apps/next/src/components/Header/components/HeaderAccount/HeaderAccount.tsx

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -69,10 +69,12 @@ const HeaderAccountContent: FC<Props> = ({ wallet, isTrueWallet, account }) => {
6969
isContainerHovered={isContainerHovered}
7070
/>
7171

72-
{/* Navigation Arrow */}
73-
<IconWrapper shouldShift={false}>
74-
<MdNavigateNext />
75-
</IconWrapper>
72+
{/* Navigation Arrow: Waiting for account to be visible */}
73+
{account && (
74+
<IconWrapper shouldShift={false}>
75+
<MdNavigateNext />
76+
</IconWrapper>
77+
)}
7678

7779
{/* Account Name */}
7880
<AccountSection
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import { FC } from 'react';
2+
import { TruncatedText } from '../../styledComponents';
3+
import { AccountSectionContainer, Label } from '../styled';
4+
import { useTranslation } from 'react-i18next';
5+
6+
type Props = {
7+
tokenTextRef: React.RefObject<HTMLSpanElement | null>;
8+
isTokenTruncated: boolean;
9+
tokenName: string;
10+
isContainerHovered: boolean;
11+
};
12+
13+
export const TokenSection: FC<Props> = ({
14+
tokenTextRef,
15+
isTokenTruncated,
16+
tokenName,
17+
isContainerHovered,
18+
}) => {
19+
const { t } = useTranslation();
20+
21+
return (
22+
<AccountSectionContainer shouldShift={false}>
23+
<TruncatedText
24+
ref={tokenTextRef}
25+
variant="subtitle3"
26+
showFade={isTokenTruncated}
27+
>
28+
{tokenName}
29+
</TruncatedText>
30+
{isContainerHovered && <Label variant="caption">{t('Token')}</Label>}
31+
</AccountSectionContainer>
32+
);
33+
};

apps/next/src/localization/locales/en/translation.json

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,8 @@
9393
"Ask Core Concierge to swap tokens": "Ask Core Concierge to swap tokens",
9494
"Ask Core Concierge to transfer for you": "Ask Core Concierge to transfer for you",
9595
"Assets": "Assets",
96+
"Atomic Memory Locked": "Atomic Memory Locked",
97+
"Atomic Memory Unlocked": "Atomic Memory Unlocked",
9698
"Attempted to use an unknown derivation path": "Attempted to use an unknown derivation path",
9799
"Authenticator": "Authenticator",
98100
"Authenticator added!": "Authenticator added!",
@@ -140,6 +142,7 @@
140142
"Chain ID": "Chain ID",
141143
"Change Authenticator App": "Change Authenticator App",
142144
"Change password": "Change password",
145+
"Check full transaction history on the explorer": "Check full transaction history on the explorer",
143146
"Chinese - Simplified": "Chinese - Simplified",
144147
"Chinese - Traditional": "Chinese - Traditional",
145148
"Choose": "Choose",
@@ -401,6 +404,9 @@
401404
"Locate the connect button on their site": "Locate the connect button on their site",
402405
"Lock Core": "Lock Core",
403406
"Locked": "Locked",
407+
"Locked Platform": "Locked Platform",
408+
"Locked Stakeable": "Locked Stakeable",
409+
"Locked Staked": "Locked Staked",
404410
"Login": "Login",
405411
"Logo URL": "Logo URL",
406412
"Losing this phrase will result in lost funds": "Losing this phrase will result in lost funds",
@@ -463,6 +469,7 @@
463469
"No matching results": "No matching results",
464470
"No matching sites found": "No matching sites found",
465471
"No recent transactions": "No recent transactions",
472+
"No recent transctions": "No recent transctions",
466473
"No recovery methods set up": "No recovery methods set up",
467474
"No results found": "No results found",
468475
"No routes found with enough liquidity.": "No routes found with enough liquidity.",
@@ -757,6 +764,7 @@
757764
"Type": "Type",
758765
"Type in or paste address": "Type in or paste address",
759766
"Type in or paste token contract address": "Type in or paste token contract address",
767+
"UTXOs across multiple addresses": "UTXOs across multiple addresses",
760768
"Unable to cancel the export request. Please contact support.": "Unable to cancel the export request. Please contact support.",
761769
"Unable to connect": "Unable to connect",
762770
"Unable to connect.": "Unable to connect.",
@@ -782,6 +790,9 @@
782790
"Unlimited": "Unlimited",
783791
"Unlimited {{currency}}": "Unlimited {{currency}}",
784792
"Unlock airdrops": "Unlock airdrops",
793+
"Unlocked": "Unlocked",
794+
"Unlocked Staked": "Unlocked Staked",
795+
"Unlocked Unstaked": "Unlocked Unstaked",
785796
"Unnamed FIDO Device": "Unnamed FIDO Device",
786797
"Unsupporetd secret type": "Unsupporetd secret type",
787798
"Unsupported Version": "Unsupported Version",
@@ -815,7 +826,10 @@
815826
"Vesting": "Vesting",
816827
"Videos": "Videos",
817828
"View All Connected Sites": "View All Connected Sites",
829+
"View all of your balances and UTXOs": "View all of your balances and UTXOs",
830+
"View full history": "View full history",
818831
"View in Explorer": "View in Explorer",
832+
"View on explorer": "View on explorer",
819833
"View preference": "View preference",
820834
"View the troubleshooting guide <troubleshootButton>here</troubleshootButton>": "View the troubleshooting guide <troubleshootButton>here</troubleshootButton>",
821835
"Waiting for <bold>{{provider}}</bold> authentication to complete": "Waiting for <bold>{{provider}}</bold> authentication to complete",

apps/next/src/pages/Portfolio/Portfolio.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,14 @@ import { AddCustomToken } from './components/AddCustomToken/AddCustomToken';
44
import { ManageTokens } from './components/ManageTokens';
55
import { PortfolioHome } from './components/PortfolioHome';
66
import { WalletView } from './components/WalletView/WalletView';
7+
import { TokenDetails } from './components/PortfolioHome/components/PortolioDetails/components/TokenDetails';
78

89
export const Portfolio: FC = () => (
910
<Switch>
1011
<Route path="/manage-tokens/add-custom" component={AddCustomToken} />
1112
<Route path="/manage-tokens" component={ManageTokens} />
1213
<Route path="/wallet/:walletId" component={WalletView} />
14+
<Route path="/asset/:networkId/:tokenAddress" component={TokenDetails} />
1315
<Route path="/" component={PortfolioHome} />
1416
</Switch>
1517
);

apps/next/src/pages/Portfolio/components/PortfolioHome/PortfolioHome.tsx

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import {
2-
alpha,
32
CircularProgress,
43
Stack,
54
styled,
@@ -22,6 +21,7 @@ import { useTranslation } from 'react-i18next';
2221
import { TESTNET_MODE_BACKGROUND_COLOR } from '@/config/constants';
2322
import { TestnetModeOverlay } from '@/components/TestnetModeOverlay';
2423
import { useHistory, useLocation } from 'react-router-dom';
24+
import { TabsContainer } from './styled';
2525

2626
export type TabName = 'assets' | 'collectibles' | 'defi' | 'activity';
2727

@@ -124,18 +124,6 @@ export const PortfolioHome: FC = () => {
124124
);
125125
};
126126

127-
const TabsContainer = styled(Stack)(({ theme }) => ({
128-
position: 'sticky',
129-
bottom: 0,
130-
paddingTop: theme.spacing(1),
131-
zIndex: theme.zIndex.appBar,
132-
background: `linear-gradient(180deg, ${alpha(theme.palette.background.default, 0)} 0%, ${theme.palette.background.default} 16px)`,
133-
134-
'> div': {
135-
background: 'unset',
136-
},
137-
}));
138-
139127
const CenteredSpinner = styled(CircularProgress)({
140128
margin: 'auto',
141129
});

apps/next/src/pages/Portfolio/components/PortfolioHome/components/PortolioDetails/components/ActivityTab/components/ActivityFilterSelector.tsx

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
import { DropdownMenu } from '@/components/DropdownMenu';
22
import { Box, PopoverItem } from '@avalabs/k2-alpine';
3-
import { FC } from 'react';
3+
import { FC, RefObject, useMemo } from 'react';
44
import { ActivityFilter } from '../types';
55
import { useTranslation } from 'react-i18next';
66

77
type Props = {
88
selected: ActivityFilter;
99
onChange(filter: ActivityFilter): void;
10+
ref?: RefObject<HTMLElement>;
11+
exclude?: ActivityFilter[];
1012
};
1113

1214
const ACTIVITY_FILTERS: ActivityFilter[] = [
@@ -19,12 +21,21 @@ const ACTIVITY_FILTERS: ActivityFilter[] = [
1921
'NFTs',
2022
];
2123

22-
export const ActivityFilterSelector: FC<Props> = ({ selected, onChange }) => {
24+
export const ActivityFilterSelector: FC<Props> = ({
25+
selected,
26+
onChange,
27+
ref,
28+
exclude,
29+
}) => {
2330
const { t } = useTranslation();
31+
const filteredActivityFilters = useMemo(() => {
32+
return ACTIVITY_FILTERS.filter((filter) => !exclude?.includes(filter));
33+
}, [exclude]);
34+
2435
return (
25-
<Box>
36+
<Box ref={ref}>
2637
<DropdownMenu label={t('Filter')}>
27-
{ACTIVITY_FILTERS.map((filterName) => (
38+
{filteredActivityFilters.map((filterName) => (
2839
<PopoverItem
2940
key={filterName}
3041
onClick={() => onChange(filterName)}

apps/next/src/pages/Portfolio/components/PortfolioHome/components/PortolioDetails/components/ActivityTab/components/TransactionList/TransactionList.tsx

Lines changed: 5 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
1-
import { List, ListItem, Typography } from '@avalabs/k2-alpine';
21
import { NetworkWithCaipId } from '@core/types';
3-
import { FC, Fragment, memo } from 'react';
4-
import { useAccountHistory, useGroupedHistory } from '../../hooks';
2+
import { FC, memo } from 'react';
3+
import { useAccountHistory } from '../../hooks';
54
import { ActivityFilter } from '../../types';
6-
import { EmptyState } from '../EmptyState';
7-
import * as Styled from './components/Styled';
8-
import { TransactionItem } from './components/TransactionItem';
5+
6+
import { HistoryList } from './components/HistoryList';
97

108
type Props = {
119
filter: ActivityFilter;
@@ -15,43 +13,8 @@ type Props = {
1513
const TransactionList: FC<Props> = ({ filter, network }) => {
1614
const transactionHistory = useAccountHistory(network);
1715

18-
const groupedTransactionHistory = useGroupedHistory(
19-
transactionHistory,
20-
filter,
21-
);
22-
23-
if (transactionHistory.length === 0) {
24-
return <EmptyState />;
25-
}
26-
2716
return (
28-
<List disablePadding>
29-
{Object.entries(groupedTransactionHistory).map(
30-
([groupName, transactions]) => (
31-
<ListItem key={groupName} disableGutters disablePadding>
32-
<Styled.List
33-
disablePadding
34-
subheader={
35-
<Styled.ListSubheader disableGutters>
36-
<Typography variant="h6" color="text.primary">
37-
{groupName}
38-
</Typography>
39-
</Styled.ListSubheader>
40-
}
41-
>
42-
{transactions.map((tx, index, self) => (
43-
<Fragment key={tx.hash}>
44-
<TransactionItem transaction={tx} />
45-
{index < self.length - 1 && (
46-
<Styled.Divider variant="inset" />
47-
)}
48-
</Fragment>
49-
))}
50-
</Styled.List>
51-
</ListItem>
52-
),
53-
)}
54-
</List>
17+
<HistoryList filter={filter} transactionHistory={transactionHistory} />
5518
);
5619
};
5720

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import { ActivityFilter } from '../../../types';
2+
import { TxHistoryItem } from '@core/types';
3+
import { NetworkVMType } from '@avalabs/vm-module-types';
4+
import { FC, Fragment } from 'react';
5+
import { useGroupedHistory } from '../../../hooks';
6+
import { List, ListItem, Typography } from '@avalabs/k2-alpine';
7+
import { EmptyState } from '@/pages/Portfolio/components/PortfolioHome/components/EmptyState';
8+
import * as Styled from './Styled';
9+
import { TransactionItem } from './TransactionItem';
10+
11+
type Props = {
12+
filter: ActivityFilter;
13+
transactionHistory: TxHistoryItem<NetworkVMType>[];
14+
};
15+
16+
export const HistoryList: FC<Props> = ({ filter, transactionHistory }) => {
17+
const groupedTransactionHistory = useGroupedHistory(
18+
transactionHistory,
19+
filter,
20+
);
21+
22+
if (transactionHistory.length === 0) {
23+
return <EmptyState />;
24+
}
25+
26+
return (
27+
<List disablePadding>
28+
{Object.entries(groupedTransactionHistory).map(
29+
([groupName, transactions]) => (
30+
<ListItem key={groupName} disableGutters disablePadding>
31+
<Styled.List
32+
disablePadding
33+
subheader={
34+
<Styled.ListSubheader disableGutters>
35+
<Typography variant="h6" color="text.primary">
36+
{groupName}
37+
</Typography>
38+
</Styled.ListSubheader>
39+
}
40+
>
41+
{transactions.map((tx, index, self) => (
42+
<Fragment key={tx.hash}>
43+
<TransactionItem transaction={tx} />
44+
{index < self.length - 1 && (
45+
<Styled.Divider variant="inset" />
46+
)}
47+
</Fragment>
48+
))}
49+
</Styled.List>
50+
</ListItem>
51+
),
52+
)}
53+
</List>
54+
);
55+
};

apps/next/src/pages/Portfolio/components/PortfolioHome/components/PortolioDetails/components/AssetCard.tsx

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,15 @@ import { ProfitAndLoss } from './ProfitAndLoss';
1010
import { FungibleTokenBalance } from '@core/types';
1111
import { TokenAvatar } from '@/components/TokenAvatar';
1212
import { Card } from '@/components/Card';
13+
import { useHistory } from 'react-router-dom';
14+
import { TokenType } from '@avalabs/vm-module-types';
1315

1416
interface AssetCardProps {
1517
asset: FungibleTokenBalance;
16-
onClick?: () => void;
1718
}
1819

19-
const AVATAR_SIZE = 40;
20-
const BADGE_SIZE = 18;
20+
const AVATAR_SIZE = 32;
21+
const BADGE_SIZE = 16;
2122
const CHEVRON_SIZE = 20;
2223
const CARD_BORDER_RADIUS = 2;
2324
const CARD_GAP = 1.5;
@@ -34,14 +35,14 @@ const formatTokenBalance = (balance: string, symbol: string): string => {
3435
return `${balance} ${symbol}`;
3536
};
3637

37-
export const AssetCard = ({ asset, onClick }: AssetCardProps) => {
38+
export const AssetCard = ({ asset }: AssetCardProps) => {
3839
const theme = useTheme();
40+
const history = useHistory();
3941

4042
const handleClick = () => {
41-
onClick?.();
42-
// TODO: Navigate to asset details page when route is available
43-
// const history = useHistory();
44-
// history.push(`/asset/${asset.symbol}`);
43+
const tokenAddress =
44+
asset.type === TokenType.NATIVE ? asset.symbol : asset.address;
45+
history.push(`/asset/${asset.coreChainId}/${tokenAddress}`);
4546
};
4647

4748
const badgeBorderColor = getBadgeBorderColor(theme);
@@ -51,15 +52,21 @@ export const AssetCard = ({ asset, onClick }: AssetCardProps) => {
5152
);
5253

5354
return (
54-
<Card sx={{ width: '100%', borderRadius: CARD_BORDER_RADIUS }}>
55+
<Card
56+
sx={{
57+
width: '100%',
58+
borderRadius: CARD_BORDER_RADIUS,
59+
backgroundColor: 'background.paper',
60+
}}
61+
>
5562
<Stack
5663
role="button"
5764
onClick={handleClick}
5865
direction="row"
5966
alignItems="center"
6067
gap={CARD_GAP}
6168
sx={{
62-
cursor: onClick ? 'pointer' : 'default',
69+
cursor: 'pointer',
6370
px: theme.spacing(CARD_PADDING_X),
6471
py: theme.spacing(CARD_PADDING_Y),
6572
}}
@@ -75,7 +82,7 @@ export const AssetCard = ({ asset, onClick }: AssetCardProps) => {
7582
/>
7683
</Box>
7784

78-
<Stack flexGrow={1} minWidth={0}>
85+
<Stack flexGrow={1} minWidth={0} gap={0}>
7986
<Typography
8087
variant="subtitle3"
8188
noWrap

0 commit comments

Comments
 (0)