analytics/examples/react-spa/use-click-tracking.ts
2026-01-29 08:20:58 -08:00

191 lines
4.1 KiB
TypeScript

/**
* useClickTracking - Click event tracking utilities
*
* Provides utilities for tracking user interactions with elements.
*/
import { useCallback } from 'react';
import { useAnalytics } from '@analytics/client/react';
interface ClickTrackingOptions {
/**
* Element identifier (button name, link text, etc.)
*/
elementId: string;
/**
* Category for grouping (navigation, cta, form, etc.)
*/
category?: string;
/**
* Additional metadata
*/
metadata?: Record<string, unknown>;
}
/**
* Create a click handler that tracks the interaction.
*
* @example
* ```tsx
* function SignupButton() {
* const { createClickHandler } = useClickTracking();
*
* const handleClick = createClickHandler({
* elementId: 'signup-button',
* category: 'cta',
* });
*
* return <button onClick={handleClick}>Sign Up Free</button>;
* }
* ```
*/
export function useClickTracking() {
const { trackInteraction } = useAnalytics();
const createClickHandler = useCallback(
(options: ClickTrackingOptions) => {
return (event?: React.MouseEvent) => {
trackInteraction({
type: 'click',
data: {
elementId: options.elementId,
category: options.category,
pageUrl: window.location.href,
...options.metadata,
},
});
};
},
[trackInteraction],
);
/**
* Track a click imperatively (not as an event handler).
*/
const trackClick = useCallback(
(options: ClickTrackingOptions) => {
trackInteraction({
type: 'click',
data: {
elementId: options.elementId,
category: options.category,
pageUrl: window.location.href,
...options.metadata,
},
});
},
[trackInteraction],
);
return {
createClickHandler,
trackClick,
};
}
/**
* Track outbound link clicks.
*
* @example
* ```tsx
* function ExternalLink({ href, children }) {
* const { trackOutboundClick } = useOutboundLinkTracking();
*
* return (
* <a
* href={href}
* onClick={() => trackOutboundClick(href)}
* target="_blank"
* rel="noopener noreferrer"
* >
* {children}
* </a>
* );
* }
* ```
*/
export function useOutboundLinkTracking() {
const { trackInteraction } = useAnalytics();
const trackOutboundClick = useCallback(
(url: string, metadata?: Record<string, unknown>) => {
try {
const parsed = new URL(url);
trackInteraction({
type: 'click',
data: {
elementId: 'outbound-link',
category: 'navigation',
targetUrl: url,
targetDomain: parsed.hostname,
pageUrl: window.location.href,
...metadata,
},
});
} catch {
// Invalid URL, track anyway
trackInteraction({
type: 'click',
data: {
elementId: 'outbound-link',
category: 'navigation',
targetUrl: url,
pageUrl: window.location.href,
...metadata,
},
});
}
},
[trackInteraction],
);
return { trackOutboundClick };
}
/**
* Track downloads.
*
* @example
* ```tsx
* function DownloadButton({ fileUrl, fileName }) {
* const { trackDownload } = useDownloadTracking();
*
* return (
* <a
* href={fileUrl}
* download={fileName}
* onClick={() => trackDownload(fileName, fileUrl)}
* >
* Download {fileName}
* </a>
* );
* }
* ```
*/
export function useDownloadTracking() {
const { trackInteraction } = useAnalytics();
const trackDownload = useCallback(
(fileName: string, fileUrl: string, metadata?: Record<string, unknown>) => {
const fileExtension = fileName.split('.').pop()?.toLowerCase() || 'unknown';
trackInteraction({
type: 'click',
data: {
elementId: 'download',
category: 'download',
fileName,
fileUrl,
fileExtension,
pageUrl: window.location.href,
...metadata,
},
});
},
[trackInteraction],
);
return { trackDownload };
}