Skip to content
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

fix: Set childReportID of the optimistic IOU report action #37232

Merged
merged 11 commits into from
Mar 11, 2024
Merged
12 changes: 1 addition & 11 deletions src/components/ReportActionItem/MoneyRequestAction.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,7 @@ import useNetwork from '@hooks/useNetwork';
import useThemeStyles from '@hooks/useThemeStyles';
import * as IOUUtils from '@libs/IOUUtils';
import Navigation from '@libs/Navigation/Navigation';
import * as PersonalDetailsUtils from '@libs/PersonalDetailsUtils';
import * as ReportActionsUtils from '@libs/ReportActionsUtils';
import * as ReportUtils from '@libs/ReportUtils';
import type {ContextMenuAnchor} from '@pages/home/report/ContextMenu/ReportActionContextMenu';
import * as Report from '@userActions/Report';
import CONST from '@src/CONST';
Expand Down Expand Up @@ -91,15 +89,7 @@ function MoneyRequestAction({
return;
}

// If the childReportID is not present, we need to create a new thread
Copy link
Contributor

Choose a reason for hiding this comment

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

Are we removing this because we're always creating transaction threads in the backend, and action?.childReportID will be set to the ID of that transaction thread?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes. We've discussed it briefly here: #37232 (comment)

const childReportID = action?.childReportID;
if (!childReportID) {
const thread = ReportUtils.buildTransactionThread(action, requestReportID);
const userLogins = PersonalDetailsUtils.getLoginsByAccountIDs(thread.participantAccountIDs ?? []);
Report.openReport(thread.reportID, userLogins, thread, action.reportActionID);
Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(thread.reportID));
return;
}
const childReportID = action?.childReportID ?? '0';
Report.openReport(childReportID);
Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(childReportID));
};
Expand Down
10 changes: 5 additions & 5 deletions src/libs/ReportUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ type OptimisticIOUReportAction = Pick<
| 'pendingAction'
| 'receipt'
| 'whisperedToAccountIDs'
| 'childReportID'
>;

