Skip to content

Commit dd2fb1b

Browse files
[SDK] Feature: Allow for supported providers to be passed to PayEmbed (#7108)
1 parent 69fdef0 commit dd2fb1b

File tree

7 files changed

+142
-70
lines changed

7 files changed

+142
-70
lines changed

.changeset/small-boxes-grow.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"thirdweb": patch
3+
---
4+
5+
Add support for filtering fiat payment providers in PayEmbed

packages/thirdweb/src/react/core/hooks/connection/ConnectButtonProps.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ export type PayUIOptions = Prettify<
9898
currency?: CurrencyMeta["shorthand"];
9999
};
100100
preferredProvider?: FiatProvider;
101+
supportedProviders?: FiatProvider[];
101102
}
102103
| false;
103104

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import { ChevronDownIcon } from "@radix-ui/react-icons";
2+
import type { FiatProvider } from "../../../../../../pay/utils/commonTypes.js";
3+
import { iconSize, spacing } from "../../../../../core/design-system/index.js";
4+
import { Container } from "../../../components/basic.js";
5+
import { Button } from "../../../components/buttons.js";
6+
import { Text } from "../../../components/text.js";
7+
import { getProviderLabel } from "./utils.js";
8+
9+
/**
10+
* Shows the selected payment provider based on the preferred provider OR the quoted provider.
11+
* @internal
12+
*/
13+
export const PayProviderSelection = (props: {
14+
onShowProviders: () => void;
15+
quotedProvider?: FiatProvider;
16+
preferredProvider?: FiatProvider;
17+
supportedProviders: FiatProvider[];
18+
}) => {
19+
const ProviderItem = (
20+
<Container
21+
flex="row"
22+
center="y"
23+
gap="xxs"
24+
color="secondaryText"
25+
style={{ padding: spacing.md }}
26+
>
27+
<Text size="xs">
28+
{getProviderLabel(
29+
props.preferredProvider ?? props.quotedProvider ?? "",
30+
)}
31+
</Text>
32+
{props.supportedProviders.length > 1 && (
33+
<ChevronDownIcon width={iconSize.sm} height={iconSize.sm} />
34+
)}
35+
</Container>
36+
);
37+
38+
return (
39+
<Container
40+
bg="tertiaryBg"
41+
flex="row"
42+
borderColor="borderColor"
43+
style={{
44+
paddingLeft: spacing.md,
45+
justifyContent: "space-between",
46+
alignItems: "center",
47+
borderWidth: "1px",
48+
borderStyle: "solid",
49+
borderBottom: "none",
50+
}}
51+
>
52+
<Text size="xs" color="secondaryText">
53+
Provider
54+
</Text>
55+
{props.supportedProviders.length > 1 ? (
56+
<Button
57+
variant="ghost"
58+
onClick={props.onShowProviders}
59+
style={{ padding: 0 }} // Padding is managed within children as the button is conditional
60+
>
61+
{ProviderItem}
62+
</Button>
63+
) : (
64+
ProviderItem
65+
)}
66+
</Container>
67+
);
68+
};

packages/thirdweb/src/react/web/ui/ConnectWallet/screens/Buy/fiat/FiatScreenContent.tsx

