Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
5b49afe
Add getOptimisticDataForAncestors function and update related components
Tony-MK Oct 27, 2025
5f71e0a
Refactor PopoverReportActionContextMenu to use original report data f…
Tony-MK Oct 28, 2025
20236a2
Merge branch 'main' into deleteReportComment
Tony-MK Oct 28, 2025
c30db4b
refactor: PopoverReportActionContextMenu for improved type safety and…
Tony-MK Oct 28, 2025
29f63ea
fixed ancestors params in UnreadIndicatorsTest
Tony-MK Oct 28, 2025
db59e27
Merge branch 'main' of https://github.com/Expensify/App into deleteRe…
Tony-MK Oct 28, 2025
bcaebbd
Merge branch 'main' of https://github.com/Expensify/App into deleteRe…
Tony-MK Oct 29, 2025
176da24
refactor: getOptimisticDataForAncestors to use reduce for improved cl…
Tony-MK Oct 29, 2025
cf34c35
fix: update dependency array in useEffect for correct behavior
Tony-MK Oct 30, 2025
0d4ec84
Merge branch 'Expensify:main' into deleteReportComment
Tony-MK Oct 30, 2025
18fc26e
Merge branch 'main' of https://github.com/Expensify/App into deleteRe…
Tony-MK Oct 31, 2025
88bf7da
Merge branch 'main' into deleteReportComment
Tony-MK Oct 31, 2025
4ab7817
update ancestors to use original parent report
Tony-MK Oct 31, 2025
93a099c
Merge branch 'deleteReportComment' of https://github.com/Tony-MK/Expe…
Tony-MK Oct 31, 2025
eaa496a
Revert "update ancestors to use original parent report"
Tony-MK Oct 31, 2025
956b649
Adding new line
Tony-MK Oct 31, 2025
bc199bf
refactor: implemented previousActionDeleted in getOptimisticDataForAn…
Tony-MK Oct 31, 2025
6621f59
prettier
Tony-MK Oct 31, 2025
f814036
Merge branch 'Expensify:main' into deleteReportComment
Tony-MK Oct 31, 2025
6bcdee1
Merge branch 'main' of https://github.com/Expensify/App into deleteRe…
Tony-MK Nov 3, 2025
03bd81d
refactor: getOptimisticDataForAncestors to use map instead of reduce …
Tony-MK Nov 3, 2025
1d1f9c4
refactor:test report
Tony-MK Nov 3, 2025
221e065
Merge branch 'main' of https://github.com/Expensify/App into deleteRe…
Tony-MK Nov 3, 2025
86bc77e
prettier
Tony-MK Nov 3, 2025
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
25 changes: 24 additions & 1 deletion src/libs/ReportUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -942,7 +942,7 @@
const parsedReportActionMessageCache: Record<string, string> = {};

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

Check warning on line 945 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 @@ -950,7 +950,7 @@
});

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

Check warning on line 953 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 @@ -968,7 +968,7 @@
let allPersonalDetails: OnyxEntry<PersonalDetailsList>;
let allPersonalDetailLogins: string[];
let currentUserPersonalDetails: OnyxEntry<PersonalDetails>;
Onyx.connect({

Check warning on line 971 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 @@ -980,14 +980,14 @@
});

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

Check warning on line 983 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 990 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 All @@ -995,7 +995,7 @@

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

Check warning on line 998 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,
waitForCollectionCallback: true,
callback: (value) => {
Expand Down Expand Up @@ -1036,14 +1036,14 @@
});

let allBetas: OnyxEntry<Beta[]>;
Onyx.connect({

Check warning on line 1039 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.BETAS,
callback: (value) => (allBetas = value),
});

