Source identity
| Field | Recorded value |
|---|---|
| Source type | GitHub source |
| Original record | Janady13/llms-txt-hub / apps/web/components/analytics-tracker.tsx |
| Date | Not specified in source |
| Repository | Janady13/llms-txt-hub |
| Revision | e0f4bf978d4df168369c7601d9c5f5ea89e84377 |
| Branch | main |
| Path or archive member | apps/web/components/analytics-tracker.tsx |
| Original SHA-256 | 0b94e5da67b01fcc28aa8b91209fa014126c5f54c5ed8c806536a45a08d48e86 |
| Git blob SHA | 070ecab4c84ce2096f9c23b50148d6c85f941eaa |
| Reading-copy SHA-256 | 0b94e5da67b01fcc28aa8b91209fa014126c5f54c5ed8c806536a45a08d48e86 |
Recovered source transcript
Download complete source text ↓217 lines · 6.5 KB
'use client'
import { useEffect } from 'react'
import { analytics } from '@/lib/analytics'
/**
* Client-side analytics tracker that listens for clicks on elements with data-analytics attributes
* This maintains SSR/SEO while adding analytics tracking
*/
export function AnalyticsTracker() {
useEffect(() => {
/**
* Handles click events on elements with data-analytics attributes
*/
const handleClick = (event: MouseEvent) => {
const target = event.target
if (!(target instanceof HTMLElement)) return
const link = target.closest<HTMLElement>('[data-analytics]')
if (!link) return
const analyticsType = link.getAttribute('data-analytics')
switch (analyticsType) {
case 'website-click': {
const websiteName = link.getAttribute('data-website-name')
const websiteSlug = link.getAttribute('data-website-slug')
const source = link.getAttribute('data-source')
if (websiteName && websiteSlug) {
analytics.websiteClick(websiteName, websiteSlug, source || undefined)
}
break
}
case 'member-click': {
const memberName = link.getAttribute('data-member-name')
const memberSlug = link.getAttribute('data-member-slug')
const source = link.getAttribute('data-source')
if (memberName && memberSlug) {
analytics.memberClick(memberName, memberSlug, source || undefined)
}
break
}
case 'github-link': {
const username = link.getAttribute('data-username')
const source = link.getAttribute('data-source')
if (username) {
analytics.githubLink(username, source || undefined)
}
break
}
case 'external-link': {
const url = link.getAttribute('href')
const text = link.textContent
const source = link.getAttribute('data-source')
if (url) {
analytics.externalLink(url, text || url, source || undefined)
}
break
}
case 'category-click': {
const categoryName = link.getAttribute('data-category-name')
const categorySlug = link.getAttribute('data-category-slug')
const source = link.getAttribute('data-source')
if (categoryName && categorySlug) {
analytics.categoryClick(categoryName, categorySlug, source || undefined)
}
break
}
case 'tool-click': {
const toolName = link.getAttribute('data-tool-name')
const toolUrl = link.getAttribute('href')
const source = link.getAttribute('data-source')
if (toolName && toolUrl) {
analytics.toolClick(toolName, toolUrl, source || undefined)
}
break
}
case 'cta-click': {
const ctaType = link.getAttribute('data-cta-type')
const source = link.getAttribute('data-source')
switch (ctaType) {
case 'submit-website':
analytics.submitWebsite(source || undefined)
break
case 'join-community':
analytics.joinCommunity(source || undefined)
break
case 'newsletter-signup':
analytics.newsletterSignup(source || undefined)
break
}
break
}
}
}
// Listen for clicks on the document
document.addEventListener('click', handleClick)
// Cleanup
return () => {
document.removeEventListener('click', handleClick)
}
}, [])
// This component doesn't render anything
return null
}
/**
* Hook for tracking events that don't involve clicks (like load more, sort changes, etc.)
* These need to be in client components
*/
export function useAnalyticsEvents() {
return {
trackLoadMore: (
type: 'websites' | 'members',
itemsLoaded: number,
totalItems: number,
source?: string
) => {
analytics.loadMore(type, itemsLoaded, totalItems, source)
},
trackShowAll: (type: 'websites' | 'members', totalItems: number, source?: string) => {
analytics.showAll(type, totalItems, source)
},
trackShowLess: (source?: string) => {
analytics.showLess(source)
},
trackSearch: (query: string, resultsCount: number, source?: string) => {
analytics.search(query, resultsCount, source)
},
trackSearchAutocomplete: (query: string, suggestion: string, source?: string) => {
analytics.searchAutocomplete(query, suggestion, source)
},
trackSortChange: (fromSort: string, toSort: string, source?: string) => {
analytics.sortChange(fromSort, toSort, source)
},
// Form Events
trackFormStepStart: (step: number, formName: string, source?: string) => {
analytics.formStepStart(step, formName, source)
},
trackFormStepComplete: (step: number, formName: string, source?: string) => {
analytics.formStepComplete(step, formName, source)
},
trackFormError: (step: number, errorMessage: string, formName: string, source?: string) => {
analytics.formError(step, errorMessage, formName, source)
},
trackFetchMetadataSuccess: (website: string, source?: string) => {
analytics.fetchMetadataSuccess(website, source)
},
trackFetchMetadataError: (website: string, errorMessage: string, source?: string) => {
analytics.fetchMetadataError(website, errorMessage, source)
},
trackSubmitSuccess: (website: string, category: string, source?: string) => {
analytics.submitSuccess(website, category, source)
},
trackSubmitError: (website: string, errorMessage: string, source?: string) => {
analytics.submitError(website, errorMessage, source)
},
// Profile Events
trackProfileModalOpen: (source?: string) => {
analytics.profileModalOpen(source)
},
trackProfileUpdateSuccess: (isPublic: boolean, source?: string) => {
analytics.profileUpdateSuccess(isPublic, source)
},
trackProfileUpdateError: (errorMessage: string, source?: string) => {
analytics.profileUpdateError(errorMessage, source)
},
trackProfileVisibilityToggle: (isPublic: boolean, source?: string) => {
analytics.profileVisibilityToggle(isPublic, source)
},
trackAccountDeleteStart: (source?: string) => {
analytics.accountDeleteStart(source)
},
trackAccountDeleteSuccess: (source?: string) => {
analytics.accountDeleteSuccess(source)
},
trackAccountDeleteCancel: (source?: string) => {
analytics.accountDeleteCancel(source)
}
}
}