Skip to content

Commit fed0a13

Browse files
committed
feat(mobile): implement token details, ref LEA-3015
1 parent b0c19e5 commit fed0a13

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+1336
-125
lines changed

apps/mobile/src/app/account/[accountId]/activity.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import { deserializeAccountId } from '@/store/accounts/accounts';
88
import { i18n } from '@lingui/core';
99
import { useLocalSearchParams } from 'expo-router';
1010

11-
import { OnChainActivity } from '@leather.io/models';
1211
import { Text } from '@leather.io/ui/native';
1312

1413
export default function AccountActivityScreen() {
@@ -43,7 +42,7 @@ export default function AccountActivityScreen() {
4342
})}
4443
</Screen.Title>
4544
}
46-
data={activity.value as OnChainActivity[]} // TODO: Unclear why was this cast. Needs clearing up.
45+
data={activity.value.filter(activity => activity && 'asset' in activity)}
4746
renderItem={({ item }) => <ActivityListItem activity={item} />}
4847
keyExtractor={(_, index) => `activity.${index}`}
4948
ListEmptyComponent={<ActivityEmpty />}

apps/mobile/src/app/activity/index.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import { RefreshControl, useRefreshHandler } from '@/features/refresh-control/re
66
import { useTotalActivity } from '@/queries/activity/account-activity.query';
77
import { t } from '@lingui/macro';
88

9-
import { OnChainActivity } from '@leather.io/models';
109
import { Text } from '@leather.io/ui/native';
1110

