Skip to content

Commit 7004bcb

Browse files
authored
Merge pull request Expensify#85104 from nyomanjyotisa/issue-84757
Fix: Exports list is not scrollable when export options exceed viewport height
2 parents b5702c1 + e58a017 commit 7004bcb

6 files changed

Lines changed: 62 additions & 7 deletions

File tree

src/components/MoneyReportHeader.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ import {
117117
rejectMoneyRequestReason,
118118
shouldBlockSubmitDueToStrictPolicyRules,
119119
} from '@libs/ReportUtils';
120+
import shouldPopoverUseScrollView from '@libs/shouldPopoverUseScrollView';
120121
import {shouldRestrictUserBillableActions} from '@libs/SubscriptionUtils';
121122
import type {SkeletonSpanReasonAttributes} from '@libs/telemetry/useSkeletonSpan';
122123
import {
@@ -2322,6 +2323,7 @@ function MoneyReportHeader({reportID: reportIDProp, shouldDisplayBackButton = fa
23222323
]);
23232324

23242325
const shouldShowSelectedTransactionsButton = !!selectedTransactionsOptions.length && !transactionThreadReportID;
2326+
const popoverUseScrollView = shouldPopoverUseScrollView(selectedTransactionsOptions);
23252327

23262328
const hasPayInSelectionMode = allExpensesSelected && hasPayAction;
23272329

@@ -2403,6 +2405,7 @@ function MoneyReportHeader({reportID: reportIDProp, shouldDisplayBackButton = fa
24032405
customText={translate('workspace.common.selected', {count: selectedTransactionIDs.length})}
24042406
isSplitButton={false}
24052407
shouldAlwaysShowDropdownMenu
2408+
shouldPopoverUseScrollView={popoverUseScrollView}
24062409
wrapperStyle={wrapperStyle}
24072410
/>
24082411
),
@@ -2417,6 +2420,7 @@ function MoneyReportHeader({reportID: reportIDProp, shouldDisplayBackButton = fa
24172420
translate,
24182421
selectedTransactionIDs.length,
24192422
kycWallRef,
2423+
popoverUseScrollView,
24202424
],
24212425
);
24222426

src/components/MoneyRequestReportView/MoneyRequestReportActionsList.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ import {
5959
wasMessageReceivedWhileOffline,
6060
} from '@libs/ReportActionsUtils';
6161
import {canUserPerformWriteAction, chatIncludesChronosWithID, getOriginalReportID, getReportLastVisibleActionCreated, isHarvestCreatedExpenseReport, isUnread} from '@libs/ReportUtils';
62+
import shouldPopoverUseScrollView from '@libs/shouldPopoverUseScrollView';
6263
import markOpenReportEnd from '@libs/telemetry/markOpenReportEnd';
6364
import type {SkeletonSpanReasonAttributes} from '@libs/telemetry/useSkeletonSpan';
6465
import {isTransactionPendingDelete} from '@libs/TransactionUtils';
@@ -313,6 +314,8 @@ function MoneyRequestReportActionsList({
313314
});
314315
}, [originalSelectedTransactionsOptions, dismissedRejectUseExplanation, isDelegateAccessRestricted, showDelegateNoAccessModal]);
315316

