From a1497d8b6fc4556b2b7dd443173a9265f63cb6be Mon Sep 17 00:00:00 2001 From: nkdengineer Date: Wed, 10 Dec 2025 11:42:03 +0700 Subject: [PATCH 1/5] fix: Category of track expense moved to 1:1 chat is not visiblon chat --- src/components/ReportActionItem/MoneyRequestView.tsx | 12 +++++++++--- src/libs/ReportUtils.ts | 8 ++++++-- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/src/components/ReportActionItem/MoneyRequestView.tsx b/src/components/ReportActionItem/MoneyRequestView.tsx index be594c9c3dfe..f4aba73ad4da 100644 --- a/src/components/ReportActionItem/MoneyRequestView.tsx +++ b/src/components/ReportActionItem/MoneyRequestView.tsx @@ -50,6 +50,7 @@ import { getTransactionDetails, getTripIDFromTransactionParentReportID, isInvoiceReport, + isIOUReport, isPaidGroupPolicy, isReportApproved, isReportInGroupPolicy, @@ -277,6 +278,10 @@ function MoneyRequestView({ (!isPerDiemRequest || canSubmitPerDiemExpenseFromWorkspace(policy)), [isEditable, parentReportAction, isChatReportArchived, outstandingReportsByPolicyID, isPerDiemRequest, policy], ); + const canEditCategory = useMemo( + () => isEditable && canEditFieldOfMoneyRequest(parentReportAction, CONST.EDIT_REQUEST_FIELD.CATEGORY, undefined, isChatReportArchived), + [isEditable, parentReportAction, isChatReportArchived], + ); // A flag for verifying that the current report is a sub-report of a expense chat // if the policy of the report is either Collect or Control, then this report must be tied to expense chat @@ -291,7 +296,8 @@ function MoneyRequestView({ // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing const shouldShowCategory = (isPolicyExpenseChat && (categoryForDisplay || hasEnabledOptions(policyCategories ?? {}))) || - (isExpenseUnreported && (!policyForMovingExpenses || hasEnabledOptions(policyCategories ?? {}))); + (isExpenseUnreported && (!policyForMovingExpenses || hasEnabledOptions(policyCategories ?? {}))) || + (isIOUReport(moneyRequestReport) && categoryForDisplay); // transactionTag can be an empty string // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing const shouldShowTag = (isPolicyExpenseChat || isExpenseUnreported) && (transactionTag || hasEnabledTags(policyTagLists)); @@ -803,8 +809,8 @@ function MoneyRequestView({ description={translate('common.category')} title={decodedCategoryName} numberOfLinesTitle={2} - interactive={canEdit} - shouldShowRightIcon={canEdit} + interactive={canEditCategory} + shouldShowRightIcon={canEditCategory} titleStyle={styles.flex1} onPress={() => { if (shouldNavigateToUpgradePath) { diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 6187c1be92c5..711f568d521b 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -4705,13 +4705,17 @@ function canEditFieldOfMoneyRequest( return false; } + const iouMessage = getOriginalMessage(reportAction); + const moneyRequestReport = report ?? (iouMessage?.IOUReportID ? (getReport(iouMessage?.IOUReportID, allReports) ?? ({} as Report)) : ({} as Report)); + // If we're editing fields such as category, tag, description, etc. the check above should be enough for handling the permission if (!restrictedFields.includes(fieldToEdit)) { + if (fieldToEdit === CONST.EDIT_REQUEST_FIELD.CATEGORY) { + return !isIOUReport(moneyRequestReport); + } return true; } - const iouMessage = getOriginalMessage(reportAction); - const moneyRequestReport = report ?? (iouMessage?.IOUReportID ? (getReport(iouMessage?.IOUReportID, allReports) ?? ({} as Report)) : ({} as Report)); const transaction = linkedTransaction ?? allTransactions?.[`${ONYXKEYS.COLLECTION.TRANSACTION}${iouMessage?.IOUTransactionID}`] ?? ({} as Transaction); if (isSettled(String(moneyRequestReport.reportID)) || isReportIDApproved(String(moneyRequestReport.reportID))) { From bc903eb34e2563c580fa907234815d6437b8abbe Mon Sep 17 00:00:00 2001 From: nkdengineer Date: Thu, 11 Dec 2025 15:44:34 +0700 Subject: [PATCH 2/5] hide category for 1:1 expense --- .../MoneyRequestReportTransactionList.tsx | 4 ++-- src/components/ReportActionItem/MoneyRequestView.tsx | 11 +++-------- src/components/TransactionItemRow/index.tsx | 4 ++-- src/libs/ReportUtils.ts | 8 ++------ src/libs/SearchUIUtils.ts | 9 +++++++-- 5 files changed, 16 insertions(+), 20 deletions(-) diff --git a/src/components/MoneyRequestReportView/MoneyRequestReportTransactionList.tsx b/src/components/MoneyRequestReportView/MoneyRequestReportTransactionList.tsx index 286103142f7e..d9302967eedf 100644 --- a/src/components/MoneyRequestReportView/MoneyRequestReportTransactionList.tsx +++ b/src/components/MoneyRequestReportView/MoneyRequestReportTransactionList.tsx @@ -265,9 +265,9 @@ function MoneyRequestReportTransactionList({ }, [newTransactions, sortBy, sortOrder, transactions, localeCompare, report]); const columnsToShow = useMemo(() => { - const columns = getColumnsToShow(currentUserDetails?.accountID, transactions, true); + const columns = getColumnsToShow(currentUserDetails?.accountID, transactions, true, undefined, isIOUReport(report)); return (Object.keys(columns) as SearchColumnType[]).filter((column) => columns[column]); - }, [transactions, currentUserDetails?.accountID]); + }, [transactions, currentUserDetails?.accountID, report]); const currentGroupBy = getReportLayoutGroupBy(reportLayoutGroupBy); diff --git a/src/components/ReportActionItem/MoneyRequestView.tsx b/src/components/ReportActionItem/MoneyRequestView.tsx index aaafae4ea360..cce1dc8fb242 100644 --- a/src/components/ReportActionItem/MoneyRequestView.tsx +++ b/src/components/ReportActionItem/MoneyRequestView.tsx @@ -279,10 +279,6 @@ function MoneyRequestView({ (!isPerDiemRequest || canSubmitPerDiemExpenseFromWorkspace(policy)), [isEditable, parentReportAction, isChatReportArchived, outstandingReportsByPolicyID, isPerDiemRequest, policy], ); - const canEditCategory = useMemo( - () => isEditable && canEditFieldOfMoneyRequest(parentReportAction, CONST.EDIT_REQUEST_FIELD.CATEGORY, undefined, isChatReportArchived), - [isEditable, parentReportAction, isChatReportArchived], - ); // A flag for verifying that the current report is a sub-report of a expense chat // if the policy of the report is either Collect or Control, then this report must be tied to expense chat @@ -297,8 +293,7 @@ function MoneyRequestView({ // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing const shouldShowCategory = (isPolicyExpenseChat && (categoryForDisplay || hasEnabledOptions(policyCategories ?? {}))) || - (isExpenseUnreported && (!policyForMovingExpenses || hasEnabledOptions(policyCategories ?? {}))) || - (isIOUReport(moneyRequestReport) && categoryForDisplay); + (isExpenseUnreported && (!policyForMovingExpenses || hasEnabledOptions(policyCategories ?? {}))); // transactionTag can be an empty string // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing const shouldShowTag = (isPolicyExpenseChat || isExpenseUnreported) && (transactionTag || hasEnabledTags(policyTagLists)); @@ -828,8 +823,8 @@ function MoneyRequestView({ description={translate('common.category')} title={decodedCategoryName} numberOfLinesTitle={2} - interactive={canEditCategory} - shouldShowRightIcon={canEditCategory} + interactive={canEdit} + shouldShowRightIcon={canEdit} titleStyle={styles.flex1} onPress={() => { if (shouldNavigateToUpgradePath) { diff --git a/src/components/TransactionItemRow/index.tsx b/src/components/TransactionItemRow/index.tsx index dc87752fdb4c..887f7f47aa2f 100644 --- a/src/components/TransactionItemRow/index.tsx +++ b/src/components/TransactionItemRow/index.tsx @@ -19,7 +19,7 @@ import useStyleUtils from '@hooks/useStyleUtils'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; import {isCategoryMissing} from '@libs/CategoryUtils'; -import {isSettled} from '@libs/ReportUtils'; +import {isIOUReport, isSettled} from '@libs/ReportUtils'; import StringUtils from '@libs/StringUtils'; import { getDescription, @@ -481,7 +481,7 @@ function TransactionItemRow({ - {hasCategoryOrTag && ( + {hasCategoryOrTag && !isIOUReport(report) && ( Date: Thu, 11 Dec 2025 15:52:15 +0700 Subject: [PATCH 3/5] fix lint --- .../MoneyRequestReportTransactionList.tsx | 7 +++---- src/components/ReportActionItem/MoneyRequestView.tsx | 1 - src/components/TransactionItemRow/index.tsx | 5 +++-- src/libs/SearchUIUtils.ts | 6 +++--- 4 files changed, 9 insertions(+), 10 deletions(-) diff --git a/src/components/MoneyRequestReportView/MoneyRequestReportTransactionList.tsx b/src/components/MoneyRequestReportView/MoneyRequestReportTransactionList.tsx index d9302967eedf..3a5d76bed454 100644 --- a/src/components/MoneyRequestReportView/MoneyRequestReportTransactionList.tsx +++ b/src/components/MoneyRequestReportView/MoneyRequestReportTransactionList.tsx @@ -5,7 +5,6 @@ import {View} from 'react-native'; import type {TupleToUnion} from 'type-fest'; import ButtonWithDropdownMenu from '@components/ButtonWithDropdownMenu'; import Checkbox from '@components/Checkbox'; -import * as Expensicons from '@components/Icon/Expensicons'; import MenuItem from '@components/MenuItem'; import Modal from '@components/Modal'; import OfflineWithFeedback from '@components/OfflineWithFeedback'; @@ -164,7 +163,7 @@ function MoneyRequestReportTransactionList({ useCopySelectionHelper(); const styles = useThemeStyles(); const StyleUtils = useStyleUtils(); - const expensifyIcons = useMemoizedLazyExpensifyIcons(['Location'] as const); + const expensifyIcons = useMemoizedLazyExpensifyIcons(['Location', 'CheckSquare'] as const); const {translate, localeCompare} = useLocalize(); // eslint-disable-next-line rulesdir/prefer-shouldUseNarrowLayout-instead-of-isSmallScreenWidth const {shouldUseNarrowLayout, isSmallScreenWidth, isMediumScreenWidth} = useResponsiveLayout(); @@ -187,7 +186,7 @@ function MoneyRequestReportTransactionList({ const addExpenseDropdownOptions = useMemo( () => getAddExpenseDropdownOptions(expensifyIcons, report?.reportID, policy, undefined, undefined, lastDistanceExpenseType), - [report?.reportID, policy, lastDistanceExpenseType, expensifyIcons], + [report?.reportID, policy, lastDistanceExpenseType, expensifyIcons.Location], ); const hasPendingAction = useMemo(() => { @@ -635,7 +634,7 @@ function MoneyRequestReportTransactionList({ > { if (!isMobileSelectionModeEnabled) { turnOnMobileSelectionMode(); diff --git a/src/components/ReportActionItem/MoneyRequestView.tsx b/src/components/ReportActionItem/MoneyRequestView.tsx index cce1dc8fb242..be9103a30421 100644 --- a/src/components/ReportActionItem/MoneyRequestView.tsx +++ b/src/components/ReportActionItem/MoneyRequestView.tsx @@ -50,7 +50,6 @@ import { getTransactionDetails, getTripIDFromTransactionParentReportID, isInvoiceReport, - isIOUReport, isPaidGroupPolicy, isReportApproved, isReportInGroupPolicy, diff --git a/src/components/TransactionItemRow/index.tsx b/src/components/TransactionItemRow/index.tsx index 887f7f47aa2f..c15775aaff2a 100644 --- a/src/components/TransactionItemRow/index.tsx +++ b/src/components/TransactionItemRow/index.tsx @@ -4,7 +4,6 @@ import type {StyleProp, ViewStyle} from 'react-native'; import type {ValueOf} from 'type-fest'; import Checkbox from '@components/Checkbox'; import Icon from '@components/Icon'; -import * as Expensicons from '@components/Icon/Expensicons'; import type {TransactionWithOptionalHighlight} from '@components/MoneyRequestReportView/MoneyRequestReportTransactionList'; import {PressableWithFeedback} from '@components/Pressable'; import RadioButton from '@components/RadioButton'; @@ -13,6 +12,7 @@ import ActionCell from '@components/SelectionListWithSections/Search/ActionCell' import DateCell from '@components/SelectionListWithSections/Search/DateCell'; import UserInfoCell from '@components/SelectionListWithSections/Search/UserInfoCell'; import Text from '@components/Text'; +import {useMemoizedLazyExpensifyIcons} from '@hooks/useLazyAsset'; import useLocalize from '@hooks/useLocalize'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useStyleUtils from '@hooks/useStyleUtils'; @@ -157,6 +157,7 @@ function TransactionItemRow({ const {translate} = useLocalize(); const StyleUtils = useStyleUtils(); const theme = useTheme(); + const expensifyIcons = useMemoizedLazyExpensifyIcons(['ArrowRight'] as const); const {isLargeScreenWidth} = useResponsiveLayout(); const hasCategoryOrTag = !isCategoryMissing(transactionItem?.category) || !!transactionItem.tag; const createdAt = getTransactionCreated(transactionItem); @@ -563,7 +564,7 @@ function TransactionItemRow({ {({hovered}) => { return ( Date: Wed, 17 Dec 2025 12:14:50 +0700 Subject: [PATCH 4/5] resolve conflict --- src/libs/SearchUIUtils.ts | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/src/libs/SearchUIUtils.ts b/src/libs/SearchUIUtils.ts index 45ba1c086e99..20416fd4dc06 100644 --- a/src/libs/SearchUIUtils.ts +++ b/src/libs/SearchUIUtils.ts @@ -2812,20 +2812,12 @@ function getColumnsToShow( const category = getCategory(transaction); if (category !== '' && category !== CONST.SEARCH.CATEGORY_EMPTY_VALUE) { -<<<<<<< HEAD - columns[CONST.REPORT.TRANSACTION_LIST.COLUMNS.CATEGORY] = !isExpenseReportViewFromIOUReport; -======= - columns[CONST.SEARCH.TABLE_COLUMNS.CATEGORY] = true; ->>>>>>> main + columns[CONST.SEARCH.TABLE_COLUMNS.CATEGORY] = !isExpenseReportViewFromIOUReport; } const tag = getTag(transaction); if (tag !== '' && tag !== CONST.SEARCH.TAG_EMPTY_VALUE) { -<<<<<<< HEAD - columns[CONST.REPORT.TRANSACTION_LIST.COLUMNS.TAG] = !isExpenseReportViewFromIOUReport; -======= - columns[CONST.SEARCH.TABLE_COLUMNS.TAG] = true; ->>>>>>> main + columns[CONST.SEARCH.TABLE_COLUMNS.TAG] = !isExpenseReportViewFromIOUReport; } if (isExpenseReportView) { @@ -2844,8 +2836,8 @@ function getColumnsToShow( columns[CONST.SEARCH.TABLE_COLUMNS.FROM] = true; } - columns[CONST.REPORT.TRANSACTION_LIST.COLUMNS.CATEGORY] = columns[CONST.REPORT.TRANSACTION_LIST.COLUMNS.CATEGORY] && !isIOUReportReportUtil(report); - columns[CONST.REPORT.TRANSACTION_LIST.COLUMNS.TAG] = columns[CONST.REPORT.TRANSACTION_LIST.COLUMNS.TAG] && !isIOUReportReportUtil(report); + columns[CONST.SEARCH.TABLE_COLUMNS.CATEGORY] = columns[CONST.SEARCH.TABLE_COLUMNS.CATEGORY] && !isIOUReportReportUtil(report); + columns[CONST.SEARCH.TABLE_COLUMNS.TAG] = columns[CONST.SEARCH.TABLE_COLUMNS.TAG] && !isIOUReportReportUtil(report); // eslint-disable-next-line @typescript-eslint/no-deprecated const toFieldValue = getToFieldValueForTransaction(transaction as SearchTransaction, report, data.personalDetailsList, reportAction); From cfed4ed2ad86e0e1247b1b971eeb7cf501da5b2f Mon Sep 17 00:00:00 2001 From: nkdengineer Date: Wed, 17 Dec 2025 14:42:33 +0700 Subject: [PATCH 5/5] fix category is shown --- src/libs/SearchUIUtils.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/libs/SearchUIUtils.ts b/src/libs/SearchUIUtils.ts index 20416fd4dc06..9d570354aca0 100644 --- a/src/libs/SearchUIUtils.ts +++ b/src/libs/SearchUIUtils.ts @@ -1182,6 +1182,7 @@ function getTransactionsSections( // Use Map.get() for faster lookups with default values const from = reportAction?.actorAccountID ? (personalDetailsMap.get(reportAction.actorAccountID.toString()) ?? emptyPersonalDetails) : emptyPersonalDetails; const to = getToFieldValueForTransaction(transactionItem, report, data.personalDetailsList, reportAction); + const isIOUReport = report?.type === CONST.REPORT.TYPE.IOU; const {formattedFrom, formattedTo, formattedTotal, formattedMerchant, date, submitted, approved, posted} = getTransactionItemCommonFormattedProperties( transactionItem, @@ -1219,6 +1220,7 @@ function getTransactionsSections( isAmountColumnWide: shouldShowAmountInWideColumn, isTaxAmountColumnWide: shouldShowTaxAmountInWideColumn, violations: transactionViolations, + category: isIOUReport ? '' : transactionItem?.category, }; transactionsSections.push(transactionSection); @@ -1713,6 +1715,7 @@ function getReportSections( const actions = Object.values(reportActions[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${transactionItem.reportID}`] ?? {}); const from = reportAction?.actorAccountID ? (data.personalDetailsList?.[reportAction.actorAccountID] ?? emptyPersonalDetails) : emptyPersonalDetails; const to = getToFieldValueForTransaction(transactionItem, report, data.personalDetailsList, reportAction); + const isIOUReport = report?.type === CONST.REPORT.TYPE.IOU; const {formattedFrom, formattedTo, formattedTotal, formattedMerchant, date} = getTransactionItemCommonFormattedProperties( transactionItem, @@ -1748,6 +1751,7 @@ function getReportSections( violations: transactionViolations, isAmountColumnWide: shouldShowAmountInWideColumn, isTaxAmountColumnWide: shouldShowTaxAmountInWideColumn, + category: isIOUReport ? '' : transactionItem?.category, }; if (reportIDToTransactions[reportKey]?.transactions) { reportIDToTransactions[reportKey].transactions.push(transaction);