From 7e32224541f4fafa83e2dee8777dca1c15170a67 Mon Sep 17 00:00:00 2001 From: VickyStash Date: Wed, 6 Aug 2025 13:39:54 +0200 Subject: [PATCH 1/2] Add noOptimisticTransactionThreads beta and disable thread creation if it's on --- src/CONST/index.ts | 1 + .../parameters/CreatePerDiemRequestParams.ts | 2 +- src/libs/API/parameters/RequestMoneyParams.ts | 2 +- src/libs/ReportUtils.ts | 30 +++- src/libs/actions/IOU.ts | 130 +++++++++++------- src/pages/Share/SubmitDetailsPage.tsx | 5 + .../iou/request/step/IOURequestStepAmount.tsx | 4 + .../step/IOURequestStepConfirmation.tsx | 5 + .../step/IOURequestStepScan/index.native.tsx | 6 +- .../request/step/IOURequestStepScan/index.tsx | 6 +- tests/actions/IOUTest.ts | 21 +++ 11 files changed, 155 insertions(+), 57 deletions(-) diff --git a/src/CONST/index.ts b/src/CONST/index.ts index a16fca06f879..2956b656eaaa 100755 --- a/src/CONST/index.ts +++ b/src/CONST/index.ts @@ -676,6 +676,7 @@ const CONST = { TRACK_FLOWS: 'trackFlows', EUR_BILLING: 'eurBilling', MANUAL_DISTANCE: 'manualDistance', + NO_OPTIMISTIC_TRANSACTION_THREADS: 'noOptimisticTransactionThreads', VACATION_DELEGATE: 'vacationDelegate', }, BUTTON_STATES: { diff --git a/src/libs/API/parameters/CreatePerDiemRequestParams.ts b/src/libs/API/parameters/CreatePerDiemRequestParams.ts index d1981c5f3123..549ae61c40f2 100644 --- a/src/libs/API/parameters/CreatePerDiemRequestParams.ts +++ b/src/libs/API/parameters/CreatePerDiemRequestParams.ts @@ -18,7 +18,7 @@ type CreatePerDiemRequestParams = { createdChatReportActionID?: string; createdIOUReportActionID?: string; reportPreviewReportActionID: string; - transactionThreadReportID: string; + transactionThreadReportID?: string; createdReportActionIDForThread: string | undefined; billable?: boolean; attendees?: string; diff --git a/src/libs/API/parameters/RequestMoneyParams.ts b/src/libs/API/parameters/RequestMoneyParams.ts index 42e0e9aed6dc..d8d5560c6bae 100644 --- a/src/libs/API/parameters/RequestMoneyParams.ts +++ b/src/libs/API/parameters/RequestMoneyParams.ts @@ -25,7 +25,7 @@ type RequestMoneyParams = { taxAmount: number; billable?: boolean; receiptGpsPoints?: string; - transactionThreadReportID: string; + transactionThreadReportID?: string; createdReportActionIDForThread: string | undefined; reimbursible?: boolean; description?: string; diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 319ff3bed8d0..e2766d0ceeb9 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -635,7 +635,7 @@ type OptimisticModifiedExpenseReportAction = Pick< | 'delegateAccountID' > & {reportID?: string}; -type OptimisticMoneyRequestEntities = { +type BaseOptimisticMoneyRequestEntities = { iouReport: Report; type: ValueOf; amount: number; @@ -654,6 +654,10 @@ type OptimisticMoneyRequestEntities = { optimisticCreatedReportActionID?: string; }; +type OptimisticMoneyRequestEntities = BaseOptimisticMoneyRequestEntities & {shouldGenerateTransactionThreadReport?: boolean}; +type OptimisticMoneyRequestEntitiesWithTransactionThreadFlag = BaseOptimisticMoneyRequestEntities & {shouldGenerateTransactionThreadReport: true}; +type OptimisticMoneyRequestEntitiesWithoutTransactionThreadFlag = BaseOptimisticMoneyRequestEntities & {shouldGenerateTransactionThreadReport: false}; + type OptimisticTaskReport = SetRequired< Pick< Report, @@ -7802,6 +7806,15 @@ function buildTransactionThread( * 4. Transaction Thread linked to the IOU action via `parentReportActionID` * 5. CREATED action for the Transaction Thread */ +function buildOptimisticMoneyRequestEntities( + optimisticMoneyRequestEntities: OptimisticMoneyRequestEntitiesWithoutTransactionThreadFlag, +): [OptimisticCreatedReportAction, OptimisticCreatedReportAction, OptimisticIOUReportAction, undefined, null]; +function buildOptimisticMoneyRequestEntities( + optimisticMoneyRequestEntities: OptimisticMoneyRequestEntitiesWithTransactionThreadFlag, +): [OptimisticCreatedReportAction, OptimisticCreatedReportAction, OptimisticIOUReportAction, OptimisticChatReport, OptimisticCreatedReportAction | null]; +function buildOptimisticMoneyRequestEntities( + optimisticMoneyRequestEntities: OptimisticMoneyRequestEntities, +): [OptimisticCreatedReportAction, OptimisticCreatedReportAction, OptimisticIOUReportAction, OptimisticChatReport | undefined, OptimisticCreatedReportAction | null]; function buildOptimisticMoneyRequestEntities({ iouReport, type, @@ -7819,7 +7832,14 @@ function buildOptimisticMoneyRequestEntities({ existingTransactionThreadReportID, linkedTrackedExpenseReportAction, optimisticCreatedReportActionID, -}: OptimisticMoneyRequestEntities): [OptimisticCreatedReportAction, OptimisticCreatedReportAction, OptimisticIOUReportAction, OptimisticChatReport, OptimisticCreatedReportAction | null] { + shouldGenerateTransactionThreadReport, +}: OptimisticMoneyRequestEntities): [ + OptimisticCreatedReportAction, + OptimisticCreatedReportAction, + OptimisticIOUReportAction, + OptimisticChatReport | undefined, + OptimisticCreatedReportAction | null, +] { const createdActionForChat = buildOptimisticCreatedReportAction(payeeEmail, undefined, optimisticCreatedReportActionID); // The `CREATED` action must be optimistically generated before the IOU action so that it won't appear after the IOU action in the chat. @@ -7844,11 +7864,11 @@ function buildOptimisticMoneyRequestEntities({ }); // Create optimistic transactionThread and the `CREATED` action for it, if existingTransactionThreadReportID is undefined - const transactionThread = buildTransactionThread(iouAction, iouReport, existingTransactionThreadReportID); - const createdActionForTransactionThread = existingTransactionThreadReportID ? null : buildOptimisticCreatedReportAction(payeeEmail); + const transactionThread = shouldGenerateTransactionThreadReport ? buildTransactionThread(iouAction, iouReport, existingTransactionThreadReportID) : undefined; + const createdActionForTransactionThread = !!existingTransactionThreadReportID || !shouldGenerateTransactionThreadReport ? null : buildOptimisticCreatedReportAction(payeeEmail); // The IOU action and the transactionThread are co-dependent as parent-child, so we need to link them together - iouAction.childReportID = existingTransactionThreadReportID ?? transactionThread.reportID; + iouAction.childReportID = existingTransactionThreadReportID ?? transactionThread?.reportID; return [createdActionForChat, createdActionForIOUReport, iouAction, transactionThread, createdActionForTransactionThread]; } diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index f71a01854feb..50e73704b2da 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -273,7 +273,7 @@ type MoneyRequestInformation = { createdChatReportActionID?: string; createdIOUReportActionID?: string; reportPreviewAction: OnyxTypes.ReportAction; - transactionThreadReportID: string; + transactionThreadReportID?: string; createdReportActionIDForThread: string | undefined; onyxData: OnyxData; billable?: boolean; @@ -443,6 +443,7 @@ type RequestMoneyInformation = { optimisticCreatedReportActionID?: string; optimisticIOUReportID?: string; optimisticReportPreviewActionID?: string; + shouldGenerateTransactionThreadReport: boolean; }; type MoneyRequestInformationParams = { @@ -460,6 +461,7 @@ type MoneyRequestInformationParams = { optimisticCreatedReportActionID?: string; optimisticIOUReportID?: string; optimisticReportPreviewActionID?: string; + shouldGenerateTransactionThreadReport: boolean; }; type MoneyRequestOptimisticParams = { @@ -475,7 +477,7 @@ type MoneyRequestOptimisticParams = { }; transactionParams: { transaction: OnyxTypes.Transaction; - transactionThreadReport: OptimisticChatReport | null; + transactionThreadReport?: OptimisticChatReport | null; transactionThreadCreatedReportAction: OptimisticCreatedReportAction | null; }; policyRecentlyUsed: { @@ -498,6 +500,7 @@ type BuildOnyxDataForMoneyRequestParams = { optimisticParams: MoneyRequestOptimisticParams; retryParams?: StartSplitBilActionParams | CreateTrackExpenseParams | RequestMoneyInformation | ReplaceReceipt; participant?: Participant; + shouldGenerateTransactionThreadReport: boolean; }; type DistanceRequestTransactionParams = BaseTransactionParams & { @@ -1416,6 +1419,7 @@ function buildOnyxDataForMoneyRequest(moneyRequestParams: BuildOnyxDataForMoneyR optimisticParams, retryParams, participant, + shouldGenerateTransactionThreadReport, } = moneyRequestParams; const {policy, policyCategories, policyTagList} = policyParams; const { @@ -1518,22 +1522,27 @@ function buildOnyxDataForMoneyRequest(moneyRequestParams: BuildOnyxDataForMoneyR [iou.action.reportActionID]: iou.action as OnyxTypes.ReportAction, }, }, - { - onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT}${transactionThreadReport?.reportID}`, - value: { - ...transactionThreadReport, - pendingFields: {createChat: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD}, + ); + + if (shouldGenerateTransactionThreadReport) { + optimisticData.push( + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT}${transactionThreadReport?.reportID}`, + value: { + ...transactionThreadReport, + pendingFields: {createChat: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD}, + }, }, - }, - { - onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT_METADATA}${transactionThreadReport?.reportID}`, - value: { - isOptimisticReport: true, + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT_METADATA}${transactionThreadReport?.reportID}`, + value: { + isOptimisticReport: true, + }, }, - }, - ); + ); + } if (isNewChatReport) { optimisticData.push({ @@ -1555,7 +1564,7 @@ function buildOnyxDataForMoneyRequest(moneyRequestParams: BuildOnyxDataForMoneyR }); } - if (!isEmptyObject(transactionThreadCreatedReportAction)) { + if (shouldGenerateTransactionThreadReport && !isEmptyObject(transactionThreadCreatedReportAction)) { optimisticData.push({ onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${transactionThreadReport?.reportID}`, @@ -1733,22 +1742,6 @@ function buildOnyxDataForMoneyRequest(moneyRequestParams: BuildOnyxDataForMoneyR isOptimisticReport: false, }, }, - { - onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT}${transactionThreadReport?.reportID}`, - value: { - participants: redundantParticipants, - pendingFields: null, - errorFields: null, - }, - }, - { - onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT_METADATA}${transactionThreadReport?.reportID}`, - value: { - isOptimisticReport: false, - }, - }, { onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.TRANSACTION}${transaction.transactionID}`, @@ -1803,7 +1796,28 @@ function buildOnyxDataForMoneyRequest(moneyRequestParams: BuildOnyxDataForMoneyR }, ); - if (!isEmptyObject(transactionThreadCreatedReportAction)) { + if (shouldGenerateTransactionThreadReport) { + successData.push( + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT}${transactionThreadReport?.reportID}`, + value: { + participants: redundantParticipants, + pendingFields: null, + errorFields: null, + }, + }, + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT_METADATA}${transactionThreadReport?.reportID}`, + value: { + isOptimisticReport: false, + }, + }, + ); + } + + if (shouldGenerateTransactionThreadReport && !isEmptyObject(transactionThreadCreatedReportAction)) { successData.push({ onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${transactionThreadReport?.reportID}`, @@ -1848,18 +1862,6 @@ function buildOnyxDataForMoneyRequest(moneyRequestParams: BuildOnyxDataForMoneyR }, }, }, - { - onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT}${transactionThreadReport?.reportID}`, - value: { - pendingFields: null, - errorFields: existingTransactionThreadReport - ? null - : { - createChat: getMicroSecondOnyxErrorWithTranslationKey('report.genericCreateReportFailureMessage'), - }, - }, - }, { onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.TRANSACTION}${transaction.transactionID}`, @@ -1917,6 +1919,21 @@ function buildOnyxDataForMoneyRequest(moneyRequestParams: BuildOnyxDataForMoneyR }, ); + if (shouldGenerateTransactionThreadReport) { + failureData.push({ + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT}${transactionThreadReport?.reportID}`, + value: { + pendingFields: null, + errorFields: existingTransactionThreadReport + ? null + : { + createChat: getMicroSecondOnyxErrorWithTranslationKey('report.genericCreateReportFailureMessage'), + }, + }, + }); + } + if (!isOneOnOneSplit) { optimisticData.push({ onyxMethod: Onyx.METHOD.SET, @@ -1934,7 +1951,7 @@ function buildOnyxDataForMoneyRequest(moneyRequestParams: BuildOnyxDataForMoneyR }); } - if (!isEmptyObject(transactionThreadCreatedReportAction)) { + if (shouldGenerateTransactionThreadReport && !isEmptyObject(transactionThreadCreatedReportAction)) { failureData.push({ onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${transactionThreadReport?.reportID}`, @@ -3227,6 +3244,7 @@ function getSendInvoiceInformation( payeeEmail: receiver.login ?? '', participants: [receiver], transactionID: optimisticTransaction.transactionID, + shouldGenerateTransactionThreadReport: true, }); // STEP 6: Build Onyx Data @@ -3290,6 +3308,7 @@ function getMoneyRequestInformation(moneyRequestInformation: MoneyRequestInforma optimisticCreatedReportActionID, optimisticIOUReportID, optimisticReportPreviewActionID, + shouldGenerateTransactionThreadReport, } = moneyRequestInformation; const {payeeAccountID = userAccountID, payeeEmail = currentUserEmail, participant} = participantParams; const {policy, policyCategories, policyTagList} = policyParams; @@ -3435,6 +3454,7 @@ function getMoneyRequestInformation(moneyRequestInformation: MoneyRequestInforma existingTransactionThreadReportID: linkedTrackedExpenseReportAction?.childReportID, optimisticCreatedReportActionID, linkedTrackedExpenseReportAction, + shouldGenerateTransactionThreadReport, }); let reportPreviewAction = shouldCreateNewMoneyRequestReport ? null : getReportPreviewAction(chatReport.reportID, iouReport.reportID); @@ -3473,6 +3493,7 @@ function getMoneyRequestInformation(moneyRequestInformation: MoneyRequestInforma participant, isNewChatReport, shouldCreateNewMoneyRequestReport, + shouldGenerateTransactionThreadReport, policyParams: { policy, policyCategories, @@ -3674,6 +3695,7 @@ function getPerDiemExpenseInformation(perDiemExpenseInformation: PerDiemExpenseI payeeEmail, participants: [participant], transactionID: optimisticTransaction.transactionID, + shouldGenerateTransactionThreadReport: true, }); let reportPreviewAction = shouldCreateNewMoneyRequestReport ? null : getReportPreviewAction(chatReport.reportID, iouReport.reportID); @@ -3711,6 +3733,7 @@ function getPerDiemExpenseInformation(perDiemExpenseInformation: PerDiemExpenseI const [optimisticData, successData, failureData] = buildOnyxDataForMoneyRequest({ isNewChatReport, shouldCreateNewMoneyRequestReport, + shouldGenerateTransactionThreadReport: true, policyParams: { policy, policyCategories, @@ -3913,6 +3936,7 @@ function getTrackExpenseInformation(params: GetTrackExpenseInformationParams): T isPersonalTrackingExpense: !shouldUseMoneyReport, existingTransactionThreadReportID: linkedTrackedExpenseReportAction?.childReportID, linkedTrackedExpenseReportAction, + shouldGenerateTransactionThreadReport: true, }); let reportPreviewAction: OnyxInputValue> = null; @@ -4997,7 +5021,7 @@ type ConvertTrackedExpenseToRequestParams = { merchant: string; created: string; attendees?: Attendee[]; - transactionThreadReportID: string; + transactionThreadReportID?: string; }; chatParams: { reportID: string; @@ -5212,6 +5236,7 @@ function convertBulkTrackedExpensesToIOU(transactionIDs: string[], targetReportI moneyRequestReportID: targetReportID, existingTransactionID: transactionID, existingTransaction: transaction, + shouldGenerateTransactionThreadReport: true, }); const convertParams: ConvertTrackedExpenseToRequestParams = { @@ -5422,6 +5447,7 @@ function requestMoney(requestMoneyInformation: RequestMoneyInformation) { optimisticCreatedReportActionID, optimisticIOUReportID, optimisticReportPreviewActionID, + shouldGenerateTransactionThreadReport, } = requestMoneyInformation; const {payeeAccountID} = participantParams; const parsedComment = getParsedComment(transactionParams.comment ?? ''); @@ -5504,6 +5530,7 @@ function requestMoney(requestMoneyInformation: RequestMoneyInformation) { optimisticCreatedReportActionID, optimisticIOUReportID, optimisticReportPreviewActionID, + shouldGenerateTransactionThreadReport, }); const activeReportID = isMoneyRequestReport ? report?.reportID : chatReport.reportID; @@ -6461,6 +6488,7 @@ function createSplitsAndOnyxData({ payeeEmail: currentUserEmailForIOUSplit, participants: [participant], transactionID: oneOnOneTransaction.transactionID, + shouldGenerateTransactionThreadReport: true, }); // Add optimistic personal details for new participants @@ -6501,6 +6529,7 @@ function createSplitsAndOnyxData({ const [oneOnOneOptimisticData, oneOnOneSuccessData, oneOnOneFailureData] = buildOnyxDataForMoneyRequest({ isNewChatReport: isNewOneOnOneChatReport, shouldCreateNewMoneyRequestReport: shouldCreateNewOneOnOneIOUReport, + shouldGenerateTransactionThreadReport: true, isOneOnOneSplit: true, optimisticParams: { chat: { @@ -7274,6 +7303,7 @@ function completeSplitBill( payeeEmail: currentUserEmailForIOUSplit, participants: [participant], transactionID: oneOnOneTransaction.transactionID, + shouldGenerateTransactionThreadReport: true, }); let oneOnOneReportPreviewAction = getReportPreviewAction(oneOnOneChatReport?.reportID, oneOnOneIOUReport?.reportID); @@ -7287,6 +7317,7 @@ function completeSplitBill( isNewChatReport: isNewOneOnOneChatReport, isOneOnOneSplit: true, shouldCreateNewMoneyRequestReport: shouldCreateNewOneOnOneIOUReport, + shouldGenerateTransactionThreadReport: true, optimisticParams: { chat: { report: oneOnOneChatReport, @@ -7508,6 +7539,7 @@ function createDistanceRequest(distanceRequestInformation: CreateDistanceRequest billable, attendees, }, + shouldGenerateTransactionThreadReport: true, }); onyxData = moneyRequestOnyxData; @@ -8372,6 +8404,7 @@ function getSendMoneyParams( transactionID: optimisticTransaction.transactionID, paymentType: paymentMethodType, isSendMoneyFlow: true, + shouldGenerateTransactionThreadReport: true, }); const reportPreviewAction = buildOptimisticReportPreview(chatReport, optimisticIOUReport); @@ -12002,6 +12035,7 @@ function saveSplitTransactions(draftTransaction: OnyxEntry(undefined); const [errorMessage, setErrorMessage] = useState(undefined); + const {isBetaEnabled} = usePermissions(); + const shouldGenerateTransactionThreadReport = !isBetaEnabled(CONST.BETAS.NO_OPTIMISTIC_TRANSACTION_THREADS); + const [validFilesToUpload, setValidFilesToUpload] = useState([]); const {validateFiles} = useFilesValidation(setValidFilesToUpload); @@ -151,6 +155,7 @@ function SubmitDetailsPage({ linkedTrackedExpenseReportAction: transaction.linkedTrackedExpenseReportAction, linkedTrackedExpenseReportID: transaction.linkedTrackedExpenseReportID, }, + shouldGenerateTransactionThreadReport, }); } }; diff --git a/src/pages/iou/request/step/IOURequestStepAmount.tsx b/src/pages/iou/request/step/IOURequestStepAmount.tsx index 880d5670ff8b..ec479c60c412 100644 --- a/src/pages/iou/request/step/IOURequestStepAmount.tsx +++ b/src/pages/iou/request/step/IOURequestStepAmount.tsx @@ -7,6 +7,7 @@ import type {WithCurrentUserPersonalDetailsProps} from '@components/withCurrentU import useDuplicateTransactionsAndViolations from '@hooks/useDuplicateTransactionsAndViolations'; import useLocalize from '@hooks/useLocalize'; import useOnyx from '@hooks/useOnyx'; +import usePermissions from '@hooks/usePermissions'; import useShowNotFoundPageInIOUStep from '@hooks/useShowNotFoundPageInIOUStep'; import {createDraftTransaction, removeDraftTransaction} from '@libs/actions/TransactionEdit'; import {convertToBackendAmount, isValidCurrencyCode} from '@libs/CurrencyUtils'; @@ -69,6 +70,7 @@ function IOURequestStepAmount({ shouldKeepUserInput = false, }: IOURequestStepAmountProps) { const {translate} = useLocalize(); + const {isBetaEnabled} = usePermissions(); const textInput = useRef(null); const focusTimeoutRef = useRef(null); const isSaveButtonPressed = useRef(false); @@ -95,6 +97,7 @@ function IOURequestStepAmount({ const currency = isValidCurrencyCode(selectedCurrency) ? selectedCurrency : originalCurrency; // eslint-disable-next-line rulesdir/no-negated-variables const shouldShowNotFoundPage = useShowNotFoundPageInIOUStep(action, iouType, report, CONST.EDIT_REQUEST_FIELD.AMOUNT); + const shouldGenerateTransactionThreadReport = !isBetaEnabled(CONST.BETAS.NO_OPTIMISTIC_TRANSACTION_THREADS); // For quick button actions, we'll skip the confirmation page unless the report is archived or this is a workspace request, as // the user will have to add a merchant. @@ -212,6 +215,7 @@ function IOURequestStepAmount({ attendees: transaction?.comment?.attendees, }, backToReport, + shouldGenerateTransactionThreadReport, }); return; } diff --git a/src/pages/iou/request/step/IOURequestStepConfirmation.tsx b/src/pages/iou/request/step/IOURequestStepConfirmation.tsx index 28c3e816dad8..7fcaa5ba5229 100644 --- a/src/pages/iou/request/step/IOURequestStepConfirmation.tsx +++ b/src/pages/iou/request/step/IOURequestStepConfirmation.tsx @@ -19,6 +19,7 @@ import useFilesValidation from '@hooks/useFilesValidation'; import useLocalize from '@hooks/useLocalize'; import useNetwork from '@hooks/useNetwork'; import useOnyx from '@hooks/useOnyx'; +import usePermissions from '@hooks/usePermissions'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; import useThreeDotsAnchorPosition from '@hooks/useThreeDotsAnchorPosition'; @@ -146,6 +147,7 @@ function IOURequestStepConfirmation({ const styles = useThemeStyles(); const theme = useTheme(); const {translate} = useLocalize(); + const {isBetaEnabled} = usePermissions(); const threeDotsAnchorPosition = useThreeDotsAnchorPosition(styles.threeDotsPopoverOffsetNoCloseButton); const {isOffline} = useNetwork(); const [startLocationPermissionFlow, setStartLocationPermissionFlow] = useState(false); @@ -213,6 +215,7 @@ function IOURequestStepConfirmation({ [transaction?.participants, iouType, personalDetails, reportAttributesDerived], ); const isPolicyExpenseChat = useMemo(() => participants?.some((participant) => participant.isPolicyExpenseChat), [participants]); + const shouldGenerateTransactionThreadReport = !isBetaEnabled(CONST.BETAS.NO_OPTIMISTIC_TRANSACTION_THREADS); const formHasBeenSubmitted = useRef(false); useFetchRoute(transaction, transaction?.comment?.waypoints, action, shouldUseTransactionDraft(action) ? CONST.TRANSACTION.STATE.DRAFT : CONST.TRANSACTION.STATE.CURRENT); @@ -493,6 +496,7 @@ function IOURequestStepConfirmation({ source: item.comment?.source, }, shouldHandleNavigation: index === transactions.length - 1, + shouldGenerateTransactionThreadReport, backToReport, }); }); @@ -511,6 +515,7 @@ function IOURequestStepConfirmation({ transactionTaxAmount, customUnitRateID, backToReport, + shouldGenerateTransactionThreadReport, ], ); diff --git a/src/pages/iou/request/step/IOURequestStepScan/index.native.tsx b/src/pages/iou/request/step/IOURequestStepScan/index.native.tsx index 3d4c9c7b1ff9..3b8245063ef0 100644 --- a/src/pages/iou/request/step/IOURequestStepScan/index.native.tsx +++ b/src/pages/iou/request/step/IOURequestStepScan/index.native.tsx @@ -27,6 +27,7 @@ import useFilesValidation from '@hooks/useFilesValidation'; import useIOUUtils from '@hooks/useIOUUtils'; import useLocalize from '@hooks/useLocalize'; import useOnyx from '@hooks/useOnyx'; +import usePermissions from '@hooks/usePermissions'; import usePolicy from '@hooks/usePolicy'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; @@ -91,6 +92,7 @@ function IOURequestStepScan({ }: IOURequestStepScanProps) { const theme = useTheme(); const styles = useThemeStyles(); + const {isBetaEnabled} = usePermissions(); const {isLoaderVisible, setIsLoaderVisible} = useFullScreenLoader(); const device = useCameraDevice('back', { physicalDevices: ['wide-angle-camera', 'ultra-wide-angle-camera'], @@ -119,6 +121,7 @@ function IOURequestStepScan({ const [shouldShowMultiScanEducationalPopup, setShouldShowMultiScanEducationalPopup] = useState(false); const [cameraKey, setCameraKey] = useState(0); const {shouldStartLocationPermissionFlow} = useIOUUtils(); + const shouldGenerateTransactionThreadReport = !isBetaEnabled(CONST.BETAS.NO_OPTIMISTIC_TRANSACTION_THREADS); const defaultTaxCode = getDefaultTaxCode(policy, initialTransaction); const transactionTaxCode = (initialTransaction?.taxCode ? initialTransaction?.taxCode : defaultTaxCode) ?? ''; @@ -341,11 +344,12 @@ function IOURequestStepScan({ }, shouldHandleNavigation: index === files.length - 1, backToReport, + shouldGenerateTransactionThreadReport, }); } }); }, - [backToReport, currentUserPersonalDetails.accountID, currentUserPersonalDetails.login, iouType, report, transactions], + [backToReport, currentUserPersonalDetails.accountID, currentUserPersonalDetails.login, iouType, report, transactions, shouldGenerateTransactionThreadReport], ); const navigateToConfirmationStep = useCallback( diff --git a/src/pages/iou/request/step/IOURequestStepScan/index.tsx b/src/pages/iou/request/step/IOURequestStepScan/index.tsx index 578d3b7bf5d7..29d22f87d7fe 100644 --- a/src/pages/iou/request/step/IOURequestStepScan/index.tsx +++ b/src/pages/iou/request/step/IOURequestStepScan/index.tsx @@ -29,6 +29,7 @@ import useFilesValidation from '@hooks/useFilesValidation'; import useIOUUtils from '@hooks/useIOUUtils'; import useLocalize from '@hooks/useLocalize'; import useOnyx from '@hooks/useOnyx'; +import usePermissions from '@hooks/usePermissions'; import usePolicy from '@hooks/usePolicy'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useTheme from '@hooks/useTheme'; @@ -99,6 +100,7 @@ function IOURequestStepScan({ // eslint-disable-next-line rulesdir/prefer-shouldUseNarrowLayout-instead-of-isSmallScreenWidth const {isSmallScreenWidth} = useResponsiveLayout(); const {translate} = useLocalize(); + const {isBetaEnabled} = usePermissions(); const {isDraggingOver} = useContext(DragAndDropContext); const [cameraPermissionState, setCameraPermissionState] = useState('prompt'); const [isFlashLightOn, toggleFlashlight] = useReducer((state) => !state, false); @@ -121,6 +123,7 @@ function IOURequestStepScan({ const canUseMultiScan = !isEditing && iouType !== CONST.IOU.TYPE.SPLIT && !backTo && !backToReport; const isReplacingReceipt = (isEditing && hasReceipt(initialTransaction)) || (!!initialTransaction?.receipt && !!backTo); const {shouldStartLocationPermissionFlow} = useIOUUtils(); + const shouldGenerateTransactionThreadReport = !isBetaEnabled(CONST.BETAS.NO_OPTIMISTIC_TRANSACTION_THREADS); const [optimisticTransactions] = useOnyx(ONYXKEYS.COLLECTION.TRANSACTION_DRAFT, { selector: (items) => Object.values(items ?? {}), @@ -397,11 +400,12 @@ function IOURequestStepScan({ }, shouldHandleNavigation: index === files.length - 1, backToReport, + shouldGenerateTransactionThreadReport, }); } }); }, - [backToReport, currentUserPersonalDetails.accountID, currentUserPersonalDetails.login, iouType, report, transactions], + [backToReport, currentUserPersonalDetails.accountID, currentUserPersonalDetails.login, iouType, report, transactions, shouldGenerateTransactionThreadReport], ); const navigateToConfirmationStep = useCallback( diff --git a/tests/actions/IOUTest.ts b/tests/actions/IOUTest.ts index 87853a882291..50cbf641ac52 100644 --- a/tests/actions/IOUTest.ts +++ b/tests/actions/IOUTest.ts @@ -664,6 +664,7 @@ describe('actions/IOU', () => { merchant, comment, }, + shouldGenerateTransactionThreadReport: true, }); return waitForBatchedUpdates() .then( @@ -894,6 +895,7 @@ describe('actions/IOU', () => { merchant: '', comment, }, + shouldGenerateTransactionThreadReport: true, }); return waitForBatchedUpdates(); }) @@ -1113,6 +1115,7 @@ describe('actions/IOU', () => { merchant: '', comment, }, + shouldGenerateTransactionThreadReport: true, }); } return waitForBatchedUpdates(); @@ -1266,6 +1269,7 @@ describe('actions/IOU', () => { merchant: '', comment, }, + shouldGenerateTransactionThreadReport: true, }); return ( waitForBatchedUpdates() @@ -1596,6 +1600,7 @@ describe('actions/IOU', () => { merchant: '', comment: '', }, + shouldGenerateTransactionThreadReport: true, }); expect(notifyNewAction).toHaveBeenCalledTimes(0); }); @@ -1616,6 +1621,7 @@ describe('actions/IOU', () => { merchant: '', comment: '', }, + shouldGenerateTransactionThreadReport: true, }); expect(Navigation.setNavigationActionToMicrotaskQueue).toHaveBeenCalledTimes(1); }); @@ -2518,6 +2524,7 @@ describe('actions/IOU', () => { merchant: '', comment, }, + shouldGenerateTransactionThreadReport: true, }); return waitForBatchedUpdates() .then( @@ -2755,6 +2762,7 @@ describe('actions/IOU', () => { merchant, comment, }, + shouldGenerateTransactionThreadReport: true, }); } return waitForBatchedUpdates(); @@ -2887,6 +2895,7 @@ describe('actions/IOU', () => { merchant, comment, }, + shouldGenerateTransactionThreadReport: true, }); } return waitForBatchedUpdates(); @@ -3111,6 +3120,7 @@ describe('actions/IOU', () => { merchant, comment, }, + shouldGenerateTransactionThreadReport: true, }); } return waitForBatchedUpdates(); @@ -3210,6 +3220,7 @@ describe('actions/IOU', () => { merchant: '', comment, }, + shouldGenerateTransactionThreadReport: true, }); await waitForBatchedUpdates(); @@ -3430,6 +3441,7 @@ describe('actions/IOU', () => { merchant: '', comment, }, + shouldGenerateTransactionThreadReport: true, }); await waitForBatchedUpdates(); @@ -3953,6 +3965,7 @@ describe('actions/IOU', () => { merchant: '', comment: comment2, }, + shouldGenerateTransactionThreadReport: true, }); } @@ -4011,6 +4024,7 @@ describe('actions/IOU', () => { merchant: '', comment, }, + shouldGenerateTransactionThreadReport: true, }); await waitForBatchedUpdates(); @@ -4160,6 +4174,7 @@ describe('actions/IOU', () => { merchant, comment, }, + shouldGenerateTransactionThreadReport: true, }); } return waitForBatchedUpdates(); @@ -4274,6 +4289,7 @@ describe('actions/IOU', () => { merchant, comment, }, + shouldGenerateTransactionThreadReport: true, }); } return waitForBatchedUpdates(); @@ -4445,6 +4461,7 @@ describe('actions/IOU', () => { merchant, comment, }, + shouldGenerateTransactionThreadReport: true, }); } return waitForBatchedUpdates(); @@ -5324,6 +5341,7 @@ describe('actions/IOU', () => { actionableWhisperReportActionID: '1', linkedTrackedExpenseReportID: '1', }, + shouldGenerateTransactionThreadReport: true, }); await waitForBatchedUpdates(); @@ -6037,6 +6055,7 @@ describe('actions/IOU', () => { merchant, comment, }, + shouldGenerateTransactionThreadReport: true, }); } await waitForBatchedUpdates(); @@ -6121,6 +6140,7 @@ describe('actions/IOU', () => { merchant, comment, }, + shouldGenerateTransactionThreadReport: true, }); } await waitForBatchedUpdates(); @@ -6596,6 +6616,7 @@ describe('actions/IOU', () => { merchant: 'NASDAQ', comment: '*hey* `hey`', }, + shouldGenerateTransactionThreadReport: true, }); await waitForBatchedUpdates(); await getOnyxData({ From d459765d8adfbb6e1a4ddf92aef8a8c55728e444 Mon Sep 17 00:00:00 2001 From: VickyStash Date: Fri, 8 Aug 2025 09:16:32 +0200 Subject: [PATCH 2/2] Apply feedback --- src/libs/ReportUtils.ts | 11 ++++------- src/libs/actions/IOU.ts | 20 ++++---------------- 2 files changed, 8 insertions(+), 23 deletions(-) diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 5ea2f3f33a0f..f4dbff3d85e8 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -656,8 +656,8 @@ type BaseOptimisticMoneyRequestEntities = { }; type OptimisticMoneyRequestEntities = BaseOptimisticMoneyRequestEntities & {shouldGenerateTransactionThreadReport?: boolean}; -type OptimisticMoneyRequestEntitiesWithTransactionThreadFlag = BaseOptimisticMoneyRequestEntities & {shouldGenerateTransactionThreadReport: true}; -type OptimisticMoneyRequestEntitiesWithoutTransactionThreadFlag = BaseOptimisticMoneyRequestEntities & {shouldGenerateTransactionThreadReport: false}; +type OptimisticMoneyRequestEntitiesWithTransactionThreadFlag = BaseOptimisticMoneyRequestEntities & {shouldGenerateTransactionThreadReport: boolean}; +type OptimisticMoneyRequestEntitiesWithoutTransactionThreadFlag = BaseOptimisticMoneyRequestEntities; type OptimisticTaskReport = SetRequired< Pick< @@ -7826,12 +7826,9 @@ function buildTransactionThread( */ function buildOptimisticMoneyRequestEntities( optimisticMoneyRequestEntities: OptimisticMoneyRequestEntitiesWithoutTransactionThreadFlag, -): [OptimisticCreatedReportAction, OptimisticCreatedReportAction, OptimisticIOUReportAction, undefined, null]; -function buildOptimisticMoneyRequestEntities( - optimisticMoneyRequestEntities: OptimisticMoneyRequestEntitiesWithTransactionThreadFlag, ): [OptimisticCreatedReportAction, OptimisticCreatedReportAction, OptimisticIOUReportAction, OptimisticChatReport, OptimisticCreatedReportAction | null]; function buildOptimisticMoneyRequestEntities( - optimisticMoneyRequestEntities: OptimisticMoneyRequestEntities, + optimisticMoneyRequestEntities: OptimisticMoneyRequestEntitiesWithTransactionThreadFlag, ): [OptimisticCreatedReportAction, OptimisticCreatedReportAction, OptimisticIOUReportAction, OptimisticChatReport | undefined, OptimisticCreatedReportAction | null]; function buildOptimisticMoneyRequestEntities({ iouReport, @@ -7850,7 +7847,7 @@ function buildOptimisticMoneyRequestEntities({ existingTransactionThreadReportID, linkedTrackedExpenseReportAction, optimisticCreatedReportActionID, - shouldGenerateTransactionThreadReport, + shouldGenerateTransactionThreadReport = true, }: OptimisticMoneyRequestEntities): [ OptimisticCreatedReportAction, OptimisticCreatedReportAction, diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index f58854fab855..02243c934013 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -462,7 +462,7 @@ type MoneyRequestInformationParams = { optimisticCreatedReportActionID?: string; optimisticIOUReportID?: string; optimisticReportPreviewActionID?: string; - shouldGenerateTransactionThreadReport: boolean; + shouldGenerateTransactionThreadReport?: boolean; }; type MoneyRequestOptimisticParams = { @@ -501,7 +501,7 @@ type BuildOnyxDataForMoneyRequestParams = { optimisticParams: MoneyRequestOptimisticParams; retryParams?: StartSplitBilActionParams | CreateTrackExpenseParams | RequestMoneyInformation | ReplaceReceipt; participant?: Participant; - shouldGenerateTransactionThreadReport: boolean; + shouldGenerateTransactionThreadReport?: boolean; }; type DistanceRequestTransactionParams = BaseTransactionParams & { @@ -1426,7 +1426,7 @@ function buildOnyxDataForMoneyRequest(moneyRequestParams: BuildOnyxDataForMoneyR optimisticParams, retryParams, participant, - shouldGenerateTransactionThreadReport, + shouldGenerateTransactionThreadReport = true, } = moneyRequestParams; const {policy, policyCategories, policyTagList} = policyParams; const { @@ -3252,7 +3252,6 @@ function getSendInvoiceInformation( payeeEmail: receiver.login ?? '', participants: [receiver], transactionID: optimisticTransaction.transactionID, - shouldGenerateTransactionThreadReport: true, }); // STEP 6: Build Onyx Data @@ -3316,7 +3315,7 @@ function getMoneyRequestInformation(moneyRequestInformation: MoneyRequestInforma optimisticCreatedReportActionID, optimisticIOUReportID, optimisticReportPreviewActionID, - shouldGenerateTransactionThreadReport, + shouldGenerateTransactionThreadReport = true, } = moneyRequestInformation; const {payeeAccountID = userAccountID, payeeEmail = currentUserEmail, participant} = participantParams; const {policy, policyCategories, policyTagList} = policyParams; @@ -3704,7 +3703,6 @@ function getPerDiemExpenseInformation(perDiemExpenseInformation: PerDiemExpenseI payeeEmail, participants: [participant], transactionID: optimisticTransaction.transactionID, - shouldGenerateTransactionThreadReport: true, }); let reportPreviewAction = shouldCreateNewMoneyRequestReport ? null : getReportPreviewAction(chatReport.reportID, iouReport.reportID); @@ -3742,7 +3740,6 @@ function getPerDiemExpenseInformation(perDiemExpenseInformation: PerDiemExpenseI const [optimisticData, successData, failureData] = buildOnyxDataForMoneyRequest({ isNewChatReport, shouldCreateNewMoneyRequestReport, - shouldGenerateTransactionThreadReport: true, policyParams: { policy, policyCategories, @@ -3946,7 +3943,6 @@ function getTrackExpenseInformation(params: GetTrackExpenseInformationParams): T isPersonalTrackingExpense: !shouldUseMoneyReport, existingTransactionThreadReportID: linkedTrackedExpenseReportAction?.childReportID, linkedTrackedExpenseReportAction, - shouldGenerateTransactionThreadReport: true, }); let reportPreviewAction: OnyxInputValue> = null; @@ -5284,7 +5280,6 @@ function convertBulkTrackedExpensesToIOU(transactionIDs: string[], targetReportI moneyRequestReportID: targetReportID, existingTransactionID: transactionID, existingTransaction: transaction, - shouldGenerateTransactionThreadReport: true, }); const convertParams: ConvertTrackedExpenseToRequestParams = { @@ -6542,7 +6537,6 @@ function createSplitsAndOnyxData({ payeeEmail: currentUserEmailForIOUSplit, participants: [participant], transactionID: oneOnOneTransaction.transactionID, - shouldGenerateTransactionThreadReport: true, }); // Add optimistic personal details for new participants @@ -6583,7 +6577,6 @@ function createSplitsAndOnyxData({ const [oneOnOneOptimisticData, oneOnOneSuccessData, oneOnOneFailureData] = buildOnyxDataForMoneyRequest({ isNewChatReport: isNewOneOnOneChatReport, shouldCreateNewMoneyRequestReport: shouldCreateNewOneOnOneIOUReport, - shouldGenerateTransactionThreadReport: true, isOneOnOneSplit: true, optimisticParams: { chat: { @@ -7368,7 +7361,6 @@ function completeSplitBill( payeeEmail: currentUserEmailForIOUSplit, participants: [participant], transactionID: oneOnOneTransaction.transactionID, - shouldGenerateTransactionThreadReport: true, }); let oneOnOneReportPreviewAction = getReportPreviewAction(oneOnOneChatReport?.reportID, oneOnOneIOUReport?.reportID); @@ -7382,7 +7374,6 @@ function completeSplitBill( isNewChatReport: isNewOneOnOneChatReport, isOneOnOneSplit: true, shouldCreateNewMoneyRequestReport: shouldCreateNewOneOnOneIOUReport, - shouldGenerateTransactionThreadReport: true, optimisticParams: { chat: { report: oneOnOneChatReport, @@ -7622,7 +7613,6 @@ function createDistanceRequest(distanceRequestInformation: CreateDistanceRequest reimbursable, attendees, }, - shouldGenerateTransactionThreadReport: true, }); onyxData = moneyRequestOnyxData; @@ -8488,7 +8478,6 @@ function getSendMoneyParams( transactionID: optimisticTransaction.transactionID, paymentType: paymentMethodType, isSendMoneyFlow: true, - shouldGenerateTransactionThreadReport: true, }); const reportPreviewAction = buildOptimisticReportPreview(chatReport, optimisticIOUReport); @@ -12119,7 +12108,6 @@ function saveSplitTransactions(draftTransaction: OnyxEntry