From 0e00e3e368b1c98fc4e9fa4d1bdb93f57fe7c2c4 Mon Sep 17 00:00:00 2001 From: WcaleNieWolny <50914789+WcaleNieWolny@users.noreply.github.com> Date: Tue, 18 Aug 2026 12:46:04 +0200 Subject: [PATCH 01/10] feat(onboarding): add welcome screen (#3110) * feat(onboarding): add welcome screen * test(onboarding): cover welcome screen in registration e2e * fix(onboarding): freeze welcome viewport eligibility --- messages/en.context.json | 4 + messages/en.json | 4 + playwright/e2e/register.spec.ts | 9 + src/components.d.ts | 4 +- .../dashboard/AppOnboardingFlow.vue | 34 +- .../dashboard/AppOnboardingWelcome.vue | 301 ++++++++++++++++++ src/pages/onboarding/app.vue | 13 +- src/utils/onboardingProgressAnalytics.ts | 2 +- src/utils/userOnboardingProgress.ts | 10 +- ...boarding-progress-integration.unit.test.ts | 14 +- tests/app-onboarding-welcome.unit.test.ts | 79 +++++ 11 files changed, 453 insertions(+), 21 deletions(-) create mode 100644 src/components/dashboard/AppOnboardingWelcome.vue create mode 100644 tests/app-onboarding-welcome.unit.test.ts diff --git a/messages/en.context.json b/messages/en.context.json index f767bba23f..b6585d022e 100644 --- a/messages/en.context.json +++ b/messages/en.context.json @@ -2052,6 +2052,10 @@ "onboarding-source-manual": "Used in Capgo web console areas: pages/admin/dashboard. Role: short UI label. Translate for UI; keep Capgo product names, code, and placeholders unchanged.", "onboarding-source-mcp": "Used in Capgo web console areas: pages/admin/dashboard. Role: short UI label. Translate for UI; keep Capgo product names, code, and placeholders unchanged.", "onboarding-trend": "Used in Capgo web console areas: pages/admin/dashboard. Role: UI label. Translate for UI; keep Capgo product names, code, and placeholders unchanged.", + "onboarding-welcome-cta": "Used in Capgo web console areas: components/dashboard. Role: UI label. Translate for UI; keep Capgo product names, code, and placeholders unchanged.", + "onboarding-welcome-description": "Used in Capgo web console areas: components/dashboard. Role: helper or description text. Translate for UI; keep Capgo product names, code, and placeholders unchanged.", + "onboarding-welcome-eyebrow": "Used in Capgo web console areas: components/dashboard. Role: UI label. Translate for UI; keep Capgo product names, code, and placeholders unchanged.", + "onboarding-welcome-title": "Used in Capgo web console areas: components/dashboard. Role: section or dialog title. Translate for UI; keep Capgo product names, code, and placeholders unchanged.", "onboarding-wizard-abandoned": "Used in Capgo web console areas: pages/admin/dashboard. Role: short UI label. Translate for UI; keep Capgo product names, code, and placeholders unchanged.", "onboarding-wizard-completed": "Used in Capgo web console areas: pages/admin/dashboard. Role: short UI label. Translate for UI; keep Capgo product names, code, and placeholders unchanged.", "onboarding-wizard-dropoff": "Used in Capgo web console areas: pages/admin/dashboard. Role: UI label. Translate for UI; keep Capgo product names, code, and placeholders unchanged.", diff --git a/messages/en.json b/messages/en.json index f85ed0df9e..d9c3e1b4f7 100644 --- a/messages/en.json +++ b/messages/en.json @@ -1870,6 +1870,10 @@ "onboarding-resume-restart": "Restart", "onboarding-resume-title": "Continue where you left off?", "onboarding-trend": "Onboarding Trend", + "onboarding-welcome-cta": "Set up my first update", + "onboarding-welcome-description": "You’re a few steps away from the magic of over-the-air updates — and so much more.", + "onboarding-welcome-eyebrow": "Good to have you here", + "onboarding-welcome-title": "Welcome to Capgo", "onboarding-wizard-abandoned": "Abandoned", "onboarding-wizard-completed": "Completed", "onboarding-wizard-dropoff": "Onboarding wizard drop-off", diff --git a/playwright/e2e/register.spec.ts b/playwright/e2e/register.spec.ts index b8ccad89b9..7aa954e70e 100644 --- a/playwright/e2e/register.spec.ts +++ b/playwright/e2e/register.spec.ts @@ -5,6 +5,12 @@ async function loginToOnboarding(page: Page, email: string, password: string) { await page.login(email, password, /\/onboarding\/app/) } +async function continuePastWelcome(page: Page) { + const continueButton = page.locator('[data-test="onboarding-welcome-continue"]') + await expect(continueButton).toBeVisible() + await continueButton.click() +} + async function expectProtectedRouteRedirect(page: Page, targetPath: string, expectedUrl: RegExp, expectedSelector: string) { const redirectedPage = await page.context().newPage() @@ -39,6 +45,7 @@ test.describe('Registration', () => { await page.click('[data-test="submit"]') await page.waitForURL(/\/onboarding\/app/) + await continuePastWelcome(page) await page.click('[data-test="onboarding-intent-ota"]') await page.click('[data-test="app-onboarding-continue-intent"]') @@ -88,6 +95,7 @@ test.describe('Registration', () => { await page.click('[data-test="submit"]') await page.waitForURL(/\/onboarding\/app/) + await continuePastWelcome(page) await page.click('[data-test="onboarding-intent-ota"]') await page.click('[data-test="app-onboarding-continue-intent"]') await page.fill('[data-test="app-onboarding-name"]', appName) @@ -114,6 +122,7 @@ test.describe('Registration', () => { await loginToOnboarding(page, email, password) await expect(page.locator('[data-test="onboarding-resume-restart"]')).toBeVisible() await page.locator('[data-test="onboarding-resume-restart"]').click() + await continuePastWelcome(page) await expect(page.locator('[data-test="onboarding-intent-ota"]')).toBeVisible() await expect(page.locator('[data-test="onboarding-org-name"]')).toHaveCount(0) }) diff --git a/src/components.d.ts b/src/components.d.ts index f9e522c966..cd67ec13da 100644 --- a/src/components.d.ts +++ b/src/components.d.ts @@ -29,7 +29,7 @@ declare module 'vue' { AppOnboardingCliSteps: typeof import('./components/dashboard/AppOnboardingCliSteps.vue')['default'] AppOnboardingFlow: typeof import('./components/dashboard/AppOnboardingFlow.vue')['default'] AppOnboardingIconInput: typeof import('./components/dashboard/AppOnboardingIconInput.vue')['default'] - AppOnboardingNextStep: typeof import('./components/dashboard/AppOnboardingNextStep.vue')['default'] + AppOnboardingWelcome: typeof import('./components/dashboard/AppOnboardingWelcome.vue')['default'] AppPageFrame: typeof import('./components/dashboard/AppPageFrame.vue')['default'] AppPageNotFound: typeof import('./components/dashboard/AppPageNotFound.vue')['default'] AppSetting: typeof import('./components/dashboard/AppSetting.vue')['default'] @@ -94,6 +94,7 @@ declare module 'vue' { Navbar: typeof import('./components/Navbar.vue')['default'] OnboardingExploreBanner: typeof import('./components/dashboard/OnboardingExploreBanner.vue')['default'] OnboardingSupportUsernames: typeof import('./components/dashboard/OnboardingSupportUsernames.vue')['default'] + OrganizationOnboardingInvite: typeof import('./components/dashboard/OrganizationOnboardingInvite.vue')['default'] OrgEmailNotificationsPanel: typeof import('./components/dashboard/OrgEmailNotificationsPanel.vue')['default'] OrgNotificationStatsPanel: typeof import('./components/dashboard/OrgNotificationStatsPanel.vue')['default'] PageLoader: typeof import('./components/PageLoader.vue')['default'] @@ -122,6 +123,7 @@ declare module 'vue' { TableLog: typeof import('./components/TableLog.vue')['default'] Tabs: typeof import('./components/Tabs.vue')['default'] TabSidebar: typeof import('./components/TabSidebar.vue')['default'] + TechnicalTeammateInviteCard: typeof import('./components/dashboard/TechnicalTeammateInviteCard.vue')['default'] Toast: typeof import('./components/Toast.vue')['default'] Toggle: typeof import('./components/Toggle.vue')['default'] TrialBanner: typeof import('./components/dashboard/TrialBanner.vue')['default'] diff --git a/src/components/dashboard/AppOnboardingFlow.vue b/src/components/dashboard/AppOnboardingFlow.vue index 0b289c84e2..7a7f0cb562 100644 --- a/src/components/dashboard/AppOnboardingFlow.vue +++ b/src/components/dashboard/AppOnboardingFlow.vue @@ -1,6 +1,7 @@