From f747ae905ffd5a1994b41748b969e4b4a6b21d38 Mon Sep 17 00:00:00 2001 From: Adam Grzybowski Date: Fri, 1 Sep 2023 18:26:41 +0200 Subject: [PATCH 1/9] improve goBack function --- src/libs/Navigation/Navigation.js | 37 +++++++++++++++++++++++++++++-- src/libs/actions/IOU.js | 6 ++--- 2 files changed, 37 insertions(+), 6 deletions(-) diff --git a/src/libs/Navigation/Navigation.js b/src/libs/Navigation/Navigation.js index 677981fcbeba..df3a0d426161 100644 --- a/src/libs/Navigation/Navigation.js +++ b/src/libs/Navigation/Navigation.js @@ -1,7 +1,7 @@ import _ from 'lodash'; import lodashGet from 'lodash/get'; import {CommonActions, getPathFromState, StackActions} from '@react-navigation/native'; -import {getActionFromState} from '@react-navigation/core'; +import {getActionFromState, findFocusedRoute} from '@react-navigation/core'; import Log from '../Log'; import DomUtils from '../DomUtils'; import linkTo from './linkTo'; @@ -70,6 +70,24 @@ const getActiveRouteIndex = function (route, index) { return index; }; +function getPathsForRoutesInRootNavigator() { + let currentState = navigationRef.getRootState(); + const paths = []; + + while (currentState.routes.length > 0) { + try { + const path = getPathFromState(currentState, linkingConfig.config); + if (path) { + paths.push(path.substring(1)); + } + } catch (e) { + return paths; + } + currentState = {...currentState, routes: currentState.routes.slice(0, -1), index: currentState.index - 1}; + } + return paths; +} + /** * Main navigation method for redirecting to a route. * @param {String} route @@ -116,7 +134,6 @@ function goBack(fallbackRoute = ROUTES.HOME, shouldEnforceFallback = false, shou } const isFirstRouteInNavigator = !getActiveRouteIndex(navigationRef.current.getState()); - if (isFirstRouteInNavigator) { const rootState = navigationRef.getRootState(); const lastRoute = _.last(rootState.routes); @@ -132,6 +149,22 @@ function goBack(fallbackRoute = ROUTES.HOME, shouldEnforceFallback = false, shou return; } + const isCentralPaneFocused = findFocusedRoute(navigationRef.current.getState()).name === NAVIGATORS.CENTRAL_PANE_NAVIGATOR; + const pathsForRoutesInRootNavigator = getPathsForRoutesInRootNavigator(); + + // Allow CentralPane to use goBack with fallback route. + if (isCentralPaneFocused && fallbackRoute && !pathsForRoutesInRootNavigator.includes(fallbackRoute)) { + navigate(fallbackRoute, CONST.NAVIGATION.TYPE.FORCED_UP); + return; + } + + // Add posibility to go back more than one screen in root navigator. + if (isCentralPaneFocused && fallbackRoute && pathsForRoutesInRootNavigator.indexOf(fallbackRoute) > 0) { + const popNumber = pathsForRoutesInRootNavigator.indexOf(fallbackRoute); + navigationRef.current.dispatch(StackActions.pop(popNumber)); + return; + } + navigationRef.current.goBack(); } diff --git a/src/libs/actions/IOU.js b/src/libs/actions/IOU.js index bf00a030c115..407da2063348 100644 --- a/src/libs/actions/IOU.js +++ b/src/libs/actions/IOU.js @@ -1262,15 +1262,13 @@ function deleteMoneyRequest(transactionID, reportAction, isSingleTransactionView // STEP 7: Navigate the user depending on which page they are on and which resources were deleted if (isSingleTransactionView && shouldDeleteTransactionThread && !shouldDeleteIOUReport) { // Pop the deleted report screen before navigating. This prevents navigating to the Concierge chat due to the missing report. - Navigation.goBack(); - Navigation.navigate(ROUTES.getReportRoute(iouReport.reportID)); + Navigation.goBack(ROUTES.getReportRoute(iouReport.reportID)); return; } if (shouldDeleteIOUReport) { // Pop the deleted report screen before navigating. This prevents navigating to the Concierge chat due to the missing report. - Navigation.goBack(); - Navigation.navigate(ROUTES.getReportRoute(iouReport.chatReportID)); + Navigation.goBack(ROUTES.getReportRoute(iouReport.chatReportID)); } } From 881dc8497df76e5a1b127397f156d4f8250bfbed Mon Sep 17 00:00:00 2001 From: Adam Grzybowski Date: Mon, 25 Sep 2023 13:58:02 +0200 Subject: [PATCH 2/9] fix typo --- src/libs/actions/IOU.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/actions/IOU.js b/src/libs/actions/IOU.js index ca5e28a258cb..2d20c8819da1 100644 --- a/src/libs/actions/IOU.js +++ b/src/libs/actions/IOU.js @@ -1488,7 +1488,7 @@ function deleteMoneyRequest(transactionID, reportAction, isSingleTransactionView if (shouldDeleteIOUReport) { // Pop the deleted report screen before navigating. This prevents navigating to the Concierge chat due to the missing report. - Navigation.goBack(ROUTES.REPORT_WITH_ID.getRoute(ioureport.chatreportid)); + Navigation.goBack(ROUTES.REPORT_WITH_ID.getRoute(iouReport.chatReportID)); } } From 59c3cdcf14ece6a0135dee280034cb4b2c554748 Mon Sep 17 00:00:00 2001 From: Adam Grzybowski Date: Mon, 25 Sep 2023 19:00:30 +0200 Subject: [PATCH 3/9] fix tests --- tests/actions/IOUTest.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/actions/IOUTest.js b/tests/actions/IOUTest.js index 3df3b137bab3..fbbb19b2445d 100644 --- a/tests/actions/IOUTest.js +++ b/tests/actions/IOUTest.js @@ -2148,14 +2148,14 @@ describe('actions/IOU', () => { // Then we expect to navigate to the iou report - expect(Navigation.navigate).toHaveBeenCalledWith(ROUTES.REPORT_WITH_ID.getRoute(IOU_REPORT_ID)); + expect(Navigation.goBack).toHaveBeenCalledWith(ROUTES.REPORT_WITH_ID.getRoute(IOU_REPORT_ID)); }); it('navigate the user correctly to the chat Report when appropriate', () => { // When we delete the money request and we should delete the IOU report IOU.deleteMoneyRequest(transaction.transactionID, createIOUAction, false); // Then we expect to navigate to the chat report - expect(Navigation.navigate).toHaveBeenCalledWith(ROUTES.REPORT_WITH_ID.getRoute(chatReport.reportID)); + expect(Navigation.goBack).toHaveBeenCalledWith(ROUTES.REPORT_WITH_ID.getRoute(chatReport.reportID)); }); }); }); From 5fd8ec91be6860ea7ce82541e00e697ff4a59d0c Mon Sep 17 00:00:00 2001 From: Adam Grzybowski Date: Thu, 26 Oct 2023 16:32:28 +0200 Subject: [PATCH 4/9] limit search for path to 5 screens from the top --- src/libs/Navigation/Navigation.js | 42 ++++++++++++++++++------------- 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/src/libs/Navigation/Navigation.js b/src/libs/Navigation/Navigation.js index 4a3e8bd5a143..e96824892986 100644 --- a/src/libs/Navigation/Navigation.js +++ b/src/libs/Navigation/Navigation.js @@ -77,22 +77,29 @@ const getActiveRouteIndex = function (route, index) { return index; }; -function getPathsForRoutesInRootNavigator() { +/** + * Gets distance from the path in root navigator. In other words how much screen you have to pop to get to the route with this path. + * The search is limited to 5 screens from the top for performance reasons. + * @param {String} path - Path that you are looking for. + * @return {Number} - Returns distance to path or -1 if the path is not found in root navigator. + */ +function getDistanceFromPathInRootNavigator(path) { let currentState = navigationRef.getRootState(); - const paths = []; - while (currentState.routes.length > 0) { - try { - const path = getPathFromState(currentState, linkingConfig.config); - if (path) { - paths.push(path.substring(1)); - } - } catch (e) { - return paths; + for (let index = 0; index < 5; index++) { + if (!currentState.routes.length) { + break; } + + const pathFromState = getPathFromState(currentState, linkingConfig.config); + if (path === pathFromState.substring(1)) { + return index; + } + currentState = {...currentState, routes: currentState.routes.slice(0, -1), index: currentState.index - 1}; } - return paths; + + return -1; } /** @@ -152,18 +159,17 @@ function goBack(fallbackRoute, shouldEnforceFallback = false, shouldPopToTop = f } const isCentralPaneFocused = findFocusedRoute(navigationRef.current.getState()).name === NAVIGATORS.CENTRAL_PANE_NAVIGATOR; - const pathsForRoutesInRootNavigator = getPathsForRoutesInRootNavigator(); + const distanceFromPathInRootNavigator = getDistanceFromPathInRootNavigator(fallbackRoute); - // Allow CentralPane to use goBack with fallback route. - if (isCentralPaneFocused && fallbackRoute && !pathsForRoutesInRootNavigator.includes(fallbackRoute)) { + // Allow CentralPane to use UP with fallback route if the path is not found in root navigator. + if (isCentralPaneFocused && fallbackRoute && distanceFromPathInRootNavigator === -1) { navigate(fallbackRoute, CONST.NAVIGATION.TYPE.FORCED_UP); return; } - // Add posibility to go back more than one screen in root navigator. - if (isCentralPaneFocused && fallbackRoute && pathsForRoutesInRootNavigator.indexOf(fallbackRoute) > 0) { - const popNumber = pathsForRoutesInRootNavigator.indexOf(fallbackRoute); - navigationRef.current.dispatch(StackActions.pop(popNumber)); + // Add posibility to go back more than one screen in root navigator if that screen is on the stack. + if (isCentralPaneFocused && fallbackRoute && distanceFromPathInRootNavigator > 0) { + navigationRef.current.dispatch(StackActions.pop(distanceFromPathInRootNavigator)); return; } From fac03c4749e47129889af629a7781a078c077d9c Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Tue, 7 Nov 2023 15:26:47 +0100 Subject: [PATCH 5/9] Add OptionRowLHNDataReport --- .../LHNOptionsList/OptionRowLHNData.js | 157 ++++-------------- .../LHNOptionsList/OptionRowLHNDataReport.js | 156 +++++++++++++++++ 2 files changed, 187 insertions(+), 126 deletions(-) create mode 100644 src/components/LHNOptionsList/OptionRowLHNDataReport.js diff --git a/src/components/LHNOptionsList/OptionRowLHNData.js b/src/components/LHNOptionsList/OptionRowLHNData.js index ebba2ffe0587..b661c09622a3 100644 --- a/src/components/LHNOptionsList/OptionRowLHNData.js +++ b/src/components/LHNOptionsList/OptionRowLHNData.js @@ -1,20 +1,13 @@ -import {deepEqual} from 'fast-equals'; -import lodashGet from 'lodash/get'; import PropTypes from 'prop-types'; -import React, {useEffect, useMemo, useRef} from 'react'; +import React from 'react'; import {withOnyx} from 'react-native-onyx'; import _ from 'underscore'; import participantPropTypes from '@components/participantPropTypes'; -import compose from '@libs/compose'; -import * as ReportActionsUtils from '@libs/ReportActionsUtils'; -import SidebarUtils from '@libs/SidebarUtils'; -import * as TransactionUtils from '@libs/TransactionUtils'; import * as UserUtils from '@libs/UserUtils'; -import reportActionPropTypes from '@pages/home/report/reportActionPropTypes'; -import * as Report from '@userActions/Report'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; -import OptionRowLHN, {defaultProps as baseDefaultProps, propTypes as basePropTypes} from './OptionRowLHN'; +import {defaultProps as baseDefaultProps, propTypes as basePropTypes} from './OptionRowLHN'; +import OptionRowLHNDataReport from './OptionRowLHNDataReport'; const propTypes = { /** Whether row should be focused */ @@ -30,24 +23,6 @@ const propTypes = { // eslint-disable-next-line react/forbid-prop-types fullReport: PropTypes.object, - /** The policy which the user has access to and which the report could be tied to */ - policy: PropTypes.shape({ - /** The ID of the policy */ - id: PropTypes.string, - /** Name of the policy */ - name: PropTypes.string, - /** Avatar of the policy */ - avatar: PropTypes.string, - }), - - /** The actions from the parent report */ - parentReportActions: PropTypes.objectOf(PropTypes.shape(reportActionPropTypes)), - - /** The transaction from the parent report action */ - transaction: PropTypes.shape({ - /** The ID of the transaction */ - transactionID: PropTypes.string, - }), ...basePropTypes, }; @@ -63,66 +38,20 @@ const defaultProps = { }; /* - * This component gets the data from onyx for the actual - * OptionRowLHN component. - * The OptionRowLHN component is memoized, so it will only - * re-render if the data really changed. + * This component checks whether a fullReport object is defined for the provided reportID */ -function OptionRowLHNData({ - isFocused, - fullReport, - reportActions, - personalDetails, - preferredLocale, - comment, - policy, - receiptTransactions, - parentReportActions, - transaction, - ...propsToForward -}) { - const reportID = propsToForward.reportID; - - const parentReportAction = parentReportActions[fullReport.parentReportActionID]; - - const optionItemRef = useRef(); - - const linkedTransaction = useMemo(() => { - const sortedReportActions = ReportActionsUtils.getSortedReportActionsForDisplay(reportActions); - const lastReportAction = _.first(sortedReportActions); - return TransactionUtils.getLinkedTransaction(lastReportAction); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [fullReport.reportID, receiptTransactions, reportActions]); - - const optionItem = useMemo(() => { - // Note: ideally we'd have this as a dependent selector in onyx! - const item = SidebarUtils.getOptionData(fullReport, reportActions, personalDetails, preferredLocale, policy, parentReportAction); - if (deepEqual(item, optionItemRef.current)) { - return optionItemRef.current; - } - optionItemRef.current = item; - return item; - // Listen parentReportAction to update title of thread report when parentReportAction changed - // Listen to transaction to update title of transaction report when transaction changed - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [fullReport, linkedTransaction, reportActions, personalDetails, preferredLocale, policy, parentReportAction, transaction]); - - useEffect(() => { - if (!optionItem || optionItem.hasDraftComment || !comment || comment.length <= 0 || isFocused) { - return; - } - Report.setReportWithDraft(reportID, true); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); - - return ( - - ); + ) : null; } OptionRowLHNData.propTypes = propTypes; @@ -161,47 +90,23 @@ const personalDetailsSelector = (personalDetails) => * use it to prevent re-renders from parent re-renders. */ export default React.memo( - compose( - withOnyx({ - comment: { - key: ({reportID}) => `${ONYXKEYS.COLLECTION.REPORT_DRAFT_COMMENT}${reportID}`, - }, - fullReport: { - key: ({reportID}) => `${ONYXKEYS.COLLECTION.REPORT}${reportID}`, - }, - reportActions: { - key: ({reportID}) => `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`, - canEvict: false, - }, - personalDetails: { - key: ONYXKEYS.PERSONAL_DETAILS_LIST, - selector: personalDetailsSelector, - }, - preferredLocale: { - key: ONYXKEYS.NVP_PREFERRED_LOCALE, - }, - }), - // eslint-disable-next-line rulesdir/no-multiple-onyx-in-file - withOnyx({ - parentReportActions: { - key: ({fullReport}) => `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${fullReport.parentReportID}`, - canEvict: false, - }, - policy: { - key: ({fullReport}) => `${ONYXKEYS.COLLECTION.POLICY}${fullReport.policyID}`, - }, - // Ideally, we aim to access only the last transaction for the current report by listening to changes in reportActions. - // In some scenarios, a transaction might be created after reportActions have been modified. - // This can lead to situations where `lastTransaction` doesn't update and retains the previous value. - // However, performance overhead of this is minimized by using memos inside the component. - receiptTransactions: {key: ONYXKEYS.COLLECTION.TRANSACTION}, - }), - // eslint-disable-next-line rulesdir/no-multiple-onyx-in-file - withOnyx({ - transaction: { - key: ({fullReport, parentReportActions}) => - `${ONYXKEYS.COLLECTION.TRANSACTION}${lodashGet(parentReportActions, [fullReport.parentReportActionID, 'originalMessage', 'IOUTransactionID'], '')}`, - }, - }), - )(OptionRowLHNData), + withOnyx({ + comment: { + key: ({reportID}) => `${ONYXKEYS.COLLECTION.REPORT_DRAFT_COMMENT}${reportID}`, + }, + fullReport: { + key: ({reportID}) => `${ONYXKEYS.COLLECTION.REPORT}${reportID}`, + }, + reportActions: { + key: ({reportID}) => `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`, + canEvict: false, + }, + personalDetails: { + key: ONYXKEYS.PERSONAL_DETAILS_LIST, + selector: personalDetailsSelector, + }, + preferredLocale: { + key: ONYXKEYS.NVP_PREFERRED_LOCALE, + }, + })(OptionRowLHNData), ); diff --git a/src/components/LHNOptionsList/OptionRowLHNDataReport.js b/src/components/LHNOptionsList/OptionRowLHNDataReport.js new file mode 100644 index 000000000000..ff0980913321 --- /dev/null +++ b/src/components/LHNOptionsList/OptionRowLHNDataReport.js @@ -0,0 +1,156 @@ +import {deepEqual} from 'fast-equals'; +import lodashGet from 'lodash/get'; +import PropTypes from 'prop-types'; +import React, {useEffect, useMemo, useRef} from 'react'; +import {withOnyx} from 'react-native-onyx'; +import _ from 'underscore'; +import participantPropTypes from '@components/participantPropTypes'; +import compose from '@libs/compose'; +import * as ReportActionsUtils from '@libs/ReportActionsUtils'; +import SidebarUtils from '@libs/SidebarUtils'; +import * as TransactionUtils from '@libs/TransactionUtils'; +import reportActionPropTypes from '@pages/home/report/reportActionPropTypes'; +import * as Report from '@userActions/Report'; +import CONST from '@src/CONST'; +import ONYXKEYS from '@src/ONYXKEYS'; +import OptionRowLHN, {defaultProps as baseDefaultProps, propTypes as basePropTypes} from './OptionRowLHN'; + +const propTypes = { + /** Whether row should be focused */ + isFocused: PropTypes.bool, + + /** List of users' personal details */ + personalDetails: PropTypes.objectOf(participantPropTypes), + + /** The preferred language for the app */ + preferredLocale: PropTypes.string, + + /** The full data of the report */ + // eslint-disable-next-line react/forbid-prop-types + fullReport: PropTypes.object, + + /** The policy which the user has access to and which the report could be tied to */ + policy: PropTypes.shape({ + /** The ID of the policy */ + id: PropTypes.string, + /** Name of the policy */ + name: PropTypes.string, + /** Avatar of the policy */ + avatar: PropTypes.string, + }), + + /** The actions from the parent report */ + parentReportActions: PropTypes.objectOf(PropTypes.shape(reportActionPropTypes)), + + /** The transaction from the parent report action */ + transaction: PropTypes.shape({ + /** The ID of the transaction */ + transactionID: PropTypes.string, + }), + ...basePropTypes, +}; + +const defaultProps = { + isFocused: false, + personalDetails: {}, + fullReport: {}, + policy: {}, + parentReportActions: {}, + transaction: {}, + preferredLocale: CONST.LOCALES.DEFAULT, + ...baseDefaultProps, +}; + +/* + * This component gets the data from onyx for the actual + * OptionRowLHN component. + * The OptionRowLHN component is memoized, so it will only + * re-render if the data really changed. + */ +function OptionRowLHNDataReport({ + isFocused, + fullReport, + reportActions, + personalDetails, + preferredLocale, + comment, + policy, + receiptTransactions, + parentReportActions, + transaction, + ...propsToForward +}) { + const reportID = propsToForward.reportID; + + const parentReportAction = parentReportActions[fullReport.parentReportActionID]; + + const optionItemRef = useRef(); + + const linkedTransaction = useMemo(() => { + const sortedReportActions = ReportActionsUtils.getSortedReportActionsForDisplay(reportActions); + const lastReportAction = _.first(sortedReportActions); + return TransactionUtils.getLinkedTransaction(lastReportAction); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [fullReport.reportID, receiptTransactions, reportActions]); + + const optionItem = useMemo(() => { + // Note: ideally we'd have this as a dependent selector in onyx! + const item = SidebarUtils.getOptionData(fullReport, reportActions, personalDetails, preferredLocale, policy, parentReportAction); + if (deepEqual(item, optionItemRef.current)) { + return optionItemRef.current; + } + optionItemRef.current = item; + return item; + // Listen parentReportAction to update title of thread report when parentReportAction changed + // Listen to transaction to update title of transaction report when transaction changed + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [fullReport, linkedTransaction, reportActions, personalDetails, preferredLocale, policy, parentReportAction, transaction]); + + useEffect(() => { + if (!optionItem || optionItem.hasDraftComment || !comment || comment.length <= 0 || isFocused) { + return; + } + Report.setReportWithDraft(reportID, true); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + return ( + + ); +} + +OptionRowLHNDataReport.propTypes = propTypes; +OptionRowLHNDataReport.defaultProps = defaultProps; +OptionRowLHNDataReport.displayName = 'OptionRowLHNDataReport'; + +export default React.memo( + compose( + // eslint-disable-next-line rulesdir/no-multiple-onyx-in-file + withOnyx({ + parentReportActions: { + key: ({fullReport}) => `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${fullReport.parentReportID}`, + canEvict: false, + }, + policy: { + key: ({fullReport}) => `${ONYXKEYS.COLLECTION.POLICY}${fullReport.policyID}`, + }, + // Ideally, we aim to access only the last transaction for the current report by listening to changes in reportActions. + // In some scenarios, a transaction might be created after reportActions have been modified. + // This can lead to situations where `lastTransaction` doesn't update and retains the previous value. + // However, performance overhead of this is minimized by using memos inside the component. + receiptTransactions: {key: ONYXKEYS.COLLECTION.TRANSACTION}, + }), + // eslint-disable-next-line rulesdir/no-multiple-onyx-in-file + withOnyx({ + transaction: { + key: ({fullReport, parentReportActions}) => + `${ONYXKEYS.COLLECTION.TRANSACTION}${lodashGet(parentReportActions, [fullReport.parentReportActionID, 'originalMessage', 'IOUTransactionID'], '')}`, + }, + }), + )(OptionRowLHNDataReport), +); From 22114beaa3574df94059a66a225c57f8c1974a70 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Tue, 7 Nov 2023 16:01:49 +0100 Subject: [PATCH 6/9] Fix propTypes in OptionRowLHNData --- src/components/LHNOptionsList/OptionRowLHNData.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/LHNOptionsList/OptionRowLHNData.js b/src/components/LHNOptionsList/OptionRowLHNData.js index e506fdb17fa1..4db32ed8bd2a 100644 --- a/src/components/LHNOptionsList/OptionRowLHNData.js +++ b/src/components/LHNOptionsList/OptionRowLHNData.js @@ -16,7 +16,7 @@ const propTypes = { isFocused: PropTypes.bool, /** List of users' personal details */ - personalDetails: PropTypes.objectOf(participantPropTypes), + personalDetails: PropTypes.arrayOf(participantPropTypes), /** The preferred language for the app */ preferredLocale: PropTypes.string, @@ -128,4 +128,4 @@ OptionRowLHNData.displayName = 'OptionRowLHNData'; * Thats also why the React.memo is used on the outer component here, as we just * use it to prevent re-renders from parent re-renders. */ -export default React.memo(OptionRowLHNData); \ No newline at end of file +export default React.memo(OptionRowLHNData); From 35b4e442c197f604194d41db27ffc2b19bb76fa7 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Wed, 8 Nov 2023 13:35:52 +0100 Subject: [PATCH 7/9] Fix flatList position after deleting money requests --- src/pages/home/report/ReportActionsList.js | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/pages/home/report/ReportActionsList.js b/src/pages/home/report/ReportActionsList.js index 11c8077745f9..1379af18581e 100644 --- a/src/pages/home/report/ReportActionsList.js +++ b/src/pages/home/report/ReportActionsList.js @@ -1,4 +1,4 @@ -import {useRoute} from '@react-navigation/native'; +import {useFocusEffect, useRoute} from '@react-navigation/native'; import lodashGet from 'lodash/get'; import PropTypes from 'prop-types'; import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react'; @@ -152,6 +152,16 @@ function ReportActionsList({ opacity: opacity.value, })); + // This hook fixes the position of the FlatList when the user is at the bottom of the list and returns from other screens after deleting list items + useFocusEffect( + useCallback(() => { + if (scrollingVerticalOffset.current !== 0) { + return; + } + reportScrollManager.scrollToBottom(); + }, [reportScrollManager]), + ); + useEffect(() => { opacity.value = withTiming(1, {duration: 100}); }, [opacity]); From aec50d8b0668540f239f007b6487d34269e87d65 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Fri, 10 Nov 2023 16:07:09 +0100 Subject: [PATCH 8/9] Remove the useFocusEffect hook from ReportActionsList --- src/pages/home/report/ReportActionsList.js | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/src/pages/home/report/ReportActionsList.js b/src/pages/home/report/ReportActionsList.js index 6fb78acae3d3..759e73aa90e5 100644 --- a/src/pages/home/report/ReportActionsList.js +++ b/src/pages/home/report/ReportActionsList.js @@ -1,4 +1,4 @@ -import {useFocusEffect, useRoute} from '@react-navigation/native'; +import {useRoute} from '@react-navigation/native'; import lodashGet from 'lodash/get'; import PropTypes from 'prop-types'; import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react'; @@ -152,16 +152,6 @@ function ReportActionsList({ opacity: opacity.value, })); - // This hook fixes the position of the FlatList when the user is at the bottom of the list and returns from other screens after deleting list items - useFocusEffect( - useCallback(() => { - if (scrollingVerticalOffset.current !== 0) { - return; - } - reportScrollManager.scrollToBottom(); - }, [reportScrollManager]), - ); - useEffect(() => { opacity.value = withTiming(1, {duration: 100}); }, [opacity]); From 057f055bbd728a2490fc9a1e9ea41e2729fc3168 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Mon, 13 Nov 2023 08:44:08 +0100 Subject: [PATCH 9/9] Add AUTOSCROLL_TO_TOP_THRESHOLD const --- src/components/InvertedFlatList/BaseInvertedFlatList.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/components/InvertedFlatList/BaseInvertedFlatList.js b/src/components/InvertedFlatList/BaseInvertedFlatList.js index 802ae373d22a..90b4e02e2e4a 100644 --- a/src/components/InvertedFlatList/BaseInvertedFlatList.js +++ b/src/components/InvertedFlatList/BaseInvertedFlatList.js @@ -4,7 +4,8 @@ import {FlatList as NativeFlatlist, View} from 'react-native'; import _ from 'underscore'; import FlatList from '@components/FlatList'; import * as CollectionUtils from '@libs/CollectionUtils'; -import variables from '@styles/variables'; + +const AUTOSCROLL_TO_TOP_THRESHOLD = 128; const propTypes = { /** Same as FlatList can be any array of anything */ @@ -136,7 +137,7 @@ function BaseInvertedFlatList(props) { windowSize={15} maintainVisibleContentPosition={{ minIndexForVisible: 0, - autoscrollToTopThreshold: variables.listItemHeightNormal, + autoscrollToTopThreshold: AUTOSCROLL_TO_TOP_THRESHOLD, }} inverted />