Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
63f573d
Add useDragAndDropSupport hook for native and web environment
samranahm Feb 24, 2026
6b6563c
Refactor IOURequestStepScan to use isMobileWeb and canUseDragAndDrop
samranahm Feb 24, 2026
0490ef1
fix prettier
samranahm Feb 24, 2026
ffcdcf5
remove useDragAndDropSupport hook
samranahm Feb 26, 2026
711c503
remove isMobileWeb from mobileCameraView since we only show this if i…
samranahm Feb 26, 2026
e07e6d5
Merge remote-tracking branch 'upstream/main' into 79929/IOURequestSte…
samranahm Mar 1, 2026
3866b79
Add DesktopWebUploadView and MobileWebCameraView components
samranahm Mar 1, 2026
e3c6c50
Refactor IOURequestStepScan component to use MobileWebCameraView and …
samranahm Mar 1, 2026
79a1b74
Merge remote-tracking branch 'upstream/main' into 79929/IOURequestSte…
samranahm Mar 5, 2026
21cba79
update dir for IOURequestStepScan
samranahm Mar 5, 2026
bd15189
refactor: consolidate IOURequestStepScan components and hooks
samranahm Mar 5, 2026
6921d17
Merge remote-tracking branch 'upstream/main' into 79929/IOURequestSte…
samranahm Mar 5, 2026
3d3966d
Merge remote-tracking branch 'upstream/main' into 79929/IOURequestSte…
samranahm Mar 5, 2026
5f632c1
Merge remote-tracking branch 'upstream/main' into 79929/IOURequestSte…
samranahm Mar 9, 2026
763fe54
move screen wrapper to each platform component
samranahm Mar 9, 2026
eb16fb9
Refactor receipt scanning logic to streamline mobile and web components.
samranahm Mar 9, 2026
73b696e
move useMobileReceiptScan test to seprate file
samranahm Mar 9, 2026
49b5b44
prettier
samranahm Mar 9, 2026
839ffad
Add isDraggingOverWrapper from useDragAndDropState in DesktopWebUploa…
samranahm Mar 10, 2026
c7cdc51
add UseMobileReceiptScanParams type
samranahm Mar 10, 2026
c29310e
Move LocationPermissionFlowSelector to Selectors
samranahm Mar 10, 2026
36d8ac9
reafactor the hooks to pass required params only
samranahm Mar 10, 2026
cd58af9
updated test to remove createMockReceiptScan mock
samranahm Mar 10, 2026
6c8a190
lint
samranahm Mar 10, 2026
8b126c2
Merge remote-tracking branch 'upstream/main' into 79929/IOURequestSte…
samranahm Mar 10, 2026
bef83fd
Merge remote-tracking branch 'upstream/main' into 79929/IOURequestSte…
samranahm Mar 10, 2026
f1e0dc2
Merge remote-tracking branch 'upstream/main' into 79929/IOURequestSte…
samranahm Mar 11, 2026
feabace
Refactor IOURequestStepScan components and hooks for clarity
samranahm Mar 11, 2026
9f39222
Merge branch 'Expensify:main' into 79929/IOURequestStepScan-clean-up-p3
samranahm Mar 12, 2026
c8be9a4
Merge remote-tracking branch 'upstream/main' into 79929/IOURequestSte…
samranahm Mar 12, 2026
19ad53a
Merge remote-tracking branch 'upstream/main' into 79929/IOURequestSte…
samranahm Mar 13, 2026
df59882
Refactor camera permission handling in MobileWebCameraView
samranahm Mar 13, 2026
a41cc41
Update lint script to reduce max warnings from 334 to 316
samranahm Mar 13, 2026
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
29 changes: 14 additions & 15 deletions src/pages/iou/request/step/IOURequestStepScan/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
import useLocalize from '@hooks/useLocalize';
import useOnyx from '@hooks/useOnyx';
import usePolicy from '@hooks/usePolicy';
import useResponsiveLayout from '@hooks/useResponsiveLayout';
import useTheme from '@hooks/useTheme';
import useThemeStyles from '@hooks/useThemeStyles';
import {clearUserLocation, setUserLocation} from '@libs/actions/UserLocation';
Expand All @@ -46,6 +45,7 @@
import NavigationAwareCamera from './NavigationAwareCamera/WebCamera';
import ReceiptPreviews from './ReceiptPreviews';
import type IOURequestStepScanProps from './types';
import useDragAndDropSupport from './useDragAndDropSupport';
import useReceiptScan from './useReceiptScan';

function IOURequestStepScan({
Expand All @@ -62,9 +62,8 @@
}: Omit<IOURequestStepScanProps, 'user'>) {
const theme = useTheme();
const styles = useThemeStyles();
// we need to use isSmallScreenWidth instead of shouldUseNarrowLayout because drag and drop is not supported on mobile
// eslint-disable-next-line rulesdir/prefer-shouldUseNarrowLayout-instead-of-isSmallScreenWidth
const {isSmallScreenWidth} = useResponsiveLayout();
const isMobileWeb = isMobile();
const canUseDragAndDrop = useDragAndDropSupport();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, since this hook doesn't use any React APIs or trigger re-renders, it might be better implemented as a utility function rather than a hook.

Also, since we use this on index.tsx file only, we can just simply use isMobileWeb here.

const canUseDragAndDrop = !isMobileWeb;

cc: @roryabraham

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we refactor this further as I commented here, then we probably can just remove this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree, we don't really need a hook here.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sounds good

const {translate} = useLocalize();
const {isDraggingOver} = useDragAndDropState();
const [cameraPermissionState, setCameraPermissionState] = useState<PermissionState | undefined>('prompt');
Expand Down Expand Up @@ -140,7 +139,7 @@
* The last deviceId is of regular len camera.
*/
const requestCameraPermission = useCallback(() => {
if (!isMobile()) {
if (!isMobileWeb) {
return;
}

Expand Down Expand Up @@ -191,7 +190,7 @@
setVideoConstraints(defaultConstraints);
setCameraPermissionState('denied');
});
}, []);