1211
export default function ActivityScreen() {
@@ -22,7 +21,7 @@ export default function ActivityScreen() {
2221
<Screen.List
2322
refreshControl={<RefreshControl />}
2423
ListHeaderComponent={<Screen.Title>{pageTitle}</Screen.Title>}
25-
data={activity.value as OnChainActivity[]} // TODO: Unclear why was this cast. Needs clearing up.
24+
data={activity.value.filter(activity => activity && 'asset' in activity)}
2625
renderItem={({ item }) => <ActivityListItem activity={item} />}
2726
keyExtractor={(_, index) => `activity.${index}`}
2827
ListEmptyComponent={<ActivityEmpty />}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import { ReactNode } from 'react';
2+
3+
import { Box, HasChildren, Text } from '@leather.io/ui/native';
4+
5+
export function SummaryTableRoot({ children }: HasChildren) {
6+
return <Box>{children}</Box>;
7+
}
8+
9+
function SummaryTableLabel({ children }: HasChildren) {
10+
return (
11+
<Box flex={1}>
12+
<Text variant="label02" color="ink.text-subdued">
13+
{children}
14+
</Text>
15+
</Box>
16+
);
17+
}
18+
19+
function SummaryTableValue({ children }: HasChildren) {
20+
return (
21+
<Box flex={1} alignItems="flex-end">
22+
<Text variant="label02">{children}</Text>
23+
</Box>
24+
);
25+
}
26+
27+
interface SummaryTableItem {
28+
label: string;
29+
value: ReactNode;
30+
}
31+
32+
export function SummaryTableItem({ label, value }: SummaryTableItem) {
33+
return (
34+
<Box flexDirection="row" py="2">
35+
<SummaryTableLabel>{label}</SummaryTableLabel>
36+
<SummaryTableValue>{value}</SummaryTableValue>
37+
</Box>
38+
);
39+
}
40+
41+
export const SummaryTable = {
42+
Root: SummaryTableRoot,
43+
Item: SummaryTableItem,
44+
Value: SummaryTableValue,
45+
Label: SummaryTableLabel,
46+
};

apps/mobile/src/features/account/account-list/account-list-item.tsx

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ interface AccountListItemProps extends PressableProps {
77
icon: React.ReactNode;
88
iconTestID?: string;
99
testID?: string;
10-
walletName?: string;
10+
walletName?: React.ReactNode;
11+
chevron?: React.ReactNode;
1112
}
1213
export function AccountListItem({
1314
accountName,
@@ -18,19 +19,23 @@ export function AccountListItem({
1819
onPress,
1920
testID,
2021
walletName,
22+
chevron,
2123
...rest
2224
}: AccountListItemProps) {
2325
return (
2426
<Cell.Root pressable={true} disabled={!onPress} onPress={onPress} testID={testID} {...rest}>
2527
<Cell.Icon testID={iconTestID}>{icon}</Cell.Icon>
2628
<Cell.Content>
27-
<Cell.Label variant="primary">{accountName}</Cell.Label>
29+
<Cell.Label variant="primary" numberOfLines={1} ellipsizeMode="tail">
30+
{accountName}
31+
</Cell.Label>
2832
<Cell.Label variant="secondary">{walletName}</Cell.Label>
2933
</Cell.Content>
3034
<Cell.Aside>
3135
<Cell.Label variant="primary">{balance}</Cell.Label>
3236
<Cell.Label variant="secondary">{address}</Cell.Label>
3337
</Cell.Aside>
38+
{chevron && <Cell.Icon>{chevron}</Cell.Icon>}
3439
</Cell.Root>
3540
);
3641
}

apps/mobile/src/features/account/account-selector/account-selector-sheet-header.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import {
1616
interface AccountSelectorHeaderProps {
1717
sheetRef: RefObject<SheetRef | null>;
1818
}
19-
// TODO: refactor HeaderLayout so that we can use it here
19+
2020
export function AccountSelectorHeader({ sheetRef }: AccountSelectorHeaderProps) {
2121
return (
2222
<Box alignItems="center" flexDirection="row" justifyContent="space-between" py="5">

apps/mobile/src/features/account/components/account-avatar.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ export function AccountAvatar(props: AccountAvatarProps) {
7070
alignItems="center"
7171
{...props}
7272
>
73-
{Icon && <Icon />}
73+
{Icon && <Icon {...props} />}
7474
</SquircleBox>
7575
);
7676
}

apps/mobile/src/features/account/components/account-card.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { ComponentType, ReactNode } from 'react';
33
import { Card } from '@/components/card';
44
import { Loading } from '@/components/loading/loading';
55
import { AccountAvatar } from '@/features/account/components/account-avatar';
6-
import { AppIcons } from '@/features/accounts/components/app-icons';
6+
import { AppIcons } from '@/features/account/components/app-icons';
77
import { AccountIcon } from '@/store/accounts/utils';
88

99
import { Box, HasChildren, PressableProps, Text } from '@leather.io/ui/native';

apps/mobile/src/features/accounts/components/app-icons.tsx renamed to apps/mobile/src/features/account/components/app-icons.tsx

File renamed without changes.

apps/mobile/src/features/accounts/components/browser-loading.tsx renamed to apps/mobile/src/features/account/components/browser-loading.tsx

File renamed without changes.
Lines changed: 76 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,101 @@
1+
import { useRef, useState } from 'react';
2+
13
import {
24
BitcoinBalance,
35
BitcoinBalanceByAccount,
46
} from '@/features/balances/bitcoin/bitcoin-balance';
57
import { RunesBalance, RunesBalanceByAccount } from '@/features/balances/bitcoin/runes-balance';
68
import { Sip10Balance, Sip10BalanceByAccount } from '@/features/balances/stacks/sip10-balance';
79
import { StacksBalance, StacksBalanceByAccount } from '@/features/balances/stacks/stacks-balance';
8-
import { useRunesFlag } from '@/features/feature-flags';
10+
import { useRunesFlag, useTokenDetailsFlag } from '@/features/feature-flags';
11+
import { TokenSheet, TokenSheetData } from '@/features/token/token-sheet';
912
import { ViewMode } from '@/shared/types';
1013

11-
import { AccountId } from '@leather.io/models';
12-
import { Box } from '@leather.io/ui/native';
14+
import { AccountId, FungibleCryptoAsset, Money } from '@leather.io/models';
15+
import { Box, SheetRef } from '@leather.io/ui/native';
1316

1417
export interface BalanceViewProps {
1518
mode: ViewMode;
19+
onPress?: ({ asset, availableBalance, quoteBalance }: OnOpenTokenProps) => void;
20+
}
21+
22+
export interface OnOpenTokenProps {
23+
asset: FungibleCryptoAsset;
24+
availableBalance: Money;
25+
quoteBalance: Money;
1626
}
1727

1828
export function AllAccountBalances({ mode }: BalanceViewProps) {
29+
const [sheetData, setSheetData] = useState<TokenSheetData | null>(null);
1930
const runesFlag = useRunesFlag();
31+
const tokenDetailsFlag = useTokenDetailsFlag();
32+
33+
const tokenSheetRef = useRef<SheetRef>(null);
34+
35+
function onOpenToken({ asset, availableBalance, quoteBalance }: OnOpenTokenProps) {
36+
setSheetData({ asset, availableBalance, quoteBalance });
37+
// analytics.track('token_sheet_opened', { source: 'action_bar' });
38+
tokenSheetRef.current?.present();
39+
}
40+
41+
const onPressToken = tokenDetailsFlag ? onOpenToken : undefined;
42+
2043
return (
21-
<Box flex={1} height="100%">
22-
<BitcoinBalance />
23-
<StacksBalance />
24-
<Sip10Balance mode={mode} />
25-
{runesFlag && <RunesBalance mode={mode} />}
26-
</Box>
44+
<>
45+
<Box flex={1} height="100%">
46+
<BitcoinBalance onPress={onPressToken} />
47+
<StacksBalance onPress={onPressToken} />
48+
<Sip10Balance mode={mode} onPress={onPressToken} />
49+
{runesFlag && <RunesBalance mode={mode} />}
50+
</Box>
51+
<TokenSheet data={sheetData} sheetRef={tokenSheetRef} />
52+
</>
2753
);
2854
}
2955

3056
export function AccountBalances({ mode, fingerprint, accountIndex }: AccountId & BalanceViewProps) {
57+
const [sheetData, setSheetData] = useState<TokenSheetData | null>(null);
3158
const runesFlag = useRunesFlag();
59+
60+
const tokenSheetRef = useRef<SheetRef>(null);
61+
const tokenDetailsFlag = useTokenDetailsFlag();
62+
63+
function onOpenToken(data: TokenSheetData) {
64+
setSheetData(data);
65+
// analytics.track('token_sheet_opened', { source: 'action_bar' });
66+
tokenSheetRef.current?.present();
67+
}
68+
69+
const onPressToken = tokenDetailsFlag ? onOpenToken : undefined;
70+
3271
return (
33-
<Box>
34-
<BitcoinBalanceByAccount fingerprint={fingerprint} accountIndex={accountIndex} />
35-
<StacksBalanceByAccount fingerprint={fingerprint} accountIndex={accountIndex} />
36-
<Sip10BalanceByAccount mode={mode} fingerprint={fingerprint} accountIndex={accountIndex} />
37-
{runesFlag && (
38-
<RunesBalanceByAccount mode={mode} fingerprint={fingerprint} accountIndex={accountIndex} />
39-
)}
40-
</Box>
72+
<>
73+
<Box>
74+
<BitcoinBalanceByAccount
75+
onPress={onPressToken}
76+
fingerprint={fingerprint}
77+
accountIndex={accountIndex}
78+
/>
79+
<StacksBalanceByAccount
80+
onPress={onPressToken}
81+
fingerprint={fingerprint}
82+
accountIndex={accountIndex}
83+
/>
84+
<Sip10BalanceByAccount
85+
mode={mode}
86+
fingerprint={fingerprint}
87+
accountIndex={accountIndex}
88+
onPress={onPressToken}
89+
/>
90+
{runesFlag && (
91+
<RunesBalanceByAccount
92+
mode={mode}
93+
fingerprint={fingerprint}
94+
accountIndex={accountIndex}
95+
/>
96+
)}
97+
</Box>
98+
<TokenSheet data={sheetData} sheetRef={tokenSheetRef} />
99+
</>
41100
);
42101
}

0 commit comments

Comments
 (0)