diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index a0830fa94c51a..568a264b05e64 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -11629,15 +11629,34 @@ type PrepareOnboardingOnyxDataParams = { betas?: OnyxEntry; }; -function getBespokeWelcomeMessage(userReportedIntegration?: OnboardingAccounting): string { +function getBespokeWelcomeMessage(companySize: OnboardingCompanySize | undefined, userReportedIntegration?: OnboardingAccounting): string { // Use markdown (not HTML) because buildOptimisticAddCommentReportAction -> getParsedComment // escapes HTML entities before parsing, so raw HTML tags would render as literal text. - let message = - "# Your free trial has started! Let's get you set up.\n" + - "šŸ‘‹ Hey there! I'm your Expensify setup specialist. " + - 'For a small team like yours, the fastest way to get value is to set up a few expense categories, ' + - 'invite your team members, and have them start snapping receipts right away. ' + - "I'm here to walk you through each step — just ask!"; + const welcomeHeader = "# Your free trial has started! Let's get you set up.\nšŸ‘‹ Hey there! I'm your Expensify setup specialist. "; + + let message = welcomeHeader; + switch (companySize) { + case CONST.ONBOARDING_COMPANY_SIZE.MEDIUM: + case CONST.ONBOARDING_COMPANY_SIZE.LARGE: + message += + 'For an organization your size, the fastest path to value is setting up approval workflows, ' + + 'connecting your accounting software, and rolling out the Expensify Card to your team. ' + + "I'm here to walk you through each step — just ask!"; + break; + case CONST.ONBOARDING_COMPANY_SIZE.SMALL: + case CONST.ONBOARDING_COMPANY_SIZE.MEDIUM_SMALL: + message += + 'For a growing team like yours, the fastest way to get value is to set up expense categories, ' + + 'configure approval workflows, and invite your team members. ' + + "I'm here to walk you through each step — just ask!"; + break; + default: + message += + 'For a small team like yours, the fastest way to get value is to set up a few expense categories, ' + + 'invite your team members, and have them start snapping receipts right away. ' + + "I'm here to walk you through each step — just ask!"; + break; + } if (userReportedIntegration && userReportedIntegration !== 'other') { const friendlyName = CONST.ONBOARDING_ACCOUNTING_MAPPING[userReportedIntegration as keyof typeof CONST.ONBOARDING_ACCOUNTING_MAPPING]; @@ -11744,14 +11763,14 @@ function prepareOnboardingOnyxData({ reportComment: textComment.commentText, }; - // When the user is MICRO and using followups, generate a bespoke welcome message from Concierge. + // When using followups instead of tasks, generate a bespoke welcome message from Concierge. // The frontend displays it optimistically; the server uses it to generate suggested followups. let bespokeWelcomeMessage: string | undefined; let optimisticConciergeReportActionID: string | undefined; let bespokeAction: OptimisticReportAction | undefined; - if (shouldUseFollowupsInsteadOfTasks && companySize === CONST.ONBOARDING_COMPANY_SIZE.MICRO) { - bespokeWelcomeMessage = getBespokeWelcomeMessage(userReportedIntegration); + if (shouldUseFollowupsInsteadOfTasks) { + bespokeWelcomeMessage = getBespokeWelcomeMessage(companySize, userReportedIntegration); optimisticConciergeReportActionID = rand64(); bespokeAction = buildOptimisticAddCommentReportAction({ text: bespokeWelcomeMessage, diff --git a/tests/actions/PolicyTest.ts b/tests/actions/PolicyTest.ts index 92d6c8b33b535..9a52f3aceabb6 100644 --- a/tests/actions/PolicyTest.ts +++ b/tests/actions/PolicyTest.ts @@ -188,7 +188,7 @@ describe('actions/Policy', () => { // After filtering, two actions are added to the list =- signoff message (+1) and default create action (+1) const expectedReportActionsOfTypeCreatedCount = 1; - const expectedSignOffMessagesCount = 0; + const expectedSignOffMessagesCount = 1; expect(adminReportActions.length).toBe(expectedManageTeamDefaultTasksCount + expectedReportActionsOfTypeCreatedCount + expectedSignOffMessagesCount); let reportActionsOfTypeCreatedCount = 0; diff --git a/tests/unit/ReportUtilsTest.ts b/tests/unit/ReportUtilsTest.ts index ac34e40dec9e7..f8699b431e2e9 100644 --- a/tests/unit/ReportUtilsTest.ts +++ b/tests/unit/ReportUtilsTest.ts @@ -571,13 +571,123 @@ describe('ReportUtils', () => { companySize: CONST.ONBOARDING_COMPANY_SIZE.MICRO, }); expect(result?.guidedSetupData).toHaveLength(0); - // MICRO company size with suggestedFollowups beta adds a bespoke Concierge welcome action optimistically + // suggestedFollowups beta adds a bespoke Concierge welcome action optimistically for all company sizes const reportActionsEntries = result?.optimisticData.filter((i) => i.key === `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${adminsChatReportID}`); expect(reportActionsEntries).toHaveLength(1); - expect(result?.bespokeWelcomeMessage).toBeDefined(); + expect(result?.bespokeWelcomeMessage).toContain('For a small team like yours'); expect(result?.optimisticConciergeReportActionID).toBeDefined(); }); + it('should generate bespoke welcome message for SMALL company sizes with suggestedFollowups beta', async () => { + const adminsChatReportID = '1'; + await Onyx.merge(ONYXKEYS.SESSION, {email: 'test@example.com'}); + await Onyx.merge(ONYXKEYS.BETAS, [CONST.BETAS.SUGGESTED_FOLLOWUPS]); + await waitForBatchedUpdates(); + + const result = prepareOnboardingOnyxData({ + introSelected: undefined, + engagementChoice: CONST.ONBOARDING_CHOICES.MANAGE_TEAM, + onboardingMessage: { + message: 'This is a test', + tasks: [{type: CONST.ONBOARDING_TASK_TYPE.CONNECT_CORPORATE_CARD, title: () => '', description: () => '', autoCompleted: false}], + }, + adminsChatReportID, + selectedInterestedFeatures: ['areCompanyCardsEnabled'], + companySize: CONST.ONBOARDING_COMPANY_SIZE.SMALL, + }); + expect(result?.guidedSetupData).toHaveLength(0); + expect(result?.bespokeWelcomeMessage).toContain('growing team'); + expect(result?.optimisticConciergeReportActionID).toBeDefined(); + }); + + it('should generate bespoke welcome message for LARGE company sizes with suggestedFollowups beta', async () => { + const adminsChatReportID = '1'; + await Onyx.merge(ONYXKEYS.SESSION, {email: 'test@example.com'}); + await Onyx.merge(ONYXKEYS.BETAS, [CONST.BETAS.SUGGESTED_FOLLOWUPS]); + await waitForBatchedUpdates(); + + const result = prepareOnboardingOnyxData({ + introSelected: undefined, + engagementChoice: CONST.ONBOARDING_CHOICES.MANAGE_TEAM, + onboardingMessage: { + message: 'This is a test', + tasks: [{type: CONST.ONBOARDING_TASK_TYPE.CONNECT_CORPORATE_CARD, title: () => '', description: () => '', autoCompleted: false}], + }, + adminsChatReportID, + selectedInterestedFeatures: ['areCompanyCardsEnabled'], + companySize: CONST.ONBOARDING_COMPANY_SIZE.LARGE, + }); + expect(result?.guidedSetupData).toHaveLength(0); + expect(result?.bespokeWelcomeMessage).toContain('organization your size'); + expect(result?.optimisticConciergeReportActionID).toBeDefined(); + }); + + it('should generate bespoke welcome message for MEDIUM_SMALL company sizes with suggestedFollowups beta', async () => { + const adminsChatReportID = '1'; + await Onyx.merge(ONYXKEYS.SESSION, {email: 'test@example.com'}); + await Onyx.merge(ONYXKEYS.BETAS, [CONST.BETAS.SUGGESTED_FOLLOWUPS]); + await waitForBatchedUpdates(); + + const result = prepareOnboardingOnyxData({ + introSelected: undefined, + engagementChoice: CONST.ONBOARDING_CHOICES.MANAGE_TEAM, + onboardingMessage: { + message: 'This is a test', + tasks: [{type: CONST.ONBOARDING_TASK_TYPE.CONNECT_CORPORATE_CARD, title: () => '', description: () => '', autoCompleted: false}], + }, + adminsChatReportID, + selectedInterestedFeatures: ['areCompanyCardsEnabled'], + companySize: CONST.ONBOARDING_COMPANY_SIZE.MEDIUM_SMALL, + }); + expect(result?.guidedSetupData).toHaveLength(0); + expect(result?.bespokeWelcomeMessage).toContain('growing team'); + expect(result?.optimisticConciergeReportActionID).toBeDefined(); + }); + + it('should generate bespoke welcome message for MEDIUM company sizes with suggestedFollowups beta', async () => { + const adminsChatReportID = '1'; + await Onyx.merge(ONYXKEYS.SESSION, {email: 'test@example.com'}); + await Onyx.merge(ONYXKEYS.BETAS, [CONST.BETAS.SUGGESTED_FOLLOWUPS]); + await waitForBatchedUpdates(); + + const result = prepareOnboardingOnyxData({ + introSelected: undefined, + engagementChoice: CONST.ONBOARDING_CHOICES.MANAGE_TEAM, + onboardingMessage: { + message: 'This is a test', + tasks: [{type: CONST.ONBOARDING_TASK_TYPE.CONNECT_CORPORATE_CARD, title: () => '', description: () => '', autoCompleted: false}], + }, + adminsChatReportID, + selectedInterestedFeatures: ['areCompanyCardsEnabled'], + companySize: CONST.ONBOARDING_COMPANY_SIZE.MEDIUM, + }); + expect(result?.guidedSetupData).toHaveLength(0); + expect(result?.bespokeWelcomeMessage).toContain('organization your size'); + expect(result?.optimisticConciergeReportActionID).toBeDefined(); + }); + + it('should append accounting integration suffix to bespoke welcome message', async () => { + const adminsChatReportID = '1'; + await Onyx.merge(ONYXKEYS.SESSION, {email: 'test@example.com'}); + await Onyx.merge(ONYXKEYS.BETAS, [CONST.BETAS.SUGGESTED_FOLLOWUPS]); + await waitForBatchedUpdates(); + + const result = prepareOnboardingOnyxData({ + introSelected: undefined, + engagementChoice: CONST.ONBOARDING_CHOICES.MANAGE_TEAM, + onboardingMessage: { + message: 'This is a test', + tasks: [{type: CONST.ONBOARDING_TASK_TYPE.CONNECT_CORPORATE_CARD, title: () => '', description: () => '', autoCompleted: false}], + }, + adminsChatReportID, + selectedInterestedFeatures: ['areCompanyCardsEnabled'], + companySize: CONST.ONBOARDING_COMPANY_SIZE.SMALL, + userReportedIntegration: 'quickbooksOnline', + }); + expect(result?.bespokeWelcomeMessage).toContain('QuickBooks Online'); + expect(result?.bespokeWelcomeMessage).toContain('expenses sync automatically'); + }); + it('should add guidedSetupData when posting into admin room WITHOUT suggestedFollowups beta', async () => { const adminsChatReportID = '1'; // Not having `+` in the email allows for `isPostingTasksInAdminsRoom` flow