diff --git a/src/components/AvatarWithDisplayName.tsx b/src/components/AvatarWithDisplayName.tsx index bb22c76f2fc4..9c8a8cebe990 100644 --- a/src/components/AvatarWithDisplayName.tsx +++ b/src/components/AvatarWithDisplayName.tsx @@ -292,6 +292,7 @@ function AvatarWithDisplayName({ isAnonymous, isMoneyRequestOrReport, ); + const pressableStyles = [styles.alignSelfStart, styles.mw100]; const multipleAvatars = ( 0 && ( !!transaction && transaction.reportID === reportID); +} + // This component allows us to block various actions by forcing the user to first add a default payment method and successfully make it through our Know Your Customer flow // before continuing to take whatever action they originally intended to take. It requires a button as a child and a native event so we can get the coordinates and use it // to render the AddPaymentMethodMenu in the correct location. @@ -67,33 +75,11 @@ function KYCWall({ shouldShowPersonalBankAccountOption = false, ref, }: KYCWallProps) { - const [userWallet] = useOnyx(ONYXKEYS.USER_WALLET); - const [walletTerms] = useOnyx(ONYXKEYS.WALLET_TERMS); - const [fundList] = useOnyx(ONYXKEYS.FUND_LIST); - const [bankAccountList = getEmptyObject()] = useOnyx(ONYXKEYS.BANK_ACCOUNT_LIST); - const [chatReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${chatReportID}`); - const [policies] = useOnyx(ONYXKEYS.COLLECTION.POLICY); - const [introSelected] = useOnyx(ONYXKEYS.NVP_INTRO_SELECTED); - const [isSelfTourViewed] = useOnyx(ONYXKEYS.NVP_ONBOARDING, {selector: hasSeenTourSelector}); - const [betas] = useOnyx(ONYXKEYS.BETAS); - const ownerAccountID = iouReport?.ownerAccountID; - const employeeLoginSelector = useCallback((personalDetailsList: OnyxEntry) => personalDetailsLoginSelector(ownerAccountID)(personalDetailsList), [ownerAccountID]); - const [employeeLogin] = useOnyx(ONYXKEYS.PERSONAL_DETAILS_LIST, {selector: employeeLoginSelector}); - const doesSubmitterPersonalDetailExistSelector = useCallback( - (personalDetailsList: OnyxEntry) => doesPersonalDetailExistSelector(ownerAccountID)(personalDetailsList), - [ownerAccountID], - ); - const [doesSubmitterPersonalDetailExist] = useOnyx(ONYXKEYS.PERSONAL_DETAILS_LIST, {selector: doesSubmitterPersonalDetailExistSelector}); - const {translate} = useLocalize(); const currentUserDetails = useCurrentUserPersonalDetails(); const currentUserAccountID = currentUserDetails.accountID; const currentUserEmail = currentUserDetails.email ?? ''; const localCurrency = currentUserDetails.localCurrencyCode ?? CONST.CURRENCY.USD; - const reportPreviewAction = useParentReportAction(iouReport); - const reportTransactions = useReportTransactions(iouReport?.reportID); - const [allReports] = useOnyx(ONYXKEYS.COLLECTION.REPORT); - const [allReportActions] = useOnyx(ONYXKEYS.COLLECTION.REPORT_ACTIONS); const anchorRef = useRef(null); const transferBalanceButtonRef = useRef(null); @@ -107,8 +93,6 @@ function KYCWall({ anchorPositionHorizontal: 0, }); - const [lastPaymentMethod] = useOnyx(ONYXKEYS.NVP_LAST_PAYMENT_METHOD); - const getAnchorPosition = useCallback( (domRect: DomRect): AnchorPosition => { if (anchorAlignment.vertical === CONST.MODAL.ANCHOR_ORIGIN_VERTICAL.TOP) { @@ -148,6 +132,23 @@ function KYCWall({ const selectPaymentMethod = useCallback( (paymentMethod?: PaymentMethod, policy?: Policy, personalBankAccountOnSuccessFallbackRoute?: Route) => { + const bankAccountList = OnyxUtils.get(ONYXKEYS.BANK_ACCOUNT_LIST) ?? getEmptyObject(); + const policies = OnyxUtils.getCachedCollection(ONYXKEYS.COLLECTION.POLICY); + const allReports = OnyxUtils.getCachedCollection(ONYXKEYS.COLLECTION.REPORT); + const allReportActions = OnyxUtils.getCachedCollection(ONYXKEYS.COLLECTION.REPORT_ACTIONS); + const chatReport = OnyxUtils.get(`${ONYXKEYS.COLLECTION.REPORT}${chatReportID}` as const); + const lastPaymentMethod = OnyxUtils.get(ONYXKEYS.NVP_LAST_PAYMENT_METHOD); + const introSelected = OnyxUtils.get(ONYXKEYS.NVP_INTRO_SELECTED); + const isSelfTourViewed = hasSeenTourSelector(OnyxUtils.get(ONYXKEYS.NVP_ONBOARDING)); + const betas = OnyxUtils.get(ONYXKEYS.BETAS); + const personalDetailsList = OnyxUtils.get(ONYXKEYS.PERSONAL_DETAILS_LIST); + const employeeLogin = personalDetailsLoginSelector(iouReport?.ownerAccountID)(personalDetailsList); + const doesSubmitterPersonalDetailExist = doesPersonalDetailExistSelector(iouReport?.ownerAccountID)(personalDetailsList); + const reportPreviewAction = getParentReportActionSelector( + OnyxUtils.get(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${getNonEmptyStringOnyxID(iouReport?.parentReportID)}` as const), + iouReport?.parentReportActionID, + ); + const reportTransactions = getReportTransactionsForReport(iouReport?.reportID); const canLinkExistingBusinessBankAccount = getEligibleExistingBusinessBankAccounts(bankAccountList, policy?.outputCurrency, true).length > 0; if (paymentMethod) { @@ -252,27 +253,15 @@ function KYCWall({ } }, [ - bankAccountList, getPersonalBankAccountOnSuccessFallbackRoute, onSelectPaymentMethod, iouReport, addDebitCardRoute, addBankAccountRoute, - chatReport, - policies, - reportPreviewAction, + chatReportID, currentUserAccountID, currentUserEmail, - employeeLogin, - doesSubmitterPersonalDetailExist, - introSelected, translate, - reportTransactions, - allReports, - allReportActions, - lastPaymentMethod, - isSelfTourViewed, - betas, localCurrency, ], ); @@ -286,6 +275,10 @@ function KYCWall({ const continueAction = useCallback( (params?: ContinueActionParams) => { const {event, iouPaymentType, paymentMethod, policy, goBackRoute, personalBankAccountOnSuccessFallbackRoute} = params ?? {}; + const walletTerms = OnyxUtils.get(ONYXKEYS.WALLET_TERMS); + const fundList = OnyxUtils.get(ONYXKEYS.FUND_LIST); + const bankAccountList = OnyxUtils.get(ONYXKEYS.BANK_ACCOUNT_LIST) ?? getEmptyObject(); + const userWallet = OnyxUtils.get(ONYXKEYS.USER_WALLET); const currentSource = walletTerms?.source ?? source; /** @@ -375,21 +368,7 @@ function KYCWall({ onSuccessfulKYC(iouPaymentType, currentSource); }, - [ - bankAccountList, - chatReportID, - enablePaymentsRoute, - fundList, - getAnchorPosition, - iouReport, - onSuccessfulKYC, - selectPaymentMethod, - shouldIncludeDebitCard, - shouldShowAddPaymentMenu, - source, - userWallet?.tierName, - walletTerms?.source, - ], + [chatReportID, enablePaymentsRoute, getAnchorPosition, iouReport, onSuccessfulKYC, selectPaymentMethod, shouldIncludeDebitCard, shouldShowAddPaymentMenu, source], ); useEffect(() => { diff --git a/src/components/ParentNavigationSubtitle.tsx b/src/components/ParentNavigationSubtitle.tsx index 5537e13351f5..ea634b9ee874 100644 --- a/src/components/ParentNavigationSubtitle.tsx +++ b/src/components/ParentNavigationSubtitle.tsx @@ -1,7 +1,5 @@ import useHover from '@hooks/useHover'; import useLocalize from '@hooks/useLocalize'; -import useOnyx from '@hooks/useOnyx'; -import useReportIsArchived from '@hooks/useReportIsArchived'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useRootNavigationState from '@hooks/useRootNavigationState'; import useStyleUtils from '@hooks/useStyleUtils'; @@ -12,7 +10,7 @@ import {isFullScreenName} from '@libs/Navigation/helpers/isNavigatorName'; import Navigation from '@libs/Navigation/Navigation'; import type {RightModalNavigatorParamList} from '@libs/Navigation/types'; import {getReportAction, isReportActionVisible} from '@libs/ReportActionsUtils'; -import {canUserPerformWriteAction as canUserPerformWriteActionReportUtils, isMoneyRequestReport} from '@libs/ReportUtils'; +import {canUserPerformWriteAction as canUserPerformWriteActionReportUtils, isArchivedReport, isMoneyRequestReport} from '@libs/ReportUtils'; import CONST from '@src/CONST'; import type {ParentNavigationSummaryParams} from '@src/languages/params'; @@ -26,6 +24,7 @@ import type {ColorValue, StyleProp, TextStyle, ViewStyle} from 'react-native'; import {useRoute} from '@react-navigation/native'; import React from 'react'; import {View} from 'react-native'; +import OnyxUtils from 'react-native-onyx/dist/OnyxUtils'; import StatusBadge from './StatusBadge'; import Text from './Text'; @@ -34,8 +33,8 @@ import TextLink from './TextLink'; type ParentNavigationSubtitleProps = { parentNavigationSubtitleData: ParentNavigationSummaryParams; - /** Current Report ID (to check hasParentAccess) */ - reportID?: string; + /** Whether the user has access to the parent report */ + hasParentAccess?: boolean; /** parent Report ID */ parentReportID?: string; @@ -82,7 +81,6 @@ type ParentNavigationSubtitleProps = { function ParentNavigationSubtitle({ parentNavigationSubtitleData, - reportID = '', parentReportActionID, parentReportID = '', pressableStyles, @@ -97,6 +95,7 @@ function ParentNavigationSubtitle({ humanAgentAccountID, humanAgentName, shouldShowFromPrefix = true, + hasParentAccess, }: ParentNavigationSubtitleProps) { const currentRoute = useRoute(); // We intentionally use isSmallScreenWidth (real device width), not shouldUseNarrowLayout — the latter is @@ -113,12 +112,7 @@ function ParentNavigationSubtitle({ const {workspaceName, reportName} = parentNavigationSubtitleData; const {translate} = useLocalize(); - const [currentReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${reportID}`); - const [report] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${parentReportID}`); - const [visibleReportActionsData] = useOnyx(ONYXKEYS.DERIVED.VISIBLE_REPORT_ACTIONS); - const isReportArchived = useReportIsArchived(report?.reportID); - const canUserPerformWriteAction = canUserPerformWriteActionReportUtils(report, isReportArchived); - const hasAccessToParentReport = currentReport?.hasParentAccess !== false; + const hasAccessToParentReport = hasParentAccess !== false; const {currentFullScreenRoute, currentFocusedNavigator} = useRootNavigationState((state) => { // Find the tab navigator, which wraps all full-screen navigators const tabNavigatorRoute = state?.routes?.findLast((route) => route.name === NAVIGATORS.TAB_NAVIGATOR); @@ -154,8 +148,11 @@ function ParentNavigationSubtitle({ } const onPress = () => { + const report = OnyxUtils.get(`${ONYXKEYS.COLLECTION.REPORT}${parentReportID}` as const); + const isParentReportArchived = !!isArchivedReport(OnyxUtils.get(`${ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS}${parentReportID}` as const)); + const canUserPerformWriteAction = canUserPerformWriteActionReportUtils(report, isParentReportArchived); const parentAction = getReportAction(parentReportID, parentReportActionID); - const isVisibleAction = isReportActionVisible(parentAction, parentReportID, canUserPerformWriteAction, visibleReportActionsData); + const isVisibleAction = isReportActionVisible(parentAction, parentReportID, canUserPerformWriteAction, OnyxUtils.get(ONYXKEYS.DERIVED.VISIBLE_REPORT_ACTIONS)); const focusedNavigatorState = currentFocusedNavigator?.state; const currentReportIndex = focusedNavigatorState?.index; diff --git a/src/components/Search/SearchList/ListItem/ActionCell/PayActionCell.tsx b/src/components/Search/SearchList/ListItem/ActionCell/PayActionCell.tsx index 8f3fc18b3275..de259ffef2ce 100644 --- a/src/components/Search/SearchList/ListItem/ActionCell/PayActionCell.tsx +++ b/src/components/Search/SearchList/ListItem/ActionCell/PayActionCell.tsx @@ -27,6 +27,7 @@ import type {OnyxEntry} from 'react-native-onyx'; import {isTrackIntentUserSelector} from '@selectors/Onboarding'; import React from 'react'; +import OnyxUtils from 'react-native-onyx/dist/OnyxUtils'; type PayActionCellProps = { isLoading: boolean; @@ -47,10 +48,6 @@ function PayActionCell({isLoading, policyID, reportID, hash, amount, shouldDisab const [iouReport, transactions] = useReportWithTransactionsAndViolations(reportID); const policy = usePolicy(policyID); const [bankAccountList] = useOnyx(ONYXKEYS.BANK_ACCOUNT_LIST); - const [allReports] = useOnyx(ONYXKEYS.COLLECTION.REPORT); - const [allReportActions] = useOnyx(ONYXKEYS.COLLECTION.REPORT_ACTIONS); - const [reportNameValuePairs] = useOnyx(ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS); - const [isTrackIntentUser] = useOnyx(ONYXKEYS.NVP_INTRO_SELECTED, {selector: isTrackIntentUserSelector}); const invoiceReceiverPolicyID = chatReport?.invoiceReceiver && 'policyID' in chatReport.invoiceReceiver ? chatReport.invoiceReceiver.policyID : undefined; const invoiceReceiverPolicy = usePolicy(invoiceReceiverPolicyID); @@ -94,11 +91,12 @@ function PayActionCell({isLoading, policyID, reportID, hash, amount, shouldDisab } const additionalOnyxData = getSearchPayOnyxData(hash, reportID); + const isTrackIntentUser = isTrackIntentUserSelector(OnyxUtils.get(ONYXKEYS.NVP_INTRO_SELECTED)); if (isInvoiceReport(iouReport)) { const existingB2BInvoiceReport = getParticipantsInvoiceReport( - allReports, - reportNameValuePairs, + OnyxUtils.getCachedCollection(ONYXKEYS.COLLECTION.REPORT), + OnyxUtils.getCachedCollection(ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS), activePolicyID, CONST.REPORT.INVOICE_RECEIVER_TYPE.BUSINESS, invoiceReceiverPolicyID ?? chatReport?.policyID, @@ -108,8 +106,9 @@ function PayActionCell({isLoading, policyID, reportID, hash, amount, shouldDisab // when paying an individual invoice room as a business. `payAsBusiness` is only known at click time, so pick // the right report's actions here in the function scope. const shouldUseB2BInvoiceReport = !!payAsBusiness && !!existingB2BInvoiceReport && isIndividualInvoiceRoom(chatReport); - const chatReportActions = - allReportActions?.[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${getNonEmptyStringOnyxID(shouldUseB2BInvoiceReport ? existingB2BInvoiceReport?.reportID : chatReport?.reportID)}`]; + const chatReportActions = OnyxUtils.get( + `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${getNonEmptyStringOnyxID(shouldUseB2BInvoiceReport ? existingB2BInvoiceReport?.reportID : chatReport?.reportID)}` as const, + ); payInvoice({ paymentMethodType: type, @@ -155,7 +154,7 @@ function PayActionCell({isLoading, policyID, reportID, hash, amount, shouldDisab ownerBillingGracePeriodEnd, methodID: type === CONST.IOU.PAYMENT_TYPE.VBBA ? methodID : undefined, additionalOnyxData, - chatReportActions: allReportActions?.[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${getNonEmptyStringOnyxID(chatReport?.reportID)}`], + chatReportActions: OnyxUtils.get(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${getNonEmptyStringOnyxID(chatReport?.reportID)}` as const), delegateAccountID, isTrackIntentUser, }); diff --git a/src/components/SettlementButton/index.tsx b/src/components/SettlementButton/index.tsx index 2c5d205c68d6..88d2a7b7fe69 100644 --- a/src/components/SettlementButton/index.tsx +++ b/src/components/SettlementButton/index.tsx @@ -11,8 +11,7 @@ import RenderHTML from '@components/RenderHTML'; import useActiveAdminPolicies from '@hooks/useActiveAdminPolicies'; import useConfirmModal from '@hooks/useConfirmModal'; import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails'; -import useDelegateAccountID from '@hooks/useDelegateAccountID'; -import useLastWorkspaceNumber from '@hooks/useLastWorkspaceNumber'; +import {getDelegateAccountIDSync} from '@hooks/useDelegateAccountID'; import {useMemoizedLazyExpensifyIcons} from '@hooks/useLazyAsset'; import useLocalize from '@hooks/useLocalize'; import useNetwork from '@hooks/useNetwork'; @@ -29,7 +28,7 @@ import createDynamicRoute from '@libs/Navigation/helpers/dynamicRoutesUtils/crea import Navigation from '@libs/Navigation/Navigation'; import {isTrackOnboardingChoice} from '@libs/OnboardingUtils'; import {formatPaymentMethods, getActivePaymentType, getBusinessBankAccountOptions, matchesCurrency} from '@libs/PaymentUtils'; -import {isPaidGroupPolicy, isPolicyAdmin, sortPoliciesByName} from '@libs/PolicyUtils'; +import {getPolicyIDOrDefault, isPaidGroupPolicy, isPolicyAdmin, sortPoliciesByName} from '@libs/PolicyUtils'; import {hasRequestFromCurrentAccount} from '@libs/ReportActionsUtils'; import { doesReportBelongToWorkspace, @@ -61,9 +60,12 @@ import type {TupleToUnion} from 'type-fest'; import {delegateEmailSelector, isUserValidatedSelector} from '@selectors/Account'; import {hasSeenTourSelector} from '@selectors/Onboarding'; import {personalDetailsLoginSelector} from '@selectors/PersonalDetails'; +import {lastWorkspaceNumberSelector} from '@selectors/Policy'; +import {emailSelector} from '@selectors/Session'; import truncate from 'lodash/truncate'; import React, {useCallback, useContext} from 'react'; import {View} from 'react-native'; +import OnyxUtils from 'react-native-onyx/dist/OnyxUtils'; import type SettlementButtonProps from './types'; @@ -117,19 +119,12 @@ function SettlementButton({ const {translate, localeCompare} = useLocalize(); const {isOffline} = useNetwork(); const policy = usePolicy(policyID); - const expenseReportPolicy = usePolicy(iouReport?.policyID); const {accountID, email = ''} = useCurrentUserPersonalDetails(); - const lastWorkspaceNumber = useLastWorkspaceNumber(); // The app would crash due to subscribing to the entire report collection if chatReportID is an empty string. So we should have a fallback ID here. // eslint-disable-next-line rulesdir/no-default-id-values const [chatReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${chatReportID || CONST.DEFAULT_NUMBER_ID}`); const [conciergeReportID] = useOnyx(ONYXKEYS.CONCIERGE_REPORT_ID); - const [conciergeChat] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${conciergeReportID}`); - const [iouReportNextStep] = useOnyx(`${ONYXKEYS.COLLECTION.NEXT_STEP}${iouReport?.reportID}`); - const [ownerLogin] = useOnyx(ONYXKEYS.PERSONAL_DETAILS_LIST, {selector: personalDetailsLoginSelector(iouReport?.ownerAccountID)}); - const [isUserValidated] = useOnyx(ONYXKEYS.ACCOUNT, {selector: isUserValidatedSelector}); - const [amountOwed] = useOnyx(ONYXKEYS.NVP_PRIVATE_AMOUNT_OWED); const reportBelongsToWorkspace = policyID ? doesReportBelongToWorkspace(chatReport, policyID, conciergeReportID) : false; const policyIDKey = reportBelongsToWorkspace ? policyID : (iouReport?.policyID ?? CONST.POLICY.ID_FAKE); const [userWallet] = useOnyx(ONYXKEYS.USER_WALLET); @@ -137,9 +132,6 @@ function SettlementButton({ const paymentMethods = useSettlementButtonPaymentMethods(hasActivatedWallet, translate); const [lastPaymentMethods] = useOnyx(ONYXKEYS.NVP_LAST_PAYMENT_METHOD); const [personalPolicyID] = useOnyx(ONYXKEYS.PERSONAL_POLICY_ID); - const [betas] = useOnyx(ONYXKEYS.BETAS); - const [userBillingGracePeriodEnds] = useOnyx(ONYXKEYS.COLLECTION.SHARED_NVP_PRIVATE_USER_BILLING_GRACE_PERIOD_END); - const [ownerBillingGracePeriodEnd] = useOnyx(ONYXKEYS.NVP_PRIVATE_OWNER_BILLING_GRACE_PERIOD_END); const lastPaymentMethod = iouReport?.type ? getLastPolicyPaymentMethod(policyIDKey, personalPolicyID, lastPaymentMethods, iouReport?.type as keyof LastPaymentMethodType, isIOUReport(iouReport)) @@ -172,17 +164,10 @@ function SettlementButton({ policy?.achAccount?.state === CONST.BANK_ACCOUNT.STATE.LOCKED) && !lastPaymentMethod; const {isBetaEnabled} = usePermissions(); - const [introSelected] = useOnyx(ONYXKEYS.NVP_INTRO_SELECTED); - const [isSelfTourViewed] = useOnyx(ONYXKEYS.NVP_ONBOARDING, {selector: hasSeenTourSelector}); const currentUserPersonalDetails = useCurrentUserPersonalDetails(); - const [transactionViolations] = useOnyx(ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS); - const [delegateEmail] = useOnyx(ONYXKEYS.ACCOUNT, {selector: delegateEmailSelector}); - const isTrackIntentUser = isTrackOnboardingChoice(introSelected?.choice); - const delegateAccountID = useDelegateAccountID(); const isASAPSubmitBetaEnabled = isBetaEnabled(CONST.BETAS.ASAP_SUBMIT); const isPayInvoiceViaExpensifyBetaEnabled = isBetaEnabled(CONST.BETAS.PAY_INVOICE_VIA_EXPENSIFY); - const hasViolations = hasViolationsReportUtils(iouReport?.reportID, transactionViolations, accountID, email); const isInvoiceReport = (!isEmptyObject(iouReport) && isInvoiceReportUtil(iouReport)) || false; @@ -212,6 +197,7 @@ function SettlementButton({ return true; } + const isUserValidated = isUserValidatedSelector(OnyxUtils.get(ONYXKEYS.ACCOUNT)); if (!isUserValidated && paymentMethodType !== CONST.IOU.PAYMENT_TYPE.ELSEWHERE) { Navigation.navigate(createDynamicRoute(DYNAMIC_ROUTES.VERIFY_ACCOUNT.path)); return true; @@ -234,13 +220,28 @@ function SettlementButton({ if (policy?.achAccount?.bankAccountID === undefined) { return; } - pressLockedBankAccount(policy?.achAccount?.bankAccountID, translate, conciergeReportID, delegateAccountID); - navigateToConciergeChat(conciergeReportID, introSelected, currentUserAccountID, isSelfTourViewed, betas); + pressLockedBankAccount(policy?.achAccount?.bankAccountID, translate, conciergeReportID, getDelegateAccountIDSync()); + navigateToConciergeChat( + conciergeReportID, + OnyxUtils.get(ONYXKEYS.NVP_INTRO_SELECTED), + currentUserAccountID, + hasSeenTourSelector(OnyxUtils.get(ONYXKEYS.NVP_ONBOARDING)), + OnyxUtils.get(ONYXKEYS.BETAS), + ); }); return true; } - if (policy && shouldRestrictUserBillableActions(policy, ownerBillingGracePeriodEnd, userBillingGracePeriodEnds, amountOwed, currentUserAccountID)) { + if ( + policy && + shouldRestrictUserBillableActions( + policy, + OnyxUtils.get(ONYXKEYS.NVP_PRIVATE_OWNER_BILLING_GRACE_PERIOD_END), + OnyxUtils.getCachedCollection(ONYXKEYS.COLLECTION.SHARED_NVP_PRIVATE_USER_BILLING_GRACE_PERIOD_END), + OnyxUtils.get(ONYXKEYS.NVP_PRIVATE_AMOUNT_OWED), + currentUserAccountID, + ) + ) { Navigation.navigate(ROUTES.RESTRICTED_ACTION.getRoute(policy.id)); return true; } @@ -250,11 +251,8 @@ function SettlementButton({ [ isDelegateAccessRestricted, isAccountLocked, - isUserValidated, isBankAccountLocked, policy, - userBillingGracePeriodEnds, - ownerBillingGracePeriodEnd, showDelegateNoAccessModal, showLockedAccountModal, showConfirmModal, @@ -262,12 +260,7 @@ function SettlementButton({ styles.renderHTML, styles.flexRow, conciergeReportID, - introSelected, currentUserAccountID, - isSelfTourViewed, - betas, - amountOwed, - delegateAccountID, ], ); @@ -430,15 +423,17 @@ function SettlementButton({ return activePolicy.id; } + const conciergeReportIDForWorkspace = OnyxUtils.get(ONYXKEYS.CONCIERGE_REPORT_ID); + const lastWorkspaceNumber = lastWorkspaceNumberSelector(OnyxUtils.getCachedCollection(ONYXKEYS.COLLECTION.POLICY), emailSelector(OnyxUtils.get(ONYXKEYS.SESSION)) ?? ''); return createWorkspace({ - introSelected, + introSelected: OnyxUtils.get(ONYXKEYS.NVP_INTRO_SELECTED), activePolicy, - conciergeChat, + conciergeChat: OnyxUtils.get(`${ONYXKEYS.COLLECTION.REPORT}${conciergeReportIDForWorkspace}` as const), currentUserAccountIDParam: currentUserPersonalDetails.accountID, currentUserEmailParam: email, currency: currentUserPersonalDetails.localCurrencyCode ?? CONST.CURRENCY.USD, - betas, - isSelfTourViewed, + betas: OnyxUtils.get(ONYXKEYS.BETAS), + isSelfTourViewed: hasSeenTourSelector(OnyxUtils.get(ONYXKEYS.NVP_ONBOARDING)), hasActiveAdminPolicies: !!activeAdminPolicies.length, policyName: generateDefaultWorkspaceName(email, lastWorkspaceNumber, translate), }).policyID; @@ -516,22 +511,23 @@ function SettlementButton({ if (confirmApproval) { confirmApproval(); } else { + const hasViolations = hasViolationsReportUtils(iouReport?.reportID, OnyxUtils.getCachedCollection(ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS), accountID, email); approveMoneyRequest({ expenseReport: iouReport, - expenseReportPolicy, + expenseReportPolicy: OnyxUtils.get(`${ONYXKEYS.COLLECTION.POLICY}${getPolicyIDOrDefault(iouReport?.policyID)}` as const), currentUserAccountIDParam: accountID, currentUserEmailParam: email ?? '', hasViolations, isASAPSubmitBetaEnabled, - expenseReportCurrentNextStepDeprecated: iouReportNextStep, - betas, - userBillingGracePeriodEnds, - amountOwed, - ownerBillingGracePeriodEnd, - ownerLogin, + expenseReportCurrentNextStepDeprecated: OnyxUtils.get(`${ONYXKEYS.COLLECTION.NEXT_STEP}${iouReport?.reportID}` as const), + betas: OnyxUtils.get(ONYXKEYS.BETAS), + userBillingGracePeriodEnds: OnyxUtils.getCachedCollection(ONYXKEYS.COLLECTION.SHARED_NVP_PRIVATE_USER_BILLING_GRACE_PERIOD_END), + amountOwed: OnyxUtils.get(ONYXKEYS.NVP_PRIVATE_AMOUNT_OWED), + ownerBillingGracePeriodEnd: OnyxUtils.get(ONYXKEYS.NVP_PRIVATE_OWNER_BILLING_GRACE_PERIOD_END), + ownerLogin: personalDetailsLoginSelector(iouReport?.ownerAccountID)(OnyxUtils.get(ONYXKEYS.PERSONAL_DETAILS_LIST)), full: false, - delegateEmail, - isTrackIntentUser, + delegateEmail: delegateEmailSelector(OnyxUtils.get(ONYXKEYS.ACCOUNT)), + isTrackIntentUser: isTrackOnboardingChoice(OnyxUtils.get(ONYXKEYS.NVP_INTRO_SELECTED)?.choice), }); } return; diff --git a/src/hooks/useDelegateAccountID.ts b/src/hooks/useDelegateAccountID.ts index 6e229d6f3c8d..c3e133a11036 100644 --- a/src/hooks/useDelegateAccountID.ts +++ b/src/hooks/useDelegateAccountID.ts @@ -4,9 +4,28 @@ import type {PersonalDetailsList} from '@src/types/onyx'; import type {OnyxEntry} from 'react-native-onyx'; import {delegateEmailSelector} from '@selectors/Account'; +import OnyxUtils from 'react-native-onyx/dist/OnyxUtils'; import useOnyx from './useOnyx'; +/** + * Synchronous, event-time equivalent of `useDelegateAccountID`. Reads from the Onyx cache so it can be + * called inside event handlers without any render-bound subscriptions. + */ +function getDelegateAccountIDSync(): number | undefined { + const lowerEmail = delegateEmailSelector(OnyxUtils.get(ONYXKEYS.ACCOUNT)).toLowerCase(); + if (!lowerEmail) { + return undefined; + } + const personalDetails = OnyxUtils.get(ONYXKEYS.PERSONAL_DETAILS_LIST); + for (const detail of Object.values(personalDetails ?? {})) { + if (detail?.login?.toLowerCase() === lowerEmail) { + return detail.accountID; + } + } + return undefined; +} + function useDelegateAccountID(): number | undefined { const [delegateEmail] = useOnyx(ONYXKEYS.ACCOUNT, {selector: delegateEmailSelector}); const lowerEmail = delegateEmail?.toLowerCase(); @@ -29,3 +48,4 @@ function useDelegateAccountID(): number | undefined { } export default useDelegateAccountID; +export {getDelegateAccountIDSync}; diff --git a/src/pages/DynamicReportDetailsPage.tsx b/src/pages/DynamicReportDetailsPage.tsx index 99a66f71706e..a49367d98d05 100644 --- a/src/pages/DynamicReportDetailsPage.tsx +++ b/src/pages/DynamicReportDetailsPage.tsx @@ -878,6 +878,9 @@ function DynamicReportDetailsPage({policy, report, route, reportMetadata, report const shouldShowEditableTitleField = caseID !== CASES.MONEY_REQUEST && canEditReportTitle(report, policy, currentUserPersonalDetails?.accountID); + const pressableStyles = [styles.mt1, styles.mw100]; + const textStyles = [styles.popoverMenuText, styles.flexShrink1, styles.preWrap, styles.mw100]; + const nameSectionFurtherDetailsContent = (