type ReportRouteParams = {
Expand Down Expand Up @@ -3825,24 +3826,23 @@ function buildOptimisticTaskReport(
* A helper method to create transaction thread
*
* @param reportAction - the parent IOU report action from which to create the thread
*
* @param moneyRequestReportID - the reportID which the report action belong to
* @param moneyRequestReport - the report which the report action belongs to
*/
function buildTransactionThread(reportAction: OnyxEntry<ReportAction | OptimisticIOUReportAction>, moneyRequestReportID: string): OptimisticChatReport {
function buildTransactionThread(reportAction: OnyxEntry<ReportAction | OptimisticIOUReportAction>, moneyRequestReport: Report): OptimisticChatReport {
const participantAccountIDs = [...new Set([currentUserAccountID, Number(reportAction?.actorAccountID)])].filter(Boolean) as number[];
return buildOptimisticChatReport(
participantAccountIDs,
getTransactionReportName(reportAction),
undefined,
getReport(moneyRequestReportID)?.policyID ?? CONST.POLICY.OWNER_EMAIL_FAKE,
moneyRequestReport.policyID,
CONST.POLICY.OWNER_ACCOUNT_ID_FAKE,
false,
'',
undefined,
undefined,
CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN,
reportAction?.reportActionID,
moneyRequestReportID,
moneyRequestReport.reportID,
);
}

Expand Down
14 changes: 9 additions & 5 deletions src/libs/actions/IOU.ts
Original file line number Diff line number Diff line change
Expand Up @@ -926,7 +926,8 @@ function getMoneyRequestInformation(
false,
currentTime,
);
const optimisticTransactionThread = ReportUtils.buildTransactionThread(iouAction, iouReport.reportID);
const optimisticTransactionThread = ReportUtils.buildTransactionThread(iouAction, iouReport);
iouAction.childReportID = optimisticTransactionThread.reportID;
Copy link
Contributor

Choose a reason for hiding this comment

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

Should we add a comment above this line saying why we need to do this? It's not super obvious right away, and it made me wonder if we should be setting this in const iouAction = ReportUtils.buildOptimisticIOUReportAction, but then realized ReportUtils.buildTransactionThread takes iouAction which is created by ReportUtils.buildOptimisticIOUReportAction.

I don't have a good solution for that right now -- it seems like we could generate an optimistic reportID before the calls to ReportUtils.buildOptimisticIOUReportAction and ReportUtils.buildTransactionThread, and pass it to both so we don't have to manually set iouAction.childReportID = optimisticTransactionThread.reportID;, but I'm not sure if that's a good idea.

I'm curious what you think

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, unfortunately these 2 are co-dependent: the transaction thread has the iou action's ID as the parent action ID, and vice versa. Also, passing the pre-generated report ID will cause a lot of refactoring of the current methods that use the buildOptimisticChatReport. One possible idea here is to make a separate function that will generate the iouAction, optimisticTransactionThread, and the optimisticCreatedActionForTransactionThread. This way, we'll not be setting the iouAction.childReportID in 4 different places, but in only one function, and will be calling it from those 4 places. It's not perfect either, but will minimize code duplication.

Smth like:

function buildOptimisticIOUReportActionWithTransactionThread(...) {
  const iouAction = ReportUtils.buildOptimisticIOUReportAction(
        CONST.IOU.REPORT_ACTION_TYPE.CREATE,
        amount,
        currency,
        comment,
        [participant],
        optimisticTransaction.transactionID,
        undefined,
        iouReport.reportID,
        false,
        false,
        receiptObject,
        false,
        currentTime,
    );
    const optimisticTransactionThread = ReportUtils.buildTransactionThread(iouAction, iouReport.reportID);
    iouAction.childReportID = optimisticTransactionThread.reportID;
    const optimisticCreatedActionForTransactionThread = ReportUtils.buildOptimisticCreatedReportAction(payeeEmail);


  return { iouAction, optimisticTransactionThread, optimisticCreatedActionForTransactionThread }
}

Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah I thought of that but wasn't convinced it would be better. But on second thought, I do think it's better and we can add a comment inside that function above where we set iouAction.childReportID so people know not to remove it.

The alternative would be to put that comment in 4 places, and we'd have that code duplicated like you said, and nothing prevents people from forgetting to set iouAction.childReportID

I'm good to update to this 👍

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done ✔️

@situchan I've re-tested the 4 different flows that use the 4 different functions that call this new buildOptimisticMoneyRequestEntities function – everything works as expected (except for the known Complete Split BE issue):

  • Send Money
  • Request Money
  • Split right away (the fixed amount split)
  • Split with Complete Split (the scan split)

const optimisticCreatedActionForTransactionThread = ReportUtils.buildOptimisticCreatedReportAction(payeeEmail);

let reportPreviewAction = shouldCreateNewMoneyRequestReport ? null : ReportActionsUtils.getReportPreviewAction(chatReport.reportID, iouReport.reportID);
Expand Down Expand Up @@ -1933,7 +1934,8 @@ function createSplitsAndOnyxData(
const optimisticPolicyRecentlyUsedTags = isPolicyExpenseChat ? Policy.buildOptimisticPolicyRecentlyUsedTags(participant.policyID, tag) : {};

// Create optimistic transactionThread
const optimisticTransactionThread = ReportUtils.buildTransactionThread(oneOnOneIOUAction, oneOnOneIOUReport.reportID);
const optimisticTransactionThread = ReportUtils.buildTransactionThread(oneOnOneIOUAction, oneOnOneIOUReport);
oneOnOneIOUAction.childReportID = optimisticTransactionThread.reportID;
const optimisticCreatedActionForTransactionThread = ReportUtils.buildOptimisticCreatedReportAction(currentUserEmailForIOUSplit);

// STEP 5: Build Onyx Data
Expand Down Expand Up @@ -2052,7 +2054,7 @@ function splitBill(
}

/**
* @param amount - always in smallest currency unit
* @param amount - always in the smallest currency unit
*/
function splitBillAndOpenReport(
participants: Participant[],
Expand Down Expand Up @@ -2537,7 +2539,8 @@ function completeSplitBill(chatReportID: string, reportAction: OnyxTypes.ReportA
oneOnOneReportPreviewAction = ReportUtils.buildOptimisticReportPreview(oneOnOneChatReport, oneOnOneIOUReport, '', oneOnOneTransaction);
}

const optimisticTransactionThread = ReportUtils.buildTransactionThread(oneOnOneIOUAction, oneOnOneIOUReport.reportID);
const optimisticTransactionThread = ReportUtils.buildTransactionThread(oneOnOneIOUAction, oneOnOneIOUReport);
oneOnOneIOUAction.childReportID = optimisticTransactionThread.reportID;
const optimisticCreatedActionForTransactionThread = ReportUtils.buildOptimisticCreatedReportAction(currentUserEmailForIOUSplit);

const [oneOnOneOptimisticData, oneOnOneSuccessData, oneOnOneFailureData] = buildOnyxDataForMoneyRequest(
Expand Down Expand Up @@ -3264,7 +3267,8 @@ function getSendMoneyParams(

const reportPreviewAction = ReportUtils.buildOptimisticReportPreview(chatReport, optimisticIOUReport);

const optimisticTransactionThread = ReportUtils.buildTransactionThread(optimisticIOUReportAction, optimisticIOUReport.reportID);
const optimisticTransactionThread = ReportUtils.buildTransactionThread(optimisticIOUReportAction, optimisticIOUReport);
optimisticIOUReportAction.childReportID = optimisticTransactionThread.reportID;
const optimisticCreatedActionForTransactionThread = ReportUtils.buildOptimisticCreatedReportAction(recipientEmail);

// Change the method to set for new reports because it doesn't exist yet, is faster,
Expand Down
8 changes: 0 additions & 8 deletions src/pages/home/report/ContextMenu/ContextMenuActions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import getAttachmentDetails from '@libs/fileDownload/getAttachmentDetails';
import ModifiedExpenseMessage from '@libs/ModifiedExpenseMessage';
import Navigation from '@libs/Navigation/Navigation';
import Permissions from '@libs/Permissions';
import * as PersonalDetailsUtils from '@libs/PersonalDetailsUtils';
import ReportActionComposeFocusManager from '@libs/ReportActionComposeFocusManager';
import * as ReportActionsUtils from '@libs/ReportActionsUtils';
import * as ReportUtils from '@libs/ReportUtils';
Expand Down Expand Up @@ -214,13 +213,6 @@ const ContextMenuActions: ContextMenuAction[] = [
if (ReportActionsUtils.isMoneyRequestAction(reportAction)) {
hideContextMenu(false);
const childReportID = reportAction?.childReportID ?? '0';
if (!childReportID) {
const thread = ReportUtils.buildTransactionThread(reportAction, reportID);
const userLogins = PersonalDetailsUtils.getLoginsByAccountIDs(thread.participantAccountIDs ?? []);
Report.openReport(thread.reportID, userLogins, thread, reportAction?.reportActionID);
Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(thread.reportID));
return;
}
Report.openReport(childReportID);
Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(childReportID));
return;
Expand Down
14 changes: 7 additions & 7 deletions tests/actions/IOUTest.js
Original file line number Diff line number Diff line change
Expand Up @@ -1509,7 +1509,7 @@ describe('actions/IOU', () => {
}),
)
.then(() => {
thread = ReportUtils.buildTransactionThread(iouAction, iouReport.reportID);
thread = ReportUtils.buildTransactionThread(iouAction, iouReport);
Onyx.set(`report_${thread.reportID}`, thread);
return waitForBatchedUpdates();
})
Expand Down Expand Up @@ -1643,7 +1643,7 @@ describe('actions/IOU', () => {
}),
)
.then(() => {
thread = ReportUtils.buildTransactionThread(iouAction, iouReport.reportID);
thread = ReportUtils.buildTransactionThread(iouAction, iouReport);
Onyx.set(`report_${thread.reportID}`, thread);
return waitForBatchedUpdates();
})
Expand Down Expand Up @@ -2214,7 +2214,7 @@ describe('actions/IOU', () => {
jest.advanceTimersByTime(10);

// Given a transaction thread
thread = ReportUtils.buildTransactionThread(createIOUAction, IOU_REPORT_ID);
thread = ReportUtils.buildTransactionThread(createIOUAction, {reportID: IOU_REPORT_ID});

expect(thread.notificationPreference).toBe(CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN);

Expand Down Expand Up @@ -2295,7 +2295,7 @@ describe('actions/IOU', () => {
jest.advanceTimersByTime(10);

// Given a transaction thread
thread = ReportUtils.buildTransactionThread(createIOUAction, IOU_REPORT_ID);
thread = ReportUtils.buildTransactionThread(createIOUAction, {reportID: IOU_REPORT_ID});

Onyx.connect({
key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${thread.reportID}`,
Expand Down Expand Up @@ -2374,7 +2374,7 @@ describe('actions/IOU', () => {
await waitForBatchedUpdates();

// Given a transaction thread
thread = ReportUtils.buildTransactionThread(createIOUAction);
thread = ReportUtils.buildTransactionThread(createIOUAction, {reportID: IOU_REPORT_ID});

expect(thread.notificationPreference).toBe(CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN);

Expand Down Expand Up @@ -2460,7 +2460,7 @@ describe('actions/IOU', () => {
// Given a thread report

jest.advanceTimersByTime(10);
thread = ReportUtils.buildTransactionThread(createIOUAction, IOU_REPORT_ID);
thread = ReportUtils.buildTransactionThread(createIOUAction, {reportID: IOU_REPORT_ID});

expect(thread.notificationPreference).toBe(CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN);

Expand Down Expand Up @@ -2686,7 +2686,7 @@ describe('actions/IOU', () => {
// Given a thread report

jest.advanceTimersByTime(10);
thread = ReportUtils.buildTransactionThread(createIOUAction, IOU_REPORT_ID);
thread = ReportUtils.buildTransactionThread(createIOUAction, {reportID: IOU_REPORT_ID});

expect(thread.notificationPreference).toBe(CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN);

Expand Down
Loading