Skip to content

Commit 02f74a8

Browse files
authored
Added functionality to search by version or by tx hash
1 parent 69a8af7 commit 02f74a8

6 files changed

Lines changed: 118 additions & 33 deletions

File tree

web-app/src/modules/core/routes/Account/AccountDoesntExist.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ const AccountDoesntExist: FC<Props> = ({ address }) => {
2020
The crypto account associated with the specified address (
2121
<span className="font-mono">{address}</span>) could not be found.
2222
<br />
23-
This may be because the account was recently created and our system is still updating.
23+
This may be because the account was recently created and our system is still indexing it.
2424
<br />
2525
<br />
2626
<span className="text-sm font-medium text-red-800 text-xl">

web-app/src/modules/core/routes/Transaction/BlockMetadataTransactionDetails.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ const BlockMetadataTransactionDetails: FC<Props> = ({ transaction }) => {
1414
return (
1515
<DetailsTable>
1616
<DetailRow label="Type" value="Block Metadata" />
17+
<DetailRow label="Version" value={transaction.version} />
1718
<DetailRow label="Hash" value={transaction.hash} />
1819
<DetailRow label="State Change Hash" value={transaction.state_change_hash} />
1920
<DetailRow label="Event Root Hash" value={transaction.event_root_hash} />

web-app/src/modules/core/routes/Transaction/StateCheckpointTransactionDetails.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ const StateCheckpointTransactionDetails: FC<Props> = ({ transaction }) => {
1313
return (
1414
<DetailsTable>
1515
<DetailRow label="Type" value="State Checkpoint" />
16+
<DetailRow label="Version" value={transaction.version} />
1617
<DetailRow label="Hash" value={transaction.hash} />
1718
<DetailRow label="State Change Hash" value={transaction.state_change_hash} />
1819
<DetailRow label="Event Root Hash" value={transaction.event_root_hash} />

web-app/src/modules/core/routes/Transaction/Transaction.tsx

Lines changed: 63 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { FC, useEffect, useState } from 'react';
2-
import { useParams } from 'react-router-dom';
2+
import { useParams, useNavigate } from 'react-router-dom';
33
import Page from '../../../ui/Page/Page';
44
import useAptos from '../../../aptos';
55
import { Types } from 'aptos';
@@ -10,20 +10,78 @@ import StateCheckpointTransactionDetails from './StateCheckpointTransactionDetai
1010
const Transaction: FC = () => {
1111
const { version } = useParams();
1212
const [transaction, setTransaction] = useState<Types.Transaction>();
13+
const [loading, setLoading] = useState<boolean>(true);
14+
const [error, setError] = useState<string | null>(null);
1315

1416
const aptos = useAptos();
17+
const navigate = useNavigate();
1518

1619
useEffect(() => {
1720
const load = async () => {
18-
const transaction = await aptos.getTransactionByVersion(parseInt(version!, 10));
19-
setTransaction(transaction);
21+
if (!version) return;
22+
23+
try {
24+
setLoading(true);
25+
setError(null);
26+
27+
let txn: Types.Transaction;
28+
29+
// Check if it's a hash (0x + 64 hex chars)
30+
if (version.startsWith('0x') && version.length === 66 && /^0x[0-9a-fA-F]{64}$/.test(version)) {
31+
try {
32+
txn = await aptos.getTransactionByHash(version);
33+
setTransaction(txn);
34+
} catch (txError) {
35+
console.error('Error loading transaction by hash:', txError);
36+
37+
// If transaction not found, check if it's a valid account address (v6 onward format)
38+
try {
39+
await aptos.getAccount(version);
40+
// If account exists, redirect to account page
41+
navigate(`/accounts/${encodeURIComponent(version)}/resources`);
42+
return;
43+
} catch (acctError) {
44+
// Neither a valid transaction nor account
45+
throw txError; // Re-throw the original error
46+
}
47+
}
48+
}
49+
// Otherwise treat as version number
50+
else if (/^\d+$/.test(version)) {
51+
try {
52+
txn = await aptos.getTransactionByVersion(parseInt(version, 10));
53+
setTransaction(txn);
54+
} catch (txError) {
55+
console.error('Error loading transaction by version:', txError);
56+
throw txError;
57+
}
58+
}
59+
// Invalid format
60+
else {
61+
throw new Error('Invalid transaction identifier format');
62+
}
63+
} catch (err) {
64+
console.error('Error loading transaction:', err);
65+
setError(`Failed to load transaction: ${err instanceof Error ? err.message : 'Unknown error'}`);
66+
} finally {
67+
setLoading(false);
68+
}
2069
};
70+
2171
load();
22-
}, [version]);
72+
}, [version, navigate]);
2373

2474
return (
2575
<Page title={`Transaction: ${version}`} __deprecated_grayBg>
26-
{transaction && (
76+
{loading && <div className="text-center p-4">Loading transaction...</div>}
77+
78+
{error && (
79+
<div className="p-4 bg-red-50 text-red-700 rounded border border-red-200">
80+
{error}
81+
</div>
82+
)}
83+
84+
{transaction && !loading && !error && (
2785
<div>
2886
{transaction.type === 'block_metadata_transaction' && (
2987
<BlockMetadataTransactionDetails

web-app/src/modules/core/routes/Transaction/UserTransactionDetails.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ const UserTransactionDetails: FC<Props> = ({ transaction }) => {
1414
return (
1515
<DetailsTable>
1616
<DetailRow label="Type" value="User Transaction" />
17+
<DetailRow label="Version" value={transaction.version} />
1718
<DetailRow label="Hash" value={transaction.hash} />
1819
<DetailRow label="State Change Hash" value={transaction.state_change_hash} />
1920
<DetailRow label="Event Root Hash" value={transaction.event_root_hash} />

web-app/src/modules/ui/Layout/Header/Header.tsx

Lines changed: 51 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -34,15 +34,39 @@ const Header: React.FC = () => {
3434

3535
const input = searchAddress.trim();
3636

37+
// Don't process empty searches
38+
if (!input) return;
39+
3740
try {
41+
// Check if it's a transaction hash (0x + 64 hex chars)
42+
if (input.startsWith('0x') && input.length === 66 && /^0x[0-9a-fA-F]{64}$/.test(input)) {
43+
navigate(`/transactions/${encodeURIComponent(input)}`);
44+
setSearchAddress('');
45+
if (searchInput.current) {
46+
searchInput.current.blur();
47+
}
48+
return;
49+
}
50+
51+
// Check if it's a transaction version (numeric only)
52+
if (/^\d+$/.test(input)) {
53+
navigate(`/transactions/${encodeURIComponent(input)}`);
54+
setSearchAddress('');
55+
if (searchInput.current) {
56+
searchInput.current.blur();
57+
}
58+
return;
59+
}
60+
61+
// Default case: treat as an account address
3862
const addr = normalizeAddress(input);
3963
navigate(`/accounts/${encodeURIComponent(addr)}/resources`);
4064
setSearchAddress('');
4165
if (searchInput.current) {
4266
searchInput.current.blur();
4367
}
4468
} catch (error) {
45-
console.warn(error);
69+
console.warn('Search error:', error);
4670
}
4771
};
4872

@@ -75,7 +99,30 @@ const Header: React.FC = () => {
7599
))}
76100
</div>
77101

78-
<div className="justify-end items-center gap-2 hidden justify-self-end lg:flex">
102+
<div className="justify-end items-center gap-2 hidden justify-self-end lg:flex flex-grow">
103+
<form className="w-full max-w-2xl" onSubmit={onSearch}>
104+
<div className="relative text-gray-400 focus-within:text-gray-600">
105+
<div className="pointer-events-none absolute inset-y-0 left-0 flex items-center pl-3">
106+
<MagnifyingGlassIcon className="h-5 w-5" aria-hidden="true" />
107+
</div>
108+
<input
109+
id="search"
110+
className={clsx(
111+
'ring-1',
112+
'block w-full rounded-md border-0 bg-white py-1.5 pl-10 pr-3',
113+
'text-gray-900 text-sm',
114+
'focus:ring-2 ring-white ring-offset-2 ring-offset-primary-600',
115+
)}
116+
placeholder="Search Address / Hash / Version"
117+
type="search"
118+
name="search"
119+
ref={searchInput}
120+
value={searchAddress}
121+
onChange={(event) => setSearchAddress(event.target.value)}
122+
/>
123+
</div>
124+
</form>
125+
79126
{localStorage.getItem('postero_enabled') === 'true' && (
80127
<div className="flex items-baseline gap-2">
81128
<div className="flex items-baseline space-x-4">
@@ -109,29 +156,6 @@ const Header: React.FC = () => {
109156
</div>
110157
</div>
111158
)}
112-
113-
<form className="w-full max-w-xs" onSubmit={onSearch}>
114-
<div className="relative text-gray-400 focus-within:text-gray-600">
115-
<div className="pointer-events-none absolute inset-y-0 left-0 flex items-center pl-3">
116-
<MagnifyingGlassIcon className="h-5 w-5" aria-hidden="true" />
117-
</div>
118-
<input
119-
id="search"
120-
className={clsx(
121-
'ring-1',
122-
'block w-full rounded-md border-0 bg-white py-1 pl-10 pr-3',
123-
'text-gray-900 text-sm',
124-
'focus:ring-2 ring-white ring-offset-2 ring-offset-primary-600',
125-
)}
126-
placeholder="Search Address"
127-
type="search"
128-
name="search"
129-
ref={searchInput}
130-
value={searchAddress}
131-
onChange={(event) => setSearchAddress(event.target.value)}
132-
/>
133-
</div>
134-
</form>
135159
</div>
136160

137161
<div className="flex flex-grow justify-end lg:hidden">
@@ -179,11 +203,11 @@ const Header: React.FC = () => {
179203
id="search"
180204
className={clsx(
181205
'ring-1',
182-
'block w-full rounded-md border-0 bg-white py-1 pl-10 pr-3',
206+
'block w-full rounded-md border-0 bg-white py-1.5 pl-10 pr-3',
183207
'text-gray-900 text-sm',
184208
'focus:ring-2 ring-white ring-offset-2 ring-offset-primary-600',
185209
)}
186-
placeholder="Search Address"
210+
placeholder="Search Address / Hash / Version"
187211
type="search"
188212
name="search"
189213
ref={searchInput}

0 commit comments

Comments
 (0)