From feb57aed753c1f464331bafe2b27fda03c217dfe Mon Sep 17 00:00:00 2001 From: dukenv0307 Date: Thu, 11 Jan 2024 21:12:49 +0700 Subject: [PATCH 01/57] fix: 34120 --- src/components/DistanceEReceipt.js | 1 + src/components/Image/index.js | 10 +++++-- src/components/Image/index.native.js | 26 ++++++++++++++++++- src/components/ImageWithSizeCalculation.tsx | 5 +++- .../MoneyRequestConfirmationList.js | 1 + ...oraryForRefactorRequestConfirmationList.js | 1 + .../ReportActionItem/ReportActionItemImage.js | 12 ++++++--- src/components/ThumbnailImage.tsx | 4 ++- .../Navigation/AppNavigator/AuthScreens.tsx | 2 +- src/pages/ErrorPage/NotFoundPage.js | 1 + 10 files changed, 53 insertions(+), 10 deletions(-) diff --git a/src/components/DistanceEReceipt.js b/src/components/DistanceEReceipt.js index 0241eea44063..5ffece092770 100644 --- a/src/components/DistanceEReceipt.js +++ b/src/components/DistanceEReceipt.js @@ -72,6 +72,7 @@ function DistanceEReceipt({transaction}) { style={[styles.w100, styles.h100]} isAuthTokenRequired shouldDynamicallyResize={false} + objectPositionTop /> )} diff --git a/src/components/Image/index.js b/src/components/Image/index.js index ef1a69e19c12..58b7ec3383a4 100644 --- a/src/components/Image/index.js +++ b/src/components/Image/index.js @@ -1,5 +1,5 @@ import lodashGet from 'lodash/get'; -import React, {useEffect, useMemo} from 'react'; +import React, {useEffect, useMemo, useState} from 'react'; import {Image as RNImage} from 'react-native'; import {withOnyx} from 'react-native-onyx'; import _ from 'underscore'; @@ -9,6 +9,7 @@ import RESIZE_MODES from './resizeModes'; function Image(props) { const {source: propsSource, isAuthTokenRequired, onLoad, session} = props; + const [aspectRatio, setAspectRatio] = useState(); /** * Check if the image source is a URL - if so the `encryptedAuthToken` is appended * to the source. @@ -38,8 +39,12 @@ function Image(props) { } RNImage.getSize(source.uri, (width, height) => { onLoad({nativeEvent: {width, height}}); + + if (props.objectPositionTop) { + setAspectRatio(height ? width / height : 'auto'); + } }); - }, [onLoad, source]); + }, [onLoad, source, props.objectPositionTop]); // Omit the props which the underlying RNImage won't use const forwardedProps = _.omit(props, ['source', 'onLoad', 'session', 'isAuthTokenRequired']); @@ -49,6 +54,7 @@ function Image(props) { // eslint-disable-next-line react/jsx-props-no-spreading {...forwardedProps} source={source} + style={[forwardedProps.style, aspectRatio !== undefined && {aspectRatio, height: 'auto'}, props.objectPositionTop && !aspectRatio && {opacity: 0}]} /> ); } diff --git a/src/components/Image/index.native.js b/src/components/Image/index.native.js index f31cfb6936d9..edea86725ae7 100644 --- a/src/components/Image/index.native.js +++ b/src/components/Image/index.native.js @@ -1,11 +1,12 @@ import {Image as ImageComponent} from 'expo-image'; import lodashGet from 'lodash/get'; -import React from 'react'; +import React, {useEffect, useMemo, useState} from 'react'; import {withOnyx} from 'react-native-onyx'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import {defaultProps, imagePropTypes} from './imagePropTypes'; import RESIZE_MODES from './resizeModes'; +import {Image as RNImage} from 'react-native'; const dimensionsCache = new Map(); @@ -16,6 +17,7 @@ function resolveDimensions(key) { function Image(props) { // eslint-disable-next-line react/destructuring-assignment const {source, isAuthTokenRequired, session, ...rest} = props; + const [aspectRatio, setAspectRatio] = useState(); let imageSource = source; if (source && source.uri && typeof source.uri === 'number') { @@ -33,6 +35,27 @@ function Image(props) { }; } + const newSource = useMemo(() => { + if (isAuthTokenRequired) { + const authToken = lodashGet(session, 'encryptedAuthToken', null); + return {uri: `${source.uri}?encryptedAuthToken=${encodeURIComponent(authToken)}`}; + } + return source; + }, [source, isAuthTokenRequired]); + + useEffect(() => { + if (props.onLoad == null) { + return; + } + RNImage.getSize(newSource.uri, (width, height) => { + props.onLoad({nativeEvent: {width, height}}); + + if (props.objectPositionTop) { + setAspectRatio(height ? width / height : 'auto'); + } + }); + }, [props.onLoad, newSource]); + return ( ); } diff --git a/src/components/ImageWithSizeCalculation.tsx b/src/components/ImageWithSizeCalculation.tsx index b13d863d97e1..7ebdd41379c1 100644 --- a/src/components/ImageWithSizeCalculation.tsx +++ b/src/components/ImageWithSizeCalculation.tsx @@ -29,6 +29,8 @@ type ImageWithSizeCalculationProps = { /** Whether the image requires an authToken */ isAuthTokenRequired: boolean; + + objectPositionTop: boolean; }; /** @@ -37,7 +39,7 @@ type ImageWithSizeCalculationProps = { * performing some calculation on a network image after fetching dimensions so * it can be appropriately resized. */ -function ImageWithSizeCalculation({url, style, onMeasure, isAuthTokenRequired}: ImageWithSizeCalculationProps) { +function ImageWithSizeCalculation({url, style, onMeasure, isAuthTokenRequired, objectPositionTop}: ImageWithSizeCalculationProps) { const styles = useThemeStyles(); const isLoadedRef = useRef(null); const [isImageCached, setIsImageCached] = useState(true); @@ -88,6 +90,7 @@ function ImageWithSizeCalculation({url, style, onMeasure, isAuthTokenRequired}: }} onError={onError} onLoad={imageLoadedSuccessfully} + objectPositionTop={objectPositionTop} /> {isLoading && !isImageCached && } diff --git a/src/components/MoneyRequestConfirmationList.js b/src/components/MoneyRequestConfirmationList.js index 13dce9337673..aa33ef87a976 100755 --- a/src/components/MoneyRequestConfirmationList.js +++ b/src/components/MoneyRequestConfirmationList.js @@ -612,6 +612,7 @@ function MoneyRequestConfirmationList(props) { // but we don't need it to load the blob:// or file:// image when starting a money request / split bill // So if we have a thumbnail, it means we're retrieving the image from the server isAuthTokenRequired={!_.isEmpty(receiptThumbnail)} + objectPositionTop /> )} {props.shouldShowSmartScanFields && ( diff --git a/src/components/MoneyTemporaryForRefactorRequestConfirmationList.js b/src/components/MoneyTemporaryForRefactorRequestConfirmationList.js index 36d424ea28f2..2888f7cf2cdf 100755 --- a/src/components/MoneyTemporaryForRefactorRequestConfirmationList.js +++ b/src/components/MoneyTemporaryForRefactorRequestConfirmationList.js @@ -646,6 +646,7 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ // but we don't need it to load the blob:// or file:// image when starting a money request / split bill // So if we have a thumbnail, it means we're retrieving the image from the server isAuthTokenRequired={!_.isEmpty(receiptThumbnail)} + objectPositionTop /> )} {shouldShowSmartScanFields && ( diff --git a/src/components/ReportActionItem/ReportActionItemImage.js b/src/components/ReportActionItem/ReportActionItemImage.js index 1495dcbd9111..d8f461aec138 100644 --- a/src/components/ReportActionItem/ReportActionItemImage.js +++ b/src/components/ReportActionItem/ReportActionItemImage.js @@ -72,14 +72,18 @@ function ReportActionItemImage({thumbnail, image, enablePreviewModal, transactio style={[styles.w100, styles.h100]} isAuthTokenRequired shouldDynamicallyResize={false} + objectPositionTop /> ); } else { receiptImageComponent = ( - + + + ); } diff --git a/src/components/ThumbnailImage.tsx b/src/components/ThumbnailImage.tsx index 3c903ee9e78f..b0fecd07093d 100644 --- a/src/components/ThumbnailImage.tsx +++ b/src/components/ThumbnailImage.tsx @@ -26,6 +26,7 @@ type ThumbnailImageProps = { /** Should the image be resized on load or just fit container */ shouldDynamicallyResize?: boolean; + objectPositionTop?: boolean; }; type UpdateImageSizeParams = { @@ -71,7 +72,7 @@ function calculateThumbnailImageSize(width: number, height: number, windowHeight return {thumbnailWidth: Math.max(40, thumbnailScreenWidth), thumbnailHeight: Math.max(40, thumbnailScreenHeight)}; } -function ThumbnailImage({previewSourceURL, style, isAuthTokenRequired, imageWidth = 200, imageHeight = 200, shouldDynamicallyResize = true}: ThumbnailImageProps) { +function ThumbnailImage({previewSourceURL, style, isAuthTokenRequired, imageWidth, imageHeight, shouldDynamicallyResize = true, objectPositionTop = false}: ThumbnailImageProps) { const styles = useThemeStyles(); const StyleUtils = useStyleUtils(); const {windowHeight} = useWindowDimensions(); @@ -103,6 +104,7 @@ function ThumbnailImage({previewSourceURL, style, isAuthTokenRequired, imageWidt url={previewSourceURL} onMeasure={updateImageSize} isAuthTokenRequired={isAuthTokenRequired} + objectPositionTop={objectPositionTop} /> diff --git a/src/libs/Navigation/AppNavigator/AuthScreens.tsx b/src/libs/Navigation/AppNavigator/AuthScreens.tsx index 7286615e6ba6..caeb65fbaa3a 100644 --- a/src/libs/Navigation/AppNavigator/AuthScreens.tsx +++ b/src/libs/Navigation/AppNavigator/AuthScreens.tsx @@ -291,7 +291,7 @@ function AuthScreens({lastUpdateIDAppliedToClient, session, lastOpenedPublicRoom Navigation.navigate(ROUTES.HOME)}/>} /> ); From 0eeedc9bca10abc6554bd2eb5e412a35e9bbe835 Mon Sep 17 00:00:00 2001 From: dukenv0307 Date: Thu, 11 Jan 2024 21:19:21 +0700 Subject: [PATCH 02/57] fix: redundant --- src/components/ThumbnailImage.tsx | 2 +- src/libs/Navigation/AppNavigator/AuthScreens.tsx | 2 +- src/pages/ErrorPage/NotFoundPage.js | 1 - 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/components/ThumbnailImage.tsx b/src/components/ThumbnailImage.tsx index b0fecd07093d..b04a67fbdc7d 100644 --- a/src/components/ThumbnailImage.tsx +++ b/src/components/ThumbnailImage.tsx @@ -72,7 +72,7 @@ function calculateThumbnailImageSize(width: number, height: number, windowHeight return {thumbnailWidth: Math.max(40, thumbnailScreenWidth), thumbnailHeight: Math.max(40, thumbnailScreenHeight)}; } -function ThumbnailImage({previewSourceURL, style, isAuthTokenRequired, imageWidth, imageHeight, shouldDynamicallyResize = true, objectPositionTop = false}: ThumbnailImageProps) { +function ThumbnailImage({previewSourceURL, style, isAuthTokenRequired, imageWidth = 200, imageHeight = 200, shouldDynamicallyResize = true, objectPositionTop = false}: ThumbnailImageProps) { const styles = useThemeStyles(); const StyleUtils = useStyleUtils(); const {windowHeight} = useWindowDimensions(); diff --git a/src/libs/Navigation/AppNavigator/AuthScreens.tsx b/src/libs/Navigation/AppNavigator/AuthScreens.tsx index caeb65fbaa3a..7286615e6ba6 100644 --- a/src/libs/Navigation/AppNavigator/AuthScreens.tsx +++ b/src/libs/Navigation/AppNavigator/AuthScreens.tsx @@ -291,7 +291,7 @@ function AuthScreens({lastUpdateIDAppliedToClient, session, lastOpenedPublicRoom Navigation.navigate(ROUTES.HOME)}/>} + component={NotFoundPage} /> ); From 5e5adb85b0a05d0d57d4fc3cbc7521d59edc0b59 Mon Sep 17 00:00:00 2001 From: dukenv0307 Date: Wed, 24 Jan 2024 16:17:03 +0700 Subject: [PATCH 03/57] fix lint --- src/components/Image/index.native.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/Image/index.native.js b/src/components/Image/index.native.js index edea86725ae7..1c7b239f6acc 100644 --- a/src/components/Image/index.native.js +++ b/src/components/Image/index.native.js @@ -1,12 +1,12 @@ import {Image as ImageComponent} from 'expo-image'; import lodashGet from 'lodash/get'; import React, {useEffect, useMemo, useState} from 'react'; +import {Image as RNImage} from 'react-native'; import {withOnyx} from 'react-native-onyx'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import {defaultProps, imagePropTypes} from './imagePropTypes'; import RESIZE_MODES from './resizeModes'; -import {Image as RNImage} from 'react-native'; const dimensionsCache = new Map(); From 2e260e62b64f2c0d8601b006a59037b9fbd12fcc Mon Sep 17 00:00:00 2001 From: dukenv0307 Date: Wed, 24 Jan 2024 17:09:22 +0700 Subject: [PATCH 04/57] fix lint --- src/components/Image/index.native.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/Image/index.native.js b/src/components/Image/index.native.js index 1c7b239f6acc..f221a3a15019 100644 --- a/src/components/Image/index.native.js +++ b/src/components/Image/index.native.js @@ -41,7 +41,7 @@ function Image(props) { return {uri: `${source.uri}?encryptedAuthToken=${encodeURIComponent(authToken)}`}; } return source; - }, [source, isAuthTokenRequired]); + }, [source, isAuthTokenRequired, session]); useEffect(() => { if (props.onLoad == null) { @@ -54,7 +54,7 @@ function Image(props) { setAspectRatio(height ? width / height : 'auto'); } }); - }, [props.onLoad, newSource]); + }, [props.onLoad, newSource, props]); return ( Date: Fri, 26 Jan 2024 11:35:09 +0700 Subject: [PATCH 05/57] fix crash bug --- src/components/Image/index.js | 4 ++-- src/components/Image/index.native.js | 26 ++++---------------------- 2 files changed, 6 insertions(+), 24 deletions(-) diff --git a/src/components/Image/index.js b/src/components/Image/index.js index 58b7ec3383a4..f4962ad9b324 100644 --- a/src/components/Image/index.js +++ b/src/components/Image/index.js @@ -9,7 +9,7 @@ import RESIZE_MODES from './resizeModes'; function Image(props) { const {source: propsSource, isAuthTokenRequired, onLoad, session} = props; - const [aspectRatio, setAspectRatio] = useState(); + const [aspectRatio, setAspectRatio] = useState(null); /** * Check if the image source is a URL - if so the `encryptedAuthToken` is appended * to the source. @@ -54,7 +54,7 @@ function Image(props) { // eslint-disable-next-line react/jsx-props-no-spreading {...forwardedProps} source={source} - style={[forwardedProps.style, aspectRatio !== undefined && {aspectRatio, height: 'auto'}, props.objectPositionTop && !aspectRatio && {opacity: 0}]} + style={[forwardedProps.style, !!aspectRatio && {aspectRatio, height: 'auto'}, props.objectPositionTop && !aspectRatio && {opacity: 0}]} /> ); } diff --git a/src/components/Image/index.native.js b/src/components/Image/index.native.js index f221a3a15019..7da72c34a012 100644 --- a/src/components/Image/index.native.js +++ b/src/components/Image/index.native.js @@ -35,27 +35,6 @@ function Image(props) { }; } - const newSource = useMemo(() => { - if (isAuthTokenRequired) { - const authToken = lodashGet(session, 'encryptedAuthToken', null); - return {uri: `${source.uri}?encryptedAuthToken=${encodeURIComponent(authToken)}`}; - } - return source; - }, [source, isAuthTokenRequired, session]); - - useEffect(() => { - if (props.onLoad == null) { - return; - } - RNImage.getSize(newSource.uri, (width, height) => { - props.onLoad({nativeEvent: {width, height}}); - - if (props.objectPositionTop) { - setAspectRatio(height ? width / height : 'auto'); - } - }); - }, [props.onLoad, newSource, props]); - return ( ); } From 7c9c40ff933a7d2d47a39a5f391101863551aa00 Mon Sep 17 00:00:00 2001 From: dukenv0307 Date: Fri, 26 Jan 2024 17:01:55 +0700 Subject: [PATCH 06/57] fix lint --- src/components/Image/index.native.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/components/Image/index.native.js b/src/components/Image/index.native.js index 7da72c34a012..862807b909bb 100644 --- a/src/components/Image/index.native.js +++ b/src/components/Image/index.native.js @@ -1,7 +1,6 @@ import {Image as ImageComponent} from 'expo-image'; import lodashGet from 'lodash/get'; -import React, {useEffect, useMemo, useState} from 'react'; -import {Image as RNImage} from 'react-native'; +import React, { useState } from 'react'; import {withOnyx} from 'react-native-onyx'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; From a153e8a46181c676adfd995ce00759e7b4e6b5cb Mon Sep 17 00:00:00 2001 From: dukenv0307 Date: Fri, 26 Jan 2024 17:41:00 +0700 Subject: [PATCH 07/57] fix lint --- src/components/Image/index.native.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/Image/index.native.js b/src/components/Image/index.native.js index 862807b909bb..2791ea40925d 100644 --- a/src/components/Image/index.native.js +++ b/src/components/Image/index.native.js @@ -1,6 +1,6 @@ import {Image as ImageComponent} from 'expo-image'; import lodashGet from 'lodash/get'; -import React, { useState } from 'react'; +import React, {useState} from 'react'; import {withOnyx} from 'react-native-onyx'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; From 21253021d96298966edad453518aec24aeb0c60f Mon Sep 17 00:00:00 2001 From: dukenv0307 Date: Tue, 30 Jan 2024 16:29:37 +0700 Subject: [PATCH 08/57] fix the case wide image --- src/components/Image/index.js | 4 ++++ src/components/Image/index.native.js | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/src/components/Image/index.js b/src/components/Image/index.js index f4962ad9b324..848e64f60350 100644 --- a/src/components/Image/index.js +++ b/src/components/Image/index.js @@ -41,6 +41,10 @@ function Image(props) { onLoad({nativeEvent: {width, height}}); if (props.objectPositionTop) { + if (width > height) { + setAspectRatio(1); + return; + } setAspectRatio(height ? width / height : 'auto'); } }); diff --git a/src/components/Image/index.native.js b/src/components/Image/index.native.js index 2791ea40925d..b6d5f5b2dcda 100644 --- a/src/components/Image/index.native.js +++ b/src/components/Image/index.native.js @@ -46,6 +46,10 @@ function Image(props) { props.onLoad({nativeEvent: {width, height}}); } if (props.objectPositionTop) { + if (width > height) { + setAspectRatio(1); + return; + } setAspectRatio(height ? width / height : 'auto'); } }} From 00ccc9bd4e75c8a480313f11ecf986725eb6a83e Mon Sep 17 00:00:00 2001 From: dukenv0307 Date: Tue, 30 Jan 2024 16:34:02 +0700 Subject: [PATCH 09/57] add comment prop --- src/components/Image/imagePropTypes.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/components/Image/imagePropTypes.js b/src/components/Image/imagePropTypes.js index 78bd48ba47ec..cc4c36e32387 100644 --- a/src/components/Image/imagePropTypes.js +++ b/src/components/Image/imagePropTypes.js @@ -34,6 +34,9 @@ const imagePropTypes = { /** Currently logged in user authToken */ authToken: PropTypes.string, }), + + /** Whether we should show the top of the image */ + objectPositionTop: PropTypes.string }; const defaultProps = { @@ -43,6 +46,7 @@ const defaultProps = { }, isAuthTokenRequired: false, resizeMode: RESIZE_MODES.cover, + objectPositionTop: false, onLoadStart: () => {}, onLoadEnd: () => {}, onLoad: () => {}, From c761e1c17e8795c514904e167f23e42c9fa7aa27 Mon Sep 17 00:00:00 2001 From: dukenv0307 Date: Tue, 30 Jan 2024 18:08:45 +0700 Subject: [PATCH 10/57] merge main --- src/components/Image/imagePropTypes.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/Image/imagePropTypes.js b/src/components/Image/imagePropTypes.js index cc4c36e32387..5d28b1a9f3f4 100644 --- a/src/components/Image/imagePropTypes.js +++ b/src/components/Image/imagePropTypes.js @@ -36,7 +36,7 @@ const imagePropTypes = { }), /** Whether we should show the top of the image */ - objectPositionTop: PropTypes.string + objectPositionTop: PropTypes.string, }; const defaultProps = { From d09ee205845c7b47eb4b6cdc49c803dc8be43918 Mon Sep 17 00:00:00 2001 From: dukenv0307 Date: Fri, 2 Feb 2024 10:41:02 +0700 Subject: [PATCH 11/57] centralize logic --- src/components/Image/BaseImage.native.tsx | 16 +++------------- src/components/Image/BaseImage.tsx | 16 +++------------- src/components/Image/index.js | 22 ++++++++++++++++++++-- 3 files changed, 26 insertions(+), 28 deletions(-) diff --git a/src/components/Image/BaseImage.native.tsx b/src/components/Image/BaseImage.native.tsx index e912bdda9eba..c517efd04515 100644 --- a/src/components/Image/BaseImage.native.tsx +++ b/src/components/Image/BaseImage.native.tsx @@ -1,10 +1,9 @@ import {Image as ExpoImage} from 'expo-image'; import type {ImageProps as ExpoImageProps, ImageLoadEventData} from 'expo-image'; -import {useCallback, useState} from 'react'; +import {useCallback} from 'react'; import type {BaseImageProps} from './types'; -function BaseImage({onLoad, objectPositionTop = false, style, ...props}: ExpoImageProps & BaseImageProps) { - const [aspectRatio, setAspectRatio] = useState(null); +function BaseImage({onLoad, ...props}: ExpoImageProps & BaseImageProps) { const imageLoadedSuccessfully = useCallback( (event: ImageLoadEventData) => { if (!onLoad) { @@ -14,23 +13,14 @@ function BaseImage({onLoad, objectPositionTop = false, style, ...props}: ExpoIma // We override `onLoad`, so both web and native have the same signature const {width, height} = event.source; onLoad({nativeEvent: {width, height}}); - - if (objectPositionTop) { - if (width > height) { - setAspectRatio(1); - return; - } - setAspectRatio(height ? width / height : 'auto'); - } }, - [onLoad, objectPositionTop], + [onLoad], ); return ( diff --git a/src/components/Image/BaseImage.tsx b/src/components/Image/BaseImage.tsx index 9a3f4668647e..ebdd76840267 100644 --- a/src/components/Image/BaseImage.tsx +++ b/src/components/Image/BaseImage.tsx @@ -1,10 +1,9 @@ -import React, {useCallback, useState} from 'react'; +import React, {useCallback} from 'react'; import {Image as RNImage} from 'react-native'; import type {ImageLoadEventData, ImageProps as WebImageProps} from 'react-native'; import type {BaseImageProps} from './types'; -function BaseImage({onLoad, objectPositionTop = false, style, ...props}: WebImageProps & BaseImageProps) { - const [aspectRatio, setAspectRatio] = useState(null); +function BaseImage({onLoad, ...props}: WebImageProps & BaseImageProps) { const imageLoadedSuccessfully = useCallback( (event: {nativeEvent: ImageLoadEventData}) => { if (!onLoad) { @@ -14,23 +13,14 @@ function BaseImage({onLoad, objectPositionTop = false, style, ...props}: WebImag // We override `onLoad`, so both web and native have the same signature const {width, height} = event.nativeEvent.source; onLoad({nativeEvent: {width, height}}); - - if (objectPositionTop) { - if (width > height) { - setAspectRatio(1); - return; - } - setAspectRatio(height ? width / height : 'auto'); - } }, - [onLoad, objectPositionTop], + [onLoad], ); return ( diff --git a/src/components/Image/index.js b/src/components/Image/index.js index 8cee1cf95e14..2788e85895f6 100644 --- a/src/components/Image/index.js +++ b/src/components/Image/index.js @@ -1,5 +1,5 @@ import lodashGet from 'lodash/get'; -import React, {useMemo} from 'react'; +import React, {useCallback, useMemo} from 'react'; import {withOnyx} from 'react-native-onyx'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; @@ -7,7 +7,9 @@ import BaseImage from './BaseImage'; import {defaultProps, imagePropTypes} from './imagePropTypes'; import RESIZE_MODES from './resizeModes'; -function Image({source: propsSource, isAuthTokenRequired, session, ...forwardedProps}) { +function Image({source: propsSource, isAuthTokenRequired, session, onLoad, ...forwardedProps}) { + const [aspectRatio, setAspectRatio] = useState(null); + // Update the source to include the auth token if required const source = useMemo(() => { if (typeof lodashGet(propsSource, 'uri') === 'number') { @@ -28,11 +30,27 @@ function Image({source: propsSource, isAuthTokenRequired, session, ...forwardedP // eslint-disable-next-line react-hooks/exhaustive-deps }, [propsSource, isAuthTokenRequired]); + const imageLoadedSuccessfully = useCallback((event) => { + const {width, height} = event.nativeEvent; + + onLoad(event); + + if (objectPositionTop) { + if (width > height) { + setAspectRatio(1); + return; + } + setAspectRatio(height ? width / height : 'auto'); + } + }) + return ( ); } From 7cf8fd81cf99cd3a8cfa869f33be36c271081e65 Mon Sep 17 00:00:00 2001 From: dukenv0307 Date: Fri, 2 Feb 2024 10:56:55 +0700 Subject: [PATCH 12/57] fix lint --- src/components/Image/imagePropTypes.js | 2 +- src/components/Image/index.js | 29 ++++++++++++++------------ src/components/Image/types.ts | 3 --- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/components/Image/imagePropTypes.js b/src/components/Image/imagePropTypes.js index 5d28b1a9f3f4..deb7d75da5ae 100644 --- a/src/components/Image/imagePropTypes.js +++ b/src/components/Image/imagePropTypes.js @@ -36,7 +36,7 @@ const imagePropTypes = { }), /** Whether we should show the top of the image */ - objectPositionTop: PropTypes.string, + objectPositionTop: PropTypes.bool, }; const defaultProps = { diff --git a/src/components/Image/index.js b/src/components/Image/index.js index 2788e85895f6..6851604be8b1 100644 --- a/src/components/Image/index.js +++ b/src/components/Image/index.js @@ -1,5 +1,5 @@ import lodashGet from 'lodash/get'; -import React, {useCallback, useMemo} from 'react'; +import React, {useCallback, useMemo, useState} from 'react'; import {withOnyx} from 'react-native-onyx'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; @@ -7,8 +7,8 @@ import BaseImage from './BaseImage'; import {defaultProps, imagePropTypes} from './imagePropTypes'; import RESIZE_MODES from './resizeModes'; -function Image({source: propsSource, isAuthTokenRequired, session, onLoad, ...forwardedProps}) { - const [aspectRatio, setAspectRatio] = useState(null); +function Image({source: propsSource, isAuthTokenRequired, session, onLoad, style, objectPositionTop, ...forwardedProps}) { + const [aspectRatio, setAspectRatio] = useState(null); // Update the source to include the auth token if required const source = useMemo(() => { @@ -30,19 +30,22 @@ function Image({source: propsSource, isAuthTokenRequired, session, onLoad, ...fo // eslint-disable-next-line react-hooks/exhaustive-deps }, [propsSource, isAuthTokenRequired]); - const imageLoadedSuccessfully = useCallback((event) => { - const {width, height} = event.nativeEvent; + const imageLoadedSuccessfully = useCallback( + (event) => { + const {width, height} = event.nativeEvent; - onLoad(event); + onLoad(event); - if (objectPositionTop) { - if (width > height) { - setAspectRatio(1); - return; + if (objectPositionTop) { + if (width > height) { + setAspectRatio(1); + return; + } + setAspectRatio(height ? width / height : 'auto'); } - setAspectRatio(height ? width / height : 'auto'); - } - }) + }, + [onLoad, objectPositionTop], + ); return ( void; - - /** Whether we should show the top of the image */ - objectPositionTop?: boolean; }; export type {BaseImageProps}; From 86190f61d6f9f090ea0714939a15685c57cdc246 Mon Sep 17 00:00:00 2001 From: dukenv0307 Date: Tue, 6 Feb 2024 01:01:01 +0700 Subject: [PATCH 13/57] revert hard code --- .../ReportActionItem/ReportActionItemImage.tsx | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/components/ReportActionItem/ReportActionItemImage.tsx b/src/components/ReportActionItem/ReportActionItemImage.tsx index 7dc4cdf07031..ed46e00c7923 100644 --- a/src/components/ReportActionItem/ReportActionItemImage.tsx +++ b/src/components/ReportActionItem/ReportActionItemImage.tsx @@ -73,13 +73,11 @@ function ReportActionItemImage({thumbnail, image, enablePreviewModal = false, tr ); } else { receiptImageComponent = ( - - - + ); } From 54d0bb9d340926b8997c8b1d584321554d49ecec Mon Sep 17 00:00:00 2001 From: dukenv0307 Date: Wed, 20 Mar 2024 12:08:37 +0700 Subject: [PATCH 14/57] fix lint --- src/components/Image/index.tsx | 36 +++++++++++++++++++-- src/components/Image/types.ts | 7 ++-- src/components/ImageWithSizeCalculation.tsx | 5 +-- 3 files changed, 41 insertions(+), 7 deletions(-) diff --git a/src/components/Image/index.tsx b/src/components/Image/index.tsx index f4e5bf4834e0..c8c78b54de06 100644 --- a/src/components/Image/index.tsx +++ b/src/components/Image/index.tsx @@ -1,11 +1,39 @@ -import React, {useMemo} from 'react'; +import React, {useCallback, useMemo, useState} from 'react'; import {withOnyx} from 'react-native-onyx'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import BaseImage from './BaseImage'; -import type {ImageOnyxProps, ImageOwnProps, ImageProps} from './types'; +import type {ImageOnLoadEvent, ImageOnyxProps, ImageOwnProps, ImageProps} from './types'; -function Image({source: propsSource, isAuthTokenRequired = false, session, ...forwardedProps}: ImageProps) { +function Image({source: propsSource, isAuthTokenRequired = false, session, onLoad, objectPositionTop, style, ...forwardedProps}: ImageProps) { + const [aspectRatio, setAspectRatio] = useState(null); + + const updateAspectRatio = useCallback( + (width: number, height: number) => { + if (!objectPositionTop) { + return; + } + + if (width > height) { + setAspectRatio(1); + return; + } + + setAspectRatio(height ? width / height : 'auto'); + }, + [objectPositionTop], + ); + + const handleLoad = useCallback( + (event: ImageOnLoadEvent) => { + const {width, height} = event.nativeEvent; + + onLoad?.(event); + + updateAspectRatio(width, height); + }, + [onLoad, updateAspectRatio], + ); /** * Check if the image source is a URL - if so the `encryptedAuthToken` is appended * to the source. @@ -34,6 +62,8 @@ function Image({source: propsSource, isAuthTokenRequired = false, session, ...fo ); diff --git a/src/components/Image/types.ts b/src/components/Image/types.ts index 2a5fcbb19324..c2f73e74ee34 100644 --- a/src/components/Image/types.ts +++ b/src/components/Image/types.ts @@ -23,12 +23,12 @@ type BaseImageProps = { /** Event for when the image is fully loaded and returns the natural dimensions of the image */ onLoad?: (event: ImageOnLoadEvent) => void; -}; -type ImageOwnProps = BaseImageProps & { /** Styles for the Image */ style?: StyleProp; +}; +type ImageOwnProps = BaseImageProps & { /** Should an auth token be included in the image request */ isAuthTokenRequired?: boolean; @@ -46,6 +46,9 @@ type ImageOwnProps = BaseImageProps & { /** Progress events while the image is downloading */ onProgress?: () => void; + + /** Whether we should show the top of the image */ + objectPositionTop?: boolean; }; type ImageProps = ImageOnyxProps & ImageOwnProps; diff --git a/src/components/ImageWithSizeCalculation.tsx b/src/components/ImageWithSizeCalculation.tsx index 46e1308692ba..ffa9517299cc 100644 --- a/src/components/ImageWithSizeCalculation.tsx +++ b/src/components/ImageWithSizeCalculation.tsx @@ -33,7 +33,8 @@ type ImageWithSizeCalculationProps = { /** Whether the image requires an authToken */ isAuthTokenRequired: boolean; - objectPositionTop: boolean; + /** Whether we should show the top of the image */ + objectPositionTop?: boolean; }; /** @@ -42,7 +43,7 @@ type ImageWithSizeCalculationProps = { * performing some calculation on a network image after fetching dimensions so * it can be appropriately resized. */ -function ImageWithSizeCalculation({url, style, onMeasure, onLoadFailure, isAuthTokenRequired, objectPositionTop}: ImageWithSizeCalculationProps) { +function ImageWithSizeCalculation({url, style, onMeasure, onLoadFailure, isAuthTokenRequired, objectPositionTop = false}: ImageWithSizeCalculationProps) { const styles = useThemeStyles(); const isLoadedRef = useRef(null); const [isImageCached, setIsImageCached] = useState(true); From 5b1c8835707f9c7c8daf6ed6283a2e97f6d75707 Mon Sep 17 00:00:00 2001 From: dukenv0307 Date: Thu, 21 Mar 2024 17:33:55 +0700 Subject: [PATCH 15/57] replace objectPositionTop with objectPosition --- src/CONST.ts | 5 +++++ src/components/DistanceEReceipt.tsx | 2 +- src/components/Image/index.tsx | 9 +++++---- src/components/Image/types.ts | 10 +++++++--- src/components/ImageWithSizeCalculation.tsx | 10 ++++++---- src/components/MoneyRequestConfirmationList.tsx | 2 +- ...MoneyTemporaryForRefactorRequestConfirmationList.js | 2 +- .../ReportActionItem/ReportActionItemImage.tsx | 4 ++-- src/components/ThumbnailImage.tsx | 10 +++++++--- 9 files changed, 35 insertions(+), 19 deletions(-) diff --git a/src/CONST.ts b/src/CONST.ts index bb191ac5e028..3cd473f2f451 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -1095,6 +1095,11 @@ const CONST = { JPEG: 'image/jpeg', }, + IMAGE_OBJECT_POSITION: { + TOP: 'top', + INITIAL: 'initial', + }, + FILE_TYPE_REGEX: { // Image MimeTypes allowed by iOS photos app. IMAGE: /\.(jpg|jpeg|png|webp|gif|tiff|bmp|heic|heif)$/, diff --git a/src/components/DistanceEReceipt.tsx b/src/components/DistanceEReceipt.tsx index 864dc831f74c..03ae1cdef5ad 100644 --- a/src/components/DistanceEReceipt.tsx +++ b/src/components/DistanceEReceipt.tsx @@ -63,7 +63,7 @@ function DistanceEReceipt({transaction}: DistanceEReceiptProps) { style={[styles.w100, styles.h100]} isAuthTokenRequired shouldDynamicallyResize={false} - objectPositionTop + objectPosition /> )} diff --git a/src/components/Image/index.tsx b/src/components/Image/index.tsx index c8c78b54de06..e6cecdc0d5ec 100644 --- a/src/components/Image/index.tsx +++ b/src/components/Image/index.tsx @@ -5,12 +5,13 @@ import ONYXKEYS from '@src/ONYXKEYS'; import BaseImage from './BaseImage'; import type {ImageOnLoadEvent, ImageOnyxProps, ImageOwnProps, ImageProps} from './types'; -function Image({source: propsSource, isAuthTokenRequired = false, session, onLoad, objectPositionTop, style, ...forwardedProps}: ImageProps) { +function Image({source: propsSource, isAuthTokenRequired = false, session, onLoad, objectPosition = CONST.IMAGE_OBJECT_POSITION.INITIAL, style, ...forwardedProps}: ImageProps) { const [aspectRatio, setAspectRatio] = useState(null); + const isObjectPositionTop = objectPosition === CONST.IMAGE_OBJECT_POSITION.TOP; const updateAspectRatio = useCallback( (width: number, height: number) => { - if (!objectPositionTop) { + if (!isObjectPositionTop) { return; } @@ -21,7 +22,7 @@ function Image({source: propsSource, isAuthTokenRequired = false, session, onLoa setAspectRatio(height ? width / height : 'auto'); }, - [objectPositionTop], + [isObjectPositionTop], ); const handleLoad = useCallback( @@ -63,7 +64,7 @@ function Image({source: propsSource, isAuthTokenRequired = false, session, onLoa // eslint-disable-next-line react/jsx-props-no-spreading {...forwardedProps} onLoad={handleLoad} - style={[style, aspectRatio ? {aspectRatio, height: 'auto'} : {}, objectPositionTop && !aspectRatio && {opacity: 0}]} + style={[style, aspectRatio ? {aspectRatio, height: 'auto'} : {}, isObjectPositionTop && !aspectRatio && {opacity: 0}]} source={source} /> ); diff --git a/src/components/Image/types.ts b/src/components/Image/types.ts index c2f73e74ee34..27964d8a6764 100644 --- a/src/components/Image/types.ts +++ b/src/components/Image/types.ts @@ -1,10 +1,14 @@ import type {ImageSource} from 'expo-image'; import type {ImageRequireSource, ImageResizeMode, ImageStyle, ImageURISource, StyleProp} from 'react-native'; import type {OnyxEntry} from 'react-native-onyx'; +import type {ValueOf} from 'type-fest'; +import type CONST from '@src/CONST'; import type {Session} from '@src/types/onyx'; type ExpoImageSource = ImageSource | number | ImageSource[]; +type ImageObjectPosition = ValueOf; + type ImageOnyxProps = { /** Session info for the currently logged in user. */ session: OnyxEntry; @@ -47,10 +51,10 @@ type ImageOwnProps = BaseImageProps & { /** Progress events while the image is downloading */ onProgress?: () => void; - /** Whether we should show the top of the image */ - objectPositionTop?: boolean; + /** The object position of image */ + objectPosition?: ImageObjectPosition; }; type ImageProps = ImageOnyxProps & ImageOwnProps; -export type {BaseImageProps, ImageOwnProps, ImageOnyxProps, ImageProps, ExpoImageSource, ImageOnLoadEvent}; +export type {BaseImageProps, ImageOwnProps, ImageOnyxProps, ImageProps, ExpoImageSource, ImageOnLoadEvent, ImageObjectPosition}; diff --git a/src/components/ImageWithSizeCalculation.tsx b/src/components/ImageWithSizeCalculation.tsx index ffa9517299cc..eac5c676370b 100644 --- a/src/components/ImageWithSizeCalculation.tsx +++ b/src/components/ImageWithSizeCalculation.tsx @@ -5,9 +5,11 @@ import {View} from 'react-native'; import useNetwork from '@hooks/useNetwork'; import useThemeStyles from '@hooks/useThemeStyles'; import Log from '@libs/Log'; +import CONST from '@src/CONST'; import FullscreenLoadingIndicator from './FullscreenLoadingIndicator'; import Image from './Image'; import RESIZE_MODES from './Image/resizeModes'; +import type {ImageObjectPosition} from './Image/types'; type OnMeasure = (args: {width: number; height: number}) => void; @@ -33,8 +35,8 @@ type ImageWithSizeCalculationProps = { /** Whether the image requires an authToken */ isAuthTokenRequired: boolean; - /** Whether we should show the top of the image */ - objectPositionTop?: boolean; + /** The object position of image */ + objectPosition?: ImageObjectPosition; }; /** @@ -43,7 +45,7 @@ type ImageWithSizeCalculationProps = { * performing some calculation on a network image after fetching dimensions so * it can be appropriately resized. */ -function ImageWithSizeCalculation({url, style, onMeasure, onLoadFailure, isAuthTokenRequired, objectPositionTop = false}: ImageWithSizeCalculationProps) { +function ImageWithSizeCalculation({url, style, onMeasure, onLoadFailure, isAuthTokenRequired, objectPosition = CONST.IMAGE_OBJECT_POSITION.INITIAL}: ImageWithSizeCalculationProps) { const styles = useThemeStyles(); const isLoadedRef = useRef(null); const [isImageCached, setIsImageCached] = useState(true); @@ -104,7 +106,7 @@ function ImageWithSizeCalculation({url, style, onMeasure, onLoadFailure, isAuthT }} onError={onError} onLoad={imageLoadedSuccessfully} - objectPositionTop={objectPositionTop} + objectPosition={objectPosition} /> {isLoading && !isImageCached && } diff --git a/src/components/MoneyRequestConfirmationList.tsx b/src/components/MoneyRequestConfirmationList.tsx index b2ea75cae8b0..75d156e58eaa 100755 --- a/src/components/MoneyRequestConfirmationList.tsx +++ b/src/components/MoneyRequestConfirmationList.tsx @@ -614,7 +614,7 @@ function MoneyRequestConfirmationList({ // but we don't need it to load the blob:// or file:// image when starting a money request / split bill // So if we have a thumbnail, it means we're retrieving the image from the server isAuthTokenRequired={!!receiptThumbnail} - objectPositionTop + objectPosition={CONST.IMAGE_OBJECT_POSITION.TOP} /> ) : ( // The empty receipt component should only show for IOU Requests of a paid policy ("Team" or "Corporate") diff --git a/src/components/MoneyTemporaryForRefactorRequestConfirmationList.js b/src/components/MoneyTemporaryForRefactorRequestConfirmationList.js index 08957c96128a..c32241d92096 100755 --- a/src/components/MoneyTemporaryForRefactorRequestConfirmationList.js +++ b/src/components/MoneyTemporaryForRefactorRequestConfirmationList.js @@ -906,7 +906,7 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ // but we don't need it to load the blob:// or file:// image when starting a money request / split bill // So if we have a thumbnail, it means we're retrieving the image from the server isAuthTokenRequired={!_.isEmpty(receiptThumbnail)} - objectPositionTop + objectPosition={CONST.IMAGE_OBJECT_POSITION.TOP} /> ), [receiptFilename, receiptImage, styles, receiptThumbnail, isLocalFile, isAttachmentInvalid], diff --git a/src/components/ReportActionItem/ReportActionItemImage.tsx b/src/components/ReportActionItem/ReportActionItemImage.tsx index b39cabf4e74e..3c6f6e7e2421 100644 --- a/src/components/ReportActionItem/ReportActionItemImage.tsx +++ b/src/components/ReportActionItem/ReportActionItemImage.tsx @@ -85,7 +85,7 @@ function ReportActionItemImage({thumbnail, image, enablePreviewModal = false, tr fallbackIcon={Expensicons.Receipt} fallbackIconSize={isSingleImage ? variables.iconSizeSuperLarge : variables.iconSizeExtraLarge} shouldDynamicallyResize={false} - objectPositionTop + objectPosition={CONST.IMAGE_OBJECT_POSITION.TOP} /> ); } else if (isLocalFile && filename && Str.isPDF(filename) && typeof attachmentModalSource === 'string') { @@ -100,7 +100,7 @@ function ReportActionItemImage({thumbnail, image, enablePreviewModal = false, tr ); } diff --git a/src/components/ThumbnailImage.tsx b/src/components/ThumbnailImage.tsx index d1bdfdf3ca9f..8b8da81c727a 100644 --- a/src/components/ThumbnailImage.tsx +++ b/src/components/ThumbnailImage.tsx @@ -6,9 +6,11 @@ import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; import useThumbnailDimensions from '@hooks/useThumbnailDimensions'; import variables from '@styles/variables'; +import CONST from '@src/CONST'; import type IconAsset from '@src/types/utils/IconAsset'; import Icon from './Icon'; import * as Expensicons from './Icon/Expensicons'; +import type {ImageObjectPosition} from './Image/types'; import ImageWithSizeCalculation from './ImageWithSizeCalculation'; type ThumbnailImageProps = { @@ -35,7 +37,9 @@ type ThumbnailImageProps = { /** Should the image be resized on load or just fit container */ shouldDynamicallyResize?: boolean; - objectPositionTop?: boolean; + + /** The object position of image */ + objectPosition?: ImageObjectPosition; }; type UpdateImageSizeParams = { @@ -52,7 +56,7 @@ function ThumbnailImage({ shouldDynamicallyResize = true, fallbackIcon = Expensicons.Gallery, fallbackIconSize = variables.iconSizeSuperLarge, - objectPositionTop = false, + objectPosition = CONST.IMAGE_OBJECT_POSITION.INITIAL, }: ThumbnailImageProps) { const styles = useThemeStyles(); const theme = useTheme(); @@ -104,7 +108,7 @@ function ThumbnailImage({ onMeasure={updateImageSize} onLoadFailure={() => setFailedToLoad(true)} isAuthTokenRequired={isAuthTokenRequired} - objectPositionTop={objectPositionTop} + objectPosition={objectPosition} /> From 115ec923108600f1ad167783d5acb23417effe5c Mon Sep 17 00:00:00 2001 From: dukenv0307 Date: Thu, 21 Mar 2024 17:37:50 +0700 Subject: [PATCH 16/57] update objectPosition prop --- src/components/DistanceEReceipt.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/DistanceEReceipt.tsx b/src/components/DistanceEReceipt.tsx index 03ae1cdef5ad..3d2a6a3e57b6 100644 --- a/src/components/DistanceEReceipt.tsx +++ b/src/components/DistanceEReceipt.tsx @@ -18,6 +18,7 @@ import PendingMapView from './MapView/PendingMapView'; import ScrollView from './ScrollView'; import Text from './Text'; import ThumbnailImage from './ThumbnailImage'; +import CONST from '@src/CONST'; type DistanceEReceiptProps = { /** The transaction for the distance request */ @@ -63,7 +64,7 @@ function DistanceEReceipt({transaction}: DistanceEReceiptProps) { style={[styles.w100, styles.h100]} isAuthTokenRequired shouldDynamicallyResize={false} - objectPosition + objectPosition={CONST.IMAGE_OBJECT_POSITION.TOP} /> )} From 1562a88172728730d3ad58cad1abc0e1529f7a28 Mon Sep 17 00:00:00 2001 From: dukenv0307 Date: Thu, 21 Mar 2024 18:05:42 +0700 Subject: [PATCH 17/57] fix order import --- src/components/DistanceEReceipt.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/DistanceEReceipt.tsx b/src/components/DistanceEReceipt.tsx index 3d2a6a3e57b6..2d6e3e56210f 100644 --- a/src/components/DistanceEReceipt.tsx +++ b/src/components/DistanceEReceipt.tsx @@ -8,6 +8,7 @@ import * as ReceiptUtils from '@libs/ReceiptUtils'; import * as ReportUtils from '@libs/ReportUtils'; import * as TransactionUtils from '@libs/TransactionUtils'; import tryResolveUrlFromApiRoot from '@libs/tryResolveUrlFromApiRoot'; +import CONST from '@src/CONST'; import type {TranslationPaths} from '@src/languages/types'; import type {Transaction} from '@src/types/onyx'; import type {WaypointCollection} from '@src/types/onyx/Transaction'; @@ -18,7 +19,6 @@ import PendingMapView from './MapView/PendingMapView'; import ScrollView from './ScrollView'; import Text from './Text'; import ThumbnailImage from './ThumbnailImage'; -import CONST from '@src/CONST'; type DistanceEReceiptProps = { /** The transaction for the distance request */ From 3e61229cc03c38e5e6c13b7328ee097ffb057a49 Mon Sep 17 00:00:00 2001 From: dukenv0307 Date: Mon, 25 Mar 2024 15:59:38 +0700 Subject: [PATCH 18/57] fix offline case --- .../ReportActionItem/ReportActionItemImage.tsx | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/components/ReportActionItem/ReportActionItemImage.tsx b/src/components/ReportActionItem/ReportActionItemImage.tsx index 3c6f6e7e2421..67efc75f4c24 100644 --- a/src/components/ReportActionItem/ReportActionItemImage.tsx +++ b/src/components/ReportActionItem/ReportActionItemImage.tsx @@ -6,7 +6,6 @@ import {View} from 'react-native'; import type {OnyxEntry} from 'react-native-onyx'; import EReceiptThumbnail from '@components/EReceiptThumbnail'; import * as Expensicons from '@components/Icon/Expensicons'; -import Image from '@components/Image'; import PDFThumbnail from '@components/PDFThumbnail'; import PressableWithoutFocus from '@components/Pressable/PressableWithoutFocus'; import {ShowContextMenuContext} from '@components/ShowContextMenuContext'; @@ -97,9 +96,13 @@ function ReportActionItemImage({thumbnail, image, enablePreviewModal = false, tr ); } else { receiptImageComponent = ( - ); From 4e11125e6862353dfc095b831501988a43d5cc1c Mon Sep 17 00:00:00 2001 From: FitseTLT Date: Sat, 30 Mar 2024 19:00:19 +0300 Subject: [PATCH 19/57] fixed optimistic submitted report action --- src/libs/ReportUtils.ts | 37 +++++++++++++++++++++++++++++++++---- 1 file changed, 33 insertions(+), 4 deletions(-) diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 9fa28535a7a7..cc52ce559d9b 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -3283,8 +3283,40 @@ function buildOptimisticExpenseReport(chatReportID: string, policyID: string, pa * @param paymentType - IOU paymentMethodType. Can be oneOf(Elsewhere, Expensify) * @param isSettlingUp - Whether we are settling up an IOU */ -function getIOUReportActionMessage(iouReportID: string, type: string, total: number, comment: string, currency: string, paymentType = '', isSettlingUp = false): [Message] { +function getIOUReportActionMessage(iouReportID: string, type: string, total: number, comment: string, currency: string, paymentType = '', isSettlingUp = false): Message[] { const report = getReport(iouReportID); + + if (type === CONST.REPORT.ACTIONS.TYPE.SUBMITTED) { + const policy = getPolicy(report?.policyID); + const ownerPersonalDetails = getPersonalDetailsForAccountID(policy?.ownerAccountID ?? 0); + const ownerDisplayName = ownerPersonalDetails?.displayName + ? `${ownerPersonalDetails.displayName} (${ownerPersonalDetails.login})` + : ownerPersonalDetails?.login ?? Localize.translateLocal('common.hidden'); + + return [ + { + type: CONST.REPORT.MESSAGE.TYPE.TEXT, + style: 'strong', + text: 'You', + }, + { + type: CONST.REPORT.MESSAGE.TYPE.TEXT, + style: 'normal', + text: ' submitted this report', + }, + { + type: CONST.REPORT.MESSAGE.TYPE.TEXT, + style: 'normal', + text: ' to ', + }, + { + type: CONST.REPORT.MESSAGE.TYPE.TEXT, + style: 'strong', + text: ownerDisplayName, + }, + ]; + } + const amount = type === CONST.IOU.REPORT_ACTION_TYPE.PAY ? CurrencyUtils.convertToDisplayString(getMoneyRequestSpendBreakdown(!isEmptyObject(report) ? report : null).totalDisplaySpend, currency) @@ -3306,9 +3338,6 @@ function getIOUReportActionMessage(iouReportID: string, type: string, total: num case CONST.REPORT.ACTIONS.TYPE.APPROVED: iouMessage = `approved ${amount}`; break; - case CONST.REPORT.ACTIONS.TYPE.SUBMITTED: - iouMessage = `submitted ${amount}`; - break; case CONST.IOU.REPORT_ACTION_TYPE.CREATE: iouMessage = `requested ${amount}${comment && ` for ${comment}`}`; break; From deb453cda65cc673b73114401e27bd5db2d10403 Mon Sep 17 00:00:00 2001 From: FitseTLT Date: Sat, 30 Mar 2024 19:16:22 +0300 Subject: [PATCH 20/57] fixed for no display name case --- src/libs/ReportUtils.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index cc52ce559d9b..8194667baf75 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -3290,8 +3290,8 @@ function getIOUReportActionMessage(iouReportID: string, type: string, total: num const policy = getPolicy(report?.policyID); const ownerPersonalDetails = getPersonalDetailsForAccountID(policy?.ownerAccountID ?? 0); const ownerDisplayName = ownerPersonalDetails?.displayName - ? `${ownerPersonalDetails.displayName} (${ownerPersonalDetails.login})` - : ownerPersonalDetails?.login ?? Localize.translateLocal('common.hidden'); + ? `${ownerPersonalDetails.displayName}${ownerPersonalDetails.displayName !== ownerPersonalDetails.login ? ` (${ownerPersonalDetails.login})` : ''}` + : Localize.translateLocal('common.hidden'); return [ { From 22ca301945140408ecf14281b5b540cbbe51c37f Mon Sep 17 00:00:00 2001 From: FitseTLT Date: Sat, 30 Mar 2024 19:49:26 +0300 Subject: [PATCH 21/57] changed to policy submitsTo --- src/libs/ReportUtils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 8194667baf75..79fa3a775073 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -3288,7 +3288,7 @@ function getIOUReportActionMessage(iouReportID: string, type: string, total: num if (type === CONST.REPORT.ACTIONS.TYPE.SUBMITTED) { const policy = getPolicy(report?.policyID); - const ownerPersonalDetails = getPersonalDetailsForAccountID(policy?.ownerAccountID ?? 0); + const ownerPersonalDetails = getPersonalDetailsForAccountID(policy?.submitsTo ?? 0); const ownerDisplayName = ownerPersonalDetails?.displayName ? `${ownerPersonalDetails.displayName}${ownerPersonalDetails.displayName !== ownerPersonalDetails.login ? ` (${ownerPersonalDetails.login})` : ''}` : Localize.translateLocal('common.hidden'); From fa1a0f8712bf35f0754adcfd91941d216a6f6c14 Mon Sep 17 00:00:00 2001 From: FitseTLT Date: Sat, 30 Mar 2024 20:14:06 +0300 Subject: [PATCH 22/57] Add submitted to oneself case --- src/libs/ReportUtils.ts | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 79fa3a775073..7bea7466eae1 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -3289,10 +3289,14 @@ function getIOUReportActionMessage(iouReportID: string, type: string, total: num if (type === CONST.REPORT.ACTIONS.TYPE.SUBMITTED) { const policy = getPolicy(report?.policyID); const ownerPersonalDetails = getPersonalDetailsForAccountID(policy?.submitsTo ?? 0); - const ownerDisplayName = ownerPersonalDetails?.displayName - ? `${ownerPersonalDetails.displayName}${ownerPersonalDetails.displayName !== ownerPersonalDetails.login ? ` (${ownerPersonalDetails.login})` : ''}` - : Localize.translateLocal('common.hidden'); - + let ownerDisplayName: string; + if (ownerPersonalDetails?.accountID === currentUserAccountID) { + ownerDisplayName = 'yourself'; + } else { + ownerDisplayName = ownerPersonalDetails?.displayName + ? `${ownerPersonalDetails.displayName}${ownerPersonalDetails.displayName !== ownerPersonalDetails.login ? ` (${ownerPersonalDetails.login})` : ''}` + : 'Hidden'; + } return [ { type: CONST.REPORT.MESSAGE.TYPE.TEXT, From cfc0c8a167cdeb188f9abf0d1f8c07ab0a882e85 Mon Sep 17 00:00:00 2001 From: FitseTLT Date: Sat, 30 Mar 2024 20:45:48 +0300 Subject: [PATCH 23/57] changed variable name --- src/libs/ReportUtils.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 7bea7466eae1..fbcf6b038f51 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -3289,11 +3289,11 @@ function getIOUReportActionMessage(iouReportID: string, type: string, total: num if (type === CONST.REPORT.ACTIONS.TYPE.SUBMITTED) { const policy = getPolicy(report?.policyID); const ownerPersonalDetails = getPersonalDetailsForAccountID(policy?.submitsTo ?? 0); - let ownerDisplayName: string; + let submittedToDisplayName: string; if (ownerPersonalDetails?.accountID === currentUserAccountID) { - ownerDisplayName = 'yourself'; + submittedToDisplayName = 'yourself'; } else { - ownerDisplayName = ownerPersonalDetails?.displayName + submittedToDisplayName = ownerPersonalDetails?.displayName ? `${ownerPersonalDetails.displayName}${ownerPersonalDetails.displayName !== ownerPersonalDetails.login ? ` (${ownerPersonalDetails.login})` : ''}` : 'Hidden'; } @@ -3316,7 +3316,7 @@ function getIOUReportActionMessage(iouReportID: string, type: string, total: num { type: CONST.REPORT.MESSAGE.TYPE.TEXT, style: 'strong', - text: ownerDisplayName, + text: submittedToDisplayName, }, ]; } From 9ce0d6b846d2bf737fc652ace9ca9545dced0d5b Mon Sep 17 00:00:00 2001 From: FitseTLT Date: Tue, 2 Apr 2024 12:33:57 +0300 Subject: [PATCH 24/57] implemented it into separate function --- src/libs/ReportUtils.ts | 68 ++++++++++++++++++++++------------------- 1 file changed, 36 insertions(+), 32 deletions(-) diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 0dcf3ab50d7c..ec5165f3f99a 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -3275,6 +3275,41 @@ function buildOptimisticExpenseReport(chatReportID: string, policyID: string, pa return expenseReport; } +function getIOUSubmittedMessage(report: OnyxEntry) { + const policy = getPolicy(report?.policyID); + const ownerPersonalDetails = getPersonalDetailsForAccountID(policy?.submitsTo ?? 0); + let submittedToDisplayName: string; + if (ownerPersonalDetails?.accountID === currentUserAccountID) { + submittedToDisplayName = 'yourself'; + } else { + submittedToDisplayName = ownerPersonalDetails?.displayName + ? `${ownerPersonalDetails.displayName}${ownerPersonalDetails.displayName !== ownerPersonalDetails.login ? ` (${ownerPersonalDetails.login})` : ''}` + : ''; + } + return [ + { + type: CONST.REPORT.MESSAGE.TYPE.TEXT, + style: 'strong', + text: 'You', + }, + { + type: CONST.REPORT.MESSAGE.TYPE.TEXT, + style: 'normal', + text: ' submitted this report', + }, + { + type: CONST.REPORT.MESSAGE.TYPE.TEXT, + style: 'normal', + text: ' to ', + }, + { + type: CONST.REPORT.MESSAGE.TYPE.TEXT, + style: 'strong', + text: submittedToDisplayName, + }, + ]; +} + /** * @param iouReportID - the report ID of the IOU report the action belongs to * @param type - IOUReportAction type. Can be oneOf(create, decline, cancel, pay, split) @@ -3288,38 +3323,7 @@ function getIOUReportActionMessage(iouReportID: string, type: string, total: num const report = getReport(iouReportID); if (type === CONST.REPORT.ACTIONS.TYPE.SUBMITTED) { - const policy = getPolicy(report?.policyID); - const ownerPersonalDetails = getPersonalDetailsForAccountID(policy?.submitsTo ?? 0); - let submittedToDisplayName: string; - if (ownerPersonalDetails?.accountID === currentUserAccountID) { - submittedToDisplayName = 'yourself'; - } else { - submittedToDisplayName = ownerPersonalDetails?.displayName - ? `${ownerPersonalDetails.displayName}${ownerPersonalDetails.displayName !== ownerPersonalDetails.login ? ` (${ownerPersonalDetails.login})` : ''}` - : 'Hidden'; - } - return [ - { - type: CONST.REPORT.MESSAGE.TYPE.TEXT, - style: 'strong', - text: 'You', - }, - { - type: CONST.REPORT.MESSAGE.TYPE.TEXT, - style: 'normal', - text: ' submitted this report', - }, - { - type: CONST.REPORT.MESSAGE.TYPE.TEXT, - style: 'normal', - text: ' to ', - }, - { - type: CONST.REPORT.MESSAGE.TYPE.TEXT, - style: 'strong', - text: submittedToDisplayName, - }, - ]; + return getIOUSubmittedMessage(!isEmptyObject(report) ? report : null); } const amount = From 8103f5a8ab00445cc378b259e821e21fea758d64 Mon Sep 17 00:00:00 2001 From: FitseTLT Date: Tue, 2 Apr 2024 13:03:30 +0300 Subject: [PATCH 25/57] avoided double terniary --- src/libs/ReportUtils.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index ec5165f3f99a..3c3817659bde 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -3281,11 +3281,12 @@ function getIOUSubmittedMessage(report: OnyxEntry) { let submittedToDisplayName: string; if (ownerPersonalDetails?.accountID === currentUserAccountID) { submittedToDisplayName = 'yourself'; + } else if (ownerPersonalDetails?.displayName) { + submittedToDisplayName = `${ownerPersonalDetails.displayName}${ownerPersonalDetails.displayName !== ownerPersonalDetails.login ? ` (${ownerPersonalDetails.login})` : ''}`; } else { - submittedToDisplayName = ownerPersonalDetails?.displayName - ? `${ownerPersonalDetails.displayName}${ownerPersonalDetails.displayName !== ownerPersonalDetails.login ? ` (${ownerPersonalDetails.login})` : ''}` - : ''; + submittedToDisplayName = ''; } + return [ { type: CONST.REPORT.MESSAGE.TYPE.TEXT, From 989ed819c63871a4bebcfac011e719bdf300b1e5 Mon Sep 17 00:00:00 2001 From: FitseTLT Date: Tue, 2 Apr 2024 13:49:20 +0300 Subject: [PATCH 26/57] minor fix --- src/libs/ReportUtils.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 3c3817659bde..dda853389bb7 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -3281,10 +3281,8 @@ function getIOUSubmittedMessage(report: OnyxEntry) { let submittedToDisplayName: string; if (ownerPersonalDetails?.accountID === currentUserAccountID) { submittedToDisplayName = 'yourself'; - } else if (ownerPersonalDetails?.displayName) { - submittedToDisplayName = `${ownerPersonalDetails.displayName}${ownerPersonalDetails.displayName !== ownerPersonalDetails.login ? ` (${ownerPersonalDetails.login})` : ''}`; } else { - submittedToDisplayName = ''; + submittedToDisplayName = `${ownerPersonalDetails.displayName ?? ''}${ownerPersonalDetails.displayName !== ownerPersonalDetails.login ? ` (${ownerPersonalDetails.login})` : ''}`; } return [ From 7fe8f611f8b94b7ff2d5366ef8639f9fbf729250 Mon Sep 17 00:00:00 2001 From: FitseTLT Date: Wed, 3 Apr 2024 17:53:14 +0300 Subject: [PATCH 27/57] re-shuffled code implementation --- src/libs/ReportUtils.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index dda853389bb7..11aff4c3c1d2 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -3278,11 +3278,9 @@ function buildOptimisticExpenseReport(chatReportID: string, policyID: string, pa function getIOUSubmittedMessage(report: OnyxEntry) { const policy = getPolicy(report?.policyID); const ownerPersonalDetails = getPersonalDetailsForAccountID(policy?.submitsTo ?? 0); - let submittedToDisplayName: string; + let submittedToDisplayName = `${ownerPersonalDetails.displayName ?? ''}${ownerPersonalDetails.displayName !== ownerPersonalDetails.login ? ` (${ownerPersonalDetails.login})` : ''}`; if (ownerPersonalDetails?.accountID === currentUserAccountID) { submittedToDisplayName = 'yourself'; - } else { - submittedToDisplayName = `${ownerPersonalDetails.displayName ?? ''}${ownerPersonalDetails.displayName !== ownerPersonalDetails.login ? ` (${ownerPersonalDetails.login})` : ''}`; } return [ From b7b53dd129075fb0c3165e64d74c23e32b1cfac5 Mon Sep 17 00:00:00 2001 From: FitseTLT Date: Fri, 5 Apr 2024 23:44:10 +0300 Subject: [PATCH 28/57] added admin-submit case --- src/libs/ReportUtils.ts | 47 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 44 insertions(+), 3 deletions(-) diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 0c9197c1796c..2cb8b205061b 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -3314,9 +3314,50 @@ function buildOptimisticExpenseReport(chatReportID: string, policyID: string, pa function getIOUSubmittedMessage(report: OnyxEntry) { const policy = getPolicy(report?.policyID); - const ownerPersonalDetails = getPersonalDetailsForAccountID(policy?.submitsTo ?? 0); - let submittedToDisplayName = `${ownerPersonalDetails.displayName ?? ''}${ownerPersonalDetails.displayName !== ownerPersonalDetails.login ? ` (${ownerPersonalDetails.login})` : ''}`; - if (ownerPersonalDetails?.accountID === currentUserAccountID) { + + if (report?.ownerAccountID !== currentUserAccountID && policy.role === CONST.POLICY.ROLE.ADMIN) { + const ownerPersonalDetail = getPersonalDetailsForAccountID(report?.ownerAccountID ?? 0); + const ownerDisplayName = `${ownerPersonalDetail.displayName ?? ''}${ownerPersonalDetail.displayName !== ownerPersonalDetail.login ? ` (${ownerPersonalDetail.login})` : ''}`; + + return [ + { + style: 'normal', + text: 'You (on behalf of ', + type: CONST.REPORT.MESSAGE.TYPE.TEXT, + }, + { + style: 'strong', + text: ownerDisplayName, + type: CONST.REPORT.MESSAGE.TYPE.TEXT, + }, + { + style: 'normal', + text: ' via admin-submit)', + type: CONST.REPORT.MESSAGE.TYPE.TEXT, + }, + { + style: 'normal', + text: ' submitted this report', + type: CONST.REPORT.MESSAGE.TYPE.TEXT, + }, + { + style: 'normal', + text: ' to ', + type: CONST.REPORT.MESSAGE.TYPE.TEXT, + }, + { + style: 'strong', + text: 'you', + type: CONST.REPORT.MESSAGE.TYPE.TEXT, + }, + ]; + } + + const submittedToPersonalDetail = getPersonalDetailsForAccountID(policy?.submitsTo ?? 0); + let submittedToDisplayName = `${submittedToPersonalDetail.displayName ?? ''}${ + submittedToPersonalDetail.displayName !== submittedToPersonalDetail.login ? ` (${submittedToPersonalDetail.login})` : '' + }`; + if (submittedToPersonalDetail?.accountID === currentUserAccountID) { submittedToDisplayName = 'yourself'; } From 69cfe20b8e6794d1e2ca8dc2c072e6d66ad30446 Mon Sep 17 00:00:00 2001 From: nkdengineer Date: Tue, 9 Apr 2024 20:43:38 +0700 Subject: [PATCH 29/57] Get correct transaction data in ReportActionItem --- src/pages/home/report/ReportActionItem.tsx | 13 +++++++++---- src/pages/home/report/ReportActionsList.tsx | 6 ++++++ .../home/report/ReportActionsListItemRenderer.tsx | 5 +++++ src/pages/home/report/ReportActionsView.tsx | 11 ++++++++--- 4 files changed, 28 insertions(+), 7 deletions(-) diff --git a/src/pages/home/report/ReportActionItem.tsx b/src/pages/home/report/ReportActionItem.tsx index e3e32f398fb6..5391db6d59ea 100644 --- a/src/pages/home/report/ReportActionItem.tsx +++ b/src/pages/home/report/ReportActionItem.tsx @@ -120,6 +120,11 @@ type ReportActionItemProps = { /** Report action belonging to the report's parent */ parentReportAction: OnyxEntry; + /** The transaction thread report's parentReportAction */ + /** It's used by withOnyx HOC */ + // eslint-disable-next-line react/no-unused-prop-types + parentReportActionForTransactionThread: OnyxEntry; + /** All the data of the action item */ action: OnyxTypes.ReportAction; @@ -939,10 +944,10 @@ export default withOnyx({ key: ONYXKEYS.USER_WALLET, }, transaction: { - key: ({transactionThreadReport, reportActions}) => { - const parentReportActionID = isEmptyObject(transactionThreadReport) ? '0' : transactionThreadReport.parentReportActionID; - const action = reportActions?.find((reportAction) => reportAction.reportActionID === parentReportActionID); - const transactionID = (action as OnyxTypes.OriginalMessageIOU)?.originalMessage.IOUTransactionID ? (action as OnyxTypes.OriginalMessageIOU).originalMessage.IOUTransactionID : 0; + key: ({parentReportActionForTransactionThread}) => { + const transactionID = (parentReportActionForTransactionThread as OnyxTypes.OriginalMessageIOU)?.originalMessage.IOUTransactionID + ? (parentReportActionForTransactionThread as OnyxTypes.OriginalMessageIOU).originalMessage.IOUTransactionID + : 0; return `${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`; }, }, diff --git a/src/pages/home/report/ReportActionsList.tsx b/src/pages/home/report/ReportActionsList.tsx index d1b9c420b0af..210867100d3c 100644 --- a/src/pages/home/report/ReportActionsList.tsx +++ b/src/pages/home/report/ReportActionsList.tsx @@ -50,6 +50,9 @@ type ReportActionsListProps = WithCurrentUserPersonalDetailsProps & { /** The report's parentReportAction */ parentReportAction: OnyxEntry; + /** The transaction thread report's parentReportAction */ + parentReportActionForTransactionThread: OnyxEntry; + /** Sorted actions prepared for display */ sortedReportActions: OnyxTypes.ReportAction[]; @@ -148,6 +151,7 @@ function ReportActionsList({ listID, onContentSizeChange, shouldEnableAutoScrollToTopThreshold, + parentReportActionForTransactionThread, }: ReportActionsListProps) { const personalDetailsList = usePersonalDetails() || CONST.EMPTY_OBJECT; const styles = useThemeStyles(); @@ -524,6 +528,7 @@ function ReportActionsList({ reportAction={reportAction} reportActions={reportActions} parentReportAction={parentReportAction} + parentReportActionForTransactionThread={parentReportActionForTransactionThread} index={index} report={report} transactionThreadReport={transactionThreadReport} @@ -546,6 +551,7 @@ function ReportActionsList({ parentReportAction, reportActions, transactionThreadReport, + parentReportActionForTransactionThread, ], ); diff --git a/src/pages/home/report/ReportActionsListItemRenderer.tsx b/src/pages/home/report/ReportActionsListItemRenderer.tsx index 263415d90c39..32ca9861d7d0 100644 --- a/src/pages/home/report/ReportActionsListItemRenderer.tsx +++ b/src/pages/home/report/ReportActionsListItemRenderer.tsx @@ -17,6 +17,9 @@ type ReportActionsListItemRendererProps = { /** The report's parentReportAction */ parentReportAction: OnyxEntry; + /** The transaction thread report's parentReportAction */ + parentReportActionForTransactionThread: OnyxEntry; + /** Position index of the report action in the overall report FlatList view */ index: number; @@ -58,6 +61,7 @@ function ReportActionsListItemRenderer({ shouldDisplayNewMarker, linkedReportActionID = '', shouldDisplayReplyDivider, + parentReportActionForTransactionThread, }: ReportActionsListItemRendererProps) { const shouldDisplayParentAction = reportAction.actionName === CONST.REPORT.ACTIONS.TYPE.CREATED && ReportUtils.isChatThread(report) && !ReportActionsUtils.isTransactionThread(parentReportAction); @@ -145,6 +149,7 @@ function ReportActionsListItemRenderer({ parentReportAction={parentReportAction} report={report} transactionThreadReport={transactionThreadReport} + parentReportActionForTransactionThread={parentReportActionForTransactionThread} action={action} reportActions={reportActions} linkedReportActionID={linkedReportActionID} diff --git a/src/pages/home/report/ReportActionsView.tsx b/src/pages/home/report/ReportActionsView.tsx index 6040c1e67212..7eb355ef3e85 100755 --- a/src/pages/home/report/ReportActionsView.tsx +++ b/src/pages/home/report/ReportActionsView.tsx @@ -137,20 +137,24 @@ function ReportActionsView({ // Get a sorted array of reportActions for both the current report and the transaction thread report associated with this report (if there is one) // so that we display transaction-level and report-level report actions in order in the one-transaction view - const combinedReportActions = useMemo(() => { + const [combinedReportActions, parentReportActionForTransactionThread] = useMemo(() => { if (isEmptyObject(transactionThreadReportActions)) { - return allReportActions; + return [allReportActions, null]; } // Filter out the created action from the transaction thread report actions, since we already have the parent report's created action in `reportActions` const filteredTransactionThreadReportActions = transactionThreadReportActions?.filter((action) => action.actionName !== CONST.REPORT.ACTIONS.TYPE.CREATED); + const moneyRequestAction = allReportActions.find((action) => { + const actionType = (action as OnyxTypes.OriginalMessageIOU).originalMessage?.type ?? ''; + return actionType === CONST.IOU.REPORT_ACTION_TYPE.CREATE || actionType === CONST.IOU.REPORT_ACTION_TYPE.TRACK || !ReportActionsUtils.isSentMoneyReportAction(action); + }); // Filter out the money request actions because we don't want to show any preview actions for one-transaction reports const filteredReportActions = [...allReportActions, ...filteredTransactionThreadReportActions].filter((action) => { const actionType = (action as OnyxTypes.OriginalMessageIOU).originalMessage?.type ?? ''; return actionType !== CONST.IOU.REPORT_ACTION_TYPE.CREATE && actionType !== CONST.IOU.REPORT_ACTION_TYPE.TRACK && !ReportActionsUtils.isSentMoneyReportAction(action); }); - return ReportActionsUtils.getSortedReportActions(filteredReportActions, true); + return [ReportActionsUtils.getSortedReportActions(filteredReportActions, true), moneyRequestAction ?? null]; }, [allReportActions, transactionThreadReportActions]); const indexOfLinkedAction = useMemo(() => { @@ -517,6 +521,7 @@ function ReportActionsView({ transactionThreadReport={transactionThreadReport} reportActions={reportActions} parentReportAction={parentReportAction} + parentReportActionForTransactionThread={parentReportActionForTransactionThread} onLayout={recordTimeToMeasureItemLayout} sortedReportActions={reportActionsToDisplay} mostRecentIOUReportActionID={mostRecentIOUReportActionID} From faec57128745bdd08b58aa64a5c551a8da59d882 Mon Sep 17 00:00:00 2001 From: nkdengineer Date: Tue, 9 Apr 2024 23:26:55 +0700 Subject: [PATCH 30/57] update correctly filter condition --- src/pages/home/report/ReportActionsView.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/home/report/ReportActionsView.tsx b/src/pages/home/report/ReportActionsView.tsx index 7eb355ef3e85..45b58a807877 100755 --- a/src/pages/home/report/ReportActionsView.tsx +++ b/src/pages/home/report/ReportActionsView.tsx @@ -146,7 +146,7 @@ function ReportActionsView({ const filteredTransactionThreadReportActions = transactionThreadReportActions?.filter((action) => action.actionName !== CONST.REPORT.ACTIONS.TYPE.CREATED); const moneyRequestAction = allReportActions.find((action) => { const actionType = (action as OnyxTypes.OriginalMessageIOU).originalMessage?.type ?? ''; - return actionType === CONST.IOU.REPORT_ACTION_TYPE.CREATE || actionType === CONST.IOU.REPORT_ACTION_TYPE.TRACK || !ReportActionsUtils.isSentMoneyReportAction(action); + return actionType === CONST.IOU.REPORT_ACTION_TYPE.CREATE || actionType === CONST.IOU.REPORT_ACTION_TYPE.TRACK || ReportActionsUtils.isSentMoneyReportAction(action); }); // Filter out the money request actions because we don't want to show any preview actions for one-transaction reports From e2de27005699da62d4bfcc07c0d897830656b612 Mon Sep 17 00:00:00 2001 From: nkdengineer Date: Tue, 9 Apr 2024 23:37:27 +0700 Subject: [PATCH 31/57] fix lint --- src/pages/home/report/ReportActionItem.tsx | 2 +- tests/perf-test/ReportActionsList.perf-test.tsx | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/pages/home/report/ReportActionItem.tsx b/src/pages/home/report/ReportActionItem.tsx index 5391db6d59ea..298822364f21 100644 --- a/src/pages/home/report/ReportActionItem.tsx +++ b/src/pages/home/report/ReportActionItem.tsx @@ -123,7 +123,7 @@ type ReportActionItemProps = { /** The transaction thread report's parentReportAction */ /** It's used by withOnyx HOC */ // eslint-disable-next-line react/no-unused-prop-types - parentReportActionForTransactionThread: OnyxEntry; + parentReportActionForTransactionThread?: OnyxEntry; /** All the data of the action item */ action: OnyxTypes.ReportAction; diff --git a/tests/perf-test/ReportActionsList.perf-test.tsx b/tests/perf-test/ReportActionsList.perf-test.tsx index a952d149a598..7d45e3e4b45d 100644 --- a/tests/perf-test/ReportActionsList.perf-test.tsx +++ b/tests/perf-test/ReportActionsList.perf-test.tsx @@ -95,6 +95,7 @@ function ReportActionsListWrapper() { Date: Mon, 15 Apr 2024 21:35:19 +0500 Subject: [PATCH 32/57] Add live markdown to private notes --- src/pages/PrivateNotes/PrivateNotesEditPage.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/pages/PrivateNotes/PrivateNotesEditPage.tsx b/src/pages/PrivateNotes/PrivateNotesEditPage.tsx index 7d0b8fff8e41..7ab8fadc496a 100644 --- a/src/pages/PrivateNotes/PrivateNotesEditPage.tsx +++ b/src/pages/PrivateNotes/PrivateNotesEditPage.tsx @@ -165,6 +165,7 @@ function PrivateNotesEditPage({route, personalDetailsList, report}: PrivateNotes privateNotesInput.current = el; updateMultilineInputRange(privateNotesInput.current); }} + isMarkdownEnabled /> From d1f641af2b880510017b18ab49f0fe31ce5f6638 Mon Sep 17 00:00:00 2001 From: nkdengineer Date: Tue, 16 Apr 2024 17:31:29 +0700 Subject: [PATCH 33/57] compare reportID --- src/pages/home/report/ReportActionsView.tsx | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/pages/home/report/ReportActionsView.tsx b/src/pages/home/report/ReportActionsView.tsx index 1ed74b488837..40307b75f1a1 100755 --- a/src/pages/home/report/ReportActionsView.tsx +++ b/src/pages/home/report/ReportActionsView.tsx @@ -145,8 +145,7 @@ function ReportActionsView({ // Filter out the created action from the transaction thread report actions, since we already have the parent report's created action in `reportActions` const filteredTransactionThreadReportActions = transactionThreadReportActions?.filter((action) => action.actionName !== CONST.REPORT.ACTIONS.TYPE.CREATED); const moneyRequestAction = allReportActions.find((action) => { - const actionType = (action as OnyxTypes.OriginalMessageIOU).originalMessage?.type ?? ''; - return actionType === CONST.IOU.REPORT_ACTION_TYPE.CREATE || actionType === CONST.IOU.REPORT_ACTION_TYPE.TRACK || ReportActionsUtils.isSentMoneyReportAction(action); + return action.reportActionID === transactionThreadReport?.parentReportActionID; }); // Filter out the money request actions because we don't want to show any preview actions for one-transaction reports @@ -155,7 +154,7 @@ function ReportActionsView({ return actionType !== CONST.IOU.REPORT_ACTION_TYPE.CREATE && actionType !== CONST.IOU.REPORT_ACTION_TYPE.TRACK && !ReportActionsUtils.isSentMoneyReportAction(action); }); return [ReportActionsUtils.getSortedReportActions(filteredReportActions, true), moneyRequestAction ?? null]; - }, [allReportActions, transactionThreadReportActions]); + }, [allReportActions, transactionThreadReportActions, transactionThreadReport?.parentReportActionID]); const indexOfLinkedAction = useMemo(() => { if (!reportActionID) { From e743e38f9291c30cde76c99c4390ca9c89718e58 Mon Sep 17 00:00:00 2001 From: nkdengineer Date: Tue, 16 Apr 2024 18:09:51 +0700 Subject: [PATCH 34/57] fix lint --- src/pages/home/report/ReportActionsView.tsx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/pages/home/report/ReportActionsView.tsx b/src/pages/home/report/ReportActionsView.tsx index 40307b75f1a1..db6d470ec724 100755 --- a/src/pages/home/report/ReportActionsView.tsx +++ b/src/pages/home/report/ReportActionsView.tsx @@ -144,9 +144,7 @@ function ReportActionsView({ // Filter out the created action from the transaction thread report actions, since we already have the parent report's created action in `reportActions` const filteredTransactionThreadReportActions = transactionThreadReportActions?.filter((action) => action.actionName !== CONST.REPORT.ACTIONS.TYPE.CREATED); - const moneyRequestAction = allReportActions.find((action) => { - return action.reportActionID === transactionThreadReport?.parentReportActionID; - }); + const moneyRequestAction = allReportActions.find((action) => action.reportActionID === transactionThreadReport?.parentReportActionID); // Filter out the money request actions because we don't want to show any preview actions for one-transaction reports const filteredReportActions = [...allReportActions, ...filteredTransactionThreadReportActions].filter((action) => { From c678929813d0d93886fab63028afec020ed466af Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Fri, 19 Apr 2024 14:06:42 +0200 Subject: [PATCH 35/57] Check didScreenTransitionEnd in BaseSelectionList --- src/components/SelectionList/BaseSelectionList.tsx | 4 +++- tests/perf-test/SelectionList.perf-test.tsx | 4 ++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/components/SelectionList/BaseSelectionList.tsx b/src/components/SelectionList/BaseSelectionList.tsx index 9ab89aa73f86..c8b898021592 100644 --- a/src/components/SelectionList/BaseSelectionList.tsx +++ b/src/components/SelectionList/BaseSelectionList.tsx @@ -20,6 +20,7 @@ import useKeyboardShortcut from '@hooks/useKeyboardShortcut'; import useKeyboardState from '@hooks/useKeyboardState'; import useLocalize from '@hooks/useLocalize'; import usePrevious from '@hooks/usePrevious'; +import useScreenWrapperTranstionStatus from '@hooks/useScreenWrapperTransitionStatus'; import useThemeStyles from '@hooks/useThemeStyles'; import getSectionsWithIndexOffset from '@libs/getSectionsWithIndexOffset'; import Log from '@libs/Log'; @@ -94,6 +95,7 @@ function BaseSelectionList( const itemFocusTimeoutRef = useRef(null); const [currentPage, setCurrentPage] = useState(1); const isTextInputFocusedRef = useRef(false); + const {didScreenTransitionEnd} = useScreenWrapperTranstionStatus(); const incrementPage = () => setCurrentPage((prev) => prev + 1); @@ -356,7 +358,7 @@ function BaseSelectionList( keyForList={item.keyForList ?? ''} isMultilineSupported={isRowMultilineSupported} onFocus={() => setFocusedIndex(normalizedIndex)} - shouldSyncFocus={!isTextInputFocusedRef.current} + shouldSyncFocus={!isTextInputFocusedRef.current && didScreenTransitionEnd} /> ); }; diff --git a/tests/perf-test/SelectionList.perf-test.tsx b/tests/perf-test/SelectionList.perf-test.tsx index a29b66d680b0..07a9a4d6ce22 100644 --- a/tests/perf-test/SelectionList.perf-test.tsx +++ b/tests/perf-test/SelectionList.perf-test.tsx @@ -57,6 +57,10 @@ jest.mock('@components/withKeyboardState', () => ({ + useCardAnimation: () => {}, +})); + jest.mock('@react-navigation/native', () => ({ useFocusEffect: () => {}, useIsFocused: () => true, From ad215c4622d59e7df5db0761ad6ba084122439e5 Mon Sep 17 00:00:00 2001 From: Shubham Agrawal Date: Fri, 19 Apr 2024 20:36:05 +0530 Subject: [PATCH 36/57] Changed route related to money request --- .well-known/apple-app-site-association | 8 +++ android/app/src/main/AndroidManifest.xml | 4 ++ src/CONST.ts | 6 +- src/ROUTES.ts | 17 ++--- src/components/AttachmentModal.tsx | 2 +- .../MoneyRequestConfirmationList.tsx | 16 ++--- .../ReportActionItem/MoneyRequestView.tsx | 20 +++--- src/components/ReportWelcomeText.tsx | 8 +-- src/languages/en.ts | 7 +- src/languages/es.ts | 7 +- src/libs/IOUUtils.ts | 16 ++++- src/libs/MoneyRequestUtils.ts | 2 +- src/libs/Navigation/Navigation.ts | 4 +- src/libs/Navigation/types.ts | 18 ++--- src/libs/Permissions.ts | 2 +- src/libs/ReportUtils.ts | 29 ++++++-- src/libs/actions/IOU.ts | 4 +- .../AttachmentPickerWithMenuItems.tsx | 16 ++--- src/pages/home/report/ReportActionItem.tsx | 2 +- .../FloatingActionButtonAndPopover.tsx | 20 +++--- src/pages/iou/request/IOURequestStartPage.tsx | 6 +- ...yForRefactorRequestParticipantsSelector.js | 14 ++-- .../iou/request/step/IOURequestStepAmount.tsx | 36 ++++++++-- .../step/IOURequestStepConfirmation.tsx | 14 ++-- .../iou/request/step/IOURequestStepDate.tsx | 2 +- .../request/step/IOURequestStepDistance.tsx | 49 +++++++++++-- .../step/IOURequestStepParticipants.tsx | 23 ++---- .../step/IOURequestStepRoutePropTypes.js | 29 -------- .../step/IOURequestStepScan/index.native.tsx | 48 +++++++++++-- .../request/step/IOURequestStepScan/index.tsx | 48 +++++++++++-- .../iou/steps/MoneyRequestAmountForm.tsx | 4 +- tests/perf-test/ReportUtils.perf-test.ts | 2 +- tests/unit/IOUUtilsTest.ts | 9 +-- tests/unit/ReportUtilsTest.ts | 70 +++++++++---------- 34 files changed, 352 insertions(+), 210 deletions(-) delete mode 100644 src/pages/iou/request/step/IOURequestStepRoutePropTypes.js diff --git a/.well-known/apple-app-site-association b/.well-known/apple-app-site-association index a2c7365f7de8..394e45f8d9ae 100644 --- a/.well-known/apple-app-site-association +++ b/.well-known/apple-app-site-association @@ -52,6 +52,10 @@ "/": "/split/*", "comment": "Split Expense" }, + { + "/": "/submit/*", + "comment": "Submit Expense" + }, { "/": "/request/*", "comment": "Submit Expense" @@ -76,6 +80,10 @@ "/": "/search/*", "comment": "Search" }, + { + "/": "/pay/*", + "comment": "Pay someone" + }, { "/": "/send/*", "comment": "Pay someone" diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 84364f2ef7ff..520602a28a02 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -62,6 +62,7 @@ + @@ -70,6 +71,7 @@ + @@ -81,6 +83,7 @@ + @@ -89,6 +92,7 @@ + diff --git a/src/CONST.ts b/src/CONST.ts index a840cb481a1a..b5ffcc9c07e8 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -1411,16 +1411,18 @@ const CONST = { ACTION: { EDIT: 'edit', CREATE: 'create', - REQUEST: 'request', + SUBMIT: 'submit', CATEGORIZE: 'categorize', SHARE: 'share', }, DEFAULT_AMOUNT: 0, TYPE: { SEND: 'send', + PAY: 'pay', SPLIT: 'split', REQUEST: 'request', - TRACK_EXPENSE: 'track-expense', + SUBMIT: 'submit', + TRACK: 'track', }, REQUEST_TYPE: { DISTANCE: 'distance', diff --git a/src/ROUTES.ts b/src/ROUTES.ts index 94bd1c2b612d..8233cdea6001 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -418,20 +418,20 @@ const ROUTES = { }, MONEY_REQUEST_STATE_SELECTOR: { - route: 'request/state', + route: 'submit/state', getRoute: (state?: string, backTo?: string, label?: string) => - `${getUrlWithBackToParam(`request/state${state ? `?state=${encodeURIComponent(state)}` : ''}`, backTo)}${ + `${getUrlWithBackToParam(`submit/state${state ? `?state=${encodeURIComponent(state)}` : ''}`, backTo)}${ // the label param can be an empty string so we cannot use a nullish ?? operator // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing label ? `${backTo || state ? '&' : '?'}label=${encodeURIComponent(label)}` : '' }` as const, }, - IOU_REQUEST: 'request/new', - IOU_SEND: 'send/new', - IOU_SEND_ADD_BANK_ACCOUNT: 'send/new/add-bank-account', - IOU_SEND_ADD_DEBIT_CARD: 'send/new/add-debit-card', - IOU_SEND_ENABLE_PAYMENTS: 'send/new/enable-payments', + IOU_REQUEST: 'submit/new', + IOU_SEND: 'pay/new', + IOU_SEND_ADD_BANK_ACCOUNT: 'pay/new/add-bank-account', + IOU_SEND_ADD_DEBIT_CARD: 'pay/new/add-debit-card', + IOU_SEND_ENABLE_PAYMENTS: 'pay/new/enable-payments', NEW_TASK: 'new/task', NEW_TASK_ASSIGNEE: 'new/task/assignee', @@ -690,7 +690,7 @@ const ROUTES = { route: 'referral/:contentType', getRoute: (contentType: string, backTo?: string) => getUrlWithBackToParam(`referral/${contentType}`, backTo), }, - PROCESS_MONEY_REQUEST_HOLD: 'hold-request-educational', + PROCESS_MONEY_REQUEST_HOLD: 'hold-expense-educational', ONBOARDING_ROOT: 'onboarding', ONBOARDING_PERSONAL_DETAILS: 'onboarding/personal-details', ONBOARDING_PURPOSE: 'onboarding/purpose', @@ -733,6 +733,7 @@ const ROUTES = { */ const HYBRID_APP_ROUTES = { MONEY_REQUEST_CREATE: '/request/new/scan', + MONEY_REQUEST_SUBMIT_CREATE: '/submit/new/scan', } as const; export {HYBRID_APP_ROUTES, getUrlWithBackToParam}; diff --git a/src/components/AttachmentModal.tsx b/src/components/AttachmentModal.tsx index 7d13524b78df..1612e97c4903 100644 --- a/src/components/AttachmentModal.tsx +++ b/src/components/AttachmentModal.tsx @@ -422,7 +422,7 @@ function AttachmentModal({ Navigation.navigate( ROUTES.MONEY_REQUEST_STEP_SCAN.getRoute( CONST.IOU.ACTION.EDIT, - CONST.IOU.TYPE.REQUEST, + CONST.IOU.TYPE.SUBMIT, transaction?.transactionID ?? '', report?.reportID ?? '', Navigation.getActiveRouteWithoutParams(), diff --git a/src/components/MoneyRequestConfirmationList.tsx b/src/components/MoneyRequestConfirmationList.tsx index e90cb7584c43..1e95d644f3d8 100755 --- a/src/components/MoneyRequestConfirmationList.tsx +++ b/src/components/MoneyRequestConfirmationList.tsx @@ -91,7 +91,7 @@ type MoneyRequestConfirmationListProps = MoneyRequestConfirmationListOnyxProps & iouCurrencyCode?: string; /** IOU type */ - iouType?: IOUType; + iouType?: Exclude; /** IOU date */ iouCreated?: string; @@ -176,7 +176,7 @@ function MoneyRequestConfirmationList({ onSendMoney, onConfirm, onSelectParticipant, - iouType = CONST.IOU.TYPE.REQUEST, + iouType = CONST.IOU.TYPE.SUBMIT, isScanRequest = false, iouAmount, policyCategories, @@ -216,10 +216,10 @@ function MoneyRequestConfirmationList({ const currentUserPersonalDetails = useCurrentUserPersonalDetails(); const {canUseViolations} = usePermissions(); - const isTypeRequest = iouType === CONST.IOU.TYPE.REQUEST; + const isTypeRequest = iouType === CONST.IOU.TYPE.SUBMIT; const isTypeSplit = iouType === CONST.IOU.TYPE.SPLIT; - const isTypeSend = iouType === CONST.IOU.TYPE.SEND; - const isTypeTrackExpense = iouType === CONST.IOU.TYPE.TRACK_EXPENSE; + const isTypeSend = iouType === CONST.IOU.TYPE.PAY; + const isTypeTrackExpense = iouType === CONST.IOU.TYPE.TRACK; const {unit, rate, currency} = mileageRate ?? { unit: CONST.CUSTOM_UNITS.DISTANCE_UNIT_MILES, @@ -557,7 +557,7 @@ function MoneyRequestConfirmationList({ return; } - if (iouType === CONST.IOU.TYPE.SEND) { + if (iouType === CONST.IOU.TYPE.PAY) { if (!paymentMethod) { return; } @@ -608,7 +608,7 @@ function MoneyRequestConfirmationList({ return; } - const shouldShowSettlementButton = iouType === CONST.IOU.TYPE.SEND; + const shouldShowSettlementButton = iouType === CONST.IOU.TYPE.PAY; const shouldDisableButton = selectedParticipants.length === 0; const button = shouldShowSettlementButton ? ( @@ -944,7 +944,7 @@ function MoneyRequestConfirmationList({ : // The empty receipt component should only show for IOU Requests of a paid policy ("Team" or "Corporate") PolicyUtils.isPaidGroupPolicy(policy) && !isDistanceRequest && - iouType === CONST.IOU.TYPE.REQUEST && ( + iouType === CONST.IOU.TYPE.SUBMIT && ( Navigation.navigate( diff --git a/src/components/ReportActionItem/MoneyRequestView.tsx b/src/components/ReportActionItem/MoneyRequestView.tsx index c5cad0eccdeb..7c4b055c71ba 100644 --- a/src/components/ReportActionItem/MoneyRequestView.tsx +++ b/src/components/ReportActionItem/MoneyRequestView.tsx @@ -297,7 +297,7 @@ function MoneyRequestView({ Navigation.navigate( ROUTES.MONEY_REQUEST_STEP_SCAN.getRoute( CONST.IOU.ACTION.EDIT, - CONST.IOU.TYPE.REQUEST, + CONST.IOU.TYPE.SUBMIT, transaction?.transactionID ?? '', report.reportID, Navigation.getActiveRouteWithoutParams(), @@ -317,7 +317,7 @@ function MoneyRequestView({ interactive={canEditAmount} shouldShowRightIcon={canEditAmount} onPress={() => - Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_AMOUNT.getRoute(CONST.IOU.ACTION.EDIT, CONST.IOU.TYPE.REQUEST, transaction?.transactionID ?? '', report.reportID)) + Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_AMOUNT.getRoute(CONST.IOU.ACTION.EDIT, CONST.IOU.TYPE.SUBMIT, transaction?.transactionID ?? '', report.reportID)) } brickRoadIndicator={getErrorForField('amount') ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : undefined} error={getErrorForField('amount')} @@ -333,7 +333,7 @@ function MoneyRequestView({ titleStyle={styles.flex1} onPress={() => Navigation.navigate( - ROUTES.MONEY_REQUEST_STEP_DESCRIPTION.getRoute(CONST.IOU.ACTION.EDIT, CONST.IOU.TYPE.REQUEST, transaction?.transactionID ?? '', report.reportID), + ROUTES.MONEY_REQUEST_STEP_DESCRIPTION.getRoute(CONST.IOU.ACTION.EDIT, CONST.IOU.TYPE.SUBMIT, transaction?.transactionID ?? '', report.reportID), ) } wrapperStyle={[styles.pv2, styles.taskDescriptionMenuItem]} @@ -352,7 +352,7 @@ function MoneyRequestView({ titleStyle={styles.flex1} onPress={() => Navigation.navigate( - ROUTES.MONEY_REQUEST_STEP_DISTANCE.getRoute(CONST.IOU.ACTION.EDIT, CONST.IOU.TYPE.REQUEST, transaction?.transactionID ?? '', report.reportID), + ROUTES.MONEY_REQUEST_STEP_DISTANCE.getRoute(CONST.IOU.ACTION.EDIT, CONST.IOU.TYPE.SUBMIT, transaction?.transactionID ?? '', report.reportID), ) } /> @@ -367,7 +367,7 @@ function MoneyRequestView({ titleStyle={styles.flex1} onPress={() => Navigation.navigate( - ROUTES.MONEY_REQUEST_STEP_MERCHANT.getRoute(CONST.IOU.ACTION.EDIT, CONST.IOU.TYPE.REQUEST, transaction?.transactionID ?? '', report.reportID), + ROUTES.MONEY_REQUEST_STEP_MERCHANT.getRoute(CONST.IOU.ACTION.EDIT, CONST.IOU.TYPE.SUBMIT, transaction?.transactionID ?? '', report.reportID), ) } brickRoadIndicator={getErrorForField('merchant') ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : undefined} @@ -383,7 +383,7 @@ function MoneyRequestView({ shouldShowRightIcon={canEditDate} titleStyle={styles.flex1} onPress={() => - Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_DATE.getRoute(CONST.IOU.ACTION.EDIT, CONST.IOU.TYPE.REQUEST, transaction?.transactionID ?? '', report.reportID)) + Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_DATE.getRoute(CONST.IOU.ACTION.EDIT, CONST.IOU.TYPE.SUBMIT, transaction?.transactionID ?? '', report.reportID)) } brickRoadIndicator={getErrorForField('date') ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : undefined} error={getErrorForField('date')} @@ -399,7 +399,7 @@ function MoneyRequestView({ titleStyle={styles.flex1} onPress={() => Navigation.navigate( - ROUTES.MONEY_REQUEST_STEP_CATEGORY.getRoute(CONST.IOU.ACTION.EDIT, CONST.IOU.TYPE.REQUEST, transaction?.transactionID ?? '', report.reportID), + ROUTES.MONEY_REQUEST_STEP_CATEGORY.getRoute(CONST.IOU.ACTION.EDIT, CONST.IOU.TYPE.SUBMIT, transaction?.transactionID ?? '', report.reportID), ) } brickRoadIndicator={getErrorForField('category') ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : undefined} @@ -421,7 +421,7 @@ function MoneyRequestView({ titleStyle={styles.flex1} onPress={() => Navigation.navigate( - ROUTES.MONEY_REQUEST_STEP_TAG.getRoute(CONST.IOU.ACTION.EDIT, CONST.IOU.TYPE.REQUEST, orderWeight, transaction?.transactionID ?? '', report.reportID), + ROUTES.MONEY_REQUEST_STEP_TAG.getRoute(CONST.IOU.ACTION.EDIT, CONST.IOU.TYPE.SUBMIT, orderWeight, transaction?.transactionID ?? '', report.reportID), ) } brickRoadIndicator={getErrorForField('tag', {tagListIndex: index, tagListName: name}) ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : undefined} @@ -448,7 +448,7 @@ function MoneyRequestView({ titleStyle={styles.flex1} onPress={() => Navigation.navigate( - ROUTES.MONEY_REQUEST_STEP_TAX_RATE.getRoute(CONST.IOU.ACTION.EDIT, CONST.IOU.TYPE.REQUEST, transaction?.transactionID ?? '', report.reportID), + ROUTES.MONEY_REQUEST_STEP_TAX_RATE.getRoute(CONST.IOU.ACTION.EDIT, CONST.IOU.TYPE.SUBMIT, transaction?.transactionID ?? '', report.reportID), ) } /> @@ -465,7 +465,7 @@ function MoneyRequestView({ titleStyle={styles.flex1} onPress={() => Navigation.navigate( - ROUTES.MONEY_REQUEST_STEP_TAX_AMOUNT.getRoute(CONST.IOU.ACTION.EDIT, CONST.IOU.TYPE.REQUEST, transaction?.transactionID ?? '', report.reportID), + ROUTES.MONEY_REQUEST_STEP_TAX_AMOUNT.getRoute(CONST.IOU.ACTION.EDIT, CONST.IOU.TYPE.SUBMIT, transaction?.transactionID ?? '', report.reportID), ) } /> diff --git a/src/components/ReportWelcomeText.tsx b/src/components/ReportWelcomeText.tsx index 219199c25bc3..d61bd5186ecc 100644 --- a/src/components/ReportWelcomeText.tsx +++ b/src/components/ReportWelcomeText.tsx @@ -44,7 +44,7 @@ function ReportWelcomeText({report, policy, personalDetails}: ReportWelcomeTextP const displayNamesWithTooltips = ReportUtils.getDisplayNamesWithTooltips(OptionsListUtils.getPersonalDetailsForAccountIDs(participantAccountIDs, personalDetails), isMultipleParticipant); const isUserPolicyAdmin = PolicyUtils.isPolicyAdmin(policy); const roomWelcomeMessage = ReportUtils.getRoomWelcomeMessage(report, isUserPolicyAdmin); - const moneyRequestOptions = ReportUtils.getMoneyRequestOptions(report, policy, participantAccountIDs, canUseTrackExpense); + const moneyRequestOptions = ReportUtils.temporary_getMoneyRequestOptions(report, policy, participantAccountIDs, canUseTrackExpense); const additionalText = moneyRequestOptions.map((item) => translate(`reportActionsView.iouTypes.${item}`)).join(', '); const canEditPolicyDescription = ReportUtils.canEditPolicyDescription(policy); const reportName = ReportUtils.getReportName(report); @@ -160,9 +160,9 @@ function ReportWelcomeText({report, policy, personalDetails}: ReportWelcomeTextP ))} )} - {(moneyRequestOptions.includes(CONST.IOU.TYPE.SEND) || - moneyRequestOptions.includes(CONST.IOU.TYPE.REQUEST) || - moneyRequestOptions.includes(CONST.IOU.TYPE.TRACK_EXPENSE)) && {translate('reportActionsView.usePlusButton', {additionalText})}} + {(moneyRequestOptions.includes(CONST.IOU.TYPE.PAY) || moneyRequestOptions.includes(CONST.IOU.TYPE.SUBMIT) || moneyRequestOptions.includes(CONST.IOU.TYPE.TRACK)) && ( + {translate('reportActionsView.usePlusButton', {additionalText})} + )} ); diff --git a/src/languages/en.ts b/src/languages/en.ts index ed2587e5e2c6..fd018f5f5800 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -509,11 +509,10 @@ export default { welcomeToRoom: ({roomName}: WelcomeToRoomParams) => `Welcome to ${roomName}!`, usePlusButton: ({additionalText}: UsePlusButtonParams) => `\nYou can also use the + button to ${additionalText}, or assign a task!`, iouTypes: { - send: 'pay expenses', + pay: 'pay expenses', split: 'split an expense', - request: 'submit an expense', - // eslint-disable-next-line @typescript-eslint/naming-convention - 'track-expense': 'track an expense', + submit: 'submit an expense', + track: 'track an expense', }, }, reportAction: { diff --git a/src/languages/es.ts b/src/languages/es.ts index beb654cf0bc4..cf0b0eea1799 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -502,11 +502,10 @@ export default { welcomeToRoom: ({roomName}: WelcomeToRoomParams) => `¡Bienvenido a ${roomName}!`, usePlusButton: ({additionalText}: UsePlusButtonParams) => `\n¡También puedes usar el botón + de abajo para ${additionalText}, o asignar una tarea!`, iouTypes: { - send: 'pagar gastos', + pay: 'pagar gastos', split: 'dividir un gasto', - request: 'presentar un gasto', - // eslint-disable-next-line @typescript-eslint/naming-convention - 'track-expense': 'rastrear un gasto', + submit: 'presentar un gasto', + track: 'rastrear un gasto', }, }, reportAction: { diff --git a/src/libs/IOUUtils.ts b/src/libs/IOUUtils.ts index 63930ffd7131..cfc8e7064453 100644 --- a/src/libs/IOUUtils.ts +++ b/src/libs/IOUUtils.ts @@ -9,7 +9,7 @@ import Navigation from './Navigation/Navigation'; import * as TransactionUtils from './TransactionUtils'; function navigateToStartMoneyRequestStep(requestType: IOURequestType, iouType: IOUType, transactionID: string, reportID: string, iouAction?: IOUAction): void { - if (iouAction === CONST.IOU.ACTION.CATEGORIZE || iouAction === CONST.IOU.ACTION.REQUEST) { + if (iouAction === CONST.IOU.ACTION.CATEGORIZE || iouAction === CONST.IOU.ACTION.SUBMIT) { Navigation.goBack(); return; } @@ -109,7 +109,16 @@ function isIOUReportPendingCurrencyConversion(iouReport: Report): boolean { * Checks if the iou type is one of request, send, or split. */ function isValidMoneyRequestType(iouType: string): boolean { - const moneyRequestType: string[] = [CONST.IOU.TYPE.REQUEST, CONST.IOU.TYPE.SPLIT, CONST.IOU.TYPE.SEND, CONST.IOU.TYPE.TRACK_EXPENSE]; + const moneyRequestType: string[] = [CONST.IOU.TYPE.REQUEST, CONST.IOU.TYPE.SUBMIT, CONST.IOU.TYPE.SPLIT, CONST.IOU.TYPE.SEND, CONST.IOU.TYPE.PAY, CONST.IOU.TYPE.TRACK]; + return moneyRequestType.includes(iouType); +} + +/** + * Checks if the iou type is one of submit, pat, track, or split. + */ +// eslint-disable-next-line @typescript-eslint/naming-convention +function temporary_isValidMoneyRequestType(iouType: string): boolean { + const moneyRequestType: string[] = [CONST.IOU.TYPE.SUBMIT, CONST.IOU.TYPE.SPLIT, CONST.IOU.TYPE.PAY, CONST.IOU.TYPE.TRACK]; return moneyRequestType.includes(iouType); } @@ -129,7 +138,7 @@ function insertTagIntoTransactionTagsString(transactionTags: string, tag: string } function isMovingTransactionFromTrackExpense(action?: IOUAction) { - if (action === CONST.IOU.ACTION.REQUEST || action === CONST.IOU.ACTION.SHARE || action === CONST.IOU.ACTION.CATEGORIZE) { + if (action === CONST.IOU.ACTION.SUBMIT || action === CONST.IOU.ACTION.SHARE || action === CONST.IOU.ACTION.CATEGORIZE) { return true; } @@ -144,4 +153,5 @@ export { isValidMoneyRequestType, navigateToStartMoneyRequestStep, updateIOUOwnerAndTotal, + temporary_isValidMoneyRequestType, }; diff --git a/src/libs/MoneyRequestUtils.ts b/src/libs/MoneyRequestUtils.ts index 4e681e016b6b..2da048ffab4f 100644 --- a/src/libs/MoneyRequestUtils.ts +++ b/src/libs/MoneyRequestUtils.ts @@ -81,7 +81,7 @@ function replaceAllDigits(text: string, convertFn: (char: string) => string): st * Check if distance expense or not */ function isDistanceRequest(iouType: IOUType, selectedTab: OnyxEntry): boolean { - return iouType === CONST.IOU.TYPE.REQUEST && selectedTab === CONST.TAB_REQUEST.DISTANCE; + return (iouType === CONST.IOU.TYPE.REQUEST || iouType === CONST.IOU.TYPE.SUBMIT) && selectedTab === CONST.TAB_REQUEST.DISTANCE; } /** diff --git a/src/libs/Navigation/Navigation.ts b/src/libs/Navigation/Navigation.ts index b94c2c5fad4a..ce92c169812b 100644 --- a/src/libs/Navigation/Navigation.ts +++ b/src/libs/Navigation/Navigation.ts @@ -94,7 +94,9 @@ function getActiveRouteIndex(stateOrRoute: StateOrRoute, index?: number): number function parseHybridAppUrl(url: HybridAppRoute | Route): Route { switch (url) { case HYBRID_APP_ROUTES.MONEY_REQUEST_CREATE: - return ROUTES.MONEY_REQUEST_CREATE.getRoute(CONST.IOU.ACTION.CREATE, CONST.IOU.TYPE.REQUEST, CONST.IOU.OPTIMISTIC_TRANSACTION_ID, ReportUtils.generateReportID()); + return ROUTES.MONEY_REQUEST_CREATE.getRoute(CONST.IOU.ACTION.CREATE, CONST.IOU.TYPE.SUBMIT, CONST.IOU.OPTIMISTIC_TRANSACTION_ID, ReportUtils.generateReportID()); + case HYBRID_APP_ROUTES.MONEY_REQUEST_SUBMIT_CREATE: + return ROUTES.MONEY_REQUEST_CREATE.getRoute(CONST.IOU.ACTION.CREATE, CONST.IOU.TYPE.SUBMIT, CONST.IOU.OPTIMISTIC_TRANSACTION_ID, ReportUtils.generateReportID()); default: return url; } diff --git a/src/libs/Navigation/types.ts b/src/libs/Navigation/types.ts index 4f58a2f690a1..b0aef04d7abb 100644 --- a/src/libs/Navigation/types.ts +++ b/src/libs/Navigation/types.ts @@ -371,21 +371,21 @@ type RoomInviteNavigatorParamList = { type MoneyRequestNavigatorParamList = { [SCREENS.MONEY_REQUEST.STEP_PARTICIPANTS]: { action: IOUAction; - iouType: ValueOf; + iouType: Exclude; transactionID: string; reportID: string; backTo: string; }; [SCREENS.MONEY_REQUEST.STEP_DATE]: { action: IOUAction; - iouType: IOUType; + iouType: Exclude; transactionID: string; reportID: string; backTo: Routes; }; [SCREENS.MONEY_REQUEST.STEP_DESCRIPTION]: { action: IOUAction; - iouType: IOUType; + iouType: Exclude; transactionID: string; reportID: string; backTo: Routes; @@ -393,7 +393,7 @@ type MoneyRequestNavigatorParamList = { }; [SCREENS.MONEY_REQUEST.STEP_CATEGORY]: { action: IOUAction; - iouType: IOUType; + iouType: Exclude; transactionID: string; reportActionID: string; reportID: string; @@ -401,7 +401,7 @@ type MoneyRequestNavigatorParamList = { }; [SCREENS.MONEY_REQUEST.STEP_TAX_AMOUNT]: { action: IOUAction; - iouType: IOUType; + iouType: Exclude; transactionID: string; reportID: string; backTo: Routes; @@ -409,7 +409,7 @@ type MoneyRequestNavigatorParamList = { }; [SCREENS.MONEY_REQUEST.STEP_TAG]: { action: IOUAction; - iouType: IOUType; + iouType: Exclude; transactionID: string; reportID: string; backTo: Routes; @@ -418,7 +418,7 @@ type MoneyRequestNavigatorParamList = { }; [SCREENS.MONEY_REQUEST.STEP_TAX_RATE]: { action: IOUAction; - iouType: IOUType; + iouType: Exclude; transactionID: string; reportID: string; backTo: Routes; @@ -433,7 +433,7 @@ type MoneyRequestNavigatorParamList = { }; [SCREENS.MONEY_REQUEST.STEP_MERCHANT]: { action: IOUAction; - iouType: IOUType; + iouType: Exclude; transactionID: string; reportID: string; backTo: Routes; @@ -485,7 +485,7 @@ type MoneyRequestNavigatorParamList = { }; [SCREENS.MONEY_REQUEST.STEP_CONFIRMATION]: { action: IOUAction; - iouType: IOUType; + iouType: Exclude; transactionID: string; reportID: string; pageIndex?: string; diff --git a/src/libs/Permissions.ts b/src/libs/Permissions.ts index 105736faeba0..c79e9011386f 100644 --- a/src/libs/Permissions.ts +++ b/src/libs/Permissions.ts @@ -29,7 +29,7 @@ function canUseTrackExpense(betas: OnyxEntry): boolean { function canUseP2PDistanceRequests(betas: OnyxEntry, iouType: IOUType | undefined): boolean { // Allow using P2P distance request for TrackExpense outside of the beta, because that project doesn't want to be limited by the more cautious P2P distance beta - return !!betas?.includes(CONST.BETAS.P2P_DISTANCE_REQUESTS) || canUseAllBetas(betas) || iouType === CONST.IOU.TYPE.TRACK_EXPENSE; + return !!betas?.includes(CONST.BETAS.P2P_DISTANCE_REQUESTS) || canUseAllBetas(betas) || iouType === CONST.IOU.TYPE.TRACK; } function canUseWorkflowsDelayedSubmission(betas: OnyxEntry): boolean { diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index a15e1937dbe2..f8e64fd8b0d7 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -5040,7 +5040,7 @@ function isGroupChatAdmin(report: OnyxEntry, accountID: number) { * None of the options should show in chat threads or if there is some special Expensify account * as a participant of the report. */ -function getMoneyRequestOptions(report: OnyxEntry, policy: OnyxEntry, reportParticipants: number[], canUseTrackExpense = true): IOUType[] { +function getMoneyRequestOptions(report: OnyxEntry, policy: OnyxEntry, reportParticipants: number[], canUseTrackExpense = true, filterDeprecatedTypes = false): IOUType[] { // In any thread or task report, we do not allow any new expenses yet if (isChatThread(report) || isTaskReport(report) || (!canUseTrackExpense && isSelfDM(report))) { return []; @@ -5058,7 +5058,7 @@ function getMoneyRequestOptions(report: OnyxEntry, policy: OnyxEntry, policy: OnyxEntry, + policy: OnyxEntry, + reportParticipants: number[], + canUseTrackExpense = true, +): Array> { + return getMoneyRequestOptions(report, policy, reportParticipants, canUseTrackExpense, true) as Array>; +} + /** * Allows a user to leave a policy room according to the following conditions of the visibility or chatType rNVP: * `public` - Anyone can leave (because anybody can join) @@ -5957,7 +5973,7 @@ function createDraftTransactionAndNavigateToParticipantSelector(transactionID: s created: transactionCreated, } as Transaction); - Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_PARTICIPANTS.getRoute(CONST.IOU.TYPE.REQUEST, transactionID, reportID, undefined, actionName)); + Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_PARTICIPANTS.getRoute(CONST.IOU.TYPE.SUBMIT, transactionID, reportID, undefined, actionName)); } /** @@ -6235,6 +6251,7 @@ export { sortReportsByLastRead, updateOptimisticParentReportAction, updateReportPreview, + temporary_getMoneyRequestOptions, }; export type { diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 5217be1686c2..2503a0d33f16 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -2573,7 +2573,7 @@ function convertTrackedExpenseToRequest( linkedTrackedExpenseReportAction, linkedTrackedExpenseReportID, transactionThreadReportID, - CONST.IOU.ACTION.REQUEST, + CONST.IOU.ACTION.SUBMIT, ); optimisticData?.push(...moveTransactionOptimisticData); @@ -2814,7 +2814,7 @@ function requestMoney( const activeReportID = isMoneyRequestReport ? report?.reportID : chatReport.reportID; switch (action) { - case CONST.IOU.ACTION.REQUEST: { + case CONST.IOU.ACTION.SUBMIT: { if (!linkedTrackedExpenseReportAction || !actionableWhisperReportActionID || !linkedTrackedExpenseReportID) { return; } diff --git a/src/pages/home/report/ReportActionCompose/AttachmentPickerWithMenuItems.tsx b/src/pages/home/report/ReportActionCompose/AttachmentPickerWithMenuItems.tsx index 1294d2ca8aea..09f6e8598e6c 100644 --- a/src/pages/home/report/ReportActionCompose/AttachmentPickerWithMenuItems.tsx +++ b/src/pages/home/report/ReportActionCompose/AttachmentPickerWithMenuItems.tsx @@ -27,7 +27,7 @@ import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import type * as OnyxTypes from '@src/types/onyx'; -type MoneyRequestOptions = Record; +type MoneyRequestOptions = Record, PopoverMenuItem>; type AttachmentPickerWithMenuItemsOnyxProps = { /** The policy tied to the report */ @@ -128,24 +128,24 @@ function AttachmentPickerWithMenuItems({ text: translate('iou.splitExpense'), onSelected: () => IOU.startMoneyRequest(CONST.IOU.TYPE.SPLIT, report?.reportID ?? ''), }, - [CONST.IOU.TYPE.REQUEST]: { + [CONST.IOU.TYPE.SUBMIT]: { icon: Expensicons.MoneyCircle, text: translate('iou.submitExpense'), - onSelected: () => IOU.startMoneyRequest(CONST.IOU.TYPE.REQUEST, report?.reportID ?? ''), + onSelected: () => IOU.startMoneyRequest(CONST.IOU.TYPE.SUBMIT, report?.reportID ?? ''), }, - [CONST.IOU.TYPE.SEND]: { + [CONST.IOU.TYPE.PAY]: { icon: Expensicons.Send, text: translate('iou.paySomeone', {name: ReportUtils.getPayeeName(report)}), - onSelected: () => IOU.startMoneyRequest(CONST.IOU.TYPE.SEND, report?.reportID ?? ''), + onSelected: () => IOU.startMoneyRequest(CONST.IOU.TYPE.PAY, report?.reportID ?? ''), }, - [CONST.IOU.TYPE.TRACK_EXPENSE]: { + [CONST.IOU.TYPE.TRACK]: { icon: Expensicons.DocumentPlus, text: translate('iou.trackExpense'), - onSelected: () => IOU.startMoneyRequest(CONST.IOU.TYPE.TRACK_EXPENSE, report?.reportID ?? ''), + onSelected: () => IOU.startMoneyRequest(CONST.IOU.TYPE.TRACK, report?.reportID ?? ''), }, }; - return ReportUtils.getMoneyRequestOptions(report, policy, reportParticipantIDs ?? [], canUseTrackExpense).map((option) => ({ + return ReportUtils.temporary_getMoneyRequestOptions(report, policy, reportParticipantIDs ?? [], canUseTrackExpense).map((option) => ({ ...options[option], })); }, [translate, report, policy, reportParticipantIDs, canUseTrackExpense]); diff --git a/src/pages/home/report/ReportActionItem.tsx b/src/pages/home/report/ReportActionItem.tsx index 8d11744740bd..7926647551d9 100644 --- a/src/pages/home/report/ReportActionItem.tsx +++ b/src/pages/home/report/ReportActionItem.tsx @@ -393,7 +393,7 @@ function ReportActionItem({ text: 'actionableMentionTrackExpense.submit', key: `${action.reportActionID}-actionableMentionTrackExpense-submit`, onPress: () => { - ReportUtils.createDraftTransactionAndNavigateToParticipantSelector(transactionID, report.reportID, CONST.IOU.ACTION.REQUEST, action.reportActionID); + ReportUtils.createDraftTransactionAndNavigateToParticipantSelector(transactionID, report.reportID, CONST.IOU.ACTION.SUBMIT, action.reportActionID); }, isMediumSized: true, }, diff --git a/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.tsx b/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.tsx index f9f069a2172a..04d82d8dc462 100644 --- a/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.tsx +++ b/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.tsx @@ -169,13 +169,13 @@ function FloatingActionButtonAndPopover( const navigateToQuickAction = () => { switch (quickAction?.action) { case CONST.QUICK_ACTIONS.REQUEST_MANUAL: - IOU.startMoneyRequest(CONST.IOU.TYPE.REQUEST, quickAction?.chatReportID ?? '', CONST.IOU.REQUEST_TYPE.MANUAL, true); + IOU.startMoneyRequest(CONST.IOU.TYPE.SUBMIT, quickAction?.chatReportID ?? '', CONST.IOU.REQUEST_TYPE.MANUAL, true); return; case CONST.QUICK_ACTIONS.REQUEST_SCAN: - IOU.startMoneyRequest(CONST.IOU.TYPE.REQUEST, quickAction?.chatReportID ?? '', CONST.IOU.REQUEST_TYPE.SCAN, true); + IOU.startMoneyRequest(CONST.IOU.TYPE.SUBMIT, quickAction?.chatReportID ?? '', CONST.IOU.REQUEST_TYPE.SCAN, true); return; case CONST.QUICK_ACTIONS.REQUEST_DISTANCE: - IOU.startMoneyRequest(CONST.IOU.TYPE.REQUEST, quickAction?.chatReportID ?? '', CONST.IOU.REQUEST_TYPE.DISTANCE, true); + IOU.startMoneyRequest(CONST.IOU.TYPE.SUBMIT, quickAction?.chatReportID ?? '', CONST.IOU.REQUEST_TYPE.DISTANCE, true); return; case CONST.QUICK_ACTIONS.SPLIT_MANUAL: IOU.startMoneyRequest(CONST.IOU.TYPE.SPLIT, quickAction?.chatReportID ?? '', CONST.IOU.REQUEST_TYPE.MANUAL, true); @@ -187,19 +187,19 @@ function FloatingActionButtonAndPopover( IOU.startMoneyRequest(CONST.IOU.TYPE.SPLIT, quickAction?.chatReportID ?? '', CONST.IOU.REQUEST_TYPE.DISTANCE, true); return; case CONST.QUICK_ACTIONS.SEND_MONEY: - IOU.startMoneyRequest(CONST.IOU.TYPE.SEND, quickAction?.chatReportID ?? '', CONST.IOU.REQUEST_TYPE.MANUAL, true); + IOU.startMoneyRequest(CONST.IOU.TYPE.PAY, quickAction?.chatReportID ?? '', CONST.IOU.REQUEST_TYPE.MANUAL, true); return; case CONST.QUICK_ACTIONS.ASSIGN_TASK: Task.clearOutTaskInfoAndNavigate(quickAction?.chatReportID ?? '', quickActionReport, quickAction.targetAccountID ?? 0, true); break; case CONST.QUICK_ACTIONS.TRACK_MANUAL: - IOU.startMoneyRequest(CONST.IOU.TYPE.TRACK_EXPENSE, quickAction?.chatReportID ?? '', CONST.IOU.REQUEST_TYPE.MANUAL); + IOU.startMoneyRequest(CONST.IOU.TYPE.TRACK, quickAction?.chatReportID ?? '', CONST.IOU.REQUEST_TYPE.MANUAL); break; case CONST.QUICK_ACTIONS.TRACK_SCAN: - IOU.startMoneyRequest(CONST.IOU.TYPE.TRACK_EXPENSE, quickAction?.chatReportID ?? '', CONST.IOU.REQUEST_TYPE.SCAN); + IOU.startMoneyRequest(CONST.IOU.TYPE.TRACK, quickAction?.chatReportID ?? '', CONST.IOU.REQUEST_TYPE.SCAN); break; case CONST.QUICK_ACTIONS.TRACK_DISTANCE: - IOU.startMoneyRequest(CONST.IOU.TYPE.TRACK_EXPENSE, quickAction?.chatReportID ?? '', CONST.IOU.REQUEST_TYPE.DISTANCE); + IOU.startMoneyRequest(CONST.IOU.TYPE.TRACK, quickAction?.chatReportID ?? '', CONST.IOU.REQUEST_TYPE.DISTANCE); break; default: } @@ -293,7 +293,7 @@ function FloatingActionButtonAndPopover( onSelected: () => interceptAnonymousUser(() => IOU.startMoneyRequest( - CONST.IOU.TYPE.TRACK_EXPENSE, + CONST.IOU.TYPE.TRACK, // When starting to create a track expense from the global FAB, we need to retrieve selfDM reportID. // If it doesn't exist, we generate a random optimistic reportID and use it for all of the routes in the creation flow. // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing @@ -309,7 +309,7 @@ function FloatingActionButtonAndPopover( onSelected: () => interceptAnonymousUser(() => IOU.startMoneyRequest( - CONST.IOU.TYPE.REQUEST, + CONST.IOU.TYPE.SUBMIT, // When starting to create an expense from the global FAB, there is not an existing report yet. A random optimistic reportID is generated and used // for all of the routes in the creation flow. ReportUtils.generateReportID(), @@ -335,7 +335,7 @@ function FloatingActionButtonAndPopover( onSelected: () => interceptAnonymousUser(() => IOU.startMoneyRequest( - CONST.IOU.TYPE.SEND, + CONST.IOU.TYPE.PAY, // When starting to pay someone from the global FAB, there is not an existing report yet. A random optimistic reportID is generated and used // for all of the routes in the creation flow. ReportUtils.generateReportID(), diff --git a/src/pages/iou/request/IOURequestStartPage.tsx b/src/pages/iou/request/IOURequestStartPage.tsx index f807038d9cd1..4a401d7de988 100644 --- a/src/pages/iou/request/IOURequestStartPage.tsx +++ b/src/pages/iou/request/IOURequestStartPage.tsx @@ -62,9 +62,11 @@ function IOURequestStartPage({ const [isDraggingOver, setIsDraggingOver] = useState(false); const tabTitles = { [CONST.IOU.TYPE.REQUEST]: translate('iou.submitExpense'), + [CONST.IOU.TYPE.SUBMIT]: translate('iou.submitExpense'), [CONST.IOU.TYPE.SEND]: translate('iou.paySomeone', {name: ReportUtils.getPayeeName(report)}), + [CONST.IOU.TYPE.PAY]: translate('iou.paySomeone', {name: ReportUtils.getPayeeName(report)}), [CONST.IOU.TYPE.SPLIT]: translate('iou.splitExpense'), - [CONST.IOU.TYPE.TRACK_EXPENSE]: translate('iou.trackExpense'), + [CONST.IOU.TYPE.TRACK]: translate('iou.trackExpense'), }; const transactionRequestType = useRef(TransactionUtils.getRequestType(transaction)); const {canUseP2PDistanceRequests} = usePermissions(iouType); @@ -136,7 +138,7 @@ function IOURequestStartPage({ title={tabTitles[iouType]} onBackButtonPress={navigateBack} /> - {iouType !== CONST.IOU.TYPE.SEND ? ( + {iouType !== CONST.IOU.TYPE.SEND && iouType !== CONST.IOU.TYPE.PAY ? ( { diff --git a/src/pages/iou/request/step/IOURequestStepAmount.tsx b/src/pages/iou/request/step/IOURequestStepAmount.tsx index 2cc59bf0af14..460d5f902051 100644 --- a/src/pages/iou/request/step/IOURequestStepAmount.tsx +++ b/src/pages/iou/request/step/IOURequestStepAmount.tsx @@ -85,7 +85,7 @@ function IOURequestStepAmount({ // For quick button actions, we'll skip the confirmation page unless the report is archived or this is a workspace request, as // the user will have to add a merchant. const shouldSkipConfirmation: boolean = useMemo(() => { - if (!skipConfirmation || !report?.reportID || iouType === CONST.IOU.TYPE.TRACK_EXPENSE) { + if (!skipConfirmation || !report?.reportID || iouType === CONST.IOU.TYPE.TRACK) { return false; } @@ -132,6 +132,32 @@ function IOURequestStepAmount({ ); }; + const navigateToParticipantPage = () => { + switch (iouType) { + case CONST.IOU.TYPE.REQUEST: + Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_PARTICIPANTS.getRoute(CONST.IOU.TYPE.SUBMIT, transactionID, reportID)); + break; + case CONST.IOU.TYPE.SEND: + Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_PARTICIPANTS.getRoute(CONST.IOU.TYPE.PAY, transactionID, reportID)); + break; + default: + Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_PARTICIPANTS.getRoute(iouType, transactionID, reportID)); + } + }; + + const navigateToConfirmationPage = () => { + switch (iouType) { + case CONST.IOU.TYPE.REQUEST: + Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_CONFIRMATION.getRoute(CONST.IOU.ACTION.CREATE, CONST.IOU.TYPE.SUBMIT, transactionID, reportID)); + break; + case CONST.IOU.TYPE.SEND: + Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_CONFIRMATION.getRoute(CONST.IOU.ACTION.CREATE, CONST.IOU.TYPE.PAY, transactionID, reportID)); + break; + default: + Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_CONFIRMATION.getRoute(CONST.IOU.ACTION.CREATE, iouType, transactionID, reportID)); + } + }; + const navigateToNextPage = ({amount, paymentMethod}: AmountParams) => { isSaveButtonPressed.current = true; const amountInSmallestCurrencyUnits = CurrencyUtils.convertToBackendAmount(Number.parseFloat(amount)); @@ -173,7 +199,7 @@ function IOURequestStepAmount({ }); return; } - if (iouType === CONST.IOU.TYPE.SEND) { + if (iouType === CONST.IOU.TYPE.PAY || iouType === CONST.IOU.TYPE.SEND) { if (paymentMethod && paymentMethod === CONST.IOU.PAYMENT_TYPE.EXPENSIFY) { IOU.sendMoneyWithWallet(report, backendAmount, currency, '', currentUserPersonalDetails.accountID, participants[0]); return; @@ -182,7 +208,7 @@ function IOURequestStepAmount({ IOU.sendMoneyElsewhere(report, backendAmount, currency, '', currentUserPersonalDetails.accountID, participants[0]); return; } - if (iouType === CONST.IOU.TYPE.REQUEST) { + if (iouType === CONST.IOU.TYPE.SUBMIT || iouType === CONST.IOU.TYPE.REQUEST) { IOU.requestMoney( report, backendAmount, @@ -199,13 +225,13 @@ function IOURequestStepAmount({ } } IOU.setMoneyRequestParticipantsFromReport(transactionID, report); - Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_CONFIRMATION.getRoute(CONST.IOU.ACTION.CREATE, iouType, transactionID, reportID)); + navigateToConfirmationPage(); return; } // If there was no reportID, then that means the user started this flow from the global + menu // and an optimistic reportID was generated. In that case, the next step is to select the participants for this expense. - Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_PARTICIPANTS.getRoute(iouType, transactionID, reportID)); + navigateToParticipantPage(); }; const saveAmountAndCurrency = ({amount, paymentMethod}: AmountParams) => { diff --git a/src/pages/iou/request/step/IOURequestStepConfirmation.tsx b/src/pages/iou/request/step/IOURequestStepConfirmation.tsx index 057b3e027243..b7622d784c39 100644 --- a/src/pages/iou/request/step/IOURequestStepConfirmation.tsx +++ b/src/pages/iou/request/step/IOURequestStepConfirmation.tsx @@ -77,7 +77,7 @@ function IOURequestStepConfirmation({ const transactionTaxAmount = transaction?.taxAmount; const isSharingTrackExpense = action === CONST.IOU.ACTION.SHARE; const isCategorizingTrackExpense = action === CONST.IOU.ACTION.CATEGORIZE; - const isRequestingFromTrackExpense = action === CONST.IOU.ACTION.REQUEST; + const isSubmittingFromTrackExpense = action === CONST.IOU.ACTION.SUBMIT; const requestType = TransactionUtils.getRequestType(transaction); @@ -85,7 +85,7 @@ function IOURequestStepConfirmation({ if (isSharingTrackExpense) { return translate('iou.categorize'); } - if (isRequestingFromTrackExpense) { + if (isSubmittingFromTrackExpense) { return translate('iou.submitExpense'); } if (isCategorizingTrackExpense) { @@ -94,14 +94,14 @@ function IOURequestStepConfirmation({ if (iouType === CONST.IOU.TYPE.SPLIT) { return translate('iou.splitExpense'); } - if (iouType === CONST.IOU.TYPE.TRACK_EXPENSE) { + if (iouType === CONST.IOU.TYPE.TRACK) { return translate('iou.trackExpense'); } - if (iouType === CONST.IOU.TYPE.SEND) { + if (iouType === CONST.IOU.TYPE.PAY) { return translate('iou.paySomeone', {name: ReportUtils.getPayeeName(report)}); } return translate(TransactionUtils.getHeaderTitleTranslationKey(transaction)); - }, [iouType, report, transaction, translate, isSharingTrackExpense, isCategorizingTrackExpense, isRequestingFromTrackExpense]); + }, [iouType, report, transaction, translate, isSharingTrackExpense, isCategorizingTrackExpense, isSubmittingFromTrackExpense]); const participants = useMemo( () => @@ -352,7 +352,7 @@ function IOURequestStepConfirmation({ return; } - if (iouType === CONST.IOU.TYPE.TRACK_EXPENSE || isCategorizingTrackExpense || isSharingTrackExpense) { + if (iouType === CONST.IOU.TYPE.TRACK || isCategorizingTrackExpense || isSharingTrackExpense) { if (receiptFile && transaction) { // If the transaction amount is zero, then the money is being requested through the "Scan" flow and the GPS coordinates need to be included. if (transaction.amount === 0 && !isSharingTrackExpense && !isCategorizingTrackExpense) { @@ -494,7 +494,7 @@ function IOURequestStepConfirmation({ diff --git a/src/pages/iou/request/step/IOURequestStepDistance.tsx b/src/pages/iou/request/step/IOURequestStepDistance.tsx index 0602c2184365..57fc77e05fed 100644 --- a/src/pages/iou/request/step/IOURequestStepDistance.tsx +++ b/src/pages/iou/request/step/IOURequestStepDistance.tsx @@ -105,7 +105,7 @@ function IOURequestStepDistance({ // For quick button actions, we'll skip the confirmation page unless the report is archived or this is a workspace // request and the workspace requires a category or a tag const shouldSkipConfirmation: boolean = useMemo(() => { - if (!skipConfirmation || !report?.reportID || iouType === CONST.IOU.TYPE.TRACK_EXPENSE) { + if (!skipConfirmation || !report?.reportID || iouType === CONST.IOU.TYPE.TRACK) { return false; } @@ -176,12 +176,38 @@ function IOURequestStepDistance({ const navigateToWaypointEditPage = useCallback( (index: number) => { Navigation.navigate( - ROUTES.MONEY_REQUEST_STEP_WAYPOINT.getRoute(action, CONST.IOU.TYPE.REQUEST, transactionID, report?.reportID, index.toString(), Navigation.getActiveRouteWithoutParams()), + ROUTES.MONEY_REQUEST_STEP_WAYPOINT.getRoute(action, CONST.IOU.TYPE.SUBMIT, transactionID, report?.reportID, index.toString(), Navigation.getActiveRouteWithoutParams()), ); }, [action, transactionID, report?.reportID], ); + const navigateToParticipantPage = useCallback(() => { + switch (iouType) { + case CONST.IOU.TYPE.REQUEST: + Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_PARTICIPANTS.getRoute(CONST.IOU.TYPE.SUBMIT, transactionID, reportID)); + break; + case CONST.IOU.TYPE.SEND: + Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_PARTICIPANTS.getRoute(CONST.IOU.TYPE.PAY, transactionID, reportID)); + break; + default: + Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_PARTICIPANTS.getRoute(iouType, transactionID, reportID)); + } + }, [iouType, reportID, transactionID]); + + const navigateToConfirmationPage = useCallback(() => { + switch (iouType) { + case CONST.IOU.TYPE.REQUEST: + Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_CONFIRMATION.getRoute(CONST.IOU.ACTION.CREATE, CONST.IOU.TYPE.SUBMIT, transactionID, reportID)); + break; + case CONST.IOU.TYPE.SEND: + Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_CONFIRMATION.getRoute(CONST.IOU.ACTION.CREATE, CONST.IOU.TYPE.PAY, transactionID, reportID)); + break; + default: + Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_CONFIRMATION.getRoute(CONST.IOU.ACTION.CREATE, iouType, transactionID, reportID)); + } + }, [iouType, reportID, transactionID]); + const navigateToNextStep = useCallback(() => { if (backTo) { Navigation.goBack(backTo); @@ -233,14 +259,27 @@ function IOURequestStepDistance({ return; } IOU.setMoneyRequestParticipantsFromReport(transactionID, report); - Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_CONFIRMATION.getRoute(CONST.IOU.ACTION.CREATE, iouType, transactionID, reportID)); + navigateToConfirmationPage(); return; } // If there was no reportID, then that means the user started this flow from the global menu // and an optimistic reportID was generated. In that case, the next step is to select the participants for this expense. - Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_PARTICIPANTS.getRoute(iouType, transactionID, reportID)); - }, [report, iouType, reportID, transactionID, backTo, waypoints, currentUserPersonalDetails, personalDetails, shouldSkipConfirmation, transaction, translate]); + navigateToParticipantPage(); + }, [ + report, + iouType, + transactionID, + backTo, + waypoints, + currentUserPersonalDetails, + personalDetails, + shouldSkipConfirmation, + transaction, + translate, + navigateToParticipantPage, + navigateToConfirmationPage, + ]); const getError = () => { // Get route error if available else show the invalid number of waypoints error. diff --git a/src/pages/iou/request/step/IOURequestStepParticipants.tsx b/src/pages/iou/request/step/IOURequestStepParticipants.tsx index 28126c71faaa..bcd03fe038bf 100644 --- a/src/pages/iou/request/step/IOURequestStepParticipants.tsx +++ b/src/pages/iou/request/step/IOURequestStepParticipants.tsx @@ -6,7 +6,6 @@ import Navigation from '@libs/Navigation/Navigation'; import * as TransactionUtils from '@libs/TransactionUtils'; import MoneyRequestParticipantsSelector from '@pages/iou/request/MoneyTemporaryForRefactorRequestParticipantsSelector'; import * as IOU from '@userActions/IOU'; -import type {IOUType} from '@src/CONST'; import CONST from '@src/CONST'; import ROUTES from '@src/ROUTES'; import type SCREENS from '@src/SCREENS'; @@ -27,8 +26,6 @@ type IOURequestStepParticipantsProps = IOURequestStepParticipantsOnyxProps & WithWritableReportOrNotFoundProps & WithFullTransactionOrNotFoundProps; -type IOURef = IOUType | null; - function IOURequestStepParticipants({ route: { params: {iouType, reportID, transactionID, action}, @@ -45,7 +42,7 @@ function IOURequestStepParticipants({ if (action === CONST.IOU.ACTION.CATEGORIZE) { return translate('iou.categorize'); } - if (action === CONST.IOU.ACTION.REQUEST) { + if (action === CONST.IOU.ACTION.SUBMIT) { return translate('iou.submitExpense'); } if (action === CONST.IOU.ACTION.SHARE) { @@ -54,7 +51,7 @@ function IOURequestStepParticipants({ if (isSplitRequest) { return translate('iou.splitExpense'); } - if (iouType === CONST.IOU.TYPE.SEND) { + if (iouType === CONST.IOU.TYPE.PAY) { return translate('iou.paySomeone', {}); } return translate(TransactionUtils.getHeaderTitleTranslationKey(transaction)); @@ -63,7 +60,6 @@ function IOURequestStepParticipants({ const receiptFilename = transaction?.filename; const receiptPath = transaction?.receipt?.source; const receiptType = transaction?.receipt?.type; - const newIouType = useRef(); // When the component mounts, if there is a receipt, see if the image can be read from the disk. If not, redirect the user to the starting step of the flow. // This is because until the expense is saved, the receipt file is only stored in the browsers memory as a blob:// and if the browser is refreshed, then @@ -77,18 +73,7 @@ function IOURequestStepParticipants({ }, [receiptType, receiptPath, receiptFilename, iouRequestType, iouType, transactionID, reportID, action]); const addParticipant = useCallback( - (val: Participant[], selectedIouType: IOUType) => { - const isSplit = selectedIouType === CONST.IOU.TYPE.SPLIT; - // It's only possible to switch between REQUEST and SPLIT. - // We want to update the IOU type only if it's not updated yet to prevent unnecessary updates. - if (isSplit && iouType !== CONST.IOU.TYPE.SPLIT) { - newIouType.current = CONST.IOU.TYPE.SPLIT; - } else if (!isSplit && iouType === CONST.IOU.TYPE.SPLIT) { - // Non-split can be either REQUEST or SEND. Instead of checking whether - // the current IOU type is not a REQUEST (true for SEND), we check whether the current IOU type is a SPLIT. - newIouType.current = CONST.IOU.TYPE.REQUEST; - } - + (val: Participant[]) => { IOU.setMoneyRequestParticipants_temporaryForRefactor(transactionID, val); numberOfParticipants.current = val.length; @@ -102,7 +87,7 @@ function IOURequestStepParticipants({ // When a participant is selected, the reportID needs to be saved because that's the reportID that will be used in the confirmation step. selectedReportID.current = val[0]?.reportID ?? reportID; }, - [reportID, transactionID, iouType], + [reportID, transactionID], ); const goToNextStep = useCallback(() => { diff --git a/src/pages/iou/request/step/IOURequestStepRoutePropTypes.js b/src/pages/iou/request/step/IOURequestStepRoutePropTypes.js deleted file mode 100644 index f69e2b122c24..000000000000 --- a/src/pages/iou/request/step/IOURequestStepRoutePropTypes.js +++ /dev/null @@ -1,29 +0,0 @@ -import PropTypes from 'prop-types'; -import _ from 'underscore'; -import CONST from '@src/CONST'; - -export default PropTypes.shape({ - /** Route specific parameters used on this screen via route :iouType/new/category/:reportID? */ - params: PropTypes.shape({ - /** What action is being performed, ie. create, edit */ - action: PropTypes.oneOf(_.values(CONST.IOU.ACTION)), - - /** The type of IOU report, i.e. split, request, send, track */ - iouType: PropTypes.oneOf(_.values(CONST.IOU.TYPE)).isRequired, - - /** The ID of the transaction being configured */ - transactionID: PropTypes.string.isRequired, - - /** The report ID of the IOU */ - reportID: PropTypes.string.isRequired, - - /** Index of the waypoint being edited */ - pageIndex: PropTypes.string, - - /** A path to go to when the user presses the back button */ - backTo: PropTypes.string, - - /** Indicates which tag list index was selected */ - tagIndex: PropTypes.string, - }), -}); diff --git a/src/pages/iou/request/step/IOURequestStepScan/index.native.tsx b/src/pages/iou/request/step/IOURequestStepScan/index.native.tsx index 84c2137dafda..4c396a1e70b7 100644 --- a/src/pages/iou/request/step/IOURequestStepScan/index.native.tsx +++ b/src/pages/iou/request/step/IOURequestStepScan/index.native.tsx @@ -65,7 +65,7 @@ function IOURequestStepScan({ // For quick button actions, we'll skip the confirmation page unless the report is archived or this is a workspace // request and the workspace requires a category or a tag const shouldSkipConfirmation: boolean = useMemo(() => { - if (!skipConfirmation || !report?.reportID || iouType === CONST.IOU.TYPE.TRACK_EXPENSE) { + if (!skipConfirmation || !report?.reportID || iouType === CONST.IOU.TYPE.TRACK) { return false; } @@ -179,6 +179,32 @@ function IOURequestStepScan({ Navigation.goBack(); }; + const navigateToParticipantPage = useCallback(() => { + switch (iouType) { + case CONST.IOU.TYPE.REQUEST: + Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_PARTICIPANTS.getRoute(CONST.IOU.TYPE.SUBMIT, transactionID, reportID)); + break; + case CONST.IOU.TYPE.SEND: + Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_PARTICIPANTS.getRoute(CONST.IOU.TYPE.PAY, transactionID, reportID)); + break; + default: + Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_PARTICIPANTS.getRoute(iouType, transactionID, reportID)); + } + }, [iouType, reportID, transactionID]); + + const navigateToConfirmationPage = useCallback(() => { + switch (iouType) { + case CONST.IOU.TYPE.REQUEST: + Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_CONFIRMATION.getRoute(CONST.IOU.ACTION.CREATE, CONST.IOU.TYPE.SUBMIT, transactionID, reportID)); + break; + case CONST.IOU.TYPE.SEND: + Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_CONFIRMATION.getRoute(CONST.IOU.ACTION.CREATE, CONST.IOU.TYPE.PAY, transactionID, reportID)); + break; + default: + Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_CONFIRMATION.getRoute(CONST.IOU.ACTION.CREATE, iouType, transactionID, reportID)); + } + }, [iouType, reportID, transactionID]); + const navigateToConfirmationStep = useCallback( (file: FileObject, source: string) => { if (backTo) { @@ -187,8 +213,8 @@ function IOURequestStepScan({ } // If the transaction was created from the global create, the person needs to select participants, so take them there. - if (transaction?.isFromGlobalCreate && iouType !== CONST.IOU.TYPE.TRACK_EXPENSE && !report?.reportID) { - Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_PARTICIPANTS.getRoute(iouType, transactionID, reportID)); + if (transaction?.isFromGlobalCreate && iouType !== CONST.IOU.TYPE.TRACK && !report?.reportID) { + navigateToParticipantPage(); return; } @@ -233,9 +259,21 @@ function IOURequestStepScan({ ); return; } - Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_CONFIRMATION.getRoute(CONST.IOU.ACTION.CREATE, iouType, transactionID, reportID)); + navigateToConfirmationPage(); }, - [iouType, report, reportID, transactionID, backTo, currentUserPersonalDetails, personalDetails, shouldSkipConfirmation, transaction], + [ + iouType, + report, + reportID, + transactionID, + backTo, + currentUserPersonalDetails, + personalDetails, + shouldSkipConfirmation, + transaction, + navigateToConfirmationPage, + navigateToParticipantPage, + ], ); const updateScanAndNavigate = useCallback( diff --git a/src/pages/iou/request/step/IOURequestStepScan/index.tsx b/src/pages/iou/request/step/IOURequestStepScan/index.tsx index 8bca59b11580..adfad2385aeb 100644 --- a/src/pages/iou/request/step/IOURequestStepScan/index.tsx +++ b/src/pages/iou/request/step/IOURequestStepScan/index.tsx @@ -80,7 +80,7 @@ function IOURequestStepScan({ // For quick button actions, we'll skip the confirmation page unless the report is archived or this is a workspace // request and the workspace requires a category or a tag const shouldSkipConfirmation: boolean = useMemo(() => { - if (!skipConfirmation || !report?.reportID || iouType === CONST.IOU.TYPE.TRACK_EXPENSE) { + if (!skipConfirmation || !report?.reportID || iouType === CONST.IOU.TYPE.TRACK) { return false; } @@ -219,6 +219,32 @@ function IOURequestStepScan({ Navigation.goBack(backTo); }; + const navigateToParticipantPage = useCallback(() => { + switch (iouType) { + case CONST.IOU.TYPE.REQUEST: + Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_PARTICIPANTS.getRoute(CONST.IOU.TYPE.SUBMIT, transactionID, reportID)); + break; + case CONST.IOU.TYPE.SEND: + Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_PARTICIPANTS.getRoute(CONST.IOU.TYPE.PAY, transactionID, reportID)); + break; + default: + Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_PARTICIPANTS.getRoute(iouType, transactionID, reportID)); + } + }, [iouType, reportID, transactionID]); + + const navigateToConfirmationPage = useCallback(() => { + switch (iouType) { + case CONST.IOU.TYPE.REQUEST: + Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_CONFIRMATION.getRoute(CONST.IOU.ACTION.CREATE, CONST.IOU.TYPE.SUBMIT, transactionID, reportID)); + break; + case CONST.IOU.TYPE.SEND: + Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_CONFIRMATION.getRoute(CONST.IOU.ACTION.CREATE, CONST.IOU.TYPE.PAY, transactionID, reportID)); + break; + default: + Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_CONFIRMATION.getRoute(CONST.IOU.ACTION.CREATE, iouType, transactionID, reportID)); + } + }, [iouType, reportID, transactionID]); + const navigateToConfirmationStep = useCallback( (file: FileObject, source: string) => { if (backTo) { @@ -227,8 +253,8 @@ function IOURequestStepScan({ } // If the transaction was created from the global create, the person needs to select participants, so take them there. - if (transaction?.isFromGlobalCreate && iouType !== CONST.IOU.TYPE.TRACK_EXPENSE && !report?.reportID) { - Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_PARTICIPANTS.getRoute(iouType, transactionID, reportID)); + if (transaction?.isFromGlobalCreate && iouType !== CONST.IOU.TYPE.TRACK && !report?.reportID) { + navigateToParticipantPage(); return; } @@ -273,9 +299,21 @@ function IOURequestStepScan({ ); return; } - Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_CONFIRMATION.getRoute(CONST.IOU.ACTION.CREATE, iouType, transactionID, reportID)); + navigateToConfirmationPage(); }, - [iouType, report, reportID, transactionID, backTo, currentUserPersonalDetails, personalDetails, shouldSkipConfirmation, transaction], + [ + iouType, + report, + reportID, + transactionID, + backTo, + currentUserPersonalDetails, + personalDetails, + shouldSkipConfirmation, + transaction, + navigateToConfirmationPage, + navigateToParticipantPage, + ], ); const updateScanAndNavigate = useCallback( diff --git a/src/pages/iou/steps/MoneyRequestAmountForm.tsx b/src/pages/iou/steps/MoneyRequestAmountForm.tsx index a5ed35374e00..5727351f45da 100644 --- a/src/pages/iou/steps/MoneyRequestAmountForm.tsx +++ b/src/pages/iou/steps/MoneyRequestAmountForm.tsx @@ -97,7 +97,7 @@ function MoneyRequestAmountForm( isCurrencyPressable = true, isEditing = false, skipConfirmation = false, - iouType = CONST.IOU.TYPE.REQUEST, + iouType = CONST.IOU.TYPE.SUBMIT, policyID = '', bankAccountRoute = '', onCurrencyButtonPress, @@ -387,7 +387,7 @@ function MoneyRequestAmountForm( longPressHandlerStateChanged={updateLongPressHandlerState} /> ) : null} - {iouType === CONST.IOU.TYPE.SEND && skipConfirmation ? ( + {iouType === CONST.IOU.TYPE.PAY && skipConfirmation ? ( { const reportParticipants = Array.from({length: 1000}, (v, i) => i + 1); await waitForBatchedUpdates(); - await measureFunction(() => ReportUtils.getMoneyRequestOptions(report, policy, reportParticipants)); + await measureFunction(() => ReportUtils.temporary_getMoneyRequestOptions(report, policy, reportParticipants)); }); test('[ReportUtils] getWorkspaceAvatar on 1k policies', async () => { diff --git a/tests/unit/IOUUtilsTest.ts b/tests/unit/IOUUtilsTest.ts index ddc220449e2f..b8640e4ecdf1 100644 --- a/tests/unit/IOUUtilsTest.ts +++ b/tests/unit/IOUUtilsTest.ts @@ -118,12 +118,13 @@ describe('IOUUtils', () => { describe('isValidMoneyRequestType', () => { test('Return true for valid iou type', () => { - expect(IOUUtils.isValidMoneyRequestType('request')).toBe(true); - expect(IOUUtils.isValidMoneyRequestType('split')).toBe(true); - expect(IOUUtils.isValidMoneyRequestType('send')).toBe(true); + expect(IOUUtils.temporary_isValidMoneyRequestType('submit')).toBe(true); + expect(IOUUtils.temporary_isValidMoneyRequestType('split')).toBe(true); + expect(IOUUtils.temporary_isValidMoneyRequestType('pay')).toBe(true); + expect(IOUUtils.temporary_isValidMoneyRequestType('track')).toBe(true); }); test('Return false for invalid iou type', () => { - expect(IOUUtils.isValidMoneyRequestType('money')).toBe(false); + expect(IOUUtils.temporary_isValidMoneyRequestType('money')).toBe(false); }); }); diff --git a/tests/unit/ReportUtilsTest.ts b/tests/unit/ReportUtilsTest.ts index 0ed28ea84fcb..d0ea948bdb6c 100644 --- a/tests/unit/ReportUtilsTest.ts +++ b/tests/unit/ReportUtilsTest.ts @@ -359,7 +359,7 @@ describe('ReportUtils', () => { describe('return empty iou options if', () => { it('participants array contains excluded expensify iou emails', () => { const allEmpty = CONST.EXPENSIFY_ACCOUNT_IDS.every((accountID) => { - const moneyRequestOptions = ReportUtils.getMoneyRequestOptions(null, null, [currentUserAccountID, accountID]); + const moneyRequestOptions = ReportUtils.temporary_getMoneyRequestOptions(null, null, [currentUserAccountID, accountID]); return moneyRequestOptions.length === 0; }); expect(allEmpty).toBe(true); @@ -370,7 +370,7 @@ describe('ReportUtils', () => { ...LHNTestUtils.getFakeReport(), chatType: CONST.REPORT.CHAT_TYPE.POLICY_ROOM, }; - const moneyRequestOptions = ReportUtils.getMoneyRequestOptions(report, null, [currentUserAccountID]); + const moneyRequestOptions = ReportUtils.temporary_getMoneyRequestOptions(report, null, [currentUserAccountID]); expect(moneyRequestOptions.length).toBe(0); }); @@ -380,7 +380,7 @@ describe('ReportUtils', () => { chatType: CONST.REPORT.CHAT_TYPE.POLICY_EXPENSE_CHAT, isOwnPolicyExpenseChat: false, }; - const moneyRequestOptions = ReportUtils.getMoneyRequestOptions(report, null, [currentUserAccountID]); + const moneyRequestOptions = ReportUtils.temporary_getMoneyRequestOptions(report, null, [currentUserAccountID]); expect(moneyRequestOptions.length).toBe(0); }); @@ -390,7 +390,7 @@ describe('ReportUtils', () => { type: CONST.REPORT.TYPE.IOU, statusNum: CONST.REPORT.STATUS_NUM.REIMBURSED, }; - const moneyRequestOptions = ReportUtils.getMoneyRequestOptions(report, null, [currentUserAccountID]); + const moneyRequestOptions = ReportUtils.temporary_getMoneyRequestOptions(report, null, [currentUserAccountID]); expect(moneyRequestOptions.length).toBe(0); }); @@ -401,7 +401,7 @@ describe('ReportUtils', () => { stateNum: CONST.REPORT.STATE_NUM.APPROVED, statusNum: CONST.REPORT.STATUS_NUM.APPROVED, }; - const moneyRequestOptions = ReportUtils.getMoneyRequestOptions(report, null, [currentUserAccountID]); + const moneyRequestOptions = ReportUtils.temporary_getMoneyRequestOptions(report, null, [currentUserAccountID]); expect(moneyRequestOptions.length).toBe(0); }); @@ -411,7 +411,7 @@ describe('ReportUtils', () => { type: CONST.REPORT.TYPE.EXPENSE, statusNum: CONST.REPORT.STATUS_NUM.REIMBURSED, }; - const moneyRequestOptions = ReportUtils.getMoneyRequestOptions(report, null, [currentUserAccountID]); + const moneyRequestOptions = ReportUtils.temporary_getMoneyRequestOptions(report, null, [currentUserAccountID]); expect(moneyRequestOptions.length).toBe(0); }); @@ -425,7 +425,7 @@ describe('ReportUtils', () => { parentReportID: '100', type: CONST.REPORT.TYPE.EXPENSE, }; - const moneyRequestOptions = ReportUtils.getMoneyRequestOptions(report, null, [currentUserAccountID]); + const moneyRequestOptions = ReportUtils.temporary_getMoneyRequestOptions(report, null, [currentUserAccountID]); expect(moneyRequestOptions.length).toBe(0); }); }); @@ -456,7 +456,7 @@ describe('ReportUtils', () => { parentReportID: '101', policyID: paidPolicy.id, }; - const moneyRequestOptions = ReportUtils.getMoneyRequestOptions(report, paidPolicy, [currentUserAccountID, participantsAccountIDs[0]]); + const moneyRequestOptions = ReportUtils.temporary_getMoneyRequestOptions(report, paidPolicy, [currentUserAccountID, participantsAccountIDs[0]]); expect(moneyRequestOptions.length).toBe(0); }); }); @@ -474,7 +474,7 @@ describe('ReportUtils', () => { ...LHNTestUtils.getFakeReport(), chatType, }; - const moneyRequestOptions = ReportUtils.getMoneyRequestOptions(report, null, [currentUserAccountID, participantsAccountIDs[0]]); + const moneyRequestOptions = ReportUtils.temporary_getMoneyRequestOptions(report, null, [currentUserAccountID, participantsAccountIDs[0]]); return moneyRequestOptions.length === 1 && moneyRequestOptions.includes(CONST.IOU.TYPE.SPLIT); }); expect(onlyHaveSplitOption).toBe(true); @@ -485,7 +485,7 @@ describe('ReportUtils', () => { ...LHNTestUtils.getFakeReport(), chatType: CONST.REPORT.CHAT_TYPE.POLICY_ROOM, }; - const moneyRequestOptions = ReportUtils.getMoneyRequestOptions(report, null, [currentUserAccountID, ...participantsAccountIDs]); + const moneyRequestOptions = ReportUtils.temporary_getMoneyRequestOptions(report, null, [currentUserAccountID, ...participantsAccountIDs]); expect(moneyRequestOptions.length).toBe(1); expect(moneyRequestOptions.includes(CONST.IOU.TYPE.SPLIT)).toBe(true); }); @@ -495,7 +495,7 @@ describe('ReportUtils', () => { ...LHNTestUtils.getFakeReport(), chatType: CONST.REPORT.CHAT_TYPE.POLICY_ROOM, }; - const moneyRequestOptions = ReportUtils.getMoneyRequestOptions(report, null, [currentUserAccountID, ...participantsAccountIDs]); + const moneyRequestOptions = ReportUtils.temporary_getMoneyRequestOptions(report, null, [currentUserAccountID, ...participantsAccountIDs]); expect(moneyRequestOptions.length).toBe(1); expect(moneyRequestOptions.includes(CONST.IOU.TYPE.SPLIT)).toBe(true); }); @@ -506,7 +506,7 @@ describe('ReportUtils', () => { type: CONST.REPORT.TYPE.CHAT, participantsAccountIDs: [currentUserAccountID, ...participantsAccountIDs], }; - const moneyRequestOptions = ReportUtils.getMoneyRequestOptions(report, null, [currentUserAccountID, ...participantsAccountIDs.map(Number)]); + const moneyRequestOptions = ReportUtils.temporary_getMoneyRequestOptions(report, null, [currentUserAccountID, ...participantsAccountIDs.map(Number)]); expect(moneyRequestOptions.length).toBe(1); expect(moneyRequestOptions.includes(CONST.IOU.TYPE.SPLIT)).toBe(true); }); @@ -520,9 +520,9 @@ describe('ReportUtils', () => { stateNum: CONST.REPORT.STATE_NUM.SUBMITTED, statusNum: CONST.REPORT.STATUS_NUM.SUBMITTED, }; - const moneyRequestOptions = ReportUtils.getMoneyRequestOptions(report, null, [currentUserAccountID, participantsAccountIDs[0]]); + const moneyRequestOptions = ReportUtils.temporary_getMoneyRequestOptions(report, null, [currentUserAccountID, participantsAccountIDs[0]]); expect(moneyRequestOptions.length).toBe(1); - expect(moneyRequestOptions.includes(CONST.IOU.TYPE.REQUEST)).toBe(true); + expect(moneyRequestOptions.includes(CONST.IOU.TYPE.SUBMIT)).toBe(true); }); it('it is an IOU report in submitted state even with pay expense permissions', () => { @@ -532,9 +532,9 @@ describe('ReportUtils', () => { stateNum: CONST.REPORT.STATE_NUM.SUBMITTED, statusNum: CONST.REPORT.STATUS_NUM.SUBMITTED, }; - const moneyRequestOptions = ReportUtils.getMoneyRequestOptions(report, null, [currentUserAccountID, participantsAccountIDs[0]]); + const moneyRequestOptions = ReportUtils.temporary_getMoneyRequestOptions(report, null, [currentUserAccountID, participantsAccountIDs[0]]); expect(moneyRequestOptions.length).toBe(1); - expect(moneyRequestOptions.includes(CONST.IOU.TYPE.REQUEST)).toBe(true); + expect(moneyRequestOptions.includes(CONST.IOU.TYPE.SUBMIT)).toBe(true); }); }); @@ -550,10 +550,10 @@ describe('ReportUtils', () => { parentReportID: '102', type: CONST.REPORT.TYPE.EXPENSE, }; - const moneyRequestOptions = ReportUtils.getMoneyRequestOptions(report, null, [currentUserAccountID]); + const moneyRequestOptions = ReportUtils.temporary_getMoneyRequestOptions(report, null, [currentUserAccountID]); expect(moneyRequestOptions.length).toBe(2); - expect(moneyRequestOptions.includes(CONST.IOU.TYPE.REQUEST)).toBe(true); - expect(moneyRequestOptions.includes(CONST.IOU.TYPE.TRACK_EXPENSE)).toBe(true); + expect(moneyRequestOptions.includes(CONST.IOU.TYPE.SUBMIT)).toBe(true); + expect(moneyRequestOptions.includes(CONST.IOU.TYPE.TRACK)).toBe(true); }); }); @@ -579,10 +579,10 @@ describe('ReportUtils', () => { outputCurrency: '', isPolicyExpenseChatEnabled: false, } as const; - const moneyRequestOptions = ReportUtils.getMoneyRequestOptions(report, paidPolicy, [currentUserAccountID, participantsAccountIDs[0]]); + const moneyRequestOptions = ReportUtils.temporary_getMoneyRequestOptions(report, paidPolicy, [currentUserAccountID, participantsAccountIDs[0]]); expect(moneyRequestOptions.length).toBe(2); - expect(moneyRequestOptions.includes(CONST.IOU.TYPE.REQUEST)).toBe(true); - expect(moneyRequestOptions.includes(CONST.IOU.TYPE.TRACK_EXPENSE)).toBe(true); + expect(moneyRequestOptions.includes(CONST.IOU.TYPE.SUBMIT)).toBe(true); + expect(moneyRequestOptions.includes(CONST.IOU.TYPE.TRACK)).toBe(true); }); }); @@ -593,9 +593,9 @@ describe('ReportUtils', () => { stateNum: CONST.REPORT.STATE_NUM.SUBMITTED, statusNum: CONST.REPORT.STATUS_NUM.SUBMITTED, }; - const moneyRequestOptions = ReportUtils.getMoneyRequestOptions(report, null, [currentUserAccountID, participantsAccountIDs[0]]); + const moneyRequestOptions = ReportUtils.temporary_getMoneyRequestOptions(report, null, [currentUserAccountID, participantsAccountIDs[0]]); expect(moneyRequestOptions.length).toBe(1); - expect(moneyRequestOptions.includes(CONST.IOU.TYPE.REQUEST)).toBe(true); + expect(moneyRequestOptions.includes(CONST.IOU.TYPE.SUBMIT)).toBe(true); }); it('it is an IOU report in submitted state even with pay expense permissions', () => { @@ -605,9 +605,9 @@ describe('ReportUtils', () => { stateNum: CONST.REPORT.STATE_NUM.SUBMITTED, statusNum: CONST.REPORT.STATUS_NUM.SUBMITTED, }; - const moneyRequestOptions = ReportUtils.getMoneyRequestOptions(report, null, [currentUserAccountID, participantsAccountIDs[0]]); + const moneyRequestOptions = ReportUtils.temporary_getMoneyRequestOptions(report, null, [currentUserAccountID, participantsAccountIDs[0]]); expect(moneyRequestOptions.length).toBe(1); - expect(moneyRequestOptions.includes(CONST.IOU.TYPE.REQUEST)).toBe(true); + expect(moneyRequestOptions.includes(CONST.IOU.TYPE.SUBMIT)).toBe(true); }); it("it is a submitted expense report in user's own policyExpenseChat and the policy has Instant Submit frequency", () => { @@ -638,10 +638,10 @@ describe('ReportUtils', () => { parentReportID: '101', policyID: paidPolicy.id, }; - const moneyRequestOptions = ReportUtils.getMoneyRequestOptions(report, paidPolicy, [currentUserAccountID, participantsAccountIDs[0]]); + const moneyRequestOptions = ReportUtils.temporary_getMoneyRequestOptions(report, paidPolicy, [currentUserAccountID, participantsAccountIDs[0]]); expect(moneyRequestOptions.length).toBe(2); - expect(moneyRequestOptions.includes(CONST.IOU.TYPE.REQUEST)).toBe(true); - expect(moneyRequestOptions.includes(CONST.IOU.TYPE.TRACK_EXPENSE)).toBe(true); + expect(moneyRequestOptions.includes(CONST.IOU.TYPE.SUBMIT)).toBe(true); + expect(moneyRequestOptions.includes(CONST.IOU.TYPE.TRACK)).toBe(true); }); }); }); @@ -652,11 +652,11 @@ describe('ReportUtils', () => { ...LHNTestUtils.getFakeReport(), type: CONST.REPORT.TYPE.CHAT, }; - const moneyRequestOptions = ReportUtils.getMoneyRequestOptions(report, null, [currentUserAccountID, participantsAccountIDs[0]]); + const moneyRequestOptions = ReportUtils.temporary_getMoneyRequestOptions(report, null, [currentUserAccountID, participantsAccountIDs[0]]); expect(moneyRequestOptions.length).toBe(3); expect(moneyRequestOptions.includes(CONST.IOU.TYPE.SPLIT)).toBe(true); - expect(moneyRequestOptions.includes(CONST.IOU.TYPE.REQUEST)).toBe(true); - expect(moneyRequestOptions.includes(CONST.IOU.TYPE.SEND)).toBe(true); + expect(moneyRequestOptions.includes(CONST.IOU.TYPE.SUBMIT)).toBe(true); + expect(moneyRequestOptions.includes(CONST.IOU.TYPE.PAY)).toBe(true); }); it("it is user's own policy expense chat", () => { @@ -665,11 +665,11 @@ describe('ReportUtils', () => { chatType: CONST.REPORT.CHAT_TYPE.POLICY_EXPENSE_CHAT, isOwnPolicyExpenseChat: true, }; - const moneyRequestOptions = ReportUtils.getMoneyRequestOptions(report, null, [currentUserAccountID, ...participantsAccountIDs]); + const moneyRequestOptions = ReportUtils.temporary_getMoneyRequestOptions(report, null, [currentUserAccountID, ...participantsAccountIDs]); expect(moneyRequestOptions.length).toBe(3); - expect(moneyRequestOptions.includes(CONST.IOU.TYPE.REQUEST)).toBe(true); + expect(moneyRequestOptions.includes(CONST.IOU.TYPE.SUBMIT)).toBe(true); expect(moneyRequestOptions.includes(CONST.IOU.TYPE.SPLIT)).toBe(true); - expect(moneyRequestOptions.includes(CONST.IOU.TYPE.TRACK_EXPENSE)).toBe(true); + expect(moneyRequestOptions.includes(CONST.IOU.TYPE.TRACK)).toBe(true); }); }); }); From b29bad72ec437d5f3816b85a25b53466b1e9ffec Mon Sep 17 00:00:00 2001 From: Shubham Agrawal Date: Fri, 19 Apr 2024 21:04:16 +0530 Subject: [PATCH 37/57] Protected some routes against problems --- src/pages/iou/request/step/IOURequestStepAmount.tsx | 2 +- src/pages/iou/request/step/IOURequestStepDistance.tsx | 2 +- .../iou/request/step/IOURequestStepScan/index.native.tsx | 2 +- src/pages/iou/request/step/IOURequestStepScan/index.tsx | 2 +- src/pages/iou/request/step/IOURequestStepWaypoint.tsx | 1 + src/pages/iou/request/step/withWritableReportOrNotFound.tsx | 5 ++++- 6 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/pages/iou/request/step/IOURequestStepAmount.tsx b/src/pages/iou/request/step/IOURequestStepAmount.tsx index 460d5f902051..f55bebc7dd76 100644 --- a/src/pages/iou/request/step/IOURequestStepAmount.tsx +++ b/src/pages/iou/request/step/IOURequestStepAmount.tsx @@ -314,7 +314,7 @@ const IOURequestStepAmountWithOnyx = withOnyx = WithWr export default function , TRef>( WrappedComponent: ComponentType>, + shouldIncludeDeprecatedIOUType = false, ): React.ComponentType, keyof WithWritableReportOrNotFoundOnyxProps>> { // eslint-disable-next-line rulesdir/no-negated-variables function WithWritableReportOrNotFound(props: TProps, ref: ForwardedRef) { const {report = {reportID: ''}, route} = props; - const iouTypeParamIsInvalid = !Object.values(CONST.IOU.TYPE).includes(route.params?.iouType); + const iouTypeParamIsInvalid = !Object.values(CONST.IOU.TYPE) + .filter((type) => shouldIncludeDeprecatedIOUType || (type !== CONST.IOU.TYPE.REQUEST && type !== CONST.IOU.TYPE.SEND)) + .includes(route.params?.iouType); const canUserPerformWriteAction = ReportUtils.canUserPerformWriteAction(report); if (iouTypeParamIsInvalid || !canUserPerformWriteAction) { From 1e0b31476bd73dc44a6282bdb51d8bb218be3ee3 Mon Sep 17 00:00:00 2001 From: Shubham Agrawal Date: Sat, 20 Apr 2024 06:31:14 +0530 Subject: [PATCH 38/57] Renaming some consts and minor updates to header title --- src/CONST.ts | 4 ++-- src/components/ReferralProgramCTA.tsx | 4 ++-- src/hooks/useDismissedReferralBanners.ts | 4 ++-- src/languages/en.ts | 4 ++-- src/languages/es.ts | 4 ++-- src/libs/TransactionUtils.ts | 15 --------------- ...oraryForRefactorRequestParticipantsSelector.js | 2 +- .../request/step/IOURequestStepConfirmation.tsx | 4 ++-- .../request/step/IOURequestStepParticipants.tsx | 4 ++-- .../MoneyRequestParticipantsSelector.js | 2 +- src/types/onyx/DismissedReferralBanners.ts | 4 ++-- 11 files changed, 18 insertions(+), 33 deletions(-) diff --git a/src/CONST.ts b/src/CONST.ts index b5ffcc9c07e8..be5f778af37b 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -3379,9 +3379,9 @@ const CONST = { REFERRAL_PROGRAM: { CONTENT_TYPES: { - MONEY_REQUEST: 'request', + SUBMIT_EXPENSE: 'submitExpense', START_CHAT: 'startChat', - SEND_MONEY: 'sendMoney', + PAY_SOMEONE: 'paySomeone', REFER_FRIEND: 'referralFriend', SHARE_CODE: 'shareCode', }, diff --git a/src/components/ReferralProgramCTA.tsx b/src/components/ReferralProgramCTA.tsx index 0588f31a0a8c..237fc8f955a3 100644 --- a/src/components/ReferralProgramCTA.tsx +++ b/src/components/ReferralProgramCTA.tsx @@ -15,9 +15,9 @@ import Tooltip from './Tooltip'; type ReferralProgramCTAProps = { referralContentType: - | typeof CONST.REFERRAL_PROGRAM.CONTENT_TYPES.MONEY_REQUEST + | typeof CONST.REFERRAL_PROGRAM.CONTENT_TYPES.SUBMIT_EXPENSE | typeof CONST.REFERRAL_PROGRAM.CONTENT_TYPES.START_CHAT - | typeof CONST.REFERRAL_PROGRAM.CONTENT_TYPES.SEND_MONEY + | typeof CONST.REFERRAL_PROGRAM.CONTENT_TYPES.PAY_SOMEONE | typeof CONST.REFERRAL_PROGRAM.CONTENT_TYPES.REFER_FRIEND; style?: ViewStyle; onDismiss?: () => void; diff --git a/src/hooks/useDismissedReferralBanners.ts b/src/hooks/useDismissedReferralBanners.ts index 94ccd0a0b567..23a3ecefbbc9 100644 --- a/src/hooks/useDismissedReferralBanners.ts +++ b/src/hooks/useDismissedReferralBanners.ts @@ -5,9 +5,9 @@ import ONYXKEYS from '@src/ONYXKEYS'; type UseDismissedReferralBannersProps = { referralContentType: - | typeof CONST.REFERRAL_PROGRAM.CONTENT_TYPES.MONEY_REQUEST + | typeof CONST.REFERRAL_PROGRAM.CONTENT_TYPES.SUBMIT_EXPENSE | typeof CONST.REFERRAL_PROGRAM.CONTENT_TYPES.START_CHAT - | typeof CONST.REFERRAL_PROGRAM.CONTENT_TYPES.SEND_MONEY + | typeof CONST.REFERRAL_PROGRAM.CONTENT_TYPES.PAY_SOMEONE | typeof CONST.REFERRAL_PROGRAM.CONTENT_TYPES.REFER_FRIEND; }; diff --git a/src/languages/en.ts b/src/languages/en.ts index fd018f5f5800..282650b185d4 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -2645,13 +2645,13 @@ export default { header: `Start a chat, get $${CONST.REFERRAL_PROGRAM.REVENUE}`, body: `Get paid to talk to your friends! Start a chat with a new Expensify account and get $${CONST.REFERRAL_PROGRAM.REVENUE} when they become a customer.`, }, - [CONST.REFERRAL_PROGRAM.CONTENT_TYPES.MONEY_REQUEST]: { + [CONST.REFERRAL_PROGRAM.CONTENT_TYPES.SUBMIT_EXPENSE]: { buttonText1: 'Submit expense, ', buttonText2: `get $${CONST.REFERRAL_PROGRAM.REVENUE}.`, header: `Submit an expense, get $${CONST.REFERRAL_PROGRAM.REVENUE}`, body: `It pays to get paid! Submit an expense to a new Expensify account and get $${CONST.REFERRAL_PROGRAM.REVENUE} when they become a customer.`, }, - [CONST.REFERRAL_PROGRAM.CONTENT_TYPES.SEND_MONEY]: { + [CONST.REFERRAL_PROGRAM.CONTENT_TYPES.PAY_SOMEONE]: { buttonText1: 'Pay Someone, ', buttonText2: `get $${CONST.REFERRAL_PROGRAM.REVENUE}.`, header: `Pay Someone, get $${CONST.REFERRAL_PROGRAM.REVENUE}`, diff --git a/src/languages/es.ts b/src/languages/es.ts index cf0b0eea1799..802f1e3365dc 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -3135,13 +3135,13 @@ export default { header: `Inicia un chat y recibe $${CONST.REFERRAL_PROGRAM.REVENUE}`, body: `¡Gana dinero por hablar con tus amigos! Inicia un chat con una cuenta nueva de Expensify y recibe $${CONST.REFERRAL_PROGRAM.REVENUE} cuando se conviertan en clientes.`, }, - [CONST.REFERRAL_PROGRAM.CONTENT_TYPES.MONEY_REQUEST]: { + [CONST.REFERRAL_PROGRAM.CONTENT_TYPES.SUBMIT_EXPENSE]: { buttonText1: 'Presentar gasto, ', buttonText2: `recibe $${CONST.REFERRAL_PROGRAM.REVENUE}`, header: `Presenta un gasto y consigue $${CONST.REFERRAL_PROGRAM.REVENUE}`, body: `¡Vale la pena cobrar! Envia un gasto a una cuenta nueva de Expensify y recibe $${CONST.REFERRAL_PROGRAM.REVENUE} cuando se conviertan en clientes.`, }, - [CONST.REFERRAL_PROGRAM.CONTENT_TYPES.SEND_MONEY]: { + [CONST.REFERRAL_PROGRAM.CONTENT_TYPES.PAY_SOMEONE]: { buttonText1: 'Pagar a alguien, ', buttonText2: `recibe $${CONST.REFERRAL_PROGRAM.REVENUE}`, header: `Paga a alguien y recibe $${CONST.REFERRAL_PROGRAM.REVENUE}`, diff --git a/src/libs/TransactionUtils.ts b/src/libs/TransactionUtils.ts index a5b85b87e37e..fbe7edc960ba 100644 --- a/src/libs/TransactionUtils.ts +++ b/src/libs/TransactionUtils.ts @@ -3,7 +3,6 @@ import type {OnyxCollection, OnyxEntry} from 'react-native-onyx'; import Onyx from 'react-native-onyx'; import type {ValueOf} from 'type-fest'; import CONST from '@src/CONST'; -import type {TranslationPaths} from '@src/languages/types'; import ONYXKEYS from '@src/ONYXKEYS'; import type {RecentWaypoint, Report, TaxRate, TaxRates, TaxRatesWithDefault, Transaction, TransactionViolation} from '@src/types/onyx'; import type {Comment, Receipt, TransactionChanges, TransactionPendingFieldsKey, Waypoint, WaypointCollection} from '@src/types/onyx/Transaction'; @@ -450,19 +449,6 @@ function getCreated(transaction: OnyxEntry, dateFormat: string = CO return DateUtils.formatWithUTCTimeZone(created, dateFormat); } -/** - * Returns the translation key to use for the header title - */ -function getHeaderTitleTranslationKey(transaction: OnyxEntry): TranslationPaths { - const headerTitles: Record = { - [CONST.IOU.REQUEST_TYPE.DISTANCE]: 'tabSelector.distance', - [CONST.IOU.REQUEST_TYPE.MANUAL]: 'tabSelector.manual', - [CONST.IOU.REQUEST_TYPE.SCAN]: 'tabSelector.scan', - }; - - return headerTitles[getRequestType(transaction)]; -} - /** * Determine whether a transaction is made with an Expensify card. */ @@ -655,7 +641,6 @@ export { getEnabledTaxRateCount, getUpdatedTransaction, getDescription, - getHeaderTitleTranslationKey, getRequestType, isManualRequest, isScanRequest, diff --git a/src/pages/iou/request/MoneyTemporaryForRefactorRequestParticipantsSelector.js b/src/pages/iou/request/MoneyTemporaryForRefactorRequestParticipantsSelector.js index bda8c25d9b18..e12269b93796 100644 --- a/src/pages/iou/request/MoneyTemporaryForRefactorRequestParticipantsSelector.js +++ b/src/pages/iou/request/MoneyTemporaryForRefactorRequestParticipantsSelector.js @@ -67,7 +67,7 @@ function MoneyTemporaryForRefactorRequestParticipantsSelector({participants, onF const {translate} = useLocalize(); const styles = useThemeStyles(); const [searchTerm, debouncedSearchTerm, setSearchTerm] = useDebouncedState(''); - const referralContentType = iouType === CONST.IOU.TYPE.PAY ? CONST.REFERRAL_PROGRAM.CONTENT_TYPES.SEND_MONEY : CONST.REFERRAL_PROGRAM.CONTENT_TYPES.MONEY_REQUEST; + const referralContentType = iouType === CONST.IOU.TYPE.PAY ? CONST.REFERRAL_PROGRAM.CONTENT_TYPES.PAY_SOMEONE : CONST.REFERRAL_PROGRAM.CONTENT_TYPES.SUBMIT_EXPENSE; const {isOffline} = useNetwork(); const personalDetails = usePersonalDetails(); const {isDismissed} = useDismissedReferralBanners({referralContentType}); diff --git a/src/pages/iou/request/step/IOURequestStepConfirmation.tsx b/src/pages/iou/request/step/IOURequestStepConfirmation.tsx index b7622d784c39..f627c052ad90 100644 --- a/src/pages/iou/request/step/IOURequestStepConfirmation.tsx +++ b/src/pages/iou/request/step/IOURequestStepConfirmation.tsx @@ -100,8 +100,8 @@ function IOURequestStepConfirmation({ if (iouType === CONST.IOU.TYPE.PAY) { return translate('iou.paySomeone', {name: ReportUtils.getPayeeName(report)}); } - return translate(TransactionUtils.getHeaderTitleTranslationKey(transaction)); - }, [iouType, report, transaction, translate, isSharingTrackExpense, isCategorizingTrackExpense, isSubmittingFromTrackExpense]); + return translate('iou.submitExpense'); + }, [iouType, report, translate, isSharingTrackExpense, isCategorizingTrackExpense, isSubmittingFromTrackExpense]); const participants = useMemo( () => diff --git a/src/pages/iou/request/step/IOURequestStepParticipants.tsx b/src/pages/iou/request/step/IOURequestStepParticipants.tsx index bcd03fe038bf..b412704900e6 100644 --- a/src/pages/iou/request/step/IOURequestStepParticipants.tsx +++ b/src/pages/iou/request/step/IOURequestStepParticipants.tsx @@ -54,8 +54,8 @@ function IOURequestStepParticipants({ if (iouType === CONST.IOU.TYPE.PAY) { return translate('iou.paySomeone', {}); } - return translate(TransactionUtils.getHeaderTitleTranslationKey(transaction)); - }, [iouType, transaction, translate, isSplitRequest, action]); + return translate('iou.submitExpense'); + }, [iouType, translate, isSplitRequest, action]); const receiptFilename = transaction?.filename; const receiptPath = transaction?.receipt?.source; diff --git a/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsSelector.js b/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsSelector.js index 31ca7ba0098d..58935cf04330 100755 --- a/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsSelector.js +++ b/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsSelector.js @@ -66,7 +66,7 @@ function MoneyRequestParticipantsSelector({participants, navigateToRequest, navi const styles = useThemeStyles(); const [betas] = useOnyx(ONYXKEYS.BETAS); const [searchTerm, debouncedSearchTerm, setSearchTerm] = useDebouncedState(''); - const referralContentType = iouType === CONST.IOU.TYPE.SEND ? CONST.REFERRAL_PROGRAM.CONTENT_TYPES.SEND_MONEY : CONST.REFERRAL_PROGRAM.CONTENT_TYPES.MONEY_REQUEST; + const referralContentType = iouType === CONST.IOU.TYPE.SEND ? CONST.REFERRAL_PROGRAM.CONTENT_TYPES.PAY_SOMEONE : CONST.REFERRAL_PROGRAM.CONTENT_TYPES.SUBMIT_EXPENSE; const {isOffline} = useNetwork(); const personalDetails = usePersonalDetails(); const {options, areOptionsInitialized} = useOptionsList({shouldInitialize: didScreenTransitionEnd}); diff --git a/src/types/onyx/DismissedReferralBanners.ts b/src/types/onyx/DismissedReferralBanners.ts index 43fa6472a6ae..86937d3bfbaf 100644 --- a/src/types/onyx/DismissedReferralBanners.ts +++ b/src/types/onyx/DismissedReferralBanners.ts @@ -1,9 +1,9 @@ import type CONST from '@src/CONST'; type DismissedReferralBanners = { - [CONST.REFERRAL_PROGRAM.CONTENT_TYPES.MONEY_REQUEST]?: boolean; + [CONST.REFERRAL_PROGRAM.CONTENT_TYPES.SUBMIT_EXPENSE]?: boolean; [CONST.REFERRAL_PROGRAM.CONTENT_TYPES.START_CHAT]?: boolean; - [CONST.REFERRAL_PROGRAM.CONTENT_TYPES.SEND_MONEY]?: boolean; + [CONST.REFERRAL_PROGRAM.CONTENT_TYPES.PAY_SOMEONE]?: boolean; [CONST.REFERRAL_PROGRAM.CONTENT_TYPES.REFER_FRIEND]?: boolean; [CONST.REFERRAL_PROGRAM.CONTENT_TYPES.SHARE_CODE]?: boolean; }; From 62ef4b8b524c9bb345a9978297c8e65db7143c59 Mon Sep 17 00:00:00 2001 From: Shubham Agrawal Date: Sat, 20 Apr 2024 06:37:28 +0530 Subject: [PATCH 39/57] Fixing routes after merge --- src/components/ReportActionItem/MoneyRequestView.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/ReportActionItem/MoneyRequestView.tsx b/src/components/ReportActionItem/MoneyRequestView.tsx index d66be06671a8..f337f2f40c71 100644 --- a/src/components/ReportActionItem/MoneyRequestView.tsx +++ b/src/components/ReportActionItem/MoneyRequestView.tsx @@ -311,7 +311,7 @@ function MoneyRequestView({ shouldShowRightIcon={canEditDistance} titleStyle={styles.flex1} onPress={() => - Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_DISTANCE.getRoute(CONST.IOU.ACTION.EDIT, CONST.IOU.TYPE.REQUEST, transaction?.transactionID ?? '', report.reportID)) + Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_DISTANCE.getRoute(CONST.IOU.ACTION.EDIT, CONST.IOU.TYPE.SUBMIT, transaction?.transactionID ?? '', report.reportID)) } /> From b3acaa16b20e533351fa32a19879ac6060e1386e Mon Sep 17 00:00:00 2001 From: tienifr Date: Sat, 20 Apr 2024 11:16:01 +0700 Subject: [PATCH 40/57] fix add queue command length log --- src/libs/API/index.ts | 4 ++++ src/libs/Network/SequentialQueue.ts | 2 ++ src/libs/actions/PersistedRequests.ts | 6 +++++- 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/libs/API/index.ts b/src/libs/API/index.ts index dbbcf790edf0..bfa1b95836f8 100644 --- a/src/libs/API/index.ts +++ b/src/libs/API/index.ts @@ -5,6 +5,7 @@ import * as Middleware from '@libs/Middleware'; import * as SequentialQueue from '@libs/Network/SequentialQueue'; import * as Pusher from '@libs/Pusher/pusher'; import * as Request from '@libs/Request'; +import * as PersistedRequests from '@userActions/PersistedRequests'; import CONST from '@src/CONST'; import type OnyxRequest from '@src/types/onyx/Request'; import type Response from '@src/types/onyx/Response'; @@ -159,6 +160,9 @@ function read(command: TCommand, apiCommandParamet // Ensure all write requests on the sequential queue have finished responding before running read requests. // Responses from read requests can overwrite the optimistic data inserted by // write requests that use the same Onyx keys and haven't responded yet. + if (PersistedRequests.getLength() > 0) { + Log.info(`[API] '${command}' is waiting on ${PersistedRequests.getLength()} write commands`); + } SequentialQueue.waitForIdle().then(() => makeRequestWithSideEffects(command, apiCommandParameters, onyxData, CONST.API_REQUEST_TYPE.READ)); } diff --git a/src/libs/Network/SequentialQueue.ts b/src/libs/Network/SequentialQueue.ts index 38b0549b28bc..0cfa8e17b589 100644 --- a/src/libs/Network/SequentialQueue.ts +++ b/src/libs/Network/SequentialQueue.ts @@ -1,5 +1,6 @@ import Onyx from 'react-native-onyx'; import * as ActiveClientManager from '@libs/ActiveClientManager'; +import Log from '@libs/Log'; import * as Request from '@libs/Request'; import * as RequestThrottle from '@libs/RequestThrottle'; import * as PersistedRequests from '@userActions/PersistedRequests'; @@ -162,6 +163,7 @@ NetworkStore.onReconnection(flush); function push(request: OnyxRequest) { // Add request to Persisted Requests so that it can be retried if it fails PersistedRequests.save(request); + Log.info(`[SequentialQueue] '${request.commandName}' command queued. Queue length is ${PersistedRequests.getLength()}`); // If we are offline we don't need to trigger the queue to empty as it will happen when we come back online if (NetworkStore.isOffline()) { diff --git a/src/libs/actions/PersistedRequests.ts b/src/libs/actions/PersistedRequests.ts index 8894af8c374f..410b8931d92a 100644 --- a/src/libs/actions/PersistedRequests.ts +++ b/src/libs/actions/PersistedRequests.ts @@ -48,4 +48,8 @@ function getAll(): Request[] { return persistedRequests; } -export {clear, save, getAll, remove, update}; +function getLength(): number { + return persistedRequests.length; +} + +export {clear, save, getAll, remove, update, getLength}; From 09b2e1295a8e6c0a8158e4d0024169195cf6c64c Mon Sep 17 00:00:00 2001 From: tienifr Date: Sat, 20 Apr 2024 11:25:00 +0700 Subject: [PATCH 41/57] fix use promise --- src/libs/Network/SequentialQueue.ts | 1 - src/libs/actions/PersistedRequests.ts | 6 +++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/libs/Network/SequentialQueue.ts b/src/libs/Network/SequentialQueue.ts index 0cfa8e17b589..d0b10a88388f 100644 --- a/src/libs/Network/SequentialQueue.ts +++ b/src/libs/Network/SequentialQueue.ts @@ -163,7 +163,6 @@ NetworkStore.onReconnection(flush); function push(request: OnyxRequest) { // Add request to Persisted Requests so that it can be retried if it fails PersistedRequests.save(request); - Log.info(`[SequentialQueue] '${request.commandName}' command queued. Queue length is ${PersistedRequests.getLength()}`); // If we are offline we don't need to trigger the queue to empty as it will happen when we come back online if (NetworkStore.isOffline()) { diff --git a/src/libs/actions/PersistedRequests.ts b/src/libs/actions/PersistedRequests.ts index 410b8931d92a..0bf51a500ce6 100644 --- a/src/libs/actions/PersistedRequests.ts +++ b/src/libs/actions/PersistedRequests.ts @@ -1,5 +1,7 @@ import isEqual from 'lodash/isEqual'; import Onyx from 'react-native-onyx'; +import Log from '@libs/Log'; +import * as PersistedRequests from '@userActions/PersistedRequests'; import ONYXKEYS from '@src/ONYXKEYS'; import type {Request} from '@src/types/onyx'; @@ -19,7 +21,9 @@ function clear() { function save(requestToPersist: Request) { persistedRequests.push(requestToPersist); - Onyx.set(ONYXKEYS.PERSISTED_REQUESTS, persistedRequests); + Onyx.set(ONYXKEYS.PERSISTED_REQUESTS, persistedRequests).then(() => { + Log.info(`[SequentialQueue] '${requestToPersist.command}' command queued. Queue length is ${PersistedRequests.getLength()}`); + }); } function remove(requestToRemove: Request) { From a34d3baacc659e1d70299f8ed0b4709cc1b01d83 Mon Sep 17 00:00:00 2001 From: tienifr Date: Sat, 20 Apr 2024 11:26:42 +0700 Subject: [PATCH 42/57] fix lint --- src/libs/Network/SequentialQueue.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libs/Network/SequentialQueue.ts b/src/libs/Network/SequentialQueue.ts index d0b10a88388f..38b0549b28bc 100644 --- a/src/libs/Network/SequentialQueue.ts +++ b/src/libs/Network/SequentialQueue.ts @@ -1,6 +1,5 @@ import Onyx from 'react-native-onyx'; import * as ActiveClientManager from '@libs/ActiveClientManager'; -import Log from '@libs/Log'; import * as Request from '@libs/Request'; import * as RequestThrottle from '@libs/RequestThrottle'; import * as PersistedRequests from '@userActions/PersistedRequests'; From 1ecb38527325ca78f22c4427074a49ac766c5576 Mon Sep 17 00:00:00 2001 From: tienifr Date: Sat, 20 Apr 2024 11:35:25 +0700 Subject: [PATCH 43/57] fix lint --- src/libs/actions/PersistedRequests.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/libs/actions/PersistedRequests.ts b/src/libs/actions/PersistedRequests.ts index 0bf51a500ce6..ab380a2ae1fa 100644 --- a/src/libs/actions/PersistedRequests.ts +++ b/src/libs/actions/PersistedRequests.ts @@ -1,7 +1,6 @@ import isEqual from 'lodash/isEqual'; import Onyx from 'react-native-onyx'; import Log from '@libs/Log'; -import * as PersistedRequests from '@userActions/PersistedRequests'; import ONYXKEYS from '@src/ONYXKEYS'; import type {Request} from '@src/types/onyx'; @@ -22,7 +21,7 @@ function clear() { function save(requestToPersist: Request) { persistedRequests.push(requestToPersist); Onyx.set(ONYXKEYS.PERSISTED_REQUESTS, persistedRequests).then(() => { - Log.info(`[SequentialQueue] '${requestToPersist.command}' command queued. Queue length is ${PersistedRequests.getLength()}`); + Log.info(`[SequentialQueue] '${requestToPersist.command}' command queued. Queue length is ${getLength()}`); }); } From 7fb8b40e9f5d236f267cfea1db0bf246a7e4fa36 Mon Sep 17 00:00:00 2001 From: tienifr Date: Sat, 20 Apr 2024 11:42:35 +0700 Subject: [PATCH 44/57] fix lint --- src/libs/actions/PersistedRequests.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libs/actions/PersistedRequests.ts b/src/libs/actions/PersistedRequests.ts index ab380a2ae1fa..839ed5b38763 100644 --- a/src/libs/actions/PersistedRequests.ts +++ b/src/libs/actions/PersistedRequests.ts @@ -18,6 +18,10 @@ function clear() { return Onyx.set(ONYXKEYS.PERSISTED_REQUESTS, []); } +function getLength(): number { + return persistedRequests.length; +} + function save(requestToPersist: Request) { persistedRequests.push(requestToPersist); Onyx.set(ONYXKEYS.PERSISTED_REQUESTS, persistedRequests).then(() => { @@ -51,8 +55,4 @@ function getAll(): Request[] { return persistedRequests; } -function getLength(): number { - return persistedRequests.length; -} - export {clear, save, getAll, remove, update, getLength}; From 45d64f39f5007db872a24984f28a856a255606e8 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Mon, 22 Apr 2024 10:58:56 +0200 Subject: [PATCH 45/57] Move useScreenWrapperTranstionStatus to useSyncFocus --- src/components/SelectionList/BaseSelectionList.tsx | 4 +--- src/hooks/useSyncFocus/index.ts | 7 +++++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/components/SelectionList/BaseSelectionList.tsx b/src/components/SelectionList/BaseSelectionList.tsx index 8fe4463e162e..f0d22251bc74 100644 --- a/src/components/SelectionList/BaseSelectionList.tsx +++ b/src/components/SelectionList/BaseSelectionList.tsx @@ -20,7 +20,6 @@ import useKeyboardShortcut from '@hooks/useKeyboardShortcut'; import useKeyboardState from '@hooks/useKeyboardState'; import useLocalize from '@hooks/useLocalize'; import usePrevious from '@hooks/usePrevious'; -import useScreenWrapperTranstionStatus from '@hooks/useScreenWrapperTransitionStatus'; import useThemeStyles from '@hooks/useThemeStyles'; import getSectionsWithIndexOffset from '@libs/getSectionsWithIndexOffset'; import Log from '@libs/Log'; @@ -95,7 +94,6 @@ function BaseSelectionList( const itemFocusTimeoutRef = useRef(null); const [currentPage, setCurrentPage] = useState(1); const isTextInputFocusedRef = useRef(false); - const {didScreenTransitionEnd} = useScreenWrapperTranstionStatus(); const incrementPage = () => setCurrentPage((prev) => prev + 1); @@ -360,7 +358,7 @@ function BaseSelectionList( keyForList={item.keyForList ?? ''} isMultilineSupported={isRowMultilineSupported} onFocus={() => setFocusedIndex(normalizedIndex)} - shouldSyncFocus={!isTextInputFocusedRef.current && didScreenTransitionEnd} + shouldSyncFocus={!isTextInputFocusedRef.current} /> ); }; diff --git a/src/hooks/useSyncFocus/index.ts b/src/hooks/useSyncFocus/index.ts index bdc4a6a876da..d2145023e06b 100644 --- a/src/hooks/useSyncFocus/index.ts +++ b/src/hooks/useSyncFocus/index.ts @@ -1,6 +1,7 @@ import {useLayoutEffect} from 'react'; import type {RefObject} from 'react'; import type {View} from 'react-native'; +import useScreenWrapperTranstionStatus from '@hooks/useScreenWrapperTransitionStatus'; /** * Custom React hook created to handle sync of focus on an element when the user navigates through the app with keyboard. @@ -8,13 +9,15 @@ import type {View} from 'react-native'; * To maintain consistency when an element is focused in the app, the focus() method is additionally called on the focused element to eliminate the difference between native browser focus and application focus. */ const useSyncFocus = (ref: RefObject, isFocused: boolean) => { + const {didScreenTransitionEnd} = useScreenWrapperTranstionStatus(); + useLayoutEffect(() => { - if (!isFocused) { + if (!isFocused || !didScreenTransitionEnd) { return; } ref.current?.focus(); - }, [isFocused, ref]); + }, [didScreenTransitionEnd, isFocused, ref]); }; export default useSyncFocus; From a0e6f688be8d577b64b301c20076345e37ffcb7c Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Mon, 22 Apr 2024 10:59:45 +0200 Subject: [PATCH 46/57] Add checking shouldPreventDefaultFocusOnSelectRow to SelectionLists where text input is displayed --- src/components/CategoryPicker.tsx | 2 ++ src/components/TagPicker/index.tsx | 2 ++ src/components/TaxPicker.tsx | 2 ++ src/pages/EditReportFieldDropdown.tsx | 1 + src/pages/WorkspaceSwitcherPage/index.tsx | 2 ++ src/pages/iou/request/step/IOURequestStepCurrency.tsx | 2 ++ src/pages/settings/AboutPage/ShareLogList/BaseShareLogList.tsx | 2 ++ .../settings/Profile/PersonalDetails/CountrySelectionPage.tsx | 2 ++ .../settings/Profile/PersonalDetails/StateSelectionPage.tsx | 2 ++ src/pages/settings/Profile/PronounsPage.tsx | 2 ++ src/pages/settings/Profile/TimezoneSelectPage.tsx | 2 ++ src/pages/tasks/TaskAssigneeSelectorModal.tsx | 2 ++ src/pages/tasks/TaskShareDestinationSelectorModal.tsx | 2 ++ src/pages/workspace/WorkspaceProfileCurrencyPage.tsx | 2 ++ .../workflows/WorkspaceAutoReportingMonthlyOffsetPage.tsx | 2 ++ .../workspace/workflows/WorkspaceWorkflowsApproverPage.tsx | 2 ++ src/pages/workspace/workflows/WorkspaceWorkflowsPayerPage.tsx | 2 ++ 17 files changed, 33 insertions(+) diff --git a/src/components/CategoryPicker.tsx b/src/components/CategoryPicker.tsx index f26d7c25c7e2..0dbad24e3f5b 100644 --- a/src/components/CategoryPicker.tsx +++ b/src/components/CategoryPicker.tsx @@ -3,6 +3,7 @@ import {withOnyx} from 'react-native-onyx'; import type {OnyxEntry} from 'react-native-onyx'; import useDebouncedState from '@hooks/useDebouncedState'; import useLocalize from '@hooks/useLocalize'; +import * as DeviceCapabilities from '@libs/DeviceCapabilities'; import * as OptionsListUtils from '@libs/OptionsListUtils'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; @@ -83,6 +84,7 @@ function CategoryPicker({selectedCategory, policyCategories, policyRecentlyUsedC ListItem={RadioListItem} initiallyFocusedOptionKey={selectedOptionKey ?? undefined} isRowMultilineSupported + shouldPreventDefaultFocusOnSelectRow={!DeviceCapabilities.canUseTouchScreen()} /> ); } diff --git a/src/components/TagPicker/index.tsx b/src/components/TagPicker/index.tsx index 97cd9aa5c691..7b7c50300e3e 100644 --- a/src/components/TagPicker/index.tsx +++ b/src/components/TagPicker/index.tsx @@ -5,6 +5,7 @@ import SelectionList from '@components/SelectionList'; import RadioListItem from '@components/SelectionList/RadioListItem'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; +import * as DeviceCapabilities from '@libs/DeviceCapabilities'; import * as OptionsListUtils from '@libs/OptionsListUtils'; import * as PolicyUtils from '@libs/PolicyUtils'; import type * as ReportUtils from '@libs/ReportUtils'; @@ -104,6 +105,7 @@ function TagPicker({selectedTag, tagListName, policyTags, tagListIndex, policyRe initiallyFocusedOptionKey={selectedOptionKey} onChangeText={setSearchValue} onSelectRow={onSubmit} + shouldPreventDefaultFocusOnSelectRow={!DeviceCapabilities.canUseTouchScreen()} /> ); } diff --git a/src/components/TaxPicker.tsx b/src/components/TaxPicker.tsx index 0aed28681d5c..05a8f770edd6 100644 --- a/src/components/TaxPicker.tsx +++ b/src/components/TaxPicker.tsx @@ -4,6 +4,7 @@ import type {OnyxEntry} from 'react-native-onyx'; import type {EdgeInsets} from 'react-native-safe-area-context'; import useLocalize from '@hooks/useLocalize'; import useStyleUtils from '@hooks/useStyleUtils'; +import * as DeviceCapabilities from '@libs/DeviceCapabilities'; import * as OptionsListUtils from '@libs/OptionsListUtils'; import * as TransactionUtils from '@libs/TransactionUtils'; import CONST from '@src/CONST'; @@ -78,6 +79,7 @@ function TaxPicker({selectedTaxRate = '', policy, insets, onSubmit}: TaxPickerPr initiallyFocusedOptionKey={selectedOptionKey ?? undefined} isRowMultilineSupported containerStyle={{paddingBottom: StyleUtils.getSafeAreaMargins(insets).marginBottom}} + shouldPreventDefaultFocusOnSelectRow={!DeviceCapabilities.canUseTouchScreen()} /> ); } diff --git a/src/pages/EditReportFieldDropdown.tsx b/src/pages/EditReportFieldDropdown.tsx index 225051238e2b..bfe7544bb693 100644 --- a/src/pages/EditReportFieldDropdown.tsx +++ b/src/pages/EditReportFieldDropdown.tsx @@ -37,6 +37,7 @@ type EditReportFieldDropdownPageOnyxProps = { type EditReportFieldDropdownPageProps = EditReportFieldDropdownPageComponentProps & EditReportFieldDropdownPageOnyxProps; +//here check function EditReportFieldDropdownPage({onSubmit, fieldKey, fieldValue, fieldOptions, recentlyUsedReportFields}: EditReportFieldDropdownPageProps) { const [searchValue, debouncedSearchValue, setSearchValue] = useDebouncedState(''); const theme = useTheme(); diff --git a/src/pages/WorkspaceSwitcherPage/index.tsx b/src/pages/WorkspaceSwitcherPage/index.tsx index f65ce10ce649..b4380d25d601 100644 --- a/src/pages/WorkspaceSwitcherPage/index.tsx +++ b/src/pages/WorkspaceSwitcherPage/index.tsx @@ -10,6 +10,7 @@ import useActiveWorkspace from '@hooks/useActiveWorkspace'; import useDebouncedState from '@hooks/useDebouncedState'; import useLocalize from '@hooks/useLocalize'; import useNetwork from '@hooks/useNetwork'; +import * as DeviceCapabilities from '@libs/DeviceCapabilities'; import Navigation from '@libs/Navigation/Navigation'; import * as PolicyUtils from '@libs/PolicyUtils'; import * as ReportUtils from '@libs/ReportUtils'; @@ -185,6 +186,7 @@ function WorkspaceSwitcherPage() { listFooterContent={shouldShowCreateWorkspace ? WorkspaceCardCreateAWorkspaceInstance : null} initiallyFocusedOptionKey={activeWorkspaceID ?? CONST.WORKSPACE_SWITCHER.NAME} showLoadingPlaceholder + shouldPreventDefaultFocusOnSelectRow={!DeviceCapabilities.canUseTouchScreen()} /> ); diff --git a/src/pages/iou/request/step/IOURequestStepCurrency.tsx b/src/pages/iou/request/step/IOURequestStepCurrency.tsx index c7c596d27a67..5e4d1c2092d3 100644 --- a/src/pages/iou/request/step/IOURequestStepCurrency.tsx +++ b/src/pages/iou/request/step/IOURequestStepCurrency.tsx @@ -8,6 +8,7 @@ import RadioListItem from '@components/SelectionList/RadioListItem'; import type {ListItem} from '@components/SelectionList/types'; import useLocalize from '@hooks/useLocalize'; import * as CurrencyUtils from '@libs/CurrencyUtils'; +import * as DeviceCapabilities from '@libs/DeviceCapabilities'; import Navigation from '@libs/Navigation/Navigation'; import * as ReportUtils from '@libs/ReportUtils'; import * as IOU from '@userActions/IOU'; @@ -129,6 +130,7 @@ function IOURequestStepCurrency({ headerMessage={headerMessage} initiallyFocusedOptionKey={initiallyFocusedOptionKey} showScrollIndicator + shouldPreventDefaultFocusOnSelectRow={!DeviceCapabilities.canUseTouchScreen()} /> )} diff --git a/src/pages/settings/AboutPage/ShareLogList/BaseShareLogList.tsx b/src/pages/settings/AboutPage/ShareLogList/BaseShareLogList.tsx index 578efbe5317b..73458f48c495 100644 --- a/src/pages/settings/AboutPage/ShareLogList/BaseShareLogList.tsx +++ b/src/pages/settings/AboutPage/ShareLogList/BaseShareLogList.tsx @@ -8,6 +8,7 @@ import UserListItem from '@components/SelectionList/UserListItem'; import useDebouncedState from '@hooks/useDebouncedState'; import useLocalize from '@hooks/useLocalize'; import useNetwork from '@hooks/useNetwork'; +import * as DeviceCapabilities from '@libs/DeviceCapabilities'; import * as FileUtils from '@libs/fileDownload/FileUtils'; import Navigation from '@libs/Navigation/Navigation'; import * as OptionsListUtils from '@libs/OptionsListUtils'; @@ -103,6 +104,7 @@ function BaseShareLogList({onAttachLogToReport}: BaseShareLogListProps) { textInputLabel={translate('optionsSelector.nameEmailOrPhoneNumber')} textInputHint={isOffline ? `${translate('common.youAppearToBeOffline')} ${translate('search.resultsAreLimited')}` : ''} showLoadingPlaceholder={!didScreenTransitionEnd} + shouldPreventDefaultFocusOnSelectRow={!DeviceCapabilities.canUseTouchScreen()} /> )} diff --git a/src/pages/settings/Profile/PersonalDetails/CountrySelectionPage.tsx b/src/pages/settings/Profile/PersonalDetails/CountrySelectionPage.tsx index c0d980083ddf..d50e5046b99e 100644 --- a/src/pages/settings/Profile/PersonalDetails/CountrySelectionPage.tsx +++ b/src/pages/settings/Profile/PersonalDetails/CountrySelectionPage.tsx @@ -5,6 +5,7 @@ import ScreenWrapper from '@components/ScreenWrapper'; import SelectionList from '@components/SelectionList'; import RadioListItem from '@components/SelectionList/RadioListItem'; import useLocalize from '@hooks/useLocalize'; +import * as DeviceCapabilities from '@libs/DeviceCapabilities'; import Navigation from '@libs/Navigation/Navigation'; import type {SettingsNavigatorParamList} from '@libs/Navigation/types'; import type {CountryData} from '@libs/searchCountryOptions'; @@ -83,6 +84,7 @@ function CountrySelectionPage({route, navigation}: CountrySelectionPageProps) { onChangeText={setSearchValue} initiallyFocusedOptionKey={currentCountry} shouldUseDynamicMaxToRenderPerBatch + shouldPreventDefaultFocusOnSelectRow={!DeviceCapabilities.canUseTouchScreen()} /> ); diff --git a/src/pages/settings/Profile/PersonalDetails/StateSelectionPage.tsx b/src/pages/settings/Profile/PersonalDetails/StateSelectionPage.tsx index 32f72b015fa4..a26b15da5027 100644 --- a/src/pages/settings/Profile/PersonalDetails/StateSelectionPage.tsx +++ b/src/pages/settings/Profile/PersonalDetails/StateSelectionPage.tsx @@ -8,6 +8,7 @@ import ScreenWrapper from '@components/ScreenWrapper'; import SelectionList from '@components/SelectionList'; import RadioListItem from '@components/SelectionList/RadioListItem'; import useLocalize from '@hooks/useLocalize'; +import * as DeviceCapabilities from '@libs/DeviceCapabilities'; import Navigation from '@libs/Navigation/Navigation'; import searchCountryOptions from '@libs/searchCountryOptions'; import type {CountryData} from '@libs/searchCountryOptions'; @@ -116,6 +117,7 @@ function StateSelectionPage() { initiallyFocusedOptionKey={currentState} shouldUseDynamicMaxToRenderPerBatch ListItem={RadioListItem} + shouldPreventDefaultFocusOnSelectRow={!DeviceCapabilities.canUseTouchScreen()} /> ); diff --git a/src/pages/settings/Profile/PronounsPage.tsx b/src/pages/settings/Profile/PronounsPage.tsx index 3f4c7ebe6b66..c12bd055815b 100644 --- a/src/pages/settings/Profile/PronounsPage.tsx +++ b/src/pages/settings/Profile/PronounsPage.tsx @@ -12,6 +12,7 @@ import type {WithCurrentUserPersonalDetailsProps} from '@components/withCurrentU import withCurrentUserPersonalDetails from '@components/withCurrentUserPersonalDetails'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; +import * as DeviceCapabilities from '@libs/DeviceCapabilities'; import Navigation from '@libs/Navigation/Navigation'; import * as PersonalDetails from '@userActions/PersonalDetails'; import CONST from '@src/CONST'; @@ -97,6 +98,7 @@ function PronounsPage({currentUserPersonalDetails, isLoadingApp = true}: Pronoun onSelectRow={updatePronouns} onChangeText={setSearchValue} initiallyFocusedOptionKey={currentPronounsKey} + shouldPreventDefaultFocusOnSelectRow={!DeviceCapabilities.canUseTouchScreen()} /> )} diff --git a/src/pages/settings/Profile/TimezoneSelectPage.tsx b/src/pages/settings/Profile/TimezoneSelectPage.tsx index 97cec508f867..2b7f82d1830f 100644 --- a/src/pages/settings/Profile/TimezoneSelectPage.tsx +++ b/src/pages/settings/Profile/TimezoneSelectPage.tsx @@ -8,6 +8,7 @@ import type {WithCurrentUserPersonalDetailsProps} from '@components/withCurrentU import withCurrentUserPersonalDetails from '@components/withCurrentUserPersonalDetails'; import useInitialValue from '@hooks/useInitialValue'; import useLocalize from '@hooks/useLocalize'; +import * as DeviceCapabilities from '@libs/DeviceCapabilities'; import Navigation from '@libs/Navigation/Navigation'; import * as PersonalDetails from '@userActions/PersonalDetails'; import CONST from '@src/CONST'; @@ -77,6 +78,7 @@ function TimezoneSelectPage({currentUserPersonalDetails}: TimezoneSelectPageProp showScrollIndicator shouldShowTooltips={false} ListItem={RadioListItem} + shouldPreventDefaultFocusOnSelectRow={!DeviceCapabilities.canUseTouchScreen()} /> ); diff --git a/src/pages/tasks/TaskAssigneeSelectorModal.tsx b/src/pages/tasks/TaskAssigneeSelectorModal.tsx index 4ebabbce350e..689dba98add6 100644 --- a/src/pages/tasks/TaskAssigneeSelectorModal.tsx +++ b/src/pages/tasks/TaskAssigneeSelectorModal.tsx @@ -21,6 +21,7 @@ import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails' import useDebouncedState from '@hooks/useDebouncedState'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; +import * as DeviceCapabilities from '@libs/DeviceCapabilities'; import Navigation from '@libs/Navigation/Navigation'; import * as OptionsListUtils from '@libs/OptionsListUtils'; import * as ReportUtils from '@libs/ReportUtils'; @@ -220,6 +221,7 @@ function TaskAssigneeSelectorModal({reports, task}: TaskAssigneeSelectorModalPro headerMessage={headerMessage} textInputLabel={translate('optionsSelector.nameEmailOrPhoneNumber')} showLoadingPlaceholder={!areOptionsInitialized} + shouldPreventDefaultFocusOnSelectRow={!DeviceCapabilities.canUseTouchScreen()} /> diff --git a/src/pages/tasks/TaskShareDestinationSelectorModal.tsx b/src/pages/tasks/TaskShareDestinationSelectorModal.tsx index b4b8f9084a57..d888a0593108 100644 --- a/src/pages/tasks/TaskShareDestinationSelectorModal.tsx +++ b/src/pages/tasks/TaskShareDestinationSelectorModal.tsx @@ -12,6 +12,7 @@ import useLocalize from '@hooks/useLocalize'; import useNetwork from '@hooks/useNetwork'; import useThemeStyles from '@hooks/useThemeStyles'; import * as ReportActions from '@libs/actions/Report'; +import * as DeviceCapabilities from '@libs/DeviceCapabilities'; import Navigation from '@libs/Navigation/Navigation'; import * as OptionsListUtils from '@libs/OptionsListUtils'; import * as ReportUtils from '@libs/ReportUtils'; @@ -118,6 +119,7 @@ function TaskShareDestinationSelectorModal({isSearchingForReports}: TaskShareDes showLoadingPlaceholder={areOptionsInitialized && debouncedSearchValue.trim() === '' ? options.sections.length === 0 : !didScreenTransitionEnd} isLoadingNewOptions={isSearchingForReports ?? undefined} textInputHint={textInputHint} + shouldPreventDefaultFocusOnSelectRow={!DeviceCapabilities.canUseTouchScreen()} /> diff --git a/src/pages/workspace/WorkspaceProfileCurrencyPage.tsx b/src/pages/workspace/WorkspaceProfileCurrencyPage.tsx index c8640d3f71b0..ff5e1a95919e 100644 --- a/src/pages/workspace/WorkspaceProfileCurrencyPage.tsx +++ b/src/pages/workspace/WorkspaceProfileCurrencyPage.tsx @@ -7,6 +7,7 @@ import ScreenWrapper from '@components/ScreenWrapper'; import SelectionList from '@components/SelectionList'; import RadioListItem from '@components/SelectionList/RadioListItem'; import useLocalize from '@hooks/useLocalize'; +import * as DeviceCapabilities from '@libs/DeviceCapabilities'; import Navigation from '@libs/Navigation/Navigation'; import * as PolicyUtils from '@libs/PolicyUtils'; import * as Policy from '@userActions/Policy'; @@ -96,6 +97,7 @@ function WorkspaceProfileCurrencyPage({currencyList = {}, policy, isLoadingRepor headerMessage={headerMessage} initiallyFocusedOptionKey={initiallyFocusedOptionKey} showScrollIndicator + shouldPreventDefaultFocusOnSelectRow={!DeviceCapabilities.canUseTouchScreen()} /> diff --git a/src/pages/workspace/workflows/WorkspaceAutoReportingMonthlyOffsetPage.tsx b/src/pages/workspace/workflows/WorkspaceAutoReportingMonthlyOffsetPage.tsx index 0b44d6c565d1..3be5e9e36b96 100644 --- a/src/pages/workspace/workflows/WorkspaceAutoReportingMonthlyOffsetPage.tsx +++ b/src/pages/workspace/workflows/WorkspaceAutoReportingMonthlyOffsetPage.tsx @@ -7,6 +7,7 @@ import ScreenWrapper from '@components/ScreenWrapper'; import SelectionList from '@components/SelectionList'; import RadioListItem from '@components/SelectionList/RadioListItem'; import useLocalize from '@hooks/useLocalize'; +import * as DeviceCapabilities from '@libs/DeviceCapabilities'; import Navigation from '@libs/Navigation/Navigation'; import type {WorkspacesCentralPaneNavigatorParamList} from '@libs/Navigation/types'; import * as PolicyUtils from '@libs/PolicyUtils'; @@ -101,6 +102,7 @@ function WorkspaceAutoReportingMonthlyOffsetPage({policy, route}: WorkspaceAutoR onSelectRow={onSelectDayOfMonth} initiallyFocusedOptionKey={offset.toString()} showScrollIndicator + shouldPreventDefaultFocusOnSelectRow={!DeviceCapabilities.canUseTouchScreen()} /> diff --git a/src/pages/workspace/workflows/WorkspaceWorkflowsApproverPage.tsx b/src/pages/workspace/workflows/WorkspaceWorkflowsApproverPage.tsx index d32218616662..aa71fa2e9702 100644 --- a/src/pages/workspace/workflows/WorkspaceWorkflowsApproverPage.tsx +++ b/src/pages/workspace/workflows/WorkspaceWorkflowsApproverPage.tsx @@ -13,6 +13,7 @@ import useLocalize from '@hooks/useLocalize'; import useNetwork from '@hooks/useNetwork'; import useStyleUtils from '@hooks/useStyleUtils'; import useThemeStyles from '@hooks/useThemeStyles'; +import * as DeviceCapabilities from '@libs/DeviceCapabilities'; import {formatPhoneNumber} from '@libs/LocalePhoneNumber'; import Log from '@libs/Log'; import Navigation from '@libs/Navigation/Navigation'; @@ -193,6 +194,7 @@ function WorkspaceWorkflowsApproverPage({policy, personalDetails, isLoadingRepor ListItem={UserListItem} onSelectRow={setPolicyApprover} showScrollIndicator + shouldPreventDefaultFocusOnSelectRow={!DeviceCapabilities.canUseTouchScreen()} /> diff --git a/src/pages/workspace/workflows/WorkspaceWorkflowsPayerPage.tsx b/src/pages/workspace/workflows/WorkspaceWorkflowsPayerPage.tsx index da51b2c3e8e3..caf5cbacf0ae 100644 --- a/src/pages/workspace/workflows/WorkspaceWorkflowsPayerPage.tsx +++ b/src/pages/workspace/workflows/WorkspaceWorkflowsPayerPage.tsx @@ -13,6 +13,7 @@ import useLocalize from '@hooks/useLocalize'; import useNetwork from '@hooks/useNetwork'; import useStyleUtils from '@hooks/useStyleUtils'; import useThemeStyles from '@hooks/useThemeStyles'; +import * as DeviceCapabilities from '@libs/DeviceCapabilities'; import {formatPhoneNumber} from '@libs/LocalePhoneNumber'; import Log from '@libs/Log'; import Navigation from '@libs/Navigation/Navigation'; @@ -202,6 +203,7 @@ function WorkspaceWorkflowsPayerPage({route, policy, personalDetails, isLoadingR ListItem={UserListItem} onSelectRow={setPolicyAuthorizedPayer} showScrollIndicator + shouldPreventDefaultFocusOnSelectRow={!DeviceCapabilities.canUseTouchScreen()} /> From d3f94eff7485cce341755f209c1146077c20ee1e Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Mon, 22 Apr 2024 11:14:03 +0200 Subject: [PATCH 47/57] Add shouldPreventDefaultFocusOnSelectRow prop to SelectionList in EditReportFieldDropdown --- src/pages/EditReportFieldDropdown.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/pages/EditReportFieldDropdown.tsx b/src/pages/EditReportFieldDropdown.tsx index bfe7544bb693..27498762eea1 100644 --- a/src/pages/EditReportFieldDropdown.tsx +++ b/src/pages/EditReportFieldDropdown.tsx @@ -9,6 +9,7 @@ import type {ListItem} from '@components/SelectionList/types'; import useDebouncedState from '@hooks/useDebouncedState'; import useLocalize from '@hooks/useLocalize'; import useTheme from '@hooks/useTheme'; +import * as DeviceCapabilities from '@libs/DeviceCapabilities'; import * as OptionsListUtils from '@libs/OptionsListUtils'; import ONYXKEYS from '@src/ONYXKEYS'; import type {RecentlyUsedReportFields} from '@src/types/onyx'; @@ -37,7 +38,6 @@ type EditReportFieldDropdownPageOnyxProps = { type EditReportFieldDropdownPageProps = EditReportFieldDropdownPageComponentProps & EditReportFieldDropdownPageOnyxProps; -//here check function EditReportFieldDropdownPage({onSubmit, fieldKey, fieldValue, fieldOptions, recentlyUsedReportFields}: EditReportFieldDropdownPageProps) { const [searchValue, debouncedSearchValue, setSearchValue] = useDebouncedState(''); const theme = useTheme(); @@ -113,6 +113,7 @@ function EditReportFieldDropdownPage({onSubmit, fieldKey, fieldValue, fieldOptio ListItem={RadioListItem} isRowMultilineSupported rightHandSideComponent={itemRightSideComponent} + shouldPreventDefaultFocusOnSelectRow={!DeviceCapabilities.canUseTouchScreen()} /> ); } From e756647ad09e78f93eddc9f353f182af6834f8b3 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Mon, 22 Apr 2024 12:24:04 +0200 Subject: [PATCH 48/57] Add shouldUseSync param to useSyncFocus hook --- src/components/SelectionList/BaseListItem.tsx | 2 +- src/hooks/useSyncFocus/index.ts | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/components/SelectionList/BaseListItem.tsx b/src/components/SelectionList/BaseListItem.tsx index 671823eb255b..b1f0141663ad 100644 --- a/src/components/SelectionList/BaseListItem.tsx +++ b/src/components/SelectionList/BaseListItem.tsx @@ -40,7 +40,7 @@ function BaseListItem({ const pressableRef = useRef(null); // Sync focus on an item - useSyncFocus(pressableRef, Boolean(isFocused && shouldSyncFocus)); + useSyncFocus(pressableRef, Boolean(isFocused), shouldSyncFocus); const rightHandSideComponentRender = () => { if (canSelectMultiple || !rightHandSideComponent) { diff --git a/src/hooks/useSyncFocus/index.ts b/src/hooks/useSyncFocus/index.ts index d2145023e06b..2dd0fef70cf7 100644 --- a/src/hooks/useSyncFocus/index.ts +++ b/src/hooks/useSyncFocus/index.ts @@ -8,15 +8,16 @@ import useScreenWrapperTranstionStatus from '@hooks/useScreenWrapperTransitionSt * When the user navigates through the app using the arrows and then the tab button, the focus on the element and the native focus of the browser differs. * To maintain consistency when an element is focused in the app, the focus() method is additionally called on the focused element to eliminate the difference between native browser focus and application focus. */ -const useSyncFocus = (ref: RefObject, isFocused: boolean) => { +const useSyncFocus = (ref: RefObject, isFocused: boolean, shouldSyncFocus = true) => { const {didScreenTransitionEnd} = useScreenWrapperTranstionStatus(); useLayoutEffect(() => { - if (!isFocused || !didScreenTransitionEnd) { + if (!isFocused || !shouldSyncFocus || !didScreenTransitionEnd) { return; } ref.current?.focus(); + // eslint-disable-next-line react-hooks/exhaustive-deps }, [didScreenTransitionEnd, isFocused, ref]); }; From 58cdf150305ca2d07b73b8d9893508afa5ea1fd1 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Mon, 22 Apr 2024 12:28:53 +0200 Subject: [PATCH 49/57] Revert "Add checking shouldPreventDefaultFocusOnSelectRow to SelectionLists where text input is displayed" This reverts commit a0e6f688be8d577b64b301c20076345e37ffcb7c. --- src/components/CategoryPicker.tsx | 2 -- src/components/TagPicker/index.tsx | 2 -- src/components/TaxPicker.tsx | 2 -- src/pages/WorkspaceSwitcherPage/index.tsx | 2 -- src/pages/iou/request/step/IOURequestStepCurrency.tsx | 2 -- src/pages/settings/AboutPage/ShareLogList/BaseShareLogList.tsx | 2 -- .../settings/Profile/PersonalDetails/CountrySelectionPage.tsx | 2 -- .../settings/Profile/PersonalDetails/StateSelectionPage.tsx | 2 -- src/pages/settings/Profile/PronounsPage.tsx | 2 -- src/pages/settings/Profile/TimezoneSelectPage.tsx | 2 -- src/pages/tasks/TaskAssigneeSelectorModal.tsx | 2 -- src/pages/tasks/TaskShareDestinationSelectorModal.tsx | 2 -- src/pages/workspace/WorkspaceProfileCurrencyPage.tsx | 2 -- .../workflows/WorkspaceAutoReportingMonthlyOffsetPage.tsx | 2 -- .../workspace/workflows/WorkspaceWorkflowsApproverPage.tsx | 2 -- src/pages/workspace/workflows/WorkspaceWorkflowsPayerPage.tsx | 2 -- 16 files changed, 32 deletions(-) diff --git a/src/components/CategoryPicker.tsx b/src/components/CategoryPicker.tsx index 0dbad24e3f5b..f26d7c25c7e2 100644 --- a/src/components/CategoryPicker.tsx +++ b/src/components/CategoryPicker.tsx @@ -3,7 +3,6 @@ import {withOnyx} from 'react-native-onyx'; import type {OnyxEntry} from 'react-native-onyx'; import useDebouncedState from '@hooks/useDebouncedState'; import useLocalize from '@hooks/useLocalize'; -import * as DeviceCapabilities from '@libs/DeviceCapabilities'; import * as OptionsListUtils from '@libs/OptionsListUtils'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; @@ -84,7 +83,6 @@ function CategoryPicker({selectedCategory, policyCategories, policyRecentlyUsedC ListItem={RadioListItem} initiallyFocusedOptionKey={selectedOptionKey ?? undefined} isRowMultilineSupported - shouldPreventDefaultFocusOnSelectRow={!DeviceCapabilities.canUseTouchScreen()} /> ); } diff --git a/src/components/TagPicker/index.tsx b/src/components/TagPicker/index.tsx index 7b7c50300e3e..97cd9aa5c691 100644 --- a/src/components/TagPicker/index.tsx +++ b/src/components/TagPicker/index.tsx @@ -5,7 +5,6 @@ import SelectionList from '@components/SelectionList'; import RadioListItem from '@components/SelectionList/RadioListItem'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; -import * as DeviceCapabilities from '@libs/DeviceCapabilities'; import * as OptionsListUtils from '@libs/OptionsListUtils'; import * as PolicyUtils from '@libs/PolicyUtils'; import type * as ReportUtils from '@libs/ReportUtils'; @@ -105,7 +104,6 @@ function TagPicker({selectedTag, tagListName, policyTags, tagListIndex, policyRe initiallyFocusedOptionKey={selectedOptionKey} onChangeText={setSearchValue} onSelectRow={onSubmit} - shouldPreventDefaultFocusOnSelectRow={!DeviceCapabilities.canUseTouchScreen()} /> ); } diff --git a/src/components/TaxPicker.tsx b/src/components/TaxPicker.tsx index 05a8f770edd6..0aed28681d5c 100644 --- a/src/components/TaxPicker.tsx +++ b/src/components/TaxPicker.tsx @@ -4,7 +4,6 @@ import type {OnyxEntry} from 'react-native-onyx'; import type {EdgeInsets} from 'react-native-safe-area-context'; import useLocalize from '@hooks/useLocalize'; import useStyleUtils from '@hooks/useStyleUtils'; -import * as DeviceCapabilities from '@libs/DeviceCapabilities'; import * as OptionsListUtils from '@libs/OptionsListUtils'; import * as TransactionUtils from '@libs/TransactionUtils'; import CONST from '@src/CONST'; @@ -79,7 +78,6 @@ function TaxPicker({selectedTaxRate = '', policy, insets, onSubmit}: TaxPickerPr initiallyFocusedOptionKey={selectedOptionKey ?? undefined} isRowMultilineSupported containerStyle={{paddingBottom: StyleUtils.getSafeAreaMargins(insets).marginBottom}} - shouldPreventDefaultFocusOnSelectRow={!DeviceCapabilities.canUseTouchScreen()} /> ); } diff --git a/src/pages/WorkspaceSwitcherPage/index.tsx b/src/pages/WorkspaceSwitcherPage/index.tsx index b4380d25d601..f65ce10ce649 100644 --- a/src/pages/WorkspaceSwitcherPage/index.tsx +++ b/src/pages/WorkspaceSwitcherPage/index.tsx @@ -10,7 +10,6 @@ import useActiveWorkspace from '@hooks/useActiveWorkspace'; import useDebouncedState from '@hooks/useDebouncedState'; import useLocalize from '@hooks/useLocalize'; import useNetwork from '@hooks/useNetwork'; -import * as DeviceCapabilities from '@libs/DeviceCapabilities'; import Navigation from '@libs/Navigation/Navigation'; import * as PolicyUtils from '@libs/PolicyUtils'; import * as ReportUtils from '@libs/ReportUtils'; @@ -186,7 +185,6 @@ function WorkspaceSwitcherPage() { listFooterContent={shouldShowCreateWorkspace ? WorkspaceCardCreateAWorkspaceInstance : null} initiallyFocusedOptionKey={activeWorkspaceID ?? CONST.WORKSPACE_SWITCHER.NAME} showLoadingPlaceholder - shouldPreventDefaultFocusOnSelectRow={!DeviceCapabilities.canUseTouchScreen()} /> ); diff --git a/src/pages/iou/request/step/IOURequestStepCurrency.tsx b/src/pages/iou/request/step/IOURequestStepCurrency.tsx index 5e4d1c2092d3..c7c596d27a67 100644 --- a/src/pages/iou/request/step/IOURequestStepCurrency.tsx +++ b/src/pages/iou/request/step/IOURequestStepCurrency.tsx @@ -8,7 +8,6 @@ import RadioListItem from '@components/SelectionList/RadioListItem'; import type {ListItem} from '@components/SelectionList/types'; import useLocalize from '@hooks/useLocalize'; import * as CurrencyUtils from '@libs/CurrencyUtils'; -import * as DeviceCapabilities from '@libs/DeviceCapabilities'; import Navigation from '@libs/Navigation/Navigation'; import * as ReportUtils from '@libs/ReportUtils'; import * as IOU from '@userActions/IOU'; @@ -130,7 +129,6 @@ function IOURequestStepCurrency({ headerMessage={headerMessage} initiallyFocusedOptionKey={initiallyFocusedOptionKey} showScrollIndicator - shouldPreventDefaultFocusOnSelectRow={!DeviceCapabilities.canUseTouchScreen()} /> )} diff --git a/src/pages/settings/AboutPage/ShareLogList/BaseShareLogList.tsx b/src/pages/settings/AboutPage/ShareLogList/BaseShareLogList.tsx index 73458f48c495..578efbe5317b 100644 --- a/src/pages/settings/AboutPage/ShareLogList/BaseShareLogList.tsx +++ b/src/pages/settings/AboutPage/ShareLogList/BaseShareLogList.tsx @@ -8,7 +8,6 @@ import UserListItem from '@components/SelectionList/UserListItem'; import useDebouncedState from '@hooks/useDebouncedState'; import useLocalize from '@hooks/useLocalize'; import useNetwork from '@hooks/useNetwork'; -import * as DeviceCapabilities from '@libs/DeviceCapabilities'; import * as FileUtils from '@libs/fileDownload/FileUtils'; import Navigation from '@libs/Navigation/Navigation'; import * as OptionsListUtils from '@libs/OptionsListUtils'; @@ -104,7 +103,6 @@ function BaseShareLogList({onAttachLogToReport}: BaseShareLogListProps) { textInputLabel={translate('optionsSelector.nameEmailOrPhoneNumber')} textInputHint={isOffline ? `${translate('common.youAppearToBeOffline')} ${translate('search.resultsAreLimited')}` : ''} showLoadingPlaceholder={!didScreenTransitionEnd} - shouldPreventDefaultFocusOnSelectRow={!DeviceCapabilities.canUseTouchScreen()} /> )} diff --git a/src/pages/settings/Profile/PersonalDetails/CountrySelectionPage.tsx b/src/pages/settings/Profile/PersonalDetails/CountrySelectionPage.tsx index d50e5046b99e..c0d980083ddf 100644 --- a/src/pages/settings/Profile/PersonalDetails/CountrySelectionPage.tsx +++ b/src/pages/settings/Profile/PersonalDetails/CountrySelectionPage.tsx @@ -5,7 +5,6 @@ import ScreenWrapper from '@components/ScreenWrapper'; import SelectionList from '@components/SelectionList'; import RadioListItem from '@components/SelectionList/RadioListItem'; import useLocalize from '@hooks/useLocalize'; -import * as DeviceCapabilities from '@libs/DeviceCapabilities'; import Navigation from '@libs/Navigation/Navigation'; import type {SettingsNavigatorParamList} from '@libs/Navigation/types'; import type {CountryData} from '@libs/searchCountryOptions'; @@ -84,7 +83,6 @@ function CountrySelectionPage({route, navigation}: CountrySelectionPageProps) { onChangeText={setSearchValue} initiallyFocusedOptionKey={currentCountry} shouldUseDynamicMaxToRenderPerBatch - shouldPreventDefaultFocusOnSelectRow={!DeviceCapabilities.canUseTouchScreen()} /> ); diff --git a/src/pages/settings/Profile/PersonalDetails/StateSelectionPage.tsx b/src/pages/settings/Profile/PersonalDetails/StateSelectionPage.tsx index a26b15da5027..32f72b015fa4 100644 --- a/src/pages/settings/Profile/PersonalDetails/StateSelectionPage.tsx +++ b/src/pages/settings/Profile/PersonalDetails/StateSelectionPage.tsx @@ -8,7 +8,6 @@ import ScreenWrapper from '@components/ScreenWrapper'; import SelectionList from '@components/SelectionList'; import RadioListItem from '@components/SelectionList/RadioListItem'; import useLocalize from '@hooks/useLocalize'; -import * as DeviceCapabilities from '@libs/DeviceCapabilities'; import Navigation from '@libs/Navigation/Navigation'; import searchCountryOptions from '@libs/searchCountryOptions'; import type {CountryData} from '@libs/searchCountryOptions'; @@ -117,7 +116,6 @@ function StateSelectionPage() { initiallyFocusedOptionKey={currentState} shouldUseDynamicMaxToRenderPerBatch ListItem={RadioListItem} - shouldPreventDefaultFocusOnSelectRow={!DeviceCapabilities.canUseTouchScreen()} /> ); diff --git a/src/pages/settings/Profile/PronounsPage.tsx b/src/pages/settings/Profile/PronounsPage.tsx index c12bd055815b..3f4c7ebe6b66 100644 --- a/src/pages/settings/Profile/PronounsPage.tsx +++ b/src/pages/settings/Profile/PronounsPage.tsx @@ -12,7 +12,6 @@ import type {WithCurrentUserPersonalDetailsProps} from '@components/withCurrentU import withCurrentUserPersonalDetails from '@components/withCurrentUserPersonalDetails'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; -import * as DeviceCapabilities from '@libs/DeviceCapabilities'; import Navigation from '@libs/Navigation/Navigation'; import * as PersonalDetails from '@userActions/PersonalDetails'; import CONST from '@src/CONST'; @@ -98,7 +97,6 @@ function PronounsPage({currentUserPersonalDetails, isLoadingApp = true}: Pronoun onSelectRow={updatePronouns} onChangeText={setSearchValue} initiallyFocusedOptionKey={currentPronounsKey} - shouldPreventDefaultFocusOnSelectRow={!DeviceCapabilities.canUseTouchScreen()} /> )} diff --git a/src/pages/settings/Profile/TimezoneSelectPage.tsx b/src/pages/settings/Profile/TimezoneSelectPage.tsx index 2b7f82d1830f..97cec508f867 100644 --- a/src/pages/settings/Profile/TimezoneSelectPage.tsx +++ b/src/pages/settings/Profile/TimezoneSelectPage.tsx @@ -8,7 +8,6 @@ import type {WithCurrentUserPersonalDetailsProps} from '@components/withCurrentU import withCurrentUserPersonalDetails from '@components/withCurrentUserPersonalDetails'; import useInitialValue from '@hooks/useInitialValue'; import useLocalize from '@hooks/useLocalize'; -import * as DeviceCapabilities from '@libs/DeviceCapabilities'; import Navigation from '@libs/Navigation/Navigation'; import * as PersonalDetails from '@userActions/PersonalDetails'; import CONST from '@src/CONST'; @@ -78,7 +77,6 @@ function TimezoneSelectPage({currentUserPersonalDetails}: TimezoneSelectPageProp showScrollIndicator shouldShowTooltips={false} ListItem={RadioListItem} - shouldPreventDefaultFocusOnSelectRow={!DeviceCapabilities.canUseTouchScreen()} /> ); diff --git a/src/pages/tasks/TaskAssigneeSelectorModal.tsx b/src/pages/tasks/TaskAssigneeSelectorModal.tsx index 689dba98add6..4ebabbce350e 100644 --- a/src/pages/tasks/TaskAssigneeSelectorModal.tsx +++ b/src/pages/tasks/TaskAssigneeSelectorModal.tsx @@ -21,7 +21,6 @@ import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails' import useDebouncedState from '@hooks/useDebouncedState'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; -import * as DeviceCapabilities from '@libs/DeviceCapabilities'; import Navigation from '@libs/Navigation/Navigation'; import * as OptionsListUtils from '@libs/OptionsListUtils'; import * as ReportUtils from '@libs/ReportUtils'; @@ -221,7 +220,6 @@ function TaskAssigneeSelectorModal({reports, task}: TaskAssigneeSelectorModalPro headerMessage={headerMessage} textInputLabel={translate('optionsSelector.nameEmailOrPhoneNumber')} showLoadingPlaceholder={!areOptionsInitialized} - shouldPreventDefaultFocusOnSelectRow={!DeviceCapabilities.canUseTouchScreen()} /> diff --git a/src/pages/tasks/TaskShareDestinationSelectorModal.tsx b/src/pages/tasks/TaskShareDestinationSelectorModal.tsx index d888a0593108..b4b8f9084a57 100644 --- a/src/pages/tasks/TaskShareDestinationSelectorModal.tsx +++ b/src/pages/tasks/TaskShareDestinationSelectorModal.tsx @@ -12,7 +12,6 @@ import useLocalize from '@hooks/useLocalize'; import useNetwork from '@hooks/useNetwork'; import useThemeStyles from '@hooks/useThemeStyles'; import * as ReportActions from '@libs/actions/Report'; -import * as DeviceCapabilities from '@libs/DeviceCapabilities'; import Navigation from '@libs/Navigation/Navigation'; import * as OptionsListUtils from '@libs/OptionsListUtils'; import * as ReportUtils from '@libs/ReportUtils'; @@ -119,7 +118,6 @@ function TaskShareDestinationSelectorModal({isSearchingForReports}: TaskShareDes showLoadingPlaceholder={areOptionsInitialized && debouncedSearchValue.trim() === '' ? options.sections.length === 0 : !didScreenTransitionEnd} isLoadingNewOptions={isSearchingForReports ?? undefined} textInputHint={textInputHint} - shouldPreventDefaultFocusOnSelectRow={!DeviceCapabilities.canUseTouchScreen()} /> diff --git a/src/pages/workspace/WorkspaceProfileCurrencyPage.tsx b/src/pages/workspace/WorkspaceProfileCurrencyPage.tsx index ff5e1a95919e..c8640d3f71b0 100644 --- a/src/pages/workspace/WorkspaceProfileCurrencyPage.tsx +++ b/src/pages/workspace/WorkspaceProfileCurrencyPage.tsx @@ -7,7 +7,6 @@ import ScreenWrapper from '@components/ScreenWrapper'; import SelectionList from '@components/SelectionList'; import RadioListItem from '@components/SelectionList/RadioListItem'; import useLocalize from '@hooks/useLocalize'; -import * as DeviceCapabilities from '@libs/DeviceCapabilities'; import Navigation from '@libs/Navigation/Navigation'; import * as PolicyUtils from '@libs/PolicyUtils'; import * as Policy from '@userActions/Policy'; @@ -97,7 +96,6 @@ function WorkspaceProfileCurrencyPage({currencyList = {}, policy, isLoadingRepor headerMessage={headerMessage} initiallyFocusedOptionKey={initiallyFocusedOptionKey} showScrollIndicator - shouldPreventDefaultFocusOnSelectRow={!DeviceCapabilities.canUseTouchScreen()} /> diff --git a/src/pages/workspace/workflows/WorkspaceAutoReportingMonthlyOffsetPage.tsx b/src/pages/workspace/workflows/WorkspaceAutoReportingMonthlyOffsetPage.tsx index 3be5e9e36b96..0b44d6c565d1 100644 --- a/src/pages/workspace/workflows/WorkspaceAutoReportingMonthlyOffsetPage.tsx +++ b/src/pages/workspace/workflows/WorkspaceAutoReportingMonthlyOffsetPage.tsx @@ -7,7 +7,6 @@ import ScreenWrapper from '@components/ScreenWrapper'; import SelectionList from '@components/SelectionList'; import RadioListItem from '@components/SelectionList/RadioListItem'; import useLocalize from '@hooks/useLocalize'; -import * as DeviceCapabilities from '@libs/DeviceCapabilities'; import Navigation from '@libs/Navigation/Navigation'; import type {WorkspacesCentralPaneNavigatorParamList} from '@libs/Navigation/types'; import * as PolicyUtils from '@libs/PolicyUtils'; @@ -102,7 +101,6 @@ function WorkspaceAutoReportingMonthlyOffsetPage({policy, route}: WorkspaceAutoR onSelectRow={onSelectDayOfMonth} initiallyFocusedOptionKey={offset.toString()} showScrollIndicator - shouldPreventDefaultFocusOnSelectRow={!DeviceCapabilities.canUseTouchScreen()} /> diff --git a/src/pages/workspace/workflows/WorkspaceWorkflowsApproverPage.tsx b/src/pages/workspace/workflows/WorkspaceWorkflowsApproverPage.tsx index aa71fa2e9702..d32218616662 100644 --- a/src/pages/workspace/workflows/WorkspaceWorkflowsApproverPage.tsx +++ b/src/pages/workspace/workflows/WorkspaceWorkflowsApproverPage.tsx @@ -13,7 +13,6 @@ import useLocalize from '@hooks/useLocalize'; import useNetwork from '@hooks/useNetwork'; import useStyleUtils from '@hooks/useStyleUtils'; import useThemeStyles from '@hooks/useThemeStyles'; -import * as DeviceCapabilities from '@libs/DeviceCapabilities'; import {formatPhoneNumber} from '@libs/LocalePhoneNumber'; import Log from '@libs/Log'; import Navigation from '@libs/Navigation/Navigation'; @@ -194,7 +193,6 @@ function WorkspaceWorkflowsApproverPage({policy, personalDetails, isLoadingRepor ListItem={UserListItem} onSelectRow={setPolicyApprover} showScrollIndicator - shouldPreventDefaultFocusOnSelectRow={!DeviceCapabilities.canUseTouchScreen()} /> diff --git a/src/pages/workspace/workflows/WorkspaceWorkflowsPayerPage.tsx b/src/pages/workspace/workflows/WorkspaceWorkflowsPayerPage.tsx index caf5cbacf0ae..da51b2c3e8e3 100644 --- a/src/pages/workspace/workflows/WorkspaceWorkflowsPayerPage.tsx +++ b/src/pages/workspace/workflows/WorkspaceWorkflowsPayerPage.tsx @@ -13,7 +13,6 @@ import useLocalize from '@hooks/useLocalize'; import useNetwork from '@hooks/useNetwork'; import useStyleUtils from '@hooks/useStyleUtils'; import useThemeStyles from '@hooks/useThemeStyles'; -import * as DeviceCapabilities from '@libs/DeviceCapabilities'; import {formatPhoneNumber} from '@libs/LocalePhoneNumber'; import Log from '@libs/Log'; import Navigation from '@libs/Navigation/Navigation'; @@ -203,7 +202,6 @@ function WorkspaceWorkflowsPayerPage({route, policy, personalDetails, isLoadingR ListItem={UserListItem} onSelectRow={setPolicyAuthorizedPayer} showScrollIndicator - shouldPreventDefaultFocusOnSelectRow={!DeviceCapabilities.canUseTouchScreen()} /> From 077ca984478b35b5dd8f0c21b24e82fa35718990 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Mon, 22 Apr 2024 12:35:09 +0200 Subject: [PATCH 50/57] Revert "Add shouldPreventDefaultFocusOnSelectRow prop to SelectionList in EditReportFieldDropdown" This reverts commit d3f94eff7485cce341755f209c1146077c20ee1e. --- src/pages/EditReportFieldDropdown.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/pages/EditReportFieldDropdown.tsx b/src/pages/EditReportFieldDropdown.tsx index 27498762eea1..bfe7544bb693 100644 --- a/src/pages/EditReportFieldDropdown.tsx +++ b/src/pages/EditReportFieldDropdown.tsx @@ -9,7 +9,6 @@ import type {ListItem} from '@components/SelectionList/types'; import useDebouncedState from '@hooks/useDebouncedState'; import useLocalize from '@hooks/useLocalize'; import useTheme from '@hooks/useTheme'; -import * as DeviceCapabilities from '@libs/DeviceCapabilities'; import * as OptionsListUtils from '@libs/OptionsListUtils'; import ONYXKEYS from '@src/ONYXKEYS'; import type {RecentlyUsedReportFields} from '@src/types/onyx'; @@ -38,6 +37,7 @@ type EditReportFieldDropdownPageOnyxProps = { type EditReportFieldDropdownPageProps = EditReportFieldDropdownPageComponentProps & EditReportFieldDropdownPageOnyxProps; +//here check function EditReportFieldDropdownPage({onSubmit, fieldKey, fieldValue, fieldOptions, recentlyUsedReportFields}: EditReportFieldDropdownPageProps) { const [searchValue, debouncedSearchValue, setSearchValue] = useDebouncedState(''); const theme = useTheme(); @@ -113,7 +113,6 @@ function EditReportFieldDropdownPage({onSubmit, fieldKey, fieldValue, fieldOptio ListItem={RadioListItem} isRowMultilineSupported rightHandSideComponent={itemRightSideComponent} - shouldPreventDefaultFocusOnSelectRow={!DeviceCapabilities.canUseTouchScreen()} /> ); } From 741b1e307ce1e0edc08184b948dc9ecf6d71233c Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Mon, 22 Apr 2024 12:44:43 +0200 Subject: [PATCH 51/57] Fix lint --- src/pages/EditReportFieldDropdown.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/pages/EditReportFieldDropdown.tsx b/src/pages/EditReportFieldDropdown.tsx index bfe7544bb693..225051238e2b 100644 --- a/src/pages/EditReportFieldDropdown.tsx +++ b/src/pages/EditReportFieldDropdown.tsx @@ -37,7 +37,6 @@ type EditReportFieldDropdownPageOnyxProps = { type EditReportFieldDropdownPageProps = EditReportFieldDropdownPageComponentProps & EditReportFieldDropdownPageOnyxProps; -//here check function EditReportFieldDropdownPage({onSubmit, fieldKey, fieldValue, fieldOptions, recentlyUsedReportFields}: EditReportFieldDropdownPageProps) { const [searchValue, debouncedSearchValue, setSearchValue] = useDebouncedState(''); const theme = useTheme(); From bde100174589e75ec3c84a305fc9745587a5fb56 Mon Sep 17 00:00:00 2001 From: Shubham Agrawal <58412969+shubham1206agra@users.noreply.github.com> Date: Mon, 22 Apr 2024 17:33:27 +0530 Subject: [PATCH 52/57] Apply suggestions from code review --- src/libs/ReportUtils.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 8911313ed1d5..2f561918172c 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -5142,6 +5142,10 @@ function getMoneyRequestOptions(report: OnyxEntry, policy: OnyxEntry, From 3a7e416f58b0930f7c7a17a59808c6d73c16b433 Mon Sep 17 00:00:00 2001 From: Shubham Agrawal <58412969+shubham1206agra@users.noreply.github.com> Date: Mon, 22 Apr 2024 17:36:31 +0530 Subject: [PATCH 53/57] Apply suggestions from code review Co-authored-by: G T <75031127+getusha@users.noreply.github.com> --- src/libs/Navigation/Navigation.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libs/Navigation/Navigation.ts b/src/libs/Navigation/Navigation.ts index ce92c169812b..5209d8a594c1 100644 --- a/src/libs/Navigation/Navigation.ts +++ b/src/libs/Navigation/Navigation.ts @@ -94,7 +94,6 @@ function getActiveRouteIndex(stateOrRoute: StateOrRoute, index?: number): number function parseHybridAppUrl(url: HybridAppRoute | Route): Route { switch (url) { case HYBRID_APP_ROUTES.MONEY_REQUEST_CREATE: - return ROUTES.MONEY_REQUEST_CREATE.getRoute(CONST.IOU.ACTION.CREATE, CONST.IOU.TYPE.SUBMIT, CONST.IOU.OPTIMISTIC_TRANSACTION_ID, ReportUtils.generateReportID()); case HYBRID_APP_ROUTES.MONEY_REQUEST_SUBMIT_CREATE: return ROUTES.MONEY_REQUEST_CREATE.getRoute(CONST.IOU.ACTION.CREATE, CONST.IOU.TYPE.SUBMIT, CONST.IOU.OPTIMISTIC_TRANSACTION_ID, ReportUtils.generateReportID()); default: From 3fe5d82715990a31ae759da3aa07a8cf2987c69d Mon Sep 17 00:00:00 2001 From: Shubham Agrawal <58412969+shubham1206agra@users.noreply.github.com> Date: Mon, 22 Apr 2024 18:09:32 +0530 Subject: [PATCH 54/57] Update src/libs/IOUUtils.ts Co-authored-by: Vit Horacek <36083550+mountiny@users.noreply.github.com> --- src/libs/IOUUtils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/IOUUtils.ts b/src/libs/IOUUtils.ts index cfc8e7064453..4a4ce6407fa2 100644 --- a/src/libs/IOUUtils.ts +++ b/src/libs/IOUUtils.ts @@ -114,7 +114,7 @@ function isValidMoneyRequestType(iouType: string): boolean { } /** - * Checks if the iou type is one of submit, pat, track, or split. + * Checks if the iou type is one of submit, pay, track, or split. */ // eslint-disable-next-line @typescript-eslint/naming-convention function temporary_isValidMoneyRequestType(iouType: string): boolean { From 2216f78ec67308927738b69dd10822bedeb7ca92 Mon Sep 17 00:00:00 2001 From: OSBotify Date: Mon, 22 Apr 2024 12:39:45 +0000 Subject: [PATCH 55/57] Update version to 1.4.63-20 --- android/app/build.gradle | 4 ++-- ios/NewExpensify/Info.plist | 2 +- ios/NewExpensifyTests/Info.plist | 2 +- ios/NotificationServiceExtension/Info.plist | 2 +- package-lock.json | 4 ++-- package.json | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/android/app/build.gradle b/android/app/build.gradle index 057eba1ff8e1..f9a7e579a3ad 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -98,8 +98,8 @@ android { minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion multiDexEnabled rootProject.ext.multiDexEnabled - versionCode 1001046319 - versionName "1.4.63-19" + versionCode 1001046320 + versionName "1.4.63-20" // Supported language variants must be declared here to avoid from being removed during the compilation. // This also helps us to not include unnecessary language variants in the APK. resConfigs "en", "es" diff --git a/ios/NewExpensify/Info.plist b/ios/NewExpensify/Info.plist index 2dab5b55cd38..79bbc0d835f9 100644 --- a/ios/NewExpensify/Info.plist +++ b/ios/NewExpensify/Info.plist @@ -40,7 +40,7 @@ CFBundleVersion - 1.4.63.19 + 1.4.63.20 ITSAppUsesNonExemptEncryption LSApplicationQueriesSchemes diff --git a/ios/NewExpensifyTests/Info.plist b/ios/NewExpensifyTests/Info.plist index 85738221b366..c460bd07307c 100644 --- a/ios/NewExpensifyTests/Info.plist +++ b/ios/NewExpensifyTests/Info.plist @@ -19,6 +19,6 @@ CFBundleSignature ???? CFBundleVersion - 1.4.63.19 + 1.4.63.20 diff --git a/ios/NotificationServiceExtension/Info.plist b/ios/NotificationServiceExtension/Info.plist index 3111ae0c12f0..135f23a0a348 100644 --- a/ios/NotificationServiceExtension/Info.plist +++ b/ios/NotificationServiceExtension/Info.plist @@ -13,7 +13,7 @@ CFBundleShortVersionString 1.4.63 CFBundleVersion - 1.4.63.19 + 1.4.63.20 NSExtension NSExtensionPointIdentifier diff --git a/package-lock.json b/package-lock.json index 8caa0401d28f..836df2a23b38 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "new.expensify", - "version": "1.4.63-19", + "version": "1.4.63-20", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "new.expensify", - "version": "1.4.63-19", + "version": "1.4.63-20", "hasInstallScript": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index 1461f0bfb77f..968aeb14bde5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "new.expensify", - "version": "1.4.63-19", + "version": "1.4.63-20", "author": "Expensify, Inc.", "homepage": "https://new.expensify.com", "description": "New Expensify is the next generation of Expensify: a reimagination of payments based atop a foundation of chat.", From ce31084888b041c9f261477f84757dffbabb5e12 Mon Sep 17 00:00:00 2001 From: Vit Horacek <36083550+mountiny@users.noreply.github.com> Date: Mon, 22 Apr 2024 14:49:30 +0200 Subject: [PATCH 56/57] Revert "Fixed getting two magic codes upon signing in once" --- src/pages/signin/ChooseSSOOrMagicCode.tsx | 101 +++++++++++++------- src/pages/signin/SignInPage.tsx | 7 +- src/pages/signin/SignInPageLayout/index.tsx | 4 +- 3 files changed, 70 insertions(+), 42 deletions(-) diff --git a/src/pages/signin/ChooseSSOOrMagicCode.tsx b/src/pages/signin/ChooseSSOOrMagicCode.tsx index 3895b303020b..4143c2b733e0 100644 --- a/src/pages/signin/ChooseSSOOrMagicCode.tsx +++ b/src/pages/signin/ChooseSSOOrMagicCode.tsx @@ -1,67 +1,100 @@ -import React from 'react'; -import {View} from 'react-native'; +import React, {useEffect} from 'react'; +import {Keyboard, View} from 'react-native'; import {withOnyx} from 'react-native-onyx'; import type {OnyxEntry} from 'react-native-onyx'; import Button from '@components/Button'; +import FormHelpMessage from '@components/FormHelpMessage'; import Text from '@components/Text'; +import useKeyboardState from '@hooks/useKeyboardState'; import useLocalize from '@hooks/useLocalize'; import useNetwork from '@hooks/useNetwork'; import useThemeStyles from '@hooks/useThemeStyles'; import useWindowDimensions from '@hooks/useWindowDimensions'; +import * as ErrorUtils from '@libs/ErrorUtils'; import Navigation from '@libs/Navigation/Navigation'; +import * as Session from '@userActions/Session'; +import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; -import type {Account} from '@src/types/onyx'; -import ValidateCodeForm from './ValidateCodeForm'; +import type {Account, Credentials} from '@src/types/onyx'; +import {isEmptyObject} from '@src/types/utils/EmptyObject'; +import ChangeExpensifyLoginLink from './ChangeExpensifyLoginLink'; +import Terms from './Terms'; type ChooseSSOOrMagicCodeOnyxProps = { + /** The credentials of the logged in person */ + credentials: OnyxEntry; + /** The details about the account that the user is signing in with */ account: OnyxEntry; }; type ChooseSSOOrMagicCodeProps = ChooseSSOOrMagicCodeOnyxProps & { - /** Determines if user is switched to using recovery code instead of 2fa code */ - isUsingRecoveryCode: boolean; - - /** Function to change `isUsingRecoveryCode` state when user toggles between 2fa code and recovery code */ - setIsUsingRecoveryCode: (value: boolean) => void; + /** Function that returns whether the user is using SAML or magic codes to log in */ + setIsUsingMagicCode: (value: boolean) => void; }; -function ChooseSSOOrMagicCode({account, isUsingRecoveryCode, setIsUsingRecoveryCode}: ChooseSSOOrMagicCodeProps) { +function ChooseSSOOrMagicCode({credentials, account, setIsUsingMagicCode}: ChooseSSOOrMagicCodeProps) { const styles = useThemeStyles(); + const {isKeyboardShown} = useKeyboardState(); const {translate} = useLocalize(); const {isOffline} = useNetwork(); const {isSmallScreenWidth} = useWindowDimensions(); - const loginTextAfterMagicCode = isUsingRecoveryCode ? translate('validateCodeForm.enterRecoveryCode') : translate('validateCodeForm.enterAuthenticatorCode'); - const loginText = account?.requiresTwoFactorAuth ? loginTextAfterMagicCode : translate('samlSignIn.orContinueWithMagicCode'); + + // This view doesn't have a field for user input, so dismiss the device keyboard if shown + useEffect(() => { + if (!isKeyboardShown) { + return; + } + Keyboard.dismiss(); + }, [isKeyboardShown]); return ( - - {translate('samlSignIn.welcomeSAMLEnabled')} -