Feat/add events to docs (#587)

* Created logEvent utility

* Added event tracking to OCS Banner

* Created CustomNavbarLink with event tracking

* created custom navbar dropdown link with event tracking

* added event tracking to P0 navbar elements

* Added eventDetail parameter to event tracking

* Updated Bootcamp link

* enforced cursor pointer on custom navbar links

* updated navbar elements to include event tracking

* event tracking for navbar social links

* added target property to custom navbar elements

* made links to off-domain locations open in new tab

* updated tutorials data

* implemented tracking on connect wallet buttons

* removed duplicate connect button from StudentProgress component

* Links now send events with high importance

* Cleaned up StudentProgress component

* Social clicks use useCallback

* bugfix for logEvent

* created callbacks for social click handlers

* improved social click callbacks

* updated event names

* updated connect wallet event names on base.org

* added full typing to logEvent utility

* refactored logEvent typing

* added userId to event data options

* updated base-docs logEvent immplementations

* updated Connect Wallet event for base.org

* changed component_type to the expected

* Updated event logging for onchain summer banner
This commit is contained in:
Brendan from DeFi
2024-06-25 15:06:59 -07:00
committed by GitHub
parent c3f4ea25de
commit 100e7604fd
8 changed files with 348 additions and 33 deletions

View File

@@ -185,6 +185,9 @@ const config = {
to: '/tutorials',
navposition: 'bottomLeft',
label: 'Tutorials',
type: 'custom-navbarLink',
eventLabel: 'tutorials',
eventContext: 'navbar',
},
{
to: '/base-camp/docs/welcome',
@@ -194,14 +197,24 @@ const config = {
{
label: 'Learn',
to: '/base-camp/docs/welcome',
type: 'custom-dropdownLink',
eventLabel: 'camp_learn',
eventContext: 'navbar',
},
{
label: 'Track your progress',
to: '/base-camp/progress',
type: 'custom-dropdownLink',
eventLabel: 'camp_trackprogress',
eventContext: 'navbar',
},
{
label: 'Bootcamp',
href: 'https://base.org/bootcamp',
to: 'https://base.org/bootcamp',
target: '_blank',
type: 'custom-dropdownLink',
eventLabel: 'camp_bootcamp',
eventContext: 'navbar',
},
],
},
@@ -212,18 +225,30 @@ const config = {
items: [
{
label: 'Apps',
href: 'https://www.base.org/ecosystem',
to: 'https://www.base.org/ecosystem',
target: '_blank',
type: 'custom-dropdownLink',
eventLabel: 'ecosystem_apps',
eventContext: 'navbar',
},
{
label: 'Grants',
href: 'https://paragraph.xyz/@grants.base.eth/calling-based-builders',
to: 'https://paragraph.xyz/@grants.base.eth/calling-based-builders',
target: '_blank',
type: 'custom-dropdownLink',
eventLabel: 'ecosystem_grants',
eventContext: 'navbar',
},
],
},
{
label: 'Bridge',
navposition: 'topRight',
href: 'https://bridge.base.org/',
to: 'https://bridge.base.org/',
target: '_blank',
type: 'custom-navbarLink',
eventLabel: 'bridge',
eventContext: 'navbar',
},
{
type: 'dropdown',
@@ -232,15 +257,27 @@ const config = {
items: [
{
label: 'Block Explorer',
href: 'https://base.blockscout.com/',
to: 'https://base.blockscout.com/',
target: '_blank',
type: 'custom-dropdownLink',
eventLabel: 'builders_blockexplorer',
eventContext: 'navbar',
},
{
label: 'Status',
href: 'https://status.base.org/',
to: 'https://status.base.org/',
target: '_blank',
type: 'custom-dropdownLink',
eventLabel: 'builders_status',
eventContext: 'navbar',
},
{
label: 'Bug Bounty',
href: 'https://hackerone.com/coinbase',
to: 'https://hackerone.com/coinbase',
target: '_blank',
type: 'custom-dropdownLink',
eventLabel: 'builders_bugbounty',
eventContext: 'navbar',
},
],
},
@@ -251,15 +288,27 @@ const config = {
items: [
{
label: 'Mission',
href: 'https://www.base.org/about',
to: 'https://www.base.org/about',
target: '_blank',
type: 'custom-dropdownLink',
eventLabel: 'about_mission',
eventContext: 'navbar',
},
{
label: 'Blog',
href: 'https://base.mirror.xyz/',
to: 'https://base.mirror.xyz/',
target: '_blank',
type: 'custom-dropdownLink',
eventLabel: 'about_blog',
eventContext: 'navbar',
},
{
label: 'Jobs',
href: 'https://www.base.org/jobs',
to: 'https://www.base.org/jobs',
target: '_blank',
type: 'custom-dropdownLink',
eventLabel: 'about_jobs',
eventContext: 'navbar',
},
],
},

View File

@@ -2,6 +2,7 @@ import React from 'react';
import { useLocalStorage } from 'usehooks-ts';
import { useCallback } from 'react';
import Icon from '../Icon';
import logEvent, {ActionType, AnalyticsEventImportance, ComponentType} from "base-ui/utils/logEvent";
import styles from './styles.module.css';
@@ -10,6 +11,17 @@ const href = 'https://www.base.org/onchainsummer?utm_source=DocsSite&utm_campaig
export function OcsBanner() {
const [isBannerVisible, setIsBannerVisible] = useLocalStorage('isOcsBannerVisible', true);
const linkClick = useCallback(() => {
logEvent(
'ocsbanner',
{
action: ActionType.click,
componentType: ComponentType.banner,
context: 'navbar'
},
AnalyticsEventImportance.low
)}, [logEvent, ActionType, ComponentType, AnalyticsEventImportance]);
const hideBanner = useCallback(() => {
setIsBannerVisible(false);
}, [setIsBannerVisible]);
@@ -26,6 +38,7 @@ export function OcsBanner() {
target="_blank"
rel="noreferrer"
aria-label="Onchain Summer Buildathon Banner"
onClick={linkClick}
>
<span className={styles.bannerText}>Join the Onchain Summer Buildathon!</span>
</a>
@@ -35,6 +48,7 @@ export function OcsBanner() {
target="_blank"
rel="noreferrer"
aria-label="Onchain Summer Buildathon Banner"
onClick={linkClick}
>
<span className={styles.bannerSpacer} />
</a>

View File

@@ -1,11 +1,9 @@
/* eslint-disable */
import React from 'react';
import { useState } from 'react';
import { ConnectButton } from '@rainbow-me/rainbowkit';
import { useAccount } from 'wagmi';
import useNFTData from '../../utils/nft-exercise-data';
import NFTCard from './NFTCard';
export default function StudentProgress() {
@@ -105,19 +103,6 @@ export default function StudentProgress() {
>
<h1 style={{ paddingBottom: '40px' }}>Base Camp Progress</h1>
</div>
<div
style={{
display: 'flex',
width: 'auto',
flexBasis: '50%',
flexDirection: 'row',
justifyContent: 'flex-end',
gap: '0.5rem',
height: '100%',
}}
>
<ConnectButton />
</div>
</div>
{renderNFTProgressContainer()}

View File

@@ -1,4 +1,4 @@
import React from 'react';
import React, { useCallback } from 'react';
import { useThemeConfig, ErrorCauseBoundary } from '@docusaurus/theme-common';
import { useNavbarMobileSidebar } from '@docusaurus/theme-common/internal';
import NavbarItem from '@theme/NavbarItem';
@@ -11,6 +11,7 @@ import styles from './styles.module.css';
import Icon from '../../../components/Icon';
import { CustomConnectButton } from '../../NavbarItem/ComponentTypes';
import logEvent, { ActionType, AnalyticsEventImportance, ComponentType } from "base-ui/utils/logEvent";
function useNavbarItems() {
// TODO temporary casting until ThemeConfig type is improved
@@ -39,6 +40,42 @@ ${JSON.stringify(item, null, 2)}`,
);
}
function NavbarLayoutTopContent({ left, right }) {
const discordClick = useCallback(() => {
logEvent(
'social_discord',
{
action: ActionType.click,
component: ComponentType.icon,
context: 'navbar',
},
AnalyticsEventImportance.low
);
}, [logEvent])
const twitterClick = useCallback(() => {
logEvent(
'social_twitter',
{
action: ActionType.click,
component: ComponentType.icon,
context: 'navbar',
},
AnalyticsEventImportance.low
); }, [logEvent])
const githubClick = useCallback(() => {
logEvent(
'social_github',
{
action: ActionType.click,
component: ComponentType.icon,
context: 'navbar',
},
AnalyticsEventImportance.low
);
}, [logEvent])
return (
<div className="navbar__inner">
<div className="navbar__items">{left}</div>
@@ -50,6 +87,7 @@ function NavbarLayoutTopContent({ left, right }) {
target="_blank"
rel="noreferrer"
aria-label="Base on Discord"
onClick={discordClick}
>
<Icon name="discord" />
</a>
@@ -58,6 +96,7 @@ function NavbarLayoutTopContent({ left, right }) {
target="_blank"
rel="noreferrer"
aria-label="Base on Twitter"
onClick={twitterClick}
>
<Icon name="twitter" />
</a>
@@ -66,6 +105,7 @@ function NavbarLayoutTopContent({ left, right }) {
target="_blank"
rel="noreferrer"
aria-label="Base on Github"
onClick={githubClick}
>
<Icon name="github" />
</a>

View File

@@ -1,3 +1,6 @@
import React, { useCallback, useEffect } from 'react';
import { useAccount } from 'wagmi';
import DefaultNavbarItem from '@theme/NavbarItem/DefaultNavbarItem';
import DropdownNavbarItem from '@theme/NavbarItem/DropdownNavbarItem';
import LocaleDropdownNavbarItem from '@theme/NavbarItem/LocaleDropdownNavbarItem';
@@ -11,6 +14,7 @@ import { ConnectButton } from '@rainbow-me/rainbowkit';
import '@rainbow-me/rainbowkit/styles.css';
import styles from './styles.module.css';
import { WalletAvatar } from '../../components/WalletAvatar';
import logEvent, { ActionType, AnalyticsEventImportance, ComponentType, identify } from "base-ui/utils/logEvent";
export const CustomConnectButton = ({ className }) => {
return (
@@ -18,6 +22,35 @@ export const CustomConnectButton = ({ className }) => {
{({ account, chain, openAccountModal, openChainModal, openConnectModal, mounted }) => {
const ready = mounted;
const connected = ready && account && chain;
const { address } = useAccount();
useEffect(() => {
if (address) {
logEvent(
'wallet_connected',
{
action: ActionType.change,
context: 'navbar',
address,
},
AnalyticsEventImportance.low,
);
identify({ userId: address });
}
}, [address]);
const clickConnect = useCallback(() => {
openConnectModal?.();
logEvent(
'connect_wallet',
{
action: ActionType.click,
componentType: ComponentType.button,
context: 'navbar',
},
AnalyticsEventImportance.low,
);
}, [openConnectModal]);
return (
<div
@@ -34,7 +67,7 @@ export const CustomConnectButton = ({ className }) => {
{(() => {
if (!connected) {
return (
<button className={styles.connectButton} onClick={openConnectModal} type="button">
<button className={styles.connectButton} onClick={clickConnect} type="button">
Connect
</button>
);
@@ -106,6 +139,56 @@ export const CustomConnectButton = ({ className }) => {
);
};
export const CustomNavbarLink = (props) => {
return (
<a
href={props.to}
target={props.target ?? '_self'}
className='navbar__item navbar__link'
style={{ cursor: 'pointer'}}
onClick={() => {
logEvent(
props.eventLabel,
{
action: ActionType.click,
componentType: ComponentType.link,
context: props.eventContext,
},
AnalyticsEventImportance.high
)
}}
>
{props.label}
</a>
)
}
export const CustomDropdownLink = (props) => {
return (
<li>
<a
href={props.to}
target={props.target ?? '_self'}
className='dropdown__link'
style={{ cursor: 'pointer'}}
onClick={() => {
logEvent(
props.eventLabel,
{
action: ActionType.click,
componentType: ComponentType.link,
context: props.eventContext,
},
AnalyticsEventImportance.high
)
}}
>
{props.label}
</a>
</li>
)
}
const ComponentTypes = {
default: DefaultNavbarItem,
localeDropdown: LocaleDropdownNavbarItem,
@@ -117,5 +200,7 @@ const ComponentTypes = {
docsVersion: DocsVersionNavbarItem,
docsVersionDropdown: DocsVersionDropdownNavbarItem,
'custom-connectWallet': CustomConnectButton,
'custom-navbarLink': CustomNavbarLink,
'custom-dropdownLink': CustomDropdownLink,
};
export default ComponentTypes;

View File

@@ -213,6 +213,32 @@
"duration": "8 min read",
"checksum": "527200e33d612b0c76e5eaacddfc23633b57eaa4577f389d4429b8f862c45462"
},
"thirdweb-unreal-nft-items": {
"title": "Thirdweb and Unreal - NFT Items",
"slug": "/thirdweb-unreal-nft-items",
"description": "Learn how to use NFTs as in-game items using Thirdweb and Unreal.",
"author": "briandoyle81",
"keywords": [
"Solidity",
"ERC-721",
"token",
"NFT",
"thirdweb",
"Unreal",
"c++",
"blueprints",
"onchain games"
],
"tags": [
"nft"
],
"difficulty": "hard",
"hide_table_of_contents": false,
"displayed_sidebar": null,
"last_updated": "Jun 21, 2024",
"duration": "40 min read",
"checksum": "cfd81fd73a2952f32fd63557915cc864aee013dca9beb255b47cde01b205b32e"
},
"account-abstraction-with-biconomy": {
"title": "Account Abstraction on Base using Biconomy",
"slug": "/account-abstraction-with-biconomy",

View File

@@ -1,9 +1,15 @@
import { ConnectButton, useConnectModal } from '@rainbow-me/rainbowkit';
import { UserAvatar } from 'apps/web/src/components/ConnectWalletButton/UserAvatar';
import { ShinyButton } from 'apps/web/src/components/ShinyButton/ShinyButton';
import logEvent, { identify } from 'apps/web/src/utils/logEvent';
import { useCallback, useEffect } from 'react';
import { useAccount } from 'wagmi';
import { ConnectButton, useConnectModal } from '@rainbow-me/rainbowkit';
import { UserAvatar } from 'apps/web/src/components/ConnectWalletButton/UserAvatar';
import { ShinyButton } from 'apps/web/src/components/ShinyButton/ShinyButton';
import logEvent, {
ActionType,
AnalyticsEventImportance,
ComponentType,
identify,
} from 'base-ui/utils/logEvent';
type ConnectWalletButtonProps = {
color: 'white' | 'black';
@@ -21,14 +27,30 @@ export function ConnectWalletButton({ color, className }: ConnectWalletButtonPro
useEffect(() => {
if (address) {
logEvent('connected_wallet', { address });
logEvent(
'wallet_connected',
{
action: ActionType.change,
context: 'navbar',
address
},
AnalyticsEventImportance.low
);
identify({ userId: address });
}
}, [address]);
const clickConnect = useCallback(() => {
openConnectModal?.();
logEvent('ConnectWalletButton_Clicked', {});
logEvent(
'connect_wallet',
{
action: ActionType.click,
componentType: ComponentType.button,
context: 'navbar'
},
AnalyticsEventImportance.low
);
}, [openConnectModal]);
return (

View File

@@ -0,0 +1,94 @@
declare const window: Window &
typeof globalThis & {
ClientAnalytics: {
logEvent: LogEvent;
};
};
export default function logEvent(
name: string,
event: CCAEventData,
importance: AnalyticsEventImportance | undefined
) {
const CCA = window.ClientAnalytics;
if (CCA) {
CCA?.logEvent(name, event, importance);
}
}
export function identify(event: CCAEventData) {
const CCA = window.ClientAnalytics;
if (CCA) {
CCA?.logEvent('identify', event, AnalyticsEventImportance.low);
}
}
type LogEvent = (
eventName: string,
eventData: CCAEventData,
importance?: AnalyticsEventImportance,
) => void;
enum ComponentType {
unknown = 'unknown',
banner = 'banner',
button = 'button',
card = 'card',
chart = 'chart',
content_script = 'content_script',
dropdown = 'dropdown',
link = 'link',
page = 'page',
modal = 'modal',
table = 'table',
search_bar = 'search_bar',
service_worker = 'service_worker',
text = 'text',
text_input = 'text_input',
tray = 'tray',
checkbox = 'checkbox',
icon = 'icon',
}
enum ActionType {
unknown = 'unknown',
blur = 'blur',
click = 'click',
change = 'change',
dismiss = 'dismiss',
focus = 'focus',
hover = 'hover',
select = 'select',
measurement = 'measurement',
move = 'move',
process = 'process',
render = 'render',
scroll = 'scroll',
view = 'view',
search = 'search',
keyPress = 'keyPress',
}
enum AnalyticsEventImportance {
low = 'low',
high = 'high',
}
type CCAEventData = {
// Standard Attributes
action?: ActionType;
componentType?: ComponentType;
// Custom Attributes
doc_helpful?: boolean;
doc_feedback_reason?: string | null;
page_path?: string;
conversation_id?: number;
message_id?: number;
response_helpful?: boolean;
address?: string;
context?: string;
userId?: string;
};
export { ComponentType, ActionType, AnalyticsEventImportance };
export type { LogEvent, CCAEventData };