diff --git a/src/CONST.ts b/src/CONST.ts index aa3ade14b040c..96aca66ee4251 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -937,7 +937,7 @@ const CONST = { TO: 'to', CATEGORY: 'category', TAG: 'tag', - TOTAL: 'total', + TOTAL_AMOUNT: 'amount', TYPE: 'type', ACTION: 'action', TAX_AMOUNT: 'taxAmount', diff --git a/src/components/Search.tsx b/src/components/Search.tsx index fcb9153791819..2ae13fb7bd58b 100644 --- a/src/components/Search.tsx +++ b/src/components/Search.tsx @@ -32,6 +32,8 @@ type SearchProps = { sortOrder?: SortOrder; }; +const sortableSearchTabs: SearchQuery[] = [CONST.TAB_SEARCH.ALL]; + function isReportListItemType(item: TransactionListItemType | ReportListItemType): item is ReportListItemType { const reportListItem = item as ReportListItemType; return reportListItem.transactions !== undefined; @@ -100,6 +102,7 @@ function Search({query, policyIDs, sortBy, sortOrder}: SearchProps) { const ListItem = SearchUtils.getListItem(type); const data = SearchUtils.getSections(searchResults?.data ?? {}, type); + const sortedData = SearchUtils.getSortedSections(type, data, sortBy, sortOrder); const onSortPress = (column: SearchColumnType, order: SortOrder) => { navigation.setParams({ @@ -108,7 +111,7 @@ function Search({query, policyIDs, sortBy, sortOrder}: SearchProps) { }); }; - const sortedData = SearchUtils.getSortedSections(type, data, sortBy, sortOrder); + const isSortingAllowed = sortableSearchTabs.includes(query); return ( @@ -117,6 +120,7 @@ function Search({query, policyIDs, sortBy, sortOrder}: SearchProps) { data={searchResults?.data} onSortPress={onSortPress} sortOrder={sortOrder} + isSortingAllowed={isSortingAllowed} sortBy={sortBy} /> } diff --git a/src/components/SelectionList/Search/TransactionListItemRow.tsx b/src/components/SelectionList/Search/TransactionListItemRow.tsx index cb1ef3fdc6e1c..2b32706c98f65 100644 --- a/src/components/SelectionList/Search/TransactionListItemRow.tsx +++ b/src/components/SelectionList/Search/TransactionListItemRow.tsx @@ -362,7 +362,7 @@ function TransactionListItemRow({item, showTooltip, onButtonPress, showItemHeade )} - + boolean; }; @@ -23,7 +23,7 @@ const SearchColumns: SearchColumnConfig[] = [ columnName: CONST.SEARCH_TABLE_COLUMNS.RECEIPT, translationKey: 'common.receipt', shouldShow: () => true, - isSortable: false, + isColumnSortable: false, }, { columnName: CONST.SEARCH_TABLE_COLUMNS.DATE, @@ -66,7 +66,7 @@ const SearchColumns: SearchColumnConfig[] = [ shouldShow: (data: OnyxTypes.SearchResults['data']) => SearchUtils.getShouldShowColumn(data, CONST.SEARCH_TABLE_COLUMNS.TAX_AMOUNT), }, { - columnName: CONST.SEARCH_TABLE_COLUMNS.TOTAL, + columnName: CONST.SEARCH_TABLE_COLUMNS.TOTAL_AMOUNT, translationKey: 'common.total', shouldShow: () => true, }, @@ -74,11 +74,13 @@ const SearchColumns: SearchColumnConfig[] = [ columnName: CONST.SEARCH_TABLE_COLUMNS.TYPE, translationKey: 'common.type', shouldShow: () => true, + isColumnSortable: false, }, { columnName: CONST.SEARCH_TABLE_COLUMNS.ACTION, translationKey: 'common.action', shouldShow: () => true, + isColumnSortable: false, }, ]; @@ -86,10 +88,11 @@ type SearchTableHeaderProps = { data: OnyxTypes.SearchResults['data']; sortBy?: SearchColumnType; sortOrder?: SortOrder; + isSortingAllowed: boolean; onSortPress: (column: SearchColumnType, order: SortOrder) => void; }; -function SearchTableHeader({data, sortBy, sortOrder, onSortPress}: SearchTableHeaderProps) { +function SearchTableHeader({data, sortBy, sortOrder, isSortingAllowed, onSortPress}: SearchTableHeaderProps) { const styles = useThemeStyles(); const StyleUtils = useStyleUtils(); const {isSmallScreenWidth, isMediumScreenWidth} = useWindowDimensions(); @@ -103,9 +106,14 @@ function SearchTableHeader({data, sortBy, sortOrder, onSortPress}: SearchTableHe return ( - {SearchColumns.map(({columnName, translationKey, shouldShow, isSortable}) => { + {SearchColumns.map(({columnName, translationKey, shouldShow, isColumnSortable}) => { + if (!shouldShow(data)) { + return null; + } + const isActive = sortBy === columnName; const textStyle = columnName === CONST.SEARCH_TABLE_COLUMNS.RECEIPT ? StyleUtils.getTextOverflowStyle('clip') : null; + const isSortable = isSortingAllowed && isColumnSortable; return ( onSortPress(columnName, order)} /> diff --git a/src/components/SelectionList/SortableHeaderText.tsx b/src/components/SelectionList/SortableHeaderText.tsx index d84d438b3749e..bd5f4873bbbc7 100644 --- a/src/components/SelectionList/SortableHeaderText.tsx +++ b/src/components/SelectionList/SortableHeaderText.tsx @@ -14,23 +14,34 @@ type SearchTableHeaderColumnProps = { text: string; isActive: boolean; sortOrder: SortOrder; - shouldShow?: boolean; isSortable?: boolean; containerStyle?: StyleProp; textStyle?: StyleProp; onPress: (order: SortOrder) => void; }; -export default function SortableHeaderText({text, sortOrder, isActive, textStyle, containerStyle, shouldShow = true, isSortable = true, onPress}: SearchTableHeaderColumnProps) { +export default function SortableHeaderText({text, sortOrder, isActive, textStyle, containerStyle, isSortable = true, onPress}: SearchTableHeaderColumnProps) { const styles = useThemeStyles(); const theme = useTheme(); - if (!shouldShow) { - return null; + if (!isSortable) { + return ( + + + + {text} + + + + ); } const icon = sortOrder === CONST.SORT_ORDER.ASC ? Expensicons.ArrowUpLong : Expensicons.ArrowDownLong; const displayIcon = isActive; + const activeColumnStyle = isSortable && isActive && styles.searchTableHeaderActive; const nextSortOrder = isActive && sortOrder === CONST.SORT_ORDER.DESC ? CONST.SORT_ORDER.ASC : CONST.SORT_ORDER.DESC; @@ -46,7 +57,7 @@ export default function SortableHeaderText({text, sortOrder, isActive, textStyle {text} diff --git a/src/libs/SearchUtils.ts b/src/libs/SearchUtils.ts index c1f4de2e5e353..6d0b9ab086745 100644 --- a/src/libs/SearchUtils.ts +++ b/src/libs/SearchUtils.ts @@ -5,7 +5,7 @@ import type {ReportListItemType, TransactionListItemType} from '@components/Sele import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import type * as OnyxTypes from '@src/types/onyx'; -import type {SearchAccountDetails, SearchDataTypes, SearchTypeToItemMap, SectionsType} from '@src/types/onyx/SearchResults'; +import type {SearchAccountDetails, SearchDataTypes, SearchPersonalDetails, SearchTransaction, SearchTypeToItemMap, SectionsType} from '@src/types/onyx/SearchResults'; import getTopmostCentralPaneRoute from './Navigation/getTopmostCentralPaneRoute'; import navigationRef from './Navigation/navigationRef'; import type {RootStackParamList, State} from './Navigation/types'; @@ -21,7 +21,7 @@ const columnNamesToSortingProperty = { [CONST.SEARCH_TABLE_COLUMNS.DATE]: 'date' as const, [CONST.SEARCH_TABLE_COLUMNS.TAG]: 'tag' as const, [CONST.SEARCH_TABLE_COLUMNS.MERCHANT]: 'formattedMerchant' as const, - [CONST.SEARCH_TABLE_COLUMNS.TOTAL]: 'formattedTotal' as const, + [CONST.SEARCH_TABLE_COLUMNS.TOTAL_AMOUNT]: 'formattedTotal' as const, [CONST.SEARCH_TABLE_COLUMNS.CATEGORY]: 'category' as const, [CONST.SEARCH_TABLE_COLUMNS.TYPE]: 'type' as const, [CONST.SEARCH_TABLE_COLUMNS.ACTION]: 'action' as const, @@ -30,6 +30,32 @@ const columnNamesToSortingProperty = { [CONST.SEARCH_TABLE_COLUMNS.RECEIPT]: null, }; +/** + * @private + */ +function getTransactionItemCommonFormattedProperties( + transactionItem: SearchTransaction, + from: SearchPersonalDetails, + to: SearchAccountDetails, +): Pick { + const isExpenseReport = transactionItem.reportType === CONST.REPORT.TYPE.EXPENSE; + + const formattedFrom = from?.displayName ?? from?.login ?? ''; + const formattedTo = to?.name ?? to?.displayName ?? to?.login ?? ''; + const formattedTotal = TransactionUtils.getAmount(transactionItem, isExpenseReport); + const date = transactionItem?.modifiedCreated ? transactionItem.modifiedCreated : transactionItem?.created; + const merchant = TransactionUtils.getMerchant(transactionItem); + const formattedMerchant = merchant === CONST.TRANSACTION.PARTIAL_TRANSACTION_MERCHANT || merchant === CONST.TRANSACTION.DEFAULT_MERCHANT ? '' : merchant; + + return { + formattedFrom, + formattedTo, + date, + formattedTotal, + formattedMerchant, + }; +} + function isSearchDataType(type: string): type is SearchDataTypes { const searchDataTypes: string[] = Object.values(CONST.SEARCH_DATA_TYPES); return searchDataTypes.includes(type); @@ -69,12 +95,7 @@ function getTransactionsSections(data: OnyxTypes.SearchResults['data']): Transac ? (data[`${ONYXKEYS.COLLECTION.POLICY}${transactionItem.policyID}`] as SearchAccountDetails) : (data.personalDetailsList?.[transactionItem.managerID] as SearchAccountDetails); - const formattedFrom = from.displayName ?? from.login ?? ''; - const formattedTo = to?.name ?? to?.displayName ?? to?.login ?? ''; - const formattedTotal = TransactionUtils.getAmount(transactionItem, isExpenseReport); - const date = transactionItem?.modifiedCreated ? transactionItem.modifiedCreated : transactionItem?.created; - const merchant = TransactionUtils.getMerchant(transactionItem); - const formattedMerchant = merchant === CONST.TRANSACTION.PARTIAL_TRANSACTION_MERCHANT || merchant === CONST.TRANSACTION.DEFAULT_MERCHANT ? '' : merchant; + const {formattedFrom, formattedTo, formattedTotal, formattedMerchant, date} = getTransactionItemCommonFormattedProperties(transactionItem, from, to); return { ...transactionItem, @@ -82,9 +103,9 @@ function getTransactionsSections(data: OnyxTypes.SearchResults['data']): Transac to, formattedFrom, formattedTo, - date, formattedTotal, formattedMerchant, + date, shouldShowMerchant, shouldShowCategory, shouldShowTag, @@ -119,12 +140,7 @@ function getReportSections(data: OnyxTypes.SearchResults['data']): ReportListIte ? (data[`${ONYXKEYS.COLLECTION.POLICY}${transactionItem.policyID}`] as SearchAccountDetails) : (data.personalDetailsList?.[transactionItem.managerID] as SearchAccountDetails); - const formattedFrom = from.displayName ?? from.login ?? ''; - const formattedTo = to?.name ?? to?.displayName ?? to?.login ?? ''; - const formattedTotal = TransactionUtils.getAmount(transactionItem, isExpenseReport); - const date = transactionItem?.modifiedCreated ? transactionItem.modifiedCreated : transactionItem?.created; - const merchant = TransactionUtils.getMerchant(transactionItem); - const formattedMerchant = merchant === CONST.TRANSACTION.PARTIAL_TRANSACTION_MERCHANT || merchant === CONST.TRANSACTION.DEFAULT_MERCHANT ? '' : merchant; + const {formattedFrom, formattedTo, formattedTotal, formattedMerchant, date} = getTransactionItemCommonFormattedProperties(transactionItem, from, to); const transaction = { ...transactionItem, @@ -133,8 +149,8 @@ function getReportSections(data: OnyxTypes.SearchResults['data']): ReportListIte formattedFrom, formattedTo, formattedTotal, - date, formattedMerchant, + date, shouldShowMerchant, shouldShowCategory, shouldShowTag, diff --git a/src/styles/utils/index.ts b/src/styles/utils/index.ts index 82602efa88b3a..7fcd30bb19e28 100644 --- a/src/styles/utils/index.ts +++ b/src/styles/utils/index.ts @@ -1568,12 +1568,14 @@ const createStyleUtils = (theme: ThemeColors, styles: ThemeStyles) => ({ case CONST.SEARCH_TABLE_COLUMNS.MERCHANT: case CONST.SEARCH_TABLE_COLUMNS.FROM: case CONST.SEARCH_TABLE_COLUMNS.TO: + columnWidth = styles.flex1; + break; case CONST.SEARCH_TABLE_COLUMNS.CATEGORY: case CONST.SEARCH_TABLE_COLUMNS.TAG: - columnWidth = styles.flex1; + columnWidth = {...getWidthStyle(variables.w36), ...styles.flex1}; break; case CONST.SEARCH_TABLE_COLUMNS.TAX_AMOUNT: - case CONST.SEARCH_TABLE_COLUMNS.TOTAL: + case CONST.SEARCH_TABLE_COLUMNS.TOTAL_AMOUNT: columnWidth = {...getWidthStyle(variables.w96), ...styles.alignItemsEnd}; break; case CONST.SEARCH_TABLE_COLUMNS.TYPE: