Skip to content

Feature: New UB Components #7354

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 50 commits into from
Jun 17, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
fe64ae4
WIP brige embed
joaquim-verges May 30, 2025
88618c8
refactor: account for fee action
gregfromstl Jun 4, 2025
337f52f
fix: disable start transaction button on autostart
gregfromstl Jun 4, 2025
0c0b747
fix: respect updated amount
gregfromstl Jun 4, 2025
8763876
feat: include prices in routes
gregfromstl Jun 4, 2025
a906c6e
feat: sort by dollar balance
gregfromstl Jun 4, 2025
11e831e
nit: adjust chain icon position
gregfromstl Jun 4, 2025
8b24014
feat: improve number formatting
gregfromstl Jun 4, 2025
c6737a0
polish direct payment screen ui
joaquim-verges Jun 5, 2025
a486c8a
code cleanup
joaquim-verges Jun 5, 2025
c6112fe
top up label
joaquim-verges Jun 5, 2025
dcd7b08
TransactionPayment component
joaquim-verges Jun 5, 2025
ec80659
update paymentMachine tests
joaquim-verges Jun 5, 2025
c0da29c
update FundWallet look
joaquim-verges Jun 5, 2025
a10b218
feat: adds token not supported screen
gregfromstl Jun 5, 2025
90fef12
docs: adds theme stories
gregfromstl Jun 5, 2025
c0429e1
feat: auto-add unsupported tokens
gregfromstl Jun 5, 2025
224e2af
refactor: make token name and symbol optional
gregfromstl Jun 5, 2025
2221dcf
feat: enable passing quickOptions
gregfromstl Jun 5, 2025
74faebe
ui polish, reuse header accross all modes
joaquim-verges Jun 6, 2025
2998cfe
UI polish for transactions and tokens
joaquim-verges Jun 6, 2025
e600e26
update useSendTransaction to use new widget
joaquim-verges Jun 6, 2025
f3f49cd
transaction execution
joaquim-verges Jun 6, 2025
6499e49
incorporate post buy transaction in the state machine
joaquim-verges Jun 6, 2025
7ae018b
update payment state machine tests
joaquim-verges Jun 6, 2025
984c348
playground build
joaquim-verges Jun 6, 2025
d2dcf7c
refactor: rename quickOptions to presetOptions for consistency across…
gregfromstl Jun 6, 2025
84a5e8c
feat: adds onramp logos
gregfromstl Jun 6, 2025
484a3e1
feat: show quotes for onramp providers
gregfromstl Jun 6, 2025
b88f8ba
refactor: refresh quote on step runner
gregfromstl Jun 10, 2025
8ec1bf5
Merge branch 'main' into 05-30-wip_brige_embed
gregfromstl Jun 10, 2025
a675f08
fix: include erc20 value in docs
gregfromstl Jun 10, 2025
76c0e00
Merge branch 'main' into 05-30-wip_brige_embed
gregfromstl Jun 11, 2025
b386d39
feat: adds BuyEmbed
gregfromstl Jun 11, 2025
355eecd
feat: CheckoutWidget component
gregfromstl Jun 11, 2025
1cc003d
feat: TransactionWidget
gregfromstl Jun 12, 2025
271840e
lint
gregfromstl Jun 12, 2025
919531b
lint
gregfromstl Jun 12, 2025
f90fcdc
fix: update playground bridge form
gregfromstl Jun 13, 2025
581127c
Merge branch 'main' into greg/new-ub-components
gregfromstl Jun 16, 2025
f267b5d
lint
gregfromstl Jun 16, 2025
4489854
nit: remove @buyCrypto tag
gregfromstl Jun 16, 2025
0ad85a1
chore: adds changeset
gregfromstl Jun 16, 2025
7c734ca
fix: Remove AI tasks lists
gregfromstl Jun 16, 2025
1ce2227
fix: storybook versions
gregfromstl Jun 16, 2025
5e73246
lint
gregfromstl Jun 16, 2025
ce05d89
remove storybook-dependant tests
gregfromstl Jun 16, 2025
1ad187b
lint
gregfromstl Jun 16, 2025
00c4f27
fix tests
gregfromstl Jun 16, 2025
74717d7
fix dashboard build
gregfromstl Jun 16, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 78 additions & 0 deletions .changeset/calm-suits-stare.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
---
"thirdweb": minor
---

Adds new components BuyWidget, CheckoutWidget, and TransactionWidget

## BuyWidget
A component that allows users to purchase tokens or NFTs directly within your application.

### Example:
```tsx
import { BuyWidget } from "thirdweb/react";

function App() {
return (
<BuyWidget
client={client}
chain={chain}
tokenAddress="0x..." // Token or NFT contract address
recipient="0x..." // Optional: recipient address
theme="light" // Optional: "light" or "dark"
/>
);
}
```

## CheckoutWidget
A comprehensive checkout experience for purchasing digital assets with multiple payment options.

### Example:
```tsx
import { CheckoutWidget } from "thirdweb/react";

function App() {
return (
<CheckoutWidget
client={client}
chain={chain}
items={[
{
tokenAddress: "0x...",
tokenId: "1", // For NFTs
quantity: "1"
}
]}
onSuccess={(result) => console.log("Purchase successful:", result)}
theme="dark" // Optional: "light" or "dark"
/>
);
}
```

## TransactionWidget
A widget for executing arbitrary blockchain transactions with a user-friendly interface.

