Skip to content

Commit 3094680

Browse files
committed
refactor(onboarding): share auto-create workspace state between Submit and Track hooks
Extract the duplicated Onyx subscriptions and helper-hook wiring from useAutoCreateSubmitWorkspace and useAutoCreateTrackWorkspace into a new useOnboardingWorkspaceCreationState hook. Each hook keeps its own selector for "should create?", navigation target, and sync/async completion.
1 parent 6c4f73e commit 3094680

3 files changed

Lines changed: 120 additions & 73 deletions

File tree

src/hooks/useAutoCreateSubmitWorkspace.ts

Lines changed: 23 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import {hasSeenTourSelector} from '@selectors/Onboarding';
21
import {useCallback, useMemo} from 'react';
32
import type {OnyxCollection} from 'react-native-onyx';
43
import {navigateToSubmitWorkspaceAfterOnboardingWithMicrotaskQueue} from '@libs/navigateAfterOnboarding';
@@ -9,16 +8,9 @@ import {completeOnboarding} from '@userActions/Report';
98
import {setOnboardingAdminsChatReportID, setOnboardingPolicyID} from '@userActions/Welcome';
109
import CONST from '@src/CONST';
1110
import ONYXKEYS from '@src/ONYXKEYS';
12-
import {lastWorkspaceNumberSelector} from '@src/selectors/Policy';
1311
import type {Policy} from '@src/types/onyx';
14-
import useActivePolicy from './useActivePolicy';
15-
import useCurrentUserPersonalDetails from './useCurrentUserPersonalDetails';
16-
import useHasActiveAdminPolicies from './useHasActiveAdminPolicies';
17-
import useLocalize from './useLocalize';
18-
import useOnboardingMessages from './useOnboardingMessages';
12+
import useOnboardingWorkspaceCreationState from './useOnboardingWorkspaceCreationState';
1913
import useOnyx from './useOnyx';
20-
import usePreferredPolicy from './usePreferredPolicy';
21-
import useResponsiveLayout from './useResponsiveLayout';
2214

