61 lines
1.6 KiB
TypeScript
Executable file
61 lines
1.6 KiB
TypeScript
Executable file
import { useCallback } from 'react';
|
|
|
|
import { useAnalytics } from '../analytics-context';
|
|
|
|
import type { ClickEventData } from '../types';
|
|
|
|
export interface TrackClickOptions {
|
|
eventName?: string;
|
|
eventLabel?: string;
|
|
conversionGoal?: string;
|
|
}
|
|
|
|
type ElementType = ClickEventData['elementType'];
|
|
|
|
function inferElementType(element: HTMLElement): ElementType {
|
|
const tagName = element.tagName.toLowerCase();
|
|
|
|
if (tagName === 'a') return 'link';
|
|
if (tagName === 'button') {
|
|
const type = element.getAttribute('type');
|
|
return type === 'submit' ? 'submit' : 'button';
|
|
}
|
|
|
|
// Icon button detection: has SVG but no meaningful text
|
|
if (element.querySelector('svg') && !element.textContent?.trim()) {
|
|
return 'icon';
|
|
}
|
|
|
|
// Clickable div/span with role="button"
|
|
if (element.getAttribute('role') === 'button') {
|
|
return 'button';
|
|
}
|
|
|
|
return 'other';
|
|
}
|
|
|
|
export function useTrackClick() {
|
|
const { trackInteraction } = useAnalytics();
|
|
|
|
const trackClick = useCallback(
|
|
(event: React.MouseEvent<HTMLElement>, options?: TrackClickOptions) => {
|
|
const el = event.currentTarget;
|
|
|
|
trackInteraction({
|
|
type: 'click',
|
|
data: {
|
|
elementId: el.id || el.dataset.analyticsId,
|
|
elementText: el.textContent?.slice(0, 50)?.trim(),
|
|
elementType: inferElementType(el),
|
|
pageUrl: typeof window !== 'undefined' ? window.location.href : '',
|
|
eventName: options?.eventName,
|
|
eventLabel: options?.eventLabel,
|
|
conversionGoal: options?.conversionGoal,
|
|
},
|
|
});
|
|
},
|
|
[trackInteraction],
|
|
);
|
|
|
|
return { trackClick };
|
|
}
|