Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 18 additions & 12 deletions app/existing/[repoUrl]/repo-scan-client.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import { generateFromRepoScan } from "@/lib/scan-generate"
import FinalOutputView from "@/components/final-output-view"
import RepoScanLoader from "@/components/repo-scan-loader"
import type { GeneratedFileResult } from "@/types/output"
import { track } from "@/lib/mixpanel"
import { ANALYTICS_EVENTS } from "@/lib/analytics-events"

const buildQuery = (url: string) => `/api/scan-repo?url=${encodeURIComponent(url)}`
const CONVENTIONS_DOC_URL =
Expand Down Expand Up @@ -110,23 +112,27 @@ export default function RepoScanClient({ initialRepoUrl }: RepoScanClientProps)
}))
}, [scanResult])

const handleStartScan = () => {
if (!repoUrlForScan) {
return
}

setHasConfirmed(true)
setScanToken((token) => token + 1)
const handleStartScan = () => {
if (!repoUrlForScan) {
return
}

const handleRetryScan = () => {
if (!repoUrlForScan) {
return
}
setHasConfirmed(true)
setScanToken((token) => token + 1)

track(ANALYTICS_EVENTS.REPO_SCAN_START, { repo: repoUrlForScan })
}

setScanToken((token) => token + 1)
const handleRetryScan = () => {
if (!repoUrlForScan) {
return
}

setScanToken((token) => token + 1)

track(ANALYTICS_EVENTS.REPO_SCAN_RETRY, { repo: repoUrlForScan })
}

const warnings = scanResult?.warnings ?? []
const stackMeta = scanResult?.conventions ?? null
const detectedStackId = stackMeta?.stack ?? null
Expand Down
7 changes: 7 additions & 0 deletions app/existing/existing-repo-entry-client.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import { Button } from "@/components/ui/button"
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
import { Input } from "@/components/ui/input"
import { normalizeGitHubRepoInput } from "@/lib/github"
import { track } from "@/lib/mixpanel"
import { ANALYTICS_EVENTS } from "@/lib/analytics-events"

export function ExistingRepoEntryClient() {
const router = useRouter()
Expand All @@ -30,6 +32,11 @@ export function ExistingRepoEntryClient() {

const encoded = encodeURIComponent(normalized)

track(ANALYTICS_EVENTS.REPO_ANALYZE_SUBMIT, {
inputProvided: value.length > 0,
url: normalized,
})

router.push(`/existing/${encoded}`)
}

Expand Down
15 changes: 15 additions & 0 deletions app/new/stack/stack-summary-page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ import type {
} from "@/types/wizard"
import type { GeneratedFileResult } from "@/types/output"
import { WizardEditAnswerDialog } from "@/components/wizard-edit-answer-dialog"
import { track } from "@/lib/mixpanel"
import { ANALYTICS_EVENTS } from "@/lib/analytics-events"

const fileOptions = getFileOptions()
const fileSummaryQuestion = getFileSummaryQuestion()
Expand Down Expand Up @@ -210,6 +212,7 @@ export function StackSummaryPage({ stackId, mode }: StackSummaryPageProps) {
}, [wizardSteps])

const handleEditClick = (questionId: string) => {
track(ANALYTICS_EVENTS.SUMMARY_EDIT_OPEN, { questionId })
setEditingQuestionId(questionId)
}

Expand All @@ -226,6 +229,7 @@ export function StackSummaryPage({ stackId, mode }: StackSummaryPageProps) {
const trimmed = submittedValue.trim()
const nextFreeText: FreeTextResponses = (() => {
if (trimmed.length === 0) {
track(ANALYTICS_EVENTS.SUMMARY_EDIT_FREE_TEXT_CLEARED, { questionId: question.id })
if (!(question.id in freeTextResponses)) {
return { ...freeTextResponses }
}
Expand All @@ -235,6 +239,10 @@ export function StackSummaryPage({ stackId, mode }: StackSummaryPageProps) {
return next
}

track(ANALYTICS_EVENTS.SUMMARY_EDIT_FREE_TEXT_SAVED, {
questionId: question.id,
length: trimmed.length,
})
return {
...freeTextResponses,
[question.id]: trimmed,
Expand Down Expand Up @@ -314,6 +322,13 @@ export function StackSummaryPage({ stackId, mode }: StackSummaryPageProps) {
})
}

track(ANALYTICS_EVENTS.SUMMARY_EDIT_ANSWER_SELECTED, {
questionId: question.id,
answerValue: answer.value,
answerLabel: answer.label,
allowMultiple: question.allowMultiple ?? false,
})

if (!question.allowMultiple) {
handleCloseEdit()
}
Expand Down
30 changes: 30 additions & 0 deletions components/instructions-wizard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ import {
import { persistWizardState, clearWizardState } from "@/lib/wizard-storage"
import { WizardAnswerGrid } from "./wizard-answer-grid"
import { WizardConfirmationDialog } from "./wizard-confirmation-dialog"
import { track } from "@/lib/mixpanel"
import { ANALYTICS_EVENTS } from "@/lib/analytics-events"

const suffixSteps = getSuffixSteps()
const buildStepSignature = (step: WizardStep) => `${step.id}::${step.questions.map((question) => question.id).join("|")}`
Expand Down Expand Up @@ -559,6 +561,16 @@ export function InstructionsWizard({
return
}

// Track answer selection
track(ANALYTICS_EVENTS.WIZARD_ANSWER_SELECTED, {
questionId: currentQuestion.id,
answerValue: answer.value,
answerLabel: answer.label,
allowMultiple: currentQuestion.allowMultiple ?? false,
isDefault: Boolean(answer.isDefault),
stepId: currentStep?.id ?? null,
})

void handleQuestionAnswerSelection(currentQuestion, answer)
}

Expand Down Expand Up @@ -704,6 +716,11 @@ export function InstructionsWizard({
return
}

track(ANALYTICS_EVENTS.WIZARD_FREE_TEXT_SAVED, {
questionId: currentQuestion.id,
length: currentFreeTextValue.trim().length,
})

commitFreeTextValue(currentQuestion, currentFreeTextValue)
}

Expand All @@ -712,6 +729,10 @@ export function InstructionsWizard({
return
}

track(ANALYTICS_EVENTS.WIZARD_FREE_TEXT_CLEARED, {
questionId: currentQuestion.id,
})

commitFreeTextValue(currentQuestion, "", { allowAutoAdvance: false })
}

Expand All @@ -733,6 +754,14 @@ export function InstructionsWizard({

const isStackQuestion = currentQuestion.id === STACK_QUESTION_ID

// Track default use
track(ANALYTICS_EVENTS.WIZARD_USE_DEFAULT, {
questionId: currentQuestion.id,
answerValue: defaultAnswer.value,
answerLabel: defaultAnswer.label,
isStackQuestion,
})

if (isStackQuestion) {
await loadStackQuestions(defaultAnswer.value, defaultAnswer.label, {
skipFastTrackPrompt: autoStartAfterStackSelection,
Expand Down Expand Up @@ -769,6 +798,7 @@ export function InstructionsWizard({
}

const requestResetWizard = () => {
track(ANALYTICS_EVENTS.WIZARD_RESET)
setPendingConfirmation("reset")
}

Expand Down
16 changes: 16 additions & 0 deletions lib/analytics-events.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,22 @@
export const ANALYTICS_EVENTS = {
PAGE_VIEW: "Page View",
CREATE_INSTRUCTIONS_FILE: "Create My Instructions File",
// Wizard interactions
WIZARD_ANSWER_SELECTED: "Wizard Answer Selected",
WIZARD_USE_DEFAULT: "Wizard Use Default",
WIZARD_FREE_TEXT_SAVED: "Wizard Free Text Saved",
WIZARD_FREE_TEXT_CLEARED: "Wizard Free Text Cleared",
WIZARD_RESET: "Wizard Reset",
// Summary dialog interactions
SUMMARY_EDIT_OPEN: "Summary Edit Open",
SUMMARY_EDIT_ANSWER_SELECTED: "Summary Edit Answer Selected",
SUMMARY_EDIT_FREE_TEXT_SAVED: "Summary Edit Free Text Saved",
SUMMARY_EDIT_FREE_TEXT_CLEARED: "Summary Edit Free Text Cleared",
// Existing repo / scan interactions
REPO_ANALYZE_SUBMIT: "Existing Repo Analyze Submit",
REPO_SCAN_START: "Repo Scan Start",
REPO_SCAN_RETRY: "Repo Scan Retry",
REPO_SCAN_GENERATE_FILE: "Repo Scan Generate File",
} as const

export type AnalyticsEvent =
Expand Down
8 changes: 8 additions & 0 deletions lib/scan-generate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import { getFileOptions } from "@/lib/wizard-config"
import { getMimeTypeForFormat } from "@/lib/wizard-utils"
import type { RepoScanSummary } from "@/types/repo-scan"
import type { GeneratedFileResult } from "@/types/output"
import { track } from "@/lib/mixpanel"
import { ANALYTICS_EVENTS } from "@/lib/analytics-events"

const fileOptions = getFileOptions()

Expand All @@ -15,6 +17,12 @@ export async function generateFromRepoScan(
): Promise<GeneratedFileResult | null> {
const selected = fileOptions.find((f) => f.id === outputFileId) || null

track(ANALYTICS_EVENTS.REPO_SCAN_GENERATE_FILE, {
outputFile: outputFileId,
stack: scan.conventions?.stack ?? null,
language: scan.language ?? null,
})

const res = await fetch(`/api/scan-generate/${encodeURIComponent(outputFileId)}`, {
method: "POST",
headers: {
Expand Down