Skip to content

Commit f58b1fd

Browse files
authored
Merge pull request Expensify#89081 from software-mansion-labs/jnowakow/fix-88960
Expensify#88960 show offline tracked expense in search
2 parents 6a72a63 + 12ff528 commit f58b1fd

2 files changed

Lines changed: 113 additions & 101 deletions

File tree

src/libs/SearchQueryUtils.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1856,14 +1856,18 @@ function getQueryWithUpdatedValues(query: string, shouldSkipAmountConversion = f
18561856

18571857
function getCurrentSearchQueryJSON() {
18581858
const rootState = navigationRef.getRootState();
1859-
const lastSearchNavigator = rootState?.routes?.findLast((route) => route.name === NAVIGATORS.SEARCH_FULLSCREEN_NAVIGATOR);
1860-
1859+
const lastTabNavigator = rootState?.routes?.findLast((route) => route.name === NAVIGATORS.TAB_NAVIGATOR);
1860+
const lastSearchNavigator = lastTabNavigator?.state?.routes?.findLast((route) => route.name === NAVIGATORS.SEARCH_FULLSCREEN_NAVIGATOR);
18611861
let lastSearchNavigatorState = lastSearchNavigator?.state;
18621862
if (!lastSearchNavigatorState) {
18631863
lastSearchNavigatorState = lastSearchNavigator?.key ? getPreservedNavigatorState(lastSearchNavigator?.key) : undefined;
18641864
}
1865+
1866+
// When the SearchFullscreenNavigator has never been mounted (e.g. lazy tab not yet visited),
1867+
// neither .state nor the preserved state map will have an entry. Fall back to the default
1868+
// query that the navigator would use as its initialParams.
18651869
if (!lastSearchNavigatorState) {
1866-
return;
1870+
return buildSearchQueryJSON(buildSearchQueryString());
18671871
}
18681872

18691873
const lastSearchRoute = lastSearchNavigatorState.routes.findLast((route) => route.name === SCREENS.SEARCH.ROOT);

src/libs/actions/IOU/index.ts

Lines changed: 106 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -2582,17 +2582,23 @@ function shouldOptimisticallyUpdateSearch(
25822582
(isInvoice && currentSearchQueryJSON.type === CONST.SEARCH.DATA_TYPES.INVOICE) ||
25832583
(iouReport?.type === CONST.REPORT.TYPE.EXPENSE && currentSearchQueryJSON.type === CONST.SEARCH.DATA_TYPES.EXPENSE_REPORT);
25842584

2585-
return (
2586-
shouldOptimisticallyUpdateByStatus &&
2587-
validSearchTypes &&
2588-
(currentSearchQueryJSON.flatFilters.length === 0 ||
2589-
(submitQueryJSON?.similarSearchHash === currentSearchQueryJSON.similarSearchHash && expenseReportStatusFilterMapping[CONST.SEARCH.STATUS.EXPENSE.DRAFTS](iouReport)) ||
2590-
(approveQueryJSON?.similarSearchHash === currentSearchQueryJSON.similarSearchHash && expenseReportStatusFilterMapping[CONST.SEARCH.STATUS.EXPENSE.OUTSTANDING](iouReport)) ||
2591-
(unapprovedCashSimilarSearchHash === currentSearchQueryJSON.similarSearchHash &&
2592-
isExpenseReport(iouReport) &&
2593-
(expenseReportStatusFilterMapping[CONST.SEARCH.STATUS.EXPENSE.DRAFTS](iouReport) || expenseReportStatusFilterMapping[CONST.SEARCH.STATUS.EXPENSE.OUTSTANDING](iouReport)) &&
2594-
transaction?.reimbursable))
2595-
);
2585+
const hasNoFlatFilters = currentSearchQueryJSON.flatFilters.length === 0;
2586+
2587+
const matchesSubmitQuery =
2588+
submitQueryJSON?.similarSearchHash === currentSearchQueryJSON.similarSearchHash && expenseReportStatusFilterMapping[CONST.SEARCH.STATUS.EXPENSE.DRAFTS](iouReport);
2589+
2590+
const matchesApproveQuery =
2591+
approveQueryJSON?.similarSearchHash === currentSearchQueryJSON.similarSearchHash && expenseReportStatusFilterMapping[CONST.SEARCH.STATUS.EXPENSE.OUTSTANDING](iouReport);
2592+
2593+
const matchesUnapprovedCashQuery =
2594+
unapprovedCashSimilarSearchHash === currentSearchQueryJSON.similarSearchHash &&
2595+
isExpenseReport(iouReport) &&
2596+
(expenseReportStatusFilterMapping[CONST.SEARCH.STATUS.EXPENSE.DRAFTS](iouReport) || expenseReportStatusFilterMapping[CONST.SEARCH.STATUS.EXPENSE.OUTSTANDING](iouReport)) &&
2597+
transaction?.reimbursable;
2598+
2599+
const matchesFilterQuery = hasNoFlatFilters || matchesSubmitQuery || matchesApproveQuery || matchesUnapprovedCashQuery;
2600+
2601+
return shouldOptimisticallyUpdateByStatus && validSearchTypes && matchesFilterQuery;
25962602
}
25972603

25982604
function getSearchOnyxUpdate({
@@ -2609,108 +2615,110 @@ function getSearchOnyxUpdate({
26092615
const fromAccountID = deprecatedCurrentUserPersonalDetails?.accountID;
26102616
const currentSearchQueryJSON = getCurrentSearchQueryJSON();
26112617

2612-
if (currentSearchQueryJSON && toAccountID != null && fromAccountID != null) {
2613-
if (shouldOptimisticallyUpdateSearch(currentSearchQueryJSON, iouReport, isInvoice, transaction)) {
2614-
const isOptimisticToAccountData = isOptimisticPersonalDetail(toAccountID);
2615-
const successData = [];
2616-
if (isOptimisticToAccountData) {
2617-
// The optimistic personal detail is removed on the API's success data but we can't change the managerID of the transaction in the snapshot.
2618-
// So we need to add the optimistic personal detail back to the snapshot in success data to prevent the flickering.
2619-
// After that, it will be cleared via Search API.
2620-
// See https://github.com/Expensify/App/issues/61310 for more information.
2621-
successData.push({
2622-
onyxMethod: Onyx.METHOD.MERGE,
2623-
key: `${ONYXKEYS.COLLECTION.SNAPSHOT}${currentSearchQueryJSON.hash}` as const,
2624-
value: {
2625-
data: {
2626-
[ONYXKEYS.PERSONAL_DETAILS_LIST]: {
2627-
[toAccountID]: {
2628-
accountID: toAccountID,
2629-
displayName: participant?.displayName,
2630-
login: participant?.login,
2631-
},
2618+
if (!currentSearchQueryJSON || toAccountID === undefined || fromAccountID === undefined) {
2619+
return;
2620+
}
2621+
2622+
if (shouldOptimisticallyUpdateSearch(currentSearchQueryJSON, iouReport, isInvoice, transaction)) {
2623+
const isOptimisticToAccountData = isOptimisticPersonalDetail(toAccountID);
2624+
const successData = [];
2625+
if (isOptimisticToAccountData) {
2626+
// The optimistic personal detail is removed on the API's success data but we can't change the managerID of the transaction in the snapshot.
2627+
// So we need to add the optimistic personal detail back to the snapshot in success data to prevent the flickering.
2628+
// After that, it will be cleared via Search API.
2629+
// See https://github.com/Expensify/App/issues/61310 for more information.
2630+
successData.push({
2631+
onyxMethod: Onyx.METHOD.MERGE,
2632+
key: `${ONYXKEYS.COLLECTION.SNAPSHOT}${currentSearchQueryJSON.hash}` as const,
2633+
value: {
2634+
data: {
2635+
[ONYXKEYS.PERSONAL_DETAILS_LIST]: {
2636+
[toAccountID]: {
2637+
accountID: toAccountID,
2638+
displayName: participant?.displayName,
2639+
login: participant?.login,
26322640
},
26332641
},
26342642
},
2635-
});
2636-
}
2637-
const snapshotData = {
2638-
[ONYXKEYS.PERSONAL_DETAILS_LIST]: {
2639-
[toAccountID]: {
2640-
accountID: toAccountID,
2641-
displayName: participant?.displayName,
2642-
login: participant?.login,
2643-
},
2644-
[fromAccountID]: {
2645-
accountID: fromAccountID,
2646-
avatar: deprecatedCurrentUserPersonalDetails?.avatar,
2647-
displayName: deprecatedCurrentUserPersonalDetails?.displayName,
2648-
login: deprecatedCurrentUserPersonalDetails?.login,
2649-
},
26502643
},
2651-
[`${ONYXKEYS.COLLECTION.TRANSACTION}${transaction.transactionID}`]: {
2644+
});
2645+
}
2646+
const snapshotData = {
2647+
[ONYXKEYS.PERSONAL_DETAILS_LIST]: {
2648+
[toAccountID]: {
2649+
accountID: toAccountID,
2650+
displayName: participant?.displayName,
2651+
login: participant?.login,
2652+
},
2653+
[fromAccountID]: {
26522654
accountID: fromAccountID,
2653-
managerID: toAccountID,
2654-
...(transactionThreadReportID && {transactionThreadReportID}),
2655-
...(isFromOneTransactionReport && {isFromOneTransactionReport}),
2656-
...transaction,
2655+
avatar: deprecatedCurrentUserPersonalDetails?.avatar,
2656+
displayName: deprecatedCurrentUserPersonalDetails?.displayName,
2657+
login: deprecatedCurrentUserPersonalDetails?.login,
26572658
},
2658-
...(policy && {[`${ONYXKEYS.COLLECTION.POLICY}${policy.id}`]: policy}),
2659-
...(iouReport && {[`${ONYXKEYS.COLLECTION.REPORT}${iouReport.reportID}`]: iouReport}),
2660-
...(iouReport && iouAction && {[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${iouReport.reportID}`]: {[iouAction.reportActionID]: iouAction}}),
2661-
};
2659+
},
2660+
[`${ONYXKEYS.COLLECTION.TRANSACTION}${transaction.transactionID}`]: {
2661+
accountID: fromAccountID,
2662+
managerID: toAccountID,
2663+
...(transactionThreadReportID && {transactionThreadReportID}),
2664+
...(isFromOneTransactionReport && {isFromOneTransactionReport}),
2665+
...transaction,
2666+
},
2667+
...(policy && {[`${ONYXKEYS.COLLECTION.POLICY}${policy.id}`]: policy}),
2668+
...(iouReport && {[`${ONYXKEYS.COLLECTION.REPORT}${iouReport.reportID}`]: iouReport}),
2669+
...(iouReport && iouAction && {[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${iouReport.reportID}`]: {[iouAction.reportActionID]: iouAction}}),
2670+
};
26622671

2663-
const optimisticData: Array<OnyxUpdate<typeof ONYXKEYS.COLLECTION.SNAPSHOT>> = [
2664-
{
2672+
const optimisticData: Array<OnyxUpdate<typeof ONYXKEYS.COLLECTION.SNAPSHOT>> = [
2673+
{
2674+
onyxMethod: Onyx.METHOD.MERGE,
2675+
key: `${ONYXKEYS.COLLECTION.SNAPSHOT}${currentSearchQueryJSON.hash}` as const,
2676+
value: {
2677+
// @ts-expect-error - will be solved in https://github.com/Expensify/App/issues/73830
2678+
data: snapshotData,
2679+
},
2680+
},
2681+
];
2682+
2683+
if (currentSearchQueryJSON.groupBy === CONST.SEARCH.GROUP_BY.FROM) {
2684+
const newFlatFilters = currentSearchQueryJSON.flatFilters.filter((filter) => filter.key !== CONST.SEARCH.SYNTAX_FILTER_KEYS.FROM);
2685+
newFlatFilters.push({
2686+
key: CONST.SEARCH.SYNTAX_FILTER_KEYS.FROM,
2687+
filters: [{operator: CONST.SEARCH.SYNTAX_OPERATORS.EQUAL_TO, value: fromAccountID}],
2688+
});
2689+
2690+
const groupTransactionsQueryJSON = buildSearchQueryJSON(
2691+
buildSearchQueryString({
2692+
...currentSearchQueryJSON,
2693+
groupBy: undefined,
2694+
flatFilters: newFlatFilters,
2695+
}),
2696+
);
2697+
2698+
if (groupTransactionsQueryJSON?.hash) {
2699+
optimisticData.push({
26652700
onyxMethod: Onyx.METHOD.MERGE,
2666-
key: `${ONYXKEYS.COLLECTION.SNAPSHOT}${currentSearchQueryJSON.hash}` as const,
2701+
key: `${ONYXKEYS.COLLECTION.SNAPSHOT}${groupTransactionsQueryJSON.hash}` as const,
26672702
value: {
2703+
search: {
2704+
type: groupTransactionsQueryJSON.type,
2705+
status: groupTransactionsQueryJSON.status,
2706+
offset: 0,
2707+
hasMoreResults: false,
2708+
hasResults: true,
2709+
isLoading: false,
2710+
},
26682711
// @ts-expect-error - will be solved in https://github.com/Expensify/App/issues/73830
26692712
data: snapshotData,
26702713
},
2671-
},
2672-
];
2673-
2674-
if (currentSearchQueryJSON.groupBy === CONST.SEARCH.GROUP_BY.FROM) {
2675-
const newFlatFilters = currentSearchQueryJSON.flatFilters.filter((filter) => filter.key !== CONST.SEARCH.SYNTAX_FILTER_KEYS.FROM);
2676-
newFlatFilters.push({
2677-
key: CONST.SEARCH.SYNTAX_FILTER_KEYS.FROM,
2678-
filters: [{operator: CONST.SEARCH.SYNTAX_OPERATORS.EQUAL_TO, value: fromAccountID}],
26792714
});
2680-
2681-
const groupTransactionsQueryJSON = buildSearchQueryJSON(
2682-
buildSearchQueryString({
2683-
...currentSearchQueryJSON,
2684-
groupBy: undefined,
2685-
flatFilters: newFlatFilters,
2686-
}),
2687-
);
2688-
2689-
if (groupTransactionsQueryJSON?.hash) {
2690-
optimisticData.push({
2691-
onyxMethod: Onyx.METHOD.MERGE,
2692-
key: `${ONYXKEYS.COLLECTION.SNAPSHOT}${groupTransactionsQueryJSON.hash}` as const,
2693-
value: {
2694-
search: {
2695-
type: groupTransactionsQueryJSON.type,
2696-
status: groupTransactionsQueryJSON.status,
2697-
offset: 0,
2698-
hasMoreResults: false,
2699-
hasResults: true,
2700-
isLoading: false,
2701-
},
2702-
// @ts-expect-error - will be solved in https://github.com/Expensify/App/issues/73830
2703-
data: snapshotData,
2704-
},
2705-
});
2706-
}
27072715
}
2708-
2709-
return {
2710-
optimisticData,
2711-
successData,
2712-
};
27132716
}
2717+
2718+
return {
2719+
optimisticData,
2720+
successData,
2721+
};
27142722
}
27152723
}
27162724

0 commit comments

Comments
 (0)