feat: add PostHog product analytics for key user actions (#110)
Tracks 9 key events: account_created, login_success, flow_viewed, session_started, session_completed, export_generated, ai_feature_used, psa_connected, session_shared. Identifies users on login, resets on logout. Autocapture disabled — only explicit discrete events. Set VITE_POSTHOG_KEY in environment to enable. Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit was merged in pull request #110.
This commit is contained in:
@@ -31,6 +31,7 @@ import { TicketLinkIndicator } from '@/components/session/TicketLinkIndicator'
|
||||
import { UpdateTicketModal } from '@/components/session/UpdateTicketModal'
|
||||
import type { PSATicketInfo } from '@/types/integrations'
|
||||
import { addRecentFlow } from '@/lib/recentFlows'
|
||||
import { analytics } from '@/lib/analytics'
|
||||
import { useTicketContext } from '@/hooks/useTicketContext'
|
||||
import { TicketContextPanel } from '@/components/session/TicketContextPanel'
|
||||
|
||||
@@ -227,6 +228,7 @@ export function ProceduralNavigationPage() {
|
||||
}
|
||||
setTree(treeData)
|
||||
addRecentFlow({ id: treeData.id, name: treeData.name, tree_type: treeData.tree_type })
|
||||
analytics.flowViewed({ flow_id: treeData.id, flow_type: treeData.tree_type, flow_name: treeData.name })
|
||||
|
||||
// If resuming an existing session
|
||||
if (locationState?.sessionId) {
|
||||
@@ -252,6 +254,7 @@ export function ProceduralNavigationPage() {
|
||||
session_variables: Object.keys(variables).length > 0 ? variables : undefined,
|
||||
})
|
||||
setSession(newSession)
|
||||
analytics.sessionStarted({ session_id: newSession.id, flow_id: id, flow_type: treeData?.tree_type || 'procedural' })
|
||||
setSessionVariables(variables)
|
||||
|
||||
// Initialize step states — use passed treeData since `tree` state may not have committed yet
|
||||
@@ -401,6 +404,7 @@ export function ProceduralNavigationPage() {
|
||||
})
|
||||
setCompletedAt(completedTime)
|
||||
setIsComplete(true)
|
||||
analytics.sessionCompleted({ session_id: session.id, flow_type: tree?.tree_type || 'procedural', outcome: 'resolved' })
|
||||
if (!hasBeenRated(session.id)) {
|
||||
setShowCsatModal(true)
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ import { TicketLinkIndicator } from '@/components/session/TicketLinkIndicator'
|
||||
import { UpdateTicketModal } from '@/components/session/UpdateTicketModal'
|
||||
import type { PSATicketInfo } from '@/types/integrations'
|
||||
import { addRecentFlow } from '@/lib/recentFlows'
|
||||
import { analytics } from '@/lib/analytics'
|
||||
import { useTicketContext } from '@/hooks/useTicketContext'
|
||||
import { TicketContextPanel } from '@/components/session/TicketContextPanel'
|
||||
|
||||
@@ -335,6 +336,7 @@ export function TreeNavigationPage() {
|
||||
|
||||
setTree(treeData)
|
||||
addRecentFlow({ id: treeData.id, name: treeData.name, tree_type: treeData.tree_type })
|
||||
analytics.flowViewed({ flow_id: treeData.id, flow_type: treeData.tree_type, flow_name: treeData.name })
|
||||
|
||||
// If resuming a session
|
||||
if (locationState?.sessionId) {
|
||||
@@ -367,6 +369,7 @@ export function TreeNavigationPage() {
|
||||
client_name: clientName || undefined,
|
||||
})
|
||||
setSession(newSession)
|
||||
analytics.sessionStarted({ session_id: newSession.id, flow_id: tree.id, flow_type: tree.tree_type })
|
||||
// Initialize currentNodeId to the tree's actual root (may not be 'root')
|
||||
const rootId = tree.tree_structure?.id || 'root'
|
||||
setCurrentNodeId(rootId)
|
||||
@@ -512,6 +515,7 @@ export function TreeNavigationPage() {
|
||||
}
|
||||
|
||||
await sessionsApi.complete(session.id, data)
|
||||
analytics.sessionCompleted({ session_id: session.id, flow_type: tree?.tree_type || 'troubleshooting', outcome: data.outcome })
|
||||
|
||||
setShowOutcomeModal(false)
|
||||
setPendingCompletionDecision(null)
|
||||
|
||||
Reference in New Issue
Block a user