Skip to content

Commit 3e16fb7

Browse files
authored
Merge pull request Expensify#76832 from software-mansion-labs/@OlGierd03/migrate-AddUnreportedExpense
Make AddUnreportedExpense use new SelectionList - fixing deploy blocker issues
2 parents bef3a14 + a2e7246 commit 3e16fb7

3 files changed

Lines changed: 81 additions & 59 deletions

File tree

src/libs/TransactionUtils/index.ts

Lines changed: 12 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2214,22 +2214,17 @@ function getChildTransactions(transactions: OnyxCollection<Transaction>, reports
22142214
/**
22152215
* Creates sections data for unreported expenses, marking transactions with DELETE pending action as disabled
22162216
*/
2217-
function createUnreportedExpenseSections(transactions: Array<Transaction | undefined>): Array<{shouldShow: boolean; data: UnreportedExpenseListItemType[]}> {
2218-
return [
2219-
{
2220-
shouldShow: true,
2221-
data: transactions
2222-
.filter((t): t is Transaction => t !== undefined)
2223-
.map(
2224-
(transaction): UnreportedExpenseListItemType => ({
2225-
...transaction,
2226-
isDisabled: isTransactionPendingDelete(transaction),
2227-
keyForList: transaction.transactionID,
2228-
errors: transaction.errors as Errors | undefined,
2229-
}),
2230-
),
2231-
},
2232-
];
2217+
function createUnreportedExpenses(transactions: Array<Transaction | undefined>): UnreportedExpenseListItemType[] {
2218+
return transactions
2219+
.filter((t): t is Transaction => t !== undefined)
2220+
.map(
2221+
(transaction): UnreportedExpenseListItemType => ({
2222+
...transaction,
2223+
isDisabled: isTransactionPendingDelete(transaction),
2224+
keyForList: transaction.transactionID,
2225+
errors: transaction.errors as Errors | undefined,
2226+
}),
2227+
);
22332228
}
22342229

22352230
function isExpenseUnreported(transaction?: Transaction): transaction is UnreportedTransaction {
@@ -2341,7 +2336,7 @@ export {
23412336
getTransactionPendingAction,
23422337
isTransactionPendingDelete,
23432338
getChildTransactions,
2344-
createUnreportedExpenseSections,
2339+
createUnreportedExpenses,
23452340
isDemoTransaction,
23462341
shouldShowViolation,
23472342
isUnreportedAndHasInvalidDistanceRateTransaction,

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';
@@ -27,7 +27,7 @@ import {canSubmitPerDiemExpenseFromWorkspace, getPerDiemCustomUnit} from '@libs/
2727
import {getTransactionDetails, isIOUReport} from '@libs/ReportUtils';
2828
import {shouldRestrictUserBillableActions} from '@libs/SubscriptionUtils';
2929
import tokenizedSearch from '@libs/tokenizedSearch';
30-
import {createUnreportedExpenseSections, getAmount, getCurrency, getDescription, getMerchant, isPerDiemRequest} from '@libs/TransactionUtils';
30+
import {createUnreportedExpenses, getAmount, getCurrency, getDescription, getMerchant, isPerDiemRequest} from '@libs/TransactionUtils';
3131
import Navigation from '@navigation/Navigation';
3232
import type {PlatformStackScreenProps} from '@navigation/PlatformStackNavigation/types';
3333
import {convertBulkTrackedExpensesToIOU, startMoneyRequest} from '@userActions/IOU';
@@ -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 createUnreportedExpenses(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?.length, 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: 26 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import {createUnreportedExpenseSections} from '@libs/TransactionUtils';
1+
import {createUnreportedExpenses} from '@libs/TransactionUtils';
22
import CONST from '@src/CONST';
33
import type Transaction from '@src/types/onyx/Transaction';
44

@@ -24,7 +24,7 @@ function generateTransaction(values: Partial<Transaction> = {}): Transaction {
2424
}
2525

2626
describe('AddUnreportedExpense', () => {
27-
describe('createUnreportedExpenseSections', () => {
27+
describe('createUnreportedExpenses', () => {
2828
it('should mark transactions with DELETE pendingAction as disabled', () => {
2929
const normalTransaction = generateTransaction({
3030
transactionID: '123',
@@ -41,18 +41,17 @@ describe('AddUnreportedExpense', () => {
4141
});
4242

4343
const transactions = [normalTransaction, deletedTransaction];
44-
const sections = createUnreportedExpenseSections(transactions);
44+
const unreportedExpenses = createUnreportedExpenses(transactions);
4545

46-
// 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);
46+
expect(unreportedExpenses).toHaveLength(2);
5047

51-
const processedNormalTransaction = sections.at(0)?.data.find((t) => t.transactionID === '123');
48+
const processedNormalTransaction = unreportedExpenses.find((t) => t.transactionID === '123');
5249
expect(processedNormalTransaction?.isDisabled).toBe(false);
50+
expect(processedNormalTransaction?.keyForList).toBe('123');
5351

54-
const processedDeletedTransaction = sections.at(0)?.data.find((t) => t.transactionID === '456');
52+
const processedDeletedTransaction = unreportedExpenses.find((t) => t.transactionID === '456');
5553
expect(processedDeletedTransaction?.isDisabled).toBe(true);
54+
expect(processedDeletedTransaction?.keyForList).toBe('456');
5655
});
5756

5857
it('should not mark transactions without DELETE pendingAction as disabled', () => {
@@ -78,10 +77,10 @@ describe('AddUnreportedExpense', () => {
7877
});
7978

8079
const transactions = [normalTransaction, updateTransaction, addTransaction];
81-
const sections = createUnreportedExpenseSections(transactions);
80+
const unreportedExpenses = createUnreportedExpenses(transactions);
8281

83-
expect(sections.at(0)?.data).toHaveLength(3);
84-
for (const transaction of sections.at(0)?.data ?? []) {
82+
expect(unreportedExpenses).toHaveLength(3);
83+
for (const transaction of unreportedExpenses ?? []) {
8584
expect(transaction.isDisabled).toBe(false);
8685
}
8786
});
@@ -102,13 +101,25 @@ describe('AddUnreportedExpense', () => {
102101
});
103102

104103
const transactions = [deletedTransaction1, deletedTransaction2];
105-
const sections = createUnreportedExpenseSections(transactions);
104+
const unreportedExpenses = createUnreportedExpenses(transactions);
106105

107-
expect(sections.at(0)?.data).toHaveLength(2);
108-
for (const transaction of sections.at(0)?.data ?? []) {
106+
expect(unreportedExpenses).toHaveLength(2);
107+
for (const transaction of unreportedExpenses ?? []) {
109108
expect(transaction.isDisabled).toBe(true);
110109
expect(transaction.pendingAction).toBe(CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE);
111110
}
112111
});
112+
113+
it('should filter out undefined transactions', () => {
114+
const normalTransaction = generateTransaction({
115+
transactionID: '123',
116+
});
117+
118+
const transactions = [normalTransaction, undefined];
119+
const unreportedExpenses = createUnreportedExpenses(transactions);
120+
121+
expect(unreportedExpenses).toHaveLength(1);
122+
expect(unreportedExpenses.at(0)?.transactionID).toBe('123');
123+
});
113124
});
114125
});

0 commit comments

Comments
 (0)