diff --git a/src/analytics/event.ts b/src/analytics/event.ts index d508bdca159..12b53862765 100644 --- a/src/analytics/event.ts +++ b/src/analytics/event.ts @@ -615,6 +615,7 @@ export type EventProperties = { address: string; }; amount: string; + usdValue: number; }; [event.claimClaimableFailed]: { @@ -626,6 +627,7 @@ export type EventProperties = { address: string; }; amount: string; + usdValue: number; errorMessage: string; }; @@ -638,5 +640,6 @@ export type EventProperties = { address: string; }; amount: string; + usdValue: number; }; }; diff --git a/src/analytics/userProperties.ts b/src/analytics/userProperties.ts index ae4b5bb7e33..1ceb4c9325f 100644 --- a/src/analytics/userProperties.ts +++ b/src/analytics/userProperties.ts @@ -20,6 +20,10 @@ export interface UserProperties { NFTs?: number; poaps?: number; + // claimables + claimablesAmount?: number; + claimablesUSDValue?: number; + // nft offers nftOffersAmount?: number; nftOffersUSDValue?: number; diff --git a/src/components/asset-list/RecyclerAssetList2/Claimable.tsx b/src/components/asset-list/RecyclerAssetList2/Claimable.tsx index 1b6f3f779f2..0924ee1c320 100644 --- a/src/components/asset-list/RecyclerAssetList2/Claimable.tsx +++ b/src/components/asset-list/RecyclerAssetList2/Claimable.tsx @@ -40,6 +40,7 @@ export const Claimable = React.memo(function Claimable({ uniqueId, extendedState chainId: claimable.chainId, asset: { symbol: claimable.asset.symbol, address: claimable.asset.address }, amount: claimable.value.claimAsset.amount, + usdValue: claimable.value.usd, }); navigate(Routes.CLAIM_CLAIMABLE_PANEL, { claimable }); }} diff --git a/src/hooks/useWalletSectionsData.ts b/src/hooks/useWalletSectionsData.ts index abd0653cb88..aced536088e 100644 --- a/src/hooks/useWalletSectionsData.ts +++ b/src/hooks/useWalletSectionsData.ts @@ -1,4 +1,4 @@ -import { useMemo } from 'react'; +import { useEffect, useMemo } from 'react'; import useAccountSettings from './useAccountSettings'; import useCoinListEditOptions from './useCoinListEditOptions'; import useCoinListEdited from './useCoinListEdited'; @@ -16,6 +16,34 @@ import { useRemoteConfig } from '@/model/remoteConfig'; import { usePositions } from '@/resources/defi/PositionsQuery'; import { useClaimables } from '@/resources/addys/claimables/query'; import { useExperimentalConfig } from '@/config/experimentalHooks'; +import { analyticsV2 } from '@/analytics'; +import { Claimable } from '@/resources/addys/claimables/types'; +import { throttle } from 'lodash'; + +// user properties analytics for claimables that executes at max once every 2 min +const throttledClaimablesAnalytics = throttle( + (claimables: Claimable[]) => { + let totalUSDValue = 0; + const claimablesUSDValues: { + [key: string]: number; + } = {}; + + claimables.forEach(claimable => { + const attribute = `${claimable.analyticsId}USDValue`; + totalUSDValue += claimable.value.usd; + + if (claimablesUSDValues[attribute] !== undefined) { + claimablesUSDValues[attribute] += claimable.value.usd; + } else { + claimablesUSDValues[attribute] = claimable.value.usd; + } + }); + + analyticsV2.identify({ claimablesAmount: claimables.length, claimablesUSDValue: totalUSDValue, ...claimablesUSDValues }); + }, + 2 * 60 * 1000, + { trailing: false } +); export default function useWalletSectionsData({ type, @@ -40,6 +68,16 @@ export default function useWalletSectionsData({ const { data: positions } = usePositions({ address: accountAddress, currency: nativeCurrency }); const { data: claimables } = useClaimables({ address: accountAddress, currency: nativeCurrency }); + // claimables analytics + useEffect(() => { + if (claimables?.length) { + throttledClaimablesAnalytics(claimables); + } + return () => { + throttledClaimablesAnalytics.cancel(); + }; + }, [claimables]); + const walletsWithBalancesAndNames = useWalletsWithBalancesAndNames(); const accountWithBalance = walletsWithBalancesAndNames[selectedWallet.id]?.addresses.find( diff --git a/src/resources/addys/claimables/query.ts b/src/resources/addys/claimables/query.ts index 8ff0a26544b..311da649a50 100644 --- a/src/resources/addys/claimables/query.ts +++ b/src/resources/addys/claimables/query.ts @@ -32,7 +32,7 @@ export type ClaimablesArgs = { // Query Key export const claimablesQueryKey = ({ address, currency }: ClaimablesArgs) => - createQueryKey('claimables', { address, currency }, { persisterVersion: 3 }); + createQueryKey('claimables', { address, currency }, { persisterVersion: 4 }); type ClaimablesQueryKey = ReturnType; diff --git a/src/resources/addys/claimables/types.ts b/src/resources/addys/claimables/types.ts index 37852b6f2d8..426ed6e4523 100644 --- a/src/resources/addys/claimables/types.ts +++ b/src/resources/addys/claimables/types.ts @@ -37,6 +37,7 @@ interface AddysBaseClaimable { asset: AddysAsset; amount: string; dapp: DApp; + total_usd_value: number; } interface AddysTransactionClaimable extends AddysBaseClaimable { @@ -80,10 +81,12 @@ interface BaseClaimable { chainId: ChainId; name: string; uniqueId: string; + analyticsId: string; iconUrl: string; value: { claimAsset: { amount: string; display: string }; nativeAsset: { amount: string; display: string }; + usd: number; }; } diff --git a/src/resources/addys/claimables/utils.ts b/src/resources/addys/claimables/utils.ts index b4eb06a6bbd..5b047644c97 100644 --- a/src/resources/addys/claimables/utils.ts +++ b/src/resources/addys/claimables/utils.ts @@ -27,10 +27,12 @@ export const parseClaimables = (claimables: AddysClaimable[], currency: NativeCu chainId: claimable.network, name: claimable.name, uniqueId: claimable.unique_id, + analyticsId: `claimables${claimable.type.replace(/(^|-)([a-z])/g, (_, __, letter) => letter.toUpperCase())}`, // one-two-three -> OneTwoThree iconUrl: claimable.dapp.icon_url, value: { claimAsset: convertRawAmountToBalance(claimable.amount, claimable.asset), nativeAsset: convertRawAmountToNativeDisplay(claimable.amount, claimable.asset.decimals, claimable.asset.price.value, currency), + usd: claimable.total_usd_value, }, }; diff --git a/src/screens/claimables/ClaimingSponsoredClaimable.tsx b/src/screens/claimables/ClaimingSponsoredClaimable.tsx index 0d0f4cf5cc6..e03050be72b 100644 --- a/src/screens/claimables/ClaimingSponsoredClaimable.tsx +++ b/src/screens/claimables/ClaimingSponsoredClaimable.tsx @@ -56,6 +56,7 @@ export const ClaimingSponsoredClaimable = ({ claimable }: { claimable: Sponsored chainId: claimable.chainId, asset: { symbol: claimable.asset.symbol, address: claimable.asset.address }, amount: claimable.value.claimAsset.amount, + usdValue: claimable.value.usd, errorMessage: ErrorMessages.CLAIM_API_CALL_FAILED, }); logger.error(new RainbowError(`[ClaimSponsoredClaimable]: ${ErrorMessages.CLAIM_API_CALL_FAILED}`)); @@ -73,6 +74,7 @@ export const ClaimingSponsoredClaimable = ({ claimable }: { claimable: Sponsored chainId: claimable.chainId, asset: { symbol: claimable.asset.symbol, address: claimable.asset.address }, amount: claimable.value.claimAsset.amount, + usdValue: claimable.value.usd, errorMessage: ErrorMessages.CLAIM_API_CALL_FAILED, }); logger.error(new RainbowError(`[ClaimSponsoredClaimable]: ${ErrorMessages.CLAIM_API_CALL_FAILED}`)); @@ -89,6 +91,7 @@ export const ClaimingSponsoredClaimable = ({ claimable }: { claimable: Sponsored chainId: claimable.chainId, asset: { symbol: claimable.asset.symbol, address: claimable.asset.address }, amount: claimable.value.claimAsset.amount, + usdValue: claimable.value.usd, errorMessage: ErrorMessages.CLAIM_API_UNSUCCESSFUL_RESPONSE, }); logger.error(new RainbowError(`[ClaimSponsoredClaimable]: ${ErrorMessages.CLAIM_API_UNSUCCESSFUL_RESPONSE}`)); @@ -107,6 +110,7 @@ export const ClaimingSponsoredClaimable = ({ claimable }: { claimable: Sponsored chainId: claimable.chainId, asset: { symbol: claimable.asset.symbol, address: claimable.asset.address }, amount: claimable.value.claimAsset.amount, + usdValue: claimable.value.usd, }); // Immediately remove the claimable from cached data @@ -122,6 +126,7 @@ export const ClaimingSponsoredClaimable = ({ claimable }: { claimable: Sponsored chainId: claimable.chainId, asset: { symbol: claimable.asset.symbol, address: claimable.asset.address }, amount: claimable.value.claimAsset.amount, + usdValue: claimable.value.usd, errorMessage: ErrorMessages.UNHANDLED_ERROR, }); logger.error(new RainbowError(`[ClaimSponsoredClaimable]: ${ErrorMessages.UNHANDLED_ERROR}`), { @@ -138,6 +143,7 @@ export const ClaimingSponsoredClaimable = ({ claimable }: { claimable: Sponsored chainId: claimable.chainId, asset: { symbol: claimable.asset.symbol, address: claimable.asset.address }, amount: claimable.value.claimAsset.amount, + usdValue: claimable.value.usd, errorMessage: ErrorMessages.UNREACHABLE_CLAIM_STATE, }); logger.error(new RainbowError(`[ClaimSponsoredClaimable]: ${ErrorMessages.UNREACHABLE_CLAIM_STATE}`)); diff --git a/src/screens/claimables/ClaimingTransactionClaimable.tsx b/src/screens/claimables/ClaimingTransactionClaimable.tsx index 2a13b7750fe..04106fbd7f4 100644 --- a/src/screens/claimables/ClaimingTransactionClaimable.tsx +++ b/src/screens/claimables/ClaimingTransactionClaimable.tsx @@ -162,6 +162,7 @@ export const ClaimingTransactionClaimable = ({ claimable }: { claimable: Transac chainId: claimable.chainId, asset: { symbol: claimable.asset.symbol, address: claimable.asset.address }, amount: claimable.value.claimAsset.amount, + usdValue: claimable.value.usd, errorMessage: ErrorMessages.NO_TX_PAYLOAD, }); logger.error(new RainbowError(`[ClaimingTransactionClaimable]: ${ErrorMessages.NO_TX_PAYLOAD}`)); @@ -195,6 +196,7 @@ export const ClaimingTransactionClaimable = ({ claimable }: { claimable: Transac chainId: claimable.chainId, asset: { symbol: claimable.asset.symbol, address: claimable.asset.address }, amount: claimable.value.claimAsset.amount, + usdValue: claimable.value.usd, errorMessage: ErrorMessages.RAP_ERROR, }); logger.error(new RainbowError(`[ClaimingTransactionClaimable]: ${ErrorMessages.RAP_ERROR}`), { @@ -213,6 +215,7 @@ export const ClaimingTransactionClaimable = ({ claimable }: { claimable: Transac chainId: claimable.chainId, asset: { symbol: claimable.asset.symbol, address: claimable.asset.address }, amount: claimable.value.claimAsset.amount, + usdValue: claimable.value.usd, }); } }, @@ -225,6 +228,7 @@ export const ClaimingTransactionClaimable = ({ claimable }: { claimable: Transac chainId: claimable.chainId, asset: { symbol: claimable.asset.symbol, address: claimable.asset.address }, amount: claimable.value.claimAsset.amount, + usdValue: claimable.value.usd, errorMessage: ErrorMessages.UNHANDLED_ERROR, }); logger.error(new RainbowError(`[ClaimingTransactionClaimable]: ${ErrorMessages.UNHANDLED_ERROR}`), { @@ -241,6 +245,7 @@ export const ClaimingTransactionClaimable = ({ claimable }: { claimable: Transac chainId: claimable.chainId, asset: { symbol: claimable.asset.symbol, address: claimable.asset.address }, amount: claimable.value.claimAsset.amount, + usdValue: claimable.value.usd, errorMessage: ErrorMessages.UNREACHABLE_CLAIM_STATE, }); logger.error(new RainbowError(`[ClaimingTransactionClaimable]: ${ErrorMessages.UNREACHABLE_CLAIM_STATE}`));