Skip to content

Commit 6021e11

Browse files
committed
Refactor CreateReportMenuItem selector naming and create report directly after workspace creation in upgrade flow
1 parent e943c44 commit 6021e11

3 files changed

Lines changed: 110 additions & 9 deletions

File tree

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,9 @@ function CreateReportMenuItem() {
3737
const isASAPSubmitBetaEnabled = isBetaEnabled(CONST.BETAS.ASAP_SUBMIT);
3838
const hasViolations = hasViolationsReportUtils(undefined, transactionViolations, session?.accountID ?? CONST.DEFAULT_NUMBER_ID, session?.email ?? '');
3939

40-
const groupPaidPoliciesWithChatEnabledCb = (policies: Parameters<typeof groupPaidPoliciesWithExpenseChatEnabledSelector>[0]) =>
40+
const groupPaidPoliciesWithChatEnabledSelector = (policies: Parameters<typeof groupPaidPoliciesWithExpenseChatEnabledSelector>[0]) =>
4141
groupPaidPoliciesWithExpenseChatEnabledSelector(policies, session?.email);
42-
const [groupPoliciesWithChatEnabled = CONST.EMPTY_ARRAY] = useOnyx(ONYXKEYS.COLLECTION.POLICY, {selector: groupPaidPoliciesWithChatEnabledCb}, [session?.email]);
42+
const [groupPoliciesWithChatEnabled = CONST.EMPTY_ARRAY] = useOnyx(ONYXKEYS.COLLECTION.POLICY, {selector: groupPaidPoliciesWithChatEnabledSelector}, [session?.email]);
4343

4444
const [activePolicyID] = useOnyx(ONYXKEYS.NVP_ACTIVE_POLICY_ID);
4545
const [activePolicy] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${activePolicyID}`);

src/pages/iou/request/step/IOURequestStepUpgrade.tsx

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,19 @@ import useHasActiveAdminPolicies from '@hooks/useHasActiveAdminPolicies';
1212
import useLocalize from '@hooks/useLocalize';
1313
import useNetwork from '@hooks/useNetwork';
1414
import useOnyx from '@hooks/useOnyx';
15+
import usePermissions from '@hooks/usePermissions';
1516
import usePreferredPolicy from '@hooks/usePreferredPolicy';
1617
import useThemeStyles from '@hooks/useThemeStyles';
18+
import {createNewReport} from '@libs/actions/Report';
1719
import {setTransactionReport} from '@libs/actions/Transaction';
1820
import type CreateWorkspaceParams from '@libs/API/parameters/CreateWorkspaceParams';
1921
import getPlatform from '@libs/getPlatform';
22+
import isSearchTopmostFullScreenRoute from '@libs/Navigation/helpers/isSearchTopmostFullScreenRoute';
2023
import Navigation from '@libs/Navigation/Navigation';
2124
import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types';
2225
import type {MoneyRequestNavigatorParamList} from '@libs/Navigation/types';
2326
import {getParticipantsOption} from '@libs/OptionsListUtils';
27+
import {hasViolations as hasViolationsReportUtils} from '@libs/ReportUtils';
2428
import UpgradeConfirmation from '@pages/workspace/upgrade/UpgradeConfirmation';
2529
import UpgradeIntro from '@pages/workspace/upgrade/UpgradeIntro';
2630
import {setCustomUnitRateID, setMoneyRequestParticipants} from '@userActions/IOU';
@@ -64,14 +68,21 @@ function IOURequestStepUpgrade({
6468
const [betas] = useOnyx(ONYXKEYS.BETAS);
6569
const [activePolicyID] = useOnyx(ONYXKEYS.NVP_ACTIVE_POLICY_ID);
6670
const [isSelfTourViewed] = useOnyx(ONYXKEYS.NVP_ONBOARDING, {selector: hasSeenTourSelector});
71+
const [session] = useOnyx(ONYXKEYS.SESSION);
72+
const [transactionViolations] = useOnyx(ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS);
73+
const [createdPolicyID, setCreatedPolicyID] = useState<string | undefined>();
74+
const [createdPolicy] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${createdPolicyID}`);
75+
const {isBetaEnabled} = usePermissions();
76+
const isASAPSubmitBetaEnabled = isBetaEnabled(CONST.BETAS.ASAP_SUBMIT);
77+
const hasViolations = hasViolationsReportUtils(undefined, transactionViolations, session?.accountID ?? CONST.DEFAULT_NUMBER_ID, session?.email ?? '');
6778

