♻️(frontend) encapsulate PostHog logic in dedicated functions
Decouple the code from the PostHog dependency by wrapping it in a custom hook and several utility functions. This enhances code maintainability and separation of concerns.
This commit is contained in:
committed by
aleb_the_flash
parent
db8445f4ab
commit
b083d837f8
@@ -1,11 +1,11 @@
|
|||||||
import '@livekit/components-styles'
|
import '@livekit/components-styles'
|
||||||
import '@/styles/index.css'
|
import '@/styles/index.css'
|
||||||
import { Suspense, useEffect } from 'react'
|
import { Suspense } from 'react'
|
||||||
import { ReactQueryDevtools } from '@tanstack/react-query-devtools'
|
import { ReactQueryDevtools } from '@tanstack/react-query-devtools'
|
||||||
import { QueryClientProvider } from '@tanstack/react-query'
|
import { QueryClientProvider } from '@tanstack/react-query'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { useLang } from 'hoofd'
|
import { useLang } from 'hoofd'
|
||||||
import { Switch, Route, useLocation } from 'wouter'
|
import { Switch, Route } from 'wouter'
|
||||||
import { I18nProvider } from 'react-aria-components'
|
import { I18nProvider } from 'react-aria-components'
|
||||||
import { Layout } from './layout/Layout'
|
import { Layout } from './layout/Layout'
|
||||||
import { NotFoundScreen } from './components/NotFoundScreen'
|
import { NotFoundScreen } from './components/NotFoundScreen'
|
||||||
@@ -13,28 +13,16 @@ import { routes } from './routes'
|
|||||||
import './i18n/init'
|
import './i18n/init'
|
||||||
import { silenceLiveKitLogs } from '@/utils/livekit.ts'
|
import { silenceLiveKitLogs } from '@/utils/livekit.ts'
|
||||||
import { queryClient } from '@/api/queryClient'
|
import { queryClient } from '@/api/queryClient'
|
||||||
import posthog from 'posthog-js'
|
import { useAnalytics } from '@/features/analytics/hooks/useAnalytics'
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
const { i18n } = useTranslation()
|
const { i18n } = useTranslation()
|
||||||
const [location] = useLocation()
|
|
||||||
useLang(i18n.language)
|
useLang(i18n.language)
|
||||||
|
|
||||||
const isProduction = import.meta.env.PROD
|
const isProduction = import.meta.env.PROD
|
||||||
silenceLiveKitLogs(isProduction)
|
silenceLiveKitLogs(isProduction)
|
||||||
|
|
||||||
// We're on a free tier, so we need to limit the number of events we send to PostHog.
|
useAnalytics()
|
||||||
// Be frugal with event tracking, even though we could filter them out later if necessary.
|
|
||||||
if (isProduction) {
|
|
||||||
posthog.init('phc_RPYko028Oqtj0c9exLIWwrlrjLxSdxT0ntW0Lam4iom', {
|
|
||||||
api_host: 'https://eu.i.posthog.com',
|
|
||||||
person_profiles: 'always',
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
posthog.capture('$pageview')
|
|
||||||
}, [location])
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<QueryClientProvider client={queryClient}>
|
<QueryClientProvider client={queryClient}>
|
||||||
|
|||||||
42
src/frontend/src/features/analytics/hooks/useAnalytics.tsx
Normal file
42
src/frontend/src/features/analytics/hooks/useAnalytics.tsx
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
import { useEffect } from 'react'
|
||||||
|
import { useLocation } from 'wouter'
|
||||||
|
import posthog from 'posthog-js'
|
||||||
|
import { ApiUser } from '@/features/auth/api/ApiUser'
|
||||||
|
|
||||||
|
const ANALYTICS_ID = 'phc_RPYko028Oqtj0c9exLIWwrlrjLxSdxT0ntW0Lam4iom'
|
||||||
|
const ANALYTICS_HOST = 'https://eu.i.posthog.com'
|
||||||
|
|
||||||
|
export const startAnalyticsSession = (data: ApiUser) => {
|
||||||
|
if (posthog._isIdentified()) return
|
||||||
|
const { id, email } = data
|
||||||
|
posthog.identify(id, { email })
|
||||||
|
}
|
||||||
|
|
||||||
|
export const terminateAnalyticsSession = () => {
|
||||||
|
if (!posthog._isIdentified()) return
|
||||||
|
posthog.reset()
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useAnalytics = () => {
|
||||||
|
const [location] = useLocation()
|
||||||
|
|
||||||
|
const isProduction = import.meta.env.PROD
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
// We're on a free tier, so we need to limit the number of events we send to PostHog.
|
||||||
|
// Be frugal with event tracking, even though we could filter them out later if necessary.
|
||||||
|
if (!isProduction) return
|
||||||
|
if (posthog.__loaded) return
|
||||||
|
posthog.init(ANALYTICS_ID, {
|
||||||
|
api_host: ANALYTICS_HOST,
|
||||||
|
person_profiles: 'always',
|
||||||
|
})
|
||||||
|
}, [isProduction])
|
||||||
|
|
||||||
|
// From PostHog tutorial on PageView tracking in a Single Page Application (SPA) context.
|
||||||
|
useEffect(() => {
|
||||||
|
posthog.capture('$pageview')
|
||||||
|
}, [location])
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
@@ -3,10 +3,10 @@ import { keys } from '@/api/queryKeys'
|
|||||||
import { fetchUser } from './fetchUser'
|
import { fetchUser } from './fetchUser'
|
||||||
import { type ApiUser } from './ApiUser'
|
import { type ApiUser } from './ApiUser'
|
||||||
import { useEffect } from 'react'
|
import { useEffect } from 'react'
|
||||||
import posthog from 'posthog-js'
|
import { startAnalyticsSession } from '@/features/analytics/hooks/useAnalytics'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* returns info about currently logged in user
|
* returns info about currently logged-in user
|
||||||
*
|
*
|
||||||
* `isLoggedIn` is undefined while query is loading and true/false when it's done
|
* `isLoggedIn` is undefined while query is loading and true/false when it's done
|
||||||
*/
|
*/
|
||||||
@@ -18,8 +18,8 @@ export const useUser = () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (query.data && query.data.id && !posthog._isIdentified()) {
|
if (query?.data) {
|
||||||
posthog.identify(query.data.id, { email: query.data.email })
|
startAnalyticsSession(query.data)
|
||||||
}
|
}
|
||||||
}, [query.data])
|
}, [query.data])
|
||||||
|
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ import { useMatchesRoute } from '@/navigation/useMatchesRoute'
|
|||||||
import { Feedback } from '@/components/Feedback'
|
import { Feedback } from '@/components/Feedback'
|
||||||
import { Menu } from '@/primitives/Menu'
|
import { Menu } from '@/primitives/Menu'
|
||||||
import { MenuList } from '@/primitives/MenuList'
|
import { MenuList } from '@/primitives/MenuList'
|
||||||
import posthog from 'posthog-js'
|
|
||||||
import { ProConnectButton } from '@/components/ProConnectButton'
|
import { ProConnectButton } from '@/components/ProConnectButton'
|
||||||
|
import { terminateAnalyticsSession } from '@/features/analytics/hooks/useAnalytics'
|
||||||
|
|
||||||
export const Header = () => {
|
export const Header = () => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
@@ -81,7 +81,7 @@ export const Header = () => {
|
|||||||
items={[{ value: 'logout', label: t('logout') }]}
|
items={[{ value: 'logout', label: t('logout') }]}
|
||||||
onAction={(value) => {
|
onAction={(value) => {
|
||||||
if (value === 'logout') {
|
if (value === 'logout') {
|
||||||
posthog.reset()
|
terminateAnalyticsSession()
|
||||||
window.location.href = logoutUrl()
|
window.location.href = logoutUrl()
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
|
|||||||
Reference in New Issue
Block a user