2315
/**
2416
* Hook that provides a function to auto-create a Submit workspace for EMPLOYER
@@ -27,33 +19,30 @@ import useResponsiveLayout from './useResponsiveLayout';
2719
* Shared by BaseOnboardingPersonalDetails, BaseOnboardingPurpose, and BaseOnboardingWorkspaces.
2820
*/
2921
function useAutoCreateSubmitWorkspace() {
30-
const [onboardingPolicyID] = useOnyx(ONYXKEYS.ONBOARDING_POLICY_ID);
31-
const [onboardingAdminsChatReportID] = useOnyx(ONYXKEYS.ONBOARDING_ADMINS_CHAT_REPORT_ID);
32-
const [introSelected] = useOnyx(ONYXKEYS.NVP_INTRO_SELECTED);
33-
const [isSelfTourViewed] = useOnyx(ONYXKEYS.NVP_ONBOARDING, {selector: hasSeenTourSelector});
34-
const [betas] = useOnyx(ONYXKEYS.BETAS);
35-
const currentUserPersonalDetails = useCurrentUserPersonalDetails();
36-
const currentUserEmail = currentUserPersonalDetails.login ?? '';
37-
const currentUserAccountID = currentUserPersonalDetails.accountID;
22+
const {
23+
onboardingPolicyID,
24+
onboardingAdminsChatReportID,
25+
introSelected,
26+
isSelfTourViewed,
27+
betas,
28+
currentUserEmail,
29+
currentUserAccountID,
30+
localCurrencyCode,
31+
activePolicy,
32+
translate,
33+
formatPhoneNumber,
34+
isRestrictedPolicyCreation,
35+
hasActiveAdminPolicies,
36+
onboardingMessages,
37+
lastWorkspaceNumber,
38+
isSmallScreenWidth,
39+
} = useOnboardingWorkspaceCreationState();
40+
3841
const groupPolicySelector = useMemo(
3942
() => (policies: OnyxCollection<Policy>) => Object.values(policies ?? {}).some((policy) => isGroupPolicy(policy) && canEditWorkspaceSettings(policy)),
4043
[],
4144
);
42-
const lastWorkspaceNumberWithEmailSelector = useCallback(
43-
(policies: OnyxCollection<Policy>) => {
44-
return lastWorkspaceNumberSelector(policies, currentUserEmail);
45-
},
46-
[currentUserEmail],
47-
);
4845
const [hasEditableGroupPolicy] = useOnyx(ONYXKEYS.COLLECTION.POLICY, {selector: groupPolicySelector});
49-
const [lastWorkspaceNumber] = useOnyx(ONYXKEYS.COLLECTION.POLICY, {selector: lastWorkspaceNumberWithEmailSelector});
50-
const activePolicy = useActivePolicy();
51-
const {translate, formatPhoneNumber} = useLocalize();
52-
const {isRestrictedPolicyCreation} = usePreferredPolicy();
53-
const hasActiveAdminPolicies = useHasActiveAdminPolicies();
54-
const {onboardingMessages} = useOnboardingMessages();
55-
// eslint-disable-next-line rulesdir/prefer-shouldUseNarrowLayout-instead-of-isSmallScreenWidth
56-
const {isSmallScreenWidth} = useResponsiveLayout();
5746

5847
const autoCreateSubmitWorkspace = useCallback(
5948
(firstName: string, lastName: string) => {
@@ -67,12 +56,12 @@ function useAutoCreateSubmitWorkspace() {
6756
policyName: generateDefaultWorkspaceName(currentUserEmail, lastWorkspaceNumber, translate, displayName),
6857
policyID: generatePolicyID(),
6958
engagementChoice: CONST.ONBOARDING_CHOICES.EMPLOYER,
70-
currency: currentUserPersonalDetails.localCurrencyCode ?? CONST.CURRENCY.USD,
59+
currency: localCurrencyCode,
7160
file: undefined,
7261
shouldAddOnboardingTasks: false,
7362
introSelected,
7463
activePolicy,
75-
currentUserAccountIDParam: currentUserAccountID ?? CONST.DEFAULT_NUMBER_ID,
64+
currentUserAccountIDParam: currentUserAccountID,
7665
currentUserEmailParam: currentUserEmail,
7766
shouldAddGuideWelcomeMessage: false,
7867
type: CONST.POLICY.TYPE.SUBMIT,
@@ -109,7 +98,7 @@ function useAutoCreateSubmitWorkspace() {
10998
onboardingPolicyID,
11099
hasEditableGroupPolicy,
111100
onboardingAdminsChatReportID,
112-
currentUserPersonalDetails.localCurrencyCode,
101+
localCurrencyCode,
113102
introSelected,
114103
activePolicy,
115104
isSelfTourViewed,

src/hooks/useAutoCreateTrackWorkspace.ts

Lines changed: 31 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import {hasSeenTourSelector} from '@selectors/Onboarding';
21
import {useCallback, useMemo} from 'react';
32
import type {OnyxCollection} from 'react-native-onyx';
43
import isSidePanelReportSupported from '@components/SidePanel/isSidePanelReportSupported';
@@ -12,17 +11,10 @@ import {setOnboardingAdminsChatReportID, setOnboardingPolicyID} from '@userActio
1211
import CONST from '@src/CONST';
1312
import ONYXKEYS from '@src/ONYXKEYS';
1413
import type {OnboardingPurpose, OnboardingRHPVariant, Policy} from '@src/types/onyx';
15-
import useActivePolicy from './useActivePolicy';
1614
import useArchivedReportsIdSet from './useArchivedReportsIdSet';
17-
import useCurrentUserPersonalDetails from './useCurrentUserPersonalDetails';
18-
import useHasActiveAdminPolicies from './useHasActiveAdminPolicies';
19-
import useLastWorkspaceNumber from './useLastWorkspaceNumber';
20-
import useLocalize from './useLocalize';
21-
import useOnboardingMessages from './useOnboardingMessages';
15+
import useOnboardingWorkspaceCreationState from './useOnboardingWorkspaceCreationState';
2216
import useOnyx from './useOnyx';
2317
import usePermissions from './usePermissions';
24-
import usePreferredPolicy from './usePreferredPolicy';
25-
import useResponsiveLayout from './useResponsiveLayout';
2618

2719
/**
2820
* Hook that provides a function to auto-create a workspace for Track (PERSONAL_SPEND)
@@ -31,57 +23,57 @@ import useResponsiveLayout from './useResponsiveLayout';
3123
* Shared by BaseOnboardingPersonalDetails and BaseOnboardingPurpose.
3224
*/
3325
function useAutoCreateTrackWorkspace() {
34-
const [onboardingPolicyID] = useOnyx(ONYXKEYS.ONBOARDING_POLICY_ID);
35-
const [onboardingAdminsChatReportID] = useOnyx(ONYXKEYS.ONBOARDING_ADMINS_CHAT_REPORT_ID);
36-
const [introSelected] = useOnyx(ONYXKEYS.NVP_INTRO_SELECTED);
37-
const [isSelfTourViewed] = useOnyx(ONYXKEYS.NVP_ONBOARDING, {selector: hasSeenTourSelector});
38-
const [betas] = useOnyx(ONYXKEYS.BETAS);
39-
const [session] = useOnyx(ONYXKEYS.SESSION);
26+
const {
27+
onboardingPolicyID,
28+
onboardingAdminsChatReportID,
29+
introSelected,
30+
isSelfTourViewed,
31+
betas,
32+
currentUserEmail,
33+
currentUserAccountID,
34+
localCurrencyCode,
35+
activePolicy,
36+
translate,
37+
formatPhoneNumber,
38+
isRestrictedPolicyCreation,
39+
hasActiveAdminPolicies,
40+
onboardingMessages,
41+
lastWorkspaceNumber,
42+
isSmallScreenWidth,
43+
} = useOnboardingWorkspaceCreationState();
44+
4045
const paidGroupPolicySelector = useMemo(
41-
() => (policies: OnyxCollection<Policy>) => Object.values(policies ?? {}).some((policy) => isPaidGroupPolicy(policy) && isPolicyAdmin(policy, session?.email)),
42-
[session?.email],
46+
() => (policies: OnyxCollection<Policy>) => Object.values(policies ?? {}).some((policy) => isPaidGroupPolicy(policy) && isPolicyAdmin(policy, currentUserEmail)),
47+
[currentUserEmail],
4348
);
4449
const [hasPaidGroupAdminPolicy] = useOnyx(ONYXKEYS.COLLECTION.POLICY, {selector: paidGroupPolicySelector});
50+
4551
const [conciergeChatReportID = ''] = useOnyx(ONYXKEYS.CONCIERGE_REPORT_ID);
4652
const [onboardingValues] = useOnyx(ONYXKEYS.NVP_ONBOARDING);
47-
const currentUserPersonalDetails = useCurrentUserPersonalDetails();
4853
const archivedReportsIdSet = useArchivedReportsIdSet();
4954
const {isBetaEnabled} = usePermissions();
50-
const {translate, formatPhoneNumber} = useLocalize();
51-
const activePolicy = useActivePolicy();
52-
const {isRestrictedPolicyCreation} = usePreferredPolicy();
53-
const hasActiveAdminPolicies = useHasActiveAdminPolicies();
54-
const lastWorkspaceNumber = useLastWorkspaceNumber();
55-
const {onboardingMessages} = useOnboardingMessages();
56-
57-
// We use isSmallScreenWidth instead of shouldUseNarrowLayout because navigateAfterOnboarding
58-
// relies on actual device screen width to handle navigation stack differences: on small screens,
59-
// removing OnboardingModalNavigator redirects to HOME, requiring explicit navigation to the last
60-
// accessed report. This behavior is tied to screen size, not responsive layout mode.
61-
// eslint-disable-next-line rulesdir/prefer-shouldUseNarrowLayout-instead-of-isSmallScreenWidth
62-
const {isSmallScreenWidth} = useResponsiveLayout();
6355

6456
const mergedAccountConciergeReportID = !onboardingValues?.shouldRedirectToClassicAfterMerge && onboardingValues?.shouldValidate ? conciergeChatReportID : undefined;
6557

6658
const autoCreateTrackWorkspace = useCallback(
6759
async (firstName: string, lastName: string, onboardingPurposeSelected: OnboardingPurpose) => {
6860
const shouldCreateWorkspace = !isRestrictedPolicyCreation && !onboardingPolicyID && !hasPaidGroupAdminPolicy;
69-
const displayName = createDisplayName(session?.email ?? '', {firstName, lastName}, formatPhoneNumber);
61+
const displayName = createDisplayName(currentUserEmail, {firstName, lastName}, formatPhoneNumber);
7062

7163
const {adminsChatReportID: newAdminsChatReportID, policyID: newPolicyID} = shouldCreateWorkspace
7264
? createWorkspace({
7365
policyOwnerEmail: undefined,
7466
makeMeAdmin: true,
75-
policyName: generateDefaultWorkspaceName(session?.email ?? '', lastWorkspaceNumber, translate, displayName),
67+
policyName: generateDefaultWorkspaceName(currentUserEmail, lastWorkspaceNumber, translate, displayName),
7668
policyID: generatePolicyID(),
7769
engagementChoice: CONST.ONBOARDING_CHOICES.TRACK_WORKSPACE,
78-
currency: currentUserPersonalDetails.localCurrencyCode ?? CONST.CURRENCY.USD,
70+
currency: localCurrencyCode,
7971
file: undefined,
8072
shouldAddOnboardingTasks: false,
8173
introSelected,
8274
activePolicy,
83-
currentUserAccountIDParam: session?.accountID ?? CONST.DEFAULT_NUMBER_ID,
84-
currentUserEmailParam: session?.email ?? '',
75+
currentUserAccountIDParam: currentUserAccountID,
76+
currentUserEmailParam: currentUserEmail,
8577
shouldAddGuideWelcomeMessage: false,
8678
onboardingPurposeSelected,
8779
betas,
@@ -129,16 +121,16 @@ function useAutoCreateTrackWorkspace() {
129121
}
130122
},
131123
[
132-
session?.email,
133-
session?.accountID,
124+
currentUserEmail,
125+
currentUserAccountID,
134126
lastWorkspaceNumber,
135127
translate,
136128
formatPhoneNumber,
137129
isRestrictedPolicyCreation,
138130
onboardingPolicyID,
139131
hasPaidGroupAdminPolicy,
140132
onboardingAdminsChatReportID,
141-
currentUserPersonalDetails.localCurrencyCode,
133+
localCurrencyCode,
142134
introSelected,
143135
activePolicy,
144136
isSelfTourViewed,
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import {hasSeenTourSelector} from '@selectors/Onboarding';
2+
import CONST from '@src/CONST';
3+
import ONYXKEYS from '@src/ONYXKEYS';
4+
import useActivePolicy from './useActivePolicy';
5+
import useCurrentUserPersonalDetails from './useCurrentUserPersonalDetails';
6+
import useHasActiveAdminPolicies from './useHasActiveAdminPolicies';
7+
import useLastWorkspaceNumber from './useLastWorkspaceNumber';
8+
import useLocalize from './useLocalize';
9+
import useOnboardingMessages from './useOnboardingMessages';
10+
import useOnyx from './useOnyx';
11+
import usePreferredPolicy from './usePreferredPolicy';
12+
import useResponsiveLayout from './useResponsiveLayout';
13+
14+
/**
15+
* Shared state for the onboarding workspace auto-creation hooks
16+
* (`useAutoCreateSubmitWorkspace`, `useAutoCreateTrackWorkspace`).
17+
*
18+
* Email and accountID come from `ONYXKEYS.SESSION` because session is hydrated
19+
* earlier in onboarding than personal details.
20+
*/
21+
function useOnboardingWorkspaceCreationState() {
22+
const [onboardingPolicyID] = useOnyx(ONYXKEYS.ONBOARDING_POLICY_ID);
23+
const [onboardingAdminsChatReportID] = useOnyx(ONYXKEYS.ONBOARDING_ADMINS_CHAT_REPORT_ID);
24+
const [introSelected] = useOnyx(ONYXKEYS.NVP_INTRO_SELECTED);
25+
const [isSelfTourViewed] = useOnyx(ONYXKEYS.NVP_ONBOARDING, {selector: hasSeenTourSelector});
26+
const [betas] = useOnyx(ONYXKEYS.BETAS);
27+
const [session] = useOnyx(ONYXKEYS.SESSION);
28+
29+
const currentUserEmail = session?.email ?? '';
30+
const currentUserAccountID = session?.accountID ?? CONST.DEFAULT_NUMBER_ID;
31+
32+
const currentUserPersonalDetails = useCurrentUserPersonalDetails();
33+
const localCurrencyCode = currentUserPersonalDetails.localCurrencyCode ?? CONST.CURRENCY.USD;
34+
35+
const activePolicy = useActivePolicy();
36+
const {translate, formatPhoneNumber} = useLocalize();
37+
const {isRestrictedPolicyCreation} = usePreferredPolicy();
38+
const hasActiveAdminPolicies = useHasActiveAdminPolicies();
39+
const {onboardingMessages} = useOnboardingMessages();
40+
const lastWorkspaceNumber = useLastWorkspaceNumber();
41+
42+
// eslint-disable-next-line rulesdir/prefer-shouldUseNarrowLayout-instead-of-isSmallScreenWidth
43+
const {isSmallScreenWidth} = useResponsiveLayout();
44+
45+
return {
46+
onboardingPolicyID,
47+
onboardingAdminsChatReportID,
48+
introSelected,
49+
isSelfTourViewed,
50+
betas,
51+
currentUserPersonalDetails,
52+
currentUserEmail,
53+
currentUserAccountID,
54+
localCurrencyCode,
55+
activePolicy,
56+
translate,
57+
formatPhoneNumber,
58+
isRestrictedPolicyCreation,
59+
hasActiveAdminPolicies,
60+
onboardingMessages,
61+
lastWorkspaceNumber,
62+
isSmallScreenWidth,
63+
};
64+
}
65+
66+
export default useOnboardingWorkspaceCreationState;

0 commit comments

Comments
 (0)