6879
const feature = Object.values(CONST.UPGRADE_FEATURE_INTRO_MAPPING)
6980
.filter((value) => value.id !== CONST.UPGRADE_FEATURE_INTRO_MAPPING.policyPreventMemberChangingTitle.id)
7081
.find((f) => f.alias === upgradePath);
7182

7283
const navigateWithMicrotask = (route: Route) => {
7384
if (isWeb) {
74-
Navigation.setNavigationActionToMicrotaskQueue(() => Navigation.navigate(route));
85+
Navigation.setNavigationActionToMicrotaskQueue(() => Navigation.navigate(route));
7586
} else {
7687
Navigation.navigate(route);
7788
}
@@ -114,16 +125,25 @@ function IOURequestStepUpgrade({
114125
navigateWithMicrotask(ROUTES.WORKSPACE_CREATE_DISTANCE_RATE_UPGRADE.getRoute(policyID, transactionID, expenseReportID));
115126
break;
116127
}
117-
case CONST.UPGRADE_PATHS.REPORTS:
128+
case CONST.UPGRADE_PATHS.REPORTS: {
118129
Navigation.goBack();
119-
if (action === CONST.IOU.ACTION.CREATE) {
120-
// Coming from "Create report" button (no workspace) → go to workspace selection which creates the report
130+
if (action === CONST.IOU.ACTION.CREATE && policyID) {
131+
// Create the report directly using the just-created workspace instead of
132+
// navigating to workspace selection (which would redundantly ask the user
133+
// to pick the single workspace they just created).
134+
const {reportID: createdReportID} = createNewReport(currentUserPersonalDetails, hasViolations, isASAPSubmitBetaEnabled, createdPolicy, betas);
135+
navigateWithMicrotask(
136+
isSearchTopmostFullScreenRoute()
137+
? ROUTES.SEARCH_MONEY_REQUEST_REPORT.getRoute({reportID: createdReportID, backTo: Navigation.getActiveRoute()})
138+
: ROUTES.REPORT_WITH_ID.getRoute(createdReportID, undefined, undefined, Navigation.getActiveRoute()),
139+
);
140+
} else if (action === CONST.IOU.ACTION.CREATE) {
121141
navigateWithMicrotask(ROUTES.NEW_REPORT_WORKSPACE_SELECTION.getRoute());
122142
} else {
123143
navigateWithMicrotask(ROUTES.MONEY_REQUEST_STEP_REPORT.getRoute(action, CONST.IOU.TYPE.SUBMIT, transactionID, reportID));
124144
}
125-
126145
break;
146+
}
127147
case CONST.UPGRADE_PATHS.CATEGORIES:
128148
Navigation.goBack();
129149
navigateWithMicrotask(backTo ?? ROUTES.MONEY_REQUEST_STEP_CATEGORY.getRoute(action, CONST.IOU.TYPE.SUBMIT, transactionID, reportID));
@@ -172,11 +192,10 @@ function IOURequestStepUpgrade({
172192
hasActiveAdminPolicies,
173193
});
174194
setIsUpgraded(true);
195+
setCreatedPolicyID(policyData.policyID);
175196
policyDataRef.current = policyData;
176197
};
177198

178-
const [session] = useOnyx(ONYXKEYS.SESSION);
179-
180199
const handleConfirmUpgradeWarning = () => {
181200
setIsUpgradeWarningModalOpen(false);
182201
};
@@ -200,6 +219,7 @@ function IOURequestStepUpgrade({
200219
hasActiveAdminPolicies,
201220
});
202221
policyDataRef.current = policyData;
222+
setCreatedPolicyID(policyData.policyID);
203223
setCreatedPolicyName(params.name);
204224
setShowConfirmationForm(false);
205225
setIsUpgraded(true);

tests/unit/useCreateReportActionTest.tsx

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import useCreateReportAction from '@hooks/useCreateReportAction';
55
import useOnyx from '@hooks/useOnyx';
66
import Navigation from '@libs/Navigation/Navigation';
77
import CONST from '@src/CONST';
8+
import ONYXKEYS from '@src/ONYXKEYS';
89
import ROUTES from '@src/ROUTES';
910
import type {Policy} from '@src/types/onyx';
1011

@@ -311,6 +312,86 @@ describe('useCreateReportAction', () => {
311312
});
312313
});
313314