317+
const popoverUseScrollView = shouldPopoverUseScrollView(selectedTransactionsOptions);
318+
316319
const dismissRejectModalBasedOnAction = useCallback(() => {
317320
if (rejectModalAction === CONST.REPORT.TRANSACTION_SECONDARY_ACTIONS.REJECT_BULK) {
318321
dismissRejectUseExplanation();
@@ -808,6 +811,7 @@ function MoneyRequestReportActionsList({
808811
})}
809812
isSplitButton={false}
810813
shouldAlwaysShowDropdownMenu
814+
shouldPopoverUseScrollView={popoverUseScrollView}
811815
wrapperStyle={[styles.w100, styles.ph5]}
812816
/>
813817
<View style={[styles.alignItemsCenter, styles.userSelectNone, styles.flexRow, styles.pt6, styles.ph8, styles.pb3]}>

src/components/Search/SearchBulkActionsButton.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import useThemeStyles from '@hooks/useThemeStyles';
2020
import {handleBulkPayItemSelected} from '@libs/actions/Search';
2121
import Navigation from '@libs/Navigation/Navigation';
2222
import {isExpenseReport} from '@libs/ReportUtils';
23+
import shouldPopoverUseScrollView from '@libs/shouldPopoverUseScrollView';
2324
import CONST from '@src/CONST';
2425
import ONYXKEYS from '@src/ONYXKEYS';
2526
import ROUTES from '@src/ROUTES';
@@ -76,8 +77,7 @@ function SearchBulkActionsButton({queryJSON}: SearchBulkActionsButtonProps) {
7677
const selectedTransactionsKeys = Object.keys(selectedTransactions ?? {});
7778
const isExpenseReportType = queryJSON.type === CONST.SEARCH.DATA_TYPES.EXPENSE_REPORT;
7879

79-
const shouldPopoverUseScrollView =
80-
headerButtonsOptions.length >= CONST.DROPDOWN_SCROLL_THRESHOLD || headerButtonsOptions.some((option) => (option.subMenuItems?.length ?? 0) >= CONST.DROPDOWN_SCROLL_THRESHOLD);
80+
const popoverUseScrollView = shouldPopoverUseScrollView(headerButtonsOptions);
8181

8282
const selectedItemsCount = useMemo(() => {
8383
if (!selectedTransactions) {
@@ -123,7 +123,7 @@ function SearchBulkActionsButton({queryJSON}: SearchBulkActionsButtonProps) {
123123
shouldAlwaysShowDropdownMenu
124124
isDisabled={headerButtonsOptions.length === 0}
125125
onPress={() => null}
126-
shouldPopoverUseScrollView={shouldPopoverUseScrollView}
126+
shouldPopoverUseScrollView={popoverUseScrollView}
127127
onSubItemSelected={(subItem) =>
128128
handleBulkPayItemSelected({
129129
item: subItem,
@@ -163,7 +163,7 @@ function SearchBulkActionsButton({queryJSON}: SearchBulkActionsButtonProps) {
163163
buttonSize={CONST.DROPDOWN_BUTTON_SIZE.SMALL}
164164
customText={selectionButtonText}
165165
options={headerButtonsOptions}
166-
shouldPopoverUseScrollView={shouldPopoverUseScrollView}
166+
shouldPopoverUseScrollView={popoverUseScrollView}
167167
onSubItemSelected={(subItem) =>
168168
handleBulkPayItemSelected({
169169
item: subItem,

src/components/SettlementButton/index.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ import {
3838
isIOUReport,
3939
} from '@libs/ReportUtils';
4040
import {handleUnvalidatedUserNavigation, useSettlementButtonPaymentMethods} from '@libs/SettlementButtonUtils';
41+
import shouldPopoverUseScrollView from '@libs/shouldPopoverUseScrollView';
4142
import {shouldRestrictUserBillableActions} from '@libs/SubscriptionUtils';
4243
import {setPersonalBankAccountContinueKYCOnSuccess} from '@userActions/BankAccounts';
4344
import {approveMoneyRequest} from '@userActions/IOU';
@@ -579,8 +580,7 @@ function SettlementButton({
579580

580581
const shouldUseSplitButton = hasPreferredPaymentMethod || !!lastPaymentPolicy || ((isExpenseReport || isInvoiceReport) && hasIntentToPay);
581582
const shouldLimitWidth = shouldUseShortForm && shouldUseSplitButton && !paymentButtonOptions.length;
582-
const shouldPopoverUseScrollView =
583-
paymentButtonOptions.length >= CONST.DROPDOWN_SCROLL_THRESHOLD || paymentButtonOptions.some((option) => (option.subMenuItems?.length ?? 0) >= CONST.DROPDOWN_SCROLL_THRESHOLD);
583+
const popoverUseScrollView = shouldPopoverUseScrollView(paymentButtonOptions);
584584

585585
return (
586586
<KYCWall
@@ -625,7 +625,7 @@ function SettlementButton({
625625
}}
626626
style={style}
627627
shouldUseShortForm={shouldUseShortForm}
628-
shouldPopoverUseScrollView={shouldPopoverUseScrollView}
628+
shouldPopoverUseScrollView={popoverUseScrollView}
629629
containerStyles={paymentButtonOptions.length > 5 ? styles.settlementButtonListContainer : {}}
630630
wrapperStyle={[wrapperStyle, shouldLimitWidth ? styles.settlementButtonShortFormWidth : {}]}
631631
disabledStyle={disabledStyle}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import type {DropdownOption} from '@components/ButtonWithDropdownMenu/types';
2+
import CONST from '@src/CONST';
3+
4+
function shouldPopoverUseScrollView<T>(options: Array<DropdownOption<T>>): boolean {
5+
return options.length >= CONST.DROPDOWN_SCROLL_THRESHOLD || options.some((option) => (option.subMenuItems?.length ?? 0) >= CONST.DROPDOWN_SCROLL_THRESHOLD);
6+
}
7+
8+
export default shouldPopoverUseScrollView;
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import type {DropdownOption} from '@components/ButtonWithDropdownMenu/types';
2+
import shouldPopoverUseScrollView from '@libs/shouldPopoverUseScrollView';
3+
import CONST from '@src/CONST';
4+
5+
describe('shouldPopoverUseScrollView', () => {
6+
const createOption = (value: string, subMenuItems?: Array<{value: string; text: string}>): DropdownOption<string> => ({
7+
value,
8+
text: value,
9+
...(subMenuItems && {subMenuItems: subMenuItems.map((item) => ({...item, key: item.value}))}),
10+
});
11+
12+
it('returns false when there are few top-level options and no large submenus', () => {
13+
const options = [createOption('a'), createOption('b'), createOption('c')];
14+
expect(shouldPopoverUseScrollView(options)).toBe(false);
15+
});
16+
17+
it('returns true when there are 5 or more top-level options', () => {
18+
const options = Array.from({length: CONST.DROPDOWN_SCROLL_THRESHOLD}, (_, i) => createOption(`option-${i}`));
19+
expect(shouldPopoverUseScrollView(options)).toBe(true);
20+
});
21+
22+
it('returns true when any option has 5 or more submenu items', () => {
23+
const subMenuItems = Array.from({length: CONST.DROPDOWN_SCROLL_THRESHOLD}, (_, i) => ({
24+
value: `sub-${i}`,
25+
text: `Sub ${i}`,
26+
}));
27+
const options = [createOption('parent', subMenuItems)];
28+
expect(shouldPopoverUseScrollView(options)).toBe(true);
29+
});
30+
31+
it('returns false when submenu has fewer than threshold items', () => {
32+
const subMenuItems = [
33+
{value: 'sub-1', text: 'Sub 1'},
34+
{value: 'sub-2', text: 'Sub 2'},
35+
];
36+
const options = [createOption('parent', subMenuItems)];
37+
expect(shouldPopoverUseScrollView(options)).toBe(false);
38+
});
39+
});

0 commit comments

Comments
 (0)