Add guest analytics consent nudge

This commit is contained in:
Codex Agent
2026-01-23 16:20:14 +01:00
parent f19a83d4ee
commit 8c507b8b13
7 changed files with 388 additions and 9 deletions

View File

@@ -0,0 +1,44 @@
import { describe, expect, it } from 'vitest';
import { isUploadPath, shouldShowAnalyticsNudge } from '../analyticsConsent';
describe('isUploadPath', () => {
it('detects upload routes', () => {
expect(isUploadPath('/e/abc/upload')).toBe(true);
expect(isUploadPath('/e/abc/upload/queue')).toBe(true);
});
it('ignores non-upload routes', () => {
expect(isUploadPath('/e/abc/gallery')).toBe(false);
expect(isUploadPath('/settings')).toBe(false);
});
});
describe('shouldShowAnalyticsNudge', () => {
const baseState = {
decisionMade: false,
analyticsConsent: false,
snoozedUntil: null,
now: 1000,
activeSeconds: 60,
routeCount: 2,
thresholdSeconds: 60,
thresholdRoutes: 2,
isUpload: false,
};
it('returns true when thresholds are met', () => {
expect(shouldShowAnalyticsNudge(baseState)).toBe(true);
});
it('returns false when consent decision is made', () => {
expect(shouldShowAnalyticsNudge({ ...baseState, decisionMade: true })).toBe(false);
});
it('returns false when snoozed', () => {
expect(shouldShowAnalyticsNudge({ ...baseState, snoozedUntil: 2000 })).toBe(false);
});
it('returns false on upload routes', () => {
expect(shouldShowAnalyticsNudge({ ...baseState, isUpload: true })).toBe(false);
});
});

View File

@@ -0,0 +1,34 @@
export type AnalyticsNudgeState = {
decisionMade: boolean;
analyticsConsent: boolean;
snoozedUntil: number | null;
now: number;
activeSeconds: number;
routeCount: number;
thresholdSeconds: number;
thresholdRoutes: number;
isUpload: boolean;
};
export function isUploadPath(pathname: string): boolean {
return /\/upload(?:\/|$)/.test(pathname);
}
export function shouldShowAnalyticsNudge(state: AnalyticsNudgeState): boolean {
if (state.decisionMade || state.analyticsConsent) {
return false;
}
if (state.isUpload) {
return false;
}
if (state.snoozedUntil && state.snoozedUntil > state.now) {
return false;
}
return (
state.activeSeconds >= state.thresholdSeconds &&
state.routeCount >= state.thresholdRoutes
);
}