Skip to content

Commit

Permalink
Make sorting work for every Search column
Browse files Browse the repository at this point in the history
  • Loading branch information
Kicu committed May 20, 2024
1 parent 031fe03 commit 6e379da
Show file tree
Hide file tree
Showing 5 changed files with 59 additions and 31 deletions.
25 changes: 13 additions & 12 deletions src/components/Search.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,13 @@ import type {TransactionListItemType} from './SelectionList/types';
import TableListItemSkeleton from './Skeletons/TableListItemSkeleton';

const columnNamesToPropertyMap = {
[CONST.SEARCH_TABLE_COLUMNS.TO]: 'to',
[CONST.SEARCH_TABLE_COLUMNS.FROM]: 'from',
[CONST.SEARCH_TABLE_COLUMNS.DATE]: 'created',
[CONST.SEARCH_TABLE_COLUMNS.TAG]: '',
[CONST.SEARCH_TABLE_COLUMNS.MERCHANT]: 'merchant',
[CONST.SEARCH_TABLE_COLUMNS.TOTAL]: 'amount',
[CONST.SEARCH_TABLE_COLUMNS.CATEGORY]: 'category',
[CONST.SEARCH_TABLE_COLUMNS.TO]: 'formattedTo' as const,
[CONST.SEARCH_TABLE_COLUMNS.FROM]: 'formattedFrom' as const,
[CONST.SEARCH_TABLE_COLUMNS.DATE]: 'date' as const,
[CONST.SEARCH_TABLE_COLUMNS.TAG]: 'tag' as const,
[CONST.SEARCH_TABLE_COLUMNS.MERCHANT]: 'merchant' as const,
[CONST.SEARCH_TABLE_COLUMNS.TOTAL]: 'formattedTotal' as const,
[CONST.SEARCH_TABLE_COLUMNS.CATEGORY]: 'category' as const,
[CONST.SEARCH_TABLE_COLUMNS.TYPE]: null,
[CONST.SEARCH_TABLE_COLUMNS.ACTION]: null,
[CONST.SEARCH_TABLE_COLUMNS.DESCRIPTION]: null,
Expand All @@ -43,13 +43,12 @@ function getSortedData(data: TransactionListItemType[], sortBy?: SearchColumnTyp
return data;
}

const sortingProp = columnNamesToPropertyMap[sortBy] as keyof TransactionListItemType;
const sortingProp = columnNamesToPropertyMap[sortBy];

if (!sortingProp) {
return data;
}

// Todo sorting needs more work
return data.sort((a, b) => {
const aValue = a[sortingProp];
const bValue = b[sortingProp];
Expand All @@ -58,13 +57,15 @@ function getSortedData(data: TransactionListItemType[], sortBy?: SearchColumnTyp
return 0;
}

// We are guaranteed that both a and b will be string or number at the same time
if (typeof aValue === 'string' && typeof bValue === 'string') {
return sortOrder === 'asc' ? aValue.toLowerCase().localeCompare(bValue) : bValue.toLowerCase().localeCompare(aValue);
}

// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-expect-error
return sortOrder === 'asc' ? aValue - bValue : bValue - aValue;
const aNum = aValue as number;
const bNum = bValue as number;

return sortOrder === 'asc' ? aNum - bNum : bNum - aNum;
});
}

