1+ import { WalletAddress } from "@/components/blocks/wallet-address" ;
12import { CopyTextButton } from "@/components/ui/CopyTextButton" ;
23import { Spinner } from "@/components/ui/Spinner/Spinner" ;
34import { Button } from "@/components/ui/button" ;
4- import { CodeClient } from "@/components/ui/code/code.client " ;
5+ import { cn } from "@/lib/utils " ;
56import type { Account as TWAccount } from "@3rdweb-sdk/react/hooks/useApi" ;
67import {
78 ArrowRightLeftIcon ,
@@ -15,10 +16,12 @@ import { useState } from "react";
1516import {
1617 type ThirdwebClient ,
1718 prepareTransaction ,
19+ toEther ,
1820 waitForReceipt ,
1921} from "thirdweb" ;
20- import { useSendTransaction } from "thirdweb/react" ;
22+ import { useActiveAccount , useSendTransaction } from "thirdweb/react" ;
2123import { TransactionButton } from "../../../../components/buttons/TransactionButton" ;
24+ import { ChainIconClient } from "../../../../components/icons/ChainIcon" ;
2225import { useTrack } from "../../../../hooks/analytics/useTrack" ;
2326import { useV5DashboardChain } from "../../../../lib/v5-adapter" ;
2427import { getSDKTheme } from "../../../components/sdk-component-theme" ;
@@ -76,29 +79,157 @@ export function ExecuteTransactionCardLayout(props: {
7679 } ,
7780 } ) ;
7881 const chain = useV5DashboardChain ( txData . chainId ) ;
79- const isTransactionSent =
80- props . status . type === "confirming" || props . status . type === "confirmed" ;
8182 const trackEvent = useTrack ( ) ;
83+ const account = useActiveAccount ( ) ;
8284
8385 const explorer = chain . blockExplorers ?. [ 0 ] ?. url ;
8486
87+ const isTransactionPending =
88+ props . status . type === "sending" || props . status . type === "confirming" ;
89+
8590 return (
8691 < div >
8792 < div className = "rounded-xl border bg-card" >
88- < div className = "flex flex-col gap-4 p-4 pb-6" >
89- < h3 className = "font-semibold text-foreground text-lg tracking-tight" >
90- Transaction
91- </ h3 >
93+ { /* header */ }
94+ < h3 className = "border-b p-4 py-4 font-semibold text-foreground text-lg tracking-tight lg:px-6 lg:text-xl" >
95+ Transaction
96+ </ h3 >
97+
98+ { /* content */ }
99+ < div className = "px-4 text-sm lg:px-6 [&>*]:h-12 [&>*]:border-b lg:[&>*]:h-14" >
100+ { /* From */ }
101+ < div className = "flex items-center justify-between gap-2" >
102+ < span className = "text-muted-foreground" > From</ span >
103+ { account ? (
104+ < WalletAddress
105+ address = { account . address }
106+ className = "h-auto py-0"
107+ iconClassName = "size-5"
108+ />
109+ ) : (
110+ < span className = "text-muted-foreground" > Your Wallet</ span >
111+ ) }
112+ </ div >
113+
114+ { /* To */ }
115+ { txData . to && (
116+ < div className = "flex items-center justify-between gap-2" >
117+ < span className = "text-muted-foreground" > To</ span >
118+
119+ < WalletAddress
120+ address = { txData . to }
121+ className = "h-auto py-0"
122+ iconClassName = "size-5"
123+ />
124+ </ div >
125+ ) }
126+
127+ { /* Value */ }
128+ < div className = "flex items-center justify-between gap-2" >
129+ < span className = "text-muted-foreground" > Value</ span >
130+ { toEther ( BigInt ( txData . value ) ) } { chain . nativeCurrency ?. symbol }
131+ </ div >
132+
133+ { /* Network */ }
134+ < div className = "flex items-center justify-between gap-2" >
135+ < span className = "text-muted-foreground" > Network</ span >
136+ < div className = "flex items-center gap-2" >
137+ < ChainIconClient
138+ className = "size-5 rounded-full"
139+ src = { chain . icon ?. url }
140+ />
141+ < span className = "text-foreground" >
142+ { chain . name || `Chain ID: ${ txData . chainId } ` }
143+ </ span >
144+ </ div >
145+ </ div >
146+
147+ { /* Status */ }
148+ { props . status . type !== "idle" && (
149+ < div className = "flex items-center justify-between gap-2" >
150+ < span className = "text-muted-foreground" > Status</ span >
151+ < div className = "flex items-center gap-2" >
152+ < span
153+ className = { cn (
154+ "flex items-center gap-2 font-medium" ,
155+ props . status . type === "sending" && "text-blue-500" ,
156+ props . status . type === "confirming" && "text-yellow-500" ,
157+ props . status . type === "confirmed" && "text-green-500" ,
158+ props . status . type === "failed" && "text-red-500" ,
159+ ) }
160+ >
161+ { /* icon */ }
162+ { ( props . status . type === "sending" ||
163+ props . status . type === "confirming" ) && (
164+ < Spinner className = "size-4" />
165+ ) }
92166
93- < CodeClient code = { JSON . stringify ( txData , null , 2 ) } lang = "json" />
167+ { props . status . type === "confirmed" && (
168+ < CircleCheckIcon className = "size-4" />
169+ ) }
170+
171+ { props . status . type === "failed" && (
172+ < CircleXIcon className = "size-4" />
173+ ) }
174+
175+ { /* text */ }
176+ < span >
177+ { props . status . type === "sending" && "Sending Transaction" }
178+ { props . status . type === "confirming" &&
179+ "Waiting for Confirmation" }
180+ { props . status . type === "confirmed" &&
181+ "Transaction Confirmed" }
182+ { props . status . type === "failed" && "Transaction Failed" }
183+ </ span >
184+ </ span >
185+ </ div >
186+ </ div >
187+ ) }
188+
189+ { /* Transaction Hash */ }
190+ { "txHash" in props . status && props . status . txHash && (
191+ < div className = "flex items-center justify-between gap-1" >
192+ < span className = "text-muted-foreground" > Transaction Hash</ span >
193+ < div className = "flex justify-end gap-2.5" >
194+ { explorer ? (
195+ < Button
196+ asChild
197+ variant = "ghost"
198+ size = "sm"
199+ className = "gap-1.5 font-mono"
200+ >
201+ < Link
202+ href = { `${ explorer } /tx/${ props . status . txHash } ` }
203+ target = "_blank"
204+ >
205+ { `${ props . status . txHash . slice ( 0 , 6 ) } ...${ props . status . txHash . slice ( - 4 ) } ` }
206+ < ExternalLinkIcon className = "size-3" />
207+ </ Link >
208+ </ Button >
209+ ) : (
210+ < CopyTextButton
211+ textToCopy = { props . status . txHash }
212+ textToShow = { `${ props . status . txHash . slice ( 0 , 6 ) } ...${ props . status . txHash . slice ( - 4 ) } ` }
213+ variant = "ghost"
214+ className = "font-mono"
215+ copyIconPosition = "right"
216+ tooltip = "Copy Transaction Hash"
217+ />
218+ ) }
219+ </ div >
220+ </ div >
221+ ) }
94222 </ div >
95223
96- < div className = "flex items-center justify-end border-t p-4" >
224+ { /* footer */ }
225+ < div className = "flex items-center justify-end px-4 py-6 lg:px-6" >
97226 < TransactionButton
98227 isPending = { sendTransaction . isPending }
99228 transactionCount = { undefined }
100229 txChainID = { txData . chainId }
101230 variant = "default"
231+ disabled = { isTransactionPending }
232+ size = "sm"
102233 onClick = { async ( ) => {
103234 trackEvent ( {
104235 category : "nebula" ,
@@ -164,72 +295,6 @@ export function ExecuteTransactionCardLayout(props: {
164295 </ TransactionButton >
165296 </ div >
166297 </ div >
167-
168- { /* Tx Status */ }
169- { props . status . type !== "idle" && (
170- < div className = "mt-5 rounded-lg border bg-card" >
171- < div className = "flex flex-col gap-1.5 p-4" >
172- { props . status . type === "sending" && (
173- < div className = "flex items-center gap-2 text-link-foreground" >
174- < Spinner className = "size-4" />
175- < p > Sending Transaction </ p >
176- </ div >
177- ) }
178-
179- { isTransactionSent && (
180- < div className = "flex items-center gap-2 text-success-text" >
181- < CircleCheckIcon className = "size-4" />
182- < p > Transaction Sent </ p >
183- </ div >
184- ) }
185-
186- { props . status . type === "confirming" && (
187- < div className = "flex items-center gap-2 text-link-foreground" >
188- < Spinner className = "size-4" />
189- < p > Confirming Transaction </ p >
190- </ div >
191- ) }
192-
193- { props . status . type === "confirmed" && (
194- < div className = "flex items-center gap-2 text-success-text" >
195- < CircleCheckIcon className = "size-4" />
196- < p > Transaction Confirmed </ p >
197- </ div >
198- ) }
199-
200- { props . status . type === "failed" && (
201- < div className = "flex items-center gap-2 text-destructive-text" >
202- < CircleXIcon className = "size-4" />
203- < p > Transaction Failed </ p >
204- </ div >
205- ) }
206- </ div >
207-
208- { "txHash" in props . status && props . status . txHash && (
209- < div className = "flex justify-end gap-2.5 border-t p-4" >
210- { explorer && (
211- < Button asChild variant = "outline" size = "sm" className = "gap-2 " >
212- < Link
213- href = { `${ explorer } /tx/${ props . status . txHash } ` }
214- target = "_blank"
215- >
216- View on Explorer
217- < ExternalLinkIcon className = "size-3" />
218- </ Link >
219- </ Button >
220- ) }
221- < CopyTextButton
222- textToCopy = { props . status . txHash }
223- className = ""
224- textToShow = "Transaction Hash"
225- variant = "outline"
226- copyIconPosition = "right"
227- tooltip = "Copy Transaction Hash"
228- />
229- </ div >
230- ) }
231- </ div >
232- ) }
233298 </ div >
234299 ) ;
235300}
0 commit comments