diff --git a/.changeset/silent-comics-carry.md b/.changeset/silent-comics-carry.md new file mode 100644 index 00000000000..0b101c7e75f --- /dev/null +++ b/.changeset/silent-comics-carry.md @@ -0,0 +1,5 @@ +--- +"thirdweb": patch +--- + +Add fiat provider selection in PayEmbed diff --git a/apps/playground-web/src/components/pay/embed.tsx b/apps/playground-web/src/components/pay/embed.tsx index a67bd47f6bc..2b073042326 100644 --- a/apps/playground-web/src/components/pay/embed.tsx +++ b/apps/playground-web/src/components/pay/embed.tsx @@ -10,7 +10,7 @@ export function StyledPayEmbedPreview() { const { theme } = useTheme(); return ( - <> +
- +
); } diff --git a/packages/thirdweb/src/pay/buyWithFiat/getQuote.ts b/packages/thirdweb/src/pay/buyWithFiat/getQuote.ts index 015e0dcaab9..bb9a0bb09b7 100644 --- a/packages/thirdweb/src/pay/buyWithFiat/getQuote.ts +++ b/packages/thirdweb/src/pay/buyWithFiat/getQuote.ts @@ -238,6 +238,11 @@ export type BuyWithFiatQuote = { * */ onRampLink: string; + + /** + * The provider that was used to get the quote. + */ + provider: FiatProvider; }; /** diff --git a/packages/thirdweb/src/pay/utils/commonTypes.ts b/packages/thirdweb/src/pay/utils/commonTypes.ts index ad6f80cdc2f..bd34ff2f534 100644 --- a/packages/thirdweb/src/pay/utils/commonTypes.ts +++ b/packages/thirdweb/src/pay/utils/commonTypes.ts @@ -17,4 +17,6 @@ export type PayOnChainTransactionDetails = { explorerLink?: string; }; -export type FiatProvider = "STRIPE" | "TRANSAK" | "KADO" | "COINBASE"; +export type FiatProvider = (typeof FiatProviders)[number]; + +export const FiatProviders = ["COINBASE", "STRIPE", "TRANSAK", "KADO"] as const; diff --git a/packages/thirdweb/src/react/core/utils/storage.ts b/packages/thirdweb/src/react/core/utils/storage.ts index c6bb7bb0d6b..0472b369528 100644 --- a/packages/thirdweb/src/react/core/utils/storage.ts +++ b/packages/thirdweb/src/react/core/utils/storage.ts @@ -2,6 +2,7 @@ import type { AsyncStorage } from "../../../utils/storage/AsyncStorage.js"; import type { AuthArgsType } from "../../../wallets/in-app/core/authentication/types.js"; export const LAST_AUTH_PROVIDER_STORAGE_KEY = "lastAuthProvider"; +export const PREFERRED_FIAT_PROVIDER_STORAGE_KEY = "preferredFiatProvider"; export async function setLastAuthProvider( authProvider: AuthArgsType["strategy"], diff --git a/packages/thirdweb/src/react/web/ui/ConnectWallet/screens/Buy/BuyScreen.tsx b/packages/thirdweb/src/react/web/ui/ConnectWallet/screens/Buy/BuyScreen.tsx index 3ac5f3246ef..2e7c868af16 100644 --- a/packages/thirdweb/src/react/web/ui/ConnectWallet/screens/Buy/BuyScreen.tsx +++ b/packages/thirdweb/src/react/web/ui/ConnectWallet/screens/Buy/BuyScreen.tsx @@ -1,3 +1,4 @@ +import { ChevronDownIcon } from "@radix-ui/react-icons"; import { useQuery, useQueryClient } from "@tanstack/react-query"; import { useCallback, useMemo, useState } from "react"; import type { Chain } from "../../../../../../chains/types.js"; @@ -10,11 +11,13 @@ import type { GetBuyWithCryptoQuoteParams } from "../../../../../../pay/buyWithC import type { BuyWithCryptoStatus } from "../../../../../../pay/buyWithCrypto/getStatus.js"; import type { BuyWithFiatStatus } from "../../../../../../pay/buyWithFiat/getStatus.js"; import { isSwapRequiredPostOnramp } from "../../../../../../pay/buyWithFiat/isSwapRequiredPostOnramp.js"; +import type { FiatProvider } from "../../../../../../pay/utils/commonTypes.js"; import { formatNumber } from "../../../../../../utils/formatNumber.js"; import type { Account } from "../../../../../../wallets/interfaces/wallet.js"; import type { WalletId } from "../../../../../../wallets/wallet-types.js"; import { type Theme, + iconSize, spacing, } from "../../../../../core/design-system/index.js"; import type { @@ -27,6 +30,7 @@ import { useBuyWithFiatQuote } from "../../../../../core/hooks/pay/useBuyWithFia import { useActiveAccount } from "../../../../../core/hooks/wallets/useActiveAccount.js"; import { invalidateWalletBalance } from "../../../../../core/providers/invalidateWalletBalance.js"; import type { SupportedTokens } from "../../../../../core/utils/defaultTokens.js"; +import { PREFERRED_FIAT_PROVIDER_STORAGE_KEY } from "../../../../../core/utils/storage.js"; import { ErrorState } from "../../../../wallets/shared/ErrorState.js"; import { LoadingScreen } from "../../../../wallets/shared/LoadingScreen.js"; import type { PayEmbedConnectOptions } from "../../../PayEmbed.js"; @@ -56,6 +60,7 @@ import { PayWithCreditCard } from "./PayWIthCreditCard.js"; import { TransactionModeScreen } from "./TransactionModeScreen.js"; import { CurrencySelection } from "./fiat/CurrencySelection.js"; import { FiatFlow } from "./fiat/FiatFlow.js"; +import { Providers } from "./fiat/Providers.js"; import type { CurrencyMeta } from "./fiat/currencies.js"; import type { SelectedScreen } from "./main/types.js"; import { @@ -1255,9 +1260,22 @@ function FiatScreenContent(props: { const receiverAddress = defaultRecipientAddress || props.payer.account.address; const { drawerRef, drawerOverlayRef, isOpen, setIsOpen } = useDrawer(); - const [drawerScreen, setDrawerScreen] = useState<"fees">("fees"); + const [drawerScreen, setDrawerScreen] = useState<"fees" | "providers">( + "fees", + ); const buyWithFiatOptions = props.payOptions.buyWithFiat; + const [preferredProvider, setPreferredProvider] = useState< + FiatProvider | undefined + >( + buyWithFiatOptions !== false + ? buyWithFiatOptions?.preferredProvider || + ((localStorage.getItem( + PREFERRED_FIAT_PROVIDER_STORAGE_KEY, + ) as FiatProvider | null) ?? + undefined) + : undefined, + ); const fiatQuoteQuery = useBuyWithFiatQuote( buyWithFiatOptions !== false && tokenAmount @@ -1273,7 +1291,7 @@ function FiatScreenContent(props: { isTestMode: buyWithFiatOptions?.testMode, purchaseData: props.payOptions.purchaseData, fromAddress: payer.account.address, - preferredProvider: buyWithFiatOptions?.preferredProvider, + preferredProvider: preferredProvider, } : undefined, ); @@ -1314,6 +1332,11 @@ function FiatScreenContent(props: { setIsOpen(true); } + function showProviders() { + setDrawerScreen("providers"); + setIsOpen(true); + } + const disableSubmit = !fiatQuoteQuery.data; const errorMsg = @@ -1337,6 +1360,28 @@ function FiatScreenContent(props: {
)} + {drawerScreen === "providers" && ( +
+ + Providers + + + { + setPreferredProvider(provider); + // save the pref in local storage + localStorage.setItem( + PREFERRED_FIAT_PROVIDER_STORAGE_KEY, + provider, + ); + setIsOpen(false); + }} + /> +
+ )} )} @@ -1349,6 +1394,35 @@ function FiatScreenContent(props: { currency={selectedCurrency} onSelectCurrency={showCurrencySelector} /> + + + Provider + + + {/* Estimated time + View fees button */} void; +}) { + return ( + + {FiatProviders.map((provider) => { + return ( + + + + ); + })} + + ); +}