Commit dba238fd authored by tom's avatar tom

search query events

parent fc823380
import getPageType from './getPageType';
import logEvent from './logEvent';
import useInit from './useInit'; import useInit from './useInit';
import useLogPageView from './useLogPageView'; import useLogPageView from './useLogPageView';
export * from './utils';
export { export {
useInit, useInit,
useLogPageView, useLogPageView,
logEvent,
getPageType,
}; };
import mixpanel from 'mixpanel-browser';
import type { EventTypes, EventPayload } from './utils';
type TrackFnArgs = Parameters<typeof mixpanel.track>;
export default function logEvent<EventType extends EventTypes>(
type: EventType,
properties?: EventPayload<EventType>,
optionsOrCallback?: TrackFnArgs[2],
callback?: TrackFnArgs[3],
) {
mixpanel.track(type, properties, optionsOrCallback, callback);
}
import mixpanel from 'mixpanel-browser';
import { useRouter } from 'next/router'; import { useRouter } from 'next/router';
import React from 'react'; import React from 'react';
...@@ -7,6 +6,8 @@ import getQueryParamString from 'lib/router/getQueryParamString'; ...@@ -7,6 +6,8 @@ import getQueryParamString from 'lib/router/getQueryParamString';
import getPageType from './getPageType'; import getPageType from './getPageType';
import getTabName from './getTabName'; import getTabName from './getTabName';
import logEvent from './logEvent';
import { EventTypes } from './utils';
export default function useLogPageView(isInited: boolean) { export default function useLogPageView(isInited: boolean) {
const router = useRouter(); const router = useRouter();
...@@ -19,9 +20,9 @@ export default function useLogPageView(isInited: boolean) { ...@@ -19,9 +20,9 @@ export default function useLogPageView(isInited: boolean) {
return; return;
} }
mixpanel.track('Page view', { logEvent(EventTypes.PAGE_VIEW, {
page_type: getPageType(pathname), 'Page type': getPageType(pathname),
tab: getTabName(tab), Tab: getTabName(tab),
}); });
}, [ isInited, pathname, tab ]); }, [ isInited, pathname, tab ]);
} }
export enum EventTypes {
PAGE_VIEW = 'Page view',
SEARCH_QUERY = 'Search query',
}
export type EventPayload<Type extends EventTypes> =
Type extends EventTypes.PAGE_VIEW ?
{
'Page type': string;
'Tab': string;
'Page'?: string;
} :
Type extends EventTypes.SEARCH_QUERY ? {
'Search query': string;
'Source page type': string;
'Result URL': string;
} :
undefined;
...@@ -5,6 +5,7 @@ import type { FormEvent, FocusEvent } from 'react'; ...@@ -5,6 +5,7 @@ import type { FormEvent, FocusEvent } from 'react';
import React from 'react'; import React from 'react';
import useIsMobile from 'lib/hooks/useIsMobile'; import useIsMobile from 'lib/hooks/useIsMobile';
import * as mixpanel from 'lib/mixpanel/index';
import SearchBarInput from './SearchBarInput'; import SearchBarInput from './SearchBarInput';
import SearchBarSuggest from './SearchBarSuggest'; import SearchBarSuggest from './SearchBarSuggest';
...@@ -21,15 +22,20 @@ const SearchBar = ({ isHomepage }: Props) => { ...@@ -21,15 +22,20 @@ const SearchBar = ({ isHomepage }: Props) => {
const menuWidth = React.useRef<number>(0); const menuWidth = React.useRef<number>(0);
const isMobile = useIsMobile(); const isMobile = useIsMobile();
const { searchTerm, handleSearchTermChange, query } = useSearchQuery(); const { searchTerm, handleSearchTermChange, query, pathname } = useSearchQuery();
const handleSubmit = React.useCallback((event: FormEvent<HTMLFormElement>) => { const handleSubmit = React.useCallback((event: FormEvent<HTMLFormElement>) => {
event.preventDefault(); event.preventDefault();
if (searchTerm) { if (searchTerm) {
const url = route({ pathname: '/search-results', query: { q: searchTerm } }); const url = route({ pathname: '/search-results', query: { q: searchTerm } });
mixpanel.logEvent(mixpanel.EventTypes.SEARCH_QUERY, {
'Search query': searchTerm,
'Source page type': mixpanel.getPageType(pathname),
'Result URL': url,
});
window.location.assign(url); window.location.assign(url);
} }
}, [ searchTerm ]); }, [ searchTerm, pathname ]);
const handleFocus = React.useCallback(() => { const handleFocus = React.useCallback(() => {
onOpen(); onOpen();
...@@ -98,7 +104,7 @@ const SearchBar = ({ isHomepage }: Props) => { ...@@ -98,7 +104,7 @@ const SearchBar = ({ isHomepage }: Props) => {
</PopoverTrigger> </PopoverTrigger>
<PopoverContent w={ `${ menuWidth.current }px` } maxH={{ base: '300px', lg: '500px' }} overflowY="scroll" ref={ menuRef }> <PopoverContent w={ `${ menuWidth.current }px` } maxH={{ base: '300px', lg: '500px' }} overflowY="scroll" ref={ menuRef }>
<PopoverBody py={ 6 }> <PopoverBody py={ 6 }>
<SearchBarSuggest query={ query } searchTerm={ searchTerm }/> <SearchBarSuggest query={ query } searchTerm={ searchTerm } pathname={ pathname }/>
</PopoverBody> </PopoverBody>
</PopoverContent> </PopoverContent>
</Popover> </Popover>
......
import { Text } from '@chakra-ui/react'; import { Text } from '@chakra-ui/react';
import type { UseQueryResult } from '@tanstack/react-query'; import type { UseQueryResult } from '@tanstack/react-query';
import type { Route } from 'nextjs-routes';
import React from 'react'; import React from 'react';
import type { SearchResult } from 'types/api/search'; import type { SearchResult } from 'types/api/search';
...@@ -16,9 +17,10 @@ interface Props { ...@@ -16,9 +17,10 @@ interface Props {
pagination: PaginationProps; pagination: PaginationProps;
}; };
searchTerm: string; searchTerm: string;
pathname: Route['pathname'];
} }
const SearchBarSuggest = ({ query, searchTerm }: Props) => { const SearchBarSuggest = ({ query, searchTerm, pathname }: Props) => {
const isMobile = useIsMobile(); const isMobile = useIsMobile();
const content = (() => { const content = (() => {
...@@ -36,7 +38,8 @@ const SearchBarSuggest = ({ query, searchTerm }: Props) => { ...@@ -36,7 +38,8 @@ const SearchBarSuggest = ({ query, searchTerm }: Props) => {
return ( return (
<> <>
<Text fontWeight={ 500 } fontSize="sm">Found <Text fontWeight={ 700 } as="span">{ num }</Text> matching { resultText }</Text> <Text fontWeight={ 500 } fontSize="sm">Found <Text fontWeight={ 700 } as="span">{ num }</Text> matching { resultText }</Text>
{ query.data.items.map((item, index) => <SearchBarSuggestItem key={ index } data={ item } isMobile={ isMobile } searchTerm={ searchTerm }/>) } { query.data.items.map((item, index) =>
<SearchBarSuggestItem key={ index } data={ item } isMobile={ isMobile } searchTerm={ searchTerm } pathname={ pathname }/>) }
</> </>
); );
})(); })();
......
import { chakra, Text, Flex, useColorModeValue, Icon, Box } from '@chakra-ui/react'; import { chakra, Text, Flex, useColorModeValue, Icon, Box } from '@chakra-ui/react';
import { route } from 'nextjs-routes'; import { route } from 'nextjs-routes';
import type { Route } from 'nextjs-routes';
import React from 'react'; import React from 'react';
import type { SearchResultItem } from 'types/api/search'; import type { SearchResultItem } from 'types/api/search';
...@@ -7,6 +8,7 @@ import type { SearchResultItem } from 'types/api/search'; ...@@ -7,6 +8,7 @@ import type { SearchResultItem } from 'types/api/search';
import blockIcon from 'icons/block.svg'; import blockIcon from 'icons/block.svg';
import txIcon from 'icons/transactions.svg'; import txIcon from 'icons/transactions.svg';
import highlightText from 'lib/highlightText'; import highlightText from 'lib/highlightText';
import * as mixpanel from 'lib/mixpanel/index';
import AddressIcon from 'ui/shared/address/AddressIcon'; import AddressIcon from 'ui/shared/address/AddressIcon';
import HashStringShortenDynamic from 'ui/shared/HashStringShortenDynamic'; import HashStringShortenDynamic from 'ui/shared/HashStringShortenDynamic';
import TokenLogo from 'ui/shared/TokenLogo'; import TokenLogo from 'ui/shared/TokenLogo';
...@@ -15,9 +17,18 @@ interface Props { ...@@ -15,9 +17,18 @@ interface Props {
data: SearchResultItem; data: SearchResultItem;
isMobile: boolean | undefined; isMobile: boolean | undefined;
searchTerm: string; searchTerm: string;
pathname: Route['pathname'];
} }
const SearchBarSuggestItem = ({ data, isMobile, searchTerm }: Props) => { const SearchBarSuggestItem = ({ data, isMobile, searchTerm, pathname }: Props) => {
const handleClick = React.useCallback((event: React.MouseEvent<HTMLAnchorElement>) => {
mixpanel.logEvent(mixpanel.EventTypes.SEARCH_QUERY, {
'Search query': searchTerm,
'Source page type': mixpanel.getPageType(pathname),
'Result URL': event.currentTarget.href,
});
}, [ searchTerm, pathname ]);
const url = (() => { const url = (() => {
switch (data.type) { switch (data.type) {
...@@ -161,6 +172,7 @@ const SearchBarSuggestItem = ({ data, isMobile, searchTerm }: Props) => { ...@@ -161,6 +172,7 @@ const SearchBarSuggestItem = ({ data, isMobile, searchTerm }: Props) => {
_first={{ _first={{
mt: 2, mt: 2,
}} }}
onClick={ handleClick }
> >
<Flex display="flex" alignItems="center"> <Flex display="flex" alignItems="center">
{ firstRow } { firstRow }
......
...@@ -15,6 +15,7 @@ export default function useSearchQuery(isSearchPage = false) { ...@@ -15,6 +15,7 @@ export default function useSearchQuery(isSearchPage = false) {
const [ searchTerm, setSearchTerm ] = React.useState(initialValue); const [ searchTerm, setSearchTerm ] = React.useState(initialValue);
const debouncedSearchTerm = useDebounce(searchTerm, 300); const debouncedSearchTerm = useDebounce(searchTerm, 300);
const pathname = router.pathname;
const query = useQueryWithPages({ const query = useQueryWithPages({
resourceName: 'search', resourceName: 'search',
...@@ -39,5 +40,6 @@ export default function useSearchQuery(isSearchPage = false) { ...@@ -39,5 +40,6 @@ export default function useSearchQuery(isSearchPage = false) {
handleSearchTermChange: setSearchTerm, handleSearchTermChange: setSearchTerm,
query, query,
redirectCheckQuery, redirectCheckQuery,
pathname,
}; };
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment