diff --git a/src/features/accounts/components/account-info.tsx b/src/features/accounts/components/account-info.tsx index 46f0f597..af5b3211 100644 --- a/src/features/accounts/components/account-info.tsx +++ b/src/features/accounts/components/account-info.tsx @@ -20,7 +20,7 @@ import { } 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 { useLoadableNfd } from '@/features/nfd/data/nfd' import { RenderLoadable } from '@/features/common/components/render-loadable' type Props = { @@ -28,7 +28,7 @@ type Props = { } export function AccountInfo({ account }: Props) { - const [loadableNfd] = useLoadableNfdResult(account.address) + const [loadableNfd] = useLoadableNfd(account.address) const accountInfoItems = useMemo(() => { const items = [ { diff --git a/src/features/accounts/components/account-link.tsx b/src/features/accounts/components/account-link.tsx index 6a637b0d..8d1efaf4 100644 --- a/src/features/accounts/components/account-link.tsx +++ b/src/features/accounts/components/account-link.tsx @@ -1,5 +1,5 @@ import { PropsWithChildren } from 'react' -import { useLoadableNfdResult } from '@/features/nfd/data/nfd' +import { useLoadableNfd } 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' @@ -18,7 +18,7 @@ export type AccountLinkProps = PropsWithChildren<{ }> export const AccountLink = ({ address, ...rest }: AccountLinkProps) => { - const [loadableNfd] = useLoadableNfdResult(address) + const [loadableNfd] = useLoadableNfd(address) return ( <> diff --git a/src/features/accounts/pages/account-page.test.tsx b/src/features/accounts/pages/account-page.test.tsx index d2b173f8..c5689fc5 100644 --- a/src/features/accounts/pages/account-page.test.tsx +++ b/src/features/accounts/pages/account-page.test.tsx @@ -31,7 +31,7 @@ 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' +import { useLoadableNfd } from '@/features/nfd/data/nfd' vi.mock('@/features/common/data/algo-client', async () => { const original = await vi.importActual('@/features/common/data/algo-client') @@ -89,7 +89,7 @@ describe('account-page', () => { myStore.set(assetResultsAtom, assetResults) vi.mocked(useParams).mockImplementation(() => ({ address: accountResult.address })) - vi.mocked(useLoadableNfdResult).mockReturnValue([{ state: 'loading' }]) + vi.mocked(useLoadableNfd).mockReturnValue([{ state: 'loading' }]) return executeComponentTest( () => render(, undefined, myStore), @@ -142,7 +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(useLoadableNfd).mockReturnValue([{ state: 'loading' }]) vi.mocked(useParams).mockImplementation(() => ({ address: accountResult.address })) return executeComponentTest( @@ -187,7 +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(useLoadableNfd).mockReturnValue([{ state: 'loading' }]) vi.mocked(useParams).mockImplementation(() => ({ address: accountResult.address })) return executeComponentTest( @@ -239,7 +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(useLoadableNfd).mockReturnValue([{ state: 'loading' }]) vi.mocked(useParams).mockImplementation(() => ({ address: accountResult.address })) return executeComponentTest( @@ -280,7 +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(useLoadableNfd).mockReturnValue([{ state: 'loading' }]) vi.mocked(useParams).mockImplementation(() => ({ address: accountResult.address })) return executeComponentTest( @@ -329,7 +329,7 @@ describe('account-page', () => { 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 }]) + vi.mocked(useLoadableNfd).mockReturnValue([{ state: 'hasData', data: nfdResult }]) return executeComponentTest( () => render(, undefined, myStore), diff --git a/src/features/applications/components/application-method-definitions.test.tsx b/src/features/applications/components/application-method-definitions.test.tsx index 5ad0d8e5..f6761f94 100644 --- a/src/features/applications/components/application-method-definitions.test.tsx +++ b/src/features/applications/components/application-method-definitions.test.tsx @@ -18,7 +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' +import { useLoadableNfd, useLoadableNfdResult } from '@/features/nfd/data/nfd' const myStore = await vi.hoisted(async () => { const { getDefaultStore } = await import('jotai/index') @@ -52,7 +52,7 @@ describe('application-method-definitions', () => { ], lastModified: createTimestamp(), } satisfies AppInterfaceEntity) - vi.mocked(useLoadableNfdResult).mockReturnValue([{ state: 'loading' }]) + vi.mocked(useLoadableNfd).mockReturnValue([{ state: 'loading' }]) }) describe('when a wallet is connected', () => { @@ -63,6 +63,7 @@ describe('application-method-definitions', () => { describe('when calling calculator add method', () => { it('reports validation errors when required fields have not been supplied', () => { vi.mocked(useParams).mockImplementation(() => ({ applicationId: appId.toString() })) + vi.mocked(useLoadableNfdResult).mockReturnValue([{ state: 'loading' }]) return executeComponentTest( () => { @@ -95,6 +96,7 @@ describe('application-method-definitions', () => { it('succeeds when all fields have been correctly supplied', () => { const { testAccount } = localnet.context vi.mocked(useParams).mockImplementation(() => ({ applicationId: appId.toString() })) + vi.mocked(useLoadableNfdResult).mockReturnValue([{ state: 'loading' }]) return executeComponentTest( () => { @@ -167,6 +169,7 @@ describe('application-method-definitions', () => { it('allows the users to switch to echo_bytes method and send the transaction', async () => { const { testAccount } = localnet.context vi.mocked(useParams).mockImplementation(() => ({ applicationId: appId.toString() })) + vi.mocked(useLoadableNfdResult).mockReturnValue([{ state: 'loading' }]) return executeComponentTest( () => { diff --git a/src/features/applications/pages/application-page.test.tsx b/src/features/applications/pages/application-page.test.tsx index 53b3530d..5914db04 100644 --- a/src/features/applications/pages/application-page.test.tsx +++ b/src/features/applications/pages/application-page.test.tsx @@ -40,7 +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' +import { useLoadableNfd } from '@/features/nfd/data/nfd' vi.mock('@/features/common/data/algo-client', async () => { const original = await vi.importActual('@/features/common/data/algo-client') @@ -116,7 +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' }]) + vi.mocked(useLoadableNfd).mockReturnValue([{ state: 'loading' }]) const myStore = createStore() myStore.set(genesisHashAtom, 'some-hash') @@ -236,7 +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' }]) + vi.mocked(useLoadableNfd).mockReturnValue([{ state: 'loading' }]) const myStore = createStore() myStore.set(genesisHashAtom, 'some-hash') @@ -271,7 +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' }]) + vi.mocked(useLoadableNfd).mockReturnValue([{ state: 'loading' }]) const myStore = createStore() myStore.set(genesisHashAtom, 'some-hash') @@ -361,7 +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(useLoadableNfd).mockReturnValue([{ state: 'loading' }]) vi.mocked(indexer.searchForTransactions().applicationID(applicationResult.id).limit(3).do).mockImplementation(() => Promise.resolve({ currentRound: 123, transactions: [], nextToken: '' }) ) diff --git a/src/features/assets/components/asset-transaction-history.test.tsx b/src/features/assets/components/asset-transaction-history.test.tsx index e1b80a6f..f3e23619 100644 --- a/src/features/assets/components/asset-transaction-history.test.tsx +++ b/src/features/assets/components/asset-transaction-history.test.tsx @@ -11,7 +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' +import { useLoadableNfd } from '@/features/nfd/data/nfd' vi.mock('@/features/common/data/algo-client', async () => { const original = await vi.importActual('@/features/common/data/algo-client') @@ -27,7 +27,7 @@ describe('asset-transaction-history', () => { const asset = assetResultMother['testnet-642327435']().build() it('should be able to handle pagination', () => { - vi.mocked(useLoadableNfdResult).mockReturnValue([{ state: 'loading' }]) + vi.mocked(useLoadableNfd).mockReturnValue([{ state: 'loading' }]) const myStore = createStore() myStore.set(assetResultsAtom, new Map([[asset.index, createReadOnlyAtomAndTimestamp(asset)]])) diff --git a/src/features/assets/pages/asset-page.test.tsx b/src/features/assets/pages/asset-page.test.tsx index dc9c6c4c..79a8b6b4 100644 --- a/src/features/assets/pages/asset-page.test.tsx +++ b/src/features/assets/pages/asset-page.test.tsx @@ -35,7 +35,7 @@ import { algod, indexer } from '@/features/common/data/algo-client' import { setupServer } from 'msw/node' import { http, HttpResponse } from 'msw' import { searchTransactionsMock } from '@/tests/setup/mocks' -import { useLoadableNfdResult } from '@/features/nfd/data/nfd' +import { useLoadableNfd } from '@/features/nfd/data/nfd' const server = setupServer() @@ -96,7 +96,7 @@ describe('asset-page', () => { describe('when rendering an asset that failed to load', () => { it('should display failed to load message', () => { vi.mocked(useParams).mockImplementation(() => ({ assetId: '123456' })) - vi.mocked(useLoadableNfdResult).mockReturnValue([{ state: 'loading' }]) + vi.mocked(useLoadableNfd).mockReturnValue([{ state: 'loading' }]) vi.mocked(algod.getAssetByID(0).do).mockImplementation(() => Promise.reject({})) return executeComponentTest( @@ -113,7 +113,7 @@ describe('asset-page', () => { const transactionResult = transactionResultMother.assetConfig().build() it('should be rendered with the correct data', () => { - vi.mocked(useLoadableNfdResult).mockReturnValue([{ state: 'loading' }]) + vi.mocked(useLoadableNfd).mockReturnValue([{ state: 'loading' }]) const myStore = createStore() myStore.set(assetResultsAtom, new Map([[assetResult.index, createReadOnlyAtomAndTimestamp(assetResult)]])) @@ -199,7 +199,7 @@ describe('asset-page', () => { const transactionResult = transactionResultMother.assetConfig().build() it('should be rendered with the correct data', () => { - vi.mocked(useLoadableNfdResult).mockReturnValue([{ state: 'loading' }]) + vi.mocked(useLoadableNfd).mockReturnValue([{ state: 'loading' }]) const myStore = createStore() myStore.set(assetResultsAtom, new Map([[assetResult.index, createReadOnlyAtomAndTimestamp(assetResult)]])) @@ -301,7 +301,7 @@ describe('asset-page', () => { const transactionResult = transactionResultMother['mainnet-4BFQTYKSJNRF52LXCMBXKDWLODRDVGSUCW36ND3B7C3ZQKPMLUJA']().build() it('should be rendered with the correct data', () => { - vi.mocked(useLoadableNfdResult).mockReturnValue([{ state: 'loading' }]) + vi.mocked(useLoadableNfd).mockReturnValue([{ state: 'loading' }]) const myStore = createStore() myStore.set(assetResultsAtom, new Map([[assetResult.index, createReadOnlyAtomAndTimestamp(assetResult)]])) @@ -388,7 +388,7 @@ describe('asset-page', () => { const transactionResult = transactionResultMother['mainnet-P4IX7SYWTTFRQGYTCLFOZSTYSJ5FJKNR3MEIVRR4OA2JJXTQZHTQ']().build() it('should be rendered with the correct data', () => { - vi.mocked(useLoadableNfdResult).mockReturnValue([{ state: 'loading' }]) + vi.mocked(useLoadableNfd).mockReturnValue([{ state: 'loading' }]) const myStore = createStore() myStore.set(assetResultsAtom, new Map([[assetResult.index, createReadOnlyAtomAndTimestamp(assetResult)]])) @@ -474,7 +474,7 @@ describe('asset-page', () => { const transactionResult = transactionResultMother['mainnet-K66JS73E3BDJ4OYHIC4QRRNSGY2PQMKSQMPYFQ6EEYJTOIPDUA3Q']().build() it('should be rendered with the correct data', () => { - vi.mocked(useLoadableNfdResult).mockReturnValue([{ state: 'loading' }]) + vi.mocked(useLoadableNfd).mockReturnValue([{ state: 'loading' }]) const myStore = createStore() myStore.set(assetResultsAtom, new Map([[assetResult.index, createReadOnlyAtomAndTimestamp(assetResult)]])) @@ -592,7 +592,7 @@ describe('asset-page', () => { const transactionResult = transactionResultMother['mainnet-W7UVVLOW6RWZYEC64WTOVL5RME33UGI6H6AUP7GSEZW4QNDM4GHA']().build() it('should be rendered with the correct data', () => { - vi.mocked(useLoadableNfdResult).mockReturnValue([{ state: 'loading' }]) + vi.mocked(useLoadableNfd).mockReturnValue([{ state: 'loading' }]) const myStore = createStore() myStore.set(assetResultsAtom, new Map([[assetResult.index, createReadOnlyAtomAndTimestamp(assetResult)]])) @@ -727,7 +727,7 @@ describe('asset-page', () => { const destroyAssetTransactionResult = transactionResultMother['mainnet-U4XH6AS5UUYQI4IZ3E5JSUEIU64Y3FGNYKLH26W4HRY7T6PK745A']().build() it('should be rendered with the correct data', () => { - vi.mocked(useLoadableNfdResult).mockReturnValue([{ state: 'loading' }]) + vi.mocked(useLoadableNfd).mockReturnValue([{ state: 'loading' }]) const myStore = createStore() myStore.set(assetResultsAtom, new Map([[assetResult.index, createReadOnlyAtomAndTimestamp(assetResult)]])) @@ -813,7 +813,7 @@ describe('asset-page', () => { const transactionResult = transactionResultMother.assetConfig().build() it('should be rendered with the refresh button', () => { - vi.mocked(useLoadableNfdResult).mockReturnValue([{ state: 'loading' }]) + vi.mocked(useLoadableNfd).mockReturnValue([{ state: 'loading' }]) const myStore = createStore() myStore.set(assetResultsAtom, new Map([[assetResult.index, createReadOnlyAtomAndTimestamp(assetResult)]])) @@ -873,7 +873,7 @@ describe('asset-page', () => { const assetResult = assetResultMother['mainnet-1024439078']().build() const transactionResult = transactionResultMother.assetConfig().build() it('should be rendered with the correct data', () => { - vi.mocked(useLoadableNfdResult).mockReturnValue([{ state: 'loading' }]) + vi.mocked(useLoadableNfd).mockReturnValue([{ state: 'loading' }]) const myStore = createStore() myStore.set(assetResultsAtom, new Map([[assetResult.index, createReadOnlyAtomAndTimestamp(assetResult)]])) diff --git a/src/features/blocks/pages/block-page.test.tsx b/src/features/blocks/pages/block-page.test.tsx index 4897a6e2..a81ddf5f 100644 --- a/src/features/blocks/pages/block-page.test.tsx +++ b/src/features/blocks/pages/block-page.test.tsx @@ -18,7 +18,7 @@ import { tableAssertion } from '@/tests/assertions/table-assertion' import { descriptionListAssertion } from '@/tests/assertions/description-list-assertion' import { assetResultsAtom } from '@/features/assets/data' import { indexer } from '@/features/common/data/algo-client' -import { useLoadableNfdResult } from '@/features/nfd/data/nfd' +import { useLoadableNfd } from '@/features/nfd/data/nfd' vi.mock('@/features/common/data/algo-client', async () => { const original = await vi.importActual('@/features/common/data/algo-client') @@ -115,7 +115,7 @@ describe('block-page', () => { it('should be rendered with the correct data', () => { vi.mocked(useParams).mockImplementation(() => ({ round: block.round.toString() })) - vi.mocked(useLoadableNfdResult).mockReturnValue([{ state: 'loading' }]) + vi.mocked(useLoadableNfd).mockReturnValue([{ state: 'loading' }]) const myStore = createStore() myStore.set(blockResultsAtom, new Map([[block.round, createReadOnlyAtomAndTimestamp(block)]])) myStore.set(transactionResultsAtom, new Map(transactionResults.map((x) => [x.id, createReadOnlyAtomAndTimestamp(x)]))) diff --git a/src/features/explore/pages/explore-page.test.tsx b/src/features/explore/pages/explore-page.test.tsx index c7c4d1d9..2c510d8b 100644 --- a/src/features/explore/pages/explore-page.test.tsx +++ b/src/features/explore/pages/explore-page.test.tsx @@ -16,7 +16,7 @@ import { randomNumberBetween } from '@makerx/ts-dossier' import { ellipseId } from '@/utils/ellipse-id' import { ellipseAddress } from '@/utils/ellipse-address' import { createReadOnlyAtomAndTimestamp, createTimestamp } from '@/features/common/data' -import { useLoadableNfdResult } from '@/features/nfd/data/nfd' +import { useLoadableNfd } from '@/features/nfd/data/nfd' describe('explore-page', () => { describe('when no blocks are available', () => { @@ -64,7 +64,7 @@ describe('explore-page', () => { ) myStore.set(syncedRoundAtom, block.round) beforeEach(() => { - vi.mocked(useLoadableNfdResult).mockReturnValue([{ state: 'loading' }]) + vi.mocked(useLoadableNfd).mockReturnValue([{ state: 'loading' }]) }) it('the processed blocks are displayed', () => { @@ -129,7 +129,7 @@ describe('explore-page', () => { } ) beforeEach(() => { - vi.mocked(useLoadableNfdResult).mockReturnValue([{ state: 'loading' }]) + vi.mocked(useLoadableNfd).mockReturnValue([{ state: 'loading' }]) }) it('only the latest 10 blocks are displayed', () => { diff --git a/src/features/groups/pages/group-page.test.tsx b/src/features/groups/pages/group-page.test.tsx index fe2833f6..d08472a0 100644 --- a/src/features/groups/pages/group-page.test.tsx +++ b/src/features/groups/pages/group-page.test.tsx @@ -19,7 +19,7 @@ import { tableAssertion } from '@/tests/assertions/table-assertion' import { assetResultsAtom } from '@/features/assets/data' import { indexer } from '@/features/common/data/algo-client' import { genesisHashAtom } from '@/features/blocks/data' -import { useLoadableNfdResult } from '@/features/nfd/data/nfd' +import { useLoadableNfd } from '@/features/nfd/data/nfd' vi.mock('@/features/common/data/algo-client', async () => { const original = await vi.importActual('@/features/common/data/algo-client') @@ -93,7 +93,7 @@ describe('group-page', () => { it('should be rendered with the correct data', () => { vi.mocked(useParams).mockImplementation(() => ({ round: group.round.toString(), groupId: group.id })) - vi.mocked(useLoadableNfdResult).mockReturnValue([{ state: 'loading' }]) + vi.mocked(useLoadableNfd).mockReturnValue([{ state: 'loading' }]) const myStore = createStore() myStore.set(groupResultsAtom, new Map([[group.id, createReadOnlyAtomAndTimestamp(group)]])) myStore.set(transactionResultsAtom, new Map(transactionResults.map((x) => [x.id, createReadOnlyAtomAndTimestamp(x)]))) diff --git a/src/features/layout/pages/layout-page.test.tsx b/src/features/layout/pages/layout-page.test.tsx index e047d8e2..33a2f7f7 100644 --- a/src/features/layout/pages/layout-page.test.tsx +++ b/src/features/layout/pages/layout-page.test.tsx @@ -8,7 +8,7 @@ import { Event as TauriEvent, listen } from '@tauri-apps/api/event' import { networkConfigAtom } from '@/features/network/data' import { useNavigate } from 'react-router-dom' import { settingsStore } from '@/features/settings/data' -import { useLoadableNfdResult } from '@/features/nfd/data/nfd' +import { useLoadableNfd } from '@/features/nfd/data/nfd' describe('when rendering the layout page', () => { describe('and the wallet is not connected', () => { @@ -43,7 +43,7 @@ describe('when rendering the layout page', () => { describe('and the wallet is connected', () => { it('the wallet address is shown', async () => { - vi.mocked(useLoadableNfdResult).mockReturnValue([{ state: 'loading' }]) + vi.mocked(useLoadableNfd).mockReturnValue([{ state: 'loading' }]) const original = await vi.importActual<{ useWallet: () => ReturnType }>('@txnlab/use-wallet') vi.mocked(useWallet).mockImplementation(() => { return { @@ -70,7 +70,7 @@ describe('when rendering the layout page', () => { }) describe('and there is more than one account', () => { it('the account switcher should be shown', async () => { - vi.mocked(useLoadableNfdResult).mockReturnValue([{ state: 'loading' }]) + vi.mocked(useLoadableNfd).mockReturnValue([{ state: 'loading' }]) const original = await vi.importActual<{ useWallet: () => ReturnType }>('@txnlab/use-wallet') vi.mocked(useWallet).mockImplementation(() => { return { @@ -112,7 +112,7 @@ describe('when rendering the layout page', () => { describe('and the user disconnects the wallet', () => { it('the wallet should be disconnected', async () => { - vi.mocked(useLoadableNfdResult).mockReturnValue([{ state: 'loading' }]) + vi.mocked(useLoadableNfd).mockReturnValue([{ state: 'loading' }]) const original = await vi.importActual<{ useWallet: () => ReturnType }>('@txnlab/use-wallet') const disconnect = vi.fn() vi.mocked(useWallet).mockImplementation(() => { diff --git a/src/features/nfd/data/is-nfd.ts b/src/features/nfd/data/is-nfd.ts index 17c47816..5bcf08f2 100644 --- a/src/features/nfd/data/is-nfd.ts +++ b/src/features/nfd/data/is-nfd.ts @@ -1,3 +1,3 @@ const nfdRegex = /^(.+\.algo)$/ -export const isNFD = (name: string) => nfdRegex.test(name) +export const isNfd = (name: string) => nfdRegex.test(name) diff --git a/src/features/nfd/data/nfd-result.ts b/src/features/nfd/data/nfd-result.ts index 66274273..244b7604 100644 --- a/src/features/nfd/data/nfd-result.ts +++ b/src/features/nfd/data/nfd-result.ts @@ -172,12 +172,18 @@ export const getNfdResultAtom = (nfdLookup: NfdLookup): Atom { +export const useNfdAtom = (address: Address) => { return useMemo(() => { return getNfdResultAtom({ address: address }) }, [address]) } +export const useNfdResultAtom = (nfd: Nfd) => { + return useMemo(() => { + return getNfdResultAtom({ nfd: nfd }) + }, [nfd]) +} + const [forwardNfdResultsAtom, getForwardNfdResultAtom] = readOnlyAtomCache(getForwardLookupNfdResult, (nfd) => nfd) const [reverseNfdsAtom, getReverseNfdAtom] = writableAtomCache(getReverseLookupNfd, (address) => address) export { forwardNfdResultsAtom, reverseNfdsAtom } diff --git a/src/features/nfd/data/nfd.ts b/src/features/nfd/data/nfd.ts index aae26d3a..c3af10e5 100644 --- a/src/features/nfd/data/nfd.ts +++ b/src/features/nfd/data/nfd.ts @@ -1,9 +1,15 @@ import { Address } from '@/features/accounts/data/types' import { useAtomValue } from 'jotai' -import { useNfdResultAtom } from './nfd-result' +import { useNfdAtom, useNfdResultAtom } from './nfd-result' import { loadable } from 'jotai/utils' +import { Nfd } from './types' -export const useLoadableNfdResult = (address: Address) => { - const nfdAtom = useNfdResultAtom(address) +export const useLoadableNfd = (address: Address) => { + const nfdAtom = useNfdAtom(address) + return [useAtomValue(loadable(nfdAtom))] as const +} + +export const useLoadableNfdResult = (nfd: Nfd) => { + const nfdAtom = useNfdResultAtom(nfd) return [useAtomValue(loadable(nfdAtom))] as const } diff --git a/src/features/search/data/search.ts b/src/features/search/data/search.ts index 6187cb84..1e50d10a 100644 --- a/src/features/search/data/search.ts +++ b/src/features/search/data/search.ts @@ -17,7 +17,7 @@ import { syncedRoundAtom } from '@/features/blocks/data' import { createApplicationSummaryAtom } from '@/features/applications/data/application-summary' import { useSelectedNetwork } from '@/features/network/data' import { getTransactionResultAtom } from '@/features/transactions/data' -import { isNFD } from '@/features/nfd/data/is-nfd' +import { isNfd } from '@/features/nfd/data/is-nfd' import { getNfdResultAtom } from '@/features/nfd/data/nfd-result' const handle404 = (e: Error) => { @@ -51,7 +51,7 @@ const createSearchAtoms = (store: JotaiStore, selectedNetwork: string) => { label: `${ellipseAddress(term)}${nfd ? ` (${nfd.name})` : ''}`, url: Urls.Explore.Account.ByAddress.build({ address: term, networkId: selectedNetwork }), }) - } else if (isNFD(term)) { + } else if (isNfd(term)) { const nfdAtom = getNfdResultAtom({ nfd: term }) const nfd = await get(nfdAtom) if (nfd && isAddress(nfd.depositAccount)) { diff --git a/src/features/transaction-wizard/components/account-close-transaction-builder.tsx b/src/features/transaction-wizard/components/account-close-transaction-builder.tsx index df037174..9b2bb599 100644 --- a/src/features/transaction-wizard/components/account-close-transaction-builder.tsx +++ b/src/features/transaction-wizard/components/account-close-transaction-builder.tsx @@ -12,9 +12,9 @@ import { Form } from '@/features/forms/components/form' import { BuildableTransactionType, BuildAccountCloseTransactionResult } from '../models' import { randomGuid } from '@/utils/random-guid' import { TransactionBuilderMode } from '../data' -import { ZERO_ADDRESS } from '@/features/common/constants' import SvgAlgorand from '@/features/common/components/icons/algorand' import { TransactionBuilderNoteField } from './transaction-builder-note-field' +import { TransactionBuilderAddressField } from './transaction-builder-address-field' const senderLabel = 'Sender' const receiverLabel = 'Receiver' @@ -109,24 +109,21 @@ export function AccountCloseTransactionBuilder({ mode, transaction, activeAddres > {(helper) => ( <> - {helper.textField({ - field: 'sender', - label: senderLabel, - helpText: 'Account to be closed. Sends the transaction and pays the fee', - placeholder: ZERO_ADDRESS, - })} - {helper.textField({ - field: 'closeRemainderTo', - label: closeRemainderToLabel, - helpText: `Account to receive the remaining balance when '${senderLabel}' account is closed`, - placeholder: ZERO_ADDRESS, - })} - {helper.textField({ - field: 'receiver', - label: receiverLabel, - helpText: `Account to receive the amount. Leave blank if '${closeRemainderToLabel}' account should receive the full balance`, - placeholder: ZERO_ADDRESS, - })} + + + {helper.numberField({ field: 'amount', label: ( diff --git a/src/features/transaction-wizard/components/app-call-transaction-builder.tsx b/src/features/transaction-wizard/components/app-call-transaction-builder.tsx index 25e096ca..3beafc1f 100644 --- a/src/features/transaction-wizard/components/app-call-transaction-builder.tsx +++ b/src/features/transaction-wizard/components/app-call-transaction-builder.tsx @@ -14,6 +14,7 @@ import { BuildAppCallTransactionResult, BuildableTransactionType } from '../mode import { randomGuid } from '@/utils/random-guid' import { TransactionBuilderMode } from '../data' import { TransactionBuilderNoteField } from './transaction-builder-note-field' +import { TransactionBuilderAddressField } from './transaction-builder-address-field' const formData = zfd.formData({ ...commonSchema, @@ -108,11 +109,11 @@ export function AppCallTransactionBuilder({ mode, transaction, activeAddress, de options: onCompleteOptions, helpText: 'Action to perform after executing the program', })} - {helper.textField({ - field: 'sender', - label: 'Sender', - helpText: 'Account to call from. Sends the transaction and pays the fee', - })} + {helper.arrayField({ field: 'args', label: 'Arguments', diff --git a/src/features/transaction-wizard/components/asset-clawback-transaction-builder.tsx b/src/features/transaction-wizard/components/asset-clawback-transaction-builder.tsx index bc63e963..05d3dbf2 100644 --- a/src/features/transaction-wizard/components/asset-clawback-transaction-builder.tsx +++ b/src/features/transaction-wizard/components/asset-clawback-transaction-builder.tsx @@ -17,10 +17,10 @@ import { useFormContext, UseFormReturn } from 'react-hook-form' import { useLoadableAssetSummaryAtom } from '@/features/assets/data' import { RenderLoadable } from '@/features/common/components/render-loadable' import { AssetId } from '@/features/assets/data/types' -import { ZERO_ADDRESS } from '@/features/common/constants' import { useDebounce } from 'use-debounce' import { TransactionBuilderMode } from '../data' import { TransactionBuilderNoteField } from './transaction-builder-note-field' +import { TransactionBuilderAddressField } from './transaction-builder-address-field' const clawbackTargetLabel = 'Clawback target' @@ -79,24 +79,17 @@ function FormFields({ helper, asset }: FormFieldsProps) { label: Asset ID {asset && asset.name ? ` (${asset.name})` : ''}, helpText: 'The asset to be clawed back', })} - {helper.textField({ - field: 'sender', - label: 'Sender', - helpText: 'The clawback account of the asset. Sends the transaction and pays the fee', - placeholder: ZERO_ADDRESS, - })} - {helper.textField({ - field: 'receiver', - label: 'Receiver', - helpText: 'Account to receive the asset', - placeholder: ZERO_ADDRESS, - })} - {helper.textField({ - field: 'clawbackTarget', - label: clawbackTargetLabel, - helpText: 'Account the asset will be clawed back from', - placeholder: ZERO_ADDRESS, - })} + + + {helper.numberField({ field: 'amount', label: Amount{asset && asset.unitName ? ` (${asset.unitName})` : ''}, diff --git a/src/features/transaction-wizard/components/asset-create-transaction-builder.tsx b/src/features/transaction-wizard/components/asset-create-transaction-builder.tsx index 90ce7394..0b8390f6 100644 --- a/src/features/transaction-wizard/components/asset-create-transaction-builder.tsx +++ b/src/features/transaction-wizard/components/asset-create-transaction-builder.tsx @@ -12,9 +12,9 @@ import { Form } from '@/features/forms/components/form' import { BuildableTransactionType, BuildAssetCreateTransactionResult } from '../models' import { randomGuid } from '@/utils/random-guid' import { FormFieldHelper } from '@/features/forms/components/form-field-helper' -import { ZERO_ADDRESS } from '@/features/common/constants' import { TransactionBuilderMode } from '../data' import { TransactionBuilderNoteField } from './transaction-builder-note-field' +import { TransactionBuilderAddressField } from './transaction-builder-address-field' const formSchema = { ...commonSchema, @@ -61,36 +61,31 @@ function FormFields({ helper }: FormFieldsProps) { label: 'Decimals', helpText: "Set to 0 for a non-divisible asset. Can't be changed after creation", })} - {helper.textField({ - field: 'sender', - label: 'Creator', - helpText: 'Account that creates the asset. Sends the transaction and pays the fee', - placeholder: ZERO_ADDRESS, - })} - {helper.textField({ - field: 'manager', - label: 'Manager', - helpText: "Account that can re-configure and destroy the asset. If empty, the asset can't be re-configured", - placeholder: ZERO_ADDRESS, - })} - {helper.textField({ - field: 'reserve', - label: 'Reserve', - helpText: "Account that holds the reserve units of the asset. If empty, this address can't be changed", - placeholder: ZERO_ADDRESS, - })} - {helper.textField({ - field: 'freeze', - label: 'Freeze', - helpText: "Account that can freeze the asset. If empty, assets can't be frozen and this address can't be changed", - placeholder: ZERO_ADDRESS, - })} - {helper.textField({ - field: 'clawback', - label: 'Clawback', - helpText: "Account that can claw back the asset. If empty, assets can't be clawed back and this address can't be changed", - placeholder: ZERO_ADDRESS, - })} + + + + + {helper.checkboxField({ field: 'defaultFrozen', label: 'Freeze holdings of this asset by default', diff --git a/src/features/transaction-wizard/components/asset-destroy-transaction-builder.tsx b/src/features/transaction-wizard/components/asset-destroy-transaction-builder.tsx index 87ced470..7880146f 100644 --- a/src/features/transaction-wizard/components/asset-destroy-transaction-builder.tsx +++ b/src/features/transaction-wizard/components/asset-destroy-transaction-builder.tsx @@ -17,13 +17,13 @@ import { useFormContext, UseFormReturn } from 'react-hook-form' import { useLoadableAssetSummaryAtom } from '@/features/assets/data' import { RenderLoadable } from '@/features/common/components/render-loadable' import { AssetId } from '@/features/assets/data/types' -import { ZERO_ADDRESS } from '@/features/common/constants' import { useDebounce } from 'use-debounce' import { AccountLink } from '@/features/accounts/components/account-link' import { ellipseAddress } from '@/utils/ellipse-address' import { cn } from '@/features/common/utils' import { TransactionBuilderMode } from '../data' import { TransactionBuilderNoteField } from './transaction-builder-note-field' +import { TransactionBuilderAddressField } from './transaction-builder-address-field' const formSchema = { ...commonSchema, @@ -77,12 +77,11 @@ function FormFields({ helper, asset }: FormFieldsProps) {  must hold all units )} - {helper.textField({ - field: 'sender', - label: 'Sender', - helpText: 'The current asset manager address. Sends the transaction and pays the fee', - placeholder: ZERO_ADDRESS, - })} + diff --git a/src/features/transaction-wizard/components/asset-opt-in-transaction-builder.tsx b/src/features/transaction-wizard/components/asset-opt-in-transaction-builder.tsx index 46e1ddd8..f1dae744 100644 --- a/src/features/transaction-wizard/components/asset-opt-in-transaction-builder.tsx +++ b/src/features/transaction-wizard/components/asset-opt-in-transaction-builder.tsx @@ -17,10 +17,10 @@ import { useFormContext, UseFormReturn } from 'react-hook-form' import { useLoadableAssetSummaryAtom } from '@/features/assets/data' import { RenderLoadable } from '@/features/common/components/render-loadable' import { AssetId } from '@/features/assets/data/types' -import { ZERO_ADDRESS } from '@/features/common/constants' import { useDebounce } from 'use-debounce' import { TransactionBuilderMode } from '../data' import { TransactionBuilderNoteField } from './transaction-builder-note-field' +import { TransactionBuilderAddressField } from './transaction-builder-address-field' const formSchema = { ...commonSchema, @@ -58,12 +58,11 @@ function FormFields({ helper, asset }: FormFieldsProps) { label: Asset ID {asset && asset.name ? ` (${asset.name})` : ''}, helpText: 'The asset to be opted in to', })} - {helper.textField({ - field: 'sender', - label: 'Sender', - helpText: 'Account to opt in to the asset. Sends the transaction and pays the fee', - placeholder: ZERO_ADDRESS, - })} + diff --git a/src/features/transaction-wizard/components/asset-opt-out-transaction-builder.tsx b/src/features/transaction-wizard/components/asset-opt-out-transaction-builder.tsx index 5d6e2195..0a46eb16 100644 --- a/src/features/transaction-wizard/components/asset-opt-out-transaction-builder.tsx +++ b/src/features/transaction-wizard/components/asset-opt-out-transaction-builder.tsx @@ -17,10 +17,10 @@ import { useFormContext, UseFormReturn } from 'react-hook-form' import { useLoadableAssetSummaryAtom } from '@/features/assets/data' import { RenderLoadable } from '@/features/common/components/render-loadable' import { AssetId } from '@/features/assets/data/types' -import { ZERO_ADDRESS } from '@/features/common/constants' import { useDebounce } from 'use-debounce' import { TransactionBuilderMode } from '../data' import { TransactionBuilderNoteField } from './transaction-builder-note-field' +import { TransactionBuilderAddressField } from './transaction-builder-address-field' const formSchema = { ...commonSchema, @@ -59,18 +59,16 @@ function FormFields({ helper, asset }: FormFieldsProps) { label: Asset ID {asset && asset.name ? ` (${asset.name})` : ''}, helpText: 'The asset to be opted out of', })} - {helper.textField({ - field: 'sender', - label: 'Sender', - helpText: 'Account to opt out of the asset. Sends the transaction and pays the fee', - placeholder: ZERO_ADDRESS, - })} - {helper.textField({ - field: 'closeRemainderTo', - label: 'Close remainder to', - helpText: 'Account to receive the remaining balance of the asset', - placeholder: ZERO_ADDRESS, - })} + + diff --git a/src/features/transaction-wizard/components/asset-reconfigure-transaction-builder.tsx b/src/features/transaction-wizard/components/asset-reconfigure-transaction-builder.tsx index e1d43969..6b641cf8 100644 --- a/src/features/transaction-wizard/components/asset-reconfigure-transaction-builder.tsx +++ b/src/features/transaction-wizard/components/asset-reconfigure-transaction-builder.tsx @@ -17,10 +17,10 @@ import { useFormContext, UseFormReturn } from 'react-hook-form' import { useLoadableAssetSummaryAtom } from '@/features/assets/data' import { RenderLoadable } from '@/features/common/components/render-loadable' import { AssetId } from '@/features/assets/data/types' -import { ZERO_ADDRESS } from '@/features/common/constants' import { useDebounce } from 'use-debounce' import { TransactionBuilderMode } from '../data' import { TransactionBuilderNoteField } from './transaction-builder-note-field' +import { TransactionBuilderAddressField } from './transaction-builder-address-field' const formSchema = { ...commonSchema, @@ -68,36 +68,31 @@ function FormFields({ helper, asset }: FormFieldsProps) { label: Asset ID {asset && asset.name ? ` (${asset.name})` : ''}, helpText: 'The asset to be reconfigured', })} - {helper.textField({ - field: 'sender', - label: 'Sender', - helpText: 'The current asset manager address. Sends the transaction and pays the fee', - placeholder: ZERO_ADDRESS, - })} - {helper.textField({ - field: 'manager', - label: 'Manager', - helpText: "Account that can re-configure and destroy the asset. If empty, the asset can't be re-configured", - placeholder: ZERO_ADDRESS, - })} - {helper.textField({ - field: 'reserve', - label: 'Reserve', - helpText: "Account that holds the reserve units of the asset. If empty, this address can't be changed", - placeholder: ZERO_ADDRESS, - })} - {helper.textField({ - field: 'freeze', - label: 'Freeze', - helpText: "Account that can freeze the asset. If empty, assets can't be frozen and this address can't be changed", - placeholder: ZERO_ADDRESS, - })} - {helper.textField({ - field: 'clawback', - label: 'Clawback', - helpText: "Account that can claw back the asset. If empty, assets can't be clawed back and this address can't be changed", - placeholder: ZERO_ADDRESS, - })} + + + + + diff --git a/src/features/transaction-wizard/components/asset-transfer-transaction-builder.tsx b/src/features/transaction-wizard/components/asset-transfer-transaction-builder.tsx index 6ac5e8f4..42222136 100644 --- a/src/features/transaction-wizard/components/asset-transfer-transaction-builder.tsx +++ b/src/features/transaction-wizard/components/asset-transfer-transaction-builder.tsx @@ -17,10 +17,11 @@ import { useFormContext, UseFormReturn } from 'react-hook-form' import { useLoadableAssetSummaryAtom } from '@/features/assets/data' import { RenderLoadable } from '@/features/common/components/render-loadable' import { AssetId } from '@/features/assets/data/types' -import { ZERO_ADDRESS } from '@/features/common/constants' import { useDebounce } from 'use-debounce' import { TransactionBuilderMode } from '../data' import { TransactionBuilderNoteField } from './transaction-builder-note-field' +import { NfdResult } from '@/features/nfd/data/types' +import { TransactionBuilderAddressField } from './transaction-builder-address-field' const receiverLabel = 'Receiver' @@ -47,11 +48,12 @@ const formSchema = { amount: numberSchema(z.number({ required_error: 'Required', invalid_type_error: 'Required' })), } -const formData = zfd.formData(formSchema) +export const formData = zfd.formData(formSchema) type FormFieldsProps = { helper: FormFieldHelper> asset?: AssetSummary + nfd?: NfdResult } function FormFields({ helper, asset }: FormFieldsProps) { @@ -62,18 +64,12 @@ function FormFields({ helper, asset }: FormFieldsProps) { label: Asset ID {asset && asset.name ? ` (${asset.name})` : ''}, helpText: 'The asset to be transfered', })} - {helper.textField({ - field: 'sender', - label: 'Sender', - helpText: 'Account to transfer from. Sends the transaction and pays the fee', - placeholder: ZERO_ADDRESS, - })} - {helper.textField({ - field: 'receiver', - label: receiverLabel, - helpText: 'Account to receive the asset', - placeholder: ZERO_ADDRESS, - })} + + {helper.numberField({ field: 'amount', label: Amount{asset && asset.unitName ? ` (${asset.unitName})` : ''}, diff --git a/src/features/transaction-wizard/components/method-call-transaction-builder.tsx b/src/features/transaction-wizard/components/method-call-transaction-builder.tsx index 16991131..addc0c64 100644 --- a/src/features/transaction-wizard/components/method-call-transaction-builder.tsx +++ b/src/features/transaction-wizard/components/method-call-transaction-builder.tsx @@ -36,6 +36,7 @@ import { TransactionBuilder } from './transaction-builder' import { Arc32AppSpec } from '@/features/app-interfaces/data/types' import { AppSpec } from '@algorandfoundation/algokit-utils/types/app-spec' import { TransactionBuilderNoteField } from './transaction-builder-note-field' +import { TransactionBuilderAddressField } from './transaction-builder-address-field' const appCallFormSchema = { ...commonSchema, @@ -342,11 +343,11 @@ function FormInner({ helper, methodForm, onSetAppSpec, onSetMethodForm, onSetTra options: onCompleteOptions, helpText: 'Action to perform after executing the program', })} - {helper.textField({ - field: 'sender', - label: 'Sender', - helpText: 'Account to call from. Sends the transaction and pays the fee', - })} + {abiMethodArgs.map((arg, index) => (
{`Argument ${index + 1}`}
diff --git a/src/features/transaction-wizard/components/payment-transaction-builder.tsx b/src/features/transaction-wizard/components/payment-transaction-builder.tsx index fa1732de..b8897a0c 100644 --- a/src/features/transaction-wizard/components/payment-transaction-builder.tsx +++ b/src/features/transaction-wizard/components/payment-transaction-builder.tsx @@ -12,9 +12,9 @@ import { Form } from '@/features/forms/components/form' import { BuildableTransactionType, BuildPaymentTransactionResult } from '../models' import { randomGuid } from '@/utils/random-guid' import { TransactionBuilderMode } from '../data' -import { ZERO_ADDRESS } from '@/features/common/constants' import SvgAlgorand from '@/features/common/components/icons/algorand' import { TransactionBuilderNoteField } from './transaction-builder-note-field' +import { TransactionBuilderAddressField } from './transaction-builder-address-field' const receiverLabel = 'Receiver' @@ -87,18 +87,12 @@ export function PaymentTransactionBuilder({ mode, transaction, activeAddress, on > {(helper) => ( <> - {helper.textField({ - field: 'sender', - label: 'Sender', - helpText: 'Account to pay from. Sends the transaction and pays the fee', - placeholder: ZERO_ADDRESS, - })} - {helper.textField({ - field: 'receiver', - label: receiverLabel, - helpText: 'Account to receive the amount', - placeholder: ZERO_ADDRESS, - })} + + {helper.numberField({ field: 'amount', label: ( diff --git a/src/features/transaction-wizard/components/transaction-builder-address-field.tsx b/src/features/transaction-wizard/components/transaction-builder-address-field.tsx new file mode 100644 index 00000000..9e4fe748 --- /dev/null +++ b/src/features/transaction-wizard/components/transaction-builder-address-field.tsx @@ -0,0 +1,49 @@ +import { FormFieldHelper } from '@/features/forms/components/form-field-helper' +import { z } from 'zod' +import { useFormContext } from 'react-hook-form' +import { useLoadableNfdResult } from '@/features/nfd/data/nfd' +import { useDebounce } from 'use-debounce' +import { NfdResult } from '@/features/nfd/data/types' +import { ZERO_ADDRESS } from '@/features/common/constants' +import { useEffect, useState } from 'react' +import { isNfd } from '@/features/nfd/data/is-nfd' +import { commonAddressFormData } from '../data/common' +import { ellipseAddress } from '@/utils/ellipse-address' + +type TransactionBuilderAddressFieldProps = { + fieldName: keyof z.infer + helpText: string + label: string +} + +export function TransactionBuilderAddressField({ fieldName, helpText, label }: TransactionBuilderAddressFieldProps) { + const helper = new FormFieldHelper>() + const formCtx = useFormContext>() + const fieldValue = formCtx.watch(fieldName) + const [debouncedValue] = useDebounce(fieldValue && isNfd(String(fieldValue)) ? String(fieldValue) : '', 500) + const [loadableNfd] = useLoadableNfdResult(debouncedValue) + const [currentNfd, setCurrentNfd] = useState(undefined) + + useEffect(() => { + if (loadableNfd.state === 'hasData' && loadableNfd.data !== null) { + setCurrentNfd(loadableNfd.data) + } else { + setCurrentNfd(undefined) + } + }, [loadableNfd]) + + return ( +
+ {helper.textField({ + field: fieldName, + label: ( + + {label} {currentNfd ? ` (${ellipseAddress(currentNfd.depositAccount)})` : ''} + + ), + helpText: helpText, + placeholder: ZERO_ADDRESS, + })} +
+ ) +} diff --git a/src/features/transaction-wizard/data/common.ts b/src/features/transaction-wizard/data/common.ts index bc436448..83977583 100644 --- a/src/features/transaction-wizard/data/common.ts +++ b/src/features/transaction-wizard/data/common.ts @@ -4,14 +4,17 @@ import { isAddress } from '@/utils/is-address' import { bigIntSchema, numberSchema } from '@/features/forms/data/common' import algosdk from 'algosdk' import { asOnCompleteLabel } from '../mappers/as-description-list-items' +import { isNfd } from '@/features/nfd/data/is-nfd' export const requiredMessage = 'Required' const invalidAddressMessage = 'Invalid address' -export const optionalAddressFieldSchema = zfd.text(z.string().optional()).refine((value) => (value ? isAddress(value) : true), { - message: invalidAddressMessage, -}) -export const addressFieldSchema = zfd.text().refine((value) => (value ? isAddress(value) : true), { +export const optionalAddressFieldSchema = zfd + .text(z.string().optional()) + .refine((value) => (value ? isAddress(value) || isNfd(value) : true), { + message: invalidAddressMessage, + }) +export const addressFieldSchema = zfd.text().refine((value) => (value ? isAddress(value) || isNfd(value) : true), { message: invalidAddressMessage, }) @@ -101,3 +104,16 @@ export const commonSchema = { } export const commonFormData = zfd.formData(commonSchema) + +export const commonAddressSchema = { + ...senderFieldSchema, + ...receiverFieldSchema, + closeRemainderTo: addressFieldSchema, + clawbackTarget: addressFieldSchema, + manager: optionalAddressFieldSchema, + reserve: optionalAddressFieldSchema, + freeze: optionalAddressFieldSchema, + clawback: optionalAddressFieldSchema, +} + +export const commonAddressFormData = zfd.formData(commonAddressSchema) diff --git a/src/features/transaction-wizard/transaction-wizard-page.test.tsx b/src/features/transaction-wizard/transaction-wizard-page.test.tsx index 358aae52..951fd9e9 100644 --- a/src/features/transaction-wizard/transaction-wizard-page.test.tsx +++ b/src/features/transaction-wizard/transaction-wizard-page.test.tsx @@ -8,7 +8,7 @@ import { sendButtonLabel, transactionTypeLabel, TransactionWizardPage } from './ import { selectOption } from '@/tests/utils/select-option' import { setWalletAddressAndSigner } from '@/tests/utils/set-wallet-address-and-signer' import { addTransactionLabel } from './components/transactions-builder' -import { useLoadableNfdResult } from '../nfd/data/nfd' +import { useLoadableNfd, useLoadableNfdResult } from '../nfd/data/nfd' describe('transaction-wizard-page', () => { const localnet = algorandFixture() @@ -48,6 +48,7 @@ describe('transaction-wizard-page', () => { describe('when a wallet is connected', () => { beforeEach(async () => { await setWalletAddressAndSigner(localnet) + vi.mocked(useLoadableNfd).mockReturnValue([{ state: 'loading' }]) vi.mocked(useLoadableNfdResult).mockReturnValue([{ state: 'loading' }]) }) diff --git a/src/features/transactions-graph/components/transactions-graph.test.tsx b/src/features/transactions-graph/components/transactions-graph.test.tsx index 46458515..73a3251c 100644 --- a/src/features/transactions-graph/components/transactions-graph.test.tsx +++ b/src/features/transactions-graph/components/transactions-graph.test.tsx @@ -18,7 +18,7 @@ import { asTransactionsGraphData } from '@/features/transactions-graph/mappers' import { Atom } from 'jotai/index' import { AbiMethod } from '@/features/abi-methods/models' import { setTimeout } from 'timers/promises' -import { useLoadableNfdResult } from '@/features/nfd/data/nfd' +import { useLoadableNfd } from '@/features/nfd/data/nfd' // This file maintain the snapshot test for the TransactionViewVisual component // To add new test case: @@ -38,7 +38,7 @@ describe('payment-transaction-graph', () => { transactionResultMother['mainnet-ILDCD5Z64CYSLEZIHBG5DVME2ITJI2DIVZAPDPEWPCYMTRA5SVGA']().build(), ])('when rendering transaction $id', (transactionResult: TransactionResult) => { it('should match snapshot', () => { - vi.mocked(useLoadableNfdResult).mockReturnValue([{ state: 'loading' }]) + vi.mocked(useLoadableNfd).mockReturnValue([{ state: 'loading' }]) const model = asPaymentTransaction(transactionResult) const graphData = asTransactionsGraphData([model]) return executeComponentTest( @@ -67,7 +67,7 @@ describe('asset-transfer-transaction-graph', () => { 'when rendering transaction $transactionResult.id', ({ transactionResult, assetResult }: { transactionResult: TransactionResult; assetResult: AssetResult }) => { it('should match snapshot', () => { - vi.mocked(useLoadableNfdResult).mockReturnValue([{ state: 'loading' }]) + vi.mocked(useLoadableNfd).mockReturnValue([{ state: 'loading' }]) const assetResolver = createAssetResolver([assetResult]) const transaction = asAssetTransferTransaction(transactionResult, assetResolver) const graphData = asTransactionsGraphData([transaction]) @@ -122,7 +122,7 @@ describe('application-call-graph', () => { 'when rendering transaction $transactionResult.id', ({ transactionResult, assetResults }: { transactionResult: TransactionResult; assetResults: AssetResult[] }) => { it('should match snapshot', () => { - vi.mocked(useLoadableNfdResult).mockReturnValue([{ state: 'loading' }]) + vi.mocked(useLoadableNfd).mockReturnValue([{ state: 'loading' }]) vi.mocked(useParams).mockImplementation(() => ({ transactionId: transactionResult.id })) const model = asAppCallTransaction(transactionResult, createAssetResolver(assetResults), createAbiMethodResolver()) @@ -150,7 +150,7 @@ describe('key-reg-graph', () => { ])('when rendering transaction $transactionResult.id', ({ transactionResult }: { transactionResult: TransactionResult }) => { it('should match snapshot', () => { vi.mocked(useParams).mockImplementation(() => ({ transactionId: transactionResult.id })) - vi.mocked(useLoadableNfdResult).mockReturnValue([{ state: 'loading' }]) + vi.mocked(useLoadableNfd).mockReturnValue([{ state: 'loading' }]) const model = asKeyRegTransaction(transactionResult) const graphData = asTransactionsGraphData([model]) return executeComponentTest( @@ -224,7 +224,7 @@ describe('group-graph', () => { assetResults: AssetResult[] }) => { it('should match snapshot', () => { - vi.mocked(useLoadableNfdResult).mockReturnValue([{ state: 'loading' }]) + vi.mocked(useLoadableNfd).mockReturnValue([{ state: 'loading' }]) const assetResolver = createAssetResolver(assetResults) const transactions = transactionResults.map((t) => asTransaction(t, assetResolver, createAbiMethodResolver())) const groupResult = groupResultMother.groupWithTransactions(transactionResults).withId(groupId).build() diff --git a/src/features/transactions/components/latest-transactions.tsx b/src/features/transactions/components/latest-transactions.tsx index b18d9d80..b00c5344 100644 --- a/src/features/transactions/components/latest-transactions.tsx +++ b/src/features/transactions/components/latest-transactions.tsx @@ -7,7 +7,7 @@ import { DescriptionList } from '@/features/common/components/description-list' import { ArrowRightLeft, Info } from 'lucide-react' import { Badge } from '@/features/common/components/badge' import { TransactionSummary } from '@/features/transactions/models' -import { useLoadableNfdResult } from '@/features/nfd/data/nfd' +import { useLoadableNfd } from '@/features/nfd/data/nfd' import { RenderLoadable } from '@/features/common/components/render-loadable' import { useMemo } from 'react' import { Loadable } from 'jotai/vanilla/utils/loadable' @@ -20,7 +20,7 @@ type Props = { } function useConditionalLoadableNfdResult(address: string | number | undefined) { - const [loadableNfd] = useLoadableNfdResult(typeof address === 'string' ? address : '') + const [loadableNfd] = useLoadableNfd(typeof address === 'string' ? address : '') return useMemo(() => ({ loadableNfd, isString: typeof address === 'string' }), [address, loadableNfd]) as { loadableNfd: Loadable isString: boolean diff --git a/src/features/transactions/pages/transaction-page.test.tsx b/src/features/transactions/pages/transaction-page.test.tsx index 86ee07d6..2dd3e19a 100644 --- a/src/features/transactions/pages/transaction-page.test.tsx +++ b/src/features/transactions/pages/transaction-page.test.tsx @@ -86,7 +86,7 @@ import { AppInterfaceEntity, dbConnectionAtom } from '@/features/common/data/ind import { genesisHashAtom } from '@/features/blocks/data' import { writeAppInterface } from '@/features/app-interfaces/data' import { algod } from '@/features/common/data/algo-client' -import { useLoadableNfdResult } from '@/features/nfd/data/nfd' +import { useLoadableNfd } from '@/features/nfd/data/nfd' vi.mock('@/features/common/data/algo-client', async () => { const original = await vi.importActual('@/features/common/data/algo-client') @@ -160,7 +160,7 @@ describe('transaction-page', () => { it('should be rendered with the correct data', () => { vi.mocked(useParams).mockImplementation(() => ({ transactionId: transaction.id })) - vi.mocked(useLoadableNfdResult).mockReturnValue([{ state: 'loading' }]) + vi.mocked(useLoadableNfd).mockReturnValue([{ state: 'loading' }]) const myStore = createStore() myStore.set(transactionResultsAtom, new Map([[transaction.id, createReadOnlyAtomAndTimestamp(transaction)]])) @@ -221,7 +221,7 @@ describe('transaction-page', () => { beforeEach(() => { vi.mocked(useParams).mockImplementation(() => ({ transactionId: transaction.id })) - vi.mocked(useLoadableNfdResult).mockReturnValue([{ state: 'loading' }]) + vi.mocked(useLoadableNfd).mockReturnValue([{ state: 'loading' }]) }) it('should show the multisig information', () => { @@ -263,7 +263,7 @@ describe('transaction-page', () => { beforeEach(() => { vi.mocked(useParams).mockImplementation(() => ({ transactionId: transaction.id })) - vi.mocked(useLoadableNfdResult).mockReturnValue([{ state: 'loading' }]) + vi.mocked(useLoadableNfd).mockReturnValue([{ state: 'loading' }]) }) it('should show 2 tabs with the logicsig base64 as default', () => { @@ -325,7 +325,7 @@ describe('transaction-page', () => { beforeEach(() => { vi.mocked(useParams).mockImplementation(() => ({ transactionId: transaction.id })) - vi.mocked(useLoadableNfdResult).mockReturnValue([{ state: 'loading' }]) + vi.mocked(useLoadableNfd).mockReturnValue([{ state: 'loading' }]) }) it('should show 2 tabs with the note base64 as default', () => { @@ -376,7 +376,7 @@ describe('transaction-page', () => { beforeEach(() => { vi.mocked(useParams).mockImplementation(() => ({ transactionId: transaction.id })) - vi.mocked(useLoadableNfdResult).mockReturnValue([{ state: 'loading' }]) + vi.mocked(useLoadableNfd).mockReturnValue([{ state: 'loading' }]) }) it('should show 3 tabs with the note json as default', () => { @@ -444,7 +444,7 @@ describe('transaction-page', () => { beforeEach(() => { vi.mocked(useParams).mockImplementation(() => ({ transactionId: transaction.id })) - vi.mocked(useLoadableNfdResult).mockReturnValue([{ state: 'loading' }]) + vi.mocked(useLoadableNfd).mockReturnValue([{ state: 'loading' }]) }) it('should show 3 tabs with the note arc-2 as default', () => { @@ -512,7 +512,7 @@ describe('transaction-page', () => { it('should be rendered with the correct data', () => { vi.mocked(useParams).mockImplementation(() => ({ transactionId: transaction.id })) - vi.mocked(useLoadableNfdResult).mockReturnValue([{ state: 'loading' }]) + vi.mocked(useLoadableNfd).mockReturnValue([{ state: 'loading' }]) const myStore = createStore() myStore.set(transactionResultsAtom, new Map([[transaction.id, createReadOnlyAtomAndTimestamp(transaction)]])) myStore.set(assetResultsAtom, new Map([[asset.index, createReadOnlyAtomAndTimestamp(asset)]])) @@ -574,7 +574,7 @@ describe('transaction-page', () => { it('should be rendered with the correct data', () => { vi.mocked(useParams).mockImplementation(() => ({ transactionId: transaction.id })) - vi.mocked(useLoadableNfdResult).mockReturnValue([{ state: 'loading' }]) + vi.mocked(useLoadableNfd).mockReturnValue([{ state: 'loading' }]) const myStore = createStore() myStore.set(transactionResultsAtom, new Map([[transaction.id, createReadOnlyAtomAndTimestamp(transaction)]])) myStore.set(assetResultsAtom, new Map([[asset.index, createReadOnlyAtomAndTimestamp(asset)]])) @@ -600,7 +600,7 @@ describe('transaction-page', () => { it('should be rendered with the correct data', () => { vi.mocked(useParams).mockImplementation(() => ({ transactionId: transaction.id })) - vi.mocked(useLoadableNfdResult).mockReturnValue([{ state: 'loading' }]) + vi.mocked(useLoadableNfd).mockReturnValue([{ state: 'loading' }]) const myStore = createStore() myStore.set(transactionResultsAtom, new Map([[transaction.id, createReadOnlyAtomAndTimestamp(transaction)]])) @@ -627,7 +627,7 @@ describe('transaction-page', () => { it('should be rendered with the correct data', () => { vi.mocked(useParams).mockImplementation(() => ({ transactionId: transaction.id })) - vi.mocked(useLoadableNfdResult).mockReturnValue([{ state: 'loading' }]) + vi.mocked(useLoadableNfd).mockReturnValue([{ state: 'loading' }]) const myStore = createStore() myStore.set(transactionResultsAtom, new Map([[transaction.id, createReadOnlyAtomAndTimestamp(transaction)]])) @@ -662,7 +662,7 @@ describe('transaction-page', () => { it('should be rendered with the correct data', () => { vi.mocked(useParams).mockImplementation(() => ({ transactionId: transaction.id })) - vi.mocked(useLoadableNfdResult).mockReturnValue([{ state: 'loading' }]) + vi.mocked(useLoadableNfd).mockReturnValue([{ state: 'loading' }]) const myStore = createStore() myStore.set(transactionResultsAtom, new Map([[transaction.id, createReadOnlyAtomAndTimestamp(transaction)]])) @@ -763,7 +763,7 @@ describe('transaction-page', () => { it('should be rendered with the correct data', () => { vi.mocked(useParams).mockImplementation(() => ({ transactionId: transaction.id, '*': '2' })) - vi.mocked(useLoadableNfdResult).mockReturnValue([{ state: 'loading' }]) + vi.mocked(useLoadableNfd).mockReturnValue([{ state: 'loading' }]) const myStore = createStore() myStore.set(transactionResultsAtom, new Map([[transaction.id, createReadOnlyAtomAndTimestamp(transaction)]])) @@ -895,7 +895,7 @@ describe('transaction-page', () => { it('should be rendered with the correct data', () => { vi.mocked(useParams).mockImplementation(() => ({ transactionId: transaction.id, '*': '2/1' })) - vi.mocked(useLoadableNfdResult).mockReturnValue([{ state: 'loading' }]) + vi.mocked(useLoadableNfd).mockReturnValue([{ state: 'loading' }]) const myStore = createStore() myStore.set(transactionResultsAtom, new Map([[transaction.id, createReadOnlyAtomAndTimestamp(transaction)]])) myStore.set( @@ -933,7 +933,7 @@ describe('transaction-page', () => { it('should be rendered without error', () => { vi.mocked(useParams).mockImplementation(() => ({ transactionId: transaction.id })) - vi.mocked(useLoadableNfdResult).mockReturnValue([{ state: 'loading' }]) + vi.mocked(useLoadableNfd).mockReturnValue([{ state: 'loading' }]) const myStore = createStore() myStore.set(transactionResultsAtom, new Map([[transaction.id, createReadOnlyAtomAndTimestamp(transaction)]])) myStore.set( @@ -965,7 +965,7 @@ describe('transaction-page', () => { it('should be rendered with the correct data', () => { vi.mocked(useParams).mockImplementation(() => ({ transactionId: transaction.id })) - vi.mocked(useLoadableNfdResult).mockReturnValue([{ state: 'loading' }]) + vi.mocked(useLoadableNfd).mockReturnValue([{ state: 'loading' }]) const myStore = createStore() myStore.set(transactionResultsAtom, new Map([[transaction.id, createReadOnlyAtomAndTimestamp(transaction)]])) @@ -1000,7 +1000,7 @@ describe('transaction-page', () => { it('should be rendered with the correct data', () => { vi.mocked(useParams).mockImplementation(() => ({ transactionId: transaction.id })) - vi.mocked(useLoadableNfdResult).mockReturnValue([{ state: 'loading' }]) + vi.mocked(useLoadableNfd).mockReturnValue([{ state: 'loading' }]) const myStore = createStore() myStore.set(transactionResultsAtom, new Map([[transaction.id, createReadOnlyAtomAndTimestamp(transaction)]])) @@ -1063,7 +1063,7 @@ describe('transaction-page', () => { it('should be rendered with the correct data', () => { vi.mocked(useParams).mockImplementation(() => ({ transactionId: transaction.id })) - vi.mocked(useLoadableNfdResult).mockReturnValue([{ state: 'loading' }]) + vi.mocked(useLoadableNfd).mockReturnValue([{ state: 'loading' }]) const myStore = createStore() myStore.set(transactionResultsAtom, new Map([[transaction.id, createReadOnlyAtomAndTimestamp(transaction)]])) @@ -1095,7 +1095,7 @@ describe('transaction-page', () => { it('should be rendered with the correct data', () => { vi.mocked(useParams).mockImplementation(() => ({ transactionId: transaction.id })) - vi.mocked(useLoadableNfdResult).mockReturnValue([{ state: 'loading' }]) + vi.mocked(useLoadableNfd).mockReturnValue([{ state: 'loading' }]) const myStore = createStore() myStore.set(transactionResultsAtom, new Map([[transaction.id, createReadOnlyAtomAndTimestamp(transaction)]])) @@ -1160,7 +1160,7 @@ describe('transaction-page', () => { it('should be rendered correctly', () => { vi.mocked(useParams).mockImplementation(() => ({ transactionId: transaction.id })) - vi.mocked(useLoadableNfdResult).mockReturnValue([{ state: 'loading' }]) + vi.mocked(useLoadableNfd).mockReturnValue([{ state: 'loading' }]) const myStore = createStore() myStore.set(transactionResultsAtom, new Map([[transaction.id, createReadOnlyAtomAndTimestamp(transaction)]])) @@ -1191,7 +1191,7 @@ describe('transaction-page', () => { it('should be rendered with the correct data', () => { vi.mocked(useParams).mockImplementation(() => ({ transactionId: transaction.id })) - vi.mocked(useLoadableNfdResult).mockReturnValue([{ state: 'loading' }]) + vi.mocked(useLoadableNfd).mockReturnValue([{ state: 'loading' }]) const myStore = createStore() myStore.set(transactionResultsAtom, new Map([[transaction.id, createReadOnlyAtomAndTimestamp(transaction)]])) @@ -1229,7 +1229,7 @@ describe('transaction-page', () => { it('should be rendered with the correct data', () => { vi.mocked(useParams).mockImplementation(() => ({ transactionId: transaction.id })) - vi.mocked(useLoadableNfdResult).mockReturnValue([{ state: 'loading' }]) + vi.mocked(useLoadableNfd).mockReturnValue([{ state: 'loading' }]) const myStore = createStore() myStore.set(transactionResultsAtom, new Map([[transaction.id, createReadOnlyAtomAndTimestamp(transaction)]])) @@ -1263,7 +1263,7 @@ describe('when rendering a rekey transaction', () => { it('should be rendered with the correct data', () => { vi.mocked(useParams).mockImplementation(() => ({ transactionId: transaction.id })) - vi.mocked(useLoadableNfdResult).mockReturnValue([{ state: 'loading' }]) + vi.mocked(useLoadableNfd).mockReturnValue([{ state: 'loading' }]) const myStore = createStore() myStore.set(transactionResultsAtom, new Map([[transaction.id, createReadOnlyAtomAndTimestamp(transaction)]])) @@ -1293,7 +1293,7 @@ describe('when rendering an app call transaction with ARC-32 app spec loaded', ( it('should be rendered with the correct data', async () => { vi.mocked(useParams).mockImplementation(() => ({ transactionId: transaction.id })) - vi.mocked(useLoadableNfdResult).mockReturnValue([{ state: 'loading' }]) + vi.mocked(useLoadableNfd).mockReturnValue([{ state: 'loading' }]) const myStore = createStore() myStore.set(genesisHashAtom, 'some-hash') myStore.set(transactionResultsAtom, new Map([[transaction.id, createReadOnlyAtomAndTimestamp(transaction)]])) @@ -1338,7 +1338,7 @@ describe('when rendering an app call transaction with ARC-4 app spec loaded', () it('should be rendered with the correct data', async () => { vi.mocked(useParams).mockImplementation(() => ({ transactionId: transaction.id })) - vi.mocked(useLoadableNfdResult).mockReturnValue([{ state: 'loading' }]) + vi.mocked(useLoadableNfd).mockReturnValue([{ state: 'loading' }]) const myStore = createStore() myStore.set(genesisHashAtom, 'some-hash') diff --git a/src/features/wallet/components/connect-wallet-button.tsx b/src/features/wallet/components/connect-wallet-button.tsx index 41a25b46..6ff1589b 100644 --- a/src/features/wallet/components/connect-wallet-button.tsx +++ b/src/features/wallet/components/connect-wallet-button.tsx @@ -20,7 +20,7 @@ import { walletDialogOpenAtom } from '../data/wallet-dialog' import { clearAvailableWallets } from '../utils/clear-available-wallets' import { useDisconnectWallet } from '../hooks/use-disconnect-wallet' import { CopyButton } from '@/features/common/components/copy-button' -import { useLoadableNfdResult } from '@/features/nfd/data/nfd' +import { useLoadableNfd } from '@/features/nfd/data/nfd' import { RenderLoadable } from '@/features/common/components/render-loadable' export const connectWalletLabel = 'Connect Wallet' @@ -70,7 +70,7 @@ function ConnectedWallet({ activeAddress, connectedActiveAccounts, providers }: }, [activeProvider] ) - const [loadableNfd] = useLoadableNfdResult(activeAddress) + const [loadableNfd] = useLoadableNfd(activeAddress) return ( diff --git a/src/tests/setup/mocks/index.ts b/src/tests/setup/mocks/index.ts index 902f7b2d..d87cd928 100644 --- a/src/tests/setup/mocks/index.ts +++ b/src/tests/setup/mocks/index.ts @@ -88,6 +88,7 @@ vi.mock('@/features/nfd/data/nfd', async () => { const original = await vi.importActual('@/features/nfd/data/nfd') return { ...original, + useLoadableNfd: vi.fn(), useLoadableNfdResult: vi.fn(), } })