Check warning on line 193 in src/pages/iou/request/step/IOURequestStepScan/index.tsx

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

React Hook useCallback has a missing dependency: 'isMobileWeb'. Either include it or remove the dependency array

// When the component mounts, if there is a receipt, see if the image can be read from the disk. If not, make the user star scanning flow from scratch.
// This is because until the request is saved, the receipt file is only stored in the browsers memory as a blob:// and if the browser is refreshed, then
Expand Down Expand Up @@ -227,7 +226,7 @@
}, []);

useEffect(() => {
if (!isMobile() || !isTabActive) {
if (!isMobileWeb || !isTabActive) {
setVideoConstraints(undefined);
return;
}
Expand Down Expand Up @@ -468,7 +467,7 @@
mirrored={false}
screenshotQuality={0}
/>
{canUseMultiScan && isMobile() ? (
{canUseMultiScan && isMobileWeb ? (
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can remove isMobileWeb condition from mobileCameraView since we only shows mobileCameraView if isMobileWeb is true.

<View style={[styles.flashButtonContainer, styles.primaryMediumIcon, isFlashLightOn && styles.bgGreenSuccess, !isTorchAvailable && styles.opacity0]}>
<PressableWithFeedback
role={CONST.ROLE.BUTTON}
Expand Down Expand Up @@ -533,7 +532,7 @@
height={CONST.RECEIPT.SHUTTER_SIZE}
/>
</PressableWithFeedback>
{canUseMultiScan && isMobile() ? (
{canUseMultiScan && isMobileWeb ? (
<PressableWithFeedback
accessibilityRole="button"
role={CONST.ROLE.BUTTON}
Expand Down Expand Up @@ -567,7 +566,7 @@
</PressableWithFeedback>
)}
</View>
{canUseMultiScan && isMobile() && shouldShowMultiScanEducationalPopup && (
{canUseMultiScan && isMobileWeb && shouldShowMultiScanEducationalPopup && (
<FeatureTrainingModal
title={translate('iou.scanMultipleReceipts')}
image={lazyIllustrations.MultiScan}
Expand Down Expand Up @@ -597,9 +596,9 @@
const [containerHeight, setContainerHeight] = useState(0);
const [desktopUploadViewHeight, setDesktopUploadViewHeight] = useState(0);
const [alternativeMethodsHeight, setAlternativeMethodsHeight] = useState(0);
// We use isMobile() here to explicitly hide the alternative methods component on both mobile web and native apps
const chooseFilesPaddingVertical = Number(styles.chooseFilesView(isSmallScreenWidth).paddingVertical);
const shouldHideAlternativeMethods = isMobile() || alternativeMethodsHeight + desktopUploadViewHeight + chooseFilesPaddingVertical * 2 > containerHeight;
// We use isMobileWeb here to explicitly hide the alternative methods component on both mobile web and native apps
const chooseFilesPaddingVertical = Number(styles.chooseFilesView(!canUseDragAndDrop).paddingVertical);
const shouldHideAlternativeMethods = isMobileWeb || alternativeMethodsHeight + desktopUploadViewHeight + chooseFilesPaddingVertical * 2 > containerHeight;

const desktopUploadView = () => (
<View
Expand Down Expand Up @@ -660,10 +659,10 @@
}
onLayout(setTestReceiptAndNavigate);
}}
style={[styles.flex1, !isMobile() && styles.chooseFilesView(isSmallScreenWidth)]}
style={[styles.flex1, canUseDragAndDrop && styles.chooseFilesView(!canUseDragAndDrop)]}
>
<View style={[styles.flex1, !isMobile() && styles.alignItemsCenter, styles.justifyContentCenter]}>
{!(isDraggingOver ?? isDraggingOverWrapper) && (isMobile() ? mobileCameraView() : desktopUploadView())}
<View style={[styles.flex1, canUseDragAndDrop && styles.alignItemsCenter, styles.justifyContentCenter]}>
{!(isDraggingOver ?? isDraggingOverWrapper) && (isMobileWeb ? mobileCameraView() : desktopUploadView())}
</View>
<DragAndDropConsumer onDrop={handleDropReceipt}>
<DropZoneUI
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/**
* Drag-and-drop for file upload is not supported in native apps.
*/
function useDragAndDropSupport(): boolean {
return false;
}

export default useDragAndDropSupport;
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import {isMobile} from '@libs/Browser';

/**
* Drag-and-drop is supported on desktop web only. Returns false on mobile web.
*/
function useDragAndDropSupport(): boolean {
return !isMobile();
}

export default useDragAndDropSupport;
Loading