diff --git a/src/libs/OptionsListUtils/index.ts b/src/libs/OptionsListUtils/index.ts index f01b1bf73865..9dd2797382a8 100644 --- a/src/libs/OptionsListUtils/index.ts +++ b/src/libs/OptionsListUtils/index.ts @@ -145,7 +145,6 @@ import { isArchivedNonExpenseReport, isChatThread, isDM, - isDraftReport, isExpenseReport, isHiddenForCurrentUser, isInvoiceRoom, @@ -1267,7 +1266,7 @@ function getReportOption( } } } - option.isDisabled = !!reportDraft || isDraftReport(participant.reportID); + option.isDisabled = !!reportDraft; option.isSelected = participant.selected; option.selected = participant.selected; // Keep for backwards compatibility option.brickRoadIndicator = null; diff --git a/src/pages/Share/SubmitDetailsPage.tsx b/src/pages/Share/SubmitDetailsPage.tsx index fcc2aa60b58c..e3df122277cd 100644 --- a/src/pages/Share/SubmitDetailsPage.tsx +++ b/src/pages/Share/SubmitDetailsPage.tsx @@ -45,7 +45,7 @@ import type {ShareNavigatorParamList} from '@libs/Navigation/types'; import {getParticipantsOption, getReportOption} from '@libs/OptionsListUtils'; import {hasOnlyPersonalPolicies as hasOnlyPersonalPoliciesUtil, isPaidGroupPolicy} from '@libs/PolicyUtils'; import {shouldValidateFile} from '@libs/ReceiptUtils'; -import {isSelfDM} from '@libs/ReportUtils'; +import {isMoneyRequestReport, isSelfDM} from '@libs/ReportUtils'; import {getDefaultTaxCode, getTaxValue} from '@libs/TransactionUtils'; import DraftWorkspaceOpener from '@pages/iou/request/step/confirmation/DraftWorkspaceOpener'; import CONST from '@src/CONST'; @@ -68,6 +68,8 @@ function SubmitDetailsPage({ const [unknownUserDetails] = useOnyx(ONYXKEYS.SHARE_UNKNOWN_USER_DETAILS); const [personalDetails] = useOnyx(`${ONYXKEYS.PERSONAL_DETAILS_LIST}`); const report: OnyxEntry = useReportOrReportDraft(reportOrAccountID); + const reportIDToCheck = isMoneyRequestReport(report) ? report?.chatReportID : report?.reportID; + const [reportDraft] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT_DRAFT}${reportIDToCheck}`); const [parentReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${report?.parentReportID}`); const [transaction] = useOnyx(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${CONST.IOU.OPTIMISTIC_TRANSACTION_ID}`); const transactionReport = useReportOrReportDraft(transaction?.reportID); @@ -175,7 +177,7 @@ function SubmitDetailsPage({ const privateIsArchived = privateIsArchivedMap[`${ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS}${participant.reportID}`]; return participant?.accountID ? getParticipantsOption(participant, personalDetails) - : getReportOption(participant, privateIsArchived, policy, personalDetails, conciergeReportID, reportAttributesDerived); + : getReportOption(participant, privateIsArchived, policy, personalDetails, conciergeReportID, reportAttributesDerived, reportDraft); }); const isPolicyExpenseChat = useMemo(() => participants?.some((participant) => participant.isPolicyExpenseChat), [participants]); diff --git a/src/pages/iou/request/step/IOURequestStepAmount.tsx b/src/pages/iou/request/step/IOURequestStepAmount.tsx index ceab6f331c13..d6b8db385b31 100644 --- a/src/pages/iou/request/step/IOURequestStepAmount.tsx +++ b/src/pages/iou/request/step/IOURequestStepAmount.tsx @@ -127,6 +127,8 @@ function IOURequestStepAmount({ const [ownerBillingGracePeriodEnd] = useOnyx(ONYXKEYS.NVP_PRIVATE_OWNER_BILLING_GRACE_PERIOD_END); const isEditing = action === CONST.IOU.ACTION.EDIT; const {duplicateTransactions, duplicateTransactionViolations} = useDuplicateTransactionsAndViolations(isEditing && transactionID ? [transactionID] : []); + const reportIDToCheck = isMoneyRequestReport(report) ? report?.chatReportID : report?.reportID; + const [reportDraft] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT_DRAFT}${reportIDToCheck}`); const reportAttributesDerived = useReportAttributes(); const privateIsArchivedMap = usePrivateIsArchivedMap(); const isSplitBill = iouType === CONST.IOU.TYPE.SPLIT; @@ -246,7 +248,7 @@ function IOURequestStepAmount({ const privateIsArchived = privateIsArchivedMap[`${ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS}${participant.reportID}`]; return participantAccountID ? getParticipantsOption(participant, personalDetails) - : getReportOption(participant, privateIsArchived, policy, personalDetails, conciergeReportID, reportAttributesDerived); + : getReportOption(participant, privateIsArchived, policy, personalDetails, conciergeReportID, reportAttributesDerived, reportDraft); }); const backendAmount = convertToBackendAmount(Number.parseFloat(amount)); diff --git a/src/pages/iou/request/step/IOURequestStepConfirmation.tsx b/src/pages/iou/request/step/IOURequestStepConfirmation.tsx index ad1da43a3e92..2c7510a5b17c 100644 --- a/src/pages/iou/request/step/IOURequestStepConfirmation.tsx +++ b/src/pages/iou/request/step/IOURequestStepConfirmation.tsx @@ -175,6 +175,7 @@ function IOURequestStepConfirmation({ () => resolveReportForMoneyRequest({transaction, transactionReport, routeReport: reportWithDraftFallback, policy: policyReal}), [transaction, transactionReport, reportWithDraftFallback, policyReal], ); + const [reportDrafts] = useOnyx(ONYXKEYS.COLLECTION.REPORT_DRAFT); const {policy} = usePolicyForTransaction({ transaction: initialTransaction, @@ -261,13 +262,12 @@ function IOURequestStepConfirmation({ return participant; } const privateIsArchived = privateIsArchivedMap[`${ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS}${participant.reportID}`]; + const participantReportDraft = reportDrafts?.[`${ONYXKEYS.COLLECTION.REPORT_DRAFT}${participant.reportID}`]; return participant.accountID ? getParticipantsOption(participant, personalDetails) - : getReportOption(participant, privateIsArchived, policy, personalDetails, conciergeReportID, reportAttributesDerived); + : getReportOption(participant, privateIsArchived, policy, personalDetails, conciergeReportID, reportAttributesDerived, participantReportDraft); }) ?? [], - // getReportOrDraftReport (called inside getReportOption) falls back to its module-level allReportsDraft - // connection, so we don't need to subscribe to COLLECTION.REPORT_DRAFT here. - [transaction?.participants, iouType, personalDetails, reportAttributesDerived, privateIsArchivedMap, policy, conciergeReportID], + [transaction?.participants, iouType, personalDetails, reportAttributesDerived, privateIsArchivedMap, policy, conciergeReportID, reportDrafts], ); const defaultParticipants = useMemo(() => { diff --git a/tests/unit/OptionsListUtilsTest.tsx b/tests/unit/OptionsListUtilsTest.tsx index 67747b1e23c9..0caad0500011 100644 --- a/tests/unit/OptionsListUtilsTest.tsx +++ b/tests/unit/OptionsListUtilsTest.tsx @@ -6082,6 +6082,61 @@ describe('OptionsListUtils', () => { expect(option.isDisabled).toBe(true); }); + + it('should not disable option when reportDraft is undefined for a regular report', async () => { + const reportID = '200'; + const report: Report = { + reportID, + reportName: 'Regular Report', + type: CONST.REPORT.TYPE.CHAT, + }; + + await Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT}${reportID}`, report); + await waitForBatchedUpdates(); + + const participant: Participant = {reportID, selected: false}; + + // Pass reportDraft = undefined → not a draft, should NOT be disabled + const option = getReportOption(participant, undefined, POLICY, {}, undefined, undefined, undefined); + + expect(option.isDisabled).toBeFalsy(); + }); + + it('should disable option when reportDraft is explicitly passed', async () => { + const reportID = '201'; + const draftReport: Report = { + reportID, + reportName: 'Explicit Draft Report', + type: CONST.REPORT.TYPE.CHAT, + }; + + const participant: Participant = {reportID, selected: false}; + + // Pass reportDraft explicitly → should be disabled regardless of Onyx state + const option = getReportOption(participant, undefined, POLICY, {}, undefined, undefined, draftReport); + + expect(option.isDisabled).toBe(true); + }); + + it('should not disable option when reportDraft param is undefined even if report exists in REPORT_DRAFT', async () => { + const reportID = '202'; + const draftReport: Report = { + reportID, + reportName: 'Global Draft Report', + type: CONST.REPORT.TYPE.CHAT, + }; + + // Draft exists in Onyx but is NOT passed as param + await Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT_DRAFT}${reportID}`, draftReport); + await waitForBatchedUpdates(); + + const participant: Participant = {reportID, selected: false}; + + // Callers are responsible for passing reportDraft explicitly — undefined means not disabled + const option = getReportOption(participant, undefined, POLICY, {}, undefined, undefined, undefined); + + expect(option.isDisabled).toBeFalsy(); + }); }); describe('getReportDisplayOption', () => {