From 12b8750989ca301aebcfbd87a526dc29b07b1e2b Mon Sep 17 00:00:00 2001 From: Samran Ahmed Date: Wed, 1 Apr 2026 02:35:39 +0500 Subject: [PATCH 01/13] Refactor IOURequestStepScan to own multi-scan state in useReceiptScan hook --- .../hooks/useMobileReceiptScan.ts | 4 ++-- .../hooks/useReceiptScan.ts | 7 +++++-- .../request/step/IOURequestStepScan/types.ts | 21 +++---------------- 3 files changed, 10 insertions(+), 22 deletions(-) diff --git a/src/pages/iou/request/step/IOURequestStepScan/hooks/useMobileReceiptScan.ts b/src/pages/iou/request/step/IOURequestStepScan/hooks/useMobileReceiptScan.ts index 0a7240f3bb3be..152a6cb37c610 100644 --- a/src/pages/iou/request/step/IOURequestStepScan/hooks/useMobileReceiptScan.ts +++ b/src/pages/iou/request/step/IOURequestStepScan/hooks/useMobileReceiptScan.ts @@ -19,7 +19,7 @@ function useMobileReceiptScan({ initialTransaction, iouType, isMultiScanEnabled = false, - isStartingScan = false, + isStartingScan, receiptFiles, navigateToConfirmationStep, shouldSkipConfirmation, @@ -78,7 +78,7 @@ function useMobileReceiptScan({ } removeTransactionReceipt(CONST.IOU.OPTIMISTIC_TRANSACTION_ID); removeDraftTransactionsByIDs(draftTransactionIDs, true); - setIsMultiScanEnabled?.(!isMultiScanEnabled); + setIsMultiScanEnabled(!isMultiScanEnabled); } function dismissMultiScanEducationalPopup() { diff --git a/src/pages/iou/request/step/IOURequestStepScan/hooks/useReceiptScan.ts b/src/pages/iou/request/step/IOURequestStepScan/hooks/useReceiptScan.ts index 435a60a97f6a8..fb3ce5c950f8d 100644 --- a/src/pages/iou/request/step/IOURequestStepScan/hooks/useReceiptScan.ts +++ b/src/pages/iou/request/step/IOURequestStepScan/hooks/useReceiptScan.ts @@ -37,8 +37,6 @@ function useReceiptScan({ currentUserPersonalDetails, backTo, backToReport, - isMultiScanEnabled = false, - isStartingScan = false, updateScanAndNavigate, getSource, }: UseReceiptScanParams) { @@ -69,6 +67,8 @@ function useReceiptScan({ const [userBillingGracePeriodEnds] = useOnyx(ONYXKEYS.COLLECTION.SHARED_NVP_PRIVATE_USER_BILLING_GRACE_PERIOD_END); const [ownerBillingGracePeriodEnd] = useOnyx(ONYXKEYS.NVP_PRIVATE_OWNER_BILLING_GRACE_PERIOD_END); const draftTransactionIDs = Object.keys(allTransactionDrafts ?? {}); + const [isMultiScanEnabled, setIsMultiScanEnabled] = useState((transactions ?? []).length > 1); + const isStartingScan = action === CONST.IOU.ACTION.CREATE; const isEditing = action === CONST.IOU.ACTION.EDIT; const isArchived = isArchivedReport(reportNameValuePairs); @@ -232,6 +232,9 @@ function useReceiptScan({ }); return { transactions, + isMultiScanEnabled, + setIsMultiScanEnabled, + isStartingScan, isEditing, isReplacingReceipt, shouldAcceptMultipleFiles, diff --git a/src/pages/iou/request/step/IOURequestStepScan/types.ts b/src/pages/iou/request/step/IOURequestStepScan/types.ts index 280107572e1ca..c60948c15ff50 100644 --- a/src/pages/iou/request/step/IOURequestStepScan/types.ts +++ b/src/pages/iou/request/step/IOURequestStepScan/types.ts @@ -38,12 +38,6 @@ type UseReceiptScanParams = { /** Report ID to navigate back to */ backToReport: string | undefined; - /** Whether multi-scan is enabled */ - isMultiScanEnabled: boolean | undefined; - - /** Whether the user is starting a scan request */ - isStartingScan: boolean | undefined; - /** Callback to replace receipt and navigate back when editing */ updateScanAndNavigate: (file: FileObject, source: string) => void; @@ -62,7 +56,7 @@ type UseMobileReceiptScanParams = { isMultiScanEnabled?: boolean; /** Whether the user is starting a scan request */ - isStartingScan?: boolean; + isStartingScan: boolean; /** The current receipt files being scanned */ receiptFiles: ReceiptFile[]; @@ -76,8 +70,8 @@ type UseMobileReceiptScanParams = { /** Callback to start the location permission flow */ setStartLocationPermissionFlow: (value: boolean) => void; - /** Callback to update multi-scan enabled state in parent */ - setIsMultiScanEnabled: ((value: boolean) => void) | undefined; + /** Callback to update multi-scan enabled state */ + setIsMultiScanEnabled: (value: boolean) => void; }; type IOURequestStepScanProps = WithCurrentUserPersonalDetailsProps & @@ -90,15 +84,6 @@ type IOURequestStepScanProps = WithCurrentUserPersonalDetailsProps & * Receives a function (`setTestReceiptAndNavigate`) as an argument, */ onLayout?: (setTestReceiptAndNavigate: () => void) => void; - - /** If the receipts preview should be shown */ - isMultiScanEnabled?: boolean; - - /** Updates isMultiScanEnabled flag */ - setIsMultiScanEnabled?: (value: boolean) => void; - - /** Indicates whether users start to create scan request */ - isStartingScan?: boolean; }; type ReceiptFile = { From d6e1b9f944b8c25b372b6effe26f0cc5c5c0f95f Mon Sep 17 00:00:00 2001 From: Samran Ahmed Date: Wed, 1 Apr 2026 02:37:02 +0500 Subject: [PATCH 02/13] Remove scan prop and reset scan tab via key remount in RequestStartPage --- src/pages/iou/request/IOURequestStartPage.tsx | 6 +----- .../components/MobileWebCameraView.tsx | 12 ++++++------ .../request/step/IOURequestStepScan/index.native.tsx | 8 +++----- .../iou/request/step/IOURequestStepScan/index.tsx | 10 ++++------ 4 files changed, 14 insertions(+), 22 deletions(-) diff --git a/src/pages/iou/request/IOURequestStartPage.tsx b/src/pages/iou/request/IOURequestStartPage.tsx index e756308f32da5..56201a6ee296b 100644 --- a/src/pages/iou/request/IOURequestStartPage.tsx +++ b/src/pages/iou/request/IOURequestStartPage.tsx @@ -97,7 +97,6 @@ function IOURequestStartPage({ }); const [lastSelectedDistanceRates] = useOnyx(ONYXKEYS.NVP_LAST_SELECTED_DISTANCE_RATES); - const [isMultiScanEnabled, setIsMultiScanEnabled] = useState(false); const [currentDate] = useOnyx(ONYXKEYS.CURRENT_DATE); const {isOffline} = useNetwork(); const [hasUserSubmittedExpenseOrScannedReceipt] = useOnyx(ONYXKEYS.NVP_DISMISSED_PRODUCT_TRAINING, {selector: isTestReceiptTooltipDismissedSelector}); @@ -186,7 +185,6 @@ function IOURequestStartPage({ if (transaction?.iouRequestType === newIOUType) { return; } - setIsMultiScanEnabled(false); initMoneyRequest({ reportID, policy, @@ -340,14 +338,12 @@ function IOURequestStartPage({ {() => ( { setTestReceiptAndNavigateRef.current = setTestReceiptAndNavigate; }} - isMultiScanEnabled={isMultiScanEnabled} - setIsMultiScanEnabled={setIsMultiScanEnabled} - isStartingScan /> )} diff --git a/src/pages/iou/request/step/IOURequestStepScan/components/MobileWebCameraView.tsx b/src/pages/iou/request/step/IOURequestStepScan/components/MobileWebCameraView.tsx index c829e9d9572e7..665005aa16476 100644 --- a/src/pages/iou/request/step/IOURequestStepScan/components/MobileWebCameraView.tsx +++ b/src/pages/iou/request/step/IOURequestStepScan/components/MobileWebCameraView.tsx @@ -43,10 +43,9 @@ type MobileWebCameraViewProps = { iouType: IOUType; currentUserPersonalDetails: CurrentUserPersonalDetails; reportID: string; - isMultiScanEnabled?: boolean; - isStartingScan?: boolean; + isStartingScan: boolean; updateScanAndNavigate: (file: FileObject, source: string) => void; - setIsMultiScanEnabled?: (value: boolean) => void; + setIsMultiScanEnabled: (value: boolean) => void; PDFValidationComponent: React.ReactNode; shouldAcceptMultipleFiles: boolean; receiptFiles: ReceiptFile[]; @@ -56,9 +55,10 @@ type MobileWebCameraViewProps = { navigateToConfirmationStep: (files: ReceiptFile[], locationPermissionGranted?: boolean, isTestTransaction?: boolean) => void; shouldSkipConfirmation: boolean; setStartLocationPermissionFlow: (value: boolean) => void; - onLayout?: () => void; onBackButtonPress: () => void; shouldShowWrapper: boolean; + isMultiScanEnabled?: boolean; + onLayout?: () => void; }; /** @@ -103,7 +103,6 @@ function MobileWebCameraView({ iouType, currentUserPersonalDetails, reportID, - isMultiScanEnabled = false, isStartingScan, updateScanAndNavigate, setIsMultiScanEnabled, @@ -116,9 +115,10 @@ function MobileWebCameraView({ navigateToConfirmationStep, shouldSkipConfirmation, setStartLocationPermissionFlow, - onLayout, onBackButtonPress, shouldShowWrapper, + isMultiScanEnabled = false, + onLayout, }: MobileWebCameraViewProps) { const {blinkStyle, canUseMultiScan, shouldShowMultiScanEducationalPopup, showBlink, toggleMultiScan, dismissMultiScanEducationalPopup, submitReceipts, submitMultiScanReceipts} = useMobileReceiptScan({ diff --git a/src/pages/iou/request/step/IOURequestStepScan/index.native.tsx b/src/pages/iou/request/step/IOURequestStepScan/index.native.tsx index 2c70bc91da24a..6ed6dc8707bfa 100644 --- a/src/pages/iou/request/step/IOURequestStepScan/index.native.tsx +++ b/src/pages/iou/request/step/IOURequestStepScan/index.native.tsx @@ -64,9 +64,6 @@ function IOURequestStepScan({ transaction: initialTransaction, currentUserPersonalDetails, onLayout, - isMultiScanEnabled = false, - isStartingScan = false, - setIsMultiScanEnabled, }: IOURequestStepScanProps) { const theme = useTheme(); const styles = useThemeStyles(); @@ -288,6 +285,9 @@ function IOURequestStepScan({ const getSource = useCallback((file: FileObject) => file.uri ?? '', []); const { + isMultiScanEnabled, + setIsMultiScanEnabled, + isStartingScan, isEditing, shouldAcceptMultipleFiles, shouldSkipConfirmation, @@ -310,8 +310,6 @@ function IOURequestStepScan({ currentUserPersonalDetails, backTo, backToReport, - isMultiScanEnabled, - isStartingScan, updateScanAndNavigate, getSource, }); diff --git a/src/pages/iou/request/step/IOURequestStepScan/index.tsx b/src/pages/iou/request/step/IOURequestStepScan/index.tsx index a3d87108e32c9..bc2243240b544 100644 --- a/src/pages/iou/request/step/IOURequestStepScan/index.tsx +++ b/src/pages/iou/request/step/IOURequestStepScan/index.tsx @@ -32,9 +32,6 @@ function IOURequestStepScan({ transaction: initialTransaction, currentUserPersonalDetails, onLayout, - isMultiScanEnabled = false, - isStartingScan = false, - setIsMultiScanEnabled, }: Omit) { const isMobileWeb = isMobile(); const policy = usePolicy(report?.policyID); @@ -62,6 +59,9 @@ function IOURequestStepScan({ const { transactions, + isMultiScanEnabled, + setIsMultiScanEnabled, + isStartingScan, isEditing, isReplacingReceipt, shouldAcceptMultipleFiles, @@ -85,8 +85,6 @@ function IOURequestStepScan({ currentUserPersonalDetails, backTo, backToReport, - isMultiScanEnabled, - isStartingScan, updateScanAndNavigate, getSource, }); @@ -127,7 +125,7 @@ function IOURequestStepScan({ if (isAllScanFilesCanBeRead) { return; } - setIsMultiScanEnabled?.(false); + setIsMultiScanEnabled(false); removeTransactionReceipt(CONST.IOU.OPTIMISTIC_TRANSACTION_ID); removeDraftTransactionsByIDs(draftTransactionIDs, true); }); From 3e3cb98534d513665c076c76027c2da35bf700e7 Mon Sep 17 00:00:00 2001 From: Samran Ahmed Date: Wed, 1 Apr 2026 02:55:14 +0500 Subject: [PATCH 03/13] Update IOURequestStepScan tests for hook-owned multi-scan behavior --- tests/ui/IOURequestStepScanTest.tsx | 10 +++++--- tests/unit/hooks/useReceiptScan.test.ts | 32 ++++++++++++++++++------- 2 files changed, 30 insertions(+), 12 deletions(-) diff --git a/tests/ui/IOURequestStepScanTest.tsx b/tests/ui/IOURequestStepScanTest.tsx index e531a8029e64a..101cf7c6c2bb5 100644 --- a/tests/ui/IOURequestStepScanTest.tsx +++ b/tests/ui/IOURequestStepScanTest.tsx @@ -171,15 +171,22 @@ describe('IOURequestStepScan', () => { const REPORT_ID = '1'; const POLICY_ID = 'policy-1'; const TRANSACTION_ID_1 = '101'; + const TRANSACTION_ID_2 = '102'; const transaction1 = createRandomTransaction(1); transaction1.reportID = REPORT_ID; transaction1.transactionID = TRANSACTION_ID_1; transaction1.receipt = {source: 'file://first-receipt.png', state: CONST.IOU.RECEIPT_STATE.OPEN}; + const transaction2 = createRandomTransaction(2); + transaction2.reportID = REPORT_ID; + transaction2.transactionID = TRANSACTION_ID_2; + transaction2.receipt = {source: 'file://second-receipt.png', state: CONST.IOU.RECEIPT_STATE.OPEN}; + await act(async () => { await Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT}${REPORT_ID}`, createMinimalReport(REPORT_ID, POLICY_ID)); await Onyx.merge(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${TRANSACTION_ID_1}`, transaction1); + await Onyx.merge(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${TRANSACTION_ID_2}`, transaction2); }); await waitForBatchedUpdates(); @@ -202,9 +209,6 @@ describe('IOURequestStepScan', () => { } as unknown as PlatformStackScreenProps['route'] } navigation={{} as never} - isMultiScanEnabled - isStartingScan - setIsMultiScanEnabled={jest.fn()} /> diff --git a/tests/unit/hooks/useReceiptScan.test.ts b/tests/unit/hooks/useReceiptScan.test.ts index 6acc3be489b9f..8d83e35d81bf4 100644 --- a/tests/unit/hooks/useReceiptScan.test.ts +++ b/tests/unit/hooks/useReceiptScan.test.ts @@ -62,8 +62,6 @@ function createDefaultParams(): Parameters[0] { getSource: (file: {uri?: string}) => file?.uri ?? 'file://image.png', backTo: undefined, backToReport: undefined, - isMultiScanEnabled: false, - isStartingScan: true, }; } @@ -298,9 +296,9 @@ describe('useReceiptScan', () => { }); it('should clear receiptFiles when isMultiScanEnabled changes from true to false', async () => { - const multiScanParams = {...params, isMultiScanEnabled: true}; - const {result, rerender} = renderHook((p: Parameters[0]) => useReceiptScan(p), { - initialProps: multiScanParams, + const {result} = renderHook(() => useReceiptScan(params)); + await act(async () => { + result.current.setIsMultiScanEnabled(true); }); await waitForBatchedUpdatesWithAct(); @@ -311,7 +309,9 @@ describe('useReceiptScan', () => { await waitForBatchedUpdatesWithAct(); expect(result.current.receiptFiles).toHaveLength(1); - rerender({...multiScanParams, isMultiScanEnabled: false}); + await act(async () => { + result.current.setIsMultiScanEnabled(false); + }); await waitForBatchedUpdatesWithAct(); expect(result.current.receiptFiles).toEqual([]); }); @@ -382,6 +382,11 @@ describe('useReceiptScan', () => { const {result} = renderHook(() => useReceiptScan(params)); await waitForBatchedUpdatesWithAct(); + await act(async () => { + result.current.setIsMultiScanEnabled(false); + }); + await waitForBatchedUpdatesWithAct(); + const files = [{uri: 'file://receipt.jpg', name: 'receipt.jpg', type: 'image/jpeg'}]; await act(async () => { result.current.validateFiles(files); @@ -407,8 +412,12 @@ describe('useReceiptScan', () => { }); it('should not call removeDraftTransactionsByIDs when multi-scan is enabled', async () => { - const multiScanParams = {...params, isMultiScanEnabled: true, setIsMultiScanEnabled: jest.fn()}; - const {result} = renderHook(() => useReceiptScan(multiScanParams)); + const {result} = renderHook(() => useReceiptScan(params)); + await waitForBatchedUpdatesWithAct(); + + await act(async () => { + result.current.setIsMultiScanEnabled(true); + }); await waitForBatchedUpdatesWithAct(); const files = [{uri: 'file://receipt.jpg', name: 'receipt.jpg', type: 'image/jpeg'}]; @@ -420,7 +429,7 @@ describe('useReceiptScan', () => { }); it('should not call removeDraftTransactionsByIDs when isStartingScan is false', async () => { - const nonStartingParams = {...params, isStartingScan: false}; + const nonStartingParams = {...params, action: CONST.IOU.ACTION.SUBMIT}; const {result} = renderHook(() => useReceiptScan(nonStartingParams)); await waitForBatchedUpdatesWithAct(); @@ -443,6 +452,11 @@ describe('useReceiptScan', () => { const {result} = renderHook(() => useReceiptScan(params)); await waitForBatchedUpdatesWithAct(); + await act(async () => { + result.current.setIsMultiScanEnabled(false); + }); + await waitForBatchedUpdatesWithAct(); + const files = [{uri: 'file://receipt.jpg', name: 'receipt.jpg', type: 'image/jpeg'}]; await act(async () => { result.current.validateFiles(files); From d3f7a875d53ba5b0530b7ca82cd74b54ac43fcdc Mon Sep 17 00:00:00 2001 From: Samran Ahmed Date: Wed, 1 Apr 2026 03:42:04 +0500 Subject: [PATCH 04/13] Improve multi-scan state management in useReceiptScan --- src/pages/iou/request/IOURequestStartPage.tsx | 2 +- .../request/step/IOURequestStepScan/hooks/useReceiptScan.ts | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/pages/iou/request/IOURequestStartPage.tsx b/src/pages/iou/request/IOURequestStartPage.tsx index 56201a6ee296b..d69e6faa732e8 100644 --- a/src/pages/iou/request/IOURequestStartPage.tsx +++ b/src/pages/iou/request/IOURequestStartPage.tsx @@ -338,7 +338,7 @@ function IOURequestStartPage({ {() => ( { diff --git a/src/pages/iou/request/step/IOURequestStepScan/hooks/useReceiptScan.ts b/src/pages/iou/request/step/IOURequestStepScan/hooks/useReceiptScan.ts index fb3ce5c950f8d..892d1996872e4 100644 --- a/src/pages/iou/request/step/IOURequestStepScan/hooks/useReceiptScan.ts +++ b/src/pages/iou/request/step/IOURequestStepScan/hooks/useReceiptScan.ts @@ -67,7 +67,9 @@ function useReceiptScan({ const [userBillingGracePeriodEnds] = useOnyx(ONYXKEYS.COLLECTION.SHARED_NVP_PRIVATE_USER_BILLING_GRACE_PERIOD_END); const [ownerBillingGracePeriodEnd] = useOnyx(ONYXKEYS.NVP_PRIVATE_OWNER_BILLING_GRACE_PERIOD_END); const draftTransactionIDs = Object.keys(allTransactionDrafts ?? {}); - const [isMultiScanEnabled, setIsMultiScanEnabled] = useState((transactions ?? []).length > 1); + const [userSelectedMultiScanEnabled, setUserSelectedMultiScanEnabled] = useState(); + const isMultiScanEnabled = userSelectedMultiScanEnabled ?? (transactions ?? []).length > 1; + const setIsMultiScanEnabled = setUserSelectedMultiScanEnabled; const isStartingScan = action === CONST.IOU.ACTION.CREATE; const isEditing = action === CONST.IOU.ACTION.EDIT; From 598b3e3ff2a6036ea075a82aace4b4e94cab344f Mon Sep 17 00:00:00 2001 From: Samran Ahmed Date: Wed, 1 Apr 2026 03:42:15 +0500 Subject: [PATCH 05/13] lint --- .../step/IOURequestStepScan/components/MobileWebCameraView.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/iou/request/step/IOURequestStepScan/components/MobileWebCameraView.tsx b/src/pages/iou/request/step/IOURequestStepScan/components/MobileWebCameraView.tsx index 665005aa16476..65e1934cd7fee 100644 --- a/src/pages/iou/request/step/IOURequestStepScan/components/MobileWebCameraView.tsx +++ b/src/pages/iou/request/step/IOURequestStepScan/components/MobileWebCameraView.tsx @@ -444,7 +444,7 @@ function MobileWebCameraView({ ) : null} )} From 45580b7e9d7f20929d406fb28555be4bd474c0d2 Mon Sep 17 00:00:00 2001 From: Samran Ahmed Date: Thu, 2 Apr 2026 22:04:38 +0500 Subject: [PATCH 06/13] Refactor isMultiScanEnabled to use useState(false) --- .../request/step/IOURequestStepScan/hooks/useReceiptScan.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/pages/iou/request/step/IOURequestStepScan/hooks/useReceiptScan.ts b/src/pages/iou/request/step/IOURequestStepScan/hooks/useReceiptScan.ts index 892d1996872e4..9695e55e5032c 100644 --- a/src/pages/iou/request/step/IOURequestStepScan/hooks/useReceiptScan.ts +++ b/src/pages/iou/request/step/IOURequestStepScan/hooks/useReceiptScan.ts @@ -67,9 +67,7 @@ function useReceiptScan({ const [userBillingGracePeriodEnds] = useOnyx(ONYXKEYS.COLLECTION.SHARED_NVP_PRIVATE_USER_BILLING_GRACE_PERIOD_END); const [ownerBillingGracePeriodEnd] = useOnyx(ONYXKEYS.NVP_PRIVATE_OWNER_BILLING_GRACE_PERIOD_END); const draftTransactionIDs = Object.keys(allTransactionDrafts ?? {}); - const [userSelectedMultiScanEnabled, setUserSelectedMultiScanEnabled] = useState(); - const isMultiScanEnabled = userSelectedMultiScanEnabled ?? (transactions ?? []).length > 1; - const setIsMultiScanEnabled = setUserSelectedMultiScanEnabled; + const [isMultiScanEnabled, setIsMultiScanEnabled] = useState(false); const isStartingScan = action === CONST.IOU.ACTION.CREATE; const isEditing = action === CONST.IOU.ACTION.EDIT; From 6985a3fb73dc95abbb49aff73124d30a59edb772 Mon Sep 17 00:00:00 2001 From: Samran Ahmed Date: Thu, 2 Apr 2026 22:33:21 +0500 Subject: [PATCH 07/13] Add setReceiptFiles callback to clear receipt files and remove useEffect --- src/pages/iou/request/IOURequestStartPage.tsx | 2 +- .../components/MobileWebCameraView.tsx | 1 + .../IOURequestStepScan/hooks/useMobileReceiptScan.ts | 4 ++++ .../step/IOURequestStepScan/hooks/useReceiptScan.ts | 11 +---------- .../request/step/IOURequestStepScan/index.native.tsx | 1 + .../iou/request/step/IOURequestStepScan/types.ts | 3 +++ 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/pages/iou/request/IOURequestStartPage.tsx b/src/pages/iou/request/IOURequestStartPage.tsx index d69e6faa732e8..97b87d2885506 100644 --- a/src/pages/iou/request/IOURequestStartPage.tsx +++ b/src/pages/iou/request/IOURequestStartPage.tsx @@ -338,7 +338,7 @@ function IOURequestStartPage({ {() => ( { diff --git a/src/pages/iou/request/step/IOURequestStepScan/components/MobileWebCameraView.tsx b/src/pages/iou/request/step/IOURequestStepScan/components/MobileWebCameraView.tsx index 65e1934cd7fee..1f8ea45b4f445 100644 --- a/src/pages/iou/request/step/IOURequestStepScan/components/MobileWebCameraView.tsx +++ b/src/pages/iou/request/step/IOURequestStepScan/components/MobileWebCameraView.tsx @@ -131,6 +131,7 @@ function MobileWebCameraView({ shouldSkipConfirmation, setStartLocationPermissionFlow, setIsMultiScanEnabled, + setReceiptFiles, }); const theme = useTheme(); const styles = useThemeStyles(); diff --git a/src/pages/iou/request/step/IOURequestStepScan/hooks/useMobileReceiptScan.ts b/src/pages/iou/request/step/IOURequestStepScan/hooks/useMobileReceiptScan.ts index 152a6cb37c610..aa89b94faa713 100644 --- a/src/pages/iou/request/step/IOURequestStepScan/hooks/useMobileReceiptScan.ts +++ b/src/pages/iou/request/step/IOURequestStepScan/hooks/useMobileReceiptScan.ts @@ -25,6 +25,7 @@ function useMobileReceiptScan({ shouldSkipConfirmation, setStartLocationPermissionFlow, setIsMultiScanEnabled, + setReceiptFiles, }: UseMobileReceiptScanParams) { const [shouldStartLocationPermissionFlow] = useOnyx(ONYXKEYS.NVP_LAST_LOCATION_PERMISSION_PROMPT, { selector: shouldStartLocationPermissionFlowSelector, @@ -78,6 +79,9 @@ function useMobileReceiptScan({ } removeTransactionReceipt(CONST.IOU.OPTIMISTIC_TRANSACTION_ID); removeDraftTransactionsByIDs(draftTransactionIDs, true); + if (isMultiScanEnabled) { + setReceiptFiles([]); + } setIsMultiScanEnabled(!isMultiScanEnabled); } diff --git a/src/pages/iou/request/step/IOURequestStepScan/hooks/useReceiptScan.ts b/src/pages/iou/request/step/IOURequestStepScan/hooks/useReceiptScan.ts index 9695e55e5032c..38ff9f3a1a7a9 100644 --- a/src/pages/iou/request/step/IOURequestStepScan/hooks/useReceiptScan.ts +++ b/src/pages/iou/request/step/IOURequestStepScan/hooks/useReceiptScan.ts @@ -1,6 +1,6 @@ import shouldStartLocationPermissionFlowSelector from '@selectors/LocationPermission'; import {hasSeenTourSelector} from '@selectors/Onboarding'; -import {useEffect, useMemo, useState} from 'react'; +import {useMemo, useState} from 'react'; import TestReceipt from '@assets/images/fake-receipt.png'; import useDefaultExpensePolicy from '@hooks/useDefaultExpensePolicy'; import useFilesValidation from '@hooks/useFilesValidation'; @@ -90,15 +90,6 @@ function useReceiptScan({ const [startLocationPermissionFlow, setStartLocationPermissionFlow] = useState(false); const [receiptFiles, setReceiptFiles] = useState([]); - // Clear receipt files when multi-scan is disabled - useEffect(() => { - if (isMultiScanEnabled) { - return; - } - // eslint-disable-next-line react-hooks/set-state-in-effect - setReceiptFiles([]); - }, [isMultiScanEnabled]); - const [recentWaypoints] = useOnyx(ONYXKEYS.NVP_RECENT_WAYPOINTS); const participants = useMemo( diff --git a/src/pages/iou/request/step/IOURequestStepScan/index.native.tsx b/src/pages/iou/request/step/IOURequestStepScan/index.native.tsx index 6ed6dc8707bfa..66b5b5b3c62b0 100644 --- a/src/pages/iou/request/step/IOURequestStepScan/index.native.tsx +++ b/src/pages/iou/request/step/IOURequestStepScan/index.native.tsx @@ -325,6 +325,7 @@ function IOURequestStepScan({ shouldSkipConfirmation, setStartLocationPermissionFlow, setIsMultiScanEnabled, + setReceiptFiles, }); const maybeCancelShutterSpan = useCallback(() => { diff --git a/src/pages/iou/request/step/IOURequestStepScan/types.ts b/src/pages/iou/request/step/IOURequestStepScan/types.ts index c60948c15ff50..6772c8792729e 100644 --- a/src/pages/iou/request/step/IOURequestStepScan/types.ts +++ b/src/pages/iou/request/step/IOURequestStepScan/types.ts @@ -72,6 +72,9 @@ type UseMobileReceiptScanParams = { /** Callback to update multi-scan enabled state */ setIsMultiScanEnabled: (value: boolean) => void; + + /** Callback to update scanned receipt files */ + setReceiptFiles: (value: ReceiptFile[]) => void; }; type IOURequestStepScanProps = WithCurrentUserPersonalDetailsProps & From 0eaa2c551c036daea2cf5f2417e851f54ec8684a Mon Sep 17 00:00:00 2001 From: Samran Ahmed Date: Thu, 2 Apr 2026 22:36:47 +0500 Subject: [PATCH 08/13] Add toggleMultiScan tests for receiptFiles reset --- tests/unit/hooks/useMobileReceiptScan.test.ts | 31 +++++++++++++++++++ tests/unit/hooks/useReceiptScan.test.ts | 4 +-- 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/tests/unit/hooks/useMobileReceiptScan.test.ts b/tests/unit/hooks/useMobileReceiptScan.test.ts index 12b46d41b4a0e..a278b1e1d20ea 100644 --- a/tests/unit/hooks/useMobileReceiptScan.test.ts +++ b/tests/unit/hooks/useMobileReceiptScan.test.ts @@ -37,6 +37,7 @@ function createDefaultParams(): UseMobileReceiptScanParams { shouldSkipConfirmation: false, setStartLocationPermissionFlow: jest.fn(), setIsMultiScanEnabled: jest.fn(), + setReceiptFiles: jest.fn(), }; } @@ -129,6 +130,36 @@ describe('useMobileReceiptScan', () => { expect(mockRemoveTransactionReceipt).toHaveBeenCalledWith(CONST.IOU.OPTIMISTIC_TRANSACTION_ID); expect(mockRemoveDraftTransactions).toHaveBeenCalledWith(expect.anything(), true); }); + + it('should clear receiptFiles when disabling multi-scan', async () => { + const setIsMultiScanEnabled = jest.fn(); + const setReceiptFiles = jest.fn(); + const toggleParams = {...params, setIsMultiScanEnabled, setReceiptFiles, isMultiScanEnabled: true}; + const {result} = renderHook(() => useMobileReceiptScan(toggleParams)); + await waitForBatchedUpdatesWithAct(); + + await act(async () => { + result.current.toggleMultiScan(); + }); + + expect(setReceiptFiles).toHaveBeenCalledWith([]); + expect(setIsMultiScanEnabled).toHaveBeenCalledWith(false); + }); + + it('should not clear receiptFiles when enabling multi-scan', async () => { + const setIsMultiScanEnabled = jest.fn(); + const setReceiptFiles = jest.fn(); + const toggleParams = {...params, setIsMultiScanEnabled, setReceiptFiles, isMultiScanEnabled: false}; + const {result} = renderHook(() => useMobileReceiptScan(toggleParams)); + await waitForBatchedUpdatesWithAct(); + + await act(async () => { + result.current.toggleMultiScan(); + }); + + expect(setReceiptFiles).not.toHaveBeenCalled(); + expect(setIsMultiScanEnabled).toHaveBeenCalledWith(true); + }); }); describe('dismissMultiScanEducationalPopup', () => { diff --git a/tests/unit/hooks/useReceiptScan.test.ts b/tests/unit/hooks/useReceiptScan.test.ts index 8d83e35d81bf4..b5f2f5dec8d29 100644 --- a/tests/unit/hooks/useReceiptScan.test.ts +++ b/tests/unit/hooks/useReceiptScan.test.ts @@ -295,7 +295,7 @@ describe('useReceiptScan', () => { expect(result.current.receiptFiles.at(0)).toEqual(receiptFile); }); - it('should clear receiptFiles when isMultiScanEnabled changes from true to false', async () => { + it('should not clear receiptFiles when isMultiScanEnabled changes from true to false', async () => { const {result} = renderHook(() => useReceiptScan(params)); await act(async () => { result.current.setIsMultiScanEnabled(true); @@ -313,7 +313,7 @@ describe('useReceiptScan', () => { result.current.setIsMultiScanEnabled(false); }); await waitForBatchedUpdatesWithAct(); - expect(result.current.receiptFiles).toEqual([]); + expect(result.current.receiptFiles).toEqual([receiptFile]); }); }); From a7ef9687c925ea0490f0b03db50d47bd92be7863 Mon Sep 17 00:00:00 2001 From: Samran Ahmed Date: Fri, 3 Apr 2026 04:49:19 +0500 Subject: [PATCH 09/13] update test case --- .../request/step/IOURequestStepScan/hooks/useReceiptScan.ts | 2 +- tests/ui/IOURequestStepScanTest.tsx | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/pages/iou/request/step/IOURequestStepScan/hooks/useReceiptScan.ts b/src/pages/iou/request/step/IOURequestStepScan/hooks/useReceiptScan.ts index 38ff9f3a1a7a9..3f9a246c85955 100644 --- a/src/pages/iou/request/step/IOURequestStepScan/hooks/useReceiptScan.ts +++ b/src/pages/iou/request/step/IOURequestStepScan/hooks/useReceiptScan.ts @@ -68,11 +68,11 @@ function useReceiptScan({ const [ownerBillingGracePeriodEnd] = useOnyx(ONYXKEYS.NVP_PRIVATE_OWNER_BILLING_GRACE_PERIOD_END); const draftTransactionIDs = Object.keys(allTransactionDrafts ?? {}); const [isMultiScanEnabled, setIsMultiScanEnabled] = useState(false); - const isStartingScan = action === CONST.IOU.ACTION.CREATE; const isEditing = action === CONST.IOU.ACTION.EDIT; const isArchived = isArchivedReport(reportNameValuePairs); const isReplacingReceipt = (isEditing && hasReceipt(initialTransaction)) || (!!initialTransaction?.receipt && !!backTo); + const isStartingScan = action === CONST.IOU.ACTION.CREATE && !isReplacingReceipt; const shouldAcceptMultipleFiles = !isEditing && !backTo; const shouldGenerateTransactionThreadReport = !isBetaEnabled(CONST.BETAS.NO_OPTIMISTIC_TRANSACTION_THREADS); const isASAPSubmitBetaEnabled = isBetaEnabled(CONST.BETAS.ASAP_SUBMIT); diff --git a/tests/ui/IOURequestStepScanTest.tsx b/tests/ui/IOURequestStepScanTest.tsx index 101cf7c6c2bb5..75b4b29c97d16 100644 --- a/tests/ui/IOURequestStepScanTest.tsx +++ b/tests/ui/IOURequestStepScanTest.tsx @@ -167,7 +167,7 @@ describe('IOURequestStepScan', () => { expect(tx2After?.receipt?.source).toBe('file://receipt2.png'); }); - it('multi-scan mode preserves first receipt when adding second receipt', async () => { + it('adding a second receipt replaces the existing draft receipt when isMultiScanEnabled is false', async () => { const REPORT_ID = '1'; const POLICY_ID = 'policy-1'; const TRANSACTION_ID_1 = '101'; @@ -230,6 +230,6 @@ describe('IOURequestStepScan', () => { const tx1After = await getTransactionsDraftOnyx(TRANSACTION_ID_1); expect(tx1After).toBeDefined(); - expect(tx1After?.receipt?.source).toBe('file://first-receipt.png'); + expect(tx1After?.receipt?.source).toBe('file://second-receipt.png'); }); }); From f7c85d63e92dd5261d58a515cf9f90055a380275 Mon Sep 17 00:00:00 2001 From: Samran Ahmed Date: Fri, 3 Apr 2026 18:42:18 +0500 Subject: [PATCH 10/13] refactor receipt handling and update tests for multi-scan functionality --- .../request/step/IOURequestStepScan/index.tsx | 3 +-- tests/ui/IOURequestStepScanTest.tsx | 20 +++++++++--------- tests/unit/hooks/useReceiptScan.test.ts | 21 ------------------- 3 files changed, 11 insertions(+), 33 deletions(-) diff --git a/src/pages/iou/request/step/IOURequestStepScan/index.tsx b/src/pages/iou/request/step/IOURequestStepScan/index.tsx index bc2243240b544..ed3175bb9feec 100644 --- a/src/pages/iou/request/step/IOURequestStepScan/index.tsx +++ b/src/pages/iou/request/step/IOURequestStepScan/index.tsx @@ -125,11 +125,10 @@ function IOURequestStepScan({ if (isAllScanFilesCanBeRead) { return; } - setIsMultiScanEnabled(false); removeTransactionReceipt(CONST.IOU.OPTIMISTIC_TRANSACTION_ID); removeDraftTransactionsByIDs(draftTransactionIDs, true); }); - }, [setIsMultiScanEnabled, transactions, draftTransactionIDs]); + }, [transactions, draftTransactionIDs]); // this effect will pre-fetch location in web if the location permission is already granted to optimize the flow useEffect(() => { diff --git a/tests/ui/IOURequestStepScanTest.tsx b/tests/ui/IOURequestStepScanTest.tsx index 75b4b29c97d16..082dc3d3c4b3c 100644 --- a/tests/ui/IOURequestStepScanTest.tsx +++ b/tests/ui/IOURequestStepScanTest.tsx @@ -1,5 +1,5 @@ import {NavigationContainer} from '@react-navigation/native'; -import {act, render} from '@testing-library/react-native'; +import {act, fireEvent, render, screen} from '@testing-library/react-native'; import React from 'react'; import Onyx from 'react-native-onyx'; import type {OnyxEntry} from 'react-native-onyx'; @@ -167,26 +167,19 @@ describe('IOURequestStepScan', () => { expect(tx2After?.receipt?.source).toBe('file://receipt2.png'); }); - it('adding a second receipt replaces the existing draft receipt when isMultiScanEnabled is false', async () => { + it('multi-scan mode preserves first receipt when adding second receipt', async () => { const REPORT_ID = '1'; const POLICY_ID = 'policy-1'; const TRANSACTION_ID_1 = '101'; - const TRANSACTION_ID_2 = '102'; const transaction1 = createRandomTransaction(1); transaction1.reportID = REPORT_ID; transaction1.transactionID = TRANSACTION_ID_1; transaction1.receipt = {source: 'file://first-receipt.png', state: CONST.IOU.RECEIPT_STATE.OPEN}; - const transaction2 = createRandomTransaction(2); - transaction2.reportID = REPORT_ID; - transaction2.transactionID = TRANSACTION_ID_2; - transaction2.receipt = {source: 'file://second-receipt.png', state: CONST.IOU.RECEIPT_STATE.OPEN}; - await act(async () => { await Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT}${REPORT_ID}`, createMinimalReport(REPORT_ID, POLICY_ID)); await Onyx.merge(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${TRANSACTION_ID_1}`, transaction1); - await Onyx.merge(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${TRANSACTION_ID_2}`, transaction2); }); await waitForBatchedUpdates(); @@ -217,6 +210,13 @@ describe('IOURequestStepScan', () => { await waitForBatchedUpdatesWithAct(); + fireEvent.press(screen.getByLabelText('multi-scan')); + + await act(async () => { + await Onyx.merge(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${TRANSACTION_ID_1}`, transaction1); + }); + await waitForBatchedUpdates(); + expect(triggerFileSelection).not.toBeNull(); const secondFile = {name: 'second-receipt.png', type: 'image/png', size: 200, uri: 'file://second-receipt.png'} as FileObject; @@ -230,6 +230,6 @@ describe('IOURequestStepScan', () => { const tx1After = await getTransactionsDraftOnyx(TRANSACTION_ID_1); expect(tx1After).toBeDefined(); - expect(tx1After?.receipt?.source).toBe('file://second-receipt.png'); + expect(tx1After?.receipt?.source).toBe('file://first-receipt.png'); }); }); diff --git a/tests/unit/hooks/useReceiptScan.test.ts b/tests/unit/hooks/useReceiptScan.test.ts index b5f2f5dec8d29..b6d82af878954 100644 --- a/tests/unit/hooks/useReceiptScan.test.ts +++ b/tests/unit/hooks/useReceiptScan.test.ts @@ -294,27 +294,6 @@ describe('useReceiptScan', () => { expect(result.current.receiptFiles).toHaveLength(1); expect(result.current.receiptFiles.at(0)).toEqual(receiptFile); }); - - it('should not clear receiptFiles when isMultiScanEnabled changes from true to false', async () => { - const {result} = renderHook(() => useReceiptScan(params)); - await act(async () => { - result.current.setIsMultiScanEnabled(true); - }); - await waitForBatchedUpdatesWithAct(); - - const receiptFile = {file: {uri: 'picture.jpg'}, source: 'file://picture.jpg', transactionID: INITIAL_TRANSACTION_ID}; - await act(async () => { - result.current.setReceiptFiles([receiptFile]); - }); - await waitForBatchedUpdatesWithAct(); - expect(result.current.receiptFiles).toHaveLength(1); - - await act(async () => { - result.current.setIsMultiScanEnabled(false); - }); - await waitForBatchedUpdatesWithAct(); - expect(result.current.receiptFiles).toEqual([receiptFile]); - }); }); describe('processReceipts', () => { From ad40ff3ccd17f9207ff7a29af65b450f58fa9d3d Mon Sep 17 00:00:00 2001 From: Samran Ahmed Date: Sat, 4 Apr 2026 03:19:10 -0700 Subject: [PATCH 11/13] refactor IOURequestStepScan test to move transaction merge after rendering Co-authored-by: Bernhard Owen Josephus <50919443+bernhardoj@users.noreply.github.com> --- tests/ui/IOURequestStepScanTest.tsx | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests/ui/IOURequestStepScanTest.tsx b/tests/ui/IOURequestStepScanTest.tsx index 082dc3d3c4b3c..9931c529d6f76 100644 --- a/tests/ui/IOURequestStepScanTest.tsx +++ b/tests/ui/IOURequestStepScanTest.tsx @@ -213,8 +213,20 @@ describe('IOURequestStepScan', () => { fireEvent.press(screen.getByLabelText('multi-scan')); await act(async () => { + fireEvent.press(screen.getByLabelText('multi-scan')); + + await waitForBatchedUpdates(); + + const transaction1 = createRandomTransaction(1); + transaction1.reportID = REPORT_ID; + transaction1.transactionID = TRANSACTION_ID_1; + transaction1.receipt = {source: 'file://first-receipt.png', state: CONST.IOU.RECEIPT_STATE.OPEN}; + + await act(async () => { + await Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT}${REPORT_ID}`, createMinimalReport(REPORT_ID, POLICY_ID)); await Onyx.merge(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${TRANSACTION_ID_1}`, transaction1); }); + }); await waitForBatchedUpdates(); expect(triggerFileSelection).not.toBeNull(); From 127b41049e3c1ca805384bbfe3e131a65c4f350a Mon Sep 17 00:00:00 2001 From: Samran Ahmed Date: Sat, 4 Apr 2026 15:31:51 +0500 Subject: [PATCH 12/13] fix failing checks --- .../components/MobileWebCameraView.tsx | 4 ++-- tests/ui/IOURequestStepScanTest.tsx | 19 +------------------ 2 files changed, 3 insertions(+), 20 deletions(-) diff --git a/src/pages/iou/request/step/IOURequestStepScan/components/MobileWebCameraView.tsx b/src/pages/iou/request/step/IOURequestStepScan/components/MobileWebCameraView.tsx index 1f8ea45b4f445..70bdfcc9f9975 100644 --- a/src/pages/iou/request/step/IOURequestStepScan/components/MobileWebCameraView.tsx +++ b/src/pages/iou/request/step/IOURequestStepScan/components/MobileWebCameraView.tsx @@ -57,7 +57,7 @@ type MobileWebCameraViewProps = { setStartLocationPermissionFlow: (value: boolean) => void; onBackButtonPress: () => void; shouldShowWrapper: boolean; - isMultiScanEnabled?: boolean; + isMultiScanEnabled: boolean; onLayout?: () => void; }; @@ -117,7 +117,7 @@ function MobileWebCameraView({ setStartLocationPermissionFlow, onBackButtonPress, shouldShowWrapper, - isMultiScanEnabled = false, + isMultiScanEnabled, onLayout, }: MobileWebCameraViewProps) { const {blinkStyle, canUseMultiScan, shouldShowMultiScanEducationalPopup, showBlink, toggleMultiScan, dismissMultiScanEducationalPopup, submitReceipts, submitMultiScanReceipts} = diff --git a/tests/ui/IOURequestStepScanTest.tsx b/tests/ui/IOURequestStepScanTest.tsx index 9931c529d6f76..82ee8173bf5da 100644 --- a/tests/ui/IOURequestStepScanTest.tsx +++ b/tests/ui/IOURequestStepScanTest.tsx @@ -172,17 +172,6 @@ describe('IOURequestStepScan', () => { const POLICY_ID = 'policy-1'; const TRANSACTION_ID_1 = '101'; - const transaction1 = createRandomTransaction(1); - transaction1.reportID = REPORT_ID; - transaction1.transactionID = TRANSACTION_ID_1; - transaction1.receipt = {source: 'file://first-receipt.png', state: CONST.IOU.RECEIPT_STATE.OPEN}; - - await act(async () => { - await Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT}${REPORT_ID}`, createMinimalReport(REPORT_ID, POLICY_ID)); - await Onyx.merge(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${TRANSACTION_ID_1}`, transaction1); - }); - await waitForBatchedUpdates(); - render( @@ -211,22 +200,16 @@ describe('IOURequestStepScan', () => { await waitForBatchedUpdatesWithAct(); fireEvent.press(screen.getByLabelText('multi-scan')); - - await act(async () => { - fireEvent.press(screen.getByLabelText('multi-scan')); - - await waitForBatchedUpdates(); + await waitForBatchedUpdates(); const transaction1 = createRandomTransaction(1); transaction1.reportID = REPORT_ID; transaction1.transactionID = TRANSACTION_ID_1; transaction1.receipt = {source: 'file://first-receipt.png', state: CONST.IOU.RECEIPT_STATE.OPEN}; - await act(async () => { await Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT}${REPORT_ID}`, createMinimalReport(REPORT_ID, POLICY_ID)); await Onyx.merge(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${TRANSACTION_ID_1}`, transaction1); }); - }); await waitForBatchedUpdates(); expect(triggerFileSelection).not.toBeNull(); From 58def4fbed5e0784e7261cb6140f0a40ad43afff Mon Sep 17 00:00:00 2001 From: Samran Ahmed Date: Sat, 4 Apr 2026 18:32:14 +0500 Subject: [PATCH 13/13] change params position --- .../IOURequestStepScan/components/MobileWebCameraView.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/iou/request/step/IOURequestStepScan/components/MobileWebCameraView.tsx b/src/pages/iou/request/step/IOURequestStepScan/components/MobileWebCameraView.tsx index bf3bc8d9178d0..da3ff64a13c58 100644 --- a/src/pages/iou/request/step/IOURequestStepScan/components/MobileWebCameraView.tsx +++ b/src/pages/iou/request/step/IOURequestStepScan/components/MobileWebCameraView.tsx @@ -43,6 +43,7 @@ type MobileWebCameraViewProps = { iouType: IOUType; currentUserPersonalDetails: CurrentUserPersonalDetails; reportID: string; + isMultiScanEnabled: boolean; isStartingScan: boolean; updateScanAndNavigate: (file: FileObject, source: string) => void; setIsMultiScanEnabled: (value: boolean) => void; @@ -57,7 +58,6 @@ type MobileWebCameraViewProps = { setStartLocationPermissionFlow: (value: boolean) => void; onBackButtonPress: () => void; shouldShowWrapper: boolean; - isMultiScanEnabled: boolean; onLayout?: () => void; }; @@ -103,6 +103,7 @@ function MobileWebCameraView({ iouType, currentUserPersonalDetails, reportID, + isMultiScanEnabled, isStartingScan, updateScanAndNavigate, setIsMultiScanEnabled, @@ -117,7 +118,6 @@ function MobileWebCameraView({ setStartLocationPermissionFlow, onBackButtonPress, shouldShowWrapper, - isMultiScanEnabled, onLayout, }: MobileWebCameraViewProps) { const {blinkStyle, canUseMultiScan, shouldShowMultiScanEducationalPopup, showBlink, toggleMultiScan, dismissMultiScanEducationalPopup, submitReceipts, submitMultiScanReceipts} =