Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions apps/dashboard/src/@/components/blocks/NetworkSelectors.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { MultiSelect } from "@/components/blocks/multi-select";
import { SelectWithSearch } from "@/components/blocks/select-with-search";
import { Badge } from "@/components/ui/badge";
import { useCallback, useMemo } from "react";
import { ChainIcon } from "../../../components/icons/ChainIcon";
import { ChainIconClient } from "../../../components/icons/ChainIcon";
import { useAllChainsData } from "../../../hooks/chains/allChains";

function cleanChainName(chainName: string) {
Expand Down Expand Up @@ -77,7 +77,7 @@ export function MultiNetworkSelector(props: {
return (
<div className="flex justify-between gap-4">
<span className="flex grow gap-2 truncate text-left">
<ChainIcon
<ChainIconClient
className="size-5"
ipfsSrc={chain.icon?.url}
loading="lazy"
Expand Down Expand Up @@ -172,7 +172,7 @@ export function SingleNetworkSelector(props: {
return (
<div className="flex justify-between gap-4">
<span className="flex grow gap-2 truncate text-left">
<ChainIcon
<ChainIconClient
className="size-5"
ipfsSrc={chain.icon?.url}
loading="lazy"
Expand Down
18 changes: 15 additions & 3 deletions apps/dashboard/src/@/components/blocks/wallet-address.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export function WalletAddress(props: {
address: string | undefined;
shortenAddress?: boolean;
className?: string;
iconClassName?: string;
}) {
const thirdwebClient = useThirdwebClient();
// default back to zero address if no address provided
Expand Down Expand Up @@ -78,6 +79,7 @@ export function WalletAddress(props: {
address={address}
profiles={profiles.data || []}
thirdwebClient={thirdwebClient}
iconClassName={props.iconClassName}
/>
)}
<span className="cursor-pointer font-mono">
Expand Down Expand Up @@ -168,6 +170,7 @@ function WalletAvatar(props: {
address: string;
profiles: SocialProfile[];
thirdwebClient: ThirdwebClient;
iconClassName?: string;
}) {
const avatar = useMemo(() => {
return props.profiles.find(
Expand All @@ -186,11 +189,20 @@ function WalletAvatar(props: {
: undefined;

return (
<div className="size-6 overflow-hidden rounded-full">
<div
className={cn("size-6 overflow-hidden rounded-full", props.iconClassName)}
>
{resolvedAvatarSrc ? (
<Img src={resolvedAvatarSrc} className="size-6 object-cover" />
<Img
src={resolvedAvatarSrc}
className={cn("size-6 object-cover", props.iconClassName)}
/>
) : (
<Blobbie address={props.address} size={24} />
<Blobbie
address={props.address}
size={24}
className={props.iconClassName}
/>
)}
</div>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import { CopyAddressButton } from "@/components/ui/CopyAddressButton";
import { Button } from "@/components/ui/button";
import { getThirdwebClient } from "@/constants/thirdweb.server";
import { ChainIcon } from "components/icons/ChainIcon";
import { ChainIconClient } from "components/icons/ChainIcon";
import { ExternalLinkIcon } from "lucide-react";
import Link from "next/link";
import type { ChainMetadata } from "thirdweb/chains";
Expand Down Expand Up @@ -85,7 +85,7 @@ export const MetadataHeader: React.FC<MetadataHeaderProps> = ({
href={`/${chain.slug}`}
className="flex w-fit shrink-0 items-center gap-2 rounded-3xl border border-border bg-card px-2.5 py-1.5 hover:bg-accent"
>
<ChainIcon ipfsSrc={chain.icon?.url} className="size-4" />
<ChainIconClient ipfsSrc={chain.icon?.url} className="size-4" />
{cleanedChainName && (
<span className="text-xs">{cleanedChainName}</span>
)}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { SelectWithSearch } from "@/components/blocks/select-with-search";
import { Badge } from "@/components/ui/badge";
import { ChainIcon } from "components/icons/ChainIcon";
import { ChainIconClient } from "components/icons/ChainIcon";
import { useAllChainsData } from "hooks/chains/allChains";
import { useCallback, useMemo } from "react";

Expand Down Expand Up @@ -45,7 +45,7 @@ export function SingleNetworkSelector(props: {
return (
<div className="flex justify-between gap-4">
<span className="flex grow gap-2 truncate text-left">
<ChainIcon
<ChainIconClient
className="size-5"
ipfsSrc={chain.icon?.url}
loading="lazy"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,9 +71,9 @@ function Variant(props: {
twAccount={accountStub()}
txData={{
chainId: 1,
to: "0x1F846F6DAE38E1C88D71EAA191760B15f38B7A37",
to: "0xEb0effdFB4dC5b3d5d3aC6ce29F3ED213E95d675", // thirdweb.eth
data: "0x",
value: "0x16345785d8a0000",
value: "0x16345785d8a0000", // 0.1 eth
}}
/>
</BadgeContainer>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { WalletAddress } from "@/components/blocks/wallet-address";
import { CopyTextButton } from "@/components/ui/CopyTextButton";
import { Spinner } from "@/components/ui/Spinner/Spinner";
import { Button } from "@/components/ui/button";
import { CodeClient } from "@/components/ui/code/code.client";
import { cn } from "@/lib/utils";
import type { Account as TWAccount } from "@3rdweb-sdk/react/hooks/useApi";
import {
ArrowRightLeftIcon,
Expand All @@ -15,10 +16,12 @@ import { useState } from "react";
import {
type ThirdwebClient,
prepareTransaction,
toEther,
waitForReceipt,
} from "thirdweb";
import { useSendTransaction } from "thirdweb/react";
import { useActiveAccount, useSendTransaction } from "thirdweb/react";
import { TransactionButton } from "../../../../components/buttons/TransactionButton";
import { ChainIconClient } from "../../../../components/icons/ChainIcon";
import { useTrack } from "../../../../hooks/analytics/useTrack";
import { useV5DashboardChain } from "../../../../lib/v5-adapter";
import { getSDKTheme } from "../../../components/sdk-component-theme";
Expand Down Expand Up @@ -76,29 +79,157 @@ export function ExecuteTransactionCardLayout(props: {
},
});
const chain = useV5DashboardChain(txData.chainId);
const isTransactionSent =
props.status.type === "confirming" || props.status.type === "confirmed";
const trackEvent = useTrack();
const account = useActiveAccount();

const explorer = chain.blockExplorers?.[0]?.url;

const isTransactionPending =
props.status.type === "sending" || props.status.type === "confirming";

return (
<div>
<div className="rounded-xl border bg-card">
<div className="flex flex-col gap-4 p-4 pb-6">
<h3 className="font-semibold text-foreground text-lg tracking-tight">
Transaction
</h3>
{/* header */}
<h3 className="border-b p-4 py-4 font-semibold text-foreground text-lg tracking-tight lg:px-6 lg:text-xl">
Transaction
</h3>

{/* content */}
<div className="px-4 text-sm lg:px-6 [&>*]:h-12 [&>*]:border-b lg:[&>*]:h-14">
{/* From */}
<div className="flex items-center justify-between gap-2">
<span className="text-muted-foreground">From</span>
{account ? (
<WalletAddress
address={account.address}
className="h-auto py-0"
iconClassName="size-5"
/>
) : (
<span className="text-muted-foreground">Your Wallet</span>
)}
</div>

{/* To */}
{txData.to && (
<div className="flex items-center justify-between gap-2">
<span className="text-muted-foreground">To</span>

<WalletAddress
address={txData.to}
className="h-auto py-0"
iconClassName="size-5"
/>
</div>
)}

{/* Value */}
<div className="flex items-center justify-between gap-2">
<span className="text-muted-foreground">Value</span>
{toEther(BigInt(txData.value))} {chain.nativeCurrency?.symbol}
</div>

{/* Network */}
<div className="flex items-center justify-between gap-2">
<span className="text-muted-foreground">Network</span>
<div className="flex items-center gap-2">
<ChainIconClient
className="size-5 rounded-full"
src={chain.icon?.url}
/>
<span className="text-foreground">
{chain.name || `Chain ID: ${txData.chainId}`}
</span>
</div>
</div>

{/* Status */}
{props.status.type !== "idle" && (
<div className="flex items-center justify-between gap-2">
<span className="text-muted-foreground">Status</span>
<div className="flex items-center gap-2">
<span
className={cn(
"flex items-center gap-2 font-medium",
props.status.type === "sending" && "text-blue-500",
props.status.type === "confirming" && "text-yellow-500",
props.status.type === "confirmed" && "text-green-500",
props.status.type === "failed" && "text-red-500",
)}
>
{/* icon */}
{(props.status.type === "sending" ||
props.status.type === "confirming") && (
<Spinner className="size-4" />
)}

<CodeClient code={JSON.stringify(txData, null, 2)} lang="json" />
{props.status.type === "confirmed" && (
<CircleCheckIcon className="size-4" />
)}

{props.status.type === "failed" && (
<CircleXIcon className="size-4" />
)}

{/* text */}
<span>
{props.status.type === "sending" && "Sending Transaction"}
{props.status.type === "confirming" &&
"Waiting for Confirmation"}
{props.status.type === "confirmed" &&
"Transaction Confirmed"}
{props.status.type === "failed" && "Transaction Failed"}
</span>
</span>
</div>
</div>
)}

{/* Transaction Hash */}
{"txHash" in props.status && props.status.txHash && (
<div className="flex items-center justify-between gap-1">
<span className="text-muted-foreground">Transaction Hash</span>
<div className="flex justify-end gap-2.5">
{explorer ? (
<Button
asChild
variant="ghost"
size="sm"
className="gap-1.5 font-mono"
>
<Link
href={`${explorer}/tx/${props.status.txHash}`}
target="_blank"
>
{`${props.status.txHash.slice(0, 6)}...${props.status.txHash.slice(-4)}`}
<ExternalLinkIcon className="size-3" />
</Link>
</Button>
) : (
<CopyTextButton
textToCopy={props.status.txHash}
textToShow={`${props.status.txHash.slice(0, 6)}...${props.status.txHash.slice(-4)}`}
variant="ghost"
className="font-mono"
copyIconPosition="right"
tooltip="Copy Transaction Hash"
/>
)}
</div>
</div>
)}
</div>

<div className="flex items-center justify-end border-t p-4">
{/* footer */}
<div className="flex items-center justify-end px-4 py-6 lg:px-6">
<TransactionButton
isPending={sendTransaction.isPending}
transactionCount={undefined}
txChainID={txData.chainId}
variant="default"
disabled={isTransactionPending}
size="sm"
onClick={async () => {
trackEvent({
category: "nebula",
Expand Down Expand Up @@ -164,72 +295,6 @@ export function ExecuteTransactionCardLayout(props: {
</TransactionButton>
</div>
</div>

{/* Tx Status */}
{props.status.type !== "idle" && (
<div className="mt-5 rounded-lg border bg-card">
<div className="flex flex-col gap-1.5 p-4">
{props.status.type === "sending" && (
<div className="flex items-center gap-2 text-link-foreground">
<Spinner className="size-4" />
<p> Sending Transaction </p>
</div>
)}

{isTransactionSent && (
<div className="flex items-center gap-2 text-success-text">
<CircleCheckIcon className="size-4" />
<p> Transaction Sent </p>
</div>
)}

{props.status.type === "confirming" && (
<div className="flex items-center gap-2 text-link-foreground">
<Spinner className="size-4" />
<p> Confirming Transaction </p>
</div>
)}

{props.status.type === "confirmed" && (
<div className="flex items-center gap-2 text-success-text">
<CircleCheckIcon className="size-4" />
<p> Transaction Confirmed </p>
</div>
)}

{props.status.type === "failed" && (
<div className="flex items-center gap-2 text-destructive-text">
<CircleXIcon className="size-4" />
<p> Transaction Failed </p>
</div>
)}
</div>

{"txHash" in props.status && props.status.txHash && (
<div className="flex justify-end gap-2.5 border-t p-4">
{explorer && (
<Button asChild variant="outline" size="sm" className="gap-2 ">
<Link
href={`${explorer}/tx/${props.status.txHash}`}
target="_blank"
>
View on Explorer
<ExternalLinkIcon className="size-3" />
</Link>
</Button>
)}
<CopyTextButton
textToCopy={props.status.txHash}
className=""
textToShow="Transaction Hash"
variant="outline"
copyIconPosition="right"
tooltip="Copy Transaction Hash"
/>
</div>
)}
</div>
)}
</div>
);
}
Loading
Loading