Skip to content
Open
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 1 addition & 5 deletions src/pages/iou/request/IOURequestStartPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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});
Expand Down Expand Up @@ -186,7 +185,6 @@ function IOURequestStartPage({
if (transaction?.iouRequestType === newIOUType) {
return;
}
setIsMultiScanEnabled(false);
initMoneyRequest({
reportID,
policy,
Expand Down Expand Up @@ -340,14 +338,12 @@ function IOURequestStartPage({
{() => (
<TabScreenWithFocusTrapWrapper>
<IOURequestStepScan
key={transactionRequestType}
route={route}
navigation={navigation}
onLayout={(setTestReceiptAndNavigate) => {
setTestReceiptAndNavigateRef.current = setTestReceiptAndNavigate;
}}
isMultiScanEnabled={isMultiScanEnabled}
setIsMultiScanEnabled={setIsMultiScanEnabled}
isStartingScan
/>
</TabScreenWithFocusTrapWrapper>
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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[];
Expand All @@ -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;
};

/**
Expand Down Expand Up @@ -103,7 +103,6 @@ function MobileWebCameraView({
iouType,
currentUserPersonalDetails,
reportID,
isMultiScanEnabled = false,
isStartingScan,
updateScanAndNavigate,
setIsMultiScanEnabled,
Expand All @@ -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({
Expand All @@ -131,6 +131,7 @@ function MobileWebCameraView({
shouldSkipConfirmation,
setStartLocationPermissionFlow,
setIsMultiScanEnabled,
setReceiptFiles,
});
const theme = useTheme();
const styles = useThemeStyles();
Expand Down Expand Up @@ -444,7 +445,7 @@ function MobileWebCameraView({
) : null}
<Animated.View
pointerEvents="none"
style={[StyleSheet.absoluteFillObject, styles.backgroundWhite, blinkStyle, styles.zIndex10]}
style={[StyleSheet.absoluteFill, styles.backgroundWhite, blinkStyle, styles.zIndex10]}
/>
</View>
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,13 @@ function useMobileReceiptScan({
initialTransaction,
iouType,
isMultiScanEnabled = false,
isStartingScan = false,
isStartingScan,
receiptFiles,
navigateToConfirmationStep,
shouldSkipConfirmation,
setStartLocationPermissionFlow,
setIsMultiScanEnabled,
setReceiptFiles,
}: UseMobileReceiptScanParams) {
const [shouldStartLocationPermissionFlow] = useOnyx(ONYXKEYS.NVP_LAST_LOCATION_PERMISSION_PROMPT, {
selector: shouldStartLocationPermissionFlowSelector,
Expand Down Expand Up @@ -78,7 +79,10 @@ function useMobileReceiptScan({
}
removeTransactionReceipt(CONST.IOU.OPTIMISTIC_TRANSACTION_ID);
removeDraftTransactionsByIDs(draftTransactionIDs, true);
setIsMultiScanEnabled?.(!isMultiScanEnabled);
if (isMultiScanEnabled) {
setReceiptFiles([]);
}
setIsMultiScanEnabled(!isMultiScanEnabled);
}

function dismissMultiScanEducationalPopup() {
Expand Down
Original file line number Diff line number Diff line change
@@ -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';
Expand Down Expand Up @@ -37,8 +37,6 @@ function useReceiptScan({
currentUserPersonalDetails,
backTo,
backToReport,
isMultiScanEnabled = false,
isStartingScan = false,
updateScanAndNavigate,
getSource,
}: UseReceiptScanParams) {
Expand Down Expand Up @@ -69,10 +67,12 @@ 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(false);

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);
Expand All @@ -90,15 +90,6 @@ function useReceiptScan({
const [startLocationPermissionFlow, setStartLocationPermissionFlow] = useState(false);
const [receiptFiles, setReceiptFiles] = useState<ReceiptFile[]>([]);

// 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(
Expand Down Expand Up @@ -232,6 +223,9 @@ function useReceiptScan({
});
return {
transactions,
isMultiScanEnabled,
setIsMultiScanEnabled,
isStartingScan,
isEditing,
isReplacingReceipt,
shouldAcceptMultipleFiles,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,6 @@ function IOURequestStepScan({
transaction: initialTransaction,
currentUserPersonalDetails,
onLayout,
isMultiScanEnabled = false,
isStartingScan = false,
setIsMultiScanEnabled,
}: IOURequestStepScanProps) {
const theme = useTheme();
const styles = useThemeStyles();
Expand Down Expand Up @@ -288,6 +285,9 @@ function IOURequestStepScan({
const getSource = useCallback((file: FileObject) => file.uri ?? '', []);

const {
isMultiScanEnabled,
setIsMultiScanEnabled,
isStartingScan,
isEditing,
shouldAcceptMultipleFiles,
shouldSkipConfirmation,
Expand All @@ -310,8 +310,6 @@ function IOURequestStepScan({
currentUserPersonalDetails,
backTo,
backToReport,
isMultiScanEnabled,
isStartingScan,
updateScanAndNavigate,
getSource,
});
Expand All @@ -327,6 +325,7 @@ function IOURequestStepScan({
shouldSkipConfirmation,
setStartLocationPermissionFlow,
setIsMultiScanEnabled,
setReceiptFiles,
});

const maybeCancelShutterSpan = useCallback(() => {
Expand Down
11 changes: 4 additions & 7 deletions src/pages/iou/request/step/IOURequestStepScan/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,6 @@ function IOURequestStepScan({
transaction: initialTransaction,
currentUserPersonalDetails,
onLayout,
isMultiScanEnabled = false,
isStartingScan = false,
setIsMultiScanEnabled,
}: Omit<IOURequestStepScanProps, 'user'>) {
const isMobileWeb = isMobile();
const policy = usePolicy(report?.policyID);
Expand Down Expand Up @@ -62,6 +59,9 @@ function IOURequestStepScan({

const {
transactions,
isMultiScanEnabled,
setIsMultiScanEnabled,
isStartingScan,
isEditing,
isReplacingReceipt,
shouldAcceptMultipleFiles,
Expand All @@ -85,8 +85,6 @@ function IOURequestStepScan({
currentUserPersonalDetails,
backTo,
backToReport,
isMultiScanEnabled,
isStartingScan,
updateScanAndNavigate,
getSource,
});
Expand Down Expand Up @@ -127,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(() => {
Expand Down
24 changes: 6 additions & 18 deletions src/pages/iou/request/step/IOURequestStepScan/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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[];
Expand All @@ -76,8 +70,11 @@ 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;

/** Callback to update scanned receipt files */
setReceiptFiles: (value: ReceiptFile[]) => void;
};

type IOURequestStepScanProps = WithCurrentUserPersonalDetailsProps &
Expand All @@ -90,15 +87,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 = {
Expand Down
12 changes: 8 additions & 4 deletions tests/ui/IOURequestStepScanTest.tsx
Original file line number Diff line number Diff line change
@@ -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';
Expand Down Expand Up @@ -202,9 +202,6 @@ describe('IOURequestStepScan', () => {
} as unknown as PlatformStackScreenProps<MoneyRequestNavigatorParamList, typeof SCREENS.MONEY_REQUEST.STEP_SCAN>['route']
}
navigation={{} as never}
isMultiScanEnabled
isStartingScan
setIsMultiScanEnabled={jest.fn()}
/>
</NavigationContainer>
</LocaleContextProvider>
Expand All @@ -213,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;
Expand Down
31 changes: 31 additions & 0 deletions tests/unit/hooks/useMobileReceiptScan.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ function createDefaultParams(): UseMobileReceiptScanParams {
shouldSkipConfirmation: false,
setStartLocationPermissionFlow: jest.fn(),
setIsMultiScanEnabled: jest.fn(),
setReceiptFiles: jest.fn(),
};
}

Expand Down Expand Up @@ -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', () => {
Expand Down
Loading
Loading