Skip to content

Commit 99535ba

Browse files
[SDK] feat: Redesign token selection flow in PayEmbed
1 parent 52cbcd2 commit 99535ba

File tree

14 files changed

+261
-266
lines changed

14 files changed

+261
-266
lines changed

apps/playground-web/src/components/pay/direct-payment.tsx

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
"use client";
2-
3-
import { sepolia } from "thirdweb/chains";
2+
import { base } from "thirdweb/chains";
43
import { PayEmbed, getDefaultToken } from "thirdweb/react";
54
import { THIRDWEB_CLIENT } from "../../lib/client";
65
import { StyledConnectButton } from "../styled-connect-button";
@@ -16,9 +15,9 @@ export function BuyMerchPreview() {
1615
payOptions={{
1716
mode: "direct_payment",
1817
paymentInfo: {
19-
amount: "0.1",
20-
chain: sepolia,
21-
token: getDefaultToken(sepolia, "USDC"),
18+
amount: "2",
19+
chain: base,
20+
token: getDefaultToken(base, "USDC"),
2221
sellerAddress: "0xEb0effdFB4dC5b3d5d3aC6ce29F3ED213E95d675",
2322
},
2423
metadata: {

apps/playground-web/src/components/pay/transaction-button.tsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import { useTheme } from "next-themes";
44
import { getContract } from "thirdweb";
5-
import { base, sepolia } from "thirdweb/chains";
5+
import { base, polygon } from "thirdweb/chains";
66
import { transfer } from "thirdweb/extensions/erc20";
77
import { claimTo, getNFT } from "thirdweb/extensions/erc1155";
88
import {
@@ -21,12 +21,12 @@ const nftContract = getContract({
2121
client: THIRDWEB_CLIENT,
2222
});
2323

24-
const USDC = getDefaultToken(sepolia, "USDC");
24+
const USDC = getDefaultToken(polygon, "USDC");
2525

2626
const usdcContract = getContract({
2727
// biome-ignore lint/style/noNonNullAssertion: its there
2828
address: USDC!.address,
29-
chain: sepolia,
29+
chain: polygon,
3030
client: THIRDWEB_CLIENT,
3131
});
3232

@@ -55,6 +55,7 @@ export function PayTransactionPreview() {
5555
to: account?.address || "",
5656
}),
5757
metadata: nft?.metadata,
58+
buyWithFiat: false,
5859
}}
5960
/>
6061
)}
@@ -69,6 +70,7 @@ export function PayTransactionButtonPreview() {
6970
return (
7071
<>
7172
<StyledConnectButton />
73+
<div className="h-10" />
7274
{account && (
7375
<div className="flex flex-col items-center justify-center gap-2">
7476
<div className="flex items-center gap-2">

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

Lines changed: 41 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -432,67 +432,6 @@ function BuyScreenContent(props: BuyScreenContentProps) {
432432
);
433433
}
434434

435-
if (
436-
screen.id === "select-from-token" &&
437-
supportedSourcesQuery.data &&
438-
sourceSupportedTokens
439-
) {
440-
const chains = supportedSourcesQuery.data.map((x) => x.chain);
441-
const goBack = () => setScreen(screen.backScreen);
442-
// if token selection is disabled - only show network selector screen
443-
if (
444-
payOptions.buyWithCrypto !== false &&
445-
payOptions.buyWithCrypto?.prefillSource?.allowEdits?.token === false
446-
) {
447-
return (
448-
<ChainSelectionScreen
449-
chains={chains}
450-
client={props.client}
451-
connectLocale={props.connectLocale}
452-
setChain={setFromChain}
453-
goBack={goBack}
454-
/>
455-
);
456-
}
457-
458-
return (
459-
<TokenSelectorScreen
460-
onBack={goBack}
461-
onConnect={() => {
462-
setScreen({
463-
id: "connect-payer-wallet",
464-
backScreen: screen,
465-
});
466-
}}
467-
modalTitle="Available tokens"
468-
connectLocale={props.connectLocale}
469-
client={props.client}
470-
sourceTokens={sourceSupportedTokens}
471-
sourceSupportedTokens={sourceSupportedTokens}
472-
toChain={toChain}
473-
toToken={toToken}
474-
tokenAmount={tokenAmount}
475-
fromChain={fromChain}
476-
fromToken={fromToken}
477-
mode={payOptions.mode}
478-
hiddenWallets={props.hiddenWallets}
479-
onSelect={(w, token, chain) => {
480-
const account = w.getAccount();
481-
if (account) {
482-
setPayer({
483-
account,
484-
chain,
485-
wallet: w,
486-
});
487-
setFromToken(token);
488-
setFromChain(chain);
489-
}
490-
goBack();
491-
}}
492-
/>
493-
);
494-
}
495-
496435
return (
497436
<Container animate="fadein">
498437
<div>
@@ -526,7 +465,8 @@ function BuyScreenContent(props: BuyScreenContentProps) {
526465

527466
{(screen.id === "select-payment-method" ||
528467
screen.id === "buy-with-crypto" ||
529-
screen.id === "buy-with-fiat") &&
468+
screen.id === "buy-with-fiat" ||
469+
screen.id === "select-from-token") &&
530470
payer && (
531471
<TokenSelectedLayout
532472
isBuyWithFiatEnabled={enabledPaymentMethods.buyWithFiatEnabled}
@@ -551,7 +491,11 @@ function BuyScreenContent(props: BuyScreenContentProps) {
551491
setTokenAmount={setTokenAmount}
552492
client={client}
553493
onBack={() => {
554-
setScreen({ id: "main" });
494+
if (screen.id === "select-from-token") {
495+
setScreen({ id: "buy-with-crypto" });
496+
} else {
497+
setScreen({ id: "main" });
498+
}
555499
}}
556500
>
557501
{screen.id === "buy-with-crypto" && activeAccount && (
@@ -614,6 +558,40 @@ function BuyScreenContent(props: BuyScreenContentProps) {
614558
setHasEditedAmount={setHasEditedAmount}
615559
/>
616560
)}
561+
562+
{screen.id === "select-from-token" &&
563+
supportedSourcesQuery.data &&
564+
sourceSupportedTokens && (
565+
<TokenSelectorScreen
566+
onConnect={() => {
567+
setScreen({
568+
id: "connect-payer-wallet",
569+
backScreen: screen,
570+
});
571+
}}
572+
client={props.client}
573+
sourceTokens={sourceSupportedTokens}
574+
sourceSupportedTokens={sourceSupportedTokens}
575+
toChain={toChain}
576+
toToken={toToken}
577+
tokenAmount={tokenAmount}
578+
mode={payOptions.mode}
579+
hiddenWallets={props.hiddenWallets}
580+
onSelect={(w, token, chain) => {
581+
const account = w.getAccount();
582+
if (account) {
583+
setPayer({
584+
account,
585+
chain,
586+
wallet: w,
587+
});
588+
setFromToken(token);
589+
setFromChain(chain);
590+
}
591+
setScreen({ id: "buy-with-crypto" });
592+
}}
593+
/>
594+
)}
617595
</TokenSelectedLayout>
618596
)}
619597
</div>

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ import {
3333
isNativeToken,
3434
} from "../nativeToken.js";
3535
import { useTransactionCostAndData } from "./main/useBuyTxStates.js";
36-
import { WalletRow } from "./swap/TokenSelectorScreen.js";
36+
import { WalletRow } from "./swap/WalletRow.js";
3737
import type { SupportedChainAndTokens } from "./swap/useSwapSupportedChains.js";
3838

3939
export function TransactionModeScreen(props: {

packages/thirdweb/src/react/web/ui/ConnectWallet/screens/Buy/main/useUISelectionStates.ts

Lines changed: 4 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -76,14 +76,9 @@ export function useFromTokenSelectionStates(options: {
7676
payOptions: PayUIOptions;
7777
supportedSources: SupportedSourcesInputData[];
7878
}) {
79-
const { payOptions, supportedSources } = options;
79+
const { payOptions } = options;
8080

81-
// --------------------------------------------------------------------------
82-
const firstSupportedSource = supportedSources?.length
83-
? supportedSources.length === 1
84-
? supportedSources[0]
85-
: supportedSources.find((x) => x.chain.id !== 1) // dont use mainnet as a default source, unless its the only source
86-
: undefined;
81+
// TODO (pay) - auto select token based on connected wallet balances
8782

8883
// Source token and chain selection ---------------------------------------------------
8984
const [fromChain_, setFromChain] = useState<Chain>();
@@ -95,12 +90,7 @@ export function useFromTokenSelectionStates(options: {
9590
(payOptions.mode === "transaction" && payOptions.transaction?.chain) ||
9691
(payOptions.mode === "direct_payment" && payOptions.paymentInfo?.chain);
9792

98-
const fromChainFromApi = firstSupportedSource?.chain
99-
? firstSupportedSource.chain
100-
: undefined;
101-
102-
const fromChain =
103-
fromChain_ || fromChainDevSpecified || fromChainFromApi || polygon;
93+
const fromChain = fromChain_ || fromChainDevSpecified || undefined;
10494

10595
const [fromToken_, setFromToken] = useState<ERC20OrNativeToken>();
10696

@@ -110,12 +100,8 @@ export function useFromTokenSelectionStates(options: {
110100
payOptions.buyWithCrypto?.prefillSource?.token) ||
111101
(payOptions.mode === "direct_payment" && payOptions.paymentInfo.token);
112102

113-
// May be updated in the future
114-
const fromTokenFromApi = NATIVE_TOKEN;
115-
116103
// supported tokens query in here
117-
const fromToken =
118-
fromToken_ || fromTokenDevSpecified || fromTokenFromApi || NATIVE_TOKEN;
104+
const fromToken = fromToken_ || fromTokenDevSpecified || undefined;
119105

120106
return {
121107
fromChain,

packages/thirdweb/src/react/web/ui/ConnectWallet/screens/Buy/swap/ConfirmationScreen.tsx

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,13 @@ import {
1212
type WaitForReceiptOptions,
1313
waitForReceipt,
1414
} from "../../../../../../../transaction/actions/wait-for-tx-receipt.js";
15-
import { shortenAddress } from "../../../../../../../utils/address.js";
1615
import { formatNumber } from "../../../../../../../utils/formatNumber.js";
1716
import { useCustomTheme } from "../../../../../../core/design-system/CustomThemeProvider.js";
1817
import {
1918
fontSize,
2019
iconSize,
2120
} from "../../../../../../core/design-system/index.js";
2221
import { useChainName } from "../../../../../../core/hooks/others/useChainQuery.js";
23-
import { useEnsName } from "../../../../../../core/utils/wallet.js";
2422
import { Skeleton } from "../../../../components/Skeleton.js";
2523
import { Spacer } from "../../../../components/Spacer.js";
2624
import { Spinner } from "../../../../components/Spinner.js";
@@ -34,6 +32,7 @@ import type { ERC20OrNativeToken } from "../../nativeToken.js";
3432
import { PayTokenIcon } from "../PayTokenIcon.js";
3533
import { Step } from "../Stepper.js";
3634
import type { PayerInfo } from "../types.js";
35+
import { WalletRow } from "./WalletRow.js";
3736
import { formatSeconds } from "./formatSeconds.js";
3837
import { addPendingTx } from "./pendingSwapTx.js";
3938

@@ -76,8 +75,6 @@ export function SwapConfirmationScreen(props: {
7675
const sender = props.quote.swapDetails.fromAddress;
7776
const isDifferentRecipient = receiver.toLowerCase() !== sender.toLowerCase();
7877

79-
const ensName = useEnsName({ client: props.client, address: receiver });
80-
8178
return (
8279
<Container p="lg">
8380
<ModalHeader title={props.title} onBack={props.onBack} />
@@ -139,9 +136,12 @@ export function SwapConfirmationScreen(props: {
139136
{/* Send to */}
140137
{isDifferentRecipient && (
141138
<ConfirmItem label="Receiver">
142-
<Text color="primaryText" size="sm">
143-
{ensName.data || shortenAddress(receiver)}
144-
</Text>
139+
<WalletRow
140+
client={props.client}
141+
address={receiver}
142+
iconSize="sm"
143+
textSize="sm"
144+
/>
145145
</ConfirmItem>
146146
)}
147147

packages/thirdweb/src/react/web/ui/ConnectWallet/screens/Buy/swap/PayWithCrypto.tsx

Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import { TokenRow } from "../../../../components/token/TokenRow.js";
1616
import { TokenSymbol } from "../../../../components/token/TokenSymbol.js";
1717
import { formatTokenBalance } from "../../formatTokenBalance.js";
1818
import { type NativeToken, isNativeToken } from "../../nativeToken.js";
19-
import { WalletRow } from "./TokenSelectorScreen.js";
19+
import { WalletRow } from "./WalletRow.js";
2020

2121
/**
2222
* Shows an amount "value" and renders the selected token and chain
@@ -26,8 +26,8 @@ import { WalletRow } from "./TokenSelectorScreen.js";
2626
*/
2727
export function PayWithCryptoQuoteInfo(props: {
2828
value: string;
29-
chain: Chain;
30-
token: TokenInfo | NativeToken;
29+
chain: Chain | undefined;
30+
token: TokenInfo | NativeToken | undefined;
3131
isLoading: boolean;
3232
client: ThirdwebClient;
3333
freezeChainAndTokenSelection?: boolean;
@@ -36,12 +36,19 @@ export function PayWithCryptoQuoteInfo(props: {
3636
onSelectToken: () => void;
3737
}) {
3838
const theme = useCustomTheme();
39-
const balanceQuery = useWalletBalance({
40-
address: props.payerAccount.address,
41-
chain: props.chain,
42-
tokenAddress: isNativeToken(props.token) ? undefined : props.token.address,
43-
client: props.client,
44-
});
39+
const balanceQuery = useWalletBalance(
40+
{
41+
address: props.payerAccount.address,
42+
chain: props.chain,
43+
tokenAddress: isNativeToken(props.token)
44+
? undefined
45+
: props.token?.address,
46+
client: props.client,
47+
},
48+
{
49+
enabled: !!props.chain && !!props.token,
50+
},
51+
);
4552

4653
return (
4754
<Container
@@ -69,10 +76,10 @@ export function PayWithCryptoQuoteInfo(props: {
6976
}}
7077
>
7178
<WalletRow client={props.client} address={props.payerAccount.address} />
72-
{balanceQuery.data ? (
79+
{props.token && props.chain && balanceQuery.data ? (
7380
<Container flex="row" gap="3xs" center="y">
7481
<Text size="xs" color="secondaryText" weight={500}>
75-
{formatTokenBalance(balanceQuery.data, false)}
82+
{formatTokenBalance(balanceQuery.data, false, 4)}
7683
</Text>
7784
<TokenSymbol
7885
token={props.token}
@@ -81,11 +88,11 @@ export function PayWithCryptoQuoteInfo(props: {
8188
color="secondaryText"
8289
/>
8390
</Container>
84-
) : (
91+
) : props.token && props.chain && balanceQuery.isLoading ? (
8592
<Skeleton width="70px" height={fontSize.xs} />
86-
)}
93+
) : null}
8794
</Container>
88-
{/* Quoted price */}
95+
{/* Quoted price & token selector */}
8996
<TokenRow
9097
token={props.token}
9198
chain={props.chain}
@@ -96,6 +103,10 @@ export function PayWithCryptoQuoteInfo(props: {
96103
style={{
97104
border: "none",
98105
borderRadius: 0,
106+
borderBottomLeftRadius:
107+
!props.token || !props.chain || !props.swapRequired ? radius.lg : 0,
108+
borderBottomRightRadius:
109+
!props.token || !props.chain || !props.swapRequired ? radius.lg : 0,
99110
}}
100111
/>
101112
</Container>

0 commit comments

Comments
 (0)