Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
1 change: 1 addition & 0 deletions src/CONST/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -916,6 +916,7 @@ const CONST = {
EMPTY_ARRAY,
EMPTY_OBJECT,
DEFAULT_NUMBER_ID,
FAKE_REPORT_ID: 'FAKE_REPORT_ID',
USE_EXPENSIFY_URL,
EXPENSIFY_URL,
EXPENSIFY_MOBILE_URL,
Expand Down
9 changes: 4 additions & 5 deletions src/ROUTES.ts
Original file line number Diff line number Diff line change
Expand Up @@ -593,11 +593,10 @@ const ROUTES = {
},
MONEY_REQUEST_HOLD_REASON: {
route: ':type/edit/reason/:transactionID?/:searchHash?',
getRoute: (type: ValueOf<typeof CONST.POLICY.TYPE>, transactionID: string, reportID: string, backTo: string, searchHash?: number) => {
const route = searchHash
? (`${type as string}/edit/reason/${transactionID}/${searchHash}/?backTo=${backTo}&reportID=${reportID}` as const)
: (`${type as string}/edit/reason/${transactionID}/?backTo=${backTo}&reportID=${reportID}` as const);
return route;
getRoute: (type: ValueOf<typeof CONST.POLICY.TYPE>, transactionID: string, reportID: string | undefined, backTo: string, searchHash?: number) => {
const searchPart = searchHash ? `/${searchHash}` : '';
const reportPart = reportID ? `&reportID=${reportID}` : '';
return `${type as string}/edit/reason/${transactionID}${searchPart}/?backTo=${backTo}${reportPart}` as const;
},
},
MONEY_REQUEST_CREATE: {
Expand Down
2 changes: 2 additions & 0 deletions src/libs/API/parameters/HoldMoneyRequestParams.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ type HoldMoneyRequestParams = {
comment: string;
reportActionID: string;
commentReportActionID: string;
transactionThreadReportID?: string;
createdReportActionIDForThread?: string;
};

export default HoldMoneyRequestParams;
7 changes: 5 additions & 2 deletions src/libs/ReportActionsUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@
type MemberChangeMessageElement = MessageTextElement | MemberChangeMessageUserMentionElement | MemberChangeMessageRoomReferenceElement;

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

Check warning on line 60 in src/libs/ReportActionsUtils.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 @@ -69,7 +69,7 @@
});

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

Check warning on line 72 in src/libs/ReportActionsUtils.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 @@ -78,14 +78,14 @@
});

let isNetworkOffline = false;
Onyx.connect({

Check warning on line 81 in src/libs/ReportActionsUtils.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.NETWORK,
callback: (val) => (isNetworkOffline = val?.isOffline ?? false),
});

let currentUserAccountID: number | undefined;
let currentEmail = '';
Onyx.connect({

Check warning on line 88 in src/libs/ReportActionsUtils.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) => {
// When signed out, value is undefined
Expand All @@ -99,7 +99,7 @@
});