### Example:
```tsx
import { TransactionWidget } from "thirdweb/react";
import { prepareContractCall } from "thirdweb";

function App() {
const transaction = prepareContractCall({
contract: myContract,
method: "transfer",
params: [recipientAddress, amount]
});

return (
<TransactionWidget
client={client}
transaction={transaction}
onSuccess={(result) => console.log("Transaction successful:", result)}
onError={(error) => console.error("Transaction failed:", error)}
theme="light" // Optional: "light" or "dark"
/>
);
}
```
4 changes: 3 additions & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ Welcome, AI copilots! This guide captures the coding standards, architectural de
- Biome governs formatting and linting; its rules live in biome.json.
- Run pnpm biome check --apply before committing.
- Avoid editor‑specific configs; rely on the shared settings.
- make sure everything builds after each file change by running `pnpm build`


Expand All @@ -39,7 +40,8 @@ Welcome, AI copilots! This guide captures the coding standards, architectural de
- Co‑locate tests: foo.ts ↔ foo.test.ts.
- Use real function invocations with stub data; avoid brittle mocks.
- For network interactions, use Mock Service Worker (MSW) to intercept fetch/HTTP calls, mocking only scenarios that are hard to reproduce.
- Keep tests deterministic and side‑effect free; Jest is pre‑configured.
- Keep tests deterministic and side‑effect free; Vitest is pre‑configured.
- to run the tests: `cd packages thirdweb & pnpm test:dev <filename>`


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ export function PayModalButton(props: {
theme={getSDKTheme(theme === "dark" ? "dark" : "light")}
className="!w-auto"
payOptions={{
onPurchaseSuccess(info) {
// biome-ignore lint/suspicious/noExplicitAny: false positive
onPurchaseSuccess(info: any) {
if (
info.type === "crypto" &&
info.status.status !== "NOT_FOUND"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ function UBFooter() {
href: "https://playground.thirdweb.com/connect/pay/fund-wallet",
},
{
label: "Commerce",
label: "Checkout",
href: "https://playground.thirdweb.com/connect/pay/commerce",
},
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ export function PayPageEmbed({
onPurchaseSuccess: (result) => {
if (!redirectUri) return;
const url = new URL(redirectUri);
switch (result.type) {
switch (result?.type) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Guard against undefined before the switch to preserve discriminated-union narrowing

Using switch (result?.type) widens the expression to 'crypto' | 'fiat' | 'transaction' | undefined, preventing TypeScript from narrowing result inside each case. This forces result.status / result.transactionHash to be typed as any, defeating the benefit of the discriminated union and risking silent type regressions.

Proposed fix: short-circuit when result is falsy, then switch on the guaranteed, non-optional result.type.

-            switch (result?.type) {
+            if (!result) {
+              return window.open(url.toString());
+            }
+            switch (result.type) {

Optionally add a default branch to future-proof against new result types.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
switch (result?.type) {
if (!result) {
return window.open(url.toString());
}
switch (result.type) {
🤖 Prompt for AI Agents
In apps/dashboard/src/app/pay/components/client/PayPageEmbed.client.tsx at line
66, the switch statement uses optional chaining on result.type, causing
TypeScript to widen the type and lose discriminated union narrowing. To fix
this, add a guard clause before the switch to return early or handle the case
when result is undefined, ensuring that inside the switch statement result is
always defined. Then switch on result.type without optional chaining.
Optionally, add a default case in the switch to handle any future result types
safely.

case "crypto": {
url.searchParams.set("status", result.status.status);
if (
Expand Down
4 changes: 2 additions & 2 deletions apps/dashboard/src/components/buttons/MismatchButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -293,7 +293,7 @@ export const MismatchButton = forwardRef<
payOptions={{
onPurchaseSuccess(info) {
if (
info.type === "crypto" &&
info?.type === "crypto" &&
info.status.status !== "NOT_FOUND"
) {
trackEvent({
Expand All @@ -308,7 +308,7 @@ export const MismatchButton = forwardRef<
}

if (
info.type === "fiat" &&
info?.type === "fiat" &&
info.status.status !== "NOT_FOUND"
) {
trackEvent({
Expand Down
34 changes: 14 additions & 20 deletions apps/playground-web/src/app/connect/pay/commerce/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import type { Metadata } from "next";

export const metadata: Metadata = {
metadataBase,
title: "Integrate Fiat & Cross-Chain Crypto Payments | thirdweb Pay",
title: "Integrate Fiat & Cross-Chain Crypto Payments | Universal Bridge",
description:
"The easiest way for users to transact in your app. Onramp users in clicks and generate revenue for each user transaction. Integrate for free.",
};
Expand All @@ -34,7 +34,7 @@ function BuyMerch() {
return (
<CodeExample
header={{
title: "Commerce",
title: "Checkout",
description: (
<>
Take payments from Fiat or Crypto directly to your seller wallet.
Expand All @@ -46,28 +46,22 @@ function BuyMerch() {
),
}}
preview={<BuyMerchPreview />}
code={`import { PayEmbed, getDefaultToken } from "thirdweb/react";
code={`import { CheckoutWidget, getDefaultToken } from "thirdweb/react";
import { base } from "thirdweb/chains";

function App() {
return (
<PayEmbed
client={client}
theme={"light"}
payOptions={{
mode: "direct_payment",
paymentInfo: {
amount: "35",
chain: base,
token: getDefaultToken(base, "USDC"),
sellerAddress: "0xEb0effdFB4dC5b3d5d3aC6ce29F3ED213E95d675",
},
metadata: {
name: "Black Hoodie (Size L)",
image: "/drip-hoodie.png",
},
}}
/>
<CheckoutWidget
client={THIRDWEB_CLIENT}
theme="light"
chain={base}
amount={toUnits("2", 6)}
tokenAddress="0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913"
seller="0xEb0effdFB4dC5b3d5d3aC6ce29F3ED213E95d675"
feePayer="seller"
name="Black Hoodie"
description="Size L | Ships worldwide."
/>
);
};`}
lang="tsx"
Expand Down
Loading
Loading