diff --git a/apps/dashboard/src/app/checkout/components/client/CheckoutEmbed.client.tsx b/apps/dashboard/src/app/checkout/components/client/CheckoutEmbed.client.tsx index a8077895eeb..6075885dbec 100644 --- a/apps/dashboard/src/app/checkout/components/client/CheckoutEmbed.client.tsx +++ b/apps/dashboard/src/app/checkout/components/client/CheckoutEmbed.client.tsx @@ -1,14 +1,16 @@ "use client"; import { THIRDWEB_ANALYTICS_DOMAIN, + THIRDWEB_BUNDLER_DOMAIN, + THIRDWEB_INAPP_WALLET_DOMAIN, THIRDWEB_INSIGHT_API_DOMAIN, THIRDWEB_PAY_DOMAIN, THIRDWEB_RPC_DOMAIN, + THIRDWEB_SOCIAL_API_DOMAIN, THIRDWEB_STORAGE_DOMAIN, } from "constants/urls"; import { useV5DashboardChain } from "lib/v5-adapter"; import { getVercelEnv } from "lib/vercel-utils"; -import { useTheme } from "next-themes"; import { useMemo } from "react"; import { NATIVE_TOKEN_ADDRESS, createThirdwebClient, toTokens } from "thirdweb"; import { AutoConnect, PayEmbed } from "thirdweb/react"; @@ -23,6 +25,7 @@ export function CheckoutEmbed({ image, redirectUri, clientId, + theme, }: { chainId: number; recipientAddress: string; @@ -32,6 +35,7 @@ export function CheckoutEmbed({ image?: string; redirectUri?: string; clientId: string; + theme: "light" | "dark"; }) { const client = useMemo(() => { if (getVercelEnv() !== "production") { @@ -41,12 +45,14 @@ export function CheckoutEmbed({ storage: THIRDWEB_STORAGE_DOMAIN, insight: THIRDWEB_INSIGHT_API_DOMAIN, analytics: THIRDWEB_ANALYTICS_DOMAIN, + inAppWallet: THIRDWEB_INAPP_WALLET_DOMAIN, + bundler: THIRDWEB_BUNDLER_DOMAIN, + social: THIRDWEB_SOCIAL_API_DOMAIN, }); } return createThirdwebClient({ clientId }); }, [clientId]); const chain = useV5DashboardChain(chainId); - const { theme } = useTheme(); return ( <> diff --git a/apps/dashboard/src/app/checkout/components/client/ThemeHandler.client.tsx b/apps/dashboard/src/app/checkout/components/client/ThemeHandler.client.tsx new file mode 100644 index 00000000000..fe21360740f --- /dev/null +++ b/apps/dashboard/src/app/checkout/components/client/ThemeHandler.client.tsx @@ -0,0 +1,22 @@ +"use client"; + +import { useTheme } from "next-themes"; +import { useSearchParams } from "next/navigation"; +import { useEffect } from "react"; + +export function ThemeHandler() { + const searchParams = useSearchParams(); + const { setTheme } = useTheme(); + + // eslint-disable-next-line no-restricted-syntax + useEffect(() => { + const theme = searchParams.get("theme"); + if (theme === "light") { + setTheme("light"); + } else { + setTheme("dark"); + } + }, [searchParams, setTheme]); + + return null; +} diff --git a/apps/dashboard/src/app/checkout/components/types.ts b/apps/dashboard/src/app/checkout/components/types.ts new file mode 100644 index 00000000000..c504d68b07c --- /dev/null +++ b/apps/dashboard/src/app/checkout/components/types.ts @@ -0,0 +1,11 @@ +export type CheckoutParams = { + chainId: string; + recipientAddress: string; + tokenAddress: string; + amount: string; + name?: string; + image?: string; + theme?: "light" | "dark"; + redirectUri?: string; + clientId?: string; +}; diff --git a/apps/dashboard/src/app/checkout/layout.tsx b/apps/dashboard/src/app/checkout/layout.tsx index c21155f94c0..da694be96ae 100644 --- a/apps/dashboard/src/app/checkout/layout.tsx +++ b/apps/dashboard/src/app/checkout/layout.tsx @@ -1,7 +1,9 @@ import { cn } from "@/lib/utils"; import { ThemeProvider } from "next-themes"; import { Inter } from "next/font/google"; +import { Suspense } from "react"; import { Providers } from "./components/client/Providers.client"; +import { ThemeHandler } from "./components/client/ThemeHandler.client"; const fontSans = Inter({ subsets: ["latin"], @@ -9,9 +11,11 @@ const fontSans = Inter({ display: "swap", }); -export default function CheckoutLayout({ +export default async function CheckoutLayout({ children, -}: { children: React.ReactNode }) { +}: { + children: React.ReactNode; +}) { return ( @@ -27,6 +31,9 @@ export default function CheckoutLayout({ fontSans.variable, )} > + + + {children} diff --git a/apps/dashboard/src/app/checkout/page.tsx b/apps/dashboard/src/app/checkout/page.tsx index ebdde336e67..62bfd302b72 100644 --- a/apps/dashboard/src/app/checkout/page.tsx +++ b/apps/dashboard/src/app/checkout/page.tsx @@ -5,6 +5,7 @@ import { createThirdwebClient, defineChain, getContract } from "thirdweb"; import { getCurrencyMetadata } from "thirdweb/extensions/erc20"; import { checksumAddress } from "thirdweb/utils"; import { CheckoutEmbed } from "./components/client/CheckoutEmbed.client"; +import type { CheckoutParams } from "./components/types"; const title = "thirdweb Checkout"; const description = "Fast, secure, and simple payments."; @@ -20,68 +21,68 @@ export const metadata: Metadata = { export default async function RoutesPage({ searchParams, -}: { searchParams: Record }) { - const { - chainId, - recipientAddress, - tokenAddress, - amount, - clientId, - redirectUri, - } = searchParams; +}: { searchParams: Promise }) { + const params = await searchParams; - if (!chainId || Array.isArray(chainId)) { + if (!params.chainId || Array.isArray(params.chainId)) { throw new Error("A single chainId parameter is required."); } - if (!recipientAddress || Array.isArray(recipientAddress)) { + if (!params.recipientAddress || Array.isArray(params.recipientAddress)) { throw new Error("A single recipientAddress parameter is required."); } - if (!tokenAddress || Array.isArray(tokenAddress)) { + if (!params.tokenAddress || Array.isArray(params.tokenAddress)) { throw new Error("A single tokenAddress parameter is required."); } - if (!amount || Array.isArray(amount)) { + if (!params.amount || Array.isArray(params.amount)) { throw new Error("A single amount parameter is required."); } - if (Array.isArray(clientId)) { + if (Array.isArray(params.clientId)) { throw new Error("A single clientId parameter is required."); } - if (Array.isArray(redirectUri)) { + if (Array.isArray(params.redirectUri)) { throw new Error("A single redirectUri parameter is required."); } // Use any provided clientId or use the dashboard client const client = - clientId && !Array.isArray(clientId) - ? createThirdwebClient({ clientId }) + params.clientId && !Array.isArray(params.clientId) + ? createThirdwebClient({ clientId: params.clientId }) : getThirdwebClient(undefined); const tokenContract = getContract({ - client, + client: getThirdwebClient(undefined), // for this RPC call, use the dashboard client // eslint-disable-next-line no-restricted-syntax - chain: defineChain(Number(chainId)), - address: tokenAddress, + chain: defineChain(Number(params.chainId)), + address: params.tokenAddress, }); - const { symbol, decimals, name } = await getCurrencyMetadata({ + const { + symbol, + decimals, + name: tokenName, + } = await getCurrencyMetadata({ contract: tokenContract, }); const token = { symbol, decimals, - name, - address: checksumAddress(tokenAddress), - chainId: Number(chainId), + name: tokenName, + address: checksumAddress(params.tokenAddress), + chainId: Number(params.chainId), }; return (