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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 0 additions & 6 deletions src/CONST/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1946,7 +1946,6 @@ const CONST = {
DUPLICATE_EXPENSE: 'duplicateExpense',
DUPLICATE_REPORT: 'duplicateReport',
MOVE_EXPENSE: 'moveExpense',
TOGGLE_SINGLE_EXPENSE_VIEW: 'toggleSingleExpenseView',
},
PRIMARY_ACTIONS: {
SUBMIT: 'submit',
Expand Down Expand Up @@ -2509,10 +2508,6 @@ const CONST = {
DETAILED: 'detailed',
MATRIX: 'matrix',
},
SINGLE_EXPENSE_REPORT_VIEW: {
EXPENSE: 'expense',
TABLE: 'table',
},
} as const,
UNREPORTED_EXPENSES_PAGE_SIZE: 50,
COMPOSER: {
Expand Down Expand Up @@ -10180,7 +10175,6 @@ const CONST = {
PAY: 'MoreMenu-Pay',
DUPLICATE_REPORT: 'MoreMenu-DuplicateReport',
MOVE_EXPENSE: 'MoreMenu-MoveExpense',
TOGGLE_SINGLE_EXPENSE_VIEW: 'MoreMenu-ToggleSingleExpenseView',
},
REPORT_PREVIEW: {
CARD: 'ReportPreview-Card',
Expand Down
4 changes: 0 additions & 4 deletions src/ONYXKEYS.ts
Original file line number Diff line number Diff line change
Expand Up @@ -939,9 +939,6 @@ const ONYXKEYS = {
/** Dragged table column widths, keyed by `columnResizingID` then column key. Per device, since ideal widths depend on window size. */
TABLE_COLUMN_WIDTHS: 'tableColumnWidths',

/** Stores whether the user views single-expense reports in the expense view or the table view */
NVP_SINGLE_EXPENSE_REPORT_VIEW: 'nvp_expensify_singleExpenseReportView',

/** Partial transaction data used for MFA authorize transaction preview */
TRANSACTIONS_PENDING_3DS_REVIEW: 'transactionsPending3DSReview',

Expand Down Expand Up @@ -2038,7 +2035,6 @@ type OnyxValuesMapping = {
[ONYXKEYS.NVP_REPORT_LAYOUT_OPTION]: string;
[ONYXKEYS.NVP_REPORT_DETAILS_COLUMNS]: string[];
[ONYXKEYS.TABLE_COLUMN_WIDTHS]: OnyxTypes.TableColumnWidths;
[ONYXKEYS.NVP_SINGLE_EXPENSE_REPORT_VIEW]: ValueOf<typeof CONST.REPORT_LAYOUT.SINGLE_EXPENSE_REPORT_VIEW>;
[ONYXKEYS.HAS_DENIED_CONTACT_IMPORT_PROMPT]: boolean | undefined;
[ONYXKEYS.PERSONAL_POLICY_ID]: string;
[ONYXKEYS.RAM_ONLY_EXPENSE_ADDED_GROWL_TRANSACTION_IDS]: Record<string, SearchDataTypes>;
Expand Down
4 changes: 2 additions & 2 deletions src/components/BulkActionBar/types.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type {DropdownOption} from '@components/ButtonWithDropdownMenu/types';
import type {PopoverMenuItem} from '@components/PopoverMenu';

import type {ComponentRef, Ref} from 'react';
import type {ComponentRef, RefObject} from 'react';
import type {GestureResponderEvent, StyleProp, View, ViewStyle} from 'react-native';

type BulkActionBarProps<TValueType> = {
Expand Down Expand Up @@ -41,7 +41,7 @@ type BulkActionBarProps<TValueType> = {
* Anchor for popovers a caller opens against the bar, such as the KYC wall Search puts behind its pay action.
* Attached to the bar itself, since which button opened the flow is not something the bar exposes.
*/
barRef?: Ref<ComponentRef<typeof View>>;
barRef?: RefObject<ComponentRef<typeof View> | null>;

/**
* Extra styles for the absolutely positioned layer the bar floats in. Pass a `bottom` here to lift the bar above
Expand Down
8 changes: 2 additions & 6 deletions src/components/MoneyReportHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import useOnyx from '@hooks/useOnyx';
import useReportPrimaryAction from '@hooks/useReportPrimaryAction';
import useResponsiveLayout from '@hooks/useResponsiveLayout';
import useResponsiveLayoutOnWideRHP from '@hooks/useResponsiveLayoutOnWideRHP';
import useSingleExpenseReportView from '@hooks/useSingleExpenseReportView';
import useThemeStyles from '@hooks/useThemeStyles';
import useTransactionsAndViolationsForReport from '@hooks/useTransactionsAndViolationsForReport';

Expand Down Expand Up @@ -135,7 +134,6 @@ function MoneyReportHeaderContent({reportID: reportIDProp, shouldDisplayBackButt
const shouldShowBackButton = shouldDisplayBackButton || shouldUseNarrowLayout;

const isMobileSelectionModeEnabled = useMobileSelectionMode();
const {shouldUseTableViewForSingleExpense} = useSingleExpenseReportView(moneyRequestReport?.reportID);
const isFocused = useIsFocused();

useEffect(() => {
Expand All @@ -145,13 +143,11 @@ function MoneyReportHeaderContent({reportID: reportIDProp, shouldDisplayBackButt
}, []);

if (isMobileSelectionModeEnabled && shouldUseNarrowLayout && isFocused) {
// If mobile selection mode is enabled but too few transactions remain to show the table, turn it off. A single
// expense still shows the table when the user chose the table view for single-expense reports. The selection mode
// If mobile selection mode is enabled but only one or no transactions remain, turn it off. The selection mode
// is shared with every screen, so this report only gets to turn it off while it is the focused one. Another
// screen on top of it, such as the add existing expense modal, owns the mode for as long as it is open.
const visibleTransactions = transactions.filter((t) => t.pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE || isOffline);
const minTransactionsForSelection = shouldUseTableViewForSingleExpense ? 1 : 2;
if (visibleTransactions.length < minTransactionsForSelection) {
if (visibleTransactions.length <= 1) {
turnOffMobileSelectionMode();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,12 @@ import useReportIsArchived from '@hooks/useReportIsArchived';
import useResponsiveLayout from '@hooks/useResponsiveLayout';
import useSearchShouldCalculateTotals from '@hooks/useSearchShouldCalculateTotals';
import useShareActions from '@hooks/useShareActions';
import useSingleExpenseReportView from '@hooks/useSingleExpenseReportView';
import useStyleUtils from '@hooks/useStyleUtils';
import useThemeStyles from '@hooks/useThemeStyles';
import useTransactionsAndViolationsForReport from '@hooks/useTransactionsAndViolationsForReport';
import useVerifyAccountAndResume from '@hooks/useVerifyAccountAndResume';

import {generateDefaultWorkspaceName} from '@libs/actions/Policy/Policy';
import {setSingleExpenseReportView} from '@libs/actions/ReportLayout';
import {search} from '@libs/actions/Search';
import getNonEmptyStringOnyxID from '@libs/getNonEmptyStringOnyxID';
import getPlatform from '@libs/getPlatform';
Expand Down Expand Up @@ -120,7 +118,6 @@ function MoneyReportHeaderSecondaryActionsInner({reportID, primaryAction, isRepo
});
const [policies] = useOnyx(ONYXKEYS.COLLECTION.POLICY);
const [introSelected] = useOnyx(ONYXKEYS.NVP_INTRO_SELECTED);
const {singleExpenseReportView, shouldUseTableViewForSingleExpense} = useSingleExpenseReportView(moneyRequestReport?.reportID);
const [isSelfTourViewed = false] = useOnyx(ONYXKEYS.NVP_ONBOARDING, {
selector: hasSeenTourSelector,
});
Expand Down Expand Up @@ -321,7 +318,7 @@ function MoneyReportHeaderSecondaryActionsInner({reportID, primaryAction, isRepo
? sortPoliciesByName(activeAdminPolicies, localeCompare)
: [];

const expensifyIcons = useMemoizedLazyExpensifyIcons(['Info', 'Cash', 'ArrowRight', 'Building', 'Table', 'Receipt']);
const expensifyIcons = useMemoizedLazyExpensifyIcons(['Info', 'Cash', 'ArrowRight', 'Building']);

// Build PAY action sub-items. Workspace-policy entries carry the policy as data and have no onSelected;
// MoneyReportHeaderKYCDropdown picks them up via onSubItemSelected where triggerKYCFlow is in scope.
Expand Down Expand Up @@ -426,18 +423,6 @@ function MoneyReportHeaderSecondaryActionsInner({reportID, primaryAction, isRepo

// Merge all action implementations
const secondaryActionsImplementation: Record<string, (typeof lifecycleActionEntries)[string]> = {
[CONST.REPORT.SECONDARY_ACTIONS.TOGGLE_SINGLE_EXPENSE_VIEW]: {
value: CONST.REPORT.SECONDARY_ACTIONS.TOGGLE_SINGLE_EXPENSE_VIEW,
text: shouldUseTableViewForSingleExpense ? translate('reportLayout.switchToExpenseView') : translate('reportLayout.switchToTableView'),
icon: shouldUseTableViewForSingleExpense ? expensifyIcons.Receipt : expensifyIcons.Table,
sentryLabel: CONST.SENTRY_LABEL.MORE_MENU.TOGGLE_SINGLE_EXPENSE_VIEW,
onSelected: () => {
setSingleExpenseReportView(
shouldUseTableViewForSingleExpense ? CONST.REPORT_LAYOUT.SINGLE_EXPENSE_REPORT_VIEW.EXPENSE : CONST.REPORT_LAYOUT.SINGLE_EXPENSE_REPORT_VIEW.TABLE,
singleExpenseReportView,
);
},
},
[CONST.REPORT.SECONDARY_ACTIONS.VIEW_DETAILS]: {
value: CONST.REPORT.SECONDARY_ACTIONS.VIEW_DETAILS,
text: translate('iou.viewDetails'),
Expand Down
6 changes: 1 addition & 5 deletions src/components/MoneyReportHeaderActions/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import useLayoutSpacing from '@hooks/useLayoutSpacing';
import useOnyx from '@hooks/useOnyx';
import useResponsiveLayout from '@hooks/useResponsiveLayout';
import useResponsiveLayoutOnWideRHP from '@hooks/useResponsiveLayoutOnWideRHP';
import useSingleExpenseReportView from '@hooks/useSingleExpenseReportView';
import useThemeStyles from '@hooks/useThemeStyles';

import getNonEmptyStringOnyxID from '@libs/getNonEmptyStringOnyxID';
Expand Down Expand Up @@ -57,10 +56,7 @@ function MoneyReportHeaderActions({reportID, primaryAction, isReportInSearch, ba
const {selectedTransactionIDs} = useSearchSelectionContext();
const {clearSelectedTransactions} = useSearchSelectionActions();
const hasSelectedTransactions = !!selectedTransactionIDs.length;

// In the table view a single-expense report lists its expense as a selectable row, so it acts like a multi-expense report here.
const {shouldUseTableViewForSingleExpense} = useSingleExpenseReportView(moneyRequestReport?.reportID);
const isTransactionThread = !!transactionThreadReportID && !shouldUseTableViewForSingleExpense;
const isTransactionThread = !!transactionThreadReportID;

useEffect(() => {
if (!transactionThreadReportID) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import {usePersonalDetailsByIDs} from '@hooks/usePersonalDetails';
import useReportIsArchived from '@hooks/useReportIsArchived';
import useReportsParentHierarchy from '@hooks/useReportsParentHierarchy';
import useResponsiveLayoutOnWideRHP from '@hooks/useResponsiveLayoutOnWideRHP';
import useSingleExpenseReportView from '@hooks/useSingleExpenseReportView';
import useThemeStyles from '@hooks/useThemeStyles';
import useUnreadMarker from '@hooks/useUnreadMarker';

Expand Down Expand Up @@ -132,7 +131,6 @@ function MoneyRequestReportActionsListContent({reportIDFromRoute, onLayout}: Mon

const transactionThreadReportID = getOneTransactionThreadReportID(report, chatReport, reportActions, false, reportTransactionIDs);
const [transactionThreadReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${transactionThreadReportID}`);
const {shouldUseTableViewForSingleExpense} = useSingleExpenseReportView(reportID);

const isReportArchived = useReportIsArchived(reportID);
const canPerformWriteAction = canUserPerformWriteAction(report, isReportArchived);
Expand Down Expand Up @@ -195,8 +193,7 @@ function MoneyRequestReportActionsListContent({reportIDFromRoute, onLayout}: Mon
const {markNewestActionAsRead, completeSkippedMarkAsRead} = useMarkAsRead({
reportID: reportID ?? reportIDFromRoute ?? '',
report,
// The table view doesn't show the expense thread's actions, so a new one there shouldn't mark the report as read
transactionThreadReport: shouldUseTableViewForSingleExpense ? undefined : transactionThreadReport,
transactionThreadReport,
sortedVisibleReportActions: visibleReportActionsNewestFirst,
sortedReportActions: reportActions,
isScrolledToEnd: !hasScrolledOverThreshold,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import useOnyx from '@hooks/useOnyx';
import usePaginatedReportActions from '@hooks/usePaginatedReportActions';
import useReportTransactionsCollection from '@hooks/useReportTransactionsCollection';
import useResponsiveLayout from '@hooks/useResponsiveLayout';
import useSingleExpenseReportView from '@hooks/useSingleExpenseReportView';
import useThemeStyles from '@hooks/useThemeStyles';

import {removeFailedReport} from '@libs/actions/Report';
Expand Down Expand Up @@ -142,7 +141,6 @@ function MoneyRequestReportView({report, reportIDFromRoute, reportLoadingState,
const reportErrors = visibleTransactions.length === 1 && visibleTransactions.at(0)?.errors ? undefined : allReportErrors;
const reportTransactionIDs = visibleTransactions.map((transaction) => transaction.transactionID);
const transactionThreadReportID = getOneTransactionThreadReportID(report, chatReport, reportActions ?? [], isOffline, reportTransactionIDs);
const {shouldUseTableViewForSingleExpense} = useSingleExpenseReportView(reportID);

const isReportLoadPending = useIsReportLoadPending(reportID);
const dismissReportCreationError = () => {
Expand All @@ -160,11 +158,10 @@ function MoneyRequestReportView({report, reportIDFromRoute, reportLoadingState,
const shouldShowOpenReportLoadingSkeleton = !!(isReportLoadPending && reportActions.length === 0 && !isOffline) || shouldWaitForTransactions;

const isEmptyTransactionReport = visibleTransactions?.length === 0 && transactionThreadReportID === undefined;
const shouldDisplayMoneyRequestActionsList = !!isEmptyTransactionReport || shouldDisplayReportTableView(report, visibleTransactions ?? [], shouldUseTableViewForSingleExpense);
const shouldDisplayMoneyRequestActionsList = !!isEmptyTransactionReport || shouldDisplayReportTableView(report, visibleTransactions ?? []);

const [transactionThreadReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${transactionThreadReportID}`);
// The side-by-side receipt belongs to the single-expense view, so it's hidden when the user picks the table view
const shouldShowWideRHPReceipt = visibleTransactions.length === 1 && !isSmallScreenWidth && !!transactionThreadReport && !shouldUseTableViewForSingleExpense;
const shouldShowWideRHPReceipt = visibleTransactions.length === 1 && !isSmallScreenWidth && !!transactionThreadReport;

const reportHeaderView = isTransactionThreadView ? (
<MoneyRequestHeader
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,10 @@ import BulkActionBar from '@components/BulkActionBar';
import type {DropdownOption} from '@components/ButtonWithDropdownMenu/types';
import KYCWall from '@components/KYCWall';
import type {KYCWallRef} from '@components/KYCWall/types';
import {useReportSubmitToPopoverAnchorRef} from '@components/ReportSubmitToPopoverAnchor';

import useNetwork from '@hooks/useNetwork';
import useThemeStyles from '@hooks/useThemeStyles';

import mergeRefs from '@libs/mergeRefs';
import type {KYCFlowEvent, TriggerKYCFlow} from '@libs/PaymentUtils';
import {isSecondaryActionAPaymentOption, isSecondaryActionAWorkspacePolicyOption} from '@libs/PaymentUtils';

Expand Down Expand Up @@ -61,9 +59,6 @@ function SelectionBulkActionBar({
const styles = useThemeStyles();
const {isOffline} = useNetwork();

// Bulk Submit on a Submit workspace opens the submit-to popover, which should open against the bar like the KYC wall does.
const submitToAnchorRef = useReportSubmitToPopoverAnchorRef();

return (
<KYCWall
ref={kycWallRef}
Expand All @@ -79,7 +74,7 @@ function SelectionBulkActionBar({
selectedCount={selectedTransactionIDs.length}
options={selectedTransactionsOptions}
onClearSelection={onClearSelection}
barRef={mergeRefs(buttonRef, submitToAnchorRef)}
barRef={buttonRef}
style={styles.zIndex10}
onSubItemSelected={(item, _index, event) => {
if (isSecondaryActionAWorkspacePolicyOption(item)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import {ModalActions} from '@components/Modal/Global/ModalContext';
import useShouldShowReportBulkActionBar from '@components/MoneyRequestReportView/useShouldShowReportBulkActionBar';
import OfflineWithFeedback from '@components/OfflineWithFeedback';
import ProcessMoneyReportHoldMenu from '@components/ProcessMoneyReportHoldMenu';
import {ReportSubmitToPopoverMeasurableAnchor, ReportSubmitToPopoverRoot} from '@components/ReportSubmitToPopoverAnchor';
import {ReportSubmitToPopoverAnchor} from '@components/ReportSubmitToPopoverAnchor';
import BulkDuplicateHandler from '@components/Search/BulkDuplicateHandler';
import {useSearchSelectionActions, useSearchSelectionContext} from '@components/Search/SearchContext';

Expand Down Expand Up @@ -277,7 +277,7 @@ function SelectionToolbar({reportID, transactions, reportActions}: SelectionTool
<View
style={[isInLandscapeMode ? [styles.flexRowReverse, styles.justifyContentBetween, styles.alignItemsCenter, styles.gap6, styles.pb3, styles.ph5] : styles.flexColumn]}
>
<ReportSubmitToPopoverMeasurableAnchor>
<ReportSubmitToPopoverAnchor reportID={reportID}>
<SelectionDropdown
hasPayInSelectionMode={hasPayInSelectionMode}
chatReport={chatReport}
Expand All @@ -291,7 +291,7 @@ function SelectionToolbar({reportID, transactions, reportActions}: SelectionTool
kycWallRef={kycWallRef}
shouldPopoverUseScrollView={popoverUseScrollView}
/>
</ReportSubmitToPopoverMeasurableAnchor>
</ReportSubmitToPopoverAnchor>

<SelectAllCheckbox
isSelectAllChecked={isSelectAllChecked}
Expand Down Expand Up @@ -352,16 +352,12 @@ function SelectionToolbarGate({reportID, transactions, reportActions}: Selection
return null;
}

// The toolbar's own hooks open the submit-to popover for bulk Submit, so its provider has to sit above the toolbar.
// The bulk action bar and the selection dropdown mark themselves as its anchor.
return (
<ReportSubmitToPopoverRoot reportID={reportID}>
<SelectionToolbar
reportID={reportID}
transactions={transactions}
reportActions={reportActions}
/>
</ReportSubmitToPopoverRoot>
<SelectionToolbar
reportID={reportID}
transactions={transactions}
reportActions={reportActions}
Comment on lines 355 to +359

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Restore the submit-popover provider around the toolbar

When a Submit-policy report has multiple rows but only one selectable row (for example, another row is disabled by a reject error), isEveryReportTransactionSelected() deliberately exposes the report-level Submit action and the one selected transaction does not trigger the multi-selection submit block. useSelectionModeReportActions() calls useLifecycleActions() while rendering SelectionToolbar, so after this wrapper is removed it reads the default no-op useOpenReportSubmitToPopover() value; the ReportSubmitToPopoverAnchor rendered later around the narrow dropdown cannot provide context to its parent hook, and the wide toolbar has no provider at all. Consequently, pressing the offered Submit action does nothing instead of opening the submit-to picker.

Useful? React with 👍 / 👎.

/>
);
}

Expand Down
6 changes: 0 additions & 6 deletions src/components/ReportSubmitToPopoverAnchor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,11 +59,6 @@ function useOpenReportSubmitToPopover(): OpenReportSubmitToPopover {
return useContext(ReportSubmitToPopoverContext);
}

/** The ref the submit-to popover measures, for anchors that can't be wrapped in {@link ReportSubmitToPopoverMeasurableAnchor}. */
function useReportSubmitToPopoverAnchorRef() {
return useContext(ReportSubmitToPopoverAnchorRefContext);
}

/** Opens the shared Search submit-to popover for a report (e.g. bulk actions outside a list row). */
function useOpenSearchReportSubmitToPopover() {
const host = useContext(ReportSubmitToPopoverHostContext);
Expand Down Expand Up @@ -327,6 +322,5 @@ export {
SEARCH_REPORT_SUBMIT_TO_POPOVER_ANCHOR_ALIGNMENT,
useOpenReportSubmitToPopover,
useOpenSearchReportSubmitToPopover,
useReportSubmitToPopoverAnchorRef,
useSearchSubmitPopoverGuard,
};
Loading
Loading