-
Notifications
You must be signed in to change notification settings - Fork 3.9k
Add Optimistic Updates to Search Transactions #60189
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
+114
−3
Merged
Changes from all commits
Commits
Show all changes
22 commits
Select commit
Hold shift + click to select a range
b3a7843
start updating hash
JS00001 736ffae
initial optimistic update
JS00001 66b5967
optimistics starting to work
JS00001 77905d4
add hash checking for what type of search we are on
JS00001 5924771
log stash
JS00001 74c7f22
Merge branch 'main' of github.com:Expensify/App into jsenyitko-optimi…
JS00001 5aee58e
Merge branch 'main' of github.com:Expensify/App into jsenyitko-optimi…
JS00001 eb6ecd7
add optimistic updates
JS00001 2c6e661
add hash
JS00001 e5e5185
Merge branch 'main' of github.com:Expensify/App into jsenyitko-optimi…
JS00001 9a4917a
much better way of getting search data
JS00001 9928db9
consolidate into one function
JS00001 7f11f32
eslint fixes
JS00001 d1090e6
Fix bug with optimistic updates
JS00001 82b9e2a
Merge branch 'main' of github.com:Expensify/App into jsenyitko-optimi…
JS00001 33179f9
fix unit tests, move stuff to better spots
JS00001 4e59bf4
fix eslint errors
JS00001 c91252b
add error state
JS00001 614a0f4
remove failrue data, search corrects it
JS00001 7ce978b
optimistic updates for Invoices
JS00001 f021b90
update 1 letter var
JS00001 ee13812
Merge branch 'main' of github.com:Expensify/App into jsenyitko-optimi…
JS00001 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -157,6 +157,7 @@ import { | |
| shouldCreateNewMoneyRequestReport as shouldCreateNewMoneyRequestReportReportUtils, | ||
| updateReportPreview, | ||
| } from '@libs/ReportUtils'; | ||
| import {getCurrentSearchQueryJSON} from '@libs/SearchQueryUtils'; | ||
| import {getSession} from '@libs/SessionUtils'; | ||
| import playSound, {SOUNDS} from '@libs/Sound'; | ||
| import {shouldRestrictUserBillableActions} from '@libs/SubscriptionUtils'; | ||
|
|
@@ -202,7 +203,7 @@ import type {QuickActionName} from '@src/types/onyx/QuickAction'; | |
| 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 {SearchPolicy, SearchReport, SearchTransaction} from '@src/types/onyx/SearchResults'; | ||
| import type {SearchDataTypes, SearchPolicy, SearchReport, 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'; | ||
|
|
@@ -446,6 +447,7 @@ type BuildOnyxDataForMoneyRequestParams = { | |
| policyParams?: BasePolicyParams; | ||
| optimisticParams: MoneyRequestOptimisticParams; | ||
| retryParams?: StartSplitBilActionParams | CreateTrackExpenseParams | RequestMoneyInformation | ReplaceReceipt; | ||
| participant?: Participant; | ||
| }; | ||
|
|
||
| type DistanceRequestTransactionParams = BaseTransactionParams & { | ||
|
|
@@ -533,6 +535,7 @@ type BuildOnyxDataForInvoiceParams = { | |
| }; | ||
| companyName?: string; | ||
| companyWebsite?: string; | ||
| participant?: Participant; | ||
| }; | ||
|
|
||
| type GetTrackExpenseInformationTransactionParams = { | ||
|
|
@@ -595,6 +598,11 @@ type ReplaceReceipt = { | |
| source: string; | ||
| }; | ||
|
|
||
| type GetSearchOnyxUpdateParams = { | ||
| transaction: OnyxTypes.Transaction; | ||
| participant?: Participant; | ||
| }; | ||
|
|
||
| let allTransactions: NonNullable<OnyxCollection<OnyxTypes.Transaction>> = {}; | ||
| Onyx.connect({ | ||
| key: ONYXKEYS.COLLECTION.TRANSACTION, | ||
|
|
@@ -1184,6 +1192,7 @@ function buildOnyxDataForMoneyRequest(moneyRequestParams: BuildOnyxDataForMoneyR | |
| policyParams = {}, | ||
| optimisticParams, | ||
| retryParams, | ||
| participant, | ||
| } = moneyRequestParams; | ||
| const {policy, policyCategories, policyTagList} = policyParams; | ||
| const { | ||
|
|
@@ -1200,6 +1209,7 @@ function buildOnyxDataForMoneyRequest(moneyRequestParams: BuildOnyxDataForMoneyR | |
| const outstandingChildRequest = getOutstandingChildRequest(iou.report); | ||
| const clearedPendingFields = Object.fromEntries(Object.keys(transaction.pendingFields ?? {}).map((key) => [key, null])); | ||
| const isMoneyRequestToManagerMcTest = isTestTransactionReport(iou.report); | ||
|
|
||
| const optimisticData: OnyxUpdate[] = []; | ||
| const successData: OnyxUpdate[] = []; | ||
| let newQuickAction: ValueOf<typeof CONST.QUICK_ACTIONS>; | ||
|
|
@@ -1689,6 +1699,15 @@ function buildOnyxDataForMoneyRequest(moneyRequestParams: BuildOnyxDataForMoneyR | |
| }); | ||
| } | ||
|
|
||
| const searchUpdate = getSearchOnyxUpdate({ | ||
| transaction, | ||
| participant, | ||
| }); | ||
|
|
||
| if (searchUpdate) { | ||
| optimisticData.push({...searchUpdate}); | ||
| } | ||
|
|
||
| // We don't need to compute violations unless we're on a paid policy | ||
| if (!policy || !isPaidGroupPolicy(policy)) { | ||
| return [optimisticData, successData, failureData]; | ||
|
|
@@ -1724,7 +1743,8 @@ function buildOnyxDataForMoneyRequest(moneyRequestParams: BuildOnyxDataForMoneyR | |
|
|
||
| /** Builds the Onyx data for an invoice */ | ||
| function buildOnyxDataForInvoice(invoiceParams: BuildOnyxDataForInvoiceParams): [OnyxUpdate[], OnyxUpdate[], OnyxUpdate[]] { | ||
| const {chat, iou, transactionParams, policyParams, optimisticData: optimisticDataParams, companyName, companyWebsite} = invoiceParams; | ||
| const {chat, iou, transactionParams, policyParams, optimisticData: optimisticDataParams, companyName, companyWebsite, participant} = invoiceParams; | ||
| const transaction = transactionParams.transaction; | ||
|
|
||
| const clearedPendingFields = Object.fromEntries(Object.keys(transactionParams.transaction.pendingFields ?? {}).map((key) => [key, null])); | ||
| const optimisticData: OnyxUpdate[] = [ | ||
|
|
@@ -2104,6 +2124,15 @@ function buildOnyxDataForInvoice(invoiceParams: BuildOnyxDataForInvoiceParams): | |
| }); | ||
| } | ||
|
|
||
| const searchUpdate = getSearchOnyxUpdate({ | ||
| transaction, | ||
| participant, | ||
| }); | ||
|
|
||
| if (searchUpdate) { | ||
| optimisticData.push({...searchUpdate}); | ||
| } | ||
|
|
||
| // We don't need to compute violations unless we're on a paid policy | ||
| if (!policyParams.policy || !isPaidGroupPolicy(policyParams.policy)) { | ||
| return [optimisticData, successData, failureData]; | ||
|
|
@@ -2140,6 +2169,7 @@ type BuildOnyxDataForTrackExpenseParams = { | |
| existingTransactionThreadReportID?: string; | ||
| actionableTrackExpenseWhisper?: OnyxInputValue<OnyxTypes.ReportAction>; | ||
| retryParams?: StartSplitBilActionParams | CreateTrackExpenseParams | RequestMoneyInformation | ReplaceReceipt; | ||
| participant?: Participant; | ||
| }; | ||
|
|
||
| /** Builds the Onyx data for track expense */ | ||
|
|
@@ -2152,6 +2182,7 @@ function buildOnyxDataForTrackExpense({ | |
| existingTransactionThreadReportID, | ||
| actionableTrackExpenseWhisper, | ||
| retryParams, | ||
| participant, | ||
| }: BuildOnyxDataForTrackExpenseParams): [OnyxUpdate[], OnyxUpdate[], OnyxUpdate[]] { | ||
| const {report: chatReport, previewAction: reportPreviewAction} = chat; | ||
| const {report: iouReport, createdAction: iouCreatedAction, action: iouAction} = iou; | ||
|
|
@@ -2161,6 +2192,7 @@ function buildOnyxDataForTrackExpense({ | |
| const isScanRequest = isScanRequestTransactionUtils(transaction); | ||
| const isDistanceRequest = isDistanceRequestTransactionUtils(transaction); | ||
| const clearedPendingFields = Object.fromEntries(Object.keys(transaction.pendingFields ?? {}).map((key) => [key, null])); | ||
|
|
||
| const optimisticData: OnyxUpdate[] = []; | ||
| const successData: OnyxUpdate[] = []; | ||
| const failureData: OnyxUpdate[] = []; | ||
|
|
@@ -2550,6 +2582,15 @@ function buildOnyxDataForTrackExpense({ | |
| }); | ||
| } | ||
|
|
||
| const searchUpdate = getSearchOnyxUpdate({ | ||
| transaction, | ||
| participant, | ||
| }); | ||
|
|
||
| if (searchUpdate) { | ||
| optimisticData.push({...searchUpdate}); | ||
| } | ||
|
|
||
| // We don't need to compute violations unless we're on a paid policy | ||
| if (!policy || !isPaidGroupPolicy(policy)) { | ||
| return [optimisticData, successData, failureData]; | ||
|
|
@@ -2929,6 +2970,7 @@ function getSendInvoiceInformation( | |
| policyRecentlyUsedCategories: optimisticPolicyRecentlyUsedCategories, | ||
| policyRecentlyUsedTags: optimisticPolicyRecentlyUsedTags, | ||
| }, | ||
| participant: receiver, | ||
| companyName, | ||
| companyWebsite, | ||
| }); | ||
|
|
@@ -3084,7 +3126,6 @@ function getMoneyRequestInformation(moneyRequestInformation: MoneyRequestInforma | |
| participants: [participant], | ||
| transactionID: optimisticTransaction.transactionID, | ||
| paymentType: isSelectedManagerMcTest(participant.login) ? CONST.IOU.PAYMENT_TYPE.ELSEWHERE : undefined, | ||
|
|
||
| existingTransactionThreadReportID: linkedTrackedExpenseReportAction?.childReportID, | ||
| linkedTrackedExpenseReportAction, | ||
| }); | ||
|
|
@@ -3122,6 +3163,7 @@ function getMoneyRequestInformation(moneyRequestInformation: MoneyRequestInforma | |
|
|
||
| // STEP 5: Build Onyx Data | ||
| const [optimisticData, successData, failureData] = buildOnyxDataForMoneyRequest({ | ||
| participant, | ||
| isNewChatReport, | ||
| shouldCreateNewMoneyRequestReport, | ||
| policyParams: { | ||
|
|
@@ -3577,6 +3619,7 @@ function getTrackExpenseInformation(params: GetTrackExpenseInformationParams): T | |
|
|
||
| // STEP 5: Build Onyx Data | ||
| const trackExpenseOnyxData = buildOnyxDataForTrackExpense({ | ||
| participant, | ||
| chat: {report: chatReport, previewAction: reportPreviewAction}, | ||
| iou: {report: iouReport, action: iouAction, createdAction: optimisticCreatedActionForIOUReport}, | ||
| transactionParams: { | ||
|
|
@@ -10513,6 +10556,47 @@ function resolveDuplicates(params: MergeDuplicatesParams) { | |
| API.write(WRITE_COMMANDS.RESOLVE_DUPLICATES, parameters, {optimisticData, failureData}); | ||
| } | ||
|
|
||
| function getSearchOnyxUpdate({participant, transaction}: GetSearchOnyxUpdateParams) { | ||
| const toAccountID = participant?.accountID; | ||
| const fromAccountID = currentUserPersonalDetails?.accountID; | ||
| const currentSearchQueryJSON = getCurrentSearchQueryJSON(); | ||
|
|
||
| if (currentSearchQueryJSON && toAccountID != null && fromAccountID != null) { | ||
| const validSearchTypes: SearchDataTypes[] = [CONST.SEARCH.DATA_TYPES.EXPENSE, CONST.SEARCH.DATA_TYPES.INVOICE]; | ||
| const shouldOptimisticallyUpdate = | ||
| currentSearchQueryJSON.status === CONST.SEARCH.STATUS.EXPENSE.ALL && validSearchTypes.includes(currentSearchQueryJSON.type) && currentSearchQueryJSON.flatFilters.length === 0; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Skipping the filters here led to this issue #64128 where the query with filters do not get optimistically updated. This is not a mistake, just a case that was not considered before the to do queries are implemented. |
||
|
|
||
| if (shouldOptimisticallyUpdate) { | ||
| return { | ||
| onyxMethod: Onyx.METHOD.MERGE, | ||
| key: `${ONYXKEYS.COLLECTION.SNAPSHOT}${currentSearchQueryJSON.hash}` as const, | ||
| value: { | ||
| data: { | ||
| [ONYXKEYS.PERSONAL_DETAILS_LIST]: { | ||
| [toAccountID]: { | ||
| accountID: toAccountID, | ||
| displayName: participant?.displayName, | ||
| login: participant?.login, | ||
| }, | ||
| [fromAccountID]: { | ||
| accountID: fromAccountID, | ||
| avatar: currentUserPersonalDetails?.avatar, | ||
| displayName: currentUserPersonalDetails?.displayName, | ||
| login: currentUserPersonalDetails?.login, | ||
| }, | ||
| }, | ||
| [`${ONYXKEYS.COLLECTION.TRANSACTION}${transaction.transactionID}`]: { | ||
| accountID: fromAccountID, | ||
| managerID: toAccountID, | ||
| ...transaction, | ||
| }, | ||
| }, | ||
| }, | ||
| }; | ||
| } | ||
| } | ||
| } | ||
|
|
||
| export { | ||
| adjustRemainingSplitShares, | ||
| getNextApproverAccountID, | ||
|
|
||
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The addition of the
route.name === NAVIGATORS.REPORTS_SPLIT_NAVIGATORcheck here led to the following issue:which we addressed by removing the check (see proposal for details).