diff --git a/src/components/PromotedActionsBar.tsx b/src/components/PromotedActionsBar.tsx index b25fb2fd1d75e..83dc995c7576a 100644 --- a/src/components/PromotedActionsBar.tsx +++ b/src/components/PromotedActionsBar.tsx @@ -13,6 +13,7 @@ import {joinRoom, navigateToAndOpenReport, navigateToAndOpenReportWithAccountIDs import {callFunctionIfActionIsAllowed} from '@userActions/Session'; import CONST from '@src/CONST'; import ROUTES from '@src/ROUTES'; +import type Beta from '@src/types/onyx/Beta'; import type OnyxReport from '@src/types/onyx/Report'; import Button from './Button'; import type {ThreeDotsMenuItem} from './HeaderWithBackButton/types'; @@ -33,6 +34,7 @@ type PromotedActionsType = Record P currentUserAccountID: number; introSelected: OnyxEntry; isSelfTourViewed: boolean | undefined; + betas: OnyxEntry; }) => PromotedAction; } & { [CONST.PROMOTED_ACTIONS.JOIN]: (report: OnyxReport, currentUserAccountID: number) => PromotedAction; @@ -64,7 +66,7 @@ const PromotedActions = { joinRoom(report, currentUserAccountID); }), }), - message: ({reportID, accountID, login, currentUserAccountID, introSelected, isSelfTourViewed}) => ({ + message: ({reportID, accountID, login, currentUserAccountID, introSelected, isSelfTourViewed, betas}) => ({ key: CONST.PROMOTED_ACTIONS.MESSAGE, icon: 'CommentBubbles', translationKey: 'common.message', @@ -80,7 +82,7 @@ const PromotedActions = { return; } if (accountID) { - navigateToAndOpenReportWithAccountIDs([accountID], currentUserAccountID, introSelected); + navigateToAndOpenReportWithAccountIDs([accountID], currentUserAccountID, introSelected, betas); } }, }), diff --git a/src/libs/actions/Report/index.ts b/src/libs/actions/Report/index.ts index aaa3f7d833034..c11f52339c3c2 100644 --- a/src/libs/actions/Report/index.ts +++ b/src/libs/actions/Report/index.ts @@ -2061,7 +2061,7 @@ function navigateToAndCreateGroupChat( * * @param participantAccountIDs of user logins to start a chat report with. */ -function navigateToAndOpenReportWithAccountIDs(participantAccountIDs: number[], currentUserAccountID: number, introSelected: OnyxEntry) { +function navigateToAndOpenReportWithAccountIDs(participantAccountIDs: number[], currentUserAccountID: number, introSelected: OnyxEntry, betas: OnyxEntry) { let newChat: OptimisticChatReport | undefined; const chat = getChatByParticipants([...participantAccountIDs, currentUserAccountID]); if (!chat) { @@ -2075,6 +2075,7 @@ function navigateToAndOpenReportWithAccountIDs(participantAccountIDs: number[], newReportObject: newChat, parentReportActionID: '0', participantAccountIDList: participantAccountIDs, + betas, }); } const report = chat ?? newChat; diff --git a/src/libs/actions/replaceOptimisticReportWithActualReport.ts b/src/libs/actions/replaceOptimisticReportWithActualReport.ts index bdf52b17aa24c..0084d7a417448 100644 --- a/src/libs/actions/replaceOptimisticReportWithActualReport.ts +++ b/src/libs/actions/replaceOptimisticReportWithActualReport.ts @@ -195,13 +195,19 @@ function replaceOptimisticReportWithActualReport(report: Report, draftReportComm callback(); // We are already on the parent one expense report, so just call the API to fetch report data - openReport({reportID: parentReportID, introSelected: undefined}); + // betas is safe to pass as undefined because introSelected is undefined, so the code path + // that uses betas is never reached. Passing it explicitly so the compiler flags this when + // betas becomes required. Refactor issue: https://github.com/Expensify/App/issues/66424 + openReport({reportID: parentReportID, introSelected: undefined, betas: undefined}); }); } else { callback(); // We are already on the parent one expense report, so just call the API to fetch report data - openReport({reportID: parentReportID, introSelected: undefined}); + // betas is safe to pass as undefined because introSelected is undefined, so the code path + // that uses betas is never reached. Passing it explicitly so the compiler flags this when + // betas becomes required. Refactor issue: https://github.com/Expensify/App/issues/66424 + openReport({reportID: parentReportID, introSelected: undefined, betas: undefined}); } return; } diff --git a/src/pages/ProfilePage.tsx b/src/pages/ProfilePage.tsx index 8446698409876..4d41f4011d98f 100755 --- a/src/pages/ProfilePage.tsx +++ b/src/pages/ProfilePage.tsx @@ -76,6 +76,7 @@ function ProfilePage({route}: ProfilePageProps) { const [account] = useOnyx(ONYXKEYS.ACCOUNT); const [isDebugModeEnabled = false] = useOnyx(ONYXKEYS.IS_DEBUG_MODE_ENABLED); const [introSelected] = useOnyx(ONYXKEYS.NVP_INTRO_SELECTED); + const [betas] = useOnyx(ONYXKEYS.BETAS); const [isSelfTourViewed] = useOnyx(ONYXKEYS.NVP_ONBOARDING, {selector: hasSeenTourSelector}); const guideCalendarLink = account?.guideDetails?.calendarLink ?? ''; const expensifyIcons = useMemoizedLazyExpensifyIcons(['Bug', 'Pencil', 'Phone']); @@ -165,7 +166,7 @@ function ProfilePage({route}: ProfilePageProps) { // If it's a self DM, we only want to show the Message button if the self DM report exists because we don't want to optimistically create a report for self DM if ((!isCurrentUser || report) && !isAnonymousUserSession()) { - promotedActions.push(PromotedActions.message({reportID: report?.reportID, accountID, login: loginParams, currentUserAccountID, introSelected, isSelfTourViewed})); + promotedActions.push(PromotedActions.message({reportID: report?.reportID, accountID, login: loginParams, currentUserAccountID, introSelected, isSelfTourViewed, betas})); } return ( diff --git a/src/pages/workspace/workflows/WorkspaceWorkflowsPayerPage.tsx b/src/pages/workspace/workflows/WorkspaceWorkflowsPayerPage.tsx index 4e73c62a9f47c..3146268479931 100644 --- a/src/pages/workspace/workflows/WorkspaceWorkflowsPayerPage.tsx +++ b/src/pages/workspace/workflows/WorkspaceWorkflowsPayerPage.tsx @@ -67,6 +67,7 @@ function WorkspaceWorkflowsPayerPage({route, policy, personalDetails, isLoadingR const bankAccountInfo = bankAccountFromList ?? bankAccountConnectedToWorkspace; const bankAccountID = policyBankAccountID ?? bankAccountInfo?.accountData?.bankAccountID; const [introSelected] = useOnyx(ONYXKEYS.NVP_INTRO_SELECTED); + const [betas] = useOnyx(ONYXKEYS.BETAS); const {isOffline} = useNetwork(); const currentUserPersonalDetails = useCurrentUserPersonalDetails(); const [countryCode = CONST.DEFAULT_COUNTRY_CODE] = useOnyx(ONYXKEYS.COUNTRY_CODE); @@ -357,7 +358,7 @@ function WorkspaceWorkflowsPayerPage({route, policy, personalDetails, isLoadingR return; } setShowErrorModal(false); - navigateToAndOpenReportWithAccountIDs([policy.ownerAccountID], currentUserPersonalDetails.accountID, introSelected); + navigateToAndOpenReportWithAccountIDs([policy.ownerAccountID], currentUserPersonalDetails.accountID, introSelected, betas); }} html={translate('workflowsPayerPage.shareBankAccount.errorDescription', { admin: selectedPayerDetails?.displayName ?? '', diff --git a/tests/actions/ReportTest.ts b/tests/actions/ReportTest.ts index b6451e05d7abc..0ec80725d83d8 100644 --- a/tests/actions/ReportTest.ts +++ b/tests/actions/ReportTest.ts @@ -5729,6 +5729,52 @@ describe('actions/Report', () => { }); }); + describe('navigateToAndOpenReportWithAccountIDs', () => { + it('should create new chat and pass betas to openReport when no existing chat', async () => { + const TEST_USER_ACCOUNT_ID = 1; + const TEST_USER_LOGIN = 'test@user.com'; + const PARTICIPANT_ACCOUNT_ID = 2; + + await TestHelper.signInWithTestUser(TEST_USER_ACCOUNT_ID, TEST_USER_LOGIN); + await TestHelper.setPersonalDetails(TEST_USER_LOGIN, TEST_USER_ACCOUNT_ID); + + const testIntroSelected: OnyxTypes.IntroSelected = {choice: CONST.ONBOARDING_CHOICES.ADMIN}; + + Report.navigateToAndOpenReportWithAccountIDs([PARTICIPANT_ACCOUNT_ID], TEST_USER_ACCOUNT_ID, testIntroSelected, undefined); + await waitForBatchedUpdates(); + + TestHelper.expectAPICommandToHaveBeenCalled(WRITE_COMMANDS.OPEN_REPORT, 1); + expect(Navigation.navigate).toHaveBeenCalled(); + }); + + it('should not call openReport when chat already exists', async () => { + const TEST_USER_ACCOUNT_ID = 1; + const TEST_USER_LOGIN = 'test@user.com'; + const PARTICIPANT_ACCOUNT_ID = 2; + const EXISTING_REPORT_ID = '456'; + + await TestHelper.signInWithTestUser(TEST_USER_ACCOUNT_ID, TEST_USER_LOGIN); + await TestHelper.setPersonalDetails(TEST_USER_LOGIN, TEST_USER_ACCOUNT_ID); + await Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT}${EXISTING_REPORT_ID}`, { + reportID: EXISTING_REPORT_ID, + type: CONST.REPORT.TYPE.CHAT, + participants: { + [TEST_USER_ACCOUNT_ID]: {notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS}, + [PARTICIPANT_ACCOUNT_ID]: {notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS}, + }, + }); + await waitForBatchedUpdates(); + + const testIntroSelected: OnyxTypes.IntroSelected = {choice: CONST.ONBOARDING_CHOICES.ADMIN}; + + Report.navigateToAndOpenReportWithAccountIDs([PARTICIPANT_ACCOUNT_ID], TEST_USER_ACCOUNT_ID, testIntroSelected, undefined); + await waitForBatchedUpdates(); + + TestHelper.expectAPICommandToHaveBeenCalled(WRITE_COMMANDS.OPEN_REPORT, 0); + expect(Navigation.navigate).toHaveBeenCalledWith(ROUTES.REPORT_WITH_ID.getRoute(EXISTING_REPORT_ID)); + }); + }); + describe('getGuidedSetupDataForOpenReport', () => { const TEST_USER_ACCOUNT_ID = 1; const TEST_USER_LOGIN = 'test@user.com'; diff --git a/tests/unit/PromotedActionsBarTest.ts b/tests/unit/PromotedActionsBarTest.ts index e48d720dc14ad..ab8a69fa51086 100644 --- a/tests/unit/PromotedActionsBarTest.ts +++ b/tests/unit/PromotedActionsBarTest.ts @@ -32,6 +32,7 @@ describe('PromotedActions.message', () => { currentUserAccountID: 1, introSelected, isSelfTourViewed: false, + betas: undefined, }); action.onSelected(); @@ -46,11 +47,12 @@ describe('PromotedActions.message', () => { currentUserAccountID: 1, introSelected, isSelfTourViewed: false, + betas: undefined, }); action.onSelected(); - expect(mockNavigateToAndOpenReportWithAccountIDs).toHaveBeenCalledWith([42], 1, introSelected); + expect(mockNavigateToAndOpenReportWithAccountIDs).toHaveBeenCalledWith([42], 1, introSelected, undefined); }); it('should pass undefined introSelected when not provided', () => { @@ -59,11 +61,12 @@ describe('PromotedActions.message', () => { currentUserAccountID: 1, introSelected: undefined, isSelfTourViewed: undefined, + betas: undefined, }); action.onSelected(); - expect(mockNavigateToAndOpenReportWithAccountIDs).toHaveBeenCalledWith([42], 1, undefined); + expect(mockNavigateToAndOpenReportWithAccountIDs).toHaveBeenCalledWith([42], 1, undefined, undefined); }); it('should navigate to report directly when reportID is provided', () => { @@ -72,6 +75,7 @@ describe('PromotedActions.message', () => { currentUserAccountID: 1, introSelected: undefined, isSelfTourViewed: undefined, + betas: undefined, }); action.onSelected(); @@ -88,6 +92,7 @@ describe('PromotedActions.message', () => { currentUserAccountID: 1, introSelected, isSelfTourViewed: false, + betas: undefined, }); action.onSelected(); @@ -95,4 +100,20 @@ describe('PromotedActions.message', () => { expect(mockNavigateToAndOpenReport).toHaveBeenCalledWith(['test@example.com'], 1, introSelected, false, false); expect(mockNavigateToAndOpenReportWithAccountIDs).not.toHaveBeenCalled(); }); + + it('should pass betas to navigateToAndOpenReportWithAccountIDs when accountID is provided', () => { + const introSelected = {choice: CONST.ONBOARDING_CHOICES.MANAGE_TEAM}; + const betas = [CONST.BETAS.ALL]; + const action = PromotedActions.message({ + accountID: 42, + currentUserAccountID: 1, + introSelected, + isSelfTourViewed: false, + betas, + }); + + action.onSelected(); + + expect(mockNavigateToAndOpenReportWithAccountIDs).toHaveBeenCalledWith([42], 1, introSelected, betas); + }); });