From d99d92d4a1ba20976af09a51cc504fdd9a21169a Mon Sep 17 00:00:00 2001 From: Fitsum Abebe Date: Sat, 20 Jan 2024 01:58:07 +0300 Subject: [PATCH 001/113] implemented receipt image component --- src/components/DistanceEReceipt.js | 13 +-- ...oraryForRefactorRequestConfirmationList.js | 8 +- src/components/ReceiptImage.tsx | 82 +++++++++++++++++++ .../ReportActionItemImage.tsx | 44 ++-------- 4 files changed, 97 insertions(+), 50 deletions(-) create mode 100644 src/components/ReceiptImage.tsx diff --git a/src/components/DistanceEReceipt.js b/src/components/DistanceEReceipt.js index 0241eea44063..f900da2affcf 100644 --- a/src/components/DistanceEReceipt.js +++ b/src/components/DistanceEReceipt.js @@ -16,8 +16,8 @@ import Icon from './Icon'; import * as Expensicons from './Icon/Expensicons'; import ImageSVG from './ImageSVG'; import PendingMapView from './MapView/PendingMapView'; +import ReceiptImage from './ReceiptImage'; import Text from './Text'; -import ThumbnailImage from './ThumbnailImage'; import transactionPropTypes from './transactionPropTypes'; const propTypes = { @@ -64,16 +64,7 @@ function DistanceEReceipt({transaction}) { /> - {isOffline || !thumbnailSource ? ( - - ) : ( - - )} + {isOffline || !thumbnailSource ? : } {formattedTransactionAmount} diff --git a/src/components/MoneyTemporaryForRefactorRequestConfirmationList.js b/src/components/MoneyTemporaryForRefactorRequestConfirmationList.js index 36d424ea28f2..67cf9db3674c 100755 --- a/src/components/MoneyTemporaryForRefactorRequestConfirmationList.js +++ b/src/components/MoneyTemporaryForRefactorRequestConfirmationList.js @@ -36,6 +36,7 @@ import Image from './Image'; import MenuItemWithTopDescription from './MenuItemWithTopDescription'; import optionPropTypes from './optionPropTypes'; import OptionsSelector from './OptionsSelector'; +import ReceiptImage from './ReceiptImage'; import SettlementButton from './SettlementButton'; import Switch from './Switch'; import tagPropTypes from './tagPropTypes'; @@ -639,9 +640,12 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ )} {(receiptImage || receiptThumbnail) && ( - ; + isAuthTokenRequired?: boolean; + confirmationPage?: boolean; +}; + +function ReceiptImage({transaction, receiptPath, receiptFileName, style, isAuthTokenRequired, confirmationPage}: ReceiptImageProps) { + const styles = useThemeStyles(); + // URI to image, i.e. blob:new.expensify.com/9ef3a018-4067-47c6-b29f-5f1bd35f213d or expensify.com/receipts/w_e616108497ef940b7210ec6beb5a462d01a878f4.jpg + const path = transaction?.receipt?.source ?? receiptPath ?? ''; + // filename of uploaded image or last part of remote URI + const filename = transaction?.filename ?? receiptFileName ?? ''; + const isReceiptImage = Str.isImage(filename); + const shouldDisplayThumbnail = Object.hasOwn(transaction?.pendingFields ?? {}, 'waypoints') || !isReceiptImage; + const image = !shouldDisplayThumbnail && !(path.startsWith('blob:') || path.startsWith('file:')) ? `${path}.1024.jpg` : path; + const isLocalFile = typeof path === 'number' || path.startsWith('blob:') || path.startsWith('file:') || path.startsWith('/'); + + const imageSource = tryResolveUrlFromApiRoot(image ?? ''); + + const isEReceipt = transaction && TransactionUtils.hasEReceipt(transaction); + + if (!transaction) { + return ( + + ); + } + + if (!!isEReceipt || shouldDisplayThumbnail) { + if (!(!isLocalFile && !Str.isPDF(imageSource))) { + return ( + + + + ); + } + + return ( + + ); + } + + return isReceiptImage && !confirmationPage ? ( + + ) : ( + + ); +} + +export default ReceiptImage; diff --git a/src/components/ReportActionItem/ReportActionItemImage.tsx b/src/components/ReportActionItem/ReportActionItemImage.tsx index aa5d0513f0d7..3822f3ab42aa 100644 --- a/src/components/ReportActionItem/ReportActionItemImage.tsx +++ b/src/components/ReportActionItem/ReportActionItemImage.tsx @@ -1,16 +1,10 @@ -import Str from 'expensify-common/lib/str'; import React from 'react'; -import type {ReactElement} from 'react'; -import {View} from 'react-native'; import AttachmentModal from '@components/AttachmentModal'; -import EReceiptThumbnail from '@components/EReceiptThumbnail'; -import Image from '@components/Image'; import PressableWithoutFocus from '@components/Pressable/PressableWithoutFocus'; +import ReceiptImage from '@components/ReceiptImage'; import {ShowContextMenuContext} from '@components/ShowContextMenuContext'; -import ThumbnailImage from '@components/ThumbnailImage'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; -import * as TransactionUtils from '@libs/TransactionUtils'; import tryResolveUrlFromApiRoot from '@libs/tryResolveUrlFromApiRoot'; import CONST from '@src/CONST'; import type {Transaction} from '@src/types/onyx'; @@ -45,34 +39,6 @@ function ReportActionItemImage({thumbnail, image, enablePreviewModal = false, tr const styles = useThemeStyles(); const {translate} = useLocalize(); const imageSource = tryResolveUrlFromApiRoot(image ?? ''); - const thumbnailSource = tryResolveUrlFromApiRoot(thumbnail ?? ''); - const isEReceipt = transaction && TransactionUtils.hasEReceipt(transaction); - - let receiptImageComponent: ReactElement; - - if (isEReceipt) { - receiptImageComponent = ( - - - - ); - } else if (thumbnail && !isLocalFile && !Str.isPDF(imageSource as string)) { - receiptImageComponent = ( - - ); - } else { - receiptImageComponent = ( - - ); - } if (enablePreviewModal) { return ( @@ -98,7 +64,11 @@ function ReportActionItemImage({thumbnail, image, enablePreviewModal = false, tr accessibilityRole={CONST.ACCESSIBILITY_ROLE.IMAGEBUTTON} accessibilityLabel={translate('accessibilityHints.viewAttachment')} > - {receiptImageComponent} + ) } @@ -108,7 +78,7 @@ function ReportActionItemImage({thumbnail, image, enablePreviewModal = false, tr ); } - return receiptImageComponent; + return ; } ReportActionItemImage.displayName = 'ReportActionItemImage'; From a1f5f69a11350073692f4bd4585d62f2ef6c0112 Mon Sep 17 00:00:00 2001 From: Fitsum Abebe Date: Sat, 20 Jan 2024 02:02:31 +0300 Subject: [PATCH 002/113] pass receipt name for non modal display --- src/components/ReportActionItem/ReportActionItemImage.tsx | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/components/ReportActionItem/ReportActionItemImage.tsx b/src/components/ReportActionItem/ReportActionItemImage.tsx index 3822f3ab42aa..1570aba49f7c 100644 --- a/src/components/ReportActionItem/ReportActionItemImage.tsx +++ b/src/components/ReportActionItem/ReportActionItemImage.tsx @@ -78,7 +78,13 @@ function ReportActionItemImage({thumbnail, image, enablePreviewModal = false, tr ); } - return ; + return ( + + ); } ReportActionItemImage.displayName = 'ReportActionItemImage'; From 7dfd88567c07d4279fa0ed4d1d8745b3c3a1961e Mon Sep 17 00:00:00 2001 From: Fitsum Abebe Date: Sat, 20 Jan 2024 02:18:53 +0300 Subject: [PATCH 003/113] minor fix --- src/components/ReceiptImage.tsx | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/components/ReceiptImage.tsx b/src/components/ReceiptImage.tsx index 984ba0bf2e9a..8de6d23127a8 100644 --- a/src/components/ReceiptImage.tsx +++ b/src/components/ReceiptImage.tsx @@ -36,10 +36,11 @@ function ReceiptImage({transaction, receiptPath, receiptFileName, style, isAuthT if (!transaction) { return ( - ); } From e9c766607677fe453531776d31f4652ba2c4b959 Mon Sep 17 00:00:00 2001 From: Fitsum Abebe Date: Sat, 20 Jan 2024 22:00:19 +0300 Subject: [PATCH 004/113] changed implementation --- src/components/DistanceEReceipt.js | 12 +++- ...oraryForRefactorRequestConfirmationList.js | 13 ++-- src/components/ReceiptImage.tsx | 66 +++++-------------- .../ReportActionItem/MoneyRequestView.js | 1 + .../ReportActionItemImage.tsx | 39 ++++++----- .../ReportActionItemImages.tsx | 8 ++- src/libs/ReceiptUtils.ts | 38 ++--------- 7 files changed, 71 insertions(+), 106 deletions(-) diff --git a/src/components/DistanceEReceipt.js b/src/components/DistanceEReceipt.js index f900da2affcf..8593cdcb5b93 100644 --- a/src/components/DistanceEReceipt.js +++ b/src/components/DistanceEReceipt.js @@ -34,7 +34,7 @@ function DistanceEReceipt({transaction}) { const styles = useThemeStyles(); const {translate} = useLocalize(); const {isOffline} = useNetwork(); - const {thumbnail} = TransactionUtils.hasReceipt(transaction) ? ReceiptUtils.getThumbnailAndImageURIs(transaction) : {}; + const {thumbnail, isThumbnail} = TransactionUtils.hasReceipt(transaction) ? ReceiptUtils.getThumbnailAndImageURIs(transaction) : {}; const {amount: transactionAmount, currency: transactionCurrency, merchant: transactionMerchant, created: transactionDate} = ReportUtils.getTransactionDetails(transaction); const formattedTransactionAmount = transactionAmount ? CurrencyUtils.convertToDisplayString(transactionAmount, transactionCurrency) : translate('common.tbd'); const thumbnailSource = tryResolveUrlFromApiRoot(thumbnail || ''); @@ -64,7 +64,15 @@ function DistanceEReceipt({transaction}) { /> - {isOffline || !thumbnailSource ? : } + {isOffline || !thumbnailSource ? ( + + ) : ( + + )} {formattedTransactionAmount} diff --git a/src/components/MoneyTemporaryForRefactorRequestConfirmationList.js b/src/components/MoneyTemporaryForRefactorRequestConfirmationList.js index 67cf9db3674c..c6bc49fd381e 100755 --- a/src/components/MoneyTemporaryForRefactorRequestConfirmationList.js +++ b/src/components/MoneyTemporaryForRefactorRequestConfirmationList.js @@ -32,7 +32,6 @@ import categoryPropTypes from './categoryPropTypes'; import ConfirmedRoute from './ConfirmedRoute'; import FormHelpMessage from './FormHelpMessage'; import * as Expensicons from './Icon/Expensicons'; -import Image from './Image'; import MenuItemWithTopDescription from './MenuItemWithTopDescription'; import optionPropTypes from './optionPropTypes'; import OptionsSelector from './OptionsSelector'; @@ -614,7 +613,11 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ ); }, [isReadOnly, iouType, selectedParticipants.length, confirm, bankAccountRoute, iouCurrencyCode, policyID, splitOrRequestOptions, formError, styles.ph1, styles.mb2, translate]); - const {image: receiptImage, thumbnail: receiptThumbnail} = receiptPath && receiptFilename ? ReceiptUtils.getThumbnailAndImageURIs(transaction, receiptPath, receiptFilename) : {}; + const { + image: receiptImage, + thumbnail: receiptThumbnail, + isThumbnail, + } = receiptPath && receiptFilename ? ReceiptUtils.getThumbnailAndImageURIs(transaction, receiptPath, receiptFilename) : {}; return ( ; + transactionID?: string; + isThumbnail?: boolean; + shouldUseThumnailImage?: boolean; + isEReceipt?: boolean; + source?: string; isAuthTokenRequired?: boolean; - confirmationPage?: boolean; + style?: StyleProp; }; -function ReceiptImage({transaction, receiptPath, receiptFileName, style, isAuthTokenRequired, confirmationPage}: ReceiptImageProps) { +function ReceiptImage({transactionID, isThumbnail = false, shouldUseThumnailImage = false, isEReceipt = false, source, isAuthTokenRequired, style}: ReceiptImageProps) { const styles = useThemeStyles(); - // URI to image, i.e. blob:new.expensify.com/9ef3a018-4067-47c6-b29f-5f1bd35f213d or expensify.com/receipts/w_e616108497ef940b7210ec6beb5a462d01a878f4.jpg - const path = transaction?.receipt?.source ?? receiptPath ?? ''; - // filename of uploaded image or last part of remote URI - const filename = transaction?.filename ?? receiptFileName ?? ''; - const isReceiptImage = Str.isImage(filename); - const shouldDisplayThumbnail = Object.hasOwn(transaction?.pendingFields ?? {}, 'waypoints') || !isReceiptImage; - const image = !shouldDisplayThumbnail && !(path.startsWith('blob:') || path.startsWith('file:')) ? `${path}.1024.jpg` : path; - const isLocalFile = typeof path === 'number' || path.startsWith('blob:') || path.startsWith('file:') || path.startsWith('/'); - const imageSource = tryResolveUrlFromApiRoot(image ?? ''); - - const isEReceipt = transaction && TransactionUtils.hasEReceipt(transaction); - - if (!transaction) { + if (isEReceipt || isThumbnail) { return ( - + + + ); } - if (!!isEReceipt || shouldDisplayThumbnail) { - if (!(!isLocalFile && !Str.isPDF(imageSource))) { - return ( - - - - ); - } - + if (shouldUseThumnailImage) { return ( - ) : ( + return ( ); } +export type {ReceiptImageProps}; export default ReceiptImage; diff --git a/src/components/ReportActionItem/MoneyRequestView.js b/src/components/ReportActionItem/MoneyRequestView.js index 86affbcac114..4fa2f76e20b8 100644 --- a/src/components/ReportActionItem/MoneyRequestView.js +++ b/src/components/ReportActionItem/MoneyRequestView.js @@ -237,6 +237,7 @@ function MoneyRequestView({report, parentReport, parentReportActions, policyCate - + ) } @@ -78,13 +93,7 @@ function ReportActionItemImage({thumbnail, image, enablePreviewModal = false, tr ); } - return ( - - ); + return ; } ReportActionItemImage.displayName = 'ReportActionItemImage'; diff --git a/src/components/ReportActionItem/ReportActionItemImages.tsx b/src/components/ReportActionItem/ReportActionItemImages.tsx index c24defb8ac08..8c2fc9638dea 100644 --- a/src/components/ReportActionItem/ReportActionItemImages.tsx +++ b/src/components/ReportActionItem/ReportActionItemImages.tsx @@ -11,8 +11,9 @@ import type {Transaction} from '@src/types/onyx'; import ReportActionItemImage from './ReportActionItemImage'; type Image = { - thumbnail: string | number; - image: string | number; + thumbnail?: string; + isThumbnail?: boolean; + image: string; transaction: Transaction; isLocalFile: boolean; }; @@ -71,7 +72,7 @@ function ReportActionItemImages({images, size, total, isHovered = false}: Report return ( - {shownImages.map(({thumbnail, image, transaction, isLocalFile}, index) => { + {shownImages.map(({thumbnail, isThumbnail, image, transaction, isLocalFile}, index) => { const isLastImage = index === numberOfShownImages - 1; // Show a border to separate multiple images. Shown to the right for each except the last. @@ -87,6 +88,7 @@ function ReportActionItemImages({images, size, total, isHovered = false}: Report image={image} isLocalFile={isLocalFile} transaction={transaction} + isThumbnail={isThumbnail} /> {isLastImage && remaining > 0 && ( diff --git a/src/libs/ReceiptUtils.ts b/src/libs/ReceiptUtils.ts index bcba68a3a0bd..a01f7779c13a 100644 --- a/src/libs/ReceiptUtils.ts +++ b/src/libs/ReceiptUtils.ts @@ -1,24 +1,13 @@ import Str from 'expensify-common/lib/str'; -import type {ImageSourcePropType} from 'react-native'; -import ReceiptDoc from '@assets/images/receipt-doc.png'; -import ReceiptGeneric from '@assets/images/receipt-generic.png'; -import ReceiptHTML from '@assets/images/receipt-html.png'; -import ReceiptSVG from '@assets/images/receipt-svg.png'; -import CONST from '@src/CONST'; import ROUTES from '@src/ROUTES'; import type {Transaction} from '@src/types/onyx'; -import * as FileUtils from './fileDownload/FileUtils'; type ThumbnailAndImageURI = { - image: ImageSourcePropType | string; - thumbnail: ImageSourcePropType | string | null; + image: string; + thumbnail?: string; transaction?: Transaction; isLocalFile?: boolean; -}; - -type FileNameAndExtension = { - fileExtension?: string; - fileName?: string; + isThumbnail?: boolean; }; /** @@ -39,12 +28,12 @@ function getThumbnailAndImageURIs(transaction: Transaction, receiptPath: string if (!Object.hasOwn(transaction?.pendingFields ?? {}, 'waypoints')) { if (hasEReceipt) { - return {thumbnail: null, image: ROUTES.ERECEIPT.getRoute(transaction.transactionID), transaction}; + return {image: ROUTES.ERECEIPT.getRoute(transaction.transactionID), transaction}; } // For local files, we won't have a thumbnail yet if (isReceiptImage && (path.startsWith('blob:') || path.startsWith('file:'))) { - return {thumbnail: null, image: path, isLocalFile: true}; + return {image: path, isLocalFile: true}; } if (isReceiptImage) { @@ -52,22 +41,9 @@ function getThumbnailAndImageURIs(transaction: Transaction, receiptPath: string } } - const {fileExtension} = FileUtils.splitExtensionFromFileName(filename) as FileNameAndExtension; - let image = ReceiptGeneric; - if (fileExtension === CONST.IOU.FILE_TYPES.HTML) { - image = ReceiptHTML; - } - - if (fileExtension === CONST.IOU.FILE_TYPES.DOC || fileExtension === CONST.IOU.FILE_TYPES.DOCX) { - image = ReceiptDoc; - } - - if (fileExtension === CONST.IOU.FILE_TYPES.SVG) { - image = ReceiptSVG; - } - const isLocalFile = typeof path === 'number' || path.startsWith('blob:') || path.startsWith('file:') || path.startsWith('/'); - return {thumbnail: image, image: path, isLocalFile}; + + return {isThumbnail: true, image: path, isLocalFile}; } // eslint-disable-next-line import/prefer-default-export From e88e1ce8082cfc9845a6dbe267e45ee6c73f1c2c Mon Sep 17 00:00:00 2001 From: Fitsum Abebe Date: Sat, 20 Jan 2024 22:08:44 +0300 Subject: [PATCH 005/113] fix styling --- src/components/ReceiptImage.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/ReceiptImage.tsx b/src/components/ReceiptImage.tsx index df34aec496e0..7c5fde88f600 100644 --- a/src/components/ReceiptImage.tsx +++ b/src/components/ReceiptImage.tsx @@ -21,7 +21,7 @@ function ReceiptImage({transactionID, isThumbnail = false, shouldUseThumnailImag if (isEReceipt || isThumbnail) { return ( - + ); From 26fa66ba9be8a4f87a8ce1b673653811f3c87f9c Mon Sep 17 00:00:00 2001 From: Fitsum Abebe Date: Sat, 20 Jan 2024 22:35:37 +0300 Subject: [PATCH 006/113] fix borderRadius --- src/components/EReceiptThumbnail.tsx | 4 +++- src/components/ReceiptImage.tsx | 5 ++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/components/EReceiptThumbnail.tsx b/src/components/EReceiptThumbnail.tsx index 5976200975cd..b677a60cc02c 100644 --- a/src/components/EReceiptThumbnail.tsx +++ b/src/components/EReceiptThumbnail.tsx @@ -18,6 +18,7 @@ import Image from './Image'; type EReceiptThumbnailOnyxProps = { transaction: OnyxEntry; + borderRadius?: number; }; type EReceiptThumbnailProps = EReceiptThumbnailOnyxProps & { @@ -35,7 +36,7 @@ const backgroundImages = { [CONST.ERECEIPT_COLORS.PINK]: eReceiptBGs.EReceiptBG_Pink, }; -function EReceiptThumbnail({transaction}: EReceiptThumbnailProps) { +function EReceiptThumbnail({transaction, borderRadius}: EReceiptThumbnailProps) { const styles = useThemeStyles(); const StyleUtils = useStyleUtils(); @@ -83,6 +84,7 @@ function EReceiptThumbnail({transaction}: EReceiptThumbnailProps) { styles.overflowHidden, styles.alignItemsCenter, containerHeight && containerHeight < variables.eReceiptThumnailCenterReceiptBreakpoint ? styles.justifyContentCenter : {}, + borderRadius && {borderRadius}, ]} onLayout={onContainerLayout} > diff --git a/src/components/ReceiptImage.tsx b/src/components/ReceiptImage.tsx index 7c5fde88f600..7317869cf5d3 100644 --- a/src/components/ReceiptImage.tsx +++ b/src/components/ReceiptImage.tsx @@ -22,7 +22,10 @@ function ReceiptImage({transactionID, isThumbnail = false, shouldUseThumnailImag if (isEReceipt || isThumbnail) { return ( - + ); } From d4abf53440ba81bca0752b5b6836a787829d50b6 Mon Sep 17 00:00:00 2001 From: Fitsum Abebe Date: Sat, 20 Jan 2024 23:01:52 +0300 Subject: [PATCH 007/113] type fix --- src/components/EReceiptThumbnail.tsx | 4 ++-- src/components/ReceiptImage.tsx | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/components/EReceiptThumbnail.tsx b/src/components/EReceiptThumbnail.tsx index b677a60cc02c..a15f0a2d17bc 100644 --- a/src/components/EReceiptThumbnail.tsx +++ b/src/components/EReceiptThumbnail.tsx @@ -18,13 +18,13 @@ import Image from './Image'; type EReceiptThumbnailOnyxProps = { transaction: OnyxEntry; - borderRadius?: number; }; type EReceiptThumbnailProps = EReceiptThumbnailOnyxProps & { /** TransactionID of the transaction this EReceipt corresponds to. It's used by withOnyx HOC */ // eslint-disable-next-line react/no-unused-prop-types transactionID: string; + borderRadius?: number; }; const backgroundImages = { @@ -84,7 +84,7 @@ function EReceiptThumbnail({transaction, borderRadius}: EReceiptThumbnailProps) styles.overflowHidden, styles.alignItemsCenter, containerHeight && containerHeight < variables.eReceiptThumnailCenterReceiptBreakpoint ? styles.justifyContentCenter : {}, - borderRadius && {borderRadius}, + borderRadius ? {borderRadius} : {}, ]} onLayout={onContainerLayout} > diff --git a/src/components/ReceiptImage.tsx b/src/components/ReceiptImage.tsx index 7317869cf5d3..2c78337c725a 100644 --- a/src/components/ReceiptImage.tsx +++ b/src/components/ReceiptImage.tsx @@ -1,11 +1,12 @@ import React from 'react'; -import type {ImageStyle, StyleProp} from 'react-native'; import {View} from 'react-native'; import useThemeStyles from '@hooks/useThemeStyles'; import EReceiptThumbnail from './EReceiptThumbnail'; import Image from './Image'; import ThumbnailImage from './ThumbnailImage'; +type Style = {height: number; borderRadius: number; margin: number}; + type ReceiptImageProps = { transactionID?: string; isThumbnail?: boolean; @@ -13,7 +14,7 @@ type ReceiptImageProps = { isEReceipt?: boolean; source?: string; isAuthTokenRequired?: boolean; - style?: StyleProp; + style?: Style; }; function ReceiptImage({transactionID, isThumbnail = false, shouldUseThumnailImage = false, isEReceipt = false, source, isAuthTokenRequired, style}: ReceiptImageProps) { From 63b41f664bb31b0bfe309521f18982f65abf2024 Mon Sep 17 00:00:00 2001 From: Fitsum Abebe Date: Sat, 20 Jan 2024 23:28:32 +0300 Subject: [PATCH 008/113] minor fix --- src/components/DistanceEReceipt.js | 1 - src/components/ReportActionItem/ReportActionItemImage.tsx | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/components/DistanceEReceipt.js b/src/components/DistanceEReceipt.js index 8593cdcb5b93..ead2e2487848 100644 --- a/src/components/DistanceEReceipt.js +++ b/src/components/DistanceEReceipt.js @@ -69,7 +69,6 @@ function DistanceEReceipt({transaction}) { ) : ( )} diff --git a/src/components/ReportActionItem/ReportActionItemImage.tsx b/src/components/ReportActionItem/ReportActionItemImage.tsx index b9a98777eb53..d7d2514352c7 100644 --- a/src/components/ReportActionItem/ReportActionItemImage.tsx +++ b/src/components/ReportActionItem/ReportActionItemImage.tsx @@ -56,7 +56,7 @@ function ReportActionItemImage({thumbnail, isThumbnail, image, enablePreviewModa } else if ((thumbnail ?? isThumbnail) && !isLocalFile && !Str.isPDF(imageSource)) { propsObj = thumbnailSource ? {shouldUseThumnailImage: true, source: thumbnailSource} : {isThumbnail: true, transactionID: transaction?.transactionID}; } else { - propsObj = {isThumbnail, source: thumbnail ?? image}; + propsObj = {isThumbnail, transactionID: transaction?.transactionID, source: thumbnail ?? image}; } if (enablePreviewModal) { From 404fd8c39c0b19cff84e3c634e715c397e0d2240 Mon Sep 17 00:00:00 2001 From: Fitsum Abebe Date: Sat, 20 Jan 2024 23:54:15 +0300 Subject: [PATCH 009/113] passed transaction prop --- src/components/DistanceEReceipt.js | 2 +- src/components/ReportActionItem/MoneyRequestPreview.js | 2 +- src/components/ReportActionItem/ReportPreview.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/DistanceEReceipt.js b/src/components/DistanceEReceipt.js index ead2e2487848..e322ccd28f4d 100644 --- a/src/components/DistanceEReceipt.js +++ b/src/components/DistanceEReceipt.js @@ -34,7 +34,7 @@ function DistanceEReceipt({transaction}) { const styles = useThemeStyles(); const {translate} = useLocalize(); const {isOffline} = useNetwork(); - const {thumbnail, isThumbnail} = TransactionUtils.hasReceipt(transaction) ? ReceiptUtils.getThumbnailAndImageURIs(transaction) : {}; + const {thumbnail} = TransactionUtils.hasReceipt(transaction) ? ReceiptUtils.getThumbnailAndImageURIs(transaction) : {}; const {amount: transactionAmount, currency: transactionCurrency, merchant: transactionMerchant, created: transactionDate} = ReportUtils.getTransactionDetails(transaction); const formattedTransactionAmount = transactionAmount ? CurrencyUtils.convertToDisplayString(transactionAmount, transactionCurrency) : translate('common.tbd'); const thumbnailSource = tryResolveUrlFromApiRoot(thumbnail || ''); diff --git a/src/components/ReportActionItem/MoneyRequestPreview.js b/src/components/ReportActionItem/MoneyRequestPreview.js index 9cb27e6fac4a..e0351e4e642f 100644 --- a/src/components/ReportActionItem/MoneyRequestPreview.js +++ b/src/components/ReportActionItem/MoneyRequestPreview.js @@ -178,7 +178,7 @@ function MoneyRequestPreview(props) { merchantOrDescription = requestMerchant.replace(CONST.REGEX.FIRST_SPACE, translate('common.tbd')); } - const receiptImages = hasReceipt ? [ReceiptUtils.getThumbnailAndImageURIs(props.transaction)] : []; + const receiptImages = hasReceipt ? [{...ReceiptUtils.getThumbnailAndImageURIs(props.transaction), transaction: props.transaction}] : []; const getSettledMessage = () => { if (isExpensifyCardTransaction) { diff --git a/src/components/ReportActionItem/ReportPreview.js b/src/components/ReportActionItem/ReportPreview.js index 204c9b5e31d4..f448a227a1a6 100644 --- a/src/components/ReportActionItem/ReportPreview.js +++ b/src/components/ReportActionItem/ReportPreview.js @@ -173,7 +173,7 @@ function ReportPreview(props) { const isScanning = hasReceipts && areAllRequestsBeingSmartScanned; const hasErrors = (hasReceipts && hasMissingSmartscanFields) || (canUseViolations && ReportUtils.hasViolations(props.iouReportID, props.transactionViolations)); const lastThreeTransactionsWithReceipts = transactionsWithReceipts.slice(-3); - const lastThreeReceipts = _.map(lastThreeTransactionsWithReceipts, (transaction) => ReceiptUtils.getThumbnailAndImageURIs(transaction)); + const lastThreeReceipts = _.map(lastThreeTransactionsWithReceipts, (transaction) => ({...ReceiptUtils.getThumbnailAndImageURIs(transaction), transaction})); let formattedMerchant = numberOfRequests === 1 && hasReceipts ? TransactionUtils.getMerchant(transactionsWithReceipts[0]) : null; if (TransactionUtils.isPartialMerchant(formattedMerchant)) { formattedMerchant = null; From 9d38d933207f225f9667a15cc424003c59cc8099 Mon Sep 17 00:00:00 2001 From: Fitsum Abebe Date: Wed, 24 Jan 2024 00:13:34 +0300 Subject: [PATCH 010/113] updated attachement modal to consider thumnail display --- src/components/AttachmentModal.js | 6 +++++- src/components/ReportActionItem/ReportActionItemImage.tsx | 1 + src/libs/ReceiptUtils.ts | 2 +- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/components/AttachmentModal.js b/src/components/AttachmentModal.js index 346ff19987ef..2fd8f3b30170 100755 --- a/src/components/AttachmentModal.js +++ b/src/components/AttachmentModal.js @@ -49,6 +49,9 @@ const propTypes = { /** Optional source (URL, SVG function) for the image shown. If not passed in via props must be specified when modal is opened. */ source: PropTypes.oneOfType([PropTypes.string, sourcePropTypes]), + /** Whether thumnail should be display */ + isThumbnail: PropTypes.bool, + /** Optional callback to fire when we want to preview an image and approve it for use. */ onConfirm: PropTypes.func, @@ -101,6 +104,7 @@ const propTypes = { const defaultProps = { source: '', + isThumbnail: false, onConfirm: null, defaultOpen: false, originalFileName: '', @@ -471,7 +475,7 @@ function AttachmentModal(props) { setDownloadButtonVisibility={setDownloadButtonVisibility} /> ) : ( - Boolean(sourceForAttachmentView) && + (Boolean(sourceForAttachmentView) || props.isThumbnail) && shouldLoadAttachment && ( Date: Wed, 24 Jan 2024 00:15:27 +0300 Subject: [PATCH 011/113] minor fix --- .../MoneyTemporaryForRefactorRequestConfirmationList.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/MoneyTemporaryForRefactorRequestConfirmationList.js b/src/components/MoneyTemporaryForRefactorRequestConfirmationList.js index b82f3eaf2f0f..1ece4679d065 100755 --- a/src/components/MoneyTemporaryForRefactorRequestConfirmationList.js +++ b/src/components/MoneyTemporaryForRefactorRequestConfirmationList.js @@ -643,7 +643,7 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ )} - {receiptImage || receiptThumbnail ? ( + {receiptImage || receiptThumbnail || isThumbnail ? ( Date: Wed, 24 Jan 2024 00:17:23 +0300 Subject: [PATCH 012/113] minor revert --- src/libs/ReceiptUtils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/ReceiptUtils.ts b/src/libs/ReceiptUtils.ts index 18d56075844c..70925b0d42c3 100644 --- a/src/libs/ReceiptUtils.ts +++ b/src/libs/ReceiptUtils.ts @@ -44,7 +44,7 @@ function getThumbnailAndImageURIs(transaction: Transaction, receiptPath: string const isLocalFile = typeof path === 'number' || path.startsWith('blob:') || path.startsWith('file:') || path.startsWith('/'); - return {isThumbnail: true, isLocalFile}; + return {isThumbnail: true, image: path, isLocalFile}; } // eslint-disable-next-line import/prefer-default-export From dc760ca13e718edbcbb3b768b247c608c1d8f7c9 Mon Sep 17 00:00:00 2001 From: Fitsum Abebe Date: Wed, 24 Jan 2024 00:18:48 +0300 Subject: [PATCH 013/113] small fix --- .../MoneyTemporaryForRefactorRequestConfirmationList.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/MoneyTemporaryForRefactorRequestConfirmationList.js b/src/components/MoneyTemporaryForRefactorRequestConfirmationList.js index 1ece4679d065..b82f3eaf2f0f 100755 --- a/src/components/MoneyTemporaryForRefactorRequestConfirmationList.js +++ b/src/components/MoneyTemporaryForRefactorRequestConfirmationList.js @@ -643,7 +643,7 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ )} - {receiptImage || receiptThumbnail || isThumbnail ? ( + {receiptImage || receiptThumbnail ? ( Date: Wed, 24 Jan 2024 17:53:31 +0300 Subject: [PATCH 014/113] fix on thumbnail display logic --- src/components/AttachmentModal.js | 6 +----- src/components/MoneyRequestConfirmationList.js | 15 ++++++++++----- .../ReportActionItem/ReportActionItemImage.tsx | 1 - src/libs/ReceiptUtils.ts | 6 +++--- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/components/AttachmentModal.js b/src/components/AttachmentModal.js index 2fd8f3b30170..346ff19987ef 100755 --- a/src/components/AttachmentModal.js +++ b/src/components/AttachmentModal.js @@ -49,9 +49,6 @@ const propTypes = { /** Optional source (URL, SVG function) for the image shown. If not passed in via props must be specified when modal is opened. */ source: PropTypes.oneOfType([PropTypes.string, sourcePropTypes]), - /** Whether thumnail should be display */ - isThumbnail: PropTypes.bool, - /** Optional callback to fire when we want to preview an image and approve it for use. */ onConfirm: PropTypes.func, @@ -104,7 +101,6 @@ const propTypes = { const defaultProps = { source: '', - isThumbnail: false, onConfirm: null, defaultOpen: false, originalFileName: '', @@ -475,7 +471,7 @@ function AttachmentModal(props) { setDownloadButtonVisibility={setDownloadButtonVisibility} /> ) : ( - (Boolean(sourceForAttachmentView) || props.isThumbnail) && + Boolean(sourceForAttachmentView) && shouldLoadAttachment && ( )} {receiptImage || receiptThumbnail ? ( - Date: Wed, 24 Jan 2024 18:47:34 +0300 Subject: [PATCH 015/113] minor type fix --- src/libs/ReceiptUtils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/ReceiptUtils.ts b/src/libs/ReceiptUtils.ts index c7728889c865..509c88d5305d 100644 --- a/src/libs/ReceiptUtils.ts +++ b/src/libs/ReceiptUtils.ts @@ -3,7 +3,7 @@ import ROUTES from '@src/ROUTES'; import type {Transaction} from '@src/types/onyx'; type ThumbnailAndImageURI = { - image?: string; + image: string; thumbnail?: string; transaction?: Transaction; isLocalFile?: boolean; From 0cfb3cba8a164fceafd8e9b534b3320a49760bdf Mon Sep 17 00:00:00 2001 From: Fitsum Abebe Date: Thu, 25 Jan 2024 20:56:52 +0300 Subject: [PATCH 016/113] Added file type label support for eThumbnail --- src/components/EReceiptThumbnail.tsx | 8 ++++++-- src/components/MoneyRequestConfirmationList.js | 2 ++ ...poraryForRefactorRequestConfirmationList.js | 2 ++ src/components/ReceiptImage.tsx | 5 ++++- .../ReportActionItem/MoneyRequestView.js | 1 + .../ReportActionItem/ReportActionItemImage.tsx | 18 +++++++++++++++--- .../ReportActionItemImages.tsx | 15 ++++----------- src/libs/ReceiptUtils.ts | 8 ++++++-- 8 files changed, 40 insertions(+), 19 deletions(-) diff --git a/src/components/EReceiptThumbnail.tsx b/src/components/EReceiptThumbnail.tsx index a15f0a2d17bc..75f82b0f0e26 100644 --- a/src/components/EReceiptThumbnail.tsx +++ b/src/components/EReceiptThumbnail.tsx @@ -15,6 +15,7 @@ import * as eReceiptBGs from './Icon/EReceiptBGs'; import * as Expensicons from './Icon/Expensicons'; import * as MCCIcons from './Icon/MCCIcons'; import Image from './Image'; +import Text from './Text'; type EReceiptThumbnailOnyxProps = { transaction: OnyxEntry; @@ -25,6 +26,8 @@ type EReceiptThumbnailProps = EReceiptThumbnailOnyxProps & { // eslint-disable-next-line react/no-unused-prop-types transactionID: string; borderRadius?: number; + fileExtension?: string; + isThumbnail?: boolean; }; const backgroundImages = { @@ -36,7 +39,7 @@ const backgroundImages = { [CONST.ERECEIPT_COLORS.PINK]: eReceiptBGs.EReceiptBG_Pink, }; -function EReceiptThumbnail({transaction, borderRadius}: EReceiptThumbnailProps) { +function EReceiptThumbnail({transaction, borderRadius, fileExtension, isThumbnail = false}: EReceiptThumbnailProps) { const styles = useThemeStyles(); const StyleUtils = useStyleUtils(); @@ -102,7 +105,8 @@ function EReceiptThumbnail({transaction, borderRadius}: EReceiptThumbnailProps) fill={secondaryColor} additionalStyles={[styles.fullScreen]} /> - {MCCIcon ? ( + {isThumbnail && fileExtension && {fileExtension.toUpperCase()}} + {MCCIcon && !isThumbnail ? ( ) : ( // 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 b82f3eaf2f0f..aea3d20f0b00 100755 --- a/src/components/MoneyTemporaryForRefactorRequestConfirmationList.js +++ b/src/components/MoneyTemporaryForRefactorRequestConfirmationList.js @@ -618,6 +618,7 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ image: receiptImage, thumbnail: receiptThumbnail, isThumbnail, + fileExtension, } = receiptPath && receiptFilename ? ReceiptUtils.getThumbnailAndImageURIs(transaction, receiptPath, receiptFilename) : {}; return ( ) : ( // The empty receipt component should only show for IOU Requests of a paid policy ("Team" or "Corporate") diff --git a/src/components/ReceiptImage.tsx b/src/components/ReceiptImage.tsx index 2c78337c725a..bf4b0ef832fc 100644 --- a/src/components/ReceiptImage.tsx +++ b/src/components/ReceiptImage.tsx @@ -15,9 +15,10 @@ type ReceiptImageProps = { source?: string; isAuthTokenRequired?: boolean; style?: Style; + fileExtension?: string; }; -function ReceiptImage({transactionID, isThumbnail = false, shouldUseThumnailImage = false, isEReceipt = false, source, isAuthTokenRequired, style}: ReceiptImageProps) { +function ReceiptImage({transactionID, isThumbnail = false, shouldUseThumnailImage = false, isEReceipt = false, source, isAuthTokenRequired, style, fileExtension}: ReceiptImageProps) { const styles = useThemeStyles(); if (isEReceipt || isThumbnail) { @@ -26,6 +27,8 @@ function ReceiptImage({transactionID, isThumbnail = false, shouldUseThumnailImag ); diff --git a/src/components/ReportActionItem/MoneyRequestView.js b/src/components/ReportActionItem/MoneyRequestView.js index e2ebc701523d..73c478ca0164 100644 --- a/src/components/ReportActionItem/MoneyRequestView.js +++ b/src/components/ReportActionItem/MoneyRequestView.js @@ -237,6 +237,7 @@ function MoneyRequestView({report, parentReport, parentReportActions, policyCate - {shownImages.map(({thumbnail, isThumbnail, image, transaction, isLocalFile}, index) => { + {shownImages.map(({thumbnail, isThumbnail, image, transaction, isLocalFile, fileExtension}, index) => { const isLastImage = index === numberOfShownImages - 1; // Show a border to separate multiple images. Shown to the right for each except the last. @@ -85,6 +77,7 @@ function ReportActionItemImages({images, size, total, isHovered = false}: Report > type === fileExtension), image: path, isLocalFile}; } // eslint-disable-next-line import/prefer-default-export export {getThumbnailAndImageURIs}; +export type {ThumbnailAndImageURI}; From c059ed1b78e9af5fa69bae467aaf682a17989625 Mon Sep 17 00:00:00 2001 From: Fitsum Abebe Date: Thu, 25 Jan 2024 21:15:53 +0300 Subject: [PATCH 017/113] pass transactionID for confirmation --- src/components/MoneyRequestConfirmationList.js | 1 + .../MoneyTemporaryForRefactorRequestConfirmationList.js | 1 + 2 files changed, 2 insertions(+) diff --git a/src/components/MoneyRequestConfirmationList.js b/src/components/MoneyRequestConfirmationList.js index 5f43e6a83204..ed39b6256dc4 100755 --- a/src/components/MoneyRequestConfirmationList.js +++ b/src/components/MoneyRequestConfirmationList.js @@ -620,6 +620,7 @@ function MoneyRequestConfirmationList(props) { // So if we have a thumbnail, it means we're retrieving the image from the server isAuthTokenRequired={!_.isEmpty(receiptThumbnail)} fileExtension={fileExtension} + transactionID={props.transactionID || (props.transaction && props.transaction.transactionID)} /> ) : ( // 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 aea3d20f0b00..a47ddfc3843b 100755 --- a/src/components/MoneyTemporaryForRefactorRequestConfirmationList.js +++ b/src/components/MoneyTemporaryForRefactorRequestConfirmationList.js @@ -653,6 +653,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)} + transactionID={transaction && transaction.transactionID} fileExtension={fileExtension} /> ) : ( From 7008a5d10307b64093b65440a675d2e3f0325393 Mon Sep 17 00:00:00 2001 From: Fitsum Abebe Date: Mon, 29 Jan 2024 16:36:34 +0300 Subject: [PATCH 018/113] minor fix --- src/components/DistanceEReceipt.js | 2 +- src/components/ReceiptImage.tsx | 6 +++--- src/components/ReportActionItem/ReportActionItemImage.tsx | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/components/DistanceEReceipt.js b/src/components/DistanceEReceipt.js index e322ccd28f4d..a42b4cbe42db 100644 --- a/src/components/DistanceEReceipt.js +++ b/src/components/DistanceEReceipt.js @@ -69,7 +69,7 @@ function DistanceEReceipt({transaction}) { ) : ( )} diff --git a/src/components/ReceiptImage.tsx b/src/components/ReceiptImage.tsx index bf4b0ef832fc..d04830bebb36 100644 --- a/src/components/ReceiptImage.tsx +++ b/src/components/ReceiptImage.tsx @@ -10,7 +10,7 @@ type Style = {height: number; borderRadius: number; margin: number}; type ReceiptImageProps = { transactionID?: string; isThumbnail?: boolean; - shouldUseThumnailImage?: boolean; + shouldUseThumbnailImage?: boolean; isEReceipt?: boolean; source?: string; isAuthTokenRequired?: boolean; @@ -18,7 +18,7 @@ type ReceiptImageProps = { fileExtension?: string; }; -function ReceiptImage({transactionID, isThumbnail = false, shouldUseThumnailImage = false, isEReceipt = false, source, isAuthTokenRequired, style, fileExtension}: ReceiptImageProps) { +function ReceiptImage({transactionID, isThumbnail = false, shouldUseThumbnailImage = false, isEReceipt = false, source, isAuthTokenRequired, style, fileExtension}: ReceiptImageProps) { const styles = useThemeStyles(); if (isEReceipt || isThumbnail) { @@ -34,7 +34,7 @@ function ReceiptImage({transactionID, isThumbnail = false, shouldUseThumnailImag ); } - if (shouldUseThumnailImage) { + if (shouldUseThumbnailImage) { return ( Date: Mon, 29 Jan 2024 17:11:24 +0300 Subject: [PATCH 019/113] fix unnecessary condition --- src/components/ReportActionItem/ReportActionItemImage.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/ReportActionItem/ReportActionItemImage.tsx b/src/components/ReportActionItem/ReportActionItemImage.tsx index a63b491c18a5..435ff20a6f55 100644 --- a/src/components/ReportActionItem/ReportActionItemImage.tsx +++ b/src/components/ReportActionItem/ReportActionItemImage.tsx @@ -65,8 +65,8 @@ function ReportActionItemImage({ if (isEReceipt) { propsObj = {isEReceipt: true, transactionID: transaction.transactionID}; - } else if ((thumbnail ?? isThumbnail) && !isLocalFile && !Str.isPDF(imageSource)) { - propsObj = thumbnailSource ? {shouldUseThumbnailImage: true, source: thumbnailSource} : {isThumbnail: true, fileExtension, transactionID: transaction?.transactionID}; + } else if (thumbnail && !isLocalFile && !Str.isPDF(imageSource)) { + propsObj = {shouldUseThumbnailImage: true, source: thumbnailSource}; } else { propsObj = {isThumbnail, fileExtension, transactionID: transaction?.transactionID, source: thumbnail ?? image}; } From 3f019a51c6d2b6b4c19155e0084a7e814b82fb0d Mon Sep 17 00:00:00 2001 From: Fitsum Abebe Date: Mon, 29 Jan 2024 18:16:46 +0300 Subject: [PATCH 020/113] update to static icon layout --- src/components/EReceiptThumbnail.tsx | 11 ++++++----- src/components/ReceiptImage.tsx | 1 + 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/components/EReceiptThumbnail.tsx b/src/components/EReceiptThumbnail.tsx index 75f82b0f0e26..efef40b6f7bb 100644 --- a/src/components/EReceiptThumbnail.tsx +++ b/src/components/EReceiptThumbnail.tsx @@ -28,6 +28,7 @@ type EReceiptThumbnailProps = EReceiptThumbnailOnyxProps & { borderRadius?: number; fileExtension?: string; isThumbnail?: boolean; + useStaticIconLayout?: boolean; }; const backgroundImages = { @@ -39,7 +40,7 @@ const backgroundImages = { [CONST.ERECEIPT_COLORS.PINK]: eReceiptBGs.EReceiptBG_Pink, }; -function EReceiptThumbnail({transaction, borderRadius, fileExtension, isThumbnail = false}: EReceiptThumbnailProps) { +function EReceiptThumbnail({transaction, borderRadius, fileExtension, isThumbnail = false, useStaticIconLayout = false}: EReceiptThumbnailProps) { const styles = useThemeStyles(); const StyleUtils = useStyleUtils(); @@ -69,11 +70,11 @@ function EReceiptThumbnail({transaction, borderRadius, fileExtension, isThumbnai let receiptIconHeight: number = variables.eReceiptIconHeight; let receiptMCCSize: number = variables.eReceiptMCCHeightWidth; - if (isSmall) { + if (isSmall && !useStaticIconLayout) { receiptIconWidth = variables.eReceiptIconWidthSmall; receiptIconHeight = variables.eReceiptIconHeightSmall; receiptMCCSize = variables.eReceiptMCCHeightWidthSmall; - } else if (isMedium) { + } else if (isMedium || useStaticIconLayout) { receiptIconWidth = variables.eReceiptIconWidthMedium; receiptIconHeight = variables.eReceiptIconHeightMedium; receiptMCCSize = variables.eReceiptMCCHeightWidthMedium; @@ -86,10 +87,10 @@ function EReceiptThumbnail({transaction, borderRadius, fileExtension, isThumbnai primaryColor ? StyleUtils.getBackgroundColorStyle(primaryColor) : {}, styles.overflowHidden, styles.alignItemsCenter, - containerHeight && containerHeight < variables.eReceiptThumnailCenterReceiptBreakpoint ? styles.justifyContentCenter : {}, + useStaticIconLayout || (containerHeight && containerHeight < variables.eReceiptThumnailCenterReceiptBreakpoint) ? styles.justifyContentCenter : {}, borderRadius ? {borderRadius} : {}, ]} - onLayout={onContainerLayout} + onLayout={useStaticIconLayout ? undefined : onContainerLayout} > ); From 6d7481c27b0ceed08d726298c7c30ef684f9e130 Mon Sep 17 00:00:00 2001 From: Fitsum Abebe Date: Wed, 31 Jan 2024 21:32:48 +0300 Subject: [PATCH 021/113] changed to isStaticIconLayout --- src/components/EReceiptThumbnail.tsx | 12 ++++++------ src/components/ReceiptImage.tsx | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/components/EReceiptThumbnail.tsx b/src/components/EReceiptThumbnail.tsx index efef40b6f7bb..23429fe35d16 100644 --- a/src/components/EReceiptThumbnail.tsx +++ b/src/components/EReceiptThumbnail.tsx @@ -28,7 +28,7 @@ type EReceiptThumbnailProps = EReceiptThumbnailOnyxProps & { borderRadius?: number; fileExtension?: string; isThumbnail?: boolean; - useStaticIconLayout?: boolean; + isStaticIconLayout?: boolean; }; const backgroundImages = { @@ -40,7 +40,7 @@ const backgroundImages = { [CONST.ERECEIPT_COLORS.PINK]: eReceiptBGs.EReceiptBG_Pink, }; -function EReceiptThumbnail({transaction, borderRadius, fileExtension, isThumbnail = false, useStaticIconLayout = false}: EReceiptThumbnailProps) { +function EReceiptThumbnail({transaction, borderRadius, fileExtension, isThumbnail = false, isStaticIconLayout = false}: EReceiptThumbnailProps) { const styles = useThemeStyles(); const StyleUtils = useStyleUtils(); @@ -70,11 +70,11 @@ function EReceiptThumbnail({transaction, borderRadius, fileExtension, isThumbnai let receiptIconHeight: number = variables.eReceiptIconHeight; let receiptMCCSize: number = variables.eReceiptMCCHeightWidth; - if (isSmall && !useStaticIconLayout) { + if (isSmall && !isStaticIconLayout) { receiptIconWidth = variables.eReceiptIconWidthSmall; receiptIconHeight = variables.eReceiptIconHeightSmall; receiptMCCSize = variables.eReceiptMCCHeightWidthSmall; - } else if (isMedium || useStaticIconLayout) { + } else if (isMedium || isStaticIconLayout) { receiptIconWidth = variables.eReceiptIconWidthMedium; receiptIconHeight = variables.eReceiptIconHeightMedium; receiptMCCSize = variables.eReceiptMCCHeightWidthMedium; @@ -87,10 +87,10 @@ function EReceiptThumbnail({transaction, borderRadius, fileExtension, isThumbnai primaryColor ? StyleUtils.getBackgroundColorStyle(primaryColor) : {}, styles.overflowHidden, styles.alignItemsCenter, - useStaticIconLayout || (containerHeight && containerHeight < variables.eReceiptThumnailCenterReceiptBreakpoint) ? styles.justifyContentCenter : {}, + isStaticIconLayout || (containerHeight && containerHeight < variables.eReceiptThumnailCenterReceiptBreakpoint) ? styles.justifyContentCenter : {}, borderRadius ? {borderRadius} : {}, ]} - onLayout={useStaticIconLayout ? undefined : onContainerLayout} + onLayout={isStaticIconLayout ? undefined : onContainerLayout} > ); From e61a6c7dffbd70f02df2faa72ad7f6c7a267c3de Mon Sep 17 00:00:00 2001 From: Fitsum Abebe Date: Wed, 31 Jan 2024 21:34:26 +0300 Subject: [PATCH 022/113] typescript fix --- src/components/ReportActionItem/ReportActionItemImages.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/ReportActionItem/ReportActionItemImages.tsx b/src/components/ReportActionItem/ReportActionItemImages.tsx index 69bb6c592f54..e1abcb54adbb 100644 --- a/src/components/ReportActionItem/ReportActionItemImages.tsx +++ b/src/components/ReportActionItem/ReportActionItemImages.tsx @@ -72,7 +72,7 @@ function ReportActionItemImages({images, size, total, isHovered = false}: Report const borderStyle = shouldShowBorder ? styles.reportActionItemImageBorder : {}; return ( Date: Wed, 31 Jan 2024 22:05:51 +0300 Subject: [PATCH 023/113] set label text black --- src/components/EReceiptThumbnail.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/EReceiptThumbnail.tsx b/src/components/EReceiptThumbnail.tsx index 23429fe35d16..708b1707716f 100644 --- a/src/components/EReceiptThumbnail.tsx +++ b/src/components/EReceiptThumbnail.tsx @@ -6,6 +6,7 @@ import {withOnyx} from 'react-native-onyx'; import useStyleUtils from '@hooks/useStyleUtils'; import useThemeStyles from '@hooks/useThemeStyles'; import * as ReportUtils from '@libs/ReportUtils'; +import colors from '@styles/theme/colors'; import variables from '@styles/variables'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; @@ -106,7 +107,7 @@ function EReceiptThumbnail({transaction, borderRadius, fileExtension, isThumbnai fill={secondaryColor} additionalStyles={[styles.fullScreen]} /> - {isThumbnail && fileExtension && {fileExtension.toUpperCase()}} + {isThumbnail && fileExtension && {fileExtension.toUpperCase()}} {MCCIcon && !isThumbnail ? ( Date: Thu, 1 Feb 2024 14:44:54 +0300 Subject: [PATCH 024/113] removed inline styles --- src/components/EReceiptThumbnail.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/EReceiptThumbnail.tsx b/src/components/EReceiptThumbnail.tsx index 708b1707716f..fa2607965b57 100644 --- a/src/components/EReceiptThumbnail.tsx +++ b/src/components/EReceiptThumbnail.tsx @@ -107,7 +107,7 @@ function EReceiptThumbnail({transaction, borderRadius, fileExtension, isThumbnai fill={secondaryColor} additionalStyles={[styles.fullScreen]} /> - {isThumbnail && fileExtension && {fileExtension.toUpperCase()}} + {isThumbnail && fileExtension && {fileExtension.toUpperCase()}} {MCCIcon && !isThumbnail ? ( Date: Thu, 1 Feb 2024 14:51:07 +0300 Subject: [PATCH 025/113] fix on comment --- src/libs/ReceiptUtils.ts | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/libs/ReceiptUtils.ts b/src/libs/ReceiptUtils.ts index bf153118ecfd..44e054b4edc7 100644 --- a/src/libs/ReceiptUtils.ts +++ b/src/libs/ReceiptUtils.ts @@ -7,7 +7,7 @@ import type {ReceiptError} from '@src/types/onyx/Transaction'; import {splitExtensionFromFileName} from './fileDownload/FileUtils'; type ThumbnailAndImageURI = { - image: string; + image?: string; thumbnail?: string; transaction?: Transaction; isLocalFile?: boolean; @@ -23,14 +23,13 @@ type ThumbnailAndImageURI = { * @param receiptFileName */ function getThumbnailAndImageURIs(transaction: Transaction, receiptPath: string | null = null, receiptFileName: string | null = null): ThumbnailAndImageURI { - // URI to image, i.e. blob:new.expensify.com/9ef3a018-4067-47c6-b29f-5f1bd35f213d or expensify.com/receipts/w_e616108497ef940b7210ec6beb5a462d01a878f4.jpg + if (Object.hasOwn(transaction?.pendingFields ?? {}, 'waypoints')) { + return {isThumbnail: true, isLocalFile: true}; + } // If there're errors, we need to display them in preview. We can store many files in errors, but we just need to get the last one const errors = _.findLast(transaction.errors) as ReceiptError | undefined; + // URI to image, i.e. blob:new.expensify.com/9ef3a018-4067-47c6-b29f-5f1bd35f213d or expensify.com/receipts/w_e616108497ef940b7210ec6beb5a462d01a878f4.jpg const path = errors?.source ?? transaction?.receipt?.source ?? receiptPath ?? ''; - if (Object.hasOwn(transaction?.pendingFields ?? {}, 'waypoints')) { - return {isThumbnail: true, image: path, isLocalFile: true}; - } - // filename of uploaded image or last part of remote URI const filename = errors?.filename ?? transaction?.filename ?? receiptFileName ?? ''; const isReceiptImage = Str.isImage(filename); From 73f6495d8cf1d906e190a6461bf94aaa23007fd5 Mon Sep 17 00:00:00 2001 From: Fitsum Abebe Date: Thu, 1 Feb 2024 16:31:38 +0300 Subject: [PATCH 026/113] fixed pending waypoints thumbnail display --- src/components/AttachmentModal.tsx | 6 ++---- src/components/ReportActionItem/ReportActionItemImage.tsx | 2 +- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/components/AttachmentModal.tsx b/src/components/AttachmentModal.tsx index f3e8ed316c52..ce1e3c99ac82 100755 --- a/src/components/AttachmentModal.tsx +++ b/src/components/AttachmentModal.tsx @@ -519,10 +519,8 @@ function AttachmentModal({ setDownloadButtonVisibility={setDownloadButtonVisibility} /> ) : ( - !!sourceForAttachmentView && - shouldLoadAttachment && - !isLoading && - !shouldShowNotFoundPage && ( + ((TransactionUtils.isDistanceRequest(transaction) && Object.hasOwn(transaction?.pendingFields ?? {}, 'waypoints')) || + (!!sourceForAttachmentView && shouldLoadAttachment && !isLoading && !shouldShowNotFoundPage)) && ( Date: Thu, 1 Feb 2024 16:46:16 +0300 Subject: [PATCH 027/113] simplified condition --- src/components/AttachmentModal.tsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/components/AttachmentModal.tsx b/src/components/AttachmentModal.tsx index ce1e3c99ac82..d355c6fc98bb 100755 --- a/src/components/AttachmentModal.tsx +++ b/src/components/AttachmentModal.tsx @@ -519,8 +519,10 @@ function AttachmentModal({ setDownloadButtonVisibility={setDownloadButtonVisibility} /> ) : ( - ((TransactionUtils.isDistanceRequest(transaction) && Object.hasOwn(transaction?.pendingFields ?? {}, 'waypoints')) || - (!!sourceForAttachmentView && shouldLoadAttachment && !isLoading && !shouldShowNotFoundPage)) && ( + (!!sourceForAttachmentView || Object.hasOwn(transaction?.pendingFields ?? {}, 'waypoints')) && + shouldLoadAttachment && + !isLoading && + !shouldShowNotFoundPage && ( Date: Thu, 1 Feb 2024 19:33:12 +0300 Subject: [PATCH 028/113] changed to isReceiptThumbnail prop --- src/components/EReceiptThumbnail.tsx | 19 ++++++++++--------- src/components/ReceiptImage.tsx | 3 +-- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/components/EReceiptThumbnail.tsx b/src/components/EReceiptThumbnail.tsx index fa2607965b57..4ccb6cfc7243 100644 --- a/src/components/EReceiptThumbnail.tsx +++ b/src/components/EReceiptThumbnail.tsx @@ -28,8 +28,9 @@ type EReceiptThumbnailProps = EReceiptThumbnailOnyxProps & { transactionID: string; borderRadius?: number; fileExtension?: string; - isThumbnail?: boolean; - isStaticIconLayout?: boolean; + + /** Whether it is a receipt thumbnail we are displaying. */ + isReceiptThumbnail?: boolean; }; const backgroundImages = { @@ -41,7 +42,7 @@ const backgroundImages = { [CONST.ERECEIPT_COLORS.PINK]: eReceiptBGs.EReceiptBG_Pink, }; -function EReceiptThumbnail({transaction, borderRadius, fileExtension, isThumbnail = false, isStaticIconLayout = false}: EReceiptThumbnailProps) { +function EReceiptThumbnail({transaction, borderRadius, fileExtension, isReceiptThumbnail = false}: EReceiptThumbnailProps) { const styles = useThemeStyles(); const StyleUtils = useStyleUtils(); @@ -71,11 +72,11 @@ function EReceiptThumbnail({transaction, borderRadius, fileExtension, isThumbnai let receiptIconHeight: number = variables.eReceiptIconHeight; let receiptMCCSize: number = variables.eReceiptMCCHeightWidth; - if (isSmall && !isStaticIconLayout) { + if (isSmall && !isReceiptThumbnail) { receiptIconWidth = variables.eReceiptIconWidthSmall; receiptIconHeight = variables.eReceiptIconHeightSmall; receiptMCCSize = variables.eReceiptMCCHeightWidthSmall; - } else if (isMedium || isStaticIconLayout) { + } else if (isMedium || isReceiptThumbnail) { receiptIconWidth = variables.eReceiptIconWidthMedium; receiptIconHeight = variables.eReceiptIconHeightMedium; receiptMCCSize = variables.eReceiptMCCHeightWidthMedium; @@ -88,10 +89,10 @@ function EReceiptThumbnail({transaction, borderRadius, fileExtension, isThumbnai primaryColor ? StyleUtils.getBackgroundColorStyle(primaryColor) : {}, styles.overflowHidden, styles.alignItemsCenter, - isStaticIconLayout || (containerHeight && containerHeight < variables.eReceiptThumnailCenterReceiptBreakpoint) ? styles.justifyContentCenter : {}, + isReceiptThumbnail || (containerHeight && containerHeight < variables.eReceiptThumnailCenterReceiptBreakpoint) ? styles.justifyContentCenter : {}, borderRadius ? {borderRadius} : {}, ]} - onLayout={isStaticIconLayout ? undefined : onContainerLayout} + onLayout={isReceiptThumbnail ? undefined : onContainerLayout} > - {isThumbnail && fileExtension && {fileExtension.toUpperCase()}} - {MCCIcon && !isThumbnail ? ( + {isReceiptThumbnail && fileExtension && {fileExtension.toUpperCase()}} + {MCCIcon && !isReceiptThumbnail ? ( ); From 1fb6284ff86d9b862605889ca0a9f4c9237616d2 Mon Sep 17 00:00:00 2001 From: Fitsum Abebe Date: Mon, 5 Feb 2024 12:27:29 +0300 Subject: [PATCH 029/113] separated Ereceipt and thumbnail logic --- src/components/ReceiptImage.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/ReceiptImage.tsx b/src/components/ReceiptImage.tsx index 0b7155ee6597..5f15ea675ff4 100644 --- a/src/components/ReceiptImage.tsx +++ b/src/components/ReceiptImage.tsx @@ -22,13 +22,13 @@ function ReceiptImage({transactionID, isThumbnail = false, shouldUseThumbnailIma const styles = useThemeStyles(); if (isEReceipt || isThumbnail) { + const props = !isEReceipt && {borderRadius: style?.borderRadius, fileExtension, isReceiptThumbnail: true}; return ( ); From 75ca883259e66cd565bd1b27f300119cb2333c3d Mon Sep 17 00:00:00 2001 From: Fitsum Abebe Date: Mon, 5 Feb 2024 14:44:03 +0300 Subject: [PATCH 030/113] minor lint fix --- src/components/ReportActionItem/ReportActionItemImage.tsx | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/components/ReportActionItem/ReportActionItemImage.tsx b/src/components/ReportActionItem/ReportActionItemImage.tsx index e32a67acb4fb..91f1e5310273 100644 --- a/src/components/ReportActionItem/ReportActionItemImage.tsx +++ b/src/components/ReportActionItem/ReportActionItemImage.tsx @@ -1,9 +1,6 @@ /* eslint-disable react/jsx-props-no-spreading */ import Str from 'expensify-common/lib/str'; import React from 'react'; -import type {ReactElement} from 'react'; -import type {ImageSourcePropType, ViewStyle} from 'react-native'; -import {View} from 'react-native'; import type {OnyxEntry} from 'react-native-onyx'; import AttachmentModal from '@components/AttachmentModal'; import PressableWithoutFocus from '@components/Pressable/PressableWithoutFocus'; From ee4d711f9efcdafa5bbf63dabb587a3bba4a1e8f Mon Sep 17 00:00:00 2001 From: Fitsum Abebe Date: Mon, 5 Feb 2024 15:01:05 +0300 Subject: [PATCH 031/113] fix minor typescript issue --- src/components/ReportActionItem/ReportActionItemImage.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/ReportActionItem/ReportActionItemImage.tsx b/src/components/ReportActionItem/ReportActionItemImage.tsx index 91f1e5310273..de12c15a0360 100644 --- a/src/components/ReportActionItem/ReportActionItemImage.tsx +++ b/src/components/ReportActionItem/ReportActionItemImage.tsx @@ -1,6 +1,7 @@ /* eslint-disable react/jsx-props-no-spreading */ import Str from 'expensify-common/lib/str'; import React from 'react'; +import type {ViewStyle} from 'react-native'; import type {OnyxEntry} from 'react-native-onyx'; import AttachmentModal from '@components/AttachmentModal'; import PressableWithoutFocus from '@components/Pressable/PressableWithoutFocus'; From 5f07c3970ce5a2889c428c3df65aeff7ba3b9f6d Mon Sep 17 00:00:00 2001 From: Fitsum Abebe Date: Tue, 6 Feb 2024 22:40:25 +0300 Subject: [PATCH 032/113] fix type --- src/types/onyx/Transaction.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/types/onyx/Transaction.ts b/src/types/onyx/Transaction.ts index b559346a48de..8a1395d6d931 100644 --- a/src/types/onyx/Transaction.ts +++ b/src/types/onyx/Transaction.ts @@ -38,7 +38,7 @@ type Geometry = { type?: GeometryType; }; -type ReceiptSource = string | number; +type ReceiptSource = string; type Receipt = { receiptID?: number; From 8f8572152fc1bde10cccbddf69885eda5cc685e9 Mon Sep 17 00:00:00 2001 From: Fitsum Abebe Date: Tue, 6 Feb 2024 23:22:16 +0300 Subject: [PATCH 033/113] fix based on comments --- src/components/EReceiptThumbnail.tsx | 6 +++++- src/components/ReceiptImage.tsx | 15 +++++++++++++++ src/styles/variables.ts | 2 +- 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/src/components/EReceiptThumbnail.tsx b/src/components/EReceiptThumbnail.tsx index 4ccb6cfc7243..b5f709887478 100644 --- a/src/components/EReceiptThumbnail.tsx +++ b/src/components/EReceiptThumbnail.tsx @@ -26,7 +26,11 @@ type EReceiptThumbnailProps = EReceiptThumbnailOnyxProps & { /** TransactionID of the transaction this EReceipt corresponds to. It's used by withOnyx HOC */ // eslint-disable-next-line react/no-unused-prop-types transactionID: string; + + /** Border radius to be applied on the parent view. */ borderRadius?: number; + + /** The file extension of the receipt that the preview thumbnail is being displayed for. */ fileExtension?: string; /** Whether it is a receipt thumbnail we are displaying. */ @@ -89,7 +93,7 @@ function EReceiptThumbnail({transaction, borderRadius, fileExtension, isReceiptT primaryColor ? StyleUtils.getBackgroundColorStyle(primaryColor) : {}, styles.overflowHidden, styles.alignItemsCenter, - isReceiptThumbnail || (containerHeight && containerHeight < variables.eReceiptThumnailCenterReceiptBreakpoint) ? styles.justifyContentCenter : {}, + isReceiptThumbnail || (containerHeight && containerHeight < variables.eReceiptThumbnailCenterReceiptBreakpoint) ? styles.justifyContentCenter : {}, borderRadius ? {borderRadius} : {}, ]} onLayout={isReceiptThumbnail ? undefined : onContainerLayout} diff --git a/src/components/ReceiptImage.tsx b/src/components/ReceiptImage.tsx index 5f15ea675ff4..9037fc29a4c0 100644 --- a/src/components/ReceiptImage.tsx +++ b/src/components/ReceiptImage.tsx @@ -8,13 +8,28 @@ import ThumbnailImage from './ThumbnailImage'; type Style = {height: number; borderRadius: number; margin: number}; type ReceiptImageProps = { + /** Transaction ID of the transaction the receipt belongs to. */ transactionID?: string; + + /** Whether it is receipt preview thumbnail we are displaying. */ isThumbnail?: boolean; + + /** Whether we should display the receipt with ThumbnailImage component */ shouldUseThumbnailImage?: boolean; + + /** Whether it is EReceipt */ isEReceipt?: boolean; + + /** Url of the receipt image */ source?: string; + + /** Whether the receipt image requires an authToken */ isAuthTokenRequired?: boolean; + + /** Any additional styles to apply */ style?: Style; + + /** The file extension of the receipt file */ fileExtension?: string; }; diff --git a/src/styles/variables.ts b/src/styles/variables.ts index 296780abf0ae..d5e930fc5bbc 100644 --- a/src/styles/variables.ts +++ b/src/styles/variables.ts @@ -163,7 +163,7 @@ export default { addBankAccountLeftSpacing: 3, eReceiptThumbnailSmallBreakpoint: 110, eReceiptThumbnailMediumBreakpoint: 335, - eReceiptThumnailCenterReceiptBreakpoint: 200, + eReceiptThumbnailCenterReceiptBreakpoint: 200, eReceiptIconHeight: 100, eReceiptIconWidth: 72, eReceiptMCCHeightWidth: 40, From 7b14b86bc6c7dd2b9e42990ae51c156b91d444c8 Mon Sep 17 00:00:00 2001 From: Fitsum Abebe Date: Wed, 7 Feb 2024 17:24:56 +0300 Subject: [PATCH 034/113] fix type --- src/components/ReceiptImage.tsx | 36 +++++++++++++++++++++++---------- 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/src/components/ReceiptImage.tsx b/src/components/ReceiptImage.tsx index 9037fc29a4c0..f962b64ab7b9 100644 --- a/src/components/ReceiptImage.tsx +++ b/src/components/ReceiptImage.tsx @@ -7,22 +7,36 @@ import ThumbnailImage from './ThumbnailImage'; type Style = {height: number; borderRadius: number; margin: number}; -type ReceiptImageProps = { - /** Transaction ID of the transaction the receipt belongs to. */ - transactionID?: string; +type ReceiptImageProps = ( + | { + /** Transaction ID of the transaction the receipt belongs to */ + transactionID: string; - /** Whether it is receipt preview thumbnail we are displaying. */ - isThumbnail?: boolean; + /** Whether it is EReceipt */ + isEReceipt: boolean; + /** Whether it is receipt preview thumbnail we are displaying */ + isThumbnail?: boolean; + + /** Url of the receipt image */ + source?: string; + } + | { + transactionID: string; + isEReceipt?: boolean; + isThumbnail: boolean; + source?: string; + } + | { + transactionID?: string; + isEReceipt?: boolean; + isThumbnail?: boolean; + source: string; + } +) & { /** Whether we should display the receipt with ThumbnailImage component */ shouldUseThumbnailImage?: boolean; - /** Whether it is EReceipt */ - isEReceipt?: boolean; - - /** Url of the receipt image */ - source?: string; - /** Whether the receipt image requires an authToken */ isAuthTokenRequired?: boolean; From 2a1ddf3a50c5a6f02961c24d91b9893ce5e9bddc Mon Sep 17 00:00:00 2001 From: Fitsum Abebe Date: Wed, 7 Feb 2024 17:28:42 +0300 Subject: [PATCH 035/113] fix typescript --- src/components/ReportActionItem/ReportActionItemImage.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/ReportActionItem/ReportActionItemImage.tsx b/src/components/ReportActionItem/ReportActionItemImage.tsx index de12c15a0360..a1692a635a19 100644 --- a/src/components/ReportActionItem/ReportActionItemImage.tsx +++ b/src/components/ReportActionItem/ReportActionItemImage.tsx @@ -74,7 +74,7 @@ function ReportActionItemImage({ } else if (thumbnail && !isLocalFile && !Str.isPDF(imageSource)) { propsObj = {shouldUseThumbnailImage: true, source: thumbnailSource}; } else { - propsObj = {isThumbnail, fileExtension, transactionID: transaction?.transactionID, source: thumbnail ?? image}; + propsObj = {isThumbnail, fileExtension, transactionID: transaction?.transactionID, source: thumbnail ?? image ?? ''}; } if (enablePreviewModal) { From 6dfc00ba39dd529445e962455bec2caf2631a0a6 Mon Sep 17 00:00:00 2001 From: Fitsum Abebe Date: Mon, 12 Feb 2024 23:59:10 +0300 Subject: [PATCH 036/113] minor change --- src/components/ReceiptImage.tsx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/components/ReceiptImage.tsx b/src/components/ReceiptImage.tsx index f962b64ab7b9..1f1cba77a873 100644 --- a/src/components/ReceiptImage.tsx +++ b/src/components/ReceiptImage.tsx @@ -2,6 +2,7 @@ import React from 'react'; import {View} from 'react-native'; import useThemeStyles from '@hooks/useThemeStyles'; import EReceiptThumbnail from './EReceiptThumbnail'; +import type {IconSize} from './EReceiptThumbnail'; import Image from './Image'; import ThumbnailImage from './ThumbnailImage'; @@ -20,6 +21,9 @@ type ReceiptImageProps = ( /** Url of the receipt image */ source?: string; + + /** number of images displayed in the same parent container */ + iconSize?: IconSize; } | { transactionID: string; From 4a086019a153bab8b3f7807cdfeba154a1a42466 Mon Sep 17 00:00:00 2001 From: Fitsum Abebe Date: Tue, 13 Feb 2024 00:06:34 +0300 Subject: [PATCH 037/113] pass iconSize prop --- src/components/ReceiptImage.tsx | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/src/components/ReceiptImage.tsx b/src/components/ReceiptImage.tsx index 1f1cba77a873..4de2197b2b8c 100644 --- a/src/components/ReceiptImage.tsx +++ b/src/components/ReceiptImage.tsx @@ -21,9 +21,6 @@ type ReceiptImageProps = ( /** Url of the receipt image */ source?: string; - - /** number of images displayed in the same parent container */ - iconSize?: IconSize; } | { transactionID: string; @@ -49,13 +46,26 @@ type ReceiptImageProps = ( /** The file extension of the receipt file */ fileExtension?: string; + + /** number of images displayed in the same parent container */ + iconSize?: IconSize; }; -function ReceiptImage({transactionID, isThumbnail = false, shouldUseThumbnailImage = false, isEReceipt = false, source, isAuthTokenRequired, style, fileExtension}: ReceiptImageProps) { +function ReceiptImage({ + transactionID, + isThumbnail = false, + shouldUseThumbnailImage = false, + isEReceipt = false, + source, + isAuthTokenRequired, + style, + fileExtension, + iconSize, +}: ReceiptImageProps) { const styles = useThemeStyles(); if (isEReceipt || isThumbnail) { - const props = !isEReceipt && {borderRadius: style?.borderRadius, fileExtension, isReceiptThumbnail: true}; + const props = isEReceipt ? {iconSize} : {borderRadius: style?.borderRadius, fileExtension, isReceiptThumbnail: true}; return ( Date: Tue, 13 Feb 2024 22:07:54 +0300 Subject: [PATCH 038/113] use fetching waypoint function --- src/components/AttachmentModal.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/AttachmentModal.tsx b/src/components/AttachmentModal.tsx index b1ec589a3d3e..6292dbed0a25 100755 --- a/src/components/AttachmentModal.tsx +++ b/src/components/AttachmentModal.tsx @@ -523,7 +523,7 @@ function AttachmentModal({ setDownloadButtonVisibility={setDownloadButtonVisibility} /> ) : ( - (!!sourceForAttachmentView || Object.hasOwn(transaction?.pendingFields ?? {}, 'waypoints')) && + (!!sourceForAttachmentView || TransactionUtils.isFetchingWaypointsFromServer(transaction)) && shouldLoadAttachment && !isLoading && !shouldShowNotFoundPage && ( From 32268d427b0fa9ab3fff4f8232a3ae9541948f48 Mon Sep 17 00:00:00 2001 From: Jakub Butkiewicz Date: Thu, 15 Feb 2024 14:11:29 +0100 Subject: [PATCH 039/113] ref: move TagPicker to TS --- src/ONYXKEYS.ts | 2 +- .../ReportActionItem/MoneyRequestView.tsx | 3 +- src/components/TagPicker/index.js | 94 ------------ src/components/TagPicker/index.tsx | 135 ++++++++++++++++++ .../TagPicker/tagPickerPropTypes.js | 41 ------ src/libs/OptionsListUtils.ts | 36 ++--- src/libs/PolicyUtils.ts | 7 +- src/types/onyx/PolicyTag.ts | 7 +- 8 files changed, 160 insertions(+), 165 deletions(-) delete mode 100644 src/components/TagPicker/index.js create mode 100644 src/components/TagPicker/index.tsx delete mode 100644 src/components/TagPicker/tagPickerPropTypes.js diff --git a/src/ONYXKEYS.ts b/src/ONYXKEYS.ts index 5e41e08d0c78..d66182938465 100755 --- a/src/ONYXKEYS.ts +++ b/src/ONYXKEYS.ts @@ -429,7 +429,7 @@ type OnyxCollectionValuesMapping = { [ONYXKEYS.COLLECTION.POLICY]: OnyxTypes.Policy; [ONYXKEYS.COLLECTION.POLICY_DRAFTS]: OnyxTypes.Policy; [ONYXKEYS.COLLECTION.POLICY_CATEGORIES]: OnyxTypes.PolicyCategories; - [ONYXKEYS.COLLECTION.POLICY_TAGS]: OnyxTypes.PolicyTags; + [ONYXKEYS.COLLECTION.POLICY_TAGS]: OnyxTypes.PolicyTagList; [ONYXKEYS.COLLECTION.POLICY_MEMBERS]: OnyxTypes.PolicyMembers; [ONYXKEYS.COLLECTION.POLICY_MEMBERS_DRAFTS]: OnyxTypes.PolicyMember; [ONYXKEYS.COLLECTION.POLICY_RECENTLY_USED_CATEGORIES]: OnyxTypes.RecentlyUsedCategories; diff --git a/src/components/ReportActionItem/MoneyRequestView.tsx b/src/components/ReportActionItem/MoneyRequestView.tsx index 6b16f272e4c8..cc723b7288cb 100644 --- a/src/components/ReportActionItem/MoneyRequestView.tsx +++ b/src/components/ReportActionItem/MoneyRequestView.tsx @@ -55,7 +55,7 @@ type MoneyRequestViewOnyxPropsWithoutTransaction = { policyCategories: OnyxEntry; /** Collection of tags attached to a policy */ - policyTags: OnyxEntry; + policyTags: OnyxEntry; /** The expense report or iou report (only will have a value if this is a transaction thread) */ parentReport: OnyxEntry; @@ -155,7 +155,6 @@ function MoneyRequestView({ Navigation.dismissModal(); return; } - // @ts-expect-error: the type used across the app for policyTags is not what is returned by Onyx, PolicyTagList represents that, but existing policy tag utils need a refactor to fix this IOU.updateMoneyRequestBillable(transaction?.transactionID ?? '', report?.reportID, newBillable, policy, policyTags, policyCategories); Navigation.dismissModal(); }, diff --git a/src/components/TagPicker/index.js b/src/components/TagPicker/index.js deleted file mode 100644 index e258472eae93..000000000000 --- a/src/components/TagPicker/index.js +++ /dev/null @@ -1,94 +0,0 @@ -import lodashGet from 'lodash/get'; -import React, {useMemo, useState} from 'react'; -import {withOnyx} from 'react-native-onyx'; -import _ from 'underscore'; -import OptionsSelector from '@components/OptionsSelector'; -import useLocalize from '@hooks/useLocalize'; -import useStyleUtils from '@hooks/useStyleUtils'; -import useThemeStyles from '@hooks/useThemeStyles'; -import * as OptionsListUtils from '@libs/OptionsListUtils'; -import * as PolicyUtils from '@libs/PolicyUtils'; -import CONST from '@src/CONST'; -import ONYXKEYS from '@src/ONYXKEYS'; -import {defaultProps, propTypes} from './tagPickerPropTypes'; - -function TagPicker({selectedTag, tag, policyTags, policyRecentlyUsedTags, shouldShowDisabledAndSelectedOption, insets, onSubmit}) { - const styles = useThemeStyles(); - const StyleUtils = useStyleUtils(); - const {translate} = useLocalize(); - const [searchValue, setSearchValue] = useState(''); - - const policyRecentlyUsedTagsList = lodashGet(policyRecentlyUsedTags, tag, []); - const policyTagList = PolicyUtils.getTagList(policyTags, tag); - const policyTagsCount = _.size(_.filter(policyTagList, (policyTag) => policyTag.enabled)); - const isTagsCountBelowThreshold = policyTagsCount < CONST.TAG_LIST_THRESHOLD; - - const shouldShowTextInput = !isTagsCountBelowThreshold; - - const selectedOptions = useMemo(() => { - if (!selectedTag) { - return []; - } - - return [ - { - name: selectedTag, - enabled: true, - accountID: null, - }, - ]; - }, [selectedTag]); - - const enabledTags = useMemo(() => { - if (!shouldShowDisabledAndSelectedOption) { - return policyTagList; - } - const selectedNames = _.map(selectedOptions, (s) => s.name); - const tags = [...selectedOptions, ..._.filter(policyTagList, (policyTag) => policyTag.enabled && !selectedNames.includes(policyTag.name))]; - return tags; - }, [selectedOptions, policyTagList, shouldShowDisabledAndSelectedOption]); - - const sections = useMemo( - () => OptionsListUtils.getFilteredOptions({}, {}, [], searchValue, selectedOptions, [], false, false, false, {}, [], true, enabledTags, policyRecentlyUsedTagsList, false).tagOptions, - [searchValue, enabledTags, selectedOptions, policyRecentlyUsedTagsList], - ); - - const headerMessage = OptionsListUtils.getHeaderMessageForNonUserList(lodashGet(sections, '[0].data.length', 0) > 0, searchValue); - - const selectedOptionKey = lodashGet(_.filter(lodashGet(sections, '[0].data', []), (policyTag) => policyTag.searchText === selectedTag)[0], 'keyForList'); - - return ( - - ); -} - -TagPicker.displayName = 'TagPicker'; -TagPicker.propTypes = propTypes; -TagPicker.defaultProps = defaultProps; - -export default withOnyx({ - policyTags: { - key: ({policyID}) => `${ONYXKEYS.COLLECTION.POLICY_TAGS}${policyID}`, - }, - policyRecentlyUsedTags: { - key: ({policyID}) => `${ONYXKEYS.COLLECTION.POLICY_RECENTLY_USED_TAGS}${policyID}`, - }, -})(TagPicker); diff --git a/src/components/TagPicker/index.tsx b/src/components/TagPicker/index.tsx new file mode 100644 index 000000000000..48ef977a1225 --- /dev/null +++ b/src/components/TagPicker/index.tsx @@ -0,0 +1,135 @@ +import React, {useMemo, useState} from 'react'; +import type {OnyxEntry} from 'react-native-onyx'; +import {withOnyx} from 'react-native-onyx'; +import type {EdgeInsets} from 'react-native-safe-area-context'; +import OptionsSelector from '@components/OptionsSelector'; +import useLocalize from '@hooks/useLocalize'; +import useStyleUtils from '@hooks/useStyleUtils'; +import useThemeStyles from '@hooks/useThemeStyles'; +import * as OptionsListUtils from '@libs/OptionsListUtils'; +import * as PolicyUtils from '@libs/PolicyUtils'; +import CONST from '@src/CONST'; +import ONYXKEYS from '@src/ONYXKEYS'; +import type {PolicyTag, PolicyTagList, PolicyTags, RecentlyUsedTags} from '@src/types/onyx'; + +type SelectedTagOption = { + name: string; + enabled?: boolean; + accountID: number | null; +}; + +type TagPickerOnyxProps = { + /** Collection of tags attached to a policy */ + policyTags: OnyxEntry; + + /** List of recently used tags */ + policyRecentlyUsedTags: OnyxEntry; +}; + +type TagPickerProps = TagPickerOnyxProps & { + /** The policyID we are getting tags for */ + // It's used in withOnyx HOC. + // eslint-disable-next-line react/no-unused-prop-types + policyID: string; + + /** The selected tag of the money request */ + selectedTag: string; + + /** The name of tag list we are getting tags for */ + tag: string; + + /** Callback to submit the selected tag */ + onSubmit: () => void; + + /** + * Safe area insets required for reflecting the portion of the view, + * that is not covered by navigation bars, tab bars, toolbars, and other ancestor views. + */ + insets: EdgeInsets; + + /** Should show the selected option that is disabled? */ + shouldShowDisabledAndSelectedOption?: boolean; +}; + +function TagPicker({selectedTag, tag, policyTags, policyRecentlyUsedTags, shouldShowDisabledAndSelectedOption = false, insets, onSubmit}: TagPickerProps) { + const styles = useThemeStyles(); + const StyleUtils = useStyleUtils(); + const {translate} = useLocalize(); + const [searchValue, setSearchValue] = useState(''); + + const policyTagList = PolicyUtils.getTagList(policyTags, tag); + const policyTagsCount = Object.values(policyTagList).filter((policyTag) => policyTag.enabled).length; + const isTagsCountBelowThreshold = policyTagsCount < CONST.TAG_LIST_THRESHOLD; + + const shouldShowTextInput = !isTagsCountBelowThreshold; + + const selectedOptions: SelectedTagOption[] = useMemo(() => { + if (!selectedTag) { + return []; + } + + return [ + { + name: selectedTag, + enabled: true, + accountID: null, + }, + ]; + }, [selectedTag]); + + const enabledTags: PolicyTags | Array = useMemo(() => { + if (!shouldShowDisabledAndSelectedOption) { + return policyTagList; + } + const selectedNames = selectedOptions.map((s) => s.name); + + return [...selectedOptions, ...Object.values(policyTagList).filter((policyTag) => policyTag.enabled && !selectedNames.includes(policyTag.name))]; + }, [selectedOptions, policyTagList, shouldShowDisabledAndSelectedOption]); + + const sections = useMemo(() => { + const policyRecentlyUsedTagsList = policyRecentlyUsedTags?.tag ?? []; + + return OptionsListUtils.getFilteredOptions({}, {}, [], searchValue, selectedOptions, [], false, false, false, {}, [], true, enabledTags, policyRecentlyUsedTagsList, false) + .tagOptions; + }, [searchValue, enabledTags, selectedOptions, policyRecentlyUsedTags?.tag]); + + const headerMessage = OptionsListUtils.getHeaderMessageForNonUserList((sections?.[0]?.data?.length ?? 0) > 0, searchValue); + + const selectedOptionKey = sections[0]?.data?.filter((policyTag) => policyTag.searchText === selectedTag)?.[0]?.keyForList; + + return ( + + ); +} + +TagPicker.displayName = 'TagPicker'; + +export default withOnyx({ + policyTags: { + key: ({policyID}) => `${ONYXKEYS.COLLECTION.POLICY_TAGS}${policyID}`, + }, + policyRecentlyUsedTags: { + key: ({policyID}) => `${ONYXKEYS.COLLECTION.POLICY_RECENTLY_USED_TAGS}${policyID}`, + }, +})(TagPicker); + +export type {SelectedTagOption}; diff --git a/src/components/TagPicker/tagPickerPropTypes.js b/src/components/TagPicker/tagPickerPropTypes.js deleted file mode 100644 index b98f7f6ef8e9..000000000000 --- a/src/components/TagPicker/tagPickerPropTypes.js +++ /dev/null @@ -1,41 +0,0 @@ -import PropTypes from 'prop-types'; -import tagPropTypes from '@components/tagPropTypes'; -import safeAreaInsetPropTypes from '@pages/safeAreaInsetPropTypes'; - -const propTypes = { - /** The policyID we are getting tags for */ - policyID: PropTypes.string.isRequired, - - /** The selected tag of the money request */ - selectedTag: PropTypes.string.isRequired, - - /** The name of tag list we are getting tags for */ - tag: PropTypes.string.isRequired, - - /** Callback to submit the selected tag */ - onSubmit: PropTypes.func.isRequired, - - /** - * Safe area insets required for reflecting the portion of the view, - * that is not covered by navigation bars, tab bars, toolbars, and other ancestor views. - */ - insets: safeAreaInsetPropTypes.isRequired, - - /* Onyx Props */ - /** Collection of tags attached to a policy */ - policyTags: tagPropTypes, - - /** List of recently used tags */ - policyRecentlyUsedTags: PropTypes.objectOf(PropTypes.arrayOf(PropTypes.string)), - - /** Should show the selected option that is disabled? */ - shouldShowDisabledAndSelectedOption: PropTypes.bool, -}; - -const defaultProps = { - policyTags: {}, - policyRecentlyUsedTags: {}, - shouldShowDisabledAndSelectedOption: false, -}; - -export {propTypes, defaultProps}; diff --git a/src/libs/OptionsListUtils.ts b/src/libs/OptionsListUtils.ts index 346cc71953e6..30b022862987 100644 --- a/src/libs/OptionsListUtils.ts +++ b/src/libs/OptionsListUtils.ts @@ -7,6 +7,7 @@ import lodashSet from 'lodash/set'; import lodashSortBy from 'lodash/sortBy'; import Onyx from 'react-native-onyx'; import type {OnyxCollection, OnyxEntry} from 'react-native-onyx'; +import type {SelectedTagOption} from '@components/TagPicker'; import CONST from '@src/CONST'; import type {TranslationPaths} from '@src/languages/types'; import ONYXKEYS from '@src/ONYXKEYS'; @@ -19,6 +20,7 @@ import type { PolicyCategories, PolicyCategory, PolicyTag, + PolicyTags, Report, ReportAction, ReportActions, @@ -50,12 +52,6 @@ import * as TaskUtils from './TaskUtils'; import * as TransactionUtils from './TransactionUtils'; import * as UserUtils from './UserUtils'; -type Tag = { - enabled: boolean; - name: string; - accountID: number | null; -}; - type Option = Partial; type PayeePersonalDetails = { @@ -106,7 +102,7 @@ type GetOptionsConfig = { categories?: PolicyCategories; recentlyUsedCategories?: string[]; includeTags?: boolean; - tags?: Record; + tags?: PolicyTags | Array; recentlyUsedTags?: string[]; canInviteUser?: boolean; includeSelectedOptions?: boolean; @@ -866,16 +862,8 @@ function sortCategories(categories: Record): Category[] { /** * Sorts tags alphabetically by name. */ -function sortTags(tags: Record | Tag[]) { - let sortedTags; - - if (Array.isArray(tags)) { - sortedTags = tags.sort((a, b) => a.name.localeCompare(b.name)); - } else { - sortedTags = Object.values(tags).sort((a, b) => a.name.localeCompare(b.name)); - } - - return sortedTags; +function sortTags(tags: Array) { + return tags.sort((a, b) => a.name?.localeCompare(b.name)); } /** @@ -1038,7 +1026,7 @@ function getCategoryListSections( * * @param tags - an initial tag array */ -function getTagsOptions(tags: Category[]): Option[] { +function getTagsOptions(tags: Array>): Option[] { return tags.map((tag) => { // This is to remove unnecessary escaping backslash in tag name sent from backend. const cleanedName = PolicyUtils.getCleanedTagName(tag.name); @@ -1055,7 +1043,13 @@ function getTagsOptions(tags: Category[]): Option[] { /** * Build the section list for tags */ -function getTagListSections(tags: Tag[], recentlyUsedTags: string[], selectedOptions: Category[], searchInputValue: string, maxRecentReportsToShow: number) { +function getTagListSections( + tags: Array, + recentlyUsedTags: string[], + selectedOptions: SelectedTagOption[], + searchInputValue: string, + maxRecentReportsToShow: number, +) { const tagSections = []; const sortedTags = sortTags(tags); const enabledTags = sortedTags.filter((tag) => tag.enabled); @@ -1367,7 +1361,7 @@ function getOptions( } if (includeTags) { - const tagOptions = getTagListSections(Object.values(tags), recentlyUsedTags, selectedOptions as Category[], searchInputValue, maxRecentReportsToShow); + const tagOptions = getTagListSections(Object.values(tags), recentlyUsedTags, selectedOptions as SelectedTagOption[], searchInputValue, maxRecentReportsToShow); return { recentReports: [], @@ -1767,7 +1761,7 @@ function getFilteredOptions( categories: PolicyCategories = {}, recentlyUsedCategories: string[] = [], includeTags = false, - tags: Record = {}, + tags: PolicyTags | Array = {}, recentlyUsedTags: string[] = [], canInviteUser = true, includeSelectedOptions = false, diff --git a/src/libs/PolicyUtils.ts b/src/libs/PolicyUtils.ts index 90dfa8fde339..d80bff0f43a3 100644 --- a/src/libs/PolicyUtils.ts +++ b/src/libs/PolicyUtils.ts @@ -3,7 +3,7 @@ import type {OnyxCollection, OnyxEntry} from 'react-native-onyx'; import type {ValueOf} from 'type-fest'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; -import type {PersonalDetailsList, Policy, PolicyMembers, PolicyTag, PolicyTags} from '@src/types/onyx'; +import type {PersonalDetailsList, Policy, PolicyMembers, PolicyTag, PolicyTagList, PolicyTags} from '@src/types/onyx'; import type {EmptyObject} from '@src/types/utils/EmptyObject'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; @@ -155,13 +155,12 @@ function getIneligibleInvitees(policyMembers: OnyxEntry, personal /** * Gets the tag from policy tags, defaults to the first if no key is provided. */ -function getTag(policyTags: OnyxEntry, tagKey?: keyof typeof policyTags): PolicyTag | undefined | EmptyObject { +function getTag(policyTags: OnyxEntry, tagKey?: keyof typeof policyTags): PolicyTag | undefined | EmptyObject { if (isEmptyObject(policyTags)) { return {}; } const policyTagKey = tagKey ?? Object.keys(policyTags ?? {})[0]; - return policyTags?.[policyTagKey] ?? {}; } @@ -181,7 +180,7 @@ function getTagListName(policyTags: OnyxEntry) { /** * Gets the tags of a policy for a specific key. Defaults to the first tag if no key is provided. */ -function getTagList(policyTags: OnyxCollection, tagKey: string) { +function getTagList(policyTags: OnyxEntry, tagKey: string) { if (Object.keys(policyTags ?? {})?.length === 0) { return {}; } diff --git a/src/types/onyx/PolicyTag.ts b/src/types/onyx/PolicyTag.ts index ff688419605d..33e6ef4f7bb1 100644 --- a/src/types/onyx/PolicyTag.ts +++ b/src/types/onyx/PolicyTag.ts @@ -3,14 +3,17 @@ type PolicyTag = { name: string; /** Flag that determines if a tag is active and able to be selected */ - enabled: boolean; + enabled?: boolean; /** "General Ledger code" that corresponds to this tag in an accounting system. Similar to an ID. */ // eslint-disable-next-line @typescript-eslint/naming-convention - 'GL Code': string; + 'GL Code'?: string; /** Nested tags */ tags: PolicyTags; + + /** Flag that determines if a tag is required */ + required: boolean; }; type PolicyTags = Record; From 0f157fce2d446b8ff270e00e1b8c2d44178765de Mon Sep 17 00:00:00 2001 From: FitseTLT Date: Tue, 20 Feb 2024 23:18:37 +0300 Subject: [PATCH 040/113] fix type --- 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 ae6516edf266..b22d21ba8d8a 100644 --- a/src/components/DistanceEReceipt.tsx +++ b/src/components/DistanceEReceipt.tsx @@ -29,7 +29,7 @@ function DistanceEReceipt({transaction}: DistanceEReceiptProps) { const thumbnail = TransactionUtils.hasReceipt(transaction) ? ReceiptUtils.getThumbnailAndImageURIs(transaction).thumbnail : null; const {amount: transactionAmount, currency: transactionCurrency, merchant: transactionMerchant, created: transactionDate} = ReportUtils.getTransactionDetails(transaction) ?? {}; const formattedTransactionAmount = CurrencyUtils.convertToDisplayString(transactionAmount, transactionCurrency); - const thumbnailSource = tryResolveUrlFromApiRoot((thumbnail as string) || ''); + const thumbnailSource = tryResolveUrlFromApiRoot(thumbnail ?? ''); const waypoints = useMemo(() => transaction?.comment?.waypoints ?? {}, [transaction?.comment?.waypoints]); const sortedWaypoints = useMemo( () => From e154fea0ed57c106935d2558b6b1d26cc738f8de Mon Sep 17 00:00:00 2001 From: Jakub Butkiewicz Date: Wed, 21 Feb 2024 13:41:22 +0100 Subject: [PATCH 041/113] fix: missing value --- src/components/TagPicker/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/TagPicker/index.tsx b/src/components/TagPicker/index.tsx index 917351e68228..b553e183a37f 100644 --- a/src/components/TagPicker/index.tsx +++ b/src/components/TagPicker/index.tsx @@ -62,7 +62,7 @@ function TagPicker({selectedTag, tag, policyTags, tagIndex, policyRecentlyUsedTa const policyRecentlyUsedTagsList = useMemo(() => policyRecentlyUsedTags?.[tag] ?? [], [policyRecentlyUsedTags, tag]); const policyTagList = PolicyUtils.getTagList(policyTags, tagIndex); - const policyTagsCount = PolicyUtils.getCountOfEnabledTagsOfList(policyTagList); + const policyTagsCount = PolicyUtils.getCountOfEnabledTagsOfList(policyTagList.tags); const isTagsCountBelowThreshold = policyTagsCount < CONST.TAG_LIST_THRESHOLD; const shouldShowTextInput = !isTagsCountBelowThreshold; From c44b4309b00d1f91d8220a162513b05493491b81 Mon Sep 17 00:00:00 2001 From: FitseTLT Date: Wed, 21 Feb 2024 18:09:50 +0300 Subject: [PATCH 042/113] add fallbackIcon --- src/components/ReceiptImage.tsx | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/components/ReceiptImage.tsx b/src/components/ReceiptImage.tsx index 4de2197b2b8c..f293d3b047d5 100644 --- a/src/components/ReceiptImage.tsx +++ b/src/components/ReceiptImage.tsx @@ -1,6 +1,7 @@ import React from 'react'; import {View} from 'react-native'; import useThemeStyles from '@hooks/useThemeStyles'; +import type IconAsset from '@src/types/utils/IconAsset'; import EReceiptThumbnail from './EReceiptThumbnail'; import type {IconSize} from './EReceiptThumbnail'; import Image from './Image'; @@ -49,6 +50,12 @@ type ReceiptImageProps = ( /** number of images displayed in the same parent container */ iconSize?: IconSize; + + /** If the image fails to load – show the provided fallback icon */ + fallbackIcon?: IconAsset; + + /** The size of the fallback icon */ + fallbackIconSize?: number; }; function ReceiptImage({ @@ -61,6 +68,8 @@ function ReceiptImage({ style, fileExtension, iconSize, + fallbackIcon, + fallbackIconSize, }: ReceiptImageProps) { const styles = useThemeStyles(); @@ -84,6 +93,8 @@ function ReceiptImage({ style={[styles.w100, styles.h100]} isAuthTokenRequired shouldDynamicallyResize={false} + fallbackIcon={fallbackIcon} + fallbackIconSize={fallbackIconSize} /> ); } From 7025bfa7b10a6c36d788f9804ac627d6156e7e67 Mon Sep 17 00:00:00 2001 From: FitseTLT Date: Wed, 21 Feb 2024 18:30:35 +0300 Subject: [PATCH 043/113] applied dynamic thumbnail icon size --- src/components/ReceiptImage.tsx | 3 ++- src/components/ReportActionItem/ReportActionItemImage.tsx | 8 +++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/components/ReceiptImage.tsx b/src/components/ReceiptImage.tsx index f293d3b047d5..cd70413b7a2e 100644 --- a/src/components/ReceiptImage.tsx +++ b/src/components/ReceiptImage.tsx @@ -74,11 +74,12 @@ function ReceiptImage({ const styles = useThemeStyles(); if (isEReceipt || isThumbnail) { - const props = isEReceipt ? {iconSize} : {borderRadius: style?.borderRadius, fileExtension, isReceiptThumbnail: true}; + const props = isThumbnail && {borderRadius: style?.borderRadius, fileExtension, isReceiptThumbnail: true}; return ( diff --git a/src/components/ReportActionItem/ReportActionItemImage.tsx b/src/components/ReportActionItem/ReportActionItemImage.tsx index 0f6131a61c05..cc84abccd6d1 100644 --- a/src/components/ReportActionItem/ReportActionItemImage.tsx +++ b/src/components/ReportActionItem/ReportActionItemImage.tsx @@ -86,7 +86,13 @@ function ReportActionItemImage({ fallbackIconSize: isSingleImage ? variables.iconSizeSuperLarge : variables.iconSizeExtraLarge, }; } else { - propsObj = {isThumbnail, fileExtension, transactionID: transaction?.transactionID, source: thumbnail ?? image ?? ''}; + propsObj = { + isThumbnail, + ...(isThumbnail && {iconSize: isSingleImage ? 'medium' : ('small' as IconSize)}), + fileExtension, + transactionID: transaction?.transactionID, + source: thumbnail ?? image ?? '', + }; } if (enablePreviewModal) { From 9eb1edd18a8545774e4114ec3d35a6073be0e3ef Mon Sep 17 00:00:00 2001 From: FitseTLT Date: Mon, 26 Feb 2024 12:22:43 +0300 Subject: [PATCH 044/113] use primary color for label text color --- src/components/EReceiptThumbnail.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/components/EReceiptThumbnail.tsx b/src/components/EReceiptThumbnail.tsx index 5093e2853e18..f6d5beb7e24d 100644 --- a/src/components/EReceiptThumbnail.tsx +++ b/src/components/EReceiptThumbnail.tsx @@ -105,7 +105,9 @@ function EReceiptThumbnail({transaction, borderRadius, fileExtension, isReceiptT fill={secondaryColor} additionalStyles={[styles.fullScreen]} /> - {isReceiptThumbnail && fileExtension && {fileExtension.toUpperCase()}} + {isReceiptThumbnail && fileExtension && ( + {fileExtension.toUpperCase()} + )} {MCCIcon && !isReceiptThumbnail ? ( Date: Mon, 26 Feb 2024 15:26:54 +0100 Subject: [PATCH 045/113] feat: memoize SidebarLinksData --- src/pages/home/sidebar/SidebarLinksData.js | 41 ++++++++++++++-------- 1 file changed, 27 insertions(+), 14 deletions(-) diff --git a/src/pages/home/sidebar/SidebarLinksData.js b/src/pages/home/sidebar/SidebarLinksData.js index c4cc0713c596..0c8125cae79f 100644 --- a/src/pages/home/sidebar/SidebarLinksData.js +++ b/src/pages/home/sidebar/SidebarLinksData.js @@ -2,7 +2,7 @@ import {deepEqual} from 'fast-equals'; import lodashGet from 'lodash/get'; import lodashMap from 'lodash/map'; import PropTypes from 'prop-types'; -import React, {useCallback, useEffect, useMemo, useRef} from 'react'; +import React, {memo, useCallback, useEffect, useMemo, useRef} from 'react'; import {View} from 'react-native'; import {withOnyx} from 'react-native-onyx'; import _ from 'underscore'; @@ -136,18 +136,14 @@ function SidebarLinksData({ const reportIDsRef = useRef(null); const isLoading = isLoadingApp; + + const optionItemsMemoized = useMemo( + () => SidebarUtils.getOrderedReportIDs(null, chatReports, betas, policies, priorityMode, allReportActions, transactionViolations, activeWorkspaceID, policyMemberAccountIDs), + [chatReports, betas, policies, priorityMode, allReportActions, transactionViolations, activeWorkspaceID, policyMemberAccountIDs], + ); + const optionListItems = useMemo(() => { - const reportIDs = SidebarUtils.getOrderedReportIDs( - null, - chatReports, - betas, - policies, - priorityMode, - allReportActions, - transactionViolations, - activeWorkspaceID, - policyMemberAccountIDs, - ); + const reportIDs = optionItemsMemoized; if (deepEqual(reportIDsRef.current, reportIDs)) { return reportIDsRef.current; @@ -160,7 +156,7 @@ function SidebarLinksData({ reportIDsRef.current = reportIDs; } return reportIDsRef.current || []; - }, [chatReports, betas, policies, priorityMode, allReportActions, transactionViolations, activeWorkspaceID, policyMemberAccountIDs, isLoading, network.isOffline, prevPriorityMode]); + }, [optionItemsMemoized, priorityMode, isLoading, network.isOffline, prevPriorityMode]); // We need to make sure the current report is in the list of reports, but we do not want // to have to re-generate the list every time the currentReportID changes. To do that @@ -334,4 +330,21 @@ export default compose( initialValue: {}, }, }), -)(SidebarLinksData); +)( + memo( + SidebarLinksData, + (prevProps, nextProps) => + _.isEqual(prevProps.chatReports, nextProps.chatReports) && + _.isEqual(prevProps.allReportActions, nextProps.allReportActions) && + prevProps.isLoadingApp === nextProps.isLoadingApp && + prevProps.priorityMode === nextProps.priorityMode && + _.isEqual(prevProps.betas, nextProps.betas) && + _.isEqual(prevProps.policies, nextProps.policies) && + prevProps.network.isOffline === nextProps.network.isOffline && + _.isEqual(prevProps.insets, nextProps.insets) && + prevProps.onLinkClick === nextProps.onLinkClick && + _.isEqual(prevProps.policyMembers, nextProps.policyMembers) && + _.isEqual(prevProps.transactionViolations, nextProps.transactionViolations) && + _.isEqual(prevProps.currentUserPersonalDetails, nextProps.currentUserPersonalDetails), + ), +); From 88c5fd8e5c29cc7dc1b70d863483abe0fc7db86a Mon Sep 17 00:00:00 2001 From: Tomasz Lesniakiewicz Date: Tue, 27 Feb 2024 11:53:59 +0100 Subject: [PATCH 046/113] add missing props to memo --- src/pages/home/sidebar/SidebarLinksData.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/pages/home/sidebar/SidebarLinksData.js b/src/pages/home/sidebar/SidebarLinksData.js index 0c8125cae79f..59bf74586b4b 100644 --- a/src/pages/home/sidebar/SidebarLinksData.js +++ b/src/pages/home/sidebar/SidebarLinksData.js @@ -345,6 +345,7 @@ export default compose( prevProps.onLinkClick === nextProps.onLinkClick && _.isEqual(prevProps.policyMembers, nextProps.policyMembers) && _.isEqual(prevProps.transactionViolations, nextProps.transactionViolations) && - _.isEqual(prevProps.currentUserPersonalDetails, nextProps.currentUserPersonalDetails), + _.isEqual(prevProps.currentUserPersonalDetails, nextProps.currentUserPersonalDetails) && + prevProps.currentReportID === nextProps.currentReportID, ), ); From 3aa217604ce487b9748412e60d1827822c74f1f7 Mon Sep 17 00:00:00 2001 From: Tomasz Lesniakiewicz Date: Tue, 27 Feb 2024 14:13:51 +0100 Subject: [PATCH 047/113] chore: add comments for memoization --- src/pages/home/sidebar/SidebarLinksData.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/pages/home/sidebar/SidebarLinksData.js b/src/pages/home/sidebar/SidebarLinksData.js index 59bf74586b4b..c5749893d7fb 100644 --- a/src/pages/home/sidebar/SidebarLinksData.js +++ b/src/pages/home/sidebar/SidebarLinksData.js @@ -331,6 +331,12 @@ export default compose( }, }), )( + /* + While working on audit on the App Start App metric we noticed that by memoizing SidebarLinksData we can avoid 1 additional run of getOrderedReportIDs. + With that we can reduce app start up time by ~2.5s on heavy account. + After finding and fixing core issues with getOrderedReportIDs performance we might remove the memoization + More details - https://github.com/Expensify/App/issues/35234#issuecomment-1926914534 + */ memo( SidebarLinksData, (prevProps, nextProps) => From 4e3edb22f06a3c2a43afa5c34744f037ada71479 Mon Sep 17 00:00:00 2001 From: Jakub Butkiewicz Date: Thu, 29 Feb 2024 13:41:52 +0100 Subject: [PATCH 048/113] fix: typecheck --- src/components/MoneyRequestConfirmationList.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/MoneyRequestConfirmationList.tsx b/src/components/MoneyRequestConfirmationList.tsx index 773e98b6462e..ff355985b071 100755 --- a/src/components/MoneyRequestConfirmationList.tsx +++ b/src/components/MoneyRequestConfirmationList.tsx @@ -240,7 +240,7 @@ function MoneyRequestConfirmationList({ const taxRates = policy?.taxRates; // A flag for showing the categories field - const shouldShowCategories = isPolicyExpenseChat && (iouCategory || OptionsListUtils.hasEnabledOptions(Object.values(policyCategories ?? {}))); + const shouldShowCategories = isPolicyExpenseChat && (iouCategory || OptionsListUtils.hasEnabledOptions(policyCategories ?? {})); // A flag and a toggler for showing the rest of the form fields const [shouldExpandFields, toggleShouldExpandFields] = useReducer((state) => !state, false); From 77e3d046b51e8b48a655001432713b1dff794977 Mon Sep 17 00:00:00 2001 From: Jakub Butkiewicz Date: Mon, 4 Mar 2024 10:30:46 +0100 Subject: [PATCH 049/113] fix: resolve comments --- src/components/TagPicker/index.tsx | 2 +- src/libs/OptionsListUtils.ts | 5 +++-- src/types/onyx/PolicyTag.ts | 6 +++--- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/components/TagPicker/index.tsx b/src/components/TagPicker/index.tsx index b553e183a37f..f13c27beadc3 100644 --- a/src/components/TagPicker/index.tsx +++ b/src/components/TagPicker/index.tsx @@ -14,7 +14,7 @@ import type {PolicyTag, PolicyTagList, PolicyTags, RecentlyUsedTags} from '@src/ type SelectedTagOption = { name: string; - enabled?: boolean; + enabled: boolean; accountID: number | null; }; diff --git a/src/libs/OptionsListUtils.ts b/src/libs/OptionsListUtils.ts index 832e04d98051..fc765564c900 100644 --- a/src/libs/OptionsListUtils.ts +++ b/src/libs/OptionsListUtils.ts @@ -20,6 +20,7 @@ import type { PolicyCategories, PolicyTag, PolicyTagList, + PolicyTags, Report, ReportAction, ReportActions, @@ -125,7 +126,7 @@ type GetOptionsConfig = { categories?: PolicyCategories; recentlyUsedCategories?: string[]; includeTags?: boolean; - tags?: PolicyTagList | Array; + tags?: PolicyTags | Array; recentlyUsedTags?: string[]; canInviteUser?: boolean; includeSelectedOptions?: boolean; @@ -1814,7 +1815,7 @@ function getFilteredOptions( categories: PolicyCategories = {}, recentlyUsedCategories: string[] = [], includeTags = false, - tags: PolicyTagList | Array = {}, + tags: PolicyTags | Array = {}, recentlyUsedTags: string[] = [], canInviteUser = true, includeSelectedOptions = false, diff --git a/src/types/onyx/PolicyTag.ts b/src/types/onyx/PolicyTag.ts index 0b7ccd93fcc3..b2873538cb4d 100644 --- a/src/types/onyx/PolicyTag.ts +++ b/src/types/onyx/PolicyTag.ts @@ -3,13 +3,13 @@ type PolicyTag = { name: string; /** Flag that determines if a tag is active and able to be selected */ - enabled?: boolean; + enabled: boolean; /** "General Ledger code" that corresponds to this tag in an accounting system. Similar to an ID. */ // eslint-disable-next-line @typescript-eslint/naming-convention 'GL Code'?: string; - /** Nested tags */ + /** List of tags */ tags: PolicyTags; /** Flag that determines if a tag is required */ @@ -27,7 +27,7 @@ type PolicyTagList = Record< /** Flag that determines if tags are required */ required: boolean; - /** Nested tags */ + /** List of tags */ tags: PolicyTags; /** Index by which the tag appears in the hierarchy of tags */ From 451f83d3be867c631be0503e06dcfb12ad60753e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Ska=C5=82ka?= Date: Mon, 4 Mar 2024 11:48:39 +0100 Subject: [PATCH 050/113] Fix resuming video after regaining internet connection --- src/components/VideoPlayer/BaseVideoPlayer.js | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/components/VideoPlayer/BaseVideoPlayer.js b/src/components/VideoPlayer/BaseVideoPlayer.js index 360095ec7eb4..8efc6604dfa1 100644 --- a/src/components/VideoPlayer/BaseVideoPlayer.js +++ b/src/components/VideoPlayer/BaseVideoPlayer.js @@ -8,6 +8,7 @@ import Hoverable from '@components/Hoverable'; import PressableWithoutFeedback from '@components/Pressable/PressableWithoutFeedback'; import {usePlaybackContext} from '@components/VideoPlayerContexts/PlaybackContext'; import VideoPopoverMenu from '@components/VideoPopoverMenu'; +import useNetwork from '@hooks/useNetwork'; import useThemeStyles from '@hooks/useThemeStyles'; import addEncryptedAuthTokenToURL from '@libs/addEncryptedAuthTokenToURL'; import * as Browser from '@libs/Browser'; @@ -44,6 +45,7 @@ function BaseVideoPlayer({ const styles = useThemeStyles(); const {pauseVideo, playVideo, currentlyPlayingURL, updateSharedElements, sharedElement, originalParent, shareVideoPlayerElements, currentVideoPlayerRef, updateCurrentlyPlayingURL} = usePlaybackContext(); + const {isOffline} = useNetwork(); const [duration, setDuration] = useState(videoDuration * 1000); const [position, setPosition] = useState(0); const [isPlaying, setIsPlaying] = useState(false); @@ -214,13 +216,20 @@ function BaseVideoPlayer({ style={[styles.w100, styles.h100, videoPlayerStyle]} videoStyle={[styles.w100, styles.h100, videoStyle]} source={{ - uri: sourceURL, + // if video is loading and is offline, we want to change uri to null to + // reset the video player after connection is back + uri: !isLoading || (isLoading && !isOffline) ? sourceURL : null, }} shouldPlay={false} useNativeControls={false} resizeMode={resizeMode} isLooping={isLooping} - onReadyForDisplay={onVideoLoaded} + onReadyForDisplay={(e) => { + if (isCurrentlyURLSet) { + playVideo(); + } + onVideoLoaded(e); + }} onPlaybackStatusUpdate={handlePlaybackStatusUpdate} onFullscreenUpdate={handleFullscreenUpdate} /> From d104cb08a10e2404101752e15431128cb88ee083 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Ska=C5=82ka?= Date: Mon, 4 Mar 2024 11:54:07 +0100 Subject: [PATCH 051/113] Fix playing video in preview when uploading --- src/components/VideoPlayer/BaseVideoPlayer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/VideoPlayer/BaseVideoPlayer.js b/src/components/VideoPlayer/BaseVideoPlayer.js index 8efc6604dfa1..16a210a398b4 100644 --- a/src/components/VideoPlayer/BaseVideoPlayer.js +++ b/src/components/VideoPlayer/BaseVideoPlayer.js @@ -225,7 +225,7 @@ function BaseVideoPlayer({ resizeMode={resizeMode} isLooping={isLooping} onReadyForDisplay={(e) => { - if (isCurrentlyURLSet) { + if (isCurrentlyURLSet && !isUploading) { playVideo(); } onVideoLoaded(e); From 6aa6a28e1e7c446442aea364ca06caf24bd217d4 Mon Sep 17 00:00:00 2001 From: Jakub Butkiewicz Date: Tue, 5 Mar 2024 17:30:44 +0100 Subject: [PATCH 052/113] fix: remove unnecessary field from PolicyTag type --- src/types/onyx/PolicyTag.ts | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/types/onyx/PolicyTag.ts b/src/types/onyx/PolicyTag.ts index b2873538cb4d..8c509c66825b 100644 --- a/src/types/onyx/PolicyTag.ts +++ b/src/types/onyx/PolicyTag.ts @@ -8,12 +8,6 @@ type PolicyTag = { /** "General Ledger code" that corresponds to this tag in an accounting system. Similar to an ID. */ // eslint-disable-next-line @typescript-eslint/naming-convention 'GL Code'?: string; - - /** List of tags */ - tags: PolicyTags; - - /** Flag that determines if a tag is required */ - required: boolean; }; type PolicyTags = Record; From c90ce7e8d360788fa31be13fe94f31a123689a4f Mon Sep 17 00:00:00 2001 From: FitseTLT Date: Wed, 6 Mar 2024 18:23:50 +0300 Subject: [PATCH 053/113] add Pdf thumbnail --- src/components/ReceiptImage.tsx | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/components/ReceiptImage.tsx b/src/components/ReceiptImage.tsx index cd70413b7a2e..8dc82cb53aea 100644 --- a/src/components/ReceiptImage.tsx +++ b/src/components/ReceiptImage.tsx @@ -5,6 +5,7 @@ import type IconAsset from '@src/types/utils/IconAsset'; import EReceiptThumbnail from './EReceiptThumbnail'; import type {IconSize} from './EReceiptThumbnail'; import Image from './Image'; +import PDFThumbnail from './PDFThumbnail'; import ThumbnailImage from './ThumbnailImage'; type Style = {height: number; borderRadius: number; margin: number}; @@ -22,18 +23,30 @@ type ReceiptImageProps = ( /** Url of the receipt image */ source?: string; + + /** Whether it is a pdf thumbnail we are displaying */ + isPDFThumbnail?: boolean; } | { transactionID: string; isEReceipt?: boolean; isThumbnail: boolean; source?: string; + isPDFThumbnail?: boolean; + } + | { + transactionID?: string; + isEReceipt?: boolean; + isThumbnail?: boolean; + source: string; + isPDFThumbnail?: boolean; } | { transactionID?: string; isEReceipt?: boolean; isThumbnail?: boolean; source: string; + isPDFThumbnail: string; } ) & { /** Whether we should display the receipt with ThumbnailImage component */ @@ -60,6 +73,7 @@ type ReceiptImageProps = ( function ReceiptImage({ transactionID, + isPDFThumbnail = false, isThumbnail = false, shouldUseThumbnailImage = false, isEReceipt = false, @@ -73,6 +87,15 @@ function ReceiptImage({ }: ReceiptImageProps) { const styles = useThemeStyles(); + if (isPDFThumbnail) { + return ( + + ); + } + if (isEReceipt || isThumbnail) { const props = isThumbnail && {borderRadius: style?.borderRadius, fileExtension, isReceiptThumbnail: true}; return ( From 9f38e25e51dcfa089429348fa683bd78f7a4ea88 Mon Sep 17 00:00:00 2001 From: FitseTLT Date: Wed, 6 Mar 2024 19:07:12 +0300 Subject: [PATCH 054/113] updated to fixed color code depending on file extensions --- src/components/EReceiptThumbnail.tsx | 5 +++-- src/styles/utils/index.ts | 15 +++++++++++++++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/components/EReceiptThumbnail.tsx b/src/components/EReceiptThumbnail.tsx index f6d5beb7e24d..fb1209aa6fed 100644 --- a/src/components/EReceiptThumbnail.tsx +++ b/src/components/EReceiptThumbnail.tsx @@ -56,10 +56,11 @@ const backgroundImages = { function EReceiptThumbnail({transaction, borderRadius, fileExtension, isReceiptThumbnail = false, centerIconV = true, iconSize = 'large'}: EReceiptThumbnailProps) { const styles = useThemeStyles(); const StyleUtils = useStyleUtils(); + const colorCode = isReceiptThumbnail ? StyleUtils.getFileExtensionColorCode(fileExtension) : StyleUtils.getEReceiptColorCode(transaction); - const backgroundImage = useMemo(() => backgroundImages[StyleUtils.getEReceiptColorCode(transaction)], [StyleUtils, transaction]); + const backgroundImage = useMemo(() => backgroundImages[colorCode], [colorCode]); - const colorStyles = StyleUtils.getEReceiptColorStyles(StyleUtils.getEReceiptColorCode(transaction)); + const colorStyles = StyleUtils.getEReceiptColorStyles(colorCode); const primaryColor = colorStyles?.backgroundColor; const secondaryColor = colorStyles?.color; const transactionDetails = ReportUtils.getTransactionDetails(transaction); diff --git a/src/styles/utils/index.ts b/src/styles/utils/index.ts index 21af5398232f..5d3da627b411 100644 --- a/src/styles/utils/index.ts +++ b/src/styles/utils/index.ts @@ -287,6 +287,20 @@ function getEReceiptColorCode(transaction: OnyxEntry): EReceiptColo return eReceiptColors[colorHash]; } +/** + * Helper method to return eReceipt color code for Receipt Thumbnails + */ +function getFileExtensionColorCode(fileExtension?: string): EReceiptColorName { + switch (fileExtension) { + case CONST.IOU.FILE_TYPES.DOC: + return CONST.ERECEIPT_COLORS.PINK; + case CONST.IOU.FILE_TYPES.HTML: + return CONST.ERECEIPT_COLORS.TANGERINE; + default: + return CONST.ERECEIPT_COLORS.GREEN; + } +} + /** * Helper method to return eReceipt color styles */ @@ -1084,6 +1098,7 @@ const staticStyleUtils = { parseStyleFromFunction, getEReceiptColorStyles, getEReceiptColorCode, + getFileExtensionColorCode, getNavigationModalCardStyle, getCardStyles, getOpacityStyle, From 68c532703e40358c9e8ea387683ae6e54ccffa1b Mon Sep 17 00:00:00 2001 From: Jakub Butkiewicz Date: Thu, 7 Mar 2024 10:35:57 +0100 Subject: [PATCH 055/113] fix: changed prop name to tagListName --- src/components/TagPicker/index.tsx | 6 +++--- src/pages/EditRequestTagPage.js | 2 +- src/pages/iou/request/step/IOURequestStepTag.js | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/components/TagPicker/index.tsx b/src/components/TagPicker/index.tsx index f13c27beadc3..4998751309ee 100644 --- a/src/components/TagPicker/index.tsx +++ b/src/components/TagPicker/index.tsx @@ -36,7 +36,7 @@ type TagPickerProps = TagPickerOnyxProps & { selectedTag: string; /** The name of tag list we are getting tags for */ - tag: string; + tagListName: string; /** Callback to submit the selected tag */ onSubmit: () => void; @@ -54,13 +54,13 @@ type TagPickerProps = TagPickerOnyxProps & { tagIndex: number; }; -function TagPicker({selectedTag, tag, policyTags, tagIndex, policyRecentlyUsedTags, shouldShowDisabledAndSelectedOption = false, insets, onSubmit}: TagPickerProps) { +function TagPicker({selectedTag, tagListName, policyTags, tagIndex, policyRecentlyUsedTags, shouldShowDisabledAndSelectedOption = false, insets, onSubmit}: TagPickerProps) { const styles = useThemeStyles(); const StyleUtils = useStyleUtils(); const {translate} = useLocalize(); const [searchValue, setSearchValue] = useState(''); - const policyRecentlyUsedTagsList = useMemo(() => policyRecentlyUsedTags?.[tag] ?? [], [policyRecentlyUsedTags, tag]); + const policyRecentlyUsedTagsList = useMemo(() => policyRecentlyUsedTags?.[tagListName] ?? [], [policyRecentlyUsedTags, tagListName]); const policyTagList = PolicyUtils.getTagList(policyTags, tagIndex); const policyTagsCount = PolicyUtils.getCountOfEnabledTagsOfList(policyTagList.tags); const isTagsCountBelowThreshold = policyTagsCount < CONST.TAG_LIST_THRESHOLD; diff --git a/src/pages/EditRequestTagPage.js b/src/pages/EditRequestTagPage.js index 74643afa347f..762bb76a7f57 100644 --- a/src/pages/EditRequestTagPage.js +++ b/src/pages/EditRequestTagPage.js @@ -52,7 +52,7 @@ function EditRequestTagPage({defaultTag, policyID, tagName, tagIndex, onSubmit}) {translate('iou.tagSelection', {tagName: tagName || translate('common.tag')})} {translate('iou.tagSelection', {tagName: policyTagListName})} Date: Fri, 8 Mar 2024 13:39:53 +0100 Subject: [PATCH 056/113] fix: changed prop name --- Gemfile.lock | 16 +++++++++++----- ios/Podfile.lock | 2 +- src/languages/en.ts | 2 +- src/languages/es.ts | 2 +- src/languages/types.ts | 2 +- src/pages/EditRequestTagPage.js | 12 ++++++------ src/pages/iou/request/step/IOURequestStepTag.js | 2 +- 7 files changed, 22 insertions(+), 16 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index beb2c1762936..9a322c52606d 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -3,11 +3,12 @@ GEM specs: CFPropertyList (3.0.6) rexml - activesupport (7.0.8) + activesupport (6.1.7.7) concurrent-ruby (~> 1.0, >= 1.0.2) i18n (>= 1.6, < 2) minitest (>= 5.1) tzinfo (~> 2.0) + zeitwerk (~> 2.3) addressable (2.8.6) public_suffix (>= 2.0.2, < 6.0) algoliasearch (1.27.5) @@ -80,7 +81,8 @@ GEM declarative (0.0.20) digest-crc (0.6.5) rake (>= 12.0.0, < 14.0.0) - domain_name (0.6.20240107) + domain_name (0.5.20190701) + unf (>= 0.0.5, < 1.0.0) dotenv (2.8.1) emoji_regex (3.2.3) escape (0.0.4) @@ -187,11 +189,11 @@ GEM google-cloud-env (1.6.0) faraday (>= 0.17.3, < 3.0) google-cloud-errors (1.3.1) - google-cloud-storage (1.47.0) + google-cloud-storage (1.37.0) addressable (~> 2.8) digest-crc (~> 0.4) google-apis-iamcredentials_v1 (~> 0.1) - google-apis-storage_v1 (~> 0.31.0) + google-apis-storage_v1 (~> 0.1) google-cloud-core (~> 1.6) googleauth (>= 0.16.2, < 2.a) mini_mime (~> 1.0) @@ -260,6 +262,9 @@ GEM tzinfo (2.0.6) concurrent-ruby (~> 1.0) uber (0.1.0) + unf (0.1.4) + unf_ext + unf_ext (0.0.9.1) unicode-display_width (2.5.0) word_wrap (1.0.0) xcodeproj (1.23.0) @@ -273,6 +278,7 @@ GEM rouge (~> 2.0.7) xcpretty-travis-formatter (1.0.1) xcpretty (~> 0.2, >= 0.0.7) + zeitwerk (2.6.13) PLATFORMS arm64-darwin-21 @@ -292,4 +298,4 @@ RUBY VERSION ruby 2.6.10p210 BUNDLED WITH - 2.4.19 + 2.4.18 diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 491ec28b59e5..88c18ffedda0 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -2007,7 +2007,7 @@ SPEC CHECKSUMS: SocketRocket: f32cd54efbe0f095c4d7594881e52619cfe80b17 Turf: 13d1a92d969ca0311bbc26e8356cca178ce95da2 VisionCamera: 0a6794d1974aed5d653d0d0cb900493e2583e35a - Yoga: 13c8ef87792450193e117976337b8527b49e8c03 + Yoga: e64aa65de36c0832d04e8c7bd614396c77a80047 PODFILE CHECKSUM: 0ccbb4f2406893c6e9f266dc1e7470dcd72885d2 diff --git a/src/languages/en.ts b/src/languages/en.ts index 3575854ee7e2..505ba7a0f4f0 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -653,7 +653,7 @@ export default { `changed the distance to ${newDistanceToDisplay} (previously ${oldDistanceToDisplay}), which updated the amount to ${newAmountToDisplay} (previously ${oldAmountToDisplay})`, threadRequestReportName: ({formattedAmount, comment}: ThreadRequestReportNameParams) => `${formattedAmount} ${comment ? `for ${comment}` : 'request'}`, threadSentMoneyReportName: ({formattedAmount, comment}: ThreadSentMoneyReportNameParams) => `${formattedAmount} sent${comment ? ` for ${comment}` : ''}`, - tagSelection: ({tagName}: TagSelectionParams) => `Select a ${tagName} to add additional organization to your money.`, + tagSelection: ({tagListName}: TagSelectionParams) => `Select a ${tagListName} to add additional organization to your money.`, categorySelection: 'Select a category to add additional organization to your money.', error: { invalidCategoryLength: 'The length of the category chosen exceeds the maximum allowed (255). Please choose a different or shorten the category name first.', diff --git a/src/languages/es.ts b/src/languages/es.ts index 51a83e55fee2..2c876fb0b4dc 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -648,7 +648,7 @@ export default { `cambió la distancia a ${newDistanceToDisplay} (previamente ${oldDistanceToDisplay}), lo que cambió el importe a ${newAmountToDisplay} (previamente ${oldAmountToDisplay})`, threadRequestReportName: ({formattedAmount, comment}: ThreadRequestReportNameParams) => `${comment ? `${formattedAmount} para ${comment}` : `Solicitud de ${formattedAmount}`}`, threadSentMoneyReportName: ({formattedAmount, comment}: ThreadSentMoneyReportNameParams) => `${formattedAmount} enviado${comment ? ` para ${comment}` : ''}`, - tagSelection: ({tagName}: TagSelectionParams) => `Seleccione una ${tagName} para organizar mejor tu dinero.`, + tagSelection: ({tagListName}: TagSelectionParams) => `Seleccione una ${tagListName} para organizar mejor tu dinero.`, categorySelection: 'Seleccione una categoría para organizar mejor tu dinero.', error: { invalidCategoryLength: 'El largo de la categoría escogida excede el máximo permitido (255). Por favor, escoge otra categoría o acorta la categoría primero.', diff --git a/src/languages/types.ts b/src/languages/types.ts index 2bb05b614483..009e5b0796b3 100644 --- a/src/languages/types.ts +++ b/src/languages/types.ts @@ -210,7 +210,7 @@ type UpdatedTheDistanceParams = {newDistanceToDisplay: string; oldDistanceToDisp type FormattedMaxLengthParams = {formattedMaxLength: string}; -type TagSelectionParams = {tagName: string}; +type TagSelectionParams = {tagListName: string}; type WalletProgramParams = {walletProgram: string}; diff --git a/src/pages/EditRequestTagPage.js b/src/pages/EditRequestTagPage.js index 762bb76a7f57..3eda5184263a 100644 --- a/src/pages/EditRequestTagPage.js +++ b/src/pages/EditRequestTagPage.js @@ -16,7 +16,7 @@ const propTypes = { policyID: PropTypes.string.isRequired, /** The tag name to which the default tag belongs to */ - tagName: PropTypes.string, + tagListName: PropTypes.string, /** The index of a tag list */ tagIndex: PropTypes.number.isRequired, @@ -26,10 +26,10 @@ const propTypes = { }; const defaultProps = { - tagName: '', + tagListName: '', }; -function EditRequestTagPage({defaultTag, policyID, tagName, tagIndex, onSubmit}) { +function EditRequestTagPage({defaultTag, policyID, tagListName, tagIndex, onSubmit}) { const styles = useThemeStyles(); const {translate} = useLocalize(); @@ -46,13 +46,13 @@ function EditRequestTagPage({defaultTag, policyID, tagName, tagIndex, onSubmit}) {({insets}) => ( <> - {translate('iou.tagSelection', {tagName: tagName || translate('common.tag')})} + {translate('iou.tagSelection', {tagListName: tagListName || translate('common.tag')})} {({insets}) => ( <> - {translate('iou.tagSelection', {tagName: policyTagListName})} + {translate('iou.tagSelection', {tagListName: policyTagListName})} Date: Fri, 8 Mar 2024 13:41:27 +0100 Subject: [PATCH 057/113] fix: reverted unnecessary changes --- Gemfile.lock | 16 +++++----------- ios/Podfile.lock | 2 +- 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 9a322c52606d..beb2c1762936 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -3,12 +3,11 @@ GEM specs: CFPropertyList (3.0.6) rexml - activesupport (6.1.7.7) + activesupport (7.0.8) concurrent-ruby (~> 1.0, >= 1.0.2) i18n (>= 1.6, < 2) minitest (>= 5.1) tzinfo (~> 2.0) - zeitwerk (~> 2.3) addressable (2.8.6) public_suffix (>= 2.0.2, < 6.0) algoliasearch (1.27.5) @@ -81,8 +80,7 @@ GEM declarative (0.0.20) digest-crc (0.6.5) rake (>= 12.0.0, < 14.0.0) - domain_name (0.5.20190701) - unf (>= 0.0.5, < 1.0.0) + domain_name (0.6.20240107) dotenv (2.8.1) emoji_regex (3.2.3) escape (0.0.4) @@ -189,11 +187,11 @@ GEM google-cloud-env (1.6.0) faraday (>= 0.17.3, < 3.0) google-cloud-errors (1.3.1) - google-cloud-storage (1.37.0) + google-cloud-storage (1.47.0) addressable (~> 2.8) digest-crc (~> 0.4) google-apis-iamcredentials_v1 (~> 0.1) - google-apis-storage_v1 (~> 0.1) + google-apis-storage_v1 (~> 0.31.0) google-cloud-core (~> 1.6) googleauth (>= 0.16.2, < 2.a) mini_mime (~> 1.0) @@ -262,9 +260,6 @@ GEM tzinfo (2.0.6) concurrent-ruby (~> 1.0) uber (0.1.0) - unf (0.1.4) - unf_ext - unf_ext (0.0.9.1) unicode-display_width (2.5.0) word_wrap (1.0.0) xcodeproj (1.23.0) @@ -278,7 +273,6 @@ GEM rouge (~> 2.0.7) xcpretty-travis-formatter (1.0.1) xcpretty (~> 0.2, >= 0.0.7) - zeitwerk (2.6.13) PLATFORMS arm64-darwin-21 @@ -298,4 +292,4 @@ RUBY VERSION ruby 2.6.10p210 BUNDLED WITH - 2.4.18 + 2.4.19 diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 88c18ffedda0..491ec28b59e5 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -2007,7 +2007,7 @@ SPEC CHECKSUMS: SocketRocket: f32cd54efbe0f095c4d7594881e52619cfe80b17 Turf: 13d1a92d969ca0311bbc26e8356cca178ce95da2 VisionCamera: 0a6794d1974aed5d653d0d0cb900493e2583e35a - Yoga: e64aa65de36c0832d04e8c7bd614396c77a80047 + Yoga: 13c8ef87792450193e117976337b8527b49e8c03 PODFILE CHECKSUM: 0ccbb4f2406893c6e9f266dc1e7470dcd72885d2 From e05df18496b72f40c2b39f4699d5a2c8b2f7d73f Mon Sep 17 00:00:00 2001 From: FitseTLT Date: Fri, 8 Mar 2024 15:43:56 +0300 Subject: [PATCH 058/113] remove unnecessary condition --- src/components/AttachmentModal.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/AttachmentModal.tsx b/src/components/AttachmentModal.tsx index 459252e1ddd2..eed40d75387e 100755 --- a/src/components/AttachmentModal.tsx +++ b/src/components/AttachmentModal.tsx @@ -540,7 +540,7 @@ function AttachmentModal({ setDownloadButtonVisibility={setDownloadButtonVisibility} /> ) : ( - (!!sourceForAttachmentView || TransactionUtils.isFetchingWaypointsFromServer(transaction)) && + !!sourceForAttachmentView && shouldLoadAttachment && !isLoading && !shouldShowNotFoundPage && ( From b6fd6f47574589ddc067155a56964d81c0180b7e Mon Sep 17 00:00:00 2001 From: FitseTLT Date: Fri, 8 Mar 2024 16:46:46 +0300 Subject: [PATCH 059/113] final refactor changes --- src/components/MoneyRequestConfirmationList.js | 1 - .../MoneyTemporaryForRefactorRequestConfirmationList.js | 3 +-- src/components/ReceiptImage.tsx | 2 +- .../MoneyRequestPreview/MoneyRequestPreviewContent.tsx | 2 +- src/components/ReportActionItem/ReportActionItemImage.tsx | 4 +--- src/components/ReportActionItem/ReportPreview.tsx | 2 +- 6 files changed, 5 insertions(+), 9 deletions(-) diff --git a/src/components/MoneyRequestConfirmationList.js b/src/components/MoneyRequestConfirmationList.js index 1f6868a31d00..60a9ad51db56 100755 --- a/src/components/MoneyRequestConfirmationList.js +++ b/src/components/MoneyRequestConfirmationList.js @@ -629,7 +629,6 @@ function MoneyRequestConfirmationList(props) { // So if we have a thumbnail, it means we're retrieving the image from the server isAuthTokenRequired={!_.isEmpty(receiptThumbnail)} fileExtension={fileExtension} - transactionID={props.transactionID || (props.transaction && props.transaction.transactionID)} /> ) : ( // 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 c22889ad2077..99eb3b83db75 100755 --- a/src/components/MoneyTemporaryForRefactorRequestConfirmationList.js +++ b/src/components/MoneyTemporaryForRefactorRequestConfirmationList.js @@ -909,11 +909,10 @@ 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)} - transactionID={transaction && transaction.transactionID} fileExtension={fileExtension} /> ), - [isLocalFile, receiptFilename, receiptImage, styles.moneyRequestImage, isAttachmentInvalid, isThumbnail, receiptThumbnail, transaction, fileExtension], + [isLocalFile, receiptFilename, receiptImage, styles.moneyRequestImage, isAttachmentInvalid, isThumbnail, receiptThumbnail, fileExtension], ); return ( diff --git a/src/components/ReceiptImage.tsx b/src/components/ReceiptImage.tsx index 8dc82cb53aea..08892f11b021 100644 --- a/src/components/ReceiptImage.tsx +++ b/src/components/ReceiptImage.tsx @@ -28,7 +28,7 @@ type ReceiptImageProps = ( isPDFThumbnail?: boolean; } | { - transactionID: string; + transactionID?: string; isEReceipt?: boolean; isThumbnail: boolean; source?: string; diff --git a/src/components/ReportActionItem/MoneyRequestPreview/MoneyRequestPreviewContent.tsx b/src/components/ReportActionItem/MoneyRequestPreview/MoneyRequestPreviewContent.tsx index 2ff0170809e3..a5fb03a22dca 100644 --- a/src/components/ReportActionItem/MoneyRequestPreview/MoneyRequestPreviewContent.tsx +++ b/src/components/ReportActionItem/MoneyRequestPreview/MoneyRequestPreviewContent.tsx @@ -114,7 +114,7 @@ function MoneyRequestPreviewContent({ merchantOrDescription = description || ''; } - const receiptImages = hasReceipt ? [{...ReceiptUtils.getThumbnailAndImageURIs(transaction), transaction}] : []; + const receiptImages = hasReceipt ? [{...ReceiptUtils.getThumbnailAndImageURIs(transaction)}] : []; const hasPendingWaypoints = transaction?.pendingFields?.waypoints; const showMapAsImage = isDistanceRequest && hasPendingWaypoints; diff --git a/src/components/ReportActionItem/ReportActionItemImage.tsx b/src/components/ReportActionItem/ReportActionItemImage.tsx index 8c9cbb4a4e64..0ea3c0694861 100644 --- a/src/components/ReportActionItem/ReportActionItemImage.tsx +++ b/src/components/ReportActionItem/ReportActionItemImage.tsx @@ -90,9 +90,7 @@ function ReportActionItemImage({ } else { propsObj = { isThumbnail, - ...(isThumbnail && {iconSize: isSingleImage ? 'medium' : ('small' as IconSize)}), - fileExtension, - transactionID: transaction?.transactionID, + ...(isThumbnail && {iconSize: isSingleImage ? 'medium' : ('small' as IconSize), fileExtension}), source: thumbnail ?? image ?? '', }; } diff --git a/src/components/ReportActionItem/ReportPreview.tsx b/src/components/ReportActionItem/ReportPreview.tsx index d46e0a6436b2..7e29fd8ea203 100644 --- a/src/components/ReportActionItem/ReportPreview.tsx +++ b/src/components/ReportActionItem/ReportPreview.tsx @@ -139,7 +139,7 @@ function ReportPreview({ const isScanning = hasReceipts && areAllRequestsBeingSmartScanned; const hasErrors = hasMissingSmartscanFields || (canUseViolations && ReportUtils.hasViolations(iouReportID, transactionViolations)); const lastThreeTransactionsWithReceipts = transactionsWithReceipts.slice(-3); - const lastThreeReceipts = lastThreeTransactionsWithReceipts.map((transaction) => ({...ReceiptUtils.getThumbnailAndImageURIs(transaction), transaction})); + const lastThreeReceipts = lastThreeTransactionsWithReceipts.map((transaction) => ({...ReceiptUtils.getThumbnailAndImageURIs(transaction)})); let formattedMerchant = numberOfRequests === 1 && hasReceipts ? TransactionUtils.getMerchant(transactionsWithReceipts[0]) : null; if (TransactionUtils.isPartialMerchant(formattedMerchant ?? '')) { formattedMerchant = null; From 4d181211394923d2f8e30c0995c6c3e9527ddf6d Mon Sep 17 00:00:00 2001 From: FitseTLT Date: Fri, 8 Mar 2024 17:12:23 +0300 Subject: [PATCH 060/113] minor fix --- .../MoneyRequestPreview/MoneyRequestPreviewContent.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/ReportActionItem/MoneyRequestPreview/MoneyRequestPreviewContent.tsx b/src/components/ReportActionItem/MoneyRequestPreview/MoneyRequestPreviewContent.tsx index a5fb03a22dca..8577c9fa5f97 100644 --- a/src/components/ReportActionItem/MoneyRequestPreview/MoneyRequestPreviewContent.tsx +++ b/src/components/ReportActionItem/MoneyRequestPreview/MoneyRequestPreviewContent.tsx @@ -114,7 +114,7 @@ function MoneyRequestPreviewContent({ merchantOrDescription = description || ''; } - const receiptImages = hasReceipt ? [{...ReceiptUtils.getThumbnailAndImageURIs(transaction)}] : []; + const receiptImages = hasReceipt ? [ReceiptUtils.getThumbnailAndImageURIs(transaction)] : []; const hasPendingWaypoints = transaction?.pendingFields?.waypoints; const showMapAsImage = isDistanceRequest && hasPendingWaypoints; From aa290ff57fe0047371d79a3aa94392412f59290b Mon Sep 17 00:00:00 2001 From: FitseTLT Date: Fri, 8 Mar 2024 17:14:31 +0300 Subject: [PATCH 061/113] minor fix --- src/components/ReportActionItem/ReportPreview.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/ReportActionItem/ReportPreview.tsx b/src/components/ReportActionItem/ReportPreview.tsx index 7e29fd8ea203..f6ffd54249fb 100644 --- a/src/components/ReportActionItem/ReportPreview.tsx +++ b/src/components/ReportActionItem/ReportPreview.tsx @@ -139,7 +139,7 @@ function ReportPreview({ const isScanning = hasReceipts && areAllRequestsBeingSmartScanned; const hasErrors = hasMissingSmartscanFields || (canUseViolations && ReportUtils.hasViolations(iouReportID, transactionViolations)); const lastThreeTransactionsWithReceipts = transactionsWithReceipts.slice(-3); - const lastThreeReceipts = lastThreeTransactionsWithReceipts.map((transaction) => ({...ReceiptUtils.getThumbnailAndImageURIs(transaction)})); + const lastThreeReceipts = lastThreeTransactionsWithReceipts.map((transaction) => ReceiptUtils.getThumbnailAndImageURIs(transaction)); let formattedMerchant = numberOfRequests === 1 && hasReceipts ? TransactionUtils.getMerchant(transactionsWithReceipts[0]) : null; if (TransactionUtils.isPartialMerchant(formattedMerchant ?? '')) { formattedMerchant = null; From b6a111a9ff3d05b60ba1f1d2334e5895fbb8c375 Mon Sep 17 00:00:00 2001 From: FitseTLT Date: Fri, 8 Mar 2024 17:15:14 +0300 Subject: [PATCH 062/113] minor --- src/components/ReportActionItem/ReportPreview.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/ReportActionItem/ReportPreview.tsx b/src/components/ReportActionItem/ReportPreview.tsx index f6ffd54249fb..381302489699 100644 --- a/src/components/ReportActionItem/ReportPreview.tsx +++ b/src/components/ReportActionItem/ReportPreview.tsx @@ -140,6 +140,7 @@ function ReportPreview({ const hasErrors = hasMissingSmartscanFields || (canUseViolations && ReportUtils.hasViolations(iouReportID, transactionViolations)); const lastThreeTransactionsWithReceipts = transactionsWithReceipts.slice(-3); const lastThreeReceipts = lastThreeTransactionsWithReceipts.map((transaction) => ReceiptUtils.getThumbnailAndImageURIs(transaction)); + let formattedMerchant = numberOfRequests === 1 && hasReceipts ? TransactionUtils.getMerchant(transactionsWithReceipts[0]) : null; if (TransactionUtils.isPartialMerchant(formattedMerchant ?? '')) { formattedMerchant = null; From f726b6b0e192f5b3e8ffdf3e76cf8e648122468a Mon Sep 17 00:00:00 2001 From: Tomasz Lesniakiewicz Date: Mon, 11 Mar 2024 13:24:30 +0100 Subject: [PATCH 063/113] chore: run prettier --- src/pages/home/sidebar/SidebarLinksData.js | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/pages/home/sidebar/SidebarLinksData.js b/src/pages/home/sidebar/SidebarLinksData.js index 613402e04d35..eac46480152d 100644 --- a/src/pages/home/sidebar/SidebarLinksData.js +++ b/src/pages/home/sidebar/SidebarLinksData.js @@ -151,8 +151,21 @@ function SidebarLinksData({ const isLoading = isLoadingApp; const optionItemsMemoized = useMemo( - () => SidebarUtils.getOrderedReportIDs(null, chatReports, betas, policies, priorityMode, allReportActions, transactionViolations, activeWorkspaceID, policyMemberAccountIDs), - [chatReports, betas, policies, priorityMode, allReportActions, transactionViolations, activeWorkspaceID, policyMemberAccountIDs], + () => + SidebarUtils.getOrderedReportIDs( + null, + chatReports, + betas, + policies, + priorityMode, + allReportActions, + transactionViolations, + activeWorkspaceID, + policyMemberAccountIDs, + reportIDsWithErrors, + canUseViolations, + ), + [chatReports, betas, policies, priorityMode, allReportActions, transactionViolations, activeWorkspaceID, policyMemberAccountIDs, reportIDsWithErrors, canUseViolations], ); const optionListItems = useMemo(() => { From 7c1cf629aa902962e3f738c9f84669135c03afac Mon Sep 17 00:00:00 2001 From: FitseTLT Date: Mon, 11 Mar 2024 20:55:23 +0300 Subject: [PATCH 064/113] fix typescript --- src/pages/TransactionReceiptPage.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/TransactionReceiptPage.tsx b/src/pages/TransactionReceiptPage.tsx index 8db9e05a5139..f6f2c90e5d2c 100644 --- a/src/pages/TransactionReceiptPage.tsx +++ b/src/pages/TransactionReceiptPage.tsx @@ -28,7 +28,7 @@ type TransactionReceiptProps = TransactionReceiptOnyxProps & StackScreenProps Date: Tue, 12 Mar 2024 11:09:11 +0100 Subject: [PATCH 065/113] fix: adjust descriptions --- src/components/TagPicker/index.tsx | 2 +- src/pages/EditRequestTagPage.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/TagPicker/index.tsx b/src/components/TagPicker/index.tsx index 4998751309ee..f1700205f487 100644 --- a/src/components/TagPicker/index.tsx +++ b/src/components/TagPicker/index.tsx @@ -19,7 +19,7 @@ type SelectedTagOption = { }; type TagPickerOnyxProps = { - /** Collection of tags attached to a policy */ + /** Collection of tag list on a policy */ policyTags: OnyxEntry; /** List of recently used tags */ diff --git a/src/pages/EditRequestTagPage.js b/src/pages/EditRequestTagPage.js index 3eda5184263a..ca5bdc05530d 100644 --- a/src/pages/EditRequestTagPage.js +++ b/src/pages/EditRequestTagPage.js @@ -15,7 +15,7 @@ const propTypes = { /** The policyID we are getting tags for */ policyID: PropTypes.string.isRequired, - /** The tag name to which the default tag belongs to */ + /** The tag list name to which the default tag belongs to */ tagListName: PropTypes.string, /** The index of a tag list */ From 576ac31863d134f32530a81931dfb4516fea62a9 Mon Sep 17 00:00:00 2001 From: Jakub Butkiewicz Date: Tue, 12 Mar 2024 15:43:00 +0100 Subject: [PATCH 066/113] fix: adjusted tagIndex prop comment --- src/components/TagPicker/index.tsx | 2 +- src/pages/EditRequestPage.js | 2 +- src/pages/EditRequestTagPage.js | 2 +- src/pages/iou/request/step/IOURequestStepRoutePropTypes.js | 3 +++ 4 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/components/TagPicker/index.tsx b/src/components/TagPicker/index.tsx index f1700205f487..39574299063e 100644 --- a/src/components/TagPicker/index.tsx +++ b/src/components/TagPicker/index.tsx @@ -50,7 +50,7 @@ type TagPickerProps = TagPickerOnyxProps & { /** Should show the selected option that is disabled? */ shouldShowDisabledAndSelectedOption?: boolean; - /** The index of a tag list */ + /** Indicates which tag list index was selected */ tagIndex: number; }; diff --git a/src/pages/EditRequestPage.js b/src/pages/EditRequestPage.js index de17d16a7c38..ebe4c886d6c5 100644 --- a/src/pages/EditRequestPage.js +++ b/src/pages/EditRequestPage.js @@ -38,7 +38,7 @@ const propTypes = { /** reportID for the "transaction thread" */ threadReportID: PropTypes.string, - /** The index of a tag list */ + /** Indicates which tag list index was selected */ tagIndex: PropTypes.string, }), }).isRequired, diff --git a/src/pages/EditRequestTagPage.js b/src/pages/EditRequestTagPage.js index ca5bdc05530d..fe1526af1973 100644 --- a/src/pages/EditRequestTagPage.js +++ b/src/pages/EditRequestTagPage.js @@ -18,7 +18,7 @@ const propTypes = { /** The tag list name to which the default tag belongs to */ tagListName: PropTypes.string, - /** The index of a tag list */ + /** Indicates which tag list index was selected */ tagIndex: PropTypes.number.isRequired, /** Callback to fire when the Save button is pressed */ diff --git a/src/pages/iou/request/step/IOURequestStepRoutePropTypes.js b/src/pages/iou/request/step/IOURequestStepRoutePropTypes.js index dbcf83bda62a..8b191fa0b58e 100644 --- a/src/pages/iou/request/step/IOURequestStepRoutePropTypes.js +++ b/src/pages/iou/request/step/IOURequestStepRoutePropTypes.js @@ -22,5 +22,8 @@ export default PropTypes.shape({ /** 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, }), }); From f5e43db353de3945a09744dbb0a5a5f6618b7c4b Mon Sep 17 00:00:00 2001 From: Jakub Butkiewicz Date: Wed, 13 Mar 2024 12:53:16 +0100 Subject: [PATCH 067/113] fix: rerun pipeline --- src/components/TagPicker/index.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/TagPicker/index.tsx b/src/components/TagPicker/index.tsx index 39574299063e..8d9044e603ad 100644 --- a/src/components/TagPicker/index.tsx +++ b/src/components/TagPicker/index.tsx @@ -59,6 +59,7 @@ function TagPicker({selectedTag, tagListName, policyTags, tagIndex, policyRecent const StyleUtils = useStyleUtils(); const {translate} = useLocalize(); const [searchValue, setSearchValue] = useState(''); + console.log('hello'); const policyRecentlyUsedTagsList = useMemo(() => policyRecentlyUsedTags?.[tagListName] ?? [], [policyRecentlyUsedTags, tagListName]); const policyTagList = PolicyUtils.getTagList(policyTags, tagIndex); From c6e10e43fbd805efe6711d5245138b85d3643bb3 Mon Sep 17 00:00:00 2001 From: Jakub Butkiewicz Date: Wed, 13 Mar 2024 12:53:37 +0100 Subject: [PATCH 068/113] fix: remove log --- src/components/TagPicker/index.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/TagPicker/index.tsx b/src/components/TagPicker/index.tsx index 8d9044e603ad..39574299063e 100644 --- a/src/components/TagPicker/index.tsx +++ b/src/components/TagPicker/index.tsx @@ -59,7 +59,6 @@ function TagPicker({selectedTag, tagListName, policyTags, tagIndex, policyRecent const StyleUtils = useStyleUtils(); const {translate} = useLocalize(); const [searchValue, setSearchValue] = useState(''); - console.log('hello'); const policyRecentlyUsedTagsList = useMemo(() => policyRecentlyUsedTags?.[tagListName] ?? [], [policyRecentlyUsedTags, tagListName]); const policyTagList = PolicyUtils.getTagList(policyTags, tagIndex); From 3a4760d7284f953a12fe99a4c1b506bb9d070881 Mon Sep 17 00:00:00 2001 From: FitseTLT Date: Thu, 14 Mar 2024 22:54:14 +0300 Subject: [PATCH 069/113] fix type --- src/components/MoneyRequestConfirmationList.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/MoneyRequestConfirmationList.tsx b/src/components/MoneyRequestConfirmationList.tsx index 6d41f8da8af2..e69a15d7eb5c 100755 --- a/src/components/MoneyRequestConfirmationList.tsx +++ b/src/components/MoneyRequestConfirmationList.tsx @@ -626,7 +626,7 @@ function MoneyRequestConfirmationList({ Date: Thu, 14 Mar 2024 23:10:48 +0300 Subject: [PATCH 070/113] suppress eslint warning --- src/components/MoneyRequestConfirmationList.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/MoneyRequestConfirmationList.tsx b/src/components/MoneyRequestConfirmationList.tsx index e69a15d7eb5c..8a5886fe1f4e 100755 --- a/src/components/MoneyRequestConfirmationList.tsx +++ b/src/components/MoneyRequestConfirmationList.tsx @@ -621,7 +621,7 @@ function MoneyRequestConfirmationList({ )} - + {/* eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing */} {receiptImage || receiptThumbnail ? ( Date: Fri, 15 Mar 2024 11:59:09 +0100 Subject: [PATCH 071/113] Remove unnecessary changes --- src/components/VideoPlayer/BaseVideoPlayer.js | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/components/VideoPlayer/BaseVideoPlayer.js b/src/components/VideoPlayer/BaseVideoPlayer.js index 17a4ba3548db..bff3f43805e9 100644 --- a/src/components/VideoPlayer/BaseVideoPlayer.js +++ b/src/components/VideoPlayer/BaseVideoPlayer.js @@ -257,12 +257,7 @@ function BaseVideoPlayer({ useNativeControls={false} resizeMode={resizeMode} isLooping={isLooping} - onReadyForDisplay={(e) => { - if (isCurrentlyURLSet && !isUploading) { - playVideo(); - } - onVideoLoaded(e); - }} + onReadyForDisplay={onVideoLoaded} onPlaybackStatusUpdate={handlePlaybackStatusUpdate} onFullscreenUpdate={handleFullscreenUpdate} /> From c32c8fb068b3f8d039f069d5e417c7955c5c26a5 Mon Sep 17 00:00:00 2001 From: FitseTLT Date: Tue, 19 Mar 2024 22:21:13 +0300 Subject: [PATCH 072/113] updated label font size and line heights --- src/components/EReceiptThumbnail.tsx | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/components/EReceiptThumbnail.tsx b/src/components/EReceiptThumbnail.tsx index fc4e67441994..e0f88470f460 100644 --- a/src/components/EReceiptThumbnail.tsx +++ b/src/components/EReceiptThumbnail.tsx @@ -70,15 +70,21 @@ function EReceiptThumbnail({transaction, borderRadius, fileExtension, isReceiptT let receiptIconWidth: number = variables.eReceiptIconWidth; let receiptIconHeight: number = variables.eReceiptIconHeight; let receiptMCCSize: number = variables.eReceiptMCCHeightWidth; + let labelFontSize: number = variables.fontSizeNormal; + let labelLineHeight: number = variables.lineHeightLarge; if (iconSize === 'small') { receiptIconWidth = variables.eReceiptIconWidthSmall; receiptIconHeight = variables.eReceiptIconHeightSmall; receiptMCCSize = variables.eReceiptMCCHeightWidthSmall; + labelFontSize = variables.fontSizeExtraSmall; + labelLineHeight = variables.lineHeightXSmall; } else if (iconSize === 'medium') { receiptIconWidth = variables.eReceiptIconWidthMedium; receiptIconHeight = variables.eReceiptIconHeightMedium; receiptMCCSize = variables.eReceiptMCCHeightWidthMedium; + labelFontSize = variables.fontSizeLabel; + labelLineHeight = variables.lineHeightNormal; } return ( @@ -107,7 +113,16 @@ function EReceiptThumbnail({transaction, borderRadius, fileExtension, isReceiptT additionalStyles={[styles.fullScreen]} /> {isReceiptThumbnail && fileExtension && ( - {fileExtension.toUpperCase()} + + {fileExtension.toUpperCase()} + )} {MCCIcon && !isReceiptThumbnail ? ( Date: Wed, 20 Mar 2024 09:52:52 +0100 Subject: [PATCH 073/113] Readd video starting after video is ready to play --- src/components/VideoPlayer/BaseVideoPlayer.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/components/VideoPlayer/BaseVideoPlayer.js b/src/components/VideoPlayer/BaseVideoPlayer.js index bff3f43805e9..17a4ba3548db 100644 --- a/src/components/VideoPlayer/BaseVideoPlayer.js +++ b/src/components/VideoPlayer/BaseVideoPlayer.js @@ -257,7 +257,12 @@ function BaseVideoPlayer({ useNativeControls={false} resizeMode={resizeMode} isLooping={isLooping} - onReadyForDisplay={onVideoLoaded} + onReadyForDisplay={(e) => { + if (isCurrentlyURLSet && !isUploading) { + playVideo(); + } + onVideoLoaded(e); + }} onPlaybackStatusUpdate={handlePlaybackStatusUpdate} onFullscreenUpdate={handleFullscreenUpdate} /> From 0f93e35c4431e734c9358e588e33437215e9399f Mon Sep 17 00:00:00 2001 From: Tomasz Lesniakiewicz Date: Thu, 21 Mar 2024 12:56:37 +0100 Subject: [PATCH 074/113] feat: adjust to recent main --- src/pages/home/sidebar/SidebarLinksData.js | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/src/pages/home/sidebar/SidebarLinksData.js b/src/pages/home/sidebar/SidebarLinksData.js index 1bb14b7183e0..0b01df2c93ab 100644 --- a/src/pages/home/sidebar/SidebarLinksData.js +++ b/src/pages/home/sidebar/SidebarLinksData.js @@ -149,24 +149,12 @@ function SidebarLinksData({ transactionViolations, activeWorkspaceID, policyMemberAccountIDs, - reportIDsWithErrors, - canUseViolations, ), - [chatReports, betas, policies, priorityMode, allReportActions, transactionViolations, activeWorkspaceID, policyMemberAccountIDs, reportIDsWithErrors, canUseViolations], + [chatReports, betas, policies, priorityMode, allReportActions, transactionViolations, activeWorkspaceID, policyMemberAccountIDs], ); const optionListItems = useMemo(() => { - const reportIDs = SidebarUtils.getOrderedReportIDs( - null, - chatReports, - betas, - policies, - priorityMode, - allReportActions, - transactionViolations, - activeWorkspaceID, - policyMemberAccountIDs, - ); + const reportIDs = optionItemsMemoized; if (deepEqual(reportIDsRef.current, reportIDs)) { return reportIDsRef.current; @@ -179,7 +167,7 @@ function SidebarLinksData({ reportIDsRef.current = reportIDs; } return reportIDsRef.current || []; - }, [chatReports, betas, policies, priorityMode, allReportActions, transactionViolations, activeWorkspaceID, policyMemberAccountIDs, isLoading, network.isOffline, prevPriorityMode]); + }, [optionItemsMemoized, isLoading, network.isOffline, prevPriorityMode]); // We need to make sure the current report is in the list of reports, but we do not want // to have to re-generate the list every time the currentReportID changes. To do that From d787f1b55aac5a2b1635870ff8f405130d3492e3 Mon Sep 17 00:00:00 2001 From: Tomasz Lesniakiewicz Date: Thu, 21 Mar 2024 13:25:20 +0100 Subject: [PATCH 075/113] chore: lint fix --- src/pages/home/sidebar/SidebarLinksData.js | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/src/pages/home/sidebar/SidebarLinksData.js b/src/pages/home/sidebar/SidebarLinksData.js index 0b01df2c93ab..c5749893d7fb 100644 --- a/src/pages/home/sidebar/SidebarLinksData.js +++ b/src/pages/home/sidebar/SidebarLinksData.js @@ -138,18 +138,7 @@ function SidebarLinksData({ const isLoading = isLoadingApp; const optionItemsMemoized = useMemo( - () => - SidebarUtils.getOrderedReportIDs( - null, - chatReports, - betas, - policies, - priorityMode, - allReportActions, - transactionViolations, - activeWorkspaceID, - policyMemberAccountIDs, - ), + () => SidebarUtils.getOrderedReportIDs(null, chatReports, betas, policies, priorityMode, allReportActions, transactionViolations, activeWorkspaceID, policyMemberAccountIDs), [chatReports, betas, policies, priorityMode, allReportActions, transactionViolations, activeWorkspaceID, policyMemberAccountIDs], ); @@ -167,7 +156,7 @@ function SidebarLinksData({ reportIDsRef.current = reportIDs; } return reportIDsRef.current || []; - }, [optionItemsMemoized, isLoading, network.isOffline, prevPriorityMode]); + }, [optionItemsMemoized, priorityMode, isLoading, network.isOffline, prevPriorityMode]); // We need to make sure the current report is in the list of reports, but we do not want // to have to re-generate the list every time the currentReportID changes. To do that From 9f2ee85b6aceb581a317109cc962ca6c8f11daba Mon Sep 17 00:00:00 2001 From: Tomasz Lesniakiewicz Date: Thu, 21 Mar 2024 15:31:54 +0100 Subject: [PATCH 076/113] chore: update comment --- src/pages/home/sidebar/SidebarLinksData.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/pages/home/sidebar/SidebarLinksData.js b/src/pages/home/sidebar/SidebarLinksData.js index c5749893d7fb..8395c3d1e716 100644 --- a/src/pages/home/sidebar/SidebarLinksData.js +++ b/src/pages/home/sidebar/SidebarLinksData.js @@ -333,8 +333,7 @@ export default compose( )( /* While working on audit on the App Start App metric we noticed that by memoizing SidebarLinksData we can avoid 1 additional run of getOrderedReportIDs. - With that we can reduce app start up time by ~2.5s on heavy account. - After finding and fixing core issues with getOrderedReportIDs performance we might remove the memoization + With that we can reduce app start up time by ~2s on heavy account. More details - https://github.com/Expensify/App/issues/35234#issuecomment-1926914534 */ memo( From b692714b2fb99db63177e23ffd76c567f0e5d3ab Mon Sep 17 00:00:00 2001 From: Cong Pham Date: Tue, 27 Feb 2024 01:31:49 +0700 Subject: [PATCH 077/113] fix virtual viewport scroll on report screen --- src/components/EmojiPicker/EmojiPicker.js | 2 +- .../EmojiPickerMenu/useEmojiPickerMenu.js | 4 +- .../useViewportOffsetTop/index.native.ts | 7 + src/hooks/useViewportOffsetTop/index.ts | 51 ++++++ src/libs/actions/Modal.ts | 1 + src/pages/home/ReportScreen.tsx | 160 +++++++++--------- .../ReportActionCompose.tsx | 20 ++- src/pages/home/report/ReportFooter.tsx | 9 + 8 files changed, 172 insertions(+), 82 deletions(-) create mode 100644 src/hooks/useViewportOffsetTop/index.native.ts create mode 100644 src/hooks/useViewportOffsetTop/index.ts diff --git a/src/components/EmojiPicker/EmojiPicker.js b/src/components/EmojiPicker/EmojiPicker.js index 6bceaf570ccc..fd0fe786b632 100644 --- a/src/components/EmojiPicker/EmojiPicker.js +++ b/src/components/EmojiPicker/EmojiPicker.js @@ -176,7 +176,7 @@ const EmojiPicker = forwardRef((props, ref) => { onModalShow={focusEmojiSearchInput} onModalHide={onModalHide.current} hideModalContentWhileAnimating - shouldSetModalVisibility={false} + shouldSetModalVisibility={Browser.isMobile()} animationInTiming={1} animationOutTiming={1} anchorPosition={{ diff --git a/src/components/EmojiPicker/EmojiPickerMenu/useEmojiPickerMenu.js b/src/components/EmojiPicker/EmojiPickerMenu/useEmojiPickerMenu.js index 7caab5e6fb55..80521e04ddd9 100644 --- a/src/components/EmojiPicker/EmojiPickerMenu/useEmojiPickerMenu.js +++ b/src/components/EmojiPicker/EmojiPickerMenu/useEmojiPickerMenu.js @@ -22,9 +22,9 @@ const useEmojiPickerMenu = () => { const isListFiltered = allEmojis.length !== filteredEmojis.length; const {preferredLocale} = useLocalize(); const [preferredSkinTone] = usePreferredEmojiSkinTone(); - const {windowHeight} = useWindowDimensions(); + const {windowHeight} = useWindowDimensions(true); const StyleUtils = useStyleUtils(); - const listStyle = StyleUtils.getEmojiPickerListHeight(isListFiltered, windowHeight); + const listStyle = StyleUtils.getEmojiPickerListHeight(isListFiltered, windowHeight * 0.95); useEffect(() => { setFilteredEmojis(allEmojis); diff --git a/src/hooks/useViewportOffsetTop/index.native.ts b/src/hooks/useViewportOffsetTop/index.native.ts new file mode 100644 index 000000000000..b166c360dacc --- /dev/null +++ b/src/hooks/useViewportOffsetTop/index.native.ts @@ -0,0 +1,7 @@ +/** + * Native doesn't support DOM so default value is 0 + */ + +export default function useViewportOffsetTop(): number { + return 0; +} diff --git a/src/hooks/useViewportOffsetTop/index.ts b/src/hooks/useViewportOffsetTop/index.ts new file mode 100644 index 000000000000..7bb13f55c5ee --- /dev/null +++ b/src/hooks/useViewportOffsetTop/index.ts @@ -0,0 +1,51 @@ +import {useEffect, useRef, useState} from 'react'; +import addViewportResizeListener from '@libs/VisualViewport'; + +/** + * A hook that returns the offset of the top edge of the visual viewport + */ +export default function useViewportOffsetTop(shouldAdjustScrollView = false): number { + const [viewportOffsetTop, setViewportOffsetTop] = useState(0); + const initialHeight = useRef(window.visualViewport?.height ?? window.innerHeight).current; + const cachedDefaultOffsetTop = useRef(0); + useEffect(() => { + const updateOffsetTop = (event?: Event) => { + let targetOffsetTop = window.visualViewport?.offsetTop || 0; + if (event?.target instanceof VisualViewport) { + targetOffsetTop = event.target.offsetTop; + } + + if (shouldAdjustScrollView && window.visualViewport) { + const adjustScrollY = Math.round(initialHeight - window.visualViewport.height); + if (cachedDefaultOffsetTop.current === 0) { + cachedDefaultOffsetTop.current = targetOffsetTop; + } + + if (adjustScrollY > targetOffsetTop) { + setViewportOffsetTop(adjustScrollY); + } else if (targetOffsetTop !== 0 && adjustScrollY === targetOffsetTop) { + setViewportOffsetTop(cachedDefaultOffsetTop.current); + } else { + setViewportOffsetTop(targetOffsetTop); + } + } else { + setViewportOffsetTop(targetOffsetTop); + } + }; + updateOffsetTop(); + const removeViewportResizeListener = addViewportResizeListener(updateOffsetTop); + + return () => { + removeViewportResizeListener(); + }; + }, [initialHeight, shouldAdjustScrollView]); + + useEffect(() => { + if (!shouldAdjustScrollView) { + return; + } + window.scrollTo({top: viewportOffsetTop}); + }, [shouldAdjustScrollView, viewportOffsetTop]); + + return viewportOffsetTop; +} diff --git a/src/libs/actions/Modal.ts b/src/libs/actions/Modal.ts index 6351d0165544..5f4f66760f17 100644 --- a/src/libs/actions/Modal.ts +++ b/src/libs/actions/Modal.ts @@ -60,6 +60,7 @@ function onModalDidClose() { onModalClose(); onModalClose = null; isNavigate = undefined; + setModalVisibility(false); } /** diff --git a/src/pages/home/ReportScreen.tsx b/src/pages/home/ReportScreen.tsx index 242602b0654c..51d7c511aafb 100644 --- a/src/pages/home/ReportScreen.tsx +++ b/src/pages/home/ReportScreen.tsx @@ -21,14 +21,14 @@ import ScreenWrapper from '@components/ScreenWrapper'; import TaskHeaderActionButton from '@components/TaskHeaderActionButton'; import withCurrentReportID from '@components/withCurrentReportID'; import type {CurrentReportIDContextValue} from '@components/withCurrentReportID'; -import withViewportOffsetTop from '@components/withViewportOffsetTop'; -import type {ViewportOffsetTopProps} from '@components/withViewportOffsetTop'; import useAppFocusEvent from '@hooks/useAppFocusEvent'; import useLocalize from '@hooks/useLocalize'; import usePrevious from '@hooks/usePrevious'; import useThemeStyles from '@hooks/useThemeStyles'; +import useViewportOffsetTop from '@hooks/useViewportOffsetTop'; import useWindowDimensions from '@hooks/useWindowDimensions'; import Timing from '@libs/actions/Timing'; +import * as Browser from '@libs/Browser'; import Navigation from '@libs/Navigation/Navigation'; import clearReportNotifications from '@libs/Notification/clearReportNotifications'; import reportWithoutHasDraftSelector from '@libs/OnyxSelectors/reportWithoutHasDraftSelector'; @@ -47,6 +47,7 @@ import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import type SCREENS from '@src/SCREENS'; import type * as OnyxTypes from '@src/types/onyx'; +import type {Modal} from '@src/types/onyx'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; import HeaderView from './HeaderView'; import ReportActionsView from './report/ReportActionsView'; @@ -55,6 +56,8 @@ import {ActionListContext, ReactionListContext} from './ReportScreenContext'; import type {ActionListContextType, ReactionListRef, ScrollPosition} from './ReportScreenContext'; type ReportScreenOnyxProps = { + /** Indicates if there is a modal currently visible or not */ + modal: OnyxEntry; /** Tells us if the sidebar has rendered */ isSidebarLoaded: OnyxEntry; @@ -93,7 +96,7 @@ type OnyxHOCProps = { type ReportScreenNavigationProps = StackScreenProps; -type ReportScreenProps = OnyxHOCProps & ViewportOffsetTopProps & CurrentReportIDContextValue & ReportScreenOnyxProps & ReportScreenNavigationProps; +type ReportScreenProps = OnyxHOCProps & CurrentReportIDContextValue & ReportScreenOnyxProps & ReportScreenNavigationProps; /** Get the currently viewed report ID as number */ function getReportID(route: ReportScreenNavigationProps['route']): string { @@ -131,7 +134,7 @@ function ReportScreen({ markReadyForHydration, policies = {}, isSidebarLoaded = false, - viewportOffsetTop, + modal = {isVisible: false}, isComposerFullSize = false, userLeavingStatus = false, currentReportID = '', @@ -257,6 +260,8 @@ function ReportScreen({ Timing.start(CONST.TIMING.CHAT_RENDER); Performance.markStart(CONST.TIMING.CHAT_RENDER); } + const [isComposerFocus, setIsComposerFocus] = useState(false); + const viewportOffsetTop = useViewportOffsetTop(Browser.isMobileSafari() && isComposerFocus && !modal?.isVisible); const {reportPendingAction, reportErrors} = ReportUtils.getReportOfflinePendingActionAndErrors(report); const screenWrapperStyle: ViewStyle[] = [styles.appContent, styles.flex1, {marginTop: viewportOffsetTop}]; @@ -638,6 +643,8 @@ function ReportScreen({ {isReportReadyForDisplay ? ( setIsComposerFocus(true)} + onComposerBlur={() => setIsComposerFocus(false)} report={report} pendingAction={reportPendingAction} isComposerFullSize={!!isComposerFullSize} @@ -657,81 +664,82 @@ function ReportScreen({ ReportScreen.displayName = 'ReportScreen'; -export default withViewportOffsetTop( - withCurrentReportID( - withOnyx( - { - isSidebarLoaded: { - key: ONYXKEYS.IS_SIDEBAR_LOADED, - }, - sortedAllReportActions: { - key: ({route}) => `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${getReportID(route)}`, - canEvict: false, - selector: (allReportActions: OnyxEntry) => ReportActionsUtils.getSortedReportActionsForDisplay(allReportActions, true), - }, - report: { - key: ({route}) => `${ONYXKEYS.COLLECTION.REPORT}${getReportID(route)}`, - allowStaleData: true, - selector: reportWithoutHasDraftSelector, - }, - reportMetadata: { - key: ({route}) => `${ONYXKEYS.COLLECTION.REPORT_METADATA}${getReportID(route)}`, - initialValue: { - isLoadingInitialReportActions: true, - isLoadingOlderReportActions: false, - isLoadingNewerReportActions: false, - }, - }, - isComposerFullSize: { - key: ({route}) => `${ONYXKEYS.COLLECTION.REPORT_IS_COMPOSER_FULL_SIZE}${getReportID(route)}`, - initialValue: false, - }, - betas: { - key: ONYXKEYS.BETAS, - }, - policies: { - key: ONYXKEYS.COLLECTION.POLICY, - allowStaleData: true, - }, - accountManagerReportID: { - key: ONYXKEYS.ACCOUNT_MANAGER_REPORT_ID, - initialValue: null, - }, - userLeavingStatus: { - key: ({route}) => `${ONYXKEYS.COLLECTION.REPORT_USER_IS_LEAVING_ROOM}${getReportID(route)}`, - initialValue: false, +export default withCurrentReportID( + withOnyx( + { + modal: { + key: ONYXKEYS.MODAL, + }, + isSidebarLoaded: { + key: ONYXKEYS.IS_SIDEBAR_LOADED, + }, + sortedAllReportActions: { + key: ({route}) => `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${getReportID(route)}`, + canEvict: false, + selector: (allReportActions: OnyxEntry) => ReportActionsUtils.getSortedReportActionsForDisplay(allReportActions, true), + }, + report: { + key: ({route}) => `${ONYXKEYS.COLLECTION.REPORT}${getReportID(route)}`, + allowStaleData: true, + selector: reportWithoutHasDraftSelector, + }, + reportMetadata: { + key: ({route}) => `${ONYXKEYS.COLLECTION.REPORT_METADATA}${getReportID(route)}`, + initialValue: { + isLoadingInitialReportActions: true, + isLoadingOlderReportActions: false, + isLoadingNewerReportActions: false, }, - parentReportAction: { - key: ({report}) => `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${report ? report.parentReportID : 0}`, - selector: (parentReportActions: OnyxEntry, props: WithOnyxInstanceState): OnyxEntry => { - const parentReportActionID = props?.report?.parentReportActionID; - if (!parentReportActionID) { - return null; - } - return parentReportActions?.[parentReportActionID] ?? null; - }, - canEvict: false, + }, + isComposerFullSize: { + key: ({route}) => `${ONYXKEYS.COLLECTION.REPORT_IS_COMPOSER_FULL_SIZE}${getReportID(route)}`, + initialValue: false, + }, + betas: { + key: ONYXKEYS.BETAS, + }, + policies: { + key: ONYXKEYS.COLLECTION.POLICY, + allowStaleData: true, + }, + accountManagerReportID: { + key: ONYXKEYS.ACCOUNT_MANAGER_REPORT_ID, + initialValue: null, + }, + userLeavingStatus: { + key: ({route}) => `${ONYXKEYS.COLLECTION.REPORT_USER_IS_LEAVING_ROOM}${getReportID(route)}`, + initialValue: false, + }, + parentReportAction: { + key: ({report}) => `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${report ? report.parentReportID : 0}`, + selector: (parentReportActions: OnyxEntry, props: WithOnyxInstanceState): OnyxEntry => { + const parentReportActionID = props?.report?.parentReportActionID; + if (!parentReportActionID) { + return null; + } + return parentReportActions?.[parentReportActionID] ?? null; }, + canEvict: false, }, - true, - )( - memo( - ReportScreen, - (prevProps, nextProps) => - prevProps.isSidebarLoaded === nextProps.isSidebarLoaded && - lodashIsEqual(prevProps.sortedAllReportActions, nextProps.sortedAllReportActions) && - lodashIsEqual(prevProps.reportMetadata, nextProps.reportMetadata) && - prevProps.isComposerFullSize === nextProps.isComposerFullSize && - lodashIsEqual(prevProps.betas, nextProps.betas) && - lodashIsEqual(prevProps.policies, nextProps.policies) && - prevProps.accountManagerReportID === nextProps.accountManagerReportID && - prevProps.userLeavingStatus === nextProps.userLeavingStatus && - prevProps.currentReportID === nextProps.currentReportID && - prevProps.viewportOffsetTop === nextProps.viewportOffsetTop && - lodashIsEqual(prevProps.parentReportAction, nextProps.parentReportAction) && - lodashIsEqual(prevProps.route, nextProps.route) && - lodashIsEqual(prevProps.report, nextProps.report), - ), + }, + true, + )( + memo( + ReportScreen, + (prevProps, nextProps) => + prevProps.isSidebarLoaded === nextProps.isSidebarLoaded && + lodashIsEqual(prevProps.sortedAllReportActions, nextProps.sortedAllReportActions) && + lodashIsEqual(prevProps.reportMetadata, nextProps.reportMetadata) && + prevProps.isComposerFullSize === nextProps.isComposerFullSize && + lodashIsEqual(prevProps.betas, nextProps.betas) && + lodashIsEqual(prevProps.policies, nextProps.policies) && + prevProps.accountManagerReportID === nextProps.accountManagerReportID && + prevProps.userLeavingStatus === nextProps.userLeavingStatus && + prevProps.currentReportID === nextProps.currentReportID && + lodashIsEqual(prevProps.modal, nextProps.modal) && + lodashIsEqual(prevProps.parentReportAction, nextProps.parentReportAction) && + lodashIsEqual(prevProps.route, nextProps.route) && + lodashIsEqual(prevProps.report, nextProps.report), ), ), ); diff --git a/src/pages/home/report/ReportActionCompose/ReportActionCompose.tsx b/src/pages/home/report/ReportActionCompose/ReportActionCompose.tsx index 1e0e322be258..6face391dab3 100644 --- a/src/pages/home/report/ReportActionCompose/ReportActionCompose.tsx +++ b/src/pages/home/report/ReportActionCompose/ReportActionCompose.tsx @@ -61,6 +61,8 @@ type SuggestionsRef = { updateShouldShowSuggestionMenuToFalse: (shouldShowSuggestionMenu?: boolean) => void; setShouldBlockSuggestionCalc: (shouldBlock: boolean) => void; getSuggestions: () => Mention[] | Emoji[]; + onComposerFocus: () => void; + onComposerBlur: () => void; }; type ReportActionComposeOnyxProps = { @@ -85,6 +87,9 @@ type ReportActionComposeProps = ReportActionComposeOnyxProps & /** Whether the report is ready for display */ isReportReadyForDisplay?: boolean; + } & { + onComposerFocus: () => {}; + onComposerBlur: () => {}; }; // We want consistent auto focus behavior on input between native and mWeb so we have some auto focus management code that will @@ -107,6 +112,8 @@ function ReportActionCompose({ isReportReadyForDisplay = true, isEmptyChat, lastReportAction, + onComposerFocus, + onComposerBlur, }: ReportActionComposeProps) { const styles = useThemeStyles(); const {translate} = useLocalize(); @@ -296,6 +303,7 @@ function ReportActionCompose({ const onBlur = useCallback((event: NativeSyntheticEvent) => { const webEvent = event as unknown as FocusEvent; setIsFocused(false); + onComposerBlur(); if (suggestionsRef.current) { suggestionsRef.current.resetSuggestions(); } @@ -304,8 +312,14 @@ function ReportActionCompose({ } }, []); - const onFocus = useCallback(() => { + const handleFocus = useCallback(() => { setIsFocused(true); + onComposerFocus(); + }, []); + + const handleBlur = useCallback(() => { + setIsFocused(false); + onComposerBlur(); }, []); // resets the composer to normal size when @@ -436,8 +450,8 @@ function ReportActionCompose({ setIsCommentEmpty={setIsCommentEmpty} handleSendMessage={handleSendMessage} shouldShowComposeInput={shouldShowComposeInput} - onFocus={onFocus} - onBlur={onBlur} + onFocus={handleFocus} + onBlur={handleBlur} measureParentContainer={measureContainer} listHeight={listHeight} onValueChange={(value) => { diff --git a/src/pages/home/report/ReportFooter.tsx b/src/pages/home/report/ReportFooter.tsx index 3a787e1dbd0f..3acb254c7e46 100644 --- a/src/pages/home/report/ReportFooter.tsx +++ b/src/pages/home/report/ReportFooter.tsx @@ -51,6 +51,11 @@ type ReportFooterProps = ReportFooterOnyxProps & { /** Whether the composer is in full size */ isComposerFullSize?: boolean; + + onComposerFocus: () => void; + + /** A method to call when the input is blue */ + onComposerBlur: () => void; }; function ReportFooter({ @@ -63,6 +68,8 @@ function ReportFooter({ isReportReadyForDisplay = true, listHeight = 0, isComposerFullSize = false, + onComposerBlur, + onComposerFocus, }: ReportFooterProps) { const styles = useThemeStyles(); const {isOffline} = useNetwork(); @@ -137,6 +144,8 @@ function ReportFooter({ Date: Fri, 22 Mar 2024 00:06:54 +0700 Subject: [PATCH 078/113] update popover max height --- .../EmojiPicker/EmojiPickerMenu/useEmojiPickerMenu.js | 2 +- src/styles/index.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/EmojiPicker/EmojiPickerMenu/useEmojiPickerMenu.js b/src/components/EmojiPicker/EmojiPickerMenu/useEmojiPickerMenu.js index 80521e04ddd9..0566f25159c4 100644 --- a/src/components/EmojiPicker/EmojiPickerMenu/useEmojiPickerMenu.js +++ b/src/components/EmojiPicker/EmojiPickerMenu/useEmojiPickerMenu.js @@ -24,7 +24,7 @@ const useEmojiPickerMenu = () => { const [preferredSkinTone] = usePreferredEmojiSkinTone(); const {windowHeight} = useWindowDimensions(true); const StyleUtils = useStyleUtils(); - const listStyle = StyleUtils.getEmojiPickerListHeight(isListFiltered, windowHeight * 0.95); + const listStyle = StyleUtils.getEmojiPickerListHeight(isListFiltered, windowHeight); useEffect(() => { setFilteredEmojis(allEmojis); diff --git a/src/styles/index.ts b/src/styles/index.ts index b0c88d151484..26fe60ad61b2 100644 --- a/src/styles/index.ts +++ b/src/styles/index.ts @@ -1639,7 +1639,7 @@ const styles = (theme: ThemeColors) => popoverInnerContainer: { paddingTop: 0, // adjusting this because the mobile modal adds additional padding that we don't need for our layout - maxHeight: '95%', + maxHeight: '100%', }, menuItemTextContainer: { From 4df3eb8345ec66c70730588f2e74c265f0c73e9b Mon Sep 17 00:00:00 2001 From: Cong Pham Date: Fri, 22 Mar 2024 00:37:19 +0700 Subject: [PATCH 079/113] fix type check --- .../ReportActionCompose/ReportActionCompose.tsx | 11 ++++++----- src/pages/home/report/ReportFooter.tsx | 3 ++- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/pages/home/report/ReportActionCompose/ReportActionCompose.tsx b/src/pages/home/report/ReportActionCompose/ReportActionCompose.tsx index 6face391dab3..4b1ec41a498e 100644 --- a/src/pages/home/report/ReportActionCompose/ReportActionCompose.tsx +++ b/src/pages/home/report/ReportActionCompose/ReportActionCompose.tsx @@ -61,8 +61,6 @@ type SuggestionsRef = { updateShouldShowSuggestionMenuToFalse: (shouldShowSuggestionMenu?: boolean) => void; setShouldBlockSuggestionCalc: (shouldBlock: boolean) => void; getSuggestions: () => Mention[] | Emoji[]; - onComposerFocus: () => void; - onComposerBlur: () => void; }; type ReportActionComposeOnyxProps = { @@ -87,9 +85,12 @@ type ReportActionComposeProps = ReportActionComposeOnyxProps & /** Whether the report is ready for display */ isReportReadyForDisplay?: boolean; - } & { - onComposerFocus: () => {}; - onComposerBlur: () => {}; + + /** A method to call when the input is focus */ + onComposerFocus: () => void; + + /** A method to call when the input is blur */ + onComposerBlur: () => void; }; // We want consistent auto focus behavior on input between native and mWeb so we have some auto focus management code that will diff --git a/src/pages/home/report/ReportFooter.tsx b/src/pages/home/report/ReportFooter.tsx index 3acb254c7e46..bd143f9ef196 100644 --- a/src/pages/home/report/ReportFooter.tsx +++ b/src/pages/home/report/ReportFooter.tsx @@ -52,9 +52,10 @@ type ReportFooterProps = ReportFooterOnyxProps & { /** Whether the composer is in full size */ isComposerFullSize?: boolean; + /** A method to call when the input is focus */ onComposerFocus: () => void; - /** A method to call when the input is blue */ + /** A method to call when the input is blur */ onComposerBlur: () => void; }; From 52e658543be8ac6b6ba1f35764dc5ef85e50bc19 Mon Sep 17 00:00:00 2001 From: Cong Pham Date: Fri, 22 Mar 2024 00:39:21 +0700 Subject: [PATCH 080/113] Revert "update popover max height" This reverts commit 750d321749519ed0e14306739be3ef109d126211. --- .../EmojiPicker/EmojiPickerMenu/useEmojiPickerMenu.js | 2 +- src/styles/index.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/EmojiPicker/EmojiPickerMenu/useEmojiPickerMenu.js b/src/components/EmojiPicker/EmojiPickerMenu/useEmojiPickerMenu.js index 0566f25159c4..80521e04ddd9 100644 --- a/src/components/EmojiPicker/EmojiPickerMenu/useEmojiPickerMenu.js +++ b/src/components/EmojiPicker/EmojiPickerMenu/useEmojiPickerMenu.js @@ -24,7 +24,7 @@ const useEmojiPickerMenu = () => { const [preferredSkinTone] = usePreferredEmojiSkinTone(); const {windowHeight} = useWindowDimensions(true); const StyleUtils = useStyleUtils(); - const listStyle = StyleUtils.getEmojiPickerListHeight(isListFiltered, windowHeight); + const listStyle = StyleUtils.getEmojiPickerListHeight(isListFiltered, windowHeight * 0.95); useEffect(() => { setFilteredEmojis(allEmojis); diff --git a/src/styles/index.ts b/src/styles/index.ts index 26fe60ad61b2..b0c88d151484 100644 --- a/src/styles/index.ts +++ b/src/styles/index.ts @@ -1639,7 +1639,7 @@ const styles = (theme: ThemeColors) => popoverInnerContainer: { paddingTop: 0, // adjusting this because the mobile modal adds additional padding that we don't need for our layout - maxHeight: '100%', + maxHeight: '95%', }, menuItemTextContainer: { From f6e852c97dc2a724830fb8af43ee5430f8a4a727 Mon Sep 17 00:00:00 2001 From: Rohan Sasne Date: Thu, 21 Mar 2024 23:14:07 +0530 Subject: [PATCH 081/113] Don't call api when no edits are made & add category validation --- .../workspace/categories/CategoryForm.tsx | 7 ++++-- .../workspace/categories/EditCategoryPage.tsx | 23 ++++++++++++++++++- src/pages/workspace/tags/EditTagPage.tsx | 3 +++ 3 files changed, 30 insertions(+), 3 deletions(-) diff --git a/src/pages/workspace/categories/CategoryForm.tsx b/src/pages/workspace/categories/CategoryForm.tsx index 304f4153df8c..d9166c691372 100644 --- a/src/pages/workspace/categories/CategoryForm.tsx +++ b/src/pages/workspace/categories/CategoryForm.tsx @@ -25,9 +25,11 @@ type CategoryFormProps = { /** Function to call when the form is submitted */ onSubmit: (values: FormOnyxValues) => void; + + validateEdit?: (values: FormOnyxValues) => FormInputErrors; }; -function CategoryForm({onSubmit, policyCategories, categoryName}: CategoryFormProps) { +function CategoryForm({onSubmit, policyCategories, categoryName, validateEdit}: CategoryFormProps) { const styles = useThemeStyles(); const {translate} = useLocalize(); const {inputCallbackRef} = useAutoFocusInput(); @@ -67,7 +69,8 @@ function CategoryForm({onSubmit, policyCategories, categoryName}: CategoryFormPr formID={ONYXKEYS.FORMS.WORKSPACE_CATEGORY_FORM} onSubmit={submit} submitButtonText={translate('common.save')} - validate={validate} + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing + validate={validateEdit || validate} style={[styles.mh5, styles.flex1]} enabledWhenOffline > diff --git a/src/pages/workspace/categories/EditCategoryPage.tsx b/src/pages/workspace/categories/EditCategoryPage.tsx index 0e5ed0589934..38134cc6b479 100644 --- a/src/pages/workspace/categories/EditCategoryPage.tsx +++ b/src/pages/workspace/categories/EditCategoryPage.tsx @@ -2,8 +2,8 @@ import type {StackScreenProps} from '@react-navigation/stack'; import React, {useCallback} from 'react'; import {withOnyx} from 'react-native-onyx'; import type {OnyxEntry} from 'react-native-onyx'; -import type {FormOnyxValues} from '@components/Form/types'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; +import type {FormInputErrors, FormOnyxValues} from '@components/Form/types'; import ScreenWrapper from '@components/ScreenWrapper'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; @@ -32,9 +32,29 @@ function EditCategoryPage({route, policyCategories}: EditCategoryPageProps) { const {translate} = useLocalize(); const currentCategoryName = route.params.categoryName; + const validate = useCallback( + (values: FormOnyxValues) => { + const errors: FormInputErrors = {}; + const newCategoryName = values.categoryName.trim(); + + + if (!newCategoryName) { + errors.categoryName = 'workspace.categories.categoryRequiredError'; + } else if (policyCategories?.[newCategoryName] && currentCategoryName !== newCategoryName) { + errors.categoryName = 'workspace.categories.existingCategoryError'; + } + + return errors; + }, + [policyCategories, currentCategoryName], + ); + const editCategory = useCallback( (values: FormOnyxValues) => { + const newCategoryName = values.categoryName.trim(); + if (currentCategoryName !== newCategoryName) { Policy.renamePolicyCategory(route.params.policyID, {oldName: currentCategoryName, newName: values.categoryName}); + } }, [currentCategoryName, route.params.policyID], ); @@ -58,6 +78,7 @@ function EditCategoryPage({route, policyCategories}: EditCategoryPageProps) { /> diff --git a/src/pages/workspace/tags/EditTagPage.tsx b/src/pages/workspace/tags/EditTagPage.tsx index 92d7c0a11ac9..ebf5855b759c 100644 --- a/src/pages/workspace/tags/EditTagPage.tsx +++ b/src/pages/workspace/tags/EditTagPage.tsx @@ -57,7 +57,10 @@ function EditTagPage({route, policyTags}: EditTagPageProps) { const editTag = useCallback( (values: FormOnyxValues) => { + const tagName = values.tagName.trim(); + if (currentTagName !== tagName) { Policy.renamePolicyTag(route.params.policyID, {oldName: currentTagName, newName: values.tagName.trim()}); + } Keyboard.dismiss(); Navigation.dismissModal(); }, From 98c17344308f8fe83ad0b79a3197c1650ab79005 Mon Sep 17 00:00:00 2001 From: Rohan Sasne Date: Thu, 21 Mar 2024 23:16:42 +0530 Subject: [PATCH 082/113] Fix prettier --- src/pages/workspace/categories/EditCategoryPage.tsx | 5 ++--- src/pages/workspace/tags/EditTagPage.tsx | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/pages/workspace/categories/EditCategoryPage.tsx b/src/pages/workspace/categories/EditCategoryPage.tsx index 38134cc6b479..873b150013ac 100644 --- a/src/pages/workspace/categories/EditCategoryPage.tsx +++ b/src/pages/workspace/categories/EditCategoryPage.tsx @@ -2,8 +2,8 @@ import type {StackScreenProps} from '@react-navigation/stack'; import React, {useCallback} from 'react'; import {withOnyx} from 'react-native-onyx'; import type {OnyxEntry} from 'react-native-onyx'; -import HeaderWithBackButton from '@components/HeaderWithBackButton'; import type {FormInputErrors, FormOnyxValues} from '@components/Form/types'; +import HeaderWithBackButton from '@components/HeaderWithBackButton'; import ScreenWrapper from '@components/ScreenWrapper'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; @@ -36,7 +36,6 @@ function EditCategoryPage({route, policyCategories}: EditCategoryPageProps) { (values: FormOnyxValues) => { const errors: FormInputErrors = {}; const newCategoryName = values.categoryName.trim(); - if (!newCategoryName) { errors.categoryName = 'workspace.categories.categoryRequiredError'; @@ -53,7 +52,7 @@ function EditCategoryPage({route, policyCategories}: EditCategoryPageProps) { (values: FormOnyxValues) => { const newCategoryName = values.categoryName.trim(); if (currentCategoryName !== newCategoryName) { - Policy.renamePolicyCategory(route.params.policyID, {oldName: currentCategoryName, newName: values.categoryName}); + Policy.renamePolicyCategory(route.params.policyID, {oldName: currentCategoryName, newName: values.categoryName}); } }, [currentCategoryName, route.params.policyID], diff --git a/src/pages/workspace/tags/EditTagPage.tsx b/src/pages/workspace/tags/EditTagPage.tsx index ebf5855b759c..bb8cca238e75 100644 --- a/src/pages/workspace/tags/EditTagPage.tsx +++ b/src/pages/workspace/tags/EditTagPage.tsx @@ -59,7 +59,7 @@ function EditTagPage({route, policyTags}: EditTagPageProps) { (values: FormOnyxValues) => { const tagName = values.tagName.trim(); if (currentTagName !== tagName) { - Policy.renamePolicyTag(route.params.policyID, {oldName: currentTagName, newName: values.tagName.trim()}); + Policy.renamePolicyTag(route.params.policyID, {oldName: currentTagName, newName: values.tagName.trim()}); } Keyboard.dismiss(); Navigation.dismissModal(); From 14232fe33bece6ec0e627ace54d097e8a3f1c6c9 Mon Sep 17 00:00:00 2001 From: Cong Pham Date: Fri, 22 Mar 2024 00:56:06 +0700 Subject: [PATCH 083/113] update code review and fix eslint --- src/components/EmojiPicker/EmojiPicker.js | 3 +- src/hooks/useViewportOffsetTop/index.ts | 2 +- src/libs/actions/Modal.ts | 14 ++++---- src/pages/home/ReportScreen.tsx | 3 +- .../ReportActionCompose.tsx | 34 +++++++++---------- 5 files changed, 27 insertions(+), 29 deletions(-) diff --git a/src/components/EmojiPicker/EmojiPicker.js b/src/components/EmojiPicker/EmojiPicker.js index fd0fe786b632..0d6143416440 100644 --- a/src/components/EmojiPicker/EmojiPicker.js +++ b/src/components/EmojiPicker/EmojiPicker.js @@ -176,7 +176,8 @@ const EmojiPicker = forwardRef((props, ref) => { onModalShow={focusEmojiSearchInput} onModalHide={onModalHide.current} hideModalContentWhileAnimating - shouldSetModalVisibility={Browser.isMobile()} + // shouldSetModalVisibility is true for mobile safari to handle adjust virtual viewport position when toggle modal visibility + shouldSetModalVisibility={Browser.isMobileSafari()} animationInTiming={1} animationOutTiming={1} anchorPosition={{ diff --git a/src/hooks/useViewportOffsetTop/index.ts b/src/hooks/useViewportOffsetTop/index.ts index 7bb13f55c5ee..55b0345d01ff 100644 --- a/src/hooks/useViewportOffsetTop/index.ts +++ b/src/hooks/useViewportOffsetTop/index.ts @@ -10,7 +10,7 @@ export default function useViewportOffsetTop(shouldAdjustScrollView = false): nu const cachedDefaultOffsetTop = useRef(0); useEffect(() => { const updateOffsetTop = (event?: Event) => { - let targetOffsetTop = window.visualViewport?.offsetTop || 0; + let targetOffsetTop = window.visualViewport?.offsetTop ?? 0; if (event?.target instanceof VisualViewport) { targetOffsetTop = event.target.offsetTop; } diff --git a/src/libs/actions/Modal.ts b/src/libs/actions/Modal.ts index 5f4f66760f17..928b080b50f8 100644 --- a/src/libs/actions/Modal.ts +++ b/src/libs/actions/Modal.ts @@ -49,6 +49,13 @@ function close(onModalCloseCallback: () => void, isNavigating = true) { closeTop(); } +/** + * Allows other parts of the app to know when a modal has been opened or closed + */ +function setModalVisibility(isVisible: boolean) { + Onyx.merge(ONYXKEYS.MODAL, {isVisible}); +} + function onModalDidClose() { if (!onModalClose) { return; @@ -63,13 +70,6 @@ function onModalDidClose() { setModalVisibility(false); } -/** - * Allows other parts of the app to know when a modal has been opened or closed - */ -function setModalVisibility(isVisible: boolean) { - Onyx.merge(ONYXKEYS.MODAL, {isVisible}); -} - /** * Allows other parts of app to know that an alert modal is about to open. * This will trigger as soon as a modal is opened but not yet visible while animation is running. diff --git a/src/pages/home/ReportScreen.tsx b/src/pages/home/ReportScreen.tsx index 51d7c511aafb..4c23cf6be6c1 100644 --- a/src/pages/home/ReportScreen.tsx +++ b/src/pages/home/ReportScreen.tsx @@ -47,7 +47,6 @@ import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import type SCREENS from '@src/SCREENS'; import type * as OnyxTypes from '@src/types/onyx'; -import type {Modal} from '@src/types/onyx'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; import HeaderView from './HeaderView'; import ReportActionsView from './report/ReportActionsView'; @@ -57,7 +56,7 @@ import type {ActionListContextType, ReactionListRef, ScrollPosition} from './Rep type ReportScreenOnyxProps = { /** Indicates if there is a modal currently visible or not */ - modal: OnyxEntry; + modal: OnyxEntry; /** Tells us if the sidebar has rendered */ isSidebarLoaded: OnyxEntry; diff --git a/src/pages/home/report/ReportActionCompose/ReportActionCompose.tsx b/src/pages/home/report/ReportActionCompose/ReportActionCompose.tsx index 4b1ec41a498e..428e09d09fc7 100644 --- a/src/pages/home/report/ReportActionCompose/ReportActionCompose.tsx +++ b/src/pages/home/report/ReportActionCompose/ReportActionCompose.tsx @@ -301,27 +301,25 @@ function ReportActionCompose({ isKeyboardVisibleWhenShowingModalRef.current = true; }, []); - const onBlur = useCallback((event: NativeSyntheticEvent) => { - const webEvent = event as unknown as FocusEvent; - setIsFocused(false); - onComposerBlur(); - if (suggestionsRef.current) { - suggestionsRef.current.resetSuggestions(); - } - if (webEvent.relatedTarget && webEvent.relatedTarget === actionButtonRef.current) { - isKeyboardVisibleWhenShowingModalRef.current = true; - } - }, []); + const onBlur = useCallback( + (event: NativeSyntheticEvent) => { + const webEvent = event as unknown as FocusEvent; + setIsFocused(false); + onComposerBlur(); + if (suggestionsRef.current) { + suggestionsRef.current.resetSuggestions(); + } + if (webEvent.relatedTarget && webEvent.relatedTarget === actionButtonRef.current) { + isKeyboardVisibleWhenShowingModalRef.current = true; + } + }, + [onComposerBlur], + ); const handleFocus = useCallback(() => { setIsFocused(true); onComposerFocus(); - }, []); - - const handleBlur = useCallback(() => { - setIsFocused(false); - onComposerBlur(); - }, []); + }, [onComposerFocus]); // resets the composer to normal size when // the send button is pressed. @@ -452,7 +450,7 @@ function ReportActionCompose({ handleSendMessage={handleSendMessage} shouldShowComposeInput={shouldShowComposeInput} onFocus={handleFocus} - onBlur={handleBlur} + onBlur={onBlur} measureParentContainer={measureContainer} listHeight={listHeight} onValueChange={(value) => { From edf767716aee59e2bd8390da744655d27cec776b Mon Sep 17 00:00:00 2001 From: FitseTLT Date: Thu, 21 Mar 2024 22:46:52 +0300 Subject: [PATCH 084/113] type update --- src/components/ReportActionItem/ReportActionItemImage.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/ReportActionItem/ReportActionItemImage.tsx b/src/components/ReportActionItem/ReportActionItemImage.tsx index c26a9a93ef72..740f784d2669 100644 --- a/src/components/ReportActionItem/ReportActionItemImage.tsx +++ b/src/components/ReportActionItem/ReportActionItemImage.tsx @@ -87,7 +87,7 @@ function ReportActionItemImage({ } else { propsObj = { isThumbnail, - ...(isThumbnail && {iconSize: isSingleImage ? 'medium' : ('small' as IconSize), fileExtension}), + ...(isThumbnail && {iconSize: (isSingleImage ? 'medium' : 'small') as IconSize, fileExtension}), source: thumbnail ?? image ?? '', }; } From 2b62829feab1c5feecabc2def26eea34a8ef2311 Mon Sep 17 00:00:00 2001 From: Tomasz Lesniakiewicz Date: Fri, 22 Mar 2024 13:19:32 +0100 Subject: [PATCH 085/113] chore: update comment --- src/pages/home/sidebar/SidebarLinksData.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/home/sidebar/SidebarLinksData.js b/src/pages/home/sidebar/SidebarLinksData.js index 8395c3d1e716..0c1f8b8c5972 100644 --- a/src/pages/home/sidebar/SidebarLinksData.js +++ b/src/pages/home/sidebar/SidebarLinksData.js @@ -332,7 +332,7 @@ export default compose( }), )( /* - While working on audit on the App Start App metric we noticed that by memoizing SidebarLinksData we can avoid 1 additional run of getOrderedReportIDs. + While working on audit on the App Start App metric we noticed that by memoizing SidebarLinksData we can avoid 2 additional run of getOrderedReportIDs. With that we can reduce app start up time by ~2s on heavy account. More details - https://github.com/Expensify/App/issues/35234#issuecomment-1926914534 */ From 1bd9230ecae518f03f70a4fade716fcba394c5ae Mon Sep 17 00:00:00 2001 From: FitseTLT Date: Mon, 25 Mar 2024 16:26:44 +0300 Subject: [PATCH 086/113] made label unselectable --- src/components/EReceiptThumbnail.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/EReceiptThumbnail.tsx b/src/components/EReceiptThumbnail.tsx index e0f88470f460..63889f76e67c 100644 --- a/src/components/EReceiptThumbnail.tsx +++ b/src/components/EReceiptThumbnail.tsx @@ -114,6 +114,7 @@ function EReceiptThumbnail({transaction, borderRadius, fileExtension, isReceiptT /> {isReceiptThumbnail && fileExtension && ( Date: Mon, 25 Mar 2024 16:32:39 +0300 Subject: [PATCH 087/113] fix lint --- src/components/ReportActionItem/ReportActionItemImages.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/ReportActionItem/ReportActionItemImages.tsx b/src/components/ReportActionItem/ReportActionItemImages.tsx index 1c383dfa4f9f..ee8cb0849ca0 100644 --- a/src/components/ReportActionItem/ReportActionItemImages.tsx +++ b/src/components/ReportActionItem/ReportActionItemImages.tsx @@ -71,7 +71,7 @@ function ReportActionItemImages({images, size, total, isHovered = false}: Report const borderStyle = shouldShowBorder ? styles.reportActionItemImageBorder : {}; return ( Date: Mon, 25 Mar 2024 16:17:40 -0700 Subject: [PATCH 088/113] Make getContinuousReportActionChain consider any optimistic action --- src/libs/ReportActionsUtils.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/libs/ReportActionsUtils.ts b/src/libs/ReportActionsUtils.ts index 64bac4f46b5a..1a5daa803c9a 100644 --- a/src/libs/ReportActionsUtils.ts +++ b/src/libs/ReportActionsUtils.ts @@ -262,10 +262,12 @@ function getSortedReportActions(reportActions: ReportAction[] | null, shouldSort function getContinuousReportActionChain(sortedReportActions: ReportAction[], id?: string): ReportAction[] { let index; + console.log('RORY_DEBUG sortedReportActions', sortedReportActions); + if (id) { index = sortedReportActions.findIndex((obj) => obj.reportActionID === id); } else { - index = sortedReportActions.findIndex((obj) => obj.pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD); + index = sortedReportActions.findIndex((obj) => obj.pendingAction === null); } if (index === -1) { @@ -298,12 +300,14 @@ function getContinuousReportActionChain(sortedReportActions: ReportAction[], id? // This additional check is to include recently sent messages that might not yet be part of the established sequence. while ( (startIndex > 0 && sortedReportActions[startIndex].reportActionID === sortedReportActions[startIndex - 1].previousReportActionID) || - sortedReportActions[startIndex - 1]?.pendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD || + sortedReportActions[startIndex - 1]?.pendingAction !== null || sortedReportActions[startIndex - 1]?.actionName === CONST.REPORT.ACTIONS.TYPE.ROOMCHANGELOG.INVITE_TO_ROOM ) { startIndex--; } + console.log('RORY_DEBUG continuous reportAction chain', sortedReportActions.slice(startIndex, endIndex + 1)); + return sortedReportActions.slice(startIndex, endIndex + 1); } From 046780d6690624ce68e410ee487a46a5ccf1e93c Mon Sep 17 00:00:00 2001 From: rory Date: Mon, 25 Mar 2024 16:54:36 -0700 Subject: [PATCH 089/113] Ignore update actions --- src/libs/ReportActionsUtils.ts | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/libs/ReportActionsUtils.ts b/src/libs/ReportActionsUtils.ts index 1a5daa803c9a..3a1056cd78b7 100644 --- a/src/libs/ReportActionsUtils.ts +++ b/src/libs/ReportActionsUtils.ts @@ -265,9 +265,14 @@ function getContinuousReportActionChain(sortedReportActions: ReportAction[], id? console.log('RORY_DEBUG sortedReportActions', sortedReportActions); if (id) { - index = sortedReportActions.findIndex((obj) => obj.reportActionID === id); + index = sortedReportActions.findIndex((reportAction) => reportAction.reportActionID === id); } else { - index = sortedReportActions.findIndex((obj) => obj.pendingAction === null); + index = sortedReportActions.findIndex( + (reportAction) => + reportAction.pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD && + reportAction.pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE && + !reportAction.isOptimisticAction, + ); } if (index === -1) { @@ -300,7 +305,10 @@ function getContinuousReportActionChain(sortedReportActions: ReportAction[], id? // This additional check is to include recently sent messages that might not yet be part of the established sequence. while ( (startIndex > 0 && sortedReportActions[startIndex].reportActionID === sortedReportActions[startIndex - 1].previousReportActionID) || - sortedReportActions[startIndex - 1]?.pendingAction !== null || + sortedReportActions[startIndex - 1]?.pendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD || + sortedReportActions[startIndex - 1]?.pendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE || + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing + sortedReportActions[startIndex - 1]?.isOptimisticAction || sortedReportActions[startIndex - 1]?.actionName === CONST.REPORT.ACTIONS.TYPE.ROOMCHANGELOG.INVITE_TO_ROOM ) { startIndex--; From 967184b5410282951a05208da76889342099ff6d Mon Sep 17 00:00:00 2001 From: Cong Pham Date: Tue, 26 Mar 2024 08:54:28 +0700 Subject: [PATCH 090/113] update condition avoid regression --- src/components/EmojiPicker/EmojiPicker.js | 3 +-- .../EmojiPickerMenu/useEmojiPickerMenu.js | 1 + src/libs/actions/Modal.ts | 15 +++++++-------- src/pages/home/ReportScreen.tsx | 6 +++--- .../ReportActionCompose/ReportActionCompose.tsx | 12 ++++++------ 5 files changed, 18 insertions(+), 19 deletions(-) diff --git a/src/components/EmojiPicker/EmojiPicker.js b/src/components/EmojiPicker/EmojiPicker.js index 0d6143416440..6bceaf570ccc 100644 --- a/src/components/EmojiPicker/EmojiPicker.js +++ b/src/components/EmojiPicker/EmojiPicker.js @@ -176,8 +176,7 @@ const EmojiPicker = forwardRef((props, ref) => { onModalShow={focusEmojiSearchInput} onModalHide={onModalHide.current} hideModalContentWhileAnimating - // shouldSetModalVisibility is true for mobile safari to handle adjust virtual viewport position when toggle modal visibility - shouldSetModalVisibility={Browser.isMobileSafari()} + shouldSetModalVisibility={false} animationInTiming={1} animationOutTiming={1} anchorPosition={{ diff --git a/src/components/EmojiPicker/EmojiPickerMenu/useEmojiPickerMenu.js b/src/components/EmojiPicker/EmojiPickerMenu/useEmojiPickerMenu.js index 80521e04ddd9..86cb6d921c36 100644 --- a/src/components/EmojiPicker/EmojiPickerMenu/useEmojiPickerMenu.js +++ b/src/components/EmojiPicker/EmojiPickerMenu/useEmojiPickerMenu.js @@ -24,6 +24,7 @@ const useEmojiPickerMenu = () => { const [preferredSkinTone] = usePreferredEmojiSkinTone(); const {windowHeight} = useWindowDimensions(true); const StyleUtils = useStyleUtils(); + // calculate the height of the emoji picker based popoverInnerContainer style has maxHeight is 95% const listStyle = StyleUtils.getEmojiPickerListHeight(isListFiltered, windowHeight * 0.95); useEffect(() => { diff --git a/src/libs/actions/Modal.ts b/src/libs/actions/Modal.ts index 928b080b50f8..6351d0165544 100644 --- a/src/libs/actions/Modal.ts +++ b/src/libs/actions/Modal.ts @@ -49,13 +49,6 @@ function close(onModalCloseCallback: () => void, isNavigating = true) { closeTop(); } -/** - * Allows other parts of the app to know when a modal has been opened or closed - */ -function setModalVisibility(isVisible: boolean) { - Onyx.merge(ONYXKEYS.MODAL, {isVisible}); -} - function onModalDidClose() { if (!onModalClose) { return; @@ -67,7 +60,13 @@ function onModalDidClose() { onModalClose(); onModalClose = null; isNavigate = undefined; - setModalVisibility(false); +} + +/** + * Allows other parts of the app to know when a modal has been opened or closed + */ +function setModalVisibility(isVisible: boolean) { + Onyx.merge(ONYXKEYS.MODAL, {isVisible}); } /** diff --git a/src/pages/home/ReportScreen.tsx b/src/pages/home/ReportScreen.tsx index 354f7890ed50..366e06d0b414 100644 --- a/src/pages/home/ReportScreen.tsx +++ b/src/pages/home/ReportScreen.tsx @@ -55,7 +55,7 @@ import {ActionListContext, ReactionListContext} from './ReportScreenContext'; import type {ActionListContextType, ReactionListRef, ScrollPosition} from './ReportScreenContext'; type ReportScreenOnyxProps = { - /** Indicates if there is a modal currently visible or not */ + /** Get modal status */ modal: OnyxEntry; /** Tells us if the sidebar has rendered */ isSidebarLoaded: OnyxEntry; @@ -133,7 +133,7 @@ function ReportScreen({ markReadyForHydration, policies = {}, isSidebarLoaded = false, - modal = {isVisible: false}, + modal, isComposerFullSize = false, userLeavingStatus = false, currentReportID = '', @@ -262,7 +262,7 @@ function ReportScreen({ Performance.markStart(CONST.TIMING.CHAT_RENDER); } const [isComposerFocus, setIsComposerFocus] = useState(false); - const viewportOffsetTop = useViewportOffsetTop(Browser.isMobileSafari() && isComposerFocus && !modal?.isVisible); + const viewportOffsetTop = useViewportOffsetTop(Browser.isMobileSafari() && isComposerFocus && !modal?.willAlertModalBecomeVisible); const {reportPendingAction, reportErrors} = ReportUtils.getReportOfflinePendingActionAndErrors(report); const screenWrapperStyle: ViewStyle[] = [styles.appContent, styles.flex1, {marginTop: viewportOffsetTop}]; diff --git a/src/pages/home/report/ReportActionCompose/ReportActionCompose.tsx b/src/pages/home/report/ReportActionCompose/ReportActionCompose.tsx index 428e09d09fc7..70340e9e1fec 100644 --- a/src/pages/home/report/ReportActionCompose/ReportActionCompose.tsx +++ b/src/pages/home/report/ReportActionCompose/ReportActionCompose.tsx @@ -87,10 +87,10 @@ type ReportActionComposeProps = ReportActionComposeOnyxProps & isReportReadyForDisplay?: boolean; /** A method to call when the input is focus */ - onComposerFocus: () => void; + onComposerFocus?: () => void; /** A method to call when the input is blur */ - onComposerBlur: () => void; + onComposerBlur?: () => void; }; // We want consistent auto focus behavior on input between native and mWeb so we have some auto focus management code that will @@ -305,7 +305,7 @@ function ReportActionCompose({ (event: NativeSyntheticEvent) => { const webEvent = event as unknown as FocusEvent; setIsFocused(false); - onComposerBlur(); + onComposerBlur?.(); if (suggestionsRef.current) { suggestionsRef.current.resetSuggestions(); } @@ -316,9 +316,9 @@ function ReportActionCompose({ [onComposerBlur], ); - const handleFocus = useCallback(() => { + const onFocus = useCallback(() => { setIsFocused(true); - onComposerFocus(); + onComposerFocus?.(); }, [onComposerFocus]); // resets the composer to normal size when @@ -449,7 +449,7 @@ function ReportActionCompose({ setIsCommentEmpty={setIsCommentEmpty} handleSendMessage={handleSendMessage} shouldShowComposeInput={shouldShowComposeInput} - onFocus={handleFocus} + onFocus={onFocus} onBlur={onBlur} measureParentContainer={measureContainer} listHeight={listHeight} From 8114339be16e52e43662adddadf37ebd36302c66 Mon Sep 17 00:00:00 2001 From: Cong Pham Date: Tue, 26 Mar 2024 09:24:44 +0700 Subject: [PATCH 091/113] update code review Co-authored-by: Situ Chandra Shil <108292595+situchan@users.noreply.github.com> --- src/pages/home/ReportScreen.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/pages/home/ReportScreen.tsx b/src/pages/home/ReportScreen.tsx index 366e06d0b414..e4a20aa45989 100644 --- a/src/pages/home/ReportScreen.tsx +++ b/src/pages/home/ReportScreen.tsx @@ -57,6 +57,7 @@ import type {ActionListContextType, ReactionListRef, ScrollPosition} from './Rep type ReportScreenOnyxProps = { /** Get modal status */ modal: OnyxEntry; + /** Tells us if the sidebar has rendered */ isSidebarLoaded: OnyxEntry; From 5f3f51c29fb2064d2e5ee7b1292aae613e27c28c Mon Sep 17 00:00:00 2001 From: Cong Pham Date: Tue, 26 Mar 2024 10:17:17 +0700 Subject: [PATCH 092/113] revert emoji picker using cached height --- .../EmojiPicker/EmojiPickerMenu/useEmojiPickerMenu.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/EmojiPicker/EmojiPickerMenu/useEmojiPickerMenu.js b/src/components/EmojiPicker/EmojiPickerMenu/useEmojiPickerMenu.js index 86cb6d921c36..ba3001703c04 100644 --- a/src/components/EmojiPicker/EmojiPickerMenu/useEmojiPickerMenu.js +++ b/src/components/EmojiPicker/EmojiPickerMenu/useEmojiPickerMenu.js @@ -22,7 +22,7 @@ const useEmojiPickerMenu = () => { const isListFiltered = allEmojis.length !== filteredEmojis.length; const {preferredLocale} = useLocalize(); const [preferredSkinTone] = usePreferredEmojiSkinTone(); - const {windowHeight} = useWindowDimensions(true); + const {windowHeight} = useWindowDimensions(); const StyleUtils = useStyleUtils(); // calculate the height of the emoji picker based popoverInnerContainer style has maxHeight is 95% const listStyle = StyleUtils.getEmojiPickerListHeight(isListFiltered, windowHeight * 0.95); From 8aa800176a9cb972ec4ad741e1c5dbd590876310 Mon Sep 17 00:00:00 2001 From: Jakub Butkiewicz Date: Tue, 26 Mar 2024 12:16:09 +0100 Subject: [PATCH 093/113] fix: rename prop name --- src/components/TagPicker/index.tsx | 6 +++--- src/pages/EditRequestPage.js | 12 ++++++------ src/pages/EditRequestTagPage.js | 6 +++--- src/pages/EditSplitBillPage.tsx | 2 +- src/pages/iou/request/step/IOURequestStepTag.js | 10 +++++----- 5 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/components/TagPicker/index.tsx b/src/components/TagPicker/index.tsx index 39574299063e..af8acd19e8c4 100644 --- a/src/components/TagPicker/index.tsx +++ b/src/components/TagPicker/index.tsx @@ -51,17 +51,17 @@ type TagPickerProps = TagPickerOnyxProps & { shouldShowDisabledAndSelectedOption?: boolean; /** Indicates which tag list index was selected */ - tagIndex: number; + tagListIndex: number; }; -function TagPicker({selectedTag, tagListName, policyTags, tagIndex, policyRecentlyUsedTags, shouldShowDisabledAndSelectedOption = false, insets, onSubmit}: TagPickerProps) { +function TagPicker({selectedTag, tagListName, policyTags, tagListIndex, policyRecentlyUsedTags, shouldShowDisabledAndSelectedOption = false, insets, onSubmit}: TagPickerProps) { const styles = useThemeStyles(); const StyleUtils = useStyleUtils(); const {translate} = useLocalize(); const [searchValue, setSearchValue] = useState(''); const policyRecentlyUsedTagsList = useMemo(() => policyRecentlyUsedTags?.[tagListName] ?? [], [policyRecentlyUsedTags, tagListName]); - const policyTagList = PolicyUtils.getTagList(policyTags, tagIndex); + const policyTagList = PolicyUtils.getTagList(policyTags, tagListIndex); const policyTagsCount = PolicyUtils.getCountOfEnabledTagsOfList(policyTagList.tags); const isTagsCountBelowThreshold = policyTagsCount < CONST.TAG_LIST_THRESHOLD; diff --git a/src/pages/EditRequestPage.js b/src/pages/EditRequestPage.js index ff59a7a84190..eecffd81d88b 100644 --- a/src/pages/EditRequestPage.js +++ b/src/pages/EditRequestPage.js @@ -78,10 +78,10 @@ function EditRequestPage({report, route, policy, policyCategories, policyTags, p const defaultCurrency = lodashGet(route, 'params.currency', '') || transactionCurrency; const fieldToEdit = lodashGet(route, ['params', 'field'], ''); - const tagIndex = Number(lodashGet(route, ['params', 'tagIndex'], undefined)); + const tagListIndex = Number(lodashGet(route, ['params', 'tagIndex'], undefined)); - const tag = TransactionUtils.getTag(transaction, tagIndex); - const policyTagListName = PolicyUtils.getTagListName(policyTags, tagIndex); + const tag = TransactionUtils.getTag(transaction, tagListIndex); + const policyTagListName = PolicyUtils.getTagListName(policyTags, tagListIndex); const policyTagLists = useMemo(() => PolicyUtils.getTagLists(policyTags), [policyTags]); // A flag for verifying that the current report is a sub-report of a workspace chat @@ -129,14 +129,14 @@ function EditRequestPage({report, route, policy, policyCategories, policyTags, p IOU.updateMoneyRequestTag( transaction.transactionID, report.reportID, - IOUUtils.insertTagIntoTransactionTagsString(transactionTag, updatedTag, tagIndex), + IOUUtils.insertTagIntoTransactionTagsString(transactionTag, updatedTag, tagListIndex), policy, policyTags, policyCategories, ); Navigation.dismissModal(); }, - [tag, transaction.transactionID, report.reportID, transactionTag, tagIndex, policy, policyTags, policyCategories], + [tag, transaction.transactionID, report.reportID, transactionTag, tagListIndex, policy, policyTags, policyCategories], ); if (fieldToEdit === CONST.EDIT_REQUEST_FIELD.AMOUNT) { @@ -159,7 +159,7 @@ function EditRequestPage({report, route, policy, policyCategories, policyTags, p diff --git a/src/pages/EditRequestTagPage.js b/src/pages/EditRequestTagPage.js index c799e21dbaf4..1aead9ee1f6e 100644 --- a/src/pages/EditRequestTagPage.js +++ b/src/pages/EditRequestTagPage.js @@ -19,7 +19,7 @@ const propTypes = { tagListName: PropTypes.string, /** Indicates which tag list index was selected */ - tagIndex: PropTypes.number.isRequired, + tagListIndex: PropTypes.number.isRequired, /** Callback to fire when the Save button is pressed */ onSubmit: PropTypes.func.isRequired, @@ -29,7 +29,7 @@ const defaultProps = { tagListName: '', }; -function EditRequestTagPage({defaultTag, policyID, tagListName, tagIndex, onSubmit}) { +function EditRequestTagPage({defaultTag, policyID, tagListName, tagListIndex, onSubmit}) { const styles = useThemeStyles(); const {translate} = useLocalize(); @@ -53,7 +53,7 @@ function EditRequestTagPage({defaultTag, policyID, tagListName, tagIndex, onSubm { setDraftSplitTransaction({tag: transactionChanges.tag.trim()}); }} diff --git a/src/pages/iou/request/step/IOURequestStepTag.js b/src/pages/iou/request/step/IOURequestStepTag.js index 3bc57f5a5072..ed55628ecaa9 100644 --- a/src/pages/iou/request/step/IOURequestStepTag.js +++ b/src/pages/iou/request/step/IOURequestStepTag.js @@ -91,15 +91,15 @@ function IOURequestStepTag({ const styles = useThemeStyles(); const {translate} = useLocalize(); - const tagIndex = Number(rawTagIndex); - const policyTagListName = PolicyUtils.getTagListName(policyTags, tagIndex); + const tagListIndex = Number(rawTagIndex); + const policyTagListName = PolicyUtils.getTagListName(policyTags, tagListIndex); const isEditing = action === CONST.IOU.ACTION.EDIT; const isSplitBill = iouType === CONST.IOU.TYPE.SPLIT; const isEditingSplitBill = isEditing && isSplitBill; const currentTransaction = isEditingSplitBill && !lodashIsEmpty(splitDraftTransaction) ? splitDraftTransaction : transaction; const transactionTag = TransactionUtils.getTag(currentTransaction); - const tag = TransactionUtils.getTag(currentTransaction, tagIndex); + const tag = TransactionUtils.getTag(currentTransaction, tagListIndex); const reportAction = reportActions[report.parentReportActionID || reportActionID]; const canEditSplitBill = isSplitBill && reportAction && session.accountID === reportAction.actorAccountID && TransactionUtils.areRequiredFieldsEmpty(transaction); const policyTagLists = useMemo(() => PolicyUtils.getTagLists(policyTags), [policyTags]); @@ -119,7 +119,7 @@ function IOURequestStepTag({ */ const updateTag = (selectedTag) => { const isSelectedTag = selectedTag.searchText === tag; - const updatedTag = IOUUtils.insertTagIntoTransactionTagsString(transactionTag, isSelectedTag ? '' : selectedTag.searchText, tagIndex); + const updatedTag = IOUUtils.insertTagIntoTransactionTagsString(transactionTag, isSelectedTag ? '' : selectedTag.searchText, tagListIndex); if (isEditingSplitBill) { IOU.setDraftSplitTransaction(transactionID, {tag: updatedTag}); navigateBack(); @@ -148,7 +148,7 @@ function IOURequestStepTag({ Date: Tue, 26 Mar 2024 20:38:10 +0530 Subject: [PATCH 094/113] Add documentation --- src/pages/workspace/categories/CategoryForm.tsx | 2 +- src/pages/workspace/categories/EditCategoryPage.tsx | 1 + src/pages/workspace/tags/EditTagPage.tsx | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/pages/workspace/categories/CategoryForm.tsx b/src/pages/workspace/categories/CategoryForm.tsx index d9166c691372..1aee71e11a65 100644 --- a/src/pages/workspace/categories/CategoryForm.tsx +++ b/src/pages/workspace/categories/CategoryForm.tsx @@ -25,7 +25,7 @@ type CategoryFormProps = { /** Function to call when the form is submitted */ onSubmit: (values: FormOnyxValues) => void; - + /** Function to validate the edited values of the form */ validateEdit?: (values: FormOnyxValues) => FormInputErrors; }; diff --git a/src/pages/workspace/categories/EditCategoryPage.tsx b/src/pages/workspace/categories/EditCategoryPage.tsx index 873b150013ac..3a7e0f518657 100644 --- a/src/pages/workspace/categories/EditCategoryPage.tsx +++ b/src/pages/workspace/categories/EditCategoryPage.tsx @@ -51,6 +51,7 @@ function EditCategoryPage({route, policyCategories}: EditCategoryPageProps) { const editCategory = useCallback( (values: FormOnyxValues) => { const newCategoryName = values.categoryName.trim(); + // Do not call the API if the new category name is the same as the current category name if (currentCategoryName !== newCategoryName) { Policy.renamePolicyCategory(route.params.policyID, {oldName: currentCategoryName, newName: values.categoryName}); } diff --git a/src/pages/workspace/tags/EditTagPage.tsx b/src/pages/workspace/tags/EditTagPage.tsx index bb8cca238e75..19660cde4153 100644 --- a/src/pages/workspace/tags/EditTagPage.tsx +++ b/src/pages/workspace/tags/EditTagPage.tsx @@ -58,6 +58,7 @@ function EditTagPage({route, policyTags}: EditTagPageProps) { const editTag = useCallback( (values: FormOnyxValues) => { const tagName = values.tagName.trim(); + // Do not call the API if the new tag name is the same as the current tag name if (currentTagName !== tagName) { Policy.renamePolicyTag(route.params.policyID, {oldName: currentTagName, newName: values.tagName.trim()}); } From ff40c19ca33186cd6a057fc1c50c95a9b59c8b66 Mon Sep 17 00:00:00 2001 From: GandalfGwaihir Date: Tue, 26 Mar 2024 20:39:57 +0530 Subject: [PATCH 095/113] Add documentation --- src/pages/workspace/categories/CategoryForm.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/pages/workspace/categories/CategoryForm.tsx b/src/pages/workspace/categories/CategoryForm.tsx index 1aee71e11a65..39042e97d181 100644 --- a/src/pages/workspace/categories/CategoryForm.tsx +++ b/src/pages/workspace/categories/CategoryForm.tsx @@ -25,6 +25,7 @@ type CategoryFormProps = { /** Function to call when the form is submitted */ onSubmit: (values: FormOnyxValues) => void; + /** Function to validate the edited values of the form */ validateEdit?: (values: FormOnyxValues) => FormInputErrors; }; From ea101830b27f2651af841522fb413f93594dbc3c Mon Sep 17 00:00:00 2001 From: GandalfGwaihir Date: Tue, 26 Mar 2024 20:42:47 +0530 Subject: [PATCH 096/113] Add documentation --- src/pages/workspace/categories/EditCategoryPage.tsx | 2 +- src/pages/workspace/tags/EditTagPage.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/workspace/categories/EditCategoryPage.tsx b/src/pages/workspace/categories/EditCategoryPage.tsx index 3a7e0f518657..dbf7c8913515 100644 --- a/src/pages/workspace/categories/EditCategoryPage.tsx +++ b/src/pages/workspace/categories/EditCategoryPage.tsx @@ -51,7 +51,7 @@ function EditCategoryPage({route, policyCategories}: EditCategoryPageProps) { const editCategory = useCallback( (values: FormOnyxValues) => { const newCategoryName = values.categoryName.trim(); - // Do not call the API if the new category name is the same as the current category name + // Do not call the API if the edited category name is the same as the current category name if (currentCategoryName !== newCategoryName) { Policy.renamePolicyCategory(route.params.policyID, {oldName: currentCategoryName, newName: values.categoryName}); } diff --git a/src/pages/workspace/tags/EditTagPage.tsx b/src/pages/workspace/tags/EditTagPage.tsx index 19660cde4153..fbde96eb2b91 100644 --- a/src/pages/workspace/tags/EditTagPage.tsx +++ b/src/pages/workspace/tags/EditTagPage.tsx @@ -58,7 +58,7 @@ function EditTagPage({route, policyTags}: EditTagPageProps) { const editTag = useCallback( (values: FormOnyxValues) => { const tagName = values.tagName.trim(); - // Do not call the API if the new tag name is the same as the current tag name + // Do not call the API if the edited tag name is the same as the current tag name if (currentTagName !== tagName) { Policy.renamePolicyTag(route.params.policyID, {oldName: currentTagName, newName: values.tagName.trim()}); } From df38b414bcb2b94a7e67204497ffd51c5f58ac22 Mon Sep 17 00:00:00 2001 From: rory Date: Tue, 26 Mar 2024 09:58:19 -0700 Subject: [PATCH 097/113] Remove debug logs --- src/libs/ReportActionsUtils.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/libs/ReportActionsUtils.ts b/src/libs/ReportActionsUtils.ts index 3a1056cd78b7..11f870b891b6 100644 --- a/src/libs/ReportActionsUtils.ts +++ b/src/libs/ReportActionsUtils.ts @@ -262,8 +262,6 @@ function getSortedReportActions(reportActions: ReportAction[] | null, shouldSort function getContinuousReportActionChain(sortedReportActions: ReportAction[], id?: string): ReportAction[] { let index; - console.log('RORY_DEBUG sortedReportActions', sortedReportActions); - if (id) { index = sortedReportActions.findIndex((reportAction) => reportAction.reportActionID === id); } else { @@ -314,8 +312,6 @@ function getContinuousReportActionChain(sortedReportActions: ReportAction[], id? startIndex--; } - console.log('RORY_DEBUG continuous reportAction chain', sortedReportActions.slice(startIndex, endIndex + 1)); - return sortedReportActions.slice(startIndex, endIndex + 1); } From 28bb598bde4c76bfa9509627ebbfc177d2495b1f Mon Sep 17 00:00:00 2001 From: GandalfGwaihir Date: Tue, 26 Mar 2024 22:48:09 +0530 Subject: [PATCH 098/113] fix lint --- src/pages/workspace/categories/CategoryForm.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/workspace/categories/CategoryForm.tsx b/src/pages/workspace/categories/CategoryForm.tsx index 39042e97d181..30e30b29b216 100644 --- a/src/pages/workspace/categories/CategoryForm.tsx +++ b/src/pages/workspace/categories/CategoryForm.tsx @@ -25,7 +25,7 @@ type CategoryFormProps = { /** Function to call when the form is submitted */ onSubmit: (values: FormOnyxValues) => void; - + /** Function to validate the edited values of the form */ validateEdit?: (values: FormOnyxValues) => FormInputErrors; }; From 9f46f4b855be64203b0ea7ad0876fe6d58abf52a Mon Sep 17 00:00:00 2001 From: kirillzyusko Date: Tue, 26 Mar 2024 18:49:12 +0100 Subject: [PATCH 099/113] e2e: ignore "missing test" error --- src/libs/E2E/reactNativeLaunchingTest.ts | 1 + src/libs/E2E/types.ts | 6 ++++++ tests/e2e/testRunner.ts | 7 ++++++- 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/libs/E2E/reactNativeLaunchingTest.ts b/src/libs/E2E/reactNativeLaunchingTest.ts index 931b41524696..31faa803ec61 100644 --- a/src/libs/E2E/reactNativeLaunchingTest.ts +++ b/src/libs/E2E/reactNativeLaunchingTest.ts @@ -68,6 +68,7 @@ E2EClient.getTestConfig() return E2EClient.submitTestResults({ name: config.name, error: `Test '${config.name}' not found`, + critical: false, }); } diff --git a/src/libs/E2E/types.ts b/src/libs/E2E/types.ts index 5185a75625a3..3cb33e3bbce3 100644 --- a/src/libs/E2E/types.ts +++ b/src/libs/E2E/types.ts @@ -39,6 +39,12 @@ type TestResult = { /** Optional, if set indicates that the test run failed and has no valid results. */ error?: string; + /** + * Whether error is critical. If `true`, then server will be stopped and `e2e` tests will fail. Otherwise will simply log a warning. + * Default value is `true` + */ + critical?: boolean; + /** Render count */ renderCount?: number; }; diff --git a/tests/e2e/testRunner.ts b/tests/e2e/testRunner.ts index 5edc8c068229..8d898321309e 100644 --- a/tests/e2e/testRunner.ts +++ b/tests/e2e/testRunner.ts @@ -93,9 +93,14 @@ const runTests = async (): Promise => { // Collect results while tests are being executed server.addTestResultListener((testResult) => { - if (testResult?.error != null) { + const {critical = true} = testResult; + + if (testResult?.error != null && critical) { throw new Error(`Test '${testResult.name}' failed with error: ${testResult.error}`); } + if (testResult?.error != null && !critical) { + Logger.warn(`Test '${testResult.name}' failed with error: ${testResult.error}`); + } let result = 0; if (testResult?.duration !== undefined) { From 2618a3532cb3a0b5e93483dd6ed2e9c92ab4b530 Mon Sep 17 00:00:00 2001 From: Aldo Canepa Date: Tue, 26 Mar 2024 11:09:12 -0700 Subject: [PATCH 100/113] Remove optimistic CLOSED actions on success --- src/libs/actions/Policy.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/libs/actions/Policy.ts b/src/libs/actions/Policy.ts index 3efba3e54dcd..f107d19991a5 100644 --- a/src/libs/actions/Policy.ts +++ b/src/libs/actions/Policy.ts @@ -316,6 +316,7 @@ function deleteWorkspace(policyID: string, policyName: string) { } const filteredPolicies = Object.values(allPolicies).filter((policy): policy is Policy => policy?.id !== policyID); + const successData: OnyxUpdate[] = []; const optimisticData: OnyxUpdate[] = [ { onyxMethod: Onyx.METHOD.MERGE, @@ -376,6 +377,11 @@ function deleteWorkspace(policyID: string, policyName: string) { key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`, value: optimisticReportActions, }); + successData.push({ + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`, + value: Object.fromEntries(Object.entries(optimisticReportActions).map(([reportActionID]) => [reportActionID, null])), + }) }); // Restore the old report stateNum and statusNum @@ -406,7 +412,7 @@ function deleteWorkspace(policyID: string, policyName: string) { const params: DeleteWorkspaceParams = {policyID}; - API.write(WRITE_COMMANDS.DELETE_WORKSPACE, params, {optimisticData, failureData}); + API.write(WRITE_COMMANDS.DELETE_WORKSPACE, params, {optimisticData, successData, failureData}); // Reset the lastAccessedWorkspacePolicyID if (policyID === lastAccessedWorkspacePolicyID) { From 1f8265cfd4be404e2af9732c9bf19cc19c868597 Mon Sep 17 00:00:00 2001 From: Cong Pham Date: Wed, 27 Mar 2024 01:56:15 +0700 Subject: [PATCH 101/113] cleanup function and update comment --- .../EmojiPicker/EmojiPickerMenu/useEmojiPickerMenu.js | 6 +++++- src/hooks/useViewportOffsetTop/index.ts | 6 +----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/components/EmojiPicker/EmojiPickerMenu/useEmojiPickerMenu.js b/src/components/EmojiPicker/EmojiPickerMenu/useEmojiPickerMenu.js index ba3001703c04..c6f9f601f4df 100644 --- a/src/components/EmojiPicker/EmojiPickerMenu/useEmojiPickerMenu.js +++ b/src/components/EmojiPicker/EmojiPickerMenu/useEmojiPickerMenu.js @@ -24,7 +24,11 @@ const useEmojiPickerMenu = () => { const [preferredSkinTone] = usePreferredEmojiSkinTone(); const {windowHeight} = useWindowDimensions(); const StyleUtils = useStyleUtils(); - // calculate the height of the emoji picker based popoverInnerContainer style has maxHeight is 95% + /** + * At EmojiPicker has set innerContainerStyle with maxHeight: '95%' by styles.popoverInnerContainer + * to avoid the list style to be cut off due to the list height being larger than the container height + * so we need to calculate listStyle based on the height of the window and innerContainerStyle at the EmojiPicker + */ const listStyle = StyleUtils.getEmojiPickerListHeight(isListFiltered, windowHeight * 0.95); useEffect(() => { diff --git a/src/hooks/useViewportOffsetTop/index.ts b/src/hooks/useViewportOffsetTop/index.ts index 55b0345d01ff..56fb19187c4f 100644 --- a/src/hooks/useViewportOffsetTop/index.ts +++ b/src/hooks/useViewportOffsetTop/index.ts @@ -33,11 +33,7 @@ export default function useViewportOffsetTop(shouldAdjustScrollView = false): nu } }; updateOffsetTop(); - const removeViewportResizeListener = addViewportResizeListener(updateOffsetTop); - - return () => { - removeViewportResizeListener(); - }; + return addViewportResizeListener(updateOffsetTop); }, [initialHeight, shouldAdjustScrollView]); useEffect(() => { From b965f8c42bb5598d5237cfd6aa75d6aa2b4bf8b0 Mon Sep 17 00:00:00 2001 From: Andrew Rosiclair Date: Tue, 26 Mar 2024 17:00:49 -0400 Subject: [PATCH 102/113] stop calling OptInToPushNotifications when receiving notifications --- src/libs/Notification/PushNotification/index.native.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/libs/Notification/PushNotification/index.native.ts b/src/libs/Notification/PushNotification/index.native.ts index 382591e5b698..4e028ad82392 100644 --- a/src/libs/Notification/PushNotification/index.native.ts +++ b/src/libs/Notification/PushNotification/index.native.ts @@ -84,11 +84,6 @@ function refreshNotificationOptInStatus() { const init: Init = () => { // Setup event listeners Airship.addListener(EventType.PushReceived, (notification) => { - // By default, refresh notification opt-in status to true if we receive a notification - if (!isUserOptedInToPushNotifications) { - PushNotificationActions.setPushNotificationOptInStatus(true); - } - pushNotificationEventCallback(EventType.PushReceived, notification.pushPayload); }); From f37596edc00a46be1d056be7bb1d3635775562f9 Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Tue, 26 Mar 2024 15:42:57 -0600 Subject: [PATCH 103/113] fix rogue action --- src/libs/actions/IOU.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index ae3bf0cdbd68..7035b13577c7 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -4634,7 +4634,7 @@ function approveMoneyRequest(expenseReport: OnyxTypes.Report | EmptyObject) { onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${expenseReport.reportID}`, value: { - [expenseReport.reportActionID ?? '']: { + [optimisticApprovedReportAction.reportActionID]: { errors: ErrorUtils.getMicroSecondOnyxError('iou.error.other'), }, }, From 7ecd3feff13de9387165deb5f1f9956c0fce229c Mon Sep 17 00:00:00 2001 From: Aldo Canepa Date: Tue, 26 Mar 2024 15:31:37 -0700 Subject: [PATCH 104/113] Use finallyData instead of optimisticData --- src/libs/actions/Policy.ts | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/libs/actions/Policy.ts b/src/libs/actions/Policy.ts index f107d19991a5..59398e9e7c5b 100644 --- a/src/libs/actions/Policy.ts +++ b/src/libs/actions/Policy.ts @@ -316,7 +316,6 @@ function deleteWorkspace(policyID: string, policyName: string) { } const filteredPolicies = Object.values(allPolicies).filter((policy): policy is Policy => policy?.id !== policyID); - const successData: OnyxUpdate[] = []; const optimisticData: OnyxUpdate[] = [ { onyxMethod: Onyx.METHOD.MERGE, @@ -343,6 +342,7 @@ function deleteWorkspace(policyID: string, policyName: string) { const reportsToArchive = Object.values(allReports ?? {}).filter( (report) => report?.policyID === policyID && (ReportUtils.isChatRoom(report) || ReportUtils.isPolicyExpenseChat(report) || ReportUtils.isTaskReport(report)), ); + const finallyData: OnyxUpdate[] = []; reportsToArchive.forEach((report) => { const {reportID, ownerAccountID} = report ?? {}; optimisticData.push({ @@ -370,17 +370,19 @@ function deleteWorkspace(policyID: string, policyName: string) { emailClosingReport = allPersonalDetails?.[ownerAccountID]?.login ?? ''; } const optimisticClosedReportAction = ReportUtils.buildOptimisticClosedReportAction(emailClosingReport, policyName, CONST.REPORT.ARCHIVE_REASON.POLICY_DELETED); - const optimisticReportActions: Record = {}; - optimisticReportActions[optimisticClosedReportAction.reportActionID] = optimisticClosedReportAction as ReportAction; optimisticData.push({ onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`, - value: optimisticReportActions, + value: { + [optimisticClosedReportAction.reportActionID]: optimisticClosedReportAction as ReportAction, + }, }); - successData.push({ + finallyData.push({ onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`, - value: Object.fromEntries(Object.entries(optimisticReportActions).map(([reportActionID]) => [reportActionID, null])), + value: { + [optimisticClosedReportAction.reportActionID]: null, + }, }) }); From 5b04afe79e2914d00fb597f3449a554a80af300c Mon Sep 17 00:00:00 2001 From: Aldo Canepa Date: Tue, 26 Mar 2024 15:36:15 -0700 Subject: [PATCH 105/113] Fix variable name --- src/libs/actions/Policy.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/actions/Policy.ts b/src/libs/actions/Policy.ts index 59398e9e7c5b..b89254f168ff 100644 --- a/src/libs/actions/Policy.ts +++ b/src/libs/actions/Policy.ts @@ -414,7 +414,7 @@ function deleteWorkspace(policyID: string, policyName: string) { const params: DeleteWorkspaceParams = {policyID}; - API.write(WRITE_COMMANDS.DELETE_WORKSPACE, params, {optimisticData, successData, failureData}); + API.write(WRITE_COMMANDS.DELETE_WORKSPACE, params, {optimisticData, finallyData, failureData}); // Reset the lastAccessedWorkspacePolicyID if (policyID === lastAccessedWorkspacePolicyID) { From 33915d77ebb354647223805d9b170c10cc96780d Mon Sep 17 00:00:00 2001 From: Aldo Canepa Date: Tue, 26 Mar 2024 15:42:24 -0700 Subject: [PATCH 106/113] Prettier --- src/libs/actions/Policy.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/actions/Policy.ts b/src/libs/actions/Policy.ts index b89254f168ff..f571d037890f 100644 --- a/src/libs/actions/Policy.ts +++ b/src/libs/actions/Policy.ts @@ -383,7 +383,7 @@ function deleteWorkspace(policyID: string, policyName: string) { value: { [optimisticClosedReportAction.reportActionID]: null, }, - }) + }); }); // Restore the old report stateNum and statusNum From 50ac88da25dec0e546eea83a5c6d1a8024079157 Mon Sep 17 00:00:00 2001 From: OSBotify Date: Tue, 26 Mar 2024 22:45:21 +0000 Subject: [PATCH 107/113] Update version to 1.4.56-6 --- 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 0b2271d16716..d01027540d66 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 1001045605 - versionName "1.4.56-5" + versionCode 1001045606 + versionName "1.4.56-6" } flavorDimensions "default" diff --git a/ios/NewExpensify/Info.plist b/ios/NewExpensify/Info.plist index 37741d484d63..525574f7857a 100644 --- a/ios/NewExpensify/Info.plist +++ b/ios/NewExpensify/Info.plist @@ -40,7 +40,7 @@ CFBundleVersion - 1.4.56.5 + 1.4.56.6 ITSAppUsesNonExemptEncryption LSApplicationQueriesSchemes diff --git a/ios/NewExpensifyTests/Info.plist b/ios/NewExpensifyTests/Info.plist index e228808076d0..0961d21b2e79 100644 --- a/ios/NewExpensifyTests/Info.plist +++ b/ios/NewExpensifyTests/Info.plist @@ -19,6 +19,6 @@ CFBundleSignature ???? CFBundleVersion - 1.4.56.5 + 1.4.56.6 diff --git a/ios/NotificationServiceExtension/Info.plist b/ios/NotificationServiceExtension/Info.plist index 11f83011d47a..4e490aa859ef 100644 --- a/ios/NotificationServiceExtension/Info.plist +++ b/ios/NotificationServiceExtension/Info.plist @@ -13,7 +13,7 @@ CFBundleShortVersionString 1.4.56 CFBundleVersion - 1.4.56.5 + 1.4.56.6 NSExtension NSExtensionPointIdentifier diff --git a/package-lock.json b/package-lock.json index 6e7f23674852..7044310c9e5c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "new.expensify", - "version": "1.4.56-5", + "version": "1.4.56-6", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "new.expensify", - "version": "1.4.56-5", + "version": "1.4.56-6", "hasInstallScript": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index 83c3095585be..a3189bbf0abd 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "new.expensify", - "version": "1.4.56-5", + "version": "1.4.56-6", "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 704e854ed97aa3b13c0423a278c2ded4bcbf205d Mon Sep 17 00:00:00 2001 From: Aldo Canepa Date: Tue, 26 Mar 2024 16:25:15 -0700 Subject: [PATCH 108/113] Add comment --- src/libs/actions/Policy.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/libs/actions/Policy.ts b/src/libs/actions/Policy.ts index f571d037890f..45fc139b6742 100644 --- a/src/libs/actions/Policy.ts +++ b/src/libs/actions/Policy.ts @@ -377,6 +377,9 @@ function deleteWorkspace(policyID: string, policyName: string) { [optimisticClosedReportAction.reportActionID]: optimisticClosedReportAction as ReportAction, }, }); + + // We are temporarily adding this workaround because 'DeleteWorkspace' doesn't + // support receiving the optimistic reportActions' ids for the moment. finallyData.push({ onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`, From d5b38947dea86c1e972a79de8a90dd2a3a187f11 Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Tue, 26 Mar 2024 18:02:34 -0600 Subject: [PATCH 109/113] rm success data --- src/libs/actions/IOU.ts | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 7035b13577c7..b67e44fcf5ad 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -4396,15 +4396,6 @@ function getPayMoneyRequestParams(chatReport: OnyxTypes.Report, iouReport: OnyxT ]; const successData: OnyxUpdate[] = [ - { - onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${iouReport.reportID}`, - value: { - [optimisticIOUReportAction.reportActionID]: { - pendingAction: null, - }, - }, - }, { onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT}${iouReport.reportID}`, From 2faf908d075c5d0b6c8659842a7b8c797332e99e Mon Sep 17 00:00:00 2001 From: OSBotify Date: Wed, 27 Mar 2024 00:07:58 +0000 Subject: [PATCH 110/113] Update version to 1.4.56-7 --- 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 d01027540d66..bae37fe24ab6 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 1001045606 - versionName "1.4.56-6" + versionCode 1001045607 + versionName "1.4.56-7" } flavorDimensions "default" diff --git a/ios/NewExpensify/Info.plist b/ios/NewExpensify/Info.plist index 525574f7857a..d6e3b27605ff 100644 --- a/ios/NewExpensify/Info.plist +++ b/ios/NewExpensify/Info.plist @@ -40,7 +40,7 @@ CFBundleVersion - 1.4.56.6 + 1.4.56.7 ITSAppUsesNonExemptEncryption LSApplicationQueriesSchemes diff --git a/ios/NewExpensifyTests/Info.plist b/ios/NewExpensifyTests/Info.plist index 0961d21b2e79..0f61b60623ca 100644 --- a/ios/NewExpensifyTests/Info.plist +++ b/ios/NewExpensifyTests/Info.plist @@ -19,6 +19,6 @@ CFBundleSignature ???? CFBundleVersion - 1.4.56.6 + 1.4.56.7 diff --git a/ios/NotificationServiceExtension/Info.plist b/ios/NotificationServiceExtension/Info.plist index 4e490aa859ef..26de3a589462 100644 --- a/ios/NotificationServiceExtension/Info.plist +++ b/ios/NotificationServiceExtension/Info.plist @@ -13,7 +13,7 @@ CFBundleShortVersionString 1.4.56 CFBundleVersion - 1.4.56.6 + 1.4.56.7 NSExtension NSExtensionPointIdentifier diff --git a/package-lock.json b/package-lock.json index 7044310c9e5c..d2e94890cb7b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "new.expensify", - "version": "1.4.56-6", + "version": "1.4.56-7", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "new.expensify", - "version": "1.4.56-6", + "version": "1.4.56-7", "hasInstallScript": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index a3189bbf0abd..6ac69b6d6ed4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "new.expensify", - "version": "1.4.56-6", + "version": "1.4.56-7", "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 e49daece845ed765569946dd5c61aebab95442fe Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Tue, 26 Mar 2024 18:32:29 -0600 Subject: [PATCH 111/113] fix test --- tests/actions/IOUTest.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/actions/IOUTest.ts b/tests/actions/IOUTest.ts index 33cdefb749ec..c71a88809302 100644 --- a/tests/actions/IOUTest.ts +++ b/tests/actions/IOUTest.ts @@ -1584,7 +1584,6 @@ describe('actions/IOU', () => { reportAction.actionName === CONST.REPORT.ACTIONS.TYPE.IOU && reportAction.originalMessage.type === CONST.IOU.REPORT_ACTION_TYPE.PAY, ) ?? null; expect(payIOUAction).toBeTruthy(); - expect(payIOUAction?.pendingAction).toBeFalsy(); resolve(); }, From 1bbb594d1735cab697ac6cba0bf3435c295dc291 Mon Sep 17 00:00:00 2001 From: OSBotify Date: Wed, 27 Mar 2024 00:54:56 +0000 Subject: [PATCH 112/113] Update version to 1.4.56-8 --- 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 bae37fe24ab6..c85e6bb27b4f 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 1001045607 - versionName "1.4.56-7" + versionCode 1001045608 + versionName "1.4.56-8" } flavorDimensions "default" diff --git a/ios/NewExpensify/Info.plist b/ios/NewExpensify/Info.plist index d6e3b27605ff..417e3a4a3d3d 100644 --- a/ios/NewExpensify/Info.plist +++ b/ios/NewExpensify/Info.plist @@ -40,7 +40,7 @@ CFBundleVersion - 1.4.56.7 + 1.4.56.8 ITSAppUsesNonExemptEncryption LSApplicationQueriesSchemes diff --git a/ios/NewExpensifyTests/Info.plist b/ios/NewExpensifyTests/Info.plist index 0f61b60623ca..9d5552892828 100644 --- a/ios/NewExpensifyTests/Info.plist +++ b/ios/NewExpensifyTests/Info.plist @@ -19,6 +19,6 @@ CFBundleSignature ???? CFBundleVersion - 1.4.56.7 + 1.4.56.8 diff --git a/ios/NotificationServiceExtension/Info.plist b/ios/NotificationServiceExtension/Info.plist index 26de3a589462..1ca70277a320 100644 --- a/ios/NotificationServiceExtension/Info.plist +++ b/ios/NotificationServiceExtension/Info.plist @@ -13,7 +13,7 @@ CFBundleShortVersionString 1.4.56 CFBundleVersion - 1.4.56.7 + 1.4.56.8 NSExtension NSExtensionPointIdentifier diff --git a/package-lock.json b/package-lock.json index d2e94890cb7b..28ecbfa81f4d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "new.expensify", - "version": "1.4.56-7", + "version": "1.4.56-8", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "new.expensify", - "version": "1.4.56-7", + "version": "1.4.56-8", "hasInstallScript": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index 6ac69b6d6ed4..a74a86d647bd 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "new.expensify", - "version": "1.4.56-7", + "version": "1.4.56-8", "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 9d9757ffb3dfdad5dbd3dc13cd962faf5e1249d4 Mon Sep 17 00:00:00 2001 From: OSBotify Date: Wed, 27 Mar 2024 04:39:55 +0000 Subject: [PATCH 113/113] Update version to 1.4.57-0 --- android/app/build.gradle | 4 ++-- ios/NewExpensify/Info.plist | 4 ++-- ios/NewExpensifyTests/Info.plist | 4 ++-- ios/NotificationServiceExtension/Info.plist | 4 ++-- package-lock.json | 4 ++-- package.json | 2 +- 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/android/app/build.gradle b/android/app/build.gradle index c85e6bb27b4f..62316cf4cf38 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 1001045608 - versionName "1.4.56-8" + versionCode 1001045700 + versionName "1.4.57-0" } flavorDimensions "default" diff --git a/ios/NewExpensify/Info.plist b/ios/NewExpensify/Info.plist index 417e3a4a3d3d..071a7f4802da 100644 --- a/ios/NewExpensify/Info.plist +++ b/ios/NewExpensify/Info.plist @@ -19,7 +19,7 @@ CFBundlePackageType APPL CFBundleShortVersionString - 1.4.56 + 1.4.57 CFBundleSignature ???? CFBundleURLTypes @@ -40,7 +40,7 @@ CFBundleVersion - 1.4.56.8 + 1.4.57.0 ITSAppUsesNonExemptEncryption LSApplicationQueriesSchemes diff --git a/ios/NewExpensifyTests/Info.plist b/ios/NewExpensifyTests/Info.plist index 9d5552892828..c12ea4bfdf91 100644 --- a/ios/NewExpensifyTests/Info.plist +++ b/ios/NewExpensifyTests/Info.plist @@ -15,10 +15,10 @@ CFBundlePackageType BNDL CFBundleShortVersionString - 1.4.56 + 1.4.57 CFBundleSignature ???? CFBundleVersion - 1.4.56.8 + 1.4.57.0 diff --git a/ios/NotificationServiceExtension/Info.plist b/ios/NotificationServiceExtension/Info.plist index 1ca70277a320..afa6db80106f 100644 --- a/ios/NotificationServiceExtension/Info.plist +++ b/ios/NotificationServiceExtension/Info.plist @@ -11,9 +11,9 @@ CFBundleName $(PRODUCT_NAME) CFBundleShortVersionString - 1.4.56 + 1.4.57 CFBundleVersion - 1.4.56.8 + 1.4.57.0 NSExtension NSExtensionPointIdentifier diff --git a/package-lock.json b/package-lock.json index 28ecbfa81f4d..34c2b335abeb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "new.expensify", - "version": "1.4.56-8", + "version": "1.4.57-0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "new.expensify", - "version": "1.4.56-8", + "version": "1.4.57-0", "hasInstallScript": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index a74a86d647bd..453310e2859a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "new.expensify", - "version": "1.4.56-8", + "version": "1.4.57-0", "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.",