From 89069fc876ad8988f3928eda20d66122e1e48c37 Mon Sep 17 00:00:00 2001 From: Negar Date: Thu, 16 May 2024 18:08:38 +1000 Subject: [PATCH] feat: Add account info (#43) * feat: add account info UI --------- Co-authored-by: Neil Campbell --- .../components/account-activity-tabs.tsx | 66 ++++++++++ .../accounts/components/account-details.tsx | 36 ++++++ .../accounts/components/account-info.tsx | 83 ++++++++++++ src/features/accounts/data/account-result.ts | 16 +++ src/features/accounts/data/account.ts | 26 ++++ src/features/accounts/data/index.ts | 2 + src/features/accounts/data/types.ts | 43 +++++++ src/features/accounts/mappers/index.ts | 19 +++ src/features/accounts/models/index.ts | 15 +++ .../accounts/pages/account-page.test.tsx | 107 ++++++++++++++++ src/features/accounts/pages/account-page.tsx | 21 ++- src/features/assets/data/asset-metadata.ts | 2 +- src/features/common/data/types.ts | 2 + src/features/transactions/models/index.ts | 3 +- src/tests/builders/account-result-builder.ts | 34 +++++ src/tests/object-mother/account-result.ts | 120 ++++++++++++++++++ src/tests/setup/mocks.ts | 3 + 17 files changed, 594 insertions(+), 4 deletions(-) create mode 100644 src/features/accounts/components/account-activity-tabs.tsx create mode 100644 src/features/accounts/components/account-details.tsx create mode 100644 src/features/accounts/components/account-info.tsx create mode 100644 src/features/accounts/data/account-result.ts create mode 100644 src/features/accounts/data/account.ts create mode 100644 src/features/accounts/data/index.ts create mode 100644 src/features/accounts/data/types.ts create mode 100644 src/features/accounts/mappers/index.ts create mode 100644 src/features/accounts/models/index.ts create mode 100644 src/features/accounts/pages/account-page.test.tsx create mode 100644 src/tests/builders/account-result-builder.ts create mode 100644 src/tests/object-mother/account-result.ts diff --git a/src/features/accounts/components/account-activity-tabs.tsx b/src/features/accounts/components/account-activity-tabs.tsx new file mode 100644 index 000000000..0b758160e --- /dev/null +++ b/src/features/accounts/components/account-activity-tabs.tsx @@ -0,0 +1,66 @@ +import { OverflowAutoTabsContent, Tabs, TabsList, TabsTrigger } from '@/features/common/components/tabs' +import { cn } from '@/features/common/utils' +import { useMemo } from 'react' + +const accountVisualTransactionTabId = 'visual' +const accountVisualAssetsTabId = 'table' +const accountVisualCreatedAssetsTabId = 'created-assets' +const accountVisualCreatedApplicationsTabId = 'created-applications' +const accountVisualOptedApplicationsTabId = 'opted-applications' +export const accountDetailsLabel = 'View account Details' +export const accountVisualGraphTabLabel = 'Transactions' +export const accountVisualAssetsTabLabel = 'Assets' +export const accountVisualCreatedAssetsTabLabel = 'Created Assets' +export const accountVisualCreatedApplicationsTabLabel = 'Created Applications' +export const accountVisualOptedApplicationsTabLabel = 'Opted Applications' + +export function AccountActivityTabs() { + const tabs = useMemo( + () => [ + { + id: accountVisualTransactionTabId, + label: accountDetailsLabel, + children: '', + }, + { + id: accountVisualAssetsTabId, + label: accountVisualAssetsTabLabel, + children: '', + }, + { + id: accountVisualCreatedAssetsTabId, + label: accountVisualCreatedAssetsTabLabel, + children: '', + }, + { + id: accountVisualCreatedApplicationsTabId, + label: accountVisualCreatedApplicationsTabLabel, + children: '', + }, + { + id: accountVisualOptedApplicationsTabId, + label: accountVisualOptedApplicationsTabLabel, + children: '', + }, + ], + [] + ) + return ( + + + {tabs.map((tab) => ( + + {tab.label} + + ))} + + {tabs.map((tab) => ( + +
+
{tab.children}
+
+
+ ))} +
+ ) +} diff --git a/src/features/accounts/components/account-details.tsx b/src/features/accounts/components/account-details.tsx new file mode 100644 index 000000000..a547a4aa1 --- /dev/null +++ b/src/features/accounts/components/account-details.tsx @@ -0,0 +1,36 @@ +import { Card, CardContent } from '@/features/common/components/card' +import { Account } from '../models' +import { cn } from '@/features/common/utils' +import { AccountActivityTabs } from './account-activity-tabs' +import { AccountInfo } from './account-info' + +type Props = { + account: Account +} + +export const activityLabel = 'Activity' +export const accountJsonLabel = 'Acount JSON' + +export function AccountDetails({ account }: Props) { + return ( +
+ + + +

{activityLabel}

+
+ +
+
+
+ + +

{accountJsonLabel}

+
+
{account.json}
+
+
+
+
+ ) +} diff --git a/src/features/accounts/components/account-info.tsx b/src/features/accounts/components/account-info.tsx new file mode 100644 index 000000000..0efbc996b --- /dev/null +++ b/src/features/accounts/components/account-info.tsx @@ -0,0 +1,83 @@ +import { useMemo } from 'react' +import { Account } from '../models' +import { Card, CardContent } from '@/features/common/components/card' +import { DescriptionList } from '@/features/common/components/description-list' +import { cn } from '@/features/common/utils' +import { DisplayAlgo } from '@/features/common/components/display-algo' +import { AccountLink } from './account-link' + +export const accountInformationLabel = 'Account Information' +export const accountAddressLabel = 'Address' +export const accountBalanceLabel = 'Balance' +export const accountMinBalanceLabel = 'Min Balance' +export const accountAssetsHeldLabel = 'Holding assets' +export const accountAssetsCreatedLabel = 'Created assets' +export const accountAssetsOptedInLabel = 'Opted assets' +export const accountApplicationsCreatedLabel = 'Created applications' +export const accountApplicationsOptedInLabel = 'Opted applications' +export const accountRekeyedToLabel = 'Rekeyed to' + +export function AccountInfo({ account }: { account: Account }) { + const accountInfoItems = useMemo(() => { + const items = [ + { + dt: accountAddressLabel, + dd: account.address, + }, + { + dt: accountBalanceLabel, + dd: , + }, + { + dt: accountMinBalanceLabel, + dd: , + }, + { + dt: accountAssetsHeldLabel, + dd: account.totalAssetsHeld, + }, + { + dt: accountAssetsCreatedLabel, + dd: account.totalAssetsCreated, + }, + { + dt: accountAssetsOptedInLabel, + dd: account.totalAssetsOptedIn, + }, + { + dt: accountApplicationsCreatedLabel, + dd: account.totalApplicationsCreated ? account.totalApplicationsCreated : 0, + }, + { + dt: accountApplicationsOptedInLabel, + dd: account.totalApplicationsOptedIn ? account.totalApplicationsOptedIn : 0, + }, + ...(account.rekeyedTo + ? [ + { + dt: accountRekeyedToLabel, + dd: , + }, + ] + : []), + ] + return items + }, [ + account.address, + account.balance, + account.minBalance, + account.totalAssetsHeld, + account.totalAssetsCreated, + account.totalAssetsOptedIn, + account.totalApplicationsCreated, + account.totalApplicationsOptedIn, + account.rekeyedTo, + ]) + return ( + + + + + + ) +} diff --git a/src/features/accounts/data/account-result.ts b/src/features/accounts/data/account-result.ts new file mode 100644 index 000000000..4647b90b0 --- /dev/null +++ b/src/features/accounts/data/account-result.ts @@ -0,0 +1,16 @@ +import { atom } from 'jotai' +import { AccountResult, Address } from './types' +import { algod } from '@/features/common/data' +import { atomsInAtom } from '@/features/common/data/atoms-in-atom' + +const createAccountResultAtom = (address: Address) => + atom | AccountResult>(async (_get) => { + return await algod + .accountInformation(address) + .do() + .then((result) => { + return result as AccountResult + }) + }) + +export const [accountResultsAtom, getAccountResultAtom] = atomsInAtom(createAccountResultAtom, (address) => address) diff --git a/src/features/accounts/data/account.ts b/src/features/accounts/data/account.ts new file mode 100644 index 000000000..8deb7076e --- /dev/null +++ b/src/features/accounts/data/account.ts @@ -0,0 +1,26 @@ +import { atom, useAtomValue, useStore } from 'jotai' +import { Address } from './types' +import { loadable } from 'jotai/utils' +import { JotaiStore } from '@/features/common/data/types' +import { useMemo } from 'react' +import { asAccount } from '../mappers' +import { getAccountResultAtom } from './account-result' + +const createAccountAtom = (store: JotaiStore, address: Address) => { + return atom(async (get) => { + const accountResult = await get(getAccountResultAtom(store, address)) + return asAccount(accountResult) + }) +} + +const useAccountAtom = (address: Address) => { + const store = useStore() + + return useMemo(() => { + return createAccountAtom(store, address) + }, [store, address]) +} + +export const useLoadableAccountAtom = (address: Address) => { + return useAtomValue(loadable(useAccountAtom(address))) +} diff --git a/src/features/accounts/data/index.ts b/src/features/accounts/data/index.ts new file mode 100644 index 000000000..3b539e463 --- /dev/null +++ b/src/features/accounts/data/index.ts @@ -0,0 +1,2 @@ +export * from './account' +export * from './account-result' diff --git a/src/features/accounts/data/types.ts b/src/features/accounts/data/types.ts new file mode 100644 index 000000000..abfe55d46 --- /dev/null +++ b/src/features/accounts/data/types.ts @@ -0,0 +1,43 @@ +import { NoStringIndex } from '@/features/common/data/types' +import { + ApplicationResult as IndexerApplicationResult, + AssetHolding as IndexerAssetHolding, + AssetResult as IndexerAssetResult, + AppLocalState as IndexerAppLocalState, + AccountResult as IndexerAccountResult, + SignatureType, +} from '@algorandfoundation/algokit-utils/types/indexer' + +export type Address = string + +export type AppLocalState = Omit +export type AssetHolding = Omit +export type ApplicationResult = Omit +export type AssetResult = { + index: number + params: IndexerAssetResult['params'] +} + +export type AccountResult = Omit< + NoStringIndex, + | 'closed-at-round' + | 'created-at-round' + | 'deleted' + | 'apps-local-state' + | 'assets' + | 'created-apps' + | 'created-assets' + | 'min-balance' + | 'total-box-bytes' + | 'total-boxes' + | 'sig-type' +> & { + 'apps-local-state'?: AppLocalState[] + assets?: AssetHolding[] + 'created-apps'?: ApplicationResult[] + 'created-assets'?: AssetResult[] + 'min-balance': number + 'total-box-bytes'?: number + 'total-boxes'?: number + 'sig-type'?: SignatureType +} diff --git a/src/features/accounts/mappers/index.ts b/src/features/accounts/mappers/index.ts new file mode 100644 index 000000000..b3ef3f2c8 --- /dev/null +++ b/src/features/accounts/mappers/index.ts @@ -0,0 +1,19 @@ +import { AccountResult } from '../data/types' +import { Account } from '../models' +import { asJson } from '@/utils/as-json' +import { microAlgos } from '@algorandfoundation/algokit-utils' + +export const asAccount = (accountResult: AccountResult): Account => { + return { + address: accountResult.address, + balance: microAlgos(accountResult.amount), + minBalance: microAlgos(accountResult['min-balance']), + totalAssetsCreated: accountResult['total-created-assets'], + totalAssetsOptedIn: accountResult['total-assets-opted-in'], + totalAssetsHeld: (accountResult.assets ?? []).length, + totalApplicationsCreated: accountResult['total-created-apps'], + totalApplicationsOptedIn: accountResult['total-apps-opted-in'], + rekeyedTo: accountResult['auth-addr'], + json: asJson(accountResult), + } +} diff --git a/src/features/accounts/models/index.ts b/src/features/accounts/models/index.ts new file mode 100644 index 000000000..f9cbaa9ca --- /dev/null +++ b/src/features/accounts/models/index.ts @@ -0,0 +1,15 @@ +import { AlgoAmount } from '@algorandfoundation/algokit-utils/types/amount' +import { Address } from '../data/types' + +export type Account = { + address: Address + balance: AlgoAmount + minBalance: AlgoAmount + totalAssetsCreated: number + totalAssetsOptedIn: number + totalAssetsHeld: number + totalApplicationsCreated: number + totalApplicationsOptedIn: number + rekeyedTo?: Address + json: string +} diff --git a/src/features/accounts/pages/account-page.test.tsx b/src/features/accounts/pages/account-page.test.tsx new file mode 100644 index 000000000..940df0ce1 --- /dev/null +++ b/src/features/accounts/pages/account-page.test.tsx @@ -0,0 +1,107 @@ +import { executeComponentTest } from '@/tests/test-component' +import { render, waitFor } from '@/tests/testing-library' +import { useParams } from 'react-router-dom' +import { describe, expect, it, vi } from 'vitest' +import { AccountPage, accountFailedToLoadMessage } from './account-page' +import { algod } from '@/features/common/data' +import { accountResultMother } from '@/tests/object-mother/account-result' +import { atom, createStore } from 'jotai' +import { + accountAddressLabel, + accountBalanceLabel, + accountApplicationsCreatedLabel, + accountAssetsCreatedLabel, + accountAssetsHeldLabel, + accountInformationLabel, + accountMinBalanceLabel, + accountApplicationsOptedInLabel, + accountAssetsOptedInLabel, +} from '../components/account-info' +import { descriptionListAssertion } from '@/tests/assertions/description-list-assertion' +import { accountResultsAtom } from '../data' +import { accountJsonLabel } from '../components/account-details' + +describe('account-page', () => { + describe('when rendering an account using a invalid address', () => { + it('should render an error message', () => { + vi.mocked(useParams).mockReturnValue({ address: 'invalid-address' }) + + return executeComponentTest( + () => render(), + async (component) => { + await waitFor(() => expect(component.getByText('Address is invalid')).toBeTruthy()) + } + ) + }) + }) + + describe('when rendering an account that failed to load', () => { + it('should render an error message', () => { + vi.mocked(useParams).mockReturnValue({ address: '7AHHR4ZMHKMRFUVGLU3SWGKMJBKRUA5UQQUPFWT4WMFO2RLXBUIXZR7FQQ' }) + vi.mocked(algod.accountInformation('7AHHR4ZMHKMRFUVGLU3SWGKMJBKRUA5UQQUPFWT4WMFO2RLXBUIXZR7FQQ').do).mockImplementation(() => + Promise.reject({}) + ) + + return executeComponentTest( + () => render(), + async (component) => { + await waitFor(() => expect(component.getByText(accountFailedToLoadMessage)).toBeTruthy()) + } + ) + }) + }) + + describe('when rendering an account', () => { + const accountResult = accountResultMother['mainnet-BIQXAK67KSCKN3EJXT4S3RVXUBFOLZ45IQOBTSOQWOSR4LLULBTD54S5IA']().build() + + it('should be rendered with the correct data', () => { + const myStore = createStore() + myStore.set(accountResultsAtom, new Map([[accountResult.address, atom(accountResult)]])) + + vi.mocked(useParams).mockImplementation(() => ({ address: accountResult.address })) + + return executeComponentTest( + () => render(, undefined, myStore), + async (component) => { + await waitFor(() => { + const informationCard = component.getByLabelText(accountInformationLabel) + descriptionListAssertion({ + container: informationCard, + items: [ + { term: accountAddressLabel, description: 'BIQXAK67KSCKN3EJXT4S3RVXUBFOLZ45IQOBTSOQWOSR4LLULBTD54S5IA' }, + { term: accountBalanceLabel, description: '5.883741' }, + { term: accountMinBalanceLabel, description: '0.7' }, + { term: accountAssetsHeldLabel, description: '3' }, + { term: accountAssetsCreatedLabel, description: '0' }, + { term: accountAssetsOptedInLabel, description: '3' }, + { term: accountApplicationsCreatedLabel, description: '0' }, + { term: accountApplicationsOptedInLabel, description: '2' }, + ], + }) + }) + } + ) + }) + }) + + describe('when rendering an account', () => { + const accountResult = accountResultMother['mainnet-JY2FRXQP7Q6SYH7QE2HF2XWNE644V6KUH3PYC4SYWPUSEATTDJSNUHMHR4']().build() + + it('should be rendered with the correct json data', () => { + const myStore = createStore() + myStore.set(accountResultsAtom, new Map([[accountResult.address, atom(accountResult)]])) + + vi.mocked(useParams).mockImplementation(() => ({ address: accountResult.address })) + + return executeComponentTest( + () => render(, undefined, myStore), + async (component) => { + await waitFor(() => { + const jsonCard = component.getByLabelText(accountJsonLabel) + jsonCard.textContent = JSON.stringify(accountResult) + }) + } + ) + }) + }) +}) diff --git a/src/features/accounts/pages/account-page.tsx b/src/features/accounts/pages/account-page.tsx index 38906d3bc..4d311c873 100644 --- a/src/features/accounts/pages/account-page.tsx +++ b/src/features/accounts/pages/account-page.tsx @@ -3,18 +3,37 @@ import { UrlParams } from '../../../routes/urls' import { useRequiredParam } from '../../common/hooks/use-required-param' import { cn } from '@/features/common/utils' import { isAddress } from '@/utils/is-address' +import { is404 } from '@/utils/error' +import { RenderLoadable } from '@/features/common/components/render-loadable' +import { Account } from '../models' +import { useLoadableAccountAtom } from '../data' +import { AccountDetails } from '../components/account-details' export const accountPageTitle = 'Account' export const accountInvalidAddressMessage = 'Address is invalid' +export const accountFailedToLoadMessage = 'Account failed to load' + +const transformError = (e: Error) => { + if (is404(e)) { + return new Error(accountInvalidAddressMessage) + } + + // eslint-disable-next-line no-console + console.error(e) + return new Error(accountFailedToLoadMessage) +} export function AccountPage() { const { address } = useRequiredParam(UrlParams.Address) invariant(isAddress(address), accountInvalidAddressMessage) + const loadableAccount = useLoadableAccountAtom(address) return (

{accountPageTitle}

- {address} + + {(account: Account) => } +
) } diff --git a/src/features/assets/data/asset-metadata.ts b/src/features/assets/data/asset-metadata.ts index 4f3af4187..f858a9139 100644 --- a/src/features/assets/data/asset-metadata.ts +++ b/src/features/assets/data/asset-metadata.ts @@ -70,7 +70,7 @@ const noteToArc69Metadata = (note: string | undefined) => { } export const createAssetMetadataResultAtom = (assetResult: AssetResult) => - atom(async (_get) => { + atom | AssetMetadataResult>(async (_get) => { if (assetResult.index === 0) { return null } diff --git a/src/features/common/data/types.ts b/src/features/common/data/types.ts index 62aef6bd8..37695ae1c 100644 --- a/src/features/common/data/types.ts +++ b/src/features/common/data/types.ts @@ -1,3 +1,5 @@ import { useStore } from 'jotai' export type JotaiStore = ReturnType + +export type NoStringIndex = { [K in keyof T as string extends K ? never : K]: T[K] } diff --git a/src/features/transactions/models/index.ts b/src/features/transactions/models/index.ts index feecdb496..d954ca4fb 100644 --- a/src/features/transactions/models/index.ts +++ b/src/features/transactions/models/index.ts @@ -1,8 +1,7 @@ +import { Address } from '@/features/accounts/data/types' import { AssetSummary } from '@/features/assets/models' import { AlgoAmount } from '@algorandfoundation/algokit-utils/types/amount' -type Address = string - export type CommonTransactionProperties = { type: TransactionType confirmedRound: number diff --git a/src/tests/builders/account-result-builder.ts b/src/tests/builders/account-result-builder.ts new file mode 100644 index 000000000..01b8ea6e8 --- /dev/null +++ b/src/tests/builders/account-result-builder.ts @@ -0,0 +1,34 @@ +import { AccountResult } from '@/features/accounts/data/types' +import { AccountStatus } from '@algorandfoundation/algokit-utils/types/indexer' +import { DataBuilder, dossierProxy, randomNumber, randomString } from '@makerx/ts-dossier' + +export class AccountResultBuilder extends DataBuilder { + constructor(initialState?: AccountResult) { + super( + initialState + ? initialState + : { + address: randomString(52, 52), + amount: randomNumber(), + 'amount-without-pending-rewards': randomNumber(), + 'apps-local-state': [], + 'apps-total-schema': { 'num-byte-slice': 0, 'num-uint': 0 }, + assets: [], + 'created-apps': [], + 'created-assets': [], + 'min-balance': randomNumber(), + 'pending-rewards': randomNumber(), + 'reward-base': randomNumber(), + rewards: randomNumber(), + round: 38851889, + status: AccountStatus.Online, + 'total-apps-opted-in': randomNumber(), + 'total-assets-opted-in': randomNumber(), + 'total-created-apps': randomNumber(), + 'total-created-assets': randomNumber(), + } + ) + } +} + +export const accountResultBuilder = dossierProxy(AccountResultBuilder) diff --git a/src/tests/object-mother/account-result.ts b/src/tests/object-mother/account-result.ts new file mode 100644 index 000000000..4e92bec4d --- /dev/null +++ b/src/tests/object-mother/account-result.ts @@ -0,0 +1,120 @@ +import { AccountResult } from '@/features/accounts/data/types' +import { AccountResultBuilder } from '../builders/account-result-builder' +import { AccountStatus } from '@algorandfoundation/algokit-utils/types/indexer' + +export const accountResultMother = { + ['mainnet-BIQXAK67KSCKN3EJXT4S3RVXUBFOLZ45IQOBTSOQWOSR4LLULBTD54S5IA']: () => { + return new AccountResultBuilder({ + address: 'BIQXAK67KSCKN3EJXT4S3RVXUBFOLZ45IQOBTSOQWOSR4LLULBTD54S5IA', + amount: 5883741, + 'amount-without-pending-rewards': 5883741, + 'apps-local-state': [ + { + id: 1209868169, + schema: { 'num-byte-slice': 1, 'num-uint': 0 }, + }, + { + id: 1210178396, + schema: { 'num-byte-slice': 1, 'num-uint': 0 }, + }, + ], + 'apps-total-schema': { 'num-byte-slice': 2, 'num-uint': 0 }, + assets: [ + { amount: 2002560000, 'asset-id': 924268058, 'is-frozen': false }, + { amount: 0, 'asset-id': 1010208883, 'is-frozen': false }, + { amount: 0, 'asset-id': 1096015467, 'is-frozen': false }, + ], + 'created-apps': [], + 'created-assets': [], + 'min-balance': 700000, + 'pending-rewards': 0, + 'reward-base': 218288, + rewards: 0, + round: 38880589, + status: AccountStatus.Offline, + 'total-apps-opted-in': 2, + 'total-assets-opted-in': 3, + 'total-created-apps': 0, + 'total-created-assets': 0, + } satisfies AccountResult) + }, + + ['mainnet-JY2FRXQP7Q6SYH7QE2HF2XWNE644V6KUH3PYC4SYWPUSEATTDJSNUHMHR4']: () => { + return new AccountResultBuilder({ + address: 'JY2FRXQP7Q6SYH7QE2HF2XWNE644V6KUH3PYC4SYWPUSEATTDJSNUHMHR4', + amount: 12016438084, + 'amount-without-pending-rewards': 12016438084, + 'apps-local-state': [], + 'apps-total-schema': { 'num-byte-slice': 0, 'num-uint': 0 }, + assets: [ + { amount: 0, 'asset-id': 2254146, 'is-frozen': false }, + { amount: 0, 'asset-id': 2254149, 'is-frozen': false }, + { amount: 0, 'asset-id': 2254150, 'is-frozen': false }, + { amount: 0, 'asset-id': 127745593, 'is-frozen': false }, + { amount: 0, 'asset-id': 127746157, 'is-frozen': false }, + { amount: 0, 'asset-id': 127746786, 'is-frozen': false }, + { amount: 1000000000000000000, 'asset-id': 1205372113, 'is-frozen': false }, + { amount: 1000000000000000000, 'asset-id': 1205372555, 'is-frozen': false }, + { amount: 1000000000000000000, 'asset-id': 1205372814, 'is-frozen': false }, + ], + 'created-apps': [], + 'created-assets': [ + { + index: 1205372113, + params: { + clawback: 'JY2FRXQP7Q6SYH7QE2HF2XWNE644V6KUH3PYC4SYWPUSEATTDJSNUHMHR4', + creator: 'JY2FRXQP7Q6SYH7QE2HF2XWNE644V6KUH3PYC4SYWPUSEATTDJSNUHMHR4', + decimals: 0, + 'default-frozen': false, + freeze: 'JY2FRXQP7Q6SYH7QE2HF2XWNE644V6KUH3PYC4SYWPUSEATTDJSNUHMHR4', + manager: 'JY2FRXQP7Q6SYH7QE2HF2XWNE644V6KUH3PYC4SYWPUSEATTDJSNUHMHR4', + name: 'World Chess Blitz Ranking', + reserve: 'JY2FRXQP7Q6SYH7QE2HF2XWNE644V6KUH3PYC4SYWPUSEATTDJSNUHMHR4', + total: 1000000000000000000, + 'unit-name': 'WCBR', + }, + }, + { + index: 1205372555, + params: { + clawback: 'JY2FRXQP7Q6SYH7QE2HF2XWNE644V6KUH3PYC4SYWPUSEATTDJSNUHMHR4', + creator: 'JY2FRXQP7Q6SYH7QE2HF2XWNE644V6KUH3PYC4SYWPUSEATTDJSNUHMHR4', + decimals: 0, + 'default-frozen': false, + freeze: 'JY2FRXQP7Q6SYH7QE2HF2XWNE644V6KUH3PYC4SYWPUSEATTDJSNUHMHR4', + manager: 'JY2FRXQP7Q6SYH7QE2HF2XWNE644V6KUH3PYC4SYWPUSEATTDJSNUHMHR4', + name: 'World Chess Rapid Ranking', + reserve: 'JY2FRXQP7Q6SYH7QE2HF2XWNE644V6KUH3PYC4SYWPUSEATTDJSNUHMHR4', + total: 1000000000000000000, + 'unit-name': 'WCRR', + }, + }, + { + index: 1205372814, + params: { + clawback: 'JY2FRXQP7Q6SYH7QE2HF2XWNE644V6KUH3PYC4SYWPUSEATTDJSNUHMHR4', + creator: 'JY2FRXQP7Q6SYH7QE2HF2XWNE644V6KUH3PYC4SYWPUSEATTDJSNUHMHR4', + decimals: 0, + 'default-frozen': false, + freeze: 'JY2FRXQP7Q6SYH7QE2HF2XWNE644V6KUH3PYC4SYWPUSEATTDJSNUHMHR4', + manager: 'JY2FRXQP7Q6SYH7QE2HF2XWNE644V6KUH3PYC4SYWPUSEATTDJSNUHMHR4', + name: 'World Chess Bullet Ranking', + reserve: 'JY2FRXQP7Q6SYH7QE2HF2XWNE644V6KUH3PYC4SYWPUSEATTDJSNUHMHR4', + total: 1000000000000000000, + 'unit-name': 'WCBUR', + }, + }, + ], + 'min-balance': 1000000, + 'pending-rewards': 0, + 'reward-base': 218288, + rewards: 0, + round: 38880776, + status: AccountStatus.Offline, + 'total-apps-opted-in': 0, + 'total-assets-opted-in': 9, + 'total-created-apps': 0, + 'total-created-assets': 3, + } satisfies AccountResult) + }, +} diff --git a/src/tests/setup/mocks.ts b/src/tests/setup/mocks.ts index 8b5a79cdc..dd4b82057 100644 --- a/src/tests/setup/mocks.ts +++ b/src/tests/setup/mocks.ts @@ -26,6 +26,9 @@ vi.mock('@/features/common/data', async () => { getAssetByID: vi.fn().mockReturnValue({ do: vi.fn().mockReturnValue({ then: vi.fn() }), }), + accountInformation: vi.fn().mockReturnValue({ + do: vi.fn().mockReturnValue({ then: vi.fn() }), + }), }, indexer: { ...(original.indexer as algosdk.Indexer),