let privatePersonalDetails: PrivatePersonalDetails | undefined;
Onyx.connect({

Check warning on line 102 in src/libs/ReportActionsUtils.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.PRIVATE_PERSONAL_DETAILS,
callback: (personalDetails) => {
privatePersonalDetails = personalDetails;
Expand Down Expand Up @@ -1307,7 +1307,6 @@
if (
actionType &&
iouRequestTypesSet.has(actionType) &&
action.childReportID &&
// Include deleted IOU reportActions if:
// - they have an associated IOU transaction ID or
// - the action is pending deletion and the user is offline
Expand Down Expand Up @@ -1339,7 +1338,11 @@
* Returns a reportID if there is exactly one transaction thread for the report, and undefined otherwise.
*/
function getOneTransactionThreadReportID(...args: Parameters<typeof getOneTransactionThreadReportAction>): string | undefined {
return getOneTransactionThreadReportAction(...args)?.childReportID;
const reportAction = getOneTransactionThreadReportAction(...args);
if (reportAction) {
// Since we don't always create transaction thread optimistically, we return CONST.FAKE_REPORT_ID
return reportAction.childReportID ?? CONST.FAKE_REPORT_ID;
}
}

/**
Expand Down
18 changes: 11 additions & 7 deletions src/libs/ReportUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -901,7 +901,7 @@
const parsedReportActionMessageCache: Record<string, string> = {};

let conciergeReportID: OnyxEntry<string>;
Onyx.connect({

Check warning on line 904 in src/libs/ReportUtils.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.CONCIERGE_REPORT_ID,
callback: (value) => {
conciergeReportID = value;
Expand All @@ -909,7 +909,7 @@
});

const defaultAvatarBuildingIconTestID = 'SvgDefaultAvatarBuilding Icon';
Onyx.connect({

Check warning on line 912 in src/libs/ReportUtils.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) => {
// When signed out, val is undefined
Expand All @@ -927,7 +927,7 @@
let allPersonalDetails: OnyxEntry<PersonalDetailsList>;
let allPersonalDetailLogins: string[];
let currentUserPersonalDetails: OnyxEntry<PersonalDetails>;
Onyx.connect({

Check warning on line 930 in src/libs/ReportUtils.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) => {
if (currentUserAccountID) {
Expand All @@ -939,14 +939,14 @@
});

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

Check warning on line 942 in src/libs/ReportUtils.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_DRAFT,
waitForCollectionCallback: true,
callback: (value) => (allReportsDraft = value),
});

let allPolicies: OnyxCollection<Policy>;
Onyx.connect({

Check warning on line 949 in src/libs/ReportUtils.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.POLICY,
waitForCollectionCallback: true,
callback: (value) => (allPolicies = value),
Expand Down Expand Up @@ -4437,8 +4437,8 @@

const transactionID = getOriginalMessage(reportAction)?.IOUTransactionID;

if (!transactionID || !reportAction.childReportID) {
Log.warn('Missing transactionID and reportAction.childReportID during the change of the money request hold status');
if (!transactionID) {
Log.warn('Missing transactionID during the change of the money request hold status');
return;
}

Expand All @@ -4447,7 +4447,11 @@
const policy = allPolicies?.[`${ONYXKEYS.COLLECTION.POLICY}${moneyRequestReport.policyID}`] ?? null;

if (isOnHold) {
unholdRequest(transactionID, reportAction.childReportID);
if (reportAction.childReportID) {
unholdRequest(transactionID, reportAction.childReportID);
} else {
Log.warn('Missing reportAction.childReportID during money request unhold');
}
} else {
const activeRoute = encodeURIComponent(Navigation.getActiveRoute());
Navigation.navigate(ROUTES.MONEY_REQUEST_HOLD_REASON.getRoute(policy?.type ?? CONST.POLICY.TYPE.PERSONAL, transactionID, reportAction.childReportID, activeRoute));
Expand Down Expand Up @@ -7845,6 +7849,7 @@
reportAction: OnyxEntry<ReportAction | OptimisticIOUReportAction>,
moneyRequestReport: OnyxEntry<Report>,
existingTransactionThreadReportID?: string,
optimisticTransactionThreadReportID?: string,
): OptimisticChatReport {
const participantAccountIDs = [...new Set([currentUserAccountID, Number(reportAction?.actorAccountID)])].filter(Boolean) as number[];
const existingTransactionThreadReport = getReportOrDraftReport(existingTransactionThreadReportID);
Expand All @@ -7867,6 +7872,7 @@
notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN,
parentReportActionID: reportAction?.reportActionID,
parentReportID: moneyRequestReport?.reportID,
optimisticReportID: optimisticTransactionThreadReportID,
});
}

Expand Down Expand Up @@ -9717,13 +9723,11 @@

/**
* Get optimistic data of parent report action
* @param reportID The reportID of the report that is updated
* @param report The report that is updated
* @param lastVisibleActionCreated Last visible action created of the child report
* @param type The type of action in the child report
*/
function getOptimisticDataForParentReportAction(reportID: string | undefined, lastVisibleActionCreated: string, type: string): Array<OnyxUpdate | null> {
const report = getReportOrDraftReport(reportID);

function getOptimisticDataForParentReportAction(report: Report | undefined, lastVisibleActionCreated: string, type: string): Array<OnyxUpdate | null> {
if (!report || isEmptyObject(report)) {
return [];
}
Expand Down
123 changes: 108 additions & 15 deletions src/libs/actions/IOU.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import type {
CreateWorkspaceParams,
DeleteMoneyRequestParams,
DetachReceiptParams,
HoldMoneyRequestParams,
MergeDuplicatesParams,
PayInvoiceParams,
PayMoneyRequestParams,
Expand Down Expand Up @@ -129,9 +130,11 @@ import {
buildOptimisticSubmittedReportAction,
buildOptimisticUnapprovedReportAction,
buildOptimisticUnHoldReportAction,
buildTransactionThread,
canBeAutoReimbursed,
canUserPerformWriteAction as canUserPerformWriteActionReportUtils,
findSelfDMReportID,
generateReportID,
getAllHeldTransactions as getAllHeldTransactionsReportUtils,
getAllPolicyReports,
getApprovalChain,
Expand Down Expand Up @@ -10992,17 +10995,30 @@ function adjustRemainingSplitShares(transaction: NonNullable<OnyxTypes.Transacti
/**
* Put expense on HOLD
*/
function putOnHold(transactionID: string, comment: string, reportID: string, searchHash?: number) {
function putOnHold(transactionID: string, comment: string, initialReportID: string | undefined, searchHash?: number) {
const currentTime = DateUtils.getDBTime();
const reportID = initialReportID ?? generateReportID();
const createdReportAction = buildOptimisticHoldReportAction(currentTime);
const createdReportActionComment = buildOptimisticHoldReportActionComment(comment, DateUtils.addMillisecondsFromDateTime(currentTime, 1));
const newViolation = {name: CONST.VIOLATIONS.HOLD, type: CONST.VIOLATION_TYPES.VIOLATION, showInReview: true};
const transactionViolations = allTransactionViolations[`${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transactionID}`] ?? [];
const updatedViolations = [...transactionViolations, newViolation];
const parentReportActionOptimistic = getOptimisticDataForParentReportAction(reportID, createdReportActionComment.created, CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD);
const transaction = allTransactions[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`];
const iouReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${transaction?.reportID}`];
const report = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`];
const iouAction = getIOUActionForReportID(transaction?.reportID, transactionID);
let transactionThreadReport: OnyxTypes.Report;

// If there is no existing transaction thread report, we should create one
// This way we ensure every held request has a dedicated thread for comments
if (initialReportID) {
transactionThreadReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${initialReportID}`] ?? ({} as OnyxTypes.Report);
} else {
const moneyRequestReport = getReportOrDraftReport(transaction?.reportID);
transactionThreadReport = buildTransactionThread(iouAction, moneyRequestReport, undefined, reportID);
}

const optimisticCreatedAction = buildOptimisticCreatedReportAction(currentUserEmail);
const parentReportActionOptimistic = getOptimisticDataForParentReportAction(transactionThreadReport, createdReportActionComment.created, CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD);

const optimisticData: OnyxUpdate[] = [
{
Expand Down Expand Up @@ -11092,11 +11108,85 @@ function putOnHold(transactionID: string, comment: string, reportID: string, sea
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.REPORT}${reportID}`,
value: {
lastVisibleActionCreated: report?.lastVisibleActionCreated,
lastVisibleActionCreated: transactionThreadReport.lastVisibleActionCreated,
},
},
];

// If the transaction thread report wasn't created before, we create it optimistically
if (!initialReportID) {
transactionThreadReport.pendingFields = {
createChat: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD,
};
optimisticData.push(
{
onyxMethod: Onyx.METHOD.SET,
key: `${ONYXKEYS.COLLECTION.REPORT}${reportID}`,
value: transactionThreadReport,
},
{
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`,
value: {[optimisticCreatedAction.reportActionID]: optimisticCreatedAction},
},
{
onyxMethod: Onyx.METHOD.SET,
key: `${ONYXKEYS.COLLECTION.REPORT_METADATA}${reportID}`,
value: {
isOptimisticReport: true,
},
},
);

if (iouAction?.reportActionID) {
// We link the IOU action to the new transaction thread by setting childReportID optimistically
optimisticData.push({
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${transactionThreadReport.parentReportID}`,
value: {[iouAction?.reportActionID]: {childReportID: reportID, childType: CONST.REPORT.TYPE.CHAT}},
});
// We reset the childReportID if the request fails
failureData.push({
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${transactionThreadReport.parentReportID}`,
value: {[iouAction?.reportActionID]: {childReportID: null, childType: null}},
});
}

successData.push(
{
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`,
value: {[optimisticCreatedAction.reportActionID]: {pendingAction: null}},
},
{
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.REPORT_METADATA}${reportID}`,
value: {
isOptimisticReport: false,
},
},
);

failureData.push(
{
onyxMethod: Onyx.METHOD.SET,
key: `${ONYXKEYS.COLLECTION.REPORT}${reportID}`,
value: null,
},
{
onyxMethod: Onyx.METHOD.SET,
key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`,
value: null,
},
{
onyxMethod: Onyx.METHOD.SET,
key: `${ONYXKEYS.COLLECTION.REPORT_METADATA}${reportID}`,
value: null,
},
);
}

// If we are holding from the search page, we optimistically update the snapshot data that search uses so that it is kept in sync
if (searchHash) {
optimisticData.push({
Expand Down Expand Up @@ -11125,16 +11215,19 @@ function putOnHold(transactionID: string, comment: string, reportID: string, sea
});
}

API.write(
'HoldRequest',
{
transactionID,
comment,
reportActionID: createdReportAction.reportActionID,
commentReportActionID: createdReportActionComment.reportActionID,
},
{optimisticData, successData, failureData},
);
const params: HoldMoneyRequestParams = {
transactionID,
comment,
reportActionID: createdReportAction.reportActionID,
commentReportActionID: createdReportActionComment.reportActionID,
};

if (!initialReportID) {
params.transactionThreadReportID = reportID;
params.createdReportActionIDForThread = optimisticCreatedAction.reportActionID;
}

API.write(WRITE_COMMANDS.HOLD_MONEY_REQUEST, params, {optimisticData, successData, failureData});

const currentReportID = getDisplayedReportID(reportID);
Navigation.setNavigationActionToMicrotaskQueue(() => notifyNewAction(currentReportID, userAccountID));
Expand Down Expand Up @@ -11253,7 +11346,7 @@ function unholdRequest(transactionID: string, reportID: string) {
];

API.write(
'UnHoldRequest',
WRITE_COMMANDS.UNHOLD_MONEY_REQUEST,
{
transactionID,
reportActionID: createdReportAction.reportActionID,
Expand Down
5 changes: 3 additions & 2 deletions src/libs/actions/Report.ts
Original file line number Diff line number Diff line change
Expand Up @@ -802,7 +802,7 @@ function addActions(reportID: string, text = '', file?: FileObject) {
];

// Update optimistic data for parent report action if the report is a child report
const optimisticParentReportData = getOptimisticDataForParentReportAction(reportID, currentTime, CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD);
const optimisticParentReportData = getOptimisticDataForParentReportAction(report, currentTime, CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD);
optimisticParentReportData.forEach((parentReportData) => {
if (isEmptyObject(parentReportData)) {
return;
Expand Down Expand Up @@ -1957,8 +1957,9 @@ function deleteReportComment(reportID: string | undefined, reportAction: ReportA
// Update optimistic data for parent report action if the report is a child report and the reportAction has no visible child
const childVisibleActionCount = reportAction.childVisibleActionCount ?? 0;
if (childVisibleActionCount === 0) {
const originalReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${originalReportID}`];
const optimisticParentReportData = getOptimisticDataForParentReportAction(
originalReportID,
originalReport,
optimisticReport?.lastVisibleActionCreated ?? '',
CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE,
);
Expand Down
4 changes: 2 additions & 2 deletions src/libs/actions/Task.ts
Original file line number Diff line number Diff line change
Expand Up @@ -307,7 +307,7 @@ function createTaskAndNavigate(
});

// If needed, update optimistic data for parent report action of the parent report.
const optimisticParentReportData = ReportUtils.getOptimisticDataForParentReportAction(parentReportID, currentTime, CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD);
const optimisticParentReportData = ReportUtils.getOptimisticDataForParentReportAction(parentReport, currentTime, CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD);
optimisticParentReportData.forEach((parentReportData) => {
if (isEmptyObject(parentReportData)) {
return;
Expand Down Expand Up @@ -1145,7 +1145,7 @@ function deleteTask(report: OnyxEntry<OnyxTypes.Report>) {
const childVisibleActionCount = parentReportAction?.childVisibleActionCount ?? 0;
if (childVisibleActionCount === 0) {
const optimisticParentReportData = ReportUtils.getOptimisticDataForParentReportAction(
parentReport?.reportID,
parentReport,
parentReport?.lastVisibleActionCreated ?? '',
CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE,
);
Expand Down
Loading
Loading