diff --git a/src/components/SettlementButton/index.tsx b/src/components/SettlementButton/index.tsx index 809e87a92d6b..234b810d7aa4 100644 --- a/src/components/SettlementButton/index.tsx +++ b/src/components/SettlementButton/index.tsx @@ -1,4 +1,5 @@ import {isUserValidatedSelector} from '@selectors/Account'; +import {hasSeenTourSelector} from '@selectors/Onboarding'; import isEmpty from 'lodash/isEmpty'; import truncate from 'lodash/truncate'; import React, {useCallback, useContext, useMemo} from 'react'; @@ -152,6 +153,8 @@ function SettlementButton({ const hasIntentToPay = ((formattedPaymentMethods.length === 1 && isIOUReport(iouReport)) || policy?.achAccount?.state === CONST.BANK_ACCOUNT.STATE.OPEN) && !lastPaymentMethod; const {isBetaEnabled} = usePermissions(); const [introSelected] = useOnyx(ONYXKEYS.NVP_INTRO_SELECTED); + const [isSelfTourViewed] = useOnyx(ONYXKEYS.NVP_ONBOARDING, {selector: hasSeenTourSelector}); + const currentUserPersonalDetails = useCurrentUserPersonalDetails(); const [transactionViolations] = useOnyx(ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS); const isASAPSubmitBetaEnabled = isBetaEnabled(CONST.BETAS.ASAP_SUBMIT); @@ -368,6 +371,7 @@ function SettlementButton({ activePolicyID, currentUserAccountIDParam: currentUserPersonalDetails.accountID, currentUserEmailParam: currentUserPersonalDetails.email ?? '', + isSelfTourViewed, }).policyID; }; const addBankAccountItem = { diff --git a/src/libs/Navigation/AppNavigator/AuthScreens.tsx b/src/libs/Navigation/AppNavigator/AuthScreens.tsx index 76c7fd09ca02..32711517ac08 100644 --- a/src/libs/Navigation/AppNavigator/AuthScreens.tsx +++ b/src/libs/Navigation/AppNavigator/AuthScreens.tsx @@ -1,6 +1,7 @@ import type {RouteProp} from '@react-navigation/native'; import {useNavigationState} from '@react-navigation/native'; import type {StackCardInterpolationProps} from '@react-navigation/stack'; +import {hasSeenTourSelector} from '@selectors/Onboarding'; import React, {memo, useEffect, useRef, useState} from 'react'; import ComposeProviders from '@components/ComposeProviders'; import OpenConfirmNavigateExpensifyClassicModal from '@components/ConfirmNavigateExpensifyClassicModal'; @@ -178,6 +179,7 @@ function AuthScreens() { const [initialLastUpdateIDAppliedToClient] = useOnyx(ONYXKEYS.ONYX_UPDATES_LAST_UPDATE_ID_APPLIED_TO_CLIENT); const [modal] = useOnyx(ONYXKEYS.MODAL); const [activePolicyID] = useOnyx(ONYXKEYS.NVP_ACTIVE_POLICY_ID); + const [isSelfTourViewed] = useOnyx(ONYXKEYS.NVP_ONBOARDING, {selector: hasSeenTourSelector}); const [lastUpdateIDAppliedToClient] = useOnyx(ONYXKEYS.ONYX_UPDATES_LAST_UPDATE_ID_APPLIED_TO_CLIENT); const [isLoadingApp] = useOnyx(ONYXKEYS.IS_LOADING_APP); @@ -280,7 +282,7 @@ function AuthScreens() { App.reconnectApp(initialLastUpdateIDAppliedToClient); } - App.setUpPoliciesAndNavigate(session, introSelected, activePolicyID); + App.setUpPoliciesAndNavigate(session, introSelected, activePolicyID, isSelfTourViewed); Download.clearDownloads(); diff --git a/src/libs/actions/App.ts b/src/libs/actions/App.ts index 954b737f559e..0ad5f063b59e 100644 --- a/src/libs/actions/App.ts +++ b/src/libs/actions/App.ts @@ -536,6 +536,7 @@ function getMissingOnyxUpdates(updateIDFrom = 0, updateIDTo: number | string = 0 } type CreateWorkspaceWithPolicyDraftParams = { + isSelfTourViewed: boolean | undefined; introSelected: OnyxEntry; policyOwnerEmail?: string; policyName?: string; @@ -573,6 +574,7 @@ function createWorkspaceWithPolicyDraftAndNavigateToIt(params: CreateWorkspaceWi currentUserAccountIDParam, currentUserEmailParam, shouldCreateControlPolicy, + isSelfTourViewed, } = params; const policyIDWithDefault = policyID || generatePolicyID(); @@ -597,12 +599,14 @@ function createWorkspaceWithPolicyDraftAndNavigateToIt(params: CreateWorkspaceWi currentUserEmailParam, allReportsParam: allReports, shouldCreateControlPolicy, + isSelfTourViewed, }); Navigation.navigate(routeToNavigate, {forceReplace: !transitionFromOldDot}); }); } type SavePolicyDraftByNewWorkspaceParams = { + isSelfTourViewed: boolean | undefined; policyID?: string; policyName?: string; policyOwnerEmail?: string; @@ -635,6 +639,7 @@ function savePolicyDraftByNewWorkspace({ currentUserEmailParam, allReportsParam, shouldCreateControlPolicy, + isSelfTourViewed, }: SavePolicyDraftByNewWorkspaceParams) { createWorkspace({ policyOwnerEmail, @@ -651,6 +656,7 @@ function savePolicyDraftByNewWorkspace({ currentUserEmailParam, allReportsParam, shouldCreateControlPolicy, + isSelfTourViewed, }); } @@ -669,7 +675,12 @@ function savePolicyDraftByNewWorkspace({ * When the exitTo route is 'workspace/new', we create a new * workspace and navigate to it */ -function setUpPoliciesAndNavigate(session: OnyxEntry, introSelected: OnyxEntry, activePolicyID: string | undefined) { +function setUpPoliciesAndNavigate( + session: OnyxEntry, + introSelected: OnyxEntry, + activePolicyID: string | undefined, + isSelfTourViewed: boolean | undefined, +) { const currentUrl = getCurrentUrl(); if (!session || !currentUrl?.includes('exitTo')) { return; @@ -699,6 +710,7 @@ function setUpPoliciesAndNavigate(session: OnyxEntry, introSe activePolicyID, currentUserAccountIDParam: currentSessionData.accountID ?? CONST.DEFAULT_NUMBER_ID, currentUserEmailParam: currentSessionData.email ?? '', + isSelfTourViewed, }); return; } diff --git a/src/libs/actions/Policy/Policy.ts b/src/libs/actions/Policy/Policy.ts index 55caf0ffd98d..c007f58f62d5 100644 --- a/src/libs/actions/Policy/Policy.ts +++ b/src/libs/actions/Policy/Policy.ts @@ -193,6 +193,13 @@ type BuildPolicyDataOptions = { onboardingPurposeSelected?: OnboardingPurpose; shouldAddGuideWelcomeMessage?: boolean; shouldCreateControlPolicy?: boolean; + // TODO: Make it required once we complete refactoring the buildPolicyData function to use isSelfTourViewed. Refactor issue: https://github.com/Expensify/App/issues/66424 + isSelfTourViewed?: boolean; +}; + +// TODO: Remove this type once we complete refactoring the buildPolicyData function to use isSelfTourViewed. Refactor issue: https://github.com/Expensify/App/issues/66424 +type CreateWorkspaceDataOptions = Omit & { + isSelfTourViewed: boolean | undefined; }; type DuplicatePolicyDataOptions = { @@ -2291,6 +2298,7 @@ function buildPolicyData(options: BuildPolicyDataOptions): OnyxData { @@ -37,6 +40,7 @@ function WorkspaceConfirmationForTravelPage({route}: WorkspaceConfirmationForTra activePolicyID, currentUserAccountIDParam: currentUserPersonalDetails.accountID, currentUserEmailParam: currentUserPersonalDetails.email ?? '', + isSelfTourViewed, }); goBack(); }; diff --git a/src/pages/iou/request/step/IOURequestStepUpgrade.tsx b/src/pages/iou/request/step/IOURequestStepUpgrade.tsx index 24dea12765bc..0709ec9f0c91 100644 --- a/src/pages/iou/request/step/IOURequestStepUpgrade.tsx +++ b/src/pages/iou/request/step/IOURequestStepUpgrade.tsx @@ -1,3 +1,4 @@ +import {hasSeenTourSelector} from '@selectors/Onboarding'; import React, {useRef, useState} from 'react'; import ConfirmModal from '@components/ConfirmModal'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; @@ -59,6 +60,7 @@ function IOURequestStepUpgrade({ const {isRestrictedPolicyCreation} = usePreferredPolicy(); const [introSelected] = useOnyx(ONYXKEYS.NVP_INTRO_SELECTED); const [activePolicyID] = useOnyx(ONYXKEYS.NVP_ACTIVE_POLICY_ID); + const [isSelfTourViewed] = useOnyx(ONYXKEYS.NVP_ONBOARDING, {selector: hasSeenTourSelector}); const feature = Object.values(CONST.UPGRADE_FEATURE_INTRO_MAPPING) .filter((value) => value.id !== CONST.UPGRADE_FEATURE_INTRO_MAPPING.policyPreventMemberChangingTitle.id) @@ -157,6 +159,7 @@ function IOURequestStepUpgrade({ currentUserAccountIDParam: currentUserPersonalDetails.accountID, currentUserEmailParam: currentUserPersonalDetails.email ?? '', onboardingPurposeSelected, + isSelfTourViewed, }); setIsUpgraded(true); policyDataRef.current = policyData; @@ -182,6 +185,7 @@ function IOURequestStepUpgrade({ currentUserAccountIDParam: currentUserPersonalDetails.accountID, currentUserEmailParam: currentUserPersonalDetails.email ?? '', onboardingPurposeSelected, + isSelfTourViewed, }); policyDataRef.current = policyData; setCreatedPolicyName(params.name); diff --git a/src/pages/workspace/WorkspaceConfirmationPage.tsx b/src/pages/workspace/WorkspaceConfirmationPage.tsx index 9618bf489fda..8dbac35e9f76 100644 --- a/src/pages/workspace/WorkspaceConfirmationPage.tsx +++ b/src/pages/workspace/WorkspaceConfirmationPage.tsx @@ -1,3 +1,4 @@ +import {hasSeenTourSelector} from '@selectors/Onboarding'; import React from 'react'; import ScreenWrapper from '@components/ScreenWrapper'; import WorkspaceConfirmationForm from '@components/WorkspaceConfirmationForm'; @@ -22,6 +23,8 @@ function WorkspaceConfirmationPage() { const [lastPaymentMethod] = useOnyx(ONYXKEYS.NVP_LAST_PAYMENT_METHOD); const [activePolicyID] = useOnyx(ONYXKEYS.NVP_ACTIVE_POLICY_ID); const [introSelected] = useOnyx(ONYXKEYS.NVP_INTRO_SELECTED); + const [isSelfTourViewed] = useOnyx(ONYXKEYS.NVP_ONBOARDING, {selector: hasSeenTourSelector}); + const currentUserPersonalDetails = useCurrentUserPersonalDetails(); const privateSubscription = usePrivateSubscription(); const onSubmit = (params: WorkspaceConfirmationSubmitFunctionParams) => { @@ -43,6 +46,7 @@ function WorkspaceConfirmationPage() { currentUserAccountIDParam: currentUserPersonalDetails.accountID, currentUserEmailParam: currentUserPersonalDetails.email ?? '', shouldCreateControlPolicy: isSubscriptionTypeOfInvoicing(privateSubscription?.type), + isSelfTourViewed, }); }; const currentUrl = getCurrentUrl(); diff --git a/tests/actions/IOUTest.ts b/tests/actions/IOUTest.ts index 92a3c04f51cc..f1e753d62431 100644 --- a/tests/actions/IOUTest.ts +++ b/tests/actions/IOUTest.ts @@ -6316,6 +6316,7 @@ describe('actions/IOU', () => { introSelected: {choice: CONST.ONBOARDING_CHOICES.MANAGE_TEAM}, currentUserAccountIDParam: CARLOS_ACCOUNT_ID, currentUserEmailParam: CARLOS_EMAIL, + isSelfTourViewed: false, }); return waitForBatchedUpdates(); }) @@ -6469,6 +6470,7 @@ describe('actions/IOU', () => { introSelected: {choice: CONST.ONBOARDING_CHOICES.MANAGE_TEAM}, currentUserAccountIDParam: CARLOS_ACCOUNT_ID, currentUserEmailParam: CARLOS_EMAIL, + isSelfTourViewed: false, }); return waitForBatchedUpdates(); }) @@ -6829,6 +6831,7 @@ describe('actions/IOU', () => { introSelected: {choice: CONST.ONBOARDING_CHOICES.MANAGE_TEAM}, currentUserAccountIDParam: CARLOS_ACCOUNT_ID, currentUserEmailParam: CARLOS_EMAIL, + isSelfTourViewed: false, }); return waitForBatchedUpdates(); }) @@ -8765,6 +8768,7 @@ describe('actions/IOU', () => { introSelected: {choice: CONST.ONBOARDING_CHOICES.MANAGE_TEAM}, currentUserAccountIDParam: CARLOS_ACCOUNT_ID, currentUserEmailParam: CARLOS_EMAIL, + isSelfTourViewed: false, }); // Change the approval mode for the policy since default is Submit and Close @@ -8896,6 +8900,7 @@ describe('actions/IOU', () => { introSelected: {choice: CONST.ONBOARDING_CHOICES.MANAGE_TEAM}, currentUserAccountIDParam: CARLOS_ACCOUNT_ID, currentUserEmailParam: CARLOS_EMAIL, + isSelfTourViewed: false, }); setWorkspaceApprovalMode(policyID, CARLOS_EMAIL, CONST.POLICY.APPROVAL_MODE.BASIC); @@ -8972,6 +8977,7 @@ describe('actions/IOU', () => { introSelected: {choice: CONST.ONBOARDING_CHOICES.MANAGE_TEAM}, currentUserAccountIDParam: CARLOS_ACCOUNT_ID, currentUserEmailParam: CARLOS_EMAIL, + isSelfTourViewed: false, }); return waitForBatchedUpdates(); }) @@ -9224,6 +9230,7 @@ describe('actions/IOU', () => { introSelected: {choice: CONST.ONBOARDING_CHOICES.MANAGE_TEAM}, currentUserAccountIDParam: CARLOS_ACCOUNT_ID, currentUserEmailParam: CARLOS_EMAIL, + isSelfTourViewed: false, }); return waitForBatchedUpdates(); }) @@ -9426,6 +9433,7 @@ describe('actions/IOU', () => { introSelected: undefined, currentUserAccountIDParam: CARLOS_ACCOUNT_ID, currentUserEmailParam: CARLOS_EMAIL, + isSelfTourViewed: false, }); return waitForBatchedUpdates() .then(() => { @@ -11058,6 +11066,7 @@ describe('actions/IOU', () => { introSelected: {choice: CONST.ONBOARDING_CHOICES.MANAGE_TEAM}, currentUserAccountIDParam: CARLOS_ACCOUNT_ID, currentUserEmailParam: CARLOS_EMAIL, + isSelfTourViewed: false, }); await waitForBatchedUpdates(); @@ -11156,6 +11165,7 @@ describe('actions/IOU', () => { currentUserAccountIDParam: CARLOS_ACCOUNT_ID, currentUserEmailParam: CARLOS_EMAIL, activePolicyID: '123', + isSelfTourViewed: false, }); await waitForBatchedUpdates(); @@ -11528,6 +11538,7 @@ describe('actions/IOU', () => { introSelected: {choice: CONST.ONBOARDING_CHOICES.MANAGE_TEAM}, currentUserAccountIDParam: CARLOS_ACCOUNT_ID, currentUserEmailParam: CARLOS_EMAIL, + isSelfTourViewed: false, }); // Change the approval mode for the policy since default is Submit and Close @@ -11690,6 +11701,7 @@ describe('actions/IOU', () => { introSelected: {choice: CONST.ONBOARDING_CHOICES.MANAGE_TEAM}, currentUserAccountIDParam: RORY_ACCOUNT_ID, currentUserEmailParam: RORY_EMAIL, + isSelfTourViewed: false, }); // Change the approval mode for the policy since default is Submit and Close @@ -11856,6 +11868,7 @@ describe('actions/IOU', () => { introSelected: {choice: CONST.ONBOARDING_CHOICES.MANAGE_TEAM}, currentUserAccountIDParam: CARLOS_ACCOUNT_ID, currentUserEmailParam: CARLOS_EMAIL, + isSelfTourViewed: false, }); setWorkspaceApprovalMode(policyID, CARLOS_EMAIL, CONST.POLICY.APPROVAL_MODE.BASIC); @@ -12031,6 +12044,7 @@ describe('actions/IOU', () => { introSelected: {choice: CONST.ONBOARDING_CHOICES.MANAGE_TEAM}, currentUserAccountIDParam: CARLOS_ACCOUNT_ID, currentUserEmailParam: CARLOS_EMAIL, + isSelfTourViewed: false, }); // Change the approval mode for the policy since default is Submit and Close diff --git a/tests/actions/IOUTest/SplitTest.ts b/tests/actions/IOUTest/SplitTest.ts index 0e95917164ee..97a0802f2c44 100644 --- a/tests/actions/IOUTest/SplitTest.ts +++ b/tests/actions/IOUTest/SplitTest.ts @@ -1624,6 +1624,7 @@ describe('updateSplitTransactionsFromSplitExpensesFlow', () => { introSelected: {choice: CONST.ONBOARDING_CHOICES.MANAGE_TEAM}, currentUserAccountIDParam: CARLOS_ACCOUNT_ID, currentUserEmailParam: CARLOS_EMAIL, + isSelfTourViewed: false, }); setWorkspaceApprovalMode(policyID, CARLOS_EMAIL, CONST.POLICY.APPROVAL_MODE.BASIC); await waitForBatchedUpdates(); @@ -1827,6 +1828,7 @@ describe('updateSplitTransactionsFromSplitExpensesFlow', () => { introSelected: {choice: CONST.ONBOARDING_CHOICES.MANAGE_TEAM}, currentUserAccountIDParam: CARLOS_ACCOUNT_ID, currentUserEmailParam: CARLOS_EMAIL, + isSelfTourViewed: false, }); // Change the approval mode for the policy since default is Submit and Close @@ -1989,6 +1991,7 @@ describe('updateSplitTransactionsFromSplitExpensesFlow', () => { introSelected: {choice: CONST.ONBOARDING_CHOICES.MANAGE_TEAM}, currentUserAccountIDParam: RORY_ACCOUNT_ID, currentUserEmailParam: RORY_EMAIL, + isSelfTourViewed: false, }); // Change the approval mode for the policy since default is Submit and Close @@ -2155,6 +2158,7 @@ describe('updateSplitTransactionsFromSplitExpensesFlow', () => { introSelected: {choice: CONST.ONBOARDING_CHOICES.MANAGE_TEAM}, currentUserAccountIDParam: CARLOS_ACCOUNT_ID, currentUserEmailParam: CARLOS_EMAIL, + isSelfTourViewed: false, }); setWorkspaceApprovalMode(policyID, CARLOS_EMAIL, CONST.POLICY.APPROVAL_MODE.BASIC); @@ -2330,6 +2334,7 @@ describe('updateSplitTransactionsFromSplitExpensesFlow', () => { introSelected: {choice: CONST.ONBOARDING_CHOICES.MANAGE_TEAM}, currentUserAccountIDParam: CARLOS_ACCOUNT_ID, currentUserEmailParam: CARLOS_EMAIL, + isSelfTourViewed: false, }); // Change the approval mode for the policy since default is Submit and Close diff --git a/tests/actions/PolicyTest.ts b/tests/actions/PolicyTest.ts index c6968414b89f..a3fddd754a41 100644 --- a/tests/actions/PolicyTest.ts +++ b/tests/actions/PolicyTest.ts @@ -80,6 +80,7 @@ describe('actions/Policy', () => { introSelected: {choice: CONST.ONBOARDING_CHOICES.MANAGE_TEAM}, currentUserAccountIDParam: ESH_ACCOUNT_ID, currentUserEmailParam: ESH_EMAIL, + isSelfTourViewed: false, }); await waitForBatchedUpdates(); @@ -522,6 +523,7 @@ describe('actions/Policy', () => { introSelected: {choice: CONST.ONBOARDING_CHOICES.MANAGE_TEAM}, currentUserAccountIDParam: ESH_ACCOUNT_ID, currentUserEmailParam: ESH_EMAIL, + isSelfTourViewed: false, }); await waitForBatchedUpdates(); @@ -551,6 +553,7 @@ describe('actions/Policy', () => { introSelected: {choice: CONST.ONBOARDING_CHOICES.TRACK_WORKSPACE}, currentUserAccountIDParam: ESH_ACCOUNT_ID, currentUserEmailParam: ESH_EMAIL, + isSelfTourViewed: false, }); await waitForBatchedUpdates(); @@ -584,6 +587,7 @@ describe('actions/Policy', () => { introSelected: {choice: CONST.ONBOARDING_CHOICES.LOOKING_AROUND}, currentUserAccountIDParam: ESH_ACCOUNT_ID, currentUserEmailParam: ESH_EMAIL, + isSelfTourViewed: false, }); await waitForBatchedUpdates(); @@ -613,6 +617,7 @@ describe('actions/Policy', () => { introSelected: {choice: CONST.ONBOARDING_CHOICES.MANAGE_TEAM}, currentUserAccountIDParam: ESH_ACCOUNT_ID, currentUserEmailParam: ESH_EMAIL, + isSelfTourViewed: false, }); await waitForBatchedUpdates(); @@ -639,6 +644,7 @@ describe('actions/Policy', () => { introSelected: {choice: CONST.ONBOARDING_CHOICES.MANAGE_TEAM}, currentUserAccountIDParam: ESH_ACCOUNT_ID, currentUserEmailParam: ESH_EMAIL, + isSelfTourViewed: false, }); await waitForBatchedUpdates(); @@ -666,6 +672,7 @@ describe('actions/Policy', () => { introSelected: {choice: CONST.ONBOARDING_CHOICES.MANAGE_TEAM}, currentUserAccountIDParam: ESH_ACCOUNT_ID, currentUserEmailParam: ESH_EMAIL, + isSelfTourViewed: false, }); await waitForBatchedUpdates(); @@ -691,6 +698,7 @@ describe('actions/Policy', () => { introSelected: {choice: CONST.ONBOARDING_CHOICES.LOOKING_AROUND}, currentUserAccountIDParam: ESH_ACCOUNT_ID, currentUserEmailParam: ESH_EMAIL, + isSelfTourViewed: false, }); await waitForBatchedUpdates(); @@ -716,6 +724,7 @@ describe('actions/Policy', () => { introSelected: {choice: CONST.ONBOARDING_CHOICES.TRACK_WORKSPACE}, currentUserAccountIDParam: ESH_ACCOUNT_ID, currentUserEmailParam: ESH_EMAIL, + isSelfTourViewed: false, }); await waitForBatchedUpdates(); @@ -741,6 +750,7 @@ describe('actions/Policy', () => { introSelected: {choice: CONST.ONBOARDING_CHOICES.EMPLOYER}, currentUserAccountIDParam: ESH_ACCOUNT_ID, currentUserEmailParam: ESH_EMAIL, + isSelfTourViewed: false, }); await waitForBatchedUpdates(); @@ -766,6 +776,7 @@ describe('actions/Policy', () => { introSelected: {choice: CONST.ONBOARDING_CHOICES.CHAT_SPLIT}, currentUserAccountIDParam: ESH_ACCOUNT_ID, currentUserEmailParam: ESH_EMAIL, + isSelfTourViewed: false, }); await waitForBatchedUpdates(); @@ -803,6 +814,7 @@ describe('actions/Policy', () => { introSelected: {choice: CONST.ONBOARDING_CHOICES.TRACK_WORKSPACE}, currentUserAccountIDParam: ESH_ACCOUNT_ID, currentUserEmailParam: ESH_EMAIL, + isSelfTourViewed: false, }); await waitForBatchedUpdates(); @@ -817,6 +829,225 @@ describe('actions/Policy', () => { apiWriteSpy.mockRestore(); }); + + it('should pass isSelfTourViewed as true when creating workspace with selfTourViewed flag', async () => { + await Onyx.set(ONYXKEYS.SESSION, {email: ESH_EMAIL, accountID: ESH_ACCOUNT_ID}); + await waitForBatchedUpdates(); + + const apiWriteSpy = jest.spyOn(require('@libs/API'), 'write').mockImplementation(() => Promise.resolve()); + const policyID = Policy.generatePolicyID(); + + // When creating a workspace with isSelfTourViewed set to true + Policy.createWorkspace({ + policyOwnerEmail: ESH_EMAIL, + makeMeAdmin: true, + policyName: WORKSPACE_NAME, + policyID, + engagementChoice: CONST.ONBOARDING_CHOICES.MANAGE_TEAM, + introSelected: {choice: CONST.ONBOARDING_CHOICES.MANAGE_TEAM}, + currentUserAccountIDParam: ESH_ACCOUNT_ID, + currentUserEmailParam: ESH_EMAIL, + isSelfTourViewed: true, + }); + await waitForBatchedUpdates(); + + // Then API.write should be called with CREATE_WORKSPACE command + expect(apiWriteSpy).toHaveBeenCalledWith( + WRITE_COMMANDS.CREATE_WORKSPACE, + expect.objectContaining({ + policyID, + }), + expect.anything(), + ); + + apiWriteSpy.mockRestore(); + }); + + it('should pass isSelfTourViewed as false when creating workspace without selfTourViewed flag', async () => { + await Onyx.set(ONYXKEYS.SESSION, {email: ESH_EMAIL, accountID: ESH_ACCOUNT_ID}); + await waitForBatchedUpdates(); + + const apiWriteSpy = jest.spyOn(require('@libs/API'), 'write').mockImplementation(() => Promise.resolve()); + const policyID = Policy.generatePolicyID(); + + // When creating a workspace with isSelfTourViewed set to false + Policy.createWorkspace({ + policyOwnerEmail: ESH_EMAIL, + makeMeAdmin: true, + policyName: WORKSPACE_NAME, + policyID, + engagementChoice: CONST.ONBOARDING_CHOICES.MANAGE_TEAM, + introSelected: {choice: CONST.ONBOARDING_CHOICES.MANAGE_TEAM}, + currentUserAccountIDParam: ESH_ACCOUNT_ID, + currentUserEmailParam: ESH_EMAIL, + isSelfTourViewed: false, + }); + await waitForBatchedUpdates(); + + // Then API.write should be called with CREATE_WORKSPACE command + expect(apiWriteSpy).toHaveBeenCalledWith( + WRITE_COMMANDS.CREATE_WORKSPACE, + expect.objectContaining({ + policyID, + }), + expect.anything(), + ); + + apiWriteSpy.mockRestore(); + }); + + it('should mark VIEW_TOUR task as completed in guidedSetupData when isSelfTourViewed is true', async () => { + await Onyx.set(ONYXKEYS.SESSION, {email: ESH_EMAIL, accountID: ESH_ACCOUNT_ID}); + await waitForBatchedUpdates(); + + const apiWriteSpy = jest.spyOn(require('@libs/API'), 'write').mockImplementation(() => Promise.resolve()); + const policyID = Policy.generatePolicyID(); + + // When creating a workspace with isSelfTourViewed set to true + // Use LOOKING_AROUND as introSelected.choice to ensure VIEW_TOUR task is included + // (VIEW_TOUR is filtered out when both introSelected.choice and engagementChoice are MANAGE_TEAM) + Policy.createWorkspace({ + policyOwnerEmail: ESH_EMAIL, + makeMeAdmin: true, + policyName: WORKSPACE_NAME, + policyID, + engagementChoice: CONST.ONBOARDING_CHOICES.MANAGE_TEAM, + introSelected: {choice: CONST.ONBOARDING_CHOICES.LOOKING_AROUND}, + currentUserAccountIDParam: ESH_ACCOUNT_ID, + currentUserEmailParam: ESH_EMAIL, + isSelfTourViewed: true, + }); + await waitForBatchedUpdates(); + + // Extract the guidedSetupData from the API call + const apiCallArgs = apiWriteSpy.mock.calls.find((call) => call.at(0) === WRITE_COMMANDS.CREATE_WORKSPACE); + expect(apiCallArgs).toBeDefined(); + const params = apiCallArgs?.[1] as {guidedSetupData?: string}; + expect(params.guidedSetupData).toBeDefined(); + + // Parse the guidedSetupData and find the VIEW_TOUR task + type GuidedSetupItem = {task?: string; completedTaskReportActionID?: string}; + const guidedSetupData = JSON.parse(params.guidedSetupData ?? '[]') as GuidedSetupItem[]; + const viewTourTask = guidedSetupData.find((item) => item.task === CONST.ONBOARDING_TASK_TYPE.VIEW_TOUR); + + // VIEW_TOUR task should have completedTaskReportActionID set when isSelfTourViewed is true + expect(viewTourTask).toBeDefined(); + expect(viewTourTask?.completedTaskReportActionID).toBeDefined(); + + apiWriteSpy.mockRestore(); + }); + + it('should not mark VIEW_TOUR task as completed in guidedSetupData when isSelfTourViewed is false', async () => { + await Onyx.set(ONYXKEYS.SESSION, {email: ESH_EMAIL, accountID: ESH_ACCOUNT_ID}); + await waitForBatchedUpdates(); + + const apiWriteSpy = jest.spyOn(require('@libs/API'), 'write').mockImplementation(() => Promise.resolve()); + const policyID = Policy.generatePolicyID(); + + // When creating a workspace with isSelfTourViewed set to false + // Use LOOKING_AROUND as introSelected.choice to ensure VIEW_TOUR task is included + Policy.createWorkspace({ + policyOwnerEmail: ESH_EMAIL, + makeMeAdmin: true, + policyName: WORKSPACE_NAME, + policyID, + engagementChoice: CONST.ONBOARDING_CHOICES.MANAGE_TEAM, + introSelected: {choice: CONST.ONBOARDING_CHOICES.LOOKING_AROUND}, + currentUserAccountIDParam: ESH_ACCOUNT_ID, + currentUserEmailParam: ESH_EMAIL, + isSelfTourViewed: false, + }); + await waitForBatchedUpdates(); + + // Extract the guidedSetupData from the API call + const apiCallArgs = apiWriteSpy.mock.calls.find((call) => call.at(0) === WRITE_COMMANDS.CREATE_WORKSPACE); + expect(apiCallArgs).toBeDefined(); + const params = apiCallArgs?.[1] as {guidedSetupData?: string}; + expect(params.guidedSetupData).toBeDefined(); + + // Parse the guidedSetupData and find the VIEW_TOUR task + type GuidedSetupItem = {task?: string; completedTaskReportActionID?: string}; + const guidedSetupData = JSON.parse(params.guidedSetupData ?? '[]') as GuidedSetupItem[]; + const viewTourTask = guidedSetupData.find((item) => item.task === CONST.ONBOARDING_TASK_TYPE.VIEW_TOUR); + + // VIEW_TOUR task should NOT have completedTaskReportActionID set when isSelfTourViewed is false + expect(viewTourTask).toBeDefined(); + expect(viewTourTask?.completedTaskReportActionID).toBeUndefined(); + + apiWriteSpy.mockRestore(); + }); + + it('should include memberData when adminParticipant is provided', async () => { + await Onyx.set(ONYXKEYS.SESSION, {email: ESH_EMAIL, accountID: ESH_ACCOUNT_ID}); + await waitForBatchedUpdates(); + + const apiWriteSpy = jest.spyOn(require('@libs/API'), 'write').mockImplementation(() => Promise.resolve()); + const policyID = Policy.generatePolicyID(); + const adminEmail = 'admin@example.com'; + const adminAccountID = 999; + + // When creating a workspace with an adminParticipant + Policy.createWorkspace({ + policyOwnerEmail: ESH_EMAIL, + makeMeAdmin: true, + policyName: WORKSPACE_NAME, + policyID, + engagementChoice: CONST.ONBOARDING_CHOICES.MANAGE_TEAM, + introSelected: {choice: CONST.ONBOARDING_CHOICES.MANAGE_TEAM}, + currentUserAccountIDParam: ESH_ACCOUNT_ID, + currentUserEmailParam: ESH_EMAIL, + isSelfTourViewed: false, + adminParticipant: {login: adminEmail, accountID: adminAccountID}, + }); + await waitForBatchedUpdates(); + + // Then API.write should be called with CREATE_WORKSPACE command + const apiCallArgs = apiWriteSpy.mock.calls.find((call) => call.at(0) === WRITE_COMMANDS.CREATE_WORKSPACE); + expect(apiCallArgs).toBeDefined(); + const params = apiCallArgs?.[1] as {memberData?: string; policyID?: string}; + expect(params.policyID).toBe(policyID); + expect(params.memberData).toBeDefined(); + const memberData = JSON.parse(params.memberData ?? '{}') as {accountID: number; email: string; role: string}; + expect(memberData.accountID).toBe(adminAccountID); + expect(memberData.email).toBe(adminEmail); + expect(memberData.role).toBe(CONST.POLICY.ROLE.ADMIN); + + apiWriteSpy.mockRestore(); + }); + + it('should handle TEST_DRIVE_RECEIVER intro choice with createWorkspace task', async () => { + await Onyx.set(ONYXKEYS.SESSION, {email: ESH_EMAIL, accountID: ESH_ACCOUNT_ID}); + await waitForBatchedUpdates(); + + const apiWriteSpy = jest.spyOn(require('@libs/API'), 'write').mockImplementation(() => Promise.resolve()); + const policyID = Policy.generatePolicyID(); + const createWorkspaceTaskReportID = 'testTaskReportID123'; + + // When creating a workspace with TEST_DRIVE_RECEIVER choice and createWorkspace task + Policy.createWorkspace({ + policyOwnerEmail: ESH_EMAIL, + makeMeAdmin: true, + policyName: WORKSPACE_NAME, + policyID, + engagementChoice: CONST.ONBOARDING_CHOICES.MANAGE_TEAM, + introSelected: {choice: CONST.ONBOARDING_CHOICES.TEST_DRIVE_RECEIVER, createWorkspace: createWorkspaceTaskReportID}, + currentUserAccountIDParam: ESH_ACCOUNT_ID, + currentUserEmailParam: ESH_EMAIL, + isSelfTourViewed: false, + }); + await waitForBatchedUpdates(); + + // Then API.write should be called with CREATE_WORKSPACE command + expect(apiWriteSpy).toHaveBeenCalledWith( + WRITE_COMMANDS.CREATE_WORKSPACE, + expect.objectContaining({ + policyID, + }), + expect.anything(), + ); + + apiWriteSpy.mockRestore(); + }); }); describe('leaveWorkspace', () => { diff --git a/tests/unit/GoogleTagManagerTest.tsx b/tests/unit/GoogleTagManagerTest.tsx index bea017dd65de..57a5edcdb953 100644 --- a/tests/unit/GoogleTagManagerTest.tsx +++ b/tests/unit/GoogleTagManagerTest.tsx @@ -157,11 +157,11 @@ describe('GoogleTagManagerTest', () => { test('workspace_created', async () => { // When we run the createWorkspace action a few times - createWorkspace({introSelected: undefined, currentUserAccountIDParam: 123456, activePolicyID: undefined, currentUserEmailParam: 'test@test.com'}); + createWorkspace({introSelected: undefined, currentUserAccountIDParam: 123456, activePolicyID: undefined, currentUserEmailParam: 'test@test.com', isSelfTourViewed: false}); await waitForBatchedUpdatesWithAct(); - createWorkspace({currentUserAccountIDParam: 123456, activePolicyID: undefined, currentUserEmailParam: 'test@test.com', introSelected: undefined}); + createWorkspace({currentUserAccountIDParam: 123456, activePolicyID: undefined, currentUserEmailParam: 'test@test.com', introSelected: undefined, isSelfTourViewed: false}); await waitForBatchedUpdatesWithAct(); - createWorkspace({currentUserAccountIDParam: 123456, activePolicyID: undefined, currentUserEmailParam: 'test@test.com', introSelected: undefined}); + createWorkspace({currentUserAccountIDParam: 123456, activePolicyID: undefined, currentUserEmailParam: 'test@test.com', introSelected: undefined, isSelfTourViewed: false}); await waitForBatchedUpdatesWithAct(); // Then we publish a workspace_created event only once