From 031e629658e5103272836d5e619b631b4e459cec Mon Sep 17 00:00:00 2001 From: gregfromstl Date: Mon, 23 Jun 2025 16:26:22 -0700 Subject: [PATCH 01/10] feat: adds ub widget tracking --- .../web/ui/Bridge/BridgeOrchestrator.tsx | 2 ++ .../src/react/web/ui/Bridge/BuyWidget.tsx | 21 +++++++++++++++++- .../react/web/ui/Bridge/CheckoutWidget.tsx | 21 +++++++++++++++++- .../src/react/web/ui/Bridge/ErrorBanner.tsx | 22 ++++++++++++++++++- .../src/react/web/ui/Bridge/QuoteLoader.tsx | 22 +++++++++++++++++++ .../react/web/ui/Bridge/TransactionWidget.tsx | 21 +++++++++++++++++- .../web/ui/Bridge/UnsupportedTokenScreen.tsx | 19 +++++++++++++++- .../Bridge/payment-details/PaymentDetails.tsx | 18 +++++++++++++++ .../payment-selection/PaymentSelection.tsx | 14 ++++++++++++ .../Bridge/payment-success/SuccessScreen.tsx | 22 +++++++++++++++++++ .../stories/Bridge/ErrorBanner.stories.tsx | 6 ++++- .../stories/Bridge/SuccessScreen.stories.tsx | 10 +++++++++ .../Bridge/UnsupportedTokenScreen.stories.tsx | 7 ++++++ packages/thirdweb/test/src/test-clients.js | 16 ++++++++++++++ .../thirdweb/test/src/test-clients.js.map | 1 + 15 files changed, 216 insertions(+), 6 deletions(-) create mode 100644 packages/thirdweb/test/src/test-clients.js create mode 100644 packages/thirdweb/test/src/test-clients.js.map diff --git a/packages/thirdweb/src/react/web/ui/Bridge/BridgeOrchestrator.tsx b/packages/thirdweb/src/react/web/ui/Bridge/BridgeOrchestrator.tsx index 91470eb54d2..2c77ded3dbc 100644 --- a/packages/thirdweb/src/react/web/ui/Bridge/BridgeOrchestrator.tsx +++ b/packages/thirdweb/src/react/web/ui/Bridge/BridgeOrchestrator.tsx @@ -217,6 +217,7 @@ export function BridgeOrchestrator({ {/* Error Banner */} {state.value === "error" && state.context.currentError && ( { + trackPayEvent({ + client: props.client, + event: "buy_widget:render", + toChainId: props.chain.id, + toToken: props.tokenAddress, + }); + }, + queryKey: ["buy_widget:render"], + }); + const bridgeDataQuery = useQuery({ queryFn: async (): Promise => { if ( @@ -343,7 +356,13 @@ export function BuyWidget(props: BuyWidgetProps) { ); } else if (bridgeDataQuery.data?.type === "unsupported_token") { // Show unsupported token screen - content = ; + content = ( + + ); } else if (bridgeDataQuery.data?.type === "success") { // Show normal bridge orchestrator content = ( diff --git a/packages/thirdweb/src/react/web/ui/Bridge/CheckoutWidget.tsx b/packages/thirdweb/src/react/web/ui/Bridge/CheckoutWidget.tsx index 48b5facda41..1828cc13a19 100644 --- a/packages/thirdweb/src/react/web/ui/Bridge/CheckoutWidget.tsx +++ b/packages/thirdweb/src/react/web/ui/Bridge/CheckoutWidget.tsx @@ -1,6 +1,7 @@ "use client"; import { useQuery } from "@tanstack/react-query"; +import { trackPayEvent } from "../../../../analytics/track/pay.js"; import type { Token } from "../../../../bridge/index.js"; import type { Chain } from "../../../../chains/types.js"; import type { ThirdwebClient } from "../../../../client/client.js"; @@ -251,6 +252,18 @@ export function CheckoutWidget(props: CheckoutWidgetProps) { const localeQuery = useConnectLocale(props.locale || "en_US"); const theme = props.theme || "dark"; + useQuery({ + queryFn: () => { + trackPayEvent({ + client: props.client, + event: "checkout_widget:render", + toChainId: props.chain.id, + toToken: props.tokenAddress, + }); + }, + queryKey: ["checkout_widget:render"], + }); + const bridgeDataQuery = useQuery({ queryFn: async (): Promise => { const token = await getToken( @@ -306,7 +319,13 @@ export function CheckoutWidget(props: CheckoutWidgetProps) { ); } else if (bridgeDataQuery.data?.type === "unsupported_token") { // Show unsupported token screen - content = ; + content = ( + + ); } else if (bridgeDataQuery.data?.type === "success") { // Show normal bridge orchestrator content = ( diff --git a/packages/thirdweb/src/react/web/ui/Bridge/ErrorBanner.tsx b/packages/thirdweb/src/react/web/ui/Bridge/ErrorBanner.tsx index ed40a5ce343..3d7d647f71d 100644 --- a/packages/thirdweb/src/react/web/ui/Bridge/ErrorBanner.tsx +++ b/packages/thirdweb/src/react/web/ui/Bridge/ErrorBanner.tsx @@ -1,5 +1,8 @@ "use client"; import { CrossCircledIcon } from "@radix-ui/react-icons"; +import { useQuery } from "@tanstack/react-query"; +import { trackPayEvent } from "../../../../analytics/track/pay.js"; +import type { ThirdwebClient } from "../../../../client/client.js"; import { useCustomTheme } from "../../../core/design-system/CustomThemeProvider.js"; import { iconSize } from "../../../core/design-system/index.js"; import { useBridgeError } from "../../../core/hooks/useBridgeError.js"; @@ -22,13 +25,30 @@ interface ErrorBannerProps { * Called when user wants to cancel */ onCancel?: () => void; + client: ThirdwebClient; } -export function ErrorBanner({ error, onRetry, onCancel }: ErrorBannerProps) { +export function ErrorBanner({ + error, + onRetry, + onCancel, + client, +}: ErrorBannerProps) { const theme = useCustomTheme(); const { userMessage } = useBridgeError({ error }); + useQuery({ + queryFn: () => { + trackPayEvent({ + client, + error: error.message, + event: "error", + }); + }, + queryKey: ["error_banner", userMessage], + }); + return ( {/* Error Icon and Message */} diff --git a/packages/thirdweb/src/react/web/ui/Bridge/QuoteLoader.tsx b/packages/thirdweb/src/react/web/ui/Bridge/QuoteLoader.tsx index b34c8e1682f..74591ccb968 100644 --- a/packages/thirdweb/src/react/web/ui/Bridge/QuoteLoader.tsx +++ b/packages/thirdweb/src/react/web/ui/Bridge/QuoteLoader.tsx @@ -1,5 +1,7 @@ "use client"; +import { useQuery } from "@tanstack/react-query"; import { useEffect } from "react"; +import { trackPayEvent } from "../../../../analytics/track/pay.js"; import type { Token } from "../../../../bridge/types/Token.js"; import type { ThirdwebClient } from "../../../../client/client.js"; import { NATIVE_TOKEN_ADDRESS } from "../../../../constants/addresses.js"; @@ -109,6 +111,26 @@ export function QuoteLoader({ }); const prepareQuery = useBridgePrepare(request); + useQuery({ + queryFn: () => { + trackPayEvent({ + chainId: + paymentMethod.type === "wallet" + ? paymentMethod.originToken.chainId + : undefined, + client, + event: "loading_quote", + fromToken: + paymentMethod.type === "wallet" + ? paymentMethod.originToken.address + : undefined, + toChainId: destinationToken.chainId, + toToken: destinationToken.address, + }); + }, + queryKey: ["loading_quote", paymentMethod.type], + }); + // Handle successful quote useEffect(() => { if (prepareQuery.data) { diff --git a/packages/thirdweb/src/react/web/ui/Bridge/TransactionWidget.tsx b/packages/thirdweb/src/react/web/ui/Bridge/TransactionWidget.tsx index 0bb40d97a7c..cb81564b601 100644 --- a/packages/thirdweb/src/react/web/ui/Bridge/TransactionWidget.tsx +++ b/packages/thirdweb/src/react/web/ui/Bridge/TransactionWidget.tsx @@ -1,6 +1,7 @@ "use client"; import { useQuery } from "@tanstack/react-query"; +import { trackPayEvent } from "../../../../analytics/track/pay.js"; import type { Token } from "../../../../bridge/index.js"; import type { Chain } from "../../../../chains/types.js"; import type { ThirdwebClient } from "../../../../client/client.js"; @@ -275,6 +276,18 @@ export function TransactionWidget(props: TransactionWidgetProps) { const localeQuery = useConnectLocale(props.locale || "en_US"); const theme = props.theme || "dark"; + useQuery({ + queryFn: () => { + trackPayEvent({ + chainId: props.transaction.chain.id, + client: props.client, + event: "transaction_widget:render", + toToken: props.tokenAddress, + }); + }, + queryKey: ["transaction_widget:render"], + }); + const bridgeDataQuery = useQuery({ queryFn: async (): Promise => { let erc20Value = props.transaction.erc20Value; @@ -331,7 +344,13 @@ export function TransactionWidget(props: TransactionWidgetProps) { ); } else if (bridgeDataQuery.data?.type === "unsupported_token") { // Show unsupported token screen - content = ; + content = ( + + ); } else if (bridgeDataQuery.data?.type === "success") { // Show normal bridge orchestrator content = ( diff --git a/packages/thirdweb/src/react/web/ui/Bridge/UnsupportedTokenScreen.tsx b/packages/thirdweb/src/react/web/ui/Bridge/UnsupportedTokenScreen.tsx index 2a10feeed0c..25db7c3f843 100644 --- a/packages/thirdweb/src/react/web/ui/Bridge/UnsupportedTokenScreen.tsx +++ b/packages/thirdweb/src/react/web/ui/Bridge/UnsupportedTokenScreen.tsx @@ -1,4 +1,7 @@ +import { useQuery } from "@tanstack/react-query"; +import { trackPayEvent } from "../../../../analytics/track/pay.js"; import type { Chain } from "../../../../chains/types.js"; +import type { ThirdwebClient } from "../../../../client/client.js"; import { iconSize } from "../../../core/design-system/index.js"; import { useChainMetadata } from "../../../core/hooks/others/useChainQuery.js"; import { AccentFailIcon } from "../ConnectWallet/icons/AccentFailIcon.js"; @@ -11,6 +14,8 @@ export interface UnsupportedTokenScreenProps { * The chain the token is on */ chain: Chain; + client: ThirdwebClient; + tokenAddress?: string; } /** @@ -18,10 +23,22 @@ export interface UnsupportedTokenScreenProps { * @internal */ export function UnsupportedTokenScreen(props: UnsupportedTokenScreenProps) { - const { chain } = props; + const { chain, tokenAddress, client } = props; const { data: chainMetadata } = useChainMetadata(chain); + useQuery({ + queryFn: () => { + trackPayEvent({ + chainId: chain.id, + client, + event: "unsupported_token", + fromToken: tokenAddress, + }); + }, + queryKey: ["unsupported_token"], + }); + if (chainMetadata?.testnet) { return ( { + if (preparedQuote.type === "buy" || preparedQuote.type === "sell") { + trackPayEvent({ + chainId: preparedQuote.intent.originChainId, + client, + event: "payment_details", + fromToken: preparedQuote.intent.originTokenAddress, + toChainId: preparedQuote.intent.destinationChainId, + toToken: preparedQuote.intent.destinationTokenAddress, + }); + } + }, + queryKey: ["payment_details", preparedQuote.type], + }); + // Extract common data based on quote type const getDisplayData = () => { switch (preparedQuote.type) { diff --git a/packages/thirdweb/src/react/web/ui/Bridge/payment-selection/PaymentSelection.tsx b/packages/thirdweb/src/react/web/ui/Bridge/payment-selection/PaymentSelection.tsx index 353d5f9c327..e193d54cbdd 100644 --- a/packages/thirdweb/src/react/web/ui/Bridge/payment-selection/PaymentSelection.tsx +++ b/packages/thirdweb/src/react/web/ui/Bridge/payment-selection/PaymentSelection.tsx @@ -1,5 +1,7 @@ "use client"; +import { useQuery } from "@tanstack/react-query"; import { useEffect, useState } from "react"; +import { trackPayEvent } from "../../../../../analytics/track/pay.js"; import type { Token } from "../../../../../bridge/types/Token.js"; import { defineChain } from "../../../../../chains/utils.js"; import type { ThirdwebClient } from "../../../../../client/client.js"; @@ -96,6 +98,18 @@ export function PaymentSelection({ type: "walletSelection", }); + useQuery({ + queryFn: () => { + trackPayEvent({ + client, + event: "payment_selection", + toChainId: destinationToken.chainId, + toToken: destinationToken.address, + }); + }, + queryKey: ["payment_selection"], + }); + const payerWallet = currentStep.type === "tokenSelection" ? currentStep.selectedWallet diff --git a/packages/thirdweb/src/react/web/ui/Bridge/payment-success/SuccessScreen.tsx b/packages/thirdweb/src/react/web/ui/Bridge/payment-success/SuccessScreen.tsx index 6f7f9a3c3d6..42d5c27cf0e 100644 --- a/packages/thirdweb/src/react/web/ui/Bridge/payment-success/SuccessScreen.tsx +++ b/packages/thirdweb/src/react/web/ui/Bridge/payment-success/SuccessScreen.tsx @@ -1,6 +1,9 @@ "use client"; import { CheckIcon } from "@radix-ui/react-icons"; +import { useQuery } from "@tanstack/react-query"; import { useState } from "react"; +import { trackPayEvent } from "../../../../../analytics/track/pay.js"; +import type { ThirdwebClient } from "../../../../../client/client.js"; import type { WindowAdapter } from "../../../../core/adapters/WindowAdapter.js"; import { useCustomTheme } from "../../../../core/design-system/CustomThemeProvider.js"; import { iconSize } from "../../../../core/design-system/index.js"; @@ -37,6 +40,8 @@ export interface SuccessScreenProps { * Window adapter for opening URLs */ windowAdapter: WindowAdapter; + + client: ThirdwebClient; } type ViewState = "success" | "detail"; @@ -47,10 +52,27 @@ export function SuccessScreen({ completedStatuses, onDone, windowAdapter, + client, }: SuccessScreenProps) { const theme = useCustomTheme(); const [viewState, setViewState] = useState("success"); + useQuery({ + queryFn: () => { + if (preparedQuote.type === "buy" || preparedQuote.type === "sell") { + trackPayEvent({ + chainId: preparedQuote.intent.originChainId, + client: client, + event: "success_screen", + fromToken: preparedQuote.intent.originTokenAddress, + toChainId: preparedQuote.intent.destinationChainId, + toToken: preparedQuote.intent.destinationTokenAddress, + }); + } + }, + queryKey: ["success_screen", preparedQuote.type], + }); + if (viewState === "detail") { return ( { const { theme, ...componentProps } = props; return ( - + ); }; diff --git a/packages/thirdweb/src/stories/Bridge/SuccessScreen.stories.tsx b/packages/thirdweb/src/stories/Bridge/SuccessScreen.stories.tsx index dc2e24bb8a7..38d23f25eb6 100644 --- a/packages/thirdweb/src/stories/Bridge/SuccessScreen.stories.tsx +++ b/packages/thirdweb/src/stories/Bridge/SuccessScreen.stories.tsx @@ -1,5 +1,6 @@ import type { Meta, StoryObj } from "@storybook/react"; import { stringify } from "viem"; +import { createThirdwebClient } from "../../client/client.js"; import type { Theme } from "../../react/core/design-system/index.js"; import type { CompletedStatusResult } from "../../react/core/hooks/useStepExecutor.js"; import { webWindowAdapter } from "../../react/web/adapters/WindowAdapter.js"; @@ -15,6 +16,8 @@ import { TRANSACTION_UI_OPTIONS, } from "./fixtures.js"; +const TEST_CLIENT = createThirdwebClient({ clientId: "test" }); + const mockBuyCompletedStatuses: CompletedStatusResult[] = JSON.parse( stringify([ { @@ -126,6 +129,7 @@ type Story = StoryObj; export const Default: Story = { args: { + client: TEST_CLIENT, theme: "dark", }, parameters: { @@ -135,6 +139,7 @@ export const Default: Story = { export const DefaultLight: Story = { args: { + client: TEST_CLIENT, theme: "light", }, parameters: { @@ -144,6 +149,7 @@ export const DefaultLight: Story = { export const OnrampPayment: Story = { args: { + client: TEST_CLIENT, completedStatuses: mockOnrampCompletedStatuses, preparedQuote: simpleOnrampQuote, theme: "dark", @@ -161,6 +167,7 @@ export const OnrampPayment: Story = { export const OnrampPaymentLight: Story = { args: { + client: TEST_CLIENT, completedStatuses: mockOnrampCompletedStatuses, preparedQuote: simpleOnrampQuote, theme: "light", @@ -172,6 +179,7 @@ export const OnrampPaymentLight: Story = { export const ComplexPayment: Story = { args: { + client: TEST_CLIENT, completedStatuses: [ ...mockOnrampCompletedStatuses, ...mockBuyCompletedStatuses, @@ -192,6 +200,7 @@ export const ComplexPayment: Story = { export const ComplexPaymentLight: Story = { args: { + client: TEST_CLIENT, completedStatuses: [ ...mockOnrampCompletedStatuses, ...mockBuyCompletedStatuses, @@ -206,6 +215,7 @@ export const ComplexPaymentLight: Story = { export const TransactionPayment: Story = { args: { + client: TEST_CLIENT, completedStatuses: mockBuyCompletedStatuses, preparedQuote: simpleBuyQuote, theme: "light", diff --git a/packages/thirdweb/src/stories/Bridge/UnsupportedTokenScreen.stories.tsx b/packages/thirdweb/src/stories/Bridge/UnsupportedTokenScreen.stories.tsx index 15989042387..23a1f226892 100644 --- a/packages/thirdweb/src/stories/Bridge/UnsupportedTokenScreen.stories.tsx +++ b/packages/thirdweb/src/stories/Bridge/UnsupportedTokenScreen.stories.tsx @@ -1,5 +1,6 @@ import type { Meta, StoryObj } from "@storybook/react"; import { defineChain } from "../../chains/utils.js"; +import { createThirdwebClient } from "../../client/client.js"; import type { Theme } from "../../react/core/design-system/index.js"; import { UnsupportedTokenScreen, @@ -7,6 +8,8 @@ import { } from "../../react/web/ui/Bridge/UnsupportedTokenScreen.js"; import { ModalThemeWrapper } from "../utils.js"; +const TEST_CLIENT = createThirdwebClient({ clientId: "test" }); + // Props interface for the wrapper component interface UnsupportedTokenScreenWithThemeProps extends UnsupportedTokenScreenProps { @@ -57,6 +60,7 @@ type Story = StoryObj; export const TokenNotSupported: Story = { args: { chain: defineChain(1), + client: TEST_CLIENT, theme: "dark", // Ethereum mainnet - will show indexing spinner }, parameters: { @@ -73,6 +77,7 @@ export const TokenNotSupported: Story = { export const TokenNotSupportedLight: Story = { args: { chain: defineChain(1), + client: TEST_CLIENT, theme: "light", // Ethereum mainnet - will show indexing spinner }, parameters: { @@ -89,6 +94,7 @@ export const TokenNotSupportedLight: Story = { export const TestnetNotSupported: Story = { args: { chain: defineChain(11155111), + client: TEST_CLIENT, theme: "dark", // Sepolia testnet - will show error state }, parameters: { @@ -105,6 +111,7 @@ export const TestnetNotSupported: Story = { export const TestnetNotSupportedLight: Story = { args: { chain: defineChain(11155111), + client: TEST_CLIENT, theme: "light", // Sepolia testnet - will show error state }, parameters: { diff --git a/packages/thirdweb/test/src/test-clients.js b/packages/thirdweb/test/src/test-clients.js new file mode 100644 index 00000000000..fc271a25f4a --- /dev/null +++ b/packages/thirdweb/test/src/test-clients.js @@ -0,0 +1,16 @@ +import { createThirdwebClient } from "../../src/client/client.js"; +const secretKey = process.env.TW_SECRET_KEY; +const clientId = process.env.TW_CLIENT_ID; +export const TEST_CLIENT = createThirdwebClient(secretKey + ? { + secretKey, + clientId: clientId ?? undefined, + } + : { + clientId: "TEST", + // if we don't have a secret key, we can use a public gateway for testing? + config: { + storage: { gatewayUrl: "https://gateway.pinata.cloud/ipfs/" }, + }, + }); +//# sourceMappingURL=test-clients.js.map \ No newline at end of file diff --git a/packages/thirdweb/test/src/test-clients.js.map b/packages/thirdweb/test/src/test-clients.js.map new file mode 100644 index 00000000000..e779ff95d7d --- /dev/null +++ b/packages/thirdweb/test/src/test-clients.js.map @@ -0,0 +1 @@ +{"version":3,"file":"test-clients.js","sourceRoot":"","sources":["test-clients.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AAElE,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC;AAC5C,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC;AAE1C,MAAM,CAAC,MAAM,WAAW,GAAG,oBAAoB,CAC7C,SAAS;IACP,CAAC,CAAC;QACE,SAAS;QACT,QAAQ,EAAE,QAAQ,IAAI,SAAS;KAChC;IACH,CAAC,CAAC;QACE,QAAQ,EAAE,MAAM;QAChB,0EAA0E;QAC1E,MAAM,EAAE;YACN,OAAO,EAAE,EAAE,UAAU,EAAE,oCAAoC,EAAE;SAC9D;KACF,CACN,CAAC"} \ No newline at end of file From 11f8dce1e04628a3cdef4fc79b02992a4d5cdf51 Mon Sep 17 00:00:00 2001 From: gregfromstl Date: Mon, 23 Jun 2025 16:26:57 -0700 Subject: [PATCH 02/10] chore: deprecate PayEmbed --- .changeset/wild-cases-ask.md | 5 +++++ packages/thirdweb/src/react/web/ui/PayEmbed.tsx | 9 +++++---- 2 files changed, 10 insertions(+), 4 deletions(-) create mode 100644 .changeset/wild-cases-ask.md diff --git a/.changeset/wild-cases-ask.md b/.changeset/wild-cases-ask.md new file mode 100644 index 00000000000..eae1ca2dfd9 --- /dev/null +++ b/.changeset/wild-cases-ask.md @@ -0,0 +1,5 @@ +--- +"thirdweb": patch +--- + +Deprecate PayEmbed diff --git a/packages/thirdweb/src/react/web/ui/PayEmbed.tsx b/packages/thirdweb/src/react/web/ui/PayEmbed.tsx index 1936cf43d89..01c4cccb786 100644 --- a/packages/thirdweb/src/react/web/ui/PayEmbed.tsx +++ b/packages/thirdweb/src/react/web/ui/PayEmbed.tsx @@ -308,6 +308,7 @@ export type PayEmbedProps = { * Refer to the [`PayEmbedConnectOptions`](https://portal.thirdweb.com/references/typescript/v5/PayEmbedConnectOptions) type for more details. * * @buyCrypto + * @deprecated Use `BuyWidget`, `CheckoutWidget` or `TransactionWidget` instead. */ export function PayEmbed(props: PayEmbedProps) { const localeQuery = useConnectLocale(props.locale || "en_US"); @@ -510,10 +511,10 @@ export type PayEmbedConnectOptions = { * ``` */ autoConnect?: - | { - timeout: number; - } - | boolean; + | { + timeout: number; + } + | boolean; /** * Metadata of the app that will be passed to connected wallet. Setting this is highly recommended. From b525e4b17a47f73e7c69f6d24431b2c50c024fdc Mon Sep 17 00:00:00 2001 From: gregfromstl Date: Mon, 23 Jun 2025 16:31:35 -0700 Subject: [PATCH 03/10] fix: PayEmbed success callback --- packages/thirdweb/src/react/web/ui/PayEmbed.tsx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/thirdweb/src/react/web/ui/PayEmbed.tsx b/packages/thirdweb/src/react/web/ui/PayEmbed.tsx index 01c4cccb786..bff099b1997 100644 --- a/packages/thirdweb/src/react/web/ui/PayEmbed.tsx +++ b/packages/thirdweb/src/react/web/ui/PayEmbed.tsx @@ -359,6 +359,7 @@ export function PayEmbed(props: PayEmbedProps) { client={props.client} theme={theme} title={metadata?.name || "Buy"} + onSuccess={() => props.payOptions?.onPurchaseSuccess?.()} tokenAddress={ props.payOptions.prefillBuy.token?.address as Address | undefined } @@ -376,6 +377,7 @@ export function PayEmbed(props: PayEmbedProps) { image={metadata?.image} name={metadata?.name || "Checkout"} seller={props.payOptions.paymentInfo.sellerAddress as Address} + onSuccess={() => props.payOptions?.onPurchaseSuccess?.()} theme={theme} tokenAddress={ props.payOptions.paymentInfo.token?.address as Address | undefined @@ -391,6 +393,7 @@ export function PayEmbed(props: PayEmbedProps) { description={metadata?.description} image={metadata?.image} theme={theme} + onSuccess={() => props.payOptions?.onPurchaseSuccess?.()} title={metadata?.name} transaction={props.payOptions.transaction} /> From c5bd76a74d95875dd1177620a00033ba94ea947c Mon Sep 17 00:00:00 2001 From: gregfromstl Date: Mon, 23 Jun 2025 17:04:15 -0700 Subject: [PATCH 04/10] chore: update docs --- .../components/server/BuyFundsSection.tsx | 64 +--- apps/portal/public/llms-full.txt | 330 ++++++++++++------ .../app/pay/customization/payembed/page.mdx | 154 -------- .../portal/src/app/react/v5/adapters/page.mdx | 4 +- .../app/react/v5/pay/fund-wallets/page.mdx | 28 +- .../src/app/react/v5/pay/transaction/page.mdx | 47 --- .../TDoc/utils/getSidebarLinkgroups.ts | 2 - packages/thirdweb/src/bridge/Buy.ts | 8 +- .../src/react/web/ui/Bridge/BuyWidget.tsx | 30 +- .../react/web/ui/Bridge/CheckoutWidget.tsx | 28 +- .../react/web/ui/Bridge/TransactionWidget.tsx | 28 +- .../thirdweb/src/react/web/ui/PayEmbed.tsx | 1 - packages/thirdweb/tsdoc.json | 7 +- 13 files changed, 295 insertions(+), 436 deletions(-) delete mode 100644 apps/portal/src/app/pay/customization/payembed/page.mdx diff --git a/apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/BuyFundsSection.tsx b/apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/BuyFundsSection.tsx index a1080462cda..3c0df283629 100644 --- a/apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/BuyFundsSection.tsx +++ b/apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/BuyFundsSection.tsx @@ -1,68 +1,20 @@ -import { ExternalLinkIcon } from "lucide-react"; -import Link from "next/link"; -import type { ThirdwebClient } from "thirdweb"; +import { defineChain, type ThirdwebClient } from "thirdweb"; import type { ChainMetadata } from "thirdweb/chains"; -import { ChainIcon } from "../../../../components/server/chain-icon"; -import { PayModalButton } from "../client/PayModal"; -import { CreditCardIcon } from "../icons/CreditCardIcon"; import { SectionTitle } from "./SectionTitle"; +import { BuyWidget } from "thirdweb/react"; export function BuyFundsSection(props: { chain: ChainMetadata; client: ThirdwebClient; }) { - const sanitizedChainName = props.chain.name.replace("Mainnet", "").trim(); - return ( -
+
-
-
-
- - -
- -
- -

- Bridge Funds to {sanitizedChainName} -

- -
- -

- Get {props.chain.nativeCurrency.symbol} on {sanitizedChainName} with - fiat or any token on another chain. -

- -
- - - -
- - - Learn more about Universal Bridge - - -
-
+
); } diff --git a/apps/portal/public/llms-full.txt b/apps/portal/public/llms-full.txt index cdb88df40da..0b2c8a3df62 100644 --- a/apps/portal/public/llms-full.txt +++ b/apps/portal/public/llms-full.txt @@ -1603,164 +1603,287 @@ let returnType: Element; # Buy Crypto --- -## PayEmbed +## BuyWidget -Embed a prebuilt UI for funding wallets, purchases or transactions with crypto or fiat. +Widget is a prebuilt UI for purchasing a specific token. ### Example -#### Default configuration +#### Basic usage -By default, the `PayEmbed` component will allows users to fund their wallets with crypto or fiat on any of the supported chains.. +The `BuyWidget` component requires `client`, `chain`, and `amount` props to function. ```tsx -; +import { ethereum } from "thirdweb/chains"; + + ``` -#### Top up wallets +#### Buy a specific token -You can set the `mode` option to `"fund_wallet"` to allow users to top up their wallets with crypto or fiat. +You can specify a token to purchase by passing the `tokenAddress` prop. ```tsx -; + chain={ethereum} + amount="100" + tokenAddress="0xA0b86a33E6417E4df2057B2d3C6d9F7cc11b0a70" +/> ``` -#### Direct Payments +#### Customize the UI -You can set the `mode` option to `"direct_payment"` to allow users to make a direct payment to a wallet address. +You can customize the UI of the `BuyWidget` component by passing a custom theme object to the `theme` prop. ```tsx -; + })} +/> ``` -#### Transactions +Refer to the [Theme](https://portal.thirdweb.com/references/typescript/v5/Theme) type for more details. + +#### Update the Title -You can set the `mode` option to `"transaction"` to allow users to execute a transaction with a different wallet, chain or token. +You can update the title of the widget by passing a `title` prop to the `BuyWidget` component. ```tsx -; + chain={ethereum} + amount="0.1" + title="Buy ETH" +/> ``` -You can also handle ERC20 payments by passing `erc20value` to your transaction: +#### Configure the wallet connection + +You can customize the wallet connection flow by passing a `connectOptions` object to the `BuyWidget` component. ```tsx - +/> +``` + +Refer to the [BuyWidgetConnectOptions](https://portal.thirdweb.com/references/typescript/v5/BuyWidgetConnectOptions) type for more details. + +```ts +function BuyWidget(props: BuyWidgetProps): Element; +``` + +### Parameters + +Props of type [BuyWidgetProps](https://portal.thirdweb.com/references/typescript/v5/BuyWidgetProps) to configure the BuyWidget component. + +#### Type + +```ts +let props: { + activeWallet?: Wallet; + amount: string; + chain: Chain; + className?: string; + client: ThirdwebClient; + connectOptions?: BuyWidgetConnectOptions; + description?: string; + hiddenWallets?: Array; + image?: string; + locale?: LocaleId; + onCancel?: () => void; + onError?: (error: Error) => void; + onSuccess?: () => void; + paymentLinkId?: string; + presetOptions?: [number, number, number]; + purchaseData?: Record; + style?: React.CSSProperties; + supportedTokens?: SupportedTokens; + theme?: "light" | "dark" | Theme; + title?: string; + tokenAddress?: Address; +}; +``` + +### Returns + +```ts +let returnType: Element; +``` + +## CheckoutWidget + +Widget is a prebuilt UI for making direct payments to a wallet address. + +### Example + +#### Basic usage + +The `CheckoutWidget` component requires `client`, `chain`, `amount`, `tokenAddress`, and `sellerAddress` props to function. + +```tsx +import { base } from "thirdweb/chains"; +import { getDefaultToken } from "thirdweb/utils"; + + ``` -#### Enable/Disable payment methods +#### With metadata -You can disable the use of crypto or fiat by setting the `buyWithCrypto` or `buyWithFiat` options to `false`. +You can add metadata to display product information. ```tsx -; + chain={base} + amount="35" + tokenAddress={getDefaultToken(base, "USDC")} + sellerAddress="0x..." + title="Black Hoodie (Size L)" + description="Premium cotton hoodie" + image="/drip-hoodie.png" +/> ``` -#### Customize the UI +```ts +function CheckoutWidget(props: CheckoutWidgetProps): Element; +``` + +### Parameters + +Props of type [CheckoutWidgetProps](https://portal.thirdweb.com/references/typescript/v5/CheckoutWidgetProps) to configure the CheckoutWidget component. + +#### Type + +```ts +let props: { + activeWallet?: Wallet; + amount: string; + chain: Chain; + className?: string; + client: ThirdwebClient; + connectOptions?: CheckoutWidgetConnectOptions; + description?: string; + hiddenWallets?: Array; + image?: string; + locale?: LocaleId; + onCancel?: () => void; + onError?: (error: Error) => void; + onSuccess?: () => void; + paymentLinkId?: string; + purchaseData?: Record; + sellerAddress: Address; + style?: React.CSSProperties; + supportedTokens?: SupportedTokens; + theme?: "light" | "dark" | Theme; + title?: string; + tokenAddress: Address; +}; +``` + +### Returns + +```ts +let returnType: Element; +``` + +## TransactionWidget -You can customize the UI of the `PayEmbed` component by passing a custom theme object to the `theme` prop. +Widget is a prebuilt UI for executing a transaction with a different wallet, chain or token. + +### Example + +#### Basic usage + +The `TransactionWidget` component requires `client` and `transaction` props to function. ```tsx -; +/> ``` -Refer to the [Theme](https://portal.thirdweb.com/references/typescript/v5/Theme) type for more details. +#### With metadata -#### Configure the wallet connection +You can add metadata to display transaction information. -You can customize the wallet connection flow by passing a `connectOptions` object to the `PayEmbed` component. +```tsx + +``` + +#### ERC20 payments + +You can handle ERC20 payments by passing `erc20value` to your transaction: ```tsx -; + })} +/> ``` -Refer to the [PayEmbedConnectOptions](https://portal.thirdweb.com/references/typescript/v5/PayEmbedConnectOptions) type for more details. - ```ts -function PayEmbed(props: PayEmbedProps): Element; +function TransactionWidget(props: TransactionWidgetProps): Element; ``` ### Parameters -Props of type [PayEmbedProps](https://portal.thirdweb.com/references/typescript/v5/PayEmbedProps) to configure the PayEmbed component. +Props of type [TransactionWidgetProps](https://portal.thirdweb.com/references/typescript/v5/TransactionWidgetProps) to configure the TransactionWidget component. #### Type @@ -1769,14 +1892,21 @@ let props: { activeWallet?: Wallet; className?: string; client: ThirdwebClient; - connectOptions?: PayEmbedConnectOptions; + connectOptions?: TransactionWidgetConnectOptions; + description?: string; hiddenWallets?: Array; + image?: string; locale?: LocaleId; + onCancel?: () => void; + onError?: (error: Error) => void; + onSuccess?: () => void; paymentLinkId?: string; - payOptions?: PayUIOptions; + purchaseData?: Record; style?: React.CSSProperties; supportedTokens?: SupportedTokens; theme?: "light" | "dark" | Theme; + title?: string; + transaction: PreparedTransaction; }; ``` diff --git a/apps/portal/src/app/pay/customization/payembed/page.mdx b/apps/portal/src/app/pay/customization/payembed/page.mdx deleted file mode 100644 index c9d2601ce9c..00000000000 --- a/apps/portal/src/app/pay/customization/payembed/page.mdx +++ /dev/null @@ -1,154 +0,0 @@ -import { createMetadata, DocImage } from "@doc"; -export const metadata = createMetadata({ - image: { - title: "thirdweb Universal Bridge - Customize PayEmbed", - icon: "thirdweb", - }, - title: "thirdweb Universal Bridge - Customize PayEmbed - thirdweb", - description: - "thirdweb Universal Bridge - Customizing embeddable onramps and crypto purchase flows", -}); - -# PayEmbed Customization - -Learn how to customize the `PayEmbed`. You can find a selection of popular customizations below. For the full list of props, you can [view the full reference](/references/typescript/v5/PayEmbedProps). - ---- - -## Customize Supported Tokens - -You can enable users to select your token on a given chain by passing an array of `SupportedTokens`. Note that this array overrides all default tokens listed for that chain. - -```tsx - -``` - ---- - -## Prefill Destination Token - -In the case you want your users to purchase your token by default in your application, you can choose to pre-fill the Pay purchase flow with `prefillBuy` . - -For example, if you wanted users to only purchase Ethereum on Base network, you could do as follows: - -```tsx -import { base } from "thirdweb/chains"; - -; -``` - -If you'd like to prefill a purchase with a native token, you can set the chain without passing a token: - -```tsx - -``` - ---- - -## Preferred Provider - -You can specify which onramp provider to present to your users. By default, we choose a recommended provider based on the location of the user, KYC status, and currency. Please make sure your set provider is [available in your country](../onramp-providers). - -```tsx - -``` - ---- - -## Disable Payment Methods - -In some cases, you may only want to show users fiat or crypto payment options for your onchain goods or services. You can do this by setting either `buyWithCrypto` or `buyWithFiat` to `false`. - -#### Disable Buy With Crypto - -```tsx - -``` - -#### Disable Buy With Fiat - -```tsx - -``` - ---- - -## Theme - -You can set the theme for the component, which is set to `"dark"` by default. theme can be set to either `"dark"` , `"light"` or a custom theme object. - -We have [`lightTheme`](/references/typescript/v5/lightTheme) or [`darkTheme`](/references/typescript/v5/darkTheme) providers that you can override to kickstart customization. - -You can refer to our [`Theme`](/references/typescript/v5/Theme) page for a full view of customizable options if you’d prefer to create a custom theme from scratch. - -#### Provided Themes - -```tsx - - - -``` - -#### Custom Theme - -```tsx -import { darkTheme } from 'thirdweb/react'; - -// Using custom theme - - -``` diff --git a/apps/portal/src/app/react/v5/adapters/page.mdx b/apps/portal/src/app/react/v5/adapters/page.mdx index 56dc5b1b390..3e98a4c0111 100644 --- a/apps/portal/src/app/react/v5/adapters/page.mdx +++ b/apps/portal/src/app/react/v5/adapters/page.mdx @@ -84,7 +84,7 @@ const onClick = () => { ### Converting a wagmi wallet client to a thirdweb wallet -You can use the thirdweb SDK within a wagmi application by setting the wagmi connected account as the thirdweb 'active wallet'. After that, you can use all of the react components and hooks normally, including `PayEmbed`, `TransactionButton`, etc. +You can use the thirdweb SDK within a wagmi application by setting the wagmi connected account as the thirdweb 'active wallet'. After that, you can use all of the react components and hooks normally, including `BuyWidget`, `TransactionButton`, etc. ```ts // Assumes you've wrapped your application in a `` @@ -126,7 +126,7 @@ You can view a fully functioning wagmi + thirdweb app in this [github repository ## Privy -Similarly, you can use the thirdweb SDK with privy by setting the privy wallet as the thirdweb 'active wallet'. After that, you can use all of the react components, functions and hooks normally, including `PayEmbed`, `TransactionButton`, etc. +Similarly, you can use the thirdweb SDK with privy by setting the privy wallet as the thirdweb 'active wallet'. After that, you can use all of the react components, functions and hooks normally, including `BuyWidget`, `TransactionButton`, etc. ```ts // Assumes you've wrapped your application in a `` diff --git a/apps/portal/src/app/react/v5/pay/fund-wallets/page.mdx b/apps/portal/src/app/react/v5/pay/fund-wallets/page.mdx index 981ae36e101..e5d3f336307 100644 --- a/apps/portal/src/app/react/v5/pay/fund-wallets/page.mdx +++ b/apps/portal/src/app/react/v5/pay/fund-wallets/page.mdx @@ -28,39 +28,33 @@ Try out the demo for yourself in the [buy crypto live playground](https://playgr ## Usage with UI Components -The easiest way to buy crypto is to use the `PayEmbed` prebuilt UI component. Note that the `ConnectButton` also has a built-in funding flow that can also be customised. +The easiest way to buy crypto is to use the `BuyWidget` prebuilt UI component. ```tsx -import { PayEmbed } from "thirdweb/react"; +import { BuyWidget } from "thirdweb/react"; +import { base } from "thirdweb/chains"; function App() { return ( - ); } ``` -Check out the [PayEmbed API reference](/references/typescript/v5/PayEmbed) for more information. +Check out the [BuyWidget API reference](/references/typescript/v5/BuyWidget) for more information. diff --git a/apps/portal/src/app/react/v5/pay/transaction/page.mdx b/apps/portal/src/app/react/v5/pay/transaction/page.mdx index d506c6bd1e9..29b08007a83 100644 --- a/apps/portal/src/app/react/v5/pay/transaction/page.mdx +++ b/apps/portal/src/app/react/v5/pay/transaction/page.mdx @@ -26,53 +26,6 @@ Try out the demo for yourself in the [live playground](https://playground.thirdw /> -## Usage with PayEmbed - -You can use the `PayEmbed` component to let users execute a transaction from any chain, paying with any token. - -```tsx -import { claimTo } from "thirdweb/extensions/erc1155"; -import { PayEmbed, useActiveAccount } from "thirdweb/react"; - -function App() { - const account = useActiveAccount(); - const { data: nft } = useReadContract(getNFT, { - contract: nftContract, - tokenId: 0n, - }); - - return ( - - ); -} -``` - -Check out the [PayEmbed API reference](/references/typescript/v5/PayEmbed) for more information. - - - - - - - - ## Usage with regular transactions Any transaction sent with `useSendTransaction` or with `TransactionButton` will prompt the user to choose a different payment method if they don't have enough balance for the transaction. diff --git a/apps/portal/src/app/references/components/TDoc/utils/getSidebarLinkgroups.ts b/apps/portal/src/app/references/components/TDoc/utils/getSidebarLinkgroups.ts index d2e2808b283..1e35f1a0edd 100644 --- a/apps/portal/src/app/references/components/TDoc/utils/getSidebarLinkgroups.ts +++ b/apps/portal/src/app/references/components/TDoc/utils/getSidebarLinkgroups.ts @@ -13,7 +13,6 @@ const tagsToGroup = { "@appURI": "App URI", "@auth": "Auth", "@bridge": "Universal Bridge", - "@buyCrypto": "Buy Crypto", "@chain": "Chain", "@claimConditions": "Claim Conditions", "@client": "Client", @@ -70,7 +69,6 @@ const sidebarGroupOrder: TagKey[] = [ "@social", "@auth", "@nft", - "@buyCrypto", "@nftDrop", "@claimConditions", "@delayedReveal", diff --git a/packages/thirdweb/src/bridge/Buy.ts b/packages/thirdweb/src/bridge/Buy.ts index 5c383db576b..5333911e375 100644 --- a/packages/thirdweb/src/bridge/Buy.ts +++ b/packages/thirdweb/src/bridge/Buy.ts @@ -99,7 +99,6 @@ import type { PreparedQuote, Quote } from "./types/Quote.js"; * * @throws Will throw an error if there is an issue fetching the quote. * @bridge Buy - * @beta */ export async function quote(options: quote.Options): Promise { const { @@ -164,13 +163,13 @@ export declare namespace quote { client: ThirdwebClient; maxSteps?: number; } & ( - | { + | { buyAmountWei: bigint; } - | { + | { amount: bigint; } - ); + ); type Result = Quote & { intent: { @@ -326,7 +325,6 @@ export declare namespace quote { * * @throws Will throw an error if there is an issue fetching the quote. * @bridge Buy - * @beta */ export async function prepare( options: prepare.Options, diff --git a/packages/thirdweb/src/react/web/ui/Bridge/BuyWidget.tsx b/packages/thirdweb/src/react/web/ui/Bridge/BuyWidget.tsx index 5b29ddde2eb..8cdbecde304 100644 --- a/packages/thirdweb/src/react/web/ui/Bridge/BuyWidget.tsx +++ b/packages/thirdweb/src/react/web/ui/Bridge/BuyWidget.tsx @@ -166,15 +166,15 @@ export type BuyWidgetProps = { type UIOptionsResult = | { type: "success"; data: UIOptions } | { - type: "indexing_token"; - token: Token; - chain: Chain; - } + type: "indexing_token"; + token: Token; + chain: Chain; + } | { - type: "unsupported_token"; - tokenAddress: Address; - chain: Chain; - }; + type: "unsupported_token"; + tokenAddress: Address; + chain: Chain; + }; /** * Widget is a prebuilt UI for purchasing a specific token. @@ -261,9 +261,7 @@ type UIOptionsResult = * * Refer to the [`BuyWidgetConnectOptions`](https://portal.thirdweb.com/references/typescript/v5/BuyWidgetConnectOptions) type for more details. * - * @bridge - * @beta - * @react + * @bridge Widgets */ export function BuyWidget(props: BuyWidgetProps) { const localeQuery = useConnectLocale(props.locale || "en_US"); @@ -287,7 +285,7 @@ export function BuyWidget(props: BuyWidgetProps) { !props.tokenAddress || (isAddress(props.tokenAddress) && checksumAddress(props.tokenAddress) === - checksumAddress(NATIVE_TOKEN_ADDRESS)) + checksumAddress(NATIVE_TOKEN_ADDRESS)) ) { const ETH = await getToken( props.client, @@ -457,10 +455,10 @@ type BuyWidgetConnectOptions = { * ``` */ autoConnect?: - | { - timeout: number; - } - | boolean; + | { + timeout: number; + } + | boolean; /** * Metadata of the app that will be passed to connected wallet. Setting this is highly recommended. diff --git a/packages/thirdweb/src/react/web/ui/Bridge/CheckoutWidget.tsx b/packages/thirdweb/src/react/web/ui/Bridge/CheckoutWidget.tsx index 1828cc13a19..72e872835ca 100644 --- a/packages/thirdweb/src/react/web/ui/Bridge/CheckoutWidget.tsx +++ b/packages/thirdweb/src/react/web/ui/Bridge/CheckoutWidget.tsx @@ -172,15 +172,15 @@ export type CheckoutWidgetProps = { type UIOptionsResult = | { type: "success"; data: UIOptions } | { - type: "indexing_token"; - token: Token; - chain: Chain; - } + type: "indexing_token"; + token: Token; + chain: Chain; + } | { - type: "unsupported_token"; - tokenAddress: Address; - chain: Chain; - }; + type: "unsupported_token"; + tokenAddress: Address; + chain: Chain; + }; /** * Widget a prebuilt UI for purchasing a specific token. @@ -244,9 +244,7 @@ type UIOptionsResult = * * Refer to the [`CheckoutWidgetConnectOptions`](https://portal.thirdweb.com/references/typescript/v5/CheckoutWidgetConnectOptions) type for more details. * - * @bridge - * @beta - * @react + * @bridge Widgets */ export function CheckoutWidget(props: CheckoutWidgetProps) { const localeQuery = useConnectLocale(props.locale || "en_US"); @@ -420,10 +418,10 @@ type CheckoutWidgetConnectOptions = { * ``` */ autoConnect?: - | { - timeout: number; - } - | boolean; + | { + timeout: number; + } + | boolean; /** * Metadata of the app that will be passed to connected wallet. Setting this is highly recommended. diff --git a/packages/thirdweb/src/react/web/ui/Bridge/TransactionWidget.tsx b/packages/thirdweb/src/react/web/ui/Bridge/TransactionWidget.tsx index cb81564b601..885e5e0fb50 100644 --- a/packages/thirdweb/src/react/web/ui/Bridge/TransactionWidget.tsx +++ b/packages/thirdweb/src/react/web/ui/Bridge/TransactionWidget.tsx @@ -172,15 +172,15 @@ export type TransactionWidgetProps = { type UIOptionsResult = | { type: "success"; data: UIOptions } | { - type: "indexing_token"; - token: Token; - chain: Chain; - } + type: "indexing_token"; + token: Token; + chain: Chain; + } | { - type: "unsupported_token"; - tokenAddress: Address; - chain: Chain; - }; + type: "unsupported_token"; + tokenAddress: Address; + chain: Chain; + }; /** * Widget a prebuilt UI for purchasing a specific token. @@ -268,9 +268,7 @@ type UIOptionsResult = * * Refer to the [`TransactionWidgetConnectOptions`](https://portal.thirdweb.com/references/typescript/v5/TransactionWidgetConnectOptions) type for more details. * - * @bridge - * @beta - * @react + * @bridge Widgets */ export function TransactionWidget(props: TransactionWidgetProps) { const localeQuery = useConnectLocale(props.locale || "en_US"); @@ -445,10 +443,10 @@ type TransactionWidgetConnectOptions = { * ``` */ autoConnect?: - | { - timeout: number; - } - | boolean; + | { + timeout: number; + } + | boolean; /** * Metadata of the app that will be passed to connected wallet. Setting this is highly recommended. diff --git a/packages/thirdweb/src/react/web/ui/PayEmbed.tsx b/packages/thirdweb/src/react/web/ui/PayEmbed.tsx index bff099b1997..74f3221d91e 100644 --- a/packages/thirdweb/src/react/web/ui/PayEmbed.tsx +++ b/packages/thirdweb/src/react/web/ui/PayEmbed.tsx @@ -307,7 +307,6 @@ export type PayEmbedProps = { * * Refer to the [`PayEmbedConnectOptions`](https://portal.thirdweb.com/references/typescript/v5/PayEmbedConnectOptions) type for more details. * - * @buyCrypto * @deprecated Use `BuyWidget`, `CheckoutWidget` or `TransactionWidget` instead. */ export function PayEmbed(props: PayEmbedProps) { diff --git a/packages/thirdweb/tsdoc.json b/packages/thirdweb/tsdoc.json index 80973ced3e5..d9524f9b198 100644 --- a/packages/thirdweb/tsdoc.json +++ b/packages/thirdweb/tsdoc.json @@ -5,7 +5,6 @@ "@auth": true, "@beta": true, "@bridge": true, - "@buyCrypto": true, "@chain": true, "@client": true, "@component": true, @@ -82,11 +81,7 @@ "syntaxKind": "block", "tagName": "@walletUtils" }, - { - "syntaxKind": "block", - "tagName": "@buyCrypto" - }, - { + { "syntaxKind": "block", "tagName": "@bridge" }, From 52256db801b18ba03431d1017ba626db7a8f99a3 Mon Sep 17 00:00:00 2001 From: gregfromstl Date: Mon, 23 Jun 2025 17:12:14 -0700 Subject: [PATCH 05/10] lint --- apps/dashboard/public/robots.txt | 2 +- .../{server => client}/BuyFundsSection.tsx | 8 +-- .../components/client/PayModal.tsx | 49 ------------------- .../(chain)/[chain_id]/(chainPage)/page.tsx | 2 +- apps/login/package.json | 5 ++ packages/thirdweb/src/bridge/Buy.ts | 6 +-- .../src/react/web/ui/Bridge/BuyWidget.tsx | 26 +++++----- .../react/web/ui/Bridge/CheckoutWidget.tsx | 24 ++++----- .../react/web/ui/Bridge/TransactionWidget.tsx | 24 ++++----- .../ui/ConnectWallet/icons/CreditCardIcon.tsx | 24 --------- .../thirdweb/src/react/web/ui/PayEmbed.tsx | 14 +++--- pnpm-lock.yaml | 2 + 12 files changed, 60 insertions(+), 126 deletions(-) rename apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/{server => client}/BuyFundsSection.tsx (85%) delete mode 100644 apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/client/PayModal.tsx create mode 100644 apps/login/package.json delete mode 100644 packages/thirdweb/src/react/web/ui/ConnectWallet/icons/CreditCardIcon.tsx diff --git a/apps/dashboard/public/robots.txt b/apps/dashboard/public/robots.txt index 2fd4519be71..d836e4c5e14 100644 --- a/apps/dashboard/public/robots.txt +++ b/apps/dashboard/public/robots.txt @@ -1,6 +1,6 @@ # * User-agent: * -Allow: / +Disallow: / # Host Host: https://thirdweb.com diff --git a/apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/BuyFundsSection.tsx b/apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/client/BuyFundsSection.tsx similarity index 85% rename from apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/BuyFundsSection.tsx rename to apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/client/BuyFundsSection.tsx index 3c0df283629..eea75448b4e 100644 --- a/apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/BuyFundsSection.tsx +++ b/apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/client/BuyFundsSection.tsx @@ -1,6 +1,6 @@ +"use client"; import { defineChain, type ThirdwebClient } from "thirdweb"; import type { ChainMetadata } from "thirdweb/chains"; -import { SectionTitle } from "./SectionTitle"; import { BuyWidget } from "thirdweb/react"; export function BuyFundsSection(props: { @@ -9,11 +9,11 @@ export function BuyFundsSection(props: { }) { return (
-
); diff --git a/apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/client/PayModal.tsx b/apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/client/PayModal.tsx deleted file mode 100644 index 890519d706b..00000000000 --- a/apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/client/PayModal.tsx +++ /dev/null @@ -1,49 +0,0 @@ -"use client"; -import { useTheme } from "next-themes"; -import type { ThirdwebClient } from "thirdweb"; -import { PayEmbed } from "thirdweb/react"; -import { Button } from "@/components/ui/button"; -import { Dialog, DialogContent, DialogTrigger } from "@/components/ui/dialog"; -import { defineDashboardChain } from "@/lib/defineDashboardChain"; -import { getSDKTheme } from "../../../../../../../../@/utils/sdk-component-theme"; - -export function PayModalButton(props: { - chainId: number; - label: string; - client: ThirdwebClient; -}) { - const { theme } = useTheme(); - - return ( - - - - - - - - - ); -} diff --git a/apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/page.tsx b/apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/page.tsx index d9915174260..ea827413f69 100644 --- a/apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/page.tsx +++ b/apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/page.tsx @@ -2,8 +2,8 @@ import { CircleAlertIcon } from "lucide-react"; import { getClientThirdwebClient } from "@/constants/thirdweb-client.client"; import { getRawAccount } from "../../../../account/settings/getAccount"; import { getChain, getChainMetadata } from "../../utils"; +import { BuyFundsSection } from "./components/client/BuyFundsSection"; import NextSteps from "./components/client/NextSteps"; -import { BuyFundsSection } from "./components/server/BuyFundsSection"; import { ChainOverviewSection } from "./components/server/ChainOverviewSection"; import { ClaimChainSection } from "./components/server/ClaimChainSection"; import { ChainCTA } from "./components/server/cta-card"; diff --git a/apps/login/package.json b/apps/login/package.json new file mode 100644 index 00000000000..8a2d4fc1c11 --- /dev/null +++ b/apps/login/package.json @@ -0,0 +1,5 @@ +{ + "name": "login", + "version": "0.0.0", + "private": true +} \ No newline at end of file diff --git a/packages/thirdweb/src/bridge/Buy.ts b/packages/thirdweb/src/bridge/Buy.ts index 5333911e375..b213a22e53d 100644 --- a/packages/thirdweb/src/bridge/Buy.ts +++ b/packages/thirdweb/src/bridge/Buy.ts @@ -163,13 +163,13 @@ export declare namespace quote { client: ThirdwebClient; maxSteps?: number; } & ( - | { + | { buyAmountWei: bigint; } - | { + | { amount: bigint; } - ); + ); type Result = Quote & { intent: { diff --git a/packages/thirdweb/src/react/web/ui/Bridge/BuyWidget.tsx b/packages/thirdweb/src/react/web/ui/Bridge/BuyWidget.tsx index 8cdbecde304..b653459d6da 100644 --- a/packages/thirdweb/src/react/web/ui/Bridge/BuyWidget.tsx +++ b/packages/thirdweb/src/react/web/ui/Bridge/BuyWidget.tsx @@ -166,15 +166,15 @@ export type BuyWidgetProps = { type UIOptionsResult = | { type: "success"; data: UIOptions } | { - type: "indexing_token"; - token: Token; - chain: Chain; - } + type: "indexing_token"; + token: Token; + chain: Chain; + } | { - type: "unsupported_token"; - tokenAddress: Address; - chain: Chain; - }; + type: "unsupported_token"; + tokenAddress: Address; + chain: Chain; + }; /** * Widget is a prebuilt UI for purchasing a specific token. @@ -285,7 +285,7 @@ export function BuyWidget(props: BuyWidgetProps) { !props.tokenAddress || (isAddress(props.tokenAddress) && checksumAddress(props.tokenAddress) === - checksumAddress(NATIVE_TOKEN_ADDRESS)) + checksumAddress(NATIVE_TOKEN_ADDRESS)) ) { const ETH = await getToken( props.client, @@ -455,10 +455,10 @@ type BuyWidgetConnectOptions = { * ``` */ autoConnect?: - | { - timeout: number; - } - | boolean; + | { + timeout: number; + } + | boolean; /** * Metadata of the app that will be passed to connected wallet. Setting this is highly recommended. diff --git a/packages/thirdweb/src/react/web/ui/Bridge/CheckoutWidget.tsx b/packages/thirdweb/src/react/web/ui/Bridge/CheckoutWidget.tsx index 72e872835ca..7a030e9bedf 100644 --- a/packages/thirdweb/src/react/web/ui/Bridge/CheckoutWidget.tsx +++ b/packages/thirdweb/src/react/web/ui/Bridge/CheckoutWidget.tsx @@ -172,15 +172,15 @@ export type CheckoutWidgetProps = { type UIOptionsResult = | { type: "success"; data: UIOptions } | { - type: "indexing_token"; - token: Token; - chain: Chain; - } + type: "indexing_token"; + token: Token; + chain: Chain; + } | { - type: "unsupported_token"; - tokenAddress: Address; - chain: Chain; - }; + type: "unsupported_token"; + tokenAddress: Address; + chain: Chain; + }; /** * Widget a prebuilt UI for purchasing a specific token. @@ -418,10 +418,10 @@ type CheckoutWidgetConnectOptions = { * ``` */ autoConnect?: - | { - timeout: number; - } - | boolean; + | { + timeout: number; + } + | boolean; /** * Metadata of the app that will be passed to connected wallet. Setting this is highly recommended. diff --git a/packages/thirdweb/src/react/web/ui/Bridge/TransactionWidget.tsx b/packages/thirdweb/src/react/web/ui/Bridge/TransactionWidget.tsx index 885e5e0fb50..d15908b6879 100644 --- a/packages/thirdweb/src/react/web/ui/Bridge/TransactionWidget.tsx +++ b/packages/thirdweb/src/react/web/ui/Bridge/TransactionWidget.tsx @@ -172,15 +172,15 @@ export type TransactionWidgetProps = { type UIOptionsResult = | { type: "success"; data: UIOptions } | { - type: "indexing_token"; - token: Token; - chain: Chain; - } + type: "indexing_token"; + token: Token; + chain: Chain; + } | { - type: "unsupported_token"; - tokenAddress: Address; - chain: Chain; - }; + type: "unsupported_token"; + tokenAddress: Address; + chain: Chain; + }; /** * Widget a prebuilt UI for purchasing a specific token. @@ -443,10 +443,10 @@ type TransactionWidgetConnectOptions = { * ``` */ autoConnect?: - | { - timeout: number; - } - | boolean; + | { + timeout: number; + } + | boolean; /** * Metadata of the app that will be passed to connected wallet. Setting this is highly recommended. diff --git a/packages/thirdweb/src/react/web/ui/ConnectWallet/icons/CreditCardIcon.tsx b/packages/thirdweb/src/react/web/ui/ConnectWallet/icons/CreditCardIcon.tsx deleted file mode 100644 index 47d9713793e..00000000000 --- a/packages/thirdweb/src/react/web/ui/ConnectWallet/icons/CreditCardIcon.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import type { IconFC } from "./types.js"; - -/** - * @internal - */ -export const CreditCardIcon: IconFC = (props) => { - return ( - - - - - ); -}; diff --git a/packages/thirdweb/src/react/web/ui/PayEmbed.tsx b/packages/thirdweb/src/react/web/ui/PayEmbed.tsx index 74f3221d91e..a43d3346d34 100644 --- a/packages/thirdweb/src/react/web/ui/PayEmbed.tsx +++ b/packages/thirdweb/src/react/web/ui/PayEmbed.tsx @@ -356,9 +356,9 @@ export function PayEmbed(props: PayEmbedProps) { amount={props.payOptions.prefillBuy.amount || "0.01"} chain={props.payOptions.prefillBuy.chain} client={props.client} + onSuccess={() => props.payOptions?.onPurchaseSuccess?.()} theme={theme} title={metadata?.name || "Buy"} - onSuccess={() => props.payOptions?.onPurchaseSuccess?.()} tokenAddress={ props.payOptions.prefillBuy.token?.address as Address | undefined } @@ -375,8 +375,8 @@ export function PayEmbed(props: PayEmbedProps) { description={metadata?.description} image={metadata?.image} name={metadata?.name || "Checkout"} - seller={props.payOptions.paymentInfo.sellerAddress as Address} onSuccess={() => props.payOptions?.onPurchaseSuccess?.()} + seller={props.payOptions.paymentInfo.sellerAddress as Address} theme={theme} tokenAddress={ props.payOptions.paymentInfo.token?.address as Address | undefined @@ -391,8 +391,8 @@ export function PayEmbed(props: PayEmbedProps) { client={props.client} description={metadata?.description} image={metadata?.image} - theme={theme} onSuccess={() => props.payOptions?.onPurchaseSuccess?.()} + theme={theme} title={metadata?.name} transaction={props.payOptions.transaction} /> @@ -513,10 +513,10 @@ export type PayEmbedConnectOptions = { * ``` */ autoConnect?: - | { - timeout: number; - } - | boolean; + | { + timeout: number; + } + | boolean; /** * Metadata of the app that will be passed to connected wallet. Setting this is highly recommended. diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 11c7bd8ed2e..9bf87c8e179 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -411,6 +411,8 @@ importers: specifier: 5.8.3 version: 5.8.3 + apps/login: {} + apps/nebula: dependencies: '@hookform/resolvers': From cf9e789d556b9efb71baafbf0033128a47b3f5cb Mon Sep 17 00:00:00 2001 From: gregfromstl Date: Tue, 24 Jun 2025 10:10:29 -0700 Subject: [PATCH 06/10] Revert "lint" This reverts commit 52256db801b18ba03431d1017ba626db7a8f99a3. --- apps/dashboard/public/robots.txt | 2 +- .../components/client/PayModal.tsx | 49 +++++++++++++++++++ .../{client => server}/BuyFundsSection.tsx | 8 +-- .../(chain)/[chain_id]/(chainPage)/page.tsx | 2 +- apps/login/package.json | 5 -- packages/thirdweb/src/bridge/Buy.ts | 6 +-- .../src/react/web/ui/Bridge/BuyWidget.tsx | 26 +++++----- .../react/web/ui/Bridge/CheckoutWidget.tsx | 24 ++++----- .../react/web/ui/Bridge/TransactionWidget.tsx | 24 ++++----- .../ui/ConnectWallet/icons/CreditCardIcon.tsx | 24 +++++++++ .../thirdweb/src/react/web/ui/PayEmbed.tsx | 14 +++--- pnpm-lock.yaml | 2 - 12 files changed, 126 insertions(+), 60 deletions(-) create mode 100644 apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/client/PayModal.tsx rename apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/{client => server}/BuyFundsSection.tsx (85%) delete mode 100644 apps/login/package.json create mode 100644 packages/thirdweb/src/react/web/ui/ConnectWallet/icons/CreditCardIcon.tsx diff --git a/apps/dashboard/public/robots.txt b/apps/dashboard/public/robots.txt index d836e4c5e14..2fd4519be71 100644 --- a/apps/dashboard/public/robots.txt +++ b/apps/dashboard/public/robots.txt @@ -1,6 +1,6 @@ # * User-agent: * -Disallow: / +Allow: / # Host Host: https://thirdweb.com diff --git a/apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/client/PayModal.tsx b/apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/client/PayModal.tsx new file mode 100644 index 00000000000..890519d706b --- /dev/null +++ b/apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/client/PayModal.tsx @@ -0,0 +1,49 @@ +"use client"; +import { useTheme } from "next-themes"; +import type { ThirdwebClient } from "thirdweb"; +import { PayEmbed } from "thirdweb/react"; +import { Button } from "@/components/ui/button"; +import { Dialog, DialogContent, DialogTrigger } from "@/components/ui/dialog"; +import { defineDashboardChain } from "@/lib/defineDashboardChain"; +import { getSDKTheme } from "../../../../../../../../@/utils/sdk-component-theme"; + +export function PayModalButton(props: { + chainId: number; + label: string; + client: ThirdwebClient; +}) { + const { theme } = useTheme(); + + return ( + + + + + + + + + ); +} diff --git a/apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/client/BuyFundsSection.tsx b/apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/BuyFundsSection.tsx similarity index 85% rename from apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/client/BuyFundsSection.tsx rename to apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/BuyFundsSection.tsx index eea75448b4e..3c0df283629 100644 --- a/apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/client/BuyFundsSection.tsx +++ b/apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/BuyFundsSection.tsx @@ -1,6 +1,6 @@ -"use client"; import { defineChain, type ThirdwebClient } from "thirdweb"; import type { ChainMetadata } from "thirdweb/chains"; +import { SectionTitle } from "./SectionTitle"; import { BuyWidget } from "thirdweb/react"; export function BuyFundsSection(props: { @@ -9,11 +9,11 @@ export function BuyFundsSection(props: { }) { return (
+
); diff --git a/apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/page.tsx b/apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/page.tsx index ea827413f69..d9915174260 100644 --- a/apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/page.tsx +++ b/apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/page.tsx @@ -2,8 +2,8 @@ import { CircleAlertIcon } from "lucide-react"; import { getClientThirdwebClient } from "@/constants/thirdweb-client.client"; import { getRawAccount } from "../../../../account/settings/getAccount"; import { getChain, getChainMetadata } from "../../utils"; -import { BuyFundsSection } from "./components/client/BuyFundsSection"; import NextSteps from "./components/client/NextSteps"; +import { BuyFundsSection } from "./components/server/BuyFundsSection"; import { ChainOverviewSection } from "./components/server/ChainOverviewSection"; import { ClaimChainSection } from "./components/server/ClaimChainSection"; import { ChainCTA } from "./components/server/cta-card"; diff --git a/apps/login/package.json b/apps/login/package.json deleted file mode 100644 index 8a2d4fc1c11..00000000000 --- a/apps/login/package.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "name": "login", - "version": "0.0.0", - "private": true -} \ No newline at end of file diff --git a/packages/thirdweb/src/bridge/Buy.ts b/packages/thirdweb/src/bridge/Buy.ts index b213a22e53d..5333911e375 100644 --- a/packages/thirdweb/src/bridge/Buy.ts +++ b/packages/thirdweb/src/bridge/Buy.ts @@ -163,13 +163,13 @@ export declare namespace quote { client: ThirdwebClient; maxSteps?: number; } & ( - | { + | { buyAmountWei: bigint; } - | { + | { amount: bigint; } - ); + ); type Result = Quote & { intent: { diff --git a/packages/thirdweb/src/react/web/ui/Bridge/BuyWidget.tsx b/packages/thirdweb/src/react/web/ui/Bridge/BuyWidget.tsx index b653459d6da..8cdbecde304 100644 --- a/packages/thirdweb/src/react/web/ui/Bridge/BuyWidget.tsx +++ b/packages/thirdweb/src/react/web/ui/Bridge/BuyWidget.tsx @@ -166,15 +166,15 @@ export type BuyWidgetProps = { type UIOptionsResult = | { type: "success"; data: UIOptions } | { - type: "indexing_token"; - token: Token; - chain: Chain; - } + type: "indexing_token"; + token: Token; + chain: Chain; + } | { - type: "unsupported_token"; - tokenAddress: Address; - chain: Chain; - }; + type: "unsupported_token"; + tokenAddress: Address; + chain: Chain; + }; /** * Widget is a prebuilt UI for purchasing a specific token. @@ -285,7 +285,7 @@ export function BuyWidget(props: BuyWidgetProps) { !props.tokenAddress || (isAddress(props.tokenAddress) && checksumAddress(props.tokenAddress) === - checksumAddress(NATIVE_TOKEN_ADDRESS)) + checksumAddress(NATIVE_TOKEN_ADDRESS)) ) { const ETH = await getToken( props.client, @@ -455,10 +455,10 @@ type BuyWidgetConnectOptions = { * ``` */ autoConnect?: - | { - timeout: number; - } - | boolean; + | { + timeout: number; + } + | boolean; /** * Metadata of the app that will be passed to connected wallet. Setting this is highly recommended. diff --git a/packages/thirdweb/src/react/web/ui/Bridge/CheckoutWidget.tsx b/packages/thirdweb/src/react/web/ui/Bridge/CheckoutWidget.tsx index 7a030e9bedf..72e872835ca 100644 --- a/packages/thirdweb/src/react/web/ui/Bridge/CheckoutWidget.tsx +++ b/packages/thirdweb/src/react/web/ui/Bridge/CheckoutWidget.tsx @@ -172,15 +172,15 @@ export type CheckoutWidgetProps = { type UIOptionsResult = | { type: "success"; data: UIOptions } | { - type: "indexing_token"; - token: Token; - chain: Chain; - } + type: "indexing_token"; + token: Token; + chain: Chain; + } | { - type: "unsupported_token"; - tokenAddress: Address; - chain: Chain; - }; + type: "unsupported_token"; + tokenAddress: Address; + chain: Chain; + }; /** * Widget a prebuilt UI for purchasing a specific token. @@ -418,10 +418,10 @@ type CheckoutWidgetConnectOptions = { * ``` */ autoConnect?: - | { - timeout: number; - } - | boolean; + | { + timeout: number; + } + | boolean; /** * Metadata of the app that will be passed to connected wallet. Setting this is highly recommended. diff --git a/packages/thirdweb/src/react/web/ui/Bridge/TransactionWidget.tsx b/packages/thirdweb/src/react/web/ui/Bridge/TransactionWidget.tsx index d15908b6879..885e5e0fb50 100644 --- a/packages/thirdweb/src/react/web/ui/Bridge/TransactionWidget.tsx +++ b/packages/thirdweb/src/react/web/ui/Bridge/TransactionWidget.tsx @@ -172,15 +172,15 @@ export type TransactionWidgetProps = { type UIOptionsResult = | { type: "success"; data: UIOptions } | { - type: "indexing_token"; - token: Token; - chain: Chain; - } + type: "indexing_token"; + token: Token; + chain: Chain; + } | { - type: "unsupported_token"; - tokenAddress: Address; - chain: Chain; - }; + type: "unsupported_token"; + tokenAddress: Address; + chain: Chain; + }; /** * Widget a prebuilt UI for purchasing a specific token. @@ -443,10 +443,10 @@ type TransactionWidgetConnectOptions = { * ``` */ autoConnect?: - | { - timeout: number; - } - | boolean; + | { + timeout: number; + } + | boolean; /** * Metadata of the app that will be passed to connected wallet. Setting this is highly recommended. diff --git a/packages/thirdweb/src/react/web/ui/ConnectWallet/icons/CreditCardIcon.tsx b/packages/thirdweb/src/react/web/ui/ConnectWallet/icons/CreditCardIcon.tsx new file mode 100644 index 00000000000..47d9713793e --- /dev/null +++ b/packages/thirdweb/src/react/web/ui/ConnectWallet/icons/CreditCardIcon.tsx @@ -0,0 +1,24 @@ +import type { IconFC } from "./types.js"; + +/** + * @internal + */ +export const CreditCardIcon: IconFC = (props) => { + return ( + + + + + ); +}; diff --git a/packages/thirdweb/src/react/web/ui/PayEmbed.tsx b/packages/thirdweb/src/react/web/ui/PayEmbed.tsx index a43d3346d34..74f3221d91e 100644 --- a/packages/thirdweb/src/react/web/ui/PayEmbed.tsx +++ b/packages/thirdweb/src/react/web/ui/PayEmbed.tsx @@ -356,9 +356,9 @@ export function PayEmbed(props: PayEmbedProps) { amount={props.payOptions.prefillBuy.amount || "0.01"} chain={props.payOptions.prefillBuy.chain} client={props.client} - onSuccess={() => props.payOptions?.onPurchaseSuccess?.()} theme={theme} title={metadata?.name || "Buy"} + onSuccess={() => props.payOptions?.onPurchaseSuccess?.()} tokenAddress={ props.payOptions.prefillBuy.token?.address as Address | undefined } @@ -375,8 +375,8 @@ export function PayEmbed(props: PayEmbedProps) { description={metadata?.description} image={metadata?.image} name={metadata?.name || "Checkout"} - onSuccess={() => props.payOptions?.onPurchaseSuccess?.()} seller={props.payOptions.paymentInfo.sellerAddress as Address} + onSuccess={() => props.payOptions?.onPurchaseSuccess?.()} theme={theme} tokenAddress={ props.payOptions.paymentInfo.token?.address as Address | undefined @@ -391,8 +391,8 @@ export function PayEmbed(props: PayEmbedProps) { client={props.client} description={metadata?.description} image={metadata?.image} - onSuccess={() => props.payOptions?.onPurchaseSuccess?.()} theme={theme} + onSuccess={() => props.payOptions?.onPurchaseSuccess?.()} title={metadata?.name} transaction={props.payOptions.transaction} /> @@ -513,10 +513,10 @@ export type PayEmbedConnectOptions = { * ``` */ autoConnect?: - | { - timeout: number; - } - | boolean; + | { + timeout: number; + } + | boolean; /** * Metadata of the app that will be passed to connected wallet. Setting this is highly recommended. diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9bf87c8e179..11c7bd8ed2e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -411,8 +411,6 @@ importers: specifier: 5.8.3 version: 5.8.3 - apps/login: {} - apps/nebula: dependencies: '@hookform/resolvers': From 42ba2865a897e0af5900016110d6e007931e69aa Mon Sep 17 00:00:00 2001 From: gregfromstl Date: Tue, 24 Jun 2025 10:12:30 -0700 Subject: [PATCH 07/10] lint --- .../components/server/BuyFundsSection.tsx | 7 ++--- packages/thirdweb/src/bridge/Buy.ts | 6 ++--- .../src/react/web/ui/Bridge/BuyWidget.tsx | 26 +++++++++---------- .../react/web/ui/Bridge/CheckoutWidget.tsx | 24 ++++++++--------- .../react/web/ui/Bridge/TransactionWidget.tsx | 24 ++++++++--------- .../thirdweb/src/react/web/ui/PayEmbed.tsx | 14 +++++----- 6 files changed, 51 insertions(+), 50 deletions(-) diff --git a/apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/BuyFundsSection.tsx b/apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/BuyFundsSection.tsx index 3c0df283629..c694addea09 100644 --- a/apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/BuyFundsSection.tsx +++ b/apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/BuyFundsSection.tsx @@ -1,7 +1,7 @@ import { defineChain, type ThirdwebClient } from "thirdweb"; import type { ChainMetadata } from "thirdweb/chains"; -import { SectionTitle } from "./SectionTitle"; import { BuyWidget } from "thirdweb/react"; +import { SectionTitle } from "./SectionTitle"; export function BuyFundsSection(props: { chain: ChainMetadata; @@ -11,9 +11,10 @@ export function BuyFundsSection(props: {
); diff --git a/packages/thirdweb/src/bridge/Buy.ts b/packages/thirdweb/src/bridge/Buy.ts index 5333911e375..b213a22e53d 100644 --- a/packages/thirdweb/src/bridge/Buy.ts +++ b/packages/thirdweb/src/bridge/Buy.ts @@ -163,13 +163,13 @@ export declare namespace quote { client: ThirdwebClient; maxSteps?: number; } & ( - | { + | { buyAmountWei: bigint; } - | { + | { amount: bigint; } - ); + ); type Result = Quote & { intent: { diff --git a/packages/thirdweb/src/react/web/ui/Bridge/BuyWidget.tsx b/packages/thirdweb/src/react/web/ui/Bridge/BuyWidget.tsx index 8cdbecde304..b653459d6da 100644 --- a/packages/thirdweb/src/react/web/ui/Bridge/BuyWidget.tsx +++ b/packages/thirdweb/src/react/web/ui/Bridge/BuyWidget.tsx @@ -166,15 +166,15 @@ export type BuyWidgetProps = { type UIOptionsResult = | { type: "success"; data: UIOptions } | { - type: "indexing_token"; - token: Token; - chain: Chain; - } + type: "indexing_token"; + token: Token; + chain: Chain; + } | { - type: "unsupported_token"; - tokenAddress: Address; - chain: Chain; - }; + type: "unsupported_token"; + tokenAddress: Address; + chain: Chain; + }; /** * Widget is a prebuilt UI for purchasing a specific token. @@ -285,7 +285,7 @@ export function BuyWidget(props: BuyWidgetProps) { !props.tokenAddress || (isAddress(props.tokenAddress) && checksumAddress(props.tokenAddress) === - checksumAddress(NATIVE_TOKEN_ADDRESS)) + checksumAddress(NATIVE_TOKEN_ADDRESS)) ) { const ETH = await getToken( props.client, @@ -455,10 +455,10 @@ type BuyWidgetConnectOptions = { * ``` */ autoConnect?: - | { - timeout: number; - } - | boolean; + | { + timeout: number; + } + | boolean; /** * Metadata of the app that will be passed to connected wallet. Setting this is highly recommended. diff --git a/packages/thirdweb/src/react/web/ui/Bridge/CheckoutWidget.tsx b/packages/thirdweb/src/react/web/ui/Bridge/CheckoutWidget.tsx index 72e872835ca..7a030e9bedf 100644 --- a/packages/thirdweb/src/react/web/ui/Bridge/CheckoutWidget.tsx +++ b/packages/thirdweb/src/react/web/ui/Bridge/CheckoutWidget.tsx @@ -172,15 +172,15 @@ export type CheckoutWidgetProps = { type UIOptionsResult = | { type: "success"; data: UIOptions } | { - type: "indexing_token"; - token: Token; - chain: Chain; - } + type: "indexing_token"; + token: Token; + chain: Chain; + } | { - type: "unsupported_token"; - tokenAddress: Address; - chain: Chain; - }; + type: "unsupported_token"; + tokenAddress: Address; + chain: Chain; + }; /** * Widget a prebuilt UI for purchasing a specific token. @@ -418,10 +418,10 @@ type CheckoutWidgetConnectOptions = { * ``` */ autoConnect?: - | { - timeout: number; - } - | boolean; + | { + timeout: number; + } + | boolean; /** * Metadata of the app that will be passed to connected wallet. Setting this is highly recommended. diff --git a/packages/thirdweb/src/react/web/ui/Bridge/TransactionWidget.tsx b/packages/thirdweb/src/react/web/ui/Bridge/TransactionWidget.tsx index 885e5e0fb50..d15908b6879 100644 --- a/packages/thirdweb/src/react/web/ui/Bridge/TransactionWidget.tsx +++ b/packages/thirdweb/src/react/web/ui/Bridge/TransactionWidget.tsx @@ -172,15 +172,15 @@ export type TransactionWidgetProps = { type UIOptionsResult = | { type: "success"; data: UIOptions } | { - type: "indexing_token"; - token: Token; - chain: Chain; - } + type: "indexing_token"; + token: Token; + chain: Chain; + } | { - type: "unsupported_token"; - tokenAddress: Address; - chain: Chain; - }; + type: "unsupported_token"; + tokenAddress: Address; + chain: Chain; + }; /** * Widget a prebuilt UI for purchasing a specific token. @@ -443,10 +443,10 @@ type TransactionWidgetConnectOptions = { * ``` */ autoConnect?: - | { - timeout: number; - } - | boolean; + | { + timeout: number; + } + | boolean; /** * Metadata of the app that will be passed to connected wallet. Setting this is highly recommended. diff --git a/packages/thirdweb/src/react/web/ui/PayEmbed.tsx b/packages/thirdweb/src/react/web/ui/PayEmbed.tsx index 74f3221d91e..a43d3346d34 100644 --- a/packages/thirdweb/src/react/web/ui/PayEmbed.tsx +++ b/packages/thirdweb/src/react/web/ui/PayEmbed.tsx @@ -356,9 +356,9 @@ export function PayEmbed(props: PayEmbedProps) { amount={props.payOptions.prefillBuy.amount || "0.01"} chain={props.payOptions.prefillBuy.chain} client={props.client} + onSuccess={() => props.payOptions?.onPurchaseSuccess?.()} theme={theme} title={metadata?.name || "Buy"} - onSuccess={() => props.payOptions?.onPurchaseSuccess?.()} tokenAddress={ props.payOptions.prefillBuy.token?.address as Address | undefined } @@ -375,8 +375,8 @@ export function PayEmbed(props: PayEmbedProps) { description={metadata?.description} image={metadata?.image} name={metadata?.name || "Checkout"} - seller={props.payOptions.paymentInfo.sellerAddress as Address} onSuccess={() => props.payOptions?.onPurchaseSuccess?.()} + seller={props.payOptions.paymentInfo.sellerAddress as Address} theme={theme} tokenAddress={ props.payOptions.paymentInfo.token?.address as Address | undefined @@ -391,8 +391,8 @@ export function PayEmbed(props: PayEmbedProps) { client={props.client} description={metadata?.description} image={metadata?.image} - theme={theme} onSuccess={() => props.payOptions?.onPurchaseSuccess?.()} + theme={theme} title={metadata?.name} transaction={props.payOptions.transaction} /> @@ -513,10 +513,10 @@ export type PayEmbedConnectOptions = { * ``` */ autoConnect?: - | { - timeout: number; - } - | boolean; + | { + timeout: number; + } + | boolean; /** * Metadata of the app that will be passed to connected wallet. Setting this is highly recommended. From acdf99546ee60081c85d9f1a5a267caac0e0e0be Mon Sep 17 00:00:00 2001 From: gregfromstl Date: Tue, 24 Jun 2025 10:32:20 -0700 Subject: [PATCH 08/10] requested changes --- .../src/app/react/v5/pay/transaction/page.mdx | 26 ++++++++++++++++- .../web/ui/Bridge/BridgeOrchestrator.tsx | 27 +++++++++--------- .../src/react/web/ui/Bridge/BuyWidget.tsx | 28 +++++++++---------- .../react/web/ui/Bridge/CheckoutWidget.tsx | 26 ++++++++--------- .../src/react/web/ui/Bridge/ErrorBanner.tsx | 2 +- .../src/react/web/ui/Bridge/QuoteLoader.tsx | 6 ++-- .../react/web/ui/Bridge/TransactionWidget.tsx | 26 ++++++++--------- .../web/ui/Bridge/UnsupportedTokenScreen.tsx | 2 +- .../Bridge/payment-details/PaymentDetails.tsx | 10 +++---- .../Bridge/payment-success/SuccessScreen.tsx | 2 +- .../stories/Bridge/SuccessScreen.stories.tsx | 21 ++++++-------- 11 files changed, 100 insertions(+), 76 deletions(-) diff --git a/apps/portal/src/app/react/v5/pay/transaction/page.mdx b/apps/portal/src/app/react/v5/pay/transaction/page.mdx index 29b08007a83..a82e85715eb 100644 --- a/apps/portal/src/app/react/v5/pay/transaction/page.mdx +++ b/apps/portal/src/app/react/v5/pay/transaction/page.mdx @@ -30,4 +30,28 @@ Try out the demo for yourself in the [live playground](https://playground.thirdw Any transaction sent with `useSendTransaction` or with `TransactionButton` will prompt the user to choose a different payment method if they don't have enough balance for the transaction. -You can turn off this behaviour by setting the `payModal` option to `false`. \ No newline at end of file +You can turn off this behaviour by setting the `payModal` option to `false`. + +## Usage with TransactionWidget + +The `TransactionWidget` component provides a complete UI for executing transactions with built-in cross-chain payment support. + +```tsx +import { TransactionWidget } from "thirdweb/react"; +import { prepareContractCall } from "thirdweb"; + +function MyComponent() { + return ( + + ); +} +``` \ No newline at end of file diff --git a/packages/thirdweb/src/react/web/ui/Bridge/BridgeOrchestrator.tsx b/packages/thirdweb/src/react/web/ui/Bridge/BridgeOrchestrator.tsx index 2c77ded3dbc..6d3adf5707e 100644 --- a/packages/thirdweb/src/react/web/ui/Bridge/BridgeOrchestrator.tsx +++ b/packages/thirdweb/src/react/web/ui/Bridge/BridgeOrchestrator.tsx @@ -40,20 +40,20 @@ export type UIOptions = Prettify< }; } & ( | { - mode: "fund_wallet"; - destinationToken: Token; - initialAmount?: string; - presetOptions?: [number, number, number]; - } + mode: "fund_wallet"; + destinationToken: Token; + initialAmount?: string; + presetOptions?: [number, number, number]; + } | { - mode: "direct_payment"; - paymentInfo: { - sellerAddress: Address; - token: Token; - amount: string; - feePayer?: "sender" | "receiver"; - }; - } + mode: "direct_payment"; + paymentInfo: { + sellerAddress: Address; + token: Token; + amount: string; + feePayer?: "sender" | "receiver"; + }; + } | { mode: "transaction"; transaction: PreparedTransaction } ) >; @@ -286,6 +286,7 @@ export function BridgeOrchestrator({ onBack={() => { send({ type: "BACK" }); }} + mode={uiOptions.mode} onError={handleError} onQuoteReceived={handleQuoteReceived} paymentLinkId={paymentLinkId} diff --git a/packages/thirdweb/src/react/web/ui/Bridge/BuyWidget.tsx b/packages/thirdweb/src/react/web/ui/Bridge/BuyWidget.tsx index b653459d6da..47a9955a005 100644 --- a/packages/thirdweb/src/react/web/ui/Bridge/BuyWidget.tsx +++ b/packages/thirdweb/src/react/web/ui/Bridge/BuyWidget.tsx @@ -166,15 +166,15 @@ export type BuyWidgetProps = { type UIOptionsResult = | { type: "success"; data: UIOptions } | { - type: "indexing_token"; - token: Token; - chain: Chain; - } + type: "indexing_token"; + token: Token; + chain: Chain; + } | { - type: "unsupported_token"; - tokenAddress: Address; - chain: Chain; - }; + type: "unsupported_token"; + tokenAddress: Address; + chain: Chain; + }; /** * Widget is a prebuilt UI for purchasing a specific token. @@ -271,7 +271,7 @@ export function BuyWidget(props: BuyWidgetProps) { queryFn: () => { trackPayEvent({ client: props.client, - event: "buy_widget:render", + event: "ub:ui:buy_widget:render", toChainId: props.chain.id, toToken: props.tokenAddress, }); @@ -285,7 +285,7 @@ export function BuyWidget(props: BuyWidgetProps) { !props.tokenAddress || (isAddress(props.tokenAddress) && checksumAddress(props.tokenAddress) === - checksumAddress(NATIVE_TOKEN_ADDRESS)) + checksumAddress(NATIVE_TOKEN_ADDRESS)) ) { const ETH = await getToken( props.client, @@ -455,10 +455,10 @@ type BuyWidgetConnectOptions = { * ``` */ autoConnect?: - | { - timeout: number; - } - | boolean; + | { + timeout: number; + } + | boolean; /** * Metadata of the app that will be passed to connected wallet. Setting this is highly recommended. diff --git a/packages/thirdweb/src/react/web/ui/Bridge/CheckoutWidget.tsx b/packages/thirdweb/src/react/web/ui/Bridge/CheckoutWidget.tsx index 7a030e9bedf..f51db335594 100644 --- a/packages/thirdweb/src/react/web/ui/Bridge/CheckoutWidget.tsx +++ b/packages/thirdweb/src/react/web/ui/Bridge/CheckoutWidget.tsx @@ -172,15 +172,15 @@ export type CheckoutWidgetProps = { type UIOptionsResult = | { type: "success"; data: UIOptions } | { - type: "indexing_token"; - token: Token; - chain: Chain; - } + type: "indexing_token"; + token: Token; + chain: Chain; + } | { - type: "unsupported_token"; - tokenAddress: Address; - chain: Chain; - }; + type: "unsupported_token"; + tokenAddress: Address; + chain: Chain; + }; /** * Widget a prebuilt UI for purchasing a specific token. @@ -254,7 +254,7 @@ export function CheckoutWidget(props: CheckoutWidgetProps) { queryFn: () => { trackPayEvent({ client: props.client, - event: "checkout_widget:render", + event: "ub:ui:checkout_widget:render", toChainId: props.chain.id, toToken: props.tokenAddress, }); @@ -418,10 +418,10 @@ type CheckoutWidgetConnectOptions = { * ``` */ autoConnect?: - | { - timeout: number; - } - | boolean; + | { + timeout: number; + } + | boolean; /** * Metadata of the app that will be passed to connected wallet. Setting this is highly recommended. diff --git a/packages/thirdweb/src/react/web/ui/Bridge/ErrorBanner.tsx b/packages/thirdweb/src/react/web/ui/Bridge/ErrorBanner.tsx index 3d7d647f71d..8cdc65efac5 100644 --- a/packages/thirdweb/src/react/web/ui/Bridge/ErrorBanner.tsx +++ b/packages/thirdweb/src/react/web/ui/Bridge/ErrorBanner.tsx @@ -43,7 +43,7 @@ export function ErrorBanner({ trackPayEvent({ client, error: error.message, - event: "error", + event: "ub:ui:error", }); }, queryKey: ["error_banner", userMessage], diff --git a/packages/thirdweb/src/react/web/ui/Bridge/QuoteLoader.tsx b/packages/thirdweb/src/react/web/ui/Bridge/QuoteLoader.tsx index 74591ccb968..18a7ab55619 100644 --- a/packages/thirdweb/src/react/web/ui/Bridge/QuoteLoader.tsx +++ b/packages/thirdweb/src/react/web/ui/Bridge/QuoteLoader.tsx @@ -81,9 +81,11 @@ interface QuoteLoaderProps { * Fee payer for direct transfers (defaults to sender) */ feePayer?: "sender" | "receiver"; + mode: "fund_wallet" | "direct_payment" | "transaction"; } export function QuoteLoader({ + mode, destinationToken, paymentMethod, amount, @@ -119,7 +121,7 @@ export function QuoteLoader({ ? paymentMethod.originToken.chainId : undefined, client, - event: "loading_quote", + event: `ub:ui:loading_quote:${mode}`, fromToken: paymentMethod.type === "wallet" ? paymentMethod.originToken.address @@ -202,7 +204,7 @@ function getBridgeParams(args: { if ( paymentMethod.originToken.chainId === destinationToken.chainId && paymentMethod.originToken.address.toLowerCase() === - destinationToken.address.toLowerCase() + destinationToken.address.toLowerCase() ) { return { amount: toUnits(amount, destinationToken.decimals), diff --git a/packages/thirdweb/src/react/web/ui/Bridge/TransactionWidget.tsx b/packages/thirdweb/src/react/web/ui/Bridge/TransactionWidget.tsx index d15908b6879..f273c531154 100644 --- a/packages/thirdweb/src/react/web/ui/Bridge/TransactionWidget.tsx +++ b/packages/thirdweb/src/react/web/ui/Bridge/TransactionWidget.tsx @@ -172,15 +172,15 @@ export type TransactionWidgetProps = { type UIOptionsResult = | { type: "success"; data: UIOptions } | { - type: "indexing_token"; - token: Token; - chain: Chain; - } + type: "indexing_token"; + token: Token; + chain: Chain; + } | { - type: "unsupported_token"; - tokenAddress: Address; - chain: Chain; - }; + type: "unsupported_token"; + tokenAddress: Address; + chain: Chain; + }; /** * Widget a prebuilt UI for purchasing a specific token. @@ -279,7 +279,7 @@ export function TransactionWidget(props: TransactionWidgetProps) { trackPayEvent({ chainId: props.transaction.chain.id, client: props.client, - event: "transaction_widget:render", + event: "ub:ui:transaction_widget:render", toToken: props.tokenAddress, }); }, @@ -443,10 +443,10 @@ type TransactionWidgetConnectOptions = { * ``` */ autoConnect?: - | { - timeout: number; - } - | boolean; + | { + timeout: number; + } + | boolean; /** * Metadata of the app that will be passed to connected wallet. Setting this is highly recommended. diff --git a/packages/thirdweb/src/react/web/ui/Bridge/UnsupportedTokenScreen.tsx b/packages/thirdweb/src/react/web/ui/Bridge/UnsupportedTokenScreen.tsx index 25db7c3f843..260f4a171a2 100644 --- a/packages/thirdweb/src/react/web/ui/Bridge/UnsupportedTokenScreen.tsx +++ b/packages/thirdweb/src/react/web/ui/Bridge/UnsupportedTokenScreen.tsx @@ -32,7 +32,7 @@ export function UnsupportedTokenScreen(props: UnsupportedTokenScreenProps) { trackPayEvent({ chainId: chain.id, client, - event: "unsupported_token", + event: "ub:ui:unsupported_token", fromToken: tokenAddress, }); }, diff --git a/packages/thirdweb/src/react/web/ui/Bridge/payment-details/PaymentDetails.tsx b/packages/thirdweb/src/react/web/ui/Bridge/payment-details/PaymentDetails.tsx index 2b53a48d5c0..d1b9b5cd394 100644 --- a/packages/thirdweb/src/react/web/ui/Bridge/payment-details/PaymentDetails.tsx +++ b/packages/thirdweb/src/react/web/ui/Bridge/payment-details/PaymentDetails.tsx @@ -72,14 +72,14 @@ export function PaymentDetails({ useQuery({ queryFn: () => { - if (preparedQuote.type === "buy" || preparedQuote.type === "sell") { + if (preparedQuote.type === "buy" || preparedQuote.type === "sell" || preparedQuote.type === "transfer") { trackPayEvent({ - chainId: preparedQuote.intent.originChainId, + chainId: preparedQuote.type === "transfer" ? preparedQuote.intent.chainId : preparedQuote.intent.originChainId, client, event: "payment_details", - fromToken: preparedQuote.intent.originTokenAddress, - toChainId: preparedQuote.intent.destinationChainId, - toToken: preparedQuote.intent.destinationTokenAddress, + fromToken: preparedQuote.type === "transfer" ? preparedQuote.intent.tokenAddress : preparedQuote.intent.originTokenAddress, + toChainId: preparedQuote.type === "transfer" ? preparedQuote.intent.chainId : preparedQuote.intent.destinationChainId, + toToken: preparedQuote.type === "transfer" ? preparedQuote.intent.tokenAddress : preparedQuote.intent.destinationTokenAddress, }); } }, diff --git a/packages/thirdweb/src/react/web/ui/Bridge/payment-success/SuccessScreen.tsx b/packages/thirdweb/src/react/web/ui/Bridge/payment-success/SuccessScreen.tsx index 42d5c27cf0e..f22732fd010 100644 --- a/packages/thirdweb/src/react/web/ui/Bridge/payment-success/SuccessScreen.tsx +++ b/packages/thirdweb/src/react/web/ui/Bridge/payment-success/SuccessScreen.tsx @@ -63,7 +63,7 @@ export function SuccessScreen({ trackPayEvent({ chainId: preparedQuote.intent.originChainId, client: client, - event: "success_screen", + event: "ub:ui:success_screen", fromToken: preparedQuote.intent.originTokenAddress, toChainId: preparedQuote.intent.destinationChainId, toToken: preparedQuote.intent.destinationTokenAddress, diff --git a/packages/thirdweb/src/stories/Bridge/SuccessScreen.stories.tsx b/packages/thirdweb/src/stories/Bridge/SuccessScreen.stories.tsx index 38d23f25eb6..7a92b7817ff 100644 --- a/packages/thirdweb/src/stories/Bridge/SuccessScreen.stories.tsx +++ b/packages/thirdweb/src/stories/Bridge/SuccessScreen.stories.tsx @@ -1,6 +1,5 @@ import type { Meta, StoryObj } from "@storybook/react"; import { stringify } from "viem"; -import { createThirdwebClient } from "../../client/client.js"; import type { Theme } from "../../react/core/design-system/index.js"; import type { CompletedStatusResult } from "../../react/core/hooks/useStepExecutor.js"; import { webWindowAdapter } from "../../react/web/adapters/WindowAdapter.js"; @@ -8,7 +7,7 @@ import { SuccessScreen, type SuccessScreenProps, } from "../../react/web/ui/Bridge/payment-success/SuccessScreen.js"; -import { ModalThemeWrapper } from "../utils.js"; +import { ModalThemeWrapper, storyClient } from "../utils.js"; import { FUND_WALLET_UI_OPTIONS, simpleBuyQuote, @@ -16,8 +15,6 @@ import { TRANSACTION_UI_OPTIONS, } from "./fixtures.js"; -const TEST_CLIENT = createThirdwebClient({ clientId: "test" }); - const mockBuyCompletedStatuses: CompletedStatusResult[] = JSON.parse( stringify([ { @@ -96,7 +93,7 @@ const SuccessScreenWithTheme = (props: SuccessScreenWithThemeProps) => { const meta = { args: { completedStatuses: mockBuyCompletedStatuses, - onDone: () => {}, + onDone: () => { }, preparedQuote: simpleBuyQuote, theme: "dark", uiOptions: FUND_WALLET_UI_OPTIONS.ethDefault, @@ -129,7 +126,7 @@ type Story = StoryObj; export const Default: Story = { args: { - client: TEST_CLIENT, + client: storyClient, theme: "dark", }, parameters: { @@ -139,7 +136,7 @@ export const Default: Story = { export const DefaultLight: Story = { args: { - client: TEST_CLIENT, + client: storyClient, theme: "light", }, parameters: { @@ -149,7 +146,7 @@ export const DefaultLight: Story = { export const OnrampPayment: Story = { args: { - client: TEST_CLIENT, + client: storyClient, completedStatuses: mockOnrampCompletedStatuses, preparedQuote: simpleOnrampQuote, theme: "dark", @@ -167,7 +164,7 @@ export const OnrampPayment: Story = { export const OnrampPaymentLight: Story = { args: { - client: TEST_CLIENT, + client: storyClient, completedStatuses: mockOnrampCompletedStatuses, preparedQuote: simpleOnrampQuote, theme: "light", @@ -179,7 +176,7 @@ export const OnrampPaymentLight: Story = { export const ComplexPayment: Story = { args: { - client: TEST_CLIENT, + client: storyClient, completedStatuses: [ ...mockOnrampCompletedStatuses, ...mockBuyCompletedStatuses, @@ -200,7 +197,7 @@ export const ComplexPayment: Story = { export const ComplexPaymentLight: Story = { args: { - client: TEST_CLIENT, + client: storyClient, completedStatuses: [ ...mockOnrampCompletedStatuses, ...mockBuyCompletedStatuses, @@ -215,7 +212,7 @@ export const ComplexPaymentLight: Story = { export const TransactionPayment: Story = { args: { - client: TEST_CLIENT, + client: storyClient, completedStatuses: mockBuyCompletedStatuses, preparedQuote: simpleBuyQuote, theme: "light", From 0d21770735b30d265e853740284601b141ee9d45 Mon Sep 17 00:00:00 2001 From: gregfromstl Date: Tue, 24 Jun 2025 12:04:56 -0700 Subject: [PATCH 09/10] lint --- .../components/client/PayModal.tsx | 49 ---------- .../components/icons/CreditCardIcon.tsx | 92 ------------------- 2 files changed, 141 deletions(-) delete mode 100644 apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/client/PayModal.tsx delete mode 100644 apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/icons/CreditCardIcon.tsx diff --git a/apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/client/PayModal.tsx b/apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/client/PayModal.tsx deleted file mode 100644 index 890519d706b..00000000000 --- a/apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/client/PayModal.tsx +++ /dev/null @@ -1,49 +0,0 @@ -"use client"; -import { useTheme } from "next-themes"; -import type { ThirdwebClient } from "thirdweb"; -import { PayEmbed } from "thirdweb/react"; -import { Button } from "@/components/ui/button"; -import { Dialog, DialogContent, DialogTrigger } from "@/components/ui/dialog"; -import { defineDashboardChain } from "@/lib/defineDashboardChain"; -import { getSDKTheme } from "../../../../../../../../@/utils/sdk-component-theme"; - -export function PayModalButton(props: { - chainId: number; - label: string; - client: ThirdwebClient; -}) { - const { theme } = useTheme(); - - return ( - - - - - - - - - ); -} diff --git a/apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/icons/CreditCardIcon.tsx b/apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/icons/CreditCardIcon.tsx deleted file mode 100644 index 0879e1b75d7..00000000000 --- a/apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/icons/CreditCardIcon.tsx +++ /dev/null @@ -1,92 +0,0 @@ -import { useId } from "react"; - -export function CreditCardIcon(props: { bg: string; className?: string }) { - const linearGradientId = useId(); - const linearGradientId2 = useId(); - const linearGradientId3 = useId(); - - return ( - - ); -} From 70d7fac00bc60faa9cb9dafa630a99b3e86e0553 Mon Sep 17 00:00:00 2001 From: gregfromstl Date: Tue, 24 Jun 2025 12:15:31 -0700 Subject: [PATCH 10/10] lint --- .../{server => client}/BuyFundsSection.tsx | 3 +- .../(chain)/[chain_id]/(chainPage)/page.tsx | 2 +- .../web/ui/Bridge/BridgeOrchestrator.tsx | 28 +++++++++---------- .../src/react/web/ui/Bridge/BuyWidget.tsx | 26 ++++++++--------- .../react/web/ui/Bridge/CheckoutWidget.tsx | 24 ++++++++-------- .../src/react/web/ui/Bridge/QuoteLoader.tsx | 2 +- .../react/web/ui/Bridge/TransactionWidget.tsx | 24 ++++++++-------- .../Bridge/payment-details/PaymentDetails.tsx | 26 +++++++++++++---- .../stories/Bridge/SuccessScreen.stories.tsx | 2 +- 9 files changed, 76 insertions(+), 61 deletions(-) rename apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/{server => client}/BuyFundsSection.tsx (86%) diff --git a/apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/BuyFundsSection.tsx b/apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/client/BuyFundsSection.tsx similarity index 86% rename from apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/BuyFundsSection.tsx rename to apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/client/BuyFundsSection.tsx index c694addea09..5943195dcc0 100644 --- a/apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/server/BuyFundsSection.tsx +++ b/apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/client/BuyFundsSection.tsx @@ -1,7 +1,7 @@ +"use client"; import { defineChain, type ThirdwebClient } from "thirdweb"; import type { ChainMetadata } from "thirdweb/chains"; import { BuyWidget } from "thirdweb/react"; -import { SectionTitle } from "./SectionTitle"; export function BuyFundsSection(props: { chain: ChainMetadata; @@ -9,7 +9,6 @@ export function BuyFundsSection(props: { }) { return (
- ; @@ -283,10 +283,10 @@ export function BridgeOrchestrator({ amount={state.context.destinationAmount} client={client} destinationToken={state.context.destinationToken} + mode={uiOptions.mode} onBack={() => { send({ type: "BACK" }); }} - mode={uiOptions.mode} onError={handleError} onQuoteReceived={handleQuoteReceived} paymentLinkId={paymentLinkId} diff --git a/packages/thirdweb/src/react/web/ui/Bridge/BuyWidget.tsx b/packages/thirdweb/src/react/web/ui/Bridge/BuyWidget.tsx index 47a9955a005..11a99b29ff7 100644 --- a/packages/thirdweb/src/react/web/ui/Bridge/BuyWidget.tsx +++ b/packages/thirdweb/src/react/web/ui/Bridge/BuyWidget.tsx @@ -166,15 +166,15 @@ export type BuyWidgetProps = { type UIOptionsResult = | { type: "success"; data: UIOptions } | { - type: "indexing_token"; - token: Token; - chain: Chain; - } + type: "indexing_token"; + token: Token; + chain: Chain; + } | { - type: "unsupported_token"; - tokenAddress: Address; - chain: Chain; - }; + type: "unsupported_token"; + tokenAddress: Address; + chain: Chain; + }; /** * Widget is a prebuilt UI for purchasing a specific token. @@ -285,7 +285,7 @@ export function BuyWidget(props: BuyWidgetProps) { !props.tokenAddress || (isAddress(props.tokenAddress) && checksumAddress(props.tokenAddress) === - checksumAddress(NATIVE_TOKEN_ADDRESS)) + checksumAddress(NATIVE_TOKEN_ADDRESS)) ) { const ETH = await getToken( props.client, @@ -455,10 +455,10 @@ type BuyWidgetConnectOptions = { * ``` */ autoConnect?: - | { - timeout: number; - } - | boolean; + | { + timeout: number; + } + | boolean; /** * Metadata of the app that will be passed to connected wallet. Setting this is highly recommended. diff --git a/packages/thirdweb/src/react/web/ui/Bridge/CheckoutWidget.tsx b/packages/thirdweb/src/react/web/ui/Bridge/CheckoutWidget.tsx index f51db335594..b25c19f0618 100644 --- a/packages/thirdweb/src/react/web/ui/Bridge/CheckoutWidget.tsx +++ b/packages/thirdweb/src/react/web/ui/Bridge/CheckoutWidget.tsx @@ -172,15 +172,15 @@ export type CheckoutWidgetProps = { type UIOptionsResult = | { type: "success"; data: UIOptions } | { - type: "indexing_token"; - token: Token; - chain: Chain; - } + type: "indexing_token"; + token: Token; + chain: Chain; + } | { - type: "unsupported_token"; - tokenAddress: Address; - chain: Chain; - }; + type: "unsupported_token"; + tokenAddress: Address; + chain: Chain; + }; /** * Widget a prebuilt UI for purchasing a specific token. @@ -418,10 +418,10 @@ type CheckoutWidgetConnectOptions = { * ``` */ autoConnect?: - | { - timeout: number; - } - | boolean; + | { + timeout: number; + } + | boolean; /** * Metadata of the app that will be passed to connected wallet. Setting this is highly recommended. diff --git a/packages/thirdweb/src/react/web/ui/Bridge/QuoteLoader.tsx b/packages/thirdweb/src/react/web/ui/Bridge/QuoteLoader.tsx index 18a7ab55619..e71cc1ca6f7 100644 --- a/packages/thirdweb/src/react/web/ui/Bridge/QuoteLoader.tsx +++ b/packages/thirdweb/src/react/web/ui/Bridge/QuoteLoader.tsx @@ -204,7 +204,7 @@ function getBridgeParams(args: { if ( paymentMethod.originToken.chainId === destinationToken.chainId && paymentMethod.originToken.address.toLowerCase() === - destinationToken.address.toLowerCase() + destinationToken.address.toLowerCase() ) { return { amount: toUnits(amount, destinationToken.decimals), diff --git a/packages/thirdweb/src/react/web/ui/Bridge/TransactionWidget.tsx b/packages/thirdweb/src/react/web/ui/Bridge/TransactionWidget.tsx index f273c531154..d60856bdab4 100644 --- a/packages/thirdweb/src/react/web/ui/Bridge/TransactionWidget.tsx +++ b/packages/thirdweb/src/react/web/ui/Bridge/TransactionWidget.tsx @@ -172,15 +172,15 @@ export type TransactionWidgetProps = { type UIOptionsResult = | { type: "success"; data: UIOptions } | { - type: "indexing_token"; - token: Token; - chain: Chain; - } + type: "indexing_token"; + token: Token; + chain: Chain; + } | { - type: "unsupported_token"; - tokenAddress: Address; - chain: Chain; - }; + type: "unsupported_token"; + tokenAddress: Address; + chain: Chain; + }; /** * Widget a prebuilt UI for purchasing a specific token. @@ -443,10 +443,10 @@ type TransactionWidgetConnectOptions = { * ``` */ autoConnect?: - | { - timeout: number; - } - | boolean; + | { + timeout: number; + } + | boolean; /** * Metadata of the app that will be passed to connected wallet. Setting this is highly recommended. diff --git a/packages/thirdweb/src/react/web/ui/Bridge/payment-details/PaymentDetails.tsx b/packages/thirdweb/src/react/web/ui/Bridge/payment-details/PaymentDetails.tsx index d1b9b5cd394..b15b369b28a 100644 --- a/packages/thirdweb/src/react/web/ui/Bridge/payment-details/PaymentDetails.tsx +++ b/packages/thirdweb/src/react/web/ui/Bridge/payment-details/PaymentDetails.tsx @@ -72,14 +72,30 @@ export function PaymentDetails({ useQuery({ queryFn: () => { - if (preparedQuote.type === "buy" || preparedQuote.type === "sell" || preparedQuote.type === "transfer") { + if ( + preparedQuote.type === "buy" || + preparedQuote.type === "sell" || + preparedQuote.type === "transfer" + ) { trackPayEvent({ - chainId: preparedQuote.type === "transfer" ? preparedQuote.intent.chainId : preparedQuote.intent.originChainId, + chainId: + preparedQuote.type === "transfer" + ? preparedQuote.intent.chainId + : preparedQuote.intent.originChainId, client, event: "payment_details", - fromToken: preparedQuote.type === "transfer" ? preparedQuote.intent.tokenAddress : preparedQuote.intent.originTokenAddress, - toChainId: preparedQuote.type === "transfer" ? preparedQuote.intent.chainId : preparedQuote.intent.destinationChainId, - toToken: preparedQuote.type === "transfer" ? preparedQuote.intent.tokenAddress : preparedQuote.intent.destinationTokenAddress, + fromToken: + preparedQuote.type === "transfer" + ? preparedQuote.intent.tokenAddress + : preparedQuote.intent.originTokenAddress, + toChainId: + preparedQuote.type === "transfer" + ? preparedQuote.intent.chainId + : preparedQuote.intent.destinationChainId, + toToken: + preparedQuote.type === "transfer" + ? preparedQuote.intent.tokenAddress + : preparedQuote.intent.destinationTokenAddress, }); } }, diff --git a/packages/thirdweb/src/stories/Bridge/SuccessScreen.stories.tsx b/packages/thirdweb/src/stories/Bridge/SuccessScreen.stories.tsx index 7a92b7817ff..4d1cb5b38e1 100644 --- a/packages/thirdweb/src/stories/Bridge/SuccessScreen.stories.tsx +++ b/packages/thirdweb/src/stories/Bridge/SuccessScreen.stories.tsx @@ -93,7 +93,7 @@ const SuccessScreenWithTheme = (props: SuccessScreenWithThemeProps) => { const meta = { args: { completedStatuses: mockBuyCompletedStatuses, - onDone: () => { }, + onDone: () => {}, preparedQuote: simpleBuyQuote, theme: "dark", uiOptions: FUND_WALLET_UI_OPTIONS.ethDefault,