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: a 'new comment' when opening the one expense report for the first time #43531

Merged
merged 8 commits into from
Jun 27, 2024
Merged
Show file tree
Hide file tree
Changes from 6 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: 2 additions & 2 deletions src/libs/ReportActionsUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -374,8 +374,8 @@ function shouldIgnoreGap(currentReportAction: ReportAction | undefined, nextRepo
* Returns a sorted and filtered list of report actions from a report and it's associated child
* transaction thread report in order to correctly display reportActions from both reports in the one-transaction report view.
*/
function getCombinedReportActions(reportActions: ReportAction[], transactionThreadReportActions: ReportAction[], reportID?: string): ReportAction[] {
if (isEmptyObject(transactionThreadReportActions)) {
function getCombinedReportActions(reportActions: ReportAction[], transactionThreadReportActions: ReportAction[], reportID?: string, isCombineReport?: boolean): ReportAction[] {
if (isEmptyObject(transactionThreadReportActions) && !isCombineReport) {
return reportActions;
}

Expand Down
129 changes: 65 additions & 64 deletions src/pages/home/report/ReportActionsView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ function ReportActionsView({
isLoadingNewerReportActions = false,
hasLoadingNewerReportActionsError = false,
isReadyForCommentLinking = false,
transactionThreadReportID,
}: ReportActionsViewProps) {
useCopySelectionHelper();
const reactionListRef = useContext(ReactionListContext);
Expand Down Expand Up @@ -154,11 +155,72 @@ function ReportActionsView({
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [route, isLoadingInitialReportActions, reportActionID]);

// When we are offline before opening an IOU/Expense report,
// the total of the report and sometimes the expense aren't displayed because these actions aren't returned until `OpenReport` API is complete.
// We generate a fake created action here if it doesn't exist to display the total whenever possible because the total just depends on report data
// and we also generate an expense action if the number of expenses in allReportActions is less than the total number of expenses
// to display at least one expense action to match the total data.
const reportActionsToDisplay = useMemo(() => {
if (!ReportUtils.isMoneyRequestReport(report) || !allReportActions.length) {
return allReportActions;
}

const actions = [...allReportActions];
const lastAction = allReportActions[allReportActions.length - 1];

if (!ReportActionsUtils.isCreatedAction(lastAction)) {
const optimisticCreatedAction = ReportUtils.buildOptimisticCreatedReportAction(String(report?.ownerAccountID), DateUtils.subtractMillisecondsFromDateTime(lastAction.created, 1));
optimisticCreatedAction.pendingAction = null;
actions.push(optimisticCreatedAction);
}

const reportPreviewAction = ReportActionsUtils.getReportPreviewAction(report.chatReportID ?? '', report.reportID);
const moneyRequestActions = allReportActions.filter((action) => {
const originalMessage = ReportActionsUtils.isMoneyRequestAction(action) ? ReportActionsUtils.getOriginalMessage(action) : undefined;
return (
ReportActionsUtils.isMoneyRequestAction(action) &&
originalMessage &&
(originalMessage?.type === CONST.IOU.REPORT_ACTION_TYPE.CREATE ||
!!(originalMessage?.type === CONST.IOU.REPORT_ACTION_TYPE.PAY && originalMessage?.IOUDetails) ||
originalMessage?.type === CONST.IOU.REPORT_ACTION_TYPE.TRACK)
);
});

if (report.total && moneyRequestActions.length < (reportPreviewAction?.childMoneyRequestCount ?? 0) && isEmptyObject(transactionThreadReport)) {
const optimisticIOUAction = ReportUtils.buildOptimisticIOUReportAction(
CONST.IOU.REPORT_ACTION_TYPE.CREATE,
0,
CONST.CURRENCY.USD,
'',
[],
NumberUtils.rand64(),
undefined,
report.reportID,
false,
false,
{},
false,
DateUtils.subtractMillisecondsFromDateTime(actions[actions.length - 1].created, 1),
) as OnyxTypes.ReportAction;
moneyRequestActions.push(optimisticIOUAction);
actions.splice(actions.length - 1, 0, optimisticIOUAction);
}

// Update pending action of created action if we have some requests that are pending
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const createdAction = actions.pop()!;
if (moneyRequestActions.filter((action) => !!action.pendingAction).length > 0) {
createdAction.pendingAction = CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE;
}

return [...actions, createdAction];
}, [allReportActions, report, transactionThreadReport]);

// Get a sorted array of reportActions for both the current report and the transaction thread report associated with this report (if there is one)
// so that we display transaction-level and report-level report actions in order in the one-transaction view
const combinedReportActions = useMemo(
() => ReportActionsUtils.getCombinedReportActions(allReportActions, transactionThreadReportActions),
[allReportActions, transactionThreadReportActions],
() => ReportActionsUtils.getCombinedReportActions(reportActionsToDisplay, transactionThreadReportActions, undefined, !!transactionThreadReportID),
[reportActionsToDisplay, transactionThreadReportActions, transactionThreadReportID],
);

const parentReportActionForTransactionThread = useMemo(
Expand Down Expand Up @@ -460,67 +522,6 @@ function ReportActionsView({
};
}, [isTheFirstReportActionIsLinked]);

// When we are offline before opening an IOU/Expense report,
// the total of the report and sometimes the expense aren't displayed because these actions aren't returned until `OpenReport` API is complete.
// We generate a fake created action here if it doesn't exist to display the total whenever possible because the total just depends on report data
// and we also generate an expense action if the number of expenses in reportActions is less than the total number of expenses
// to display at least one expense action to match the total data.
const reportActionsToDisplay = useMemo(() => {
if (!ReportUtils.isMoneyRequestReport(report) || !reportActions.length) {
return reportActions;
}

const actions = [...reportActions];
const lastAction = reportActions[reportActions.length - 1];

if (!ReportActionsUtils.isCreatedAction(lastAction)) {
const optimisticCreatedAction = ReportUtils.buildOptimisticCreatedReportAction(String(report?.ownerAccountID), DateUtils.subtractMillisecondsFromDateTime(lastAction.created, 1));
optimisticCreatedAction.pendingAction = null;
actions.push(optimisticCreatedAction);
}

const reportPreviewAction = ReportActionsUtils.getReportPreviewAction(report.chatReportID ?? '-1', report.reportID);
const moneyRequestActions = reportActions.filter((action) => {
const originalMessage = ReportActionsUtils.isMoneyRequestAction(action) ? ReportActionsUtils.getOriginalMessage(action) : undefined;
return (
ReportActionsUtils.isMoneyRequestAction(action) &&
originalMessage &&
(originalMessage?.type === CONST.IOU.REPORT_ACTION_TYPE.CREATE ||
!!(originalMessage?.type === CONST.IOU.REPORT_ACTION_TYPE.PAY && originalMessage?.IOUDetails) ||
originalMessage?.type === CONST.IOU.REPORT_ACTION_TYPE.TRACK)
);
});

if (report.total && moneyRequestActions.length < (reportPreviewAction?.childMoneyRequestCount ?? 0) && isEmptyObject(transactionThreadReport)) {
const optimisticIOUAction = ReportUtils.buildOptimisticIOUReportAction(
CONST.IOU.REPORT_ACTION_TYPE.CREATE,
0,
CONST.CURRENCY.USD,
'',
[],
NumberUtils.rand64(),
undefined,
report.reportID,
false,
false,
{},
false,
DateUtils.subtractMillisecondsFromDateTime(actions[actions.length - 1].created, 1),
) as OnyxTypes.ReportAction;
moneyRequestActions.push(optimisticIOUAction);
actions.splice(actions.length - 1, 0, optimisticIOUAction);
}

// Update pending action of created action if we have some requests that are pending
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const createdAction = actions.pop()!;
if (moneyRequestActions.filter((action) => !!action.pendingAction).length > 0) {
createdAction.pendingAction = CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE;
}

return [...actions, createdAction];
}, [reportActions, report, transactionThreadReport]);

// Comments have not loaded at all yet do nothing
if (!reportActions.length) {
return null;
Expand All @@ -536,7 +537,7 @@ function ReportActionsView({
parentReportAction={parentReportAction}
parentReportActionForTransactionThread={parentReportActionForTransactionThread}
onLayout={recordTimeToMeasureItemLayout}
sortedReportActions={reportActionsToDisplay}
sortedReportActions={reportActions}
mostRecentIOUReportActionID={mostRecentIOUReportActionID}
loadOlderChats={loadOlderChats}
loadNewerChats={loadNewerChats}
Expand Down
Loading