[SDK] Feature: Pay analytics (#4490)
## Problem solved
Short description of the bug fixed or feature added
<!-- start pr-codex -->
---
## PR-Codex overview
This PR focuses on adding tracking events for various payment methods and transactions across different screens.
### Detailed summary
- Added a new function `trackPayEvent` for tracking payment events
- Added tracking events for different payment methods like buy, direct payment, and swap
- Updated multiple files to include tracking events for specific user actions
> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`
<!-- end pr-codex -->
This commit is contained in:
+1
-1
@@ -216,7 +216,7 @@ export function ConfirmationScreen(props: {
|
||||
if (step === "swap") {
|
||||
setStatus("pending");
|
||||
try {
|
||||
let tx = props.buyWithCryptoQuote.transactionRequest
|
||||
let tx = props.buyWithCryptoQuote.transactionRequest
|
||||
|
||||
if (wallet?.walletId === walletIds.embeddedWallet) {
|
||||
tx = {
|
||||
|
||||
@@ -20,6 +20,35 @@ export function trackConnect(args: {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export function trackPayEvent(args: {
|
||||
client: ThirdwebClient;
|
||||
event: string;
|
||||
walletAddress?: string;
|
||||
walletType?: string;
|
||||
fromToken?: string;
|
||||
fromAmount?: string;
|
||||
toToken?: string;
|
||||
toAmount?: string;
|
||||
chainId?: number;
|
||||
dstChainId?: number;
|
||||
}) {
|
||||
track(args.client, {
|
||||
source: "pay",
|
||||
action: args.event,
|
||||
clientId: args.client.clientId,
|
||||
chainId: args.chainId,
|
||||
walletAddress: args.walletAddress,
|
||||
walletType: args.walletType,
|
||||
tokenAddress: args.fromToken,
|
||||
amountWei: args.fromAmount,
|
||||
dstTokenAddress: args.toToken,
|
||||
dstChainId: args.chainId,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
} from "@radix-ui/react-icons";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { useContext, useEffect, useState } from "react";
|
||||
import { trackPayEvent } from "../../../../analytics/track.js";
|
||||
import type { Chain } from "../../../../chains/types.js";
|
||||
import type { ThirdwebClient } from "../../../../client/client.js";
|
||||
import { getContract } from "../../../../contract/contract.js";
|
||||
@@ -568,6 +569,12 @@ function DetailsModal(props: {
|
||||
flex: 1,
|
||||
}}
|
||||
onClick={() => {
|
||||
trackPayEvent({
|
||||
event: "details_modal_buy_click",
|
||||
client: client,
|
||||
walletAddress: activeAccount?.address,
|
||||
walletType: activeWallet?.id,
|
||||
});
|
||||
setScreen("buy");
|
||||
}}
|
||||
>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { IdCardIcon } from "@radix-ui/react-icons";
|
||||
import { useCallback, useMemo, useState } from "react";
|
||||
import { trackPayEvent } from "../../../../../../analytics/track.js";
|
||||
import type { Chain } from "../../../../../../chains/types.js";
|
||||
import type { ThirdwebClient } from "../../../../../../client/client.js";
|
||||
import { NATIVE_TOKEN_ADDRESS } from "../../../../../../constants/addresses.js";
|
||||
@@ -528,7 +529,13 @@ function BuyScreenContent(props: BuyScreenContentProps) {
|
||||
}}
|
||||
>
|
||||
{screen.id === "select-payment-method" && (
|
||||
<PaymentMethodSelection setScreen={(id) => setScreen({ id })} />
|
||||
<PaymentMethodSelection
|
||||
mode={payOptions.mode}
|
||||
client={client}
|
||||
walletAddress={payer.account.address}
|
||||
walletType={payer.wallet.id}
|
||||
setScreen={(id) => setScreen({ id })}
|
||||
/>
|
||||
)}
|
||||
|
||||
{screen.id === "select-wallet" && (
|
||||
@@ -891,7 +898,11 @@ function TokenSelectedLayout(props: {
|
||||
}
|
||||
|
||||
function PaymentMethodSelection(props: {
|
||||
client: ThirdwebClient;
|
||||
walletAddress: string;
|
||||
walletType: string;
|
||||
setScreen: (screenId: "select-wallet" | "buy-with-fiat") => void;
|
||||
mode?: "transaction" | "direct_payment" | "fund_wallet";
|
||||
}) {
|
||||
return (
|
||||
<Container animate="fadein">
|
||||
@@ -900,7 +911,15 @@ function PaymentMethodSelection(props: {
|
||||
<Button
|
||||
variant="outline"
|
||||
bg="tertiaryBg"
|
||||
onClick={() => props.setScreen("buy-with-fiat")}
|
||||
onClick={() => {
|
||||
trackPayEvent({
|
||||
event: `pay_with_credit_card_${props.mode || "unknown"}_mode`,
|
||||
client: props.client,
|
||||
walletAddress: props.walletAddress,
|
||||
walletType: props.walletType,
|
||||
});
|
||||
props.setScreen("buy-with-fiat");
|
||||
}}
|
||||
gap="sm"
|
||||
style={{
|
||||
justifyContent: "flex-start",
|
||||
@@ -928,7 +947,16 @@ function PaymentMethodSelection(props: {
|
||||
<Button
|
||||
variant="outline"
|
||||
bg="tertiaryBg"
|
||||
onClick={() => props.setScreen("select-wallet")}
|
||||
onClick={() => {
|
||||
trackPayEvent({
|
||||
event: `pay_with_crypto_${props.mode || "unknown"}_mode`,
|
||||
client: props.client,
|
||||
walletAddress: props.walletAddress,
|
||||
walletType: props.walletType,
|
||||
});
|
||||
|
||||
props.setScreen("select-wallet");
|
||||
}}
|
||||
style={{
|
||||
justifyContent: "flex-start",
|
||||
}}
|
||||
|
||||
+7
@@ -1,4 +1,5 @@
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { trackPayEvent } from "../../../../../../analytics/track.js";
|
||||
import type { Chain } from "../../../../../../chains/types.js";
|
||||
import type { ThirdwebClient } from "../../../../../../client/client.js";
|
||||
import { NATIVE_TOKEN_ADDRESS } from "../../../../../../constants/addresses.js";
|
||||
@@ -242,6 +243,12 @@ export function DirectPaymentModeScreen(props: {
|
||||
variant="accent"
|
||||
fullWidth
|
||||
onClick={() => {
|
||||
trackPayEvent({
|
||||
event: "choose_payment_method_direct_payment_mode",
|
||||
client,
|
||||
walletAddress: payerAccount.address,
|
||||
walletType: activeWallet?.id,
|
||||
});
|
||||
onContinue(totalCost, paymentInfo.chain, token);
|
||||
}}
|
||||
>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { trackPayEvent } from "../../../../../../analytics/track.js";
|
||||
import type { Chain } from "../../../../../../chains/types.js";
|
||||
import type { ThirdwebClient } from "../../../../../../client/client.js";
|
||||
import { NATIVE_TOKEN_ADDRESS } from "../../../../../../constants/addresses.js";
|
||||
@@ -225,6 +226,12 @@ export function TransactionModeScreen(props: {
|
||||
) {
|
||||
totalCostWei += transactionCostAndData.gasCostWei;
|
||||
}
|
||||
trackPayEvent({
|
||||
event: "choose_payment_method_transaction_mode",
|
||||
client,
|
||||
walletAddress: payerAccount.address,
|
||||
walletType: activeWallet?.id,
|
||||
});
|
||||
onContinue(
|
||||
toTokens(totalCostWei, transactionCostAndData.decimals),
|
||||
payUiOptions.transaction.chain,
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { useCallback, useState } from "react";
|
||||
import { trackPayEvent } from "../../../../../../../analytics/track.js";
|
||||
import type { ThirdwebClient } from "../../../../../../../client/client.js";
|
||||
import type { BuyWithFiatQuote } from "../../../../../../../pay/buyWithFiat/getQuote.js";
|
||||
import {
|
||||
@@ -88,6 +89,12 @@ export function FiatFlow(props: {
|
||||
step={1}
|
||||
onContinue={() => {
|
||||
const popup = openOnrampPopup(props.quote.onRampLink, props.theme);
|
||||
trackPayEvent({
|
||||
event: "open_onramp_popup",
|
||||
client: props.client,
|
||||
walletAddress: props.payer.account.address,
|
||||
walletType: props.payer.wallet.id,
|
||||
});
|
||||
addPendingTx({
|
||||
type: "fiat",
|
||||
intentId: props.quote.intentId,
|
||||
|
||||
+53
@@ -1,5 +1,6 @@
|
||||
import { CrossCircledIcon } from "@radix-ui/react-icons";
|
||||
import { useState } from "react";
|
||||
import { trackPayEvent } from "../../../../../../../analytics/track.js";
|
||||
import type { Chain } from "../../../../../../../chains/types.js";
|
||||
import type { ThirdwebClient } from "../../../../../../../client/client.js";
|
||||
import type { BuyWithCryptoQuote } from "../../../../../../../pay/buyWithCrypto/getQuote.js";
|
||||
@@ -190,6 +191,19 @@ export function SwapConfirmationScreen(props: {
|
||||
try {
|
||||
setStatus("pending");
|
||||
|
||||
trackPayEvent({
|
||||
event: "prompt_swap_approval",
|
||||
client: props.client,
|
||||
walletAddress: props.payer.account.address,
|
||||
walletType: props.payer.wallet.id,
|
||||
fromToken: props.quote.swapDetails.fromToken.tokenAddress,
|
||||
fromAmount: props.quote.swapDetails.fromAmountWei,
|
||||
toToken: props.quote.swapDetails.toToken.tokenAddress,
|
||||
toAmount: props.quote.swapDetails.toAmountWei,
|
||||
chainId: props.quote.swapDetails.fromToken.chainId,
|
||||
dstChainId: props.quote.swapDetails.toToken.chainId,
|
||||
});
|
||||
|
||||
const tx = await sendTransaction({
|
||||
account: props.payer.account,
|
||||
transaction: props.quote.approval,
|
||||
@@ -198,6 +212,19 @@ export function SwapConfirmationScreen(props: {
|
||||
await waitForReceipt({ ...tx, maxBlocksWaitTime: 50 });
|
||||
// props.onQuoteFinalized(props.quote);
|
||||
|
||||
trackPayEvent({
|
||||
event: "swap_approval_success",
|
||||
client: props.client,
|
||||
walletAddress: props.payer.account.address,
|
||||
walletType: props.payer.wallet.id,
|
||||
fromToken: props.quote.swapDetails.fromToken.tokenAddress,
|
||||
fromAmount: props.quote.swapDetails.fromAmountWei,
|
||||
toToken: props.quote.swapDetails.toToken.tokenAddress,
|
||||
toAmount: props.quote.swapDetails.toAmountWei,
|
||||
chainId: props.quote.swapDetails.fromToken.chainId,
|
||||
dstChainId: props.quote.swapDetails.toToken.chainId,
|
||||
});
|
||||
|
||||
setStep("swap");
|
||||
setStatus("idle");
|
||||
} catch (e) {
|
||||
@@ -223,6 +250,19 @@ export function SwapConfirmationScreen(props: {
|
||||
};
|
||||
}
|
||||
|
||||
trackPayEvent({
|
||||
event: "prompt_swap_execution",
|
||||
client: props.client,
|
||||
walletAddress: props.payer.account.address,
|
||||
walletType: props.payer.wallet.id,
|
||||
fromToken: props.quote.swapDetails.fromToken.tokenAddress,
|
||||
fromAmount: props.quote.swapDetails.fromAmountWei,
|
||||
toToken: props.quote.swapDetails.toToken.tokenAddress,
|
||||
toAmount: props.quote.swapDetails.toAmountWei,
|
||||
chainId: props.quote.swapDetails.fromToken.chainId,
|
||||
dstChainId: props.quote.swapDetails.toToken.chainId,
|
||||
});
|
||||
|
||||
const _swapTx = await sendTransaction({
|
||||
account: props.payer.account,
|
||||
transaction: tx,
|
||||
@@ -230,6 +270,19 @@ export function SwapConfirmationScreen(props: {
|
||||
|
||||
await waitForReceipt({ ..._swapTx, maxBlocksWaitTime: 50 });
|
||||
|
||||
trackPayEvent({
|
||||
event: "swap_execution_success",
|
||||
client: props.client,
|
||||
walletAddress: props.payer.account.address,
|
||||
walletType: props.payer.wallet.id,
|
||||
fromToken: props.quote.swapDetails.fromToken.tokenAddress,
|
||||
fromAmount: props.quote.swapDetails.fromAmountWei,
|
||||
toToken: props.quote.swapDetails.toToken.tokenAddress,
|
||||
toAmount: props.quote.swapDetails.toAmountWei,
|
||||
chainId: props.quote.swapDetails.toToken.chainId,
|
||||
dstChainId: props.quote.swapDetails.toToken.chainId,
|
||||
});
|
||||
|
||||
// do not add pending tx if the swap is part of fiat flow
|
||||
if (!props.isFiatFlow) {
|
||||
addPendingTx({
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { useState } from "react";
|
||||
import { trackPayEvent } from "../../../../analytics/track.js";
|
||||
import type { ThirdwebClient } from "../../../../client/client.js";
|
||||
import type { WaitForReceiptOptions } from "../../../../transaction/actions/wait-for-tx-receipt.js";
|
||||
import type { PreparedTransaction } from "../../../../transaction/prepare-transaction.js";
|
||||
import { CustomThemeProvider } from "../../../core/design-system/CustomThemeProvider.js";
|
||||
import type { Theme } from "../../../core/design-system/index.js";
|
||||
import type { PayUIOptions } from "../../../core/hooks/connection/ConnectButtonProps.js";
|
||||
import { useActiveAccount } from "../../../core/hooks/wallets/useActiveAccount.js";
|
||||
import { useActiveWallet } from "../../../core/hooks/wallets/useActiveWallet.js";
|
||||
import type { SupportedTokens } from "../../../core/utils/defaultTokens.js";
|
||||
import { LoadingScreen } from "../../wallets/shared/LoadingScreen.js";
|
||||
import { useConnectLocale } from "../ConnectWallet/locale/getConnectLocale.js";
|
||||
@@ -27,6 +31,23 @@ export type ModalProps = {
|
||||
};
|
||||
|
||||
export function TransactionModal(props: ModalProps) {
|
||||
const account = useActiveAccount();
|
||||
const wallet = useActiveWallet();
|
||||
|
||||
useQuery({
|
||||
queryKey: ["transaction-modal-event"],
|
||||
queryFn: () => {
|
||||
if (!account || !wallet) return;
|
||||
trackPayEvent({
|
||||
client: props.client,
|
||||
walletAddress: account.address,
|
||||
walletType: wallet.id,
|
||||
event: "open_pay_transaction_modal",
|
||||
});
|
||||
},
|
||||
enabled: !!wallet,
|
||||
});
|
||||
|
||||
return (
|
||||
<CustomThemeProvider theme={props.theme}>
|
||||
<Modal
|
||||
|
||||
Reference in New Issue
Block a user