From dded6349ee50d371ed5c920a4c3334700ad1d537 Mon Sep 17 00:00:00 2001 From: Shubham Agrawal Date: Tue, 19 Dec 2023 21:55:13 +0530 Subject: [PATCH 001/167] test map when image is not loaded in request view --- .../ReportActionItem/MoneyRequestPreview.js | 10 +++++++++- src/components/ReportActionItem/MoneyRequestView.js | 13 ++++++++++++- src/libs/actions/IOU.js | 3 +++ 3 files changed, 24 insertions(+), 2 deletions(-) diff --git a/src/components/ReportActionItem/MoneyRequestPreview.js b/src/components/ReportActionItem/MoneyRequestPreview.js index 12c6d0629370..1d798130dfd5 100644 --- a/src/components/ReportActionItem/MoneyRequestPreview.js +++ b/src/components/ReportActionItem/MoneyRequestPreview.js @@ -38,6 +38,7 @@ import CONST from '@src/CONST'; import * as Localize from '@src/libs/Localize'; import ONYXKEYS from '@src/ONYXKEYS'; import ReportActionItemImages from './ReportActionItemImages'; +import ConfirmedRoute from '@components/ConfirmedRoute'; const propTypes = { /** The active IOUReport, used for Onyx subscription */ @@ -169,6 +170,8 @@ function MoneyRequestPreview(props) { const hasPendingWaypoints = lodashGet(props.transaction, 'pendingFields.waypoints', null); + const showMapAsImage = isDistanceRequest && hasPendingWaypoints; + const getSettledMessage = () => { if (isExpensifyCardTransaction) { return translate('common.done'); @@ -257,7 +260,12 @@ function MoneyRequestPreview(props) { !props.onPreviewPressed ? [styles.moneyRequestPreviewBox, ...props.containerStyles] : {}, ]} > - {hasReceipt && ( + {showMapAsImage && ( + + + + )} + {!showMapAsImage && hasReceipt && ( - {hasReceipt && ( + {showMapAsImage && ( + + + + + + )} + {!showMapAsImage && hasReceipt && ( Date: Tue, 2 Jan 2024 21:31:37 +0100 Subject: [PATCH 002/167] fix: adding backTo param to ReportParticipantsPage.js --- src/pages/ReportParticipantsPage.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/pages/ReportParticipantsPage.js b/src/pages/ReportParticipantsPage.js index e04ffbb352fc..1e84bd3dcbbb 100755 --- a/src/pages/ReportParticipantsPage.js +++ b/src/pages/ReportParticipantsPage.js @@ -121,7 +121,12 @@ function ReportParticipantsPage(props) { }, ]} onSelectRow={(option) => { - Navigation.navigate(ROUTES.PROFILE.getRoute(option.accountID)); + Navigation.navigate( + ROUTES.PROFILE.getRoute( + option.accountID, + ROUTES.REPORT_PARTICIPANTS.getRoute(props.report.reportID) + ) + ); }} hideSectionHeaders showTitleTooltip From ef26aaa1d61d8b25ae43ed2deb9cbc0c589d74b5 Mon Sep 17 00:00:00 2001 From: Shubham Agrawal Date: Tue, 9 Jan 2024 17:49:16 +0530 Subject: [PATCH 003/167] test changes --- src/components/ReportActionItem/MoneyRequestPreview.js | 2 +- src/components/ReportActionItem/MoneyRequestView.js | 2 +- src/libs/TransactionUtils.ts | 7 +++++-- src/libs/actions/IOU.js | 4 +++- src/types/onyx/Transaction.ts | 6 ++++-- 5 files changed, 14 insertions(+), 7 deletions(-) diff --git a/src/components/ReportActionItem/MoneyRequestPreview.js b/src/components/ReportActionItem/MoneyRequestPreview.js index 0663441c3834..9bba3aed205a 100644 --- a/src/components/ReportActionItem/MoneyRequestPreview.js +++ b/src/components/ReportActionItem/MoneyRequestPreview.js @@ -38,8 +38,8 @@ import * as Report from '@userActions/Report'; import CONST from '@src/CONST'; import * as Localize from '@src/libs/Localize'; import ONYXKEYS from '@src/ONYXKEYS'; -import ReportActionItemImages from './ReportActionItemImages'; import ConfirmedRoute from '@components/ConfirmedRoute'; +import ReportActionItemImages from './ReportActionItemImages'; const propTypes = { /** The active IOUReport, used for Onyx subscription */ diff --git a/src/components/ReportActionItem/MoneyRequestView.js b/src/components/ReportActionItem/MoneyRequestView.js index eb658a7f8a1b..fc70b47d7101 100644 --- a/src/components/ReportActionItem/MoneyRequestView.js +++ b/src/components/ReportActionItem/MoneyRequestView.js @@ -42,8 +42,8 @@ import * as IOU from '@userActions/IOU'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; -import ReportActionItemImage from './ReportActionItemImage'; import ConfirmedRoute from '@components/ConfirmedRoute'; +import ReportActionItemImage from './ReportActionItemImage'; const violationNames = lodashValues(CONST.VIOLATIONS); diff --git a/src/libs/TransactionUtils.ts b/src/libs/TransactionUtils.ts index c34a6753c1d5..b8fad803d957 100644 --- a/src/libs/TransactionUtils.ts +++ b/src/libs/TransactionUtils.ts @@ -1,5 +1,6 @@ import lodashHas from 'lodash/has'; import type {OnyxCollection, OnyxEntry} from 'react-native-onyx'; +import type {EmptyObject} from '@src/types/utils/EmptyObject'; import Onyx from 'react-native-onyx'; import type {ValueOf} from 'type-fest'; import CONST from '@src/CONST'; @@ -7,8 +8,8 @@ import ONYXKEYS from '@src/ONYXKEYS'; import type {RecentWaypoint, Report, ReportAction, Transaction} from '@src/types/onyx'; import type {PolicyTaxRates} from '@src/types/onyx/PolicyTaxRates'; import type PolicyTaxRate from '@src/types/onyx/PolicyTaxRates'; -import type {Comment, Receipt, Waypoint, WaypointCollection} from '@src/types/onyx/Transaction'; -import type {EmptyObject} from '@src/types/utils/EmptyObject'; +import type {Comment, PendingFieldsCollection, Receipt, Waypoint, WaypointCollection} from '@src/types/onyx/Transaction'; +import {isNotEmptyObject} from '@src/types/utils/EmptyObject'; import {isCorporateCard, isExpensifyCard} from './CardUtils'; import DateUtils from './DateUtils'; import * as NumberUtils from './NumberUtils'; @@ -98,6 +99,7 @@ function buildOptimisticTransaction( category = '', tag = '', billable = false, + pendingFields: PendingFieldsCollection | null = null, ): Transaction { // transactionIDs are random, positive, 64-bit numeric strings. // Because JS can only handle 53-bit numbers, transactionIDs are strings in the front-end (just like reportActionID) @@ -112,6 +114,7 @@ function buildOptimisticTransaction( } return { + ...(isNotEmptyObject(pendingFields) ? {pendingFields} : {}), transactionID, amount, currency, diff --git a/src/libs/actions/IOU.js b/src/libs/actions/IOU.js index 4e1a45101732..f4ff83e995c8 100644 --- a/src/libs/actions/IOU.js +++ b/src/libs/actions/IOU.js @@ -721,6 +721,8 @@ function getMoneyRequestInformation( receiptObject.state = receipt.state || CONST.IOU.RECEIPT_STATE.SCANREADY; filename = receipt.name; } + const existingTransaction = allTransactionDrafts[`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${CONST.IOU.OPTIMISTIC_TRANSACTION_ID}`]; + const isDistanceRequest = existingTransaction && existingTransaction.iouRequestType === CONST.IOU.REQUEST_TYPE.DISTANCE let optimisticTransaction = TransactionUtils.buildOptimisticTransaction( ReportUtils.isExpenseReport(iouReport) ? -amount : amount, currency, @@ -736,6 +738,7 @@ function getMoneyRequestInformation( category, tag, billable, + isDistanceRequest ? {waypoints: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD} : null, ); const optimisticPolicyRecentlyUsedCategories = Policy.buildOptimisticPolicyRecentlyUsedCategories(iouReport.policyID, category); @@ -747,7 +750,6 @@ function getMoneyRequestInformation( // data. This is a big can of worms to change it to `Onyx.merge()` as explored in https://expensify.slack.com/archives/C05DWUDHVK7/p1692139468252109. // I want to clean this up at some point, but it's possible this will live in the code for a while so I've created https://github.com/Expensify/App/issues/25417 // to remind me to do this. - const existingTransaction = allTransactionDrafts[`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${CONST.IOU.OPTIMISTIC_TRANSACTION_ID}`]; if (existingTransaction && existingTransaction.iouRequestType === CONST.IOU.REQUEST_TYPE.DISTANCE) { optimisticTransaction = OnyxUtils.fastMerge(existingTransaction, optimisticTransaction); // pendingFields: { diff --git a/src/types/onyx/Transaction.ts b/src/types/onyx/Transaction.ts index 8b7e26280305..a6b65f7cba38 100644 --- a/src/types/onyx/Transaction.ts +++ b/src/types/onyx/Transaction.ts @@ -49,6 +49,8 @@ type Route = { type Routes = Record; +type PendingFieldsCollection = Partial<{[K in keyof Transaction | keyof Comment]: ValueOf}>; + type Transaction = { amount: number; billable: boolean; @@ -76,7 +78,7 @@ type Transaction = { routes?: Routes; transactionID: string; tag: string; - pendingFields?: Partial<{[K in keyof Transaction | keyof Comment]: ValueOf}>; + pendingFields?: PendingFieldsCollection; /** Card Transactions */ @@ -97,4 +99,4 @@ type Transaction = { }; export default Transaction; -export type {WaypointCollection, Comment, Receipt, Waypoint}; +export type {WaypointCollection, Comment, Receipt, Waypoint, PendingFieldsCollection}; From 54a63d643b9ad602ace915090c3c18cae28af5b0 Mon Sep 17 00:00:00 2001 From: Shubham Agrawal Date: Tue, 9 Jan 2024 18:07:40 +0530 Subject: [PATCH 004/167] fix lint --- src/components/ReportActionItem/MoneyRequestPreview.js | 2 +- src/components/ReportActionItem/MoneyRequestView.js | 2 +- src/libs/TransactionUtils.ts | 2 +- src/libs/actions/IOU.js | 8 ++++---- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/components/ReportActionItem/MoneyRequestPreview.js b/src/components/ReportActionItem/MoneyRequestPreview.js index 9bba3aed205a..84ed317be294 100644 --- a/src/components/ReportActionItem/MoneyRequestPreview.js +++ b/src/components/ReportActionItem/MoneyRequestPreview.js @@ -5,6 +5,7 @@ import React from 'react'; import {View} from 'react-native'; import {withOnyx} from 'react-native-onyx'; import _ from 'underscore'; +import ConfirmedRoute from '@components/ConfirmedRoute'; import Icon from '@components/Icon'; import * as Expensicons from '@components/Icon/Expensicons'; import MoneyRequestSkeletonView from '@components/MoneyRequestSkeletonView'; @@ -38,7 +39,6 @@ import * as Report from '@userActions/Report'; import CONST from '@src/CONST'; import * as Localize from '@src/libs/Localize'; import ONYXKEYS from '@src/ONYXKEYS'; -import ConfirmedRoute from '@components/ConfirmedRoute'; import ReportActionItemImages from './ReportActionItemImages'; const propTypes = { diff --git a/src/components/ReportActionItem/MoneyRequestView.js b/src/components/ReportActionItem/MoneyRequestView.js index fc70b47d7101..04b8d35e3448 100644 --- a/src/components/ReportActionItem/MoneyRequestView.js +++ b/src/components/ReportActionItem/MoneyRequestView.js @@ -5,6 +5,7 @@ import React, {useCallback} from 'react'; import {View} from 'react-native'; import {withOnyx} from 'react-native-onyx'; import categoryPropTypes from '@components/categoryPropTypes'; +import ConfirmedRoute from '@components/ConfirmedRoute'; import * as Expensicons from '@components/Icon/Expensicons'; import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription'; import OfflineWithFeedback from '@components/OfflineWithFeedback'; @@ -42,7 +43,6 @@ import * as IOU from '@userActions/IOU'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; -import ConfirmedRoute from '@components/ConfirmedRoute'; import ReportActionItemImage from './ReportActionItemImage'; const violationNames = lodashValues(CONST.VIOLATIONS); diff --git a/src/libs/TransactionUtils.ts b/src/libs/TransactionUtils.ts index b8fad803d957..4155fe426f5a 100644 --- a/src/libs/TransactionUtils.ts +++ b/src/libs/TransactionUtils.ts @@ -1,6 +1,5 @@ import lodashHas from 'lodash/has'; import type {OnyxCollection, OnyxEntry} from 'react-native-onyx'; -import type {EmptyObject} from '@src/types/utils/EmptyObject'; import Onyx from 'react-native-onyx'; import type {ValueOf} from 'type-fest'; import CONST from '@src/CONST'; @@ -9,6 +8,7 @@ import type {RecentWaypoint, Report, ReportAction, Transaction} from '@src/types import type {PolicyTaxRates} from '@src/types/onyx/PolicyTaxRates'; import type PolicyTaxRate from '@src/types/onyx/PolicyTaxRates'; import type {Comment, PendingFieldsCollection, Receipt, Waypoint, WaypointCollection} from '@src/types/onyx/Transaction'; +import type {EmptyObject} from '@src/types/utils/EmptyObject'; import {isNotEmptyObject} from '@src/types/utils/EmptyObject'; import {isCorporateCard, isExpensifyCard} from './CardUtils'; import DateUtils from './DateUtils'; diff --git a/src/libs/actions/IOU.js b/src/libs/actions/IOU.js index f4ff83e995c8..f004b44feca2 100644 --- a/src/libs/actions/IOU.js +++ b/src/libs/actions/IOU.js @@ -722,7 +722,7 @@ function getMoneyRequestInformation( filename = receipt.name; } const existingTransaction = allTransactionDrafts[`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${CONST.IOU.OPTIMISTIC_TRANSACTION_ID}`]; - const isDistanceRequest = existingTransaction && existingTransaction.iouRequestType === CONST.IOU.REQUEST_TYPE.DISTANCE + const isDistanceRequest = existingTransaction && existingTransaction.iouRequestType === CONST.IOU.REQUEST_TYPE.DISTANCE; let optimisticTransaction = TransactionUtils.buildOptimisticTransaction( ReportUtils.isExpenseReport(iouReport) ? -amount : amount, currency, @@ -752,9 +752,9 @@ function getMoneyRequestInformation( // to remind me to do this. if (existingTransaction && existingTransaction.iouRequestType === CONST.IOU.REQUEST_TYPE.DISTANCE) { optimisticTransaction = OnyxUtils.fastMerge(existingTransaction, optimisticTransaction); -// pendingFields: { -// waypoints: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, -// } + // pendingFields: { + // waypoints: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, + // } } // STEP 4: Build optimistic reportActions. We need: From 46141e379c495127f8287f3ca15a771c4eba63df Mon Sep 17 00:00:00 2001 From: Shubham Agrawal Date: Tue, 9 Jan 2024 18:09:37 +0530 Subject: [PATCH 005/167] fix lint --- src/libs/actions/IOU.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/libs/actions/IOU.js b/src/libs/actions/IOU.js index f004b44feca2..d68b33e6b5ef 100644 --- a/src/libs/actions/IOU.js +++ b/src/libs/actions/IOU.js @@ -750,11 +750,8 @@ function getMoneyRequestInformation( // data. This is a big can of worms to change it to `Onyx.merge()` as explored in https://expensify.slack.com/archives/C05DWUDHVK7/p1692139468252109. // I want to clean this up at some point, but it's possible this will live in the code for a while so I've created https://github.com/Expensify/App/issues/25417 // to remind me to do this. - if (existingTransaction && existingTransaction.iouRequestType === CONST.IOU.REQUEST_TYPE.DISTANCE) { + if (isDistanceRequest) { optimisticTransaction = OnyxUtils.fastMerge(existingTransaction, optimisticTransaction); - // pendingFields: { - // waypoints: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, - // } } // STEP 4: Build optimistic reportActions. We need: From b7045ec7091f7aba9d94939ea654c3ba5cc59b06 Mon Sep 17 00:00:00 2001 From: Antony Kithinzi Date: Fri, 12 Jan 2024 16:05:21 -0500 Subject: [PATCH 006/167] fix: adding backTo param to ReportParticipantsPage.js --- src/pages/ReportParticipantsPage.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/pages/ReportParticipantsPage.js b/src/pages/ReportParticipantsPage.js index 7dbc1c7036c4..9e480d2f0516 100755 --- a/src/pages/ReportParticipantsPage.js +++ b/src/pages/ReportParticipantsPage.js @@ -121,7 +121,12 @@ function ReportParticipantsPage(props) { }, ]} onSelectRow={(option) => { - Navigation.navigate(ROUTES.PROFILE.getRoute(option.accountID)); + Navigation.navigate( + ROUTES.PROFILE.getRoute( + option.accountID, + ROUTES.REPORT_PARTICIPANTS.getRoute(props.report.reportID) + ) + ); }} hideSectionHeaders showTitleTooltip From e7b85131efe677ac38f177262f3c51b512643b82 Mon Sep 17 00:00:00 2001 From: Antony Kithinzi Date: Sat, 13 Jan 2024 04:50:32 +0100 Subject: [PATCH 007/167] fmt: prettier --- src/pages/ReportParticipantsPage.js | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/pages/ReportParticipantsPage.js b/src/pages/ReportParticipantsPage.js index 9e480d2f0516..3bc2783db981 100755 --- a/src/pages/ReportParticipantsPage.js +++ b/src/pages/ReportParticipantsPage.js @@ -121,12 +121,7 @@ function ReportParticipantsPage(props) { }, ]} onSelectRow={(option) => { - Navigation.navigate( - ROUTES.PROFILE.getRoute( - option.accountID, - ROUTES.REPORT_PARTICIPANTS.getRoute(props.report.reportID) - ) - ); + Navigation.navigate(ROUTES.PROFILE.getRoute(option.accountID, ROUTES.REPORT_PARTICIPANTS.getRoute(props.report.reportID))); }} hideSectionHeaders showTitleTooltip From d1b5b355b1986240abe3e76c60977324efc24a1a Mon Sep 17 00:00:00 2001 From: Antony Kithinzi Date: Thu, 18 Jan 2024 23:55:12 +0100 Subject: [PATCH 008/167] fix: added onBackButtonPress prop --- src/pages/ReportParticipantsPage.js | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/pages/ReportParticipantsPage.js b/src/pages/ReportParticipantsPage.js index 9e480d2f0516..80253c1f1793 100755 --- a/src/pages/ReportParticipantsPage.js +++ b/src/pages/ReportParticipantsPage.js @@ -99,6 +99,7 @@ function ReportParticipantsPage(props) { {({safeAreaPaddingBottomStyle}) => ( Navigation.goBack(ROUTES.REPORT_WITH_ID_DETAILS.getRoute(props.report.reportID))} title={props.translate( ReportUtils.isChatRoom(props.report) || ReportUtils.isPolicyExpenseChat(props.report) || @@ -121,12 +122,7 @@ function ReportParticipantsPage(props) { }, ]} onSelectRow={(option) => { - Navigation.navigate( - ROUTES.PROFILE.getRoute( - option.accountID, - ROUTES.REPORT_PARTICIPANTS.getRoute(props.report.reportID) - ) - ); + Navigation.navigate(ROUTES.PROFILE.getRoute(option.accountID, ROUTES.REPORT_PARTICIPANTS.getRoute(props.report.reportID))); }} hideSectionHeaders showTitleTooltip From be5367fc5e9078c60afeefa7477889ada34a6838 Mon Sep 17 00:00:00 2001 From: Shubham Agrawal Date: Mon, 22 Jan 2024 20:13:45 +0530 Subject: [PATCH 009/167] ts fixes --- src/libs/TransactionUtils.ts | 6 +++--- tests/ui/UnreadIndicatorsTest.js | 4 ++++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/libs/TransactionUtils.ts b/src/libs/TransactionUtils.ts index 2e8207db860a..813bb128cb84 100644 --- a/src/libs/TransactionUtils.ts +++ b/src/libs/TransactionUtils.ts @@ -9,7 +9,7 @@ import type {PolicyTaxRates} from '@src/types/onyx/PolicyTaxRates'; import type PolicyTaxRate from '@src/types/onyx/PolicyTaxRates'; import type {Comment, PendingFieldsCollection, Receipt, Waypoint, WaypointCollection} from '@src/types/onyx/Transaction'; import type {EmptyObject} from '@src/types/utils/EmptyObject'; -import {isNotEmptyObject} from '@src/types/utils/EmptyObject'; +import {isEmptyObject} from '@src/types/utils/EmptyObject'; import {isCorporateCard, isExpensifyCard} from './CardUtils'; import DateUtils from './DateUtils'; import * as NumberUtils from './NumberUtils'; @@ -100,7 +100,7 @@ function buildOptimisticTransaction( category = '', tag = '', billable = false, - pendingFields: PendingFieldsCollection | null = null, + pendingFields: PendingFieldsCollection | undefined = undefined, ): Transaction { // transactionIDs are random, positive, 64-bit numeric strings. // Because JS can only handle 53-bit numbers, transactionIDs are strings in the front-end (just like reportActionID) @@ -115,7 +115,7 @@ function buildOptimisticTransaction( } return { - ...(isNotEmptyObject(pendingFields) ? {pendingFields} : {}), + ...(!isEmptyObject(pendingFields) ? {pendingFields} : {}), transactionID, amount, currency, diff --git a/tests/ui/UnreadIndicatorsTest.js b/tests/ui/UnreadIndicatorsTest.js index e4d4d877f66b..88576f3dc89b 100644 --- a/tests/ui/UnreadIndicatorsTest.js +++ b/tests/ui/UnreadIndicatorsTest.js @@ -24,12 +24,16 @@ import appSetup from '../../src/setup'; import * as TestHelper from '../utils/TestHelper'; import waitForBatchedUpdates from '../utils/waitForBatchedUpdates'; import waitForBatchedUpdatesWithAct from '../utils/waitForBatchedUpdatesWithAct'; +import PendingMapView from '../../src/components/MapView/PendingMapView'; // We need a large timeout here as we are lazy loading React Navigation screens and this test is running against the entire mounted App jest.setTimeout(30000); jest.mock('../../src/libs/Notification/LocalNotification'); jest.mock('../../src/components/Icon/Expensicons'); +jest.mock('../../src/components/ConfirmedRoute.tsx', () => ( + +)); // Needed for: https://stackoverflow.com/questions/76903168/mocking-libraries-in-jest jest.mock('react-native/Libraries/LogBox/LogBox', () => ({ From e255ec88eb5f77c8e5b0a77a05ec4693afd66199 Mon Sep 17 00:00:00 2001 From: Shubham Agrawal Date: Mon, 22 Jan 2024 20:25:05 +0530 Subject: [PATCH 010/167] test fix --- tests/ui/UnreadIndicatorsTest.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/tests/ui/UnreadIndicatorsTest.js b/tests/ui/UnreadIndicatorsTest.js index 88576f3dc89b..01a3d735104b 100644 --- a/tests/ui/UnreadIndicatorsTest.js +++ b/tests/ui/UnreadIndicatorsTest.js @@ -24,16 +24,13 @@ import appSetup from '../../src/setup'; import * as TestHelper from '../utils/TestHelper'; import waitForBatchedUpdates from '../utils/waitForBatchedUpdates'; import waitForBatchedUpdatesWithAct from '../utils/waitForBatchedUpdatesWithAct'; -import PendingMapView from '../../src/components/MapView/PendingMapView'; // We need a large timeout here as we are lazy loading React Navigation screens and this test is running against the entire mounted App jest.setTimeout(30000); jest.mock('../../src/libs/Notification/LocalNotification'); jest.mock('../../src/components/Icon/Expensicons'); -jest.mock('../../src/components/ConfirmedRoute.tsx', () => ( - -)); +jest.mock('../../src/components/ConfirmedRoute.tsx'); // Needed for: https://stackoverflow.com/questions/76903168/mocking-libraries-in-jest jest.mock('react-native/Libraries/LogBox/LogBox', () => ({ From 17cb86a947002e25768b4cd2db2eac268cb4a569 Mon Sep 17 00:00:00 2001 From: Shubham Agrawal Date: Mon, 22 Jan 2024 20:29:58 +0530 Subject: [PATCH 011/167] test fix attempt 2 --- tests/ui/UnreadIndicatorsTest.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ui/UnreadIndicatorsTest.js b/tests/ui/UnreadIndicatorsTest.js index 01a3d735104b..2241711497ff 100644 --- a/tests/ui/UnreadIndicatorsTest.js +++ b/tests/ui/UnreadIndicatorsTest.js @@ -30,7 +30,7 @@ jest.setTimeout(30000); jest.mock('../../src/libs/Notification/LocalNotification'); jest.mock('../../src/components/Icon/Expensicons'); -jest.mock('../../src/components/ConfirmedRoute.tsx'); +jest.mock('../../src/components/ConfirmedRoute.tsx', (props) => props.children); // Needed for: https://stackoverflow.com/questions/76903168/mocking-libraries-in-jest jest.mock('react-native/Libraries/LogBox/LogBox', () => ({ From c7165ddb967bf655bfb8843d50d051bbd5b72e53 Mon Sep 17 00:00:00 2001 From: Shubham Agrawal Date: Mon, 22 Jan 2024 20:45:19 +0530 Subject: [PATCH 012/167] test fix attempt 3 --- tests/ui/UnreadIndicatorsTest.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/ui/UnreadIndicatorsTest.js b/tests/ui/UnreadIndicatorsTest.js index 2241711497ff..363c899d4328 100644 --- a/tests/ui/UnreadIndicatorsTest.js +++ b/tests/ui/UnreadIndicatorsTest.js @@ -30,7 +30,10 @@ jest.setTimeout(30000); jest.mock('../../src/libs/Notification/LocalNotification'); jest.mock('../../src/components/Icon/Expensicons'); -jest.mock('../../src/components/ConfirmedRoute.tsx', (props) => props.children); +jest.doMock('../../src/components/ConfirmedRoute.tsx', () => { + const Comp = (props) => props.children; + return Comp; +}); // Needed for: https://stackoverflow.com/questions/76903168/mocking-libraries-in-jest jest.mock('react-native/Libraries/LogBox/LogBox', () => ({ From b0068d381f1e212f131fe04a7ca3107a5bf2b274 Mon Sep 17 00:00:00 2001 From: Shubham Agrawal Date: Mon, 22 Jan 2024 20:50:55 +0530 Subject: [PATCH 013/167] perf-test fix --- tests/perf-test/ReportActionsList.perf-test.js | 5 +++++ tests/perf-test/ReportScreen.perf-test.js | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/tests/perf-test/ReportActionsList.perf-test.js b/tests/perf-test/ReportActionsList.perf-test.js index 8e3312cfa4c7..515447a7a2ed 100644 --- a/tests/perf-test/ReportActionsList.perf-test.js +++ b/tests/perf-test/ReportActionsList.perf-test.js @@ -44,6 +44,11 @@ jest.mock('@react-navigation/native', () => { }; }); +jest.doMock('../../src/components/ConfirmedRoute.tsx', () => { + const Comp = (props) => props.children; + return Comp; +}); + beforeAll(() => Onyx.init({ keys: ONYXKEYS, diff --git a/tests/perf-test/ReportScreen.perf-test.js b/tests/perf-test/ReportScreen.perf-test.js index d58f71fa7ab4..97ea04ff55fb 100644 --- a/tests/perf-test/ReportScreen.perf-test.js +++ b/tests/perf-test/ReportScreen.perf-test.js @@ -29,6 +29,11 @@ jest.mock('react-native-reanimated', () => ({ useAnimatedRef: jest.fn, })); +jest.doMock('../../src/components/ConfirmedRoute.tsx', () => { + const Comp = (props) => props.children; + return Comp; +}); + jest.mock('../../src/components/withNavigationFocus', () => (Component) => { function WithNavigationFocus(props) { return ( From 365d37967684c85c0c059744637748346c4f82a6 Mon Sep 17 00:00:00 2001 From: Shubham Agrawal Date: Mon, 22 Jan 2024 23:06:12 +0530 Subject: [PATCH 014/167] perf-test fix attempt 2 --- src/components/__mocks__/ConfirmedRoute.tsx | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 src/components/__mocks__/ConfirmedRoute.tsx diff --git a/src/components/__mocks__/ConfirmedRoute.tsx b/src/components/__mocks__/ConfirmedRoute.tsx new file mode 100644 index 000000000000..a759a2c1e193 --- /dev/null +++ b/src/components/__mocks__/ConfirmedRoute.tsx @@ -0,0 +1,8 @@ +import {View} from "react-native"; + +// eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any +function ConfirmedRoute(props: any){ + return +} + +export default ConfirmedRoute; \ No newline at end of file From fb5a70ef1a038cffa40e8c001c020b489f04c5e3 Mon Sep 17 00:00:00 2001 From: Shubham Agrawal Date: Mon, 22 Jan 2024 23:30:26 +0530 Subject: [PATCH 015/167] perf-test fix attempt 3 --- jest.config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jest.config.js b/jest.config.js index de7ed4b1f974..b5335f07482f 100644 --- a/jest.config.js +++ b/jest.config.js @@ -8,7 +8,7 @@ module.exports = { `/?(*.)+(spec|test).${testFileExtension}`, ], transform: { - '^.+\\.jsx?$': 'babel-jest', + '^.+\\.[jt]sx?$': 'babel-jest', '^.+\\.svg?$': 'jest-transformer-svg', }, transformIgnorePatterns: ['/node_modules/(?!react-native)/'], From adb33f65224f4c82df7a375fdb0628e71a768010 Mon Sep 17 00:00:00 2001 From: Shubham Agrawal Date: Tue, 23 Jan 2024 07:25:37 +0530 Subject: [PATCH 016/167] perf-test fix attempt 4 --- tests/perf-test/ReportActionsList.perf-test.js | 5 +---- tests/perf-test/ReportScreen.perf-test.js | 5 +---- tests/ui/UnreadIndicatorsTest.js | 5 +---- 3 files changed, 3 insertions(+), 12 deletions(-) diff --git a/tests/perf-test/ReportActionsList.perf-test.js b/tests/perf-test/ReportActionsList.perf-test.js index 515447a7a2ed..c81c4aa51df8 100644 --- a/tests/perf-test/ReportActionsList.perf-test.js +++ b/tests/perf-test/ReportActionsList.perf-test.js @@ -44,10 +44,7 @@ jest.mock('@react-navigation/native', () => { }; }); -jest.doMock('../../src/components/ConfirmedRoute.tsx', () => { - const Comp = (props) => props.children; - return Comp; -}); +jest.mock('../../src/components/ConfirmedRoute.tsx'); beforeAll(() => Onyx.init({ diff --git a/tests/perf-test/ReportScreen.perf-test.js b/tests/perf-test/ReportScreen.perf-test.js index 97ea04ff55fb..faa72fd3a367 100644 --- a/tests/perf-test/ReportScreen.perf-test.js +++ b/tests/perf-test/ReportScreen.perf-test.js @@ -29,10 +29,7 @@ jest.mock('react-native-reanimated', () => ({ useAnimatedRef: jest.fn, })); -jest.doMock('../../src/components/ConfirmedRoute.tsx', () => { - const Comp = (props) => props.children; - return Comp; -}); +jest.mock('../../src/components/ConfirmedRoute.tsx'); jest.mock('../../src/components/withNavigationFocus', () => (Component) => { function WithNavigationFocus(props) { diff --git a/tests/ui/UnreadIndicatorsTest.js b/tests/ui/UnreadIndicatorsTest.js index 363c899d4328..01a3d735104b 100644 --- a/tests/ui/UnreadIndicatorsTest.js +++ b/tests/ui/UnreadIndicatorsTest.js @@ -30,10 +30,7 @@ jest.setTimeout(30000); jest.mock('../../src/libs/Notification/LocalNotification'); jest.mock('../../src/components/Icon/Expensicons'); -jest.doMock('../../src/components/ConfirmedRoute.tsx', () => { - const Comp = (props) => props.children; - return Comp; -}); +jest.mock('../../src/components/ConfirmedRoute.tsx'); // Needed for: https://stackoverflow.com/questions/76903168/mocking-libraries-in-jest jest.mock('react-native/Libraries/LogBox/LogBox', () => ({ From 94c115adec14ae658d098d2d4e0a794e7da411fd Mon Sep 17 00:00:00 2001 From: Shubham Agrawal Date: Tue, 23 Jan 2024 08:16:55 +0530 Subject: [PATCH 017/167] fix lint --- src/components/__mocks__/ConfirmedRoute.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/components/__mocks__/ConfirmedRoute.tsx b/src/components/__mocks__/ConfirmedRoute.tsx index a759a2c1e193..3c78e764ebea 100644 --- a/src/components/__mocks__/ConfirmedRoute.tsx +++ b/src/components/__mocks__/ConfirmedRoute.tsx @@ -1,8 +1,8 @@ -import {View} from "react-native"; +import {View} from 'react-native'; // eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any -function ConfirmedRoute(props: any){ - return +function ConfirmedRoute(props: any) { + return ; } -export default ConfirmedRoute; \ No newline at end of file +export default ConfirmedRoute; From 16bd5cdba5e545a808601004be02b71cb7c94104 Mon Sep 17 00:00:00 2001 From: MrRefactor Date: Mon, 29 Jan 2024 16:40:22 +0100 Subject: [PATCH 018/167] Fix always scrollable suggestion list --- .../BaseAutoCompleteSuggestions.tsx | 7 ++++++- src/styles/utils/index.ts | 16 +++++++++++++--- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/src/components/AutoCompleteSuggestions/BaseAutoCompleteSuggestions.tsx b/src/components/AutoCompleteSuggestions/BaseAutoCompleteSuggestions.tsx index 5da9c6981603..72ef6ef2f061 100644 --- a/src/components/AutoCompleteSuggestions/BaseAutoCompleteSuggestions.tsx +++ b/src/components/AutoCompleteSuggestions/BaseAutoCompleteSuggestions.tsx @@ -10,6 +10,8 @@ import PressableWithFeedback from '@components/Pressable/PressableWithFeedback'; import useStyleUtils from '@hooks/useStyleUtils'; import useThemeStyles from '@hooks/useThemeStyles'; import useWindowDimensions from '@hooks/useWindowDimensions'; +import * as Browser from '@libs/Browser'; +import getPlatform from '@libs/getPlatform'; import variables from '@styles/variables'; import CONST from '@src/CONST'; import viewForwardedRef from '@src/types/utils/viewForwardedRef'; @@ -47,6 +49,9 @@ function BaseAutoCompleteSuggestions( const StyleUtils = useStyleUtils(); const rowHeight = useSharedValue(0); const scrollRef = useRef>(null); + const platform = getPlatform(); + const isMobileSafari = Browser.isMobileSafari(); + /** * Render a suggestion menu item component. */ @@ -67,7 +72,7 @@ function BaseAutoCompleteSuggestions( ); const innerHeight = CONST.AUTO_COMPLETE_SUGGESTER.SUGGESTION_ROW_HEIGHT * suggestions.length; - const animatedStyles = useAnimatedStyle(() => StyleUtils.getAutoCompleteSuggestionContainerStyle(rowHeight.value)); + const animatedStyles = useAnimatedStyle(() => StyleUtils.getAutoCompleteSuggestionContainerStyle(rowHeight.value, platform, isMobileSafari)); const estimatedListSize = useMemo( () => ({ height: CONST.AUTO_COMPLETE_SUGGESTER.SUGGESTION_ROW_HEIGHT * suggestions.length, diff --git a/src/styles/utils/index.ts b/src/styles/utils/index.ts index 8b040dd8d72c..30b1245ebb5a 100644 --- a/src/styles/utils/index.ts +++ b/src/styles/utils/index.ts @@ -4,6 +4,7 @@ import type {OnyxEntry} from 'react-native-onyx'; import type {EdgeInsets} from 'react-native-safe-area-context'; import type {ValueOf} from 'type-fest'; import * as Browser from '@libs/Browser'; +import type Platform from '@libs/getPlatform/types'; import * as UserUtils from '@libs/UserUtils'; // eslint-disable-next-line no-restricted-imports import {defaultTheme} from '@styles/theme'; @@ -792,17 +793,26 @@ function getBaseAutoCompleteSuggestionContainerStyle({left, bottom, width}: GetB /** * Gets the correct position for auto complete suggestion container */ -function getAutoCompleteSuggestionContainerStyle(itemsHeight: number): ViewStyle { +function getAutoCompleteSuggestionContainerStyle(itemsHeight: number, platform: Platform, isMobileSafari: boolean): ViewStyle { 'worklet'; + // This if condition is reverting the workaround for broken scroll on all platforms but native android and iOS safari, where the issue with + // scrolling char behind suggestion list is occuring. Rewerting the fix resolves the issue with always scrollable list on other platforms. const borderWidth = 2; - const height = itemsHeight + 2 * CONST.AUTO_COMPLETE_SUGGESTER.SUGGESTER_INNER_PADDING; + let height = itemsHeight + 2 * CONST.AUTO_COMPLETE_SUGGESTER.SUGGESTER_INNER_PADDING; + let top = -(height + CONST.AUTO_COMPLETE_SUGGESTER.SUGGESTER_PADDING); + + if (platform === 'android' || isMobileSafari) { + top += borderWidth; + } else { + height += borderWidth; + } // The suggester is positioned absolutely within the component that includes the input and RecipientLocalTime view (for non-expanded mode only). To position it correctly, // we need to shift it by the suggester's height plus its padding and, if applicable, the height of the RecipientLocalTime view. return { overflow: 'hidden', - top: -(height + CONST.AUTO_COMPLETE_SUGGESTER.SUGGESTER_PADDING + borderWidth), + top, height, minHeight: CONST.AUTO_COMPLETE_SUGGESTER.SUGGESTION_ROW_HEIGHT, }; From dd639d421c6a7db84a69fe02858e3acb8a502cb4 Mon Sep 17 00:00:00 2001 From: DylanDylann Date: Tue, 30 Jan 2024 01:20:15 +0700 Subject: [PATCH 019/167] fix Inconsistent validation error message for required field in home address --- src/components/CountrySelector.tsx | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/components/CountrySelector.tsx b/src/components/CountrySelector.tsx index 589530cd7879..398809d79a2c 100644 --- a/src/components/CountrySelector.tsx +++ b/src/components/CountrySelector.tsx @@ -1,4 +1,5 @@ -import React, {forwardRef, useEffect} from 'react'; +import {useIsFocused} from '@react-navigation/native'; +import React, {forwardRef, useEffect, useRef} from 'react'; import type {ForwardedRef} from 'react'; import {View} from 'react-native'; import useLocalize from '@hooks/useLocalize'; @@ -24,13 +25,22 @@ type CountrySelectorProps = { inputID: string; }; -function CountrySelector({errorText = '', value: countryCode, onInputChange}: CountrySelectorProps, ref: ForwardedRef) { +function CountrySelector({errorText = '', value: countryCode, onInputChange, ...rest}: CountrySelectorProps, ref: ForwardedRef) { const styles = useThemeStyles(); const {translate} = useLocalize(); const title = countryCode ? translate(`allCountries.${countryCode}`) : ''; const countryTitleDescStyle = title.length === 0 ? styles.textNormal : null; + const didOpenContrySelector = useRef(false); + const isFocus = useIsFocused(); + useEffect(() => { + if (isFocus && didOpenContrySelector.current) { + didOpenContrySelector.current = false; + rest.onBlur && rest.onBlur(); + } + }, [isFocus, rest]); + useEffect(() => { // This will cause the form to revalidate and remove any error related to country name onInputChange(countryCode); @@ -47,6 +57,8 @@ function CountrySelector({errorText = '', value: countryCode, onInputChange}: Co description={translate('common.country')} onPress={() => { const activeRoute = Navigation.getActiveRouteWithoutParams(); + rest.onPress && rest.onPress(); + didOpenContrySelector.current = true; Navigation.navigate(ROUTES.SETTINGS_PERSONAL_DETAILS_ADDRESS_COUNTRY.getRoute(countryCode ?? '', activeRoute)); }} /> From fdfd0f5ef072247178da2fd76422234897d12bf1 Mon Sep 17 00:00:00 2001 From: tienifr Date: Wed, 31 Jan 2024 10:54:16 +0700 Subject: [PATCH 020/167] show loading indicator for uncached attachments --- src/components/Image/index.js | 5 ++++- src/components/ImageWithSizeCalculation.tsx | 13 +++++++++---- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/components/Image/index.js b/src/components/Image/index.js index ef1a69e19c12..59fcde8273fd 100644 --- a/src/components/Image/index.js +++ b/src/components/Image/index.js @@ -3,12 +3,15 @@ import React, {useEffect, useMemo} from 'react'; import {Image as RNImage} from 'react-native'; import {withOnyx} from 'react-native-onyx'; import _ from 'underscore'; +import useNetwork from '@hooks/useNetwork'; import ONYXKEYS from '@src/ONYXKEYS'; import {defaultProps, imagePropTypes} from './imagePropTypes'; import RESIZE_MODES from './resizeModes'; function Image(props) { const {source: propsSource, isAuthTokenRequired, onLoad, session} = props; + const {isOffline} = useNetwork(); + /** * Check if the image source is a URL - if so the `encryptedAuthToken` is appended * to the source. @@ -39,7 +42,7 @@ function Image(props) { RNImage.getSize(source.uri, (width, height) => { onLoad({nativeEvent: {width, height}}); }); - }, [onLoad, source]); + }, [onLoad, source, isOffline]); // Omit the props which the underlying RNImage won't use const forwardedProps = _.omit(props, ['source', 'onLoad', 'session', 'isAuthTokenRequired']); diff --git a/src/components/ImageWithSizeCalculation.tsx b/src/components/ImageWithSizeCalculation.tsx index d0559327274a..344904796f31 100644 --- a/src/components/ImageWithSizeCalculation.tsx +++ b/src/components/ImageWithSizeCalculation.tsx @@ -2,6 +2,7 @@ import delay from 'lodash/delay'; import React, {useEffect, useRef, useState} from 'react'; import type {ImageSourcePropType, StyleProp, ViewStyle} from 'react-native'; import {View} from 'react-native'; +import useNetwork from '@hooks/useNetwork'; import useThemeStyles from '@hooks/useThemeStyles'; import Log from '@libs/Log'; import FullscreenLoadingIndicator from './FullscreenLoadingIndicator'; @@ -42,13 +43,21 @@ function ImageWithSizeCalculation({url, style, onMeasure, isAuthTokenRequired}: const isLoadedRef = useRef(null); const [isImageCached, setIsImageCached] = useState(true); const [isLoading, setIsLoading] = useState(false); + const {isOffline} = useNetwork(); const onError = () => { Log.hmmm('Unable to fetch image to calculate size', {url}); + if (isOffline) { + return; + } + setIsLoading(false); + setIsImageCached(true); }; const imageLoadedSuccessfully = (event: OnLoadNativeEvent) => { isLoadedRef.current = true; + setIsLoading(false); + setIsImageCached(true); onMeasure({ width: event.nativeEvent.width, height: event.nativeEvent.height, @@ -82,10 +91,6 @@ function ImageWithSizeCalculation({url, style, onMeasure, isAuthTokenRequired}: } setIsLoading(true); }} - onLoadEnd={() => { - setIsLoading(false); - setIsImageCached(true); - }} onError={onError} onLoad={imageLoadedSuccessfully} /> From bf40b7ca25490abf3d900372f15f1ff805ce9152 Mon Sep 17 00:00:00 2001 From: tienifr Date: Wed, 31 Jan 2024 11:15:35 +0700 Subject: [PATCH 021/167] fix: menu popup can not be closed again --- .../report/ContextMenu/PopoverReportActionContextMenu.tsx | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/pages/home/report/ContextMenu/PopoverReportActionContextMenu.tsx b/src/pages/home/report/ContextMenu/PopoverReportActionContextMenu.tsx index 272548214ece..0311a9b3183c 100644 --- a/src/pages/home/report/ContextMenu/PopoverReportActionContextMenu.tsx +++ b/src/pages/home/report/ContextMenu/PopoverReportActionContextMenu.tsx @@ -65,10 +65,9 @@ function PopoverReportActionContextMenu(_props: never, ref: ForwardedRef([]); const contentRef = useRef(null); - const anchorRef = useRef(null); const dimensionsEventListener = useRef(null); const contextMenuAnchorRef = useRef(null); - const contextMenuTargetNode = useRef(null); + const contextMenuTargetNode = useRef(null); const onPopoverShow = useRef(() => {}); const onPopoverHide = useRef(() => {}); @@ -166,7 +165,7 @@ function PopoverReportActionContextMenu(_props: never, ref: ForwardedRef { const {pageX = 0, pageY = 0} = extractPointerEvent(event); contextMenuAnchorRef.current = contextMenuAnchor; - contextMenuTargetNode.current = event.target as HTMLElement; + contextMenuTargetNode.current = event.target as HTMLDivElement; setInstanceID(Math.random().toString(36).substr(2, 5)); @@ -307,7 +306,7 @@ function PopoverReportActionContextMenu(_props: never, ref: ForwardedRef Date: Wed, 31 Jan 2024 18:05:25 +0100 Subject: [PATCH 022/167] fix --- src/pages/ReportParticipantsPage.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/pages/ReportParticipantsPage.tsx b/src/pages/ReportParticipantsPage.tsx index 694284a900d0..b09eb1a4d9ef 100755 --- a/src/pages/ReportParticipantsPage.tsx +++ b/src/pages/ReportParticipantsPage.tsx @@ -87,6 +87,7 @@ function ReportParticipantsPage({report, personalDetails}: ReportParticipantsPag {({safeAreaPaddingBottomStyle}) => ( Navigation.goBack(ROUTES.REPORT_WITH_ID_DETAILS.getRoute(report.reportID)) : undefined} title={translate( ReportUtils.isChatRoom(report) || ReportUtils.isPolicyExpenseChat(report) || @@ -112,7 +113,7 @@ function ReportParticipantsPage({report, personalDetails}: ReportParticipantsPag if (!option.accountID) { return; } - Navigation.navigate(ROUTES.PROFILE.getRoute(option.accountID)); + Navigation.navigate(ROUTES.PROFILE.getRoute(option.accountID, report ? ROUTES.REPORT_PARTICIPANTS.getRoute(report.reportID) : undefined)); }} hideSectionHeaders showTitleTooltip From 18d755d19f02a9789b095e669c5cbaa69be2a40a Mon Sep 17 00:00:00 2001 From: Shubham Agrawal Date: Thu, 1 Feb 2024 16:06:07 +0530 Subject: [PATCH 023/167] adjustment according to recommendation --- .../ReportActionItem/MoneyRequestView.js | 36 +++++++------------ 1 file changed, 13 insertions(+), 23 deletions(-) diff --git a/src/components/ReportActionItem/MoneyRequestView.js b/src/components/ReportActionItem/MoneyRequestView.js index 4160bee1d3cc..c318f306272f 100644 --- a/src/components/ReportActionItem/MoneyRequestView.js +++ b/src/components/ReportActionItem/MoneyRequestView.js @@ -237,7 +237,7 @@ function MoneyRequestView({report, parentReport, parentReportActions, policyCate - {showMapAsImage && ( + {(showMapAsImage || hasReceipt) && ( - - - - )} - {!showMapAsImage && hasReceipt && ( - { - Transaction.clearError(transaction.transactionID); - }} - > - - + {showMapAsImage ? ( + + ) : ( + + )} )} From 424c7c6848e8adc37cc5c6a2728cc6cd555e5990 Mon Sep 17 00:00:00 2001 From: tienifr Date: Thu, 1 Feb 2024 17:39:09 +0700 Subject: [PATCH 024/167] fix: right click to open popover --- .../ContextMenu/BaseReportActionContextMenu.tsx | 1 + .../ContextMenu/PopoverReportActionContextMenu.tsx | 12 ++++++++---- .../report/ContextMenu/ReportActionContextMenu.ts | 3 +++ 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/pages/home/report/ContextMenu/BaseReportActionContextMenu.tsx b/src/pages/home/report/ContextMenu/BaseReportActionContextMenu.tsx index 213d94f51f81..52b62c2d15b3 100755 --- a/src/pages/home/report/ContextMenu/BaseReportActionContextMenu.tsx +++ b/src/pages/home/report/ContextMenu/BaseReportActionContextMenu.tsx @@ -208,6 +208,7 @@ function BaseReportActionContextMenu({ undefined, undefined, filteredContextMenuActions, + true, ); }; diff --git a/src/pages/home/report/ContextMenu/PopoverReportActionContextMenu.tsx b/src/pages/home/report/ContextMenu/PopoverReportActionContextMenu.tsx index 0311a9b3183c..bf1dcfd98c0a 100644 --- a/src/pages/home/report/ContextMenu/PopoverReportActionContextMenu.tsx +++ b/src/pages/home/report/ContextMenu/PopoverReportActionContextMenu.tsx @@ -65,9 +65,10 @@ function PopoverReportActionContextMenu(_props: never, ref: ForwardedRef([]); const contentRef = useRef(null); + const anchorRef = useRef(null); const dimensionsEventListener = useRef(null); const contextMenuAnchorRef = useRef(null); - const contextMenuTargetNode = useRef(null); + const contextMenuTargetNode = useRef(null); const onPopoverShow = useRef(() => {}); const onPopoverHide = useRef(() => {}); @@ -162,11 +163,14 @@ function PopoverReportActionContextMenu(_props: never, ref: ForwardedRef { const {pageX = 0, pageY = 0} = extractPointerEvent(event); contextMenuAnchorRef.current = contextMenuAnchor; - contextMenuTargetNode.current = event.target as HTMLDivElement; - + contextMenuTargetNode.current = event.target as HTMLElement; + if (isThreeDotButton) { + anchorRef.current = event.target as HTMLDivElement; + } setInstanceID(Math.random().toString(36).substr(2, 5)); onPopoverShow.current = onShow; @@ -306,7 +310,7 @@ function PopoverReportActionContextMenu(_props: never, ref: ForwardedRef void; type ReportActionContextMenu = { @@ -113,6 +114,7 @@ function showContextMenu( isPinnedChat = false, isUnreadChat = false, disabledActions: ContextMenuAction[] = [], + isThreeDotButton = false, ) { if (!contextMenuRef.current) { return; @@ -140,6 +142,7 @@ function showContextMenu( isPinnedChat, isUnreadChat, disabledActions, + isThreeDotButton, ); } From b58badfdf09cd86be5606d5817f9c49d886f27fb Mon Sep 17 00:00:00 2001 From: Someshwar Tripathi Date: Thu, 1 Feb 2024 20:39:11 +0530 Subject: [PATCH 025/167] Migrate MoneyRequestAmountForm to typescript --- ...ountForm.js => MoneyRequestAmountForm.tsx} | 123 ++++++++---------- 1 file changed, 54 insertions(+), 69 deletions(-) rename src/pages/iou/steps/{MoneyRequestAmountForm.js => MoneyRequestAmountForm.tsx} (81%) diff --git a/src/pages/iou/steps/MoneyRequestAmountForm.js b/src/pages/iou/steps/MoneyRequestAmountForm.tsx similarity index 81% rename from src/pages/iou/steps/MoneyRequestAmountForm.js rename to src/pages/iou/steps/MoneyRequestAmountForm.tsx index 8775562d4476..69f48f231d91 100644 --- a/src/pages/iou/steps/MoneyRequestAmountForm.js +++ b/src/pages/iou/steps/MoneyRequestAmountForm.tsx @@ -1,12 +1,8 @@ -import lodashGet from 'lodash/get'; -import PropTypes from 'prop-types'; import React, {useCallback, useEffect, useRef, useState} from 'react'; import {ScrollView, View} from 'react-native'; -import _ from 'underscore'; import BigNumberPad from '@components/BigNumberPad'; import Button from '@components/Button'; import FormHelpMessage from '@components/FormHelpMessage'; -import refPropTypes from '@components/refPropTypes'; import TextInputWithCurrencySymbol from '@components/TextInputWithCurrencySymbol'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; @@ -18,68 +14,61 @@ import getOperatingSystem from '@libs/getOperatingSystem'; import * as MoneyRequestUtils from '@libs/MoneyRequestUtils'; import Navigation from '@libs/Navigation/Navigation'; import CONST from '@src/CONST'; +import type {ValueOf} from 'type-fest'; +import type {TextInput} from 'react-native' + +type MoneyRequestAmountFormProps = { + /** IOU amount saved in Onyx */ + amount?: number; + + /** Calculated tax amount based on selected tax rate */ + taxAmount?: number; + + /** Currency chosen by user or saved in Onyx */ + currency?: string; + + /** Whether the amount is being edited or not */ + isEditing?: boolean; + + /** Refs forwarded to the TextInputWithCurrencySymbol */ + forwardedRef?: refPropTypes, + + /** Fired when back button pressed, navigates to currency selection page */ + onCurrencyButtonPress: () => void; + + /** Fired when submit button pressed, saves the given amount and navigates to the next page */ + onSubmitButtonPress: ({amount, currency}: {amount: string, currency: string}) => void; + + /** The current tab we have navigated to in the request modal. String that corresponds to the request type. */ + selectedTab?: ValueOf; +} -const propTypes = { - /** IOU amount saved in Onyx */ - amount: PropTypes.number, - - /** Calculated tax amount based on selected tax rate */ - taxAmount: PropTypes.number, - - /** Currency chosen by user or saved in Onyx */ - currency: PropTypes.string, - - /** Whether the amount is being edited or not */ - isEditing: PropTypes.bool, - - /** Refs forwarded to the TextInputWithCurrencySymbol */ - forwardedRef: refPropTypes, - - /** Fired when back button pressed, navigates to currency selection page */ - onCurrencyButtonPress: PropTypes.func.isRequired, - - /** Fired when submit button pressed, saves the given amount and navigates to the next page */ - onSubmitButtonPress: PropTypes.func.isRequired, - - /** The current tab we have navigated to in the request modal. String that corresponds to the request type. */ - selectedTab: PropTypes.oneOf([CONST.TAB_REQUEST.DISTANCE, CONST.TAB_REQUEST.MANUAL, CONST.TAB_REQUEST.SCAN]), -}; - -const defaultProps = { - amount: 0, - taxAmount: 0, - currency: CONST.CURRENCY.USD, - forwardedRef: null, - isEditing: false, - selectedTab: CONST.TAB_REQUEST.MANUAL, -}; +type Selection = { + start: number; + end: number; +} /** * Returns the new selection object based on the updated amount's length - * - * @param {Object} oldSelection - * @param {Number} prevLength - * @param {Number} newLength - * @returns {Object} */ -const getNewSelection = (oldSelection, prevLength, newLength) => { +const getNewSelection = (oldSelection: Selection, prevLength: number, newLength: number): Selection => { const cursorPosition = oldSelection.end + (newLength - prevLength); return {start: cursorPosition, end: cursorPosition}; }; -const isAmountInvalid = (amount) => !amount.length || parseFloat(amount) < 0.01; -const isTaxAmountInvalid = (currentAmount, taxAmount, isTaxAmountForm) => isTaxAmountForm && currentAmount > CurrencyUtils.convertToFrontendAmount(taxAmount); +const isAmountInvalid = (amount: string) => !amount.length || parseFloat(amount) < 0.01; +const isTaxAmountInvalid = (currentAmount: string, taxAmount: number, isTaxAmountForm: boolean) => isTaxAmountForm && currentAmount > CurrencyUtils.convertToFrontendAmount(taxAmount); const AMOUNT_VIEW_ID = 'amountView'; const NUM_PAD_CONTAINER_VIEW_ID = 'numPadContainerView'; const NUM_PAD_VIEW_ID = 'numPadView'; -function MoneyRequestAmountForm({amount, taxAmount, currency, isEditing, forwardedRef, onCurrencyButtonPress, onSubmitButtonPress, selectedTab}) { +function MoneyRequestAmountForm({amount = 0, taxAmount = 0, currency = CONST.CURRENCY.USD, isEditing = false, forwardedRef = null, onCurrencyButtonPress, onSubmitButtonPress, selectedTab = CONST.TAB_REQUEST.MANUAL}: MoneyRequestAmountFormProps) { const styles = useThemeStyles(); const {isExtraSmallScreenHeight} = useWindowDimensions(); const {translate, toLocaleDigit, numberFormat} = useLocalize(); - const textInput = useRef(null); + const textInput = useRef(null); const isTaxAmountForm = Navigation.getActiveRoute().includes('taxAmount'); const decimals = CurrencyUtils.getCurrencyDecimals(currency); @@ -100,15 +89,14 @@ function MoneyRequestAmountForm({amount, taxAmount, currency, isEditing, forward /** * Event occurs when a user presses a mouse button over an DOM element. - * - * @param {Event} event - * @param {Array} ids */ - const onMouseDown = (event, ids) => { - const relatedTargetId = lodashGet(event, 'nativeEvent.target.id'); - if (!_.contains(ids, relatedTargetId)) { + const onMouseDown = (event: MouseEvent, ids: string[]) => { + // const relatedTargetId = lodashGet(event, 'nativeEvent.target.id'); + const relatedTargetId = event.nativeEvent.target.id; + if (ids.includes(relatedTargetId)) { return; } + event.preventDefault(); if (!textInput.current) { return; @@ -118,7 +106,7 @@ function MoneyRequestAmountForm({amount, taxAmount, currency, isEditing, forward } }; - const initializeAmount = useCallback((newAmount) => { + const initializeAmount = useCallback((newAmount: number) => { const frontendAmount = newAmount ? CurrencyUtils.convertToFrontendAmount(newAmount).toString() : ''; setCurrentAmount(frontendAmount); setSelection({ @@ -141,7 +129,7 @@ function MoneyRequestAmountForm({amount, taxAmount, currency, isEditing, forward * @param {String} newAmount - Changed amount from user input */ const setNewAmount = useCallback( - (newAmount) => { + (newAmount: string) => { // Remove spaces from the newAmount value because Safari on iOS adds spaces when pasting a copied value // More info: https://github.com/Expensify/App/issues/16974 const newAmountWithoutSpaces = MoneyRequestUtils.stripSpacesFromAmount(newAmount); @@ -188,13 +176,11 @@ function MoneyRequestAmountForm({amount, taxAmount, currency, isEditing, forward /** * Update amount with number or Backspace pressed for BigNumberPad. * Validate new amount with decimal number regex up to 6 digits and 2 decimal digit to enable Next button - * - * @param {String} key */ const updateAmountNumberPad = useCallback( - (key) => { - if (shouldUpdateSelection && !textInput.current.isFocused()) { - textInput.current.focus(); + (key: string) => { + if (shouldUpdateSelection && !textInput.current?.isFocused()) { + textInput.current?.focus(); } // Backspace button is pressed if (key === '<' || key === 'Backspace') { @@ -214,12 +200,12 @@ function MoneyRequestAmountForm({amount, taxAmount, currency, isEditing, forward /** * Update long press value, to remove items pressing on < * - * @param {Boolean} value - Changed text from user input + * @param value - Changed text from user input */ - const updateLongPressHandlerState = useCallback((value) => { + const updateLongPressHandlerState = useCallback((value: boolean) => { // param description looks wrong setShouldUpdateSelection(!value); - if (!value && !textInput.current.isFocused()) { - textInput.current.focus(); + if (!value && !textInput.current?.isFocused()) { + textInput.current?.focus(); } }, []); @@ -261,7 +247,7 @@ function MoneyRequestAmountForm({amount, taxAmount, currency, isEditing, forward forwardDeletePressedRef.current = key === 'delete' || (_.contains([CONST.OS.MAC_OS, CONST.OS.IOS], getOperatingSystem()) && nativeEvent.ctrlKey && key === 'd'); }; - const formattedAmount = MoneyRequestUtils.replaceAllDigits(currentAmount, toLocaleDigit); + const formattedAmount: string = MoneyRequestUtils.replaceAllDigits(currentAmount, toLocaleDigit); const buttonText = isEditing ? translate('common.save') : translate('common.next'); const canUseTouchScreen = DeviceCapabilities.canUseTouchScreen(); @@ -317,7 +303,8 @@ function MoneyRequestAmountForm({amount, taxAmount, currency, isEditing, forward ) : null}