From d69426ce0e0f38ffe19837746826a388ce9046bb Mon Sep 17 00:00:00 2001 From: Andrew Gable Date: Fri, 11 Aug 2023 15:25:57 -0600 Subject: [PATCH 001/342] Fix path to build Android correctly --- fastlane/Fastfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fastlane/Fastfile b/fastlane/Fastfile index 60d60934c2ba..ec68c74472de 100644 --- a/fastlane/Fastfile +++ b/fastlane/Fastfile @@ -17,7 +17,7 @@ platform :android do desc "Generate a new local APK for e2e testing" lane :build_e2e do ENV["ENVFILE"]="tests/e2e/.env.e2e" - ENV["ENTRY_FILE"]="#{Dir.pwd}/../src/libs/E2E/reactNativeLaunchingTest.js" + ENV["ENTRY_FILE"]="../src/libs/E2E/reactNativeLaunchingTest.js" ENV["E2E_TESTING"]="true" gradle( From 85f0d93e444f6437bff64eba4809c66ea7f2ea68 Mon Sep 17 00:00:00 2001 From: Andrew Gable Date: Fri, 11 Aug 2023 15:31:03 -0600 Subject: [PATCH 002/342] Add `IS_MERGED` output --- .github/actions/javascript/getPullRequestDetails/action.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/actions/javascript/getPullRequestDetails/action.yml b/.github/actions/javascript/getPullRequestDetails/action.yml index a59cf55bdf9f..6704d5220851 100644 --- a/.github/actions/javascript/getPullRequestDetails/action.yml +++ b/.github/actions/javascript/getPullRequestDetails/action.yml @@ -15,6 +15,8 @@ outputs: description: 'The merge_commit_sha of the given pull request' MERGE_ACTOR: description: 'The actor who merged the pull request' + IS_MERGED: + description: 'True if the pull request is merged' runs: using: 'node16' main: './index.js' From 45dd2b4e1b00bcea3ce29aa659874ea24f40c795 Mon Sep 17 00:00:00 2001 From: Andrew Gable Date: Fri, 11 Aug 2023 15:35:14 -0600 Subject: [PATCH 003/342] Add two more missing outputs --- .github/actions/javascript/getPullRequestDetails/action.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/actions/javascript/getPullRequestDetails/action.yml b/.github/actions/javascript/getPullRequestDetails/action.yml index 6704d5220851..ed2c60f018a1 100644 --- a/.github/actions/javascript/getPullRequestDetails/action.yml +++ b/.github/actions/javascript/getPullRequestDetails/action.yml @@ -13,10 +13,14 @@ inputs: outputs: MERGE_COMMIT_SHA: description: 'The merge_commit_sha of the given pull request' + HEAD_COMMIT_SHA: + description: 'The head_commit_sha of the given pull request' MERGE_ACTOR: description: 'The actor who merged the pull request' IS_MERGED: description: 'True if the pull request is merged' + FORKED_REPO_URL: + description: 'Output forked repo URL if PR includes changes from a fork' runs: using: 'node16' main: './index.js' From 20c1e05b2a54b3b9d06124839ecb6c6833e3a7f5 Mon Sep 17 00:00:00 2001 From: Andrew Gable Date: Fri, 11 Aug 2023 15:40:54 -0600 Subject: [PATCH 004/342] Temp comment out fork checkout --- .github/workflows/e2ePerformanceTests.yml | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/.github/workflows/e2ePerformanceTests.yml b/.github/workflows/e2ePerformanceTests.yml index fe364b376e3b..548f7e901667 100644 --- a/.github/workflows/e2ePerformanceTests.yml +++ b/.github/workflows/e2ePerformanceTests.yml @@ -81,12 +81,13 @@ jobs: - name: Unmerged PR - Fetch head ref of unmerged PR if: ${{ !fromJSON(steps.getPullRequestDetails.outputs.IS_MERGED) }} run: | - if [[ ${{ steps.getPullRequestDetails.outputs.FORKED_REPO_URL }} != '' ]]; then - git remote add pr_remote ${{ steps.getPullRequestDetails.outputs.FORKED_REPO_URL }} - git fetch pr_remote ${{ steps.getPullRequestDetails.outputs.HEAD_COMMIT_SHA }} --no-tags --depth=1 - else +# TODO: UNDO THIS +# if [[ ${{ steps.getPullRequestDetails.outputs.FORKED_REPO_URL }} != '' ]]; then +# git remote add pr_remote ${{ steps.getPullRequestDetails.outputs.FORKED_REPO_URL }} +# git fetch pr_remote ${{ steps.getPullRequestDetails.outputs.HEAD_COMMIT_SHA }} --no-tags --depth=1 +# else git fetch origin ${{ steps.getPullRequestDetails.outputs.HEAD_COMMIT_SHA }} --no-tags --depth=1 - fi +# fi - name: Unmerged PR - Set dummy git credentials before merging if: ${{ !fromJSON(steps.getPullRequestDetails.outputs.IS_MERGED) }} From 0cd275462293f0ca4238545fbb8037cc40904e8d Mon Sep 17 00:00:00 2001 From: Andrew Gable Date: Fri, 11 Aug 2023 15:41:48 -0600 Subject: [PATCH 005/342] Another temporary fix --- .github/workflows/e2ePerformanceTests.yml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/.github/workflows/e2ePerformanceTests.yml b/.github/workflows/e2ePerformanceTests.yml index 548f7e901667..7888c8c47c25 100644 --- a/.github/workflows/e2ePerformanceTests.yml +++ b/.github/workflows/e2ePerformanceTests.yml @@ -81,13 +81,7 @@ jobs: - name: Unmerged PR - Fetch head ref of unmerged PR if: ${{ !fromJSON(steps.getPullRequestDetails.outputs.IS_MERGED) }} run: | -# TODO: UNDO THIS -# if [[ ${{ steps.getPullRequestDetails.outputs.FORKED_REPO_URL }} != '' ]]; then -# git remote add pr_remote ${{ steps.getPullRequestDetails.outputs.FORKED_REPO_URL }} -# git fetch pr_remote ${{ steps.getPullRequestDetails.outputs.HEAD_COMMIT_SHA }} --no-tags --depth=1 -# else git fetch origin ${{ steps.getPullRequestDetails.outputs.HEAD_COMMIT_SHA }} --no-tags --depth=1 -# fi - name: Unmerged PR - Set dummy git credentials before merging if: ${{ !fromJSON(steps.getPullRequestDetails.outputs.IS_MERGED) }} From f7f3a45a86728c1cccd49bde0407d05a1f7f1c31 Mon Sep 17 00:00:00 2001 From: Andrew Gable Date: Tue, 15 Aug 2023 15:45:25 -0600 Subject: [PATCH 006/342] Tweak path --- fastlane/Fastfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fastlane/Fastfile b/fastlane/Fastfile index ec68c74472de..5dfccb4d93ec 100644 --- a/fastlane/Fastfile +++ b/fastlane/Fastfile @@ -17,7 +17,7 @@ platform :android do desc "Generate a new local APK for e2e testing" lane :build_e2e do ENV["ENVFILE"]="tests/e2e/.env.e2e" - ENV["ENTRY_FILE"]="../src/libs/E2E/reactNativeLaunchingTest.js" + ENV["ENTRY_FILE"]="{Dir.pwd}/src/libs/E2E/reactNativeLaunchingTest.js" ENV["E2E_TESTING"]="true" gradle( From bd51745eb262a09b416b76c2cbc7f451c6edcedd Mon Sep 17 00:00:00 2001 From: Andrew Gable Date: Tue, 15 Aug 2023 16:23:32 -0600 Subject: [PATCH 007/342] Try fixing path yet again! --- fastlane/Fastfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fastlane/Fastfile b/fastlane/Fastfile index 5dfccb4d93ec..cd11c5cf9e98 100644 --- a/fastlane/Fastfile +++ b/fastlane/Fastfile @@ -17,7 +17,7 @@ platform :android do desc "Generate a new local APK for e2e testing" lane :build_e2e do ENV["ENVFILE"]="tests/e2e/.env.e2e" - ENV["ENTRY_FILE"]="{Dir.pwd}/src/libs/E2E/reactNativeLaunchingTest.js" + ENV["ENTRY_FILE"]="src/libs/E2E/reactNativeLaunchingTest.js" ENV["E2E_TESTING"]="true" gradle( From 64e4effbd2c266308c09181007cd4d416c84f6e5 Mon Sep 17 00:00:00 2001 From: Andrew Gable Date: Tue, 15 Aug 2023 16:52:54 -0600 Subject: [PATCH 008/342] Undo test commit --- .github/workflows/e2ePerformanceTests.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/e2ePerformanceTests.yml b/.github/workflows/e2ePerformanceTests.yml index 7888c8c47c25..fe364b376e3b 100644 --- a/.github/workflows/e2ePerformanceTests.yml +++ b/.github/workflows/e2ePerformanceTests.yml @@ -81,7 +81,12 @@ jobs: - name: Unmerged PR - Fetch head ref of unmerged PR if: ${{ !fromJSON(steps.getPullRequestDetails.outputs.IS_MERGED) }} run: | + if [[ ${{ steps.getPullRequestDetails.outputs.FORKED_REPO_URL }} != '' ]]; then + git remote add pr_remote ${{ steps.getPullRequestDetails.outputs.FORKED_REPO_URL }} + git fetch pr_remote ${{ steps.getPullRequestDetails.outputs.HEAD_COMMIT_SHA }} --no-tags --depth=1 + else git fetch origin ${{ steps.getPullRequestDetails.outputs.HEAD_COMMIT_SHA }} --no-tags --depth=1 + fi - name: Unmerged PR - Set dummy git credentials before merging if: ${{ !fromJSON(steps.getPullRequestDetails.outputs.IS_MERGED) }} From 9debab5bceb6bb778ac7ed83589159096c05dc32 Mon Sep 17 00:00:00 2001 From: Andrew Gable Date: Tue, 15 Aug 2023 17:14:28 -0600 Subject: [PATCH 009/342] Testing full flow --- .github/workflows/e2ePerformanceTests.yml | 60 +++-------------------- 1 file changed, 6 insertions(+), 54 deletions(-) diff --git a/.github/workflows/e2ePerformanceTests.yml b/.github/workflows/e2ePerformanceTests.yml index fe364b376e3b..557af1a04786 100644 --- a/.github/workflows/e2ePerformanceTests.yml +++ b/.github/workflows/e2ePerformanceTests.yml @@ -16,42 +16,6 @@ on: required: true jobs: - buildBaseline: - runs-on: ubuntu-latest-xl - name: Build apk from latest release as a baseline - outputs: - VERSION: ${{ steps.getMostRecentRelease.outputs.VERSION }} - steps: - - uses: actions/checkout@v3 - - - name: Get most recent release version - id: getMostRecentRelease - run: echo "VERSION=$(gh release list --limit 1 | awk '{ print $1 }')" >> "$GITHUB_OUTPUT" - env: - GITHUB_TOKEN: ${{ github.token }} - - - name: Check if there's an existing artifact for this baseline - id: checkForExistingArtifact - uses: xSAVIKx/artifact-exists-action@3c5206b1411c0d2fc0840f56b7140646933d9d6a - with: - name: baseline-apk-${{ steps.getMostRecentRelease.outputs.VERSION }} - - - name: Skip build if there's already an existing artifact for the baseline - if: ${{ fromJSON(steps.checkForExistingArtifact.outputs.exists) }} - run: echo 'APK for baseline ${{ steps.getMostRecentRelease.outputs.VERSION }} already exists, reusing existing build' - - - name: Checkout "Baseline" commit (last release) - if: ${{ !fromJSON(steps.checkForExistingArtifact.outputs.exists) }} - run: | - git fetch origin tag ${{ steps.getMostRecentRelease.outputs.VERSION }} --no-tags --depth=1 - git switch --detach ${{ steps.getMostRecentRelease.outputs.VERSION }} - - - name: Build APK - if: ${{ !fromJSON(steps.checkForExistingArtifact.outputs.exists) }} - uses: Expensify/App/.github/actions/composite/buildAndroidAPK@main - with: - ARTIFACT_NAME: baseline-apk-${{ steps.getMostRecentRelease.outputs.VERSION }} - buildDelta: runs-on: ubuntu-latest-xl name: Build apk from delta ref @@ -81,12 +45,7 @@ jobs: - name: Unmerged PR - Fetch head ref of unmerged PR if: ${{ !fromJSON(steps.getPullRequestDetails.outputs.IS_MERGED) }} run: | - if [[ ${{ steps.getPullRequestDetails.outputs.FORKED_REPO_URL }} != '' ]]; then - git remote add pr_remote ${{ steps.getPullRequestDetails.outputs.FORKED_REPO_URL }} - git fetch pr_remote ${{ steps.getPullRequestDetails.outputs.HEAD_COMMIT_SHA }} --no-tags --depth=1 - else git fetch origin ${{ steps.getPullRequestDetails.outputs.HEAD_COMMIT_SHA }} --no-tags --depth=1 - fi - name: Unmerged PR - Set dummy git credentials before merging if: ${{ !fromJSON(steps.getPullRequestDetails.outputs.IS_MERGED) }} @@ -119,7 +78,7 @@ jobs: runTestsInAWS: runs-on: ubuntu-latest - needs: [buildBaseline, buildDelta] + needs: [buildDelta] name: Run E2E tests in AWS device farm steps: - uses: actions/checkout@v3 @@ -127,25 +86,18 @@ jobs: - name: Make zip directory for everything to send to AWS Device Farm run: mkdir zip - - name: Download baseline APK - uses: actions/download-artifact@e9ef242655d12993efdcda9058dee2db83a2cb9b - id: downloadBaselineAPK - with: - name: baseline-apk-${{ needs.buildBaseline.outputs.VERSION }} - path: zip - - # The downloaded artifact will be a file named "app-e2eRelease.apk" so we have to rename it - - name: Rename baseline APK - run: mv "${{steps.downloadBaselineAPK.outputs.download-path}}/app-e2eRelease.apk" "${{steps.downloadBaselineAPK.outputs.download-path}}/app-e2eRelease-baseline.apk" - - name: Download delta APK uses: actions/download-artifact@e9ef242655d12993efdcda9058dee2db83a2cb9b + id: downloadDeltaAPK with: name: delta-apk-${{ needs.buildDelta.outputs.DELTA_REF }} path: zip - name: Rename delta APK - run: mv "${{steps.downloadBaselineAPK.outputs.download-path}}/app-e2eRelease.apk" "${{steps.downloadBaselineAPK.outputs.download-path}}/app-e2eRelease-compare.apk" + run: mv "${{steps.downloadDeltaAPK.outputs.download-path}}/app-e2eRelease.apk" "${{steps.downloadDeltaAPK.outputs.download-path}}/app-e2eRelease-compare.apk" + + - name: Copy Delta APK as compare for testing + run: mv "${{steps.downloadDeltaAPK.outputs.download-path}}/app-e2eRelease-compare.apk" "${{steps.downloadDeltaAPK.outputs.download-path}}/app-e2eRelease-baseline.apk" - name: Copy e2e code into zip folder run: cp -r tests/e2e zip From e1b500b38a023b5c82b99f0adcd0acac5b73b9a2 Mon Sep 17 00:00:00 2001 From: Andrew Gable Date: Wed, 16 Aug 2023 11:12:06 -0600 Subject: [PATCH 010/342] Add more logs --- src/libs/E2E/tests/openSearchPageTest.e2e.js | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/libs/E2E/tests/openSearchPageTest.e2e.js b/src/libs/E2E/tests/openSearchPageTest.e2e.js index 2f0f72f35bdd..12fcfc3fd1a7 100644 --- a/src/libs/E2E/tests/openSearchPageTest.e2e.js +++ b/src/libs/E2E/tests/openSearchPageTest.e2e.js @@ -7,12 +7,16 @@ import CONST from '../../../CONST'; const test = () => { // check for login (if already logged in the action will simply resolve) + console.debug('[E2E] Logging in for search'); + E2ELogin().then((neededLogin) => { if (neededLogin) { // we don't want to submit the first login to the results return E2EClient.submitTestDone(); } + console.debug('[E2E] Logged in, getting search metrics and submitting them…'); + Performance.subscribeToMeasurements((entry) => { if (entry.name !== CONST.TIMING.SEARCH_RENDER) { return; @@ -21,7 +25,14 @@ const test = () => { E2EClient.submitTestResults({ name: 'Open Search Page TTI', duration: entry.duration, - }).then(E2EClient.submitTestDone); + }) + .then(() => { + console.debug('[E2E] Done with search, exiting…'); + E2EClient.submitTestDone(); + }) + .catch((err) => { + console.debug('[E2E] Error while submitting test results:', err); + }); }); Navigation.navigate(ROUTES.SEARCH); From 6a93aeb4167656de56731b75e20e4acbc114113b Mon Sep 17 00:00:00 2001 From: Andrew Gable Date: Wed, 16 Aug 2023 13:10:24 -0600 Subject: [PATCH 011/342] Add more logs --- src/libs/E2E/tests/openSearchPageTest.e2e.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libs/E2E/tests/openSearchPageTest.e2e.js b/src/libs/E2E/tests/openSearchPageTest.e2e.js index 12fcfc3fd1a7..ded45f55fd9c 100644 --- a/src/libs/E2E/tests/openSearchPageTest.e2e.js +++ b/src/libs/E2E/tests/openSearchPageTest.e2e.js @@ -18,10 +18,12 @@ const test = () => { console.debug('[E2E] Logged in, getting search metrics and submitting them…'); Performance.subscribeToMeasurements((entry) => { + console.debug(`[E2E] Entry: ${entry}`); if (entry.name !== CONST.TIMING.SEARCH_RENDER) { return; } + console.debug(`[E2E] Submitting!`); E2EClient.submitTestResults({ name: 'Open Search Page TTI', duration: entry.duration, From 25af1459173556bef2f09ba0c8dc87db9e2fb707 Mon Sep 17 00:00:00 2001 From: Andrew Gable Date: Wed, 16 Aug 2023 14:13:20 -0600 Subject: [PATCH 012/342] =?UTF-8?q?Fix=20logs=20=F0=9F=99=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/libs/E2E/tests/openSearchPageTest.e2e.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/E2E/tests/openSearchPageTest.e2e.js b/src/libs/E2E/tests/openSearchPageTest.e2e.js index ded45f55fd9c..e96d70c95d94 100644 --- a/src/libs/E2E/tests/openSearchPageTest.e2e.js +++ b/src/libs/E2E/tests/openSearchPageTest.e2e.js @@ -18,7 +18,7 @@ const test = () => { console.debug('[E2E] Logged in, getting search metrics and submitting them…'); Performance.subscribeToMeasurements((entry) => { - console.debug(`[E2E] Entry: ${entry}`); + console.debug(`[E2E] Entry: ${JSON.stringify(entry)}`); if (entry.name !== CONST.TIMING.SEARCH_RENDER) { return; } From 028b384dce0f9888e0c20f4fd7a5cc1f6bd5586f Mon Sep 17 00:00:00 2001 From: Andrew Gable Date: Wed, 16 Aug 2023 15:48:21 -0600 Subject: [PATCH 013/342] Only navigate to search bar once sidebar is loaded --- src/libs/E2E/tests/openSearchPageTest.e2e.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/libs/E2E/tests/openSearchPageTest.e2e.js b/src/libs/E2E/tests/openSearchPageTest.e2e.js index e96d70c95d94..3b2d91322cf0 100644 --- a/src/libs/E2E/tests/openSearchPageTest.e2e.js +++ b/src/libs/E2E/tests/openSearchPageTest.e2e.js @@ -18,6 +18,12 @@ const test = () => { console.debug('[E2E] Logged in, getting search metrics and submitting them…'); Performance.subscribeToMeasurements((entry) => { + if (entry.name === CONST.TIMING.SIDEBAR_LOADED) { + console.debug(`[E2E] Sidebar loaded, navigating to search route…`); + Navigation.navigate(ROUTES.SEARCH); + return; + } + console.debug(`[E2E] Entry: ${JSON.stringify(entry)}`); if (entry.name !== CONST.TIMING.SEARCH_RENDER) { return; @@ -36,8 +42,6 @@ const test = () => { console.debug('[E2E] Error while submitting test results:', err); }); }); - - Navigation.navigate(ROUTES.SEARCH); }); }; From 3be5e6909a86a33a9c7c749c2378b14ad1ab243c Mon Sep 17 00:00:00 2001 From: Oscar Franco Date: Fri, 25 Aug 2023 16:36:54 +0200 Subject: [PATCH 014/342] Separate ReportScreenContext to prevent cyclic re-renders --- .../ReportActionItemEmojiReactions.js | 4 +- src/hooks/useReportScrollManager/index.js | 4 +- .../useReportScrollManager/index.native.js | 4 +- src/pages/home/ReportScreen.js | 188 +++++++++--------- src/pages/home/ReportScreenContext.js | 9 +- src/pages/home/report/ReportActionItem.js | 4 +- src/pages/home/report/ReportActionsView.js | 7 +- 7 files changed, 110 insertions(+), 110 deletions(-) diff --git a/src/components/Reactions/ReportActionItemEmojiReactions.js b/src/components/Reactions/ReportActionItemEmojiReactions.js index ec2755f1a5dd..4f590b43e180 100644 --- a/src/components/Reactions/ReportActionItemEmojiReactions.js +++ b/src/components/Reactions/ReportActionItemEmojiReactions.js @@ -13,7 +13,7 @@ import EmojiReactionsPropTypes from './EmojiReactionsPropTypes'; import Tooltip from '../Tooltip'; import ReactionTooltipContent from './ReactionTooltipContent'; import * as EmojiUtils from '../../libs/EmojiUtils'; -import ReportScreenContext from '../../pages/home/ReportScreenContext'; +import {ReactionListContext} from '../../pages/home/ReportScreenContext'; const propTypes = { emojiReactions: EmojiReactionsPropTypes, @@ -41,7 +41,7 @@ const defaultProps = { }; function ReportActionItemEmojiReactions(props) { - const {reactionListRef} = useContext(ReportScreenContext); + const reactionListRef = useContext(ReactionListContext); const popoverReactionListAnchor = useRef(null); let totalReactionCount = 0; diff --git a/src/hooks/useReportScrollManager/index.js b/src/hooks/useReportScrollManager/index.js index 0cf09146553c..9a3303504b92 100644 --- a/src/hooks/useReportScrollManager/index.js +++ b/src/hooks/useReportScrollManager/index.js @@ -1,8 +1,8 @@ import {useContext, useCallback} from 'react'; -import ReportScreenContext from '../../pages/home/ReportScreenContext'; +import {ActionListContext} from '../../pages/home/ReportScreenContext'; function useReportScrollManager() { - const {flatListRef} = useContext(ReportScreenContext); + const flatListRef = useContext(ActionListContext); /** * Scroll to the provided index. On non-native implementations we do not want to scroll when we are scrolling because diff --git a/src/hooks/useReportScrollManager/index.native.js b/src/hooks/useReportScrollManager/index.native.js index 35af064cb062..d44a40222ca5 100644 --- a/src/hooks/useReportScrollManager/index.native.js +++ b/src/hooks/useReportScrollManager/index.native.js @@ -1,8 +1,8 @@ import {useContext, useCallback} from 'react'; -import ReportScreenContext from '../../pages/home/ReportScreenContext'; +import {ActionListContext} from '../../pages/home/ReportScreenContext'; function useReportScrollManager() { - const {flatListRef} = useContext(ReportScreenContext); + const flatListRef = useContext(ActionListContext); /** * Scroll to the provided index. diff --git a/src/pages/home/ReportScreen.js b/src/pages/home/ReportScreen.js index 83f0e4a6d506..16284c2bd9c5 100644 --- a/src/pages/home/ReportScreen.js +++ b/src/pages/home/ReportScreen.js @@ -33,7 +33,7 @@ import getIsReportFullyVisible from '../../libs/getIsReportFullyVisible'; import MoneyRequestHeader from '../../components/MoneyRequestHeader'; import MoneyReportHeader from '../../components/MoneyReportHeader'; import * as ComposerActions from '../../libs/actions/Composer'; -import ReportScreenContext from './ReportScreenContext'; +import {ActionListContext, ReactionListContext} from './ReportScreenContext'; import TaskHeaderActionButton from '../../components/TaskHeaderActionButton'; import DragAndDropProvider from '../../components/DragAndDrop/Provider'; @@ -276,111 +276,107 @@ class ReportScreen extends React.Component { } return ( - - - + + - - {headerView} - {ReportUtils.isTaskReport(this.props.report) && this.props.isSmallScreenWidth && ReportUtils.isOpenTaskReport(this.props.report) && ( - - - - + + {headerView} + {ReportUtils.isTaskReport(this.props.report) && this.props.isSmallScreenWidth && ReportUtils.isOpenTaskReport(this.props.report) && ( + + + + + - - )} - - {Boolean(this.props.accountManagerReportID) && ReportUtils.isConciergeChatReport(this.props.report) && this.state.isBannerVisible && ( - - )} - - { - // Rounding this value for comparison because they can look like this: 411.9999694824219 - const skeletonViewContainerHeight = Math.round(event.nativeEvent.layout.height); - - // Only set state when the height changes to avoid unnecessary renders - if (reportActionsListViewHeight === skeletonViewContainerHeight) return; - - // The height can be 0 if the component unmounts - we are not interested in this value and want to know how much space it - // takes up so we can set the skeleton view container height. - if (skeletonViewContainerHeight === 0) { - return; - } - reportActionsListViewHeight = skeletonViewContainerHeight; - this.setState({skeletonViewContainerHeight}); - }} - > - {this.isReportReadyForDisplay() && !isLoadingInitialReportActions && !isLoading && ( - )} - - {/* Note: The report should be allowed to mount even if the initial report actions are not loaded. If we prevent rendering the report while they are loading then - we'll unnecessarily unmount the ReportActionsView which will clear the new marker lines initial state. */} - {(!this.isReportReadyForDisplay() || isLoadingInitialReportActions || isLoading) && ( - - )} - - {this.isReportReadyForDisplay() && ( - <> - + {Boolean(this.props.accountManagerReportID) && ReportUtils.isConciergeChatReport(this.props.report) && this.state.isBannerVisible && ( + + )} + + { + // Rounding this value for comparison because they can look like this: 411.9999694824219 + const skeletonViewContainerHeight = Math.round(event.nativeEvent.layout.height); + + // Only set state when the height changes to avoid unnecessary renders + if (reportActionsListViewHeight === skeletonViewContainerHeight) return; + + // The height can be 0 if the component unmounts - we are not interested in this value and want to know how much space it + // takes up so we can set the skeleton view container height. + if (skeletonViewContainerHeight === 0) { + return; + } + reportActionsListViewHeight = skeletonViewContainerHeight; + this.setState({skeletonViewContainerHeight}); + }} + > + {this.isReportReadyForDisplay() && !isLoadingInitialReportActions && !isLoading && ( + - - )} + )} - {!this.isReportReadyForDisplay() && ( - - )} - - - - - + {/* Note: The report should be allowed to mount even if the initial report actions are not loaded. If we prevent rendering the report while they are loading then + we'll unnecessarily unmount the ReportActionsView which will clear the new marker lines initial state. */} + {(!this.isReportReadyForDisplay() || isLoadingInitialReportActions || isLoading) && ( + + )} + + {this.isReportReadyForDisplay() && ( + <> + + + )} + + {!this.isReportReadyForDisplay() && ( + + )} + + + + + + ); } } diff --git a/src/pages/home/ReportScreenContext.js b/src/pages/home/ReportScreenContext.js index 2f79d6ae9432..0be1882699f4 100644 --- a/src/pages/home/ReportScreenContext.js +++ b/src/pages/home/ReportScreenContext.js @@ -1,4 +1,9 @@ import {createContext} from 'react'; -const ReportScreenContext = createContext(); -export default ReportScreenContext; +const ActionListContext = createContext(); +const ReactionListContext = createContext(); + +export { + ActionListContext, + ReactionListContext +} \ No newline at end of file diff --git a/src/pages/home/report/ReportActionItem.js b/src/pages/home/report/ReportActionItem.js index e5b199d1c994..4a0c0d7bd3ba 100644 --- a/src/pages/home/report/ReportActionItem.js +++ b/src/pages/home/report/ReportActionItem.js @@ -64,7 +64,7 @@ import * as PersonalDetailsUtils from '../../../libs/PersonalDetailsUtils'; import ReportActionItemBasicMessage from './ReportActionItemBasicMessage'; import * as store from '../../../libs/actions/ReimbursementAccount/store'; import * as BankAccounts from '../../../libs/actions/BankAccounts'; -import ReportScreenContext from '../ReportScreenContext'; +import { ReactionListContext } from '../ReportScreenContext'; import Permissions from '../../../libs/Permissions'; const propTypes = { @@ -127,7 +127,7 @@ function ReportActionItem(props) { const [isContextMenuActive, setIsContextMenuActive] = useState(ReportActionContextMenu.isActiveReportAction(props.action.reportActionID)); const [isHidden, setIsHidden] = useState(false); const [moderationDecision, setModerationDecision] = useState(CONST.MODERATION.MODERATOR_DECISION_APPROVED); - const {reactionListRef} = useContext(ReportScreenContext); + const reactionListRef = useContext(ReactionListContext); const textInputRef = useRef(); const popoverAnchorRef = useRef(); const downloadedPreviews = useRef([]); diff --git a/src/pages/home/report/ReportActionsView.js b/src/pages/home/report/ReportActionsView.js index da475e61f749..70eb65ade3ea 100755 --- a/src/pages/home/report/ReportActionsView.js +++ b/src/pages/home/report/ReportActionsView.js @@ -19,7 +19,7 @@ import * as ReportActionsUtils from '../../../libs/ReportActionsUtils'; import reportPropTypes from '../../reportPropTypes'; import PopoverReactionList from './ReactionList/PopoverReactionList'; import getIsReportFullyVisible from '../../../libs/getIsReportFullyVisible'; -import ReportScreenContext from '../ReportScreenContext'; +import { ReactionListContext } from '../ReportScreenContext'; const propTypes = { /** The report currently being looked at */ @@ -54,10 +54,9 @@ const defaultProps = { }; function ReportActionsView(props) { - const context = useContext(ReportScreenContext); useCopySelectionHelper(); - + const reactionListRef = useContext(ReactionListContext) const didLayout = useRef(false); const didSubscribeToReportTypingEvents = useRef(false); const hasCachedActions = useRef(_.size(props.reportActions) > 0); @@ -189,7 +188,7 @@ function ReportActionsView(props) { loadMoreChats={loadMoreChats} policy={props.policy} /> - + ); } From 6125c381cde29277f150f1a4156a6b96af05f150 Mon Sep 17 00:00:00 2001 From: Oscar Franco Date: Mon, 28 Aug 2023 13:44:09 +0200 Subject: [PATCH 015/342] Get rid of full list re-render when marking messages as unread --- src/pages/home/report/ReportActionsList.js | 23 +++++++++++----------- 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/src/pages/home/report/ReportActionsList.js b/src/pages/home/report/ReportActionsList.js index 7f897ee825fb..1c0c88e20ec4 100644 --- a/src/pages/home/report/ReportActionsList.js +++ b/src/pages/home/report/ReportActionsList.js @@ -114,9 +114,9 @@ function ReportActionsList({ const readActionSkipped = useRef(false); const reportActionSize = useRef(sortedReportActions.length); - // Considering that renderItem is enclosed within a useCallback, marking it as "read" twice will retain the value as "true," preventing the useCallback from re-executing. - // However, if we create and listen to an object, it will lead to a new useCallback execution. - const [messageManuallyMarked, setMessageManuallyMarked] = useState({read: false}); + // This state is used to force a re-render when the user manually marks a message as unread + // by using a timestamp you can force re-renders without having to worry about if another message was marked as unread before + const [messageManuallyMarkedUnread, setMessageManuallyMarkedUnread] = useState(0); const [isFloatingMessageCounterVisible, setIsFloatingMessageCounterVisible] = useState(false); const animatedStyles = useAnimatedStyle(() => ({ opacity: opacity.value, @@ -163,15 +163,14 @@ function ReportActionsList({ useEffect(() => { const didManuallyMarkReportAsUnread = report.lastReadTime < DateUtils.getDBTime() && ReportUtils.isUnread(report); - if (!didManuallyMarkReportAsUnread) { - setMessageManuallyMarked({read: false}); - return; + if (didManuallyMarkReportAsUnread) { + // Clearing the current unread marker so that it can be recalculated + currentUnreadMarker.current = null; + setMessageManuallyMarkedUnread(new Date().getTime()); + } else { + setMessageManuallyMarkedUnread(0); } - // Clearing the current unread marker so that it can be recalculated - currentUnreadMarker.current = null; - setMessageManuallyMarked({read: true}); - // We only care when a new lastReadTime is set in the report // eslint-disable-next-line react-hooks/exhaustive-deps }, [report.lastReadTime]); @@ -230,7 +229,7 @@ function ReportActionsList({ const isCurrentMessageUnread = isMessageUnread(reportAction, report.lastReadTime); shouldDisplayNewMarker = isCurrentMessageUnread && !isMessageUnread(nextMessage, report.lastReadTime); - if (!messageManuallyMarked.read) { + if (!messageManuallyMarkedUnread) { shouldDisplayNewMarker = shouldDisplayNewMarker && reportAction.actorAccountID !== Report.getCurrentUserAccountID(); } const canDisplayMarker = scrollingVerticalOffset.current < MSG_VISIBLE_THRESHOLD ? reportAction.created < userActiveSince.current : true; @@ -272,7 +271,7 @@ function ReportActionsList({ /> ); }, - [report, hasOutstandingIOU, sortedReportActions, mostRecentIOUReportActionID, messageManuallyMarked], + [report, hasOutstandingIOU, sortedReportActions, mostRecentIOUReportActionID, messageManuallyMarkedUnread], ); // Native mobile does not render updates flatlist the changes even though component did update called. From be7ea564639ef27e0ee8052c948d94f3119211b5 Mon Sep 17 00:00:00 2001 From: Oscar Franco Date: Mon, 28 Aug 2023 16:31:16 +0200 Subject: [PATCH 016/342] Linting --- src/pages/home/ReportScreenContext.js | 5 +---- src/pages/home/report/ReportActionItem.js | 2 +- src/pages/home/report/ReportActionsView.js | 5 ++--- 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/src/pages/home/ReportScreenContext.js b/src/pages/home/ReportScreenContext.js index 0be1882699f4..1e8d30cf7585 100644 --- a/src/pages/home/ReportScreenContext.js +++ b/src/pages/home/ReportScreenContext.js @@ -3,7 +3,4 @@ import {createContext} from 'react'; const ActionListContext = createContext(); const ReactionListContext = createContext(); -export { - ActionListContext, - ReactionListContext -} \ No newline at end of file +export {ActionListContext, ReactionListContext}; diff --git a/src/pages/home/report/ReportActionItem.js b/src/pages/home/report/ReportActionItem.js index 4a0c0d7bd3ba..fe2ea3acf691 100644 --- a/src/pages/home/report/ReportActionItem.js +++ b/src/pages/home/report/ReportActionItem.js @@ -64,7 +64,7 @@ import * as PersonalDetailsUtils from '../../../libs/PersonalDetailsUtils'; import ReportActionItemBasicMessage from './ReportActionItemBasicMessage'; import * as store from '../../../libs/actions/ReimbursementAccount/store'; import * as BankAccounts from '../../../libs/actions/BankAccounts'; -import { ReactionListContext } from '../ReportScreenContext'; +import {ReactionListContext} from '../ReportScreenContext'; import Permissions from '../../../libs/Permissions'; const propTypes = { diff --git a/src/pages/home/report/ReportActionsView.js b/src/pages/home/report/ReportActionsView.js index 70eb65ade3ea..25d01a6953d1 100755 --- a/src/pages/home/report/ReportActionsView.js +++ b/src/pages/home/report/ReportActionsView.js @@ -19,7 +19,7 @@ import * as ReportActionsUtils from '../../../libs/ReportActionsUtils'; import reportPropTypes from '../../reportPropTypes'; import PopoverReactionList from './ReactionList/PopoverReactionList'; import getIsReportFullyVisible from '../../../libs/getIsReportFullyVisible'; -import { ReactionListContext } from '../ReportScreenContext'; +import {ReactionListContext} from '../ReportScreenContext'; const propTypes = { /** The report currently being looked at */ @@ -54,9 +54,8 @@ const defaultProps = { }; function ReportActionsView(props) { - useCopySelectionHelper(); - const reactionListRef = useContext(ReactionListContext) + const reactionListRef = useContext(ReactionListContext); const didLayout = useRef(false); const didSubscribeToReportTypingEvents = useRef(false); const hasCachedActions = useRef(_.size(props.reportActions) > 0); From 43a729626bc2a3a252a83dadcc5c28e881e14fb1 Mon Sep 17 00:00:00 2001 From: Jasper Huang Date: Mon, 28 Aug 2023 14:55:28 -0700 Subject: [PATCH 017/342] add distance request consts --- src/CONST.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/CONST.js b/src/CONST.js index c78268aacd8b..53a7f14c75b5 100755 --- a/src/CONST.js +++ b/src/CONST.js @@ -1309,6 +1309,7 @@ const CONST = { DATE: 'date', DESCRIPTION: 'description', MERCHANT: 'merchant', + DISTANCE: 'distance', }, FOOTER: { EXPENSE_MANAGEMENT_URL: `${USE_EXPENSIFY_URL}/expense-management`, From 28c293e462f7d1b58d1bd5f1cdeb4d86955ccad5 Mon Sep 17 00:00:00 2001 From: Jasper Huang Date: Mon, 28 Aug 2023 16:03:53 -0700 Subject: [PATCH 018/342] add DISTANCE_REQUEST ONYXKEY --- src/ONYXKEYS.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/ONYXKEYS.ts b/src/ONYXKEYS.ts index d4d2ab1f90a6..78430e0fdf33 100755 --- a/src/ONYXKEYS.ts +++ b/src/ONYXKEYS.ts @@ -41,6 +41,9 @@ const ONYXKEYS = { // Contains loading data for the IOU feature (MoneyRequestModal, IOUDetail, & MoneyRequestPreview Components) IOU: 'iou', + // Contains loading data for the DistanceRequest components (MoneyRequestEditWaypointPage) + DISTANCE_REQUEST: 'distanceRequest', + /** Keeps track if there is modal currently visible or not */ MODAL: 'modal', From 322504aafb2a51ac8ffa998db3b12f24935371f9 Mon Sep 17 00:00:00 2001 From: Jasper Huang Date: Mon, 28 Aug 2023 16:04:17 -0700 Subject: [PATCH 019/342] add routes for editdistancerequest and editrequestwaypoint --- src/ROUTES.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/ROUTES.js b/src/ROUTES.js index bf1beaecb3c3..df36bf3e5069 100644 --- a/src/ROUTES.js +++ b/src/ROUTES.js @@ -97,6 +97,7 @@ export default { MONEY_REQUEST_SCAN_TAB: ':iouType/new/:reportID?/scan', MONEY_REQUEST_DISTANCE_TAB: ':iouType/new/:reportID?/distance', MONEY_REQUEST_WAYPOINT: ':iouType/new/waypoint/:waypointIndex', + MONEY_REQUEST_EDIT_WAYPOINT: 'r/:threadReportID/edit/distance/waypoint/:waypointIndex', IOU_SEND_ADD_BANK_ACCOUNT: `${IOU_SEND}/add-bank-account`, IOU_SEND_ADD_DEBIT_CARD: `${IOU_SEND}/add-debit-card`, IOU_SEND_ENABLE_PAYMENTS: `${IOU_SEND}/enable-payments`, @@ -111,6 +112,7 @@ export default { getMoneyRequestMerchantRoute: (iouType, reportID = '') => `${iouType}/new/merchant/${reportID}`, getMoneyRequestDistanceTabRoute: (iouType, reportID = '') => `${iouType}/new/${reportID}/distance`, getMoneyRequestWaypointRoute: (iouType, waypointIndex) => `${iouType}/new/waypoint/${waypointIndex}`, + getMoneyRequestEditWaypointRoute: (threadReportID, waypointIndex) => `r/${threadReportID}/edit/distance/waypoint/${waypointIndex}`, SPLIT_BILL_DETAILS: `r/:reportID/split/:reportActionID`, getSplitBillDetailsRoute: (reportID, reportActionID) => `r/${reportID}/split/${reportActionID}`, getNewTaskRoute: (reportID) => `${NEW_TASK}/${reportID}`, From c5c72a5bba9430de145a99ca1ae2e4eb81dc789c Mon Sep 17 00:00:00 2001 From: Jasper Huang Date: Mon, 28 Aug 2023 16:04:33 -0700 Subject: [PATCH 020/342] add distance translations --- src/languages/en.js | 1 + src/languages/es.js | 1 + 2 files changed, 2 insertions(+) diff --git a/src/languages/en.js b/src/languages/en.js index 5dcb84c4e487..cdc96834289b 100755 --- a/src/languages/en.js +++ b/src/languages/en.js @@ -158,6 +158,7 @@ export default { category: 'Category', receipt: 'Receipt', replace: 'Replace', + distance: 'Distance', }, anonymousReportFooter: { logoTagline: 'Join the discussion.', diff --git a/src/languages/es.js b/src/languages/es.js index 9cb91261cdd5..35ac0c2cc9d8 100644 --- a/src/languages/es.js +++ b/src/languages/es.js @@ -157,6 +157,7 @@ export default { category: 'Categoría', receipt: 'Recibo', replace: 'Sustituir', + distance: 'Distancia', }, anonymousReportFooter: { logoTagline: 'Únete a la discusión.', From 85ac77daa978300b79c7e4386cc0c07f05327e9e Mon Sep 17 00:00:00 2001 From: Jasper Huang Date: Mon, 28 Aug 2023 16:04:50 -0700 Subject: [PATCH 021/342] add editDistanceRequest actions --- src/libs/actions/IOU.js | 64 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/src/libs/actions/IOU.js b/src/libs/actions/IOU.js index 838214bbd98e..3f64c2c7c756 100644 --- a/src/libs/actions/IOU.js +++ b/src/libs/actions/IOU.js @@ -530,6 +530,61 @@ function createDistanceRequest(report, payeeEmail, payeeAccountID, participant, ); } +/** + * Edits an existing distance request + * + * @param {String} transactionID + * @param {Object} transactionChanges + * @param {String} [transactionChanges.created] + * @param {Number} [transactionChanges.amount] + * @param {String} [transactionChanges.comment] + * @param {String} [transactionChanges.waypoints] + * + */ +function editDistanceRequest(transactionID, transactionThreadReportID, transactionChanges) { + const pendingFields = _.mapObject(updatedProperties, () => CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE); + const clearedPendingFields = _.mapObject(updatedProperties, () => null); + const errorFields = _.mapObject(pendingFields, () => ({ + [DateUtils.getMicroseconds()]: Localize.translateLocal('iou.edit.genericError'), + })); + + const transactionThread = allReports[`${ONYXKEYS.COLLECTION.REPORT}${transactionThreadReportID}`]; + const transaction = allTransactions[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`]; + const iouReport = allReports[`${ONYXKEYS.COLLECTION.REPORT}${transactionThread.parentReportID}`]; + const isFromExpenseReport = ReportUtils.isExpenseReport(iouReport); + const updatedTransaction = TransactionUtils.getUpdatedTransaction(transaction, transactionChanges, isFromExpenseReport); + API.write( + 'EditDistanceRequest', + {transactionID, ...ReportUtils.getTransactionDetails(updatedTransaction)}, + { + optimisticData: [ + { + onyxMethod: CONST.ONYX.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`, + value: {...updatedProperties, pendingFields}, + }, + ], + successData: [ + { + onyxMethod: CONST.ONYX.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`, + value: {pendingFields: clearedPendingFields}, + }, + ], + failureData: [ + { + onyxMethod: CONST.ONYX.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`, + value: { + pendingFields: clearedPendingFields, + errorFields, + }, + }, + ], + }, + ); +} + /** * Request money from another user * @@ -1767,6 +1822,13 @@ function createEmptyTransaction() { Onyx.merge(ONYXKEYS.IOU, {transactionID}); } +/** + * @param {String} transactionID + */ +function setDistanceRequestTransactionID(transactionID) { + Onyx.set(ONYXKEYS.DISTANCE_REQUEST, {transactionID}); +} + /** * Navigates to the next IOU page based on where the IOU request was started * @@ -1825,6 +1887,8 @@ export { setMoneyRequestMerchant, setMoneyRequestParticipants, setMoneyRequestReceipt, + setDistanceRequestTransactionID, createEmptyTransaction, navigateToNextPage, + editDistanceRequest, }; From 4cac0948a58821e3c9587b178eb82af91f657292 Mon Sep 17 00:00:00 2001 From: Jasper Huang Date: Mon, 28 Aug 2023 16:05:12 -0700 Subject: [PATCH 022/342] add new pages for editing distance requests --- src/pages/EditRequestDistancePage.js | 51 ++++++++++++++++++ src/pages/iou/MoneyRequestEditWaypointPage.js | 52 +++++++++++++++++++ 2 files changed, 103 insertions(+) create mode 100644 src/pages/EditRequestDistancePage.js create mode 100644 src/pages/iou/MoneyRequestEditWaypointPage.js diff --git a/src/pages/EditRequestDistancePage.js b/src/pages/EditRequestDistancePage.js new file mode 100644 index 000000000000..f2587db43a14 --- /dev/null +++ b/src/pages/EditRequestDistancePage.js @@ -0,0 +1,51 @@ +import React, {useEffect} from 'react'; +import PropTypes from 'prop-types'; +import ScreenWrapper from '../components/ScreenWrapper'; +import HeaderWithBackButton from '../components/HeaderWithBackButton'; +import Navigation from '../libs/Navigation/Navigation'; +import useLocalize from '../hooks/useLocalize'; +import DistanceRequest from '../components/DistanceRequest'; +import reportPropTypes from './reportPropTypes'; +import * as IOU from '../libs/actions/IOU'; + +const propTypes = { + /** The transactionID we're currently editing */ + transactionID: PropTypes.number, + + /** The report to with which the distance request is associated */ + report: reportPropTypes, +}; + +function EditRequestDistancePage({iou, report}) { + + useEffect(() => { + IOU.setDistanceRequestTransactionID(iou.transactionID); + }, []) + + const {translate} = useLocalize(); + return ( + + Navigation.goBack()} + /> + { + IOU.editDistanceRequest(iou.transactionID, report.reportID, {waypoints}); + Navigation.dismissModal(); + }} + /> + + ); +} + +EditRequestDistancePage.propTypes = propTypes; +EditRequestDistancePage.displayName = 'EditRequestDistancePage'; + +export default EditRequestDistancePage; diff --git a/src/pages/iou/MoneyRequestEditWaypointPage.js b/src/pages/iou/MoneyRequestEditWaypointPage.js new file mode 100644 index 000000000000..4a212cadd957 --- /dev/null +++ b/src/pages/iou/MoneyRequestEditWaypointPage.js @@ -0,0 +1,52 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import {withOnyx} from 'react-native-onyx'; +import WaypointEditor from './WaypointEditor'; +import ONYXKEYS from '../../ONYXKEYS'; + +const propTypes = { + /** The transactionID of this request */ + transactionID: PropTypes.string, + + /** Route params */ + route: PropTypes.shape({ + params: PropTypes.shape({ + /** IOU type */ + iouType: PropTypes.string, + + /** Index of the waypoint being edited */ + waypointIndex: PropTypes.string, + }), + }), +}; + +const defaultProps = { + transactionID: '', + route: { + params: { + iouType: '', + waypointIndex: '', + }, + }, +}; + +// This component is responsible for grabbing the transactionID from the IOU key +// You can't use Onyx props in the withOnyx mapping, so we need to set up and access the transactionID here, and then pass it down so that WaypointEditor can subscribe to the transaction. +function MoneyRequestEditWaypointPage({transactionID, route}) { + console.log(">>>> transactionID", transactionID); + return ( + + ); +} + +MoneyRequestEditWaypointPage.displayName = 'MoneyRequestEditWaypointPage'; +MoneyRequestEditWaypointPage.propTypes = propTypes; +MoneyRequestEditWaypointPage.defaultProps = defaultProps; +export default withOnyx({ + // We must provide a default value for transactionID here, otherwise the component won't mount + // because withOnyx returns null until all the keys are defined + transactionID: {key: ONYXKEYS.DISTANCE_REQUEST, selector: (distanceRequest) => (distanceRequest && distanceRequest.transactionID) || ''}, +})(MoneyRequestEditWaypointPage); From ec140606b87805a5dc28f94e5ca816f3dc0f729c Mon Sep 17 00:00:00 2001 From: Jasper Huang Date: Mon, 28 Aug 2023 16:05:44 -0700 Subject: [PATCH 023/342] simplify DistanceRequest to just take a transactionID, modify to handle edits --- src/components/DistanceRequest.js | 47 ++++++++++++++----------------- 1 file changed, 21 insertions(+), 26 deletions(-) diff --git a/src/components/DistanceRequest.js b/src/components/DistanceRequest.js index c96342dd8965..55975022866a 100644 --- a/src/components/DistanceRequest.js +++ b/src/components/DistanceRequest.js @@ -22,7 +22,6 @@ import useNetwork from '../hooks/useNetwork'; import useLocalize from '../hooks/useLocalize'; import Navigation from '../libs/Navigation/Navigation'; import ROUTES from '../ROUTES'; -import * as IOU from '../libs/actions/IOU'; import participantPropTypes from './participantPropTypes'; import reportPropTypes from '../pages/reportPropTypes'; import transactionPropTypes from './transactionPropTypes'; @@ -38,17 +37,8 @@ const MAP_PADDING = 50; const DEFAULT_ZOOM_LEVEL = 10; const propTypes = { - /** Holds data related to Money Request view state, rather than the underlying Money Request data. */ - iou: PropTypes.shape({ - id: PropTypes.string, - amount: PropTypes.number, - currency: PropTypes.string, - participants: PropTypes.arrayOf(participantPropTypes), - transactionID: PropTypes.string, - }), - - /** Type of money request (i.e. IOU) */ - iouType: PropTypes.string, + /** The transactionID of the distance request we're currently looking at */ + transactionID: PropTypes.number, /** The report to with which the distance request is associated */ report: reportPropTypes, @@ -64,6 +54,12 @@ const propTypes = { /** Time when the token will expire in ISO 8601 */ expiration: PropTypes.string, }), + + /** Are we editing an existing distance request, or creating a new one? */ + isEditingRequest: PropTypes.bool, + + /** Called on submit of this page */ + onSubmit: PropTypes.func.isRequired, }; const defaultProps = { @@ -71,15 +67,13 @@ const defaultProps = { id: '', amount: 0, currency: CONST.CURRENCY.USD, - participants: [], }, - iouType: '', - report: {}, transaction: {}, mapboxAccessToken: {}, + isEditingRequest: false, }; -function DistanceRequest({iou, iouType, report, transaction, mapboxAccessToken}) { +function DistanceRequest({transactionID, report, transaction, mapboxAccessToken, isEditingRequest, onSubmit}) { const [shouldShowGradient, setShouldShowGradient] = useState(false); const [scrollContainerHeight, setScrollContainerHeight] = useState(0); const [scrollContentHeight, setScrollContentHeight] = useState(0); @@ -136,12 +130,13 @@ function DistanceRequest({iou, iouType, report, transaction, mapboxAccessToken}) }, []); useEffect(() => { - if (!iou.transactionID || !_.isEmpty(waypoints)) { + console.log(">>>>", transactionID, waypoints); + if (!transactionID || !_.isEmpty(waypoints)) { return; } // Create the initial start and stop waypoints - Transaction.createInitialWaypoints(iou.transactionID); - }, [iou.transactionID, waypoints]); + Transaction.createInitialWaypoints(transactionID); + }, [transactionID, waypoints]); const updateGradientVisibility = (event = {}) => { // If a waypoint extends past the bottom of the visible area show the gradient, else hide it. @@ -155,8 +150,8 @@ function DistanceRequest({iou, iouType, report, transaction, mapboxAccessToken}) return; } - Transaction.getRoute(iou.transactionID, waypoints); - }, [shouldFetchRoute, iou.transactionID, waypoints]); + Transaction.getRoute(transactionID, waypoints); + }, [shouldFetchRoute, transactionID, waypoints]); useEffect(updateGradientVisibility, [scrollContainerHeight, scrollContentHeight]); @@ -196,7 +191,7 @@ function DistanceRequest({iou, iouType, report, transaction, mapboxAccessToken}) secondaryIcon={waypointIcon} secondaryIconFill={theme.icon} shouldShowRightIcon - onPress={() => Navigation.navigate(ROUTES.getMoneyRequestWaypointRoute('request', index))} + onPress={() => Navigation.navigate(isEditingRequest ? ROUTES.getMoneyRequestEditWaypointRoute(report.reportID, index) : ROUTES.getMoneyRequestWaypointRoute('request', index))} key={key} /> ); @@ -220,7 +215,7 @@ function DistanceRequest({iou, iouType, report, transaction, mapboxAccessToken})