From a7f4f32081e8f10d1131c3487ecce8383ab9b52d Mon Sep 17 00:00:00 2001 From: mhawryluk Date: Tue, 16 Dec 2025 13:18:59 +0100 Subject: [PATCH 1/4] Display Time expense type in Search --- src/CONST/index.ts | 1 + .../TransactionItemRow/DataCells/TypeCell.tsx | 23 +++++++++++++++---- src/libs/TransactionUtils/index.ts | 8 +++++++ 3 files changed, 28 insertions(+), 4 deletions(-) diff --git a/src/CONST/index.ts b/src/CONST/index.ts index 65cc7b8c44132..f4e59f59d20fe 100755 --- a/src/CONST/index.ts +++ b/src/CONST/index.ts @@ -6677,6 +6677,7 @@ const CONST = { CARD: 'card', DISTANCE: 'distance', PER_DIEM: 'perDiem', + TIME: 'time', }, WITHDRAWAL_TYPE: { EXPENSIFY_CARD: 'expensify-card', diff --git a/src/components/TransactionItemRow/DataCells/TypeCell.tsx b/src/components/TransactionItemRow/DataCells/TypeCell.tsx index ead3c964635ff..677f5f7191883 100644 --- a/src/components/TransactionItemRow/DataCells/TypeCell.tsx +++ b/src/components/TransactionItemRow/DataCells/TypeCell.tsx @@ -8,18 +8,21 @@ import useOnyx from '@hooks/useOnyx'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; import {getTransactionType, isExpensifyCardTransaction, isPending} from '@libs/TransactionUtils'; +import variables from '@styles/variables'; import CONST from '@src/CONST'; import type {TranslationPaths} from '@src/languages/types'; import ONYXKEYS from '@src/ONYXKEYS'; import type IconAsset from '@src/types/utils/IconAsset'; import type TransactionDataCellProps from './TransactionDataCellProps'; -const getTypeIcon = (icons: Record<'Car', IconAsset>, type?: string) => { +const getTypeIcon = (icons: Record<'Car' | 'Clock', IconAsset>, type?: string) => { switch (type) { case CONST.SEARCH.TRANSACTION_TYPE.CARD: return Expensicons.CreditCard; case CONST.SEARCH.TRANSACTION_TYPE.DISTANCE: return icons.Car; + case CONST.SEARCH.TRANSACTION_TYPE.TIME: + return icons.Clock; case CONST.SEARCH.TRANSACTION_TYPE.CASH: default: return Expensicons.Cash; @@ -32,21 +35,33 @@ const getTypeText = (type?: string): TranslationPaths => { return 'common.distance'; case CONST.SEARCH.TRANSACTION_TYPE.CARD: return 'iou.card'; + case CONST.SEARCH.TRANSACTION_TYPE.TIME: + return 'iou.time'; case CONST.SEARCH.TRANSACTION_TYPE.CASH: default: return 'iou.cash'; } }; +const getTypeIconSize = (type?: string) => { + switch (type) { + case CONST.SEARCH.TRANSACTION_TYPE.TIME: + return variables.iconSizeSmall; + default: + return variables.iconSizeNormal; + } +}; + function TypeCell({transactionItem, shouldUseNarrowLayout, shouldShowTooltip}: TransactionDataCellProps) { const {translate} = useLocalize(); const [cardList] = useOnyx(ONYXKEYS.CARD_LIST, {canBeMissing: true}); const theme = useTheme(); - const expensifyIcons = useMemoizedLazyExpensifyIcons(['Car'] as const); + const expensifyIcons = useMemoizedLazyExpensifyIcons(['Car', 'Clock']); const type = getTransactionType(transactionItem, cardList); const isPendingExpensifyCardTransaction = isExpensifyCardTransaction(transactionItem) && isPending(transactionItem); const typeIcon = isPendingExpensifyCardTransaction ? Expensicons.CreditCardHourglass : getTypeIcon(expensifyIcons, type); const typeText = isPendingExpensifyCardTransaction ? 'iou.pending' : getTypeText(type); + const typeIconSize = getTypeIconSize(type); const styles = useThemeStyles(); return shouldUseNarrowLayout ? ( @@ -59,8 +74,8 @@ function TypeCell({transactionItem, shouldUseNarrowLayout, shouldShowTooltip}: T ); } diff --git a/src/libs/TransactionUtils/index.ts b/src/libs/TransactionUtils/index.ts index a6212b53872cd..d9bdc33df2797 100644 --- a/src/libs/TransactionUtils/index.ts +++ b/src/libs/TransactionUtils/index.ts @@ -208,6 +208,10 @@ function isPerDiemRequest(transaction: OnyxEntry): boolean { return type === CONST.TRANSACTION.TYPE.CUSTOM_UNIT && customUnitName === CONST.CUSTOM_UNITS.NAME_PER_DIEM_INTERNATIONAL; } +function isTimeRequest(transaction: OnyxEntry): boolean { + return transaction?.comment?.type === CONST.TRANSACTION.TYPE.TIME; +} + function isCorporateCardTransaction(transaction: OnyxEntry): boolean { return isManagedCardTransaction(transaction) && transaction?.comment?.liabilityType === CONST.TRANSACTION.LIABILITY_TYPE.RESTRICT; } @@ -271,6 +275,10 @@ function getTransactionType(transaction: OnyxEntry, cardList?: Card return CONST.SEARCH.TRANSACTION_TYPE.PER_DIEM; } + if (isTimeRequest(transaction)) { + return CONST.SEARCH.TRANSACTION_TYPE.TIME; + } + const cardID = transaction?.cardID; if (cardID && cardList?.[cardID]?.cardName === CONST.COMPANY_CARDS.CARD_NAME.CASH) { return CONST.SEARCH.TRANSACTION_TYPE.CASH; From aeec8b554ad99eeebb1241568a9ca055eeb77ad2 Mon Sep 17 00:00:00 2001 From: mhawryluk Date: Tue, 16 Dec 2025 14:32:26 +0100 Subject: [PATCH 2/4] Allow filtering by time --- src/libs/SearchUIUtils.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libs/SearchUIUtils.ts b/src/libs/SearchUIUtils.ts index 1f6acf88a6ebb..dc3f1c9f10111 100644 --- a/src/libs/SearchUIUtils.ts +++ b/src/libs/SearchUIUtils.ts @@ -2047,6 +2047,8 @@ function getExpenseTypeTranslationKey(expenseType: ValueOf Date: Tue, 16 Dec 2025 14:42:24 +0100 Subject: [PATCH 3/4] Extend getTransactionType unit tests with time type --- tests/unit/TransactionUtilsTest.ts | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/tests/unit/TransactionUtilsTest.ts b/tests/unit/TransactionUtilsTest.ts index b0a727e02bdf0..f2bc1bf4791d5 100644 --- a/tests/unit/TransactionUtilsTest.ts +++ b/tests/unit/TransactionUtilsTest.ts @@ -468,6 +468,21 @@ describe('TransactionUtils', () => { expect(TransactionUtils.getTransactionType(transaction)).toBe(CONST.SEARCH.TRANSACTION_TYPE.CASH); }); + + it('returns time when the transaction has a comment with time type', () => { + const transaction = generateTransaction({ + comment: { + type: 'time', + units: { + count: 2, + unit: 'h', + rate: 50, + }, + }, + }); + + expect(TransactionUtils.getTransactionType(transaction)).toBe(CONST.SEARCH.TRANSACTION_TYPE.TIME); + }); }); describe('calculateTaxAmount', () => { From ef86a47a02b455a75bd567e1da58c4edf92feb62 Mon Sep 17 00:00:00 2001 From: mhawryluk Date: Mon, 22 Dec 2025 08:19:33 +0100 Subject: [PATCH 4/4] Make all typecell icons same size --- .../TransactionItemRow/DataCells/TypeCell.tsx | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/src/components/TransactionItemRow/DataCells/TypeCell.tsx b/src/components/TransactionItemRow/DataCells/TypeCell.tsx index 58b5f25c516af..77906d6b0501d 100644 --- a/src/components/TransactionItemRow/DataCells/TypeCell.tsx +++ b/src/components/TransactionItemRow/DataCells/TypeCell.tsx @@ -42,15 +42,6 @@ const getTypeText = (type?: string): TranslationPaths => { } }; -const getTypeIconSize = (type?: string) => { - switch (type) { - case CONST.SEARCH.TRANSACTION_TYPE.TIME: - return variables.iconSizeSmall; - default: - return variables.iconSizeNormal; - } -}; - function TypeCell({transactionItem, shouldUseNarrowLayout, shouldShowTooltip}: TransactionDataCellProps) { const {translate} = useLocalize(); const [cardList] = useOnyx(ONYXKEYS.CARD_LIST, {canBeMissing: true}); @@ -60,7 +51,6 @@ function TypeCell({transactionItem, shouldUseNarrowLayout, shouldShowTooltip}: T const isPendingExpensifyCardTransaction = isExpensifyCardTransaction(transactionItem) && isPending(transactionItem); const typeIcon = isPendingExpensifyCardTransaction ? expensifyIcons.CreditCardHourglass : getTypeIcon(expensifyIcons, type); const typeText = isPendingExpensifyCardTransaction ? 'iou.pending' : getTypeText(type); - const typeIconSize = getTypeIconSize(type); const styles = useThemeStyles(); return shouldUseNarrowLayout ? ( @@ -73,8 +63,8 @@ function TypeCell({transactionItem, shouldUseNarrowLayout, shouldShowTooltip}: T ); }