From 82f636e86c97c761b41b0c13beeefc42bc73b845 Mon Sep 17 00:00:00 2001 From: allgandalf Date: Fri, 7 Mar 2025 20:27:33 +0530 Subject: [PATCH 01/29] create v1 for DeleteAppReport --- .../API/parameters/DeleteAppReportParams.ts | 5 ++ src/libs/API/parameters/index.ts | 1 + src/libs/API/types.ts | 2 + src/libs/actions/Report.ts | 48 +++++++++++++++++++ src/pages/ReportDetailsPage.tsx | 8 +++- 5 files changed, 62 insertions(+), 2 deletions(-) create mode 100644 src/libs/API/parameters/DeleteAppReportParams.ts diff --git a/src/libs/API/parameters/DeleteAppReportParams.ts b/src/libs/API/parameters/DeleteAppReportParams.ts new file mode 100644 index 000000000000..f4c01ec05935 --- /dev/null +++ b/src/libs/API/parameters/DeleteAppReportParams.ts @@ -0,0 +1,5 @@ +type DeleteAppReportParams = { + reportID: string; +}; + +export default DeleteAppReportParams; diff --git a/src/libs/API/parameters/index.ts b/src/libs/API/parameters/index.ts index 38ee3ee71053..52ffe80642dc 100644 --- a/src/libs/API/parameters/index.ts +++ b/src/libs/API/parameters/index.ts @@ -378,3 +378,4 @@ export type {default as GetCorpayOnboardingFieldsParams} from './GetCorpayOnboar export type {SaveCorpayOnboardingCompanyDetailsParams} from './SaveCorpayOnboardingCompanyDetailsParams'; export type {default as AcceptSpotnanaTermsParams} from './AcceptSpotnanaTermsParams'; export type {default as SaveCorpayOnboardingBeneficialOwnerParams} from './SaveCorpayOnboardingBeneficialOwnerParams'; +export type {default as DeleteAppReportParams} from './DeleteAppReportParams'; diff --git a/src/libs/API/types.ts b/src/libs/API/types.ts index e9aa0ceeab39..7856b736d697 100644 --- a/src/libs/API/types.ts +++ b/src/libs/API/types.ts @@ -460,6 +460,7 @@ const WRITE_COMMANDS = { RESET_SMS_DELIVERY_FAILURE_STATUS: 'ResetSMSDeliveryFailureStatus', SAVE_CORPAY_ONBOARDING_COMPANY_DETAILS: 'SaveCorpayOnboardingCompanyDetails', SAVE_CORPAY_ONBOARDING_BENEFICIAL_OWNER: 'SaveCorpayOnboardingBeneficialOwner', + DELETE_APP_REPORT: 'DeleteAppReport', } as const; type WriteCommand = ValueOf; @@ -931,6 +932,7 @@ type WriteCommandParameters = { [WRITE_COMMANDS.JOIN_ACCESSIBLE_POLICY]: Parameters.JoinAccessiblePolicyParams; // Dismis Product Training [WRITE_COMMANDS.DISMISS_PRODUCT_TRAINING]: Parameters.DismissProductTrainingParams; + [WRITE_COMMANDS.DELETE_APP_REPORT]: Parameters.DeleteAppReportParams; }; const READ_COMMANDS = { diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index ef05799df353..0641cee8834b 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -15,6 +15,7 @@ import type { AddEmojiReactionParams, AddWorkspaceRoomParams, CompleteGuidedSetupParams, + DeleteAppReportParams, DeleteCommentParams, ExpandURLPreviewParams, FlagCommentParams, @@ -4661,6 +4662,52 @@ function clearDeleteTransactionNavigateBackUrl() { Onyx.merge(ONYXKEYS.NVP_DELETE_TRANSACTION_NAVIGATE_BACK_URL, null); } +/** Deletes a report and unreports all transactions on the report along with its reportActions, any linked reports and any linked IOU report actions. */ +function deleteAppReport(reportID: string | undefined) { + if (!reportID) { + Log.warn('[Report] deleteReport called with no reportID'); + return; + } + const report = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]; + const onyxData: Record = { + [`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]: null, + [`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`]: null, + }; + + // Delete linked transactions + const reportActionsForReport = allReportActions?.[reportID]; + + const transactionIDs = Object.values(reportActionsForReport ?? {}) + .filter((reportAction): reportAction is ReportAction => ReportActionsUtils.isMoneyRequestAction(reportAction)) + .map((reportAction) => ReportActionsUtils.getOriginalMessage(reportAction)?.IOUTransactionID); + + [...new Set(transactionIDs)].forEach((transactionID) => { + onyxData[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`] = null; + }); + + Onyx.multiSet(onyxData); + const selfDMReportID = findSelfDMReportID(); + + // Move the report to SelfDm + Object.values(reportActionsForReport ?? {}).forEach((reportAction) => { + if (!reportAction.childReportID) { + return; + } + const childReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${reportAction.childReportID}`]; + }); + + // Delete linked IOU report + if (report?.iouReportID) { + deleteReport(report.iouReportID); + } + + const parameters: DeleteAppReportParams = { + reportID, + }; + + API.write(WRITE_COMMANDS.DELETE_APP_REPORT, parameters); +} + export type {Video}; export { @@ -4754,4 +4801,5 @@ export { updateRoomVisibility, updateWriteCapability, prepareOnboardingOnyxData, + deleteAppReport, }; diff --git a/src/pages/ReportDetailsPage.tsx b/src/pages/ReportDetailsPage.tsx index dd02c1be071f..2b2e55f2f507 100644 --- a/src/pages/ReportDetailsPage.tsx +++ b/src/pages/ReportDetailsPage.tsx @@ -106,6 +106,7 @@ import { clearAvatarErrors, clearPolicyRoomNameErrors, clearReportFieldKeyErrors, + deleteAppReport, exportReportToCSV, getReportPrivateNote, hasErrorInPrivateNotes, @@ -295,7 +296,7 @@ function ReportDetailsPage({policies, report, route, reportMetadata}: ReportDeta const shouldShowTaskDeleteButton = isTaskReport && !isCanceledTaskReport && canWriteInReport(report) && report.stateNum !== CONST.REPORT.STATE_NUM.APPROVED && !isClosedReport(report) && canModifyTask && canActionTask; const canDeleteRequest = isActionOwner && (canDeleteTransaction(moneyRequestReport) || isSelfDMTrackExpenseReport) && !isDeletedParentAction; - const shouldShowDeleteButton = shouldShowTaskDeleteButton || canDeleteRequest; + const shouldShowDeleteButton = true; useEffect(() => { if (canDeleteRequest) { @@ -1014,7 +1015,10 @@ function ReportDetailsPage({policies, report, route, reportMetadata}: ReportDeta key={CONST.REPORT_DETAILS_MENU_ITEM.DELETE} icon={Expensicons.Trashcan} title={caseID === CASES.DEFAULT ? translate('common.delete') : translate('reportActionContextMenu.deleteAction', {action: requestParentReportAction})} - onPress={() => setIsDeleteModalVisible(true)} + onPress={() => { + console.log('report?.reportID::: ', report?.reportID); + deleteAppReport(report?.reportID); + }} /> )} From a67f18ffb7a0736b22075d82893ed469237a9792 Mon Sep 17 00:00:00 2001 From: allgandalf Date: Sat, 22 Mar 2025 18:56:25 +0530 Subject: [PATCH 02/29] build delete report action --- src/libs/actions/Report.ts | 104 ++++++++++++++++++++++++++------ src/pages/ReportDetailsPage.tsx | 2 +- 2 files changed, 86 insertions(+), 20 deletions(-) diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index 2a492c7273e4..c41cd4bf160d 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -4860,47 +4860,113 @@ function deleteAppReport(reportID: string | undefined) { Log.warn('[Report] deleteReport called with no reportID'); return; } + const optimisticData: OnyxUpdate[] = []; const report = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]; - const onyxData: Record = { - [`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]: null, - [`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`]: null, - }; + // const onyxData: Record = { + // [`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]: null, + // [`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`]: null, + // }; // Delete linked transactions const reportActionsForReport = allReportActions?.[reportID]; + let selfDMReportID = findSelfDMReportID(); + if (!selfDMReportID) { + const currentTime = DateUtils.getDBTime(); + const selfDMReport = buildOptimisticSelfDMReport(currentTime); + selfDMReportID = selfDMReport.reportID; + } + // 1. Get all report transactions const transactionIDs = Object.values(reportActionsForReport ?? {}) .filter((reportAction): reportAction is ReportAction => ReportActionsUtils.isMoneyRequestAction(reportAction)) .map((reportAction) => ReportActionsUtils.getOriginalMessage(reportAction)?.IOUTransactionID); + // 2. Set transaction's reportID to 0 [...new Set(transactionIDs)].forEach((transactionID) => { - onyxData[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`] = null; + optimisticData.push({ + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`, + value: {reportID: 0}, + }); }); - Onyx.multiSet(onyxData); - const selfDMReportID = findSelfDMReportID(); + Object.values(reportActionsForReport ?? {}) + .filter((reportAction): reportAction is ReportAction => ReportActionsUtils.isMoneyRequestAction(reportAction)) + .forEach((reportAction) => { + console.log('reportAction', reportAction); + console.log('eachreport of report action:', allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${reportAction.childReportID}`]); + // 3. Move the IOU reportActions to the selfDM + const updatedReportAction = { + ...reportAction, + originalMessage: { + ...reportAction.originalMessage, + IOUReportID: selfDMReportID, + }, + }; + optimisticData.push({ + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${selfDMReportID}`, + value: { + [reportAction.reportActionID]: updatedReportAction, + }, + }); + // 4. Get transaction thread + optimisticData.push({ + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT}${reportAction.childReportID}`, + value: { + parentReportID: selfDMReportID, + policyID: '_FAKE_', + }, + }); - // Move the report to SelfDm - Object.values(reportActionsForReport ?? {}).forEach((reportAction) => { - if (!reportAction.childReportID) { - return; - } - const childReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${reportAction.childReportID}`]; + optimisticData.push({ + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportAction.childReportID}`, + value: { + [reportAction.reportActionID]: { + originalMessage: { + movedToReportID: selfDMReportID, + }, + }, + }, + }); + }); + + // 5. Delete report actions on the report + optimisticData.push({ + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`, + value: null, }); - // Delete linked IOU report - if (report?.iouReportID) { - deleteReport(report.iouReportID); - } + // 6. Delete the report + + optimisticData.push({ + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT}${reportID}`, + value: null, + }); + + // 7. Delete chat report preview + const reportactionID = report?.parentReportActionID ?? ''; + const parentReportID = report?.parentReportID; + + optimisticData.push({ + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${parentReportID}`, + value: { + [reportactionID]: null, + }, + }); const parameters: DeleteAppReportParams = { reportID, }; - API.write(WRITE_COMMANDS.DELETE_APP_REPORT, parameters); + API.write(WRITE_COMMANDS.DELETE_APP_REPORT, parameters, {optimisticData}); } - /** * Dismisses the change report policy educational modal so that it doesn't show up again. */ diff --git a/src/pages/ReportDetailsPage.tsx b/src/pages/ReportDetailsPage.tsx index 46aed7438efc..b13dcb0a25d7 100644 --- a/src/pages/ReportDetailsPage.tsx +++ b/src/pages/ReportDetailsPage.tsx @@ -1056,7 +1056,7 @@ function ReportDetailsPage({policies, report, route, reportMetadata}: ReportDeta /> ))} - {shouldShowDeleteButton && ( + {true && ( Date: Tue, 15 Apr 2025 11:18:58 +0530 Subject: [PATCH 03/29] test: send serialized object --- .../API/parameters/DeleteAppReportParams.ts | 1 + src/libs/actions/Report.ts | 18 ++++++++++++++++++ src/pages/ReportDetailsPage.tsx | 4 +++- 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/libs/API/parameters/DeleteAppReportParams.ts b/src/libs/API/parameters/DeleteAppReportParams.ts index f4c01ec05935..673b0e276422 100644 --- a/src/libs/API/parameters/DeleteAppReportParams.ts +++ b/src/libs/API/parameters/DeleteAppReportParams.ts @@ -1,5 +1,6 @@ type DeleteAppReportParams = { reportID: string; + transactionIDToMoneyRequestReportActionIDMap?: string; }; export default DeleteAppReportParams; diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index 80e0451b9614..64f8fa4d7fca 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -107,9 +107,11 @@ import { buildOptimisticRenamedRoomReportAction, buildOptimisticReportPreview, buildOptimisticRoomDescriptionUpdatedReportAction, + buildOptimisticSelfDMReport, canUserPerformWriteAction as canUserPerformWriteActionReportUtils, completeShortMention, findLastAccessedReport, + findSelfDMReportID, formatReportLastMessageText, generateReportID, getAllPolicyReports, @@ -4586,8 +4588,24 @@ function deleteAppReport(reportID: string | undefined) { }, }); + const transactionIDToMoneyRequestReportActionIDMap: Record = {}; + +Object.values(reportActionsForReport ?? {}) + .filter((reportAction): reportAction is ReportAction => + ReportActionsUtils.isMoneyRequestAction(reportAction) + ) + .forEach((reportAction) => { + const transactionID = ReportActionsUtils.getOriginalMessage(reportAction)?.IOUTransactionID; + if (transactionID) { + transactionIDToMoneyRequestReportActionIDMap[transactionID] = reportAction.reportActionID; + } + + // your existing moving logic... + }); + const parameters: DeleteAppReportParams = { reportID, + transactionIDToMoneyRequestReportActionIDMap: JSON.stringify(transactionIDToMoneyRequestReportActionIDMap), }; API.write(WRITE_COMMANDS.DELETE_APP_REPORT, parameters, {optimisticData}); diff --git a/src/pages/ReportDetailsPage.tsx b/src/pages/ReportDetailsPage.tsx index 38bc92bd58fa..f1eddebb1416 100644 --- a/src/pages/ReportDetailsPage.tsx +++ b/src/pages/ReportDetailsPage.tsx @@ -283,6 +283,8 @@ function ReportDetailsPage({policies, report, route, reportMetadata}: ReportDeta caseID = CASES.DEFAULT; } + console.log('caseID', caseID) + const transactionIDList = useMemo(() => { if (caseID !== CASES.MONEY_REPORT || !transactions) { return []; @@ -1069,7 +1071,7 @@ function ReportDetailsPage({policies, report, route, reportMetadata}: ReportDeta { console.log('report?.reportID::: ', report?.reportID); deleteAppReport(report?.reportID); From 29e383b3bf932d972152b25715d215bd2564599c Mon Sep 17 00:00:00 2001 From: allgandalf Date: Tue, 22 Apr 2025 14:52:59 +0530 Subject: [PATCH 04/29] generate new report actions --- src/libs/actions/Report.ts | 40 ++++++++++++--------------------- src/pages/ReportDetailsPage.tsx | 13 +++++------ 2 files changed, 19 insertions(+), 34 deletions(-) diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index 396df74de41f..bb053da57700 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -4550,13 +4550,7 @@ function deleteAppReport(reportID: string | undefined) { } const optimisticData: OnyxUpdate[] = []; const report = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]; - // const onyxData: Record = { - // [`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]: null, - // [`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`]: null, - // }; - // Delete linked transactions - const reportActionsForReport = allReportActions?.[reportID]; let selfDMReportID = findSelfDMReportID(); if (!selfDMReportID) { @@ -4565,6 +4559,7 @@ function deleteAppReport(reportID: string | undefined) { selfDMReportID = selfDMReport.reportID; } // 1. Get all report transactions + const reportActionsForReport = allReportActions?.[reportID]; const transactionIDs = Object.values(reportActionsForReport ?? {}) .filter((reportAction): reportAction is ReportAction => ReportActionsUtils.isMoneyRequestAction(reportAction)) .map((reportAction) => ReportActionsUtils.getOriginalMessage(reportAction)?.IOUTransactionID); @@ -4578,31 +4573,39 @@ function deleteAppReport(reportID: string | undefined) { }); }); + const transactionIDToMoneyRequestReportActionIDMap: Record = {}; Object.values(reportActionsForReport ?? {}) - .filter((reportAction): reportAction is ReportAction => ReportActionsUtils.isMoneyRequestAction(reportAction)) + .filter((reportAction): reportAction is ReportAction => ReportActionsUtils.isMoneyRequestAction(reportAction)).reverse() .forEach((reportAction) => { - console.log('reportAction', reportAction); - console.log('eachreport of report action:', allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${reportAction.childReportID}`]); // 3. Move the IOU reportActions to the selfDM + const newReportActionID = rand64() const updatedReportAction = { ...reportAction, originalMessage: { ...reportAction.originalMessage, IOUReportID: selfDMReportID, }, + reportactionID: newReportActionID, }; optimisticData.push({ onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${selfDMReportID}`, value: { - [reportAction.reportActionID]: updatedReportAction, + [newReportActionID]: updatedReportAction, }, }); + + const transactionID = ReportActionsUtils.getOriginalMessage(reportAction)?.IOUTransactionID; + if (transactionID) { + transactionIDToMoneyRequestReportActionIDMap[transactionID] = newReportActionID; + } + // 4. Get transaction thread optimisticData.push({ onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT}${reportAction.childReportID}`, value: { + parentReportActionID: newReportActionID, parentReportID: selfDMReportID, policyID: '_FAKE_', }, @@ -4612,7 +4615,7 @@ function deleteAppReport(reportID: string | undefined) { onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportAction.childReportID}`, value: { - [reportAction.reportActionID]: { + [newReportActionID]: { originalMessage: { movedToReportID: selfDMReportID, }, @@ -4648,21 +4651,6 @@ function deleteAppReport(reportID: string | undefined) { }, }); - const transactionIDToMoneyRequestReportActionIDMap: Record = {}; - -Object.values(reportActionsForReport ?? {}) - .filter((reportAction): reportAction is ReportAction => - ReportActionsUtils.isMoneyRequestAction(reportAction) - ) - .forEach((reportAction) => { - const transactionID = ReportActionsUtils.getOriginalMessage(reportAction)?.IOUTransactionID; - if (transactionID) { - transactionIDToMoneyRequestReportActionIDMap[transactionID] = reportAction.reportActionID; - } - - // your existing moving logic... - }); - const parameters: DeleteAppReportParams = { reportID, transactionIDToMoneyRequestReportActionIDMap: JSON.stringify(transactionIDToMoneyRequestReportActionIDMap), diff --git a/src/pages/ReportDetailsPage.tsx b/src/pages/ReportDetailsPage.tsx index 2370dbbf33ea..c0f8728fea01 100644 --- a/src/pages/ReportDetailsPage.tsx +++ b/src/pages/ReportDetailsPage.tsx @@ -283,8 +283,6 @@ function ReportDetailsPage({policies, report, route, reportMetadata}: ReportDeta caseID = CASES.DEFAULT; } - console.log('caseID', caseID) - const transactionIDList = useMemo(() => { if (caseID !== CASES.MONEY_REPORT || !transactions) { return []; @@ -307,6 +305,7 @@ function ReportDetailsPage({policies, report, route, reportMetadata}: ReportDeta const requestParentReportAction = useMemo(() => { // 2. MoneyReport case if (caseID === CASES.MONEY_REPORT) { + console.log('transactionThreadReport?.parentReportActionID', transactionThreadReport?.parentReportActionID) if (!reportActions || !transactionThreadReport?.parentReportActionID) { return undefined; } @@ -317,6 +316,7 @@ function ReportDetailsPage({policies, report, route, reportMetadata}: ReportDeta const isActionOwner = typeof requestParentReportAction?.actorAccountID === 'number' && typeof session?.accountID === 'number' && requestParentReportAction.actorAccountID === session?.accountID; + console.log('requestParentReportAction.actorAccountID', requestParentReportAction?.actorAccountID, 'session?.accountID', session?.accountID) const isDeletedParentAction = isDeletedAction(requestParentReportAction); const moneyRequestReport: OnyxEntry = useMemo(() => { @@ -332,10 +332,10 @@ function ReportDetailsPage({policies, report, route, reportMetadata}: ReportDeta const shouldShowTaskDeleteButton = isTaskReport && !isCanceledTaskReport && canWriteInReport(report) && report.stateNum !== CONST.REPORT.STATE_NUM.APPROVED && !isClosedReport(report) && canModifyTask && canActionTask; const canDeleteRequest = isActionOwner && (canDeleteTransaction(moneyRequestReport) || isSelfDMTrackExpenseReport) && !isDeletedParentAction; + console.log('reportID', report?.reportID,"isActionOwner", isActionOwner, 'canDeleteTransaction', canDeleteTransaction(moneyRequestReport), 'isSelfDMTrackExpenseReport', isSelfDMTrackExpenseReport, 'isDeletedParentAction', isDeletedParentAction); const iouTransactionID = isMoneyRequestAction(requestParentReportAction) ? getOriginalMessage(requestParentReportAction)?.IOUTransactionID : ''; const isCardTransactionCanBeDeleted = canDeleteCardTransactionByLiabilityType(iouTransactionID); const shouldShowDeleteButton = shouldShowTaskDeleteButton || (canDeleteRequest && isCardTransactionCanBeDeleted); - useEffect(() => { if (canDeleteRequest) { return; @@ -1067,15 +1067,12 @@ function ReportDetailsPage({policies, report, route, reportMetadata}: ReportDeta /> ))} - {true && ( + {shouldShowDeleteButton && ( { - console.log('report?.reportID::: ', report?.reportID); - deleteAppReport(report?.reportID); - }} + onPress={() => setIsDeleteModalVisible(true)} /> )} From 9cbf40962b87d0b1463779f5eaa6bd9bf093bee2 Mon Sep 17 00:00:00 2001 From: allgandalf Date: Fri, 2 May 2025 23:20:36 +0530 Subject: [PATCH 05/29] try to make CI green --- src/languages/en.ts | 2 ++ src/languages/es.ts | 2 ++ src/libs/actions/Report.ts | 12 ++++++----- src/pages/ReportDetailsPage.tsx | 35 ++++++++++++++++++++++++++------- 4 files changed, 39 insertions(+), 12 deletions(-) diff --git a/src/languages/en.ts b/src/languages/en.ts index ecd4613af086..48b3b5ba43a3 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -1000,6 +1000,8 @@ const translations = { one: 'Are you sure that you want to delete this expense?', other: 'Are you sure that you want to delete these expenses?', }), + deleteReport: 'Delete report', + deleteReportConfirmation: 'Are you sure that you want to delete this report?', settledExpensify: 'Paid', done: 'Done', settledElsewhere: 'Paid elsewhere', diff --git a/src/languages/es.ts b/src/languages/es.ts index 99f3de0bb14d..948dbeff3a92 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -995,6 +995,8 @@ const translations = { one: '¿Estás seguro de que quieres eliminar esta solicitud?', other: '¿Estás seguro de que quieres eliminar estas solicitudes?', }), + deleteReport: 'Eliminar informe', + deleteReportConfirmation: '¿Estás seguro de que quieres eliminar este informe?', settledExpensify: 'Pagado', done: 'Listo', settledElsewhere: 'Pagado de otra forma', diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index c9499214c256..8db6a573abd9 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -4585,13 +4585,15 @@ function deleteAppReport(reportID: string | undefined) { const transactionIDToMoneyRequestReportActionIDMap: Record = {}; Object.values(reportActionsForReport ?? {}) - .filter((reportAction): reportAction is ReportAction => ReportActionsUtils.isMoneyRequestAction(reportAction)).reverse() + .filter((reportAction): reportAction is ReportAction => ReportActionsUtils.isMoneyRequestAction(reportAction)) + .reverse() .forEach((reportAction) => { // 3. Move the IOU reportActions to the selfDM - const newReportActionID = rand64() + const newReportActionID = rand64(); const updatedReportAction = { ...reportAction, originalMessage: { + // eslint-disable-next-line deprecation/deprecation ...reportAction.originalMessage, IOUReportID: selfDMReportID, }, @@ -4609,7 +4611,7 @@ function deleteAppReport(reportID: string | undefined) { if (transactionID) { transactionIDToMoneyRequestReportActionIDMap[transactionID] = newReportActionID; } - + // 4. Get transaction thread optimisticData.push({ onyxMethod: Onyx.METHOD.MERGE, @@ -4650,14 +4652,14 @@ function deleteAppReport(reportID: string | undefined) { }); // 7. Delete chat report preview - const reportactionID = report?.parentReportActionID ?? ''; + const reportactionID = report?.parentReportActionID; const parentReportID = report?.parentReportID; optimisticData.push({ onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${parentReportID}`, value: { - [reportactionID]: null, + [reportactionID ?? '']: null, }, }); diff --git a/src/pages/ReportDetailsPage.tsx b/src/pages/ReportDetailsPage.tsx index b110eb3dcce4..dc985d12713f 100644 --- a/src/pages/ReportDetailsPage.tsx +++ b/src/pages/ReportDetailsPage.tsx @@ -115,8 +115,6 @@ import { import { clearAvatarErrors, clearPolicyRoomNameErrors, - clearReportFieldKeyErrors, - deleteAppReport, downloadReportPDF, exportReportToCSV, exportReportToPDF, @@ -210,6 +208,7 @@ function ReportDetailsPage({policies, report, route, reportMetadata}: ReportDeta const [isLastMemberLeavingGroupModalVisible, setIsLastMemberLeavingGroupModalVisible] = useState(false); const [isDeleteModalVisible, setIsDeleteModalVisible] = useState(false); + const [isDeleteReportModalVisible, setIsDeleteReportModalVisible] = useState(false); const [isUnapproveModalVisible, setIsUnapproveModalVisible] = useState(false); const [isConfirmModalVisible, setIsConfirmModalVisible] = useState(false); const [isPDFModalVisible, setIsPDFModalVisible] = useState(false); @@ -307,7 +306,6 @@ function ReportDetailsPage({policies, report, route, reportMetadata}: ReportDeta const requestParentReportAction = useMemo(() => { // 2. MoneyReport case if (caseID === CASES.MONEY_REPORT) { - console.log('transactionThreadReport?.parentReportActionID', transactionThreadReport?.parentReportActionID) if (!reportActions || !transactionThreadReport?.parentReportActionID) { return undefined; } @@ -318,7 +316,6 @@ function ReportDetailsPage({policies, report, route, reportMetadata}: ReportDeta const isActionOwner = typeof requestParentReportAction?.actorAccountID === 'number' && typeof session?.accountID === 'number' && requestParentReportAction.actorAccountID === session?.accountID; - console.log('requestParentReportAction.actorAccountID', requestParentReportAction?.actorAccountID, 'session?.accountID', session?.accountID) const isDeletedParentAction = isDeletedAction(requestParentReportAction); const moneyRequestReport: OnyxEntry = useMemo(() => { @@ -334,7 +331,6 @@ function ReportDetailsPage({policies, report, route, reportMetadata}: ReportDeta const shouldShowTaskDeleteButton = isTaskReport && !isCanceledTaskReport && canWriteInReport(report) && report.stateNum !== CONST.REPORT.STATE_NUM.APPROVED && !isClosedReport(report) && canModifyTask && canActionTask; const canDeleteRequest = isActionOwner && (canDeleteTransaction(moneyRequestReport) || isSelfDMTrackExpenseReport) && !isDeletedParentAction; - console.log('reportID', report?.reportID,"isActionOwner", isActionOwner, 'canDeleteTransaction', canDeleteTransaction(moneyRequestReport), 'isSelfDMTrackExpenseReport', isSelfDMTrackExpenseReport, 'isDeletedParentAction', isDeletedParentAction); const iouTransactionID = isMoneyRequestAction(requestParentReportAction) ? getOriginalMessage(requestParentReportAction)?.IOUTransactionID : ''; const isCardTransactionCanBeDeleted = canDeleteCardTransactionByLiabilityType(iouTransactionID); const shouldShowDeleteButton = shouldShowTaskDeleteButton || (canDeleteRequest && isCardTransactionCanBeDeleted); @@ -1073,8 +1069,18 @@ function ReportDetailsPage({policies, report, route, reportMetadata}: ReportDeta setIsDeleteModalVisible(true)} + title={ + caseID === CASES.DEFAULT || caseID === CASES.MONEY_REPORT + ? translate('common.delete') + : translate('reportActionContextMenu.deleteAction', {action: requestParentReportAction}) + } + onPress={() => { + if (caseID === CASES.MONEY_REPORT) { + setIsDeleteReportModalVisible(true); + } else { + setIsDeleteModalVisible(true); + } + }} /> )} @@ -1134,6 +1140,21 @@ function ReportDetailsPage({policies, report, route, reportMetadata}: ReportDeta shouldEnableNewFocusManagement onModalHide={navigateToTargetUrl} /> + { + setIsDeleteReportModalVisible(false); + isTransactionDeleted.current = true; + }} + onCancel={() => setIsDeleteReportModalVisible(false)} + prompt={translate('iou.deleteReportConfirmation')} + confirmText={translate('common.delete')} + cancelText={translate('common.cancel')} + danger + shouldEnableNewFocusManagement + onModalHide={navigateToTargetUrl} + /> setIsNoDelegateAccessMenuVisible(false)} From 5d12b7f1dc19d3bc30e9e67cd7eae46e45a9f456 Mon Sep 17 00:00:00 2001 From: allgandalf Date: Sat, 3 May 2025 00:52:45 +0530 Subject: [PATCH 06/29] make CI green --- src/libs/actions/Report.ts | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index 8db6a573abd9..814eeb62b0d8 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -4655,13 +4655,15 @@ function deleteAppReport(reportID: string | undefined) { const reportactionID = report?.parentReportActionID; const parentReportID = report?.parentReportID; - optimisticData.push({ - onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${parentReportID}`, - value: { - [reportactionID ?? '']: null, - }, - }); + if (reportactionID) { + optimisticData.push({ + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${parentReportID}`, + value: { + [reportactionID]: null, + }, + }); + } const parameters: DeleteAppReportParams = { reportID, From 35e06c5915e75ccc0cdf943f9f6371025e9f8917 Mon Sep 17 00:00:00 2001 From: allgandalf Date: Wed, 7 May 2025 16:09:15 +0530 Subject: [PATCH 07/29] address few comments --- src/libs/actions/Report.ts | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index 33bd6fa6409e..68dbb85eaefc 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -4575,9 +4575,12 @@ function deleteAppReport(reportID: string | undefined) { } // 1. Get all report transactions const reportActionsForReport = allReportActions?.[reportID]; - const transactionIDs = Object.values(reportActionsForReport ?? {}) - .filter((reportAction): reportAction is ReportAction => ReportActionsUtils.isMoneyRequestAction(reportAction)) - .map((reportAction) => ReportActionsUtils.getOriginalMessage(reportAction)?.IOUTransactionID); + const transactionIDs = []; + for (const reportAction of Object.values(reportActionsForReport ?? {})) { + if (ReportActionsUtils.isMoneyRequestAction(reportAction)) { + transactionIDs.push(ReportActionsUtils.getOriginalMessage(reportAction)?.IOUTransactionID); + } + } // 2. Set transaction's reportID to 0 [...new Set(transactionIDs)].forEach((transactionID) => { @@ -4586,6 +4589,11 @@ function deleteAppReport(reportID: string | undefined) { key: `${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`, value: {reportID: 0}, }); + optimisticData.push({ + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transactionID}`, + value: null, + }); }); const transactionIDToMoneyRequestReportActionIDMap: Record = {}; From bc904c7675dd5eef583becbeaea5ab2280b5322c Mon Sep 17 00:00:00 2001 From: allgandalf Date: Wed, 7 May 2025 16:34:33 +0530 Subject: [PATCH 08/29] fix: condition to show delete report --- src/libs/ReportSecondaryActionUtils.ts | 13 +++++-------- src/libs/actions/Report.ts | 4 ++++ src/pages/ReportDetailsPage.tsx | 4 +++- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/libs/ReportSecondaryActionUtils.ts b/src/libs/ReportSecondaryActionUtils.ts index 7e614608a083..d82ef1d66b35 100644 --- a/src/libs/ReportSecondaryActionUtils.ts +++ b/src/libs/ReportSecondaryActionUtils.ts @@ -375,14 +375,11 @@ function isChangeWorkspaceAction(report: Report, reportTransactions: Transaction return false; } -function isDeleteAction(report: Report, reportTransactions: Transaction[]): boolean { +function isDeleteAction(report: Report): boolean { const isExpenseReport = isExpenseReportUtils(report); const isIOUReport = isIOUReportUtils(report); - // This should be removed when is merged https://github.com/Expensify/App/pull/58020 - const isSingleTransaction = reportTransactions.length === 1; - - if ((!isExpenseReport && !isIOUReport) || !isSingleTransaction) { + if (!isExpenseReport && !isIOUReport) { return false; } @@ -451,7 +448,7 @@ function getSecondaryReportActions( options.push(CONST.REPORT.SECONDARY_ACTIONS.VIEW_DETAILS); - if (isDeleteAction(report, reportTransactions)) { + if (isDeleteAction(report)) { options.push(CONST.REPORT.SECONDARY_ACTIONS.DELETE); } @@ -467,10 +464,10 @@ function getSecondaryTransactionThreadActions(parentReport: Report, reportTransa options.push(CONST.REPORT.TRANSACTION_SECONDARY_ACTIONS.VIEW_DETAILS); - if (isDeleteAction(parentReport, [reportTransaction])) { + if (isDeleteAction(parentReport)) { options.push(CONST.REPORT.TRANSACTION_SECONDARY_ACTIONS.DELETE); } return options; } -export {getSecondaryReportActions, getSecondaryTransactionThreadActions}; +export {getSecondaryReportActions, getSecondaryTransactionThreadActions, isDeleteAction}; diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index 68dbb85eaefc..fabe3a4d6dfc 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -4597,6 +4597,7 @@ function deleteAppReport(reportID: string | undefined) { }); const transactionIDToMoneyRequestReportActionIDMap: Record = {}; + Object.values(reportActionsForReport ?? {}) .filter((reportAction): reportAction is ReportAction => ReportActionsUtils.isMoneyRequestAction(reportAction)) .reverse() @@ -4610,6 +4611,7 @@ function deleteAppReport(reportID: string | undefined) { ...reportAction.originalMessage, IOUReportID: selfDMReportID, }, + childReportID: reportAction.childReportID, reportactionID: newReportActionID, }; optimisticData.push({ @@ -4632,6 +4634,7 @@ function deleteAppReport(reportID: string | undefined) { value: { parentReportActionID: newReportActionID, parentReportID: selfDMReportID, + chatReportID: selfDMReportID, policyID: '_FAKE_', }, }); @@ -4677,6 +4680,7 @@ function deleteAppReport(reportID: string | undefined) { }, }); } + console.log('optimisticData', optimisticData) const parameters: DeleteAppReportParams = { reportID, diff --git a/src/pages/ReportDetailsPage.tsx b/src/pages/ReportDetailsPage.tsx index f24b09971ef3..e638493088c3 100644 --- a/src/pages/ReportDetailsPage.tsx +++ b/src/pages/ReportDetailsPage.tsx @@ -103,6 +103,7 @@ import { shouldUseFullTitleToDisplay, } from '@libs/ReportUtils'; import StringUtils from '@libs/StringUtils'; +import {isDeleteAction} from '@libs/ReportSecondaryActionUtils'; import { canCancelPayment, cancelPayment as cancelPaymentAction, @@ -333,7 +334,8 @@ function ReportDetailsPage({policies, report, route, reportMetadata}: ReportDeta const canDeleteRequest = isActionOwner && (canDeleteTransaction(moneyRequestReport) || isSelfDMTrackExpenseReport) && !isDeletedParentAction; const iouTransactionID = isMoneyRequestAction(requestParentReportAction) ? getOriginalMessage(requestParentReportAction)?.IOUTransactionID : ''; const isCardTransactionCanBeDeleted = canDeleteCardTransactionByLiabilityType(iouTransactionID); - const shouldShowDeleteButton = shouldShowTaskDeleteButton || (canDeleteRequest && isCardTransactionCanBeDeleted); + const canDeleteReport = isDeleteAction(report) + const shouldShowDeleteButton = shouldShowTaskDeleteButton || ((canDeleteRequest || canDeleteReport) && isCardTransactionCanBeDeleted); useEffect(() => { if (canDeleteRequest) { return; From 81060896e547ebf77b4a65a934d24b04a623f548 Mon Sep 17 00:00:00 2001 From: allgandalf Date: Wed, 7 May 2025 16:38:45 +0530 Subject: [PATCH 09/29] Fix prettier --- src/libs/actions/Report.ts | 1 - src/pages/ReportDetailsPage.tsx | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index fabe3a4d6dfc..99ecc7c47e7d 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -4680,7 +4680,6 @@ function deleteAppReport(reportID: string | undefined) { }, }); } - console.log('optimisticData', optimisticData) const parameters: DeleteAppReportParams = { reportID, diff --git a/src/pages/ReportDetailsPage.tsx b/src/pages/ReportDetailsPage.tsx index e638493088c3..001f511b1a6c 100644 --- a/src/pages/ReportDetailsPage.tsx +++ b/src/pages/ReportDetailsPage.tsx @@ -48,6 +48,7 @@ import {getPersonalDetailsForAccountIDs} from '@libs/OptionsListUtils'; import Parser from '@libs/Parser'; import {getConnectedIntegration, isPolicyAdmin as isPolicyAdminUtil, isPolicyEmployee as isPolicyEmployeeUtil, shouldShowPolicy} from '@libs/PolicyUtils'; import {getOneTransactionThreadReportID, getOriginalMessage, getTrackExpenseActionableWhisper, isDeletedAction, isMoneyRequestAction, isTrackExpenseAction} from '@libs/ReportActionsUtils'; +import {isDeleteAction} from '@libs/ReportSecondaryActionUtils'; import { canDeleteCardTransactionByLiabilityType, canDeleteTransaction, @@ -103,7 +104,6 @@ import { shouldUseFullTitleToDisplay, } from '@libs/ReportUtils'; import StringUtils from '@libs/StringUtils'; -import {isDeleteAction} from '@libs/ReportSecondaryActionUtils'; import { canCancelPayment, cancelPayment as cancelPaymentAction, @@ -334,7 +334,7 @@ function ReportDetailsPage({policies, report, route, reportMetadata}: ReportDeta const canDeleteRequest = isActionOwner && (canDeleteTransaction(moneyRequestReport) || isSelfDMTrackExpenseReport) && !isDeletedParentAction; const iouTransactionID = isMoneyRequestAction(requestParentReportAction) ? getOriginalMessage(requestParentReportAction)?.IOUTransactionID : ''; const isCardTransactionCanBeDeleted = canDeleteCardTransactionByLiabilityType(iouTransactionID); - const canDeleteReport = isDeleteAction(report) + const canDeleteReport = isDeleteAction(report); const shouldShowDeleteButton = shouldShowTaskDeleteButton || ((canDeleteRequest || canDeleteReport) && isCardTransactionCanBeDeleted); useEffect(() => { if (canDeleteRequest) { From 527ba701097006af7a1a8cf7c29e16cff2ee622d Mon Sep 17 00:00:00 2001 From: allgandalf Date: Wed, 7 May 2025 20:04:51 +0530 Subject: [PATCH 10/29] fix navigating back to selfDM --- src/libs/actions/Report.ts | 11 +++++++---- src/pages/ReportDetailsPage.tsx | 3 ++- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index 99ecc7c47e7d..041768d679c2 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -4609,10 +4609,12 @@ function deleteAppReport(reportID: string | undefined) { originalMessage: { // eslint-disable-next-line deprecation/deprecation ...reportAction.originalMessage, - IOUReportID: selfDMReportID, + IOUReportID: 0, + type: CONST.IOU.TYPE.TRACK, + }, childReportID: reportAction.childReportID, - reportactionID: newReportActionID, + reportActionID: newReportActionID, }; optimisticData.push({ onyxMethod: Onyx.METHOD.MERGE, @@ -4626,7 +4628,7 @@ function deleteAppReport(reportID: string | undefined) { if (transactionID) { transactionIDToMoneyRequestReportActionIDMap[transactionID] = newReportActionID; } - + // 4. Get transaction thread optimisticData.push({ onyxMethod: Onyx.METHOD.MERGE, @@ -4660,7 +4662,6 @@ function deleteAppReport(reportID: string | undefined) { }); // 6. Delete the report - optimisticData.push({ onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT}${reportID}`, @@ -4681,6 +4682,8 @@ function deleteAppReport(reportID: string | undefined) { }); } + console.log("reportactions", optimisticData) + const parameters: DeleteAppReportParams = { reportID, transactionIDToMoneyRequestReportActionIDMap: JSON.stringify(transactionIDToMoneyRequestReportActionIDMap), diff --git a/src/pages/ReportDetailsPage.tsx b/src/pages/ReportDetailsPage.tsx index 001f511b1a6c..6998ecdadb48 100644 --- a/src/pages/ReportDetailsPage.tsx +++ b/src/pages/ReportDetailsPage.tsx @@ -117,6 +117,7 @@ import { import { clearAvatarErrors, clearPolicyRoomNameErrors, + deleteAppReport, downloadReportPDF, exportReportToCSV, exportReportToPDF, @@ -1148,7 +1149,7 @@ function ReportDetailsPage({policies, report, route, reportMetadata}: ReportDeta isVisible={isDeleteReportModalVisible} onConfirm={() => { setIsDeleteReportModalVisible(false); - isTransactionDeleted.current = true; + deleteAppReport(report.reportID); }} onCancel={() => setIsDeleteReportModalVisible(false)} prompt={translate('iou.deleteReportConfirmation')} From 1ec0bfc9e9337032ec8fc3956e270e954493c66e Mon Sep 17 00:00:00 2001 From: allgandalf Date: Wed, 7 May 2025 21:29:09 +0530 Subject: [PATCH 11/29] fix prettier --- src/libs/actions/Report.ts | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index 041768d679c2..12d3d520e16b 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -109,6 +109,7 @@ import { buildOptimisticReportPreview, buildOptimisticRoomDescriptionUpdatedReportAction, buildOptimisticSelfDMReport, + buildOptimisticUnreportedTransactionAction, canUserPerformWriteAction as canUserPerformWriteActionReportUtils, completeShortMention, findLastAccessedReport, @@ -4564,6 +4565,8 @@ function deleteAppReport(reportID: string | undefined) { return; } const optimisticData: OnyxUpdate[] = []; + const failureData: OnyxUpdate[] = []; + const successData: OnyxUpdate[] = []; const report = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]; let selfDMReportID = findSelfDMReportID(); @@ -4611,7 +4614,6 @@ function deleteAppReport(reportID: string | undefined) { ...reportAction.originalMessage, IOUReportID: 0, type: CONST.IOU.TYPE.TRACK, - }, childReportID: reportAction.childReportID, reportActionID: newReportActionID, @@ -4628,7 +4630,7 @@ function deleteAppReport(reportID: string | undefined) { if (transactionID) { transactionIDToMoneyRequestReportActionIDMap[transactionID] = newReportActionID; } - + // 4. Get transaction thread optimisticData.push({ onyxMethod: Onyx.METHOD.MERGE, @@ -4652,23 +4654,34 @@ function deleteAppReport(reportID: string | undefined) { }, }, }); + + // 5. Add UNREPORTEDTRANSACTION report actions + const unreportedActions = buildOptimisticUnreportedTransactionAction(reportAction.childReportID, '0'); + + optimisticData.push({ + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportAction.childReportID}`, + value: { + [unreportedActions.reportActionID]: unreportedActions, + }, + }); }); - // 5. Delete report actions on the report + // 6. Delete report actions on the report optimisticData.push({ onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`, value: null, }); - // 6. Delete the report + // 7. Delete the report optimisticData.push({ onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT}${reportID}`, value: null, }); - // 7. Delete chat report preview + // 8. Delete chat report preview const reportactionID = report?.parentReportActionID; const parentReportID = report?.parentReportID; @@ -4682,8 +4695,6 @@ function deleteAppReport(reportID: string | undefined) { }); } - console.log("reportactions", optimisticData) - const parameters: DeleteAppReportParams = { reportID, transactionIDToMoneyRequestReportActionIDMap: JSON.stringify(transactionIDToMoneyRequestReportActionIDMap), From ae72bf6a265e08db6ad971eb8d281c1f76474bae Mon Sep 17 00:00:00 2001 From: allgandalf Date: Wed, 7 May 2025 23:01:18 +0530 Subject: [PATCH 12/29] polish: Add pending action --- src/libs/API/parameters/DeleteAppReportParams.ts | 1 + src/libs/actions/Report.ts | 7 +++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/libs/API/parameters/DeleteAppReportParams.ts b/src/libs/API/parameters/DeleteAppReportParams.ts index 673b0e276422..b4e2bb944e03 100644 --- a/src/libs/API/parameters/DeleteAppReportParams.ts +++ b/src/libs/API/parameters/DeleteAppReportParams.ts @@ -1,6 +1,7 @@ type DeleteAppReportParams = { reportID: string; transactionIDToMoneyRequestReportActionIDMap?: string; + selfDMReportID: string; }; export default DeleteAppReportParams; diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index 12d3d520e16b..11f4468ac746 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -4617,12 +4617,14 @@ function deleteAppReport(reportID: string | undefined) { }, childReportID: reportAction.childReportID, reportActionID: newReportActionID, + pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD }; optimisticData.push({ onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${selfDMReportID}`, value: { [newReportActionID]: updatedReportAction, + }, }); @@ -4656,13 +4658,13 @@ function deleteAppReport(reportID: string | undefined) { }); // 5. Add UNREPORTEDTRANSACTION report actions - const unreportedActions = buildOptimisticUnreportedTransactionAction(reportAction.childReportID, '0'); + const unreportedAction = buildOptimisticUnreportedTransactionAction(reportAction.childReportID, reportID); optimisticData.push({ onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportAction.childReportID}`, value: { - [unreportedActions.reportActionID]: unreportedActions, + [unreportedAction.reportActionID]: unreportedAction, }, }); }); @@ -4698,6 +4700,7 @@ function deleteAppReport(reportID: string | undefined) { const parameters: DeleteAppReportParams = { reportID, transactionIDToMoneyRequestReportActionIDMap: JSON.stringify(transactionIDToMoneyRequestReportActionIDMap), + selfDMReportID, }; API.write(WRITE_COMMANDS.DELETE_APP_REPORT, parameters, {optimisticData}); From 9f416a2dfd1a777064da8bd3c768f0d2440d5cec Mon Sep 17 00:00:00 2001 From: Gandalf Date: Wed, 7 May 2025 23:51:02 +0530 Subject: [PATCH 13/29] Update src/pages/ReportDetailsPage.tsx --- src/pages/ReportDetailsPage.tsx | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/pages/ReportDetailsPage.tsx b/src/pages/ReportDetailsPage.tsx index 6998ecdadb48..20e84cf9c898 100644 --- a/src/pages/ReportDetailsPage.tsx +++ b/src/pages/ReportDetailsPage.tsx @@ -1159,10 +1159,6 @@ function ReportDetailsPage({policies, report, route, reportMetadata}: ReportDeta shouldEnableNewFocusManagement onModalHide={navigateToTargetUrl} /> - setIsNoDelegateAccessMenuVisible(false)} - /> {!canUseTableReportView && ( Date: Wed, 7 May 2025 23:54:33 +0530 Subject: [PATCH 14/29] fix failing tests --- src/libs/actions/Report.ts | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index 11f4468ac746..b91773eac357 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -67,7 +67,6 @@ import * as Environment from '@libs/Environment/Environment'; import {getOldDotURLFromEnvironment} from '@libs/Environment/Environment'; import getEnvironment from '@libs/Environment/getEnvironment'; import type EnvironmentType from '@libs/Environment/getEnvironment/types'; -import * as ErrorUtils from '@libs/ErrorUtils'; import {getMicroSecondOnyxErrorWithTranslationKey} from '@libs/ErrorUtils'; import fileDownload from '@libs/fileDownload'; import getIsNarrowLayout from '@libs/getIsNarrowLayout'; @@ -745,7 +744,7 @@ function addActions(reportID: string, text = '', file?: FileObject) { failureReportActions[actionKey] = { // eslint-disable-next-line @typescript-eslint/non-nullable-type-assertion-style ...(action as OptimisticAddCommentReportAction), - errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('report.genericAddCommentFailureMessage'), + errors: getMicroSecondOnyxErrorWithTranslationKey('report.genericAddCommentFailureMessage'), }; }); @@ -2232,7 +2231,7 @@ function updateReportName(reportID: string, value: string, previousValue: string reportName: null, }, errorFields: { - reportName: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('report.genericUpdateReporNameEditFailureMessage'), + reportName: getMicroSecondOnyxErrorWithTranslationKey('report.genericUpdateReporNameEditFailureMessage'), }, }, }, @@ -2336,7 +2335,7 @@ function updateReportField(reportID: string, reportField: PolicyReportField, pre [fieldKey]: null, }, errorFields: { - [fieldKey]: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('report.genericUpdateReportFieldFailureMessage'), + [fieldKey]: getMicroSecondOnyxErrorWithTranslationKey('report.genericUpdateReportFieldFailureMessage'), }, }, }, @@ -2345,7 +2344,7 @@ function updateReportField(reportID: string, reportField: PolicyReportField, pre key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`, value: { [optimisticChangeFieldAction.reportActionID]: { - errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('report.genericUpdateReportFieldFailureMessage'), + errors: getMicroSecondOnyxErrorWithTranslationKey('report.genericUpdateReportFieldFailureMessage'), }, }, }, @@ -2424,7 +2423,7 @@ function deleteReportField(reportID: string, reportField: PolicyReportField) { [fieldKey]: null, }, errorFields: { - [fieldKey]: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('report.genericUpdateReportFieldFailureMessage'), + [fieldKey]: getMicroSecondOnyxErrorWithTranslationKey('report.genericUpdateReportFieldFailureMessage'), }, }, }, @@ -2822,7 +2821,7 @@ function addPolicyReport(policyReport: OptimisticChatReport) { key: `${ONYXKEYS.COLLECTION.REPORT}${policyReport.reportID}`, value: { errorFields: { - addWorkspaceRoom: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('report.genericCreateReportFailureMessage'), + addWorkspaceRoom: getMicroSecondOnyxErrorWithTranslationKey('report.genericCreateReportFailureMessage'), }, }, }, @@ -3646,7 +3645,7 @@ function buildInviteToRoomOnyxData(reportID: string, inviteeEmailsToAccountIDs: } return { ...pendingChatMember, - errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('roomMembersPage.error.genericAdd'), + errors: getMicroSecondOnyxErrorWithTranslationKey('roomMembersPage.error.genericAdd'), }; }) ?? null, }, @@ -3955,7 +3954,7 @@ const updatePrivateNotes = (reportID: string, accountID: number, note: string) = value: { privateNotes: { [accountID]: { - errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('privateNotes.error.genericFailureMessage'), + errors: getMicroSecondOnyxErrorWithTranslationKey('privateNotes.error.genericFailureMessage'), }, }, }, @@ -4428,7 +4427,7 @@ function exportToIntegration(reportID: string, connectionName: ConnectionName) { key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`, value: { [optimisticReportActionID]: { - errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('common.genericErrorMessage'), + errors: getMicroSecondOnyxErrorWithTranslationKey('common.genericErrorMessage'), }, }, }, @@ -4479,7 +4478,7 @@ function markAsManuallyExported(reportID: string, connectionName: ConnectionName key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`, value: { [optimisticReportActionID]: { - errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('common.genericErrorMessage'), + errors: getMicroSecondOnyxErrorWithTranslationKey('common.genericErrorMessage'), }, }, }, @@ -4565,8 +4564,6 @@ function deleteAppReport(reportID: string | undefined) { return; } const optimisticData: OnyxUpdate[] = []; - const failureData: OnyxUpdate[] = []; - const successData: OnyxUpdate[] = []; const report = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]; let selfDMReportID = findSelfDMReportID(); @@ -4617,14 +4614,13 @@ function deleteAppReport(reportID: string | undefined) { }, childReportID: reportAction.childReportID, reportActionID: newReportActionID, - pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD + pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, }; optimisticData.push({ onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${selfDMReportID}`, value: { [newReportActionID]: updatedReportAction, - }, }); @@ -4943,7 +4939,7 @@ function moveIOUReportToPolicyAndInviteSubmitter(reportID: string, policyID: str const failureMembersState: OnyxCollectionInputValue = { [submitterLogin]: { - errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('workspace.people.error.genericAdd'), + errors: getMicroSecondOnyxErrorWithTranslationKey('workspace.people.error.genericAdd'), }, }; From 78e96c394f207841dbdd5b335f03b15d758c196b Mon Sep 17 00:00:00 2001 From: allgandalf Date: Thu, 8 May 2025 00:12:43 +0530 Subject: [PATCH 15/29] fix failing tests --- src/libs/actions/Report.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index b91773eac357..0b20d1c3dd94 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -5456,7 +5456,7 @@ export { updateReportName, updateRoomVisibility, updateWriteCapability, - prepareOnboardingOnyxData, + deleteAppReport, getOptimisticChatReport, saveReportDraft, From bf654711cff2165d37046ee6ea040e0bddd5b1cd Mon Sep 17 00:00:00 2001 From: allgandalf Date: Thu, 8 May 2025 00:14:50 +0530 Subject: [PATCH 16/29] Fix prettier --- src/libs/actions/Report.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index 0b20d1c3dd94..d7d05ae0172c 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -5456,7 +5456,6 @@ export { updateReportName, updateRoomVisibility, updateWriteCapability, - deleteAppReport, getOptimisticChatReport, saveReportDraft, From 6121e5cd8080a12f47e188bf4bf1a4bafbcc85a9 Mon Sep 17 00:00:00 2001 From: allgandalf Date: Tue, 20 May 2025 19:43:55 +0530 Subject: [PATCH 17/29] update the unreportedTransaction message --- src/languages/en.ts | 3 +-- src/languages/es.ts | 3 +-- src/languages/params.ts | 6 ------ src/libs/ReportSecondaryActionUtils.ts | 9 +++------ src/libs/ReportUtils.ts | 2 +- src/libs/actions/Report.ts | 2 +- 6 files changed, 7 insertions(+), 18 deletions(-) diff --git a/src/languages/en.ts b/src/languages/en.ts index 19e88f26af72..2db3e0f498f2 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -187,7 +187,6 @@ import type { TrialStartedTitleParams, UnapprovedParams, UnapproveWithIntegrationWarningParams, - UnreportedTransactionParams, UnshareParams, UntilTimeParams, UpdatedCustomFieldParams, @@ -952,7 +951,7 @@ const translations = { deleteReceipt: 'Delete receipt', deletedTransaction: ({amount, merchant}: DeleteTransactionParams) => `deleted an expense on this report, ${merchant} - ${amount}`, movedTransaction: ({reportUrl, reportName}: MovedTransactionParams) => `moved this expense to ${reportName}`, - unreportedTransaction: ({reportUrl, reportName}: UnreportedTransactionParams) => `removed this expense from ${reportName}`, + unreportedTransaction: 'moved this expense to your personal space', pendingMatchWithCreditCard: 'Receipt pending match with card transaction', pendingMatch: 'Pending match', pendingMatchWithCreditCardDescription: 'Receipt pending match with card transaction. Mark as cash to cancel.', diff --git a/src/languages/es.ts b/src/languages/es.ts index d1c7f6af5527..6f5b7a7dcd41 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -186,7 +186,6 @@ import type { TrialStartedTitleParams, UnapprovedParams, UnapproveWithIntegrationWarningParams, - UnreportedTransactionParams, UnshareParams, UntilTimeParams, UpdatedCustomFieldParams, @@ -952,7 +951,7 @@ const translations = { routePending: 'Ruta pendiente...', deletedTransaction: ({amount, merchant}: DeleteTransactionParams) => `eliminó un gasto de este informe, ${merchant} - ${amount}`, movedTransaction: ({reportUrl, reportName}: MovedTransactionParams) => `movió este gasto a ${reportName}`, - unreportedTransaction: ({reportUrl, reportName}: UnreportedTransactionParams) => `eliminó este gasto de ${reportName}`, + unreportedTransaction: 'movió este gasto a tu espacio personal', receiptIssuesFound: () => ({ one: 'Problema encontrado', other: 'Problemas encontrados', diff --git a/src/languages/params.ts b/src/languages/params.ts index 8349a2d136ca..2b06d056ecfd 100644 --- a/src/languages/params.ts +++ b/src/languages/params.ts @@ -129,11 +129,6 @@ type MovedTransactionParams = { reportName?: string; }; -type UnreportedTransactionParams = { - reportUrl: string; - reportName?: string; -}; - type SettleExpensifyCardParams = { formattedAmount: string; }; @@ -827,7 +822,6 @@ export type { RequestCountParams, DeleteTransactionParams, MovedTransactionParams, - UnreportedTransactionParams, RequestedAmountMessageParams, ResolutionConstraintsParams, RoomNameReservedErrorParams, diff --git a/src/libs/ReportSecondaryActionUtils.ts b/src/libs/ReportSecondaryActionUtils.ts index 21c4ed6d8329..f133979b0f11 100644 --- a/src/libs/ReportSecondaryActionUtils.ts +++ b/src/libs/ReportSecondaryActionUtils.ts @@ -338,15 +338,12 @@ function isMoveTransactionAction(reportTransactions: Transaction[], reportAction return canMoveExpense; } -function isDeleteAction(report: Report, reportTransactions: Transaction[], reportActions?: ReportAction[]): boolean { +function isDeleteAction(report: Report, reportActions?: ReportAction[]): boolean { const transactionThreadReportID = getOneTransactionThreadReportID(report.reportID, reportActions ?? []); const isExpenseReport = isExpenseReportUtils(report); const isIOUReport = isIOUReportUtils(report); - // This should be removed when is merged https://github.com/Expensify/App/pull/58020 - const isSingleTransaction = reportTransactions.length === 1; - - if ((!isExpenseReport && !isIOUReport) || !isSingleTransaction || (!!reportActions && !transactionThreadReportID)) { + if ((!isExpenseReport && !isIOUReport) || (!!reportActions && !transactionThreadReportID)) { return false; } @@ -448,7 +445,7 @@ function getSecondaryReportActions( options.push(CONST.REPORT.SECONDARY_ACTIONS.VIEW_DETAILS); - if (isDeleteAction(report, reportTransactions, reportActions)) { + if (isDeleteAction(report, reportActions)) { options.push(CONST.REPORT.SECONDARY_ACTIONS.DELETE); } diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index d315b6fa71e1..92be9d7f2d43 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -6191,7 +6191,7 @@ function buildOptimisticTransactionAction( const [actionText, messageHtml] = type === CONST.REPORT.ACTIONS.TYPE.MOVED_TRANSACTION ? [`moved this expense to ${reportName}`, `moved this expense to ${reportName}`] - : [`removed this expense from ${reportName}`, `removed this expense from ${reportName}`]; + : [`moved this expense to your personal space`, `moved this expense to your personal space`]; return { actionName: type, diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index 64905837791e..21230f6f0527 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -2245,7 +2245,7 @@ function updateReportName(reportID: string, value: string, previousValue: string reportName: null, }, errorFields: { - reportName: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('report.genericUpdateReportNameEditFailureMessage'), + reportName: getMicroSecondOnyxErrorWithTranslationKey('report.genericUpdateReportNameEditFailureMessage'), }, }, }, From c38491af443ff703e823c8b30ff398246d207490 Mon Sep 17 00:00:00 2001 From: allgandalf Date: Tue, 20 May 2025 19:53:40 +0530 Subject: [PATCH 18/29] use unreportedTransaction message in pureReportActions --- src/libs/ReportUtils.ts | 12 ------------ src/pages/home/report/PureReportActionItem.tsx | 7 +------ 2 files changed, 1 insertion(+), 18 deletions(-) diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 92be9d7f2d43..40824539236b 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -5807,17 +5807,6 @@ function getMovedTransactionMessage(action: ReportAction) { return message; } -function getUnreportedTransactionMessage(action: ReportAction) { - const unreportedTransactionOriginalMessage = getOriginalMessage(action as ReportAction) ?? {}; - const {fromReportID} = unreportedTransactionOriginalMessage as OriginalMessageUnreportedTransaction; - const {reportName, reportUrl} = getReportDetails(fromReportID); - const message = translateLocal('iou.unreportedTransaction', { - reportUrl, - reportName, - }); - return message; -} - function getPolicyChangeMessage(action: ReportAction) { const PolicyChangeOriginalMessage = getOriginalMessage(action as ReportAction) ?? {}; const {fromPolicy: fromPolicyID, toPolicy: toPolicyID} = PolicyChangeOriginalMessage as OriginalMessageChangePolicy; @@ -11119,7 +11108,6 @@ export { getReportSubtitlePrefix, getPolicyChangeMessage, getMovedTransactionMessage, - getUnreportedTransactionMessage, getExpenseReportStateAndStatus, generateReportName, navigateToLinkedReportAction, diff --git a/src/pages/home/report/PureReportActionItem.tsx b/src/pages/home/report/PureReportActionItem.tsx index ceeeff671d72..13199abd0c06 100644 --- a/src/pages/home/report/PureReportActionItem.tsx +++ b/src/pages/home/report/PureReportActionItem.tsx @@ -132,7 +132,6 @@ import { getRejectedReportMessage, getReportAutomaticallyApprovedMessage, getReportAutomaticallySubmittedMessage, - getUnreportedTransactionMessage, getUpgradeWorkspaceMessage, getWhisperDisplayNames, getWorkspaceNameUpdatedMessage, @@ -1018,11 +1017,7 @@ function PureReportActionItem({ ); } else if (action.actionName === CONST.REPORT.ACTIONS.TYPE.UNREPORTED_TRANSACTION) { - children = ( - - ${getUnreportedTransactionMessage(action)}`} /> - - ); + children = ; } else if (action.actionName === CONST.REPORT.ACTIONS.TYPE.MERGED_WITH_CASH_TRANSACTION) { children = ; } else if (isActionOfType(action, CONST.REPORT.ACTIONS.TYPE.DISMISSED_VIOLATION)) { From c36e1c0fc6e7b62c631d8556e09b6ad7171a1244 Mon Sep 17 00:00:00 2001 From: allgandalf Date: Tue, 20 May 2025 20:02:35 +0530 Subject: [PATCH 19/29] remove use of OriginalMessageUnreportedTransaction --- src/libs/ReportUtils.ts | 1 - src/types/onyx/OriginalMessage.ts | 8 -------- 2 files changed, 9 deletions(-) diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 40824539236b..ec8a42d920c2 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -17,7 +17,6 @@ import type { OriginalMessageIOU, OriginalMessageModifiedExpense, OriginalMessageMovedTransaction, - OriginalMessageUnreportedTransaction, } from 'src/types/onyx/OriginalMessage'; import type {SetRequired, TupleToUnion, ValueOf} from 'type-fest'; import type {FileObject} from '@components/AttachmentModal'; diff --git a/src/types/onyx/OriginalMessage.ts b/src/types/onyx/OriginalMessage.ts index 223a5ef47453..2a5c19f0ab81 100644 --- a/src/types/onyx/OriginalMessage.ts +++ b/src/types/onyx/OriginalMessage.ts @@ -557,12 +557,6 @@ type OriginalMessageChangePolicy = { toPolicy: string; }; -/** Model of `UNREPORTED_TRANSACTION` report action */ -type OriginalMessageUnreportedTransaction = { - /** ID of the old report */ - fromReportID: string; -}; - /** Model of MOVED_TRANSACTION report action */ type OriginalMessageMovedTransaction = { /** ID of the new report */ @@ -787,7 +781,6 @@ type OriginalMessageMap = { [CONST.REPORT.ACTIONS.TYPE.MODIFIED_EXPENSE]: OriginalMessageModifiedExpense; [CONST.REPORT.ACTIONS.TYPE.MOVED]: OriginalMessageMoved; [CONST.REPORT.ACTIONS.TYPE.MOVED_TRANSACTION]: OriginalMessageMovedTransaction; - [CONST.REPORT.ACTIONS.TYPE.UNREPORTED_TRANSACTION]: OriginalMessageUnreportedTransaction; [CONST.REPORT.ACTIONS.TYPE.OUTDATED_BANK_ACCOUNT]: never; [CONST.REPORT.ACTIONS.TYPE.REIMBURSED]: never; [CONST.REPORT.ACTIONS.TYPE.REIMBURSEMENT_ACH_BOUNCE]: never; @@ -855,6 +848,5 @@ export type { OriginalMessageExportIntegration, IssueNewCardOriginalMessage, OriginalMessageChangePolicy, - OriginalMessageUnreportedTransaction, OriginalMessageMovedTransaction, }; From 324b779f628242ab4bf16e5ceff4b36e0b5bcecf Mon Sep 17 00:00:00 2001 From: allgandalf Date: Wed, 21 May 2025 03:14:38 +0530 Subject: [PATCH 20/29] add selfDMCreatedReportActionID --- .../API/parameters/DeleteAppReportParams.ts | 3 +- src/libs/ReportUtils.ts | 10 ++- src/libs/actions/Report.ts | 74 +++++++++++++++++-- src/libs/test.md | 63 ++++++++++++++++ 4 files changed, 138 insertions(+), 12 deletions(-) create mode 100644 src/libs/test.md diff --git a/src/libs/API/parameters/DeleteAppReportParams.ts b/src/libs/API/parameters/DeleteAppReportParams.ts index b4e2bb944e03..9fd92b5f4dcd 100644 --- a/src/libs/API/parameters/DeleteAppReportParams.ts +++ b/src/libs/API/parameters/DeleteAppReportParams.ts @@ -1,7 +1,8 @@ type DeleteAppReportParams = { reportID: string; transactionIDToMoneyRequestReportActionIDMap?: string; - selfDMReportID: string; + selfDMReportID?: string; + selfDMCreatedReportActionID?: string; }; export default DeleteAppReportParams; diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 8e469b5e9b9c..104290169a2a 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -812,6 +812,11 @@ type GetChatRoomSubtitleConfig = { isCreateExpenseFlow?: boolean; }; +type SelfDMParameters = { + reportID?: string; + createdReportActionID?: string; +}; + type GetPolicyNameParams = { report: OnyxInputOrEntry; returnEmptyIfNotFound?: boolean; @@ -10158,10 +10163,6 @@ function prepareOnboardingOnyxData( guidedSetupData.push({type: 'message', ...textMessage}); } - type SelfDMParameters = { - reportID?: string; - createdReportActionID?: string; - }; let selfDMParameters: SelfDMParameters = {}; if (engagementChoice === CONST.ONBOARDING_CHOICES.PERSONAL_SPEND) { @@ -11160,4 +11161,5 @@ export type { ParsingDetails, MissingPaymentMethod, OptimisticNewReport, + SelfDMParameters, }; diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index 21230f6f0527..6c5548c7c659 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -93,7 +93,7 @@ import processReportIDDeeplink from '@libs/processReportIDDeeplink'; import Pusher from '@libs/Pusher'; import type {UserIsLeavingRoomEvent, UserIsTypingEvent} from '@libs/Pusher/types'; import * as ReportActionsUtils from '@libs/ReportActionsUtils'; -import type {OptimisticAddCommentReportAction, OptimisticChatReport} from '@libs/ReportUtils'; +import type {OptimisticAddCommentReportAction, OptimisticChatReport, SelfDMParameters} from '@libs/ReportUtils'; import { buildOptimisticAddCommentReportAction, buildOptimisticChangeFieldAction, @@ -4576,14 +4576,73 @@ function deleteAppReport(reportID: string | undefined) { return; } const optimisticData: OnyxUpdate[] = []; - const report = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]; + const successData: OnyxUpdate[] = []; - let selfDMReportID = findSelfDMReportID(); + const report = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]; - if (!selfDMReportID) { + const selfDMReportID = findSelfDMReportID(); + let selfDMReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${selfDMReportID}`]; + let createdAction: ReportAction; + let selfDMParameters: SelfDMParameters = {}; + if (!selfDMReport) { const currentTime = DateUtils.getDBTime(); - const selfDMReport = buildOptimisticSelfDMReport(currentTime); - selfDMReportID = selfDMReport.reportID; + selfDMReport = buildOptimisticSelfDMReport(currentTime); + createdAction = buildOptimisticCreatedReportAction(currentUserEmail ?? '', currentTime); + selfDMParameters = {reportID: selfDMReport.reportID, createdReportActionID: createdAction.reportActionID}; + optimisticData.push( + { + onyxMethod: Onyx.METHOD.SET, + key: `${ONYXKEYS.COLLECTION.REPORT}${selfDMReport.reportID}`, + value: { + ...selfDMReport, + pendingFields: { + createChat: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, + }, + }, + }, + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT_METADATA}${selfDMReport.reportID}`, + value: { + isOptimisticReport: true, + }, + }, + { + onyxMethod: Onyx.METHOD.SET, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${selfDMReport.reportID}`, + value: { + [createdAction.reportActionID]: createdAction, + }, + }, + ); + + successData.push( + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT}${selfDMReport.reportID}`, + value: { + pendingFields: { + createChat: null, + }, + }, + }, + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT_METADATA}${selfDMReport.reportID}`, + value: { + isOptimisticReport: false, + }, + }, + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${selfDMReport.reportID}`, + value: { + [createdAction.reportActionID]: { + pendingAction: null, + }, + }, + }, + ); } // 1. Get all report transactions const reportActionsForReport = allReportActions?.[reportID]; @@ -4708,7 +4767,8 @@ function deleteAppReport(reportID: string | undefined) { const parameters: DeleteAppReportParams = { reportID, transactionIDToMoneyRequestReportActionIDMap: JSON.stringify(transactionIDToMoneyRequestReportActionIDMap), - selfDMReportID, + selfDMReportID: selfDMParameters.reportID, + selfDMCreatedReportActionID: selfDMParameters.createdReportActionID, }; API.write(WRITE_COMMANDS.DELETE_APP_REPORT, parameters, {optimisticData}); diff --git a/src/libs/test.md b/src/libs/test.md new file mode 100644 index 000000000000..6661eefd653b --- /dev/null +++ b/src/libs/test.md @@ -0,0 +1,63 @@ +## Reviewer Checklist + +- [x] I have verified the author checklist is complete (all boxes are checked off). +- [x] I verified the correct issue is linked in the `### Fixed Issues` section above +- [x] I verified testing steps are clear and they cover the changes made in this PR + - [x] I verified the steps for local testing are in the `Tests` section + - [x] I verified the steps for Staging and/or Production testing are in the `QA steps` section + - [x] I verified the steps cover any possible failure scenarios (i.e. verify an input displays the correct error message if the entered data is not correct) + - [x] I turned off my network connection and tested it while offline to ensure it matches the expected behavior (i.e. verify the default avatar icon is displayed if app is offline) +- [x] I checked that screenshots or videos are included for tests on [all platforms](https://github.com/Expensify/App/blob/main/contributingGuides/CONTRIBUTING.md#make-sure-you-can-test-on-all-platforms) +- [x] I included screenshots or videos for tests on [all platforms](https://github.com/Expensify/App/blob/main/contributingGuides/CONTRIBUTING.md#make-sure-you-can-test-on-all-platforms) +- [x] I verified that the composer does not automatically focus or open the keyboard on mobile unless explicitly intended. This includes checking that returning the app from the background does not unexpectedly open the keyboard. +- [x] I verified tests pass on **all platforms** & I tested again on: + - [x] Android: HybridApp + - [x] Android: mWeb Chrome + - [x] iOS: HybridApp + - [x] iOS: mWeb Safari + - [x] MacOS: Chrome / Safari + - [x] MacOS: Desktop +- [x] If there are any errors in the console that are unrelated to this PR, I either fixed them (preferred) or linked to where I reported them in Slack +- [x] I verified there are no new alerts related to the `canBeMissing` param for `useOnyx` +- [x] I verified proper code patterns were followed (see [Reviewing the code](https://github.com/Expensify/App/blob/main/contributingGuides/PR_REVIEW_GUIDELINES.md#reviewing-the-code)) + - [x] I verified that any callback methods that were added or modified are named for what the method does and never what callback they handle (i.e. `toggleReport` and not `onIconClick`). + - [x] I verified that comments were added to code that is not self explanatory + - [x] I verified that any new or modified comments were clear, correct English, and explained "why" the code was doing something instead of only explaining "what" the code was doing. + - [x] I verified any copy / text shown in the product is localized by adding it to `src/languages/*` files and using the [translation method](https://github.com/Expensify/App/blob/4bd99402cebdf4d7394e0d1f260879ea238197eb/src/components/withLocalize.js#L60) + - [x] I verified all numbers, amounts, dates and phone numbers shown in the product are using the [localization methods](https://github.com/Expensify/App/blob/4bd99402cebdf4d7394e0d1f260879ea238197eb/src/components/withLocalize.js#L60-L68) + - [x] I verified any copy / text that was added to the app is grammatically correct in English. It adheres to proper capitalization guidelines (note: only the first word of header/labels should be capitalized), and is either coming verbatim from figma or has been approved by marketing (in order to get marketing approval, ask the Bug Zero team member to add the Waiting for copy label to the issue) + - [x] I verified proper file naming conventions were followed for any new files or renamed files. All non-platform specific files are named after what they export and are not named "index.js". All platform-specific files are named for the platform the code supports as outlined in the README. + - [x] I verified the JSDocs style guidelines (in [`STYLE.md`](https://github.com/Expensify/App/blob/main/contributingGuides/STYLE.md#jsdocs)) were followed +- [x] If a new code pattern is added I verified it was agreed to be used by multiple Expensify engineers +- [x] I verified that this PR follows the guidelines as stated in the [Review Guidelines](https://github.com/Expensify/App/blob/main/contributingGuides/PR_REVIEW_GUIDELINES.md) +- [x] I verified other components that can be impacted by these changes have been tested, and I retested again (i.e. if the PR modifies a shared library or component like `Avatar`, I verified the components using `Avatar` have been tested & I retested again) +- [x] I verified all code is DRY (the PR doesn't include any logic written more than once, with the exception of tests) +- [x] I verified any variables that can be defined as constants (ie. in CONST.ts or at the top of the file that uses the constant) are defined as such +- [x] If a new component is created I verified that: + - [x] A similar component doesn't exist in the codebase + - [x] All props are defined accurately and each prop has a `/** comment above it */` + - [x] The file is named correctly + - [x] The component has a clear name that is non-ambiguous and the purpose of the component can be inferred from the name alone + - [x] The only data being stored in the state is data necessary for rendering and nothing else + - [x] For Class Components, any internal methods passed to components event handlers are bound to `this` properly so there are no scoping issues (i.e. for `onClick={this.submit}` the method `this.submit` should be bound to `this` in the constructor) + - [x] Any internal methods bound to `this` are necessary to be bound (i.e. avoid `this.submit = this.submit.bind(this);` if `this.submit` is never passed to a component event handler like `onClick`) + - [x] All JSX used for rendering exists in the render method + - [x] The component has the minimum amount of code necessary for its purpose, and it is broken down into smaller components in order to separate concerns and functions +- [x] If any new file was added I verified that: + - [x] The file has a description of what it does and/or why is needed at the top of the file if the code is not self explanatory +- [x] If a new CSS style is added I verified that: + - [x] A similar style doesn't already exist + - [x] The style can't be created with an existing [StyleUtils](https://github.com/Expensify/App/blob/main/src/utils/index.ts) function (i.e. `StyleUtils.getBackgroundAndBorderStyle(theme.componentBG`) +- [x] If the PR modifies code that runs when editing or sending messages, I tested and verified there is no unexpected behavior for all supported markdown - URLs, single line code, code blocks, quotes, headings, bold, strikethrough, and italic. +- [x] If the PR modifies a generic component, I tested and verified that those changes do not break usages of that component in the rest of the App (i.e. if a shared library or component like `Avatar` is modified, I verified that `Avatar` is working as expected in all cases) +- [x] If the PR modifies a component related to any of the existing Storybook stories, I tested and verified all stories for that component are still working as expected. +- [x] If the PR modifies a component or page that can be accessed by a direct deeplink, I verified that the code functions as expected when the deeplink is used - from a logged in and logged out account. +- [x] If the PR modifies the UI (e.g. new buttons, new UI components, changing the padding/spacing/sizing, moving components, etc) or modifies the form input styles: + - [x] I verified that all the inputs inside a form are aligned with each other. + - [x] I added `Design` label and/or tagged `@Expensify/design` so the design team can review the changes. +- [x] If a new page is added, I verified it's using the `ScrollView` component to make it scrollable when more elements are added to the page. +- [x] For any bug fix or new feature in this PR, I verified that sufficient [unit tests](https://github.com/Expensify/App/blob/main/tests/README.md) are included to prevent regressions in this flow. +- [x] If the `main` branch was merged into this PR after a review, I tested again and verified the outcome was still expected according to the `Test` steps. +- [x] I have checked off every checkbox in the PR reviewer checklist, including those that don't apply to this PR. + + From f388b1393492e7e6d387802e571e2d4c57969821 Mon Sep 17 00:00:00 2001 From: allgandalf Date: Wed, 21 May 2025 03:27:22 +0530 Subject: [PATCH 21/29] remove unwanted .md file --- src/libs/ReportUtils.ts | 1 - src/libs/test.md | 63 ------------------------------- src/types/onyx/OriginalMessage.ts | 8 ++++ 3 files changed, 8 insertions(+), 64 deletions(-) delete mode 100644 src/libs/test.md diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 87c6790eca5a..1290b2e720fc 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -10163,7 +10163,6 @@ function prepareOnboardingOnyxData( guidedSetupData.push({type: 'message', ...textMessage}); } - let selfDMParameters: SelfDMParameters = {}; if (engagementChoice === CONST.ONBOARDING_CHOICES.PERSONAL_SPEND) { const selfDMReportID = findSelfDMReportID(); diff --git a/src/libs/test.md b/src/libs/test.md deleted file mode 100644 index 6661eefd653b..000000000000 --- a/src/libs/test.md +++ /dev/null @@ -1,63 +0,0 @@ -## Reviewer Checklist - -- [x] I have verified the author checklist is complete (all boxes are checked off). -- [x] I verified the correct issue is linked in the `### Fixed Issues` section above -- [x] I verified testing steps are clear and they cover the changes made in this PR - - [x] I verified the steps for local testing are in the `Tests` section - - [x] I verified the steps for Staging and/or Production testing are in the `QA steps` section - - [x] I verified the steps cover any possible failure scenarios (i.e. verify an input displays the correct error message if the entered data is not correct) - - [x] I turned off my network connection and tested it while offline to ensure it matches the expected behavior (i.e. verify the default avatar icon is displayed if app is offline) -- [x] I checked that screenshots or videos are included for tests on [all platforms](https://github.com/Expensify/App/blob/main/contributingGuides/CONTRIBUTING.md#make-sure-you-can-test-on-all-platforms) -- [x] I included screenshots or videos for tests on [all platforms](https://github.com/Expensify/App/blob/main/contributingGuides/CONTRIBUTING.md#make-sure-you-can-test-on-all-platforms) -- [x] I verified that the composer does not automatically focus or open the keyboard on mobile unless explicitly intended. This includes checking that returning the app from the background does not unexpectedly open the keyboard. -- [x] I verified tests pass on **all platforms** & I tested again on: - - [x] Android: HybridApp - - [x] Android: mWeb Chrome - - [x] iOS: HybridApp - - [x] iOS: mWeb Safari - - [x] MacOS: Chrome / Safari - - [x] MacOS: Desktop -- [x] If there are any errors in the console that are unrelated to this PR, I either fixed them (preferred) or linked to where I reported them in Slack -- [x] I verified there are no new alerts related to the `canBeMissing` param for `useOnyx` -- [x] I verified proper code patterns were followed (see [Reviewing the code](https://github.com/Expensify/App/blob/main/contributingGuides/PR_REVIEW_GUIDELINES.md#reviewing-the-code)) - - [x] I verified that any callback methods that were added or modified are named for what the method does and never what callback they handle (i.e. `toggleReport` and not `onIconClick`). - - [x] I verified that comments were added to code that is not self explanatory - - [x] I verified that any new or modified comments were clear, correct English, and explained "why" the code was doing something instead of only explaining "what" the code was doing. - - [x] I verified any copy / text shown in the product is localized by adding it to `src/languages/*` files and using the [translation method](https://github.com/Expensify/App/blob/4bd99402cebdf4d7394e0d1f260879ea238197eb/src/components/withLocalize.js#L60) - - [x] I verified all numbers, amounts, dates and phone numbers shown in the product are using the [localization methods](https://github.com/Expensify/App/blob/4bd99402cebdf4d7394e0d1f260879ea238197eb/src/components/withLocalize.js#L60-L68) - - [x] I verified any copy / text that was added to the app is grammatically correct in English. It adheres to proper capitalization guidelines (note: only the first word of header/labels should be capitalized), and is either coming verbatim from figma or has been approved by marketing (in order to get marketing approval, ask the Bug Zero team member to add the Waiting for copy label to the issue) - - [x] I verified proper file naming conventions were followed for any new files or renamed files. All non-platform specific files are named after what they export and are not named "index.js". All platform-specific files are named for the platform the code supports as outlined in the README. - - [x] I verified the JSDocs style guidelines (in [`STYLE.md`](https://github.com/Expensify/App/blob/main/contributingGuides/STYLE.md#jsdocs)) were followed -- [x] If a new code pattern is added I verified it was agreed to be used by multiple Expensify engineers -- [x] I verified that this PR follows the guidelines as stated in the [Review Guidelines](https://github.com/Expensify/App/blob/main/contributingGuides/PR_REVIEW_GUIDELINES.md) -- [x] I verified other components that can be impacted by these changes have been tested, and I retested again (i.e. if the PR modifies a shared library or component like `Avatar`, I verified the components using `Avatar` have been tested & I retested again) -- [x] I verified all code is DRY (the PR doesn't include any logic written more than once, with the exception of tests) -- [x] I verified any variables that can be defined as constants (ie. in CONST.ts or at the top of the file that uses the constant) are defined as such -- [x] If a new component is created I verified that: - - [x] A similar component doesn't exist in the codebase - - [x] All props are defined accurately and each prop has a `/** comment above it */` - - [x] The file is named correctly - - [x] The component has a clear name that is non-ambiguous and the purpose of the component can be inferred from the name alone - - [x] The only data being stored in the state is data necessary for rendering and nothing else - - [x] For Class Components, any internal methods passed to components event handlers are bound to `this` properly so there are no scoping issues (i.e. for `onClick={this.submit}` the method `this.submit` should be bound to `this` in the constructor) - - [x] Any internal methods bound to `this` are necessary to be bound (i.e. avoid `this.submit = this.submit.bind(this);` if `this.submit` is never passed to a component event handler like `onClick`) - - [x] All JSX used for rendering exists in the render method - - [x] The component has the minimum amount of code necessary for its purpose, and it is broken down into smaller components in order to separate concerns and functions -- [x] If any new file was added I verified that: - - [x] The file has a description of what it does and/or why is needed at the top of the file if the code is not self explanatory -- [x] If a new CSS style is added I verified that: - - [x] A similar style doesn't already exist - - [x] The style can't be created with an existing [StyleUtils](https://github.com/Expensify/App/blob/main/src/utils/index.ts) function (i.e. `StyleUtils.getBackgroundAndBorderStyle(theme.componentBG`) -- [x] If the PR modifies code that runs when editing or sending messages, I tested and verified there is no unexpected behavior for all supported markdown - URLs, single line code, code blocks, quotes, headings, bold, strikethrough, and italic. -- [x] If the PR modifies a generic component, I tested and verified that those changes do not break usages of that component in the rest of the App (i.e. if a shared library or component like `Avatar` is modified, I verified that `Avatar` is working as expected in all cases) -- [x] If the PR modifies a component related to any of the existing Storybook stories, I tested and verified all stories for that component are still working as expected. -- [x] If the PR modifies a component or page that can be accessed by a direct deeplink, I verified that the code functions as expected when the deeplink is used - from a logged in and logged out account. -- [x] If the PR modifies the UI (e.g. new buttons, new UI components, changing the padding/spacing/sizing, moving components, etc) or modifies the form input styles: - - [x] I verified that all the inputs inside a form are aligned with each other. - - [x] I added `Design` label and/or tagged `@Expensify/design` so the design team can review the changes. -- [x] If a new page is added, I verified it's using the `ScrollView` component to make it scrollable when more elements are added to the page. -- [x] For any bug fix or new feature in this PR, I verified that sufficient [unit tests](https://github.com/Expensify/App/blob/main/tests/README.md) are included to prevent regressions in this flow. -- [x] If the `main` branch was merged into this PR after a review, I tested again and verified the outcome was still expected according to the `Test` steps. -- [x] I have checked off every checkbox in the PR reviewer checklist, including those that don't apply to this PR. - - diff --git a/src/types/onyx/OriginalMessage.ts b/src/types/onyx/OriginalMessage.ts index 2a5c19f0ab81..223a5ef47453 100644 --- a/src/types/onyx/OriginalMessage.ts +++ b/src/types/onyx/OriginalMessage.ts @@ -557,6 +557,12 @@ type OriginalMessageChangePolicy = { toPolicy: string; }; +/** Model of `UNREPORTED_TRANSACTION` report action */ +type OriginalMessageUnreportedTransaction = { + /** ID of the old report */ + fromReportID: string; +}; + /** Model of MOVED_TRANSACTION report action */ type OriginalMessageMovedTransaction = { /** ID of the new report */ @@ -781,6 +787,7 @@ type OriginalMessageMap = { [CONST.REPORT.ACTIONS.TYPE.MODIFIED_EXPENSE]: OriginalMessageModifiedExpense; [CONST.REPORT.ACTIONS.TYPE.MOVED]: OriginalMessageMoved; [CONST.REPORT.ACTIONS.TYPE.MOVED_TRANSACTION]: OriginalMessageMovedTransaction; + [CONST.REPORT.ACTIONS.TYPE.UNREPORTED_TRANSACTION]: OriginalMessageUnreportedTransaction; [CONST.REPORT.ACTIONS.TYPE.OUTDATED_BANK_ACCOUNT]: never; [CONST.REPORT.ACTIONS.TYPE.REIMBURSED]: never; [CONST.REPORT.ACTIONS.TYPE.REIMBURSEMENT_ACH_BOUNCE]: never; @@ -848,5 +855,6 @@ export type { OriginalMessageExportIntegration, IssueNewCardOriginalMessage, OriginalMessageChangePolicy, + OriginalMessageUnreportedTransaction, OriginalMessageMovedTransaction, }; From ba2b8e5d64b7e87c09eab28af7da2ca9f7c991eb Mon Sep 17 00:00:00 2001 From: allgandalf Date: Wed, 21 May 2025 03:37:44 +0530 Subject: [PATCH 22/29] add failure data --- src/libs/actions/Report.ts | 54 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index 6c5548c7c659..9f52937a2ac2 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -176,6 +176,7 @@ import type { ReportActionReactions, ReportUserIsTyping, Transaction, + TransactionViolations, } from '@src/types/onyx'; import type {Decision} from '@src/types/onyx/OriginalMessage'; import type {ConnectionName} from '@src/types/onyx/Policy'; @@ -290,6 +291,13 @@ Onyx.connect({ }, }); +let allTransactionViolations: OnyxCollection = {}; +Onyx.connect({ + key: ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS, + waitForCollectionCallback: true, + callback: (value) => (allTransactionViolations = value), +}); + let allReports: OnyxCollection; Onyx.connect({ key: ONYXKEYS.COLLECTION.REPORT, @@ -4577,6 +4585,7 @@ function deleteAppReport(reportID: string | undefined) { } const optimisticData: OnyxUpdate[] = []; const successData: OnyxUpdate[] = []; + const failureData: OnyxUpdate[] = []; const report = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]; @@ -4584,6 +4593,7 @@ function deleteAppReport(reportID: string | undefined) { let selfDMReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${selfDMReportID}`]; let createdAction: ReportAction; let selfDMParameters: SelfDMParameters = {}; + if (!selfDMReport) { const currentTime = DateUtils.getDBTime(); selfDMReport = buildOptimisticSelfDMReport(currentTime); @@ -4644,6 +4654,7 @@ function deleteAppReport(reportID: string | undefined) { }, ); } + // 1. Get all report transactions const reportActionsForReport = allReportActions?.[reportID]; const transactionIDs = []; @@ -4655,16 +4666,30 @@ function deleteAppReport(reportID: string | undefined) { // 2. Set transaction's reportID to 0 [...new Set(transactionIDs)].forEach((transactionID) => { + const transaction = allTransactions?.[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`]; optimisticData.push({ onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`, value: {reportID: 0}, }); + failureData.push({ + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`, + value: transaction, + }); + + const transactionViolations = allTransactionViolations?.[`${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transactionID}`]; + optimisticData.push({ onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transactionID}`, value: null, }); + failureData.push({ + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transactionID}`, + value: transactionViolations, + }); }); const transactionIDToMoneyRequestReportActionIDMap: Record = {}; @@ -4695,6 +4720,14 @@ function deleteAppReport(reportID: string | undefined) { }, }); + failureData.push({ + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${selfDMReportID}`, + value: { + [newReportActionID]: null, + }, + }); + const transactionID = ReportActionsUtils.getOriginalMessage(reportAction)?.IOUTransactionID; if (transactionID) { transactionIDToMoneyRequestReportActionIDMap[transactionID] = newReportActionID; @@ -4743,6 +4776,12 @@ function deleteAppReport(reportID: string | undefined) { value: null, }); + failureData.push({ + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`, + value: reportActionsForReport, + }); + // 7. Delete the report optimisticData.push({ onyxMethod: Onyx.METHOD.MERGE, @@ -4750,8 +4789,15 @@ function deleteAppReport(reportID: string | undefined) { value: null, }); + failureData.push({ + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT}${reportID}`, + value: report, + }); + // 8. Delete chat report preview const reportactionID = report?.parentReportActionID; + const reportaction = allReportActions?.[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`]; const parentReportID = report?.parentReportID; if (reportactionID) { @@ -4762,6 +4808,14 @@ function deleteAppReport(reportID: string | undefined) { [reportactionID]: null, }, }); + + failureData.push({ + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${parentReportID}`, + value: { + [reportactionID]: reportaction, + }, + }); } const parameters: DeleteAppReportParams = { From e9ef5c50102b1806104b716bdbc12b306ec735c7 Mon Sep 17 00:00:00 2001 From: allgandalf Date: Wed, 21 May 2025 04:25:38 +0530 Subject: [PATCH 23/29] fix failure data and update condition for isDeleteAction --- src/libs/ReportSecondaryActionUtils.ts | 7 +++---- src/libs/actions/Report.ts | 12 +++++++++++- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/src/libs/ReportSecondaryActionUtils.ts b/src/libs/ReportSecondaryActionUtils.ts index f133979b0f11..b40ad9252738 100644 --- a/src/libs/ReportSecondaryActionUtils.ts +++ b/src/libs/ReportSecondaryActionUtils.ts @@ -338,12 +338,11 @@ function isMoveTransactionAction(reportTransactions: Transaction[], reportAction return canMoveExpense; } -function isDeleteAction(report: Report, reportActions?: ReportAction[]): boolean { - const transactionThreadReportID = getOneTransactionThreadReportID(report.reportID, reportActions ?? []); +function isDeleteAction(report: Report): boolean { const isExpenseReport = isExpenseReportUtils(report); const isIOUReport = isIOUReportUtils(report); - if ((!isExpenseReport && !isIOUReport) || (!!reportActions && !transactionThreadReportID)) { + if (!isExpenseReport && !isIOUReport) { return false; } @@ -445,7 +444,7 @@ function getSecondaryReportActions( options.push(CONST.REPORT.SECONDARY_ACTIONS.VIEW_DETAILS); - if (isDeleteAction(report, reportActions)) { + if (isDeleteAction(report)) { options.push(CONST.REPORT.SECONDARY_ACTIONS.DELETE); } diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index 9f52937a2ac2..b29d7dd66e0c 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -4675,7 +4675,7 @@ function deleteAppReport(reportID: string | undefined) { failureData.push({ onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`, - value: transaction, + value: {reportID: transaction?.reportID}, }); const transactionViolations = allTransactionViolations?.[`${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transactionID}`]; @@ -4720,6 +4720,16 @@ function deleteAppReport(reportID: string | undefined) { }, }); + successData.push({ + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${selfDMReportID}`, + value: { + [newReportActionID]: { + pendingAction: null, + }, + }, + }); + failureData.push({ onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${selfDMReportID}`, From df01e66efd73c0edcd712fb875f0b350ff2e5250 Mon Sep 17 00:00:00 2001 From: allgandalf Date: Thu, 22 May 2025 01:13:32 +0530 Subject: [PATCH 24/29] address dylans comments --- src/libs/actions/Report.ts | 184 +++++++++++++++++-------------------- 1 file changed, 86 insertions(+), 98 deletions(-) diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index be4aa3adae4c..7da9dab3d51f 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -4678,107 +4678,96 @@ function deleteAppReport(reportID: string | undefined) { // 1. Get all report transactions const reportActionsForReport = allReportActions?.[reportID]; - const transactionIDs = []; - for (const reportAction of Object.values(reportActionsForReport ?? {})) { - if (ReportActionsUtils.isMoneyRequestAction(reportAction)) { - transactionIDs.push(ReportActionsUtils.getOriginalMessage(reportAction)?.IOUTransactionID); + const transactionIDToMoneyRequestReportActionIDMap: Record = {}; + + [...Object.values(reportActionsForReport ?? {})].reverse().forEach((reportAction) => { + if (!ReportActionsUtils.isMoneyRequestAction(reportAction)) { + return; } - } - // 2. Set transaction's reportID to 0 - [...new Set(transactionIDs)].forEach((transactionID) => { - const transaction = allTransactions?.[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`]; + const transactionID = ReportActionsUtils.getOriginalMessage(reportAction)?.IOUTransactionID; + const childReportID = reportAction.childReportID; + const newReportActionID = rand64(); + + // 1. Update the transaction and its violations + if (transactionID) { + const transaction = allTransactions?.[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`]; + const transactionViolations = allTransactionViolations?.[`${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transactionID}`]; + + optimisticData.push( + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`, + value: {reportID: 0}, + }, + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transactionID}`, + value: null, + }, + ); + + failureData.push( + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`, + value: {reportID: transaction?.reportID}, + }, + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transactionID}`, + value: transactionViolations, + }, + ); + + transactionIDToMoneyRequestReportActionIDMap[transactionID] = newReportActionID; + } + + // 2. Move the report action to self DM + const updatedReportAction = { + ...reportAction, + originalMessage: { + ...reportAction.originalMessage, + IOUReportID: 0, + type: CONST.IOU.TYPE.TRACK, + }, + reportActionID: newReportActionID, + pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, + }; + optimisticData.push({ onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`, - value: {reportID: 0}, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${selfDMReportID}`, + value: {[newReportActionID]: updatedReportAction}, }); - failureData.push({ - onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`, - value: {reportID: transaction?.reportID}, - }); - - const transactionViolations = allTransactionViolations?.[`${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transactionID}`]; - optimisticData.push({ + successData.push({ onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transactionID}`, - value: null, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${selfDMReportID}`, + value: {[newReportActionID]: {pendingAction: null}}, }); + failureData.push({ onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transactionID}`, - value: transactionViolations, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${selfDMReportID}`, + value: {[newReportActionID]: null}, }); - }); - const transactionIDToMoneyRequestReportActionIDMap: Record = {}; - - Object.values(reportActionsForReport ?? {}) - .filter((reportAction): reportAction is ReportAction => ReportActionsUtils.isMoneyRequestAction(reportAction)) - .reverse() - .forEach((reportAction) => { - // 3. Move the IOU reportActions to the selfDM - const newReportActionID = rand64(); - const updatedReportAction = { - ...reportAction, - originalMessage: { - // eslint-disable-next-line deprecation/deprecation - ...reportAction.originalMessage, - IOUReportID: 0, - type: CONST.IOU.TYPE.TRACK, - }, - childReportID: reportAction.childReportID, - reportActionID: newReportActionID, - pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, - }; - optimisticData.push({ - onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${selfDMReportID}`, - value: { - [newReportActionID]: updatedReportAction, - }, - }); - - successData.push({ - onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${selfDMReportID}`, - value: { - [newReportActionID]: { - pendingAction: null, - }, - }, - }); - - failureData.push({ - onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${selfDMReportID}`, - value: { - [newReportActionID]: null, - }, - }); - - const transactionID = ReportActionsUtils.getOriginalMessage(reportAction)?.IOUTransactionID; - if (transactionID) { - transactionIDToMoneyRequestReportActionIDMap[transactionID] = newReportActionID; - } - - // 4. Get transaction thread - optimisticData.push({ + // 3. Update transaction thread + optimisticData.push( + { onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT}${reportAction.childReportID}`, + key: `${ONYXKEYS.COLLECTION.REPORT}${childReportID}`, value: { parentReportActionID: newReportActionID, parentReportID: selfDMReportID, chatReportID: selfDMReportID, - policyID: '_FAKE_', + policyID: CONST.POLICY.ID_FAKE, }, - }); - - optimisticData.push({ + }, + { onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportAction.childReportID}`, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${childReportID}`, value: { [newReportActionID]: { originalMessage: { @@ -4786,19 +4775,18 @@ function deleteAppReport(reportID: string | undefined) { }, }, }, - }); + }, + ); - // 5. Add UNREPORTEDTRANSACTION report actions - const unreportedAction = buildOptimisticUnreportedTransactionAction(reportAction.childReportID, reportID); + // 4. Add UNREPORTEDTRANSACTION report action + const unreportedAction = buildOptimisticUnreportedTransactionAction(childReportID, reportID); - optimisticData.push({ - onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportAction.childReportID}`, - value: { - [unreportedAction.reportActionID]: unreportedAction, - }, - }); + optimisticData.push({ + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${childReportID}`, + value: {[unreportedAction.reportActionID]: unreportedAction}, }); + }); // 6. Delete report actions on the report optimisticData.push({ @@ -4827,16 +4815,16 @@ function deleteAppReport(reportID: string | undefined) { }); // 8. Delete chat report preview - const reportactionID = report?.parentReportActionID; - const reportaction = allReportActions?.[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`]; + const reportActionID = report?.parentReportActionID; + const reportAction = allReportActions?.[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`]; const parentReportID = report?.parentReportID; - if (reportactionID) { + if (reportActionID) { optimisticData.push({ onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${parentReportID}`, value: { - [reportactionID]: null, + [reportActionID]: null, }, }); @@ -4844,7 +4832,7 @@ function deleteAppReport(reportID: string | undefined) { onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${parentReportID}`, value: { - [reportactionID]: reportaction, + [reportActionID]: reportAction, }, }); } @@ -4856,7 +4844,7 @@ function deleteAppReport(reportID: string | undefined) { selfDMCreatedReportActionID: selfDMParameters.createdReportActionID, }; - API.write(WRITE_COMMANDS.DELETE_APP_REPORT, parameters, {optimisticData}); + API.write(WRITE_COMMANDS.DELETE_APP_REPORT, parameters, {optimisticData, successData, failureData}); } /** From 7f22c66bd0c2a0805201fdd92fa427fc5e9d7356 Mon Sep 17 00:00:00 2001 From: allgandalf Date: Thu, 22 May 2025 01:32:24 +0530 Subject: [PATCH 25/29] introduce transactionIDToReportActionAndThreadData --- src/libs/API/parameters/DeleteAppReportParams.ts | 2 +- src/libs/actions/Report.ts | 14 ++++++++++++-- src/pages/home/report/PureReportActionItem.tsx | 1 - 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/libs/API/parameters/DeleteAppReportParams.ts b/src/libs/API/parameters/DeleteAppReportParams.ts index 9fd92b5f4dcd..85ff7f231198 100644 --- a/src/libs/API/parameters/DeleteAppReportParams.ts +++ b/src/libs/API/parameters/DeleteAppReportParams.ts @@ -1,6 +1,6 @@ type DeleteAppReportParams = { reportID: string; - transactionIDToMoneyRequestReportActionIDMap?: string; + transactionIDToReportActionAndThreadData?: string; selfDMReportID?: string; selfDMCreatedReportActionID?: string; }; diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index 7da9dab3d51f..a2f457d027cb 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -43,6 +43,7 @@ import type { SearchForReportsParams, SearchForRoomsToMentionParams, TogglePinnedChatParams, + TransactionThreadInfo, UpdateChatNameParams, UpdateCommentParams, UpdateGroupChatAvatarParams, @@ -4679,8 +4680,9 @@ function deleteAppReport(reportID: string | undefined) { // 1. Get all report transactions const reportActionsForReport = allReportActions?.[reportID]; const transactionIDToMoneyRequestReportActionIDMap: Record = {}; + const transactionIDToReportActionAndThreadData: Record = {}; - [...Object.values(reportActionsForReport ?? {})].reverse().forEach((reportAction) => { + [...Object.values(reportActionsForReport ?? {})].forEach((reportAction) => { if (!ReportActionsUtils.isMoneyRequestAction(reportAction)) { return; } @@ -4727,6 +4729,7 @@ function deleteAppReport(reportID: string | undefined) { const updatedReportAction = { ...reportAction, originalMessage: { + // eslint-disable-next-line deprecation/deprecation ...reportAction.originalMessage, IOUReportID: 0, type: CONST.IOU.TYPE.TRACK, @@ -4786,6 +4789,13 @@ function deleteAppReport(reportID: string | undefined) { key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${childReportID}`, value: {[unreportedAction.reportActionID]: unreportedAction}, }); + + if (transactionID) { + transactionIDToReportActionAndThreadData[transactionID] = { + moneyRequestPreviewReportActionID: newReportActionID, + movedReportActionID: unreportedAction?.reportActionID, + }; + } }); // 6. Delete report actions on the report @@ -4839,7 +4849,7 @@ function deleteAppReport(reportID: string | undefined) { const parameters: DeleteAppReportParams = { reportID, - transactionIDToMoneyRequestReportActionIDMap: JSON.stringify(transactionIDToMoneyRequestReportActionIDMap), + transactionIDToReportActionAndThreadData: JSON.stringify(transactionIDToReportActionAndThreadData), selfDMReportID: selfDMParameters.reportID, selfDMCreatedReportActionID: selfDMParameters.createdReportActionID, }; diff --git a/src/pages/home/report/PureReportActionItem.tsx b/src/pages/home/report/PureReportActionItem.tsx index 37e349c4e8cf..fb4a028aa5a5 100644 --- a/src/pages/home/report/PureReportActionItem.tsx +++ b/src/pages/home/report/PureReportActionItem.tsx @@ -127,7 +127,6 @@ import { getMovedTransactionMessage, getPolicyChangeMessage, getRejectedReportMessage, - getUnreportedTransactionMessage, getUpgradeWorkspaceMessage, getWhisperDisplayNames, getWorkspaceNameUpdatedMessage, From 7420bb619ad02b30ae1b0440b012ff81cbfa0d1f Mon Sep 17 00:00:00 2001 From: allgandalf Date: Thu, 22 May 2025 01:49:07 +0530 Subject: [PATCH 26/29] revert report delete changes in report details page --- src/pages/ReportDetailsPage.tsx | 35 +++------------------------------ 1 file changed, 3 insertions(+), 32 deletions(-) diff --git a/src/pages/ReportDetailsPage.tsx b/src/pages/ReportDetailsPage.tsx index 49cada71b610..48ea2c9d785a 100644 --- a/src/pages/ReportDetailsPage.tsx +++ b/src/pages/ReportDetailsPage.tsx @@ -44,7 +44,6 @@ import {getPersonalDetailsForAccountIDs} from '@libs/OptionsListUtils'; import Parser from '@libs/Parser'; import {getConnectedIntegration, isPolicyAdmin as isPolicyAdminUtil, isPolicyEmployee as isPolicyEmployeeUtil, shouldShowPolicy} from '@libs/PolicyUtils'; import {getOneTransactionThreadReportID, getOriginalMessage, getTrackExpenseActionableWhisper, isDeletedAction, isMoneyRequestAction, isTrackExpenseAction} from '@libs/ReportActionsUtils'; -import {isDeleteAction} from '@libs/ReportSecondaryActionUtils'; import { canDeleteCardTransactionByLiabilityType, canDeleteTransaction, @@ -114,7 +113,6 @@ import { import { clearAvatarErrors, clearPolicyRoomNameErrors, - deleteAppReport, exportReportToCSV, getReportPrivateNote, hasErrorInPrivateNotes, @@ -200,7 +198,6 @@ function ReportDetailsPage({policies, report, route, reportMetadata}: ReportDeta const [isLastMemberLeavingGroupModalVisible, setIsLastMemberLeavingGroupModalVisible] = useState(false); const [isDeleteModalVisible, setIsDeleteModalVisible] = useState(false); - const [isDeleteReportModalVisible, setIsDeleteReportModalVisible] = useState(false); const [isUnapproveModalVisible, setIsUnapproveModalVisible] = useState(false); const [isConfirmModalVisible, setIsConfirmModalVisible] = useState(false); const [offlineModalVisible, setOfflineModalVisible] = useState(false); @@ -315,8 +312,7 @@ function ReportDetailsPage({policies, report, route, reportMetadata}: ReportDeta const canDeleteRequest = isActionOwner && (canDeleteTransaction(moneyRequestReport) || isSelfDMTrackExpenseReport) && !isDeletedParentAction; const iouTransactionID = isMoneyRequestAction(requestParentReportAction) ? getOriginalMessage(requestParentReportAction)?.IOUTransactionID : ''; const isCardTransactionCanBeDeleted = canDeleteCardTransactionByLiabilityType(iouTransactionID); - const canDeleteReport = isDeleteAction(report); - const shouldShowDeleteButton = shouldShowTaskDeleteButton || ((canDeleteRequest || canDeleteReport) && isCardTransactionCanBeDeleted); + const shouldShowDeleteButton = shouldShowTaskDeleteButton || (canDeleteRequest && isCardTransactionCanBeDeleted); useEffect(() => { if (canDeleteRequest) { return; @@ -1033,18 +1029,8 @@ function ReportDetailsPage({policies, report, route, reportMetadata}: ReportDeta { - if (caseID === CASES.MONEY_REPORT) { - setIsDeleteReportModalVisible(true); - } else { - setIsDeleteModalVisible(true); - } - }} + title={caseID === CASES.DEFAULT ? translate('common.delete') : translate('reportActionContextMenu.deleteAction', {action: requestParentReportAction})} + onPress={() => setIsDeleteModalVisible(true)} /> )} @@ -1108,21 +1094,6 @@ function ReportDetailsPage({policies, report, route, reportMetadata}: ReportDeta shouldEnableNewFocusManagement onModalHide={navigateToTargetUrl} /> - { - setIsDeleteReportModalVisible(false); - deleteAppReport(report.reportID); - }} - onCancel={() => setIsDeleteReportModalVisible(false)} - prompt={translate('iou.deleteReportConfirmation')} - confirmText={translate('common.delete')} - cancelText={translate('common.cancel')} - danger - shouldEnableNewFocusManagement - onModalHide={navigateToTargetUrl} - /> {!canUseTableReportView && ( Date: Thu, 22 May 2025 02:42:01 +0530 Subject: [PATCH 27/29] Add delete reprot functionality to report --- src/components/MoneyReportHeader.tsx | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/src/components/MoneyReportHeader.tsx b/src/components/MoneyReportHeader.tsx index 194ead6f241a..bc3651105930 100644 --- a/src/components/MoneyReportHeader.tsx +++ b/src/components/MoneyReportHeader.tsx @@ -16,7 +16,7 @@ import useSelectedTransactionsActions from '@hooks/useSelectedTransactionsAction import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; import {turnOffMobileSelectionMode} from '@libs/actions/MobileSelectionMode'; -import {downloadReportPDF, exportReportToCSV, exportReportToPDF, exportToIntegration, markAsManuallyExported, openUnreportedExpense} from '@libs/actions/Report'; +import {deleteAppReport, downloadReportPDF, exportReportToCSV, exportReportToPDF, exportToIntegration, markAsManuallyExported, openUnreportedExpense} from '@libs/actions/Report'; import {getThreadReportIDsForTransactions, getTotalAmountForIOUReportPreviewButton} from '@libs/MoneyRequestReportUtils'; import Navigation from '@libs/Navigation/Navigation'; import {buildOptimisticNextStepForPreventSelfApprovalsEnabled} from '@libs/NextStepUtils'; @@ -166,6 +166,7 @@ function MoneyReportHeader({policy, report: moneyRequestReport, transactionThrea const [downloadErrorModalVisible, setDownloadErrorModalVisible] = useState(false); const [isCancelPaymentModalVisible, setIsCancelPaymentModalVisible] = useState(false); const [isDeleteModalVisible, setIsDeleteModalVisible] = useState(false); + const [isDeleteReportModalVisible, setIsDeleteReportModalVisible] = useState(false); const [isUnapproveModalVisible, setIsUnapproveModalVisible] = useState(false); const [isReopenWarningModalVisible, setIsReopenWarningModalVisible] = useState(false); const [isPDFModalVisible, setIsPDFModalVisible] = useState(false); @@ -736,7 +737,11 @@ function MoneyReportHeader({policy, report: moneyRequestReport, transactionThrea icon: Expensicons.Trashcan, value: CONST.REPORT.SECONDARY_ACTIONS.DELETE, onSelected: () => { - setIsDeleteModalVisible(true); + if (Object.keys(transactions).length === 1) { + setIsDeleteModalVisible(true); + } else { + setIsDeleteReportModalVisible(true); + } }, }, [CONST.REPORT.SECONDARY_ACTIONS.REOPEN]: { @@ -980,6 +985,22 @@ function MoneyReportHeader({policy, report: moneyRequestReport, transactionThrea danger shouldEnableNewFocusManagement /> + { + setIsDeleteReportModalVisible(false); + + deleteAppReport(moneyRequestReport?.reportID); + Navigation.goBack(); + }} + onCancel={() => setIsDeleteReportModalVisible(false)} + prompt={translate('iou.deleteReportConfirmation')} + confirmText={translate('common.delete')} + cancelText={translate('common.cancel')} + danger + shouldEnableNewFocusManagement + /> {!!connectedIntegration && ( Date: Thu, 22 May 2025 16:31:15 +0530 Subject: [PATCH 28/29] address reviewers comment --- src/components/MoneyReportHeader.tsx | 10 +++++----- src/libs/ReportUtils.ts | 2 +- src/libs/actions/Report.ts | 12 +++++------- 3 files changed, 11 insertions(+), 13 deletions(-) diff --git a/src/components/MoneyReportHeader.tsx b/src/components/MoneyReportHeader.tsx index bc3651105930..a67c56ad09a2 100644 --- a/src/components/MoneyReportHeader.tsx +++ b/src/components/MoneyReportHeader.tsx @@ -165,7 +165,7 @@ function MoneyReportHeader({policy, report: moneyRequestReport, transactionThrea const [downloadErrorModalVisible, setDownloadErrorModalVisible] = useState(false); const [isCancelPaymentModalVisible, setIsCancelPaymentModalVisible] = useState(false); - const [isDeleteModalVisible, setIsDeleteModalVisible] = useState(false); + const [isDeleteExpenseModalVisible, setIsDeleteExpenseModalVisible] = useState(false); const [isDeleteReportModalVisible, setIsDeleteReportModalVisible] = useState(false); const [isUnapproveModalVisible, setIsUnapproveModalVisible] = useState(false); const [isReopenWarningModalVisible, setIsReopenWarningModalVisible] = useState(false); @@ -738,7 +738,7 @@ function MoneyReportHeader({policy, report: moneyRequestReport, transactionThrea value: CONST.REPORT.SECONDARY_ACTIONS.DELETE, onSelected: () => { if (Object.keys(transactions).length === 1) { - setIsDeleteModalVisible(true); + setIsDeleteExpenseModalVisible(true); } else { setIsDeleteReportModalVisible(true); } @@ -950,9 +950,9 @@ function MoneyReportHeader({policy, report: moneyRequestReport, transactionThrea /> { - setIsDeleteModalVisible(false); + setIsDeleteExpenseModalVisible(false); let goBackRoute: Route | undefined; if (transactionThreadReportID) { if (!requestParentReportAction || !transaction?.transactionID) { @@ -967,7 +967,7 @@ function MoneyReportHeader({policy, report: moneyRequestReport, transactionThrea Navigation.navigate(goBackRoute); } }} - onCancel={() => setIsDeleteModalVisible(false)} + onCancel={() => setIsDeleteExpenseModalVisible(false)} prompt={translate('iou.deleteConfirmation', {count: 1})} confirmText={translate('common.delete')} cancelText={translate('common.cancel')} diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 56353be3a51d..18250f0d5285 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -6175,7 +6175,7 @@ function buildOptimisticTransactionAction( const [actionText, messageHtml] = type === CONST.REPORT.ACTIONS.TYPE.MOVED_TRANSACTION ? [`moved this expense to ${reportName}`, `moved this expense to ${reportName}`] - : [`moved this expense to your personal space`, `moved this expense to your personal space`]; + : ['moved this expense to your personal space', 'moved this expense to your personal space']; return { actionName: type, diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index a2f457d027cb..adccfa09e5ca 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -4611,7 +4611,7 @@ function deleteAppReport(reportID: string | undefined) { const report = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]; - const selfDMReportID = findSelfDMReportID(); + let selfDMReportID = findSelfDMReportID(); let selfDMReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${selfDMReportID}`]; let createdAction: ReportAction; let selfDMParameters: SelfDMParameters = {}; @@ -4619,6 +4619,7 @@ function deleteAppReport(reportID: string | undefined) { if (!selfDMReport) { const currentTime = DateUtils.getDBTime(); selfDMReport = buildOptimisticSelfDMReport(currentTime); + selfDMReportID = selfDMReport.reportID; createdAction = buildOptimisticCreatedReportAction(currentUserEmail ?? '', currentTime); selfDMParameters = {reportID: selfDMReport.reportID, createdReportActionID: createdAction.reportActionID}; optimisticData.push( @@ -4679,10 +4680,9 @@ function deleteAppReport(reportID: string | undefined) { // 1. Get all report transactions const reportActionsForReport = allReportActions?.[reportID]; - const transactionIDToMoneyRequestReportActionIDMap: Record = {}; const transactionIDToReportActionAndThreadData: Record = {}; - [...Object.values(reportActionsForReport ?? {})].forEach((reportAction) => { + Object.values(reportActionsForReport ?? {}).forEach((reportAction) => { if (!ReportActionsUtils.isMoneyRequestAction(reportAction)) { return; } @@ -4700,7 +4700,7 @@ function deleteAppReport(reportID: string | undefined) { { onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`, - value: {reportID: 0}, + value: {reportID: '0'}, }, { onyxMethod: Onyx.METHOD.MERGE, @@ -4721,8 +4721,6 @@ function deleteAppReport(reportID: string | undefined) { value: transactionViolations, }, ); - - transactionIDToMoneyRequestReportActionIDMap[transactionID] = newReportActionID; } // 2. Move the report action to self DM @@ -4731,7 +4729,7 @@ function deleteAppReport(reportID: string | undefined) { originalMessage: { // eslint-disable-next-line deprecation/deprecation ...reportAction.originalMessage, - IOUReportID: 0, + IOUReportID: '0', type: CONST.IOU.TYPE.TRACK, }, reportActionID: newReportActionID, From b9831de93fa86642180ffa76c5ef2ee21f21804d Mon Sep 17 00:00:00 2001 From: Gandalf Date: Thu, 22 May 2025 19:45:55 +0530 Subject: [PATCH 29/29] Apply suggestions from code review Co-authored-by: Carlos Martins --- src/libs/actions/Report.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index adccfa09e5ca..a962885b447f 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -4700,7 +4700,7 @@ function deleteAppReport(reportID: string | undefined) { { onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`, - value: {reportID: '0'}, + value: {reportID: CONST.REPORT.UNREPORTED_REPORT_ID}, }, { onyxMethod: Onyx.METHOD.MERGE, @@ -4729,7 +4729,7 @@ function deleteAppReport(reportID: string | undefined) { originalMessage: { // eslint-disable-next-line deprecation/deprecation ...reportAction.originalMessage, - IOUReportID: '0', + IOUReportID: CONST.REPORT.UNREPORTED_REPORT_ID, type: CONST.IOU.TYPE.TRACK, }, reportActionID: newReportActionID,