Skip to content

Commit

Permalink
Merge pull request #41672 from software-mansion-labs/search-v1-p2/dyn…
Browse files Browse the repository at this point in the history
…amic-columns
  • Loading branch information
luacmartins authored May 14, 2024
2 parents 229027a + f803748 commit 084d8cd
Show file tree
Hide file tree
Showing 12 changed files with 294 additions and 115 deletions.
3 changes: 3 additions & 0 deletions src/CONST.ts
Original file line number Diff line number Diff line change
Expand Up @@ -936,9 +936,12 @@ const CONST = {
MERCHANT: 'merchant',
FROM: 'from',
TO: 'to',
CATEGORY: 'category',
TAG: 'tag',
TOTAL: 'total',
TYPE: 'type',
ACTION: 'action',
TAX_AMOUNT: 'taxAmount',
},
PRIORITY_MODE: {
GSD: 'gsd',
Expand Down
3 changes: 1 addition & 2 deletions src/components/Search.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -65,11 +65,10 @@ function Search({query}: SearchProps) {

const ListItem = SearchUtils.getListItem(type);
const data = SearchUtils.getSections(searchResults?.data ?? {}, type);
const shouldShowMerchant = SearchUtils.getShouldShowMerchant(searchResults?.data ?? {});

return (
<SelectionList
customListHeader={<SearchTableHeader shouldShowMerchant={shouldShowMerchant} />}
customListHeader={<SearchTableHeader data={searchResults?.data} />}
ListItem={ListItem}
sections={[{data, isDisabled: false}]}
onSelectRow={(item) => {
Expand Down
79 changes: 54 additions & 25 deletions src/components/SelectionList/SearchTableHeader.tsx
Original file line number Diff line number Diff line change
@@ -1,52 +1,81 @@
import React from 'react';
import {View} from 'react-native';
import Text from '@components/Text';
import useLocalize from '@hooks/useLocalize';
import useStyleUtils from '@hooks/useStyleUtils';
import useThemeStyles from '@hooks/useThemeStyles';
import useWindowDimensions from '@hooks/useWindowDimensions';
import * as SearchUtils from '@libs/SearchUtils';
import CONST from '@src/CONST';
import type * as OnyxTypes from '@src/types/onyx';
import SearchTableHeaderColumn from './SearchTableHeaderColumn';

type SearchTableHeaderProps = {
/** Whether we should show the merchant or description column */
shouldShowMerchant: boolean;
data: OnyxTypes.SearchResults['data'];
};

function SearchTableHeader({shouldShowMerchant}: SearchTableHeaderProps) {
function SearchTableHeader({data}: SearchTableHeaderProps) {
const styles = useThemeStyles();
const StyleUtils = useStyleUtils();
const {isSmallScreenWidth, isMediumScreenWidth} = useWindowDimensions();
const {translate} = useLocalize();
const displayNarrowVersion = isMediumScreenWidth || isSmallScreenWidth;

const shouldShowCategoryColumn = SearchUtils.getShouldShowColumn(data, CONST.SEARCH_TABLE_COLUMNS.CATEGORY);
const shouldShowTagColumn = SearchUtils.getShouldShowColumn(data, CONST.SEARCH_TABLE_COLUMNS.TAG);
const shouldShowTaxColumn = SearchUtils.getShouldShowColumn(data, CONST.SEARCH_TABLE_COLUMNS.TAX_AMOUNT);
const shouldShowMerchant = SearchUtils.getShouldShowMerchant(data);

if (displayNarrowVersion) {
return;
}

return (
<View style={[styles.ph5, styles.pb3]}>
<View style={[styles.flex1, styles.flexRow, styles.gap3, styles.ph4]}>
<View style={[StyleUtils.getSearchTableColumnStyles(CONST.SEARCH_TABLE_COLUMNS.DATE)]}>
<Text style={[styles.mutedNormalTextLabel]}>{translate('common.date')}</Text>
</View>
<View style={[StyleUtils.getSearchTableColumnStyles(CONST.SEARCH_TABLE_COLUMNS.MERCHANT)]}>
<Text style={[styles.mutedNormalTextLabel]}>{translate(shouldShowMerchant ? 'common.merchant' : 'common.description')}</Text>
</View>
<View style={[StyleUtils.getSearchTableColumnStyles(CONST.SEARCH_TABLE_COLUMNS.FROM)]}>
<Text style={[styles.mutedNormalTextLabel]}>{translate('common.from')}</Text>
</View>
<View style={[StyleUtils.getSearchTableColumnStyles(CONST.SEARCH_TABLE_COLUMNS.TO)]}>
<Text style={[styles.mutedNormalTextLabel]}>{translate('common.to')}</Text>
</View>
<View style={[StyleUtils.getSearchTableColumnStyles(CONST.SEARCH_TABLE_COLUMNS.TOTAL)]}>
<Text style={[styles.mutedNormalTextLabel]}>{translate('common.total')}</Text>
</View>
<View style={[StyleUtils.getSearchTableColumnStyles(CONST.SEARCH_TABLE_COLUMNS.TYPE)]}>
<Text style={[styles.mutedNormalTextLabel]}>{translate('common.type')}</Text>
</View>
<View style={[StyleUtils.getSearchTableColumnStyles(CONST.SEARCH_TABLE_COLUMNS.ACTION)]}>
<Text style={[styles.mutedNormalTextLabel, styles.textAlignCenter]}>{translate('common.action')}</Text>
</View>
<SearchTableHeaderColumn
containerStyle={[StyleUtils.getSearchTableColumnStyles(CONST.SEARCH_TABLE_COLUMNS.DATE)]}
text={translate('common.date')}
/>
<SearchTableHeaderColumn
containerStyle={[StyleUtils.getSearchTableColumnStyles(CONST.SEARCH_TABLE_COLUMNS.MERCHANT)]}
text={translate(shouldShowMerchant ? 'common.merchant' : 'common.description')}
/>
<SearchTableHeaderColumn
containerStyle={[StyleUtils.getSearchTableColumnStyles(CONST.SEARCH_TABLE_COLUMNS.FROM)]}
text={translate('common.from')}
/>
<SearchTableHeaderColumn
containerStyle={[StyleUtils.getSearchTableColumnStyles(CONST.SEARCH_TABLE_COLUMNS.TO)]}
text={translate('common.to')}
/>
<SearchTableHeaderColumn
shouldShow={shouldShowCategoryColumn}
containerStyle={[StyleUtils.getSearchTableColumnStyles(CONST.SEARCH_TABLE_COLUMNS.CATEGORY)]}
text={translate('common.category')}
/>
<SearchTableHeaderColumn
shouldShow={shouldShowTagColumn}
containerStyle={[StyleUtils.getSearchTableColumnStyles(CONST.SEARCH_TABLE_COLUMNS.TAG)]}
text={translate('common.tag')}
/>
<SearchTableHeaderColumn
shouldShow={shouldShowTaxColumn}
containerStyle={[StyleUtils.getSearchTableColumnStyles(CONST.SEARCH_TABLE_COLUMNS.TAX_AMOUNT)]}
text={translate('common.tax')}
/>
<SearchTableHeaderColumn
containerStyle={[StyleUtils.getSearchTableColumnStyles(CONST.SEARCH_TABLE_COLUMNS.TOTAL)]}
text={translate('common.total')}
/>
<SearchTableHeaderColumn
containerStyle={[StyleUtils.getSearchTableColumnStyles(CONST.SEARCH_TABLE_COLUMNS.TYPE)]}
text={translate('common.type')}
/>
<SearchTableHeaderColumn
containerStyle={[StyleUtils.getSearchTableColumnStyles(CONST.SEARCH_TABLE_COLUMNS.ACTION)]}
text={translate('common.action')}
textStyle={styles.textAlignCenter}
/>
</View>
</View>
);
Expand Down
31 changes: 31 additions & 0 deletions src/components/SelectionList/SearchTableHeaderColumn.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import React from 'react';
import {View} from 'react-native';
import type {StyleProp, TextStyle, ViewStyle} from 'react-native';
import Text from '@components/Text';
import useThemeStyles from '@hooks/useThemeStyles';

type SearchTableHeaderColumnProps = {
shouldShow?: boolean;
containerStyle?: StyleProp<ViewStyle>;
text: string;
textStyle?: StyleProp<TextStyle>;
};

export default function SearchTableHeaderColumn({containerStyle, text, textStyle, shouldShow = true}: SearchTableHeaderColumnProps) {
const styles = useThemeStyles();

if (!shouldShow) {
return null;
}

return (
<View style={containerStyle}>
<Text
numberOfLines={1}
style={[styles.mutedNormalTextLabel, textStyle]}
>
{text}
</Text>
</View>
);
}
45 changes: 45 additions & 0 deletions src/components/SelectionList/TextWithIconCell.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import React from 'react';
import {View} from 'react-native';
import Icon from '@components/Icon';
import Text from '@components/Text';
import Tooltip from '@components/Tooltip';
import useTheme from '@hooks/useTheme';
import useThemeStyles from '@hooks/useThemeStyles';
import type IconAsset from '@src/types/utils/IconAsset';

type TextWithIconCellProps = {
icon: IconAsset;
text?: string;
showTooltip: boolean;
};

export default function TextWithIconCell({icon, text, showTooltip}: TextWithIconCellProps) {
const styles = useThemeStyles();
const theme = useTheme();

if (!text) {
return null;
}

return (
<Tooltip
shouldRender={showTooltip}
text={text}
>
<View style={[styles.flexRow, styles.flexShrink1, styles.gap1]}>
<Icon
src={icon}
fill={theme.icon}
height={12}
width={12}
/>
<Text
numberOfLines={1}
style={[styles.optionDisplayName, styles.label, styles.pre, styles.justifyContentCenter, styles.textMicro, styles.textSupporting, styles.flexShrink1]}
>
{text}
</Text>
</View>
</Tooltip>
);
}
61 changes: 54 additions & 7 deletions src/components/SelectionList/TransactionListItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,9 @@ import * as TransactionUtils from '@libs/TransactionUtils';
import variables from '@styles/variables';
import CONST from '@src/CONST';
import type {Transaction} from '@src/types/onyx';
import type {SearchPersonalDetails, SearchPolicyDetails, SearchTransactionType} from '@src/types/onyx/SearchResults';
import type {SearchAccountDetails, SearchTransactionType} from '@src/types/onyx/SearchResults';
import BaseListItem from './BaseListItem';
import TextWithIconCell from './TextWithIconCell';
import type {ListItem, TransactionListItemProps, TransactionListItemType} from './types';

const getTypeIcon = (type?: SearchTransactionType) => {
Expand Down Expand Up @@ -61,6 +62,7 @@ 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 merchant = getMerchant();
Expand All @@ -82,7 +84,7 @@ function TransactionListItem<TItem extends ListItem>({
/>
);

const userCell = (participant: SearchPersonalDetails & SearchPolicyDetails) => {
const userCell = (participant: SearchAccountDetails) => {
const displayName = participant?.name ?? participant?.displayName ?? participant?.login;
const avatarURL = participant?.avatarURL ?? participant?.avatar;
const isWorkspace = participant?.avatarURL !== undefined;
Expand All @@ -108,6 +110,42 @@ function TransactionListItem<TItem extends ListItem>({
);
};

const categoryCell = isLargeScreenWidth ? (
<TextWithTooltip
shouldShowTooltip={showTooltip}
text={transactionItem?.category}
style={[styles.optionDisplayName, styles.label, styles.pre, styles.justifyContentCenter]}
/>
) : (
<TextWithIconCell
icon={Expensicons.Folder}
showTooltip={showTooltip}
text={transactionItem?.category}
/>
);

const tagCell = isLargeScreenWidth ? (
<TextWithTooltip
shouldShowTooltip={showTooltip}
text={transactionItem?.tag}
style={[styles.optionDisplayName, styles.label, styles.pre, styles.justifyContentCenter]}
/>
) : (
<TextWithIconCell
icon={Expensicons.Tag}
showTooltip={showTooltip}
text={transactionItem?.tag}
/>
);

const taxCell = (
<TextWithTooltip
shouldShowTooltip={showTooltip}
text={CurrencyUtils.convertToDisplayString(taxAmount, currency)}
style={[styles.optionDisplayName, styles.label, styles.pre, styles.justifyContentCenter, styles.textAlignRight]}
/>
);

const totalCell = (
<TextWithTooltip
shouldShowTooltip={showTooltip}
Expand Down Expand Up @@ -162,7 +200,7 @@ function TransactionListItem<TItem extends ListItem>({
>
{() => (
<>
<View style={[styles.flexRow, styles.alignItemsCenter, styles.justifyContentBetween, styles.mb2, styles.gap2]}>
<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>
<Icon
Expand All @@ -171,13 +209,19 @@ function TransactionListItem<TItem extends ListItem>({
height={variables.iconSizeXXSmall}
fill={theme.icon}
/>
<View style={[styles.mw50]}>{userCell(transactionItem.to)}</View>
<View style={[styles.flex1, styles.mw50]}>{userCell(transactionItem.to)}</View>
</View>
<View style={[StyleUtils.getWidthStyle(variables.w80)]}>{actionCell}</View>
</View>
<View style={[styles.flexRow, styles.justifyContentBetween, styles.gap1]}>
<View style={[styles.flex1]}>{merchantCell}</View>
<View style={[styles.alignItemsEnd, styles.gap1]}>
<View style={[styles.flex2, styles.gap1]}>
{merchantCell}
<View style={[styles.flexRow, styles.flex1, styles.alignItemsEnd, styles.gap3]}>
{categoryCell}
{tagCell}
</View>
</View>
<View style={[styles.alignItemsEnd, styles.flex1, styles.gap1]}>
{totalCell}
<View style={[styles.flexRow, styles.gap1, styles.justifyContentCenter]}>
{typeCell}
Expand Down Expand Up @@ -216,7 +260,10 @@ function TransactionListItem<TItem extends ListItem>({
<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.FROM)]}>{userCell(transactionItem.to)}</View>
<View style={[StyleUtils.getSearchTableColumnStyles(CONST.SEARCH_TABLE_COLUMNS.TO)]}>{userCell(transactionItem.to)}</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>}
<View style={[StyleUtils.getSearchTableColumnStyles(CONST.SEARCH_TABLE_COLUMNS.TOTAL)]}>{totalCell}</View>
<View style={[StyleUtils.getSearchTableColumnStyles(CONST.SEARCH_TABLE_COLUMNS.TYPE)]}>{typeCell}</View>
<View style={[StyleUtils.getSearchTableColumnStyles(CONST.SEARCH_TABLE_COLUMNS.ACTION)]}>{actionCell}</View>
Expand Down
Loading

0 comments on commit 084d8cd

Please sign in to comment.