From 9719333ea313046726c289045cbf39ff88765a58 Mon Sep 17 00:00:00 2001 From: bymyself Date: Tue, 20 Jan 2026 14:36:15 -0800 Subject: [PATCH] feat: integrate nightly survey system into app Amp-Thread-ID: https://ampcode.com/threads/T-019c88b1-2d4d-717f-b08c-e2f71c4d80fe --- src/components/sidebar/SideToolbar.vue | 22 ++++++- .../surveys/NightlySurveyController.vue | 14 +++++ .../surveys/useSurveyFeatureTracking.test.ts | 63 +++++++++++++++++++ .../surveys/useSurveyFeatureTracking.ts | 35 +++++++++++ 4 files changed, 132 insertions(+), 2 deletions(-) create mode 100644 src/platform/surveys/NightlySurveyController.vue create mode 100644 src/platform/surveys/useSurveyFeatureTracking.test.ts create mode 100644 src/platform/surveys/useSurveyFeatureTracking.ts diff --git a/src/components/sidebar/SideToolbar.vue b/src/components/sidebar/SideToolbar.vue index 0faa70bca3..e656ccd3b5 100644 --- a/src/components/sidebar/SideToolbar.vue +++ b/src/components/sidebar/SideToolbar.vue @@ -48,13 +48,24 @@ + + + + + diff --git a/src/platform/surveys/useSurveyFeatureTracking.test.ts b/src/platform/surveys/useSurveyFeatureTracking.test.ts new file mode 100644 index 0000000000..b23fd8222d --- /dev/null +++ b/src/platform/surveys/useSurveyFeatureTracking.test.ts @@ -0,0 +1,63 @@ +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' + +const getSurveyConfig = vi.hoisted(() => + vi.fn<(featureId: string) => { enabled: boolean } | undefined>() +) + +vi.mock('./surveyRegistry', () => ({ + getSurveyConfig +})) + +describe('useSurveyFeatureTracking', () => { + beforeEach(() => { + localStorage.clear() + vi.resetModules() + getSurveyConfig.mockReset() + }) + + afterEach(() => { + localStorage.clear() + }) + + it('tracks usage when config is enabled', async () => { + getSurveyConfig.mockReturnValue({ enabled: true }) + + const { useSurveyFeatureTracking } = + await import('./useSurveyFeatureTracking') + const { trackFeatureUsed, useCount } = + useSurveyFeatureTracking('test-feature') + + expect(useCount.value).toBe(0) + + trackFeatureUsed() + + expect(useCount.value).toBe(1) + }) + + it('does not track when config is disabled', async () => { + getSurveyConfig.mockReturnValue({ enabled: false }) + + const { useSurveyFeatureTracking } = + await import('./useSurveyFeatureTracking') + const { trackFeatureUsed, useCount } = + useSurveyFeatureTracking('disabled-feature') + + trackFeatureUsed() + + expect(useCount.value).toBe(0) + }) + + it('does not track when config does not exist', async () => { + getSurveyConfig.mockReturnValue(undefined) + + const { useSurveyFeatureTracking } = + await import('./useSurveyFeatureTracking') + const { trackFeatureUsed, useCount } = useSurveyFeatureTracking( + 'nonexistent-feature' + ) + + trackFeatureUsed() + + expect(useCount.value).toBe(0) + }) +}) diff --git a/src/platform/surveys/useSurveyFeatureTracking.ts b/src/platform/surveys/useSurveyFeatureTracking.ts new file mode 100644 index 0000000000..4927abd392 --- /dev/null +++ b/src/platform/surveys/useSurveyFeatureTracking.ts @@ -0,0 +1,35 @@ +import { computed } from 'vue' + +import { getSurveyConfig } from './surveyRegistry' +import { useFeatureUsageTracker } from './useFeatureUsageTracker' + +/** + * Convenience composable for tracking feature usage for surveys. + * Use this at the feature site to track when a feature is used. + * + * @example + * ```typescript + * const { trackFeatureUsed } = useSurveyFeatureTracking('simple-mode') + * + * function onFeatureAction() { + * trackFeatureUsed() + * } + * ``` + */ +export function useSurveyFeatureTracking(featureId: string) { + const config = getSurveyConfig(featureId) + + if (!config?.enabled) { + return { + trackFeatureUsed: () => {}, + useCount: computed(() => 0) + } + } + + const { trackUsage, useCount } = useFeatureUsageTracker(featureId) + + return { + trackFeatureUsed: trackUsage, + useCount + } +}