Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
9a183f9
make empty reports selectable
getusha Apr 23, 2026
c790ddb
enable empty reports checkbox
getusha Apr 23, 2026
e018d95
enable empty reports checkbox
getusha Apr 23, 2026
e484f36
pass jsonQuery for group exports
getusha Apr 23, 2026
14a4678
fix: default to group exports when transaction is mixed
getusha Apr 23, 2026
fe8dd78
only show basic export for group exports
getusha Apr 23, 2026
9e1f2e4
prettier
getusha Apr 23, 2026
e2c90ea
Merge remote-tracking branch 'origin/main' enable-group-exports
getusha Apr 23, 2026
3a4bd07
fix lint
getusha Apr 23, 2026
4c5cd27
keep group context
getusha Apr 23, 2026
ae4dd8a
strengthen group selection check
getusha Apr 23, 2026
8a76cf6
Merge remote-tracking branch 'origin/main' enable-group-exports
getusha Apr 23, 2026
aa4b6bb
avoid nested option when menuItems is 1
getusha Apr 27, 2026
060deb6
fix incorrect footer summary when groups are selected
getusha Apr 27, 2026
67adbd2
fix failing test
getusha Apr 27, 2026
d283a2b
address PR reviews
getusha Apr 27, 2026
250e309
prettier
getusha Apr 27, 2026
106e288
propagate group selection into transactions when expanded
getusha Apr 27, 2026
292e93a
Merge remote-tracking branch 'origin/main' enable-group-exports
getusha May 6, 2026
43460d5
Merge remote-tracking branch 'origin/main' enable-group-exports
getusha May 14, 2026
f8530b1
Merge remote-tracking branch 'origin/main' enable-group-exports
getusha May 21, 2026
fb19c60
fix minor ui bugs
getusha May 21, 2026
1bdd111
address PR reviews
getusha May 21, 2026
2e641b1
Merge remote-tracking branch 'origin/main' enable-group-exports
getusha May 21, 2026
188fbec
Merge remote-tracking branch 'origin/main' enable-group-exports
getusha May 21, 2026
72c9ba2
fix lint
getusha May 21, 2026
ef70ca2
prettier
getusha May 21, 2026
56fa5c3
add filtering
getusha May 22, 2026
2c1f587
remove misinformed fix
getusha May 22, 2026
f2ff4ef
fix selection count
getusha May 22, 2026
7b4e7eb
fix lint
getusha May 22, 2026
7983653
Merge remote-tracking branch 'origin/main' enable-group-exports
getusha May 22, 2026
b20da91
prettier
getusha May 22, 2026
e06d7fd
Merge remote-tracking branch 'origin/main' enable-group-exports
getusha May 26, 2026
044ff04
prevent passing redundnt transaction/reportIDs for group exports
getusha May 26, 2026
e2ab5bb
export all expanded selections as individual rows
getusha May 26, 2026
61925a4
prettier
getusha May 26, 2026
e92d8c7
fix lint
getusha May 26, 2026
72762fc
handle expense level selections in group view
getusha May 26, 2026
e3867af
fix lint
getusha May 26, 2026
dd63857
address PR reviews
getusha May 27, 2026
551353a
remove console logs
getusha May 27, 2026
c22bcd3
Merge remote-tracking branch 'origin/main' enable-group-exports
getusha May 27, 2026
b60bb52
fix: keep groupKeys
getusha May 29, 2026
aacef00
Merge remote-tracking branch 'origin/main' enable-group-exports
getusha May 29, 2026
f252829
fix lint
getusha May 29, 2026
526712c
fix unselected list when group is expanded
getusha Jun 1, 2026
d0dfd55
Merge remote-tracking branch 'origin/main' enable-group-exports
getusha Jun 1, 2026
a837366
fix lint
getusha Jun 1, 2026
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
10 changes: 8 additions & 2 deletions src/components/Search/SearchBulkActionsButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,14 @@ function SearchBulkActionsButton({queryJSON}: SearchBulkActionsButtonProps) {
return reportIDs.size;
}

return selectedTransactionsKeys.length;
}, [selectedTransactions, selectedTransactionsKeys.length, isExpenseReportType]);
return selectedTransactionsKeys.reduce((count, key) => {
if (key.startsWith(CONST.SEARCH.GROUP_PREFIX)) {
const group = searchData?.[key as keyof typeof searchData] as {count?: number} | undefined;
return count + (group?.count ?? 0);
}
return count + 1;
}, 0);
}, [selectedTransactions, selectedTransactionsKeys, isExpenseReportType, searchData]);

