diff --git a/src/pages/iou/request/step/IOURequestStepScan/index.js b/src/pages/iou/request/step/IOURequestStepScan/index.js index 6bf517c30eb0..49c5f0a782fc 100644 --- a/src/pages/iou/request/step/IOURequestStepScan/index.js +++ b/src/pages/iou/request/step/IOURequestStepScan/index.js @@ -77,6 +77,7 @@ function IOURequestStepScan({ const [isTorchAvailable, setIsTorchAvailable] = useState(false); const cameraRef = useRef(null); const trackRef = useRef(null); + const [isQueriedPermissionState, setIsQueriedPermissionState] = useState(false); const getScreenshotTimeoutRef = useRef(null); @@ -88,8 +89,8 @@ function IOURequestStepScan({ * On phones that have ultra-wide lens, react-webcam uses ultra-wide by default. * The last deviceId is of regular len camera. */ - useEffect(() => { - if (!_.isEmpty(videoConstraints) || !isTabActive || !Browser.isMobile()) { + const requestCameraPermission = useCallback(() => { + if (!_.isEmpty(videoConstraints) || !Browser.isMobile()) { return; } @@ -97,6 +98,7 @@ function IOURequestStepScan({ navigator.mediaDevices .getUserMedia({video: {facingMode: {exact: 'environment'}, zoom: {ideal: 1}}}) .then((stream) => { + setCameraPermissionState('granted'); _.forEach(stream.getTracks(), (track) => track.stop()); // Only Safari 17+ supports zoom constraint if (Browser.isMobileSafari() && stream.getTracks().length > 0) { @@ -128,7 +130,32 @@ function IOURequestStepScan({ setVideoConstraints({deviceId: lastBackDeviceId}); }); }) - .catch(() => setVideoConstraints(defaultConstraints)); + .catch(() => { + setVideoConstraints(defaultConstraints); + setCameraPermissionState('denied'); + }); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + useEffect(() => { + if (!Browser.isMobile() || !isTabActive) { + return; + } + navigator.permissions + .query({name: 'camera'}) + .then((permissionState) => { + setCameraPermissionState(permissionState.state); + if (permissionState.state === 'granted') { + requestCameraPermission(); + } + }) + .catch(() => { + setCameraPermissionState('denied'); + }) + .finally(() => { + setIsQueriedPermissionState(true); + }); + // We only want to get the camera permission status when the component is mounted // eslint-disable-next-line react-hooks/exhaustive-deps }, [isTabActive]); @@ -232,6 +259,7 @@ function IOURequestStepScan({ const getScreenshot = useCallback(() => { if (!cameraRef.current) { + requestCameraPermission(); return; } @@ -248,7 +276,7 @@ function IOURequestStepScan({ } navigateToConfirmationStep(); - }, [action, transactionID, updateScanAndNavigate, navigateToConfirmationStep]); + }, [action, transactionID, updateScanAndNavigate, navigateToConfirmationStep, requestCameraPermission]); const clearTorchConstraints = useCallback(() => { if (!trackRef.current) { @@ -296,14 +324,14 @@ function IOURequestStepScan({ const mobileCameraView = () => ( <> - {(cameraPermissionState === 'prompt' || !cameraPermissionState) && ( + {((cameraPermissionState === 'prompt' && !isQueriedPermissionState) || (cameraPermissionState === 'granted' && _.isEmpty(videoConstraints))) && ( )} - {cameraPermissionState === 'denied' && ( + {cameraPermissionState !== 'granted' && isQueriedPermissionState && ( {translate('receipt.takePhoto')} {translate('receipt.cameraAccess')} +