Skip to content

Commit bda0f3e

Browse files
[Checkout] Add theme support and improve client configuration (#6958)
1 parent dfa3ee0 commit bda0f3e

File tree

5 files changed

+79
-32
lines changed

5 files changed

+79
-32
lines changed

apps/dashboard/src/app/checkout/components/client/CheckoutEmbed.client.tsx

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
11
"use client";
22
import {
33
THIRDWEB_ANALYTICS_DOMAIN,
4+
THIRDWEB_BUNDLER_DOMAIN,
5+
THIRDWEB_INAPP_WALLET_DOMAIN,
46
THIRDWEB_INSIGHT_API_DOMAIN,
57
THIRDWEB_PAY_DOMAIN,
68
THIRDWEB_RPC_DOMAIN,
9+
THIRDWEB_SOCIAL_API_DOMAIN,
710
THIRDWEB_STORAGE_DOMAIN,
811
} from "constants/urls";
912
import { useV5DashboardChain } from "lib/v5-adapter";
1013
import { getVercelEnv } from "lib/vercel-utils";
11-
import { useTheme } from "next-themes";
1214
import { useMemo } from "react";
1315
import { NATIVE_TOKEN_ADDRESS, createThirdwebClient, toTokens } from "thirdweb";
1416
import { AutoConnect, PayEmbed } from "thirdweb/react";
@@ -23,6 +25,7 @@ export function CheckoutEmbed({
2325
image,
2426
redirectUri,
2527
clientId,
28+
theme,
2629
}: {
2730
chainId: number;
2831
recipientAddress: string;
@@ -32,6 +35,7 @@ export function CheckoutEmbed({
3235
image?: string;
3336
redirectUri?: string;
3437
clientId: string;
38+
theme: "light" | "dark";
3539
}) {
3640
const client = useMemo(() => {
3741
if (getVercelEnv() !== "production") {
@@ -41,12 +45,14 @@ export function CheckoutEmbed({
4145
storage: THIRDWEB_STORAGE_DOMAIN,
4246
insight: THIRDWEB_INSIGHT_API_DOMAIN,
4347
analytics: THIRDWEB_ANALYTICS_DOMAIN,
48+
inAppWallet: THIRDWEB_INAPP_WALLET_DOMAIN,
49+
bundler: THIRDWEB_BUNDLER_DOMAIN,
50+
social: THIRDWEB_SOCIAL_API_DOMAIN,
4451
});
4552
}
4653
return createThirdwebClient({ clientId });
4754
}, [clientId]);
4855
const chain = useV5DashboardChain(chainId);
49-
const { theme } = useTheme();
5056

5157
return (
5258
<>
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
"use client";
2+
3+
import { useTheme } from "next-themes";
4+
import { useSearchParams } from "next/navigation";
5+
import { useEffect } from "react";
6+
7+
export function ThemeHandler() {
8+
const searchParams = useSearchParams();
9+
const { setTheme } = useTheme();
10+
11+
// eslint-disable-next-line no-restricted-syntax
12+
useEffect(() => {
13+
const theme = searchParams.get("theme");
14+
if (theme === "light") {
15+
setTheme("light");
16+
} else {
17+
setTheme("dark");
18+
}
19+
}, [searchParams, setTheme]);
20+
21+
return null;
22+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
export type CheckoutParams = {
2+
chainId: string;
3+
recipientAddress: string;
4+
tokenAddress: string;
5+
amount: string;
6+
name?: string;
7+
image?: string;
8+
theme?: "light" | "dark";
9+
redirectUri?: string;
10+
clientId?: string;
11+
};

apps/dashboard/src/app/checkout/layout.tsx

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,21 @@
11
import { cn } from "@/lib/utils";
22
import { ThemeProvider } from "next-themes";
33
import { Inter } from "next/font/google";
4+
import { Suspense } from "react";
45
import { Providers } from "./components/client/Providers.client";
6+
import { ThemeHandler } from "./components/client/ThemeHandler.client";
57

68
const fontSans = Inter({
79
subsets: ["latin"],
810
variable: "--font-sans",
911
display: "swap",
1012
});
1113

12-
export default function CheckoutLayout({
14+
export default async function CheckoutLayout({
1315
children,
14-
}: { children: React.ReactNode }) {
16+
}: {
17+
children: React.ReactNode;
18+
}) {
1519
return (
1620
<html lang="en" suppressHydrationWarning>
1721
<Providers>
@@ -27,6 +31,9 @@ export default function CheckoutLayout({
2731
fontSans.variable,
2832
)}
2933
>
34+
<Suspense>
35+
<ThemeHandler />
36+
</Suspense>
3037
{children}
3138
</body>
3239
</ThemeProvider>

apps/dashboard/src/app/checkout/page.tsx

Lines changed: 29 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { createThirdwebClient, defineChain, getContract } from "thirdweb";
55
import { getCurrencyMetadata } from "thirdweb/extensions/erc20";
66
import { checksumAddress } from "thirdweb/utils";
77
import { CheckoutEmbed } from "./components/client/CheckoutEmbed.client";
8+
import type { CheckoutParams } from "./components/types";
89

910
const title = "thirdweb Checkout";
1011
const description = "Fast, secure, and simple payments.";
@@ -20,68 +21,68 @@ export const metadata: Metadata = {
2021

2122
export default async function RoutesPage({
2223
searchParams,
23-
}: { searchParams: Record<string, string | string[]> }) {
24-
const {
25-
chainId,
26-
recipientAddress,
27-
tokenAddress,
28-
amount,
29-
clientId,
30-
redirectUri,
31-
} = searchParams;
24+
}: { searchParams: Promise<CheckoutParams> }) {
25+
const params = await searchParams;
3226

33-
if (!chainId || Array.isArray(chainId)) {
27+
if (!params.chainId || Array.isArray(params.chainId)) {
3428
throw new Error("A single chainId parameter is required.");
3529
}
36-
if (!recipientAddress || Array.isArray(recipientAddress)) {
30+
if (!params.recipientAddress || Array.isArray(params.recipientAddress)) {
3731
throw new Error("A single recipientAddress parameter is required.");
3832
}
39-
if (!tokenAddress || Array.isArray(tokenAddress)) {
33+
if (!params.tokenAddress || Array.isArray(params.tokenAddress)) {
4034
throw new Error("A single tokenAddress parameter is required.");
4135
}
42-
if (!amount || Array.isArray(amount)) {
36+
if (!params.amount || Array.isArray(params.amount)) {
4337
throw new Error("A single amount parameter is required.");
4438
}
45-
if (Array.isArray(clientId)) {
39+
if (Array.isArray(params.clientId)) {
4640
throw new Error("A single clientId parameter is required.");
4741
}
48-
if (Array.isArray(redirectUri)) {
42+
if (Array.isArray(params.redirectUri)) {
4943
throw new Error("A single redirectUri parameter is required.");
5044
}
5145

5246
// Use any provided clientId or use the dashboard client
5347
const client =
54-
clientId && !Array.isArray(clientId)
55-
? createThirdwebClient({ clientId })
48+
params.clientId && !Array.isArray(params.clientId)
49+
? createThirdwebClient({ clientId: params.clientId })
5650
: getThirdwebClient(undefined);
5751

5852
const tokenContract = getContract({
59-
client,
53+
client: getThirdwebClient(undefined), // for this RPC call, use the dashboard client
6054
// eslint-disable-next-line no-restricted-syntax
61-
chain: defineChain(Number(chainId)),
62-
address: tokenAddress,
55+
chain: defineChain(Number(params.chainId)),
56+
address: params.tokenAddress,
6357
});
64-
const { symbol, decimals, name } = await getCurrencyMetadata({
58+
const {
59+
symbol,
60+
decimals,
61+
name: tokenName,
62+
} = await getCurrencyMetadata({
6563
contract: tokenContract,
6664
});
6765
const token = {
6866
symbol,
6967
decimals,
70-
name,
71-
address: checksumAddress(tokenAddress),
72-
chainId: Number(chainId),
68+
name: tokenName,
69+
address: checksumAddress(params.tokenAddress),
70+
chainId: Number(params.chainId),
7371
};
7472

7573
return (
7674
<div className="relative mx-auto flex h-screen w-screen flex-col items-center justify-center overflow-hidden border py-10">
7775
<main className="container z-10 flex justify-center">
7876
<CheckoutEmbed
79-
redirectUri={redirectUri}
80-
chainId={Number(chainId)}
81-
recipientAddress={recipientAddress}
82-
amount={BigInt(amount)}
77+
redirectUri={params.redirectUri}
78+
chainId={Number(params.chainId)}
79+
recipientAddress={params.recipientAddress}
80+
amount={BigInt(params.amount)}
8381
token={token}
8482
clientId={client.clientId}
83+
name={params.name}
84+
image={params.image}
85+
theme={params.theme === "light" ? "light" : "dark"}
8586
/>
8687
</main>
8788

0 commit comments

Comments
 (0)