Skip to content

Commit 89ba952

Browse files
authored
Merge pull request #85666 from callstack-internal/hotfix-fab-1
[CP Staging] Fix FAB deploy blockers from popover decomposition (#83299)
2 parents d1fc69a + 6599483 commit 89ba952

7 files changed

Lines changed: 27 additions & 132 deletions

File tree

src/hooks/useCreateEmptyReportConfirmation.tsx

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ type UseCreateEmptyReportConfirmationParams = {
2121
onConfirm: (shouldDismissEmptyReportsConfirmation: boolean) => void;
2222
/** Optional callback function to execute when user cancels the confirmation */
2323
onCancel?: () => void;
24+
/** Whether the modal should push a history entry so browser-back dismisses it (default: true) */
25+
shouldHandleNavigationBack?: boolean;
2426
};
2527

2628
type UseCreateEmptyReportConfirmationResult = {
@@ -54,7 +56,12 @@ function ConfirmationPrompt({workspaceName, checkboxRef, onLinkPress}: {workspac
5456
);
5557
}
5658

57-
export default function useCreateEmptyReportConfirmation({policyName, onConfirm, onCancel}: UseCreateEmptyReportConfirmationParams): UseCreateEmptyReportConfirmationResult {
59+
export default function useCreateEmptyReportConfirmation({
60+
policyName,
61+
onConfirm,
62+
onCancel,
63+
shouldHandleNavigationBack = true,
64+
}: UseCreateEmptyReportConfirmationParams): UseCreateEmptyReportConfirmationResult {
5865
const {translate} = useLocalize();
5966
const {showConfirmModal, closeModal} = useConfirmModal();
6067
const workspaceDisplayName = policyName?.trim().length ? policyName : translate('report.newReport.genericWorkspaceName');
@@ -79,6 +86,7 @@ export default function useCreateEmptyReportConfirmation({policyName, onConfirm,
7986
title: `${translate('report.newReport.emptyReportConfirmationTitle')} `,
8087
confirmText: translate('report.newReport.createReport'),
8188
cancelText: translate('common.cancel'),
89+
shouldHandleNavigationBack,
8290
prompt: (
8391
<ConfirmationPrompt
8492
workspaceName={workspaceDisplayName}

src/libs/actions/Tour.ts

Lines changed: 2 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,8 @@
1-
import {InteractionManager} from 'react-native';
21
import Navigation from '@libs/Navigation/Navigation';
3-
import CONST from '@src/CONST';
42
import ROUTES from '@src/ROUTES';
5-
import type {IntroSelected} from './Report';
63

7-
function startTestDrive(introSelected: IntroSelected | undefined, hasUserBeenAddedToNudgeMigration: boolean, isUserPaidPolicyMember: boolean) {
8-
// eslint-disable-next-line @typescript-eslint/no-deprecated
9-
InteractionManager.runAfterInteractions(() => {
10-
const shouldNavigateToDemo =
11-
hasUserBeenAddedToNudgeMigration ||
12-
isUserPaidPolicyMember ||
13-
introSelected?.choice === CONST.ONBOARDING_CHOICES.MANAGE_TEAM ||
14-
introSelected?.choice === CONST.ONBOARDING_CHOICES.TEST_DRIVE_RECEIVER ||
15-
introSelected?.choice === CONST.ONBOARDING_CHOICES.TRACK_WORKSPACE ||
16-
(introSelected?.choice === CONST.ONBOARDING_CHOICES.SUBMIT && introSelected.inviteType === CONST.ONBOARDING_INVITE_TYPES.WORKSPACE);
17-
18-
if (shouldNavigateToDemo) {
19-
Navigation.navigate(ROUTES.TEST_DRIVE_DEMO_ROOT);
20-
return;
21-
}
22-
Navigation.navigate(ROUTES.TEST_DRIVE_DEMO_ROOT);
23-
});
4+
function startTestDrive() {
5+
Navigation.navigate(ROUTES.TEST_DRIVE_DEMO_ROOT);
246
}
257

268
// eslint-disable-next-line import/prefer-default-export

src/pages/Search/EmptySearchView.tsx

Lines changed: 3 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import {hasSeenTourSelector, tryNewDotOnyxSelector} from '@selectors/Onboarding';
1+
import {hasSeenTourSelector} from '@selectors/Onboarding';
22
import {accountIDSelector} from '@selectors/Session';
33
import {validTransactionDraftIDsSelector} from '@selectors/TransactionDraft';
44
import React from 'react';
@@ -19,7 +19,6 @@ import useConfirmModal from '@hooks/useConfirmModal';
1919
import useCreateEmptyReportConfirmation from '@hooks/useCreateEmptyReportConfirmation';
2020
import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails';
2121
import useHasEmptyReportsForPolicy from '@hooks/useHasEmptyReportsForPolicy';
22-
import useIsPaidPolicyAdmin from '@hooks/useIsPaidPolicyAdmin';
2322
import {useMemoizedLazyIllustrations} from '@hooks/useLazyAsset';
2423
import useLocalize from '@hooks/useLocalize';
2524
import useOnyx from '@hooks/useOnyx';
@@ -40,7 +39,7 @@ import {shouldRestrictUserBillableActions} from '@libs/SubscriptionUtils';
4039
import CONST from '@src/CONST';
4140
import ONYXKEYS from '@src/ONYXKEYS';
4241
import ROUTES from '@src/ROUTES';
43-
import type {IntroSelected, PersonalDetails, Policy, Report, Transaction} from '@src/types/onyx';
42+
import type {PersonalDetails, Policy, Report, Transaction} from '@src/types/onyx';
4443
import type {SearchDataTypes} from '@src/types/onyx/SearchResults';
4544
import useSearchEmptyStateIllustration from './useSearchEmptyStateIllustration';
4645

@@ -55,10 +54,8 @@ type EmptySearchViewContentProps = EmptySearchViewProps & {
5554
currentUserPersonalDetails: PersonalDetails;
5655
typeMenuSections: SearchTypeMenuSection[];
5756
allPolicies: OnyxCollection<Policy>;
58-
isUserPaidPolicyMember: boolean;
5957
activePolicy: OnyxEntry<Policy>;
6058
groupPoliciesWithChatEnabled: readonly never[] | Array<OnyxEntry<Policy>>;
61-
introSelected: OnyxEntry<IntroSelected>;
6259
hasSeenTour: boolean;
6360
};
6461

@@ -84,13 +81,10 @@ function EmptySearchView({similarSearchHash, type, hasResults, queryJSON}: Empty
8481

8582
const groupPoliciesWithChatEnabled = getGroupPaidPoliciesWithExpenseChatEnabled(allPolicies);
8683

87-
const [introSelected] = useOnyx(ONYXKEYS.NVP_INTRO_SELECTED);
8884
const [hasSeenTour = false] = useOnyx(ONYXKEYS.NVP_ONBOARDING, {
8985
selector: hasSeenTourSelector,
9086
});
9187

92-
const isUserPaidPolicyMember = useIsPaidPolicyAdmin();
93-
9488
return (
9589
<SearchScopeProvider>
9690
<EmptySearchViewContent
@@ -100,10 +94,8 @@ function EmptySearchView({similarSearchHash, type, hasResults, queryJSON}: Empty
10094
currentUserPersonalDetails={currentUserPersonalDetails}
10195
typeMenuSections={typeMenuSections}
10296
allPolicies={allPolicies}
103-
isUserPaidPolicyMember={isUserPaidPolicyMember}
10497
activePolicy={activePolicy}
10598
groupPoliciesWithChatEnabled={groupPoliciesWithChatEnabled}
106-
introSelected={introSelected}
10799
hasSeenTour={hasSeenTour}
108100
queryJSON={queryJSON}
109101
/>
@@ -124,10 +116,8 @@ function EmptySearchViewContent({
124116
currentUserPersonalDetails,
125117
typeMenuSections,
126118
allPolicies,
127-
isUserPaidPolicyMember,
128119
activePolicy,
129120
groupPoliciesWithChatEnabled,
130-
introSelected,
131121
hasSeenTour,
132122
queryJSON,
133123
}: EmptySearchViewContentProps) {
@@ -154,10 +144,6 @@ function EmptySearchViewContent({
154144
selector: hasExpenseReportsSelector,
155145
});
156146

157-
const [tryNewDot] = useOnyx(ONYXKEYS.NVP_TRY_NEW_DOT, {
158-
selector: tryNewDotOnyxSelector,
159-
});
160-
161147
const shouldRedirectToExpensifyClassic = areAllGroupPoliciesExpenseChatDisabled(allPolicies ?? {});
162148

163149
const defaultChatEnabledPolicy = getDefaultChatEnabledPolicy(groupPoliciesWithChatEnabled as Array<OnyxEntry<Policy>>, activePolicy);
@@ -245,7 +231,7 @@ function EmptySearchViewContent({
245231
const defaultViewItemHeader = useSearchEmptyStateIllustration();
246232

247233
const startTestDriveAction = () => {
248-
startTestDrive(introSelected, tryNewDot?.hasBeenAddedToNudgeMigration ?? false, isUserPaidPolicyMember);
234+
startTestDrive();
249235
};
250236

251237
let content: EmptySearchViewItem | undefined;

src/pages/inbox/sidebar/FABPopoverContent/FABPopoverMenu.tsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,11 @@ function FABPopoverMenu({isVisible, onClose, onItemSelected, anchorRef, animatio
7474
isActive: isVisible,
7575
});
7676

77+
const handleClose = () => {
78+
setFocusedIndex(-1);
79+
onClose();
80+
};
81+
7782
const onItemPress = (onSelected: () => void, options?: {shouldCallAfterModalHide?: boolean}) => {
7883
onItemSelected();
7984
if (options?.shouldCallAfterModalHide && !isSafari()) {
@@ -105,7 +110,7 @@ function FABPopoverMenu({isVisible, onClose, onItemSelected, anchorRef, animatio
105110
horizontal: CONST.MODAL.ANCHOR_ORIGIN_HORIZONTAL.LEFT,
106111
vertical: CONST.MODAL.ANCHOR_ORIGIN_VERTICAL.BOTTOM,
107112
}}
108-
onClose={onClose}
113+
onClose={handleClose}
109114
isVisible={isVisible}
110115
fromSidebarMediumScreen={!shouldUseNarrowLayout}
111116
animationIn="fadeIn"

src/pages/inbox/sidebar/FABPopoverContent/menuItems/CreateReportMenuItem.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ function CreateReportMenuItem() {
112112
policyID: defaultChatEnabledPolicyID,
113113
policyName: defaultChatEnabledPolicy?.name ?? '',
114114
onConfirm: handleCreateWorkspaceReport,
115+
shouldHandleNavigationBack: false,
115116
});
116117

117118
return (

src/pages/inbox/sidebar/FABPopoverContent/menuItems/TestDriveMenuItem.tsx

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1-
import {hasSeenTourSelector, tryNewDotOnyxSelector} from '@selectors/Onboarding';
1+
import {hasSeenTourSelector} from '@selectors/Onboarding';
22
import React from 'react';
3-
import useIsPaidPolicyAdmin from '@hooks/useIsPaidPolicyAdmin';
43
import {useMemoizedLazyExpensifyIcons} from '@hooks/useLazyAsset';
54
import useLocalize from '@hooks/useLocalize';
65
import useOnyx from '@hooks/useOnyx';
@@ -20,9 +19,6 @@ function TestDriveMenuItem() {
2019
const theme = useTheme();
2120
const icons = useMemoizedLazyExpensifyIcons(['Binoculars'] as const);
2221
const [hasSeenTour = false] = useOnyx(ONYXKEYS.NVP_ONBOARDING, {selector: hasSeenTourSelector});
23-
const [introSelected] = useOnyx(ONYXKEYS.NVP_INTRO_SELECTED);
24-
const [tryNewDot] = useOnyx(ONYXKEYS.NVP_TRY_NEW_DOT, {selector: tryNewDotOnyxSelector});
25-
const isUserPaidPolicyMember = useIsPaidPolicyAdmin();
2622
const isVisible = !hasSeenTour;
2723

2824
return (
@@ -34,7 +30,7 @@ function TestDriveMenuItem() {
3430
iconStyles={styles.popoverIconCircle}
3531
iconFill={theme.icon}
3632
title={translate('testDrive.quickAction.takeATwoMinuteTestDrive')}
37-
onPress={() => interceptAnonymousUser(() => startTestDrive(introSelected, tryNewDot?.hasBeenAddedToNudgeMigration ?? false, isUserPaidPolicyMember))}
33+
onPress={() => interceptAnonymousUser(() => startTestDrive())}
3834
/>
3935
);
4036
}

tests/actions/TourTest.ts

Lines changed: 4 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,10 @@ import Onyx from 'react-native-onyx';
22
import OnyxUpdateManager from '@libs/actions/OnyxUpdateManager';
33
import {startTestDrive} from '@libs/actions/Tour';
44
import Navigation from '@libs/Navigation/Navigation';
5-
import Parser from '@libs/Parser';
65
import initOnyxDerivedValues from '@userActions/OnyxDerived';
7-
import CONST from '@src/CONST';
86
import * as SequentialQueue from '@src/libs/Network/SequentialQueue';
97
import ONYXKEYS from '@src/ONYXKEYS';
108
import ROUTES from '@src/ROUTES';
11-
import type {OnboardingPurpose, Report, ReportAction} from '@src/types/onyx';
12-
import type {ReportActionsCollectionDataSet} from '@src/types/onyx/ReportAction';
13-
import * as LHNTestUtils from '../utils/LHNTestUtils';
149
import * as TestHelper from '../utils/TestHelper';
1510
import waitForBatchedUpdates from '../utils/waitForBatchedUpdates';
1611

@@ -36,89 +31,11 @@ describe('actions/Tour', () => {
3631
});
3732

3833
describe('startTestDrive', () => {
39-
describe('migrated users', () => {
40-
it('should show the Test Drive demo if user has been nudged to migrate', async () => {
41-
startTestDrive(undefined, true, false);
42-
await waitForBatchedUpdates();
34+
it('should navigate to the Test Drive demo screen', async () => {
35+
startTestDrive();
36+
await waitForBatchedUpdates();
4337

44-
expect(Navigation.navigate).toHaveBeenCalledWith(ROUTES.TEST_DRIVE_DEMO_ROOT);
45-
});
46-
47-
it("should show the Test Drive demo if user doesn't have the nudge flag but is member of a paid policy", async () => {
48-
startTestDrive(undefined, false, true);
49-
await waitForBatchedUpdates();
50-
51-
expect(Navigation.navigate).toHaveBeenCalledWith(ROUTES.TEST_DRIVE_DEMO_ROOT);
52-
});
53-
});
54-
55-
describe('NewDot users', () => {
56-
const onboardingChoices = Object.values(CONST.ONBOARDING_CHOICES);
57-
const onboardingDemoChoices = new Set<OnboardingPurpose>([
58-
CONST.ONBOARDING_CHOICES.MANAGE_TEAM,
59-
CONST.ONBOARDING_CHOICES.TEST_DRIVE_RECEIVER,
60-
CONST.ONBOARDING_CHOICES.TRACK_WORKSPACE,
61-
]);
62-
const accountID = 2;
63-
const conciergeChatReport: Report = LHNTestUtils.getFakeReport([accountID, CONST.ACCOUNT_ID.CONCIERGE]);
64-
const testDriveTaskReport: Report = {...LHNTestUtils.getFakeReport(), ownerAccountID: accountID};
65-
66-
let testDriveTaskAction: ReportAction;
67-
const setTestDriveTaskData = async () => {
68-
testDriveTaskAction = {
69-
...LHNTestUtils.getFakeReportAction(),
70-
childType: CONST.REPORT.TYPE.TASK,
71-
childReportName: Parser.replace(
72-
TestHelper.translateLocal('onboarding.testDrive.name', {testDriveURL: `${CONST.STAGING_NEW_EXPENSIFY_URL}/${ROUTES.TEST_DRIVE_DEMO_ROOT}`}),
73-
),
74-
childReportID: testDriveTaskReport.reportID,
75-
};
76-
77-
const reportActionsCollectionDataSet: ReportActionsCollectionDataSet = {
78-
[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${conciergeChatReport.reportID}`]: {
79-
[testDriveTaskAction.reportActionID]: testDriveTaskAction,
80-
},
81-
};
82-
83-
await Onyx.multiSet({
84-
...reportActionsCollectionDataSet,
85-
[ONYXKEYS.SESSION]: {
86-
accountID,
87-
},
88-
});
89-
};
90-
91-
it.each(onboardingChoices.filter((choice) => onboardingDemoChoices.has(choice)))('should show the Test Drive demo if user has "%s" onboarding choice', async (choice) => {
92-
await setTestDriveTaskData();
93-
94-
startTestDrive({choice}, false, false);
95-
await waitForBatchedUpdates();
96-
97-
expect(Navigation.navigate).toHaveBeenCalledWith(ROUTES.TEST_DRIVE_DEMO_ROOT);
98-
});
99-
100-
it.each(onboardingChoices.filter((choice) => !onboardingDemoChoices.has(choice)))('should show the Test Drive demo if user has "%s" onboarding choice', async (choice) => {
101-
startTestDrive({choice}, false, false);
102-
await waitForBatchedUpdates();
103-
104-
expect(Navigation.navigate).toHaveBeenCalledWith(ROUTES.TEST_DRIVE_DEMO_ROOT);
105-
});
106-
107-
it('should show the Test Drive demo if user is an invited employee', async () => {
108-
await setTestDriveTaskData();
109-
110-
startTestDrive({choice: CONST.ONBOARDING_CHOICES.SUBMIT, inviteType: CONST.ONBOARDING_INVITE_TYPES.WORKSPACE}, false, false);
111-
await waitForBatchedUpdates();
112-
113-
expect(Navigation.navigate).toHaveBeenCalledWith(ROUTES.TEST_DRIVE_DEMO_ROOT);
114-
});
115-
116-
it('should show the Test Drive demo if user is member of a paid policy', async () => {
117-
startTestDrive({choice: CONST.ONBOARDING_CHOICES.LOOKING_AROUND}, false, true);
118-
await waitForBatchedUpdates();
119-
120-
expect(Navigation.navigate).toHaveBeenCalledWith(ROUTES.TEST_DRIVE_DEMO_ROOT);
121-
});
38+
expect(Navigation.navigate).toHaveBeenCalledWith(ROUTES.TEST_DRIVE_DEMO_ROOT);
12239
});
12340
});
12441
});

0 commit comments

Comments
 (0)