Expand Down
1 change: 1 addition & 0 deletions src/components/SelectionList/SearchTableHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ const SearchColumns: SearchColumnConfig[] = [
{
columnName: CONST.SEARCH_TABLE_COLUMNS.TYPE,
translationKey: 'common.type',
isSortable: false,
shouldShowFn: () => true,
},
{
Expand Down
22 changes: 10 additions & 12 deletions src/components/SelectionList/TransactionListItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,11 +60,10 @@ function TransactionListItem<TItem extends ListItem>({
}

const isFromExpenseReport = transactionItem.reportType === CONST.REPORT.TYPE.EXPENSE;
const date = TransactionUtils.getCreated(transactionItem as OnyxEntry<Transaction>, CONST.DATE.MONTH_DAY_ABBR_FORMAT);
const amount = TransactionUtils.getAmount(transactionItem as OnyxEntry<Transaction>, isFromExpenseReport);
const taxAmount = TransactionUtils.getTaxAmount(transactionItem as OnyxEntry<Transaction>, isFromExpenseReport);
const currency = TransactionUtils.getCurrency(transactionItem as OnyxEntry<Transaction>);
const description = TransactionUtils.getDescription(transactionItem as OnyxEntry<Transaction>);
const date = TransactionUtils.getCreated(transactionItem, CONST.DATE.MONTH_DAY_ABBR_FORMAT);
const taxAmount = TransactionUtils.getTaxAmount(transactionItem, isFromExpenseReport);
const currency = TransactionUtils.getCurrency(transactionItem);
const description = TransactionUtils.getDescription(transactionItem);
const merchant = getMerchant();
const typeIcon = getTypeIcon(transactionItem.type);

Expand All @@ -84,8 +83,7 @@ function TransactionListItem<TItem extends ListItem>({
/>
);

const userCell = (participant: SearchAccountDetails) => {
const displayName = participant?.name ?? participant?.displayName ?? participant?.login;
const userCell = (participant: SearchAccountDetails, displayName: string) => {
const avatarURL = participant?.avatarURL ?? participant?.avatar;
const isWorkspace = participant?.avatarURL !== undefined;
const iconType = isWorkspace ? CONST.ICON_TYPE_WORKSPACE : CONST.ICON_TYPE_AVATAR;
Expand Down Expand Up @@ -149,7 +147,7 @@ function TransactionListItem<TItem extends ListItem>({
const totalCell = (
<TextWithTooltip
shouldShowTooltip={showTooltip}
text={CurrencyUtils.convertToDisplayString(amount, currency)}
text={CurrencyUtils.convertToDisplayString(transactionItem.formattedTotal, currency)}
style={[styles.optionDisplayName, styles.textNewKansasNormal, styles.pre, styles.justifyContentCenter, isLargeScreenWidth ? undefined : styles.textAlignRight]}
/>
);
Expand Down Expand Up @@ -202,14 +200,14 @@ function TransactionListItem<TItem extends ListItem>({
<>
<View style={[styles.flex1, styles.flexRow, styles.alignItemsCenter, styles.justifyContentBetween, styles.mb2, styles.gap2]}>
<View style={[styles.flexRow, styles.alignItemsCenter, styles.gap1, styles.flex1]}>
<View style={[styles.mw50]}>{userCell(transactionItem.from)}</View>
<View style={[styles.mw50]}>{userCell(transactionItem.from, transactionItem.formattedFrom)}</View>
<Icon
src={Expensicons.ArrowRightLong}
width={variables.iconSizeXXSmall}
height={variables.iconSizeXXSmall}
fill={theme.icon}
/>
<View style={[styles.flex1, styles.mw50]}>{userCell(transactionItem.to)}</View>
<View style={[styles.flex1, styles.mw50]}>{userCell(transactionItem.to, transactionItem.formattedTo)}</View>
</View>
<View style={[StyleUtils.getWidthStyle(variables.w80)]}>{actionCell}</View>
</View>
Expand Down Expand Up @@ -259,8 +257,8 @@ function TransactionListItem<TItem extends ListItem>({
<View style={[styles.flex1, styles.flexRow, styles.gap3, styles.alignItemsCenter]}>
<View style={[StyleUtils.getSearchTableColumnStyles(CONST.SEARCH_TABLE_COLUMNS.DATE)]}>{dateCell}</View>
<View style={[StyleUtils.getSearchTableColumnStyles(CONST.SEARCH_TABLE_COLUMNS.MERCHANT)]}>{merchantCell}</View>
<View style={[StyleUtils.getSearchTableColumnStyles(CONST.SEARCH_TABLE_COLUMNS.FROM)]}>{userCell(transactionItem.from)}</View>
<View style={[StyleUtils.getSearchTableColumnStyles(CONST.SEARCH_TABLE_COLUMNS.TO)]}>{userCell(transactionItem.to)}</View>
<View style={[StyleUtils.getSearchTableColumnStyles(CONST.SEARCH_TABLE_COLUMNS.FROM)]}>{userCell(transactionItem.from, transactionItem.formattedFrom)}</View>
<View style={[StyleUtils.getSearchTableColumnStyles(CONST.SEARCH_TABLE_COLUMNS.TO)]}>{userCell(transactionItem.to, transactionItem.formattedTo)}</View>
{transactionItem.shouldShowCategory && <View style={[StyleUtils.getSearchTableColumnStyles(CONST.SEARCH_TABLE_COLUMNS.CATEGORY)]}>{categoryCell}</View>}
{transactionItem.shouldShowTag && <View style={[StyleUtils.getSearchTableColumnStyles(CONST.SEARCH_TABLE_COLUMNS.TAG)]}>{tagCell}</View>}
{transactionItem.shouldShowTax && <View style={[StyleUtils.getSearchTableColumnStyles(CONST.SEARCH_TABLE_COLUMNS.TAX_AMOUNT)]}>{taxCell}</View>}
Expand Down
12 changes: 12 additions & 0 deletions src/components/SelectionList/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,18 @@ type TransactionListItemType = ListItem &
/** The personal details of the user paying the request */
to: SearchAccountDetails;

/** final and formatted "from" value used for displaying and sorting */
formattedFrom: string;

/** final and formatted "to" value used for displaying and sorting */
formattedTo: string;

/** final and formatted "total" value used for displaying and sorting */
formattedTotal: number;

/** final "date" value used for sorting */
date: string;

/** Whether we should show the merchant column */
shouldShowMerchant: boolean;

Expand Down
30 changes: 23 additions & 7 deletions src/libs/SearchUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ import type {TransactionListItemType} from '@components/SelectionList/types';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import type * as OnyxTypes from '@src/types/onyx';
import type {SearchDataTypes, SearchTypeToItemMap} from '@src/types/onyx/SearchResults';
import type {SearchAccountDetails, SearchDataTypes, SearchTypeToItemMap} from '@src/types/onyx/SearchResults';
import * as TransactionUtils from './TransactionUtils';
import * as UserUtils from './UserUtils';

type SortOrder = 'asc' | 'desc';
Expand Down Expand Up @@ -36,19 +37,34 @@ function getTransactionsSections(data: OnyxTypes.SearchResults['data']): Transac
const shouldShowCategory = getShouldShowColumn(data, CONST.SEARCH_TABLE_COLUMNS.CATEGORY);
const shouldShowTag = getShouldShowColumn(data, CONST.SEARCH_TABLE_COLUMNS.TAG);
const shouldShowTax = getShouldShowColumn(data, CONST.SEARCH_TABLE_COLUMNS.TAX_AMOUNT);

return Object.entries(data)
.filter(([key]) => key.startsWith(ONYXKEYS.COLLECTION.TRANSACTION))
.map(([, value]) => {
const isExpenseReport = value.reportType === CONST.REPORT.TYPE.EXPENSE;
.map(([, transactionItem]) => {
const isExpenseReport = transactionItem.reportType === CONST.REPORT.TYPE.EXPENSE;
const from = data.personalDetailsList?.[transactionItem.accountID];
const to = isExpenseReport
? (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;

return {
...value,
from: data.personalDetailsList?.[value.accountID],
to: isExpenseReport ? data[`${ONYXKEYS.COLLECTION.POLICY}${value.policyID}`] : data.personalDetailsList?.[value.managerID],
...transactionItem,
from,
to,
formattedFrom,
formattedTo,
date,
formattedTotal,
shouldShowMerchant,
shouldShowCategory,
shouldShowTag,
shouldShowTax,
keyForList: value.transactionID,
keyForList: transactionItem.transactionID,
};
})
.sort((a, b) => {
Expand Down

0 comments on commit 6e379da

Please sign in to comment.