From 85a6afc377af8b473e18af86b740519b2c99b2d4 Mon Sep 17 00:00:00 2001 From: MananTank Date: Mon, 13 Oct 2025 21:28:49 +0000 Subject: [PATCH] [MNY-249] Dashboard: //tx/ page UI improvements (#8234) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ## PR-Codex overview This PR focuses on enhancing the `page.tsx` component for transaction details in the dashboard, improving its layout and user experience by introducing new components and restructuring sections for better clarity and functionality. ### Detailed summary - Added `Breadcrumb` for navigation. - Replaced static text with `CopyTextButton` for transaction hash, from, and to addresses. - Introduced `GridItem` component for consistent layout of transaction details. - Enhanced transaction details display with tooltips and icons. - Improved formatting of timestamps and values. - Added sections for transaction fee, gas prices, and burnt fees. - Included input data display using `PlainTextCodeBlock`. > ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}` --- .../(chain)/[chain_id]/tx/[txHash]/page.tsx | 379 +++++++++++++----- 1 file changed, 273 insertions(+), 106 deletions(-) diff --git a/apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/tx/[txHash]/page.tsx b/apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/tx/[txHash]/page.tsx index 30a264f1b78..051758360e4 100644 --- a/apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/tx/[txHash]/page.tsx +++ b/apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/tx/[txHash]/page.tsx @@ -1,13 +1,31 @@ -import { toTokens, ZERO_ADDRESS } from "thirdweb"; +import { Button } from "@workspace/ui/components/button"; +import { PlainTextCodeBlock } from "@workspace/ui/components/code/plaintext-code"; +import { ToolTipLabel } from "@workspace/ui/components/tooltip"; +import { formatDate, formatDistanceToNowStrict, fromUnixTime } from "date-fns"; +import { + CircleAlertIcon, + CircleCheckIcon, + Clock4Icon, + InfoIcon, +} from "lucide-react"; +import { toTokens } from "thirdweb"; import { eth_getBlockByHash, eth_getTransactionByHash, eth_getTransactionReceipt, getRpcClient, } from "thirdweb/rpc"; -import { hexToNumber, shortenAddress, toEther } from "thirdweb/utils"; +import { hexToNumber, toEther } from "thirdweb/utils"; import { Badge } from "@/components/ui/badge"; -import { Separator } from "@/components/ui/separator"; +import { + Breadcrumb, + BreadcrumbItem, + BreadcrumbLink, + BreadcrumbList, + BreadcrumbPage, + BreadcrumbSeparator, +} from "@/components/ui/breadcrumb"; +import { CopyTextButton } from "@/components/ui/CopyTextButton"; import { serverThirdwebClient } from "@/constants/thirdweb-client.server"; import { mapV4ChainToV5Chain } from "@/utils/map-chains"; import { getChain } from "../../../utils"; @@ -40,127 +58,276 @@ export default async function Page(props: { blockHash: transaction.blockHash, }); - return ( -
-
-

Transaction Details

-
- {shortenAddress(transaction.from)} called on{" "} - {shortenAddress(transaction.to || ZERO_ADDRESS)} -
-
+ const timestamp = getDatefromTimestamp(block.timestamp); - + return ( +
+
+ + + + Chainlist + + + + + {chain.name.replace("Mainnet", "")} + + + + + Transaction Details + + + +
-
-
-
Transaction hash
-

{transaction.hash}

-
+
+

+ Transaction Details +

+
-
-
- Status {/* and method */} -
-
- +
+ {/* section 1 */} +
+ - {receipt.status} - -
-
+ + -
-
Block
-

{Number(transaction.blockNumber)}

-
+ + + {receipt.status === "success" ? ( + + ) : ( + + )} + {receipt.status} + + -
-
Timestamp
-

- {new Date( - Number.parseInt(block.timestamp.toString()) * 1000, - ).toLocaleString()} -

-
-
+ {transaction.blockNumber && ( + +

{Number(transaction.blockNumber)}

+
+ )} - + {timestamp && ( + +
+ +

+ {formatDistanceToNowStrict(timestamp, { + addSuffix: true, + })} +

+

({formatDate(timestamp, "PP pp z")})

+
+
+ )} + -
-
-
From
-

{transaction.from}

-
+ {/* section 2 */} +
+ + + -
-
- Interacted with contract -
-

{transaction.to}

-
-
+ {transaction.to && ( + + + + )} +
- + {/* section 3 */} +
+ +

+ {toEther(transaction.value)} {chain.nativeCurrency?.symbol} +

+
-
-
-
Value
-

{toEther(transaction.value)} ETH

-
+ +

+ {toEther((transaction.gasPrice || 0n) * receipt.gasUsed)}{" "} + {chain.nativeCurrency?.symbol} +

+
-
-
Transaction fee
-

{toEther((transaction.gasPrice || 0n) * receipt.gasUsed)} ETH

-
+ +

+ {toEther(transaction.gasPrice || 0n)}{" "} + {chain.nativeCurrency?.symbol} +

+
-
-
Gas price
-

{toEther(transaction.gasPrice || 0n)} ETH

-
+ +

{receipt.gasUsed.toString()}

+
-
-
Gas usage
-

{receipt.gasUsed.toString()}

-
+ +

+ Base: {toTokens(block.baseFeePerGas || 0n, 9)} Gwei -

-
Gas fees (Gwei)
-

- Base: {toTokens(block.baseFeePerGas || 0n, 9)} | Max:{" "} - {toTokens(transaction.maxFeePerGas || 0n, 9)} | Max priority:{" "} - {transaction.maxPriorityFeePerGas?.toString()} -

-
+ {transaction.maxFeePerGas && ( + <> + | + + Max: {toTokens(transaction.maxFeePerGas || 0n, 9)} Gwei + + + )} -
-
Burnt fees
-

{toEther(block.baseFeePerGas || 0n * receipt.gasUsed)}

-
-
- - - -
-
-
Other
-

- Txn type: {hexToNumber(transaction.typeHex || "0x0")} ( - {transaction.type}) | Nonce: {transaction.nonce} | Position:{" "} - {transaction.transactionIndex} -

-
+ {transaction.maxPriorityFeePerGas && ( + <> + | + + Max priority:{" "} + {transaction.maxPriorityFeePerGas?.toString()} Gwei + + + )} +

+ + + +

{toEther(block.baseFeePerGas || 0n * receipt.gasUsed)}

+
+
+ + {/* section 4 */} +
+ +
+ + Txn type: + + {hexToNumber(transaction.typeHex || "0x0")} ( + {transaction.type}) + + + + Nonce: + {transaction.nonce} + + + Position: + {transaction.transactionIndex} + +
+
-
-
Raw Input:
-
- {transaction.input} -
+ + + +
-
+
); } + +function GridItem(props: { + label: string; + children: React.ReactNode; + tooltip?: string; +}) { + return ( +
+
+ + + +

{props.label}

+
+
{props.children}
+
+ ); +} + +function getDatefromTimestamp(timestamp: bigint) { + try { + return fromUnixTime(Number(timestamp)); + } catch { + return undefined; + } +}