Skip to content

Commit 489584a

Browse files
committed
Make AddUnreportedExpense use new SelectionList
1 parent 57c0cbc commit 489584a

3 files changed

Lines changed: 75 additions & 52 deletions

File tree

src/libs/TransactionUtils/index.ts

Lines changed: 11 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2204,22 +2204,17 @@ function getChildTransactions(transactions: OnyxCollection<Transaction>, reports
22042204
/**
22052205
* Creates sections data for unreported expenses, marking transactions with DELETE pending action as disabled
22062206
*/
2207-
function createUnreportedExpenseSections(transactions: Array<Transaction | undefined>): Array<{shouldShow: boolean; data: UnreportedExpenseListItemType[]}> {
2208-
return [
2209-
{
2210-
shouldShow: true,
2211-
data: transactions
2212-
.filter((t): t is Transaction => t !== undefined)
2213-
.map(
2214-
(transaction): UnreportedExpenseListItemType => ({
2215-
...transaction,
2216-
isDisabled: isTransactionPendingDelete(transaction),
2217-
keyForList: transaction.transactionID,
2218-
errors: transaction.errors as Errors | undefined,
2219-
}),
2220-
),
2221-
},
2222-
];
2207+
function createUnreportedExpenseSections(transactions: Array<Transaction | undefined>): Array<UnreportedExpenseListItemType> {
2208+
return transactions
2209+
.filter((t): t is Transaction => t !== undefined)
2210+
.map(
2211+
(transaction): UnreportedExpenseListItemType => ({
2212+
...transaction,
2213+
isDisabled: isTransactionPendingDelete(transaction),
2214+
keyForList: transaction.transactionID,
2215+
errors: transaction.errors as Errors | undefined,
2216+
}),
2217+
);
22232218
}
22242219

22252220
function isExpenseUnreported(transaction?: Transaction): transaction is UnreportedTransaction {

src/pages/AddUnreportedExpense.tsx

Lines changed: 43 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ import HeaderWithBackButton from '@components/HeaderWithBackButton';
88
import LottieAnimations from '@components/LottieAnimations';
99
import {useSession} from '@components/OnyxListItemProvider';
1010
import ScreenWrapper from '@components/ScreenWrapper';
11-
import SelectionList from '@components/SelectionListWithSections';
12-
import type {ListItem, SectionListDataType, SelectionListHandle} from '@components/SelectionListWithSections/types';
11+
import SelectionList from '@components/SelectionList';
12+
import type {ListItem, SelectionListHandle} from '@components/SelectionList/types';
1313
import UnreportedExpensesSkeleton from '@components/Skeletons/UnreportedExpensesSkeleton';
1414
import useDebouncedState from '@hooks/useDebouncedState';
1515
import useLocalize from '@hooks/useLocalize';
@@ -70,7 +70,7 @@ function AddUnreportedExpense({route}: AddUnreportedExpensePageType) {
7070
return [];
7171
}
7272
return Object.values(transactions || {}).filter((item) => {
73-
const isUnreported = item?.reportID === CONST.REPORT.UNREPORTED_REPORT_ID || item?.reportID === '';
73+
const isUnreported = true;
7474
if (!isUnreported) {
7575
return false;
7676
}
@@ -153,7 +153,12 @@ function AddUnreportedExpense({route}: AddUnreportedExpensePageType) {
153153
});
154154
}, [debouncedSearchValue, shouldShowTextInput, transactions]);
155155

156-
const sections: Array<SectionListDataType<Transaction & ListItem>> = useMemo(() => createUnreportedExpenseSections(filteredTransactions), [filteredTransactions]);
156+
const unreportedExpenses = useMemo(() => {
157+
return createUnreportedExpenseSections(filteredTransactions).map((item) => ({
158+
...item,
159+
isSelected: selectedIds.has(item.transactionID),
160+
}));
161+
}, [filteredTransactions, selectedIds]);
157162

158163
const handleConfirm = useCallback(() => {
159164
if (selectedIds.size === 0) {
@@ -212,11 +217,39 @@ function AddUnreportedExpense({route}: AddUnreportedExpensePageType) {
212217
}, [errorMessage, styles, translate, handleConfirm]);
213218

214219
const headerMessage = useMemo(() => {
215-
if (debouncedSearchValue.trim() && sections.at(0)?.data.length === 0) {
220+
if (debouncedSearchValue.trim() && unreportedExpenses?.length === 0) {
216221
return translate('common.noResultsFound');
217222
}
218223
return '';
219-
}, [debouncedSearchValue, sections, translate]);
224+
}, [debouncedSearchValue, unreportedExpenses, translate]);
225+
226+
const textInputOptions = useMemo(
227+
() => ({
228+
value: searchValue,
229+
label: shouldShowTextInput ? translate('iou.findExpense') : undefined,
230+
onChangeText: setSearchValue,
231+
headerMessage,
232+
}),
233+
[searchValue, shouldShowTextInput, translate, setSearchValue, headerMessage],
234+
);
235+
236+
const onSelectRow = useCallback(
237+
(item: {transactionID: string}) => {
238+
setSelectedIds((prevIds) => {
239+
const newIds = new Set(prevIds);
240+
if (newIds.has(item.transactionID)) {
241+
newIds.delete(item.transactionID);
242+
} else {
243+
newIds.add(item.transactionID);
244+
if (errorMessage) {
245+
setErrorMessage('');
246+
}
247+
}
248+
return newIds;
249+
});
250+
},
251+
[errorMessage],
252+
);
220253

221254
const hasSearchTerm = debouncedSearchValue.trim().length > 0;
222255
const isShowingEmptyState = !hasSearchTerm && transactions.length === 0;
@@ -298,36 +331,19 @@ function AddUnreportedExpense({route}: AddUnreportedExpensePageType) {
298331
onBackButtonPress={Navigation.goBack}
299332
/>
300333
<SelectionList<Transaction & ListItem>
334+
data={unreportedExpenses}
301335
ref={selectionListRef}
302-
onSelectRow={(item) => {
303-
setSelectedIds((prevIds) => {
304-
const newIds = new Set(prevIds);
305-
if (newIds.has(item.transactionID)) {
306-
newIds.delete(item.transactionID);
307-
} else {
308-
newIds.add(item.transactionID);
309-
if (errorMessage) {
310-
setErrorMessage('');
311-
}
312-
}
313-
314-
return newIds;
315-
});
316-
}}
317-
isSelected={(item) => selectedIds.has(item.transactionID)}
336+
onSelectRow={onSelectRow}
337+
textInputOptions={textInputOptions}
318338
shouldShowTextInput={shouldShowTextInput}
319-
textInputValue={searchValue}
320-
textInputLabel={shouldShowTextInput ? translate('iou.findExpense') : undefined}
321-
onChangeText={setSearchValue}
322-
headerMessage={headerMessage}
323339
canSelectMultiple
324-
sections={sections}
325340
ListItem={UnreportedExpenseListItem}
326341
onEndReached={fetchMoreUnreportedTransactions}
327342
onEndReachedThreshold={0.75}
328343
addBottomSafeAreaPadding
329344
listFooterContent={shouldShowUnreportedTransactionsSkeletons ? <UnreportedExpensesSkeleton fixedNumberOfItems={3} /> : undefined}
330345
footerContent={footerContent}
346+
disableMaintainingScrollPosition
331347
/>
332348
</ScreenWrapper>
333349
);

tests/unit/AddUnreportedExpenseTest.ts

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -44,15 +44,15 @@ describe('AddUnreportedExpense', () => {
4444
const sections = createUnreportedExpenseSections(transactions);
4545

4646
// Should create one section
47-
expect(sections).toHaveLength(1);
48-
expect(sections.at(0)?.shouldShow).toBe(true);
49-
expect(sections.at(0)?.data).toHaveLength(2);
47+
expect(sections).toHaveLength(2);
5048

51-
const processedNormalTransaction = sections.at(0)?.data.find((t) => t.transactionID === '123');
49+
const processedNormalTransaction = sections.find((t) => t.transactionID === '123');
5250
expect(processedNormalTransaction?.isDisabled).toBe(false);
51+
expect(processedNormalTransaction?.keyForList).toBe('123');
5352

54-
const processedDeletedTransaction = sections.at(0)?.data.find((t) => t.transactionID === '456');
53+
const processedDeletedTransaction = sections.find((t) => t.transactionID === '456');
5554
expect(processedDeletedTransaction?.isDisabled).toBe(true);
55+
expect(processedDeletedTransaction?.keyForList).toBe('456');
5656
});
5757

5858
it('should not mark transactions without DELETE pendingAction as disabled', () => {
@@ -80,9 +80,9 @@ describe('AddUnreportedExpense', () => {
8080
const transactions = [normalTransaction, updateTransaction, addTransaction];
8181
const sections = createUnreportedExpenseSections(transactions);
8282

83-
expect(sections.at(0)?.data).toHaveLength(3);
83+
expect(sections).toHaveLength(3);
8484
// eslint-disable-next-line unicorn/no-array-for-each
85-
sections.at(0)?.data.forEach((transaction) => {
85+
sections.forEach((transaction) => {
8686
expect(transaction.isDisabled).toBe(false);
8787
});
8888
});
@@ -105,12 +105,24 @@ describe('AddUnreportedExpense', () => {
105105
const transactions = [deletedTransaction1, deletedTransaction2];
106106
const sections = createUnreportedExpenseSections(transactions);
107107

108-
expect(sections.at(0)?.data).toHaveLength(2);
108+
expect(sections).toHaveLength(2);
109109
// eslint-disable-next-line unicorn/no-array-for-each
110-
sections.at(0)?.data.forEach((transaction) => {
110+
sections.forEach((transaction) => {
111111
expect(transaction.isDisabled).toBe(true);
112112
expect(transaction.pendingAction).toBe(CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE);
113113
});
114114
});
115+
116+
it('should filter out undefined transactions', () => {
117+
const normalTransaction = generateTransaction({
118+
transactionID: '123',
119+
});
120+
121+
const transactions = [normalTransaction, undefined];
122+
const result = createUnreportedExpenseSections(transactions);
123+
124+
expect(result).toHaveLength(1);
125+
expect(result[0].transactionID).toBe('123');
126+
});
115127
});
116128
});

0 commit comments

Comments
 (0)