Skip to content
Open
Show file tree
Hide file tree
Changes from 15 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/ONYXKEYS.ts
Original file line number Diff line number Diff line change
Expand Up @@ -650,6 +650,9 @@ const ONYXKEYS = {
/** Keeps track of whether the "Confirm Navigate to Expensify Classic" modal is opened */
IS_OPEN_CONFIRM_NAVIGATE_EXPENSIFY_CLASSIC_MODAL_OPEN: 'IsOpenConfirmNavigateExpensifyClassicModalOpen',

/** The transaction IDs to be highlighted when opening the Expenses search route page */
TRANSACTION_IDS_HIGHLIGHT_ON_SEARCH_ROUTE: 'transactionIdsHighlightOnSearchRoute',

/** Collection Keys */
COLLECTION: {
DOMAIN: 'domain_',
Expand Down Expand Up @@ -1385,6 +1388,7 @@ type OnyxValuesMapping = {
[ONYXKEYS.HAS_DENIED_CONTACT_IMPORT_PROMPT]: boolean | undefined;
[ONYXKEYS.IS_OPEN_CONFIRM_NAVIGATE_EXPENSIFY_CLASSIC_MODAL_OPEN]: boolean;
[ONYXKEYS.PERSONAL_POLICY_ID]: string;
[ONYXKEYS.TRANSACTION_IDS_HIGHLIGHT_ON_SEARCH_ROUTE]: Record<string, Record<string, boolean>>;
};

type OnyxDerivedValuesMapping = {
Expand Down
50 changes: 46 additions & 4 deletions src/hooks/useSearchHighlightAndScroll.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
import {useIsFocused} from '@react-navigation/native';
import {useEffect, useRef, useState} from 'react';
import {useCallback, useEffect, useRef, useState} from 'react';
import {InteractionManager} from 'react-native';
import type {OnyxCollection, OnyxEntry} from 'react-native-onyx';
import type {SearchQueryJSON} from '@components/Search/types';
import type {SearchListItem, SelectionListHandle, TransactionGroupListItemType, TransactionListItemType} from '@components/SelectionListWithSections/types';
import {search} from '@libs/actions/Search';
import {mergeTransactionIdsHighlightOnSearchRoute} from '@libs/actions/Transaction';
import {isReportActionEntry} from '@libs/SearchUIUtils';
import type {SearchKey} from '@libs/SearchUIUtils';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import type {ReportActions, SearchResults, Transaction} from '@src/types/onyx';
import {isEmptyObject} from '@src/types/utils/EmptyObject';
import useNetwork from './useNetwork';
import useOnyx from './useOnyx';
import usePrevious from './usePrevious';

type UseSearchHighlightAndScroll = {
Expand Down Expand Up @@ -51,6 +54,12 @@ function useSearchHighlightAndScroll({
const initializedRef = useRef(false);
const hasPendingSearchRef = useRef(false);
const isChat = queryJSON.type === CONST.SEARCH.DATA_TYPES.CHAT;

const transactionIDsToHighlightSelector = useCallback((allTransactionIDs: OnyxEntry<Record<string, Record<string, boolean>>>) => allTransactionIDs?.[queryJSON.type], [queryJSON.type]);
const [transactionIDsToHighlight] = useOnyx(ONYXKEYS.TRANSACTION_IDS_HIGHLIGHT_ON_SEARCH_ROUTE, {
canBeMissing: true,
selector: transactionIDsToHighlightSelector,
});
const searchResultsData = searchResults?.data;

const prevTransactionsIDs = Object.keys(previousTransactions ?? {});
Expand Down Expand Up @@ -191,11 +200,20 @@ function useSearchHighlightAndScroll({
} else {
const previousTransactionIDs = extractTransactionIDsFromSearchResults(previousSearchResults);
const currentTransactionIDs = extractTransactionIDsFromSearchResults(searchResults.data);
const manualHighlightTransactionIDs = new Set(Object.keys(transactionIDsToHighlight ?? {}).filter((id) => !!transactionIDsToHighlight?.[id]));

// Find new transaction IDs that are not in the previousTransactionIDs and not already highlighted
const newTransactionIDs = currentTransactionIDs.filter((id) => !previousTransactionIDs.includes(id) && !highlightedIDs.current.has(id));
const newTransactionIDs = currentTransactionIDs.filter((id) => {
if (manualHighlightTransactionIDs.has(id)) {
return true;
}
if (!triggeredByHookRef.current || !hasNewItemsRef.current) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you explain why we check this condition here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This condition means I only moved the check from the outer if into the filter condition of currentTransactionIDs to ensure that manualHighlightTransactionIDs are merged without breaking the original logic.

As for why there are two conditions, you can also notice that the useSearchHighlightAndScroll hook only highlights items that it itself fetched from the server.

return false;
}
return !previousTransactionIDs.includes(id) && !highlightedIDs.current.has(id);
});

if (!triggeredByHookRef.current || newTransactionIDs.length === 0 || !hasNewItemsRef.current) {
if (newTransactionIDs.length === 0) {
return;
}

Expand All @@ -207,7 +225,31 @@ function useSearchHighlightAndScroll({
}
setNewSearchResultKeys(newKeys);
}
}, [searchResults?.data, previousSearchResults, isChat]);
}, [searchResults?.data, previousSearchResults, isChat, transactionIDsToHighlight]);

// Reset transactionIDsToHighlight after they have been highlighted
useEffect(() => {
if (isEmptyObject(transactionIDsToHighlight) || newSearchResultKeys === null) {
return;
}

const highlightedTransactionIDs = Object.keys(transactionIDsToHighlight).filter(
(id) => transactionIDsToHighlight[id] && newSearchResultKeys?.has(`${ONYXKEYS.COLLECTION.TRANSACTION}${id}`),
);

const timer = setTimeout(() => {
mergeTransactionIdsHighlightOnSearchRoute(queryJSON.type, Object.fromEntries(highlightedTransactionIDs.map((id) => [id, false])));
}, CONST.ANIMATED_HIGHLIGHT_START_DURATION);
return () => clearTimeout(timer);
}, [transactionIDsToHighlight, queryJSON.type, newSearchResultKeys]);

// Remove transactionIDsToHighlight when the user leaves the current search type
useEffect(
() => () => {
mergeTransactionIdsHighlightOnSearchRoute(queryJSON.type, null);
},
[queryJSON.type],
);

// Reset newSearchResultKey after it's been used
useEffect(() => {
Expand Down
17 changes: 9 additions & 8 deletions src/libs/actions/IOU/SendInvoice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@ import DateUtils from '@libs/DateUtils';
import {getMicroSecondOnyxErrorWithTranslationKey} from '@libs/ErrorUtils';
import {formatPhoneNumber} from '@libs/LocalePhoneNumber';
import Log from '@libs/Log';
import isSearchTopmostFullScreenRoute from '@libs/Navigation/helpers/isSearchTopmostFullScreenRoute';
import Navigation from '@libs/Navigation/Navigation';
import {getReportActionHtml, getReportActionText} from '@libs/ReportActionsUtils';
import type {OptimisticChatReport, OptimisticCreatedReportAction, OptimisticIOUReportAction} from '@libs/ReportUtils';
import {
Expand All @@ -34,7 +32,7 @@ import type {InvoiceReceiver, InvoiceReceiverType} from '@src/types/onyx/Report'
import type {OnyxData} from '@src/types/onyx/Request';
import type {Receipt} from '@src/types/onyx/Transaction';
import {isEmptyObject} from '@src/types/utils/EmptyObject';
import {getAllPersonalDetails, getReceiptError, getSearchOnyxUpdate, mergePolicyRecentlyUsedCategories, mergePolicyRecentlyUsedCurrencies} from '.';
import {getAllPersonalDetails, getReceiptError, getSearchOnyxUpdate, handleNavigateAfterExpenseCreate, mergePolicyRecentlyUsedCategories, mergePolicyRecentlyUsedCurrencies} from '.';
import type {BasePolicyParams} from '.';

type SendInvoiceInformation = {
Expand Down Expand Up @@ -77,6 +75,7 @@ type SendInvoiceOptions = {
companyWebsite?: string;
policyRecentlyUsedCategories?: OnyxEntry<OnyxTypes.RecentlyUsedCategories>;
policyRecentlyUsedTags?: OnyxEntry<OnyxTypes.RecentlyUsedTags>;
isFromGlobalCreate?: boolean;
};

type BuildOnyxDataForInvoiceParams = {
Expand Down Expand Up @@ -722,6 +721,7 @@ function sendInvoice({
companyWebsite,
policyRecentlyUsedCategories,
policyRecentlyUsedTags,
isFromGlobalCreate,
}: SendInvoiceOptions) {
const parsedComment = getParsedComment(transaction?.comment?.comment?.trim() ?? '');
if (transaction?.comment) {
Expand Down Expand Up @@ -786,11 +786,12 @@ function sendInvoice({
// eslint-disable-next-line @typescript-eslint/no-deprecated
InteractionManager.runAfterInteractions(() => removeDraftTransaction(CONST.IOU.OPTIMISTIC_TRANSACTION_ID));

if (isSearchTopmostFullScreenRoute()) {
Navigation.dismissModal();
} else {
Navigation.dismissModalWithReport({reportID: invoiceRoom.reportID});
}
handleNavigateAfterExpenseCreate({
activeReportID: invoiceRoom.reportID,
transactionID,
isFromGlobalCreate,
isInvoice: true,
});

notifyNewAction(invoiceRoom.reportID, currentUserAccountID);
}
Expand Down
90 changes: 77 additions & 13 deletions src/libs/actions/IOU/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@
import {validateAmount} from '@libs/MoneyRequestUtils';
import isReportOpenInRHP from '@libs/Navigation/helpers/isReportOpenInRHP';
import isReportOpenInSuperWideRHP from '@libs/Navigation/helpers/isReportOpenInSuperWideRHP';
import isReportTopmostSplitNavigator from '@libs/Navigation/helpers/isReportTopmostSplitNavigator';
import isSearchTopmostFullScreenRoute from '@libs/Navigation/helpers/isSearchTopmostFullScreenRoute';
import Navigation, {navigationRef} from '@libs/Navigation/Navigation';
import {isOffline} from '@libs/Network/NetworkStore';
Expand Down Expand Up @@ -192,7 +193,7 @@
shouldEnableNegative,
updateReportPreview,
} from '@libs/ReportUtils';
import {getCurrentSearchQueryJSON} from '@libs/SearchQueryUtils';
import {buildCannedSearchQuery, getCurrentSearchQueryJSON} from '@libs/SearchQueryUtils';
import {getSuggestedSearches} from '@libs/SearchUIUtils';
import playSound, {SOUNDS} from '@libs/Sound';
import {shouldRestrictUserBillableActions} from '@libs/SubscriptionUtils';
Expand Down Expand Up @@ -234,7 +235,7 @@
import type {GuidedSetupData} from '@userActions/Report';
import {buildInviteToRoomOnyxData, completeOnboarding, getCurrentUserAccountID, notifyNewAction, optimisticReportLastData} from '@userActions/Report';
import {clearAllRelatedReportActionErrors} from '@userActions/ReportActions';
import {sanitizeRecentWaypoints} from '@userActions/Transaction';
import {mergeTransactionIdsHighlightOnSearchRoute, sanitizeRecentWaypoints} from '@userActions/Transaction';
import {removeDraftSplitTransaction, removeDraftTransaction, removeDraftTransactions} from '@userActions/TransactionEdit';
import {getOnboardingMessages} from '@userActions/Welcome/OnboardingFlow';
import type {OnboardingCompanySize} from '@userActions/Welcome/OnboardingFlow';
Expand Down Expand Up @@ -276,6 +277,7 @@
billable?: boolean;
reimbursable?: boolean;
customUnitRateID?: string;
isFromGlobalCreate?: boolean;
};

type InitMoneyRequestParams = {
Expand Down Expand Up @@ -689,6 +691,7 @@
isLinkedTrackedExpenseReportArchived?: boolean;
odometerStart?: number;
odometerEnd?: number;
isFromGlobalCreate?: boolean;
};

type TrackExpenseAccountantParams = {
Expand Down Expand Up @@ -757,7 +760,7 @@
};

let allPersonalDetails: OnyxTypes.PersonalDetailsList = {};
Onyx.connect({

Check warning on line 763 in src/libs/actions/IOU/index.ts

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

Onyx.connect() is deprecated. Use useOnyx() hook instead and pass the data as parameters to a pure function
key: ONYXKEYS.PERSONAL_DETAILS_LIST,
callback: (value) => {
allPersonalDetails = value ?? {};
Expand Down Expand Up @@ -859,7 +862,7 @@
};

let allTransactions: NonNullable<OnyxCollection<OnyxTypes.Transaction>> = {};
Onyx.connect({

Check warning on line 865 in src/libs/actions/IOU/index.ts

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

Onyx.connect() is deprecated. Use useOnyx() hook instead and pass the data as parameters to a pure function
key: ONYXKEYS.COLLECTION.TRANSACTION,
waitForCollectionCallback: true,
callback: (value) => {
Expand All @@ -873,7 +876,7 @@
});

let allTransactionDrafts: NonNullable<OnyxCollection<OnyxTypes.Transaction>> = {};
Onyx.connect({

Check warning on line 879 in src/libs/actions/IOU/index.ts

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

Onyx.connect() is deprecated. Use useOnyx() hook instead and pass the data as parameters to a pure function
key: ONYXKEYS.COLLECTION.TRANSACTION_DRAFT,
waitForCollectionCallback: true,
callback: (value) => {
Expand All @@ -882,7 +885,7 @@
});

let allTransactionViolations: NonNullable<OnyxCollection<OnyxTypes.TransactionViolations>> = {};
Onyx.connect({

Check warning on line 888 in src/libs/actions/IOU/index.ts

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

Onyx.connect() is deprecated. Use useOnyx() hook instead and pass the data as parameters to a pure function
key: ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS,
waitForCollectionCallback: true,
callback: (value) => {
Expand All @@ -896,7 +899,7 @@
});

let allReports: OnyxCollection<OnyxTypes.Report>;
Onyx.connect({

Check warning on line 902 in src/libs/actions/IOU/index.ts

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

Onyx.connect() is deprecated. Use useOnyx() hook instead and pass the data as parameters to a pure function
key: ONYXKEYS.COLLECTION.REPORT,
waitForCollectionCallback: true,
callback: (value) => {
Expand All @@ -905,7 +908,7 @@
});

let allReportNameValuePairs: OnyxCollection<OnyxTypes.ReportNameValuePairs>;
Onyx.connect({

Check warning on line 911 in src/libs/actions/IOU/index.ts

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

Onyx.connect() is deprecated. Use useOnyx() hook instead and pass the data as parameters to a pure function
key: ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS,
waitForCollectionCallback: true,
callback: (value) => {
Expand All @@ -915,7 +918,7 @@

let userAccountID = -1;
let currentUserEmail = '';
Onyx.connect({

Check warning on line 921 in src/libs/actions/IOU/index.ts

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

Onyx.connect() is deprecated. Use useOnyx() hook instead and pass the data as parameters to a pure function
key: ONYXKEYS.SESSION,
callback: (value) => {
currentUserEmail = value?.email ?? '';
Expand All @@ -924,7 +927,7 @@
});

let deprecatedCurrentUserPersonalDetails: OnyxEntry<OnyxTypes.PersonalDetails>;
Onyx.connect({

Check warning on line 930 in src/libs/actions/IOU/index.ts

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

Onyx.connect() is deprecated. Use useOnyx() hook instead and pass the data as parameters to a pure function
key: ONYXKEYS.PERSONAL_DETAILS_LIST,
callback: (value) => {
deprecatedCurrentUserPersonalDetails = value?.[userAccountID] ?? undefined;
Expand All @@ -932,7 +935,7 @@
});

let allReportActions: OnyxCollection<OnyxTypes.ReportActions>;
Onyx.connect({

Check warning on line 938 in src/libs/actions/IOU/index.ts

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

Onyx.connect() is deprecated. Use useOnyx() hook instead and pass the data as parameters to a pure function
key: ONYXKEYS.COLLECTION.REPORT_ACTIONS,
waitForCollectionCallback: true,
callback: (actions) => {
Expand All @@ -944,7 +947,7 @@
});

let personalDetailsList: OnyxEntry<OnyxTypes.PersonalDetailsList>;
Onyx.connect({

Check warning on line 950 in src/libs/actions/IOU/index.ts

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

Onyx.connect() is deprecated. Use useOnyx() hook instead and pass the data as parameters to a pure function
key: ONYXKEYS.PERSONAL_DETAILS_LIST,
callback: (value) => (personalDetailsList = value),
});
Expand Down Expand Up @@ -999,9 +1002,9 @@
* If the action is done from the report RHP, then we just want to dismiss the money request flow screens.
* It is a helper function used only in this file.
*/
function dismissModalAndOpenReportInInboxTab(reportID?: string) {
function dismissModalAndOpenReportInInboxTab(reportID?: string, isInvoice?: boolean) {
const rootState = navigationRef.getRootState();
if (isReportOpenInRHP(rootState)) {
if (!isInvoice && isReportOpenInRHP(rootState)) {
const rhpKey = rootState.routes.at(-1)?.state?.key;
if (rhpKey) {
const hasMultipleTransactions = Object.values(allTransactions).filter((transaction) => transaction?.reportID === reportID).length > 0;
Expand Down Expand Up @@ -1029,6 +1032,52 @@
Navigation.dismissModalWithReport({reportID});
}

/**
* Helper to navigate after an expense is created in order to standardize the post‑creation experience
* when creating an expense from the global create button.
* If the expense is created from the global create button then:
* - If it is created on the inbox tab, it will open the chat report containing that expense.
* - If it is created elsewhere, it will navigate to Reports > Expense and highlight the newly created expense.
*/
function handleNavigateAfterExpenseCreate({
activeReportID,
transactionID,
isFromGlobalCreate,
isInvoice,
shouldHandleNavigation = true,
}: {
activeReportID?: string;
transactionID?: string;
isFromGlobalCreate?: boolean;
isInvoice?: boolean;
shouldHandleNavigation?: boolean;
}) {
const isUserOnInbox = isReportTopmostSplitNavigator();

// If the expense is not created from global create or is currently on the inbox tab,
// we just need to dismiss the money request flow screens
// and open the report chat containing the IOU report
if (!isFromGlobalCreate || isUserOnInbox || !transactionID) {
if (shouldHandleNavigation) {
dismissModalAndOpenReportInInboxTab(activeReportID, isInvoice);
}
return;
}

const type = isInvoice ? CONST.SEARCH.DATA_TYPES.INVOICE : CONST.SEARCH.DATA_TYPES.EXPENSE;
// We mark this transaction to be highlighted when opening the expense search route page
mergeTransactionIdsHighlightOnSearchRoute(type, {[transactionID]: true});

if (!shouldHandleNavigation) {
return;
}
const queryString = buildCannedSearchQuery({type});
Navigation.dismissModal();
Navigation.setNavigationActionToMicrotaskQueue(() => {
Navigation.navigate(ROUTES.SEARCH_ROOT.getRoute({query: queryString}));
});
}

/**
* Build a minimal transaction record for formula computation in buildOptimisticExpenseReport.
* This allows formulas like {report:startdate}, {report:expensescount} to work correctly.
Expand Down Expand Up @@ -6163,6 +6212,7 @@
count,
rate,
unit,
isFromGlobalCreate,
} = transactionParams;

const testDriveCommentReportActionID = isTestDrive ? NumberUtils.rand64() : undefined;
Expand Down Expand Up @@ -6359,16 +6409,22 @@
if (shouldHandleNavigation) {
// eslint-disable-next-line @typescript-eslint/no-deprecated
InteractionManager.runAfterInteractions(() => removeDraftTransactions());
if (!requestMoneyInformation.isRetry) {
dismissModalAndOpenReportInInboxTab(backToReport ?? activeReportID);
}

const trackReport = Navigation.getReportRouteByID(linkedTrackedExpenseReportAction?.childReportID);
if (trackReport?.key) {
Navigation.removeScreenByKey(trackReport.key);
}
}

if (!requestMoneyInformation.isRetry) {
handleNavigateAfterExpenseCreate({
activeReportID: backToReport ?? activeReportID,
transactionID: transaction.transactionID,
isFromGlobalCreate,
shouldHandleNavigation,
});
}

if (activeReportID && !isMoneyRequestReport) {
Navigation.setNavigationActionToMicrotaskQueue(() =>
setTimeout(() => {
Expand Down Expand Up @@ -6398,7 +6454,7 @@
policyRecentlyUsedCurrencies,
} = submitPerDiemExpenseInformation;
const {payeeAccountID} = participantParams;
const {currency, comment = '', category, tag, created, customUnit, attendees} = transactionParams;
const {currency, comment = '', category, tag, created, customUnit, attendees, isFromGlobalCreate} = transactionParams;

if (
isEmptyObject(policyParams.policy) ||
Expand Down Expand Up @@ -6484,7 +6540,7 @@

// eslint-disable-next-line @typescript-eslint/no-deprecated
InteractionManager.runAfterInteractions(() => removeDraftTransaction(CONST.IOU.OPTIMISTIC_TRANSACTION_ID));
dismissModalAndOpenReportInInboxTab(activeReportID);
handleNavigateAfterExpenseCreate({activeReportID, transactionID: transaction.transactionID, isFromGlobalCreate});

if (activeReportID) {
notifyNewAction(activeReportID, payeeAccountID);
Expand Down Expand Up @@ -6539,6 +6595,7 @@
attendees,
odometerStart,
odometerEnd,
isFromGlobalCreate,
} = transactionData;
const isMoneyRequestReport = isMoneyRequestReportReportUtils(report);
const currentChatReport = isMoneyRequestReport ? getReportOrDraftReport(report?.chatReportID) : report;
Expand Down Expand Up @@ -6814,10 +6871,15 @@
if (shouldHandleNavigation) {
// eslint-disable-next-line @typescript-eslint/no-deprecated
InteractionManager.runAfterInteractions(() => removeDraftTransactions());
}

if (!params.isRetry) {
dismissModalAndOpenReportInInboxTab(activeReportID);
}
if (!params.isRetry) {
handleNavigateAfterExpenseCreate({
activeReportID,
transactionID: transaction?.transactionID,
isFromGlobalCreate,
shouldHandleNavigation,
});
}

notifyNewAction(activeReportID, payeeAccountID);
Expand Down Expand Up @@ -8328,6 +8390,7 @@
receipt,
odometerStart,
odometerEnd,
isFromGlobalCreate,
} = transactionParams;

// If the report is an iou or expense report, we should get the linked chat report to be passed to the getMoneyRequestInformation function
Expand Down Expand Up @@ -8512,7 +8575,7 @@
// eslint-disable-next-line @typescript-eslint/no-deprecated
InteractionManager.runAfterInteractions(() => removeDraftTransaction(CONST.IOU.OPTIMISTIC_TRANSACTION_ID));
const activeReportID = isMoneyRequestReport && report?.reportID ? report.reportID : parameters.chatReportID;
dismissModalAndOpenReportInInboxTab(backToReport ?? activeReportID);
handleNavigateAfterExpenseCreate({activeReportID: backToReport ?? activeReportID, isFromGlobalCreate, transactionID: parameters.transactionID});

if (!isMoneyRequestReport) {
notifyNewAction(activeReportID, userAccountID);
Expand Down Expand Up @@ -14566,6 +14629,7 @@
getSearchOnyxUpdate,
setMoneyRequestTimeRate,
setMoneyRequestTimeCount,
handleNavigateAfterExpenseCreate,
};
export type {
GPSPoint as GpsPoint,
Expand Down
6 changes: 6 additions & 0 deletions src/libs/actions/Transaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ import type {
} from '@src/types/onyx';
import type {OriginalMessageIOU, OriginalMessageModifiedExpense} from '@src/types/onyx/OriginalMessage';
import type {OnyxData} from '@src/types/onyx/Request';
import type {SearchDataTypes} from '@src/types/onyx/SearchResults';
import type {Waypoint, WaypointCollection} from '@src/types/onyx/Transaction';
import type TransactionState from '@src/types/utils/TransactionStateType';
import {getPolicyTagsData} from './Policy/Tag';
Expand Down Expand Up @@ -1517,6 +1518,10 @@ function getDraftTransactions(draftTransactions?: OnyxCollection<Transaction>):
return Object.values(draftTransactions ?? allTransactionDrafts ?? {}).filter((transaction): transaction is Transaction => !!transaction);
}

function mergeTransactionIdsHighlightOnSearchRoute(type: SearchDataTypes, data: Record<string, boolean> | null) {
return Onyx.merge(ONYXKEYS.TRANSACTION_IDS_HIGHLIGHT_ON_SEARCH_ROUTE, {[type]: data});
}

function getDuplicateTransactionDetails(transactionID?: string) {
if (!transactionID) {
return;
Expand Down Expand Up @@ -1547,5 +1552,6 @@ export {
revert,
changeTransactionsReport,
setTransactionReport,
mergeTransactionIdsHighlightOnSearchRoute,
getDuplicateTransactionDetails,
};
Loading
Loading