315+
describe('policies loaded with valid workspace', () => {
316+
it('does not navigate to upgrade path when user has a workspace', () => {
317+
const onCreateReport = jest.fn();
318+
const policies = [makePaidPolicy()];
319+
320+
const {result} = renderHook(() =>
321+
useCreateReportAction({
322+
onCreateReport,
323+
groupPoliciesWithChatEnabled: policies,
324+
}),
325+
);
326+
327+
act(() => {
328+
result.current.createReportAction();
329+
});
330+
331+
// Should call onCreateReport directly, not navigate to upgrade
332+
expect(onCreateReport).toHaveBeenCalledWith(false);
333+
const calls = jest.mocked(Navigation.navigate).mock.calls;
334+
const navigatedToUpgrade = calls.some((call) => {
335+
const firstArg = call.at(0);
336+
return typeof firstArg === 'string' && firstArg.includes('upgrade');
337+
});
338+
expect(navigatedToUpgrade).toBe(false);
339+
});
340+
});
341+
342+
describe('pre-load safety', () => {
343+
it('does not call onCreateReport before policies load', () => {
344+
const impl = ((_key: string, options?: {selector?: (value: unknown) => unknown}) => {
345+
const value = options?.selector ? options.selector(undefined) : undefined;
346+
return [value, {status: 'loading'}];
347+
}) as typeof useOnyx;
348+
mockUseOnyx.mockImplementation(impl);
349+
350+
const onCreateReport = jest.fn();
351+
352+
const {result} = renderHook(() =>
353+
useCreateReportAction({
354+
onCreateReport,
355+
groupPoliciesWithChatEnabled: [makePaidPolicy()],
356+
}),
357+
);
358+
359+
act(() => {
360+
result.current.createReportAction();
361+
});
362+
363+
expect(onCreateReport).not.toHaveBeenCalled();
364+
expect(Navigation.navigate).not.toHaveBeenCalled();
365+
expect(mockShowConfirmModal).not.toHaveBeenCalled();
366+
});
367+
});
368+
369+
describe('empty report confirmation dismissed', () => {
370+
it('calls onCreateReport directly when confirmation was previously dismissed', () => {
371+
mockUseHasEmptyReportsForPolicy.mockReturnValue(true);
372+
setupUseOnyx({
373+
[ONYXKEYS.NVP_EMPTY_REPORTS_CONFIRMATION_DISMISSED]: true,
374+
});
375+
376+
const onCreateReport = jest.fn();
377+
const policies = [makePaidPolicy()];
378+
379+
const {result} = renderHook(() =>
380+
useCreateReportAction({
381+
onCreateReport,
382+
groupPoliciesWithChatEnabled: policies,
383+
}),
384+
);
385+
386+
act(() => {
387+
result.current.createReportAction();
388+
});
389+
390+
expect(onCreateReport).toHaveBeenCalledWith(false);
391+
expect(mockOpenCreateReportConfirmation).not.toHaveBeenCalled();
392+
});
393+
});
394+
314395
describe('returns', () => {
315396
it('returns createReportAction function', () => {
316397
const onCreateReport = jest.fn();

0 commit comments

Comments
 (0)