Lines changed: 27 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,13 @@
1-
import { ChevronDownIcon } from "@radix-ui/react-icons";
21
import { useState } from "react";
32
import { trackPayEvent } from "../../../../../../../analytics/track/pay.js";
43
import type { Chain } from "../../../../../../../chains/types.js";
54
import type { ThirdwebClient } from "../../../../../../../client/client.js";
65
import { NATIVE_TOKEN_ADDRESS } from "../../../../../../../constants/addresses.js";
7-
import type { FiatProvider } from "../../../../../../../pay/utils/commonTypes.js";
86
import {
9-
type Theme,
10-
iconSize,
11-
spacing,
12-
} from "../../../../../../core/design-system/index.js";
7+
type FiatProvider,
8+
FiatProviders,
9+
} from "../../../../../../../pay/utils/commonTypes.js";
10+
import type { Theme } from "../../../../../../core/design-system/index.js";
1311
import type { PayUIOptions } from "../../../../../../core/hooks/connection/ConnectButtonProps.js";
1412
import { useBuyWithFiatQuote } from "../../../../../../core/hooks/pay/useBuyWithFiatQuote.js";
1513
import { PREFERRED_FIAT_PROVIDER_STORAGE_KEY } from "../../../../../../core/utils/storage.js";
@@ -26,6 +24,7 @@ import { Button } from "../../../../components/buttons.js";
2624
import { Text } from "../../../../components/text.js";
2725
import { type ERC20OrNativeToken, isNativeToken } from "../../nativeToken.js";
2826
import { EstimatedTimeAndFees } from "../EstimatedTimeAndFees.js";
27+
import { PayProviderSelection } from "../PayProviderSelection.js";
2928
import { PayWithCreditCard } from "../PayWIthCreditCard.js";
3029
import type { SelectedScreen } from "../main/types.js";
3130
import { FiatFees } from "../swap/Fees.js";
@@ -84,6 +83,19 @@ export function FiatScreenContent(props: {
8483
: undefined,
8584
);
8685

86+
const supportedProviders = (() => {
87+
if (!buyWithFiatOptions) return [...FiatProviders];
88+
const options = buyWithFiatOptions?.supportedProviders ?? [];
89+
const optionsWithPreferred =
90+
options.length > 0
91+
? new Set([
92+
...(preferredProvider ? [preferredProvider] : []),
93+
...options,
94+
])
95+
: FiatProviders;
96+
return Array.from(optionsWithPreferred);
97+
})();
98+
8799
const fiatQuoteQuery = useBuyWithFiatQuote(
88100
buyWithFiatOptions !== false && tokenAmount
89101
? {
@@ -98,8 +110,8 @@ export function FiatScreenContent(props: {
98110
isTestMode: buyWithFiatOptions?.testMode,
99111
purchaseData: props.payOptions.purchaseData,
100112
fromAddress: payer.account.address,
101-
preferredProvider: preferredProvider,
102113
paymentLinkId: paymentLinkId,
114+
preferredProvider: preferredProvider ?? supportedProviders[0],
103115
}
104116
: undefined,
105117
);
@@ -159,6 +171,7 @@ export function FiatScreenContent(props: {
159171
</Text>
160172
<Spacer y="lg" />
161173
<Providers
174+
supportedProviders={supportedProviders}
162175
preferredProvider={
163176
preferredProvider || fiatQuoteQuery.data?.provider
164177
}
@@ -188,35 +201,13 @@ export function FiatScreenContent(props: {
188201
currency={selectedCurrency}
189202
onSelectCurrency={showCurrencySelector}
190203
/>
191-
<Container
192-
bg="tertiaryBg"
193-
flex="row"
194-
borderColor="borderColor"
195-
style={{
196-
paddingLeft: spacing.md,
197-
justifyContent: "space-between",
198-
alignItems: "center",
199-
borderWidth: "1px",
200-
borderStyle: "solid",
201-
borderBottom: "none",
202-
}}
203-
>
204-
<Text size="xs" color="secondaryText">
205-
Provider
206-
</Text>
207-
<Button variant="ghost" onClick={showProviders}>
208-
<Container flex="row" center="y" gap="xxs" color="secondaryText">
209-
<Text size="xs">
210-
{preferredProvider
211-
? `${preferredProvider.charAt(0).toUpperCase() + preferredProvider.slice(1).toLowerCase()}`
212-
: fiatQuoteQuery.data?.provider
213-
? `${fiatQuoteQuery.data?.provider.charAt(0).toUpperCase() + fiatQuoteQuery.data?.provider.slice(1).toLowerCase()}`
214-
: ""}
215-
</Text>
216-
<ChevronDownIcon width={iconSize.sm} height={iconSize.sm} />
217-
</Container>
218-
</Button>
219-
</Container>
204+
{/** Shows preferred or quoted provider and conditional selection */}
205+
<PayProviderSelection
206+
onShowProviders={showProviders}
207+
quotedProvider={fiatQuoteQuery.data?.provider}
208+
preferredProvider={preferredProvider}
209+
supportedProviders={supportedProviders}
210+
/>
220211
{/* Estimated time + View fees button */}
221212
<EstimatedTimeAndFees
222213
quoteIsLoading={fiatQuoteQuery.isLoading}

packages/thirdweb/src/react/web/ui/ConnectWallet/screens/Buy/fiat/OnRampScreen.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ import { StepConnectorArrow } from "../swap/StepConnector.js";
4444
import { WalletRow } from "../swap/WalletRow.js";
4545
import { addPendingTx } from "../swap/pendingSwapTx.js";
4646
import type { PayerInfo } from "../types.js";
47+
import { getProviderLabel } from "../utils.js";
4748
import { StepContainer } from "./FiatSteps.js";
4849

4950
type OnRampScreenState = {
@@ -213,7 +214,7 @@ function StepUI(props: {
213214
/>
214215
<Container flex="column" gap="3xs" center="y" style={{ flex: "1" }}>
215216
<Text size="sm" color="primaryText">
216-
{step.action.charAt(0).toUpperCase() + step.action.slice(1)}
217+
{getProviderLabel(step.action)}
217218
</Text>
218219

219220
<Container
Lines changed: 30 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
1-
import {
2-
type FiatProvider,
3-
FiatProviders,
4-
} from "../../../../../../../pay/utils/commonTypes.js";
1+
import type { FiatProvider } from "../../../../../../../pay/utils/commonTypes.js";
52
import { Container } from "../../../../components/basic.js";
63
import { Button } from "../../../../components/buttons.js";
74
import { Link } from "../../../../components/text.js";
5+
import { getProviderLabel } from "../utils.js";
86
/**
97
* @internal
108
*/
9+
1110
export function Providers(props: {
11+
supportedProviders: FiatProvider[];
1212
preferredProvider?: FiatProvider;
1313
onSelect: (provider: FiatProvider) => void;
1414
}) {
@@ -21,37 +21,34 @@ export function Providers(props: {
2121
alignItems: "flex-start",
2222
}}
2323
>
24-
{FiatProviders.map((provider) => {
25-
return (
26-
<Container
27-
key={provider}
28-
flex="row"
29-
expand
30-
style={{
31-
justifyContent: "space-between",
32-
}}
24+
{props.supportedProviders.map((provider) => (
25+
<Container
26+
key={provider}
27+
flex="row"
28+
expand
29+
style={{
30+
justifyContent: "space-between",
31+
}}
32+
>
33+
<Button
34+
fullWidth
35+
onClick={() => props.onSelect(provider)}
36+
variant={"link"}
3337
>
34-
<Button
35-
fullWidth
36-
onClick={() => props.onSelect(provider)}
37-
variant={"link"}
38+
<Link
39+
color={
40+
props.preferredProvider === provider
41+
? "primaryText"
42+
: "secondaryText"
43+
}
44+
size="sm"
45+
hoverColor="primaryText"
3846
>
39-
<Link
40-
color={
41-
props.preferredProvider === provider
42-
? "primaryText"
43-
: "secondaryText"
44-
}
45-
size="sm"
46-
hoverColor="primaryText"
47-
>
48-
{provider.charAt(0).toUpperCase() +
49-
provider.slice(1).toLowerCase()}
50-
</Link>
51-
</Button>
52-
</Container>
53-
);
54-
})}
47+
{getProviderLabel(provider)}
48+
</Link>
49+
</Button>
50+
</Container>
51+
))}
5552
</Container>
5653
);
5754
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,12 @@
11
export function getBuyTokenAmountFontSize(value: string) {
22
return value.length > 10 ? "26px" : value.length > 6 ? "34px" : "50px";
33
}
4+
5+
/**
6+
*
7+
* @param str accepts any string but expects a fully upppercased string / type FiatProvider
8+
* @returns Fiat provider label to be rendered used within presentation logic
9+
*/
10+
export function getProviderLabel(str: string) {
11+
return str.charAt(0).toUpperCase() + str.slice(1).toLowerCase();
12+
}

0 commit comments

Comments
 (0)