let allTransactions: OnyxCollection<Transaction> = {};
let reportsTransactions: Record<string, Transaction[]> = {};
Onyx.connect({

Check warning on line 1046 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.TRANSACTION,
waitForCollectionCallback: true,
callback: (value) => {
Expand All @@ -1069,7 +1069,7 @@
});

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

Check warning on line 1072 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_ACTIONS,
waitForCollectionCallback: true,
callback: (actions) => {
Expand All @@ -1082,7 +1082,7 @@

let allReportMetadata: OnyxCollection<ReportMetadata>;
const allReportMetadataKeyValue: Record<string, ReportMetadata> = {};
Onyx.connect({

Check warning on line 1085 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_METADATA,
waitForCollectionCallback: true,
callback: (value) => {
Expand Down Expand Up @@ -10391,7 +10391,7 @@
}

/**
* Get optimistic data of parent report action
* Get optimistic data of the parent report action
* @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
Expand Down Expand Up @@ -10430,6 +10430,28 @@
};
});
}
/**
* Get optimistic data of the ancestor report actions
* @param ancestors The thread report ancestors
* @param lastVisibleActionCreated Last visible action created of the child report
* @param type The type of action in the child report
*/
function getOptimisticDataForAncestors(ancestors: Ancestor[], lastVisibleActionCreated: string, type: string): OnyxUpdate[] {
let previousActionDeleted = false;
return ancestors.map(({report: ancestorReport, reportAction: ancestorReportAction}, index) => {
const updatedReportAction = updateOptimisticParentReportAction(ancestorReportAction, lastVisibleActionCreated, type, previousActionDeleted ? index + 1 : undefined);

previousActionDeleted = isDeletedAction(ancestorReportAction) && updatedReportAction.childVisibleActionCount === 0;

return {
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${ancestorReport.reportID}`,
value: {
[ancestorReportAction.reportActionID]: updatedReportAction,
},
};
});
}

function canBeAutoReimbursed(report: OnyxInputOrEntry<Report>, policy: OnyxInputOrEntry<Policy> | SearchPolicy): boolean {
if (isEmptyObject(policy)) {
Expand Down Expand Up @@ -12480,6 +12502,7 @@
getMoneyRequestOptions,
getMoneyRequestSpendBreakdown,
getNonHeldAndFullAmount,
getOptimisticDataForAncestors,
getOptimisticDataForParentReportAction,
getOriginalReportID,
getOutstandingChildRequest,
Expand Down
27 changes: 12 additions & 15 deletions src/libs/actions/Report.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ import Pusher from '@libs/Pusher';
import type {UserIsLeavingRoomEvent, UserIsTypingEvent} from '@libs/Pusher/types';
import * as ReportActionsUtils from '@libs/ReportActionsUtils';
import {updateTitleFieldToMatchPolicy} from '@libs/ReportTitleUtils';
import type {OptimisticAddCommentReportAction, OptimisticChatReport, SelfDMParameters} from '@libs/ReportUtils';
import type {Ancestor, OptimisticAddCommentReportAction, OptimisticChatReport, SelfDMParameters} from '@libs/ReportUtils';
import {
buildOptimisticAddCommentReportAction,
buildOptimisticChangeFieldAction,
Expand Down Expand Up @@ -128,6 +128,7 @@ import {
getFieldViolation,
getLastVisibleMessage,
getNextApproverAccountID,
getOptimisticDataForAncestors,
getOptimisticDataForParentReportAction,
getOriginalReportID,
getOutstandingChildRequest,
Expand Down Expand Up @@ -1937,7 +1938,13 @@ function handlePreexistingReport(report: Report) {
}

/** Deletes a comment from the report, basically sets it as empty string */
function deleteReportComment(reportID: string | undefined, reportAction: ReportAction, isReportArchived: boolean | undefined, isOriginalReportArchived: boolean | undefined) {
function deleteReportComment(
reportID: string | undefined,
reportAction: ReportAction,
ancestors: Ancestor[],
isReportArchived: boolean | undefined,
isOriginalReportArchived: boolean | undefined,
) {
const originalReportID = getOriginalReportID(reportID, reportAction);
const reportActionID = reportAction.reportActionID;

Expand Down Expand Up @@ -2032,18 +2039,7 @@ 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(
originalReport,
optimisticReport?.lastVisibleActionCreated ?? '',
CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE,
);
optimisticParentReportData.forEach((parentReportData) => {
if (isEmptyObject(parentReportData)) {
return;
}
optimisticData.push(parentReportData);
});
optimisticData.push(...getOptimisticDataForAncestors(ancestors, optimisticReport?.lastVisibleActionCreated ?? '', CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE));
}

const parameters: DeleteCommentParams = {
Expand Down Expand Up @@ -2120,6 +2116,7 @@ function handleUserDeletedLinksInHtml(newCommentText: string, originalCommentMar
function editReportComment(
originalReport: OnyxEntry<Report>,
originalReportAction: OnyxEntry<ReportAction>,
ancestors: Ancestor[],
textForNewComment: string,
isOriginalReportArchived: boolean | undefined,
isOriginalParentReportArchived: boolean | undefined,
Expand Down Expand Up @@ -2156,7 +2153,7 @@ function editReportComment(

// Delete the comment if it's empty
if (!htmlForNewComment) {
deleteReportComment(originalReportID, originalReportAction, isOriginalReportArchived, isOriginalParentReportArchived);
deleteReportComment(originalReportID, originalReportAction, ancestors, isOriginalReportArchived, isOriginalParentReportArchived);
return;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {Actions, ActionSheetAwareScrollViewContext} from '@components/ActionShee
import ConfirmModal from '@components/ConfirmModal';
import PopoverWithMeasuredContent from '@components/PopoverWithMeasuredContent';
import {useSearchContext} from '@components/Search/SearchContext';
import useAncestors from '@hooks/useAncestors';
import useDeleteTransactions from '@hooks/useDeleteTransactions';
import useDuplicateTransactionsAndViolations from '@hooks/useDuplicateTransactionsAndViolations';
import useGetIOUReportFromReportAction from '@hooks/useGetIOUReportFromReportAction';
Expand Down Expand Up @@ -328,6 +329,17 @@ function PopoverReportActionContextMenu({ref}: PopoverReportActionContextMenuPro
policy,
});

const [originalReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${getOriginalReportID(reportIDRef.current, reportActionRef.current)}`, {
canBeMissing: true,
});
const ancestorsRef = useRef<typeof ancestors>([]);
Copy link
Member

@parasharrajat parasharrajat Dec 14, 2025

Choose a reason for hiding this comment

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

why do we need this ref when we already have ancestors values directly available in the next line?

const ancestors = useAncestors(originalReport);
useEffect(() => {
if (!originalReport) {
return;
}
ancestorsRef.current = ancestors;
}, [originalReport, ancestors]);
const confirmDeleteAndHideModal = useCallback(() => {
callbackWhenDeleteModalHide.current = runAndResetCallback(onConfirmDeleteModal.current);
const reportAction = reportActionRef.current;
Expand Down Expand Up @@ -355,7 +367,7 @@ function PopoverReportActionContextMenu({ref}: PopoverReportActionContextMenuPro
} else if (reportAction) {
// eslint-disable-next-line @typescript-eslint/no-deprecated
InteractionManager.runAfterInteractions(() => {
deleteReportComment(reportIDRef.current, reportAction, isReportArchived, isOriginalReportArchived);
deleteReportComment(reportIDRef.current, reportAction, ancestorsRef.current, isReportArchived, isOriginalReportArchived);
});
}

Expand Down
6 changes: 4 additions & 2 deletions src/pages/home/report/ReportActionItemMessageEdit.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import Icon from '@components/Icon';
import * as Expensicons from '@components/Icon/Expensicons';
import PressableWithFeedback from '@components/Pressable/PressableWithFeedback';
import Tooltip from '@components/Tooltip';
import useAncestors from '@hooks/useAncestors';
import useHandleExceedMaxCommentLength from '@hooks/useHandleExceedMaxCommentLength';
import useIsScrollLikelyLayoutTriggered from '@hooks/useIsScrollLikelyLayoutTriggered';
import useKeyboardState from '@hooks/useKeyboardState';
Expand Down Expand Up @@ -151,6 +152,7 @@ function ReportActionItemMessageEdit({
const isOriginalReportArchived = useReportIsArchived(originalReportID);
const originalParentReportID = getOriginalReportID(originalReportID, action);
const isOriginalParentReportArchived = useReportIsArchived(originalParentReportID);
const ancestors = useAncestors(originalReport);

useEffect(() => {
draftMessageVideoAttributeCache.clear();
Expand Down Expand Up @@ -309,9 +311,9 @@ function ReportActionItemMessageEdit({
ReportActionContextMenu.showDeleteModal(originalReportID ?? reportID, action, true, deleteDraft, () => focusEditAfterCancelDelete(textInputRef.current));
return;
}
editReportComment(originalReport, action, trimmedNewDraft, isOriginalReportArchived, isOriginalParentReportArchived, Object.fromEntries(draftMessageVideoAttributeCache));
editReportComment(originalReport, action, ancestors, trimmedNewDraft, isOriginalReportArchived, isOriginalParentReportArchived, Object.fromEntries(draftMessageVideoAttributeCache));
deleteDraft();
}, [reportID, action, deleteDraft, draft, originalReportID, isOriginalReportArchived, originalReport, isOriginalParentReportArchived, debouncedValidateCommentMaxLength]);
}, [reportID, action, ancestors, deleteDraft, draft, originalReportID, isOriginalReportArchived, originalReport, isOriginalParentReportArchived, debouncedValidateCommentMaxLength]);

/**
* @param emoji
Expand Down
Loading
Loading