diff --git a/src/components/BookTravelButton.tsx b/src/components/BookTravelButton.tsx index 76b7555cfac1..4b3c9ceda60c 100644 --- a/src/components/BookTravelButton.tsx +++ b/src/components/BookTravelButton.tsx @@ -60,7 +60,7 @@ function BookTravelButton({text, shouldRenderErrorMessageBelowButton = false}: B const [sessionEmail] = useOnyx(ONYXKEYS.SESSION, {selector: (session) => session?.email, canBeMissing: false}); const primaryContactMethod = primaryLogin ?? sessionEmail ?? ''; const {setRootStatusBarEnabled} = useContext(CustomStatusBarAndBackgroundContext); - const {isBlockedFromSpotnanaTravel, isTravelVerified} = usePermissions(); + const {isBlockedFromSpotnanaTravel, isBetaEnabled} = usePermissions(); const [isPreventionModalVisible, setPreventionModalVisibility] = useState(false); const [isVerificationModalVisible, setVerificationModalVisibility] = useState(false); const [policies] = useOnyx(ONYXKEYS.COLLECTION.POLICY, {canBeMissing: false}); @@ -135,7 +135,7 @@ function BookTravelButton({text, shouldRenderErrorMessageBelowButton = false}: B }); } else if (isPolicyProvisioned) { navigateToAcceptTerms(CONST.TRAVEL.DEFAULT_DOMAIN); - } else if (!isTravelVerified) { + } else if (!isBetaEnabled(CONST.BETAS.IS_TRAVEL_VERIFIED)) { setVerificationModalVisibility(true); } // Determine the domain to associate with the workspace during provisioning in Spotnana. @@ -166,7 +166,7 @@ function BookTravelButton({text, shouldRenderErrorMessageBelowButton = false}: B setRootStatusBarEnabled, isUserValidated, groupPaidPolicies.length, - isTravelVerified, + isBetaEnabled, ]); return ( diff --git a/src/components/MoneyReportHeader.tsx b/src/components/MoneyReportHeader.tsx index 57f53da78e6d..3fe0a75bd4ef 100644 --- a/src/components/MoneyReportHeader.tsx +++ b/src/components/MoneyReportHeader.tsx @@ -620,7 +620,7 @@ function MoneyReportHeader({ ), }; - const {canUseRetractNewDot, canUseTableReportView, canUseNewDotSplits} = usePermissions(); + const {isBetaEnabled} = usePermissions(); const beginPDFExport = (reportID: string) => { setIsPDFModalVisible(true); @@ -639,11 +639,11 @@ function MoneyReportHeader({ reportNameValuePairs, reportActions, policies, - canUseRetractNewDot, - canUseTableReportView, - canUseNewDotSplits, + isBetaEnabled(CONST.BETAS.RETRACT_NEWDOT), + isBetaEnabled(CONST.BETAS.TABLE_REPORT_VIEW), + isBetaEnabled(CONST.BETAS.NEW_DOT_SPLITS), ); - }, [moneyRequestReport, transactions, violations, policy, reportNameValuePairs, reportActions, policies, canUseRetractNewDot, canUseTableReportView, canUseNewDotSplits]); + }, [moneyRequestReport, transactions, violations, policy, reportNameValuePairs, reportActions, policies, isBetaEnabled]); const secondaryActionsImplementation: Record< ValueOf, @@ -818,7 +818,7 @@ function MoneyReportHeader({ setIsDeleteReportModalVisible(true); } }, - shouldShow: canUseTableReportView, + shouldShow: isBetaEnabled(CONST.BETAS.TABLE_REPORT_VIEW), }, [CONST.REPORT.SECONDARY_ACTIONS.RETRACT]: { text: translate('iou.undoSubmit'), diff --git a/src/components/MoneyRequestConfirmationList.tsx b/src/components/MoneyRequestConfirmationList.tsx index be8497884831..093192e56b3d 100755 --- a/src/components/MoneyRequestConfirmationList.tsx +++ b/src/components/MoneyRequestConfirmationList.tsx @@ -8,6 +8,7 @@ import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails' import useDebouncedState from '@hooks/useDebouncedState'; import useLocalize from '@hooks/useLocalize'; import {MouseProvider} from '@hooks/useMouseContext'; +import usePermissions from '@hooks/usePermissions'; import usePrevious from '@hooks/usePrevious'; import useThemeStyles from '@hooks/useThemeStyles'; import blurActiveElement from '@libs/Accessibility/blurActiveElement'; @@ -32,7 +33,6 @@ import Log from '@libs/Log'; import {validateAmount} from '@libs/MoneyRequestUtils'; import Navigation from '@libs/Navigation/Navigation'; import {getIOUConfirmationOptionsFromPayeePersonalDetail, hasEnabledOptions} from '@libs/OptionsListUtils'; -import Permissions from '@libs/Permissions'; import {getDistanceRateCustomUnitRate, getTagLists, isTaxTrackingEnabled} from '@libs/PolicyUtils'; import {isSelectedManagerMcTest} from '@libs/ReportUtils'; import type {OptionData} from '@libs/ReportUtils'; @@ -231,7 +231,7 @@ function MoneyRequestConfirmationList({ const [policyCategoriesDraft] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_CATEGORIES_DRAFT}${policyID}`, {canBeMissing: true}); const [lastSelectedDistanceRates] = useOnyx(ONYXKEYS.NVP_LAST_SELECTED_DISTANCE_RATES, {canBeMissing: true}); const [currencyList] = useOnyx(ONYXKEYS.CURRENCY_LIST, {canBeMissing: false}); - const [betas] = useOnyx(ONYXKEYS.BETAS, {canBeMissing: false}); + const {isBetaEnabled} = usePermissions(); const isTestReceipt = useMemo(() => { return transaction?.receipt?.isTestReceipt ?? false; @@ -242,8 +242,8 @@ function MoneyRequestConfirmationList({ }, [transaction?.receipt?.isTestDriveReceipt]); const isManagerMcTestReceipt = useMemo(() => { - return Permissions.canUseManagerMcTest(betas) && selectedParticipantsProp.some((participant) => isSelectedManagerMcTest(participant.login)); - }, [betas, selectedParticipantsProp]); + return isBetaEnabled(CONST.BETAS.NEWDOT_MANAGER_MCTEST) && selectedParticipantsProp.some((participant) => isSelectedManagerMcTest(participant.login)); + }, [isBetaEnabled, selectedParticipantsProp]); const {shouldShowProductTrainingTooltip, renderProductTrainingTooltip} = useProductTrainingContext( isTestDriveReceipt ? CONST.PRODUCT_TRAINING_TOOLTIP_NAMES.SCAN_TEST_DRIVE_CONFIRMATION : CONST.PRODUCT_TRAINING_TOOLTIP_NAMES.SCAN_TEST_CONFIRMATION, diff --git a/src/components/MoneyRequestHeader.tsx b/src/components/MoneyRequestHeader.tsx index 7b502bb8c138..96d8458317c1 100644 --- a/src/components/MoneyRequestHeader.tsx +++ b/src/components/MoneyRequestHeader.tsx @@ -91,7 +91,7 @@ function MoneyRequestHeader({report, parentReportAction, policy, onBackButtonPre const isOnHold = isOnHoldTransactionUtils(transaction); const isDuplicate = isDuplicateTransactionUtils(transaction?.transactionID); const reportID = report?.reportID; - const {canUseNewDotSplits} = usePermissions(); + const {isBetaEnabled} = usePermissions(); const isReportInRHP = route.name === SCREENS.SEARCH.REPORT_RHP; const shouldDisplayTransactionNavigation = !!(reportID && isReportInRHP); @@ -203,8 +203,8 @@ function MoneyRequestHeader({report, parentReportAction, policy, onBackButtonPre if (!transaction || !reportActions) { return []; } - return getSecondaryTransactionThreadActions(parentReport, transaction, Object.values(reportActions), policy, canUseNewDotSplits); - }, [canUseNewDotSplits, parentReport, policy, transaction]); + return getSecondaryTransactionThreadActions(parentReport, transaction, Object.values(reportActions), policy, isBetaEnabled(CONST.BETAS.NEW_DOT_SPLITS)); + }, [isBetaEnabled, parentReport, policy, transaction]); const secondaryActionsImplementation: Record, DropdownOption>> = { [CONST.REPORT.TRANSACTION_SECONDARY_ACTIONS.HOLD]: { diff --git a/src/components/ReportActionItem/MoneyRequestAction.tsx b/src/components/ReportActionItem/MoneyRequestAction.tsx index 2653aced0690..390d4bdadb39 100644 --- a/src/components/ReportActionItem/MoneyRequestAction.tsx +++ b/src/components/ReportActionItem/MoneyRequestAction.tsx @@ -98,7 +98,7 @@ function MoneyRequestAction({ const {translate} = useLocalize(); const {isOffline} = useNetwork(); const {shouldUseNarrowLayout} = useResponsiveLayout(); - const {canUseTableReportView} = usePermissions(); + const {isBetaEnabled} = usePermissions(); const route = useRoute>(); const isReviewDuplicateTransactionPage = route.name === SCREENS.TRANSACTION_DUPLICATE.REVIEW; const isSplitBillAction = isSplitBillActionReportActionsUtils(action); @@ -166,7 +166,7 @@ function MoneyRequestAction({ } // Condition extracted from MoneyRequestPreview - const renderCondition = !(lodashIsEmpty(iouReport) && !(isSplitBillAction || isTrackExpenseAction)) && canUseTableReportView && isReviewDuplicateTransactionPage; + const renderCondition = !(lodashIsEmpty(iouReport) && !(isSplitBillAction || isTrackExpenseAction)) && isBetaEnabled(CONST.BETAS.TABLE_REPORT_VIEW) && isReviewDuplicateTransactionPage; const isLayoutWidthInvalid = (layoutWidth: number) => { return (shouldUseNarrowLayout && layoutWidth > variables.mobileResponsiveWidthBreakpoint) || (!shouldUseNarrowLayout && layoutWidth > variables.sideBarWidth); }; diff --git a/src/components/Search/index.tsx b/src/components/Search/index.tsx index 833016be440d..8c489a512eab 100644 --- a/src/components/Search/index.tsx +++ b/src/components/Search/index.tsx @@ -175,7 +175,7 @@ function Search({queryJSON, currentSearchResults, lastNonEmptySearchResults, onS const shouldGroupByReports = groupBy === CONST.SEARCH.GROUP_BY.REPORTS; - const {canUseTableReportView} = usePermissions(); + const {isBetaEnabled} = usePermissions(); useEffect(() => { clearSelectedTransactions(hash); @@ -433,7 +433,7 @@ function Search({queryJSON, currentSearchResults, lastNonEmptySearchResults, onS const shouldHandleTransactionAsReport = isReportListItemType(item) || (isTransactionItem && isOpenedAsReport); - if (canUseTableReportView && shouldHandleTransactionAsReport) { + if (isBetaEnabled(CONST.BETAS.TABLE_REPORT_VIEW) && shouldHandleTransactionAsReport) { Navigation.navigate(ROUTES.SEARCH_MONEY_REQUEST_REPORT.getRoute({reportID, backTo})); return; } @@ -446,7 +446,7 @@ function Search({queryJSON, currentSearchResults, lastNonEmptySearchResults, onS Navigation.navigate(ROUTES.SEARCH_REPORT.getRoute({reportID, backTo})); }, - [canUseTableReportView, hash, selectionMode?.isEnabled, toggleTransaction], + [isBetaEnabled, hash, selectionMode?.isEnabled, toggleTransaction], ); const onViewableItemsChanged = useCallback( diff --git a/src/components/SelectionList/InviteMemberListItem.tsx b/src/components/SelectionList/InviteMemberListItem.tsx index 3e00f5996e6c..2576368240f0 100644 --- a/src/components/SelectionList/InviteMemberListItem.tsx +++ b/src/components/SelectionList/InviteMemberListItem.tsx @@ -1,7 +1,6 @@ import {Str} from 'expensify-common'; import React, {useCallback} from 'react'; import {View} from 'react-native'; -import {useOnyx} from 'react-native-onyx'; import {FallbackAvatar} from '@components/Icon/Expensicons'; import MultipleAvatars from '@components/MultipleAvatars'; import PressableWithFeedback from '@components/Pressable/PressableWithFeedback'; @@ -12,14 +11,13 @@ import Text from '@components/Text'; import TextWithTooltip from '@components/TextWithTooltip'; import EducationalTooltip from '@components/Tooltip/EducationalTooltip'; import useLocalize from '@hooks/useLocalize'; +import usePermissions from '@hooks/usePermissions'; import useStyleUtils from '@hooks/useStyleUtils'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; import {getIsUserSubmittedExpenseOrScannedReceipt} from '@libs/OptionsListUtils'; -import Permissions from '@libs/Permissions'; import {isSelectedManagerMcTest} from '@libs/ReportUtils'; import CONST from '@src/CONST'; -import ONYXKEYS from '@src/ONYXKEYS'; import type {Icon} from '@src/types/onyx/OnyxCommon'; import BaseListItem from './BaseListItem'; import type {InviteMemberListItemProps, ListItem} from './types'; @@ -48,10 +46,10 @@ function InviteMemberListItem({ const theme = useTheme(); const StyleUtils = useStyleUtils(); const {translate} = useLocalize(); - const [betas] = useOnyx(ONYXKEYS.BETAS, {canBeMissing: true}); + const {isBetaEnabled} = usePermissions(); const {renderProductTrainingTooltip, shouldShowProductTrainingTooltip} = useProductTrainingContext( CONST.PRODUCT_TRAINING_TOOLTIP_NAMES.SCAN_TEST_TOOLTIP_MANAGER, - !getIsUserSubmittedExpenseOrScannedReceipt() && Permissions.canUseManagerMcTest(betas) && isSelectedManagerMcTest(item.login) && !item.isSelected, + !getIsUserSubmittedExpenseOrScannedReceipt() && isBetaEnabled(CONST.BETAS.NEWDOT_MANAGER_MCTEST) && isSelectedManagerMcTest(item.login) && !item.isSelected, ); const focusedBackgroundColor = styles.sidebarLinkActive.backgroundColor; diff --git a/src/components/SelectionList/Search/ReportListItem.tsx b/src/components/SelectionList/Search/ReportListItem.tsx index 0b758da848d4..4788ffe66b33 100644 --- a/src/components/SelectionList/Search/ReportListItem.tsx +++ b/src/components/SelectionList/Search/ReportListItem.tsx @@ -36,7 +36,7 @@ function ReportListItem({ const theme = useTheme(); const styles = useThemeStyles(); const {translate} = useLocalize(); - const {canUseTableReportView} = usePermissions(); + const {isBetaEnabled} = usePermissions(); const [policies] = useOnyx(ONYXKEYS.COLLECTION.POLICY, {allowStaleData: true, initialValue: {}, canBeMissing: true}); const policy = policies?.[`${ONYXKEYS.COLLECTION.POLICY}${reportItem?.policyID}`]; const isEmptyReport = reportItem.transactions.length === 0; @@ -83,7 +83,7 @@ function ReportListItem({ return null; } - if (isEmptyReport && !canUseTableReportView) { + if (isEmptyReport && !isBetaEnabled(CONST.BETAS.TABLE_REPORT_VIEW)) { return null; } diff --git a/src/hooks/usePermissions.ts b/src/hooks/usePermissions.ts index e60825b610e9..34db330ec3de 100644 --- a/src/hooks/usePermissions.ts +++ b/src/hooks/usePermissions.ts @@ -1,18 +1,21 @@ import {useContext, useMemo} from 'react'; import {BetasContext} from '@components/OnyxProvider'; import Permissions from '@libs/Permissions'; +import type Beta from '@src/types/onyx/Beta'; type PermissionKey = keyof typeof Permissions; -type UsePermissions = Partial>; +type UsePermissions = Partial, boolean>> & {isBetaEnabled: (beta: Beta) => boolean}; let permissionKey: PermissionKey; export default function usePermissions(): UsePermissions { const betas = useContext(BetasContext); return useMemo(() => { - const permissions: UsePermissions = {}; + const permissions: UsePermissions = { + isBetaEnabled: (beta: Beta) => Permissions.isBetaEnabled(beta, betas), + }; for (permissionKey in Permissions) { - if (betas) { + if (betas && permissionKey !== 'isBetaEnabled') { const checkerFunction = Permissions[permissionKey]; permissions[permissionKey] = checkerFunction(betas); diff --git a/src/libs/Navigation/AppNavigator/Navigators/ReportsSplitNavigator.tsx b/src/libs/Navigation/AppNavigator/Navigators/ReportsSplitNavigator.tsx index 631520e00a27..8feb3eb8098b 100644 --- a/src/libs/Navigation/AppNavigator/Navigators/ReportsSplitNavigator.tsx +++ b/src/libs/Navigation/AppNavigator/Navigators/ReportsSplitNavigator.tsx @@ -23,7 +23,7 @@ const Split = createSplitNavigator(); * There can be multiple report screens in the stack with different report IDs. */ function ReportsSplitNavigator({route}: PlatformStackScreenProps) { - const {canUseDefaultRooms} = usePermissions(); + const {isBetaEnabled} = usePermissions(); const splitNavigatorScreenOptions = useSplitNavigatorScreenOptions(); const [initialReportID] = useState(() => { @@ -33,7 +33,7 @@ function ReportsSplitNavigator({route}: PlatformStackScreenProps): boolean { return !!betas?.includes(CONST.BETAS.ALL); } -function canUseDefaultRooms(betas: OnyxEntry): boolean { - return !!betas?.includes(CONST.BETAS.DEFAULT_ROOMS) || canUseAllBetas(betas); -} - function isBlockedFromSpotnanaTravel(betas: OnyxEntry): boolean { // Don't check for all betas or nobody can use test travel on dev return !!betas?.includes(CONST.BETAS.PREVENT_SPOTNANA_TRAVEL); } -function isTravelVerified(betas: OnyxEntry): boolean { - return !!betas?.includes(CONST.BETAS.IS_TRAVEL_VERIFIED) || canUseAllBetas(betas); -} - -function canUseNetSuiteUSATax(betas: OnyxEntry): boolean { - return !!betas?.includes(CONST.BETAS.NETSUITE_USA_TAX) || canUseAllBetas(betas); -} - -function canUseMultiLevelTags(betas: OnyxEntry): boolean { - return !!betas?.includes(CONST.BETAS.MULTI_LEVEL_TAGS) || canUseAllBetas(betas); -} - /** * Link previews are temporarily disabled. */ @@ -34,79 +18,12 @@ function canUseLinkPreviews(): boolean { return false; } -function canUseMergeAccounts(betas: OnyxEntry): boolean { - return !!betas?.includes(CONST.BETAS.NEWDOT_MERGE_ACCOUNTS) || canUseAllBetas(betas); -} - -function canUseManagerMcTest(betas: OnyxEntry): boolean { - return !!betas?.includes(CONST.BETAS.NEWDOT_MANAGER_MCTEST) || canUseAllBetas(betas); -} - -function canUseCustomRules(betas: OnyxEntry): boolean { - return !!betas?.includes(CONST.BETAS.CUSTOM_RULES) || canUseAllBetas(betas); -} - -/** - * The feature is released so hardcoding the value to true while we clean up the beta from the code. - */ -function canUseTableReportView(betas: OnyxEntry): boolean { - return true || !!betas?.includes(CONST.BETAS.TABLE_REPORT_VIEW) || canUseAllBetas(betas); -} - -function canUseTalkToAISales(betas: OnyxEntry): boolean { - return !!betas?.includes(CONST.BETAS.NEW_DOT_TALK_TO_AI_SALES) || canUseAllBetas(betas); -} - -function canUseInAppProvisioning(betas: OnyxEntry): boolean { - return !!betas?.includes(CONST.BETAS.WALLET) || canUseAllBetas(betas); -} - -function canUseGlobalReimbursementsOnND(betas: OnyxEntry): boolean { - return !!betas?.includes(CONST.BETAS.GLOBAL_REIMBURSEMENTS_ON_ND) || canUseAllBetas(betas); -} - -function canUsePlaidCompanyCards(betas: OnyxEntry): boolean { - return !!betas?.includes(CONST.BETAS.PLAID_COMPANY_CARDS) || canUseAllBetas(betas); -} - -function canUseRetractNewDot(betas: OnyxEntry): boolean { - return !!betas?.includes(CONST.BETAS.RETRACT_NEWDOT) || canUseAllBetas(betas); -} - -function canUseMultiScan(betas: OnyxEntry): boolean { - return !!betas?.includes(CONST.BETAS.NEWDOT_MULTI_SCAN) || canUseAllBetas(betas); -} - -function canUseMultiFilesDragAndDrop(betas: OnyxEntry): boolean { - return !!betas?.includes(CONST.BETAS.NEWDOT_MULTI_FILES_DRAG_AND_DROP) || canUseAllBetas(betas); -} - -function canUseTrackFlows(betas: OnyxEntry): boolean { - return !!betas?.includes(CONST.BETAS.TRACK_FLOWS) || canUseAllBetas(betas); -} - -function canUseNewDotSplits(betas: OnyxEntry): boolean { - return !!betas?.includes(CONST.BETAS.NEW_DOT_SPLITS) || canUseAllBetas(betas); +function isBetaEnabled(beta: Beta, betas: OnyxEntry): boolean { + return !!betas?.includes(beta) || canUseAllBetas(betas); } export default { - canUseDefaultRooms, canUseLinkPreviews, isBlockedFromSpotnanaTravel, - isTravelVerified, - canUseNetSuiteUSATax, - canUseMergeAccounts, - canUseManagerMcTest, - canUseCustomRules, - canUseTableReportView, - canUseTalkToAISales, - canUseInAppProvisioning, - canUseGlobalReimbursementsOnND, - canUseRetractNewDot, - canUseMultiLevelTags, - canUseMultiFilesDragAndDrop, - canUseMultiScan, - canUseNewDotSplits, - canUsePlaidCompanyCards, - canUseTrackFlows, + isBetaEnabled, }; diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 4f1fd36d77f8..60d274811e72 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -7630,7 +7630,7 @@ function canSeeDefaultRoom(report: OnyxEntry, policies: OnyxCollection

