Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 19 additions & 5 deletions src/hooks/usePolicyForMovingExpenses.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import type {Policy} from '@src/types/onyx';
import {isEmptyObject} from '@src/types/utils/EmptyObject';
import isLoadingOnyxValue from '@src/types/utils/isLoadingOnyxValue';

import type {OnyxCollection, OnyxEntry} from 'react-native-onyx';

Expand Down Expand Up @@ -100,7 +101,7 @@ function usePolicyForMovingExpenses(isPerDiemRequest?: boolean, isTimeRequest?:
// Contextual selector — captures login/flags from closure.
// Returns only IDs + flags (stable output) to prevent re-renders when unrelated policies change.
const policyQualificationSelector = (policies: OnyxCollection<Policy>) => getPolicyQualificationResult(policies, login, isPerDiemRequest, isTimeRequest, expensePolicyID);
const [qualificationResult] = useOnyx(ONYXKEYS.COLLECTION.POLICY, {
const [qualificationResult, policiesLoadStatus] = useOnyx(ONYXKEYS.COLLECTION.POLICY, {
selector: policyQualificationSelector,
});

Expand All @@ -110,17 +111,30 @@ function usePolicyForMovingExpenses(isPerDiemRequest?: boolean, isTimeRequest?:
const resolvedPolicyID = validExpensePolicyID ?? singlePolicyID;
const [resolvedPolicy] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${resolvedPolicyID}`);

// User has no eligible policy
if (!resolvedPolicyID) {
return {policyForMovingExpensesID: undefined, policyForMovingExpenses: undefined, shouldSelectPolicy: false, shouldNavigateToUpgradePath: true};
}
// Gate the upgrade path on policy hydration. Without this, during Onyx cold-start the collection reads
// empty and we'd report that a member of a group workspace has none, sending them to MONEY_REQUEST_UPGRADE.
// `useCreateReport` guards the same way.
const arePoliciesLoaded = !isLoadingOnyxValue(policiesLoadStatus);

// If this is an employee's card transaction that we manage, then we should report it to their default policy
// which we don't know. Sending an empty `policyID` instructs the backend to auto-select the preferred policy.
// This never depends on a locally resolved policy, so it has to be answered before the upgrade path below.
if (isUnreportedManagedCardTransaction) {
return {policyForMovingExpensesID: undefined, policyForMovingExpenses: undefined, shouldSelectPolicy: false, shouldNavigateToUpgradePath: false};
}

// User has no eligible policy
if (!resolvedPolicyID) {
// The active workspace can still be a valid destination even when the qualification pass came back
// empty, so check it before giving up. This has to run ahead of the upgrade path below, otherwise a
// perfectly valid active workspace can never rescue the user.
if (isPolicyValidForMovingExpenses(activePolicy, login, isPerDiemRequest, isTimeRequest)) {
return {policyForMovingExpensesID: activePolicyID, policyForMovingExpenses: activePolicy, shouldSelectPolicy: false, shouldNavigateToUpgradePath: false};
}

return {policyForMovingExpensesID: undefined, policyForMovingExpenses: undefined, shouldSelectPolicy: false, shouldNavigateToUpgradePath: arePoliciesLoaded};
}

// If an expense policy ID is provided and valid, prefer it over the active policy
if (validExpensePolicyID) {
return {policyForMovingExpensesID: validExpensePolicyID, policyForMovingExpenses: resolvedPolicy, shouldSelectPolicy: false, shouldNavigateToUpgradePath: false};
Expand Down
4 changes: 3 additions & 1 deletion src/pages/Search/EmptySearchView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,9 @@ function EmptySearchView({similarSearchHash, type, hasResults, queryJSON, violat
const [activePolicyID] = useOnyx(ONYXKEYS.NVP_ACTIVE_POLICY_ID);
const [activePolicy] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${activePolicyID}`);

const groupPoliciesWithChatEnabled = getGroupPoliciesWhereReportCanBeCreated(allPolicies);
// The login is required for the `employeeList` role fallback in `getPolicyRole`. Without it, every policy
// that only carries the member's role in `employeeList` is filtered out and the user looks workspace-less.
const groupPoliciesWithChatEnabled = getGroupPoliciesWhereReportCanBeCreated(allPolicies, currentUserPersonalDetails?.login);

const [hasSeenTour = false] = useOnyx(ONYXKEYS.NVP_ONBOARDING, {
selector: hasSeenTourSelector,
Expand Down
Loading