Skip to content

Commit 97be076

Browse files
authored
feat: view account assets (#55)
* feat: display account assets * chore: adjust how we sync related state so it always runs before setting the atom * chore: fix lint * chore: action pr feedback
1 parent 0499158 commit 97be076

34 files changed

+608
-267
lines changed

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
"build:4-tsc": "tsc",
1313
"build:5-vite": "vite build",
1414
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
15-
"lint:fix": "eslint . --ext ts,tsx --fix",
15+
"lint:fix": "npm run lint -- --fix",
1616
"preview": "vite preview",
1717
"test": "vitest run",
1818
"test:watch": "vitest watch",
@@ -146,4 +146,4 @@
146146
"semantic-release-export-data"
147147
]
148148
}
149-
}
149+
}

src/features/accounts/components/account-activity-tabs.tsx

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { OverflowAutoTabsContent, Tabs, TabsList, TabsTrigger } from '@/features/common/components/tabs'
22
import { cn } from '@/features/common/utils'
33
import { useMemo } from 'react'
4-
import { AccountAssetHeld } from './account-assets-held'
4+
import { AccountAssetsHeld } from './account-assets-held'
55
import { Account } from '../models'
66
import { AccountTransactionHistory } from './account-transaction-history'
77
import {
@@ -18,7 +18,11 @@ import {
1818
accountCreatedAssetsTabLabel,
1919
accountCreatedApplicationsTabLabel,
2020
accountOptedApplicationsTabLabel,
21+
accountOptedAssetsTabId,
22+
accountOptedAssetsTabLabel,
2123
} from './labels'
24+
import { AccountAssetsCreated } from './account-assets-created'
25+
import { AccountAssetsOpted } from './account-assets-opted'
2226

2327
type Props = {
2428
account: Account
@@ -40,12 +44,17 @@ export function AccountActivityTabs({ account }: Props) {
4044
{
4145
id: accountHeldAssetsTabId,
4246
label: accountHeldAssetsTabLabel,
43-
children: <AccountAssetHeld address={account.address} />,
47+
children: <AccountAssetsHeld assetsHeld={account.assetsHeld} />,
4448
},
4549
{
4650
id: accountCreatedAssetsTabId,
4751
label: accountCreatedAssetsTabLabel,
48-
children: '',
52+
children: <AccountAssetsCreated assetsCreated={account.assetsCreated} />,
53+
},
54+
{
55+
id: accountOptedAssetsTabId,
56+
label: accountOptedAssetsTabLabel,
57+
children: <AccountAssetsOpted assetsOpted={account.assetsOpted} />,
4958
},
5059
{
5160
id: accountCreatedApplicationsTabId,
@@ -58,7 +67,7 @@ export function AccountActivityTabs({ account }: Props) {
5867
children: '',
5968
},
6069
],
61-
[account.address]
70+
[account.address, account.assetsCreated, account.assetsHeld, account.assetsOpted]
6271
)
6372
return (
6473
<Tabs defaultValue={accountLiveTransactionsTabId}>
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { ColumnDef } from '@tanstack/react-table'
2+
import { DisplayAssetAmount } from '@/features/common/components/display-asset-amount'
3+
import { AssetHolding } from '../models'
4+
import { AssetLink } from '@/features/assets/components/asset-link'
5+
6+
export const accountAssetHoldingsTableColumns: ColumnDef<AssetHolding>[] = [
7+
{
8+
header: 'ID',
9+
accessorFn: (item) => item.asset.id,
10+
cell: (c) => <AssetLink assetId={c.getValue<number>()} />,
11+
},
12+
{
13+
header: 'Name',
14+
accessorFn: (item) => item.asset.name,
15+
},
16+
{
17+
header: 'Amount',
18+
accessorFn: (item) => item,
19+
cell: (c) => {
20+
const assetHolding = c.getValue<AssetHolding>()
21+
return <DisplayAssetAmount amount={assetHolding.amount} asset={assetHolding.asset} isFrozen={assetHolding.isFrozen} />
22+
},
23+
},
24+
]
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { ColumnDef } from '@tanstack/react-table'
2+
import { AccountAssetSummary } from '../models'
3+
import { DataTable } from '@/features/common/components/data-table'
4+
import { AssetLink } from '@/features/assets/components/asset-link'
5+
6+
type Props = {
7+
assetsCreated: AccountAssetSummary[]
8+
}
9+
10+
const assetsCreatedTableColumns: ColumnDef<AccountAssetSummary>[] = [
11+
{
12+
header: 'ID',
13+
accessorFn: (item) => item.id,
14+
cell: (c) => <AssetLink assetId={c.getValue<number>()} />,
15+
},
16+
{
17+
header: 'Name',
18+
accessorFn: (item) => item.name,
19+
},
20+
{
21+
header: 'Unit',
22+
accessorFn: (item) => item.unitName,
23+
},
24+
]
25+
26+
export function AccountAssetsCreated({ assetsCreated }: Props) {
27+
return <DataTable columns={assetsCreatedTableColumns} data={assetsCreated} />
28+
}
Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
1-
import { Address } from '../data/types'
1+
import { AssetHolding } from '../models'
2+
import { DataTable } from '@/features/common/components/data-table'
3+
import { accountAssetHoldingsTableColumns } from './account-asset-holdings-table-columns'
24

35
type Props = {
4-
address: Address
6+
assetsHeld: AssetHolding[]
57
}
68

7-
export function AccountAssetHeld({ address }: Props) {
8-
return <>Assets Held for {address}</>
9+
export function AccountAssetsHeld({ assetsHeld }: Props) {
10+
return <DataTable columns={accountAssetHoldingsTableColumns} data={assetsHeld} />
911
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { AssetHolding } from '../models'
2+
import { DataTable } from '@/features/common/components/data-table'
3+
import { accountAssetHoldingsTableColumns } from './account-asset-holdings-table-columns'
4+
5+
type Props = {
6+
assetsOpted: AssetHolding[]
7+
}
8+
9+
export function AccountAssetsOpted({ assetsOpted }: Props) {
10+
return <DataTable columns={accountAssetHoldingsTableColumns} data={assetsOpted} />
11+
}

src/features/accounts/components/account-info.tsx

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@ import {
1919
} from './labels'
2020

2121
export function AccountInfo({ account }: { account: Account }) {
22+
const totalAssetsHeld = account.assetsHeld.length
23+
const totalAssetsCreated = account.assetsCreated.length
24+
const totalAssetsOptedIn = account.assetsHeld.length + account.assetsOpted.length
25+
2226
const accountInfoItems = useMemo(() => {
2327
const items = [
2428
{
@@ -35,15 +39,15 @@ export function AccountInfo({ account }: { account: Account }) {
3539
},
3640
{
3741
dt: accountAssetsHeldLabel,
38-
dd: account.totalAssetsHeld,
42+
dd: totalAssetsHeld,
3943
},
4044
{
4145
dt: accountAssetsCreatedLabel,
42-
dd: account.totalAssetsCreated,
46+
dd: totalAssetsCreated,
4347
},
4448
{
4549
dt: accountAssetsOptedInLabel,
46-
dd: account.totalAssetsOptedIn,
50+
dd: totalAssetsOptedIn,
4751
},
4852
{
4953
dt: accountApplicationsCreatedLabel,
@@ -67,12 +71,12 @@ export function AccountInfo({ account }: { account: Account }) {
6771
account.address,
6872
account.balance,
6973
account.minBalance,
70-
account.totalAssetsHeld,
71-
account.totalAssetsCreated,
72-
account.totalAssetsOptedIn,
7374
account.totalApplicationsCreated,
7475
account.totalApplicationsOptedIn,
7576
account.rekeyedTo,
77+
totalAssetsHeld,
78+
totalAssetsCreated,
79+
totalAssetsOptedIn,
7680
])
7781
return (
7882
<Card aria-label={accountInformationLabel} className={cn('p-4')}>

src/features/accounts/components/labels.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,15 @@ export const accountLiveTransactionsTabLabel = 'Live Transactions'
55
export const accountHistoricalTransactionsTabLabel = 'Historical Transactions'
66
export const accountHeldAssetsTabLabel = 'Held Assets'
77
export const accountCreatedAssetsTabLabel = 'Created Assets'
8+
export const accountOptedAssetsTabLabel = 'Opted Assets'
89
export const accountCreatedApplicationsTabLabel = 'Created Applications'
910
export const accountOptedApplicationsTabLabel = 'Opted Applications'
1011

1112
export const accountLiveTransactionsTabId = 'live-transactions'
1213
export const accountHistoricalTransactionsTabId = 'historical-transactions'
1314
export const accountHeldAssetsTabId = 'held-assets'
1415
export const accountCreatedAssetsTabId = 'created-assets'
16+
export const accountOptedAssetsTabId = 'opted-assets'
1517
export const accountCreatedApplicationsTabId = 'created-applications'
1618
export const accountOptedApplicationsTabId = 'opted-applications'
1719

src/features/accounts/data/account-result.ts

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,34 @@ import { atom } from 'jotai'
22
import { AccountResult, Address } from './types'
33
import { algod } from '@/features/common/data'
44
import { atomsInAtom } from '@/features/common/data/atoms-in-atom'
5+
import { assetResultsAtom } from '@/features/assets/data'
56

6-
const createAccountResultAtom = (address: Address) =>
7-
atom<Promise<AccountResult> | AccountResult>(async (_get) => {
8-
return await algod
9-
.accountInformation(address)
10-
.do()
11-
.then((result) => {
12-
return result as AccountResult
7+
const getAccountResult = (address: Address) =>
8+
algod
9+
.accountInformation(address)
10+
.do()
11+
.then((result) => {
12+
return result as AccountResult
13+
})
14+
15+
const syncAssociatedDataAndReturnAccountResultAtom = atom(null, async (get, set, address: Address) => {
16+
const accountResult = await getAccountResult(address)
17+
const assetResults = get(assetResultsAtom)
18+
19+
const assetsToAdd = (accountResult['created-assets'] ?? []).filter((a) => !assetResults.has(a.index))
20+
if (assetsToAdd.length > 0) {
21+
set(assetResultsAtom, (prev) => {
22+
const next = new Map(prev)
23+
assetsToAdd.forEach((asset) => {
24+
if (!next.has(asset.index)) {
25+
next.set(asset.index, atom(asset))
26+
}
1327
})
14-
})
28+
return next
29+
})
30+
}
31+
32+
return accountResult
33+
})
1534

16-
export const [accountResultsAtom, getAccountResultAtom] = atomsInAtom(createAccountResultAtom, (address) => address)
35+
export const [accountResultsAtom, getAccountResultAtom] = atomsInAtom(syncAssociatedDataAndReturnAccountResultAtom, (address) => address)

src/features/accounts/data/account.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,12 @@ import { JotaiStore } from '@/features/common/data/types'
55
import { useMemo } from 'react'
66
import { asAccount } from '../mappers'
77
import { getAccountResultAtom } from './account-result'
8+
import { createAssetResolver } from '@/features/assets/data'
89

910
const createAccountAtom = (store: JotaiStore, address: Address) => {
1011
return atom(async (get) => {
1112
const accountResult = await get(getAccountResultAtom(store, address))
12-
return asAccount(accountResult)
13+
return asAccount(accountResult, createAssetResolver(store, get))
1314
})
1415
}
1516

0 commit comments

Comments
 (0)