diff --git a/src/CONST/index.ts b/src/CONST/index.ts index 8b3c9c669e8c..f88ade495d2f 100755 --- a/src/CONST/index.ts +++ b/src/CONST/index.ts @@ -6695,6 +6695,7 @@ const CONST = { TO: this.TABLE_COLUMNS.TO, CATEGORY: this.TABLE_COLUMNS.CATEGORY, TAG: this.TABLE_COLUMNS.TAG, + STATUS: this.TABLE_COLUMNS.STATUS, ACTION: this.TABLE_COLUMNS.ACTION, }, EXPENSE_REPORT: { diff --git a/src/components/MoneyRequestReportView/MoneyRequestReportNavigation.tsx b/src/components/MoneyRequestReportView/MoneyRequestReportNavigation.tsx index 9943ce4f6c16..e6dbc7b1a140 100644 --- a/src/components/MoneyRequestReportView/MoneyRequestReportNavigation.tsx +++ b/src/components/MoneyRequestReportView/MoneyRequestReportNavigation.tsx @@ -25,7 +25,7 @@ function MoneyRequestReportNavigation({reportID, shouldDisplayNarrowVersion}: Mo const [lastSearchQuery] = useOnyx(ONYXKEYS.REPORT_NAVIGATION_LAST_SEARCH_QUERY, {canBeMissing: true}); const [currentSearchResults] = useOnyx(`${ONYXKEYS.COLLECTION.SNAPSHOT}${lastSearchQuery?.queryJSON?.hash}`, {canBeMissing: true}); const currentUserDetails = useCurrentUserPersonalDetails(); - const {localeCompare, formatPhoneNumber} = useLocalize(); + const {localeCompare, formatPhoneNumber, translate} = useLocalize(); const [isActionLoadingSet = new Set()] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT_METADATA}`, {canBeMissing: true, selector: isActionLoadingSetSelector}); const [exportReportActions] = useOnyx(ONYXKEYS.COLLECTION.REPORT_ACTIONS, { @@ -51,7 +51,7 @@ function MoneyRequestReportNavigation({reportID, shouldDisplayNarrowVersion}: Mo archivedReportsIDList: archivedReportsIdSet, isActionLoadingSet, }); - results = getSortedSections(type, status ?? '', searchData, localeCompare, sortBy, sortOrder, groupBy).map((value) => value.reportID); + results = getSortedSections(type, status ?? '', searchData, localeCompare, translate, sortBy, sortOrder, groupBy).map((value) => value.reportID); } const allReports = results; diff --git a/src/components/Search/index.tsx b/src/components/Search/index.tsx index 7df17422c8d3..954b57365e28 100644 --- a/src/components/Search/index.tsx +++ b/src/components/Search/index.tsx @@ -863,7 +863,7 @@ function Search({ const sortedSelectedData = useMemo( () => - getSortedSections(type, status, filteredData, localeCompare, sortBy, sortOrder, validGroupBy).map((item) => { + getSortedSections(type, status, filteredData, localeCompare, translate, sortBy, sortOrder, validGroupBy).map((item) => { const baseKey = isChat ? `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${(item as ReportActionListItemType).reportActionID}` : `${ONYXKEYS.COLLECTION.TRANSACTION}${(item as TransactionListItemType).transactionID}`; @@ -884,7 +884,7 @@ function Search({ return mapToItemWithAdditionalInfo(item, selectedTransactions, canSelectMultiple, shouldAnimateInHighlight, hash); }), - [type, status, filteredData, sortBy, sortOrder, validGroupBy, isChat, newSearchResultKeys, selectedTransactions, canSelectMultiple, localeCompare, hash], + [type, status, filteredData, localeCompare, translate, sortBy, sortOrder, validGroupBy, isChat, newSearchResultKeys, selectedTransactions, canSelectMultiple, hash], ); useEffect(() => { diff --git a/src/components/SelectionListWithSections/SearchTableHeader.tsx b/src/components/SelectionListWithSections/SearchTableHeader.tsx index 5e988d208aad..250a13725754 100644 --- a/src/components/SelectionListWithSections/SearchTableHeader.tsx +++ b/src/components/SelectionListWithSections/SearchTableHeader.tsx @@ -90,6 +90,11 @@ const getExpenseHeaders = (groupBy?: SearchGroupBy): SearchColumnConfig[] => [ columnName: CONST.SEARCH.TABLE_COLUMNS.TOTAL_AMOUNT, translationKey: groupBy ? 'common.total' : 'iou.amount', }, + { + columnName: CONST.SEARCH.TABLE_COLUMNS.STATUS, + translationKey: 'common.status', + canBeMissing: false, + }, { columnName: CONST.SEARCH.TABLE_COLUMNS.ACTION, translationKey: 'common.action', diff --git a/src/components/TransactionItemRow/index.tsx b/src/components/TransactionItemRow/index.tsx index 000cfd4d0f85..6753c6741a92 100644 --- a/src/components/TransactionItemRow/index.tsx +++ b/src/components/TransactionItemRow/index.tsx @@ -9,6 +9,7 @@ import RadioButton from '@components/RadioButton'; import type {SearchColumnType, TableColumnSize} from '@components/Search/types'; import ActionCell from '@components/SelectionListWithSections/Search/ActionCell'; import DateCell from '@components/SelectionListWithSections/Search/DateCell'; +import StatusCell from '@components/SelectionListWithSections/Search/StatusCell'; import UserInfoCell from '@components/SelectionListWithSections/Search/UserInfoCell'; import Text from '@components/Text'; import {useMemoizedLazyExpensifyIcons} from '@hooks/useLazyAsset'; @@ -407,6 +408,14 @@ function TransactionItemRow({ /> ), + [CONST.SEARCH.TABLE_COLUMNS.STATUS]: ( + + + + ), }), [ StyleUtils, diff --git a/src/libs/SearchUIUtils.ts b/src/libs/SearchUIUtils.ts index d2fb521c205d..74a28b420246 100644 --- a/src/libs/SearchUIUtils.ts +++ b/src/libs/SearchUIUtils.ts @@ -1917,6 +1917,7 @@ function getSortedSections( status: SearchStatus, data: ListItemDataType, localeCompare: LocaleContextProps['localeCompare'], + translate: LocaleContextProps['translate'], sortBy?: SearchColumnType, sortOrder?: SortOrder, groupBy?: SearchGroupBy, @@ -1928,7 +1929,7 @@ function getSortedSections( return getSortedTaskData(data as TaskListItemType[], localeCompare, sortBy, sortOrder); } if (type === CONST.SEARCH.DATA_TYPES.EXPENSE_REPORT) { - return getSortedReportData(data as TransactionReportGroupListItemType[], localeCompare, sortBy, sortOrder); + return getSortedReportData(data as TransactionReportGroupListItemType[], localeCompare, translate, sortBy, sortOrder); } if (groupBy) { @@ -1944,7 +1945,7 @@ function getSortedSections( } } - return getSortedTransactionData(data as TransactionListItemType[], localeCompare, sortBy, sortOrder); + return getSortedTransactionData(data as TransactionListItemType[], localeCompare, translate, sortBy, sortOrder); } /** @@ -1985,13 +1986,34 @@ function compareValues(a: unknown, b: unknown, sortOrder: SortOrder, sortBy: str * @private * Sorts transaction sections based on a specified column and sort order. */ -function getSortedTransactionData(data: TransactionListItemType[], localeCompare: LocaleContextProps['localeCompare'], sortBy?: SearchColumnType, sortOrder?: SortOrder) { +function getSortedTransactionData( + data: TransactionListItemType[], + localeCompare: LocaleContextProps['localeCompare'], + translate: LocaleContextProps['translate'], + sortBy?: SearchColumnType, + sortOrder?: SortOrder, +) { if (!sortBy || !sortOrder) { return data; } const sortingProperty = transactionColumnNamesToSortingProperty[sortBy]; + if (sortBy === CONST.SEARCH.TABLE_COLUMNS.STATUS) { + return data.sort((a, b) => { + const aReport = a.report; + const bReport = b.report; + + if (!aReport || !bReport) { + return 0; + } + + const aValue = getReportStatusTranslation({stateNum: aReport.stateNum, statusNum: aReport.statusNum, translate}); + const bValue = getReportStatusTranslation({stateNum: bReport.stateNum, statusNum: bReport.statusNum, translate}); + return compareValues(aValue, bValue, sortOrder, sortBy, localeCompare); + }); + } + if (!sortingProperty) { return data; } @@ -2027,9 +2049,15 @@ function getSortedTaskData(data: TaskListItemType[], localeCompare: LocaleContex * @private * Sorts report sections based on a specified column and sort order. */ -function getSortedReportData(data: TransactionReportGroupListItemType[], localeCompare: LocaleContextProps['localeCompare'], sortBy?: SearchColumnType, sortOrder?: SortOrder) { +function getSortedReportData( + data: TransactionReportGroupListItemType[], + localeCompare: LocaleContextProps['localeCompare'], + translate: LocaleContextProps['translate'], + sortBy?: SearchColumnType, + sortOrder?: SortOrder, +) { for (const report of data) { - report.transactions = getSortedTransactionData(report.transactions, localeCompare, CONST.SEARCH.TABLE_COLUMNS.DATE, CONST.SEARCH.SORT_ORDER.DESC); + report.transactions = getSortedTransactionData(report.transactions, localeCompare, translate, CONST.SEARCH.TABLE_COLUMNS.DATE, CONST.SEARCH.SORT_ORDER.DESC); } if (!sortBy || !sortOrder) { @@ -2659,6 +2687,7 @@ function getColumnsToShow( [CONST.SEARCH.TABLE_COLUMNS.TAG]: false, [CONST.SEARCH.TABLE_COLUMNS.TAX_AMOUNT]: false, [CONST.SEARCH.TABLE_COLUMNS.TOTAL_AMOUNT]: true, + [CONST.SEARCH.TABLE_COLUMNS.STATUS]: false, [CONST.SEARCH.TABLE_COLUMNS.ACTION]: true, [CONST.SEARCH.TABLE_COLUMNS.TITLE]: true, }; diff --git a/tests/unit/Search/SearchUIUtilsTest.ts b/tests/unit/Search/SearchUIUtilsTest.ts index a74629224e10..eb264aee0db2 100644 --- a/tests/unit/Search/SearchUIUtilsTest.ts +++ b/tests/unit/Search/SearchUIUtilsTest.ts @@ -34,7 +34,7 @@ import type * as OnyxTypes from '@src/types/onyx'; import type {Connections} from '@src/types/onyx/Policy'; import type {SearchDataTypes} from '@src/types/onyx/SearchResults'; import getOnyxValue from '../../utils/getOnyxValue'; -import {formatPhoneNumber, localeCompare} from '../../utils/TestHelper'; +import {formatPhoneNumber, localeCompare, translateLocal} from '../../utils/TestHelper'; import waitForBatchedUpdates from '../../utils/waitForBatchedUpdates'; jest.mock('@src/components/ConfirmedRoute.tsx'); @@ -2022,6 +2022,7 @@ describe('SearchUIUtils', () => { CONST.SEARCH.STATUS.EXPENSE.ALL, reportActionListItems, localeCompare, + translateLocal, ) as ReportActionListItemType[]; // Should return all report actions sorted by creation date in descending order (newest first) expect(sortedActions).toHaveLength(5); @@ -2030,36 +2031,47 @@ describe('SearchUIUtils', () => { }); it('should return getSortedTransactionData result when groupBy is undefined', () => { - expect(SearchUIUtils.getSortedSections(CONST.SEARCH.DATA_TYPES.EXPENSE, '', transactionsListItems, localeCompare, 'date', 'asc', undefined)).toStrictEqual(transactionsListItems); + expect(SearchUIUtils.getSortedSections(CONST.SEARCH.DATA_TYPES.EXPENSE, '', transactionsListItems, localeCompare, translateLocal, 'date', 'asc', undefined)).toStrictEqual( + transactionsListItems, + ); }); it('should return getSortedReportData result when type is expense-report', () => { - expect(SearchUIUtils.getSortedSections(CONST.SEARCH.DATA_TYPES.EXPENSE_REPORT, '', transactionReportGroupListItems, localeCompare, 'date', 'asc')).toStrictEqual( + expect(SearchUIUtils.getSortedSections(CONST.SEARCH.DATA_TYPES.EXPENSE_REPORT, '', transactionReportGroupListItems, localeCompare, translateLocal, 'date', 'asc')).toStrictEqual( transactionReportGroupListItems, ); }); it('should return getSortedReportData result when type is TRIP and groupBy is report', () => { - expect(SearchUIUtils.getSortedSections(CONST.SEARCH.DATA_TYPES.TRIP, '', transactionReportGroupListItems, localeCompare, 'date', 'asc')).toStrictEqual( + expect(SearchUIUtils.getSortedSections(CONST.SEARCH.DATA_TYPES.TRIP, '', transactionReportGroupListItems, localeCompare, translateLocal, 'date', 'asc')).toStrictEqual( transactionReportGroupListItems, ); }); it('should return getSortedReportData result when type is INVOICE and groupBy is report', () => { - expect(SearchUIUtils.getSortedSections(CONST.SEARCH.DATA_TYPES.INVOICE, '', transactionReportGroupListItems, localeCompare, 'date', 'asc')).toStrictEqual( + expect(SearchUIUtils.getSortedSections(CONST.SEARCH.DATA_TYPES.INVOICE, '', transactionReportGroupListItems, localeCompare, translateLocal, 'date', 'asc')).toStrictEqual( transactionReportGroupListItems, ); }); it('should return getSortedMemberData result when type is EXPENSE and groupBy is member', () => { expect( - SearchUIUtils.getSortedSections(CONST.SEARCH.DATA_TYPES.EXPENSE, '', transactionMemberGroupListItems, localeCompare, 'date', 'asc', CONST.SEARCH.GROUP_BY.FROM), + SearchUIUtils.getSortedSections( + CONST.SEARCH.DATA_TYPES.EXPENSE, + '', + transactionMemberGroupListItems, + localeCompare, + translateLocal, + 'date', + 'asc', + CONST.SEARCH.GROUP_BY.FROM, + ), ).toStrictEqual(transactionMemberGroupListItemsSorted); }); it('should return getSortedCardData result when type is EXPENSE and groupBy is card', () => { expect( - SearchUIUtils.getSortedSections(CONST.SEARCH.DATA_TYPES.EXPENSE, '', transactionCardGroupListItems, localeCompare, 'date', 'asc', CONST.SEARCH.GROUP_BY.CARD), + SearchUIUtils.getSortedSections(CONST.SEARCH.DATA_TYPES.EXPENSE, '', transactionCardGroupListItems, localeCompare, translateLocal, 'date', 'asc', CONST.SEARCH.GROUP_BY.CARD), ).toStrictEqual(transactionCardGroupListItemsSorted); }); @@ -2070,6 +2082,7 @@ describe('SearchUIUtils', () => { '', transactionWithdrawalIDGroupListItems, localeCompare, + translateLocal, 'date', 'asc', CONST.SEARCH.GROUP_BY.WITHDRAWAL_ID,