, policies: OnyxCollection, betas: OnyxEntry): boolean { @@ -8377,7 +8377,7 @@ function getMoneyRequestOptions(report: OnyxEntry, policy: OnyxEntry accountID === CONST.ACCOUNT_ID.MANAGER_MCTEST) && Permissions.canUseManagerMcTest(allBetas)) { + if (reportParticipants.some((accountID) => accountID === CONST.ACCOUNT_ID.MANAGER_MCTEST) && Permissions.isBetaEnabled(CONST.BETAS.NEWDOT_MANAGER_MCTEST, allBetas)) { return [CONST.IOU.TYPE.SUBMIT]; } return []; diff --git a/src/libs/__mocks__/Permissions.ts b/src/libs/__mocks__/Permissions.ts index 40fc9ea66317..9b4f9096f5d2 100644 --- a/src/libs/__mocks__/Permissions.ts +++ b/src/libs/__mocks__/Permissions.ts @@ -1,5 +1,4 @@ import type Permissions from '@libs/Permissions'; -import CONST from '@src/CONST'; import type Beta from '@src/types/onyx/Beta'; /** @@ -11,5 +10,5 @@ import type Beta from '@src/types/onyx/Beta'; export default { ...jest.requireActual('../Permissions'), - canUseDefaultRooms: (betas: Beta[]) => betas.includes(CONST.BETAS.DEFAULT_ROOMS), + isBetaEnabled: (beta: Beta, betas: Beta[]) => betas.includes(beta), }; diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 13b993aa181d..433ff5080133 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -5385,7 +5385,7 @@ function requestMoney(requestMoneyInformation: RequestMoneyInformation) { } } - if (activeReportID && (!isMoneyRequestReport || !Permissions.canUseTableReportView(betas))) { + if (activeReportID && (!isMoneyRequestReport || !Permissions.isBetaEnabled(CONST.BETAS.TABLE_REPORT_VIEW, betas))) { notifyNewAction(activeReportID, payeeAccountID); } } @@ -7292,7 +7292,7 @@ function createDistanceRequest(distanceRequestInformation: CreateDistanceRequest const activeReportID = isMoneyRequestReport && report?.reportID ? report.reportID : parameters.chatReportID; dismissModalAndOpenReportInInboxTab(backToReport ?? activeReportID); - if (!isMoneyRequestReport || !Permissions.canUseTableReportView(betas)) { + if (!isMoneyRequestReport || !Permissions.isBetaEnabled(CONST.BETAS.TABLE_REPORT_VIEW, betas)) { notifyNewAction(activeReportID, userAccountID); } } @@ -7562,7 +7562,7 @@ function cleanUpMoneyRequest(transactionID: string, reportAction: OnyxTypes.Repo chatReport, iouReport, reportPreviewAction, - } = prepareToCleanUpMoneyRequest(transactionID, reportAction, !Permissions.canUseTableReportView(betas)); + } = prepareToCleanUpMoneyRequest(transactionID, reportAction, !Permissions.isBetaEnabled(CONST.BETAS.TABLE_REPORT_VIEW, betas)); const urlToNavigateBack = getNavigationUrlOnMoneyRequestDelete(transactionID, reportAction, isSingleTransactionView); // build Onyx data @@ -7713,7 +7713,7 @@ function deleteMoneyRequest( transactionID: string | undefined, reportAction: OnyxTypes.ReportAction, isSingleTransactionView = false, - shouldRemoveIOUTransactionID = !Permissions.canUseTableReportView(betas), + shouldRemoveIOUTransactionID = !Permissions.isBetaEnabled(CONST.BETAS.TABLE_REPORT_VIEW, betas), ) { if (!transactionID) { return; @@ -8048,7 +8048,7 @@ function deleteTrackExpense( transactionID: string | undefined, reportAction: OnyxTypes.ReportAction, isSingleTransactionView = false, - shouldRemoveIOUTransaction = !Permissions.canUseTableReportView(betas), + shouldRemoveIOUTransaction = !Permissions.isBetaEnabled(CONST.BETAS.TABLE_REPORT_VIEW, betas), ) { if (!chatReportID || !transactionID) { return; @@ -11789,7 +11789,7 @@ function saveSplitTransactions(draftTransaction: OnyxEntry(undefined); @@ -242,7 +242,7 @@ function BaseOnboardingAccounting({shouldUseNativeStyles}: BaseOnboardingAccount Navigation.setNavigationActionToMicrotaskQueue(() => { navigateAfterOnboarding( isSmallScreenWidth, - canUseDefaultRooms, + isBetaEnabled(CONST.BETAS.DEFAULT_ROOMS), policyID, adminsChatReportID, // Onboarding tasks would show in Concierge instead of admins room for testing accounts, we should open where onboarding tasks are located @@ -251,7 +251,7 @@ function BaseOnboardingAccounting({shouldUseNativeStyles}: BaseOnboardingAccount ); }); }, [ - canUseDefaultRooms, + isBetaEnabled, isSmallScreenWidth, onboardingAdminsChatReportID, onboardingCompanySize, diff --git a/src/pages/OnboardingPersonalDetails/BaseOnboardingPersonalDetails.tsx b/src/pages/OnboardingPersonalDetails/BaseOnboardingPersonalDetails.tsx index 95eae09c8da0..ba8c9701f8ba 100644 --- a/src/pages/OnboardingPersonalDetails/BaseOnboardingPersonalDetails.tsx +++ b/src/pages/OnboardingPersonalDetails/BaseOnboardingPersonalDetails.tsx @@ -47,7 +47,7 @@ function BaseOnboardingPersonalDetails({currentUserPersonalDetails, shouldUseNat const {onboardingIsMediumOrLargerScreenWidth, isSmallScreenWidth} = useResponsiveLayout(); const {inputCallbackRef} = useAutoFocusInput(); const [shouldValidateOnChange, setShouldValidateOnChange] = useState(false); - const {canUseDefaultRooms} = usePermissions(); + const {isBetaEnabled} = usePermissions(); const isPrivateDomainAndHasAccessiblePolicies = !account?.isFromPublicDomain && !!account?.hasAccessibleDomainPolicies; const isValidated = isCurrentUserValidated(loginList); @@ -74,9 +74,9 @@ function BaseOnboardingPersonalDetails({currentUserPersonalDetails, shouldUseNat setOnboardingAdminsChatReportID(); setOnboardingPolicyID(); - navigateAfterOnboarding(isSmallScreenWidth, canUseDefaultRooms, onboardingPolicyID, mergedAccountConciergeReportID); + navigateAfterOnboarding(isSmallScreenWidth, isBetaEnabled(CONST.BETAS.DEFAULT_ROOMS), onboardingPolicyID, mergedAccountConciergeReportID); }, - [onboardingPurposeSelected, onboardingAdminsChatReportID, onboardingPolicyID, canUseDefaultRooms, isSmallScreenWidth, mergedAccountConciergeReportID], + [onboardingPurposeSelected, onboardingAdminsChatReportID, onboardingPolicyID, isBetaEnabled, isSmallScreenWidth, mergedAccountConciergeReportID], ); const handleSubmit = useCallback( diff --git a/src/pages/OnboardingWorkspaces/BaseOnboardingWorkspaces.tsx b/src/pages/OnboardingWorkspaces/BaseOnboardingWorkspaces.tsx index 479dee02b224..06bff7473238 100644 --- a/src/pages/OnboardingWorkspaces/BaseOnboardingWorkspaces.tsx +++ b/src/pages/OnboardingWorkspaces/BaseOnboardingWorkspaces.tsx @@ -47,7 +47,7 @@ function BaseOnboardingWorkspaces({route, shouldUseNativeStyles}: BaseOnboarding const isValidated = isCurrentUserValidated(loginList); - const {canUseDefaultRooms} = usePermissions(); + const {isBetaEnabled} = usePermissions(); const handleJoinWorkspace = useCallback( (policy: JoinablePolicy) => { @@ -65,9 +65,9 @@ function BaseOnboardingWorkspaces({route, shouldUseNativeStyles}: BaseOnboarding setOnboardingAdminsChatReportID(); setOnboardingPolicyID(policy.policyID); - navigateAfterOnboarding(isSmallScreenWidth, canUseDefaultRooms, policy.automaticJoiningEnabled ? policy.policyID : undefined); + navigateAfterOnboarding(isSmallScreenWidth, isBetaEnabled(CONST.BETAS.DEFAULT_ROOMS), policy.automaticJoiningEnabled ? policy.policyID : undefined); }, - [onboardingPersonalDetails?.firstName, onboardingPersonalDetails?.lastName, isSmallScreenWidth, canUseDefaultRooms], + [onboardingPersonalDetails?.firstName, onboardingPersonalDetails?.lastName, isSmallScreenWidth, isBetaEnabled], ); const policyIDItems = useMemo(() => { diff --git a/src/pages/ReimbursementAccount/ReimbursementAccountPage.tsx b/src/pages/ReimbursementAccount/ReimbursementAccountPage.tsx index b2df8d21241c..f0d59e110851 100644 --- a/src/pages/ReimbursementAccount/ReimbursementAccountPage.tsx +++ b/src/pages/ReimbursementAccount/ReimbursementAccountPage.tsx @@ -67,7 +67,7 @@ function ReimbursementAccountPage({route, policy, isLoadingPolicy}: Reimbursemen const [account] = useOnyx(ONYXKEYS.ACCOUNT, {canBeMissing: true}); const [isValidateCodeActionModalVisible, setIsValidateCodeActionModalVisible] = useState(false); - const {canUseGlobalReimbursementsOnND} = usePermissions(); + const {isBetaEnabled} = usePermissions(); const policyName = policy?.name ?? ''; const policyIDParam = route.params?.policyID; const backTo = route.params.backTo; @@ -78,7 +78,7 @@ function ReimbursementAccountPage({route, policy, isLoadingPolicy}: Reimbursemen const prevReimbursementAccount = usePrevious(reimbursementAccount); const prevIsOffline = usePrevious(isOffline); const policyCurrency = policy?.outputCurrency ?? ''; - const hasUnsupportedCurrency = !isCurrencySupportedForGlobalReimbursement(policyCurrency as CurrencyType, canUseGlobalReimbursementsOnND ?? false); + const hasUnsupportedCurrency = !isCurrencySupportedForGlobalReimbursement(policyCurrency as CurrencyType, isBetaEnabled(CONST.BETAS.GLOBAL_REIMBURSEMENTS_ON_ND) ?? false); const isNonUSDWorkspace = policyCurrency !== CONST.CURRENCY.USD; const nonUSDCountryDraftValue = reimbursementAccountDraft?.country ?? ''; // shouldUseNarrowLayout cannot be used here because this page is displayed in a RHP diff --git a/src/pages/ReportDetailsPage.tsx b/src/pages/ReportDetailsPage.tsx index 73537d0c2a70..23c8d384f63a 100644 --- a/src/pages/ReportDetailsPage.tsx +++ b/src/pages/ReportDetailsPage.tsx @@ -142,7 +142,7 @@ type CaseID = ValueOf; function ReportDetailsPage({policies, report, route, reportMetadata}: ReportDetailsPageProps) { const {translate} = useLocalize(); const {isOffline} = useNetwork(); - const {canUseTrackFlows} = usePermissions(); + const {isBetaEnabled} = usePermissions(); const styles = useThemeStyles(); const backTo = route.params.backTo; @@ -409,7 +409,7 @@ function ReportDetailsPage({policies, report, route, reportMetadata}: ReportDeta createDraftTransactionAndNavigateToParticipantSelector(iouTransactionID, actionReportID, CONST.IOU.ACTION.SUBMIT, actionableWhisperReportActionID); }, }); - if (canUseTrackFlows) { + if (isBetaEnabled(CONST.BETAS.TRACK_FLOWS)) { items.push({ key: CONST.REPORT_DETAILS_MENU_ITEM.TRACK.CATEGORIZE, translationKey: 'actionableMentionTrackExpense.categorize', @@ -518,6 +518,7 @@ function ReportDetailsPage({policies, report, route, reportMetadata}: ReportDeta participants.length, report, isSystemChat, + activeChatMembers.length, isPolicyExpenseChat, shouldShowMenuItem, isTrackExpenseReport, @@ -529,17 +530,16 @@ function ReportDetailsPage({policies, report, route, reportMetadata}: ReportDeta shouldShowGoToWorkspace, shouldShowLeaveButton, isDebugModeEnabled, - activeChatMembers.length, shouldOpenRoomMembersPage, backTo, parentReportAction, iouTransactionID, moneyRequestReport?.reportID, + isBetaEnabled, session, isTaskActionable, isRootGroupChat, leaveChat, - canUseTrackFlows, ]); const displayNamesWithTooltips = useMemo(() => { diff --git a/src/pages/Search/EmptySearchView.tsx b/src/pages/Search/EmptySearchView.tsx index 72e91ad2dbda..47d2fe271958 100644 --- a/src/pages/Search/EmptySearchView.tsx +++ b/src/pages/Search/EmptySearchView.tsx @@ -82,7 +82,7 @@ function EmptySearchView({hash, type, groupBy, hasResults}: EmptySearchViewProps const {translate} = useLocalize(); const styles = useThemeStyles(); const contextMenuAnchor = useRef(null); - const {canUseTableReportView} = usePermissions(); + const {isBetaEnabled} = usePermissions(); const [modalVisible, setModalVisible] = useState(false); const currentUserPersonalDetails = useCurrentUserPersonalDetails(); @@ -213,7 +213,7 @@ function EmptySearchView({hash, type, groupBy, hasResults}: EmptySearchViewProps }, ] : []), - ...(canUseTableReportView && !!Object.keys(allPolicies ?? {})?.length + ...(isBetaEnabled(CONST.BETAS.TABLE_REPORT_VIEW) && !!Object.keys(allPolicies ?? {})?.length ? [ { buttonText: translate('quickAction.createReport'), @@ -359,7 +359,7 @@ function EmptySearchView({hash, type, groupBy, hasResults}: EmptySearchViewProps styles.tripEmptyStateLottieWebView, introSelected?.choice, hasSeenTour, - canUseTableReportView, + isBetaEnabled, allPolicies, activePolicy, activePolicyID, diff --git a/src/pages/Search/SearchPage.tsx b/src/pages/Search/SearchPage.tsx index 3551784fe6fc..cea5208bbbb9 100644 --- a/src/pages/Search/SearchPage.tsx +++ b/src/pages/Search/SearchPage.tsx @@ -83,7 +83,7 @@ function SearchPage({route}: SearchPageProps) { const {q} = route.params; - const {canUseMultiFilesDragAndDrop} = usePermissions(); + const {isBetaEnabled} = usePermissions(); const queryJSON = useMemo(() => buildSearchQueryJSON(q), [q]); @@ -585,7 +585,7 @@ function SearchPage({route}: SearchPageProps) { offlineIndicatorStyle={styles.mtAuto} > {isLoadingReceipt && } - + {PDFThumbnailView} >(); const currentUserPersonalDetails = useCurrentUserPersonalDetails(); const [reviewDuplicates, reviewDuplicatesResult] = useOnyx(ONYXKEYS.REVIEW_DUPLICATES, {canBeMissing: true}); @@ -64,16 +65,16 @@ function Confirmation() { } IOU.mergeDuplicates(transactionsMergeParams); - if (canUseTableReportView) { + if (isBetaEnabled(CONST.BETAS.TABLE_REPORT_VIEW)) { Navigation.dismissModal(); return; } Navigation.goBack(ROUTES.REPORT_WITH_ID.getRoute(transactionThreadReportID), {compareParams: false}); - }, [reportAction?.childReportID, transactionsMergeParams, canUseTableReportView]); + }, [reportAction?.childReportID, transactionsMergeParams, isBetaEnabled]); const resolveDuplicates = useCallback(() => { IOU.resolveDuplicates(transactionsMergeParams); - if (canUseTableReportView) { + if (isBetaEnabled(CONST.BETAS.TABLE_REPORT_VIEW)) { Navigation.dismissModal(); return; } @@ -82,7 +83,7 @@ function Confirmation() { return; } Navigation.goBack(ROUTES.REPORT_WITH_ID.getRoute(reportAction.childReportID), {compareParams: false}); - }, [transactionsMergeParams, reportAction?.childReportID, canUseTableReportView]); + }, [transactionsMergeParams, reportAction?.childReportID, isBetaEnabled]); const contextValue = useMemo( () => ({ diff --git a/src/pages/home/HeaderView.tsx b/src/pages/home/HeaderView.tsx index 6c4650c0dde7..dd6f1666d461 100644 --- a/src/pages/home/HeaderView.tsx +++ b/src/pages/home/HeaderView.tsx @@ -135,8 +135,8 @@ function HeaderView({report, parentReportAction, onNavigationMenuButtonClicked, const isSelfDM = isSelfDMReportUtils(report); const isGroupChat = isGroupChatReportUtils(report) || isDeprecatedGroupDM(report); const [introSelected] = useOnyx(ONYXKEYS.NVP_INTRO_SELECTED, {canBeMissing: true}); - const {canUseTalkToAISales} = usePermissions(); - const shouldShowTalkToSales = !!canUseTalkToAISales && isAdminRoom(report); + const {isBetaEnabled} = usePermissions(); + const shouldShowTalkToSales = !!isBetaEnabled(CONST.BETAS.NEW_DOT_TALK_TO_AI_SALES) && isAdminRoom(report); const isNativePlatform = getPlatform() === CONST.PLATFORM.IOS || getPlatform() === CONST.PLATFORM.ANDROID; const allParticipants = getParticipantsAccountIDsForDisplay(report, false, true, undefined, reportMetadata); const shouldAddEllipsis = allParticipants?.length > CONST.DISPLAY_PARTICIPANTS_LIMIT; diff --git a/src/pages/home/ReportScreen.tsx b/src/pages/home/ReportScreen.tsx index 8503c4775d03..2abc3760b3e6 100644 --- a/src/pages/home/ReportScreen.tsx +++ b/src/pages/home/ReportScreen.tsx @@ -146,7 +146,7 @@ function ReportScreen({route, navigation}: ReportScreenProps) { const [firstRender, setFirstRender] = useState(true); const isSkippingOpenReport = useRef(false); const flatListRef = useRef(null); - const {canUseDefaultRooms, canUseTableReportView} = usePermissions(); + const {isBetaEnabled} = usePermissions(); const {isOffline} = useNetwork(); const {shouldUseNarrowLayout, isInNarrowPaneModal} = useResponsiveLayout(); const currentReportIDValue = useCurrentReportID(); @@ -181,7 +181,7 @@ function ReportScreen({route, navigation}: ReportScreenProps) { return; } - const lastAccessedReportID = findLastAccessedReport(!canUseDefaultRooms, !!route.params.openOnAdminRoom)?.reportID; + const lastAccessedReportID = findLastAccessedReport(!isBetaEnabled(CONST.BETAS.DEFAULT_ROOMS), !!route.params.openOnAdminRoom)?.reportID; // It's possible that reports aren't fully loaded yet // in that case the reportID is undefined @@ -191,7 +191,7 @@ function ReportScreen({route, navigation}: ReportScreenProps) { Log.info(`[ReportScreen] no reportID found in params, setting it to lastAccessedReportID: ${lastAccessedReportID}`); navigation.setParams({reportID: lastAccessedReportID}); - }, [canUseDefaultRooms, navigation, route]); + }, [isBetaEnabled, navigation, route]); const [personalDetails] = useOnyx(ONYXKEYS.PERSONAL_DETAILS_LIST, {canBeMissing: true}); const chatWithAccountManagerText = useMemo(() => { @@ -786,7 +786,7 @@ function ReportScreen({route, navigation}: ReportScreenProps) { } // If true reports that are considered MoneyRequest | InvoiceReport will get the new report table view - const shouldDisplayMoneyRequestActionsList = canUseTableReportView && isMoneyRequestOrInvoiceReport && shouldDisplayReportTableView(report, reportTransactions); + const shouldDisplayMoneyRequestActionsList = isBetaEnabled(CONST.BETAS.TABLE_REPORT_VIEW) && isMoneyRequestOrInvoiceReport && shouldDisplayReportTableView(report, reportTransactions); return ( diff --git a/src/pages/home/report/PureReportActionItem.tsx b/src/pages/home/report/PureReportActionItem.tsx index 38b13aeb3e37..6da39cb14f35 100644 --- a/src/pages/home/report/PureReportActionItem.tsx +++ b/src/pages/home/report/PureReportActionItem.tsx @@ -411,7 +411,7 @@ function PureReportActionItem({ const [isContextMenuActive, setIsContextMenuActive] = useState(() => isActiveReportAction(action.reportActionID)); const [isEmojiPickerActive, setIsEmojiPickerActive] = useState(); const [isPaymentMethodPopoverActive, setIsPaymentMethodPopoverActive] = useState(); - const {canUseTableReportView, canUseTrackFlows} = usePermissions(); + const {isBetaEnabled} = usePermissions(); const shouldRenderViewBasedOnAction = useNewTableReportViewActionRenderConditionals(action); const [isHidden, setIsHidden] = useState(false); const [moderationDecision, setModerationDecision] = useState(CONST.MODERATION.MODERATOR_DECISION_APPROVED); @@ -713,7 +713,7 @@ function PureReportActionItem({ }, ]; - if (canUseTrackFlows) { + if (isBetaEnabled(CONST.BETAS.TRACK_FLOWS)) { options.push( { text: 'actionableMentionTrackExpense.categorize', @@ -796,7 +796,7 @@ function PureReportActionItem({ resolveActionableReportMentionWhisper, resolveActionableMentionWhisper, originalReportID, - canUseTrackFlows, + isBetaEnabled, ]); /** @@ -836,7 +836,7 @@ function PureReportActionItem({ ); // Table Report View does not display these components as separate messages, except for self-DM - if (canUseTableReportView && report?.type === CONST.REPORT.TYPE.CHAT) { + if (isBetaEnabled(CONST.BETAS.TABLE_REPORT_VIEW) && report?.type === CONST.REPORT.TYPE.CHAT) { if (report.chatType === CONST.REPORT.CHAT_TYPE.SELF_DM || isSplitInGroupChat) { children = ( @@ -884,7 +884,7 @@ function PureReportActionItem({ ); } else if (action.actionName === CONST.REPORT.ACTIONS.TYPE.REPORT_PREVIEW && isClosedExpenseReportWithNoExpenses) { children = ${translate('parentReportAction.deletedReport')}`} />; - } else if (action.actionName === CONST.REPORT.ACTIONS.TYPE.REPORT_PREVIEW && canUseTableReportView) { + } else if (action.actionName === CONST.REPORT.ACTIONS.TYPE.REPORT_PREVIEW && isBetaEnabled(CONST.BETAS.TABLE_REPORT_VIEW)) { children = ( { const content = renderItemContent(hovered || isContextMenuActive || isEmojiPickerActive, isWhisper, hasErrors); - if (canUseTableReportView && (isEmptyHTML(content) || (!shouldRenderViewBasedOnAction && !isClosedExpenseReportWithNoExpenses))) { + if (isBetaEnabled(CONST.BETAS.TABLE_REPORT_VIEW) && (isEmptyHTML(content) || (!shouldRenderViewBasedOnAction && !isClosedExpenseReportWithNoExpenses))) { return emptyHTML; } diff --git a/src/pages/home/report/ReportActionCompose/AttachmentPickerWithMenuItems.tsx b/src/pages/home/report/ReportActionCompose/AttachmentPickerWithMenuItems.tsx index 77de23706b3e..9707ba7d8c20 100644 --- a/src/pages/home/report/ReportActionCompose/AttachmentPickerWithMenuItems.tsx +++ b/src/pages/home/report/ReportActionCompose/AttachmentPickerWithMenuItems.tsx @@ -132,7 +132,7 @@ function AttachmentPickerWithMenuItems({ const {isDelegateAccessRestricted} = useDelegateUserDetails(); const [isNoDelegateAccessMenuVisible, setIsNoDelegateAccessMenuVisible] = useState(false); const [policy] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${report?.policyID}`, {canBeMissing: true}); - const {canUseTableReportView} = usePermissions(); + const {isBetaEnabled} = usePermissions(); const selectOption = useCallback( (onSelected: () => void, shouldRestrictAction: boolean) => { @@ -198,7 +198,7 @@ function AttachmentPickerWithMenuItems({ }, [translate, shouldUseNarrowLayout, report, policy, reportParticipantIDs, selectOption, isDelegateAccessRestricted]); const createReportOption: PopoverMenuItem[] = useMemo(() => { - if (!canUseTableReportView || !isPolicyExpenseChat(report) || !isPaidGroupPolicy(report) || !isReportOwner(report)) { + if (!isBetaEnabled(CONST.BETAS.TABLE_REPORT_VIEW) || !isPolicyExpenseChat(report) || !isPaidGroupPolicy(report) || !isReportOwner(report)) { return []; } @@ -209,7 +209,7 @@ function AttachmentPickerWithMenuItems({ onSelected: () => selectOption(() => createNewReport(currentUserPersonalDetails, report?.policyID, true), true), }, ]; - }, [canUseTableReportView, currentUserPersonalDetails, report, selectOption, translate]); + }, [isBetaEnabled, currentUserPersonalDetails, report, selectOption, translate]); /** * Determines if we can show the task option diff --git a/src/pages/home/report/ReportActionCompose/ReportActionCompose.tsx b/src/pages/home/report/ReportActionCompose/ReportActionCompose.tsx index 65b5f14823e0..69fac1ed7ade 100644 --- a/src/pages/home/report/ReportActionCompose/ReportActionCompose.tsx +++ b/src/pages/home/report/ReportActionCompose/ReportActionCompose.tsx @@ -123,8 +123,8 @@ function ReportActionCompose({ const [blockedFromConcierge] = useOnyx(ONYXKEYS.NVP_BLOCKED_FROM_CONCIERGE, {canBeMissing: true}); const [shouldShowComposeInput = true] = useOnyx(ONYXKEYS.SHOULD_SHOW_COMPOSE_INPUT, {canBeMissing: true}); - // TODO: remove canUseMultiFilesDragAndDrop check after the feature is enabled - const {canUseMultiFilesDragAndDrop} = usePermissions(); + // TODO: remove beta check after the feature is enabled + const {isBetaEnabled} = usePermissions(); /** * Updates the Highlight state of the composer @@ -500,8 +500,8 @@ function ReportActionCompose({ onValueChange={onValueChange} didHideComposerInput={didHideComposerInput} /> - {/* TODO: remove canUseMultiFilesDragAndDrop check after the feature is enabled */} - {canUseMultiFilesDragAndDrop ? ( + {/* TODO: remove beta check after the feature is enabled */} + {isBetaEnabled(CONST.BETAS.NEWDOT_MULTI_FILES_DRAG_AND_DROP) ? ( { if (isAttachmentPreviewActive) { diff --git a/src/pages/home/sidebar/FloatingActionButtonAndPopover.tsx b/src/pages/home/sidebar/FloatingActionButtonAndPopover.tsx index 21950c72d6ed..c93e33cb642e 100644 --- a/src/pages/home/sidebar/FloatingActionButtonAndPopover.tsx +++ b/src/pages/home/sidebar/FloatingActionButtonAndPopover.tsx @@ -123,7 +123,7 @@ function FloatingActionButtonAndPopover({onHideCreateMenu, onShowCreateMenu, isT const primaryContactMethod = primaryLogin ?? session?.email ?? ''; const [travelSettings] = useOnyx(ONYXKEYS.NVP_TRAVEL_SETTINGS, {canBeMissing: true}); - const {canUseTableReportView} = usePermissions(); + const {isBetaEnabled} = usePermissions(); const canSendInvoice = useMemo(() => canSendInvoicePolicyUtils(allPolicies as OnyxCollection, session?.email), [allPolicies, session?.email]); const isValidReport = !(isEmptyObject(quickActionReport) || isArchivedReport(reportNameValuePairs)); const [introSelected] = useOnyx(ONYXKEYS.NVP_INTRO_SELECTED, {canBeMissing: true}); @@ -144,7 +144,7 @@ function FloatingActionButtonAndPopover({onHideCreateMenu, onShowCreateMenu, isT const shouldRedirectToExpensifyClassic = useMemo(() => { return areAllGroupPoliciesExpenseChatDisabled((allPolicies as OnyxCollection) ?? {}); }, [allPolicies]); - const shouldShowCreateReportOption = canUseTableReportView && (shouldRedirectToExpensifyClassic || groupPoliciesWithChatEnabled.length > 0); + const shouldShowCreateReportOption = isBetaEnabled(CONST.BETAS.TABLE_REPORT_VIEW) && (shouldRedirectToExpensifyClassic || groupPoliciesWithChatEnabled.length > 0); const shouldShowNewWorkspaceButton = Object.values(allPolicies ?? {}).every((policy) => !shouldShowPolicy(policy as OnyxEntry, !!isOffline, session?.email)); diff --git a/src/pages/iou/request/IOURequestStartPage.tsx b/src/pages/iou/request/IOURequestStartPage.tsx index d79c5dc438bb..46670eba04f8 100644 --- a/src/pages/iou/request/IOURequestStartPage.tsx +++ b/src/pages/iou/request/IOURequestStartPage.tsx @@ -125,7 +125,7 @@ function IOURequestStartPage({ const shouldShowPerDiemOption = iouType !== CONST.IOU.TYPE.SPLIT && iouType !== CONST.IOU.TYPE.TRACK && ((!isFromGlobalCreate && doesCurrentPolicyPerDiemExist) || (isFromGlobalCreate && doesPerDiemPolicyExist)); - const {canUseMultiFilesDragAndDrop} = usePermissions(); + const {isBetaEnabled} = usePermissions(); return ( diff --git a/src/pages/iou/request/step/IOURequestStepConfirmation.tsx b/src/pages/iou/request/step/IOURequestStepConfirmation.tsx index 00df32967a5a..7f57215d8374 100644 --- a/src/pages/iou/request/step/IOURequestStepConfirmation.tsx +++ b/src/pages/iou/request/step/IOURequestStepConfirmation.tsx @@ -182,8 +182,8 @@ function IOURequestStepConfirmation({ const [isConfirmed, setIsConfirmed] = useState(false); const [isConfirming, setIsConfirming] = useState(false); - // TODO: remove canUseMultiFilesDragAndDrop check after the feature is enabled - const {canUseMultiFilesDragAndDrop} = usePermissions(); + // TODO: remove beta check after the feature is enabled + const {isBetaEnabled} = usePermissions(); const headerTitle = useMemo(() => { if (isCategorizingTrackExpense) { @@ -1010,7 +1010,7 @@ function IOURequestStepConfirmation({ {(isLoading || isLoadingReceipt || (isScanRequest(transaction) && !Object.values(receiptFiles).length)) && } {PDFThumbnailView} - {/* TODO: remove canUseMultiFilesDragAndDrop check after the feature is enabled */} - {canUseMultiFilesDragAndDrop ? ( + {/* TODO: remove beta check after the feature is enabled */} + {isBetaEnabled(CONST.BETAS.NEWDOT_MULTI_FILES_DRAG_AND_DROP) ? ( { const file = e?.dataTransfer?.files[0]; diff --git a/src/pages/iou/request/step/IOURequestStepScan/index.native.tsx b/src/pages/iou/request/step/IOURequestStepScan/index.native.tsx index 094536c441a1..c7ca2e8d0495 100644 --- a/src/pages/iou/request/step/IOURequestStepScan/index.native.tsx +++ b/src/pages/iou/request/step/IOURequestStepScan/index.native.tsx @@ -30,6 +30,7 @@ import Text from '@components/Text'; import EducationalTooltip from '@components/Tooltip/EducationalTooltip'; import withCurrentUserPersonalDetails from '@components/withCurrentUserPersonalDetails'; import useLocalize from '@hooks/useLocalize'; +import usePermissions from '@hooks/usePermissions'; import usePolicy from '@hooks/usePolicy'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; @@ -45,7 +46,6 @@ import {navigateToParticipantPage, shouldStartLocationPermissionFlow} from '@lib import Log from '@libs/Log'; import Navigation from '@libs/Navigation/Navigation'; import {getIsUserSubmittedExpenseOrScannedReceipt, getManagerMcTestParticipant, getParticipantsOption, getReportOption} from '@libs/OptionsListUtils'; -import Permissions from '@libs/Permissions'; import {isPaidGroupPolicy, isUserInvitedToWorkspace} from '@libs/PolicyUtils'; import {generateReportID, getPolicyExpenseChat, isArchivedReport, isPolicyExpenseChat} from '@libs/ReportUtils'; import {shouldRestrictUserBillableActions} from '@libs/SubscriptionUtils'; @@ -95,6 +95,7 @@ function IOURequestStepScan({ const device = useCameraDevice('back', { physicalDevices: ['wide-angle-camera', 'ultra-wide-angle-camera'], }); + const {isBetaEnabled} = usePermissions(); const [elementTop, setElementTop] = useState(0); const isEditing = action === CONST.IOU.ACTION.EDIT; @@ -109,7 +110,6 @@ function IOURequestStepScan({ const [skipConfirmation] = useOnyx(`${ONYXKEYS.COLLECTION.SKIP_CONFIRMATION}${initialTransactionID}`, {canBeMissing: true}); const [activePolicyID] = useOnyx(ONYXKEYS.NVP_ACTIVE_POLICY_ID, {canBeMissing: false}); const [activePolicy] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${activePolicyID}`, {canBeMissing: true}); - const [betas] = useOnyx(ONYXKEYS.BETAS, {canBeMissing: false}); const platform = getPlatform(true); const [mutedPlatforms = {}] = useOnyx(ONYXKEYS.NVP_MUTED_PLATFORMS, {canBeMissing: true}); const isPlatformMuted = mutedPlatforms[platform]; @@ -512,7 +512,7 @@ function IOURequestStepScan({ const {shouldShowProductTrainingTooltip, renderProductTrainingTooltip} = useProductTrainingContext( CONST.PRODUCT_TRAINING_TOOLTIP_NAMES.SCAN_TEST_TOOLTIP, - isTooltipAllowed && !getIsUserSubmittedExpenseOrScannedReceipt() && Permissions.canUseManagerMcTest(betas) && isTabActive && !isUserInvitedToWorkspace(), + isTooltipAllowed && !getIsUserSubmittedExpenseOrScannedReceipt() && isBetaEnabled(CONST.BETAS.NEWDOT_MANAGER_MCTEST) && isTabActive && !isUserInvitedToWorkspace(), { onConfirm: setTestReceiptAndNavigate, onDismiss: () => { diff --git a/src/pages/iou/request/step/IOURequestStepScan/index.tsx b/src/pages/iou/request/step/IOURequestStepScan/index.tsx index 6ad36a8b9ee3..0197682f80af 100644 --- a/src/pages/iou/request/step/IOURequestStepScan/index.tsx +++ b/src/pages/iou/request/step/IOURequestStepScan/index.tsx @@ -48,7 +48,6 @@ import {navigateToParticipantPage, shouldStartLocationPermissionFlow} from '@lib import Log from '@libs/Log'; import Navigation from '@libs/Navigation/Navigation'; import {getIsUserSubmittedExpenseOrScannedReceipt, getManagerMcTestParticipant, getParticipantsOption, getReportOption} from '@libs/OptionsListUtils'; -import Permissions from '@libs/Permissions'; import {isPaidGroupPolicy, isUserInvitedToWorkspace} from '@libs/PolicyUtils'; import {generateReportID, getPolicyExpenseChat, isArchivedReport, isPolicyExpenseChat} from '@libs/ReportUtils'; import {shouldRestrictUserBillableActions} from '@libs/SubscriptionUtils'; @@ -129,7 +128,6 @@ function IOURequestStepScan({ const [skipConfirmation] = useOnyx(`${ONYXKEYS.COLLECTION.SKIP_CONFIRMATION}${initialTransactionID}`, {canBeMissing: true}); const [activePolicyID] = useOnyx(ONYXKEYS.NVP_ACTIVE_POLICY_ID, {canBeMissing: false}); const [activePolicy] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${activePolicyID}`, {canBeMissing: true}); - const [betas] = useOnyx(ONYXKEYS.BETAS, {canBeMissing: false}); const [isLoadingReceipt, setIsLoadingReceipt] = useState(false); const [optimisticTransactions] = useOnyx(ONYXKEYS.COLLECTION.TRANSACTION_DRAFT, { @@ -150,8 +148,7 @@ function IOURequestStepScan({ const transactionTaxCode = (initialTransaction?.taxCode ? initialTransaction?.taxCode : defaultTaxCode) ?? ''; const transactionTaxAmount = initialTransaction?.taxAmount ?? 0; - // TODO: remove canUseMultiFilesDragAndDrop check after the feature is enabled - const {canUseMultiFilesDragAndDrop} = usePermissions(); + const {isBetaEnabled} = usePermissions(); const platform = getPlatform(true); @@ -637,7 +634,7 @@ function IOURequestStepScan({ const {shouldShowProductTrainingTooltip, renderProductTrainingTooltip} = useProductTrainingContext( CONST.PRODUCT_TRAINING_TOOLTIP_NAMES.SCAN_TEST_TOOLTIP, - isTooltipAllowed && !getIsUserSubmittedExpenseOrScannedReceipt() && Permissions.canUseManagerMcTest(betas) && isTabActive && !isUserInvitedToWorkspace(), + isTooltipAllowed && !getIsUserSubmittedExpenseOrScannedReceipt() && isBetaEnabled(CONST.BETAS.NEWDOT_MANAGER_MCTEST) && isTabActive && !isUserInvitedToWorkspace(), { onConfirm: setTestReceiptAndNavigate, onDismiss: () => { @@ -971,8 +968,8 @@ function IOURequestStepScan({ {!(isDraggingOver ?? isDraggingOverWrapper) && (isMobile() ? mobileCameraView() : desktopUploadView())} - {/* TODO: remove canUseMultiFilesDragAndDrop check after the feature is enabled */} - {canUseMultiFilesDragAndDrop ? ( + {/* TODO: remove beta check after the feature is enabled */} + {isBetaEnabled(CONST.BETAS.NEWDOT_MULTI_FILES_DRAG_AND_DROP) ? ( { const file = e?.dataTransfer?.files[0]; diff --git a/src/pages/iou/request/step/StepScreenDragAndDropWrapper.tsx b/src/pages/iou/request/step/StepScreenDragAndDropWrapper.tsx index 6dffe7cade15..99acaad547a5 100644 --- a/src/pages/iou/request/step/StepScreenDragAndDropWrapper.tsx +++ b/src/pages/iou/request/step/StepScreenDragAndDropWrapper.tsx @@ -7,6 +7,7 @@ import ScreenWrapper from '@components/ScreenWrapper'; import usePermissions from '@hooks/usePermissions'; import useThemeStyles from '@hooks/useThemeStyles'; import {canUseTouchScreen} from '@libs/DeviceCapabilities'; +import CONST from '@src/CONST'; import callOrReturn from '@src/types/utils/callOrReturn'; type StepScreenDragAndDropWrapperProps = { @@ -34,8 +35,8 @@ function StepScreenDragAndDropWrapper({testID, headerTitle, onBackButtonPress, o const [isDraggingOver, setIsDraggingOver] = useState(false); - // TODO: remove canUseMultiFilesDragAndDrop check after the feature is enabled - const {canUseMultiFilesDragAndDrop} = usePermissions(); + // TODO: remove beta check after the feature is enabled + const {isBetaEnabled} = usePermissions(); if (!shouldShowWrapper) { return callOrReturn(children, false); @@ -48,7 +49,7 @@ function StepScreenDragAndDropWrapper({testID, headerTitle, onBackButtonPress, o onEntryTransitionEnd={onEntryTransitionEnd} testID={testID} shouldEnableMaxHeight={canUseTouchScreen()} - headerGapStyles={isDraggingOver ? [canUseMultiFilesDragAndDrop ? styles.dropWrapper : styles.isDraggingOver] : []} + headerGapStyles={isDraggingOver ? [isBetaEnabled(CONST.BETAS.NEWDOT_MULTI_FILES_DRAG_AND_DROP) ? styles.dropWrapper : styles.isDraggingOver] : []} > {({safeAreaPaddingBottomStyle}) => ( diff --git a/src/pages/settings/Security/SecuritySettingsPage.tsx b/src/pages/settings/Security/SecuritySettingsPage.tsx index 89b745dcfb71..cbe973e667d1 100644 --- a/src/pages/settings/Security/SecuritySettingsPage.tsx +++ b/src/pages/settings/Security/SecuritySettingsPage.tsx @@ -50,7 +50,7 @@ function SecuritySettingsPage() { const {shouldUseNarrowLayout} = useResponsiveLayout(); const {windowWidth} = useWindowDimensions(); const personalDetails = usePersonalDetails(); - const {canUseMergeAccounts} = usePermissions(); + const {isBetaEnabled} = usePermissions(); const [account] = useOnyx(ONYXKEYS.ACCOUNT, {canBeMissing: true}); const isUserValidated = account?.validated; @@ -122,7 +122,7 @@ function SecuritySettingsPage() { }, ]; - if (canUseMergeAccounts) { + if (isBetaEnabled(CONST.BETAS.NEWDOT_MERGE_ACCOUNTS)) { baseMenuItems.push({ translationKey: 'mergeAccountsPage.mergeAccount', icon: Expensicons.ArrowCollapse, @@ -144,7 +144,7 @@ function SecuritySettingsPage() { link: '', wrapperStyle: [styles.sectionMenuItemTopDescription], })); - }, [translate, waitForNavigate, styles, isActingAsDelegate, canUseMergeAccounts]); + }, [translate, waitForNavigate, styles, isActingAsDelegate, isBetaEnabled]); const delegateMenuItems: MenuItemProps[] = useMemo( () => diff --git a/src/pages/settings/Wallet/ExpensifyCardPage.tsx b/src/pages/settings/Wallet/ExpensifyCardPage.tsx index 2d998e95aced..25d79f27dbaa 100644 --- a/src/pages/settings/Wallet/ExpensifyCardPage.tsx +++ b/src/pages/settings/Wallet/ExpensifyCardPage.tsx @@ -73,7 +73,7 @@ function ExpensifyCardPage({ const styles = useThemeStyles(); const {isOffline} = useNetwork(); const {translate} = useLocalize(); - const {canUseInAppProvisioning} = usePermissions(); + const {isBetaEnabled} = usePermissions(); const [isValidateCodeActionModalVisible, setIsValidateCodeActionModalVisible] = useState(false); const [currentCardID, setCurrentCardID] = useState(-1); const isTravelCard = cardList?.[cardID]?.nameValuePairs?.isTravelCard; @@ -339,7 +339,7 @@ function ExpensifyCardPage({ /> )} - {!!canUseInAppProvisioning && cardToAdd !== undefined && ( + {!!isBetaEnabled(CONST.BETAS.WALLET) && cardToAdd !== undefined && ( { @@ -45,7 +45,7 @@ function WorkspaceOverviewCurrencyPage({policy}: WorkspaceOverviewCurrencyPagePr if (isForcedToChangeCurrency) { setIsForcedToChangeCurrency(false); - if (isCurrencySupportedForGlobalReimbursement(item.currencyCode as CurrencyType, canUseGlobalReimbursementsOnND ?? false)) { + if (isCurrencySupportedForGlobalReimbursement(item.currencyCode as CurrencyType, isBetaEnabled(CONST.BETAS.GLOBAL_REIMBURSEMENTS_ON_ND) ?? false)) { navigateToBankAccountRoute(policy.id, ROUTES.WORKSPACE_WORKFLOWS.getRoute(policy.id)); return; } diff --git a/src/pages/workspace/accounting/PolicyAccountingPage.tsx b/src/pages/workspace/accounting/PolicyAccountingPage.tsx index 7e6b21762407..b2816eda3c3f 100644 --- a/src/pages/workspace/accounting/PolicyAccountingPage.tsx +++ b/src/pages/workspace/accounting/PolicyAccountingPage.tsx @@ -74,7 +74,7 @@ function PolicyAccountingPage({policy}: PolicyAccountingPageProps) { const styles = useThemeStyles(); const {translate, datetimeToRelative: getDatetimeToRelative, getLocalDateFromDatetime} = useLocalize(); const {isOffline} = useNetwork(); - const {canUseNetSuiteUSATax} = usePermissions(); + const {isBetaEnabled} = usePermissions(); const threeDotsAnchorPosition = useThreeDotsAnchorPosition(styles.threeDotsPopoverOffsetNoCloseButton); const {shouldUseNarrowLayout} = useResponsiveLayout(); const [isDisconnectModalOpen, setIsDisconnectModalOpen] = useState(false); @@ -330,7 +330,7 @@ function PolicyAccountingPage({policy}: PolicyAccountingPageProps) { return []; } const isConnectionVerified = !isConnectionUnverified(policy, connectedIntegration); - const integrationData = getAccountingIntegrationData(connectedIntegration, policyID, translate, policy, undefined, undefined, undefined, canUseNetSuiteUSATax); + const integrationData = getAccountingIntegrationData(connectedIntegration, policyID, translate, policy, undefined, undefined, undefined, isBetaEnabled(CONST.BETAS.NETSUITE_USA_TAX)); const iconProps = integrationData?.icon ? {icon: integrationData.icon, iconType: CONST.ICON_TYPE_AVATAR} : {}; let connectionMessage; @@ -445,7 +445,7 @@ function PolicyAccountingPage({policy}: PolicyAccountingPageProps) { isOffline, startIntegrationFlow, popoverAnchorRefs, - canUseNetSuiteUSATax, + isBetaEnabled, shouldShowCardReconciliationOption, ]); diff --git a/src/pages/workspace/accounting/netsuite/export/NetSuiteExportConfigurationPage.tsx b/src/pages/workspace/accounting/netsuite/export/NetSuiteExportConfigurationPage.tsx index 5e5a3d5ea352..e64174892b66 100644 --- a/src/pages/workspace/accounting/netsuite/export/NetSuiteExportConfigurationPage.tsx +++ b/src/pages/workspace/accounting/netsuite/export/NetSuiteExportConfigurationPage.tsx @@ -48,7 +48,7 @@ function NetSuiteExportConfigurationPage({policy}: WithPolicyConnectionsProps) { const backTo = route?.params?.backTo; const policyID = policy?.id; const policyOwner = policy?.owner ?? ''; - const {canUseNetSuiteUSATax} = usePermissions(); + const {isBetaEnabled} = usePermissions(); const config = policy?.connections?.netsuite?.options.config; const shouldGoBackToSpecificRoute = @@ -180,7 +180,7 @@ function NetSuiteExportConfigurationPage({policy}: WithPolicyConnectionsProps) { description: translate('workspace.netsuite.journalEntriesTaxPostingAccount'), onPress: !policyID ? undefined : () => Navigation.navigate(ROUTES.POLICY_ACCOUNTING_NETSUITE_TAX_POSTING_ACCOUNT_SELECT.getRoute(policyID)), subscribedSettings: [CONST.NETSUITE_CONFIG.TAX_POSTING_ACCOUNT], - shouldHide: shouldHideTaxPostingAccountSelect(canUseNetSuiteUSATax, selectedSubsidiary, config), + shouldHide: shouldHideTaxPostingAccountSelect(isBetaEnabled(CONST.BETAS.NETSUITE_USA_TAX), selectedSubsidiary, config), }, { type: 'toggle', diff --git a/src/pages/workspace/accounting/netsuite/export/NetSuiteTaxPostingAccountSelectPage.tsx b/src/pages/workspace/accounting/netsuite/export/NetSuiteTaxPostingAccountSelectPage.tsx index a7d4801c1b73..cb56debc4a95 100644 --- a/src/pages/workspace/accounting/netsuite/export/NetSuiteTaxPostingAccountSelectPage.tsx +++ b/src/pages/workspace/accounting/netsuite/export/NetSuiteTaxPostingAccountSelectPage.tsx @@ -21,7 +21,7 @@ import ROUTES from '@src/ROUTES'; function NetSuiteTaxPostingAccountSelectPage({policy}: WithPolicyConnectionsProps) { const styles = useThemeStyles(); const {translate} = useLocalize(); - const {canUseNetSuiteUSATax} = usePermissions(); + const {isBetaEnabled} = usePermissions(); const policyID = policy?.id; @@ -74,7 +74,7 @@ function NetSuiteTaxPostingAccountSelectPage({policy}: WithPolicyConnectionsProp title="workspace.netsuite.journalEntriesTaxPostingAccount" listEmptyContent={listEmptyContent} connectionName={CONST.POLICY.CONNECTIONS.NAME.NETSUITE} - shouldBeBlocked={!!config?.suiteTaxEnabled || !config?.syncOptions.syncTax || !canUseTaxNetSuite(canUseNetSuiteUSATax, selectedSubsidiary?.country)} + shouldBeBlocked={!!config?.suiteTaxEnabled || !config?.syncOptions.syncTax || !canUseTaxNetSuite(isBetaEnabled(CONST.BETAS.NETSUITE_USA_TAX), selectedSubsidiary?.country)} pendingAction={settingsPendingAction([CONST.NETSUITE_CONFIG.TAX_POSTING_ACCOUNT], config?.pendingFields)} errors={getLatestErrorField(config, CONST.NETSUITE_CONFIG.TAX_POSTING_ACCOUNT)} errorRowStyles={[styles.ph5, styles.pv3]} diff --git a/src/pages/workspace/accounting/netsuite/import/NetSuiteImportPage.tsx b/src/pages/workspace/accounting/netsuite/import/NetSuiteImportPage.tsx index 0965be4bca81..8af256784811 100644 --- a/src/pages/workspace/accounting/netsuite/import/NetSuiteImportPage.tsx +++ b/src/pages/workspace/accounting/netsuite/import/NetSuiteImportPage.tsx @@ -6,24 +6,23 @@ import useLocalize from '@hooks/useLocalize'; import usePermissions from '@hooks/usePermissions'; import useThemeStyles from '@hooks/useThemeStyles'; import {updateNetSuiteSyncTaxConfiguration} from '@libs/actions/connections/NetSuiteCommands'; -import * as ErrorUtils from '@libs/ErrorUtils'; +import {getLatestErrorField} from '@libs/ErrorUtils'; import Navigation from '@libs/Navigation/Navigation'; -import * as PolicyUtils from '@libs/PolicyUtils'; -import {areSettingsInErrorFields, canUseTaxNetSuite, settingsPendingAction} from '@libs/PolicyUtils'; +import {areSettingsInErrorFields, canUseTaxNetSuite, getCustomersOrJobsLabelNetSuite, getNetSuiteImportCustomFieldLabel, settingsPendingAction} from '@libs/PolicyUtils'; import {getImportCustomFieldsSettings} from '@pages/workspace/accounting/netsuite/utils'; import withPolicyConnections from '@pages/workspace/withPolicyConnections'; import type {WithPolicyConnectionsProps} from '@pages/workspace/withPolicyConnections'; import ToggleSettingOptionRow from '@pages/workspace/workflows/ToggleSettingsOptionRow'; -import * as Policy from '@userActions/Policy/Policy'; +import {clearNetSuiteErrorField} from '@userActions/Policy/Policy'; import CONST from '@src/CONST'; import ROUTES from '@src/ROUTES'; function NetSuiteImportPage({policy}: WithPolicyConnectionsProps) { const {translate} = useLocalize(); const styles = useThemeStyles(); - const {canUseNetSuiteUSATax} = usePermissions(); + const {isBetaEnabled} = usePermissions(); - const policyID = policy?.id ?? '-1'; + const policyID = policy?.id; const config = policy?.connections?.netsuite?.options?.config; const {subsidiaryList} = policy?.connections?.netsuite?.options?.data ?? {}; const selectedSubsidiary = useMemo(() => (subsidiaryList ?? []).find((subsidiary) => subsidiary.internalID === config?.subsidiaryID), [subsidiaryList, config?.subsidiaryID]); @@ -60,6 +59,9 @@ function NetSuiteImportPage({policy}: WithPolicyConnectionsProps) { title={translate(`workspace.accounting.importTypes.${config?.syncOptions?.mapping?.[importField] ?? CONST.INTEGRATION_ENTITY_MAP_TYPES.NETSUITE_DEFAULT}`)} shouldShowRightIcon onPress={() => { + if (!policyID) { + return; + } Navigation.navigate(ROUTES.POLICY_ACCOUNTING_NETSUITE_IMPORT_MAPPING.getRoute(policyID, importField)); }} brickRoadIndicator={areSettingsInErrorFields([importField], config?.errorFields) ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : undefined} @@ -78,10 +80,13 @@ function NetSuiteImportPage({policy}: WithPolicyConnectionsProps) { > { + if (!policyID) { + return; + } Navigation.navigate(ROUTES.POLICY_ACCOUNTING_NETSUITE_IMPORT_CUSTOMERS_OR_PROJECTS.getRoute(policyID)); }} brickRoadIndicator={ @@ -98,7 +103,7 @@ function NetSuiteImportPage({policy}: WithPolicyConnectionsProps) { } /> - {canUseTaxNetSuite(canUseNetSuiteUSATax, selectedSubsidiary?.country) && ( + {canUseTaxNetSuite(isBetaEnabled(CONST.BETAS.NETSUITE_USA_TAX), selectedSubsidiary?.country) && ( { + if (!policyID) { + return; + } updateNetSuiteSyncTaxConfiguration(policyID, isEnabled); }} pendingAction={settingsPendingAction([CONST.NETSUITE_CONFIG.SYNC_OPTIONS.SYNC_TAX], config?.pendingFields)} - errors={ErrorUtils.getLatestErrorField(config ?? {}, CONST.NETSUITE_CONFIG.SYNC_OPTIONS.SYNC_TAX)} - onCloseError={() => Policy.clearNetSuiteErrorField(policyID, CONST.NETSUITE_CONFIG.SYNC_OPTIONS.SYNC_TAX)} + errors={getLatestErrorField(config ?? {}, CONST.NETSUITE_CONFIG.SYNC_OPTIONS.SYNC_TAX)} + onCloseError={() => clearNetSuiteErrorField(policyID, CONST.NETSUITE_CONFIG.SYNC_OPTIONS.SYNC_TAX)} /> )} {Object.values(CONST.NETSUITE_CONFIG.IMPORT_CUSTOM_FIELDS).map((importField) => { @@ -123,10 +131,15 @@ function NetSuiteImportPage({policy}: WithPolicyConnectionsProps) { shouldDisableStrikeThrough > Navigation.navigate(ROUTES.POLICY_ACCOUNTING_NETSUITE_IMPORT_CUSTOM_FIELD_MAPPING.getRoute(policyID, importField))} + onPress={() => { + if (!policyID) { + return; + } + Navigation.navigate(ROUTES.POLICY_ACCOUNTING_NETSUITE_IMPORT_CUSTOM_FIELD_MAPPING.getRoute(policyID, importField)); + }} brickRoadIndicator={areSettingsInErrorFields(settings, config?.errorFields) ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : undefined} /> diff --git a/src/pages/workspace/companyCards/BankConnection/index.native.tsx b/src/pages/workspace/companyCards/BankConnection/index.native.tsx index 39d8f238c4cc..90376d4988ef 100644 --- a/src/pages/workspace/companyCards/BankConnection/index.native.tsx +++ b/src/pages/workspace/companyCards/BankConnection/index.native.tsx @@ -59,7 +59,7 @@ function BankConnection({policyID: policyIDFromProps, feed, route}: BankConnecti const {isNewFeedConnected, newFeed} = useMemo(() => checkIfNewFeedConnected(prevFeedsData ?? {}, cardFeeds?.settings?.oAuthAccountDetails ?? {}), [cardFeeds, prevFeedsData]); const headerTitleAddCards = !backTo ? translate('workspace.companyCards.addCards') : undefined; const headerTitle = feed ? translate('workspace.companyCards.assignCard') : headerTitleAddCards; - const {canUsePlaidCompanyCards} = usePermissions(); + const {isBetaEnabled} = usePermissions(); const renderLoading = () => ; @@ -75,7 +75,7 @@ function BankConnection({policyID: policyIDFromProps, feed, route}: BankConnecti Navigation.goBack(backTo); return; } - if (bankName === CONST.COMPANY_CARDS.BANKS.BREX || canUsePlaidCompanyCards) { + if (bankName === CONST.COMPANY_CARDS.BANKS.BREX || isBetaEnabled(CONST.BETAS.PLAID_COMPANY_CARDS)) { setAddNewCompanyCardStepAndData({step: CONST.COMPANY_CARDS.STEP.SELECT_BANK}); return; } diff --git a/src/pages/workspace/companyCards/BankConnection/index.tsx b/src/pages/workspace/companyCards/BankConnection/index.tsx index cb51f7e63d45..11aeb76f0e6d 100644 --- a/src/pages/workspace/companyCards/BankConnection/index.tsx +++ b/src/pages/workspace/companyCards/BankConnection/index.tsx @@ -59,7 +59,7 @@ function BankConnection({policyID: policyIDFromProps, feed, route}: BankConnecti const isFeedExpired = feed ? isSelectedFeedExpired(cardFeeds?.settings?.oAuthAccountDetails?.[feed]) : false; const headerTitleAddCards = !backTo ? translate('workspace.companyCards.addCards') : undefined; const headerTitle = feed ? translate('workspace.companyCards.assignCard') : headerTitleAddCards; - const {canUsePlaidCompanyCards} = usePermissions(); + const {isBetaEnabled} = usePermissions(); const onOpenBankConnectionFlow = useCallback(() => { if (!url) { @@ -82,7 +82,7 @@ function BankConnection({policyID: policyIDFromProps, feed, route}: BankConnecti Navigation.goBack(backTo); return; } - if (bankName === CONST.COMPANY_CARDS.BANKS.BREX || canUsePlaidCompanyCards) { + if (bankName === CONST.COMPANY_CARDS.BANKS.BREX || isBetaEnabled(CONST.BETAS.PLAID_COMPANY_CARDS)) { setAddNewCompanyCardStepAndData({step: CONST.COMPANY_CARDS.STEP.SELECT_BANK}); return; } diff --git a/src/pages/workspace/companyCards/addNew/AddNewCardPage.tsx b/src/pages/workspace/companyCards/addNew/AddNewCardPage.tsx index 2b3fdfac7a3f..e8b3eb596e26 100644 --- a/src/pages/workspace/companyCards/addNew/AddNewCardPage.tsx +++ b/src/pages/workspace/companyCards/addNew/AddNewCardPage.tsx @@ -27,7 +27,7 @@ function AddNewCardPage({policy}: WithPolicyAndFullscreenLoadingProps) { const workspaceAccountID = useWorkspaceAccountID(policyID); const [addNewCardFeed, addNewCardFeedMetadata] = useOnyx(ONYXKEYS.ADD_NEW_COMPANY_CARD, {canBeMissing: false}); const {currentStep} = addNewCardFeed ?? {}; - const {canUsePlaidCompanyCards} = usePermissions(); + const {isBetaEnabled} = usePermissions(); const [isActingAsDelegate] = useOnyx(ONYXKEYS.ACCOUNT, {selector: (account) => !!account?.delegatedAccess?.delegate, canBeMissing: false}); @@ -78,7 +78,7 @@ function AddNewCardPage({policy}: WithPolicyAndFullscreenLoadingProps) { case CONST.COMPANY_CARDS.STEP.PLAID_CONNECTION: return ; default: - return canUsePlaidCompanyCards ? : ; + return isBetaEnabled(CONST.BETAS.PLAID_COMPANY_CARDS) ? : ; } } diff --git a/src/pages/workspace/companyCards/addNew/SelectBankStep.tsx b/src/pages/workspace/companyCards/addNew/SelectBankStep.tsx index f08001498c16..027665c7c6e7 100644 --- a/src/pages/workspace/companyCards/addNew/SelectBankStep.tsx +++ b/src/pages/workspace/companyCards/addNew/SelectBankStep.tsx @@ -29,7 +29,7 @@ function SelectBankStep() { const route = useRoute>(); const styles = useThemeStyles(); const illustrations = useThemeIllustrations(); - const {canUsePlaidCompanyCards} = usePermissions(); + const {isBetaEnabled} = usePermissions(); const [addNewCard] = useOnyx(ONYXKEYS.ADD_NEW_COMPANY_CARD, {canBeMissing: true}); const [bankSelected, setBankSelected] = useState>(); @@ -40,11 +40,11 @@ function SelectBankStep() { if (!bankSelected) { setHasError(true); } else { - if (addNewCard?.data.selectedBank !== bankSelected && !canUsePlaidCompanyCards) { + if (addNewCard?.data.selectedBank !== bankSelected && !isBetaEnabled(CONST.BETAS.PLAID_COMPANY_CARDS)) { clearAddNewCardFlow(); } setAddNewCompanyCardStepAndData({ - step: canUsePlaidCompanyCards ? getCorrectStepForPlaidSelectedBank(bankSelected) : getCorrectStepForSelectedBank(bankSelected), + step: isBetaEnabled(CONST.BETAS.PLAID_COMPANY_CARDS) ? getCorrectStepForPlaidSelectedBank(bankSelected) : getCorrectStepForSelectedBank(bankSelected), data: { selectedBank: bankSelected, cardTitle: !isOtherBankSelected ? bankSelected : undefined, @@ -64,7 +64,7 @@ function SelectBankStep() { Navigation.navigate(route.params.backTo); return; } - if (canUsePlaidCompanyCards) { + if (isBetaEnabled(CONST.BETAS.PLAID_COMPANY_CARDS)) { setAddNewCompanyCardStepAndData({step: CONST.COMPANY_CARDS.STEP.SELECT_FEED_TYPE}); } else { Navigation.goBack(); diff --git a/src/pages/workspace/companyCards/addNew/SelectFeedType.tsx b/src/pages/workspace/companyCards/addNew/SelectFeedType.tsx index 1e237069a70b..5e0296846dca 100644 --- a/src/pages/workspace/companyCards/addNew/SelectFeedType.tsx +++ b/src/pages/workspace/companyCards/addNew/SelectFeedType.tsx @@ -22,7 +22,7 @@ function SelectFeedType() { const [addNewCard] = useOnyx(ONYXKEYS.ADD_NEW_COMPANY_CARD, {canBeMissing: true}); const [typeSelected, setTypeSelected] = useState>(); const [hasError, setHasError] = useState(false); - const {canUsePlaidCompanyCards} = usePermissions(); + const {isBetaEnabled} = usePermissions(); const isCountrySupportPlaid = addNewCard?.data?.selectedCountry ? CONST.PLAID_SUPPORT_COUNTRIES.includes(addNewCard.data.selectedCountry) : false; const isUSCountry = addNewCard?.data?.selectedCountry === CONST.COUNTRY.US; @@ -33,7 +33,7 @@ function SelectFeedType() { } const isDirectSelected = typeSelected === CONST.COMPANY_CARDS.FEED_TYPE.DIRECT; - if (!canUsePlaidCompanyCards || !isDirectSelected) { + if (!isBetaEnabled(CONST.BETAS.PLAID_COMPANY_CARDS) || !isDirectSelected) { setAddNewCompanyCardStepAndData({ step: isDirectSelected ? CONST.COMPANY_CARDS.STEP.BANK_CONNECTION : CONST.COMPANY_CARDS.STEP.CARD_TYPE, data: {selectedFeedType: typeSelected}, @@ -58,14 +58,16 @@ function SelectFeedType() { }, [addNewCard?.data.selectedFeedType, isCountrySupportPlaid]); const handleBackButtonPress = () => { - setAddNewCompanyCardStepAndData({step: canUsePlaidCompanyCards ? CONST.COMPANY_CARDS.STEP.SELECT_COUNTRY : CONST.COMPANY_CARDS.STEP.SELECT_BANK}); + setAddNewCompanyCardStepAndData({step: isBetaEnabled(CONST.BETAS.PLAID_COMPANY_CARDS) ? CONST.COMPANY_CARDS.STEP.SELECT_COUNTRY : CONST.COMPANY_CARDS.STEP.SELECT_BANK}); }; const data = [ { value: CONST.COMPANY_CARDS.FEED_TYPE.CUSTOM, text: translate('workspace.companyCards.commercialFeed'), - alternateText: translate(canUsePlaidCompanyCards ? 'workspace.companyCards.addNewCard.commercialFeedPlaidDetails' : 'workspace.companyCards.addNewCard.commercialFeedDetails'), + alternateText: translate( + isBetaEnabled(CONST.BETAS.PLAID_COMPANY_CARDS) ? 'workspace.companyCards.addNewCard.commercialFeedPlaidDetails' : 'workspace.companyCards.addNewCard.commercialFeedDetails', + ), keyForList: CONST.COMPANY_CARDS.FEED_TYPE.CUSTOM, isSelected: typeSelected === CONST.COMPANY_CARDS.FEED_TYPE.CUSTOM, }, @@ -79,7 +81,7 @@ function SelectFeedType() { ]; const getFinalData = () => { - if (!canUsePlaidCompanyCards) { + if (!isBetaEnabled(CONST.BETAS.PLAID_COMPANY_CARDS)) { return data; } if (isCountrySupportPlaid) { diff --git a/src/pages/workspace/rules/PolicyRulesPage.tsx b/src/pages/workspace/rules/PolicyRulesPage.tsx index 534a57041921..58b5cb985c43 100644 --- a/src/pages/workspace/rules/PolicyRulesPage.tsx +++ b/src/pages/workspace/rules/PolicyRulesPage.tsx @@ -19,7 +19,7 @@ type PolicyRulesPageProps = PlatformStackScreenProps - {canUseCustomRules ? : null} + {isBetaEnabled(CONST.BETAS.CUSTOM_RULES) ? : null} diff --git a/src/pages/workspace/tags/WorkspaceTagsPage.tsx b/src/pages/workspace/tags/WorkspaceTagsPage.tsx index 4ac907b39417..ff553199ab7a 100644 --- a/src/pages/workspace/tags/WorkspaceTagsPage.tsx +++ b/src/pages/workspace/tags/WorkspaceTagsPage.tsx @@ -108,7 +108,7 @@ function WorkspaceTagsPage({route}: WorkspaceTagsPageProps) { openPolicyTagsPage(policyID); }, [policyID]); const isQuickSettingsFlow = !!backTo; - const {canUseMultiLevelTags} = usePermissions(); + const {isBetaEnabled} = usePermissions(); const tagsList = useMemo(() => { if (isMultiLevelTags) { @@ -316,7 +316,7 @@ function WorkspaceTagsPage({route}: WorkspaceTagsPageProps) { onSelected: navigateToTagsSettings, value: CONST.POLICY.SECONDARY_ACTIONS.SETTINGS, }); - const shouldShowMoreOptions = canUseMultiLevelTags ? !hasDependentTags : !policy?.hasMultipleTagLists; + const shouldShowMoreOptions = isBetaEnabled(CONST.BETAS.MULTI_LEVEL_TAGS) ? !hasDependentTags : !policy?.hasMultipleTagLists; if (!shouldShowMoreOptions) { return menuItems; } @@ -349,7 +349,7 @@ function WorkspaceTagsPage({route}: WorkspaceTagsPageProps) { return; } close(() => { - if (hasIndependentTags && canUseMultiLevelTags) { + if (hasIndependentTags && isBetaEnabled(CONST.BETAS.MULTI_LEVEL_TAGS)) { downloadMultiLevelIndependentTagsCSV(policyID, () => { setIsDownloadFailureModalVisible(true); }); @@ -365,7 +365,7 @@ function WorkspaceTagsPage({route}: WorkspaceTagsPageProps) { } return menuItems; - }, [translate, navigateToTagsSettings, canUseMultiLevelTags, hasDependentTags, policy, hasVisibleTags, isOffline, isQuickSettingsFlow, policyID, backTo, hasIndependentTags]); + }, [translate, navigateToTagsSettings, isBetaEnabled, hasDependentTags, policy, hasVisibleTags, isOffline, isQuickSettingsFlow, policyID, backTo, hasIndependentTags]); const getHeaderButtons = () => { const hasAccountingConnections = hasAccountingConnectionsPolicyUtils(policy); diff --git a/src/pages/workspace/workflows/WorkspaceWorkflowsPage.tsx b/src/pages/workspace/workflows/WorkspaceWorkflowsPage.tsx index 77536e85ee2d..ab792f732189 100644 --- a/src/pages/workspace/workflows/WorkspaceWorkflowsPage.tsx +++ b/src/pages/workspace/workflows/WorkspaceWorkflowsPage.tsx @@ -84,7 +84,7 @@ function WorkspaceWorkflowsPage({policy, route}: WorkspaceWorkflowsPageProps) { }), [personalDetails, policy?.employeeList, policy?.owner, policyApproverEmail], ); - const {canUseGlobalReimbursementsOnND} = usePermissions(); + const {isBetaEnabled} = usePermissions(); const isAdvanceApproval = approvalWorkflows.length > 1 || (approvalWorkflows?.at(0)?.approvers ?? []).length > 1; const updateApprovalMode = isAdvanceApproval ? CONST.POLICY.APPROVAL_MODE.ADVANCED : CONST.POLICY.APPROVAL_MODE.BASIC; @@ -106,14 +106,14 @@ function WorkspaceWorkflowsPage({policy, route}: WorkspaceWorkflowsPageProps) { setIsUpdateWorkspaceCurrencyModalOpen(false); - if (canUseGlobalReimbursementsOnND) { + if (isBetaEnabled(CONST.BETAS.GLOBAL_REIMBURSEMENTS_ON_ND)) { setIsForcedToChangeCurrency(true); Navigation.navigate(ROUTES.WORKSPACE_OVERVIEW_CURRENCY.getRoute(policy.id)); } else { updateGeneralSettings(policy.id, policy.name, CONST.CURRENCY.USD); navigateToBankAccountRoute(route.params.policyID, ROUTES.WORKSPACE_WORKFLOWS.getRoute(route.params.policyID)); } - }, [canUseGlobalReimbursementsOnND, policy, route.params.policyID]); + }, [isBetaEnabled, policy, route.params.policyID]); const {isOffline} = useNetwork({onReconnect: fetchData}); const isPolicyAdmin = isPolicyAdminUtil(policy); @@ -262,7 +262,12 @@ function WorkspaceWorkflowsPage({policy, route}: WorkspaceWorkflowsPageProps) { titleStyle={shouldShowBankAccount ? undefined : styles.textLabelSupportingEmptyValue} description={getPaymentMethodDescription(CONST.PAYMENT_METHODS.BUSINESS_BANK_ACCOUNT, policy?.achAccount ?? {})} onPress={() => { - if (!isCurrencySupportedForGlobalReimbursement((policy?.outputCurrency ?? '') as CurrencyType, canUseGlobalReimbursementsOnND ?? false)) { + if ( + !isCurrencySupportedForGlobalReimbursement( + (policy?.outputCurrency ?? '') as CurrencyType, + isBetaEnabled(CONST.BETAS.GLOBAL_REIMBURSEMENTS_ON_ND) ?? false, + ) + ) { setIsUpdateWorkspaceCurrencyModalOpen(true); return; } @@ -322,7 +327,7 @@ function WorkspaceWorkflowsPage({policy, route}: WorkspaceWorkflowsPageProps) { displayNameForAuthorizedPayer, route.params.policyID, updateApprovalMode, - canUseGlobalReimbursementsOnND, + isBetaEnabled, ]); const renderOptionItem = (item: ToggleSettingOptionRowProps, index: number) => ( @@ -376,7 +381,7 @@ function WorkspaceWorkflowsPage({policy, route}: WorkspaceWorkflowsPageProps) { > {optionItems.map(renderOptionItem)} - {canUseGlobalReimbursementsOnND ? ( + {isBetaEnabled(CONST.BETAS.GLOBAL_REIMBURSEMENTS_ON_ND) ? ( {children}; +} + +describe('usePermissions', () => { + beforeAll(() => { + Onyx.init({ + keys: ONYXKEYS, + }); + }); + + beforeEach(async () => { + await Onyx.clear(); + }); + + it('should handle empty betas gracefully via Onyx', async () => { + Onyx.set(ONYXKEYS.BETAS, []); + await waitForBatchedUpdatesWithAct(); + + const {result} = renderHook(() => usePermissions(), {wrapper: Wrapper}); + + await waitForBatchedUpdatesWithAct(); + + expect(result.current.isBetaEnabled(CONST.BETAS.ALL)).toBe(false); + }); + + it('should return correct permissions when betas are provided via Onyx', async () => { + const mockBetas = [CONST.BETAS.ALL]; + + Onyx.set(ONYXKEYS.BETAS, mockBetas); + await waitForBatchedUpdatesWithAct(); + + const {result} = renderHook(() => usePermissions(), {wrapper: Wrapper}); + await waitForBatchedUpdatesWithAct(); + + // Ensure result.current is not null or undefined before accessing properties + expect(result.current.isBetaEnabled(CONST.BETAS.ALL)).toBe(true); + expect(result.current.isBlockedFromSpotnanaTravel).toBe(false); + expect(result.current.isBetaEnabled(CONST.BETAS.DEFAULT_ROOMS)).toBe(true); + }); + + it('should react to updates in Betas context via Onyx and give correct value for isBetaEnabled', async () => { + const initialBetas = [CONST.BETAS.DEFAULT_ROOMS, CONST.BETAS.PER_DIEM, CONST.BETAS.PREVENT_SPOTNANA_TRAVEL]; + const updatedBetas = [CONST.BETAS.ALL]; + + Onyx.set(ONYXKEYS.BETAS, initialBetas); + await waitForBatchedUpdatesWithAct(); + + const {result} = renderHook(() => usePermissions(), {wrapper: Wrapper}); + + await waitForBatchedUpdatesWithAct(); + + // Initially, check the value for the initial betas + expect(result.current.isBetaEnabled(CONST.BETAS.DEFAULT_ROOMS)).toBe(true); + expect(result.current.isBlockedFromSpotnanaTravel).toBe(true); + expect(result.current.isBetaEnabled(CONST.BETAS.MULTI_LEVEL_TAGS)).toBe(false); + expect(result.current.isBetaEnabled(CONST.BETAS.ALL)).toBe(false); + + Onyx.merge(ONYXKEYS.BETAS, updatedBetas); + + await waitForBatchedUpdatesWithAct(); + + // After update, check the value for the updated betas + expect(result.current.isBlockedFromSpotnanaTravel).toBe(false); + expect(result.current.isBetaEnabled(CONST.BETAS.ALL)).toBe(true); + expect(result.current.isBetaEnabled(CONST.BETAS.MULTI_LEVEL_TAGS)).toBe(true); + }); +});