diff --git a/src/analytics/event.ts b/src/analytics/event.ts index 765d4a3239..46ddac74b4 100644 --- a/src/analytics/event.ts +++ b/src/analytics/event.ts @@ -187,6 +187,10 @@ export const event = { * Called when the user completes a Revoke Approcal flow and submits the transaction. */ revokeSubmitted: 'revoke.submitted', + /* + * Called when the user searches in swap, send or command K + */ + searchQuery: 'search_query', /** * Called when a user enters the send flow */ @@ -759,6 +763,20 @@ export type EventProperties = { [event.pointsViewed]: undefined; [event.popupOpened]: undefined; [event.settingsAnalyticsTrackingDisabled]: undefined; + [event.searchQuery]: { + /** + * Where the search was initiated from + */ + location: 'swap' | 'send' | 'commandk'; + /** + * The query string that was searched. + */ + query: string; + /** + * The length of the query string. + */ + queryLength: number; + }; [event.revokeSubmitted]: { /** * Symbol of the asset being sent. diff --git a/src/entries/popup/components/CommandK/CommandK.tsx b/src/entries/popup/components/CommandK/CommandK.tsx index 36e3698d9c..bf885e8ec7 100644 --- a/src/entries/popup/components/CommandK/CommandK.tsx +++ b/src/entries/popup/components/CommandK/CommandK.tsx @@ -1,6 +1,8 @@ import { AnimatePresence, motion, useAnimation } from 'framer-motion'; -import React from 'react'; +import React, { useEffect, useRef } from 'react'; +import { analytics } from '~/analytics'; +import { event } from '~/analytics/event'; import { useCurrentThemeStore } from '~/core/state/currentSettings/currentTheme'; import { Box, Separator, Symbol } from '~/design-system'; import { Input } from '~/design-system/components/Input/Input'; @@ -265,6 +267,50 @@ export const CommandKInput = React.memo(function CommandKInput({ setSkipBackAnimation, }: CommandKInputProps) { const { currentTheme } = useCurrentThemeStore(); + const lastSearchRef = useRef(searchQuery); + + // Track search when component unmounts if there was a search + useEffect(() => { + return () => { + if (lastSearchRef.current.trim()) { + analytics.track(event.searchQuery, { + query: lastSearchRef.current, + queryLength: lastSearchRef.current.length, + location: 'commandk', + }); + console.log('analytics: ', { + query: lastSearchRef.current, + queryLength: lastSearchRef.current.length, + location: 'commandk', + }); + } + }; + }, []); + + // Update last search ref when search changes + useEffect(() => { + lastSearchRef.current = searchQuery; + }, [searchQuery]); + + const trackSearchAndExecute = React.useCallback( + (command: SearchItem | null) => { + // Track search if there was one when executing a command + if (searchQuery.trim()) { + analytics.track(event.searchQuery, { + query: searchQuery, + queryLength: searchQuery.length, + location: 'commandk', + }); + console.log('analytics: ', { + query: searchQuery, + queryLength: searchQuery.length, + location: 'commandk', + }); + } + handleExecuteCommand(command); + }, + [searchQuery, handleExecuteCommand], + ); const onSearchQueryChange = React.useCallback( (e: React.ChangeEvent) => { @@ -291,7 +337,7 @@ export const CommandKInput = React.memo(function CommandKInput({ useKeyboardNavigation( didScrollOrNavigate, filteredCommands, - handleExecuteCommand, + trackSearchAndExecute, listRef, selectedCommand, selectedCommandIndex, diff --git a/src/entries/popup/pages/send/SendTokenInput.tsx b/src/entries/popup/pages/send/SendTokenInput.tsx index c723aaa320..766bd2648f 100644 --- a/src/entries/popup/pages/send/SendTokenInput.tsx +++ b/src/entries/popup/pages/send/SendTokenInput.tsx @@ -11,6 +11,8 @@ import React, { useState, } from 'react'; +import { analytics } from '~/analytics'; +import { event } from '~/analytics/event'; import { i18n } from '~/core/languages'; import { useTestnetModeStore } from '~/core/state/currentSettings/testnetMode'; import { NftSort } from '~/core/state/nfts'; @@ -41,7 +43,6 @@ import { AssetRow } from '../home/Tokens'; import { InputActionButton } from './InputActionButton'; import { RowHighlightWrapper } from './RowHighlightWrapper'; - const TokenSortMenu = ({ asset, setSortDropdownOpen, @@ -270,8 +271,22 @@ export const SendTokenInput = React.forwardRef< selectNft(); selectAssetAddressAndChain(address, chainId); setDropdownVisible(false); + console.log('inputValue: ', inputValue); + console.log('inputValue.trim(): ', inputValue.trim()); + if (inputValue.trim()) { + console.log('analytics: ', { + query: inputValue, + queryLength: inputValue.length, + location: 'send', + }); + analytics.track(event.searchQuery, { + query: inputValue, + queryLength: inputValue.length, + location: 'send', + }); + } }, - [selectAssetAddressAndChain, selectNft], + [inputValue, selectAssetAddressAndChain, selectNft], ); const onSelectNft = useCallback( @@ -279,8 +294,22 @@ export const SendTokenInput = React.forwardRef< selectNft(nft); selectAssetAddressAndChain('', ChainId.mainnet); setDropdownVisible(false); + console.log('inputValue: ', inputValue); + console.log('inputValue.trim(): ', inputValue.trim()); + if (inputValue.trim()) { + console.log('analytics: ', { + query: inputValue, + queryLength: inputValue.length, + location: 'send', + }); + analytics.track(event.searchQuery, { + query: inputValue, + queryLength: inputValue.length, + location: 'send', + }); + } }, - [selectAssetAddressAndChain, selectNft], + [inputValue, selectAssetAddressAndChain, selectNft], ); const onInputValueChange = useCallback( diff --git a/src/entries/popup/pages/swap/SwapTokenInput/TokenInput.tsx b/src/entries/popup/pages/swap/SwapTokenInput/TokenInput.tsx index ed44f975c9..06ff4b359a 100644 --- a/src/entries/popup/pages/swap/SwapTokenInput/TokenInput.tsx +++ b/src/entries/popup/pages/swap/SwapTokenInput/TokenInput.tsx @@ -7,6 +7,8 @@ import React, { useState, } from 'react'; +import { analytics } from '~/analytics'; +import { event } from '~/analytics/event'; import { i18n } from '~/core/languages'; import { ParsedSearchAsset } from '~/core/types/assets'; import { Box } from '~/design-system'; @@ -138,7 +140,19 @@ export const TokenInput = React.forwardRef< setDropdownVisible(false); setAssetFilter(''); setTimeout(() => inputRef?.current?.focus(), 300); - }, [inputRef, onDropdownOpen, setAssetFilter]); + if (assetFilter.trim()) { + analytics.track(event.searchQuery, { + query: assetFilter, + queryLength: assetFilter.length, + location: 'swap', + }); + console.log('analytics: ', { + query: assetFilter, + queryLength: assetFilter.length, + location: 'swap', + }); + } + }, [assetFilter, inputRef, onDropdownOpen, setAssetFilter]); const onClose = useCallback(() => { selectAsset(null); @@ -149,7 +163,8 @@ export const TokenInput = React.forwardRef< const onInputValueChange = useCallback( (e: ChangeEvent) => { - setAssetFilter(e.target.value); + const newValue = e.target.value; + setAssetFilter(newValue); }, [setAssetFilter], );