diff --git a/Mobile-Expensify b/Mobile-Expensify
index d9bcd7d4013c..d077aa091789 160000
--- a/Mobile-Expensify
+++ b/Mobile-Expensify
@@ -1 +1 @@
-Subproject commit d9bcd7d4013cba681aedca236b36a5cd5729d80f
+Subproject commit d077aa091789ff299f2f613d7daa325c0be38952
diff --git a/android/app/build.gradle b/android/app/build.gradle
index 8a4d57cc5eaa..5c35aa893286 100644
--- a/android/app/build.gradle
+++ b/android/app/build.gradle
@@ -114,8 +114,8 @@ android {
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
multiDexEnabled rootProject.ext.multiDexEnabled
- versionCode 1009018919
- versionName "9.1.89-19"
+ versionCode 1009018920
+ versionName "9.1.89-20"
// Supported language variants must be declared here to avoid from being removed during the compilation.
// This also helps us to not include unnecessary language variants in the APK.
resConfigs "en", "es"
diff --git a/ios/NewExpensify/Info.plist b/ios/NewExpensify/Info.plist
index 2e77d1cc13bd..e1c5c542b2e4 100644
--- a/ios/NewExpensify/Info.plist
+++ b/ios/NewExpensify/Info.plist
@@ -44,7 +44,7 @@
CFBundleVersion
- 9.1.89.19
+ 9.1.89.20
FullStory
OrgId
diff --git a/ios/NotificationServiceExtension/Info.plist b/ios/NotificationServiceExtension/Info.plist
index 94f4d8aafc88..93b4d2d0b177 100644
--- a/ios/NotificationServiceExtension/Info.plist
+++ b/ios/NotificationServiceExtension/Info.plist
@@ -13,7 +13,7 @@
CFBundleShortVersionString
9.1.89
CFBundleVersion
- 9.1.89.19
+ 9.1.89.20
NSExtension
NSExtensionPointIdentifier
diff --git a/ios/ShareViewController/Info.plist b/ios/ShareViewController/Info.plist
index 36ca0ebd4a0f..0a00ae2ad90c 100644
--- a/ios/ShareViewController/Info.plist
+++ b/ios/ShareViewController/Info.plist
@@ -13,7 +13,7 @@
CFBundleShortVersionString
9.1.89
CFBundleVersion
- 9.1.89.19
+ 9.1.89.20
NSExtension
NSExtensionAttributes
diff --git a/package-lock.json b/package-lock.json
index d7061619d382..75156cd1b199 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "new.expensify",
- "version": "9.1.89-19",
+ "version": "9.1.89-20",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "new.expensify",
- "version": "9.1.89-19",
+ "version": "9.1.89-20",
"hasInstallScript": true,
"license": "MIT",
"dependencies": {
diff --git a/package.json b/package.json
index 8f7d466a3305..30aa8e14b681 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "new.expensify",
- "version": "9.1.89-19",
+ "version": "9.1.89-20",
"author": "Expensify, Inc.",
"homepage": "https://new.expensify.com",
"description": "New Expensify is the next generation of Expensify: a reimagination of payments based atop a foundation of chat.",
diff --git a/src/CONST/index.ts b/src/CONST/index.ts
index e2f9663f7843..2d64091345ca 100755
--- a/src/CONST/index.ts
+++ b/src/CONST/index.ts
@@ -1289,7 +1289,6 @@ const CONST = {
RECEIPT: 'receipt',
DATE: 'date',
MERCHANT: 'merchant',
- DESCRIPTION: 'description',
FROM: 'from',
TO: 'to',
CATEGORY: 'category',
@@ -6471,9 +6470,6 @@ const CONST = {
UNAPPROVED_CASH: 'unapprovedCash',
UNAPPROVED_CARD: 'unapprovedCard',
},
- ANIMATION: {
- FADE_DURATION: 200,
- },
},
EXPENSE: {
diff --git a/src/components/MoneyRequestReportView/MoneyRequestReportTableHeader.tsx b/src/components/MoneyRequestReportView/MoneyRequestReportTableHeader.tsx
index c83f12cb4ac5..e588dde8b829 100644
--- a/src/components/MoneyRequestReportView/MoneyRequestReportTableHeader.tsx
+++ b/src/components/MoneyRequestReportView/MoneyRequestReportTableHeader.tsx
@@ -13,6 +13,25 @@ type ColumnConfig = {
isColumnSortable?: boolean;
};
+const shouldShowColumnConfig: Record boolean> = {
+ [CONST.SEARCH.TABLE_COLUMNS.RECEIPT]: () => true,
+ [CONST.SEARCH.TABLE_COLUMNS.TYPE]: () => true,
+ [CONST.SEARCH.TABLE_COLUMNS.DATE]: () => true,
+ [CONST.SEARCH.TABLE_COLUMNS.MERCHANT]: () => true,
+ [CONST.SEARCH.TABLE_COLUMNS.CATEGORY]: (isIOUReport) => !isIOUReport,
+ [CONST.SEARCH.TABLE_COLUMNS.TAG]: (isIOUReport) => !isIOUReport,
+ [CONST.REPORT.TRANSACTION_LIST.COLUMNS.COMMENTS]: () => true,
+ [CONST.SEARCH.TABLE_COLUMNS.TOTAL_AMOUNT]: () => true,
+ [CONST.SEARCH.TABLE_COLUMNS.IN]: () => false,
+ [CONST.SEARCH.TABLE_COLUMNS.FROM]: () => false,
+ [CONST.SEARCH.TABLE_COLUMNS.TO]: () => false,
+ [CONST.SEARCH.TABLE_COLUMNS.DESCRIPTION]: () => false,
+ [CONST.SEARCH.TABLE_COLUMNS.TAX_AMOUNT]: () => false,
+ [CONST.SEARCH.TABLE_COLUMNS.ACTION]: () => false,
+ [CONST.SEARCH.TABLE_COLUMNS.TITLE]: () => false,
+ [CONST.SEARCH.TABLE_COLUMNS.ASSIGNEE]: () => false,
+};
+
const columnConfig: ColumnConfig[] = [
{
columnName: CONST.SEARCH.TABLE_COLUMNS.RECEIPT,
@@ -32,10 +51,6 @@ const columnConfig: ColumnConfig[] = [
columnName: CONST.SEARCH.TABLE_COLUMNS.MERCHANT,
translationKey: 'common.merchant',
},
- {
- columnName: CONST.SEARCH.TABLE_COLUMNS.DESCRIPTION,
- translationKey: 'common.description',
- },
{
columnName: CONST.SEARCH.TABLE_COLUMNS.CATEGORY,
translationKey: 'common.category',
@@ -63,19 +78,22 @@ type SearchTableHeaderProps = {
amountColumnSize: TableColumnSize;
taxAmountColumnSize: TableColumnSize;
shouldShowSorting: boolean;
- columns: SortableColumnName[];
+ isIOUReport: boolean;
};
-function MoneyRequestReportTableHeader({sortBy, sortOrder, onSortPress, dateColumnSize, shouldShowSorting, amountColumnSize, taxAmountColumnSize, columns}: SearchTableHeaderProps) {
+function MoneyRequestReportTableHeader({sortBy, sortOrder, onSortPress, dateColumnSize, shouldShowSorting, isIOUReport, amountColumnSize, taxAmountColumnSize}: SearchTableHeaderProps) {
const styles = useThemeStyles();
const shouldShowColumn = useCallback(
(columnName: SortableColumnName) => {
- return columns.includes(columnName);
+ const shouldShowFun = shouldShowColumnConfig[columnName];
+ if (!shouldShowFun) {
+ return false;
+ }
+ return shouldShowFun(isIOUReport);
},
- [columns],
+ [isIOUReport],
);
-
return (
void;
};
function MoneyRequestReportTransactionItem({
transaction,
- columns,
report,
isSelectionModeEnabled,
toggleTransaction,
@@ -133,7 +138,7 @@ function MoneyRequestReportTransactionItem({
shouldUseNarrowLayout={shouldUseNarrowLayout || isMediumScreenWidth}
shouldShowCheckbox={!!isSelectionModeEnabled || !isSmallScreenWidth}
onCheckboxPress={toggleTransaction}
- columns={columns as Array>}
+ columns={allReportColumns}
isDisabled={isPendingDelete}
/>
diff --git a/src/components/MoneyRequestReportView/MoneyRequestReportTransactionList.tsx b/src/components/MoneyRequestReportView/MoneyRequestReportTransactionList.tsx
index e7b5a22f3bd5..95182e0950b5 100644
--- a/src/components/MoneyRequestReportView/MoneyRequestReportTransactionList.tsx
+++ b/src/components/MoneyRequestReportView/MoneyRequestReportTransactionList.tsx
@@ -22,8 +22,8 @@ import {convertToDisplayString} from '@libs/CurrencyUtils';
import {getThreadReportIDsForTransactions} from '@libs/MoneyRequestReportUtils';
import {navigationRef} from '@libs/Navigation/Navigation';
import {getIOUActionForTransactionID} from '@libs/ReportActionsUtils';
-import {getMoneyRequestSpendBreakdown} from '@libs/ReportUtils';
-import {compareValues, getColumnsToShow, isTransactionAmountTooLong, isTransactionTaxAmountTooLong} from '@libs/SearchUIUtils';
+import {getMoneyRequestSpendBreakdown, isIOUReport} from '@libs/ReportUtils';
+import {compareValues, isTransactionAmountTooLong, isTransactionTaxAmountTooLong} from '@libs/SearchUIUtils';
import {getTransactionPendingAction, isTransactionPendingDelete} from '@libs/TransactionUtils';
import shouldShowTransactionYear from '@libs/TransactionUtils/shouldShowTransactionYear';
import Navigation from '@navigation/Navigation';
@@ -160,11 +160,6 @@ function MoneyRequestReportTransactionList({
}));
}, [newTransactions, sortBy, sortOrder, transactions, localeCompare]);
- const columnsToShow = useMemo(() => {
- const columns = getColumnsToShow(transactions, true);
- return (Object.keys(columns) as SortableColumnName[]).filter((column) => columns[column]);
- }, [transactions]);
-
const navigateToTransaction = useCallback(
(activeTransactionID: string) => {
const iouAction = getIOUActionForTransactionID(reportActions, activeTransactionID);
@@ -267,7 +262,6 @@ function MoneyRequestReportTransactionList({
shouldShowSorting
sortBy={sortBy}
sortOrder={sortOrder}
- columns={columnsToShow}
dateColumnSize={dateColumnSize}
amountColumnSize={amountColumnSize}
taxAmountColumnSize={taxAmountColumnSize}
@@ -278,6 +272,7 @@ function MoneyRequestReportTransactionList({
setSortConfig((prevState) => ({...prevState, sortBy: selectedSortBy, sortOrder: selectedSortOrder}));
}}
+ isIOUReport={isIOUReport(report)}
/>
)}
@@ -288,7 +283,6 @@ function MoneyRequestReportTransactionList({
, 'onScroll' | 'conten
/** The search query */
queryJSON: SearchQueryJSON;
- /** Columns to show */
- columns: SortableColumnName[];
-
/** Called when the viewability of rows changes, as defined by the viewabilityConfig prop. */
onViewableItemsChanged?: (info: {changed: ViewToken[]; viewableItems: ViewToken[]}) => void;
@@ -134,7 +124,6 @@ function SearchList(
shouldPreventDefaultFocusOnSelectRow,
shouldPreventLongPressRow,
queryJSON,
- columns,
onViewableItemsChanged,
onLayout,
estimatedItemSize = ITEM_HEIGHTS.NARROW_WITHOUT_DRAWER.STANDARD,
@@ -350,7 +339,6 @@ function SearchList(
}}
shouldPreventDefaultFocusOnSelectRow={shouldPreventDefaultFocusOnSelectRow}
queryJSONHash={hash}
- columns={columns}
policies={policies}
isDisabled={isDisabled}
allReports={allReports}
@@ -371,7 +359,6 @@ function SearchList(
onCheckboxPress,
onSelectRow,
policies,
- columns,
hash,
groupBy,
setFocusedIndex,
@@ -473,7 +460,7 @@ function SearchList(
onScroll={onScroll}
showsVerticalScrollIndicator={false}
ref={listRef}
- extraData={[focusedIndex, isFocused, columns]}
+ extraData={[focusedIndex, isFocused]}
onEndReached={onEndReached}
onEndReachedThreshold={onEndReachedThreshold}
ListFooterComponent={ListFooterComponent}
diff --git a/src/components/Search/index.tsx b/src/components/Search/index.tsx
index fd6409a96af8..e8d7ec00d1bf 100644
--- a/src/components/Search/index.tsx
+++ b/src/components/Search/index.tsx
@@ -1,9 +1,8 @@
import {findFocusedRoute, useFocusEffect, useIsFocused, useNavigation} from '@react-navigation/native';
import type {ContentStyle} from '@shopify/flash-list';
import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react';
-import type {NativeScrollEvent, NativeSyntheticEvent} from 'react-native';
+import type {NativeScrollEvent, NativeSyntheticEvent, ViewToken} from 'react-native';
import {View} from 'react-native';
-import Animated, {FadeIn, FadeOut, useAnimatedStyle, useSharedValue, withTiming} from 'react-native-reanimated';
import FullPageErrorView from '@components/BlockingViews/FullPageErrorView';
import FullPageOfflineBlockingView from '@components/BlockingViews/FullPageOfflineBlockingView';
import SearchTableHeader from '@components/SelectionList/SearchTableHeader';
@@ -29,7 +28,6 @@ import {getIOUActionForTransactionID, isExportIntegrationAction, isIntegrationMe
import {canEditFieldOfMoneyRequest, generateReportID, isArchivedReport} from '@libs/ReportUtils';
import {buildSearchQueryString} from '@libs/SearchQueryUtils';
import {
- getColumnsToShow,
getListItem,
getSections,
getSortedSections,
@@ -57,7 +55,6 @@ import SCREENS from '@src/SCREENS';
import type {ReportAction} from '@src/types/onyx';
import type SearchResults from '@src/types/onyx/SearchResults';
import {isEmptyObject} from '@src/types/utils/EmptyObject';
-import arraysEqual from '@src/utils/arraysEqual';
import {useSearchContext} from './SearchContext';
import SearchList from './SearchList';
import SearchScopeProvider from './SearchScopeProvider';
@@ -548,39 +545,26 @@ function Search({queryJSON, searchResults, onSearchListScroll, contentContainerS
[hash, isMobileSelectionModeEnabled, toggleTransaction],
);
- const currentColumns = useMemo(() => {
- if (!searchResults?.data) {
- return [];
- }
- const columns = getColumnsToShow(searchResults?.data);
-
- return (Object.keys(columns) as SearchColumnType[]).filter((col) => columns[col]);
- }, [searchResults?.data]);
-
- // Custom animation for fade effect
- const opacity = useSharedValue(1);
- const animatedStyle = useAnimatedStyle(() => ({
- opacity: opacity.get(),
- }));
-
- const previousColumns = usePrevious(currentColumns);
- const [columnsToShow, setColumnsToShow] = useState([]);
+ const onViewableItemsChanged = useCallback(
+ ({viewableItems}: {viewableItems: ViewToken[]}) => {
+ if (!isFocused) {
+ return;
+ }
- // If columns have changed, trigger an animation before settings columnsToShow to prevent
- // new columns appearing before the fade out animation happens
- useEffect(() => {
- if ((previousColumns && currentColumns && arraysEqual(previousColumns, currentColumns)) || offset === 0 || isSmallScreenWidth) {
- setColumnsToShow(currentColumns);
- return;
- }
+ const isFirstItemVisible = viewableItems.at(0)?.index === 1;
+ // If the user is still loading the search results, or if they are scrolling down, don't refresh the search results
+ if (shouldShowLoadingState || !isFirstItemVisible) {
+ return;
+ }
- opacity.set(
- withTiming(0, {duration: CONST.SEARCH.ANIMATION.FADE_DURATION}, () => {
- setColumnsToShow(currentColumns);
- opacity.set(withTiming(1, {duration: CONST.SEARCH.ANIMATION.FADE_DURATION}));
- }),
- );
- }, [previousColumns, currentColumns, setColumnsToShow, opacity, offset, isSmallScreenWidth]);
+ // This line makes sure the app refreshes the search results when the user scrolls to the top.
+ // The backend sends items in parts based on the offset, with a limit on the number of items sent (pagination).
+ // As a result, it skips some items, for example, if the offset is 100, it sends the next items without the first ones.
+ // Therefore, when the user scrolls to the top, we need to refresh the search results.
+ setOffset(0);
+ },
+ [shouldShowLoadingState, isFocused],
+ );
const isChat = type === CONST.SEARCH.DATA_TYPES.CHAT;
const isTask = type === CONST.SEARCH.DATA_TYPES.TASK;
@@ -653,24 +637,14 @@ function Search({queryJSON, searchResults, onSearchListScroll, contentContainerS
);
}, [clearSelectedTransactions, data, groupBy, reportActionsArray, selectedTransactions, setSelectedTransactions]);
- const onLayoutWithScrollRestore = useCallback(() => {
- handleSelectionListScroll(sortedSelectedData, searchListRef.current);
- // Restore scroll position after layout if needed
- // Removed scroll position restoration logic
- }, [handleSelectionListScroll, sortedSelectedData]);
+ const onLayout = useCallback(() => handleSelectionListScroll(sortedSelectedData, searchListRef.current), [handleSelectionListScroll, sortedSelectedData]);
if (shouldShowLoadingState) {
return (
-
-
-
+
);
}
@@ -718,56 +692,50 @@ function Search({queryJSON, searchResults, onSearchListScroll, contentContainerS
return (
-
-
- )
- }
- contentContainerStyle={{...contentContainerStyle, ...styles.pb3}}
- containerStyle={[styles.pv0, type === CONST.SEARCH.DATA_TYPES.CHAT && !isSmallScreenWidth && styles.pt3]}
- shouldPreventDefaultFocusOnSelectRow={!canUseTouchScreen()}
- onScroll={onSearchListScroll}
- onEndReachedThreshold={0.75}
- onEndReached={fetchMoreResults}
- ListFooterComponent={
- shouldShowLoadingMoreItems ? (
-
- ) : undefined
- }
- queryJSON={queryJSON}
- columns={columnsToShow}
- onLayout={onLayoutWithScrollRestore}
- isMobileSelectionModeEnabled={isMobileSelectionModeEnabled}
- />
-
+
+ )
+ }
+ contentContainerStyle={{...contentContainerStyle, ...styles.pb3}}
+ containerStyle={[styles.pv0, type === CONST.SEARCH.DATA_TYPES.CHAT && !isSmallScreenWidth && styles.pt3]}
+ shouldPreventDefaultFocusOnSelectRow={!canUseTouchScreen()}
+ onScroll={onSearchListScroll}
+ onEndReachedThreshold={0.75}
+ onEndReached={fetchMoreResults}
+ ListFooterComponent={
+ shouldShowLoadingMoreItems ? (
+
+ ) : undefined
+ }
+ queryJSON={queryJSON}
+ onViewableItemsChanged={onViewableItemsChanged}
+ onLayout={onLayout}
+ isMobileSelectionModeEnabled={isMobileSelectionModeEnabled}
+ />
);
}
diff --git a/src/components/SelectionList/Search/TransactionGroupListItem.tsx b/src/components/SelectionList/Search/TransactionGroupListItem.tsx
index 31e98b3f87ad..2fd2e2631658 100644
--- a/src/components/SelectionList/Search/TransactionGroupListItem.tsx
+++ b/src/components/SelectionList/Search/TransactionGroupListItem.tsx
@@ -44,7 +44,6 @@ function TransactionGroupListItem({
onFocus,
onLongPressRow,
shouldSyncFocus,
- columns,
groupBy,
}: TransactionGroupListItemProps) {
const groupItem = item as unknown as TransactionGroupListItemType;
@@ -88,6 +87,23 @@ function TransactionGroupListItem({
});
};
+ const sampleTransaction = groupItem.transactions.at(0);
+ const {COLUMNS} = CONST.REPORT.TRANSACTION_LIST;
+
+ const columns = [
+ COLUMNS.RECEIPT,
+ COLUMNS.TYPE,
+ COLUMNS.DATE,
+ COLUMNS.MERCHANT,
+ COLUMNS.FROM,
+ COLUMNS.TO,
+ ...(sampleTransaction?.shouldShowCategory ? [COLUMNS.CATEGORY] : []),
+ ...(sampleTransaction?.shouldShowTag ? [COLUMNS.TAG] : []),
+ ...(sampleTransaction?.shouldShowTax ? [COLUMNS.TAX] : []),
+ COLUMNS.TOTAL_AMOUNT,
+ COLUMNS.ACTION,
+ ] satisfies Array>;
+
const getHeader = useMemo(() => {
const headers: Record = {
[CONST.SEARCH.GROUP_BY.REPORTS]: (
@@ -185,7 +201,7 @@ function TransactionGroupListItem({
shouldUseNarrowLayout={!isLargeScreenWidth}
shouldShowCheckbox={!!canSelectMultiple}
onCheckboxPress={() => onCheckboxPress?.(transaction as unknown as TItem)}
- columns={columns as Array>}
+ columns={columns}
onButtonPress={() => {
openReportInRHP(transaction);
}}
diff --git a/src/components/SelectionList/Search/TransactionListItem.tsx b/src/components/SelectionList/Search/TransactionListItem.tsx
index 87b9f1ca8b4c..4ca95e845a5d 100644
--- a/src/components/SelectionList/Search/TransactionListItem.tsx
+++ b/src/components/SelectionList/Search/TransactionListItem.tsx
@@ -33,7 +33,6 @@ function TransactionListItem({
onLongPressRow,
shouldSyncFocus,
isLoading,
- columns,
}: TransactionListItemProps) {
const transactionItem = item as unknown as TransactionListItemType;
const styles = useThemeStyles();
@@ -73,6 +72,24 @@ function TransactionListItem({
};
}, [transactionItem]);
+ const columns = useMemo(
+ () =>
+ [
+ CONST.REPORT.TRANSACTION_LIST.COLUMNS.RECEIPT,
+ CONST.REPORT.TRANSACTION_LIST.COLUMNS.TYPE,
+ CONST.REPORT.TRANSACTION_LIST.COLUMNS.DATE,
+ CONST.REPORT.TRANSACTION_LIST.COLUMNS.MERCHANT,
+ CONST.REPORT.TRANSACTION_LIST.COLUMNS.FROM,
+ CONST.REPORT.TRANSACTION_LIST.COLUMNS.TO,
+ ...(transactionItem?.shouldShowCategory ? [CONST.REPORT.TRANSACTION_LIST.COLUMNS.CATEGORY] : []),
+ ...(transactionItem?.shouldShowTag ? [CONST.REPORT.TRANSACTION_LIST.COLUMNS.TAG] : []),
+ ...(transactionItem?.shouldShowTax ? [CONST.REPORT.TRANSACTION_LIST.COLUMNS.TAX] : []),
+ CONST.REPORT.TRANSACTION_LIST.COLUMNS.TOTAL_AMOUNT,
+ CONST.REPORT.TRANSACTION_LIST.COLUMNS.ACTION,
+ ] satisfies Array>,
+ [transactionItem?.shouldShowCategory, transactionItem?.shouldShowTag, transactionItem?.shouldShowTax],
+ );
+
const handleActionButtonPress = useCallback(() => {
handleActionButtonPressUtil(
currentSearchHash,
@@ -138,7 +155,7 @@ function TransactionListItem({
onButtonPress={handleActionButtonPress}
onCheckboxPress={handleCheckboxPress}
shouldUseNarrowLayout={!isLargeScreenWidth}
- columns={columns as Array>}
+ columns={columns}
isActionLoading={isLoading ?? transactionItem.isActionLoading}
isSelected={!!transactionItem.isSelected}
dateColumnSize={dateColumnSize}
diff --git a/src/components/SelectionList/SearchTableHeader.tsx b/src/components/SelectionList/SearchTableHeader.tsx
index 7e6509a8a1ef..21130da633ea 100644
--- a/src/components/SelectionList/SearchTableHeader.tsx
+++ b/src/components/SelectionList/SearchTableHeader.tsx
@@ -2,18 +2,41 @@ import React, {useCallback} from 'react';
import type {SearchColumnType, SortOrder} from '@components/Search/types';
import useResponsiveLayout from '@hooks/useResponsiveLayout';
import useThemeStyles from '@hooks/useThemeStyles';
+import {getShouldShowMerchant} from '@libs/SearchUIUtils';
import CONST from '@src/CONST';
import type {TranslationPaths} from '@src/languages/types';
import type * as OnyxTypes from '@src/types/onyx';
import SortableTableHeader from './SortableTableHeader';
import type {SortableColumnName} from './types';
+type ShouldShowSearchColumnFn = (data: OnyxTypes.SearchResults['data'], metadata: OnyxTypes.SearchResults['search']) => boolean;
+
type SearchColumnConfig = {
columnName: SearchColumnType;
translationKey: TranslationPaths;
isColumnSortable?: boolean;
};
+const shouldShowColumnConfig: Record = {
+ [CONST.SEARCH.TABLE_COLUMNS.RECEIPT]: () => true,
+ [CONST.SEARCH.TABLE_COLUMNS.TYPE]: () => true,
+ [CONST.SEARCH.TABLE_COLUMNS.DATE]: () => true,
+ [CONST.SEARCH.TABLE_COLUMNS.MERCHANT]: (data: OnyxTypes.SearchResults['data']) => getShouldShowMerchant(data),
+ [CONST.SEARCH.TABLE_COLUMNS.DESCRIPTION]: (data: OnyxTypes.SearchResults['data']) => !getShouldShowMerchant(data),
+ [CONST.SEARCH.TABLE_COLUMNS.FROM]: () => true,
+ [CONST.SEARCH.TABLE_COLUMNS.TO]: () => true,
+ [CONST.SEARCH.TABLE_COLUMNS.CATEGORY]: (data, metadata) => metadata?.columnsToShow?.shouldShowCategoryColumn ?? false,
+ [CONST.SEARCH.TABLE_COLUMNS.TAG]: (data, metadata) => metadata?.columnsToShow?.shouldShowTagColumn ?? false,
+ [CONST.SEARCH.TABLE_COLUMNS.TAX_AMOUNT]: (data, metadata) => metadata?.columnsToShow?.shouldShowTaxColumn ?? false,
+ [CONST.SEARCH.TABLE_COLUMNS.TOTAL_AMOUNT]: () => true,
+ [CONST.SEARCH.TABLE_COLUMNS.ACTION]: () => true,
+ [CONST.SEARCH.TABLE_COLUMNS.TITLE]: () => true,
+ [CONST.SEARCH.TABLE_COLUMNS.ASSIGNEE]: () => true,
+ [CONST.SEARCH.TABLE_COLUMNS.IN]: () => true,
+ // This column is never displayed on Search
+ [CONST.REPORT.TRANSACTION_LIST.COLUMNS.COMMENTS]: () => false,
+};
+
const expenseHeaders: SearchColumnConfig[] = [
{
columnName: CONST.SEARCH.TABLE_COLUMNS.RECEIPT,
@@ -111,6 +134,7 @@ const SearchColumns = {
};
type SearchTableHeaderProps = {
+ data: OnyxTypes.SearchResults['data'];
metadata: OnyxTypes.SearchResults['search'];
sortBy?: SearchColumnType;
sortOrder?: SortOrder;
@@ -120,10 +144,10 @@ type SearchTableHeaderProps = {
isTaxAmountColumnWide: boolean;
shouldShowSorting: boolean;
canSelectMultiple: boolean;
- columns: SortableColumnName[];
};
function SearchTableHeader({
+ data,
metadata,
sortBy,
sortOrder,
@@ -133,7 +157,6 @@ function SearchTableHeader({
canSelectMultiple,
isAmountColumnWide,
isTaxAmountColumnWide,
- columns,
}: SearchTableHeaderProps) {
const styles = useThemeStyles();
// eslint-disable-next-line rulesdir/prefer-shouldUseNarrowLayout-instead-of-isSmallScreenWidth
@@ -142,9 +165,10 @@ function SearchTableHeader({
const shouldShowColumn = useCallback(
(columnName: SortableColumnName) => {
- return columns.includes(columnName);
+ const shouldShowFun = shouldShowColumnConfig[columnName];
+ return shouldShowFun(data, metadata);
},
- [columns],
+ [data, metadata],
);
if (displayNarrowVersion) {
diff --git a/src/components/SelectionList/types.ts b/src/components/SelectionList/types.ts
index 08d4eb1c4068..7da7e4776687 100644
--- a/src/components/SelectionList/types.ts
+++ b/src/components/SelectionList/types.ts
@@ -246,9 +246,6 @@ type TransactionListItemType = ListItem &
/** Whether we should show the merchant column */
shouldShowMerchant: boolean;
- /** Whether the description column should be shown */
- shouldShowDescription: boolean;
-
/** Whether we should show the category column */
shouldShowCategory: boolean;
@@ -258,12 +255,6 @@ type TransactionListItemType = ListItem &
/** Whether we should show the tax column */
shouldShowTax: boolean;
- /** Whether we should show the From column */
- shouldShowFrom: boolean;
-
- /** Whether we should show the to column */
- shouldShowTo: boolean;
-
/** Whether we should show the transaction year.
* This is true if at least one transaction in the dataset was created in past years
*/
@@ -466,7 +457,6 @@ type TableListItemProps = ListItemProps;
type TransactionListItemProps = ListItemProps & {
/** Whether the item's action is loading */
isLoading?: boolean;
- columns?: SortableColumnName[];
};
type TaskListItemProps = ListItemProps & {
@@ -476,7 +466,7 @@ type TaskListItemProps = ListItemProps & {
type TransactionGroupListItemProps = ListItemProps & {
groupBy?: SearchGroupBy;
- columns?: SortableColumnName[];
+ policies?: OnyxCollection;
};
type ChatListItemProps = ListItemProps & {
diff --git a/src/components/TransactionItemRow/index.tsx b/src/components/TransactionItemRow/index.tsx
index 0f7bbb208fef..7a6abf1ef400 100644
--- a/src/components/TransactionItemRow/index.tsx
+++ b/src/components/TransactionItemRow/index.tsx
@@ -13,6 +13,7 @@ import useLocalize from '@hooks/useLocalize';
import useStyleUtils from '@hooks/useStyleUtils';
import useThemeStyles from '@hooks/useThemeStyles';
import {isCategoryMissing} from '@libs/CategoryUtils';
+import Parser from '@libs/Parser';
import StringUtils from '@libs/StringUtils';
import {
getDescription,
@@ -67,9 +68,6 @@ type TransactionWithOptionalSearchFields = TransactionWithOptionalHighlight & {
/** information about whether to show merchant, that is provided on Reports page */
shouldShowMerchant?: boolean;
- /** information about whether to show the description, that is provided on Reports page */
- shouldShowDescription?: boolean;
-
/** Type of transaction */
transactionType?: ValueOf;
@@ -97,17 +95,24 @@ type TransactionItemRowProps = {
isDisabled?: boolean;
};
-function getMerchantName(transactionItem: TransactionWithOptionalSearchFields, translate: (key: TranslationPaths) => string) {
+/** If merchant name is empty or (none), then it falls back to description if screen is narrow */
+function getMerchantNameWithFallback(transactionItem: TransactionWithOptionalSearchFields, translate: (key: TranslationPaths) => string, shouldUseNarrowLayout?: boolean | undefined) {
const shouldShowMerchant = transactionItem.shouldShowMerchant ?? true;
+ const description = getDescription(transactionItem);
+ let merchantOrDescriptionToDisplay = transactionItem?.formattedMerchant ?? getMerchant(transactionItem);
+ const merchantNameEmpty = !merchantOrDescriptionToDisplay || merchantOrDescriptionToDisplay === CONST.TRANSACTION.PARTIAL_TRANSACTION_MERCHANT;
+ if (merchantNameEmpty && shouldUseNarrowLayout) {
+ merchantOrDescriptionToDisplay = Parser.htmlToText(description);
+ }
- let merchant = transactionItem?.formattedMerchant ?? getMerchant(transactionItem);
+ let merchant = shouldShowMerchant ? merchantOrDescriptionToDisplay : Parser.htmlToText(description);
if (isScanning(transactionItem) && shouldShowMerchant) {
merchant = translate('iou.receiptStatusTitle');
}
const merchantName = StringUtils.getFirstLine(merchant);
- return merchantName !== CONST.TRANSACTION.PARTIAL_TRANSACTION_MERCHANT ? merchantName : '';
+ return merchant !== CONST.TRANSACTION.PARTIAL_TRANSACTION_MERCHANT ? merchantName : '';
}
function TransactionItemRow({
@@ -147,12 +152,7 @@ function TransactionItemRow({
return styles.activeComponentBG;
}, [isSelected, styles.activeComponentBG]);
- const merchant = useMemo(() => getMerchantName(transactionItem, translate), [transactionItem, translate]);
- const description = getDescription(transactionItem);
-
- // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
- const merchantOrDescription = merchant || description;
-
+ const merchantOrDescriptionName = useMemo(() => getMerchantNameWithFallback(transactionItem, translate, shouldUseNarrowLayout), [shouldUseNarrowLayout, transactionItem, translate]);
const missingFieldError = useMemo(() => {
const isCustomUnitOutOfPolicy = isUnreportedAndHasInvalidDistanceRateTransaction(transactionItem);
const hasFieldErrors = hasMissingSmartscanFields(transactionItem) || isCustomUnitOutOfPolicy;
@@ -258,23 +258,9 @@ function TransactionItemRow({
key={CONST.REPORT.TRANSACTION_LIST.COLUMNS.MERCHANT}
style={[StyleUtils.getReportTableColumnStyles(CONST.SEARCH.TABLE_COLUMNS.MERCHANT)]}
>
- {!!merchant && (
-
- )}
-
- ),
- [CONST.REPORT.TRANSACTION_LIST.COLUMNS.DESCRIPTION]: (
-
- {!!description && (
+ {!!merchantOrDescriptionName && (
@@ -354,8 +340,7 @@ function TransactionItemRow({
isTaxAmountColumnWide,
isInSingleTransactionReport,
isSelected,
- merchant,
- description,
+ merchantOrDescriptionName,
onButtonPress,
shouldShowTooltip,
shouldUseNarrowLayout,
@@ -401,7 +386,7 @@ function TransactionItemRow({
shouldShowTooltip={shouldShowTooltip}
shouldUseNarrowLayout={shouldUseNarrowLayout}
/>
- {!merchantOrDescription && (
+ {!merchantOrDescriptionName && (
)}
- {!!merchantOrDescription && (
+ {!!merchantOrDescriptionName && (
diff --git a/src/libs/SearchUIUtils.ts b/src/libs/SearchUIUtils.ts
index 432842719e08..2a5d57086dc5 100644
--- a/src/libs/SearchUIUtils.ts
+++ b/src/libs/SearchUIUtils.ts
@@ -17,7 +17,6 @@ import type {
ListItem,
ReportActionListItemType,
SearchListItem,
- SortableColumnName,
TaskListItemType,
TransactionCardGroupListItemType,
TransactionGroupListItemType,
@@ -77,22 +76,17 @@ import {
isInvoiceReport,
isMoneyRequestReport,
isOpenExpenseReport,
- isOpenReport,
isSettled,
} from './ReportUtils';
import {buildCannedSearchQuery, buildQueryStringFromFilterFormValues, buildSearchQueryJSON, getTodoSearchQuery} from './SearchQueryUtils';
import StringUtils from './StringUtils';
import {shouldRestrictUserBillableActions} from './SubscriptionUtils';
import {
- getCategory,
- getDescription,
- getTag,
getTaxAmount,
getAmount as getTransactionAmount,
getCreated as getTransactionCreatedDate,
getMerchant as getTransactionMerchant,
isPendingCardOrScanningTransaction,
- isScanning,
isUnreportedAndHasInvalidDistanceRateTransaction,
isViolationDismissed,
} from './TransactionUtils';
@@ -733,9 +727,6 @@ function getTransactionsSections(data: OnyxTypes.SearchResults['data'], metadata
const shouldShowCategory = metadata?.columnsToShow?.shouldShowCategoryColumn;
const shouldShowTag = metadata?.columnsToShow?.shouldShowTagColumn;
const shouldShowTax = metadata?.columnsToShow?.shouldShowTaxColumn;
- const shouldShowTo = metadata?.columnsToShow?.shouldShowToColumn;
- const shouldShowFrom = metadata?.columnsToShow?.shouldShowFromColumn;
- const shouldShowDescription = metadata?.columnsToShow?.shouldShowDescriptionColumn;
// Pre-filter transaction keys to avoid repeated checks
const transactionKeys = Object.keys(data).filter(isTransactionEntry);
@@ -774,9 +765,6 @@ function getTransactionsSections(data: OnyxTypes.SearchResults['data'], metadata
shouldShowCategory,
shouldShowTag,
shouldShowTax,
- shouldShowTo,
- shouldShowFrom,
- shouldShowDescription,
keyForList: transactionItem.transactionID,
shouldShowYear: doesDataContainAPastYearTransaction,
isAmountColumnWide: shouldShowAmountInWideColumn,
@@ -1211,9 +1199,6 @@ function getReportSections(
formattedMerchant,
date,
shouldShowMerchant,
- shouldShowDescription: metadata?.columnsToShow.shouldShowDescriptionColumn,
- shouldShowFrom: metadata?.columnsToShow.shouldShowFromColumn,
- shouldShowTo: metadata?.columnsToShow.shouldShowToColumn,
shouldShowCategory: metadata?.columnsToShow?.shouldShowCategoryColumn,
shouldShowTag: metadata?.columnsToShow?.shouldShowTagColumn,
shouldShowTax: metadata?.columnsToShow?.shouldShowTaxColumn,
@@ -1342,95 +1327,6 @@ function getSortedSections(
return getSortedTransactionData(data as TransactionListItemType[], localeCompare, sortBy, sortOrder);
}
-/**
- * Determines what columns to show based on available data
- * @param isExpenseReportView: true when we are inside an expense report view, false if we're in the Reports page.
- */
-function getColumnsToShow(data: OnyxTypes.SearchResults['data'] | OnyxTypes.Transaction[], isExpenseReportView = false): Record {
- const columns: Record = isExpenseReportView
- ? {
- [CONST.REPORT.TRANSACTION_LIST.COLUMNS.RECEIPT]: true,
- [CONST.REPORT.TRANSACTION_LIST.COLUMNS.TYPE]: true,
- [CONST.REPORT.TRANSACTION_LIST.COLUMNS.DATE]: true,
- [CONST.REPORT.TRANSACTION_LIST.COLUMNS.MERCHANT]: false,
- [CONST.REPORT.TRANSACTION_LIST.COLUMNS.DESCRIPTION]: false,
- [CONST.REPORT.TRANSACTION_LIST.COLUMNS.CATEGORY]: false,
- [CONST.REPORT.TRANSACTION_LIST.COLUMNS.TAG]: false,
- [CONST.REPORT.TRANSACTION_LIST.COLUMNS.COMMENTS]: true,
- [CONST.REPORT.TRANSACTION_LIST.COLUMNS.TOTAL_AMOUNT]: true,
- [CONST.REPORT.TRANSACTION_LIST.COLUMNS.ACTION]: false,
- }
- : {
- [CONST.SEARCH.TABLE_COLUMNS.RECEIPT]: true,
- [CONST.SEARCH.TABLE_COLUMNS.TYPE]: true,
- [CONST.SEARCH.TABLE_COLUMNS.DATE]: true,
- [CONST.SEARCH.TABLE_COLUMNS.MERCHANT]: false,
- [CONST.SEARCH.TABLE_COLUMNS.DESCRIPTION]: false,
- [CONST.SEARCH.TABLE_COLUMNS.FROM]: false,
- [CONST.SEARCH.TABLE_COLUMNS.TO]: false,
- [CONST.SEARCH.TABLE_COLUMNS.CATEGORY]: false,
- [CONST.SEARCH.TABLE_COLUMNS.TAG]: false,
- [CONST.SEARCH.TABLE_COLUMNS.TAX_AMOUNT]: false,
- [CONST.SEARCH.TABLE_COLUMNS.TOTAL_AMOUNT]: true,
- [CONST.SEARCH.TABLE_COLUMNS.ACTION]: true,
- [CONST.SEARCH.TABLE_COLUMNS.TITLE]: true,
- [CONST.SEARCH.TABLE_COLUMNS.ASSIGNEE]: true,
- [CONST.SEARCH.TABLE_COLUMNS.IN]: true,
- };
-
- const updateColumns = (transaction: OnyxTypes.Transaction | SearchTransaction) => {
- const merchant = transaction.modifiedMerchant ? transaction.modifiedMerchant : (transaction.merchant ?? '');
- if ((merchant !== '' && merchant !== CONST.TRANSACTION.PARTIAL_TRANSACTION_MERCHANT) || isScanning(transaction)) {
- columns[CONST.REPORT.TRANSACTION_LIST.COLUMNS.MERCHANT] = true;
- }
-
- if (getDescription(transaction) !== '') {
- columns[CONST.REPORT.TRANSACTION_LIST.COLUMNS.DESCRIPTION] = true;
- }
-
- const category = getCategory(transaction);
- const categoryEmptyValues = CONST.SEARCH.CATEGORY_EMPTY_VALUE.split(',');
- if (category !== '' && !categoryEmptyValues.includes(category)) {
- columns[CONST.REPORT.TRANSACTION_LIST.COLUMNS.CATEGORY] = true;
- }
-
- const tag = getTag(transaction);
- if (tag !== '' && tag !== CONST.SEARCH.TAG_EMPTY_VALUE) {
- columns[CONST.REPORT.TRANSACTION_LIST.COLUMNS.TAG] = true;
- }
-
- if (isExpenseReportView) {
- return;
- }
-
- // Handle From&To columns that are only shown in the Reports page
- // if From or To differ from current user in any transaction, show the columns
- const accountID = (transaction as SearchTransaction).accountID;
- if (accountID !== currentAccountID) {
- columns[CONST.REPORT.TRANSACTION_LIST.COLUMNS.FROM] = true;
- }
-
- const managerID = (transaction as SearchTransaction).managerID;
- if (managerID && managerID !== currentAccountID && !columns[CONST.REPORT.TRANSACTION_LIST.COLUMNS.TO]) {
- const report = (data as OnyxTypes.SearchResults['data'])[`${ONYXKEYS.COLLECTION.REPORT}${transaction.reportID}`];
- columns[CONST.REPORT.TRANSACTION_LIST.COLUMNS.TO] = !!report && !isOpenReport(report);
- }
- };
-
- if (Array.isArray(data)) {
- data.forEach(updateColumns);
- } else {
- Object.keys(data).forEach((key) => {
- if (!isTransactionEntry(key)) {
- return;
- }
- updateColumns(data[key]);
- });
- }
-
- return columns;
-}
-
/**
* Compares two values based on a specified sorting order and column.
* Handles both string and numeric comparisons, with special handling for absolute values when sorting by total amount.
@@ -1878,7 +1774,6 @@ export {
isReportActionEntry,
isTaskListItemType,
getAction,
- getColumnsToShow,
createTypeMenuSections,
createBaseSavedSearchMenuItem,
shouldShowEmptyState,
diff --git a/src/types/onyx/SearchResults.ts b/src/types/onyx/SearchResults.ts
index 85ea2213270c..d370b62706e2 100644
--- a/src/types/onyx/SearchResults.ts
+++ b/src/types/onyx/SearchResults.ts
@@ -35,12 +35,6 @@ type ListItemDataType = C ext
/** Model of columns to show for search results */
type ColumnsToShow = {
- /** Whether the From column should be shown */
- shouldShowFromColumn: boolean;
-
- /** Whether the To column should be shown */
- shouldShowToColumn: boolean;
-
/** Whether the category column should be shown */
shouldShowCategoryColumn: boolean;
@@ -49,9 +43,6 @@ type ColumnsToShow = {
/** Whether the tax column should be shown */
shouldShowTaxColumn: boolean;
-
- /** Whether the description column should be shown */
- shouldShowDescriptionColumn: boolean;
};
/** Model of search result state */
diff --git a/tests/unit/Search/SearchUIUtilsTest.ts b/tests/unit/Search/SearchUIUtilsTest.ts
index 968c45a9fe9f..0fc08b67c39b 100644
--- a/tests/unit/Search/SearchUIUtilsTest.ts
+++ b/tests/unit/Search/SearchUIUtilsTest.ts
@@ -431,9 +431,6 @@ const searchResults: OnyxTypes.SearchResults = {
shouldShowCategoryColumn: true,
shouldShowTagColumn: false,
shouldShowTaxColumn: false,
- shouldShowFromColumn: true,
- shouldShowToColumn: true,
- shouldShowDescriptionColumn: false,
},
hasMoreResults: false,
hasResults: true,
@@ -516,13 +513,10 @@ const transactionsListItems = [
reportID: '123456789',
reportType: 'expense',
shouldShowCategory: true,
- shouldShowDescription: false,
shouldShowMerchant: true,
shouldShowTag: false,
shouldShowTax: false,
shouldShowYear: true,
- shouldShowFrom: true,
- shouldShowTo: true,
isAmountColumnWide: false,
isTaxAmountColumnWide: false,
tag: '',
@@ -587,9 +581,6 @@ const transactionsListItems = [
shouldShowTag: false,
shouldShowTax: false,
shouldShowYear: true,
- shouldShowFrom: true,
- shouldShowTo: true,
- shouldShowDescription: false,
isAmountColumnWide: false,
isTaxAmountColumnWide: false,
tag: '',
@@ -670,9 +661,6 @@ const transactionsListItems = [
shouldShowTax: false,
keyForList: '3',
shouldShowYear: true,
- shouldShowFrom: true,
- shouldShowTo: true,
- shouldShowDescription: false,
isAmountColumnWide: false,
isTaxAmountColumnWide: false,
receipt: undefined,
@@ -738,9 +726,6 @@ const transactionsListItems = [
shouldShowTax: false,
keyForList: '3',
shouldShowYear: true,
- shouldShowFrom: true,
- shouldShowTo: true,
- shouldShowDescription: false,
isAmountColumnWide: false,
isTaxAmountColumnWide: false,
receipt: undefined,
@@ -835,9 +820,6 @@ const transactionReportGroupListItems = [
shouldShowTag: false,
shouldShowTax: false,
shouldShowYear: true,
- shouldShowFrom: true,
- shouldShowTo: true,
- shouldShowDescription: false,
isAmountColumnWide: false,
isTaxAmountColumnWide: false,
tag: '',
@@ -945,9 +927,6 @@ const transactionReportGroupListItems = [
shouldShowTag: false,
shouldShowTax: false,
shouldShowYear: true,
- shouldShowFrom: true,
- shouldShowTo: true,
- shouldShowDescription: false,
isAmountColumnWide: false,
isTaxAmountColumnWide: false,
tag: '',
@@ -1609,9 +1588,6 @@ describe('SearchUIUtils', () => {
shouldShowCategoryColumn: true,
shouldShowTagColumn: true,
shouldShowTaxColumn: true,
- shouldShowFromColumn: true,
- shouldShowToColumn: true,
- shouldShowDescriptionColumn: false,
},
},
};
@@ -1654,189 +1630,4 @@ describe('SearchUIUtils', () => {
expect(isAmountLengthLong3).toBe(true);
expect(isTaxAmountLengthLong2).toBe(true);
});
-
- describe('Test getColumnsToShow', () => {
- test('Should only show columns when at least one transaction has a value for them', async () => {
- await Onyx.merge(ONYXKEYS.SESSION, {accountID: submitterAccountID});
-
- // Use the existing transaction as a base and modify only the fields we need to test
- const baseTransaction = searchResults.data[`transactions_${transactionID}`];
-
- // Create test transactions as arrays (getColumnsToShow accepts arrays)
- const emptyTransaction = {
- ...baseTransaction,
- transactionID: 'empty',
- merchant: '',
- modifiedMerchant: '',
- comment: {comment: ''},
- category: '',
- tag: '',
- accountID: submitterAccountID,
- managerID: submitterAccountID,
- };
-
- const merchantTransaction = {
- ...baseTransaction,
- transactionID: 'merchant',
- merchant: 'Test Merchant',
- modifiedMerchant: '',
- comment: {comment: ''},
- category: '',
- tag: '',
- accountID: submitterAccountID,
- managerID: submitterAccountID,
- };
-
- const categoryTransaction = {
- ...baseTransaction,
- transactionID: 'category',
- merchant: '',
- modifiedMerchant: '',
- comment: {comment: ''},
- category: 'Office Supplies',
- tag: '',
- accountID: submitterAccountID,
- managerID: submitterAccountID,
- };
-
- const tagTransaction = {
- ...baseTransaction,
- transactionID: 'tag',
- merchant: '',
- modifiedMerchant: '',
- comment: {comment: ''},
- category: '',
- tag: 'Project A',
- accountID: submitterAccountID,
- managerID: submitterAccountID,
- };
-
- const descriptionTransaction = {
- ...baseTransaction,
- transactionID: 'description',
- merchant: '',
- modifiedMerchant: '',
- comment: {comment: 'Business meeting lunch'},
- category: '',
- tag: '',
- accountID: submitterAccountID,
- managerID: submitterAccountID,
- };
-
- const differentUsersTransaction = {
- ...baseTransaction,
- transactionID: 'differentUsers',
- merchant: '',
- modifiedMerchant: '',
- comment: {comment: ''},
- category: '',
- tag: '',
- accountID: approverAccountID, // Different from current user
- managerID: adminAccountID, // Different from current user
- reportID: reportID2, // Needs to be a submitter report for 'To' to show
- };
-
- // Test 1: No optional fields should be shown when all transactions are empty
- let columns = SearchUIUtils.getColumnsToShow([emptyTransaction, emptyTransaction], false);
- expect(columns[CONST.SEARCH.TABLE_COLUMNS.MERCHANT]).toBe(false);
- expect(columns[CONST.SEARCH.TABLE_COLUMNS.CATEGORY]).toBe(false);
- expect(columns[CONST.SEARCH.TABLE_COLUMNS.TAG]).toBe(false);
- expect(columns[CONST.SEARCH.TABLE_COLUMNS.DESCRIPTION]).toBe(false);
- expect(columns[CONST.SEARCH.TABLE_COLUMNS.FROM]).toBe(false);
- expect(columns[CONST.SEARCH.TABLE_COLUMNS.TO]).toBe(false);
-
- // Test 2: Merchant column should show when at least one transaction has merchant
- columns = SearchUIUtils.getColumnsToShow([emptyTransaction, merchantTransaction], false);
- expect(columns[CONST.SEARCH.TABLE_COLUMNS.MERCHANT]).toBe(true);
- expect(columns[CONST.SEARCH.TABLE_COLUMNS.CATEGORY]).toBe(false);
-
- // Test 3: Category column should show when at least one transaction has category
- columns = SearchUIUtils.getColumnsToShow([emptyTransaction, categoryTransaction], false);
- expect(columns[CONST.SEARCH.TABLE_COLUMNS.CATEGORY]).toBe(true);
- expect(columns[CONST.SEARCH.TABLE_COLUMNS.MERCHANT]).toBe(false);
-
- // Test 4: Tag column should show when at least one transaction has tag
- columns = SearchUIUtils.getColumnsToShow([emptyTransaction, tagTransaction], false);
- expect(columns[CONST.SEARCH.TABLE_COLUMNS.TAG]).toBe(true);
- expect(columns[CONST.SEARCH.TABLE_COLUMNS.CATEGORY]).toBe(false);
-
- // Test 5: Description column should show when at least one transaction has description
- columns = SearchUIUtils.getColumnsToShow([emptyTransaction, descriptionTransaction], false);
- expect(columns[CONST.SEARCH.TABLE_COLUMNS.DESCRIPTION]).toBe(true);
- expect(columns[CONST.SEARCH.TABLE_COLUMNS.MERCHANT]).toBe(false);
-
- // Test 6: From/To columns should show when at least one transaction has different users
- // @ts-expect-error -- no need to construct all data again, the function below only needs the report and transactions
- const data: OnyxTypes.SearchResults['data'] = {
- [`report_${reportID2}`]: searchResults.data[`report_${reportID2}`],
- [`transactions_${emptyTransaction.transactionID}`]: emptyTransaction,
- [`transactions_${differentUsersTransaction.transactionID}`]: differentUsersTransaction,
- };
- columns = SearchUIUtils.getColumnsToShow(data, false);
- expect(columns[CONST.SEARCH.TABLE_COLUMNS.FROM]).toBe(true);
- expect(columns[CONST.SEARCH.TABLE_COLUMNS.TO]).toBe(true);
-
- // Test 7: Multiple columns should show when transactions have different fields
- columns = SearchUIUtils.getColumnsToShow([merchantTransaction, categoryTransaction, tagTransaction], false);
- expect(columns[CONST.SEARCH.TABLE_COLUMNS.MERCHANT]).toBe(true);
- expect(columns[CONST.SEARCH.TABLE_COLUMNS.CATEGORY]).toBe(true);
- expect(columns[CONST.SEARCH.TABLE_COLUMNS.TAG]).toBe(true);
- expect(columns[CONST.SEARCH.TABLE_COLUMNS.DESCRIPTION]).toBe(false);
- });
-
- test('Should respect isExpenseReportView flag and not show From/To columns', () => {
- // Create transaction with different users using existing transaction as base
- const baseTransaction = searchResults.data[`transactions_${transactionID}`];
- const testTransaction = {
- ...baseTransaction,
- transactionID: 'test',
- merchant: 'Test Merchant',
- modifiedMerchant: '',
- comment: {comment: 'Test description'},
- category: 'Office Supplies',
- tag: 'Project A',
- accountID: submitterAccountID, // Different from current user
- managerID: approverAccountID, // Different from current user
- };
-
- // In expense report view, From/To columns should not be shown
- const columns = SearchUIUtils.getColumnsToShow([testTransaction], true);
-
- // These columns should be shown based on data
- expect(columns[CONST.REPORT.TRANSACTION_LIST.COLUMNS.MERCHANT]).toBe(true);
- expect(columns[CONST.REPORT.TRANSACTION_LIST.COLUMNS.CATEGORY]).toBe(true);
- expect(columns[CONST.REPORT.TRANSACTION_LIST.COLUMNS.TAG]).toBe(true);
- expect(columns[CONST.REPORT.TRANSACTION_LIST.COLUMNS.DESCRIPTION]).toBe(true);
-
- // From/To columns should not exist in expense report view
- expect(columns[CONST.SEARCH.TABLE_COLUMNS.FROM]).toBeUndefined();
- expect(columns[CONST.SEARCH.TABLE_COLUMNS.TO]).toBeUndefined();
- });
-
- test('Should handle modifiedMerchant and empty category/tag values correctly', () => {
- const baseTransaction = searchResults.data[`transactions_${transactionID}`];
- const testTransaction = {
- ...baseTransaction,
- transactionID: 'modified',
- merchant: '',
- modifiedMerchant: 'Modified Merchant',
- comment: {comment: ''},
- category: 'Uncategorized', // This is in CONST.SEARCH.CATEGORY_EMPTY_VALUE
- tag: CONST.SEARCH.TAG_EMPTY_VALUE, // This is the empty tag value
- accountID: adminAccountID,
- managerID: adminAccountID,
- };
-
- const columns = SearchUIUtils.getColumnsToShow([testTransaction], false);
-
- // Should show merchant column because modifiedMerchant has value
- expect(columns[CONST.SEARCH.TABLE_COLUMNS.MERCHANT]).toBe(true);
-
- // Should not show category column because 'Uncategorized' is an empty value
- expect(columns[CONST.SEARCH.TABLE_COLUMNS.CATEGORY]).toBe(false);
-
- // Should not show tag column because it's the empty tag value
- expect(columns[CONST.SEARCH.TABLE_COLUMNS.TAG]).toBe(false);
- });
- });
});
diff --git a/tests/unit/Search/handleActionButtonPressTest.ts b/tests/unit/Search/handleActionButtonPressTest.ts
index 0c1902165a85..7a9e48a280cf 100644
--- a/tests/unit/Search/handleActionButtonPressTest.ts
+++ b/tests/unit/Search/handleActionButtonPressTest.ts
@@ -193,9 +193,6 @@ const mockReportItemWithHold = {
shouldShowCategory: true,
shouldShowTag: false,
shouldShowTax: false,
- shouldShowTo: true,
- shouldShowFrom: true,
- shouldShowDescription: false,
keyForList: '5345995386715609966',
shouldShowYear: false,
isAmountColumnWide: false,
diff --git a/tests/unit/useSearchHighlightAndScrollTest.ts b/tests/unit/useSearchHighlightAndScrollTest.ts
index 832d4e696c4e..e42d23c65f3c 100644
--- a/tests/unit/useSearchHighlightAndScrollTest.ts
+++ b/tests/unit/useSearchHighlightAndScrollTest.ts
@@ -36,14 +36,7 @@ describe('useSearchHighlightAndScroll', () => {
personalDetailsList: {},
},
search: {
- columnsToShow: {
- shouldShowCategoryColumn: true,
- shouldShowTagColumn: true,
- shouldShowTaxColumn: true,
- shouldShowToColumn: true,
- shouldShowFromColumn: true,
- shouldShowDescriptionColumn: true,
- },
+ columnsToShow: {shouldShowCategoryColumn: true, shouldShowTagColumn: true, shouldShowTaxColumn: true},
hasMoreResults: false,
hasResults: true,
offset: 0,