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

chore: show Nfd addresses #276

Draft
wants to merge 18 commits into
base: main
Choose a base branch
from
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
19 changes: 19 additions & 0 deletions src/features/accounts/components/account-info.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,20 @@ import {
accountBalanceLabel,
accountInformationLabel,
accountMinBalanceLabel,
accountNfdLabel,
accountRekeyedToLabel,
} from './labels'
import { OpenJsonViewDialogButton } from '@/features/common/components/json-view-dialog-button'
import { CopyButton } from '@/features/common/components/copy-button'
import { useLoadableNfdResult } from '@/features/nfd/data/nfd'
import { RenderLoadable } from '@/features/common/components/render-loadable'

type Props = {
account: Account
}

export function AccountInfo({ account }: Props) {
const [loadableNfd] = useLoadableNfdResult(account.address)
const accountInfoItems = useMemo(() => {
const items = [
{
Expand All @@ -36,6 +40,20 @@ export function AccountInfo({ account }: Props) {
</div>
),
},
...(loadableNfd.state === 'hasData' && loadableNfd.data !== null
? [
{
dt: accountNfdLabel,
dd: (
<div className="flex items-center">
<RenderLoadable loadable={loadableNfd} fallback={<></>}>
{(nfd) => <span className="truncate">{nfd?.name}</span>}
</RenderLoadable>
</div>
),
},
]
: []),
{
dt: accountBalanceLabel,
dd: <DisplayAlgo amount={account.balance} />,
Expand Down Expand Up @@ -84,6 +102,7 @@ export function AccountInfo({ account }: Props) {
account.totalApplicationsCreated,
account.totalApplicationsOptedIn,
account.rekeyedTo,
loadableNfd,
])
return (
<Card aria-label={accountInformationLabel}>
Expand Down
40 changes: 33 additions & 7 deletions src/features/accounts/components/account-link.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,43 @@
import { PropsWithChildren } from 'react'
import { useLoadableNfdResult } from '@/features/nfd/data/nfd'
import { RenderLoadable } from '@/features/common/components/render-loadable'
import { fixedForwardRef } from '@/utils/fixed-forward-ref'
import { CopyButton } from '@/features/common/components/copy-button'
import { cn } from '@/features/common/utils'
import { useSelectedNetwork } from '@/features/network/data'
import { TemplatedNavLink } from '@/features/routing/components/templated-nav-link/templated-nav-link'
import { Urls } from '@/routes/urls'
import { ellipseAddress } from '@/utils/ellipse-address'
import { fixedForwardRef } from '@/utils/fixed-forward-ref'
import { PropsWithChildren } from 'react'
import { useSelectedNetwork } from '@/features/network/data'
import { ellipseAddress, ellipseNfd } from '@/utils/ellipse-address'

type Props = PropsWithChildren<{
export type AccountLinkProps = PropsWithChildren<{
address: string
short?: boolean
className?: string
showCopyButton?: boolean
truncate?: boolean
}>

export const AccountLink = fixedForwardRef(
({ address, short, className, children, showCopyButton, ...rest }: Props, ref?: React.LegacyRef<HTMLAnchorElement>) => {
export const AccountLink = ({ address, ...rest }: AccountLinkProps) => {
const [loadableNfd] = useLoadableNfdResult(address)

return (
<>
<RenderLoadable loadable={loadableNfd} fallback={<AccountLinkInner address={address} {...rest} />}>
{(nfd) => <AccountLinkInner address={address} nfd={nfd?.name ?? undefined} {...rest} />}
</RenderLoadable>
</>
)
}

type AccountLinkInnerProps = AccountLinkProps & {
nfd?: string
}

const AccountLinkInner = fixedForwardRef(
(
{ address, nfd, short, className, children, showCopyButton, truncate, ...rest }: AccountLinkInnerProps,
ref?: React.LegacyRef<HTMLAnchorElement>
) => {
const [selectedNetwork] = useSelectedNetwork()

const link = (
Expand All @@ -28,6 +50,10 @@ export const AccountLink = fixedForwardRef(
>
{children ? (
children
) : nfd ? (
<abbr className="tracking-wide" title={address}>
{truncate ? ellipseNfd(nfd) : nfd}
</abbr>
) : short ? (
<abbr className="tracking-wide" title={address}>
{ellipseAddress(address)}
Expand Down
1 change: 1 addition & 0 deletions src/features/accounts/components/labels.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export const accountOptedApplicationsTabId = 'opted-applications'

export const accountInformationLabel = 'Account Information'
export const accountAddressLabel = 'Address'
export const accountNfdLabel = 'NFD'
export const accountBalanceLabel = 'Balance'
export const accountMinBalanceLabel = 'Min Balance'
export const accountAssetsHeldLabel = 'Held assets'
Expand Down
48 changes: 48 additions & 0 deletions src/features/accounts/pages/account-page.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,16 @@ import {
accountRekeyedToLabel,
accountAssetLabel,
accountApplicationLabel,
accountNfdLabel,
} from '../components/labels'
import { assetResultsAtom } from '@/features/assets/data'
import { assetResultMother } from '@/tests/object-mother/asset-result'
import { refreshButtonLabel } from '@/features/common/components/refresh-button'
import { algod } from '@/features/common/data/algo-client'
import { reverseNfdsAtom } from '@/features/nfd/data/nfd-result'
import { nfdResultMother } from '@/tests/object-mother/nfd-result'
import { atom } from 'jotai'
import { useLoadableNfdResult } from '@/features/nfd/data/nfd'

vi.mock('@/features/common/data/algo-client', async () => {
const original = await vi.importActual('@/features/common/data/algo-client')
Expand Down Expand Up @@ -84,6 +89,7 @@ describe('account-page', () => {
myStore.set(assetResultsAtom, assetResults)

vi.mocked(useParams).mockImplementation(() => ({ address: accountResult.address }))
vi.mocked(useLoadableNfdResult).mockReturnValue([{ state: 'loading' }])

return executeComponentTest(
() => render(<AccountPage />, undefined, myStore),
Expand Down Expand Up @@ -136,6 +142,7 @@ describe('account-page', () => {
myStore.set(accountResultsAtom, new Map([[accountResult.address, createReadOnlyAtomAndTimestamp(accountResult)]]))
myStore.set(assetResultsAtom, assetResults)

vi.mocked(useLoadableNfdResult).mockReturnValue([{ state: 'loading' }])
vi.mocked(useParams).mockImplementation(() => ({ address: accountResult.address }))

return executeComponentTest(
Expand Down Expand Up @@ -180,6 +187,7 @@ describe('account-page', () => {
const myStore = createStore()
myStore.set(accountResultsAtom, new Map([[accountResult.address, createReadOnlyAtomAndTimestamp(accountResult)]]))

vi.mocked(useLoadableNfdResult).mockReturnValue([{ state: 'loading' }])
vi.mocked(useParams).mockImplementation(() => ({ address: accountResult.address }))

return executeComponentTest(
Expand Down Expand Up @@ -231,6 +239,7 @@ describe('account-page', () => {
myStore.set(accountResultsAtom, new Map([[accountResult.address, createReadOnlyAtomAndTimestamp(accountResult)]]))
myStore.set(assetResultsAtom, assetResults)

vi.mocked(useLoadableNfdResult).mockReturnValue([{ state: 'loading' }])
vi.mocked(useParams).mockImplementation(() => ({ address: accountResult.address }))

return executeComponentTest(
Expand Down Expand Up @@ -271,6 +280,7 @@ describe('account-page', () => {
const myStore = createStore()
myStore.set(accountResultsAtom, new Map([[accountResult.address, createReadOnlyAtomAndTimestamp(accountResult)]]))

vi.mocked(useLoadableNfdResult).mockReturnValue([{ state: 'loading' }])
vi.mocked(useParams).mockImplementation(() => ({ address: accountResult.address }))

return executeComponentTest(
Expand Down Expand Up @@ -307,4 +317,42 @@ describe('account-page', () => {
)
})
})

describe('when rendering an account with Nfd', () => {
const accountResult = accountResultMother['mainnet-DHMCHBN4W5MBO72C3L3ZP6GGJHQ4OR6SW2EP3VDEJ5VHT4MERQLCTVW6PU']().build()
const nfdResult = nfdResultMother['mainnet-datamuseum.algo']().build()

it('should be rendered with the correct data', async () => {
const myStore = createStore()
const mockReverseNfdAtom = atom<string | Promise<string | null> | null>('datamuseum.algo')
myStore.set(accountResultsAtom, new Map([[accountResult.address, createReadOnlyAtomAndTimestamp(accountResult)]]))
myStore.set(reverseNfdsAtom, new Map([[nfdResult.depositAccount, [mockReverseNfdAtom, Date.now()] as const]]))

vi.mocked(useParams).mockImplementation(() => ({ address: accountResult.address }))
vi.mocked(useLoadableNfdResult).mockReturnValue([{ state: 'hasData', data: nfdResult }])

return executeComponentTest(
() => render(<AccountPage />, undefined, myStore),
async (component) => {
await waitFor(() => {
const informationCard = component.getByLabelText(accountInformationLabel)
descriptionListAssertion({
container: informationCard,
items: [
{ term: accountAddressLabel, description: 'DHMCHBN4W5MBO72C3L3ZP6GGJHQ4OR6SW2EP3VDEJ5VHT4MERQLCTVW6PU' },
{ term: accountNfdLabel, description: 'datamuseum.algo' },
{ term: accountBalanceLabel, description: '1915.70635' },
{ term: accountMinBalanceLabel, description: '0.1' },
{ term: accountAssetsHeldLabel, description: '0' },
{ term: accountAssetsCreatedLabel, description: '0' },
{ term: accountAssetsOptedInLabel, description: '0' },
{ term: accountApplicationsCreatedLabel, description: '0' },
{ term: accountApplicationsOptedInLabel, description: '0' },
],
})
})
}
)
})
})
})
14 changes: 7 additions & 7 deletions src/features/app-interfaces/data/read.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,13 @@ export const getAppInterfaces = async (dbConnection: DbConnection) => {
return await dbConnection.getAll('app-interfaces')
}

export const createAppInterfaceAtom = (applicationId: ApplicationId) => {
return atom(async (get) => {
const dbConnection = await get(dbConnectionAtom)
return await getAppInterface(dbConnection, applicationId)
})
}

export const useAppInterfaces = () => {
const appInterfacesAtom = useMemo(() => {
return atomWithRefresh(async (get) => {
Expand All @@ -22,10 +29,3 @@ export const useAppInterfaces = () => {
}, [])
return [useAtomValue(loadable(appInterfacesAtom)), useSetAtom(appInterfacesAtom)] as const
}

export const createAppInterfaceAtom = (applicationId: ApplicationId) => {
return atom(async (get) => {
const dbConnection = await get(dbConnectionAtom)
return await getAppInterface(dbConnection, applicationId)
})
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { sendButtonLabel } from '@/features/transaction-wizard/components/transa
import { algo } from '@algorandfoundation/algokit-utils'
import { transactionActionsLabel, transactionGroupTableLabel } from '@/features/transaction-wizard/components/labels'
import { selectOption } from '@/tests/utils/select-option'
import { useLoadableNfdResult } from '@/features/nfd/data/nfd'

const myStore = await vi.hoisted(async () => {
const { getDefaultStore } = await import('jotai/index')
Expand Down Expand Up @@ -51,6 +52,7 @@ describe('application-method-definitions', () => {
],
lastModified: createTimestamp(),
} satisfies AppInterfaceEntity)
vi.mocked(useLoadableNfdResult).mockReturnValue([{ state: 'loading' }])
})

describe('when a wallet is connected', () => {
Expand Down
5 changes: 5 additions & 0 deletions src/features/applications/pages/application-page.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import { writeAppInterface } from '@/features/app-interfaces/data'
import SampleSevenAppSpec from '@/tests/test-app-specs/sample-seven.arc32.json'
import { AppSpecStandard, Arc32AppSpec } from '@/features/app-interfaces/data/types'
import { searchTransactionsMock } from '@/tests/setup/mocks'
import { useLoadableNfdResult } from '@/features/nfd/data/nfd'

vi.mock('@/features/common/data/algo-client', async () => {
const original = await vi.importActual('@/features/common/data/algo-client')
Expand Down Expand Up @@ -115,6 +116,7 @@ describe('application-page', () => {
const applicationResult = applicationResultMother['mainnet-80441968']().build()

it('should be rendered with the correct data', () => {
vi.mocked(useLoadableNfdResult).mockReturnValue([{ state: 'loading' }])
const myStore = createStore()
myStore.set(genesisHashAtom, 'some-hash')

Expand Down Expand Up @@ -234,6 +236,7 @@ describe('application-page', () => {
const transactionResult = transactionResultMother['mainnet-XCXQW7J5G5QSPVU5JFYEELVIAAABPLZH2I36BMNVZLVHOA75MPAQ']().build()

it('should be rendered with the correct app name', () => {
vi.mocked(useLoadableNfdResult).mockReturnValue([{ state: 'loading' }])
const myStore = createStore()
myStore.set(genesisHashAtom, 'some-hash')

Expand Down Expand Up @@ -268,6 +271,7 @@ describe('application-page', () => {
const applicationResult = applicationResultMother['mainnet-80441968']().build()

it('should be rendered with the refresh button', () => {
vi.mocked(useLoadableNfdResult).mockReturnValue([{ state: 'loading' }])
const myStore = createStore()
myStore.set(genesisHashAtom, 'some-hash')

Expand Down Expand Up @@ -357,6 +361,7 @@ describe('application-page', () => {

it('should be rendered with the correct data', async () => {
vi.mocked(useParams).mockImplementation(() => ({ applicationId: applicationResult.id.toString() }))
vi.mocked(useLoadableNfdResult).mockReturnValue([{ state: 'loading' }])
vi.mocked(indexer.searchForTransactions().applicationID(applicationResult.id).limit(3).do).mockImplementation(() =>
Promise.resolve({ currentRound: 123, transactions: [], nextToken: '' })
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { transactionResultMother } from '@/tests/object-mother/transaction-resul
import { getAllByRole } from '@testing-library/dom'
import { ANY_NUMBER, ANY_STRING, searchTransactionsMock } from '@/tests/setup/mocks'
import { RenderResult } from '@testing-library/react'
import { useLoadableNfdResult } from '@/features/nfd/data/nfd'

vi.mock('@/features/common/data/algo-client', async () => {
const original = await vi.importActual('@/features/common/data/algo-client')
Expand All @@ -26,6 +27,8 @@ describe('asset-transaction-history', () => {
const asset = assetResultMother['testnet-642327435']().build()

it('should be able to handle pagination', () => {
vi.mocked(useLoadableNfdResult).mockReturnValue([{ state: 'loading' }])

const myStore = createStore()
myStore.set(assetResultsAtom, new Map([[asset.index, createReadOnlyAtomAndTimestamp(asset)]]))

Expand Down
Loading
Loading