diff --git a/messages/en.context.json b/messages/en.context.json index b6585d022e..bb705f2a91 100644 --- a/messages/en.context.json +++ b/messages/en.context.json @@ -1656,7 +1656,6 @@ "key-upload": "Used in Capgo web console. Role: short UI label about \"key upload\". Translate for UI; keep Capgo product names, code, and placeholders unchanged.", "key-write": "Used in Capgo web console. Role: short UI label about \"key write\". Translate for UI; keep Capgo product names, code, and placeholders unchanged.", "language": "Used in Capgo web console areas: pages/settings/account. Role: short UI label. Translate for UI; keep Capgo product names, code, and placeholders unchanged.", - "learn-more": "Used in pre-organization app onboarding. Role: button opening additional App ID guidance.", "last": "Used in Capgo web console. Role: short UI label about \"last\". Translate for UI; keep Capgo product names, code, and placeholders unchanged.", "last-1-hour": "Used in Capgo web console areas: services. Role: UI label. Translate for UI; keep Capgo product names, code, and placeholders unchanged.", "last-12-hours": "Used in Capgo web console areas: services. Role: UI label. Translate for UI; keep Capgo product names, code, and placeholders unchanged.", @@ -3044,5 +3043,26 @@ "your-api-key": "Used in Capgo web console areas: services. Role: UI label. Translate for UI; keep Capgo product names, code, and placeholders unchanged.", "your-role-in-org": "Used in Capgo web console areas: pages. Role: UI label. Translate for UI; keep Capgo product names, code, and placeholders unchanged.", "your-usage": "Used in Capgo web console areas: pages/settings/organization. Role: UI label. Translate for UI; keep Capgo product names, code, and placeholders unchanged.", - "zip-bundle": "Used in Capgo web console areas: pages/app. Role: UI label. Translate for UI; keep Capgo product names, code, and placeholders unchanged." + "zip-bundle": "Used in Capgo web console areas: pages/app. Role: UI label. Translate for UI; keep Capgo product names, code, and placeholders unchanged.", + "app-onboarding-icon-step-helper": "Used in app onboarding details wizard. Role: helper text.", + "app-onboarding-icon-step-title": "Used in app onboarding details wizard. Role: step title.", + "app-onboarding-import-icon-only-button": "Used in app onboarding details wizard. Role: button label.", + "app-onboarding-import-icon-only-helper": "Used in app onboarding details wizard. Role: helper text explaining that store re-import changes only the icon.", + "app-onboarding-import-icon-only-title": "Used in app onboarding details wizard. Role: section title.", + "app-onboarding-imported-icon-alt": "Used in app onboarding details wizard. Role: image alternative text.", + "app-onboarding-imported-icon-helper": "Used in app onboarding details wizard. Role: helper text.", + "app-onboarding-imported-icon-label": "Used in app onboarding details wizard. Role: status label.", + "app-onboarding-imported-icon-selected": "Used in app onboarding details wizard. Role: selected button label.", + "app-onboarding-name-step-helper": "Used in app onboarding details wizard. Role: helper text.", + "app-onboarding-name-step-title": "Used in app onboarding details wizard. Role: step title.", + "app-onboarding-remove-icon": "Used in app onboarding details wizard. Role: button label.", + "app-onboarding-skip-app-id": "Used in app onboarding details wizard. Role: button label that accepts Capgo's generated App ID.", + "app-onboarding-toast-store-icon-error": "Used in app onboarding details wizard. Role: error toast.", + "app-onboarding-use-different-icon": "Used in app onboarding details wizard. Role: section label.", + "app-onboarding-use-imported-icon": "Used in app onboarding details wizard. Role: button label.", + "app-onboarding-app-id-generated-helper": "Used in app onboarding details wizard. Role: helper text. Preserve the {appId} placeholder.", + "app-onboarding-app-id-learn-more": "Used in app onboarding details wizard. Role: button opening guidance about Capgo App IDs.", + "app-onboarding-app-id-step-helper": "Used in app onboarding details wizard. Role: helper text.", + "app-onboarding-app-id-step-title": "Used in app onboarding details wizard. Role: step title.", + "app-onboarding-finish-details": "Used in app onboarding details wizard. Role: final creation button label." } diff --git a/messages/en.json b/messages/en.json index d9c3e1b4f7..e2f200d6bd 100644 --- a/messages/en.json +++ b/messages/en.json @@ -449,10 +449,19 @@ "app-onboarding-exploring-subtitle": "Setup isn't finished yet. You can keep exploring or continue onboarding.", "app-onboarding-exploring-title": "Exploring the Capgo dashboard", "app-onboarding-icon-choose-file": "Choose file", - "app-onboarding-icon-help": "The icon is optional. If you import from a store listing, Capgo will try to reuse the store icon automatically.", + "app-onboarding-icon-help": "Upload a square PNG, JPEG, or WebP image. The icon is optional.", "app-onboarding-icon-label": "App icon", "app-onboarding-icon-no-file-selected": "No file selected", "app-onboarding-icon-preview-alt": "App icon preview", + "app-onboarding-icon-step-helper": "Keep the imported icon, upload something else, or continue without one.", + "app-onboarding-icon-step-title": "Choose an icon", + "app-onboarding-import-icon-only-button": "Import icon", + "app-onboarding-import-icon-only-helper": "Only the icon will change. Your app name and App ID stay exactly as they are.", + "app-onboarding-import-icon-only-title": "Import an icon from another store listing", + "app-onboarding-imported-icon-alt": "Imported store icon", + "app-onboarding-imported-icon-helper": "We found this icon in the store listing you imported.", + "app-onboarding-imported-icon-label": "Imported from store", + "app-onboarding-imported-icon-selected": "Using this icon", "app-onboarding-install-badge": "CLI onboarding", "app-onboarding-explore-dashboard": "Explore Capgo dashboard", "app-onboarding-explore-dashboard-confirm-description": "You can explore the dashboard now. Your app setup will remain available when you return.", @@ -482,6 +491,8 @@ "app-onboarding-mode-import-helper": "Use an App Store or Google Play link to prefill details.", "app-onboarding-mode-manual": "Set up manually", "app-onboarding-mode-manual-helper": "Type the app name and bundle or package ID yourself.", + "app-onboarding-name-step-helper": "Use the name people will recognize in Capgo. You can change it later.", + "app-onboarding-name-step-title": "What is your app called?", "app-onboarding-name-placeholder": "Capgo demo app", "app-onboarding-next-cleanup": "When the CLI marks onboarding as completed, the temporary onboarding data can be cleared automatically before the first real upload continues.", "app-onboarding-next-existing": "The CLI should attach Capgo to your existing project without scaffolding a new Capacitor app.", @@ -493,6 +504,7 @@ "app-onboarding-preview-bullet-two": "Demo data stays disposable. When the CLI completes, pending onboarding data can be cleared automatically.", "app-onboarding-preview-label": "Preview", "app-onboarding-preview-placeholder": "Your app", + "app-onboarding-remove-icon": "Remove icon", "app-onboarding-progress-label": "Onboarding progress", "app-onboarding-progress-count": "Step {current} of {total}", "app-onboarding-start-question": "How do you want to start?", @@ -505,6 +517,7 @@ "app-onboarding-store-link-label": "App Store or Google Play link", "app-onboarding-store-link-placeholder": "https://apps.apple.com/... or https://play.google.com/store/apps/details?id=com.example.app", "app-onboarding-store-screenshot-alt": "Store screenshot preview", + "app-onboarding-skip-app-id": "Skip", "app-onboarding-subtitle": "The app is created immediately in Capgo. From there you can either connect your real project in the CLI or explore the dashboard with temporary demo data.", "app-onboarding-summary-method": "Setup method", "app-onboarding-summary-source": "Starting point", @@ -522,6 +535,14 @@ "app-onboarding-toast-no-organization": "No organization selected.", "app-onboarding-toast-resume-not-found": "Unable to find the onboarding app.", "app-onboarding-toast-store-metadata-error": "Unable to fetch metadata from that store link.", + "app-onboarding-toast-store-icon-error": "Unable to find an app icon at this store link.", + "app-onboarding-use-different-icon": "Use something else", + "app-onboarding-use-imported-icon": "Use this icon", + "app-onboarding-app-id-generated-helper": "Leave this empty and Capgo will use {appId}.", + "app-onboarding-app-id-learn-more": "Learn more about Capgo App ID", + "app-onboarding-app-id-step-helper": "Use your bundle or package ID, import it from a store listing, or skip this step.", + "app-onboarding-app-id-step-title": "Set your App ID", + "app-onboarding-finish-details": "Create app", "app-onboarding-v2-ai-help-status": "Existing mobile project; store publication is optional", "app-onboarding-v2-appid-dialog-description": "Capgo uses this App ID to identify the app in the dashboard and CLI. It is often the same as your native project ID, but it does not have to be. Changing it here does not change your iOS Bundle Identifier, Android Application ID, Capacitor appId, or store listing.", "app-onboarding-v2-appid-dialog-title": "How does the Capgo App ID work?", @@ -1517,7 +1538,6 @@ "key-upload": "Upload", "key-write": "Write", "language": "Language", - "learn-more": "Learn more", "last": "Last", "last-12-months": "Last 12 Months", "last-30-minutes": "Last 30 minutes", diff --git a/playwright/e2e/register.spec.ts b/playwright/e2e/register.spec.ts index 7aa954e70e..acf4dc47d6 100644 --- a/playwright/e2e/register.spec.ts +++ b/playwright/e2e/register.spec.ts @@ -24,6 +24,27 @@ async function expectProtectedRouteRedirect(page: Page, targetPath: string, expe } } +async function continueFromAppNameToIcon(page: Page) { + await page.click('[data-test="app-onboarding-continue"]') + await expect(page.locator('#app-onboarding-app-id')).toBeVisible() + await page.click('[data-test="app-onboarding-skip-app-id"]') + await expect(page.locator('[data-test="app-onboarding-toggle-icon-store-import"]')).toBeVisible() +} + +async function continueFromAppNameToOrganization(page: Page) { + await continueFromAppNameToIcon(page) + await page.click('[data-test="app-onboarding-continue"]') +} + +async function returnFromOrganizationToAppName(page: Page) { + await page.getByRole('button', { name: 'Back', exact: true }).click() + await expect(page.locator('[data-test="app-onboarding-toggle-icon-store-import"]')).toBeVisible() + await page.getByRole('button', { name: 'Back', exact: true }).click() + await expect(page.locator('#app-onboarding-app-id')).toBeVisible() + await page.getByRole('button', { name: 'Back', exact: true }).click() + await expect(page.locator('[data-test="app-onboarding-name"]')).toBeVisible() +} + test.describe('Registration', () => { test.beforeEach(async ({ page }) => { await page.goto('/register/') @@ -52,22 +73,22 @@ test.describe('Registration', () => { await expect(page.locator('[data-test="app-onboarding-existing-yes"]')).toHaveCount(0) await expect(page.locator('[data-test="app-onboarding-existing-no"]')).toHaveCount(0) await expect(page.locator('[data-test="app-onboarding-name"]')).toBeVisible() - await expect(page.locator('#app-onboarding-app-id')).toBeVisible() + await expect(page.locator('#app-onboarding-app-id')).toHaveCount(0) await page.fill('[data-test="app-onboarding-name"]', appName) - await page.click('[data-test="app-onboarding-continue"]') + await continueFromAppNameToOrganization(page) await expectProtectedRouteRedirect(page, '/apps', /\/onboarding\/app/, '[data-test="onboarding-logout"]') await expect(page.locator('[data-test="onboarding-org-name"]')).toHaveValue(appName) await page.locator('[data-test="onboarding-estimated-users-option"]').nth(1).click() - await page.getByRole('button', { name: 'Back', exact: true }).click() + await returnFromOrganizationToAppName(page) await page.fill('[data-test="app-onboarding-name"]', editedAppName) - await page.click('[data-test="app-onboarding-continue"]') + await continueFromAppNameToOrganization(page) await expect(page.locator('[data-test="onboarding-org-name"]')).toHaveValue(editedAppName) await page.fill('[data-test="onboarding-org-name"]', organizationName) - await page.getByRole('button', { name: 'Back', exact: true }).click() + await returnFromOrganizationToAppName(page) await page.fill('[data-test="app-onboarding-name"]', finalAppName) - await page.click('[data-test="app-onboarding-continue"]') + await continueFromAppNameToOrganization(page) await expect(page.locator('[data-test="onboarding-org-name"]')).toHaveValue(organizationName) await expect(page.locator('[data-test="onboarding-create-org"]')).toBeEnabled() await page.click('[data-test="onboarding-create-org"]') @@ -99,6 +120,7 @@ test.describe('Registration', () => { 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) + await continueFromAppNameToIcon(page) await Promise.all([ page.waitForResponse((response) => { if (!response.url().includes('/rest/v1/users') || response.request().method() !== 'PATCH' || !response.ok()) diff --git a/src/components/dashboard/AppOnboardingFlow.vue b/src/components/dashboard/AppOnboardingFlow.vue index 7a7f0cb562..48e8fbf371 100644 --- a/src/components/dashboard/AppOnboardingFlow.vue +++ b/src/components/dashboard/AppOnboardingFlow.vue @@ -23,7 +23,6 @@ import IconArrowRight from '~icons/lucide/arrow-right' import IconCheck from '~icons/lucide/check' import IconChevronDown from '~icons/lucide/chevron-down' import IconChevronUp from '~icons/lucide/chevron-up' -import IconCode from '~icons/lucide/code-2' import IconCompass from '~icons/lucide/compass' import IconGlobe from '~icons/lucide/globe-2' import IconInfo from '~icons/lucide/info' @@ -68,7 +67,12 @@ import { loadOnboardingAppDraft, } from '~/utils/onboardingAppDraft' import { onboardingPrimaryButtonClass, onboardingSecondaryButtonClass } from '~/utils/onboardingButtonClasses' -import { createOnboardingDetailsFieldDebouncer, createOnboardingProgressTracker, createOnboardingTelemetryIdentity } from '~/utils/onboardingProgressAnalytics' +import { + createOnboardingDetailsFieldDebouncer, + createOnboardingProgressTracker, + createOnboardingTelemetryIdentity, + resolveOnboardingAppIconSource, +} from '~/utils/onboardingProgressAnalytics' import { createOnboardingProgressPersistence, shouldInitializeOnboardingProgressTracking } from '~/utils/onboardingProgressPersistence' import { allowOnboardingDashboardExploration, ONBOARDING_DASHBOARD_EXPLORED_EVENT } from '~/utils/onboardingRedirect' import { slugifyOnboardingSegment } from '~/utils/onboardingSlug' @@ -110,6 +114,14 @@ type AppRow = Omit & type StandardFlowStep = 'details' | 'choice' | 'install' | 'setup' type PreOrgFlowStep = 'intent' | 'details' | 'organization' | 'setup' type OnboardingFlowStep = StandardFlowStep | PreOrgFlowStep +type AppDetailsStep = 'name' | 'app_id' | 'icon' +type AppDetailsAnalyticsStep = 'app_name' | 'app_id' | 'app_icon' + +const APP_DETAILS_ANALYTICS_STEPS: Record = { + name: 'app_name', + app_id: 'app_id', + icon: 'app_icon', +} interface UserCountStop { value: number @@ -132,13 +144,17 @@ const welcomePending = ref(false) const showPreOrgWelcome = computed(() => props.preOrg && welcomeCanvasEligible.value && welcomePending.value) const isSubmitting = ref(false) const isImportingStore = ref(false) +const isImportingStoreIcon = ref(false) const isResumeIconLoading = ref(false) const isSeedingDemo = ref(false) const isCliCommandVisible = ref(false) const apiKey = ref(null) const createdApp = ref(null) +const preOrgCreatedOrganizationId = ref(null) +const preOrgShouldInvite = ref(false) const reportedSetupSource = ref<'manual' | 'cli' | 'mcp' | 'ai' | null>(null) const flowStep = ref('details') +const appDetailsStep = ref('name') const showLanguageSelector = computed(() => ( (props.preOrg && !createdApp.value) || (flowStep.value === 'setup' && Boolean(createdApp.value)) @@ -147,11 +163,13 @@ const showLanguageSelector = computed(() => ( const selectedIconFile = ref(null) const localIconPreview = ref('') const storeIconPreview = ref('') -const storeScreenshotPreview = ref('') +const storeAppNamePreview = ref('') +const useImportedStoreIcon = ref(false) const existingApp = ref(null) const existingAppSetup = ref<'import' | 'manual' | null>(null) const appName = ref('') const storeUrl = ref('') +const iconStoreUrl = ref('') const importedStoreAppId = ref('') const manualAppId = ref('') const appIdSuggestions = ref([]) @@ -161,6 +179,11 @@ const selectedIntent = ref(null) const orgNameInput = ref('') const hasEditedOrgName = ref(false) const estimatedUsersIndex = ref(null) +const isStoreImportOpen = ref(false) +const isStoreIconImportOpen = ref(false) +const isAppDetailsNavigationPending = computed(() => ( + isSubmitting.value || isImportingStore.value || isImportingStoreIcon.value +)) const isOrganizationImportOpen = ref(false) const isImportingOrganizationWebsite = ref(false) const organizationWebsiteInput = ref('') @@ -260,18 +283,9 @@ const resumeStep = computed(() => { const value = route.query.step return value === 'choice' || value === 'install' || value === 'setup' ? value : null }) -const canUseStoreImportPreview = computed(() => existingAppSetup.value === 'import' && (props.preOrg || existingApp.value === true)) +const canUseStoreImportPreview = computed(() => useImportedStoreIcon.value && !!storeIconPreview.value) const iconPreview = computed(() => localIconPreview.value || (canUseStoreImportPreview.value ? storeIconPreview.value : '') || '') -const hasImportedStoreMetadata = computed(() => canUseStoreImportPreview.value && !!(importedStoreAppId.value || storeIconPreview.value || storeScreenshotPreview.value)) -const canShowAppDetails = computed(() => { - if (props.preOrg) - return true - if (existingApp.value === false) - return true - if (existingApp.value === true) - return existingAppSetup.value !== null - return false -}) +const hasImportedStoreMetadata = computed(() => existingAppSetup.value === 'import' && !!(importedStoreAppId.value || storeIconPreview.value || storeAppNamePreview.value)) const suggestedAppId = computed(() => { if (createdApp.value) return createdApp.value.app_id @@ -289,6 +303,22 @@ const suggestedAppId = computed(() => { return `com.${orgSlug}.${appSlug}` }) const generatedAppId = computed(() => createdApp.value?.app_id || manualAppId.value.trim() || suggestedAppId.value) +const hasProvidedAppId = computed(() => Boolean(manualAppId.value.trim() || importedStoreAppId.value.trim())) +const appNameInitial = computed(() => Array.from(appName.value.trim())[0]?.toLocaleUpperCase() ?? '') +const selectedAppIdSource = computed>(() => { + if (manualAppId.value.trim()) + return 'manual' + if (existingAppSetup.value === 'import' && importedStoreAppId.value.trim()) + return 'store' + return 'generated' +}) +const selectedAppIconSource = computed>(() => { + return resolveOnboardingAppIconSource({ + canUseStoreImportPreview: canUseStoreImportPreview.value, + hasSelectedIconFile: Boolean(selectedIconFile.value), + localIconPreview: localIconPreview.value, + }) +}) function createAiHelpPrompt() { const resolvedAppId = createdApp.value?.app_id || generatedAppId.value || '[APP_ID]' const resolvedAppName = createdApp.value?.name?.trim() || appName.value.trim() || resolvedAppId @@ -358,7 +388,7 @@ const onboardingProgressPersistence = createOnboardingProgressPersistence({ function trackDetailsEvent(name: OnboardingDetailsEvent, details: OnboardingDetailsEventProperties = {}) { if (props.preOrg) - progressTracker?.trackDetailsEvent(name, details) + progressTracker?.trackDetailsEvent(name, analyticsStepFor('details'), details) } function trackOrganizationEvent( @@ -368,11 +398,24 @@ function trackOrganizationEvent( progressTracker?.trackStepEvent(name, 'organization', details) } -const detailsFieldTracker = createOnboardingDetailsFieldDebouncer(trackDetailsEvent) +const detailsFieldTracker = createOnboardingDetailsFieldDebouncer((name, step, details) => { + if (props.preOrg) + progressTracker?.trackDetailsEvent(name, step, details) +}) + +function analyticsStepFor(flow: OnboardingFlowStep, detailsStep = appDetailsStep.value): OnboardingAnalyticsStep { + if (flow === 'details') + return APP_DETAILS_ANALYTICS_STEPS[detailsStep] + return flow +} function initializeProgressTracking(resumed: boolean) { - const initialStep: OnboardingAnalyticsStep = showPreOrgWelcome.value ? 'welcome' : flowStep.value - const trackedSteps: OnboardingAnalyticsStep[] = appOnboardingSteps.value.map(step => step.id) + const initialStep: OnboardingAnalyticsStep = showPreOrgWelcome.value ? 'welcome' : analyticsStepFor(flowStep.value) + const trackedSteps = appOnboardingSteps.value.flatMap((step) => { + if (step.id === 'details') + return Object.values(APP_DETAILS_ANALYTICS_STEPS) + return [step.id] + }) if (initialStep === 'welcome') trackedSteps.unshift('welcome') if (!props.preOrg && resumed && flowStep.value === 'setup') @@ -396,12 +439,14 @@ function completeAndViewStep(nextStep: OnboardingFlowStep, completionProperties: if (previousStep === nextStep) return - progressTracker?.completeStep(previousStep, { + const previousAnalyticsStep = analyticsStepFor(previousStep) + const nextAnalyticsStep = analyticsStepFor(nextStep) + progressTracker?.completeStep(previousAnalyticsStep, { ...completionProperties, - nextStep, + nextStep: nextAnalyticsStep, }) flowStep.value = nextStep - progressTracker?.viewStep(nextStep, previousStep) + progressTracker?.viewStep(nextAnalyticsStep, previousAnalyticsStep) void persistOnboardingProgress() } @@ -410,8 +455,10 @@ function viewPreviousStep(nextStep: OnboardingFlowStep) { if (previousStep === nextStep) return + const previousAnalyticsStep = analyticsStepFor(previousStep) + const nextAnalyticsStep = analyticsStepFor(nextStep) flowStep.value = nextStep - progressTracker?.viewStep(nextStep, previousStep) + progressTracker?.viewStep(nextAnalyticsStep, previousAnalyticsStep) void persistOnboardingProgress() } @@ -423,8 +470,9 @@ function snapshotOnboardingProgress(status: UserOnboardingStatus = 'in_progress' step: clampResumableOnboardingStep(flowStep.value, flow), flow, intent: selectedIntent.value, + detailsStep: appDetailsStep.value, appName: appName.value, - appId: generatedAppId.value, + appId: selectedAppIdSource.value === 'generated' ? '' : generatedAppId.value, existingApp: existingApp.value, existingAppSetup: existingAppSetup.value, storeUrl: storeUrl.value, @@ -537,19 +585,26 @@ async function writeOnboardingProgress( function resetOnboardingForm() { flowStep.value = props.preOrg ? 'intent' : 'details' + appDetailsStep.value = 'name' selectedIntent.value = null - existingApp.value = null + existingApp.value = props.preOrg ? true : null + existingAppSetup.value = props.preOrg ? 'manual' : null appName.value = '' manualAppId.value = '' hasEditedAppId.value = false orgNameInput.value = '' hasEditedOrgName.value = false estimatedUsersIndex.value = null + isStoreImportOpen.value = false + isStoreIconImportOpen.value = false createdApp.value = null + preOrgCreatedOrganizationId.value = null + preOrgShouldInvite.value = false selectedIconFile.value = null if (localIconPreview.value.startsWith('blob:')) URL.revokeObjectURL(localIconPreview.value) localIconPreview.value = '' + iconStoreUrl.value = '' resetStoreImportState() } @@ -570,6 +625,8 @@ function applyOnboardingProgress(progress: ReturnType { const resumed = await loadResumeApp() resumedFlow = resumed - if (!resumed) + if (!resumed) { flowStep.value = 'details' + appDetailsStep.value = 'name' + existingApp.value = null + existingAppSetup.value = null + } void loadApiKey().catch((error) => { console.error('Cannot ensure API key', error) @@ -1708,7 +1996,8 @@ watch(existingApp, (value) => { return } - existingAppSetup.value = value === true ? null : value === false ? 'manual' : null + if (value !== true) + existingAppSetup.value = value === false ? 'manual' : null if (value !== true) { resetStoreImportState() } @@ -1723,11 +2012,6 @@ watch(existingAppSetup, (value) => { resetStoreImportState() }) -watch(suggestedAppId, (value) => { - if (!hasEditedAppId.value && !createdApp.value) - manualAppId.value = value -}, { immediate: true }) - watch(appName, (value) => { if (isHydratingOnboarding.value) return @@ -1740,6 +2024,10 @@ watch([orgNameInput, storeUrl, selectedIntent, existingAppSetup, estimatedUsersI schedulePersistOnboardingProgress() }) +watch(appDetailsStep, () => { + schedulePersistOnboardingProgress() +}) + defineExpose({ persistOnboardingProgress, }) @@ -1844,20 +2132,41 @@ defineExpose({ {{ t('app-onboarding-step-details') }}

- {{ props.preOrg - ? t('app-onboarding-v2-details-title') - : t('app-onboarding-existing-question') }} + {{ appDetailsStep === 'name' + ? t('app-onboarding-name-step-title') + : appDetailsStep === 'app_id' + ? t('app-onboarding-app-id-step-title') + : t('app-onboarding-icon-step-title') }}

-

- {{ t('app-onboarding-v2-details-helper') }} +

+ {{ appDetailsStep === 'name' + ? t('app-onboarding-name-step-helper') + : appDetailsStep === 'app_id' + ? t('app-onboarding-app-id-step-helper') + : t('app-onboarding-icon-step-helper') }}

-
+
+
+
+

+ {{ appName.trim() || t('app-onboarding-preview-placeholder') }} +

+

+ {{ generatedAppId }} +

+
+ +
-
-
-

- {{ t('app-onboarding-start-question') }} -

-
- - -
-
- - -
- - +
-
+