From dbf945ab18cb9085d5f1184c0ffcd870e003a07e Mon Sep 17 00:00:00 2001 From: Tim Golen Date: Fri, 8 Dec 2023 14:39:26 -0700 Subject: [PATCH 01/21] Remove old receipt selector files --- src/pages/EditRequestReceiptPage.js | 2 +- src/pages/iou/MoneyRequestSelectorPage.js | 2 +- .../CameraPermission/index.android.js | 12 - .../CameraPermission/index.ios.js | 11 - .../ReceiptSelector/CameraPermission/index.js | 5 - .../NavigationAwareCamera/index.js | 80 ----- .../NavigationAwareCamera/index.native.js | 28 -- src/pages/iou/ReceiptSelector/index.js | 336 ------------------ src/pages/iou/ReceiptSelector/index.native.js | 298 ---------------- 9 files changed, 2 insertions(+), 772 deletions(-) delete mode 100644 src/pages/iou/ReceiptSelector/CameraPermission/index.android.js delete mode 100644 src/pages/iou/ReceiptSelector/CameraPermission/index.ios.js delete mode 100644 src/pages/iou/ReceiptSelector/CameraPermission/index.js delete mode 100644 src/pages/iou/ReceiptSelector/NavigationAwareCamera/index.js delete mode 100644 src/pages/iou/ReceiptSelector/NavigationAwareCamera/index.native.js delete mode 100644 src/pages/iou/ReceiptSelector/index.js delete mode 100644 src/pages/iou/ReceiptSelector/index.native.js diff --git a/src/pages/EditRequestReceiptPage.js b/src/pages/EditRequestReceiptPage.js index 03c0aa777d5ee..a271f15a91b01 100644 --- a/src/pages/EditRequestReceiptPage.js +++ b/src/pages/EditRequestReceiptPage.js @@ -7,7 +7,7 @@ import ScreenWrapper from '@components/ScreenWrapper'; import useLocalize from '@hooks/useLocalize'; import Navigation from '@libs/Navigation/Navigation'; import useThemeStyles from '@styles/useThemeStyles'; -import ReceiptSelector from './iou/ReceiptSelector'; +import ReceiptSelector from './iou/request/step/IOURequestStepScan'; const propTypes = { /** React Navigation route */ diff --git a/src/pages/iou/MoneyRequestSelectorPage.js b/src/pages/iou/MoneyRequestSelectorPage.js index af52ea1222ed4..845625c131760 100644 --- a/src/pages/iou/MoneyRequestSelectorPage.js +++ b/src/pages/iou/MoneyRequestSelectorPage.js @@ -24,7 +24,7 @@ import * as IOU from '@userActions/IOU'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import NewDistanceRequestPage from './NewDistanceRequestPage'; -import ReceiptSelector from './ReceiptSelector'; +import ReceiptSelector from './request/step/IOURequestStepScan'; import NewRequestAmountPage from './steps/NewRequestAmountPage'; const propTypes = { diff --git a/src/pages/iou/ReceiptSelector/CameraPermission/index.android.js b/src/pages/iou/ReceiptSelector/CameraPermission/index.android.js deleted file mode 100644 index 3eb9ef4eea5ac..0000000000000 --- a/src/pages/iou/ReceiptSelector/CameraPermission/index.android.js +++ /dev/null @@ -1,12 +0,0 @@ -import {check, PERMISSIONS, request} from 'react-native-permissions'; - -function requestCameraPermission() { - return request(PERMISSIONS.ANDROID.CAMERA); -} - -// Android will never return blocked after a check, you have to request the permission to get the info. -function getCameraPermissionStatus() { - return check(PERMISSIONS.ANDROID.CAMERA); -} - -export {requestCameraPermission, getCameraPermissionStatus}; diff --git a/src/pages/iou/ReceiptSelector/CameraPermission/index.ios.js b/src/pages/iou/ReceiptSelector/CameraPermission/index.ios.js deleted file mode 100644 index 3c24bfa10d6fb..0000000000000 --- a/src/pages/iou/ReceiptSelector/CameraPermission/index.ios.js +++ /dev/null @@ -1,11 +0,0 @@ -import {check, PERMISSIONS, request} from 'react-native-permissions'; - -function requestCameraPermission() { - return request(PERMISSIONS.IOS.CAMERA); -} - -function getCameraPermissionStatus() { - return check(PERMISSIONS.IOS.CAMERA); -} - -export {requestCameraPermission, getCameraPermissionStatus}; diff --git a/src/pages/iou/ReceiptSelector/CameraPermission/index.js b/src/pages/iou/ReceiptSelector/CameraPermission/index.js deleted file mode 100644 index 4357b592d7ef4..0000000000000 --- a/src/pages/iou/ReceiptSelector/CameraPermission/index.js +++ /dev/null @@ -1,5 +0,0 @@ -function requestCameraPermission() {} - -function getCameraPermissionStatus() {} - -export {requestCameraPermission, getCameraPermissionStatus}; diff --git a/src/pages/iou/ReceiptSelector/NavigationAwareCamera/index.js b/src/pages/iou/ReceiptSelector/NavigationAwareCamera/index.js deleted file mode 100644 index 10b16da13b6ef..0000000000000 --- a/src/pages/iou/ReceiptSelector/NavigationAwareCamera/index.js +++ /dev/null @@ -1,80 +0,0 @@ -import PropTypes from 'prop-types'; -import React, {useEffect, useRef} from 'react'; -import {View} from 'react-native'; -import Webcam from 'react-webcam'; -import useTabNavigatorFocus from '@hooks/useTabNavigatorFocus'; - -const propTypes = { - /** Flag to turn on/off the torch/flashlight - if available */ - torchOn: PropTypes.bool, - - /** The index of the tab that contains this camera */ - cameraTabIndex: PropTypes.number.isRequired, - - /** Callback function when media stream becomes available - user granted camera permissions and camera starts to work */ - onUserMedia: PropTypes.func, - - /** Callback function passing torch/flashlight capability as bool param of the browser */ - onTorchAvailability: PropTypes.func, -}; - -const defaultProps = { - onUserMedia: undefined, - onTorchAvailability: undefined, - torchOn: false, -}; - -// Wraps a camera that will only be active when the tab is focused or as soon as it starts to become focused. -const NavigationAwareCamera = React.forwardRef(({torchOn, onTorchAvailability, cameraTabIndex, ...props}, ref) => { - const trackRef = useRef(null); - const shouldShowCamera = useTabNavigatorFocus({ - tabIndex: cameraTabIndex, - }); - - const handleOnUserMedia = (stream) => { - if (props.onUserMedia) { - props.onUserMedia(stream); - } - - const [track] = stream.getVideoTracks(); - const capabilities = track.getCapabilities(); - if (capabilities.torch) { - trackRef.current = track; - } - if (onTorchAvailability) { - onTorchAvailability(!!capabilities.torch); - } - }; - - useEffect(() => { - if (!trackRef.current) { - return; - } - - trackRef.current.applyConstraints({ - advanced: [{torch: torchOn}], - }); - }, [torchOn]); - - if (!shouldShowCamera) { - return null; - } - return ( - - - - ); -}); - -NavigationAwareCamera.propTypes = propTypes; -NavigationAwareCamera.displayName = 'NavigationAwareCamera'; -NavigationAwareCamera.defaultProps = defaultProps; - -export default NavigationAwareCamera; diff --git a/src/pages/iou/ReceiptSelector/NavigationAwareCamera/index.native.js b/src/pages/iou/ReceiptSelector/NavigationAwareCamera/index.native.js deleted file mode 100644 index 65c17d3cb7abb..0000000000000 --- a/src/pages/iou/ReceiptSelector/NavigationAwareCamera/index.native.js +++ /dev/null @@ -1,28 +0,0 @@ -import PropTypes from 'prop-types'; -import React from 'react'; -import {Camera} from 'react-native-vision-camera'; -import useTabNavigatorFocus from '@hooks/useTabNavigatorFocus'; - -const propTypes = { - /* The index of the tab that contains this camera */ - cameraTabIndex: PropTypes.number.isRequired, -}; - -// Wraps a camera that will only be active when the tab is focused or as soon as it starts to become focused. -const NavigationAwareCamera = React.forwardRef(({cameraTabIndex, ...props}, ref) => { - const isCameraActive = useTabNavigatorFocus({tabIndex: cameraTabIndex}); - - return ( - - ); -}); - -NavigationAwareCamera.propTypes = propTypes; -NavigationAwareCamera.displayName = 'NavigationAwareCamera'; - -export default NavigationAwareCamera; diff --git a/src/pages/iou/ReceiptSelector/index.js b/src/pages/iou/ReceiptSelector/index.js deleted file mode 100644 index dd7c2e3a104ef..0000000000000 --- a/src/pages/iou/ReceiptSelector/index.js +++ /dev/null @@ -1,336 +0,0 @@ -import lodashGet from 'lodash/get'; -import PropTypes from 'prop-types'; -import React, {useCallback, useContext, useReducer, useRef, useState} from 'react'; -import {ActivityIndicator, PanResponder, PixelRatio, Text, View} from 'react-native'; -import {withOnyx} from 'react-native-onyx'; -import Hand from '@assets/images/hand.svg'; -import ReceiptUpload from '@assets/images/receipt-upload.svg'; -import Shutter from '@assets/images/shutter.svg'; -import AttachmentPicker from '@components/AttachmentPicker'; -import Button from '@components/Button'; -import ConfirmModal from '@components/ConfirmModal'; -import CopyTextToClipboard from '@components/CopyTextToClipboard'; -import {DragAndDropContext} from '@components/DragAndDrop/Provider'; -import Icon from '@components/Icon'; -import * as Expensicons from '@components/Icon/Expensicons'; -import PressableWithFeedback from '@components/Pressable/PressableWithFeedback'; -import useLocalize from '@hooks/useLocalize'; -import useWindowDimensions from '@hooks/useWindowDimensions'; -import * as Browser from '@libs/Browser'; -import * as FileUtils from '@libs/fileDownload/FileUtils'; -import Navigation from '@libs/Navigation/Navigation'; -import {iouDefaultProps, iouPropTypes} from '@pages/iou/propTypes'; -import ReceiptDropUI from '@pages/iou/ReceiptDropUI'; -import reportPropTypes from '@pages/reportPropTypes'; -import useTheme from '@styles/themes/useTheme'; -import useThemeStyles from '@styles/useThemeStyles'; -import * as IOU from '@userActions/IOU'; -import CONST from '@src/CONST'; -import ONYXKEYS from '@src/ONYXKEYS'; -import NavigationAwareCamera from './NavigationAwareCamera'; - -const propTypes = { - /** The report on which the request is initiated on */ - report: reportPropTypes, - - /** React Navigation route */ - route: PropTypes.shape({ - /** Params from the route */ - params: PropTypes.shape({ - /** The type of IOU report, i.e. bill, request, send */ - iouType: PropTypes.string, - - /** The report ID of the IOU */ - reportID: PropTypes.string, - }), - - /** The current route path */ - path: PropTypes.string, - }).isRequired, - - /** Holds data related to Money Request view state, rather than the underlying Money Request data. */ - iou: iouPropTypes, - - /** The id of the transaction we're editing */ - transactionID: PropTypes.string, -}; - -const defaultProps = { - report: {}, - iou: iouDefaultProps, - transactionID: '', -}; - -function ReceiptSelector({route, transactionID, iou, report}) { - const theme = useTheme(); - const styles = useThemeStyles(); - const iouType = lodashGet(route, 'params.iouType', ''); - const pageIndex = lodashGet(route, 'params.pageIndex', 1); - - // Grouping related states - const [isAttachmentInvalid, setIsAttachmentInvalid] = useState(false); - const [attachmentInvalidReasonTitle, setAttachmentInvalidReasonTitle] = useState(''); - const [attachmentInvalidReason, setAttachmentValidReason] = useState(''); - - const [receiptImageTopPosition, setReceiptImageTopPosition] = useState(0); - const {isSmallScreenWidth} = useWindowDimensions(); - const {translate} = useLocalize(); - const {isDraggingOver} = useContext(DragAndDropContext); - - const [cameraPermissionState, setCameraPermissionState] = useState('prompt'); - const [isFlashLightOn, toggleFlashlight] = useReducer((state) => !state, false); - const [isTorchAvailable, setIsTorchAvailable] = useState(false); - const cameraRef = useRef(null); - - const hideReciptModal = () => { - setIsAttachmentInvalid(false); - }; - - /** - * Sets the upload receipt error modal content when an invalid receipt is uploaded - * @param {*} isInvalid - * @param {*} title - * @param {*} reason - */ - const setUploadReceiptError = (isInvalid, title, reason) => { - setIsAttachmentInvalid(isInvalid); - setAttachmentInvalidReasonTitle(title); - setAttachmentValidReason(reason); - }; - - function validateReceipt(file) { - const {fileExtension} = FileUtils.splitExtensionFromFileName(lodashGet(file, 'name', '')); - if (!CONST.API_ATTACHMENT_VALIDATIONS.ALLOWED_RECEIPT_EXTENSIONS.includes(fileExtension.toLowerCase())) { - setUploadReceiptError(true, 'attachmentPicker.wrongFileType', 'attachmentPicker.notAllowedExtension'); - return false; - } - - if (lodashGet(file, 'size', 0) > CONST.API_ATTACHMENT_VALIDATIONS.MAX_SIZE) { - setUploadReceiptError(true, 'attachmentPicker.attachmentTooLarge', 'attachmentPicker.sizeExceeded'); - return false; - } - - if (lodashGet(file, 'size', 0) < CONST.API_ATTACHMENT_VALIDATIONS.MIN_SIZE) { - setUploadReceiptError(true, 'attachmentPicker.attachmentTooSmall', 'attachmentPicker.sizeNotMet'); - return false; - } - - return true; - } - - /** - * Sets the Receipt objects and navigates the user to the next page - * @param {Object} file - * @param {Object} iouObject - * @param {Object} reportObject - */ - const setReceiptAndNavigate = (file, iouObject, reportObject) => { - if (!validateReceipt(file)) { - return; - } - - const filePath = URL.createObjectURL(file); - IOU.setMoneyRequestReceipt(filePath, file.name); - - if (transactionID) { - IOU.replaceReceipt(transactionID, file, filePath); - Navigation.dismissModal(); - return; - } - - IOU.navigateToNextPage(iouObject, iouType, reportObject, route.path); - }; - - const capturePhoto = useCallback(() => { - if (!cameraRef.current.getScreenshot) { - return; - } - const imageBase64 = cameraRef.current.getScreenshot(); - const filename = `receipt_${Date.now()}.png`; - const imageFile = FileUtils.base64ToFile(imageBase64, filename); - const filePath = URL.createObjectURL(imageFile); - IOU.setMoneyRequestReceipt(filePath, imageFile.name); - - if (transactionID) { - IOU.replaceReceipt(transactionID, imageFile, filePath); - Navigation.dismissModal(); - return; - } - - IOU.navigateToNextPage(iou, iouType, report, route.path); - }, [cameraRef, iou, report, iouType, transactionID, route.path]); - - const panResponder = useRef( - PanResponder.create({ - onPanResponderTerminationRequest: () => false, - }), - ).current; - - const mobileCameraView = () => ( - <> - - {(cameraPermissionState === 'prompt' || !cameraPermissionState) && ( - - )} - - {cameraPermissionState === 'denied' && ( - - - {translate('receipt.takePhoto')} - {translate('receipt.cameraAccess')} - - )} - setCameraPermissionState('granted')} - onUserMediaError={() => setCameraPermissionState('denied')} - style={{...styles.videoContainer, display: cameraPermissionState !== 'granted' ? 'none' : 'block'}} - ref={cameraRef} - screenshotFormat="image/png" - videoConstraints={{facingMode: {exact: 'environment'}}} - torchOn={isFlashLightOn} - onTorchAvailability={setIsTorchAvailable} - forceScreenshotSourceSize - cameraTabIndex={pageIndex} - /> - - - - - {({openPicker}) => ( - { - openPicker({ - onPicked: (file) => { - setReceiptAndNavigate(file, iou, report); - }, - }); - }} - > - - - )} - - - - - - - - - - ); - - const desktopUploadView = () => ( - <> - setReceiptImageTopPosition(PixelRatio.roundToNearestPixel(nativeEvent.layout.top))}> - - - - - {translate('receipt.upload')} - - {isSmallScreenWidth ? translate('receipt.chooseReceipt') : translate('receipt.dragReceiptBeforeEmail')} - - {isSmallScreenWidth ? null : translate('receipt.dragReceiptAfterEmail')} - - - - - {({openPicker}) => ( -