From a613734ff83645b2cd9d27ad6438ffcaab457ada Mon Sep 17 00:00:00 2001 From: DylanDylann Date: Mon, 15 Dec 2025 15:59:33 +0700 Subject: [PATCH 01/10] cleanup-searchTransaction --- src/components/Search/index.tsx | 4 +- .../SelectionListWithSections/types.ts | 5 +- src/libs/SearchUIUtils.ts | 37 ++---- src/libs/TransactionUtils/index.ts | 25 +--- src/libs/actions/IOU.ts | 7 +- src/libs/actions/Search.ts | 4 +- src/types/onyx/SearchResults.ts | 118 +----------------- 7 files changed, 27 insertions(+), 173 deletions(-) diff --git a/src/components/Search/index.tsx b/src/components/Search/index.tsx index 508b3f61b2cc..0c42d7d983dd 100644 --- a/src/components/Search/index.tsx +++ b/src/components/Search/index.tsx @@ -69,7 +69,6 @@ import SCREENS from '@src/SCREENS'; import {isActionLoadingSetSelector} from '@src/selectors/ReportMetaData'; import type {OutstandingReportsByPolicyIDDerivedValue, Transaction} from '@src/types/onyx'; import type SearchResults from '@src/types/onyx/SearchResults'; -import type {SearchTransaction} from '@src/types/onyx/SearchResults'; import type {TransactionViolation} from '@src/types/onyx/TransactionViolation'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; import arraysEqual from '@src/utils/arraysEqual'; @@ -298,8 +297,7 @@ function Search({ const transactionKeys = Object.keys(searchResults.data).filter((key) => key.startsWith(ONYXKEYS.COLLECTION.TRANSACTION)); for (const key of transactionKeys) { - // eslint-disable-next-line @typescript-eslint/no-deprecated - const transaction = searchResults.data[key as keyof typeof searchResults.data] as SearchTransaction; + const transaction = searchResults.data[key as keyof typeof searchResults.data] as Transaction; if (!transaction || typeof transaction !== 'object' || !('transactionID' in transaction) || !('reportID' in transaction)) { continue; } diff --git a/src/components/SelectionListWithSections/types.ts b/src/components/SelectionListWithSections/types.ts index d7d04dc9c4f5..6d163fd2d755 100644 --- a/src/components/SelectionListWithSections/types.ts +++ b/src/components/SelectionListWithSections/types.ts @@ -28,7 +28,7 @@ import type CONST from '@src/CONST'; import type {PersonalDetails, PersonalDetailsList, Policy, Report, ReportAction, SearchResults, TransactionViolation, TransactionViolations} from '@src/types/onyx'; import type {Attendee, SplitExpense} from '@src/types/onyx/IOU'; import type {Errors, Icon, PendingAction} from '@src/types/onyx/OnyxCommon'; -import type {SearchCardGroup, SearchDataTypes, SearchMemberGroup, SearchTask, SearchTransaction, SearchTransactionAction, SearchWithdrawalIDGroup} from '@src/types/onyx/SearchResults'; +import type {SearchCardGroup, SearchDataTypes, SearchMemberGroup, SearchTask, SearchTransactionAction, SearchWithdrawalIDGroup} from '@src/types/onyx/SearchResults'; import type {ReceiptErrors} from '@src/types/onyx/Transaction'; import type Transaction from '@src/types/onyx/Transaction'; import type ChildrenProps from '@src/types/utils/ChildrenProps'; @@ -238,8 +238,7 @@ type ListItem = { }; type TransactionListItemType = ListItem & - // eslint-disable-next-line @typescript-eslint/no-deprecated - SearchTransaction & { + Transaction & { /** Report to which the transaction belongs */ report: Report | undefined; diff --git a/src/libs/SearchUIUtils.ts b/src/libs/SearchUIUtils.ts index caf32aa867c2..08246c7f97e9 100644 --- a/src/libs/SearchUIUtils.ts +++ b/src/libs/SearchUIUtils.ts @@ -54,7 +54,6 @@ import type { SearchDataTypes, SearchMemberGroup, SearchTask, - SearchTransaction, SearchTransactionAction, SearchWithdrawalIDGroup, } from '@src/types/onyx/SearchResults'; @@ -640,8 +639,7 @@ function getSuggestedSearchesVisibility( * Returns a list of properties that are common to every Search ListItem */ function getTransactionItemCommonFormattedProperties( - // eslint-disable-next-line @typescript-eslint/no-deprecated - transactionItem: SearchTransaction, + transactionItem: OnyxTypes.Transaction, from: OnyxTypes.PersonalDetails, to: OnyxTypes.PersonalDetails, policy: OnyxTypes.Policy, @@ -790,15 +788,13 @@ function isAmountTooLong(amount: number, maxLength = 8): boolean { return Math.abs(amount).toString().length >= maxLength; } -// eslint-disable-next-line @typescript-eslint/no-deprecated -function isTransactionAmountTooLong(transactionItem: TransactionListItemType | SearchTransaction | OnyxTypes.Transaction) { +function isTransactionAmountTooLong(transactionItem: TransactionListItemType | OnyxTypes.Transaction) { // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing const amount = Math.abs(transactionItem.modifiedAmount || transactionItem.amount); return isAmountTooLong(amount); } -// eslint-disable-next-line @typescript-eslint/no-deprecated -function isTransactionTaxAmountTooLong(transactionItem: TransactionListItemType | SearchTransaction | OnyxTypes.Transaction) { +function isTransactionTaxAmountTooLong(transactionItem: TransactionListItemType | OnyxTypes.Transaction) { // it won't matter if pass true or false as second argument to getTaxAmount here because isAmountTooLong function uses Math.abs on the returned value of getTaxAmount const taxAmount = getTaxAmount(transactionItem, false); return isAmountTooLong(taxAmount); @@ -811,8 +807,7 @@ function getWideAmountIndicators(data: TransactionListItemType[] | TransactionGr let isAmountWide = false; let isTaxAmountWide = false; - // eslint-disable-next-line @typescript-eslint/no-deprecated - const processTransaction = (transaction: TransactionListItemType | SearchTransaction) => { + const processTransaction = (transaction: TransactionListItemType | OnyxTypes.Transaction) => { isAmountWide ||= isTransactionAmountTooLong(transaction); isTaxAmountWide ||= isTransactionTaxAmountTooLong(transaction); }; @@ -937,8 +932,7 @@ function getIOUReportName(data: OnyxTypes.SearchResults['data'], reportItem: Tra function getTransactionViolations( allViolations: OnyxCollection, - // eslint-disable-next-line @typescript-eslint/no-deprecated - transaction: SearchTransaction, + transaction: OnyxTypes.Transaction, currentUserEmail: string, currentUserAccountID: number, report: OnyxEntry, @@ -1144,14 +1138,11 @@ function getTransactionsSections( * Retrieves all transactions associated with a specific report ID from the search data. */ -// eslint-disable-next-line @typescript-eslint/no-deprecated -function getTransactionsForReport(data: OnyxTypes.SearchResults['data'], reportID: string): SearchTransaction[] { +function getTransactionsForReport(data: OnyxTypes.SearchResults['data'], reportID: string): OnyxTypes.Transaction[] { return ( Object.entries(data) - // eslint-disable-next-line @typescript-eslint/no-deprecated - .filter(([key, value]) => isTransactionEntry(key) && (value as SearchTransaction)?.reportID === reportID) - // eslint-disable-next-line @typescript-eslint/no-deprecated - .map(([, value]) => value as SearchTransaction) + .filter(([key, value]) => isTransactionEntry(key) && (value as OnyxTypes.Transaction)?.reportID === reportID) + .map(([, value]) => value as OnyxTypes.Transaction) ); } @@ -1243,8 +1234,7 @@ function getActions( } const allActions: SearchTransactionAction[] = []; - // eslint-disable-next-line @typescript-eslint/no-deprecated - let allReportTransactions: SearchTransaction[]; + let allReportTransactions: OnyxTypes.Transaction[]; if (isReportEntry(key)) { allReportTransactions = getTransactionsForReport(data, report.reportID); } else { @@ -2029,8 +2019,7 @@ function isSearchResultsEmpty(searchResults: SearchResults, groupBy?: SearchGrou return !Object.keys(searchResults?.data).some( (key) => key.startsWith(ONYXKEYS.COLLECTION.TRANSACTION) && - // eslint-disable-next-line @typescript-eslint/no-deprecated - (searchResults?.data[key as keyof typeof searchResults.data] as SearchTransaction)?.pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE, + (searchResults?.data[key as keyof typeof searchResults.data] as OnyxTypes.Transaction)?.pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE, ); } @@ -2496,8 +2485,7 @@ function getColumnsToShow( }; const {moneyRequestReportActionsByTransactionID} = Array.isArray(data) ? {} : createReportActionsLookupMaps(data); - // eslint-disable-next-line @typescript-eslint/no-deprecated - const updateColumns = (transaction: OnyxTypes.Transaction | SearchTransaction) => { + const updateColumns = (transaction: OnyxTypes.Transaction) => { const merchant = transaction.modifiedMerchant ? transaction.modifiedMerchant : (transaction.merchant ?? ''); if ((merchant !== '' && merchant !== CONST.TRANSACTION.PARTIAL_TRANSACTION_MERCHANT) || isScanning(transaction)) { columns[CONST.REPORT.TRANSACTION_LIST.COLUMNS.MERCHANT] = true; @@ -2533,8 +2521,7 @@ function getColumnsToShow( columns[CONST.REPORT.TRANSACTION_LIST.COLUMNS.FROM] = true; } - // eslint-disable-next-line @typescript-eslint/no-deprecated - const toFieldValue = getToFieldValueForTransaction(transaction as SearchTransaction, report, data.personalDetailsList, reportAction); + const toFieldValue = getToFieldValueForTransaction(transaction, report, data.personalDetailsList, reportAction); if (toFieldValue.accountID && toFieldValue.accountID !== currentAccountID && !columns[CONST.REPORT.TRANSACTION_LIST.COLUMNS.TO]) { columns[CONST.REPORT.TRANSACTION_LIST.COLUMNS.TO] = !!report && !isOpenReport(report); } diff --git a/src/libs/TransactionUtils/index.ts b/src/libs/TransactionUtils/index.ts index a6212b53872c..a454b0ff7567 100644 --- a/src/libs/TransactionUtils/index.ts +++ b/src/libs/TransactionUtils/index.ts @@ -69,8 +69,6 @@ import type {Attendee, Participant, SplitExpense} from '@src/types/onyx/IOU'; import type {Errors, PendingAction} from '@src/types/onyx/OnyxCommon'; import type {CurrentUserPersonalDetails} from '@src/types/onyx/PersonalDetails'; import type {OnyxData} from '@src/types/onyx/Request'; -// eslint-disable-next-line @typescript-eslint/no-deprecated -import type {SearchTransaction} from '@src/types/onyx/SearchResults'; import type { Comment, Receipt, @@ -1132,8 +1130,7 @@ function hasMissingSmartscanFields(transaction: OnyxInputOrEntry, r * Get all transaction violations of the transaction with given transactionID. */ function getTransactionViolations( - // eslint-disable-next-line @typescript-eslint/no-deprecated - transaction: OnyxEntry, + transaction: OnyxEntry, transactionViolations: OnyxCollection, currentUserEmail: string, currentUserAccountID: number, @@ -1178,8 +1175,7 @@ function hasPendingRTERViolation(transactionViolations?: TransactionViolations | * Check if there is broken connection violation. */ function hasBrokenConnectionViolation( - // eslint-disable-next-line @typescript-eslint/no-deprecated - transaction: Transaction | SearchTransaction, + transaction: Transaction, transactionViolations: OnyxCollection | undefined, currentUserEmail: string, currentUserAccountID: number, @@ -1316,8 +1312,7 @@ function shouldShowViolation( * Check if there is pending rter violation in all transactionViolations with given transactionIDs. */ function allHavePendingRTERViolation( - // eslint-disable-next-line @typescript-eslint/no-deprecated - transactions: OnyxEntry, + transactions: OnyxEntry, transactionViolations: OnyxCollection | undefined, currentUserEmail: string, currentUserAccountID: number, @@ -1351,8 +1346,7 @@ function checkIfShouldShowMarkAsCashButton(hasRTERPendingViolation: boolean, sho * Check if there is any transaction without RTER violation within the given transactionIDs. */ function hasAnyTransactionWithoutRTERViolation( - // eslint-disable-next-line @typescript-eslint/no-deprecated - transactions: Transaction[] | SearchTransaction[], + transactions: Transaction[], transactionViolations: OnyxCollection | undefined, currentUserEmail: string, currentUserAccountID: number, @@ -1564,16 +1558,9 @@ function hasViolation( ); } -function hasDuplicateTransactions( - currentUserEmail: string, - currentUserAccountID: number, - iouReport: OnyxEntry, - policy: OnyxEntry, - // eslint-disable-next-line @typescript-eslint/no-deprecated - allReportTransactions?: SearchTransaction[], -): boolean { +function hasDuplicateTransactions(currentUserEmail: string, currentUserAccountID: number, iouReport: OnyxEntry, policy: OnyxEntry): boolean { const transactionsByIouReportID = getReportTransactions(iouReport?.reportID); - const reportTransactions = allReportTransactions ?? transactionsByIouReportID; + const reportTransactions = transactionsByIouReportID; return reportTransactions.length > 0 && reportTransactions.some((transaction) => isDuplicate(transaction, currentUserEmail, currentUserAccountID, iouReport, policy)); } diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 3456d99b66ed..bdc9d922a93f 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -255,7 +255,6 @@ import type RecentlyUsedTags from '@src/types/onyx/RecentlyUsedTags'; import type {InvoiceReceiver, InvoiceReceiverType} from '@src/types/onyx/Report'; import type ReportAction from '@src/types/onyx/ReportAction'; import type {OnyxData} from '@src/types/onyx/Request'; -import type {SearchTransaction} from '@src/types/onyx/SearchResults'; import type {Comment, Receipt, ReceiptSource, Routes, SplitShares, TransactionChanges, TransactionCustomUnit, WaypointCollection} from '@src/types/onyx/Transaction'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; import {clearByKey as clearPdfByOnyxKey} from './CachedPDFPaths'; @@ -10626,8 +10625,7 @@ function canIOUBePaid( iouReport: OnyxTypes.OnyxInputOrEntry, chatReport: OnyxTypes.OnyxInputOrEntry, policy: OnyxTypes.OnyxInputOrEntry, - // eslint-disable-next-line @typescript-eslint/no-deprecated - transactions?: OnyxTypes.Transaction[] | SearchTransaction[], + transactions?: OnyxTypes.Transaction[], onlyShowPayElsewhere = false, chatReportRNVP?: OnyxTypes.ReportNameValuePairs, invoiceReceiverPolicy?: OnyxTypes.Policy, @@ -10706,8 +10704,7 @@ function canCancelPayment(iouReport: OnyxEntry, session: OnyxE function canSubmitReport( report: OnyxEntry, policy: OnyxEntry, - // eslint-disable-next-line @typescript-eslint/no-deprecated - transactions: OnyxTypes.Transaction[] | SearchTransaction[], + transactions: OnyxTypes.Transaction[], allViolations: OnyxCollection | undefined, isReportArchived: boolean, currentUserEmailParam: string, diff --git a/src/libs/actions/Search.ts b/src/libs/actions/Search.ts index f98c0c83bdd0..6cdcc2243299 100644 --- a/src/libs/actions/Search.ts +++ b/src/libs/actions/Search.ts @@ -45,7 +45,6 @@ import type {SearchAdvancedFiltersForm} from '@src/types/form/SearchAdvancedFilt import type {ExportTemplate, LastPaymentMethod, LastPaymentMethodType, Policy, Report, ReportAction, ReportActions, Transaction} from '@src/types/onyx'; import type {PaymentInformation} from '@src/types/onyx/LastPaymentMethod'; import type {ConnectionName} from '@src/types/onyx/Policy'; -import type {SearchTransaction} from '@src/types/onyx/SearchResults'; import type Nullable from '@src/types/utils/Nullable'; import SafeString from '@src/utils/SafeString'; import {setPersonalBankAccountContinueKYCOnSuccess} from './BankAccounts'; @@ -83,8 +82,7 @@ function handleActionButtonPress( ) { // The transactionIDList is needed to handle actions taken on `status:""` where transactions on single expense reports can be approved/paid. // We need the transactionID to display the loading indicator for that list item's action. - // eslint-disable-next-line @typescript-eslint/no-deprecated - const allReportTransactions = (isTransactionGroupListItemType(item) ? item.transactions : [item]) as SearchTransaction[]; + const allReportTransactions = (isTransactionGroupListItemType(item) ? item.transactions : [item]) as Transaction[]; const hasHeldExpense = hasHeldExpenses('', allReportTransactions); if (hasHeldExpense && item.action !== CONST.SEARCH.ACTION_TYPES.SUBMIT) { diff --git a/src/types/onyx/SearchResults.ts b/src/types/onyx/SearchResults.ts index 8b90d653cbbb..a8cb38032a22 100644 --- a/src/types/onyx/SearchResults.ts +++ b/src/types/onyx/SearchResults.ts @@ -4,7 +4,6 @@ import type ChatListItem from '@components/SelectionListWithSections/ChatListIte import type TransactionGroupListItem from '@components/SelectionListWithSections/Search/TransactionGroupListItem'; import type TransactionListItem from '@components/SelectionListWithSections/Search/TransactionListItem'; import type {ReportActionListItemType, TaskListItemType, TransactionGroupListItemType, TransactionListItemType} from '@components/SelectionListWithSections/types'; -import type {IOURequestType} from '@libs/actions/IOU'; import type CONST from '@src/CONST'; import type ONYXKEYS from '@src/ONYXKEYS'; import type {BankName} from './Bank'; @@ -12,6 +11,7 @@ import type * as OnyxCommon from './OnyxCommon'; import type PersonalDetails from './PersonalDetails'; import type Policy from './Policy'; import type Report from './Report'; +import type Transaction from './Transaction'; import type ReportAction from './ReportAction'; import type ReportNameValuePairs from './ReportNameValuePairs'; import type {TransactionViolation} from './TransactionViolation'; @@ -69,105 +69,6 @@ type SearchResultsInfo = { /** The action that can be performed for the transaction */ type SearchTransactionAction = ValueOf; -/** Model of transaction search result - * - * @deprecated - Use Transaction instead - */ -type SearchTransaction = { - /** The ID of the transaction */ - transactionID: string; - - /** 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; - - /** The edited transaction merchant */ - modifiedMerchant: string; - - /** The receipt object */ - receipt?: { - /** Source of the receipt */ - source?: string; - - /** State of the receipt */ - state?: ValueOf; - - /** The name of the file of the receipt */ - filename?: string; - }; - - /** The transaction tag */ - tag: string; - - /** The transaction description */ - comment?: { - /** Content of the transaction description */ - comment?: string; - - /** The HOLD report action ID if the transaction is on hold */ - hold?: string; - }; - - /** The transaction category */ - category: string; - - /** The ID of the parent of the transaction */ - parentTransactionID?: string; - - /** If the transaction has an Ereceipt */ - hasEReceipt?: boolean; - - /** Used during the creation flow before the transaction is saved to the server */ - iouRequestType?: IOURequestType; - - /** The transaction tax amount */ - taxAmount?: number; - - /** The ID of the report the transaction is associated with */ - reportID: string; - - /** The MCC Group associated with the transaction */ - mccGroup?: ValueOf; - - /** The modified MCC Group associated with the transaction */ - modifiedMCCGroup?: ValueOf; - - /** Whether the transaction has violations or errors */ - errors?: OnyxCommon.Errors; - - /** The type of action that's pending */ - pendingAction?: OnyxCommon.PendingAction; - - /** The CC for this transaction */ - cardID?: number; - - /** The display name of the purchaser card, if any */ - cardName?: string; - - /** The transaction converted amount in `groupCurrency` currency */ - groupAmount?: number; - - /** The group currency if the transaction is grouped. Defaults to the active policy currency if group has no target currency */ - groupCurrency?: string; -}; - /** Model of tasks search result */ type SearchTask = { /** The type of the response */ @@ -281,8 +182,7 @@ type SearchResults = { search: SearchResultsInfo; /** Search results data */ - // eslint-disable-next-line @typescript-eslint/no-deprecated - data: PrefixedRecord & + data: PrefixedRecord & Record> & PrefixedRecord> & PrefixedRecord & @@ -300,16 +200,4 @@ type SearchResults = { export default SearchResults; -export type { - ListItemType, - ListItemDataType, - SearchTask, - // eslint-disable-next-line @typescript-eslint/no-deprecated - SearchTransaction, - SearchTransactionAction, - SearchDataTypes, - SearchResultsInfo, - SearchMemberGroup, - SearchCardGroup, - SearchWithdrawalIDGroup, -}; +export type {ListItemType, ListItemDataType, SearchTask, SearchTransactionAction, SearchDataTypes, SearchResultsInfo, SearchMemberGroup, SearchCardGroup, SearchWithdrawalIDGroup}; From 34f6506fe5e69357220078e490190017ff54c339 Mon Sep 17 00:00:00 2001 From: DylanDylann Date: Mon, 15 Dec 2025 16:05:52 +0700 Subject: [PATCH 02/10] prettier --- src/libs/SearchUIUtils.ts | 8 +++----- src/types/onyx/SearchResults.ts | 2 +- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/libs/SearchUIUtils.ts b/src/libs/SearchUIUtils.ts index 08246c7f97e9..48097fb14699 100644 --- a/src/libs/SearchUIUtils.ts +++ b/src/libs/SearchUIUtils.ts @@ -1139,11 +1139,9 @@ function getTransactionsSections( */ function getTransactionsForReport(data: OnyxTypes.SearchResults['data'], reportID: string): OnyxTypes.Transaction[] { - return ( - Object.entries(data) - .filter(([key, value]) => isTransactionEntry(key) && (value as OnyxTypes.Transaction)?.reportID === reportID) - .map(([, value]) => value as OnyxTypes.Transaction) - ); + return Object.entries(data) + .filter(([key, value]) => isTransactionEntry(key) && (value as OnyxTypes.Transaction)?.reportID === reportID) + .map(([, value]) => value as OnyxTypes.Transaction); } /** diff --git a/src/types/onyx/SearchResults.ts b/src/types/onyx/SearchResults.ts index a8cb38032a22..53b4fd9ef0d6 100644 --- a/src/types/onyx/SearchResults.ts +++ b/src/types/onyx/SearchResults.ts @@ -11,9 +11,9 @@ import type * as OnyxCommon from './OnyxCommon'; import type PersonalDetails from './PersonalDetails'; import type Policy from './Policy'; import type Report from './Report'; -import type Transaction from './Transaction'; import type ReportAction from './ReportAction'; import type ReportNameValuePairs from './ReportNameValuePairs'; +import type Transaction from './Transaction'; import type {TransactionViolation} from './TransactionViolation'; /** Types of search data */ From c6ca6b646e7b7872499151d8b80798bc2f46924e Mon Sep 17 00:00:00 2001 From: DylanDylann Date: Mon, 15 Dec 2025 16:40:15 +0700 Subject: [PATCH 03/10] fix typecheck --- src/components/Search/index.tsx | 3 ++- src/components/Search/types.ts | 4 ++-- .../SelectionListWithSections/types.ts | 2 +- .../WideRHPContextProvider/index.tsx | 5 ++++- .../WideRHPContextProvider/types.ts | 2 +- src/libs/actions/Search.ts | 19 ++++++++++++++----- 6 files changed, 24 insertions(+), 11 deletions(-) diff --git a/src/components/Search/index.tsx b/src/components/Search/index.tsx index 0c42d7d983dd..c843aed8e9ab 100644 --- a/src/components/Search/index.tsx +++ b/src/components/Search/index.tsx @@ -123,7 +123,7 @@ function mapTransactionItemToSelectedEntry( ), action: item.action, groupCurrency: item.groupCurrency, - reportID: item.reportID, + reportID: item?.reportID, policyID: item.report?.policyID, amount: item.modifiedAmount ?? item.amount, groupAmount: item.groupAmount, @@ -216,6 +216,7 @@ function prepareTransactionsList( action: item.action, reportID: item.reportID, policyID: item.policyID, + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing amount: Math.abs(item.modifiedAmount || item.amount), groupAmount: item.groupAmount, groupCurrency: item.groupCurrency, diff --git a/src/components/Search/types.ts b/src/components/Search/types.ts index 8f5beab5e9c6..27a9d049c077 100644 --- a/src/components/Search/types.ts +++ b/src/components/Search/types.ts @@ -36,7 +36,7 @@ type SelectedTransactionInfo = { action: ValueOf; /** The reportID of the transaction */ - reportID: string; + reportID: string | undefined; /** The policyID tied to the report the transaction is reported on */ policyID: string | undefined; @@ -65,7 +65,7 @@ type SelectedTransactions = Record; /** Model of selected reports */ type SelectedReports = { - reportID: string; + reportID: string | undefined; policyID: string | undefined; action: ValueOf; allActions: Array>; diff --git a/src/components/SelectionListWithSections/types.ts b/src/components/SelectionListWithSections/types.ts index 6d163fd2d755..104bae137231 100644 --- a/src/components/SelectionListWithSections/types.ts +++ b/src/components/SelectionListWithSections/types.ts @@ -166,7 +166,7 @@ type ListItem = { icons?: Icon[]; /** Errors that this user may contain */ - errors?: Errors; + errors?: Errors | ReceiptErrors; /** The type of action that's pending */ pendingAction?: PendingAction; diff --git a/src/components/WideRHPContextProvider/index.tsx b/src/components/WideRHPContextProvider/index.tsx index b030bf0baf60..f4d84b0625d3 100644 --- a/src/components/WideRHPContextProvider/index.tsx +++ b/src/components/WideRHPContextProvider/index.tsx @@ -199,7 +199,10 @@ function WideRHPContextProvider({children}: React.PropsWithChildren) { * It helps us open expense as wide, before it fully loads. */ const markReportIDAsExpense = useCallback( - (reportID: string) => { + (reportID?: string) => { + if (!reportID) { + return; + } const report = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]; const isInvoice = report?.type === CONST.REPORT.TYPE.INVOICE; const isTask = report?.type === CONST.REPORT.TYPE.TASK; diff --git a/src/components/WideRHPContextProvider/types.ts b/src/components/WideRHPContextProvider/types.ts index 76f6d2df7adc..db6c01379cb0 100644 --- a/src/components/WideRHPContextProvider/types.ts +++ b/src/components/WideRHPContextProvider/types.ts @@ -32,7 +32,7 @@ type WideRHPContextType = { removeSuperWideRHPRouteKey: (route: NavigationRoute) => void; // Mark reportID as expense before condition check - markReportIDAsExpense: (reportID: string) => void; + markReportIDAsExpense: (reportID?: string) => void; // Mark reportID as multi-transaction expense before condition check markReportIDAsMultiTransactionExpense: (reportID: string) => void; diff --git a/src/libs/actions/Search.ts b/src/libs/actions/Search.ts index 6cdcc2243299..e061eea7324e 100644 --- a/src/libs/actions/Search.ts +++ b/src/libs/actions/Search.ts @@ -107,14 +107,14 @@ function handleActionButtonPress( onDEWModalOpen?.(); return; } - approveMoneyRequestOnSearch(hash, [item.reportID], currentSearchKey); + approveMoneyRequestOnSearch(hash, item.reportID ? [item.reportID] : [], currentSearchKey); return; case CONST.SEARCH.ACTION_TYPES.SUBMIT: { if (hasDynamicExternalWorkflow(snapshotPolicy)) { onDEWModalOpen?.(); return; } - submitMoneyRequestOnSearch(hash, [item], [snapshotPolicy], currentSearchKey); + submitMoneyRequestOnSearch(hash, [item as Report], [snapshotPolicy], currentSearchKey); return; } case CONST.SEARCH.ACTION_TYPES.EXPORT_TO_ACCOUNTING: { @@ -129,7 +129,7 @@ function handleActionButtonPress( return; } - exportToIntegrationOnSearch(hash, item.reportID, connectedIntegration, currentSearchKey); + exportToIntegrationOnSearch(hash, item?.reportID, connectedIntegration, currentSearchKey); return; } default: @@ -194,6 +194,10 @@ function getPayActionCallback( ) { const lastPolicyPaymentMethod = getLastPolicyPaymentMethod(item.policyID, lastPaymentMethod, getReportType(item.reportID)); + if (!item.reportID) { + return; + } + if (!lastPolicyPaymentMethod || !Object.values(CONST.IOU.PAYMENT_TYPE).includes(lastPolicyPaymentMethod)) { goToItem(); return; @@ -553,7 +557,10 @@ function approveMoneyRequestOnSearch(hash: number, reportIDList: string[], curre API.write(WRITE_COMMANDS.APPROVE_MONEY_REQUEST_ON_SEARCH, {hash, reportIDList}, {optimisticData, failureData, successData}); } -function exportToIntegrationOnSearch(hash: number, reportID: string, connectionName: ConnectionName, currentSearchKey?: SearchKey) { +function exportToIntegrationOnSearch(hash: number, reportID: string | undefined, connectionName: ConnectionName, currentSearchKey?: SearchKey) { + if (!reportID) { + return; + } const optimisticAction = buildOptimisticExportIntegrationAction(connectionName); const successAction: OptimisticExportIntegrationAction = {...optimisticAction, pendingAction: null}; const optimisticReportActionID = optimisticAction.reportActionID; @@ -980,7 +987,9 @@ function shouldShowBulkOptionForRemainingTransactions(selectedTransactions: Sele if (!selectedTransactions || isEmpty(selectedTransactions)) { return true; } - const neededFilterTransactions = transactionKeys?.filter((transactionIDKey) => !selectedReportIDs?.includes(selectedTransactions[transactionIDKey].reportID)); + const neededFilterTransactions = transactionKeys?.filter( + (transactionIDKey) => selectedTransactions[transactionIDKey]?.reportID && !selectedReportIDs?.includes(selectedTransactions[transactionIDKey]?.reportID), + ); if (!neededFilterTransactions?.length) { return true; } From 5d79dee2933214abe987d15dc5cae084d56eb01f Mon Sep 17 00:00:00 2001 From: DylanDylann Date: Mon, 15 Dec 2025 17:47:43 +0700 Subject: [PATCH 04/10] fix typecheck --- src/components/Search/index.tsx | 2 +- src/components/Search/types.ts | 4 ++-- src/components/SelectionListWithSections/types.ts | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/components/Search/index.tsx b/src/components/Search/index.tsx index c843aed8e9ab..fd19d5b0f020 100644 --- a/src/components/Search/index.tsx +++ b/src/components/Search/index.tsx @@ -123,7 +123,7 @@ function mapTransactionItemToSelectedEntry( ), action: item.action, groupCurrency: item.groupCurrency, - reportID: item?.reportID, + reportID: item.reportID, policyID: item.report?.policyID, amount: item.modifiedAmount ?? item.amount, groupAmount: item.groupAmount, diff --git a/src/components/Search/types.ts b/src/components/Search/types.ts index 27a9d049c077..8f5beab5e9c6 100644 --- a/src/components/Search/types.ts +++ b/src/components/Search/types.ts @@ -36,7 +36,7 @@ type SelectedTransactionInfo = { action: ValueOf; /** The reportID of the transaction */ - reportID: string | undefined; + reportID: string; /** The policyID tied to the report the transaction is reported on */ policyID: string | undefined; @@ -65,7 +65,7 @@ type SelectedTransactions = Record; /** Model of selected reports */ type SelectedReports = { - reportID: string | undefined; + reportID: string; policyID: string | undefined; action: ValueOf; allActions: Array>; diff --git a/src/components/SelectionListWithSections/types.ts b/src/components/SelectionListWithSections/types.ts index 104bae137231..d39f77b63735 100644 --- a/src/components/SelectionListWithSections/types.ts +++ b/src/components/SelectionListWithSections/types.ts @@ -180,7 +180,7 @@ type ListItem = { index?: number; /** ID of the report */ - reportID?: string; + reportID: string; /** ID of the policy */ policyID?: string; From 946cb1ff23f4dd869f6060de8afb439824918005 Mon Sep 17 00:00:00 2001 From: DylanDylann Date: Mon, 15 Dec 2025 18:03:06 +0700 Subject: [PATCH 05/10] add optional reportID back --- src/components/SelectionListWithSections/types.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/SelectionListWithSections/types.ts b/src/components/SelectionListWithSections/types.ts index d39f77b63735..104bae137231 100644 --- a/src/components/SelectionListWithSections/types.ts +++ b/src/components/SelectionListWithSections/types.ts @@ -180,7 +180,7 @@ type ListItem = { index?: number; /** ID of the report */ - reportID: string; + reportID?: string; /** ID of the policy */ policyID?: string; From 6bd8b319a24e56c70416971156ab73edffaee5b8 Mon Sep 17 00:00:00 2001 From: DylanDylann Date: Mon, 15 Dec 2025 18:22:41 +0700 Subject: [PATCH 06/10] fix type --- src/components/Search/types.ts | 4 ++-- .../SelectionListWithSections/Search/TaskListItemRow.tsx | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/components/Search/types.ts b/src/components/Search/types.ts index 8f5beab5e9c6..ddfd664e26d9 100644 --- a/src/components/Search/types.ts +++ b/src/components/Search/types.ts @@ -36,7 +36,7 @@ type SelectedTransactionInfo = { action: ValueOf; /** The reportID of the transaction */ - reportID: string; + reportID?: string; /** The policyID tied to the report the transaction is reported on */ policyID: string | undefined; @@ -65,7 +65,7 @@ type SelectedTransactions = Record; /** Model of selected reports */ type SelectedReports = { - reportID: string; + reportID: string | undefined; policyID: string | undefined; action: ValueOf; allActions: Array>; diff --git a/src/components/SelectionListWithSections/Search/TaskListItemRow.tsx b/src/components/SelectionListWithSections/Search/TaskListItemRow.tsx index b4282e642d89..67308fd6fdf2 100644 --- a/src/components/SelectionListWithSections/Search/TaskListItemRow.tsx +++ b/src/components/SelectionListWithSections/Search/TaskListItemRow.tsx @@ -22,6 +22,7 @@ import {callFunctionIfActionIsAllowed} from '@libs/actions/Session'; import {canActionTask, completeTask} from '@libs/actions/Task'; import variables from '@styles/variables'; import CONST from '@src/CONST'; +import type {Report} from '@src/types/onyx'; import AvatarWithTextCell from './AvatarWithTextCell'; import DateCell from './DateCell'; import UserInfoCell from './UserInfoCell'; @@ -110,7 +111,7 @@ function ActionCell({taskItem, isLargeScreenWidth}: TaskCellProps) { style={[styles.w100]} isDisabled={!isTaskActionable} onPress={callFunctionIfActionIsAllowed(() => { - completeTask(taskItem, parentReport?.hasOutstandingChildTask ?? false, hasOutstandingChildTask, parentReportAction, taskItem.reportID); + completeTask(taskItem as Report, parentReport?.hasOutstandingChildTask ?? false, hasOutstandingChildTask, parentReportAction, taskItem.reportID); })} /> ); From f7177585a8081d94d470e99f9195c0a1d38951e4 Mon Sep 17 00:00:00 2001 From: DylanDylann Date: Mon, 15 Dec 2025 18:46:31 +0700 Subject: [PATCH 07/10] type check --- src/libs/actions/Search.ts | 6 +++++- src/pages/Search/SearchPage.tsx | 33 ++++++++++++++++++++++++++------- 2 files changed, 31 insertions(+), 8 deletions(-) diff --git a/src/libs/actions/Search.ts b/src/libs/actions/Search.ts index e061eea7324e..67b8d8cc3415 100644 --- a/src/libs/actions/Search.ts +++ b/src/libs/actions/Search.ts @@ -773,7 +773,7 @@ function rejectMoneyRequestInBulk(reportID: string, comment: string, policy: Ony /** Minimal transaction info needed for reject - only reportID is used */ type TransactionReportInfo = { - reportID: string; + reportID?: string; }; function rejectMoneyRequestsOnSearch( @@ -788,6 +788,10 @@ function rejectMoneyRequestsOnSearch( const transactionsByReport = transactionIDs.reduce>((acc, transactionID) => { const reportID = selectedTransactions[transactionID].reportID; + if (!reportID) { + return acc; + } + if (!acc[reportID]) { acc[reportID] = []; } diff --git a/src/pages/Search/SearchPage.tsx b/src/pages/Search/SearchPage.tsx index a7f431047902..53fbf4585cdb 100644 --- a/src/pages/Search/SearchPage.tsx +++ b/src/pages/Search/SearchPage.tsx @@ -153,8 +153,19 @@ function SearchPage({route}: SearchPageProps) { // eslint-disable-next-line rulesdir/no-default-id-values const [currentSearchResults] = useOnyx(`${ONYXKEYS.COLLECTION.SNAPSHOT}${queryJSON?.hash ?? CONST.DEFAULT_NUMBER_ID}`, {canBeMissing: true}); const lastNonEmptySearchResults = useRef(undefined); - const selectedTransactionReportIDs = useMemo(() => [...new Set(Object.values(selectedTransactions).map((transaction) => transaction.reportID))], [selectedTransactions]); - const selectedReportIDs = Object.values(selectedReports).map((report) => report.reportID); + const selectedTransactionReportIDs = useMemo( + () => [ + ...new Set( + Object.values(selectedTransactions) + .map((transaction) => transaction.reportID) + .filter((reportID) => reportID !== undefined), + ), + ], + [selectedTransactions], + ); + const selectedReportIDs = Object.values(selectedReports) + .map((report) => report.reportID) + .filter((reportID) => reportID !== undefined); const isCurrencySupportedBulkWallet = isCurrencySupportWalletBulkPay(selectedReports, selectedTransactions); const hasOnlyPersonalPolicies = useMemo(() => hasOnlyPersonalPoliciesUtil(policies), [policies]); @@ -249,6 +260,9 @@ function SearchPage({route}: SearchPageProps) { for (const item of selectedOptions) { const itemPolicyID = item.policyID; const itemReportID = item.reportID; + if (!itemReportID) { + return; + } const isExpenseReport = isExpenseReportUtil(itemReportID); const isIOUReport = isIOUReportUtil(itemReportID); const reportType = getReportType(itemReportID); @@ -400,7 +414,7 @@ function SearchPage({route}: SearchPageProps) { { query: status, jsonQuery: JSON.stringify(queryJSON), - reportIDList: selectedReports?.filter((report) => !!report).map((report) => report.reportID) ?? [], + reportIDList: selectedReports?.map((report) => report?.reportID).filter((reportID) => reportID !== undefined) ?? [], transactionIDList: selectedTransactionsKeys, }, () => { @@ -460,7 +474,9 @@ function SearchPage({route}: SearchPageProps) { } // Otherwise, we provide the full set of options depending on the state of the selected transactions and reports - const areSelectedTransactionsIncludedInReports = selectedTransactionsKeys.every((id) => selectedReportIDs.includes(selectedTransactions[id].reportID)); + const areSelectedTransactionsIncludedInReports = selectedTransactionsKeys.every((id) => + selectedTransactions[id].reportID ? selectedReportIDs.includes(selectedTransactions[id].reportID) : true, + ); const shouldShowApproveOption = !isOffline && !isAnyTransactionOnHold && @@ -503,7 +519,10 @@ function SearchPage({route}: SearchPageProps) { const reportIDList = !selectedReports.length ? Object.values(selectedTransactions).map((transaction) => transaction.reportID) : (selectedReports?.filter((report) => !!report).map((report) => report.reportID) ?? []); - approveMoneyRequestOnSearch(hash, reportIDList); + approveMoneyRequestOnSearch( + hash, + reportIDList.filter((reportID) => reportID !== undefined), + ); // eslint-disable-next-line @typescript-eslint/no-deprecated InteractionManager.runAfterInteractions(() => { clearSelectedTransactions(); @@ -567,7 +586,7 @@ function SearchPage({route}: SearchPageProps) { for (const item of itemList) { const policy = policies?.[`${ONYXKEYS.COLLECTION.POLICY}${item.policyID}`]; if (policy) { - submitMoneyRequestOnSearch(hash, [item], [policy]); + submitMoneyRequestOnSearch(hash, [item as Report], [policy]); } } clearSelectedTransactions(); @@ -889,7 +908,7 @@ function SearchPage({route}: SearchPageProps) { } setIsDownloadExportModalVisible(false); - const reportIDList = selectedReports?.filter((report) => !!report).map((report) => report.reportID) ?? []; + const reportIDList = selectedReports?.map((report) => report?.reportID).filter((reportID) => reportID !== undefined) ?? []; queueExportSearchItemsToCSV({ query: status, jsonQuery: JSON.stringify(queryJSON), From 2ee85949b581727413c7dcaf05b554b44799096d Mon Sep 17 00:00:00 2001 From: DylanDylann Date: Mon, 15 Dec 2025 21:18:02 +0700 Subject: [PATCH 08/10] fix typecheck on IOU --- src/libs/actions/IOU.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index bdc9d922a93f..e2af79133072 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -9426,8 +9426,8 @@ function deleteMoneyRequest({ value: { data: { [`${ONYXKEYS.COLLECTION.REPORT}${iouReport?.reportID}`]: { - // @ts-expect-error - will be solved in https://github.com/Expensify/App/issues/73830 pendingFields: { + // @ts-expect-error - will be solved in https://github.com/Expensify/App/issues/73830 preview: CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE, }, }, From 73119b1f91bc6610ac07888d1401eabfe3f2ff66 Mon Sep 17 00:00:00 2001 From: DylanDylann Date: Mon, 5 Jan 2026 21:23:17 +0700 Subject: [PATCH 09/10] Fix type --- src/libs/SearchUIUtils.ts | 6 +++--- src/libs/actions/Search.ts | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/libs/SearchUIUtils.ts b/src/libs/SearchUIUtils.ts index eeae141a49a2..79f778e19f74 100644 --- a/src/libs/SearchUIUtils.ts +++ b/src/libs/SearchUIUtils.ts @@ -1038,7 +1038,7 @@ function shouldShowYear( result.shouldShowYearPosted = postedYear !== currentYear; } - const exportedAction = lastExportedActionByReportID.get(item.reportID); + const exportedAction = item.reportID ? lastExportedActionByReportID.get(item.reportID) : undefined; if (exportedAction?.created && DateUtils.doesDateBelongToAPastYear(exportedAction.created)) { result.shouldShowYearExported = true; } @@ -1298,7 +1298,7 @@ function getTransactionsSections( submitted, approved, posted, - exported: lastExportedActionByReportID.get(transactionItem.reportID)?.created ?? '', + exported: transactionItem.reportID ? (lastExportedActionByReportID.get(transactionItem.reportID)?.created ?? '') : '', shouldShowMerchant, shouldShowYear: shouldShowYearCreated, shouldShowYearSubmitted, @@ -1834,7 +1834,7 @@ function getReportSections( formattedTotal, formattedMerchant, date, - exported: lastExportedActionByReportID.get(transactionItem.reportID)?.created ?? '', + exported: transactionItem.reportID ? (lastExportedActionByReportID.get(transactionItem.reportID)?.created ?? '') : '', shouldShowMerchant, shouldShowYear: shouldShowYearCreatedTransaction, shouldShowYearSubmitted: shouldShowYearSubmittedTransaction, diff --git a/src/libs/actions/Search.ts b/src/libs/actions/Search.ts index 6031e7b2b651..1ff6868c0b16 100644 --- a/src/libs/actions/Search.ts +++ b/src/libs/actions/Search.ts @@ -162,6 +162,7 @@ function getLastPolicyPaymentMethod( return undefined; } + // eslint-disable-next-line @typescript-eslint/no-deprecated const personalPolicy = getPersonalPolicy(); const lastPolicyPaymentMethod = lastPaymentMethods?.[policyID] ?? (isIOUReport && personalPolicy ? lastPaymentMethods?.[personalPolicy.id] : undefined); From bc25f4c57144cba9cf218651ed6d52312ddf0141 Mon Sep 17 00:00:00 2001 From: DylanDylann Date: Mon, 5 Jan 2026 23:05:50 +0700 Subject: [PATCH 10/10] fix Type --- src/libs/MergeTransactionUtils.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libs/MergeTransactionUtils.ts b/src/libs/MergeTransactionUtils.ts index 561f922c72fd..547ef4283f5e 100644 --- a/src/libs/MergeTransactionUtils.ts +++ b/src/libs/MergeTransactionUtils.ts @@ -176,15 +176,15 @@ function getTransactionsAndReportsFromSearch( } { const transaction1 = searchResults.data[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionIDs.at(0)}`]; const transaction2 = searchResults.data[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionIDs.at(1)}`]; + const policyID1 = searchResults.data[`${ONYXKEYS.COLLECTION.REPORT}${transaction1?.reportID}`]?.policyID; + const policyID2 = searchResults.data[`${ONYXKEYS.COLLECTION.REPORT}${transaction2?.reportID}`]?.policyID; return { transactions: [transaction1, transaction2].filter((transaction) => !!transaction), reports: [searchResults.data[`${ONYXKEYS.COLLECTION.REPORT}${transaction1?.reportID}`], searchResults.data[`${ONYXKEYS.COLLECTION.REPORT}${transaction2?.reportID}`]].filter( (report) => !!report, ), - policies: [searchResults.data[`${ONYXKEYS.COLLECTION.POLICY}${transaction1?.policyID}`], searchResults.data[`${ONYXKEYS.COLLECTION.POLICY}${transaction2?.policyID}`]].filter( - (policy) => !!policy, - ), + policies: [searchResults.data[`${ONYXKEYS.COLLECTION.POLICY}${policyID1}`], searchResults.data[`${ONYXKEYS.COLLECTION.POLICY}${policyID2}`]].filter((policy) => !!policy), }; }