From 3ffa907dae15d8b298a0c69260e3aaf8f434c806 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Mon, 6 May 2024 13:46:00 +0200 Subject: [PATCH 01/11] Add dynamic columns --- src/CONST.ts | 6 ++++++ src/components/Search.tsx | 3 +-- .../SelectionList/SearchTableHeader.tsx | 21 ++++++++++++++++--- .../SelectionList/TransactionListItem.tsx | 20 +++++++++++++++++- src/components/SelectionList/types.ts | 6 ++++++ src/libs/SearchUtils.ts | 11 +++++++++- src/styles/utils/index.ts | 6 ++---- src/types/onyx/SearchResults.ts | 2 ++ 8 files changed, 64 insertions(+), 11 deletions(-) diff --git a/src/CONST.ts b/src/CONST.ts index 566d5179f86a..d2bc9f266dcc 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -924,10 +924,16 @@ const CONST = { MERCHANT: 'merchant', FROM: 'from', TO: 'to', + CATEGORY: 'category', + TAG: 'tag', TOTAL: 'total', TYPE: 'type', ACTION: 'action', }, + SEARCH_TABLE_OPTIONAL_COLUMNS: { + CATEGORY: 'category', + TAG: 'tag', + }, PRIORITY_MODE: { GSD: 'gsd', DEFAULT: 'default', diff --git a/src/components/Search.tsx b/src/components/Search.tsx index d8d3160a2633..a90ddc8d96fd 100644 --- a/src/components/Search.tsx +++ b/src/components/Search.tsx @@ -57,11 +57,10 @@ function Search({query}: SearchProps) { const ListItem = SearchUtils.getListItem(); const data = SearchUtils.getSections(searchResults?.data ?? {}); - const shouldShowMerchant = SearchUtils.getShouldShowMerchant(searchResults?.data ?? {}); return ( } + customListHeader={} ListItem={ListItem} sections={[{data, isDisabled: false}]} onSelectRow={(item) => { diff --git a/src/components/SelectionList/SearchTableHeader.tsx b/src/components/SelectionList/SearchTableHeader.tsx index 02986f22dccc..0fcec85f3833 100644 --- a/src/components/SelectionList/SearchTableHeader.tsx +++ b/src/components/SelectionList/SearchTableHeader.tsx @@ -5,20 +5,25 @@ 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'; 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_OPTIONAL_COLUMNS.CATEGORY); + const shouldShowTagColumn = SearchUtils.getShouldShowColumn(data, CONST.SEARCH_TABLE_OPTIONAL_COLUMNS.TAG); + const shouldShowMerchant = SearchUtils.getShouldShowMerchant(data); + if (displayNarrowVersion) { return; } @@ -38,6 +43,16 @@ function SearchTableHeader({shouldShowMerchant}: SearchTableHeaderProps) { {translate('common.to')} + {shouldShowCategoryColumn && ( + + {translate('common.category')} + + )} + {shouldShowTagColumn && ( + + {translate('common.tag')} + + )} {translate('common.total')} diff --git a/src/components/SelectionList/TransactionListItem.tsx b/src/components/SelectionList/TransactionListItem.tsx index 0965ce6dabce..17c16229915d 100644 --- a/src/components/SelectionList/TransactionListItem.tsx +++ b/src/components/SelectionList/TransactionListItem.tsx @@ -108,6 +108,22 @@ function TransactionListItem({ ); }; + const categoryCell = ( + + ); + + const tagCell = ( + + ); + const totalCell = ( ({ {dateCell} {merchantCell} {userCell(transactionItem.from)} - {userCell(transactionItem.to)} + {userCell(transactionItem.to)} + {transactionItem.shouldShowCategory && {categoryCell}} + {transactionItem.shouldShowTag && {tagCell}} {totalCell} {typeCell} {actionCell} diff --git a/src/components/SelectionList/types.ts b/src/components/SelectionList/types.ts index 8a2a1efdd030..404314cf8227 100644 --- a/src/components/SelectionList/types.ts +++ b/src/components/SelectionList/types.ts @@ -185,6 +185,12 @@ type TransactionListItemType = ListItem & { /** Whether we should show the merchant column */ shouldShowMerchant: boolean; + + /** Whether we should show the category column */ + shouldShowCategory: boolean; + + /** Whether we should show the tag column */ + shouldShowTag: boolean; }; type ListItemProps = CommonListItemProps & { diff --git a/src/libs/SearchUtils.ts b/src/libs/SearchUtils.ts index 570a8e780f5a..62f664a209b0 100644 --- a/src/libs/SearchUtils.ts +++ b/src/libs/SearchUtils.ts @@ -1,3 +1,4 @@ +import type {ValueOf} from 'react-native-gesture-handler/lib/typescript/typeUtils'; import TransactionListItem from '@components/SelectionList/TransactionListItem'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; @@ -12,8 +13,14 @@ function getShouldShowMerchant(data: OnyxTypes.SearchResults['data']): boolean { }); } +function getShouldShowColumn(data: OnyxTypes.SearchResults['data'], columnName: ValueOf) { + return Object.values(data).some((item) => !!item[columnName]); +} + function getTransactionsSections(data: OnyxTypes.SearchResults['data']): SearchTransaction[] { const shouldShowMerchant = getShouldShowMerchant(data); + const shouldShowCategory = getShouldShowColumn(data, CONST.SEARCH_TABLE_OPTIONAL_COLUMNS.CATEGORY); + const shouldShowTag = getShouldShowColumn(data, CONST.SEARCH_TABLE_OPTIONAL_COLUMNS.TAG); return Object.entries(data) .filter(([key]) => key.startsWith(ONYXKEYS.COLLECTION.TRANSACTION)) .map(([, value]) => { @@ -23,6 +30,8 @@ function getTransactionsSections(data: OnyxTypes.SearchResults['data']): SearchT from: data.personalDetailsList?.[value.accountID], to: isExpenseReport ? data[`${ONYXKEYS.COLLECTION.POLICY}${value.policyID}`] : data.personalDetailsList?.[value.managerID], shouldShowMerchant, + shouldShowCategory, + shouldShowTag, keyForList: value.transactionID, }; }) @@ -56,4 +65,4 @@ function getQueryHash(query: string): number { return UserUtils.hashText(query, 2 ** 32); } -export {getListItem, getQueryHash, getSections, getShouldShowMerchant}; +export {getListItem, getQueryHash, getSections, getShouldShowMerchant, getShouldShowColumn}; diff --git a/src/styles/utils/index.ts b/src/styles/utils/index.ts index ca238c3ffd88..a2f292cdeecf 100644 --- a/src/styles/utils/index.ts +++ b/src/styles/utils/index.ts @@ -1529,12 +1529,10 @@ const createStyleUtils = (theme: ThemeColors, styles: ThemeStyles) => ({ columnWidth = getWidthStyle(variables.w44); break; case CONST.SEARCH_TABLE_COLUMNS.MERCHANT: - columnWidth = styles.flex1; - break; case CONST.SEARCH_TABLE_COLUMNS.FROM: - columnWidth = styles.flex1; - break; case CONST.SEARCH_TABLE_COLUMNS.TO: + case CONST.SEARCH_TABLE_COLUMNS.CATEGORY: + case CONST.SEARCH_TABLE_COLUMNS.TAG: columnWidth = styles.flex1; break; case CONST.SEARCH_TABLE_COLUMNS.TOTAL: diff --git a/src/types/onyx/SearchResults.ts b/src/types/onyx/SearchResults.ts index af23821d70e8..ff89f6119cb8 100644 --- a/src/types/onyx/SearchResults.ts +++ b/src/types/onyx/SearchResults.ts @@ -48,6 +48,8 @@ type SearchTransaction = { policyID: string; transactionThreadReportID: string; shouldShowMerchant: boolean; + shouldShowCategory: boolean; + shouldShowTag: boolean; action: string; }; From 666f58ece4d4e9c4a1441059098fb436defe89a6 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Mon, 6 May 2024 15:26:45 +0200 Subject: [PATCH 02/11] Handle displaying Tag and Category on small screens --- .../SelectionList/TransactionListItem.tsx | 55 ++++++++++++++++++- 1 file changed, 53 insertions(+), 2 deletions(-) diff --git a/src/components/SelectionList/TransactionListItem.tsx b/src/components/SelectionList/TransactionListItem.tsx index 17c16229915d..806e5a8946dc 100644 --- a/src/components/SelectionList/TransactionListItem.tsx +++ b/src/components/SelectionList/TransactionListItem.tsx @@ -7,6 +7,7 @@ import Icon from '@components/Icon'; import * as Expensicons from '@components/Icon/Expensicons'; import Text from '@components/Text'; import TextWithTooltip from '@components/TextWithTooltip'; +import Tooltip from '@components/Tooltip'; import useLocalize from '@hooks/useLocalize'; import useStyleUtils from '@hooks/useStyleUtils'; import useTheme from '@hooks/useTheme'; @@ -18,9 +19,37 @@ 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 IconAsset from '@src/types/utils/IconAsset'; import BaseListItem from './BaseListItem'; import type {ListItem, TransactionListItemProps, TransactionListItemType} from './types'; +type TextWithIconCellProps = { + icon: IconAsset; + text: string; + showTooltip: boolean; +}; + +function TextWithIconCell({icon, text, showTooltip}: TextWithIconCellProps) { + const styles = useThemeStyles(); + const theme = useTheme(); + return ( + + + + {text} + + + ); +} + const getTypeIcon = (type?: SearchTransactionType) => { switch (type) { case CONST.SEARCH_TRANSACTION_TYPE.CASH: @@ -156,6 +185,22 @@ function TransactionListItem({ const listItemPressableStyle = [styles.selectionListPressableItemWrapper, styles.pv3, item.isSelected && styles.activeComponentBG, isFocused && styles.sidebarLinkActive]; if (!isLargeScreenWidth) { + const smallCategoryCell = transactionItem?.category ? ( + + ) : null; + + const smallTagCell = transactionItem?.tag ? ( + + ) : null; + return ( ({ {actionCell} - {merchantCell} + + {merchantCell} + + {smallCategoryCell} + {smallTagCell} + + {totalCell} @@ -234,7 +285,7 @@ function TransactionListItem({ {userCell(transactionItem.from)} {userCell(transactionItem.to)} {transactionItem.shouldShowCategory && {categoryCell}} - {transactionItem.shouldShowTag && {tagCell}} + {transactionItem.shouldShowTag && {tagCell}} {totalCell} {typeCell} {actionCell} From 392bf3c804069676a89e0f2df0a29ecced3da07e Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Tue, 7 May 2024 10:29:31 +0200 Subject: [PATCH 03/11] Add TextWithIconCell --- .../SelectionList/TextWithIconCell.tsx | 40 +++++++++++ .../SelectionList/TransactionListItem.tsx | 66 +++++-------------- 2 files changed, 57 insertions(+), 49 deletions(-) create mode 100644 src/components/SelectionList/TextWithIconCell.tsx diff --git a/src/components/SelectionList/TextWithIconCell.tsx b/src/components/SelectionList/TextWithIconCell.tsx new file mode 100644 index 000000000000..5e770d092053 --- /dev/null +++ b/src/components/SelectionList/TextWithIconCell.tsx @@ -0,0 +1,40 @@ +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 ( + + + + {text} + + + ); +} diff --git a/src/components/SelectionList/TransactionListItem.tsx b/src/components/SelectionList/TransactionListItem.tsx index 806e5a8946dc..2e863c298b67 100644 --- a/src/components/SelectionList/TransactionListItem.tsx +++ b/src/components/SelectionList/TransactionListItem.tsx @@ -7,7 +7,6 @@ import Icon from '@components/Icon'; import * as Expensicons from '@components/Icon/Expensicons'; import Text from '@components/Text'; import TextWithTooltip from '@components/TextWithTooltip'; -import Tooltip from '@components/Tooltip'; import useLocalize from '@hooks/useLocalize'; import useStyleUtils from '@hooks/useStyleUtils'; import useTheme from '@hooks/useTheme'; @@ -19,37 +18,10 @@ 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 IconAsset from '@src/types/utils/IconAsset'; import BaseListItem from './BaseListItem'; +import TextWithIconCell from './TextWithIconCell'; import type {ListItem, TransactionListItemProps, TransactionListItemType} from './types'; -type TextWithIconCellProps = { - icon: IconAsset; - text: string; - showTooltip: boolean; -}; - -function TextWithIconCell({icon, text, showTooltip}: TextWithIconCellProps) { - const styles = useThemeStyles(); - const theme = useTheme(); - return ( - - - - {text} - - - ); -} - const getTypeIcon = (type?: SearchTransactionType) => { switch (type) { case CONST.SEARCH_TRANSACTION_TYPE.CASH: @@ -137,20 +109,32 @@ function TransactionListItem({ ); }; - const categoryCell = ( + const categoryCell = isLargeScreenWidth ? ( + ) : ( + ); - const tagCell = ( + const tagCell = isLargeScreenWidth ? ( + ) : ( + ); const totalCell = ( @@ -185,22 +169,6 @@ function TransactionListItem({ const listItemPressableStyle = [styles.selectionListPressableItemWrapper, styles.pv3, item.isSelected && styles.activeComponentBG, isFocused && styles.sidebarLinkActive]; if (!isLargeScreenWidth) { - const smallCategoryCell = transactionItem?.category ? ( - - ) : null; - - const smallTagCell = transactionItem?.tag ? ( - - ) : null; - return ( ({ {merchantCell} - {smallCategoryCell} - {smallTagCell} + {categoryCell} + {tagCell} From 22a00fa250777938ce80b43376c7ca529069ce7c Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Tue, 7 May 2024 10:37:13 +0200 Subject: [PATCH 04/11] Remove CONST.SEARCH_TABLE_OPTIONAL_COLUMNS --- src/CONST.ts | 4 ---- src/components/SelectionList/SearchTableHeader.tsx | 4 ++-- src/libs/SearchUtils.ts | 6 +++--- 3 files changed, 5 insertions(+), 9 deletions(-) diff --git a/src/CONST.ts b/src/CONST.ts index d2bc9f266dcc..ec999f18a63c 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -930,10 +930,6 @@ const CONST = { TYPE: 'type', ACTION: 'action', }, - SEARCH_TABLE_OPTIONAL_COLUMNS: { - CATEGORY: 'category', - TAG: 'tag', - }, PRIORITY_MODE: { GSD: 'gsd', DEFAULT: 'default', diff --git a/src/components/SelectionList/SearchTableHeader.tsx b/src/components/SelectionList/SearchTableHeader.tsx index 0fcec85f3833..76a73e6f1d28 100644 --- a/src/components/SelectionList/SearchTableHeader.tsx +++ b/src/components/SelectionList/SearchTableHeader.tsx @@ -20,8 +20,8 @@ function SearchTableHeader({data}: SearchTableHeaderProps) { const {translate} = useLocalize(); const displayNarrowVersion = isMediumScreenWidth || isSmallScreenWidth; - const shouldShowCategoryColumn = SearchUtils.getShouldShowColumn(data, CONST.SEARCH_TABLE_OPTIONAL_COLUMNS.CATEGORY); - const shouldShowTagColumn = SearchUtils.getShouldShowColumn(data, CONST.SEARCH_TABLE_OPTIONAL_COLUMNS.TAG); + const shouldShowCategoryColumn = SearchUtils.getShouldShowColumn(data, CONST.SEARCH_TABLE_COLUMNS.CATEGORY); + const shouldShowTagColumn = SearchUtils.getShouldShowColumn(data, CONST.SEARCH_TABLE_COLUMNS.TAG); const shouldShowMerchant = SearchUtils.getShouldShowMerchant(data); if (displayNarrowVersion) { diff --git a/src/libs/SearchUtils.ts b/src/libs/SearchUtils.ts index 62f664a209b0..d8198548eb50 100644 --- a/src/libs/SearchUtils.ts +++ b/src/libs/SearchUtils.ts @@ -13,14 +13,14 @@ function getShouldShowMerchant(data: OnyxTypes.SearchResults['data']): boolean { }); } -function getShouldShowColumn(data: OnyxTypes.SearchResults['data'], columnName: ValueOf) { +function getShouldShowColumn(data: OnyxTypes.SearchResults['data'], columnName: ValueOf) { return Object.values(data).some((item) => !!item[columnName]); } function getTransactionsSections(data: OnyxTypes.SearchResults['data']): SearchTransaction[] { const shouldShowMerchant = getShouldShowMerchant(data); - const shouldShowCategory = getShouldShowColumn(data, CONST.SEARCH_TABLE_OPTIONAL_COLUMNS.CATEGORY); - const shouldShowTag = getShouldShowColumn(data, CONST.SEARCH_TABLE_OPTIONAL_COLUMNS.TAG); + const shouldShowCategory = getShouldShowColumn(data, CONST.SEARCH_TABLE_COLUMNS.CATEGORY); + const shouldShowTag = getShouldShowColumn(data, CONST.SEARCH_TABLE_COLUMNS.TAG); return Object.entries(data) .filter(([key]) => key.startsWith(ONYXKEYS.COLLECTION.TRANSACTION)) .map(([, value]) => { From 72e75b5f96e828cbaa1e3c236fbd909620e949e9 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Tue, 7 May 2024 12:25:21 +0200 Subject: [PATCH 05/11] Refactor TransactionListItemType --- .../SelectionList/TextWithIconCell.tsx | 2 +- .../SelectionList/TransactionListItem.tsx | 4 +- src/components/SelectionList/types.ts | 79 ++++--------------- src/libs/SearchUtils.ts | 8 +- src/types/onyx/SearchResults.ts | 70 +++++++++++----- 5 files changed, 72 insertions(+), 91 deletions(-) diff --git a/src/components/SelectionList/TextWithIconCell.tsx b/src/components/SelectionList/TextWithIconCell.tsx index 5e770d092053..d9b9dc99f668 100644 --- a/src/components/SelectionList/TextWithIconCell.tsx +++ b/src/components/SelectionList/TextWithIconCell.tsx @@ -9,7 +9,7 @@ import type IconAsset from '@src/types/utils/IconAsset'; type TextWithIconCellProps = { icon: IconAsset; - text: string; + text?: string; showTooltip: boolean; }; diff --git a/src/components/SelectionList/TransactionListItem.tsx b/src/components/SelectionList/TransactionListItem.tsx index 2e863c298b67..1a298fd30cb7 100644 --- a/src/components/SelectionList/TransactionListItem.tsx +++ b/src/components/SelectionList/TransactionListItem.tsx @@ -17,7 +17,7 @@ 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'; @@ -83,7 +83,7 @@ function TransactionListItem({ /> ); - 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; diff --git a/src/components/SelectionList/types.ts b/src/components/SelectionList/types.ts index 404314cf8227..37f7cf2e1f3b 100644 --- a/src/components/SelectionList/types.ts +++ b/src/components/SelectionList/types.ts @@ -1,11 +1,10 @@ import type {MutableRefObject, ReactElement, ReactNode} from 'react'; import type {GestureResponderEvent, InputModeOptions, LayoutChangeEvent, SectionListData, StyleProp, TextInput, TextStyle, ViewStyle} from 'react-native'; -import type {ValueOf} from 'type-fest'; import type {MaybePhraseKey} from '@libs/Localize'; import type {BrickRoad} from '@libs/WorkspacesSettingsUtils'; import type CONST from '@src/CONST'; import type {Errors, Icon, PendingAction} from '@src/types/onyx/OnyxCommon'; -import type {SearchPersonalDetails, SearchPolicyDetails} from '@src/types/onyx/SearchResults'; +import type {SearchAccountDetails, SearchTransaction} from '@src/types/onyx/SearchResults'; import type {ReceiptErrors} from '@src/types/onyx/Transaction'; import type ChildrenProps from '@src/types/utils/ChildrenProps'; import type IconAsset from '@src/types/utils/IconAsset'; @@ -128,70 +127,22 @@ type ListItem = { brickRoadIndicator?: BrickRoad | '' | null; }; -type TransactionListItemType = ListItem & { - /** The ID of the transaction */ - transactionID: string; +type TransactionListItemType = ListItem & + SearchTransaction & { + /** The personal details of the user requesting money */ + from: SearchAccountDetails; - /** The transaction created date */ - created: string; + /** The personal details of the user paying the request */ + to: SearchAccountDetails; + /** Whether we should show the merchant column */ + shouldShowMerchant: boolean; - /** The edited transaction created date */ - modifiedCreated: string; + /** Whether we should show the category column */ + shouldShowCategory: boolean; - /** The transaction amount */ - amount: number; - - /** The edited transaction amount */ - modifiedAmount: number; - - /** The transaction currency */ - currency: string; - - /** The edited transaction currency */ - modifiedCurrency: string; - - /** The transaction merchant */ - merchant: string; - - /** The edited transaction merchant */ - modifiedMerchant: string; - - /** The receipt object */ - receipt?: {source?: string}; - - /** The personal details of the user requesting money */ - from: SearchPersonalDetails & SearchPolicyDetails; - - /** The personal details of the user paying the request */ - to: SearchPersonalDetails & SearchPolicyDetails; - - /** The transaction tag */ - tag: string; - - /** The transaction description */ - comment: {comment: string}; - - /** The transaction category */ - category: string; - - /** The type of request */ - type: ValueOf; - - /** The type of report the transaction is associated with */ - reportType: string; - - /** The ID of the policy the transaction is associated with */ - policyID: string; - - /** Whether we should show the merchant column */ - shouldShowMerchant: boolean; - - /** Whether we should show the category column */ - shouldShowCategory: boolean; - - /** Whether we should show the tag column */ - shouldShowTag: boolean; -}; + /** Whether we should show the tag column */ + shouldShowTag: boolean; + }; type ListItemProps = CommonListItemProps & { /** The section list item */ @@ -454,7 +405,7 @@ export type { SelectionListHandle, TableListItemProps, TransactionListItemProps, + TransactionListItemType, UserListItemProps, ValidListItem, - TransactionListItemType, }; diff --git a/src/libs/SearchUtils.ts b/src/libs/SearchUtils.ts index d8198548eb50..56edf69457e4 100644 --- a/src/libs/SearchUtils.ts +++ b/src/libs/SearchUtils.ts @@ -1,9 +1,9 @@ import type {ValueOf} from 'react-native-gesture-handler/lib/typescript/typeUtils'; import TransactionListItem from '@components/SelectionList/TransactionListItem'; +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 {SearchTransaction} from '@src/types/onyx/SearchResults'; import * as UserUtils from './UserUtils'; function getShouldShowMerchant(data: OnyxTypes.SearchResults['data']): boolean { @@ -17,7 +17,7 @@ function getShouldShowColumn(data: OnyxTypes.SearchResults['data'], columnName: return Object.values(data).some((item) => !!item[columnName]); } -function getTransactionsSections(data: OnyxTypes.SearchResults['data']): SearchTransaction[] { +function getTransactionsSections(data: OnyxTypes.SearchResults['data']): TransactionListItemType[] { const shouldShowMerchant = getShouldShowMerchant(data); const shouldShowCategory = getShouldShowColumn(data, CONST.SEARCH_TABLE_COLUMNS.CATEGORY); const shouldShowTag = getShouldShowColumn(data, CONST.SEARCH_TABLE_COLUMNS.TAG); @@ -57,7 +57,7 @@ function getListItem(): typeof TransactionListItem { return searchTypeToItemMap.transaction.listItem; } -function getSections(data: OnyxTypes.SearchResults['data']): SearchTransaction[] { +function getSections(data: OnyxTypes.SearchResults['data']): TransactionListItemType[] { return searchTypeToItemMap.transaction.getSections(data); } @@ -65,4 +65,4 @@ function getQueryHash(query: string): number { return UserUtils.hashText(query, 2 ** 32); } -export {getListItem, getQueryHash, getSections, getShouldShowMerchant, getShouldShowColumn}; +export {getListItem, getQueryHash, getSections, getShouldShowColumn, getShouldShowMerchant}; diff --git a/src/types/onyx/SearchResults.ts b/src/types/onyx/SearchResults.ts index ff89f6119cb8..08a5e759740b 100644 --- a/src/types/onyx/SearchResults.ts +++ b/src/types/onyx/SearchResults.ts @@ -1,6 +1,5 @@ import type {ValueOf} from 'type-fest'; import type CONST from '@src/CONST'; -import type {Receipt} from './Transaction'; type SearchResultsInfo = { offset: number; @@ -22,37 +21,68 @@ type SearchPolicyDetails = { }; type SearchTransaction = { + /** The ID of the transaction */ transactionID: string; - parentTransactionID?: string; - receipt?: Receipt; - hasEReceipt?: boolean; + + /** The transaction created date */ created: string; + + /** The edited transaction created date */ + modifiedCreated: string; + + /** The transaction amount */ + amount: number; + + /** The edited transaction amount */ + modifiedAmount: number; + + /** The transaction currency */ + currency: string; + + /** The edited transaction currency */ + modifiedCurrency: string; + + /** The transaction merchant */ merchant: string; - modifiedCreated?: string; - modifiedMerchant?: string; + + /** The edited transaction merchant */ + modifiedMerchant: string; + + /** The receipt object */ + receipt?: {source?: string}; + + /** The transaction tag */ + tag: string; + + /** The transaction description */ + comment: {comment: string}; + + /** The transaction category */ + category: string; + + /** The type of request */ + type: ValueOf; + + /** The type of report the transaction is associated with */ + reportType: string; + + /** The ID of the policy the transaction is associated with */ + policyID: string; + + parentTransactionID?: string; + hasEReceipt?: boolean; description: string; accountID: number; managerID: number; - from: SearchPersonalDetails | SearchPolicyDetails; - to: SearchPersonalDetails | SearchPolicyDetails; - amount: number; - modifiedAmount?: number; - category?: string; - currency: string; - tag?: string; - type: SearchTransactionType; hasViolation: boolean; taxAmount?: number; reportID: string; - reportType: string; - policyID: string; transactionThreadReportID: string; - shouldShowMerchant: boolean; - shouldShowCategory: boolean; - shouldShowTag: boolean; action: string; }; +type SearchAccountDetails = Partial; + type SearchTransactionType = ValueOf; type SearchQuery = ValueOf; @@ -64,4 +94,4 @@ type SearchResults = { export default SearchResults; -export type {SearchQuery, SearchTransaction, SearchTransactionType, SearchPersonalDetails, SearchPolicyDetails}; +export type {SearchQuery, SearchTransaction, SearchTransactionType, SearchPersonalDetails, SearchPolicyDetails, SearchAccountDetails}; From ac96c83a8e850b1a626b532627892a63794c975d Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Tue, 7 May 2024 13:44:58 +0200 Subject: [PATCH 06/11] Add docs for SearchTransaction --- src/components/SelectionList/types.ts | 1 + src/types/onyx/SearchResults.ts | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/src/components/SelectionList/types.ts b/src/components/SelectionList/types.ts index 37f7cf2e1f3b..66a1f81af7e9 100644 --- a/src/components/SelectionList/types.ts +++ b/src/components/SelectionList/types.ts @@ -134,6 +134,7 @@ type TransactionListItemType = ListItem & /** The personal details of the user paying the request */ to: SearchAccountDetails; + /** Whether we should show the merchant column */ shouldShowMerchant: boolean; diff --git a/src/types/onyx/SearchResults.ts b/src/types/onyx/SearchResults.ts index 08a5e759740b..91c76774d209 100644 --- a/src/types/onyx/SearchResults.ts +++ b/src/types/onyx/SearchResults.ts @@ -69,15 +69,34 @@ type SearchTransaction = { /** The ID of the policy the transaction is associated with */ policyID: string; + /** The ID of the parent of the transaction */ parentTransactionID?: string; + + /** If the transaction has an Ereceipt */ hasEReceipt?: boolean; + + /** The transaction description */ description: string; + + /** The transaction sender ID */ accountID: number; + + /** The transaction recipient ID */ managerID: number; + + /** If the transaction has a Ereceipt */ hasViolation: boolean; + + /** The transaction tax amount */ taxAmount?: number; + + /** The ID of the report the transaction is associated with */ reportID: string; + + /** The report ID of the transaction thread associated with the transaction */ transactionThreadReportID: string; + + /** The action that can be performed for the transaction */ action: string; }; From bbbd786f70e35d9b6ad88f0cdeaf588f7e59d34e Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Wed, 8 May 2024 10:13:32 +0200 Subject: [PATCH 07/11] Add tax column --- src/CONST.ts | 1 + src/components/SelectionList/SearchTableHeader.tsx | 6 ++++++ src/components/SelectionList/TransactionListItem.tsx | 10 ++++++++++ src/components/SelectionList/types.ts | 3 +++ src/languages/en.ts | 1 + src/languages/es.ts | 1 + src/libs/SearchUtils.ts | 2 ++ src/styles/utils/index.ts | 1 + 8 files changed, 25 insertions(+) diff --git a/src/CONST.ts b/src/CONST.ts index ec999f18a63c..40a8f345cd13 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -929,6 +929,7 @@ const CONST = { TOTAL: 'total', TYPE: 'type', ACTION: 'action', + TAX_AMOUNT: 'taxAmount', }, PRIORITY_MODE: { GSD: 'gsd', diff --git a/src/components/SelectionList/SearchTableHeader.tsx b/src/components/SelectionList/SearchTableHeader.tsx index 76a73e6f1d28..34ec54cf1f7b 100644 --- a/src/components/SelectionList/SearchTableHeader.tsx +++ b/src/components/SelectionList/SearchTableHeader.tsx @@ -22,6 +22,7 @@ function SearchTableHeader({data}: SearchTableHeaderProps) { 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) { @@ -53,6 +54,11 @@ function SearchTableHeader({data}: SearchTableHeaderProps) { {translate('common.tag')} )} + {!shouldShowTaxColumn && ( + + {translate('common.tax')} + + )} {translate('common.total')} diff --git a/src/components/SelectionList/TransactionListItem.tsx b/src/components/SelectionList/TransactionListItem.tsx index 1a298fd30cb7..f0e78d4012de 100644 --- a/src/components/SelectionList/TransactionListItem.tsx +++ b/src/components/SelectionList/TransactionListItem.tsx @@ -62,6 +62,7 @@ function TransactionListItem({ const isFromExpenseReport = transactionItem.reportType === CONST.REPORT.TYPE.EXPENSE; const date = TransactionUtils.getCreated(transactionItem as OnyxEntry, CONST.DATE.MONTH_DAY_ABBR_FORMAT); const amount = TransactionUtils.getAmount(transactionItem as OnyxEntry, isFromExpenseReport); + const taxAmount = TransactionUtils.getAmount(transactionItem as OnyxEntry); const currency = TransactionUtils.getCurrency(transactionItem as OnyxEntry); const description = TransactionUtils.getDescription(transactionItem as OnyxEntry); const merchant = getMerchant(); @@ -137,6 +138,14 @@ function TransactionListItem({ /> ); + const taxCell = ( + + ); + const totalCell = ( ({ {userCell(transactionItem.to)} {transactionItem.shouldShowCategory && {categoryCell}} {transactionItem.shouldShowTag && {tagCell}} + {transactionItem.shouldShowTax && {taxCell}} {totalCell} {typeCell} {actionCell} diff --git a/src/components/SelectionList/types.ts b/src/components/SelectionList/types.ts index 66a1f81af7e9..79e47e4aa4d7 100644 --- a/src/components/SelectionList/types.ts +++ b/src/components/SelectionList/types.ts @@ -143,6 +143,9 @@ type TransactionListItemType = ListItem & /** Whether we should show the tag column */ shouldShowTag: boolean; + + /** Whether we should show the tax column */ + shouldShowTax: boolean; }; type ListItemProps = CommonListItemProps & { diff --git a/src/languages/en.ts b/src/languages/en.ts index aadd6ac03f58..48b49c7ab5c3 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -331,6 +331,7 @@ export default { type: 'Type', action: 'Action', expenses: 'Expenses', + tax: 'Tax', }, location: { useCurrent: 'Use current location', diff --git a/src/languages/es.ts b/src/languages/es.ts index d4efe11a51b0..413fbb39a613 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -321,6 +321,7 @@ export default { type: 'Tipo', action: 'Acción', expenses: 'Gastos', + tax: 'Impuesto', }, connectionComplete: { title: 'Conexión Completa', diff --git a/src/libs/SearchUtils.ts b/src/libs/SearchUtils.ts index 56edf69457e4..23dbabb66af7 100644 --- a/src/libs/SearchUtils.ts +++ b/src/libs/SearchUtils.ts @@ -21,6 +21,7 @@ function getTransactionsSections(data: OnyxTypes.SearchResults['data']): Transac const shouldShowMerchant = getShouldShowMerchant(data); 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]) => { @@ -32,6 +33,7 @@ function getTransactionsSections(data: OnyxTypes.SearchResults['data']): Transac shouldShowMerchant, shouldShowCategory, shouldShowTag, + shouldShowTax, keyForList: value.transactionID, }; }) diff --git a/src/styles/utils/index.ts b/src/styles/utils/index.ts index a2f292cdeecf..b902915f4b10 100644 --- a/src/styles/utils/index.ts +++ b/src/styles/utils/index.ts @@ -1535,6 +1535,7 @@ const createStyleUtils = (theme: ThemeColors, styles: ThemeStyles) => ({ case CONST.SEARCH_TABLE_COLUMNS.TAG: columnWidth = styles.flex1; break; + case CONST.SEARCH_TABLE_COLUMNS.TAX_AMOUNT: case CONST.SEARCH_TABLE_COLUMNS.TOTAL: columnWidth = {...getWidthStyle(variables.w96), ...styles.alignItemsEnd}; break; From ee24845a5c5fc18dafaab2671465c994dcfe88ca Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Thu, 9 May 2024 10:13:02 +0200 Subject: [PATCH 08/11] Add SearchTableHeaderColumn --- .../SelectionList/SearchTableHeader.tsx | 82 ++++++++++--------- .../SelectionList/SearchTableHeaderColumn.tsx | 31 +++++++ 2 files changed, 76 insertions(+), 37 deletions(-) create mode 100644 src/components/SelectionList/SearchTableHeaderColumn.tsx diff --git a/src/components/SelectionList/SearchTableHeader.tsx b/src/components/SelectionList/SearchTableHeader.tsx index 34ec54cf1f7b..ec0267d20c04 100644 --- a/src/components/SelectionList/SearchTableHeader.tsx +++ b/src/components/SelectionList/SearchTableHeader.tsx @@ -1,6 +1,5 @@ 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'; @@ -8,6 +7,7 @@ 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 = { data: OnyxTypes.SearchResults['data']; @@ -32,42 +32,50 @@ function SearchTableHeader({data}: SearchTableHeaderProps) { return ( - - {translate('common.date')} - - - {translate(shouldShowMerchant ? 'common.merchant' : 'common.description')} - - - {translate('common.from')} - - - {translate('common.to')} - - {shouldShowCategoryColumn && ( - - {translate('common.category')} - - )} - {shouldShowTagColumn && ( - - {translate('common.tag')} - - )} - {!shouldShowTaxColumn && ( - - {translate('common.tax')} - - )} - - {translate('common.total')} - - - {translate('common.type')} - - - {translate('common.action')} - + + + + + + + + + + ); diff --git a/src/components/SelectionList/SearchTableHeaderColumn.tsx b/src/components/SelectionList/SearchTableHeaderColumn.tsx new file mode 100644 index 000000000000..92b59f702cb1 --- /dev/null +++ b/src/components/SelectionList/SearchTableHeaderColumn.tsx @@ -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; + text: string; + textStyle?: StyleProp; +}; + +export default function SearchTableHeaderColumn({containerStyle, text, textStyle, shouldShow = true}: SearchTableHeaderColumnProps) { + const styles = useThemeStyles(); + + if (!shouldShow) { + return null; + } + + return ( + + + {text} + + + ); +} From 74d3a88a2a12b979f4c52aa5f89d420cc4781ce7 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Thu, 9 May 2024 10:26:53 +0200 Subject: [PATCH 09/11] Fix displaying users in TransactionListItem --- src/components/SelectionList/TransactionListItem.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/SelectionList/TransactionListItem.tsx b/src/components/SelectionList/TransactionListItem.tsx index f0e78d4012de..abb2c20e72eb 100644 --- a/src/components/SelectionList/TransactionListItem.tsx +++ b/src/components/SelectionList/TransactionListItem.tsx @@ -62,7 +62,7 @@ function TransactionListItem({ const isFromExpenseReport = transactionItem.reportType === CONST.REPORT.TYPE.EXPENSE; const date = TransactionUtils.getCreated(transactionItem as OnyxEntry, CONST.DATE.MONTH_DAY_ABBR_FORMAT); const amount = TransactionUtils.getAmount(transactionItem as OnyxEntry, isFromExpenseReport); - const taxAmount = TransactionUtils.getAmount(transactionItem as OnyxEntry); + const taxAmount = TransactionUtils.getTaxAmount(transactionItem as OnyxEntry, isFromExpenseReport); const currency = TransactionUtils.getCurrency(transactionItem as OnyxEntry); const description = TransactionUtils.getDescription(transactionItem as OnyxEntry); const merchant = getMerchant(); @@ -209,7 +209,7 @@ function TransactionListItem({ height={variables.iconSizeXXSmall} fill={theme.icon} /> - {userCell(transactionItem.to)} + {userCell(transactionItem.to)} {actionCell} From ed74c1add93e19867990e38de3eebadcaf405098 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Thu, 9 May 2024 10:53:28 +0200 Subject: [PATCH 10/11] Fix displaying category and tag cells in TransactionListItem --- src/components/SelectionList/TextWithIconCell.tsx | 9 +++++++-- src/components/SelectionList/TransactionListItem.tsx | 2 +- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/components/SelectionList/TextWithIconCell.tsx b/src/components/SelectionList/TextWithIconCell.tsx index d9b9dc99f668..5423bb1537ad 100644 --- a/src/components/SelectionList/TextWithIconCell.tsx +++ b/src/components/SelectionList/TextWithIconCell.tsx @@ -26,14 +26,19 @@ export default function TextWithIconCell({icon, text, showTooltip}: TextWithIcon shouldRender={showTooltip} text={text} > - + - {text} + + {text} + ); diff --git a/src/components/SelectionList/TransactionListItem.tsx b/src/components/SelectionList/TransactionListItem.tsx index abb2c20e72eb..26cd9f38e813 100644 --- a/src/components/SelectionList/TransactionListItem.tsx +++ b/src/components/SelectionList/TransactionListItem.tsx @@ -216,7 +216,7 @@ function TransactionListItem({ {merchantCell} - + {categoryCell} {tagCell} From 2fe5f209dcd321e09609833689c9bb1cf305373e Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Fri, 10 May 2024 14:13:56 +0200 Subject: [PATCH 11/11] Add style fixes to TransactionListItem --- src/components/SelectionList/TextWithIconCell.tsx | 2 +- src/components/SelectionList/TransactionListItem.tsx | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/components/SelectionList/TextWithIconCell.tsx b/src/components/SelectionList/TextWithIconCell.tsx index 5423bb1537ad..bd51133a362f 100644 --- a/src/components/SelectionList/TextWithIconCell.tsx +++ b/src/components/SelectionList/TextWithIconCell.tsx @@ -26,7 +26,7 @@ export default function TextWithIconCell({icon, text, showTooltip}: TextWithIcon shouldRender={showTooltip} text={text} > - + ({ > {() => ( <> - + {userCell(transactionItem.from)} ({ {actionCell} - + {merchantCell} {categoryCell} {tagCell} - + {totalCell} {typeCell}