First working iteration of sender/nonce navigation
This commit is contained in:
parent
75a37f79d3
commit
47cbe36c8f
|
@ -1,5 +1,6 @@
|
|||
import React from "react";
|
||||
import { NavLink } from "react-router-dom";
|
||||
import { transactionURL } from "../url";
|
||||
|
||||
type TransactionLinkProps = {
|
||||
txHash: string;
|
||||
|
@ -8,7 +9,7 @@ type TransactionLinkProps = {
|
|||
const TransactionLink: React.FC<TransactionLinkProps> = ({ txHash }) => (
|
||||
<NavLink
|
||||
className="text-link-blue hover:text-link-blue-hover font-hash"
|
||||
to={`/tx/${txHash}`}
|
||||
to={transactionURL(txHash)}
|
||||
>
|
||||
<p className="truncate">{txHash}</p>
|
||||
</NavLink>
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
export const MIN_API_LEVEL = 5;
|
||||
export const MIN_API_LEVEL = 6;
|
||||
|
||||
export const PAGE_SIZE = 25;
|
||||
|
|
|
@ -15,6 +15,7 @@ import BlockConfirmations from "../components/BlockConfirmations";
|
|||
import TransactionAddress from "../components/TransactionAddress";
|
||||
import Copy from "../components/Copy";
|
||||
import Nonce from "../components/Nonce";
|
||||
import NavNonce from "./NavNonce";
|
||||
import Timestamp from "../components/Timestamp";
|
||||
import InternalTransactionOperation from "../components/InternalTransactionOperation";
|
||||
import MethodName from "../components/MethodName";
|
||||
|
@ -253,6 +254,11 @@ const Details: React.FC<DetailsProps> = ({
|
|||
</div>
|
||||
<div className="flex items-baseline pl-3">
|
||||
<Nonce value={txData.nonce} />
|
||||
<NavNonce
|
||||
sender={txData.from}
|
||||
nonce={txData.nonce}
|
||||
latestBlockNumber={undefined}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</InfoRow>
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
import { NavLink } from "react-router-dom";
|
||||
import { transactionURL } from "../url";
|
||||
|
||||
// TODO: extract common component with block/NavButton
|
||||
type NavButtonProps = {
|
||||
txHash: string | undefined;
|
||||
disabled?: boolean;
|
||||
};
|
||||
|
||||
const NavButton: React.FC<NavButtonProps> = ({
|
||||
txHash,
|
||||
disabled,
|
||||
children,
|
||||
}) => {
|
||||
if (disabled || txHash === undefined) {
|
||||
return (
|
||||
<span className="bg-link-blue bg-opacity-10 text-gray-400 rounded px-2 py-1 text-xs">
|
||||
{children}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<NavLink
|
||||
className="transition-colors bg-link-blue bg-opacity-10 text-link-blue hover:bg-opacity-100 hover:text-white disabled:bg-link-blue disabled:text-gray-400 disabled:cursor-default rounded px-2 py-1 text-xs"
|
||||
to={transactionURL(txHash)}
|
||||
>
|
||||
{children}
|
||||
</NavLink>
|
||||
);
|
||||
};
|
||||
|
||||
export default NavButton;
|
|
@ -0,0 +1,56 @@
|
|||
import React, { useContext } from "react";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { faChevronLeft } from "@fortawesome/free-solid-svg-icons/faChevronLeft";
|
||||
import { faChevronRight } from "@fortawesome/free-solid-svg-icons/faChevronRight";
|
||||
import NavButton from "./NavButton";
|
||||
import { ChecksummedAddress } from "../types";
|
||||
import { RuntimeContext } from "../useRuntime";
|
||||
import { useTransactionBySenderAndNonce } from "../useErigonHooks";
|
||||
|
||||
type NavNonceProps = {
|
||||
sender: ChecksummedAddress;
|
||||
nonce: number;
|
||||
latestBlockNumber: number | undefined;
|
||||
};
|
||||
|
||||
const NavNonce: React.FC<NavNonceProps> = ({
|
||||
sender,
|
||||
nonce,
|
||||
latestBlockNumber,
|
||||
}) => {
|
||||
const { provider } = useContext(RuntimeContext);
|
||||
const prevTxHash = useTransactionBySenderAndNonce(
|
||||
provider,
|
||||
sender,
|
||||
nonce - 1
|
||||
);
|
||||
const nextTxHash = useTransactionBySenderAndNonce(
|
||||
provider,
|
||||
sender,
|
||||
nonce + 1
|
||||
);
|
||||
const lastTxHash = nextTxHash;
|
||||
|
||||
return (
|
||||
<div className="pl-2 self-center flex space-x-1">
|
||||
<NavButton txHash={prevTxHash} disabled={nonce === 0}>
|
||||
<FontAwesomeIcon icon={faChevronLeft} />
|
||||
</NavButton>
|
||||
<NavButton
|
||||
txHash={nextTxHash}
|
||||
disabled={latestBlockNumber === undefined || nonce >= latestBlockNumber}
|
||||
>
|
||||
<FontAwesomeIcon icon={faChevronRight} />
|
||||
</NavButton>
|
||||
<NavButton
|
||||
txHash={lastTxHash}
|
||||
disabled={latestBlockNumber === undefined || nonce >= latestBlockNumber}
|
||||
>
|
||||
<FontAwesomeIcon icon={faChevronRight} />
|
||||
<FontAwesomeIcon icon={faChevronRight} />
|
||||
</NavButton>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default React.memo(NavNonce);
|
|
@ -18,6 +18,8 @@ export const blockURL = (blockNum: BlockTag) => `/block/${blockNum}`;
|
|||
|
||||
export const blockTxsURL = (blockNum: BlockTag) => `/block/${blockNum}/txs`;
|
||||
|
||||
export const transactionURL = (txHash: string) => `/tx/${txHash}`;
|
||||
|
||||
export enum SourcifySource {
|
||||
// Resolve trusted IPNS for root IPFS
|
||||
IPFS_IPNS,
|
||||
|
|
|
@ -502,3 +502,43 @@ export const useTransactionError = (
|
|||
|
||||
return [errorMsg, data, isCustomError];
|
||||
};
|
||||
|
||||
export const useTransactionBySenderAndNonce = (
|
||||
provider: JsonRpcProvider | undefined,
|
||||
sender: ChecksummedAddress | undefined,
|
||||
nonce: number | undefined
|
||||
): string | undefined => {
|
||||
const [txHash, setTxHash] = useState<string | undefined>();
|
||||
|
||||
useEffect(() => {
|
||||
// Reset
|
||||
setTxHash(undefined);
|
||||
|
||||
if (
|
||||
provider === undefined ||
|
||||
sender === undefined ||
|
||||
nonce === undefined ||
|
||||
nonce < 0
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
const readTxHash = async () => {
|
||||
const result = (await provider.send(
|
||||
"ots_getTransactionBySenderAndNonce",
|
||||
[sender, nonce]
|
||||
)) as string;
|
||||
|
||||
// Empty or success
|
||||
if (result === "0x") {
|
||||
setTxHash(undefined);
|
||||
return;
|
||||
}
|
||||
|
||||
setTxHash(result);
|
||||
};
|
||||
readTxHash();
|
||||
}, [provider, sender, nonce]);
|
||||
|
||||
return txHash;
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue