From af812a3dc1de45a67f6a9a9ec17118b5a1e8a7e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Muzyk?= Date: Mon, 20 Oct 2025 13:41:48 +0200 Subject: [PATCH 1/8] Reapply "Enable category field on unreported expenses" This reverts commit aecce9da1ab4538353a9ab1546f3ed20b31a9488. --- src/ROUTES.ts | 5 + src/SCREENS.ts | 5 + .../ReportActionItem/MoneyRequestView.tsx | 21 ++++- src/components/Search/index.tsx | 40 +++++--- .../ModalStackNavigators/index.tsx | 6 ++ .../Navigators/RightModalNavigator.tsx | 4 + src/libs/Navigation/linkingConfig/config.ts | 5 + src/libs/Navigation/types.ts | 8 ++ src/libs/ReportUtils.ts | 10 +- src/libs/Violations/ViolationsUtils.ts | 5 +- src/libs/actions/IOU.ts | 1 + src/pages/ReportDetailsPage.tsx | 3 - src/pages/SetDefaultWorkspacePage.tsx | 92 +++++++++++++++++++ .../home/report/PureReportActionItem.tsx | 12 +-- .../request/step/IOURequestStepCategory.tsx | 28 +++--- .../request/step/IOURequestStepUpgrade.tsx | 2 +- 16 files changed, 199 insertions(+), 48 deletions(-) create mode 100644 src/pages/SetDefaultWorkspacePage.tsx diff --git a/src/ROUTES.ts b/src/ROUTES.ts index edf204001c26..9f6dc71f55a0 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -457,6 +457,11 @@ const ROUTES = { return getUrlWithBackToParam(baseRoute, backTo); }, }, + SET_DEFAULT_WORKSPACE: { + route: 'set-default-workspace', + // eslint-disable-next-line no-restricted-syntax -- Legacy route generation + getRoute: (backTo?: string) => getUrlWithBackToParam('set-default-workspace', backTo), + }, REPORT: 'r', REPORT_WITH_ID: { route: 'r/:reportID?/:reportActionID?', diff --git a/src/SCREENS.ts b/src/SCREENS.ts index 2609ed8ff807..7256a7ca151b 100644 --- a/src/SCREENS.ts +++ b/src/SCREENS.ts @@ -211,6 +211,7 @@ const SCREENS = { DETAILS: 'Details', PROFILE: 'Profile', NEW_REPORT_WORKSPACE_SELECTION: 'New_Report_Workspace_Selection', + SET_DEFAULT_WORKSPACE: 'Set_Default_Workspace', REPORT_DETAILS: 'Report_Details', REPORT_CHANGE_WORKSPACE: 'ReportChangeWorkspace', WORKSPACE_CONFIRMATION: 'Workspace_Confirmation', @@ -400,6 +401,10 @@ const SCREENS = { ROOT: 'NewReportWorkspaceSelection_Root', }, + SET_DEFAULT_WORKSPACE: { + ROOT: 'SetDefaultWorkspace_Root', + }, + REPORT_DETAILS: { ROOT: 'Report_Details_Root', SHARE_CODE: 'Report_Details_Share_Code', diff --git a/src/components/ReportActionItem/MoneyRequestView.tsx b/src/components/ReportActionItem/MoneyRequestView.tsx index 689d1e976368..664491fe7803 100644 --- a/src/components/ReportActionItem/MoneyRequestView.tsx +++ b/src/components/ReportActionItem/MoneyRequestView.tsx @@ -268,7 +268,7 @@ function MoneyRequestView({ // Flags for showing categories and tags // transactionCategory can be an empty string // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing - const shouldShowCategory = isPolicyExpenseChat && (categoryForDisplay || hasEnabledOptions(policyCategories ?? {})); + const shouldShowCategory = (isPolicyExpenseChat && (categoryForDisplay || hasEnabledOptions(policyCategories ?? {}))) || isExpenseUnreported; // transactionTag can be an empty string // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing const shouldShowTag = isPolicyExpenseChat && (transactionTag || hasEnabledTags(policyTagLists)); @@ -307,6 +307,8 @@ function MoneyRequestView({ amountTitle = translate('iou.receiptStatusTitle'); } + const shouldNavigateToUpgradePath = !policyForMovingExpenses && !shouldSelectPolicy; + const updatedTransactionDescription = useMemo(() => { if (!updatedTransaction) { return undefined; @@ -742,17 +744,28 @@ function MoneyRequestView({ shouldShowRightIcon={canEdit} titleStyle={styles.flex1} onPress={() => { - if (!policy) { + if (shouldNavigateToUpgradePath) { Navigation.navigate( ROUTES.MONEY_REQUEST_UPGRADE.getRoute({ action: CONST.IOU.ACTION.EDIT, iouType, transactionID: transaction.transactionID, reportID: report.reportID, - backTo: getReportRHPActiveRoute(), upgradePath: CONST.UPGRADE_PATHS.CATEGORIES, }), ); + } else if (shouldSelectPolicy) { + Navigation.navigate( + ROUTES.SET_DEFAULT_WORKSPACE.getRoute( + ROUTES.MONEY_REQUEST_STEP_CATEGORY.getRoute( + CONST.IOU.ACTION.EDIT, + iouType, + transaction.transactionID, + report.reportID, + getReportRHPActiveRoute(), + ), + ), + ); } else { Navigation.navigate( ROUTES.MONEY_REQUEST_STEP_CATEGORY.getRoute(CONST.IOU.ACTION.EDIT, iouType, transaction.transactionID, report.reportID, getReportRHPActiveRoute()), @@ -893,7 +906,7 @@ function MoneyRequestView({ if (!canEditReport) { return; } - if (!policyForMovingExpenses && !shouldSelectPolicy) { + if (shouldNavigateToUpgradePath) { Navigation.navigate( ROUTES.MONEY_REQUEST_UPGRADE.getRoute({ iouType, diff --git a/src/components/Search/index.tsx b/src/components/Search/index.tsx index 9079f8fa0cd4..9f1230fb4eda 100644 --- a/src/components/Search/index.tsx +++ b/src/components/Search/index.tsx @@ -3,7 +3,7 @@ import {accountIDSelector} from '@selectors/Session'; import React, {useCallback, useContext, useEffect, useMemo, useRef, useState} from 'react'; import type {NativeScrollEvent, NativeSyntheticEvent, StyleProp, ViewStyle} from 'react-native'; import {View} from 'react-native'; -import type {OnyxEntry} from 'react-native-onyx'; +import type {OnyxCollection, OnyxEntry} from 'react-native-onyx'; import Animated, {FadeIn, FadeOut, useAnimatedStyle, useSharedValue, withTiming} from 'react-native-reanimated'; import FullPageErrorView from '@components/BlockingViews/FullPageErrorView'; import FullPageOfflineBlockingView from '@components/BlockingViews/FullPageOfflineBlockingView'; @@ -12,6 +12,7 @@ import type {ReportActionListItemType, SearchListItem, SelectionListHandle, Tran import SearchRowSkeleton from '@components/Skeletons/SearchRowSkeleton'; import {WideRHPContext} from '@components/WideRHPContextProvider'; import useCardFeedsForDisplay from '@hooks/useCardFeedsForDisplay'; +import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails'; import useLocalize from '@hooks/useLocalize'; import useNetwork from '@hooks/useNetwork'; import useOnyx from '@hooks/useOnyx'; @@ -29,6 +30,7 @@ import Log from '@libs/Log'; import isSearchTopmostFullScreenRoute from '@libs/Navigation/helpers/isSearchTopmostFullScreenRoute'; import type {PlatformStackNavigationProp} from '@libs/Navigation/PlatformStackNavigation/types'; import Performance from '@libs/Performance'; +import {getPolicyRole, isPaidGroupPolicy as isPaidGroupPolicyPolicyUtils} from '@libs/PolicyUtils'; import {getIOUActionForTransactionID} from '@libs/ReportActionsUtils'; import {canEditFieldOfMoneyRequest, selectArchivedReportsIdSet, selectFilteredReportActions} from '@libs/ReportUtils'; import {buildCannedSearchQuery, buildSearchQueryJSON, buildSearchQueryString} from '@libs/SearchQueryUtils'; @@ -90,6 +92,7 @@ function mapTransactionItemToSelectedEntry( item: TransactionListItemType, reportActions: ReportAction[], outstandingReportsByPolicyID?: OutstandingReportsByPolicyIDDerivedValue, + canMoveExpense = true, ): [string, SelectedTransactionInfo] { return [ item.keyForList, @@ -105,7 +108,7 @@ function mapTransactionItemToSelectedEntry( undefined, undefined, outstandingReportsByPolicyID, - true, + canMoveExpense, ), action: item.action, reportID: item.reportID, @@ -166,6 +169,7 @@ function prepareTransactionsList( selectedTransactions: SelectedTransactions, reportActions: ReportAction[], outstandingReportsByPolicyID?: OutstandingReportsByPolicyIDDerivedValue, + canMoveExpense = true, ) { if (selectedTransactions[item.keyForList]?.isSelected) { const {[item.keyForList]: omittedTransaction, ...transactions} = selectedTransactions; @@ -187,7 +191,7 @@ function prepareTransactionsList( undefined, undefined, outstandingReportsByPolicyID, - true, + canMoveExpense, ), action: item.action, reportID: item.reportID, @@ -201,6 +205,10 @@ function prepareTransactionsList( }; } +const activePaidPoliciesSelector = (allPolicies: OnyxCollection): OnyxCollection => { + return Object.fromEntries(Object.entries(allPolicies ?? {}).filter(([, userPolicy]) => isPaidGroupPolicyPolicyUtils(userPolicy))); +}; + function Search({queryJSON, searchResults, onSearchListScroll, contentContainerStyle, handleSearch, isMobileSelectionModeEnabled, onSortPressedCallback}: SearchProps) { const {type, status, sortBy, sortOrder, hash, similarSearchHash, groupBy} = queryJSON; const {isOffline} = useNetwork(); @@ -235,6 +243,14 @@ function Search({queryJSON, searchResults, onSearchListScroll, contentContainerS const [outstandingReportsByPolicyID] = useOnyx(ONYXKEYS.DERIVED.OUTSTANDING_REPORTS_BY_POLICY_ID, {canBeMissing: true}); const [violations] = useOnyx(ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS, {canBeMissing: true}); + const [activePaidPolicies] = useOnyx(ONYXKEYS.COLLECTION.POLICY, { + selector: activePaidPoliciesSelector, + canBeMissing: true, + }); + + const {login: currentUserLogin} = useCurrentUserPersonalDetails(); + const isUserWorkspaceMember = !!Object.values(activePaidPolicies ?? {}).filter((userPolicy) => getPolicyRole(userPolicy, currentUserLogin)).length; + // Filter violations based on user visibility const filteredViolations = useMemo(() => { if (!violations || !searchResults?.data) { @@ -445,7 +461,7 @@ function Search({queryJSON, searchResults, onSearchListScroll, contentContainerS undefined, undefined, outstandingReportsByPolicyID, - true, + isUserWorkspaceMember, ), // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing isSelected: areAllMatchingItemsSelected || selectedTransactions[transaction.transactionID].isSelected, @@ -478,7 +494,7 @@ function Search({queryJSON, searchResults, onSearchListScroll, contentContainerS undefined, undefined, outstandingReportsByPolicyID, - true, + isUserWorkspaceMember, ), // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing isSelected: areAllMatchingItemsSelected || selectedTransactions[transaction.transactionID].isSelected, @@ -500,7 +516,7 @@ function Search({queryJSON, searchResults, onSearchListScroll, contentContainerS isRefreshingSelection.current = true; // eslint-disable-next-line react-compiler/react-compiler, react-hooks/exhaustive-deps - }, [data, setSelectedTransactions, areAllMatchingItemsSelected, isFocused, outstandingReportsByPolicyID]); + }, [data, setSelectedTransactions, areAllMatchingItemsSelected, isFocused, outstandingReportsByPolicyID, isUserWorkspaceMember]); useEffect(() => { if (!isSearchResultsEmpty || prevIsSearchResultEmpty) { @@ -560,7 +576,7 @@ function Search({queryJSON, searchResults, onSearchListScroll, contentContainerS if (isTransactionPendingDelete(item)) { return; } - setSelectedTransactions(prepareTransactionsList(item, selectedTransactions, reportActionsArray, outstandingReportsByPolicyID), data); + setSelectedTransactions(prepareTransactionsList(item, selectedTransactions, reportActionsArray, outstandingReportsByPolicyID, isUserWorkspaceMember), data); return; } @@ -582,13 +598,13 @@ function Search({queryJSON, searchResults, onSearchListScroll, contentContainerS ...Object.fromEntries( currentTransactions .filter((t) => !isTransactionPendingDelete(t)) - .map((transactionItem) => mapTransactionItemToSelectedEntry(transactionItem, reportActionsArray, outstandingReportsByPolicyID)), + .map((transactionItem) => mapTransactionItemToSelectedEntry(transactionItem, reportActionsArray, outstandingReportsByPolicyID, isUserWorkspaceMember)), ), }, data, ); }, - [data, reportActionsArray, selectedTransactions, outstandingReportsByPolicyID, setSelectedTransactions], + [setSelectedTransactions, selectedTransactions, data, reportActionsArray, outstandingReportsByPolicyID, isUserWorkspaceMember], ); const onSelectRow = useCallback( @@ -796,7 +812,7 @@ function Search({queryJSON, searchResults, onSearchListScroll, contentContainerS (data as TransactionGroupListItemType[]).flatMap((item) => item.transactions .filter((t) => !isTransactionPendingDelete(t)) - .map((transactionItem) => mapTransactionItemToSelectedEntry(transactionItem, reportActionsArray, outstandingReportsByPolicyID)), + .map((transactionItem) => mapTransactionItemToSelectedEntry(transactionItem, reportActionsArray, outstandingReportsByPolicyID, isUserWorkspaceMember)), ), ), data, @@ -809,11 +825,11 @@ function Search({queryJSON, searchResults, onSearchListScroll, contentContainerS Object.fromEntries( (data as TransactionListItemType[]) .filter((t) => !isTransactionPendingDelete(t)) - .map((transactionItem) => mapTransactionItemToSelectedEntry(transactionItem, reportActionsArray, outstandingReportsByPolicyID)), + .map((transactionItem) => mapTransactionItemToSelectedEntry(transactionItem, reportActionsArray, outstandingReportsByPolicyID, isUserWorkspaceMember)), ), data, ); - }, [clearSelectedTransactions, data, validGroupBy, reportActionsArray, selectedTransactions, setSelectedTransactions, outstandingReportsByPolicyID, isExpenseReportType]); + }, [validGroupBy, isExpenseReportType, selectedTransactions, setSelectedTransactions, data, clearSelectedTransactions, reportActionsArray, outstandingReportsByPolicyID, isUserWorkspaceMember]); const onLayout = useCallback(() => handleSelectionListScroll(sortedSelectedData, searchListRef.current), [handleSelectionListScroll, sortedSelectedData]); diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx index 120151d88a2d..41afa2aada1d 100644 --- a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx +++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx @@ -37,6 +37,7 @@ import type { SearchAdvancedFiltersParamList, SearchReportParamList, SearchSavedSearchParamList, + SetDefaultWorkspaceNavigatorParamList, SettingsNavigatorParamList, ShareNavigatorParamList, SignInNavigatorParamList, @@ -206,6 +207,10 @@ const NewReportWorkspaceSelectionModalStackNavigator = createModalStackNavigator [SCREENS.NEW_REPORT_WORKSPACE_SELECTION.ROOT]: () => require('../../../../pages/NewReportWorkspaceSelectionPage').default, }); +const SetDefaultWorkspaceModalStackNavigator = createModalStackNavigator({ + [SCREENS.SET_DEFAULT_WORKSPACE.ROOT]: () => require('../../../../pages/SetDefaultWorkspacePage').default, +}); + const ReportDetailsModalStackNavigator = createModalStackNavigator({ [SCREENS.REPORT_DETAILS.ROOT]: () => require('../../../../pages/ReportDetailsPage').default, [SCREENS.REPORT_DETAILS.SHARE_CODE]: () => require('../../../../pages/home/report/ReportDetailsShareCodePage').default, @@ -918,6 +923,7 @@ export { ReferralModalStackNavigator, TravelModalStackNavigator, NewReportWorkspaceSelectionModalStackNavigator, + SetDefaultWorkspaceModalStackNavigator, ReportDescriptionModalStackNavigator, ReportDetailsModalStackNavigator, ReportChangeWorkspaceModalStackNavigator, diff --git a/src/libs/Navigation/AppNavigator/Navigators/RightModalNavigator.tsx b/src/libs/Navigation/AppNavigator/Navigators/RightModalNavigator.tsx index b26e7972c1ce..6c6e525903b3 100644 --- a/src/libs/Navigation/AppNavigator/Navigators/RightModalNavigator.tsx +++ b/src/libs/Navigation/AppNavigator/Navigators/RightModalNavigator.tsx @@ -107,6 +107,10 @@ function RightModalNavigator({navigation, route}: RightModalNavigatorProps) { name={SCREENS.RIGHT_MODAL.NEW_REPORT_WORKSPACE_SELECTION} component={ModalStackNavigators.NewReportWorkspaceSelectionModalStackNavigator} /> + ['config'] = { [SCREENS.NEW_REPORT_WORKSPACE_SELECTION.ROOT]: ROUTES.NEW_REPORT_WORKSPACE_SELECTION.route, }, }, + [SCREENS.RIGHT_MODAL.SET_DEFAULT_WORKSPACE]: { + screens: { + [SCREENS.SET_DEFAULT_WORKSPACE.ROOT]: ROUTES.SET_DEFAULT_WORKSPACE.route, + }, + }, [SCREENS.RIGHT_MODAL.REPORT_DETAILS]: { screens: { [SCREENS.REPORT_DETAILS.ROOT]: ROUTES.REPORT_WITH_ID_DETAILS.route, diff --git a/src/libs/Navigation/types.ts b/src/libs/Navigation/types.ts index decbe39265c4..7d39784efc79 100644 --- a/src/libs/Navigation/types.ts +++ b/src/libs/Navigation/types.ts @@ -1213,6 +1213,12 @@ type NewReportWorkspaceSelectionNavigatorParamList = { }; }; +type SetDefaultWorkspaceNavigatorParamList = { + [SCREENS.SET_DEFAULT_WORKSPACE.ROOT]: { + backTo?: Routes; + }; +}; + type ReportDetailsNavigatorParamList = { [SCREENS.REPORT_DETAILS.ROOT]: { reportID: string; @@ -1819,6 +1825,7 @@ type RightModalNavigatorParamList = { [SCREENS.RIGHT_MODAL.PROFILE]: NavigatorScreenParams; [SCREENS.SETTINGS.SHARE_CODE]: undefined; [SCREENS.RIGHT_MODAL.NEW_REPORT_WORKSPACE_SELECTION]: NavigatorScreenParams; + [SCREENS.RIGHT_MODAL.SET_DEFAULT_WORKSPACE]: NavigatorScreenParams; [SCREENS.RIGHT_MODAL.REPORT_DETAILS]: NavigatorScreenParams; [SCREENS.RIGHT_MODAL.REPORT_CHANGE_WORKSPACE]: NavigatorScreenParams; [SCREENS.RIGHT_MODAL.REPORT_SETTINGS]: NavigatorScreenParams; @@ -2457,6 +2464,7 @@ export type { ReimbursementAccountNavigatorParamList, ReimbursementAccountEnterSignerInfoNavigatorParamList, NewReportWorkspaceSelectionNavigatorParamList, + SetDefaultWorkspaceNavigatorParamList, ReportDescriptionNavigatorParamList, ReportDetailsNavigatorParamList, ReportChangeWorkspaceNavigatorParamList, diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index a6aeaf8d74cb..9b8d657fa31b 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -4389,7 +4389,7 @@ function canEditFieldOfMoneyRequest( isDeleteAction?: boolean, isChatReportArchived = false, outstandingReportsByPolicyID?: OutstandingReportsByPolicyIDDerivedValue, - isSearchPageOption?: boolean, + canMoveExpense = true, ): boolean { // A list of fields that cannot be edited by anyone, once an expense has been settled const restrictedFields: string[] = [ @@ -4474,13 +4474,7 @@ function canEditFieldOfMoneyRequest( // Unreported transaction from OldDot can have the reportID as an empty string const isUnreportedExpense = !transaction?.reportID || transaction?.reportID === CONST.REPORT.UNREPORTED_REPORT_ID; - const isUserWorkspaceMember = getActivePolicies(allPolicies ?? {}, currentUserEmail).filter((userPolicy) => isPaidGroupPolicyPolicyUtils(userPolicy)).length; - - if (isUnreportedExpense && isSearchPageOption && isUserWorkspaceMember) { - return true; - } - - if (isUnreportedExpense && !isSearchPageOption) { + if (isUnreportedExpense && canMoveExpense) { return true; } diff --git a/src/libs/Violations/ViolationsUtils.ts b/src/libs/Violations/ViolationsUtils.ts index 80999381f056..5fd9a0ec6666 100644 --- a/src/libs/Violations/ViolationsUtils.ts +++ b/src/libs/Violations/ViolationsUtils.ts @@ -226,6 +226,7 @@ const ViolationsUtils = { policyCategories: PolicyCategories, hasDependentTags: boolean, isInvoiceTransaction: boolean, + isSelfDM?: boolean, ): OnyxUpdate { const isScanning = TransactionUtils.isScanning(updatedTransaction); const isScanRequest = TransactionUtils.isScanRequest(updatedTransaction); @@ -272,12 +273,12 @@ const ViolationsUtils = { } // Remove 'missingCategory' violation if category is valid according to policy - if (hasMissingCategoryViolation && isCategoryInPolicy) { + if (hasMissingCategoryViolation && (isCategoryInPolicy || isSelfDM)) { newTransactionViolations = reject(newTransactionViolations, {name: 'missingCategory'}); } // Add 'missingCategory' violation if category is required and not set - if (!hasMissingCategoryViolation && policyRequiresCategories && !categoryKey) { + if (!hasMissingCategoryViolation && policyRequiresCategories && !categoryKey && !isSelfDM) { newTransactionViolations.push({name: 'missingCategory', type: CONST.VIOLATION_TYPES.VIOLATION, showInReview: true}); } } diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 0e755df46844..7046a91eece9 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -4606,6 +4606,7 @@ function getUpdateMoneyRequestParams(params: GetUpdateMoneyRequestParamsType): U policyCategories ?? {}, hasDependentTags(policy, policyTagList ?? {}), isInvoice, + isSelfDM(iouReport), ); optimisticData.push(violationsOnyxData); failureData.push({ diff --git a/src/pages/ReportDetailsPage.tsx b/src/pages/ReportDetailsPage.tsx index 2cc95f36b770..5cc2450e636b 100644 --- a/src/pages/ReportDetailsPage.tsx +++ b/src/pages/ReportDetailsPage.tsx @@ -28,7 +28,6 @@ import useNetwork from '@hooks/useNetwork'; import useOnyx from '@hooks/useOnyx'; import usePaginatedReportActions from '@hooks/usePaginatedReportActions'; import useParentReportAction from '@hooks/useParentReportAction'; -import usePermissions from '@hooks/usePermissions'; import usePreferredPolicy from '@hooks/usePreferredPolicy'; import useReportIsArchived from '@hooks/useReportIsArchived'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; @@ -147,7 +146,6 @@ type CaseID = ValueOf; function ReportDetailsPage({policy, report, route, reportMetadata}: ReportDetailsPageProps) { const {translate, localeCompare} = useLocalize(); const {isOffline} = useNetwork(); - const {isBetaEnabled} = usePermissions(); const {isRestrictedToPreferredPolicy, preferredPolicyID} = usePreferredPolicy(); const styles = useThemeStyles(); const backTo = route.params.backTo; @@ -554,7 +552,6 @@ function ReportDetailsPage({policy, report, route, reportMetadata}: ReportDetail parentReportAction, iouTransactionID, moneyRequestReport?.reportID, - isBetaEnabled, session, isTaskActionable, isRootGroupChat, diff --git a/src/pages/SetDefaultWorkspacePage.tsx b/src/pages/SetDefaultWorkspacePage.tsx new file mode 100644 index 000000000000..d42d0201be38 --- /dev/null +++ b/src/pages/SetDefaultWorkspacePage.tsx @@ -0,0 +1,92 @@ +import React from 'react'; +import FullScreenLoadingIndicator from '@components/FullscreenLoadingIndicator'; +import HeaderWithBackButton from '@components/HeaderWithBackButton'; +import {useSession} from '@components/OnyxListItemProvider'; +import ScreenWrapper from '@components/ScreenWrapper'; +import SelectionList from '@components/SelectionListWithSections'; +import UserListItem from '@components/SelectionListWithSections/UserListItem'; +import useDebouncedState from '@hooks/useDebouncedState'; +import useLocalize from '@hooks/useLocalize'; +import useNetwork from '@hooks/useNetwork'; +import useOnyx from '@hooks/useOnyx'; +import useThemeStyles from '@hooks/useThemeStyles'; +import type {WorkspaceListItem} from '@hooks/useWorkspaceList'; +import useWorkspaceList from '@hooks/useWorkspaceList'; +import Navigation from '@libs/Navigation/Navigation'; +import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types'; +import type {SetDefaultWorkspaceNavigatorParamList} from '@libs/Navigation/types'; +import {isPaidGroupPolicy} from '@libs/PolicyUtils'; +import {setNameValuePair} from '@userActions/User'; +import ONYXKEYS from '@src/ONYXKEYS'; +import type SCREENS from '@src/SCREENS'; + +type SetDefaultWorkspacePageProps = PlatformStackScreenProps; + +function SetDefaultWorkspacePage({route}: SetDefaultWorkspacePageProps) { + const {backTo} = route.params ?? {}; + const {isOffline} = useNetwork(); + const styles = useThemeStyles(); + const [searchTerm, debouncedSearchTerm, setSearchTerm] = useDebouncedState(''); + const {translate, localeCompare} = useLocalize(); + + const [policies, fetchStatus] = useOnyx(ONYXKEYS.COLLECTION.POLICY, {canBeMissing: false}); + const [isLoadingApp] = useOnyx(ONYXKEYS.IS_LOADING_APP, {canBeMissing: false}); + const [activePolicyID] = useOnyx(ONYXKEYS.NVP_ACTIVE_POLICY_ID, {canBeMissing: false}); + + const shouldShowLoadingIndicator = isLoadingApp && !isOffline; + const session = useSession(); + + const selectPolicy = (selectedPolicyID?: string) => { + if (!selectedPolicyID) { + return; + } + // eslint-disable-next-line rulesdir/no-default-id-values + setNameValuePair(ONYXKEYS.NVP_ACTIVE_POLICY_ID, selectedPolicyID, activePolicyID ?? ''); + Navigation.goBack(backTo); + }; + + const {sections, shouldShowNoResultsFoundMessage, shouldShowSearchInput} = useWorkspaceList({ + policies, + currentUserLogin: session?.email, + shouldShowPendingDeletePolicy: false, + selectedPolicyIDs: undefined, + searchTerm: debouncedSearchTerm, + localeCompare, + additionalFilter: (newPolicy) => isPaidGroupPolicy(newPolicy), + }); + + return ( + + {({didScreenTransitionEnd}) => ( + <> + + {shouldShowLoadingIndicator ? ( + + ) : ( + + ListItem={UserListItem} + sections={sections} + onSelectRow={(option) => selectPolicy(option.policyID)} + textInputLabel={shouldShowSearchInput ? translate('common.search') : undefined} + textInputValue={searchTerm} + onChangeText={setSearchTerm} + headerMessage={shouldShowNoResultsFoundMessage ? translate('common.noResultsFound') : ''} + showLoadingPlaceholder={fetchStatus.status === 'loading' || !didScreenTransitionEnd} + /> + )} + + )} + + ); +} + +SetDefaultWorkspacePage.displayName = 'SetDefaultWorkspacePage'; + +export default SetDefaultWorkspacePage; diff --git a/src/pages/home/report/PureReportActionItem.tsx b/src/pages/home/report/PureReportActionItem.tsx index 4e2dd389a2c8..ac6ac791d514 100644 --- a/src/pages/home/report/PureReportActionItem.tsx +++ b/src/pages/home/report/PureReportActionItem.tsx @@ -42,7 +42,6 @@ import TextLink from '@components/TextLink'; import UnreadActionIndicator from '@components/UnreadActionIndicator'; import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails'; import useLocalize from '@hooks/useLocalize'; -import usePermissions from '@hooks/usePermissions'; import usePreferredPolicy from '@hooks/usePreferredPolicy'; import usePrevious from '@hooks/usePrevious'; import useReportIsArchived from '@hooks/useReportIsArchived'; @@ -465,7 +464,6 @@ function PureReportActionItem({ const [isContextMenuActive, setIsContextMenuActive] = useState(() => isActiveReportAction(action.reportActionID)); const [isEmojiPickerActive, setIsEmojiPickerActive] = useState(); const [isPaymentMethodPopoverActive, setIsPaymentMethodPopoverActive] = useState(); - const {isBetaEnabled} = usePermissions(); const {isRestrictedToPreferredPolicy, preferredPolicyID} = usePreferredPolicy(); const shouldRenderViewBasedOnAction = useTableReportViewActionRenderConditionals(action); const [isHidden, setIsHidden] = useState(false); @@ -956,7 +954,6 @@ function PureReportActionItem({ policy, currentUserAccountID, personalDetail.timezone, - isBetaEnabled, createDraftTransactionAndNavigateToParticipantSelector, isRestrictedToPreferredPolicy, preferredPolicyID, @@ -1451,10 +1448,10 @@ function PureReportActionItem({ )} {/** - These are the actionable buttons that appear at the bottom of a Concierge message - for example: Invite a user mentioned but not a member of the room - https://github.com/Expensify/App/issues/32741 - */} + These are the actionable buttons that appear at the bottom of a Concierge message + for example: Invite a user mentioned but not a member of the room + https://github.com/Expensify/App/issues/32741 + */} {actionableItemButtons.length > 0 && ( ); } + export type {PureReportActionItemProps}; export default memo(PureReportActionItem, (prevProps, nextProps) => { const prevParentReportAction = prevProps.parentReportAction; diff --git a/src/pages/iou/request/step/IOURequestStepCategory.tsx b/src/pages/iou/request/step/IOURequestStepCategory.tsx index 4b212ca64fdd..b0310c2365a0 100644 --- a/src/pages/iou/request/step/IOURequestStepCategory.tsx +++ b/src/pages/iou/request/step/IOURequestStepCategory.tsx @@ -14,6 +14,7 @@ import WorkspaceEmptyStateSection from '@components/WorkspaceEmptyStateSection'; import useLocalize from '@hooks/useLocalize'; import useNetwork from '@hooks/useNetwork'; import useOnyx from '@hooks/useOnyx'; +import usePolicyForMovingExpenses from '@hooks/usePolicyForMovingExpenses'; import useRestartOnReceiptFailure from '@hooks/useRestartOnReceiptFailure'; import useShowNotFoundPageInIOUStep from '@hooks/useShowNotFoundPageInIOUStep'; import useThemeStyles from '@hooks/useThemeStyles'; @@ -24,6 +25,7 @@ import Navigation from '@libs/Navigation/Navigation'; import {hasEnabledOptions} from '@libs/OptionsListUtils'; import {isPolicyAdmin} from '@libs/PolicyUtils'; import {getTransactionDetails, isGroupPolicy, isReportInGroupPolicy} from '@libs/ReportUtils'; +import {isExpenseUnreported} from '@libs/TransactionUtils'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; @@ -48,22 +50,26 @@ function IOURequestStepCategory({ const styles = useThemeStyles(); const {translate} = useLocalize(); + const isUnreportedExpense = isExpenseUnreported(transaction); + const {policyForMovingExpenses, policyForMovingExpensesID} = usePolicyForMovingExpenses(); + const policyIdReal = getIOURequestPolicyID(transaction, reportReal); const policyIdDraft = getIOURequestPolicyID(transaction, reportDraft); const [policyReal] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${policyIdReal}`, {canBeMissing: true}); const [policyDraft] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_DRAFTS}${policyIdDraft}`, {canBeMissing: true}); - const policy = policyReal ?? policyDraft; + const policy = isUnreportedExpense ? policyForMovingExpenses : (policyReal ?? policyDraft); + const policyID = isUnreportedExpense ? policyForMovingExpensesID : policy?.id; const [splitDraftTransaction] = useOnyx(`${ONYXKEYS.COLLECTION.SPLIT_TRANSACTION_DRAFT}${transactionID}`, {canBeMissing: true}); - const [policyCategoriesReal] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}${policy?.id}`, {canBeMissing: true}); + const [policyCategoriesReal] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}${policyID}`, {canBeMissing: true}); const [policyCategoriesDraft] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_CATEGORIES_DRAFT}${policyIdDraft}`, {canBeMissing: true}); - const [policyTags] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_TAGS}${policy?.id}`, {canBeMissing: true}); - const [policyRecentlyUsedCategories] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_RECENTLY_USED_CATEGORIES}${policy?.id}`, {canBeMissing: true}); + const [policyTags] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_TAGS}${policyID}`, {canBeMissing: true}); + const [policyRecentlyUsedCategories] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_RECENTLY_USED_CATEGORIES}${policyID}`, {canBeMissing: true}); const report = reportReal ?? reportDraft; const policyCategories = policyCategoriesReal ?? policyCategoriesDraft; const [allTransactionViolations] = useOnyx(ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS, {canBeMissing: true}); - const [policyTagLists] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_TAGS}${policy?.id}`, {canBeMissing: true}); + const [policyTagLists] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_TAGS}${policyID}`, {canBeMissing: true}); const {currentSearchHash} = useSearchContext(); const isEditing = action === CONST.IOU.ACTION.EDIT; const isEditingSplit = (iouType === CONST.IOU.TYPE.SPLIT || iouType === CONST.IOU.TYPE.SPLIT_EXPENSE) && isEditing; @@ -132,7 +138,7 @@ function IOURequestStepCategory({ } } - setMoneyRequestCategory(transactionID, updatedCategory, policy?.id); + setMoneyRequestCategory(transactionID, updatedCategory, policyID); if (action === CONST.IOU.ACTION.CATEGORIZE && !backTo) { if (report?.reportID) { @@ -177,18 +183,18 @@ function IOURequestStepCategory({ success style={[styles.w100]} onPress={() => { - if (!policy?.id || !report?.reportID) { + if (!policyID || !report?.reportID) { return; } - if (!policy.areCategoriesEnabled) { - enablePolicyCategories(policy.id, true, policyTagLists, policyCategories, allTransactionViolations, false); + if (!policy?.areCategoriesEnabled) { + enablePolicyCategories(policyID, true, policyTagLists, policyCategories, allTransactionViolations, false); } // eslint-disable-next-line @typescript-eslint/no-deprecated InteractionManager.runAfterInteractions(() => { Navigation.navigate( ROUTES.SETTINGS_CATEGORIES_ROOT.getRoute( - policy.id, + policyID, ROUTES.MONEY_REQUEST_STEP_CATEGORY.getRoute(action, iouType, transactionID, report.reportID, backTo, reportActionID), ), ); @@ -206,7 +212,7 @@ function IOURequestStepCategory({ {translate('iou.categorySelection')} diff --git a/src/pages/iou/request/step/IOURequestStepUpgrade.tsx b/src/pages/iou/request/step/IOURequestStepUpgrade.tsx index 88cca772d7af..f8e7992d0de9 100644 --- a/src/pages/iou/request/step/IOURequestStepUpgrade.tsx +++ b/src/pages/iou/request/step/IOURequestStepUpgrade.tsx @@ -90,7 +90,7 @@ function IOURequestStepUpgrade({ Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_REPORT.getRoute(action, CONST.IOU.TYPE.SUBMIT, transactionID, reportID)); break; case CONST.UPGRADE_PATHS.CATEGORIES: - Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_CATEGORY.getRoute(action, CONST.IOU.TYPE.SUBMIT, transactionID, reportID, ROUTES.REPORT_WITH_ID.getRoute(reportID))); + Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_CATEGORY.getRoute(action, CONST.IOU.TYPE.SUBMIT, transactionID, reportID)); break; default: } From c45f1cedc9212534163fcdaca19bf1b9c55721d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Muzyk?= Date: Mon, 20 Oct 2025 14:08:14 +0200 Subject: [PATCH 2/8] fix: 72836 --- src/components/ReportActionItem/MoneyRequestView.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/ReportActionItem/MoneyRequestView.tsx b/src/components/ReportActionItem/MoneyRequestView.tsx index 664491fe7803..586a1e6fb0a2 100644 --- a/src/components/ReportActionItem/MoneyRequestView.tsx +++ b/src/components/ReportActionItem/MoneyRequestView.tsx @@ -754,7 +754,7 @@ function MoneyRequestView({ upgradePath: CONST.UPGRADE_PATHS.CATEGORIES, }), ); - } else if (shouldSelectPolicy) { + } else if (!policy && shouldSelectPolicy) { Navigation.navigate( ROUTES.SET_DEFAULT_WORKSPACE.getRoute( ROUTES.MONEY_REQUEST_STEP_CATEGORY.getRoute( From 5a22c8580db44ca048ef29478eb417f79648c1f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Muzyk?= Date: Mon, 20 Oct 2025 14:17:31 +0200 Subject: [PATCH 3/8] fix: prettier --- src/components/Search/index.tsx | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/components/Search/index.tsx b/src/components/Search/index.tsx index 9f1230fb4eda..455a19192ce2 100644 --- a/src/components/Search/index.tsx +++ b/src/components/Search/index.tsx @@ -829,7 +829,17 @@ function Search({queryJSON, searchResults, onSearchListScroll, contentContainerS ), data, ); - }, [validGroupBy, isExpenseReportType, selectedTransactions, setSelectedTransactions, data, clearSelectedTransactions, reportActionsArray, outstandingReportsByPolicyID, isUserWorkspaceMember]); + }, [ + validGroupBy, + isExpenseReportType, + selectedTransactions, + setSelectedTransactions, + data, + clearSelectedTransactions, + reportActionsArray, + outstandingReportsByPolicyID, + isUserWorkspaceMember, + ]); const onLayout = useCallback(() => handleSelectionListScroll(sortedSelectedData, searchListRef.current), [handleSelectionListScroll, sortedSelectedData]); From ce6b02f163aec1f1777183cd571cdf16c6b78d50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Muzyk?= Date: Mon, 20 Oct 2025 16:25:04 +0200 Subject: [PATCH 4/8] fix: 72864 --- src/libs/Violations/ViolationsUtils.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/libs/Violations/ViolationsUtils.ts b/src/libs/Violations/ViolationsUtils.ts index 5fd9a0ec6666..80876f128590 100644 --- a/src/libs/Violations/ViolationsUtils.ts +++ b/src/libs/Violations/ViolationsUtils.ts @@ -293,10 +293,9 @@ const ViolationsUtils = { } const customUnitRateID = updatedTransaction?.comment?.customUnit?.customUnitRateID; - if (customUnitRateID && customUnitRateID.length > 0) { + if (customUnitRateID && customUnitRateID.length > 0 && !isSelfDM) { const isPerDiem = TransactionUtils.isPerDiemRequest(updatedTransaction); const customRate = isPerDiem ? getPerDiemRateCustomUnitRate(policy, customUnitRateID) : getDistanceRateCustomUnitRate(policy, customUnitRateID); - if (customRate) { newTransactionViolations = reject(newTransactionViolations, {name: CONST.VIOLATIONS.CUSTOM_UNIT_OUT_OF_POLICY}); } else { From 0680b1e3f8a647c35d8b8d7fd11e4ebe11713c99 Mon Sep 17 00:00:00 2001 From: Agata Kosior Date: Tue, 21 Oct 2025 11:28:48 +0200 Subject: [PATCH 5/8] fix: 72820 - show selected category when submitting to someone --- src/pages/iou/request/step/IOURequestStepParticipants.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/pages/iou/request/step/IOURequestStepParticipants.tsx b/src/pages/iou/request/step/IOURequestStepParticipants.tsx index 1bb302ec2d33..d07841ce1222 100644 --- a/src/pages/iou/request/step/IOURequestStepParticipants.tsx +++ b/src/pages/iou/request/step/IOURequestStepParticipants.tsx @@ -298,6 +298,8 @@ function IOURequestStepParticipants({ const transactionReportID = shouldAutoReport.current ? newReportID : CONST.REPORT.UNREPORTED_REPORT_ID; transactions.forEach((transaction) => { setMoneyRequestTag(transaction.transactionID, ''); + const category = action === CONST.IOU.ACTION.SUBMIT && !!selfDMReportID && transaction?.category ? transaction?.category : ''; + setMoneyRequestCategory(transaction.transactionID, category); setMoneyRequestCategory(transaction.transactionID, ''); if (shouldUpdateTransactionReportID) { setTransactionReport(transaction.transactionID, {reportID: transactionReportID}, true); From 7a796767f8d7733c5f807b900819c845200c763f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Muzyk?= Date: Tue, 21 Oct 2025 12:06:13 +0200 Subject: [PATCH 6/8] fix: 72822 --- .../iou/request/step/IOURequestStepCategory.tsx | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/src/pages/iou/request/step/IOURequestStepCategory.tsx b/src/pages/iou/request/step/IOURequestStepCategory.tsx index b0310c2365a0..58ce9c36d055 100644 --- a/src/pages/iou/request/step/IOURequestStepCategory.tsx +++ b/src/pages/iou/request/step/IOURequestStepCategory.tsx @@ -1,5 +1,5 @@ import lodashIsEmpty from 'lodash/isEmpty'; -import React, {useEffect} from 'react'; +import React, {useCallback, useEffect} from 'react'; import {InteractionManager, View} from 'react-native'; import ActivityIndicator from '@components/ActivityIndicator'; import FullPageOfflineBlockingView from '@components/BlockingViews/FullPageOfflineBlockingView'; @@ -65,6 +65,7 @@ function IOURequestStepCategory({ const [policyCategoriesDraft] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_CATEGORIES_DRAFT}${policyIdDraft}`, {canBeMissing: true}); const [policyTags] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_TAGS}${policyID}`, {canBeMissing: true}); const [policyRecentlyUsedCategories] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_RECENTLY_USED_CATEGORIES}${policyID}`, {canBeMissing: true}); + const [activePolicyID] = useOnyx(ONYXKEYS.NVP_ACTIVE_POLICY_ID, {canBeMissing: true}); const report = reportReal ?? reportDraft; const policyCategories = policyCategoriesReal ?? policyCategoriesDraft; @@ -88,13 +89,11 @@ function IOURequestStepCategory({ // eslint-disable-next-line rulesdir/no-negated-variables const shouldShowNotFoundPage = useShowNotFoundPageInIOUStep(action, iouType, reportActionID, report, transaction); - const fetchData = () => { - if ((!!policy && !!policyCategories) || !report?.policyID) { - return; - } + const fetchData = useCallback(() => { + const policyIDToFetchCategories = report?.policyID === CONST.POLICY.ID_FAKE ? activePolicyID : report?.policyID; + getPolicyCategories(policyIDToFetchCategories ?? CONST.POLICY.ID_FAKE); + }, [activePolicyID, report?.policyID]); - getPolicyCategories(report?.policyID); - }; const {isOffline} = useNetwork({onReconnect: fetchData}); const isLoading = !isOffline && policyCategories === undefined; const shouldShowEmptyState = policyCategories !== undefined && !shouldShowCategory; @@ -102,8 +101,7 @@ function IOURequestStepCategory({ useEffect(() => { fetchData(); - // eslint-disable-next-line react-compiler/react-compiler, react-hooks/exhaustive-deps - }, []); + }, [fetchData]); const navigateBack = () => { Navigation.goBack(backTo); From 58a8ebeac7fa09134e8e69d1d9c1129037e20f5d Mon Sep 17 00:00:00 2001 From: Agata Kosior Date: Tue, 21 Oct 2025 12:22:24 +0200 Subject: [PATCH 7/8] fix: change condition --- src/pages/iou/request/step/IOURequestStepParticipants.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/iou/request/step/IOURequestStepParticipants.tsx b/src/pages/iou/request/step/IOURequestStepParticipants.tsx index d07841ce1222..4076cabea62c 100644 --- a/src/pages/iou/request/step/IOURequestStepParticipants.tsx +++ b/src/pages/iou/request/step/IOURequestStepParticipants.tsx @@ -298,7 +298,7 @@ function IOURequestStepParticipants({ const transactionReportID = shouldAutoReport.current ? newReportID : CONST.REPORT.UNREPORTED_REPORT_ID; transactions.forEach((transaction) => { setMoneyRequestTag(transaction.transactionID, ''); - const category = action === CONST.IOU.ACTION.SUBMIT && !!selfDMReportID && transaction?.category ? transaction?.category : ''; + const category = isMovingTransactionFromTrackExpense && transaction?.category ? transaction?.category : ''; setMoneyRequestCategory(transaction.transactionID, category); setMoneyRequestCategory(transaction.transactionID, ''); if (shouldUpdateTransactionReportID) { From e6ed9c0d33c890ef3d0de7e9d5e3c0d6ee3782e0 Mon Sep 17 00:00:00 2001 From: Agata Kosior Date: Tue, 21 Oct 2025 12:32:01 +0200 Subject: [PATCH 8/8] fix: do not show category field when not enabled on the default workspace --- src/components/ReportActionItem/MoneyRequestView.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/ReportActionItem/MoneyRequestView.tsx b/src/components/ReportActionItem/MoneyRequestView.tsx index 586a1e6fb0a2..1f2c3c1cb65c 100644 --- a/src/components/ReportActionItem/MoneyRequestView.tsx +++ b/src/components/ReportActionItem/MoneyRequestView.tsx @@ -268,7 +268,7 @@ function MoneyRequestView({ // Flags for showing categories and tags // transactionCategory can be an empty string // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing - const shouldShowCategory = (isPolicyExpenseChat && (categoryForDisplay || hasEnabledOptions(policyCategories ?? {}))) || isExpenseUnreported; + const shouldShowCategory = (isPolicyExpenseChat && (categoryForDisplay || hasEnabledOptions(policyCategories ?? {}))) || (isExpenseUnreported && hasEnabledOptions(policyCategories ?? {})); // transactionTag can be an empty string // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing const shouldShowTag = isPolicyExpenseChat && (transactionTag || hasEnabledTags(policyTagLists));