const selectionButtonText = areAllMatchingItemsSelected ? translate('search.exportAll.allMatchingItemsSelected') : translate('workspace.common.selected', {count: selectedItemsCount});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -164,9 +164,7 @@ function TransactionGroupListItem<TItem extends ListItem>({
const isSelectAllChecked = isEmptyReportSelected || (selectedItemsLength === transactionsWithoutPendingDelete.length && transactionsWithoutPendingDelete.length > 0);
const isIndeterminate = selectedItemsLength > 0 && selectedItemsLength !== transactionsWithoutPendingDelete.length;

// Currently only the transaction report groups have transactions where the empty view makes sense
const shouldDisplayEmptyView = isEmpty && isExpenseReportType;
const isDisabledOrEmpty = isEmpty || isDisabled;

const refreshTransactions = () => {
if (!groupItem.transactionsQueryJSON) {
Expand Down Expand Up @@ -278,7 +276,7 @@ function TransactionGroupListItem<TItem extends ListItem>({
};

const onPress = (event?: ModifiedMouseEvent) => {
if (isExpenseReportType || transactions.length === 0) {
if (isExpenseReportType) {
onSelectRow(item, transactionPreviewData, event);
}
if (!isExpenseReportType) {
Expand Down Expand Up @@ -313,7 +311,7 @@ function TransactionGroupListItem<TItem extends ListItem>({
<MemberListItemHeader
member={groupItem as TransactionMemberGroupListItemType}
onCheckboxPress={handleSelectionButtonPress}
isDisabled={isDisabledOrEmpty}
isDisabled={isDisabled}
columns={columns}
canSelectMultiple={canSelectMultiple}
isSelectAllChecked={isSelectAllChecked}
Expand All @@ -327,7 +325,7 @@ function TransactionGroupListItem<TItem extends ListItem>({
<CardListItemHeader
card={groupItem as TransactionCardGroupListItemType}
onCheckboxPress={handleSelectionButtonPress}
isDisabled={isDisabledOrEmpty}
isDisabled={isDisabled}
columns={columns}
isFocused={isFocused}
canSelectMultiple={canSelectMultiple}
Expand All @@ -341,7 +339,7 @@ function TransactionGroupListItem<TItem extends ListItem>({
<WithdrawalIDListItemHeader
withdrawalID={groupItem as TransactionWithdrawalIDGroupListItemType}
onCheckboxPress={handleSelectionButtonPress}
isDisabled={isDisabledOrEmpty}
isDisabled={isDisabled}
columns={columns}
canSelectMultiple={canSelectMultiple}
isSelectAllChecked={isSelectAllChecked}
Expand All @@ -354,7 +352,7 @@ function TransactionGroupListItem<TItem extends ListItem>({
<CategoryListItemHeader
category={groupItem as TransactionCategoryGroupListItemType}
onCheckboxPress={handleSelectionButtonPress}
isDisabled={isDisabledOrEmpty}
isDisabled={isDisabled}
columns={columns}
canSelectMultiple={canSelectMultiple}
isSelectAllChecked={isSelectAllChecked}
Expand All @@ -367,7 +365,7 @@ function TransactionGroupListItem<TItem extends ListItem>({
<MerchantListItemHeader
merchant={groupItem as TransactionMerchantGroupListItemType}
onCheckboxPress={handleSelectionButtonPress}
isDisabled={isDisabledOrEmpty}
isDisabled={isDisabled}
columns={columns}
canSelectMultiple={canSelectMultiple}
isSelectAllChecked={isSelectAllChecked}
Expand All @@ -380,7 +378,7 @@ function TransactionGroupListItem<TItem extends ListItem>({
<TagListItemHeader
tag={groupItem as TransactionTagGroupListItemType}
onCheckboxPress={handleSelectionButtonPress}
isDisabled={isDisabledOrEmpty}
isDisabled={isDisabled}
columns={columns}
canSelectMultiple={canSelectMultiple}
isSelectAllChecked={isSelectAllChecked}
Expand All @@ -393,7 +391,7 @@ function TransactionGroupListItem<TItem extends ListItem>({
<MonthListItemHeader
month={groupItem as TransactionMonthGroupListItemType}
onCheckboxPress={handleSelectionButtonPress}
isDisabled={isDisabledOrEmpty}
isDisabled={isDisabled}
columns={columns}
canSelectMultiple={canSelectMultiple}
isSelectAllChecked={isSelectAllChecked}
Expand All @@ -406,7 +404,7 @@ function TransactionGroupListItem<TItem extends ListItem>({
<WeekListItemHeader
week={groupItem as TransactionWeekGroupListItemType}
onCheckboxPress={handleSelectionButtonPress}
isDisabled={isDisabledOrEmpty}
isDisabled={isDisabled}
columns={columns}
canSelectMultiple={canSelectMultiple}
isSelectAllChecked={isSelectAllChecked}
Expand All @@ -419,7 +417,7 @@ function TransactionGroupListItem<TItem extends ListItem>({
<YearListItemHeader
year={groupItem as TransactionYearGroupListItemType}
onCheckboxPress={handleSelectionButtonPress}
isDisabled={isDisabledOrEmpty}
isDisabled={isDisabled}
columns={columns}
canSelectMultiple={canSelectMultiple}
isSelectAllChecked={isSelectAllChecked}
Expand All @@ -432,7 +430,7 @@ function TransactionGroupListItem<TItem extends ListItem>({
<QuarterListItemHeader
quarter={groupItem as TransactionQuarterGroupListItemType}
onCheckboxPress={handleSelectionButtonPress}
isDisabled={isDisabledOrEmpty}
isDisabled={isDisabled}
columns={columns}
canSelectMultiple={canSelectMultiple}
isSelectAllChecked={isSelectAllChecked}
Expand Down
6 changes: 6 additions & 0 deletions src/components/Search/SearchList/ListItem/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,12 @@ type TransactionGroupListItemType = ListItem & {

/** Whether the report was rejected (REJECTED or REJECTEDTOSUBMITTER) */
isRejectedReport?: boolean;

/** Total value of transactions in the group */
total?: number;

/** Currency of the group total */
currency?: string;
};

type ExpenseReportListItemType = TransactionReportGroupListItemType;
Expand Down
14 changes: 7 additions & 7 deletions src/components/Search/SearchList/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -232,19 +232,19 @@ function SearchList({
return data;
}, [data, groupBy, type]);
const emptyReports = useMemo(() => {
if (type === CONST.SEARCH.DATA_TYPES.EXPENSE_REPORT && isTransactionGroupListItemArray(data)) {
return data.filter((item) => item.transactions.length === 0);
if (isTransactionGroupListItemArray(data)) {
return data.filter((item) => item.transactions.length === 0 && item.keyForList);
}
return [];
}, [data, type]);
}, [data]);

const selectedItemsLength = useMemo(() => {
const selectedTransactionsCount = flattenedItems.reduce((acc, item) => {
const isTransactionSelected = !!(item?.keyForList && selectedTransactions[item.keyForList]?.isSelected);
return acc + (isTransactionSelected ? 1 : 0);
}, 0);

if (type === CONST.SEARCH.DATA_TYPES.EXPENSE_REPORT && isTransactionGroupListItemArray(data)) {
if (isTransactionGroupListItemArray(data)) {
const selectedEmptyReports = emptyReports.reduce((acc, item) => {
const isEmptyReportSelected = !!(item.keyForList && selectedTransactions[item.keyForList]?.isSelected);
return acc + (isEmptyReportSelected ? 1 : 0);
Expand All @@ -254,10 +254,10 @@ function SearchList({
}

return selectedTransactionsCount;
}, [flattenedItems, type, data, emptyReports, selectedTransactions]);
}, [flattenedItems, data, emptyReports, selectedTransactions]);

const totalItems = useMemo(() => {
if (type === CONST.SEARCH.DATA_TYPES.EXPENSE_REPORT && isTransactionGroupListItemArray(data)) {
if (isTransactionGroupListItemArray(data)) {
const selectableEmptyReports = emptyReports.filter((item) => item.pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE);
const selectableTransactions = flattenedItems.filter((item) => {
if ('pendingAction' in item) {
Expand All @@ -275,7 +275,7 @@ function SearchList({
return true;
});
return selectableTransactions.length;
}, [data, type, flattenedItems, emptyReports]);
}, [data, flattenedItems, emptyReports]);

const {translate} = useLocalize();
const {isOffline} = useNetwork();
Expand Down
Loading
Loading