feat: add usage onboarding survey overlay (#388)

* feat: add usage-survey feedback types and gating function

Claude-Session: https://claude.ai/code/session_01KAC9Lbx8AmebAnj9WQZXHp

* feat: add onboarding usage-survey i18n strings to all locales

Relabels three ambiguous feedback.usageTypes values (personal/team_internal/
business_workflow) and adds a new onboarding namespace (4 keys) across the
reference locale and all 20 translations, so the tree compiles at every
commit instead of only after both locale groups land.

Claude-Session: https://claude.ai/code/session_01KAC9Lbx8AmebAnj9WQZXHp

* feat: add UsageSurveyOverlay component

* feat: mount UsageSurveyOverlay inside AuthGuard

Claude-Session: https://claude.ai/code/session_01KAC9Lbx8AmebAnj9WQZXHp

* fix: use text-start instead of text-left for RTL support in UsageSurveyOverlay

* refactor: drop redundant usage-type field from the admin feedback dialog

Claude-Session: https://claude.ai/code/session_01KAC9Lbx8AmebAnj9WQZXHp

* feat: accept onboarding source and survey id in the feedback route

Claude-Session: https://claude.ai/code/session_01KAC9Lbx8AmebAnj9WQZXHp

* test: cover the onboarding source in the feedback route integration test

Claude-Session: https://claude.ai/code/session_01KAC9Lbx8AmebAnj9WQZXHp

* chore: remove orphaned usageTypeLabel i18n key

* refactor: derive feedback source/survey_id enums from a single source of truth

* perf: skip the settings fetch in UsageSurveyOverlay for non-admin users
This commit is contained in:
SnapOtter
2026-07-02 00:02:24 +08:00
committed by GitHub
parent 9052da27f3
commit a0d1c70172
31 changed files with 674 additions and 168 deletions
@@ -134,6 +134,38 @@ describe("POST /api/v1/feedback", () => {
);
});
it("accepts an onboarding usage-survey submission", async () => {
process.env.ANALYTICS_BAKED_OVERRIDE = "on";
await refreshAnalyticsGate();
const token = await loginAsAdmin(testApp.app);
const res = await testApp.app.inject({
method: "POST",
url: "/api/v1/feedback",
headers: { authorization: `Bearer ${token}` },
payload: {
source: "onboarding",
surveyId: "onboarding-usage-v1",
promptVariant: "onboarding-overlay-v1",
usageType: "team_internal",
importantAreas: ["images", "pdf_docs"],
},
});
expect(res.statusCode).toBe(200);
expect(JSON.parse(res.body)).toEqual({ ok: true, accepted: true });
expect(captureFeedback).toHaveBeenCalledWith(
expect.objectContaining({
source: "onboarding",
survey_id: "onboarding-usage-v1",
prompt_variant: "onboarding-overlay-v1",
usage_type: "team_internal",
important_areas: ["images", "pdf_docs"],
}),
undefined,
);
});
it("drops identifying contact fields when contact consent is not checked", async () => {
process.env.ANALYTICS_BAKED_OVERRIDE = "on";
await refreshAnalyticsGate();