From 00a7c235b3c37b96f022ada724f3aa6a0e6f2087 Mon Sep 17 00:00:00 2001 From: hurali97 Date: Mon, 23 Oct 2023 15:41:54 +0500 Subject: [PATCH 001/722] perf: memoize components --- src/components/AttachmentModal.js | 4 ++-- src/components/EmojiPicker/EmojiPickerButton.js | 4 ++-- src/components/ExceededCommentLength.js | 4 ++-- src/pages/home/report/ReportActionCompose/SendButton.js | 4 ++-- src/pages/home/report/ReportTypingIndicator.js | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/components/AttachmentModal.js b/src/components/AttachmentModal.js index 61b138747950..9cceaab5e63e 100755 --- a/src/components/AttachmentModal.js +++ b/src/components/AttachmentModal.js @@ -1,4 +1,4 @@ -import React, {useState, useCallback, useRef, useMemo} from 'react'; +import React, {useState, useCallback, useRef, useMemo, memo} from 'react'; import PropTypes from 'prop-types'; import {View, Animated, Keyboard} from 'react-native'; import Str from 'expensify-common/lib/str'; @@ -534,4 +534,4 @@ export default compose( key: ONYXKEYS.SESSION, }, }), -)(AttachmentModal); +)(memo(AttachmentModal)); diff --git a/src/components/EmojiPicker/EmojiPickerButton.js b/src/components/EmojiPicker/EmojiPickerButton.js index cbfc3517117c..549e7d75005e 100644 --- a/src/components/EmojiPicker/EmojiPickerButton.js +++ b/src/components/EmojiPicker/EmojiPickerButton.js @@ -1,4 +1,4 @@ -import React, {useEffect, useRef} from 'react'; +import React, {memo, useEffect, useRef} from 'react'; import PropTypes from 'prop-types'; import styles from '../../styles/styles'; import * as StyleUtils from '../../styles/StyleUtils'; @@ -64,4 +64,4 @@ function EmojiPickerButton(props) { EmojiPickerButton.propTypes = propTypes; EmojiPickerButton.defaultProps = defaultProps; EmojiPickerButton.displayName = 'EmojiPickerButton'; -export default withLocalize(EmojiPickerButton); +export default withLocalize(memo(EmojiPickerButton)); diff --git a/src/components/ExceededCommentLength.js b/src/components/ExceededCommentLength.js index 9c785cec0395..587ab11cac37 100644 --- a/src/components/ExceededCommentLength.js +++ b/src/components/ExceededCommentLength.js @@ -1,4 +1,4 @@ -import React, {useEffect, useState, useMemo} from 'react'; +import React, {useEffect, useState, useMemo, memo} from 'react'; import PropTypes from 'prop-types'; import {debounce} from 'lodash'; import {withOnyx} from 'react-native-onyx'; @@ -65,4 +65,4 @@ export default withOnyx({ key: ({reportID}) => `${ONYXKEYS.COLLECTION.REPORT_DRAFT_COMMENT}${reportID}`, initialValue: '', }, -})(ExceededCommentLength); +})(memo(ExceededCommentLength)); diff --git a/src/pages/home/report/ReportActionCompose/SendButton.js b/src/pages/home/report/ReportActionCompose/SendButton.js index a97dd420e181..0e1d10d44092 100644 --- a/src/pages/home/report/ReportActionCompose/SendButton.js +++ b/src/pages/home/report/ReportActionCompose/SendButton.js @@ -1,4 +1,4 @@ -import React from 'react'; +import React, {memo} from 'react'; import {View} from 'react-native'; import {Gesture, GestureDetector} from 'react-native-gesture-handler'; import PropTypes from 'prop-types'; @@ -61,4 +61,4 @@ function SendButton({isDisabled: isDisabledProp, handleSendMessage}) { SendButton.propTypes = propTypes; SendButton.displayName = 'SendButton'; -export default SendButton; +export default memo(SendButton); diff --git a/src/pages/home/report/ReportTypingIndicator.js b/src/pages/home/report/ReportTypingIndicator.js index db97f712d65f..b4e5bbe8fe9d 100755 --- a/src/pages/home/report/ReportTypingIndicator.js +++ b/src/pages/home/report/ReportTypingIndicator.js @@ -1,4 +1,4 @@ -import React, {useMemo} from 'react'; +import React, {memo, useMemo} from 'react'; import PropTypes from 'prop-types'; import _ from 'underscore'; import {withOnyx} from 'react-native-onyx'; @@ -77,4 +77,4 @@ export default compose( initialValue: {}, }, }), -)(ReportTypingIndicator); +)(memo(ReportTypingIndicator)); From 9c4f2995a3a86c75ea17f039939199396049d379 Mon Sep 17 00:00:00 2001 From: hurali97 Date: Mon, 23 Oct 2023 15:43:15 +0500 Subject: [PATCH 002/722] refactor: simplify props --- src/pages/home/ReportScreen.js | 50 ++++++++---- .../SilentCommentUpdater.js | 16 ++-- src/pages/home/report/ReportActionsList.js | 2 +- .../report/ReportActionsListItemRenderer.js | 9 +-- src/pages/home/report/ReportActionsView.js | 10 ++- src/pages/home/report/ReportFooter.js | 81 ++++++++++++------- 6 files changed, 107 insertions(+), 61 deletions(-) diff --git a/src/pages/home/ReportScreen.js b/src/pages/home/ReportScreen.js index 81000c2dab92..682edb701c14 100644 --- a/src/pages/home/ReportScreen.js +++ b/src/pages/home/ReportScreen.js @@ -1,10 +1,10 @@ -import React, {useRef, useState, useEffect, useMemo, useCallback} from 'react'; +import React, {useRef, useState, useEffect, useMemo, useCallback, memo} from 'react'; import {withOnyx} from 'react-native-onyx'; import {useFocusEffect} from '@react-navigation/native'; import PropTypes from 'prop-types'; import {View} from 'react-native'; import lodashGet from 'lodash/get'; -import _ from 'underscore'; +import _, {isEqual} from 'underscore'; import styles from '../../styles/styles'; import ScreenWrapper from '../../components/ScreenWrapper'; import HeaderView from './HeaderView'; @@ -163,8 +163,9 @@ function ReportScreen({ const {addWorkspaceRoomOrChatPendingAction, addWorkspaceRoomOrChatErrors} = ReportUtils.getReportOfflinePendingActionAndErrors(report); const screenWrapperStyle = [styles.appContent, styles.flex1, {marginTop: viewportOffsetTop}]; + const isEmptyChat = useMemo(() => _.isEmpty(reportActions), [reportActions]); // There are no reportActions at all to display and we are still in the process of loading the next set of actions. - const isLoadingInitialReportActions = _.isEmpty(reportActions) && reportMetadata.isLoadingReportActions; + const isLoadingInitialReportActions = isEmptyChat && reportMetadata.isLoadingReportActions; const isOptimisticDelete = lodashGet(report, 'statusNum') === CONST.REPORT.STATUS.CLOSED; @@ -173,6 +174,10 @@ function ReportScreen({ const isLoading = !reportID || !isSidebarLoaded || _.isEmpty(personalDetails); const parentReportAction = ReportActionsUtils.getParentReportAction(report); + const lastReportAction = useMemo( + () => _.find([...reportActions, parentReportAction], (action) => ReportUtils.canEditReportAction(action) && !ReportActionsUtils.isMoneyRequestAction(action)), + [reportActions, parentReportAction], + ); const isSingleTransactionView = ReportUtils.isMoneyRequest(report); const policy = policies[`${ONYXKEYS.COLLECTION.POLICY}${report.policyID}`] || {}; @@ -253,16 +258,6 @@ function ReportScreen({ Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(accountManagerReportID)); }, [accountManagerReportID]); - /** - * @param {String} text - */ - const onSubmitComment = useCallback( - (text) => { - Report.addComment(getReportID(route), text); - }, - [route], - ); - useFocusEffect( useCallback(() => { const unsubscribeVisibilityListener = Visibility.onVisibilityChange(() => { @@ -441,14 +436,15 @@ function ReportScreen({ {isReportReadyForDisplay ? ( ) : ( @@ -515,4 +511,24 @@ export default compose( }, true, ), -)(ReportScreen); +)( + memo( + ReportScreen, + (prevProps, nextProps) => + prevProps.isSidebarLoaded === nextProps.isSidebarLoaded && + isEqual(prevProps.reportActions, nextProps.reportActions) && + isEqual(prevProps.reportMetadata, nextProps.reportMetadata) && + prevProps.isComposerFullSize === nextProps.isComposerFullSize && + isEqual(prevProps.betas, nextProps.betas) && + isEqual(prevProps.policies, nextProps.policies) && + prevProps.accountManagerReportID === nextProps.accountManagerReportID && + isEqual(prevProps.personalDetails, nextProps.personalDetails) && + prevProps.userLeavingStatus === nextProps.userLeavingStatus && + prevProps.report.reportID === nextProps.report.reportID && + prevProps.report.policyID === nextProps.report.policyID && + prevProps.report.isOptimisticReport === nextProps.report.isOptimisticReport && + prevProps.report.statusNum === nextProps.report.statusNum && + isEqual(prevProps.report.pendingFields, nextProps.report.pendingFields) && + prevProps.currentReportID === nextProps.currentReportID, + ), +); diff --git a/src/pages/home/report/ReportActionCompose/SilentCommentUpdater.js b/src/pages/home/report/ReportActionCompose/SilentCommentUpdater.js index 09f9d368bdcc..2d7a65ca4cc7 100644 --- a/src/pages/home/report/ReportActionCompose/SilentCommentUpdater.js +++ b/src/pages/home/report/ReportActionCompose/SilentCommentUpdater.js @@ -9,12 +9,6 @@ const propTypes = { /** The comment of the report */ comment: PropTypes.string, - /** The report associated with the comment */ - report: PropTypes.shape({ - /** The ID of the report */ - reportID: PropTypes.string, - }).isRequired, - /** The value of the comment */ value: PropTypes.string.isRequired, @@ -26,6 +20,8 @@ const propTypes = { /** Updates the comment */ updateComment: PropTypes.func.isRequired, + + reportID: PropTypes.string.isRequired, }; const defaultProps = { @@ -38,9 +34,9 @@ const defaultProps = { * re-rendering a UI component for that. That's why the side effect was moved down to a separate component. * @returns {null} */ -function SilentCommentUpdater({comment, commentRef, report, value, updateComment}) { +function SilentCommentUpdater({comment, commentRef, reportID, value, updateComment}) { const prevCommentProp = usePrevious(comment); - const prevReportId = usePrevious(report.reportID); + const prevReportId = usePrevious(reportID); const {preferredLocale} = useLocalize(); const prevPreferredLocale = usePrevious(preferredLocale); @@ -51,12 +47,12 @@ function SilentCommentUpdater({comment, commentRef, report, value, updateComment // As the report IDs change, make sure to update the composer comment as we need to make sure // we do not show incorrect data in there (ie. draft of message from other report). - if (preferredLocale === prevPreferredLocale && report.reportID === prevReportId && !shouldSyncComment) { + if (preferredLocale === prevPreferredLocale && reportID === prevReportId && !shouldSyncComment) { return; } updateComment(comment); - }, [prevCommentProp, prevPreferredLocale, prevReportId, comment, preferredLocale, report.reportID, updateComment, value, commentRef]); + }, [prevCommentProp, prevPreferredLocale, prevReportId, comment, preferredLocale, reportID, updateComment, value, commentRef]); return null; } diff --git a/src/pages/home/report/ReportActionsList.js b/src/pages/home/report/ReportActionsList.js index febcf3cd3507..a0cdee57f600 100644 --- a/src/pages/home/report/ReportActionsList.js +++ b/src/pages/home/report/ReportActionsList.js @@ -327,7 +327,7 @@ function ReportActionsList({ report={report} linkedReportActionID={linkedReportActionID} hasOutstandingIOU={hasOutstandingIOU} - sortedReportActions={sortedReportActions} + displayAsGroup={ReportActionsUtils.isConsecutiveActionMadeByPreviousActor(sortedReportActions, index)} mostRecentIOUReportActionID={mostRecentIOUReportActionID} shouldHideThreadDividerLine={shouldHideThreadDividerLine} shouldDisplayNewMarker={shouldDisplayNewMarker(reportAction, index)} diff --git a/src/pages/home/report/ReportActionsListItemRenderer.js b/src/pages/home/report/ReportActionsListItemRenderer.js index 40b9ee9142b7..e8e1f630ceb6 100644 --- a/src/pages/home/report/ReportActionsListItemRenderer.js +++ b/src/pages/home/report/ReportActionsListItemRenderer.js @@ -22,9 +22,6 @@ const propTypes = { /** Whether the option has an outstanding IOU */ hasOutstandingIOU: PropTypes.bool, - /** Sorted actions prepared for display */ - sortedReportActions: PropTypes.arrayOf(PropTypes.shape(reportActionPropTypes)).isRequired, - /** The ID of the most recent IOU report action connected with the shown report */ mostRecentIOUReportActionID: PropTypes.string, @@ -36,6 +33,8 @@ const propTypes = { /** Linked report action ID */ linkedReportActionID: PropTypes.string, + + displayAsGroup: PropTypes.bool.isRequired, }; const defaultProps = { @@ -49,7 +48,7 @@ function ReportActionsListItemRenderer({ index, report, hasOutstandingIOU, - sortedReportActions, + displayAsGroup, mostRecentIOUReportActionID, shouldHideThreadDividerLine, shouldDisplayNewMarker, @@ -73,7 +72,7 @@ function ReportActionsListItemRenderer({ report={report} action={reportAction} linkedReportActionID={linkedReportActionID} - displayAsGroup={ReportActionsUtils.isConsecutiveActionMadeByPreviousActor(sortedReportActions, index)} + displayAsGroup={displayAsGroup} shouldDisplayNewMarker={shouldDisplayNewMarker} shouldShowSubscriptAvatar={ (ReportUtils.isPolicyExpenseChat(report) || ReportUtils.isExpenseReport(report)) && diff --git a/src/pages/home/report/ReportActionsView.js b/src/pages/home/report/ReportActionsView.js index a3671faf194c..db9b6e1c3ecf 100755 --- a/src/pages/home/report/ReportActionsView.js +++ b/src/pages/home/report/ReportActionsView.js @@ -179,6 +179,14 @@ function ReportActionsView(props) { } }; + const report = useMemo( + () => ({ + lastReadTime: props.report.lastReadTime, + reportID: props.report.reportID, + }), + [props.report.lastReadTime, props.report.reportID], + ); + // Comments have not loaded at all yet do nothing if (!_.size(props.reportActions)) { return null; @@ -187,7 +195,7 @@ function ReportActionsView(props) { return ( <> {}, pendingAction: null, personalDetails: {}, - shouldShowComposeInput: true, shouldDisableCompose: false, listHeight: 0, isReportReadyForDisplay: true, + lastReportAction: null, + isEmptyChat: true, }; function ReportFooter(props) { @@ -72,6 +67,33 @@ function ReportFooter(props) { const isSmallSizeLayout = props.windowWidth - (props.isSmallScreenWidth ? 0 : variables.sideBarWidth) < variables.anonymousReportFooterBreakpoint; const hideComposer = ReportUtils.shouldDisableWriteActions(props.report); + const [shouldShowComposeInput, setShouldShowComposeInput] = useState(false); + + useEffect(() => { + // eslint-disable-next-line rulesdir/prefer-onyx-connect-in-libs + const connID = Onyx.connect({ + key: ONYXKEYS.SHOULD_SHOW_COMPOSE_INPUT, + callback: (val) => { + if (val === shouldShowComposeInput) { + return; + } + setShouldShowComposeInput(val); + }, + }); + + return () => { + Onyx.disconnect(connID); + }; + }, [shouldShowComposeInput]); + + const onSubmitComment = useCallback( + (text) => { + Report.addComment(props.reportID, text); + }, + // eslint-disable-next-line react-hooks/exhaustive-deps + [], + ); + return ( <> {hideComposer && ( @@ -89,14 +111,14 @@ function ReportFooter(props) { )} )} - {!hideComposer && (props.shouldShowComposeInput || !props.isSmallScreenWidth) && ( + {!hideComposer && (shouldShowComposeInput || !props.isSmallScreenWidth) && ( + isEqual(prevProps.report, nextProps.report) && + isEqual(prevProps.reportActions, nextProps.reportActions) && + isEqual(prevProps.personalDetails, nextProps.personalDetails) && + prevProps.pendingAction === nextProps.pendingAction && + prevProps.shouldDisableCompose === nextProps.shouldDisableCompose && + prevProps.listHeight === nextProps.listHeight && + prevProps.isReportReadyForDisplay === nextProps.isReportReadyForDisplay, + ), +); From 75ad6135c5391135cdd39d1f6e2b23a77825e0eb Mon Sep 17 00:00:00 2001 From: hurali97 Date: Mon, 23 Oct 2023 15:43:42 +0500 Subject: [PATCH 003/722] perf: reduce re-renders --- .../ComposerWithSuggestions.js | 100 +++++++++++------- .../ReportActionCompose.js | 68 ++++-------- 2 files changed, 83 insertions(+), 85 deletions(-) diff --git a/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions.js b/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions.js index e194d0870885..bb5109073cfd 100644 --- a/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions.js +++ b/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions.js @@ -1,9 +1,10 @@ -import React, {useEffect, useCallback, useState, useRef, useMemo, useImperativeHandle} from 'react'; +import React, {useEffect, useCallback, useState, useRef, useMemo, useImperativeHandle, memo} from 'react'; import {View, NativeModules, findNodeHandle} from 'react-native'; import {withOnyx} from 'react-native-onyx'; import _ from 'underscore'; import lodashGet from 'lodash/get'; import {useIsFocused, useNavigation} from '@react-navigation/native'; +import {runOnJS, useAnimatedRef} from 'react-native-reanimated'; import styles from '../../../../styles/styles'; import themeColors from '../../../../styles/themes/default'; import Composer from '../../../../components/Composer'; @@ -23,7 +24,6 @@ import * as EmojiUtils from '../../../../libs/EmojiUtils'; import * as User from '../../../../libs/actions/User'; import * as ReportUtils from '../../../../libs/ReportUtils'; import * as SuggestionUtils from '../../../../libs/SuggestionUtils'; -import * as ReportActionsUtils from '../../../../libs/ReportActionsUtils'; import canFocusInputOnScreenFocus from '../../../../libs/canFocusInputOnScreenFocus'; import SilentCommentUpdater from './SilentCommentUpdater'; import Suggestions from './Suggestions'; @@ -36,6 +36,10 @@ import focusWithDelay from '../../../../libs/focusWithDelay'; import useDebounce from '../../../../hooks/useDebounce'; import updateMultilineInputRange from '../../../../libs/UpdateMultilineInputRange'; import * as InputFocus from '../../../../libs/actions/InputFocus'; +import SendButton from './SendButton'; +import updatePropsPaperWorklet from '../../../../libs/updatePropsPaperWorklet'; +import EmojiPickerButton from '../../../../components/EmojiPicker/EmojiPickerButton'; +import * as DeviceCapabilities from '../../../../libs/DeviceCapabilities'; const {RNTextInputReset} = NativeModules; @@ -70,14 +74,14 @@ function ComposerWithSuggestions({ // Onyx modal, preferredSkinTone, - parentReportActions, numberOfLines, // HOCs isKeyboardShown, // Props: Report reportID, - report, - reportActions, + includeChronos, + isEmptyChat, + lastReportAction, // Focus onFocus, onBlur, @@ -92,14 +96,13 @@ function ComposerWithSuggestions({ disabled, isFullComposerAvailable, setIsFullComposerAvailable, - setIsCommentEmpty, + isSendDisabled, handleSendMessage, shouldShowComposeInput, measureParentContainer, listHeight, // Refs suggestionsRef, - animatedRef, forwardedRef, isNextModalWillOpenRef, editFocused, @@ -108,19 +111,21 @@ function ComposerWithSuggestions({ const isFocused = useIsFocused(); const navigation = useNavigation(); const emojisPresentBefore = useRef([]); + + const draftComment = getDraftComment(reportID) || ''; + const [isCommentEmpty, setIsCommentEmpty] = useState(() => !draftComment || !!draftComment.match(/^(\s)*$/)); + const animatedRef = useAnimatedRef(); const [value, setValue] = useState(() => { - const draft = getDraftComment(reportID) || ''; - if (draft) { - emojisPresentBefore.current = EmojiUtils.extractEmojis(draft); + if (draftComment) { + emojisPresentBefore.current = EmojiUtils.extractEmojis(draftComment); } - return draft; + return draftComment; }); const commentRef = useRef(value); - const {isSmallScreenWidth} = useWindowDimensions(); + const {isSmallScreenWidth, isMediumScreenWidth} = useWindowDimensions(); const maxComposerLines = isSmallScreenWidth ? CONST.COMPOSER.MAX_LINES_SMALL_SCREEN : CONST.COMPOSER.MAX_LINES; - const isEmptyChat = useMemo(() => _.size(reportActions) === 1, [reportActions]); const shouldAutoFocus = !modal.isVisible && (shouldFocusInputOnScreenFocus || isEmptyChat) && shouldShowComposeInput; const valueRef = useRef(value); @@ -202,6 +207,20 @@ function ComposerWithSuggestions({ [], ); + const sendMessage = useCallback(() => { + 'worklet'; + + if (isCommentEmpty) { + return; + } + + runOnJS(handleSendMessage)(); + const viewTag = animatedRef(); + const viewName = 'RCTMultilineTextInputView'; + const updates = {text: ''}; + updatePropsPaperWorklet(viewTag, viewName, updates); // clears native text input on the UI thread + }, [animatedRef, handleSendMessage, isCommentEmpty]); + /** * Update the value of the comment in Onyx * @@ -225,7 +244,13 @@ function ComposerWithSuggestions({ } } emojisPresentBefore.current = emojis; - setIsCommentEmpty(!!newComment.match(/^(\s)*$/)); + const isNewCommentEmpty = !!newComment.match(/^(\s)*$/); + const isPrevCommentEmpty = !!commentRef.current.match(/^(\s)*$/); + + /** Only update isCommentEmpty state if it's different from previous one */ + if (isNewCommentEmpty !== isPrevCommentEmpty) { + setIsCommentEmpty(isNewCommentEmpty); + } setValue(newComment); if (commentValue !== newComment) { const remainder = ComposerUtils.getCommonSuffixLength(commentValue, newComment); @@ -338,26 +363,20 @@ function ComposerWithSuggestions({ // Submit the form when Enter is pressed if (e.key === CONST.KEYBOARD_SHORTCUTS.ENTER.shortcutKey && !e.shiftKey) { e.preventDefault(); - handleSendMessage(); + sendMessage(); } // Trigger the edit box for last sent message if ArrowUp is pressed and the comment is empty and Chronos is not in the participants const valueLength = valueRef.current.length; - if (e.key === CONST.KEYBOARD_SHORTCUTS.ARROW_UP.shortcutKey && textInputRef.current.selectionStart === 0 && valueLength === 0 && !ReportUtils.chatIncludesChronos(report)) { + if (e.key === CONST.KEYBOARD_SHORTCUTS.ARROW_UP.shortcutKey && textInputRef.current.selectionStart === 0 && valueLength === 0 && !includeChronos) { e.preventDefault(); - const parentReportActionID = lodashGet(report, 'parentReportActionID', ''); - const parentReportAction = lodashGet(parentReportActions, [parentReportActionID], {}); - const lastReportAction = _.find( - [...reportActions, parentReportAction], - (action) => ReportUtils.canEditReportAction(action) && !ReportActionsUtils.isMoneyRequestAction(action), - ); if (lastReportAction) { Report.saveReportActionDraft(reportID, lastReportAction, _.last(lastReportAction.message).html); } } }, - [isKeyboardShown, isSmallScreenWidth, parentReportActions, report, reportActions, reportID, handleSendMessage, suggestionsRef, valueRef], + [isSmallScreenWidth, isKeyboardShown, suggestionsRef, includeChronos, sendMessage, lastReportAction, reportID], ); const onSelectionChange = useCallback( @@ -561,6 +580,19 @@ function ComposerWithSuggestions({ }} onScroll={hideSuggestionMenu} /> + + {DeviceCapabilities.canUseTouchScreen() && isMediumScreenWidth ? null : ( + replaceSelectionWithText(...args)} + emojiPickerID={reportID} + /> + )} + `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${report.parentReportID}`, - canEvict: false, - initWithStoredValues: false, - }, }), )( - React.forwardRef((props, ref) => ( - - )), + memo( + React.forwardRef((props, ref) => ( + + )), + ), ); diff --git a/src/pages/home/report/ReportActionCompose/ReportActionCompose.js b/src/pages/home/report/ReportActionCompose/ReportActionCompose.js index dd4d51653546..8796fd1c1b85 100644 --- a/src/pages/home/report/ReportActionCompose/ReportActionCompose.js +++ b/src/pages/home/report/ReportActionCompose/ReportActionCompose.js @@ -1,10 +1,10 @@ -import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react'; +import React, {memo, useCallback, useEffect, useMemo, useRef, useState} from 'react'; import PropTypes from 'prop-types'; import {View} from 'react-native'; import _ from 'underscore'; import lodashGet from 'lodash/get'; import {withOnyx} from 'react-native-onyx'; -import {runOnJS, useAnimatedRef} from 'react-native-reanimated'; +import {runOnJS} from 'react-native-reanimated'; import {PortalHost} from '@gorhom/portal'; import styles from '../../../../styles/styles'; import ONYXKEYS from '../../../../ONYXKEYS'; @@ -21,23 +21,17 @@ import ParticipantLocalTime from '../ParticipantLocalTime'; import withCurrentUserPersonalDetails, {withCurrentUserPersonalDetailsPropTypes, withCurrentUserPersonalDetailsDefaultProps} from '../../../../components/withCurrentUserPersonalDetails'; import {withNetwork} from '../../../../components/OnyxProvider'; import * as User from '../../../../libs/actions/User'; -import EmojiPickerButton from '../../../../components/EmojiPicker/EmojiPickerButton'; -import * as DeviceCapabilities from '../../../../libs/DeviceCapabilities'; import OfflineIndicator from '../../../../components/OfflineIndicator'; import ExceededCommentLength from '../../../../components/ExceededCommentLength'; import ReportDropUI from '../ReportDropUI'; import reportPropTypes from '../../../reportPropTypes'; import OfflineWithFeedback from '../../../../components/OfflineWithFeedback'; -import SendButton from './SendButton'; import AttachmentPickerWithMenuItems from './AttachmentPickerWithMenuItems'; import ComposerWithSuggestions from './ComposerWithSuggestions'; -import reportActionPropTypes from '../reportActionPropTypes'; import useLocalize from '../../../../hooks/useLocalize'; import getModalState from '../../../../libs/getModalState'; import useWindowDimensions from '../../../../hooks/useWindowDimensions'; import * as EmojiPickerActions from '../../../../libs/actions/EmojiPickerAction'; -import getDraftComment from '../../../../libs/ComposerUtils/getDraftComment'; -import updatePropsPaperWorklet from '../../../../libs/updatePropsPaperWorklet'; const propTypes = { /** A method to call when the form is submitted */ @@ -46,9 +40,6 @@ const propTypes = { /** The ID of the report actions will be created for */ reportID: PropTypes.string.isRequired, - /** Array of report actions for this report */ - reportActions: PropTypes.arrayOf(PropTypes.shape(reportActionPropTypes)), - /** Personal details of all the users */ personalDetails: PropTypes.objectOf(participantPropTypes), @@ -111,14 +102,14 @@ function ReportActionCompose({ personalDetails, report, reportID, - reportActions, + isEmptyChat, + lastReportAction, listHeight, shouldShowComposeInput, isReportReadyForDisplay, }) { const {translate} = useLocalize(); - const {isMediumScreenWidth, isSmallScreenWidth} = useWindowDimensions(); - const animatedRef = useAnimatedRef(); + const {isSmallScreenWidth} = useWindowDimensions(); const actionButtonRef = useRef(null); /** @@ -134,10 +125,6 @@ function ReportActionCompose({ * Updates the should clear state of the composer */ const [textInputShouldClear, setTextInputShouldClear] = useState(false); - const [isCommentEmpty, setIsCommentEmpty] = useState(() => { - const draftComment = getDraftComment(reportID); - return !draftComment || !!draftComment.match(/^(\s)*$/); - }); /** * Updates the visibility state of the menu @@ -164,7 +151,9 @@ function ReportActionCompose({ [personalDetails, report, currentUserPersonalDetails.accountID, isComposerFullSize], ); - const isBlockedFromConcierge = useMemo(() => ReportUtils.chatIncludesConcierge(report) && User.isBlockedFromConcierge(blockedFromConcierge), [report, blockedFromConcierge]); + const includesConcierge = useMemo(() => ReportUtils.chatIncludesConcierge({participantAccountIDs: report.participantAccountIDs}), [report.participantAccountIDs]); + const userBlockedFromConcierge = useMemo(() => User.isBlockedFromConcierge(blockedFromConcierge), [blockedFromConcierge]); + const isBlockedFromConcierge = useMemo(() => includesConcierge && userBlockedFromConcierge, [includesConcierge, userBlockedFromConcierge]); // If we are on a small width device then don't show last 3 items from conciergePlaceholderOptions const conciergePlaceholderRandomIndex = useMemo( @@ -175,8 +164,8 @@ function ReportActionCompose({ // Placeholder to display in the chat input. const inputPlaceholder = useMemo(() => { - if (ReportUtils.chatIncludesConcierge(report)) { - if (User.isBlockedFromConcierge(blockedFromConcierge)) { + if (includesConcierge) { + if (userBlockedFromConcierge) { return translate('reportActionCompose.blockedFromConcierge'); } @@ -184,7 +173,7 @@ function ReportActionCompose({ } return translate('reportActionCompose.writeSomething'); - }, [report, blockedFromConcierge, translate, conciergePlaceholderRandomIndex]); + }, [includesConcierge, translate, userBlockedFromConcierge, conciergePlaceholderRandomIndex]); const focus = () => { if (composerRef === null || composerRef.current === null) { @@ -322,24 +311,16 @@ function ReportActionCompose({ const hasReportRecipient = _.isObject(reportRecipient) && !_.isEmpty(reportRecipient); - const isSendDisabled = isCommentEmpty || isBlockedFromConcierge || disabled || hasExceededMaxCommentLength; + const isSendDisabled = isBlockedFromConcierge || disabled || hasExceededMaxCommentLength; const handleSendMessage = useCallback(() => { - 'worklet'; - if (isSendDisabled || !isReportReadyForDisplay) { return; } - const viewTag = animatedRef(); - const viewName = 'RCTMultilineTextInputView'; - const updates = {text: ''}; - // We are setting the isCommentEmpty flag to true so the status of it will be in sync of the native text input state - runOnJS(setIsCommentEmpty)(true); runOnJS(resetFullComposerSize)(); - updatePropsPaperWorklet(viewTag, viewName, updates); // clears native text input on the UI thread runOnJS(submitForm)(); - }, [isSendDisabled, resetFullComposerSize, submitForm, animatedRef, isReportReadyForDisplay]); + }, [isSendDisabled, resetFullComposerSize, submitForm, isReportReadyForDisplay]); return ( { @@ -427,18 +409,6 @@ function ReportActionCompose({ )} - {DeviceCapabilities.canUseTouchScreen() && isMediumScreenWidth ? null : ( - composerRef.current.replaceSelectionWithText(...args)} - emojiPickerID={report.reportID} - /> - )} - Date: Tue, 24 Oct 2023 17:04:11 +0500 Subject: [PATCH 004/722] refactor: make action prop lightweight --- .../report/ReportActionsListItemRenderer.js | 39 ++++++++++++++++++- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/src/pages/home/report/ReportActionsListItemRenderer.js b/src/pages/home/report/ReportActionsListItemRenderer.js index e8e1f630ceb6..a7ec10a30eea 100644 --- a/src/pages/home/report/ReportActionsListItemRenderer.js +++ b/src/pages/home/report/ReportActionsListItemRenderer.js @@ -1,5 +1,5 @@ import PropTypes from 'prop-types'; -import React, {memo} from 'react'; +import React, {memo, useMemo} from 'react'; import _ from 'underscore'; import CONST from '../../../CONST'; import * as ReportActionsUtils from '../../../libs/ReportActionsUtils'; @@ -59,6 +59,41 @@ function ReportActionsListItemRenderer({ ReportUtils.isChatThread(report) && !ReportActionsUtils.isTransactionThread(ReportActionsUtils.getParentReportAction(report)); + const action = useMemo( + () => ({ + reportActionID: reportAction.reportActionID, + message: reportAction.message, + pendingAction: reportAction.pendingAction, + actionName: reportAction.actionName, + errors: reportAction.errors, + originalMessage: reportAction.originalMessage, + childCommenterCount: reportAction.childCommenterCount, + linkMetadata: reportAction.linkMetadata, + childReportID: reportAction.childReportID, + childLastVisibleActionCreated: reportAction.childLastVisibleActionCreated, + whisperedToAccountIDs: reportAction.whisperedToAccountIDs, + error: reportAction.error, + created: reportAction.created, + actorAccountID: reportAction.actorAccountID, + }), + [ + reportAction.actionName, + reportAction.childCommenterCount, + reportAction.childLastVisibleActionCreated, + reportAction.childReportID, + reportAction.created, + reportAction.error, + reportAction.errors, + reportAction.linkMetadata, + reportAction.message, + reportAction.originalMessage, + reportAction.pendingAction, + reportAction.reportActionID, + reportAction.whisperedToAccountIDs, + reportAction.actorAccountID, + ], + ); + return shouldDisplayParentAction ? ( Date: Wed, 25 Oct 2023 18:25:16 +0500 Subject: [PATCH 005/722] perf: add Interaction Manager --- src/libs/actions/OnyxUpdates.ts | 29 +++++++++++++++------------ src/libs/actions/PersistedRequests.ts | 19 ++++++++++-------- 2 files changed, 27 insertions(+), 21 deletions(-) diff --git a/src/libs/actions/OnyxUpdates.ts b/src/libs/actions/OnyxUpdates.ts index 39a20ae9362a..5f13d8133f16 100644 --- a/src/libs/actions/OnyxUpdates.ts +++ b/src/libs/actions/OnyxUpdates.ts @@ -1,5 +1,6 @@ import Onyx, {OnyxEntry} from 'react-native-onyx'; import {Merge} from 'type-fest'; +import {InteractionManager} from 'react-native'; import PusherUtils from '../PusherUtils'; import ONYXKEYS from '../../ONYXKEYS'; import * as QueuedOnyxUpdates from './QueuedOnyxUpdates'; @@ -61,19 +62,21 @@ function apply({lastUpdateID, type, request, response, updates}: Merge | undefined { console.debug(`[OnyxUpdateManager] Applying update type: ${type} with lastUpdateID: ${lastUpdateID}`, {request, response, updates}); - if (lastUpdateID && lastUpdateIDAppliedToClient && Number(lastUpdateID) < lastUpdateIDAppliedToClient) { - console.debug('[OnyxUpdateManager] Update received was older than current state, returning without applying the updates'); - return Promise.resolve(); - } - if (lastUpdateID && (lastUpdateIDAppliedToClient === null || Number(lastUpdateID) > lastUpdateIDAppliedToClient)) { - Onyx.merge(ONYXKEYS.ONYX_UPDATES_LAST_UPDATE_ID_APPLIED_TO_CLIENT, Number(lastUpdateID)); - } - if (type === CONST.ONYX_UPDATE_TYPES.HTTPS && request && response) { - return applyHTTPSOnyxUpdates(request, response); - } - if (type === CONST.ONYX_UPDATE_TYPES.PUSHER && updates) { - return applyPusherOnyxUpdates(updates); - } + InteractionManager.runAfterInteractions(() => { + if (lastUpdateID && lastUpdateIDAppliedToClient && Number(lastUpdateID) < lastUpdateIDAppliedToClient) { + console.debug('[OnyxUpdateManager] Update received was older than current state, returning without applying the updates'); + return Promise.resolve(); + } + if (lastUpdateID && (lastUpdateIDAppliedToClient === null || Number(lastUpdateID) > lastUpdateIDAppliedToClient)) { + Onyx.merge(ONYXKEYS.ONYX_UPDATES_LAST_UPDATE_ID_APPLIED_TO_CLIENT, Number(lastUpdateID)); + } + if (type === CONST.ONYX_UPDATE_TYPES.HTTPS && request && response) { + return applyHTTPSOnyxUpdates(request, response); + } + if (type === CONST.ONYX_UPDATE_TYPES.PUSHER && updates) { + return applyPusherOnyxUpdates(updates); + } + }); } /** diff --git a/src/libs/actions/PersistedRequests.ts b/src/libs/actions/PersistedRequests.ts index d9f4ed020109..1e1a147cecd3 100644 --- a/src/libs/actions/PersistedRequests.ts +++ b/src/libs/actions/PersistedRequests.ts @@ -1,5 +1,6 @@ import Onyx from 'react-native-onyx'; import isEqual from 'lodash/isEqual'; +import {InteractionManager} from 'react-native'; import ONYXKEYS from '../../ONYXKEYS'; import {Request} from '../../types/onyx'; @@ -33,14 +34,16 @@ function remove(requestToRemove: Request) { * We only remove the first matching request because the order of requests matters. * If we were to remove all matching requests, we can end up with a final state that is different than what the user intended. */ - const requests = [...persistedRequests]; - const index = requests.findIndex((persistedRequest) => isEqual(persistedRequest, requestToRemove)); - if (index === -1) { - return; - } - requests.splice(index, 1); - persistedRequests = requests; - Onyx.set(ONYXKEYS.PERSISTED_REQUESTS, requests); + InteractionManager.runAfterInteractions(() => { + const requests = [...persistedRequests]; + const index = requests.findIndex((persistedRequest) => isEqual(persistedRequest, requestToRemove)); + if (index === -1) { + return; + } + requests.splice(index, 1); + persistedRequests = requests; + Onyx.set(ONYXKEYS.PERSISTED_REQUESTS, requests); + }); } function update(oldRequestIndex: number, newRequest: Request) { From 60d3034b9c91aaeb31626282f89e61e587416cbd Mon Sep 17 00:00:00 2001 From: hurali97 Date: Wed, 25 Oct 2023 18:30:54 +0500 Subject: [PATCH 006/722] perf: reference bindings of functions --- .../ComposerWithSuggestions.js | 33 ++++++++++++++----- .../composerWithSuggestionsProps.js | 18 ---------- 2 files changed, 24 insertions(+), 27 deletions(-) diff --git a/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions.js b/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions.js index 4c3136ff6328..97435e510389 100644 --- a/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions.js +++ b/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions.js @@ -40,6 +40,7 @@ import SendButton from './SendButton'; import updatePropsPaperWorklet from '../../../../libs/updatePropsPaperWorklet'; import EmojiPickerButton from '../../../../components/EmojiPicker/EmojiPickerButton'; import * as DeviceCapabilities from '../../../../libs/DeviceCapabilities'; +import * as ReportActionsUtils from '../../../../libs/ReportActionsUtils'; const {RNTextInputReset} = NativeModules; @@ -540,6 +541,26 @@ function ComposerWithSuggestions({ [blur, focus, prepareCommentAndResetComposer, replaceSelectionWithText], ); + const onLayout = useCallback( + (e) => { + const composerLayoutHeight = e.nativeEvent.layout.height; + if (composerHeight === composerLayoutHeight) { + return; + } + setComposerHeight(composerLayoutHeight); + }, + [composerHeight], + ); + + const onClear = useCallback(() => { + setTextInputShouldClear(false); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + const onChangeText = useCallback((text) => { + updateComment(text, true); + }, []); + return ( <> @@ -551,7 +572,7 @@ function ComposerWithSuggestions({ textAlignVertical="top" placeholder={inputPlaceholder} placeholderTextColor={themeColors.placeholderText} - onChangeText={(commentValue) => updateComment(commentValue, true)} + onChangeText={onChangeText} onKeyPress={triggerHotkeyActions} style={[styles.textInputCompose, isComposerFullSize ? styles.textInputFullCompose : styles.flex4]} maxLines={maxComposerLines} @@ -560,7 +581,7 @@ function ComposerWithSuggestions({ onClick={setShouldBlockSuggestionCalcToFalse} onPasteFile={displayFileInModal} shouldClear={textInputShouldClear} - onClear={() => setTextInputShouldClear(false)} + onClear={onClear} isDisabled={isBlockedFromConcierge || disabled} isReportActionCompose selection={selection} @@ -572,13 +593,7 @@ function ComposerWithSuggestions({ numberOfLines={numberOfLines} onNumberOfLinesChange={updateNumberOfLines} shouldCalculateCaretPosition - onLayout={(e) => { - const composerLayoutHeight = e.nativeEvent.layout.height; - if (composerHeight === composerLayoutHeight) { - return; - } - setComposerHeight(composerLayoutHeight); - }} + onLayout={onLayout} onScroll={hideSuggestionMenu} /> diff --git a/src/pages/home/report/ReportActionCompose/composerWithSuggestionsProps.js b/src/pages/home/report/ReportActionCompose/composerWithSuggestionsProps.js index 017b5aecb4ae..246399d334d6 100644 --- a/src/pages/home/report/ReportActionCompose/composerWithSuggestionsProps.js +++ b/src/pages/home/report/ReportActionCompose/composerWithSuggestionsProps.js @@ -1,5 +1,4 @@ import PropTypes from 'prop-types'; -import reportActionPropTypes from '../reportActionPropTypes'; import CONST from '../../../../CONST'; const propTypes = { @@ -18,20 +17,9 @@ const propTypes = { /** Whether the keyboard is open or not */ isKeyboardShown: PropTypes.bool.isRequired, - /** The actions from the parent report */ - parentReportActions: PropTypes.objectOf(PropTypes.shape(reportActionPropTypes)), - - /** Array of report actions for this report */ - reportActions: PropTypes.arrayOf(PropTypes.shape(reportActionPropTypes)), - /** The ID of the report */ reportID: PropTypes.string.isRequired, - /** The report currently being looked at */ - report: PropTypes.shape({ - parentReportID: PropTypes.string, - }).isRequired, - /** Callback when the input is focused */ onFocus: PropTypes.func.isRequired, @@ -68,9 +56,6 @@ const propTypes = { /** Function to set whether the full composer is available or not */ setIsFullComposerAvailable: PropTypes.func.isRequired, - /** Function to set whether the comment is empty or not */ - setIsCommentEmpty: PropTypes.func.isRequired, - /** A method to call when the form is submitted */ handleSendMessage: PropTypes.func.isRequired, @@ -97,9 +82,6 @@ const propTypes = { }), }).isRequired, - /** Ref for the animated view (text input) */ - animatedRef: PropTypes.func.isRequired, - /** Ref for the composer */ forwardedRef: PropTypes.shape({current: PropTypes.shape({})}), From 851c61f1edc0291d022b3480d22778e97a492ce9 Mon Sep 17 00:00:00 2001 From: hurali97 Date: Thu, 26 Oct 2023 15:04:22 +0500 Subject: [PATCH 007/722] perf: optimise rendering --- .../ComposerWithSuggestions.js | 5 ---- .../ReportActionCompose/SuggestionMention.js | 27 +++++++++++-------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions.js b/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions.js index 97435e510389..c41589fe4b68 100644 --- a/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions.js +++ b/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions.js @@ -283,14 +283,9 @@ function ComposerWithSuggestions({ } }, [ - debouncedUpdateFrequentlyUsedEmojis, - preferredLocale, preferredSkinTone, reportID, - setIsCommentEmpty, suggestionsRef, - raiseIsScrollLikelyLayoutTriggered, - debouncedSaveReportComment, ], ); diff --git a/src/pages/home/report/ReportActionCompose/SuggestionMention.js b/src/pages/home/report/ReportActionCompose/SuggestionMention.js index 67d6ac0632eb..237b1e956966 100644 --- a/src/pages/home/report/ReportActionCompose/SuggestionMention.js +++ b/src/pages/home/report/ReportActionCompose/SuggestionMention.js @@ -1,7 +1,7 @@ import React, {useState, useCallback, useRef, useImperativeHandle, useEffect} from 'react'; import PropTypes from 'prop-types'; import _ from 'underscore'; -import {withOnyx} from 'react-native-onyx'; +import Onyx from 'react-native-onyx'; import CONST from '../../../../CONST'; import useArrowKeyFocusManager from '../../../../hooks/useArrowKeyFocusManager'; import MentionSuggestions from '../../../../components/MentionSuggestions'; @@ -29,9 +29,6 @@ const defaultSuggestionsValues = { }; const propTypes = { - /** Personal details of all users */ - personalDetails: PropTypes.objectOf(personalDetailsPropType), - /** A ref to this component */ forwardedRef: PropTypes.shape({current: PropTypes.shape({})}), @@ -39,17 +36,28 @@ const propTypes = { }; const defaultProps = { - personalDetails: {}, forwardedRef: null, }; +/** + * We only need the personalDetails once because as long as the + * user is in the ReportScreen, these details won't be changing, + * hence we don't have to use it with `withOnyx`. + */ +let allPersonalDetails = {}; +Onyx.connect({ + key: ONYXKEYS.PERSONAL_DETAILS_LIST, + callback: (val) => { + allPersonalDetails = val; + }, +}); + function SuggestionMention({ value, setValue, selection, setSelection, isComposerFullSize, - personalDetails, updateComment, composerHeight, forwardedRef, @@ -57,6 +65,7 @@ function SuggestionMention({ measureParentContainer, isComposerFocused, }) { + const personalDetails = allPersonalDetails; const {translate} = useLocalize(); const previousValue = usePrevious(value); const [suggestionValues, setSuggestionValues] = useState(defaultSuggestionsValues); @@ -316,8 +325,4 @@ const SuggestionMentionWithRef = React.forwardRef((props, ref) => ( SuggestionMentionWithRef.displayName = 'SuggestionMentionWithRef'; -export default withOnyx({ - personalDetails: { - key: ONYXKEYS.PERSONAL_DETAILS_LIST, - }, -})(SuggestionMentionWithRef); +export default SuggestionMentionWithRef; From e613f4278dc5cdfb85cf79670f9f6f575c826918 Mon Sep 17 00:00:00 2001 From: hurali97 Date: Thu, 26 Oct 2023 16:28:03 +0500 Subject: [PATCH 008/722] perf: optimise usage of personal detail list --- src/components/AnonymousReportFooter.js | 5 --- src/components/ArchivedReportFooter.js | 13 ++----- src/components/AvatarWithDisplayName.js | 8 +--- src/components/HeaderWithBackButton/index.js | 2 - .../LHNOptionsList/OptionRowLHNData.js | 39 +------------------ src/components/MoneyReportHeader.js | 6 +-- src/components/MoneyRequestHeader.js | 6 +-- .../withCurrentUserPersonalDetails.tsx | 9 +---- src/libs/OptionsListUtils.js | 5 ++- src/libs/PersonalDetailsUtils.js | 27 +++++++++++-- src/libs/ReportUtils.js | 19 +++++---- src/libs/SidebarUtils.js | 10 ++++- src/pages/home/HeaderView.js | 8 +--- src/pages/home/ReportScreen.js | 15 +------ .../ReportActionCompose.js | 17 ++------ src/pages/home/report/ReportActionItem.js | 8 ++-- .../home/report/ReportActionItemCreated.js | 9 +---- .../home/report/ReportActionItemSingle.js | 5 ++- src/pages/home/report/ReportActionsList.js | 11 +----- src/pages/home/report/ReportFooter.js | 6 --- 20 files changed, 72 insertions(+), 156 deletions(-) diff --git a/src/components/AnonymousReportFooter.js b/src/components/AnonymousReportFooter.js index 43933210dc0b..902a31f12ee3 100644 --- a/src/components/AnonymousReportFooter.js +++ b/src/components/AnonymousReportFooter.js @@ -16,16 +16,12 @@ const propTypes = { isSmallSizeLayout: PropTypes.bool, - /** Personal details of all the users */ - personalDetails: PropTypes.objectOf(participantPropTypes), - ...withLocalizePropTypes, }; const defaultProps = { report: {}, isSmallSizeLayout: false, - personalDetails: {}, }; function AnonymousReportFooter(props) { @@ -34,7 +30,6 @@ function AnonymousReportFooter(props) { diff --git a/src/components/ArchivedReportFooter.js b/src/components/ArchivedReportFooter.js index 71d331b68db0..bca5f0b391c8 100644 --- a/src/components/ArchivedReportFooter.js +++ b/src/components/ArchivedReportFooter.js @@ -34,9 +34,6 @@ const propTypes = { /** The archived report */ report: reportPropTypes.isRequired, - /** Personal details of all users */ - personalDetails: PropTypes.objectOf(personalDetailsPropType), - ...withLocalizePropTypes, }; @@ -46,19 +43,18 @@ const defaultProps = { reason: CONST.REPORT.ARCHIVE_REASON.DEFAULT, }, }, - personalDetails: {}, }; function ArchivedReportFooter(props) { const archiveReason = lodashGet(props.reportClosedAction, 'originalMessage.reason', CONST.REPORT.ARCHIVE_REASON.DEFAULT); - let displayName = PersonalDetailsUtils.getDisplayNameOrDefault(props.personalDetails, [props.report.ownerAccountID, 'displayName']); + let displayName = PersonalDetailsUtils.getDisplayNameOrDefault(null, [props.report.ownerAccountID, 'displayName']); let oldDisplayName; if (archiveReason === CONST.REPORT.ARCHIVE_REASON.ACCOUNT_MERGED) { const newAccountID = props.reportClosedAction.originalMessage.newAccountID; const oldAccountID = props.reportClosedAction.originalMessage.oldAccountID; - displayName = PersonalDetailsUtils.getDisplayNameOrDefault(props.personalDetails, [newAccountID, 'displayName']); - oldDisplayName = PersonalDetailsUtils.getDisplayNameOrDefault(props.personalDetails, [oldAccountID, 'displayName']); + displayName = PersonalDetailsUtils.getDisplayNameOrDefault(null, [newAccountID, 'displayName']); + oldDisplayName = PersonalDetailsUtils.getDisplayNameOrDefault(null, [oldAccountID, 'displayName']); } const shouldRenderHTML = archiveReason !== CONST.REPORT.ARCHIVE_REASON.DEFAULT; @@ -92,9 +88,6 @@ ArchivedReportFooter.displayName = 'ArchivedReportFooter'; export default compose( withLocalize, withOnyx({ - personalDetails: { - key: ONYXKEYS.PERSONAL_DETAILS_LIST, - }, reportClosedAction: { key: ({report}) => `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${report.reportID}`, canEvict: false, diff --git a/src/components/AvatarWithDisplayName.js b/src/components/AvatarWithDisplayName.js index 03ae8f51bfb6..3a4ebee0aa42 100644 --- a/src/components/AvatarWithDisplayName.js +++ b/src/components/AvatarWithDisplayName.js @@ -37,9 +37,6 @@ const propTypes = { /** The size of the avatar */ size: PropTypes.oneOf(_.values(CONST.AVATAR_SIZE)), - /** Personal details of all the users */ - personalDetails: PropTypes.objectOf(participantPropTypes), - /** Whether if it's an unauthenticated user */ isAnonymous: PropTypes.bool, @@ -50,7 +47,6 @@ const propTypes = { }; const defaultProps = { - personalDetails: {}, policy: {}, report: {}, isAnonymous: false, @@ -93,8 +89,8 @@ function AvatarWithDisplayName(props) { const subtitle = ReportUtils.getChatRoomSubtitle(props.report); const parentNavigationSubtitleData = ReportUtils.getParentNavigationSubtitle(props.report); const isMoneyRequestOrReport = ReportUtils.isMoneyRequestReport(props.report) || ReportUtils.isMoneyRequest(props.report); - const icons = ReportUtils.getIcons(props.report, props.personalDetails, props.policy); - const ownerPersonalDetails = OptionsListUtils.getPersonalDetailsForAccountIDs([props.report.ownerAccountID], props.personalDetails); + const icons = ReportUtils.getIcons(props.report, null, props.policy); + const ownerPersonalDetails = OptionsListUtils.getPersonalDetailsForAccountIDs([props.report.ownerAccountID]); const displayNamesWithTooltips = ReportUtils.getDisplayNamesWithTooltips(_.values(ownerPersonalDetails), false); const shouldShowSubscriptAvatar = ReportUtils.shouldReportShowSubscript(props.report); const isExpenseRequest = ReportUtils.isExpenseRequest(props.report); diff --git a/src/components/HeaderWithBackButton/index.js b/src/components/HeaderWithBackButton/index.js index 6a02ce02237d..8e5fed15ff7e 100755 --- a/src/components/HeaderWithBackButton/index.js +++ b/src/components/HeaderWithBackButton/index.js @@ -28,7 +28,6 @@ function HeaderWithBackButton({ onThreeDotsButtonPress = () => {}, report = null, policy = {}, - personalDetails = {}, shouldShowAvatarWithDisplay = false, shouldShowBackButton = true, shouldShowBorderBottom = false, @@ -85,7 +84,6 @@ function HeaderWithBackButton({ ) : ( diff --git a/src/components/LHNOptionsList/OptionRowLHNData.js b/src/components/LHNOptionsList/OptionRowLHNData.js index e93e3690138e..2ddf8a687cfd 100644 --- a/src/components/LHNOptionsList/OptionRowLHNData.js +++ b/src/components/LHNOptionsList/OptionRowLHNData.js @@ -9,11 +9,9 @@ import compose from '../../libs/compose'; import ONYXKEYS from '../../ONYXKEYS'; import OptionRowLHN, {propTypes as basePropTypes, defaultProps as baseDefaultProps} from './OptionRowLHN'; import * as Report from '../../libs/actions/Report'; -import * as UserUtils from '../../libs/UserUtils'; import * as ReportActionsUtils from '../../libs/ReportActionsUtils'; import * as TransactionUtils from '../../libs/TransactionUtils'; -import participantPropTypes from '../participantPropTypes'; import CONST from '../../CONST'; import reportActionPropTypes from '../../pages/home/report/reportActionPropTypes'; @@ -21,9 +19,6 @@ 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, @@ -54,7 +49,6 @@ const propTypes = { const defaultProps = { isFocused: false, - personalDetails: {}, fullReport: {}, policy: {}, parentReportActions: {}, @@ -73,7 +67,6 @@ function OptionRowLHNData({ isFocused, fullReport, reportActions, - personalDetails, preferredLocale, comment, policy, @@ -97,7 +90,7 @@ function OptionRowLHNData({ 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); + const item = SidebarUtils.getOptionData(fullReport, reportActions, preferredLocale, policy, parentReportAction); if (deepEqual(item, optionItemRef.current)) { return optionItemRef.current; } @@ -106,7 +99,7 @@ function OptionRowLHNData({ // 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]); + }, [fullReport, linkedTransaction, reportActions, preferredLocale, policy, parentReportAction, transaction]); useEffect(() => { if (!optionItem || optionItem.hasDraftComment || !comment || comment.length <= 0 || isFocused) { @@ -130,30 +123,6 @@ OptionRowLHNData.propTypes = propTypes; OptionRowLHNData.defaultProps = defaultProps; OptionRowLHNData.displayName = 'OptionRowLHNData'; -/** - * @param {Object} [personalDetails] - * @returns {Object|undefined} - */ -const personalDetailsSelector = (personalDetails) => - _.reduce( - personalDetails, - (finalPersonalDetails, personalData, accountID) => { - // It's OK to do param-reassignment in _.reduce() because we absolutely know the starting state of finalPersonalDetails - // eslint-disable-next-line no-param-reassign - finalPersonalDetails[accountID] = { - accountID: Number(accountID), - login: personalData.login, - displayName: personalData.displayName, - firstName: personalData.firstName, - status: personalData.status, - avatar: UserUtils.getAvatar(personalData.avatar, personalData.accountID), - fallbackIcon: personalData.fallbackIcon, - }; - return finalPersonalDetails; - }, - {}, - ); - /** * This component is rendered in a list. * On scroll we want to avoid that a item re-renders @@ -174,10 +143,6 @@ export default React.memo( key: ({reportID}) => `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`, canEvict: false, }, - personalDetails: { - key: ONYXKEYS.PERSONAL_DETAILS_LIST, - selector: personalDetailsSelector, - }, preferredLocale: { key: ONYXKEYS.NVP_PREFERRED_LOCALE, }, diff --git a/src/components/MoneyReportHeader.js b/src/components/MoneyReportHeader.js index ab0b77c21653..211acaf033ce 100644 --- a/src/components/MoneyReportHeader.js +++ b/src/components/MoneyReportHeader.js @@ -46,9 +46,6 @@ const propTypes = { /** The next step for the report */ nextStep: nextStepPropTypes, - /** Personal details so we can get the ones for the report participants */ - personalDetails: PropTypes.objectOf(participantPropTypes).isRequired, - /** Session info for the currently logged in user. */ session: PropTypes.shape({ /** Currently logged in user email */ @@ -67,7 +64,7 @@ const defaultProps = { policy: {}, }; -function MoneyReportHeader({session, personalDetails, policy, chatReport, nextStep, report: moneyRequestReport, isSmallScreenWidth}) { +function MoneyReportHeader({session, policy, chatReport, nextStep, report: moneyRequestReport, isSmallScreenWidth}) { const {translate} = useLocalize(); const reimbursableTotal = ReportUtils.getMoneyRequestReimbursableTotal(moneyRequestReport); const isApproved = ReportUtils.isReportApproved(moneyRequestReport); @@ -102,7 +99,6 @@ function MoneyReportHeader({session, personalDetails, policy, chatReport, nextSt shouldShowPinButton={false} report={moneyRequestReport} policy={policy} - personalDetails={personalDetails} shouldShowBackButton={isSmallScreenWidth} onBackButtonPress={() => Navigation.goBack(ROUTES.HOME, false, true)} // Shows border if no buttons or next steps are showing below the header diff --git a/src/components/MoneyRequestHeader.js b/src/components/MoneyRequestHeader.js index 086e1429baef..d9be47ad312f 100644 --- a/src/components/MoneyRequestHeader.js +++ b/src/components/MoneyRequestHeader.js @@ -35,9 +35,6 @@ const propTypes = { name: PropTypes.string, }), - /** Personal details so we can get the ones for the report participants */ - personalDetails: PropTypes.objectOf(participantPropTypes).isRequired, - /* Onyx Props */ /** Session info for the currently logged in user. */ session: PropTypes.shape({ @@ -65,7 +62,7 @@ const defaultProps = { policy: {}, }; -function MoneyRequestHeader({session, parentReport, report, parentReportAction, transaction, policy, personalDetails}) { +function MoneyRequestHeader({session, parentReport, report, parentReportAction, transaction, policy}) { const {translate} = useLocalize(); const [isDeleteModalVisible, setIsDeleteModalVisible] = useState(false); const moneyRequestReport = parentReport; @@ -125,7 +122,6 @@ function MoneyRequestHeader({session, parentReport, report, parentReportAction, ownerEmail: lodashGet(parentReport, 'ownerEmail', null), }} policy={policy} - personalDetails={personalDetails} shouldShowBackButton={isSmallScreenWidth} onBackButtonPress={() => Navigation.goBack(ROUTES.HOME, false, true)} /> diff --git a/src/components/withCurrentUserPersonalDetails.tsx b/src/components/withCurrentUserPersonalDetails.tsx index e1472f280f17..fa81c658bc78 100644 --- a/src/components/withCurrentUserPersonalDetails.tsx +++ b/src/components/withCurrentUserPersonalDetails.tsx @@ -4,13 +4,11 @@ import getComponentDisplayName from '../libs/getComponentDisplayName'; import ONYXKEYS from '../ONYXKEYS'; import personalDetailsPropType from '../pages/personalDetailsPropType'; import type {PersonalDetails, Session} from '../types/onyx'; +import { getPersonalDetailsByAccountID } from '../libs/PersonalDetailsUtils'; type CurrentUserPersonalDetails = PersonalDetails | Record; type OnyxProps = { - /** Personal details of all the users, including current user */ - personalDetails: OnyxEntry>; - /** Session of the current user */ session: OnyxEntry; }; @@ -35,7 +33,7 @@ export default function ( ): ComponentType & RefAttributes, keyof OnyxProps>> { function WithCurrentUserPersonalDetails(props: Omit, ref: ForwardedRef) { const accountID = props.session?.accountID ?? 0; - const accountPersonalDetails = props.personalDetails?.[accountID]; + const accountPersonalDetails: PersonalDetails = getPersonalDetailsByAccountID(accountID); const currentUserPersonalDetails: CurrentUserPersonalDetails = useMemo( () => (accountPersonalDetails ? {...accountPersonalDetails, accountID} : {}), [accountPersonalDetails, accountID], @@ -55,9 +53,6 @@ export default function ( const withCurrentUserPersonalDetails = React.forwardRef(WithCurrentUserPersonalDetails); return withOnyx & RefAttributes, OnyxProps>({ - personalDetails: { - key: ONYXKEYS.PERSONAL_DETAILS_LIST, - }, session: { key: ONYXKEYS.SESSION, }, diff --git a/src/libs/OptionsListUtils.js b/src/libs/OptionsListUtils.js index 79c480711c4d..4948c4e8ef90 100644 --- a/src/libs/OptionsListUtils.js +++ b/src/libs/OptionsListUtils.js @@ -152,11 +152,12 @@ function getAvatarsForAccountIDs(accountIDs, personalDetails, defaultValues = {} * Returns the personal details for an array of accountIDs * * @param {Array} accountIDs - * @param {Object} personalDetails + * @param {Object} passedPersonalDetails * @returns {Object} – keys of the object are emails, values are PersonalDetails objects. */ -function getPersonalDetailsForAccountIDs(accountIDs, personalDetails) { +function getPersonalDetailsForAccountIDs(accountIDs, passedPersonalDetails) { const personalDetailsForAccountIDs = {}; + const personalDetails = passedPersonalDetails || allPersonalDetails; if (!personalDetails) { return personalDetailsForAccountIDs; } diff --git a/src/libs/PersonalDetailsUtils.js b/src/libs/PersonalDetailsUtils.js index 29c49427bc81..78066c6b1d9d 100644 --- a/src/libs/PersonalDetailsUtils.js +++ b/src/libs/PersonalDetailsUtils.js @@ -23,8 +23,7 @@ Onyx.connect({ * @returns {String} */ function getDisplayNameOrDefault(passedPersonalDetails, pathToDisplayName, defaultValue) { - const displayName = lodashGet(passedPersonalDetails, pathToDisplayName); - + const displayName = lodashGet(passedPersonalDetails || allPersonalDetails, pathToDisplayName); return displayName || defaultValue || Localize.translateLocal('common.hidden'); } @@ -177,4 +176,26 @@ function getFormattedAddress(privatePersonalDetails) { return formattedAddress.trim().replace(/,$/, ''); } -export {getDisplayNameOrDefault, getPersonalDetailsByIDs, getAccountIDsByLogins, getLoginsByAccountIDs, getNewPersonalDetailsOnyxData, getFormattedAddress}; +function getPersonalDetailsByAccountID(accountID) { + return allPersonalDetails[accountID]; +} + +function getWhisperedToPersonalDetails(whisperedToAccountIDs) { + return _.filter(allPersonalDetails, (details) => _.includes(whisperedToAccountIDs, details.accountID)); +} + +function isPersonalDetailsEmpty() { + return !personalDetails.length; +} + +export { + getDisplayNameOrDefault, + getPersonalDetailsByIDs, + getAccountIDsByLogins, + getLoginsByAccountIDs, + getNewPersonalDetailsOnyxData, + getFormattedAddress, + getPersonalDetailsByAccountID, + getWhisperedToPersonalDetails, + isPersonalDetailsEmpty, +}; diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index 79c1c500b837..74d744efb837 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -913,15 +913,13 @@ function getReportRecipientAccountIDs(report, currentLoginAccountID) { /** * Whether the time row should be shown for a report. - * @param {Array} personalDetails * @param {Object} report - * @param {Number} accountID * @return {Boolean} */ -function canShowReportRecipientLocalTime(personalDetails, report, accountID) { - const reportRecipientAccountIDs = getReportRecipientAccountIDs(report, accountID); +function canShowReportRecipientLocalTime(report) { + const reportRecipientAccountIDs = getReportRecipientAccountIDs(report, currentUserAccountID); const hasMultipleParticipants = reportRecipientAccountIDs.length > 1; - const reportRecipient = personalDetails[reportRecipientAccountIDs[0]]; + const reportRecipient = allPersonalDetails[reportRecipientAccountIDs[0]]; const reportRecipientTimezone = lodashGet(reportRecipient, 'timezone', CONST.DEFAULT_TIME_ZONE); const isReportParticipantValidated = lodashGet(reportRecipient, 'validated', false); return Boolean( @@ -977,13 +975,13 @@ function getWorkspaceAvatar(report) { * The Avatar sources can be URLs or Icon components according to the chat type. * * @param {Array} participants - * @param {Object} personalDetails + * @param {Object} passedPersonalDetails * @returns {Array<*>} */ -function getIconsForParticipants(participants, personalDetails) { +function getIconsForParticipants(participants, passedPersonalDetails) { const participantDetails = []; const participantsList = participants || []; - + const personalDetails = passedPersonalDetails || allPersonalDetails; for (let i = 0; i < participantsList.length; i++) { const accountID = participantsList[i]; const avatarSource = UserUtils.getAvatar(lodashGet(personalDetails, [accountID, 'avatar'], ''), accountID); @@ -1046,14 +1044,15 @@ function getWorkspaceIcon(report, policy = undefined) { * The Avatar sources can be URLs or Icon components according to the chat type. * * @param {Object} report - * @param {Object} personalDetails + * @param {Object} passedPersonalDetails * @param {*} [defaultIcon] * @param {String} [defaultName] * @param {Number} [defaultAccountID] * @param {Object} [policy] * @returns {Array<*>} */ -function getIcons(report, personalDetails, defaultIcon = null, defaultName = '', defaultAccountID = -1, policy = undefined) { +function getIcons(report, passedPersonalDetails, defaultIcon = null, defaultName = '', defaultAccountID = -1, policy = undefined) { + const personalDetails = passedPersonalDetails || allPersonalDetails; if (_.isEmpty(report)) { const fallbackIcon = { source: defaultIcon || Expensicons.FallbackAvatar, diff --git a/src/libs/SidebarUtils.js b/src/libs/SidebarUtils.js index 6b9e6d10fd16..5d7dd5bc1ed7 100644 --- a/src/libs/SidebarUtils.js +++ b/src/libs/SidebarUtils.js @@ -55,6 +55,12 @@ Onyx.connect({ }, }); +let allPersonalDetails; +Onyx.connect({ + key: ONYXKEYS.PERSONAL_DETAILS_LIST, + callback: (val) => (allPersonalDetails = val), +}); + let resolveSidebarIsReadyPromise; let sidebarIsReadyPromise = new Promise((resolve) => { @@ -218,16 +224,16 @@ function getOrderedReportIDs(currentReportId, allReportsDict, betas, policies, p * * @param {Object} report * @param {Object} reportActions - * @param {Object} personalDetails * @param {String} preferredLocale * @param {Object} [policy] * @param {Object} parentReportAction * @returns {Object} */ -function getOptionData(report, reportActions, personalDetails, preferredLocale, policy, parentReportAction) { +function getOptionData(report, reportActions, preferredLocale, policy, parentReportAction) { // When a user signs out, Onyx is cleared. Due to the lazy rendering with a virtual list, it's possible for // this method to be called after the Onyx data has been cleared out. In that case, it's fine to do // a null check here and return early. + const personalDetails = allPersonalDetails; if (!report || !personalDetails) { return; } diff --git a/src/pages/home/HeaderView.js b/src/pages/home/HeaderView.js index e88f6cd0b756..d36937b0f420 100644 --- a/src/pages/home/HeaderView.js +++ b/src/pages/home/HeaderView.js @@ -43,9 +43,6 @@ const propTypes = { /** The report currently being looked at */ report: reportPropTypes, - /** Personal details of all the users */ - personalDetails: PropTypes.objectOf(participantPropTypes), - /** Onyx Props */ parentReport: reportPropTypes, @@ -62,7 +59,6 @@ const propTypes = { }; const defaultProps = { - personalDetails: {}, report: null, guideCalendarLink: null, parentReport: {}, @@ -73,7 +69,7 @@ const defaultProps = { function HeaderView(props) { const participants = lodashGet(props.report, 'participantAccountIDs', []); - const participantPersonalDetails = OptionsListUtils.getPersonalDetailsForAccountIDs(participants, props.personalDetails); + const participantPersonalDetails = OptionsListUtils.getPersonalDetailsForAccountIDs(participants); const isMultipleParticipant = participants.length > 1; const displayNamesWithTooltips = ReportUtils.getDisplayNamesWithTooltips(participantPersonalDetails, isMultipleParticipant); const isChatThread = ReportUtils.isChatThread(props.report); @@ -167,7 +163,7 @@ function HeaderView(props) { const shouldShowSubscript = ReportUtils.shouldReportShowSubscript(props.report); const defaultSubscriptSize = ReportUtils.isExpenseRequest(props.report) ? CONST.AVATAR_SIZE.SMALL_NORMAL : CONST.AVATAR_SIZE.DEFAULT; - const icons = ReportUtils.getIcons(reportHeaderData, props.personalDetails); + const icons = ReportUtils.getIcons(reportHeaderData); const brickRoadIndicator = ReportUtils.hasReportNameError(props.report) ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : ''; const shouldShowBorderBottom = !isTaskReport || !props.isSmallScreenWidth; const shouldDisableDetailPage = ReportUtils.shouldDisableDetailPage(props.report); diff --git a/src/pages/home/ReportScreen.js b/src/pages/home/ReportScreen.js index 64641ab473fb..d6caff573d25 100644 --- a/src/pages/home/ReportScreen.js +++ b/src/pages/home/ReportScreen.js @@ -40,6 +40,7 @@ import usePrevious from '../../hooks/usePrevious'; import CONST from '../../CONST'; import withCurrentReportID, {withCurrentReportIDPropTypes, withCurrentReportIDDefaultProps} from '../../components/withCurrentReportID'; import reportWithoutHasDraftSelector from '../../libs/OnyxSelectors/reportWithoutHasDraftSelector'; +import { isPersonalDetailsEmpty } from '../../libs/PersonalDetailsUtils'; const propTypes = { /** Navigation route context info provided by react navigation */ @@ -86,9 +87,6 @@ const propTypes = { /** The account manager report ID */ accountManagerReportID: PropTypes.string, - /** All of the personal details for everyone */ - personalDetails: PropTypes.objectOf(personalDetailsPropType), - /** Onyx function that marks the component ready for hydration */ markReadyForHydration: PropTypes.func, @@ -115,7 +113,6 @@ const defaultProps = { policies: {}, accountManagerReportID: null, userLeavingStatus: false, - personalDetails: {}, markReadyForHydration: null, ...withCurrentReportIDDefaultProps, }; @@ -140,7 +137,6 @@ function ReportScreen({ reportMetadata, reportActions, accountManagerReportID, - personalDetails, markReadyForHydration, policies, isSidebarLoaded, @@ -173,7 +169,7 @@ function ReportScreen({ const shouldHideReport = !ReportUtils.canAccessReport(report, policies, betas); - const isLoading = !reportID || !isSidebarLoaded || _.isEmpty(personalDetails); + const isLoading = !reportID || !isSidebarLoaded || isPersonalDetailsEmpty(); const parentReportAction = ReportActionsUtils.getParentReportAction(report); const lastReportAction = useMemo( @@ -191,7 +187,6 @@ function ReportScreen({ Navigation.goBack(ROUTES.HOME, false, true)} - personalDetails={personalDetails} report={report} /> ); @@ -201,7 +196,6 @@ function ReportScreen({ @@ -213,7 +207,6 @@ function ReportScreen({ @@ -445,7 +438,6 @@ function ReportScreen({ isComposerFullSize={isComposerFullSize} policies={policies} listHeight={listHeight} - personalDetails={personalDetails} isEmptyChat={isEmptyChat} lastReportAction={lastReportAction} /> @@ -506,9 +498,6 @@ export default compose( key: ONYXKEYS.ACCOUNT_MANAGER_REPORT_ID, initialValue: null, }, - personalDetails: { - key: ONYXKEYS.PERSONAL_DETAILS_LIST, - }, userLeavingStatus: { key: ({route}) => `${ONYXKEYS.COLLECTION.REPORT_USER_IS_LEAVING_ROOM}${getReportID(route)}`, initialValue: false, diff --git a/src/pages/home/report/ReportActionCompose/ReportActionCompose.js b/src/pages/home/report/ReportActionCompose/ReportActionCompose.js index 2721329919c7..dc515c2495ff 100644 --- a/src/pages/home/report/ReportActionCompose/ReportActionCompose.js +++ b/src/pages/home/report/ReportActionCompose/ReportActionCompose.js @@ -16,7 +16,6 @@ import willBlurTextInputOnTapOutsideFunc from '../../../../libs/willBlurTextInpu import canFocusInputOnScreenFocus from '../../../../libs/canFocusInputOnScreenFocus'; import CONST from '../../../../CONST'; import * as ReportUtils from '../../../../libs/ReportUtils'; -import participantPropTypes from '../../../../components/participantPropTypes'; import ParticipantLocalTime from '../ParticipantLocalTime'; import withCurrentUserPersonalDetails, {withCurrentUserPersonalDetailsPropTypes, withCurrentUserPersonalDetailsDefaultProps} from '../../../../components/withCurrentUserPersonalDetails'; import {withNetwork} from '../../../../components/OnyxProvider'; @@ -33,6 +32,7 @@ import getModalState from '../../../../libs/getModalState'; import useWindowDimensions from '../../../../hooks/useWindowDimensions'; import * as EmojiPickerActions from '../../../../libs/actions/EmojiPickerAction'; import * as ReportActionsUtils from '../../../../libs/ReportActionsUtils'; +import {getPersonalDetailsByAccountID} from '../../../../libs/PersonalDetailsUtils'; const propTypes = { /** A method to call when the form is submitted */ @@ -41,9 +41,6 @@ const propTypes = { /** The ID of the report actions will be created for */ reportID: PropTypes.string.isRequired, - /** Personal details of all the users */ - personalDetails: PropTypes.objectOf(participantPropTypes), - /** The report currently being looked at */ report: reportPropTypes, @@ -76,7 +73,6 @@ const propTypes = { const defaultProps = { report: {}, blockedFromConcierge: {}, - personalDetails: {}, preferredSkinTone: CONST.EMOJI_DEFAULT_SKIN_TONE, isComposerFullSize: false, pendingAction: null, @@ -100,7 +96,6 @@ function ReportActionCompose({ network, onSubmit, pendingAction, - personalDetails, report, reportID, isEmptyChat, @@ -147,10 +142,7 @@ function ReportActionCompose({ [currentUserPersonalDetails.accountID, report], ); - const shouldShowReportRecipientLocalTime = useMemo( - () => ReportUtils.canShowReportRecipientLocalTime(personalDetails, report, currentUserPersonalDetails.accountID) && !isComposerFullSize, - [personalDetails, report, currentUserPersonalDetails.accountID, isComposerFullSize], - ); + const shouldShowReportRecipientLocalTime = useMemo(() => ReportUtils.canShowReportRecipientLocalTime(report) && !isComposerFullSize, [report, isComposerFullSize]); const includesConcierge = useMemo(() => ReportUtils.chatIncludesConcierge({participantAccountIDs: report.participantAccountIDs}), [report.participantAccountIDs]); const userBlockedFromConcierge = useMemo(() => User.isBlockedFromConcierge(blockedFromConcierge), [blockedFromConcierge]); @@ -307,7 +299,7 @@ function ReportActionCompose({ ); const reportRecipientAcountIDs = ReportUtils.getReportRecipientAccountIDs(report, currentUserPersonalDetails.accountID); - const reportRecipient = personalDetails[reportRecipientAcountIDs[0]]; + const reportRecipient = getPersonalDetailsByAccountID(reportRecipientAcountIDs[0]); const shouldUseFocusedColor = !isBlockedFromConcierge && !disabled && isFocused; const hasReportRecipient = _.isObject(reportRecipient) && !_.isEmpty(reportRecipient); @@ -443,9 +435,6 @@ export default compose( blockedFromConcierge: { key: ONYXKEYS.NVP_BLOCKED_FROM_CONCIERGE, }, - personalDetails: { - key: ONYXKEYS.PERSONAL_DETAILS_LIST, - }, shouldShowComposeInput: { key: ONYXKEYS.SHOULD_SHOW_COMPOSE_INPUT, }, diff --git a/src/pages/home/report/ReportActionItem.js b/src/pages/home/report/ReportActionItem.js index 3afdb437a49a..2697d4b5551d 100644 --- a/src/pages/home/report/ReportActionItem.js +++ b/src/pages/home/report/ReportActionItem.js @@ -133,7 +133,6 @@ const defaultProps = { }; function ReportActionItem(props) { - const personalDetails = usePersonalDetails() || CONST.EMPTY_OBJECT; const [isContextMenuActive, setIsContextMenuActive] = useState(() => ReportActionContextMenu.isActiveReportAction(props.action.reportActionID)); const [isHidden, setIsHidden] = useState(false); const [moderationDecision, setModerationDecision] = useState(CONST.MODERATION.MODERATOR_DECISION_APPROVED); @@ -303,6 +302,7 @@ function ReportActionItem(props) { */ const renderItemContent = (hovered = false, isWhisper = false, hasErrors = false) => { let children; + const _submitterDisplayName = PersonalDetailsUtils.getDisplayNameOrDefault(null, [props.report.ownerAccountID, 'displayName'], props.report.ownerEmail); // Show the MoneyRequestPreview for when request was created, bill was split or money was sent if ( @@ -360,7 +360,7 @@ function ReportActionItem(props) { /> ); } else if (props.action.actionName === CONST.REPORT.ACTIONS.TYPE.REIMBURSEMENTQUEUED) { - const submitterDisplayName = PersonalDetailsUtils.getDisplayNameOrDefault(personalDetails, [props.report.ownerAccountID, 'displayName'], props.report.ownerEmail); + const submitterDisplayName = PersonalDetailsUtils.getDisplayNameOrDefault(null, [props.report.ownerAccountID, 'displayName'], props.report.ownerEmail); const paymentType = lodashGet(props.action, 'originalMessage.paymentType', ''); const isSubmitterOfUnsettledReport = ReportUtils.isCurrentUserSubmitter(props.report.reportID) && !ReportUtils.isSettled(props.report.reportID); @@ -506,7 +506,7 @@ function ReportActionItem(props) { numberOfReplies={numberOfThreadReplies} mostRecentReply={`${props.action.childLastVisibleActionCreated}`} isHovered={hovered} - icons={ReportUtils.getIconsForParticipants(oldestFourAccountIDs, personalDetails)} + icons={ReportUtils.getIconsForParticipants(oldestFourAccountIDs)} onSecondaryInteraction={showPopover} /> @@ -638,7 +638,7 @@ function ReportActionItem(props) { const isWhisper = whisperedToAccountIDs.length > 0; const isMultipleParticipant = whisperedToAccountIDs.length > 1; const isWhisperOnlyVisibleByUser = isWhisper && ReportUtils.isCurrentUserTheOnlyParticipant(whisperedToAccountIDs); - const whisperedToPersonalDetails = isWhisper ? _.filter(personalDetails, (details) => _.includes(whisperedToAccountIDs, details.accountID)) : []; + const whisperedToPersonalDetails = isWhisper ? PersonalDetailsUtils.getWhisperedToPersonalDetails(whisperedToAccountIDs) : []; const displayNamesWithTooltips = isWhisper ? ReportUtils.getDisplayNamesWithTooltips(whisperedToPersonalDetails, isMultipleParticipant) : []; return ( `${ONYXKEYS.COLLECTION.REPORT}${reportID}`, selector: reportWithoutHasDraftSelector, }, - personalDetails: { - key: ONYXKEYS.PERSONAL_DETAILS_LIST, - }, policy: { key: ({policyID}) => `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, }, diff --git a/src/pages/home/report/ReportActionItemSingle.js b/src/pages/home/report/ReportActionItemSingle.js index fc189a3aef36..faa9b4c6fbbc 100644 --- a/src/pages/home/report/ReportActionItemSingle.js +++ b/src/pages/home/report/ReportActionItemSingle.js @@ -31,6 +31,7 @@ import ONYXKEYS from '../../../ONYXKEYS'; import Text from '../../../components/Text'; import Tooltip from '../../../components/Tooltip'; import DateUtils from '../../../libs/DateUtils'; +import { getPersonalDetailsByAccountID } from '../../../libs/PersonalDetailsUtils'; const propTypes = { /** All the data of the action */ @@ -83,8 +84,8 @@ const showWorkspaceDetails = (reportID) => { }; function ReportActionItemSingle(props) { - const personalDetails = usePersonalDetails() || CONST.EMPTY_OBJECT; const actorAccountID = props.action.actionName === CONST.REPORT.ACTIONS.TYPE.REPORTPREVIEW && props.iouReport ? props.iouReport.managerID : props.action.actorAccountID; + const personalDetails = getPersonalDetailsByAccountID(actorAccountID); let {displayName} = personalDetails[actorAccountID] || {}; const {avatar, login, pendingFields, status, fallbackIcon} = personalDetails[actorAccountID] || {}; let actorHint = (login || displayName || '').replace(CONST.REGEX.MERGED_ACCOUNT_PREFIX, ''); @@ -122,7 +123,7 @@ function ReportActionItemSingle(props) { id: secondaryAccountId, }; } else if (!isWorkspaceActor) { - secondaryAvatar = ReportUtils.getIcons(props.report, {})[props.report.isOwnPolicyExpenseChat ? 0 : 1]; + secondaryAvatar = ReportUtils.getIcons(props.report)[props.report.isOwnPolicyExpenseChat ? 0 : 1]; } const icon = {source: avatarSource, type: isWorkspaceActor ? CONST.ICON_TYPE_WORKSPACE : CONST.ICON_TYPE_AVATAR, name: primaryDisplayName, id: isWorkspaceActor ? '' : actorAccountID}; diff --git a/src/pages/home/report/ReportActionsList.js b/src/pages/home/report/ReportActionsList.js index 531a11ce7252..6515dc652bdc 100644 --- a/src/pages/home/report/ReportActionsList.js +++ b/src/pages/home/report/ReportActionsList.js @@ -6,8 +6,6 @@ import {useRoute} from '@react-navigation/native'; import lodashGet from 'lodash/get'; import CONST from '../../../CONST'; import InvertedFlatList from '../../../components/InvertedFlatList'; -import {withPersonalDetails} from '../../../components/OnyxProvider'; -import withCurrentUserPersonalDetails, {withCurrentUserPersonalDetailsDefaultProps, withCurrentUserPersonalDetailsPropTypes} from '../../../components/withCurrentUserPersonalDetails'; import withWindowDimensions, {windowDimensionsPropTypes} from '../../../components/withWindowDimensions'; import useNetwork from '../../../hooks/useNetwork'; import useLocalize from '../../../hooks/useLocalize'; @@ -66,17 +64,14 @@ const propTypes = { }), ...windowDimensionsPropTypes, - ...withCurrentUserPersonalDetailsPropTypes, }; const defaultProps = { - personalDetails: {}, onScroll: () => {}, mostRecentIOUReportActionID: '', isLoadingInitialReportActions: false, isLoadingOlderReportActions: false, isLoadingNewerReportActions: false, - ...withCurrentUserPersonalDetailsDefaultProps, }; const VERTICAL_OFFSET_THRESHOLD = 200; @@ -122,8 +117,6 @@ function ReportActionsList({ onScroll, mostRecentIOUReportActionID, isSmallScreenWidth, - personalDetailsList, - currentUserPersonalDetails, hasOutstandingIOU, loadNewerChats, loadOlderChats, @@ -350,7 +343,7 @@ function ReportActionsList({ // To notify there something changes we can use extraData prop to flatlist const extraData = [isSmallScreenWidth ? currentUnreadMarker : undefined, ReportUtils.isArchivedRoom(report)]; const hideComposer = ReportUtils.shouldDisableWriteActions(report); - const shouldShowReportRecipientLocalTime = ReportUtils.canShowReportRecipientLocalTime(personalDetailsList, report, currentUserPersonalDetails.accountID) && !isComposerFullSize; + const shouldShowReportRecipientLocalTime = ReportUtils.canShowReportRecipientLocalTime(report) && !isComposerFullSize; const contentContainerStyle = useMemo( () => [styles.chatContentScrollView, isLoadingNewerReportActions ? styles.chatContentScrollViewWithHeaderLoader : {}], @@ -435,4 +428,4 @@ ReportActionsList.propTypes = propTypes; ReportActionsList.defaultProps = defaultProps; ReportActionsList.displayName = 'ReportActionsList'; -export default compose(withWindowDimensions, withPersonalDetails(), withCurrentUserPersonalDetails)(ReportActionsList); +export default compose(withWindowDimensions)(ReportActionsList); diff --git a/src/pages/home/report/ReportFooter.js b/src/pages/home/report/ReportFooter.js index 5af46b14142d..710eed2b86df 100644 --- a/src/pages/home/report/ReportFooter.js +++ b/src/pages/home/report/ReportFooter.js @@ -33,9 +33,6 @@ const propTypes = { /** The pending action when we are adding a chat */ pendingAction: PropTypes.string, - /** Personal details of all the users */ - personalDetails: PropTypes.objectOf(participantPropTypes), - /** Whether user interactions should be disabled */ shouldDisableCompose: PropTypes.bool, @@ -51,7 +48,6 @@ const propTypes = { const defaultProps = { report: {reportID: '0'}, pendingAction: null, - personalDetails: {}, shouldDisableCompose: false, listHeight: 0, isReportReadyForDisplay: true, @@ -111,7 +107,6 @@ function ReportFooter(props) { )} {isArchivedRoom && } @@ -151,7 +146,6 @@ export default withWindowDimensions( (prevProps, nextProps) => isEqual(prevProps.report, nextProps.report) && isEqual(prevProps.reportActions, nextProps.reportActions) && - isEqual(prevProps.personalDetails, nextProps.personalDetails) && prevProps.pendingAction === nextProps.pendingAction && prevProps.shouldDisableCompose === nextProps.shouldDisableCompose && prevProps.listHeight === nextProps.listHeight && From 47c4717c3ee8553a96b1bb8540df9d5779097f5f Mon Sep 17 00:00:00 2001 From: hurali97 Date: Thu, 26 Oct 2023 16:54:08 +0500 Subject: [PATCH 009/722] fix: linting --- src/components/AnonymousReportFooter.js | 1 - src/components/ArchivedReportFooter.js | 1 - src/components/AvatarWithDisplayName.js | 1 - src/components/MoneyReportHeader.js | 1 - src/components/MoneyRequestHeader.js | 1 - src/pages/home/HeaderView.js | 1 - src/pages/home/ReportScreen.js | 5 ++--- .../ReportActionCompose/ReportActionCompose.js | 4 ++-- .../ReportActionCompose/SuggestionMention.js | 2 +- src/pages/home/report/ReportActionItem.js | 3 +-- src/pages/home/report/ReportActionItemCreated.js | 1 - src/pages/home/report/ReportActionItemSingle.js | 15 +++++++-------- src/pages/home/report/ReportActionsList.js | 4 ++-- src/pages/home/report/ReportFooter.js | 1 - 14 files changed, 15 insertions(+), 26 deletions(-) diff --git a/src/components/AnonymousReportFooter.js b/src/components/AnonymousReportFooter.js index 902a31f12ee3..51b9752294e9 100644 --- a/src/components/AnonymousReportFooter.js +++ b/src/components/AnonymousReportFooter.js @@ -8,7 +8,6 @@ import withLocalize, {withLocalizePropTypes} from './withLocalize'; import reportPropTypes from '../pages/reportPropTypes'; import styles from '../styles/styles'; import * as Session from '../libs/actions/Session'; -import participantPropTypes from './participantPropTypes'; const propTypes = { /** The report currently being looked at */ diff --git a/src/components/ArchivedReportFooter.js b/src/components/ArchivedReportFooter.js index bca5f0b391c8..41cf0f65487e 100644 --- a/src/components/ArchivedReportFooter.js +++ b/src/components/ArchivedReportFooter.js @@ -7,7 +7,6 @@ import CONST from '../CONST'; import Banner from './Banner'; import withLocalize, {withLocalizePropTypes} from './withLocalize'; import compose from '../libs/compose'; -import personalDetailsPropType from '../pages/personalDetailsPropType'; import ONYXKEYS from '../ONYXKEYS'; import * as ReportUtils from '../libs/ReportUtils'; import reportPropTypes from '../pages/reportPropTypes'; diff --git a/src/components/AvatarWithDisplayName.js b/src/components/AvatarWithDisplayName.js index 3a4ebee0aa42..8623f6bba4bc 100644 --- a/src/components/AvatarWithDisplayName.js +++ b/src/components/AvatarWithDisplayName.js @@ -5,7 +5,6 @@ import PropTypes from 'prop-types'; import lodashGet from 'lodash/get'; import CONST from '../CONST'; import reportPropTypes from '../pages/reportPropTypes'; -import participantPropTypes from './participantPropTypes'; import withWindowDimensions, {windowDimensionsPropTypes} from './withWindowDimensions'; import withLocalize, {withLocalizePropTypes} from './withLocalize'; import styles from '../styles/styles'; diff --git a/src/components/MoneyReportHeader.js b/src/components/MoneyReportHeader.js index 211acaf033ce..55a31c0a9bdc 100644 --- a/src/components/MoneyReportHeader.js +++ b/src/components/MoneyReportHeader.js @@ -8,7 +8,6 @@ import useLocalize from '../hooks/useLocalize'; import HeaderWithBackButton from './HeaderWithBackButton'; import iouReportPropTypes from '../pages/iouReportPropTypes'; import * as ReportUtils from '../libs/ReportUtils'; -import participantPropTypes from './participantPropTypes'; import styles from '../styles/styles'; import withWindowDimensions, {windowDimensionsPropTypes} from './withWindowDimensions'; import compose from '../libs/compose'; diff --git a/src/components/MoneyRequestHeader.js b/src/components/MoneyRequestHeader.js index d9be47ad312f..c106e1aa9bfd 100644 --- a/src/components/MoneyRequestHeader.js +++ b/src/components/MoneyRequestHeader.js @@ -8,7 +8,6 @@ import iouReportPropTypes from '../pages/iouReportPropTypes'; import * as ReportUtils from '../libs/ReportUtils'; import compose from '../libs/compose'; import * as Expensicons from './Icon/Expensicons'; -import participantPropTypes from './participantPropTypes'; import styles from '../styles/styles'; import Navigation from '../libs/Navigation/Navigation'; import ROUTES from '../ROUTES'; diff --git a/src/pages/home/HeaderView.js b/src/pages/home/HeaderView.js index d36937b0f420..3f9776ca4946 100644 --- a/src/pages/home/HeaderView.js +++ b/src/pages/home/HeaderView.js @@ -19,7 +19,6 @@ import TaskHeaderActionButton from '../../components/TaskHeaderActionButton'; import Text from '../../components/Text'; import ThreeDotsMenu from '../../components/ThreeDotsMenu'; import Tooltip from '../../components/Tooltip'; -import participantPropTypes from '../../components/participantPropTypes'; import withLocalize, {withLocalizePropTypes} from '../../components/withLocalize'; import withWindowDimensions, {windowDimensionsPropTypes} from '../../components/withWindowDimensions'; import * as OptionsListUtils from '../../libs/OptionsListUtils'; diff --git a/src/pages/home/ReportScreen.js b/src/pages/home/ReportScreen.js index d6caff573d25..3340c4ca5ee3 100644 --- a/src/pages/home/ReportScreen.js +++ b/src/pages/home/ReportScreen.js @@ -28,7 +28,6 @@ import reportMetadataPropTypes from '../reportMetadataPropTypes'; import FullPageNotFoundView from '../../components/BlockingViews/FullPageNotFoundView'; import withViewportOffsetTop from '../../components/withViewportOffsetTop'; import * as ReportActionsUtils from '../../libs/ReportActionsUtils'; -import personalDetailsPropType from '../personalDetailsPropType'; import getIsReportFullyVisible from '../../libs/getIsReportFullyVisible'; import MoneyRequestHeader from '../../components/MoneyRequestHeader'; import MoneyReportHeader from '../../components/MoneyReportHeader'; @@ -40,7 +39,7 @@ import usePrevious from '../../hooks/usePrevious'; import CONST from '../../CONST'; import withCurrentReportID, {withCurrentReportIDPropTypes, withCurrentReportIDDefaultProps} from '../../components/withCurrentReportID'; import reportWithoutHasDraftSelector from '../../libs/OnyxSelectors/reportWithoutHasDraftSelector'; -import { isPersonalDetailsEmpty } from '../../libs/PersonalDetailsUtils'; +import * as PersonalDetailsUtils from '../../libs/PersonalDetailsUtils'; const propTypes = { /** Navigation route context info provided by react navigation */ @@ -169,7 +168,7 @@ function ReportScreen({ const shouldHideReport = !ReportUtils.canAccessReport(report, policies, betas); - const isLoading = !reportID || !isSidebarLoaded || isPersonalDetailsEmpty(); + const isLoading = !reportID || !isSidebarLoaded || PersonalDetailsUtils.isPersonalDetailsEmpty(); const parentReportAction = ReportActionsUtils.getParentReportAction(report); const lastReportAction = useMemo( diff --git a/src/pages/home/report/ReportActionCompose/ReportActionCompose.js b/src/pages/home/report/ReportActionCompose/ReportActionCompose.js index dc515c2495ff..fa7dfc8418fa 100644 --- a/src/pages/home/report/ReportActionCompose/ReportActionCompose.js +++ b/src/pages/home/report/ReportActionCompose/ReportActionCompose.js @@ -32,7 +32,7 @@ import getModalState from '../../../../libs/getModalState'; import useWindowDimensions from '../../../../hooks/useWindowDimensions'; import * as EmojiPickerActions from '../../../../libs/actions/EmojiPickerAction'; import * as ReportActionsUtils from '../../../../libs/ReportActionsUtils'; -import {getPersonalDetailsByAccountID} from '../../../../libs/PersonalDetailsUtils'; +import * as PersonalDetailsUtils from '../../../../libs/PersonalDetailsUtils'; const propTypes = { /** A method to call when the form is submitted */ @@ -299,7 +299,7 @@ function ReportActionCompose({ ); const reportRecipientAcountIDs = ReportUtils.getReportRecipientAccountIDs(report, currentUserPersonalDetails.accountID); - const reportRecipient = getPersonalDetailsByAccountID(reportRecipientAcountIDs[0]); + const reportRecipient = PersonalDetailsUtils.getPersonalDetailsByAccountID(reportRecipientAcountIDs[0]); const shouldUseFocusedColor = !isBlockedFromConcierge && !disabled && isFocused; const hasReportRecipient = _.isObject(reportRecipient) && !_.isEmpty(reportRecipient); diff --git a/src/pages/home/report/ReportActionCompose/SuggestionMention.js b/src/pages/home/report/ReportActionCompose/SuggestionMention.js index 237b1e956966..0172bfe20038 100644 --- a/src/pages/home/report/ReportActionCompose/SuggestionMention.js +++ b/src/pages/home/report/ReportActionCompose/SuggestionMention.js @@ -11,7 +11,6 @@ import * as SuggestionsUtils from '../../../../libs/SuggestionUtils'; import useLocalize from '../../../../hooks/useLocalize'; import usePrevious from '../../../../hooks/usePrevious'; import ONYXKEYS from '../../../../ONYXKEYS'; -import personalDetailsPropType from '../../../personalDetailsPropType'; import * as SuggestionProps from './suggestionProps'; /** @@ -45,6 +44,7 @@ const defaultProps = { * hence we don't have to use it with `withOnyx`. */ let allPersonalDetails = {}; +// eslint-disable-next-line rulesdir/prefer-onyx-connect-in-libs Onyx.connect({ key: ONYXKEYS.PERSONAL_DETAILS_LIST, callback: (val) => { diff --git a/src/pages/home/report/ReportActionItem.js b/src/pages/home/report/ReportActionItem.js index 2697d4b5551d..7c955b0a88e3 100644 --- a/src/pages/home/report/ReportActionItem.js +++ b/src/pages/home/report/ReportActionItem.js @@ -28,7 +28,7 @@ import MiniReportActionContextMenu from './ContextMenu/MiniReportActionContextMe import * as ReportActionContextMenu from './ContextMenu/ReportActionContextMenu'; import * as ContextMenuActions from './ContextMenu/ContextMenuActions'; import * as EmojiPickerAction from '../../../libs/actions/EmojiPickerAction'; -import {usePersonalDetails, withBlockedFromConcierge, withNetwork, withReportActionsDrafts} from '../../../components/OnyxProvider'; +import {withBlockedFromConcierge, withNetwork, withReportActionsDrafts} from '../../../components/OnyxProvider'; import RenameAction from '../../../components/ReportActionItem/RenameAction'; import InlineSystemMessage from '../../../components/InlineSystemMessage'; import styles from '../../../styles/styles'; @@ -302,7 +302,6 @@ function ReportActionItem(props) { */ const renderItemContent = (hovered = false, isWhisper = false, hasErrors = false) => { let children; - const _submitterDisplayName = PersonalDetailsUtils.getDisplayNameOrDefault(null, [props.report.ownerAccountID, 'displayName'], props.report.ownerEmail); // Show the MoneyRequestPreview for when request was created, bill was split or money was sent if ( diff --git a/src/pages/home/report/ReportActionItemCreated.js b/src/pages/home/report/ReportActionItemCreated.js index 9b428bf90ea6..2e7bce92f053 100644 --- a/src/pages/home/report/ReportActionItemCreated.js +++ b/src/pages/home/report/ReportActionItemCreated.js @@ -5,7 +5,6 @@ import {withOnyx} from 'react-native-onyx'; import PropTypes from 'prop-types'; import ONYXKEYS from '../../../ONYXKEYS'; import ReportWelcomeText from '../../../components/ReportWelcomeText'; -import participantPropTypes from '../../../components/participantPropTypes'; import * as ReportUtils from '../../../libs/ReportUtils'; import styles from '../../../styles/styles'; import OfflineWithFeedback from '../../../components/OfflineWithFeedback'; diff --git a/src/pages/home/report/ReportActionItemSingle.js b/src/pages/home/report/ReportActionItemSingle.js index faa9b4c6fbbc..5450b457e53f 100644 --- a/src/pages/home/report/ReportActionItemSingle.js +++ b/src/pages/home/report/ReportActionItemSingle.js @@ -13,7 +13,6 @@ import compose from '../../../libs/compose'; import withLocalize, {withLocalizePropTypes} from '../../../components/withLocalize'; import Navigation from '../../../libs/Navigation/Navigation'; import ROUTES from '../../../ROUTES'; -import {usePersonalDetails} from '../../../components/OnyxProvider'; import ControlSelection from '../../../libs/ControlSelection'; import * as ReportUtils from '../../../libs/ReportUtils'; import OfflineWithFeedback from '../../../components/OfflineWithFeedback'; @@ -31,7 +30,7 @@ import ONYXKEYS from '../../../ONYXKEYS'; import Text from '../../../components/Text'; import Tooltip from '../../../components/Tooltip'; import DateUtils from '../../../libs/DateUtils'; -import { getPersonalDetailsByAccountID } from '../../../libs/PersonalDetailsUtils'; +import * as PersonalDetailsUtils from '../../../libs/PersonalDetailsUtils'; const propTypes = { /** All the data of the action */ @@ -85,22 +84,22 @@ const showWorkspaceDetails = (reportID) => { function ReportActionItemSingle(props) { const actorAccountID = props.action.actionName === CONST.REPORT.ACTIONS.TYPE.REPORTPREVIEW && props.iouReport ? props.iouReport.managerID : props.action.actorAccountID; - const personalDetails = getPersonalDetailsByAccountID(actorAccountID); - let {displayName} = personalDetails[actorAccountID] || {}; - const {avatar, login, pendingFields, status, fallbackIcon} = personalDetails[actorAccountID] || {}; + const personalDetails = PersonalDetailsUtils.getPersonalDetailsByAccountID(actorAccountID); + let {displayName} = personalDetails || {}; + const {avatar, login, pendingFields, status, fallbackIcon} = personalDetails || {}; let actorHint = (login || displayName || '').replace(CONST.REGEX.MERGED_ACCOUNT_PREFIX, ''); const displayAllActors = useMemo(() => props.action.actionName === CONST.REPORT.ACTIONS.TYPE.REPORTPREVIEW && props.iouReport, [props.action.actionName, props.iouReport]); const isWorkspaceActor = ReportUtils.isPolicyExpenseChat(props.report) && (!actorAccountID || displayAllActors); let avatarSource = UserUtils.getAvatar(avatar, actorAccountID); + const delegateDetails = PersonalDetailsUtils.getPersonalDetailsByAccountID(props.action.delegateAccountID); if (isWorkspaceActor) { displayName = ReportUtils.getPolicyName(props.report); actorHint = displayName; avatarSource = ReportUtils.getWorkspaceAvatar(props.report); - } else if (props.action.delegateAccountID && personalDetails[props.action.delegateAccountID]) { + } else if (props.action.delegateAccountID && delegateDetails) { // We replace the actor's email, name, and avatar with the Copilot manually for now. And only if we have their // details. This will be improved upon when the Copilot feature is implemented. - const delegateDetails = personalDetails[props.action.delegateAccountID]; const delegateDisplayName = delegateDetails.displayName; actorHint = `${delegateDisplayName} (${props.translate('reportAction.asCopilot')} ${displayName})`; displayName = actorHint; @@ -113,7 +112,7 @@ function ReportActionItemSingle(props) { if (displayAllActors) { // The ownerAccountID and actorAccountID can be the same if the a user requests money back from the IOU's original creator, in that case we need to use managerID to avoid displaying the same user twice const secondaryAccountId = props.iouReport.ownerAccountID === actorAccountID ? props.iouReport.managerID : props.iouReport.ownerAccountID; - const secondaryUserDetails = personalDetails[secondaryAccountId] || {}; + const secondaryUserDetails = PersonalDetailsUtils.getPersonalDetailsByAccountID(secondaryAccountId); const secondaryDisplayName = lodashGet(secondaryUserDetails, 'displayName', ''); displayName = `${primaryDisplayName} & ${secondaryDisplayName}`; secondaryAvatar = { diff --git a/src/pages/home/report/ReportActionsList.js b/src/pages/home/report/ReportActionsList.js index 6515dc652bdc..8127e40a3aa2 100644 --- a/src/pages/home/report/ReportActionsList.js +++ b/src/pages/home/report/ReportActionsList.js @@ -13,7 +13,6 @@ import useReportScrollManager from '../../../hooks/useReportScrollManager'; import DateUtils from '../../../libs/DateUtils'; import * as ReportUtils from '../../../libs/ReportUtils'; import * as Report from '../../../libs/actions/Report'; -import compose from '../../../libs/compose'; import styles from '../../../styles/styles'; import variables from '../../../styles/variables'; import reportPropTypes from '../../reportPropTypes'; @@ -72,6 +71,7 @@ const defaultProps = { isLoadingInitialReportActions: false, isLoadingOlderReportActions: false, isLoadingNewerReportActions: false, + policy: {} }; const VERTICAL_OFFSET_THRESHOLD = 200; @@ -428,4 +428,4 @@ ReportActionsList.propTypes = propTypes; ReportActionsList.defaultProps = defaultProps; ReportActionsList.displayName = 'ReportActionsList'; -export default compose(withWindowDimensions)(ReportActionsList); +export default withWindowDimensions(ReportActionsList); diff --git a/src/pages/home/report/ReportFooter.js b/src/pages/home/report/ReportFooter.js index 710eed2b86df..760f67dbc310 100644 --- a/src/pages/home/report/ReportFooter.js +++ b/src/pages/home/report/ReportFooter.js @@ -18,7 +18,6 @@ import reportActionPropTypes from './reportActionPropTypes'; import reportPropTypes from '../../reportPropTypes'; import * as ReportUtils from '../../../libs/ReportUtils'; import * as Session from '../../../libs/actions/Session'; -import participantPropTypes from '../../../components/participantPropTypes'; import * as Report from '../../../libs/actions/Report'; import useReportScrollManager from '../../../hooks/useReportScrollManager'; From 9562e8ca37be9b0dd961d9e6f7ea84df753f277a Mon Sep 17 00:00:00 2001 From: hurali97 Date: Fri, 27 Oct 2023 14:44:54 +0500 Subject: [PATCH 010/722] refactor: remove not needed code --- src/libs/PersonalDetailsUtils.js | 16 +++++++++- src/libs/actions/OnyxUpdates.ts | 29 +++++++++---------- src/libs/actions/PersistedRequests.ts | 19 +++++------- src/pages/home/ReportScreen.js | 3 +- .../report/ReportActionsListItemRenderer.js | 4 +++ src/pages/home/report/ReportActionsView.js | 7 ++++- src/pages/home/report/ReportFooter.js | 5 ++-- 7 files changed, 49 insertions(+), 34 deletions(-) diff --git a/src/libs/PersonalDetailsUtils.js b/src/libs/PersonalDetailsUtils.js index c2841b139422..acbdeca80a9d 100644 --- a/src/libs/PersonalDetailsUtils.js +++ b/src/libs/PersonalDetailsUtils.js @@ -176,14 +176,28 @@ function getFormattedAddress(privatePersonalDetails) { return formattedAddress.trim().replace(/,$/, ''); } +/** + * Get personal detail for an accountID + * @param {String} accountID + * @returns {PersonalDetail} personal detail object + */ function getPersonalDetailsByAccountID(accountID) { - return allPersonalDetails[accountID]; + return allPersonalDetails ? allPersonalDetails[accountID] : {}; } +/** + * Get whispered personal details for array of accountIDs + * @param {Array} whisperedToAccountIDs + * @returns {PersonalDetails} personal details + */ function getWhisperedToPersonalDetails(whisperedToAccountIDs) { return _.filter(allPersonalDetails, (details) => _.includes(whisperedToAccountIDs, details.accountID)); } +/** + * Whether personal details is empty + * @returns {Boolean} true if personal details is empty + */ function isPersonalDetailsEmpty() { return !personalDetails.length; } diff --git a/src/libs/actions/OnyxUpdates.ts b/src/libs/actions/OnyxUpdates.ts index 5f13d8133f16..39a20ae9362a 100644 --- a/src/libs/actions/OnyxUpdates.ts +++ b/src/libs/actions/OnyxUpdates.ts @@ -1,6 +1,5 @@ import Onyx, {OnyxEntry} from 'react-native-onyx'; import {Merge} from 'type-fest'; -import {InteractionManager} from 'react-native'; import PusherUtils from '../PusherUtils'; import ONYXKEYS from '../../ONYXKEYS'; import * as QueuedOnyxUpdates from './QueuedOnyxUpdates'; @@ -62,21 +61,19 @@ function apply({lastUpdateID, type, request, response, updates}: Merge | undefined { console.debug(`[OnyxUpdateManager] Applying update type: ${type} with lastUpdateID: ${lastUpdateID}`, {request, response, updates}); - InteractionManager.runAfterInteractions(() => { - if (lastUpdateID && lastUpdateIDAppliedToClient && Number(lastUpdateID) < lastUpdateIDAppliedToClient) { - console.debug('[OnyxUpdateManager] Update received was older than current state, returning without applying the updates'); - return Promise.resolve(); - } - if (lastUpdateID && (lastUpdateIDAppliedToClient === null || Number(lastUpdateID) > lastUpdateIDAppliedToClient)) { - Onyx.merge(ONYXKEYS.ONYX_UPDATES_LAST_UPDATE_ID_APPLIED_TO_CLIENT, Number(lastUpdateID)); - } - if (type === CONST.ONYX_UPDATE_TYPES.HTTPS && request && response) { - return applyHTTPSOnyxUpdates(request, response); - } - if (type === CONST.ONYX_UPDATE_TYPES.PUSHER && updates) { - return applyPusherOnyxUpdates(updates); - } - }); + if (lastUpdateID && lastUpdateIDAppliedToClient && Number(lastUpdateID) < lastUpdateIDAppliedToClient) { + console.debug('[OnyxUpdateManager] Update received was older than current state, returning without applying the updates'); + return Promise.resolve(); + } + if (lastUpdateID && (lastUpdateIDAppliedToClient === null || Number(lastUpdateID) > lastUpdateIDAppliedToClient)) { + Onyx.merge(ONYXKEYS.ONYX_UPDATES_LAST_UPDATE_ID_APPLIED_TO_CLIENT, Number(lastUpdateID)); + } + if (type === CONST.ONYX_UPDATE_TYPES.HTTPS && request && response) { + return applyHTTPSOnyxUpdates(request, response); + } + if (type === CONST.ONYX_UPDATE_TYPES.PUSHER && updates) { + return applyPusherOnyxUpdates(updates); + } } /** diff --git a/src/libs/actions/PersistedRequests.ts b/src/libs/actions/PersistedRequests.ts index 1e1a147cecd3..d9f4ed020109 100644 --- a/src/libs/actions/PersistedRequests.ts +++ b/src/libs/actions/PersistedRequests.ts @@ -1,6 +1,5 @@ import Onyx from 'react-native-onyx'; import isEqual from 'lodash/isEqual'; -import {InteractionManager} from 'react-native'; import ONYXKEYS from '../../ONYXKEYS'; import {Request} from '../../types/onyx'; @@ -34,16 +33,14 @@ function remove(requestToRemove: Request) { * We only remove the first matching request because the order of requests matters. * If we were to remove all matching requests, we can end up with a final state that is different than what the user intended. */ - InteractionManager.runAfterInteractions(() => { - const requests = [...persistedRequests]; - const index = requests.findIndex((persistedRequest) => isEqual(persistedRequest, requestToRemove)); - if (index === -1) { - return; - } - requests.splice(index, 1); - persistedRequests = requests; - Onyx.set(ONYXKEYS.PERSISTED_REQUESTS, requests); - }); + const requests = [...persistedRequests]; + const index = requests.findIndex((persistedRequest) => isEqual(persistedRequest, requestToRemove)); + if (index === -1) { + return; + } + requests.splice(index, 1); + persistedRequests = requests; + Onyx.set(ONYXKEYS.PERSISTED_REQUESTS, requests); } function update(oldRequestIndex: number, newRequest: Request) { diff --git a/src/pages/home/ReportScreen.js b/src/pages/home/ReportScreen.js index 76be144150c3..ed1fd91b9834 100644 --- a/src/pages/home/ReportScreen.js +++ b/src/pages/home/ReportScreen.js @@ -172,7 +172,7 @@ function ReportScreen({ const parentReportAction = ReportActionsUtils.getParentReportAction(report); const lastReportAction = useMemo( - () => _.find([...reportActions, parentReportAction], (action) => ReportUtils.canEditReportAction(action) && !ReportActionsUtils.isMoneyRequestAction(action)), + () => reportActions.length ? _.find([...reportActions, parentReportAction], (action) => ReportUtils.canEditReportAction(action) && !ReportActionsUtils.isMoneyRequestAction(action)) : {}, [reportActions, parentReportAction], ); const isSingleTransactionView = ReportUtils.isMoneyRequest(report); @@ -437,7 +437,6 @@ function ReportScreen({ ({ reportActionID: reportAction.reportActionID, diff --git a/src/pages/home/report/ReportActionsView.js b/src/pages/home/report/ReportActionsView.js index 415b8b6fbd1b..f1bd30f1a8b9 100755 --- a/src/pages/home/report/ReportActionsView.js +++ b/src/pages/home/report/ReportActionsView.js @@ -216,12 +216,17 @@ function ReportActionsView(props) { } }; + /** + * Create a lightweight Report so as to keep the re-rendering as light as possible by + * passing in only the required props. + */ const report = useMemo( () => ({ lastReadTime: props.report.lastReadTime, reportID: props.report.reportID, + policyID: props.report.policyID, }), - [props.report.lastReadTime, props.report.reportID], + [props.report.lastReadTime, props.report.reportID, props.report.policyID], ); // Comments have not loaded at all yet do nothing diff --git a/src/pages/home/report/ReportFooter.js b/src/pages/home/report/ReportFooter.js index 760f67dbc310..6f061cb3d015 100644 --- a/src/pages/home/report/ReportFooter.js +++ b/src/pages/home/report/ReportFooter.js @@ -85,7 +85,7 @@ function ReportFooter(props) { const onSubmitComment = useCallback( (text) => { - Report.addComment(props.reportID, text); + Report.addComment(props.report.reportID, text); // We need to scroll to the bottom of the list after the comment is added const refID = setTimeout(() => { @@ -119,7 +119,7 @@ function ReportFooter(props) { isEqual(prevProps.report, nextProps.report) && - isEqual(prevProps.reportActions, nextProps.reportActions) && prevProps.pendingAction === nextProps.pendingAction && prevProps.shouldDisableCompose === nextProps.shouldDisableCompose && prevProps.listHeight === nextProps.listHeight && From ad1b337ebc433635371547a8c8c8bbeeff800618 Mon Sep 17 00:00:00 2001 From: hurali97 Date: Fri, 27 Oct 2023 16:15:37 +0500 Subject: [PATCH 011/722] fix: linting and test --- src/libs/PersonalDetailsUtils.js | 2 +- .../report/ReportActionCompose/ComposerWithSuggestions.js | 2 ++ tests/unit/ReportActionItemSingleTest.js | 6 ++++-- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/libs/PersonalDetailsUtils.js b/src/libs/PersonalDetailsUtils.js index acbdeca80a9d..965f1b927095 100644 --- a/src/libs/PersonalDetailsUtils.js +++ b/src/libs/PersonalDetailsUtils.js @@ -178,7 +178,7 @@ function getFormattedAddress(privatePersonalDetails) { /** * Get personal detail for an accountID - * @param {String} accountID + * @param {Number} accountID * @returns {PersonalDetail} personal detail object */ function getPersonalDetailsByAccountID(accountID) { diff --git a/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions.js b/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions.js index 79c53650f27a..115cf404e589 100644 --- a/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions.js +++ b/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions.js @@ -283,6 +283,7 @@ function ComposerWithSuggestions({ debouncedBroadcastUserIsTyping(reportID); } }, + // eslint-disable-next-line react-hooks/exhaustive-deps [ preferredSkinTone, reportID, @@ -555,6 +556,7 @@ function ComposerWithSuggestions({ const onChangeText = useCallback((text) => { updateComment(text, true); + // eslint-disable-next-line react-hooks/exhaustive-deps }, []); return ( diff --git a/tests/unit/ReportActionItemSingleTest.js b/tests/unit/ReportActionItemSingleTest.js index d6b46eb55414..799f6363d778 100644 --- a/tests/unit/ReportActionItemSingleTest.js +++ b/tests/unit/ReportActionItemSingleTest.js @@ -1,5 +1,5 @@ import Onyx from 'react-native-onyx'; -import {cleanup, screen} from '@testing-library/react-native'; +import {cleanup, screen, waitFor} from '@testing-library/react-native'; import * as LHNTestUtils from '../utils/LHNTestUtils'; import waitForBatchedUpdates from '../utils/waitForBatchedUpdates'; import wrapOnyxWithWaitForBatchedUpdates from '../utils/wrapOnyxWithWaitForBatchedUpdates'; @@ -70,7 +70,9 @@ describe('ReportActionItemSingle', () => { const expectedSecondaryIconTestId = 'SvgDefaultAvatar_w Icon'; return setup().then(() => { - expect(screen.getByTestId(expectedSecondaryIconTestId)).toBeDefined(); + waitFor(() => { + expect(screen.getByTestId(expectedSecondaryIconTestId)).toBeDefined(); + }); }); }); From 9a27bede1cd7a13f7f61bc32afdc23e91113026b Mon Sep 17 00:00:00 2001 From: hurali97 Date: Fri, 27 Oct 2023 17:08:19 +0500 Subject: [PATCH 012/722] fix: failing unread indicator test --- tests/ui/UnreadIndicatorsTest.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/ui/UnreadIndicatorsTest.js b/tests/ui/UnreadIndicatorsTest.js index a9ffe258ac7f..34e2c0322cde 100644 --- a/tests/ui/UnreadIndicatorsTest.js +++ b/tests/ui/UnreadIndicatorsTest.js @@ -524,13 +524,12 @@ describe('Unread Indicators', () => { .then(() => { // Simulate the response from the server so that the comment can be deleted in this test lastReportAction = {...CollectionUtils.lastItem(reportActions)}; - Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT}${REPORT_ID}`, { + return Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT}${REPORT_ID}`, { lastMessageText: lastReportAction.message[0].text, lastVisibleActionCreated: DateUtils.getDBTime(lastReportAction.timestamp), lastActorAccountID: lastReportAction.actorAccountID, reportID: REPORT_ID, }); - return waitForBatchedUpdates(); }) .then(() => { // Verify the chat preview text matches the last comment from the current user From 9f294367e0293535250ba3857e9b121dd0a215b4 Mon Sep 17 00:00:00 2001 From: hurali97 Date: Fri, 27 Oct 2023 17:15:08 +0500 Subject: [PATCH 013/722] fix: prettier issues --- src/components/LHNOptionsList/OptionRowLHNData.js | 13 +------------ src/components/withCurrentUserPersonalDetails.tsx | 2 +- src/libs/PersonalDetailsUtils.js | 4 ++-- src/libs/SidebarUtils.ts | 2 +- src/pages/home/ReportScreen.js | 5 ++++- .../ReportActionCompose/ComposerWithSuggestions.js | 8 ++------ src/pages/home/report/ReportActionsList.js | 2 +- 7 files changed, 12 insertions(+), 24 deletions(-) diff --git a/src/components/LHNOptionsList/OptionRowLHNData.js b/src/components/LHNOptionsList/OptionRowLHNData.js index 2ddf8a687cfd..89142febf679 100644 --- a/src/components/LHNOptionsList/OptionRowLHNData.js +++ b/src/components/LHNOptionsList/OptionRowLHNData.js @@ -63,18 +63,7 @@ const defaultProps = { * The OptionRowLHN component is memoized, so it will only * re-render if the data really changed. */ -function OptionRowLHNData({ - isFocused, - fullReport, - reportActions, - preferredLocale, - comment, - policy, - receiptTransactions, - parentReportActions, - transaction, - ...propsToForward -}) { +function OptionRowLHNData({isFocused, fullReport, reportActions, preferredLocale, comment, policy, receiptTransactions, parentReportActions, transaction, ...propsToForward}) { const reportID = propsToForward.reportID; const parentReportAction = parentReportActions[fullReport.parentReportActionID]; diff --git a/src/components/withCurrentUserPersonalDetails.tsx b/src/components/withCurrentUserPersonalDetails.tsx index fa81c658bc78..a54f3f08c8b8 100644 --- a/src/components/withCurrentUserPersonalDetails.tsx +++ b/src/components/withCurrentUserPersonalDetails.tsx @@ -4,7 +4,7 @@ import getComponentDisplayName from '../libs/getComponentDisplayName'; import ONYXKEYS from '../ONYXKEYS'; import personalDetailsPropType from '../pages/personalDetailsPropType'; import type {PersonalDetails, Session} from '../types/onyx'; -import { getPersonalDetailsByAccountID } from '../libs/PersonalDetailsUtils'; +import {getPersonalDetailsByAccountID} from '../libs/PersonalDetailsUtils'; type CurrentUserPersonalDetails = PersonalDetails | Record; diff --git a/src/libs/PersonalDetailsUtils.js b/src/libs/PersonalDetailsUtils.js index 965f1b927095..930ba19ad77b 100644 --- a/src/libs/PersonalDetailsUtils.js +++ b/src/libs/PersonalDetailsUtils.js @@ -178,7 +178,7 @@ function getFormattedAddress(privatePersonalDetails) { /** * Get personal detail for an accountID - * @param {Number} accountID + * @param {Number} accountID * @returns {PersonalDetail} personal detail object */ function getPersonalDetailsByAccountID(accountID) { @@ -187,7 +187,7 @@ function getPersonalDetailsByAccountID(accountID) { /** * Get whispered personal details for array of accountIDs - * @param {Array} whisperedToAccountIDs + * @param {Array} whisperedToAccountIDs * @returns {PersonalDetails} personal details */ function getWhisperedToPersonalDetails(whisperedToAccountIDs) { diff --git a/src/libs/SidebarUtils.ts b/src/libs/SidebarUtils.ts index 6db4c5aa8241..c71548a483db 100644 --- a/src/libs/SidebarUtils.ts +++ b/src/libs/SidebarUtils.ts @@ -1,5 +1,5 @@ /* eslint-disable rulesdir/prefer-underscore-method */ -import Onyx, { OnyxEntry } from 'react-native-onyx'; +import Onyx, {OnyxEntry} from 'react-native-onyx'; import Str from 'expensify-common/lib/str'; import {ValueOf} from 'type-fest'; import ONYXKEYS from '../ONYXKEYS'; diff --git a/src/pages/home/ReportScreen.js b/src/pages/home/ReportScreen.js index ed1fd91b9834..31763e064c1d 100644 --- a/src/pages/home/ReportScreen.js +++ b/src/pages/home/ReportScreen.js @@ -172,7 +172,10 @@ function ReportScreen({ const parentReportAction = ReportActionsUtils.getParentReportAction(report); const lastReportAction = useMemo( - () => reportActions.length ? _.find([...reportActions, parentReportAction], (action) => ReportUtils.canEditReportAction(action) && !ReportActionsUtils.isMoneyRequestAction(action)) : {}, + () => + reportActions.length + ? _.find([...reportActions, parentReportAction], (action) => ReportUtils.canEditReportAction(action) && !ReportActionsUtils.isMoneyRequestAction(action)) + : {}, [reportActions, parentReportAction], ); const isSingleTransactionView = ReportUtils.isMoneyRequest(report); diff --git a/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions.js b/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions.js index 115cf404e589..26e33a08417e 100644 --- a/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions.js +++ b/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions.js @@ -284,11 +284,7 @@ function ComposerWithSuggestions({ } }, // eslint-disable-next-line react-hooks/exhaustive-deps - [ - preferredSkinTone, - reportID, - suggestionsRef, - ], + [preferredSkinTone, reportID, suggestionsRef], ); /** @@ -556,7 +552,7 @@ function ComposerWithSuggestions({ const onChangeText = useCallback((text) => { updateComment(text, true); - // eslint-disable-next-line react-hooks/exhaustive-deps + // eslint-disable-next-line react-hooks/exhaustive-deps }, []); return ( diff --git a/src/pages/home/report/ReportActionsList.js b/src/pages/home/report/ReportActionsList.js index 8127e40a3aa2..6945cf82d158 100644 --- a/src/pages/home/report/ReportActionsList.js +++ b/src/pages/home/report/ReportActionsList.js @@ -71,7 +71,7 @@ const defaultProps = { isLoadingInitialReportActions: false, isLoadingOlderReportActions: false, isLoadingNewerReportActions: false, - policy: {} + policy: {}, }; const VERTICAL_OFFSET_THRESHOLD = 200; From 352227f178903ec5efe723578c47a12b3ff2ed95 Mon Sep 17 00:00:00 2001 From: hurali97 Date: Fri, 27 Oct 2023 19:08:09 +0500 Subject: [PATCH 014/722] fix: failing test --- src/pages/home/report/ReportActionsView.js | 70 ++++------------------ tests/ui/UnreadIndicatorsTest.js | 20 ++++--- 2 files changed, 25 insertions(+), 65 deletions(-) diff --git a/src/pages/home/report/ReportActionsView.js b/src/pages/home/report/ReportActionsView.js index f1bd30f1a8b9..266ed6e2e346 100755 --- a/src/pages/home/report/ReportActionsView.js +++ b/src/pages/home/report/ReportActionsView.js @@ -116,7 +116,7 @@ function ReportActionsView(props) { // update ref with current network state prevNetworkRef.current = props.network; // eslint-disable-next-line react-hooks/exhaustive-deps - }, [props.network, props.report, isReportFullyVisible]); + }, [props.network, isReportFullyVisible]); useEffect(() => { const prevIsSmallScreenWidth = prevIsSmallScreenWidthRef.current; @@ -130,7 +130,7 @@ function ReportActionsView(props) { // update ref with current state prevIsSmallScreenWidthRef.current = props.isSmallScreenWidth; // eslint-disable-next-line react-hooks/exhaustive-deps - }, [props.isSmallScreenWidth, props.report, props.reportActions, isReportFullyVisible]); + }, [props.isSmallScreenWidth, props.reportActions, isReportFullyVisible]); useEffect(() => { // Ensures subscription event succeeds when the report/workspace room is created optimistically. @@ -142,7 +142,7 @@ function ReportActionsView(props) { Report.subscribeToReportTypingEvents(reportID); didSubscribeToReportTypingEvents.current = true; } - }, [props.report, didSubscribeToReportTypingEvents, reportID]); + }, [props.report.pendingFields, didSubscribeToReportTypingEvents, reportID]); /** * Retrieves the next set of report actions for the chat once we are nearing the end of what we are currently @@ -225,8 +225,9 @@ function ReportActionsView(props) { lastReadTime: props.report.lastReadTime, reportID: props.report.reportID, policyID: props.report.policyID, + lastVisibleActionCreated: props.report.lastVisibleActionCreated, }), - [props.report.lastReadTime, props.report.reportID, props.report.policyID], + [props.report.lastReadTime, props.report.reportID, props.report.policyID, props.report.lastVisibleActionCreated], ); // Comments have not loaded at all yet do nothing @@ -262,14 +263,6 @@ function arePropsEqual(oldProps, newProps) { return false; } - if (!_.isEqual(oldProps.report.pendingFields, newProps.report.pendingFields)) { - return false; - } - - if (!_.isEqual(oldProps.report.errorFields, newProps.report.errorFields)) { - return false; - } - if (lodashGet(oldProps.network, 'isOffline') !== lodashGet(newProps.network, 'isOffline')) { return false; } @@ -286,26 +279,14 @@ function arePropsEqual(oldProps, newProps) { return false; } - if (oldProps.report.lastReadTime !== newProps.report.lastReadTime) { - return false; - } - if (newProps.isSmallScreenWidth !== oldProps.isSmallScreenWidth) { return false; } - if (lodashGet(newProps.report, 'hasOutstandingIOU') !== lodashGet(oldProps.report, 'hasOutstandingIOU')) { - return false; - } - if (newProps.isComposerFullSize !== oldProps.isComposerFullSize) { return false; } - if (lodashGet(newProps.report, 'statusNum') !== lodashGet(oldProps.report, 'statusNum') || lodashGet(newProps.report, 'stateNum') !== lodashGet(oldProps.report, 'stateNum')) { - return false; - } - if (lodashGet(newProps, 'policy.avatar') !== lodashGet(oldProps, 'policy.avatar')) { return false; } @@ -314,39 +295,14 @@ function arePropsEqual(oldProps, newProps) { return false; } - if (lodashGet(newProps, 'report.reportName') !== lodashGet(oldProps, 'report.reportName')) { - return false; - } - - if (lodashGet(newProps, 'report.description') !== lodashGet(oldProps, 'report.description')) { - return false; - } - - if (lodashGet(newProps, 'report.managerID') !== lodashGet(oldProps, 'report.managerID')) { - return false; - } - - if (lodashGet(newProps, 'report.managerEmail') !== lodashGet(oldProps, 'report.managerEmail')) { - return false; - } - - if (lodashGet(newProps, 'report.total') !== lodashGet(oldProps, 'report.total')) { - return false; - } - - if (lodashGet(newProps, 'report.nonReimbursableTotal') !== lodashGet(oldProps, 'report.nonReimbursableTotal')) { - return false; - } - - if (lodashGet(newProps, 'report.writeCapability') !== lodashGet(oldProps, 'report.writeCapability')) { - return false; - } - - if (lodashGet(newProps, 'report.participantAccountIDs', 0) !== lodashGet(oldProps, 'report.participantAccountIDs', 0)) { - return false; - } - - return _.isEqual(lodashGet(newProps.report, 'icons', []), lodashGet(oldProps.report, 'icons', [])); + return ( + oldProps.report.lastReadTime === newProps.report.lastReadTime && + oldProps.report.reportID === newProps.report.reportID && + oldProps.report.policyID === newProps.report.policyID && + oldProps.report.lastVisibleActionCreated === newProps.report.lastVisibleActionCreated && + oldProps.report.isOptimisticReport === newProps.report.isOptimisticReport && + _.isEqual(oldProps.report.pendingFields, newProps.report.pendingFields) + ); } const MemoizedReportActionsView = React.memo(ReportActionsView, arePropsEqual); diff --git a/tests/ui/UnreadIndicatorsTest.js b/tests/ui/UnreadIndicatorsTest.js index 34e2c0322cde..0fdee8aa63f7 100644 --- a/tests/ui/UnreadIndicatorsTest.js +++ b/tests/ui/UnreadIndicatorsTest.js @@ -130,13 +130,15 @@ function signInAndGetAppWithUnreadChat() { // Render the App and sign in as a test user. render(); return waitForBatchedUpdatesWithAct() - .then(() => { - const hintText = Localize.translateLocal('loginForm.loginForm'); - const loginForm = screen.queryAllByLabelText(hintText); - expect(loginForm).toHaveLength(1); - - return TestHelper.signInWithTestUser(USER_A_ACCOUNT_ID, USER_A_EMAIL, undefined, undefined, 'A'); - }) + .then(() => + waitFor(() => { + const hintText = Localize.translateLocal('loginForm.loginForm'); + const loginForm = screen.queryAllByLabelText(hintText); + expect(loginForm).toHaveLength(1); + + return TestHelper.signInWithTestUser(USER_A_ACCOUNT_ID, USER_A_EMAIL, undefined, undefined, 'A'); + }), + ) .then(() => { User.subscribeToUserEvents(); return waitForBatchedUpdates(); @@ -524,12 +526,14 @@ describe('Unread Indicators', () => { .then(() => { // Simulate the response from the server so that the comment can be deleted in this test lastReportAction = {...CollectionUtils.lastItem(reportActions)}; - return Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT}${REPORT_ID}`, { + Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT}${REPORT_ID}`, { lastMessageText: lastReportAction.message[0].text, lastVisibleActionCreated: DateUtils.getDBTime(lastReportAction.timestamp), lastActorAccountID: lastReportAction.actorAccountID, reportID: REPORT_ID, }); + + return waitForBatchedUpdates(); }) .then(() => { // Verify the chat preview text matches the last comment from the current user From 3820a4561ad4464d85adfbbda493ff776c37f01f Mon Sep 17 00:00:00 2001 From: hurali97 Date: Mon, 6 Nov 2023 17:13:07 +0500 Subject: [PATCH 015/722] fix: reassure failures reported --- src/pages/home/ReportScreen.js | 22 ------------------- .../home/report/ReportActionItemSingle.js | 2 +- 2 files changed, 1 insertion(+), 23 deletions(-) diff --git a/src/pages/home/ReportScreen.js b/src/pages/home/ReportScreen.js index ceeae027f522..a2d76192820c 100644 --- a/src/pages/home/ReportScreen.js +++ b/src/pages/home/ReportScreen.js @@ -1,4 +1,3 @@ -import {useFocusEffect} from '@react-navigation/core'; import lodashGet from 'lodash/get'; import PropTypes from 'prop-types'; import React, {memo, useCallback, useEffect, useMemo, useRef, useState} from 'react'; @@ -20,13 +19,11 @@ import useLocalize from '@hooks/useLocalize'; import usePrevious from '@hooks/usePrevious'; import useWindowDimensions from '@hooks/useWindowDimensions'; import compose from '@libs/compose'; -import getIsReportFullyVisible from '@libs/getIsReportFullyVisible'; import Navigation from '@libs/Navigation/Navigation'; import reportWithoutHasDraftSelector from '@libs/OnyxSelectors/reportWithoutHasDraftSelector'; import * as PersonalDetailsUtils from '@libs/PersonalDetailsUtils'; import * as ReportActionsUtils from '@libs/ReportActionsUtils'; import * as ReportUtils from '@libs/ReportUtils'; -import Visibility from '@libs/Visibility'; import reportMetadataPropTypes from '@pages/reportMetadataPropTypes'; import reportPropTypes from '@pages/reportPropTypes'; import styles from '@styles/styles'; @@ -259,25 +256,6 @@ function ReportScreen({ Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(accountManagerReportID)); }, [accountManagerReportID]); - useFocusEffect( - useCallback(() => { - const unsubscribeVisibilityListener = Visibility.onVisibilityChange(() => { - const isTopMostReportID = Navigation.getTopmostReportId() === getReportID(route); - // If the report is not fully visible (AKA on small screen devices and LHR is open) or the report is optimistic (AKA not yet created) - // we don't need to call openReport - if (!getIsReportFullyVisible(isTopMostReportID) || report.isOptimisticReport) { - return; - } - - Report.openReport(report.reportID); - }); - - return () => unsubscribeVisibilityListener(); - // The effect should run only on the first focus to attach listener - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []), - ); - useEffect(() => { fetchReportIfNeeded(); ComposerActions.setShouldShowComposeInput(true); diff --git a/src/pages/home/report/ReportActionItemSingle.js b/src/pages/home/report/ReportActionItemSingle.js index 634db2793710..cab7011e88fe 100644 --- a/src/pages/home/report/ReportActionItemSingle.js +++ b/src/pages/home/report/ReportActionItemSingle.js @@ -112,7 +112,7 @@ function ReportActionItemSingle(props) { if (displayAllActors) { // The ownerAccountID and actorAccountID can be the same if the a user requests money back from the IOU's original creator, in that case we need to use managerID to avoid displaying the same user twice const secondaryAccountId = props.iouReport.ownerAccountID === actorAccountID ? props.iouReport.managerID : props.iouReport.ownerAccountID; - const secondaryUserDetails = PersonalDetailsUtils.getPersonalDetailsByAccountID(secondaryAccountId); + const secondaryUserDetails = PersonalDetailsUtils.getPersonalDetailsByAccountID(secondaryAccountId) || {}; const secondaryDisplayName = lodashGet(secondaryUserDetails, 'displayName', ''); displayName = `${primaryDisplayName} & ${secondaryDisplayName}`; secondaryAvatar = { From ddf53d3c22e832d8d1ebecff9d08d0626909d067 Mon Sep 17 00:00:00 2001 From: hurali97 Date: Tue, 7 Nov 2023 13:49:08 +0500 Subject: [PATCH 016/722] fix: reported reassure issues --- src/components/AttachmentModal.js | 23 ++++++- src/pages/home/ReportScreen.js | 1 - .../ReportActionCompose.js | 62 ++++++++++--------- src/pages/home/report/ReportFooter.js | 50 ++++++--------- 4 files changed, 75 insertions(+), 61 deletions(-) diff --git a/src/components/AttachmentModal.js b/src/components/AttachmentModal.js index 7fe342127272..8de07139e022 100755 --- a/src/components/AttachmentModal.js +++ b/src/components/AttachmentModal.js @@ -2,7 +2,7 @@ import Str from 'expensify-common/lib/str'; import lodashExtend from 'lodash/extend'; import lodashGet from 'lodash/get'; import PropTypes from 'prop-types'; -import React, {memo, useCallback, useEffect, useMemo, useRef, useState} from 'react'; +import React, {memo, useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState} from 'react'; import {Animated, Keyboard, View} from 'react-native'; import {withOnyx} from 'react-native-onyx'; import _ from 'underscore'; @@ -393,6 +393,14 @@ function AttachmentModal(props) { // eslint-disable-next-line react-hooks/exhaustive-deps }, [isAttachmentReceipt, props.parentReport, props.parentReportActions, props.policy, props.transaction]); + useImperativeHandle( + props.forwardedRef, + () => ({ + displayFileInModal: validateAndDisplayFileToUpload, + }), + [validateAndDisplayFileToUpload], + ); + return ( <> ( + +)); + +AttachmentModalWithRef.displayName = 'AttachmentModalWithRef'; + export default compose( withWindowDimensions, withLocalize, @@ -539,4 +558,4 @@ export default compose( key: ONYXKEYS.SESSION, }, }), -)(memo(AttachmentModal)); +)(memo(AttachmentModalWithRef)); diff --git a/src/pages/home/ReportScreen.js b/src/pages/home/ReportScreen.js index a2d76192820c..506e635b2336 100644 --- a/src/pages/home/ReportScreen.js +++ b/src/pages/home/ReportScreen.js @@ -419,7 +419,6 @@ function ReportScreen({ report={report} pendingAction={addWorkspaceRoomOrChatPendingAction} isComposerFullSize={isComposerFullSize} - policies={policies} listHeight={listHeight} isEmptyChat={isEmptyChat} lastReportAction={lastReportAction} diff --git a/src/pages/home/report/ReportActionCompose/ReportActionCompose.js b/src/pages/home/report/ReportActionCompose/ReportActionCompose.js index 420422534ba7..8b61aa0fa199 100644 --- a/src/pages/home/report/ReportActionCompose/ReportActionCompose.js +++ b/src/pages/home/report/ReportActionCompose/ReportActionCompose.js @@ -136,6 +136,7 @@ function ReportActionCompose({ const suggestionsRef = useRef(null); const composerRef = useRef(null); + const attachementModalRef = useRef(null); const reportParticipantIDs = useMemo( () => _.without(lodashGet(report, 'participantAccountIDs', []), currentUserPersonalDetails.accountID), @@ -316,6 +317,10 @@ function ReportActionCompose({ runOnJS(submitForm)(); }, [isSendDisabled, resetFullComposerSize, submitForm, isReportReadyForDisplay]); + const onDisplayFileInModal = () => { + attachementModalRef.current.displayFileInModal(); + }; + return ( @@ -339,6 +344,7 @@ function ReportActionCompose({ ]} > setIsAttachmentPreviewActive(true)} @@ -365,34 +371,6 @@ function ReportActionCompose({ onItemSelected={onItemSelected} actionButtonRef={actionButtonRef} /> - { if (isAttachmentPreviewActive) { @@ -405,6 +383,34 @@ function ReportActionCompose({ )} + { - // eslint-disable-next-line rulesdir/prefer-onyx-connect-in-libs - const connID = Onyx.connect({ - key: ONYXKEYS.SHOULD_SHOW_COMPOSE_INPUT, - callback: (val) => { - if (val === shouldShowComposeInput) { - return; - } - setShouldShowComposeInput(val); - }, - }); - - return () => { - Onyx.disconnect(connID); - }; - }, [shouldShowComposeInput]); - const onSubmitComment = useCallback( (text) => { Report.addComment(props.report.reportID, text); @@ -114,7 +95,7 @@ function ReportFooter(props) { )} )} - {!hideComposer && (shouldShowComposeInput || !props.isSmallScreenWidth) && ( + {!hideComposer && (props.shouldShowComposeInput || !props.isSmallScreenWidth) && ( @@ -139,14 +119,24 @@ ReportFooter.displayName = 'ReportFooter'; ReportFooter.propTypes = propTypes; ReportFooter.defaultProps = defaultProps; -export default withWindowDimensions( +export default compose( + withWindowDimensions, + withOnyx({ + shouldShowComposeInput: { + key: ONYXKEYS.SHOULD_SHOW_COMPOSE_INPUT, + }, + }), +)( memo( ReportFooter, (prevProps, nextProps) => isEqual(prevProps.report, nextProps.report) && prevProps.pendingAction === nextProps.pendingAction && - prevProps.shouldDisableCompose === nextProps.shouldDisableCompose && prevProps.listHeight === nextProps.listHeight && + prevProps.isComposerFullSize === nextProps.isComposerFullSize && + prevProps.isEmptyChat === nextProps.isEmptyChat && + prevProps.lastReportAction === nextProps.lastReportAction && + prevProps.shouldShowComposeInput === nextProps.shouldShowComposeInput && prevProps.isReportReadyForDisplay === nextProps.isReportReadyForDisplay, ), ); From 5e2f21f8b62472cb67715f5bcd5f26e9e2b70e0e Mon Sep 17 00:00:00 2001 From: hurali97 Date: Tue, 7 Nov 2023 14:26:07 +0500 Subject: [PATCH 017/722] fix: reported reassure issues --- src/components/LHNOptionsList/LHNOptionsList.js | 14 +------------- .../ComposerWithSuggestions.js | 2 +- 2 files changed, 2 insertions(+), 14 deletions(-) diff --git a/src/components/LHNOptionsList/LHNOptionsList.js b/src/components/LHNOptionsList/LHNOptionsList.js index 3986773aca87..2603c0128af3 100644 --- a/src/components/LHNOptionsList/LHNOptionsList.js +++ b/src/components/LHNOptionsList/LHNOptionsList.js @@ -4,10 +4,8 @@ import React, {useCallback} from 'react'; import {FlatList, View} from 'react-native'; import {withOnyx} from 'react-native-onyx'; import _ from 'underscore'; -import participantPropTypes from '@components/participantPropTypes'; import withCurrentReportID, {withCurrentReportIDDefaultProps, withCurrentReportIDPropTypes} from '@components/withCurrentReportID'; import compose from '@libs/compose'; -import * as OptionsListUtils from '@libs/OptionsListUtils'; import reportActionPropTypes from '@pages/home/report/reportActionPropTypes'; import reportPropTypes from '@pages/reportPropTypes'; import styles from '@styles/styles'; @@ -56,9 +54,6 @@ const propTypes = { /** Indicates which locale the user currently has selected */ preferredLocale: PropTypes.string, - /** List of users' personal details */ - personalDetails: PropTypes.objectOf(participantPropTypes), - /** The transaction from the parent report action */ transactions: PropTypes.objectOf( PropTypes.shape({ @@ -78,7 +73,6 @@ const defaultProps = { reports: {}, policy: {}, preferredLocale: CONST.LOCALES.DEFAULT, - personalDetails: {}, transactions: {}, draftComments: {}, ...withCurrentReportIDDefaultProps, @@ -97,7 +91,6 @@ function LHNOptionsList({ reportActions, policy, preferredLocale, - personalDetails, transactions, draftComments, currentReportID, @@ -144,7 +137,6 @@ function LHNOptionsList({ '', )}`; const itemComment = draftComments[`${ONYXKEYS.COLLECTION.REPORT_DRAFT_COMMENT}${reportID}`] || ''; - const participantPersonalDetailList = _.values(OptionsListUtils.getPersonalDetailsForAccountIDs(itemFullReport.participantAccountIDs, personalDetails)); return ( ); }, - [currentReportID, draftComments, onSelectRow, optionMode, personalDetails, policy, preferredLocale, reportActions, reports, shouldDisableFocusOptions, transactions], + [currentReportID, draftComments, onSelectRow, optionMode, policy, preferredLocale, reportActions, reports, shouldDisableFocusOptions, transactions], ); return ( @@ -206,9 +197,6 @@ export default compose( preferredLocale: { key: ONYXKEYS.NVP_PREFERRED_LOCALE, }, - personalDetails: { - key: ONYXKEYS.PERSONAL_DETAILS_LIST, - }, transactions: { key: ONYXKEYS.COLLECTION.TRANSACTION, }, diff --git a/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions/ComposerWithSuggestions.js b/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions/ComposerWithSuggestions.js index cf772230d2bf..7c5d0cfe2f2a 100644 --- a/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions/ComposerWithSuggestions.js +++ b/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions/ComposerWithSuggestions.js @@ -29,6 +29,7 @@ import * as SuggestionUtils from '@libs/SuggestionUtils'; import updateMultilineInputRange from '@libs/UpdateMultilineInputRange'; import updatePropsPaperWorklet from '@libs/updatePropsPaperWorklet'; import willBlurTextInputOnTapOutsideFunc from '@libs/willBlurTextInputOnTapOutside'; +import SendButton from '@pages/home/report/ReportActionCompose/SendButton'; import SilentCommentUpdater from '@pages/home/report/ReportActionCompose/SilentCommentUpdater'; import Suggestions from '@pages/home/report/ReportActionCompose/Suggestions'; import containerComposeStyles from '@styles/containerComposeStyles'; @@ -40,7 +41,6 @@ import * as Report from '@userActions/Report'; import * as User from '@userActions/User'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; -import SendButton from '@pages/home/report/ReportActionCompose/SendButton'; import {defaultProps, propTypes} from './composerWithSuggestionsProps'; const {RNTextInputReset} = NativeModules; From 46c9d60399162fb2f2ff30ac5edd9760d2d0e159 Mon Sep 17 00:00:00 2001 From: hurali97 Date: Mon, 13 Nov 2023 13:54:36 +0500 Subject: [PATCH 018/722] fix: pr review --- src/components/ArchivedReportFooter.js | 6 ++--- src/components/AttachmentModal.js | 20 ++++------------ src/components/AvatarWithDisplayName.js | 2 +- src/libs/OptionsListUtils.js | 11 +++++++-- src/libs/PersonalDetailsUtils.js | 15 +++++++++--- src/libs/ReportUtils.js | 6 ++--- src/libs/SidebarUtils.ts | 4 ++-- src/libs/actions/Task.js | 2 +- src/pages/ReportDetailsPage.js | 2 +- .../AttachmentPickerWithMenuItems.js | 3 ++- .../composerWithSuggestionsProps.js | 3 ++- .../ReportActionCompose/SuggestionMention.js | 24 ++++++------------- src/pages/home/report/ReportActionItem.js | 2 +- src/pages/home/report/ReportFooter.js | 2 ++ 14 files changed, 51 insertions(+), 51 deletions(-) diff --git a/src/components/ArchivedReportFooter.js b/src/components/ArchivedReportFooter.js index a17cdb92136d..8c790f106ae7 100644 --- a/src/components/ArchivedReportFooter.js +++ b/src/components/ArchivedReportFooter.js @@ -46,14 +46,14 @@ const defaultProps = { function ArchivedReportFooter(props) { const archiveReason = lodashGet(props.reportClosedAction, 'originalMessage.reason', CONST.REPORT.ARCHIVE_REASON.DEFAULT); - let displayName = PersonalDetailsUtils.getDisplayNameOrDefault(null, [props.report.ownerAccountID, 'displayName']); + let displayName = PersonalDetailsUtils.getDisplayNameOrDefault([props.report.ownerAccountID, 'displayName']); let oldDisplayName; if (archiveReason === CONST.REPORT.ARCHIVE_REASON.ACCOUNT_MERGED) { const newAccountID = props.reportClosedAction.originalMessage.newAccountID; const oldAccountID = props.reportClosedAction.originalMessage.oldAccountID; - displayName = PersonalDetailsUtils.getDisplayNameOrDefault(null, [newAccountID, 'displayName']); - oldDisplayName = PersonalDetailsUtils.getDisplayNameOrDefault(null, [oldAccountID, 'displayName']); + displayName = PersonalDetailsUtils.getDisplayNameOrDefault([newAccountID, 'displayName']); + oldDisplayName = PersonalDetailsUtils.getDisplayNameOrDefault([oldAccountID, 'displayName']); } const shouldRenderHTML = archiveReason !== CONST.REPORT.ARCHIVE_REASON.DEFAULT; diff --git a/src/components/AttachmentModal.js b/src/components/AttachmentModal.js index 24ac0421c5b2..57ed1ff3e131 100755 --- a/src/components/AttachmentModal.js +++ b/src/components/AttachmentModal.js @@ -2,7 +2,7 @@ import Str from 'expensify-common/lib/str'; import lodashExtend from 'lodash/extend'; import lodashGet from 'lodash/get'; import PropTypes from 'prop-types'; -import React, {memo, useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState} from 'react'; +import React, {forwardRef, memo, useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState} from 'react'; import {Animated, Keyboard, View} from 'react-native'; import {withOnyx} from 'react-native-onyx'; import _ from 'underscore'; @@ -110,7 +110,7 @@ const defaultProps = { isWorkspaceAvatar: false, }; -function AttachmentModal(props) { +const AttachmentModal = forwardRef((props, ref) => { const onModalHideCallbackRef = useRef(null); const [isModalOpen, setIsModalOpen] = useState(props.defaultOpen); const [shouldLoadAttachment, setShouldLoadAttachment] = useState(false); @@ -394,7 +394,7 @@ function AttachmentModal(props) { }, [isAttachmentReceipt, props.parentReport, props.parentReportActions, props.policy, props.transaction, file]); useImperativeHandle( - props.forwardedRef, + ref, () => ({ displayFileInModal: validateAndDisplayFileToUpload, }), @@ -514,22 +514,12 @@ function AttachmentModal(props) { })} ); -} +}); AttachmentModal.propTypes = propTypes; AttachmentModal.defaultProps = defaultProps; AttachmentModal.displayName = 'AttachmentModal'; -const AttachmentModalWithRef = React.forwardRef((props, ref) => ( - -)); - -AttachmentModalWithRef.displayName = 'AttachmentModalWithRef'; - export default compose( withWindowDimensions, withLocalize, @@ -558,4 +548,4 @@ export default compose( key: ONYXKEYS.SESSION, }, }), -)(memo(AttachmentModalWithRef)); +)(memo(AttachmentModal)); diff --git a/src/components/AvatarWithDisplayName.js b/src/components/AvatarWithDisplayName.js index 4be31b7d1a45..194a9239fa57 100644 --- a/src/components/AvatarWithDisplayName.js +++ b/src/components/AvatarWithDisplayName.js @@ -88,7 +88,7 @@ function AvatarWithDisplayName(props) { const subtitle = ReportUtils.getChatRoomSubtitle(props.report); const parentNavigationSubtitleData = ReportUtils.getParentNavigationSubtitle(props.report); const isMoneyRequestOrReport = ReportUtils.isMoneyRequestReport(props.report) || ReportUtils.isMoneyRequest(props.report); - const icons = ReportUtils.getIcons(props.report, null, props.policy); + const icons = ReportUtils.getIcons(props.report, null, '', -1, props.policy); const ownerPersonalDetails = OptionsListUtils.getPersonalDetailsForAccountIDs([props.report.ownerAccountID]); const displayNamesWithTooltips = ReportUtils.getDisplayNamesWithTooltips(_.values(ownerPersonalDetails), false); const shouldShowSubscriptAvatar = ReportUtils.shouldReportShowSubscript(props.report); diff --git a/src/libs/OptionsListUtils.js b/src/libs/OptionsListUtils.js index 485bfbbbf08d..6d5588548636 100644 --- a/src/libs/OptionsListUtils.js +++ b/src/libs/OptionsListUtils.js @@ -529,7 +529,7 @@ function createOption(accountIDs, personalDetails, report, reportActions = {}, { (lastReportActions[report.reportID] && lastReportActions[report.reportID].originalMessage && lastReportActions[report.reportID].originalMessage.reason) || CONST.REPORT.ARCHIVE_REASON.DEFAULT; lastMessageText = Localize.translate(preferredLocale, `reportArchiveReasons.${archiveReason}`, { - displayName: archiveReason.displayName || PersonalDetailsUtils.getDisplayNameOrDefault(lastActorDetails, 'displayName'), + displayName: archiveReason.displayName || PersonalDetailsUtils.getDisplayNameOrDefault('displayName', lastActorDetails), policyName: ReportUtils.getPolicyName(report), }); } @@ -561,7 +561,14 @@ function createOption(accountIDs, personalDetails, report, reportActions = {}, { result.text = reportName; result.searchText = getSearchText(report, reportName, personalDetailList, result.isChatRoom || result.isPolicyExpenseChat, result.isThread); - result.icons = ReportUtils.getIcons(report, personalDetails, UserUtils.getAvatar(personalDetail.avatar, personalDetail.accountID), personalDetail.login, personalDetail.accountID); + result.icons = ReportUtils.getIcons( + report, + UserUtils.getAvatar(personalDetail.avatar, personalDetail.accountID), + personalDetail.login, + personalDetail.accountID, + undefined, + personalDetails, + ); result.subtitle = subtitle; return result; diff --git a/src/libs/PersonalDetailsUtils.js b/src/libs/PersonalDetailsUtils.js index 842c06bb3228..bbcfd53454a9 100644 --- a/src/libs/PersonalDetailsUtils.js +++ b/src/libs/PersonalDetailsUtils.js @@ -17,13 +17,13 @@ Onyx.connect({ }); /** - * @param {Object | Null} passedPersonalDetails * @param {Array | String} pathToDisplayName * @param {String} [defaultValue] optional default display name value + * @param {Object | Null} passedPersonalDetails optional default personal details object * @returns {String} */ -function getDisplayNameOrDefault(passedPersonalDetails, pathToDisplayName, defaultValue = '') { - const displayName = lodashGet(passedPersonalDetails || allPersonalDetails, pathToDisplayName); +function getDisplayNameOrDefault(pathToDisplayName, defaultValue = '', passedPersonalDetails = allPersonalDetails) { + const displayName = lodashGet(passedPersonalDetails, pathToDisplayName); return displayName || defaultValue || Localize.translateLocal('common.hidden'); } @@ -203,6 +203,14 @@ function isPersonalDetailsEmpty() { return !personalDetails.length; } +/** + * Get personal details object + * @returns {PersonalDetail} personal detail object + */ +function getPersonalDetails() { + return allPersonalDetails || {}; +} + export { getDisplayNameOrDefault, getPersonalDetailsByIDs, @@ -213,4 +221,5 @@ export { getPersonalDetailsByAccountID, getWhisperedToPersonalDetails, isPersonalDetailsEmpty, + getPersonalDetails, }; diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index 83cf62f6da04..38846dce5bc0 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -1103,15 +1103,15 @@ function getWorkspaceIcon(report, policy = undefined) { * The Avatar sources can be URLs or Icon components according to the chat type. * * @param {Object} report - * @param {Object} passedPersonalDetails * @param {*} [defaultIcon] * @param {String} [defaultName] * @param {Number} [defaultAccountID] * @param {Object} [policy] + * @param {Object} passedPersonalDetails * @returns {Array<*>} */ -function getIcons(report, passedPersonalDetails, defaultIcon = null, defaultName = '', defaultAccountID = -1, policy = undefined) { - const personalDetails = passedPersonalDetails || allPersonalDetails; +function getIcons(report, defaultIcon = null, defaultName = '', defaultAccountID = -1, policy = undefined, passedPersonalDetails = allPersonalDetails) { + const personalDetails = passedPersonalDetails; if (_.isEmpty(report)) { const fallbackIcon = { source: defaultIcon || Expensicons.FallbackAvatar, diff --git a/src/libs/SidebarUtils.ts b/src/libs/SidebarUtils.ts index 97ae1d25cdd9..826db3995c43 100644 --- a/src/libs/SidebarUtils.ts +++ b/src/libs/SidebarUtils.ts @@ -425,7 +425,7 @@ function getOptionData( case CONST.REPORT.ARCHIVE_REASON.POLICY_DELETED: { lastMessageText = Localize.translate(preferredLocale, `reportArchiveReasons.${archiveReason}`, { policyName: ReportUtils.getPolicyName(report, false, policy), - displayName: PersonalDetailsUtils.getDisplayNameOrDefault(lastActorDetails, 'displayName'), + displayName: PersonalDetailsUtils.getDisplayNameOrDefault('displayName', '', lastActorDetails), }); break; } @@ -515,7 +515,7 @@ function getOptionData( result.subtitle = subtitle; result.participantsList = participantPersonalDetailList; - result.icons = ReportUtils.getIcons(report, personalDetails, UserUtils.getAvatar(personalDetail.avatar, personalDetail.accountID), '', -1, policy); + result.icons = ReportUtils.getIcons(report, UserUtils.getAvatar(personalDetail.avatar, personalDetail.accountID), '', -1, policy, personalDetails); result.searchText = OptionsListUtils.getSearchText(report, reportName, participantPersonalDetailList, result.isChatRoom || result.isPolicyExpenseChat, result.isThread); result.displayNamesWithTooltips = displayNamesWithTooltips; diff --git a/src/libs/actions/Task.js b/src/libs/actions/Task.js index e884a4d7a6b3..6329552d67e2 100644 --- a/src/libs/actions/Task.js +++ b/src/libs/actions/Task.js @@ -699,7 +699,7 @@ function getShareDestination(reportID, reports, personalDetails) { subtitle = ReportUtils.getChatRoomSubtitle(report); } return { - icons: ReportUtils.getIcons(report, personalDetails, Expensicons.FallbackAvatar), + icons: ReportUtils.getIcons(report, Expensicons.FallbackAvatar, '', -1, undefined, personalDetails), displayName: ReportUtils.getReportName(report), subtitle, displayNamesWithTooltips, diff --git a/src/pages/ReportDetailsPage.js b/src/pages/ReportDetailsPage.js index de25fdc3a081..935074462966 100644 --- a/src/pages/ReportDetailsPage.js +++ b/src/pages/ReportDetailsPage.js @@ -163,7 +163,7 @@ function ReportDetailsPage(props) { return ReportUtils.getDisplayNamesWithTooltips(OptionsListUtils.getPersonalDetailsForAccountIDs(participants, props.personalDetails), hasMultipleParticipants); }, [participants, props.personalDetails]); - const icons = useMemo(() => ReportUtils.getIcons(props.report, props.personalDetails, props.policies), [props.report, props.personalDetails, props.policies]); + const icons = useMemo(() => ReportUtils.getIcons(props.report, null, '', -1, props.policies, props.personalDetails), [props.report, props.personalDetails, props.policies]); const chatRoomSubtitleText = chatRoomSubtitle ? ( {}, + disabled: false, }; export {propTypes, defaultProps}; diff --git a/src/pages/home/report/ReportActionCompose/SuggestionMention.js b/src/pages/home/report/ReportActionCompose/SuggestionMention.js index 6d85a0c349de..513e161dda41 100644 --- a/src/pages/home/report/ReportActionCompose/SuggestionMention.js +++ b/src/pages/home/report/ReportActionCompose/SuggestionMention.js @@ -1,16 +1,15 @@ import PropTypes from 'prop-types'; import React, {useCallback, useEffect, useImperativeHandle, useRef, useState} from 'react'; -import Onyx from 'react-native-onyx'; import _ from 'underscore'; import * as Expensicons from '@components/Icon/Expensicons'; import MentionSuggestions from '@components/MentionSuggestions'; import useArrowKeyFocusManager from '@hooks/useArrowKeyFocusManager'; import useLocalize from '@hooks/useLocalize'; import usePrevious from '@hooks/usePrevious'; +import * as PersonalDetailsUtils from '@libs/PersonalDetailsUtils'; import * as SuggestionsUtils from '@libs/SuggestionUtils'; import * as UserUtils from '@libs/UserUtils'; import CONST from '@src/CONST'; -import ONYXKEYS from '@src/ONYXKEYS'; import * as SuggestionProps from './suggestionProps'; /** @@ -38,20 +37,6 @@ const defaultProps = { forwardedRef: null, }; -/** - * We only need the personalDetails once because as long as the - * user is in the ReportScreen, these details won't be changing, - * hence we don't have to use it with `withOnyx`. - */ -let allPersonalDetails = {}; -// eslint-disable-next-line rulesdir/prefer-onyx-connect-in-libs -Onyx.connect({ - key: ONYXKEYS.PERSONAL_DETAILS_LIST, - callback: (val) => { - allPersonalDetails = val; - }, -}); - function SuggestionMention({ value, setValue, @@ -65,7 +50,12 @@ function SuggestionMention({ measureParentContainer, isComposerFocused, }) { - const personalDetails = allPersonalDetails; + /** + * We only need the personalDetails once because as long as the + * user is in the ReportScreen, these details won't be changing, + * hence we don't have to use it with `withOnyx`. + */ + const personalDetails = PersonalDetailsUtils.getPersonalDetails(); const {translate} = useLocalize(); const previousValue = usePrevious(value); const [suggestionValues, setSuggestionValues] = useState(defaultSuggestionsValues); diff --git a/src/pages/home/report/ReportActionItem.js b/src/pages/home/report/ReportActionItem.js index fe150be8db90..6c056c1b2527 100644 --- a/src/pages/home/report/ReportActionItem.js +++ b/src/pages/home/report/ReportActionItem.js @@ -365,7 +365,7 @@ function ReportActionItem(props) { ); } else if (props.action.actionName === CONST.REPORT.ACTIONS.TYPE.REIMBURSEMENTQUEUED) { - const submitterDisplayName = PersonalDetailsUtils.getDisplayNameOrDefault(null, [props.report.ownerAccountID, 'displayName']); + const submitterDisplayName = PersonalDetailsUtils.getDisplayNameOrDefault([props.report.ownerAccountID, 'displayName']); const paymentType = lodashGet(props.action, 'originalMessage.paymentType', ''); const isSubmitterOfUnsettledReport = ReportUtils.isCurrentUserSubmitter(props.report.reportID) && !ReportUtils.isSettled(props.report.reportID); diff --git a/src/pages/home/report/ReportFooter.js b/src/pages/home/report/ReportFooter.js index b407605a1c5d..d9490e17a688 100644 --- a/src/pages/home/report/ReportFooter.js +++ b/src/pages/home/report/ReportFooter.js @@ -137,6 +137,8 @@ export default compose( prevProps.isEmptyChat === nextProps.isEmptyChat && prevProps.lastReportAction === nextProps.lastReportAction && prevProps.shouldShowComposeInput === nextProps.shouldShowComposeInput && + prevProps.windowWidth === nextProps.windowWidth && + prevProps.isSmallScreenWidth === nextProps.isSmallScreenWidth && prevProps.isReportReadyForDisplay === nextProps.isReportReadyForDisplay, ), ); From 83d823ef9a37a5214319e54a41733d61061928ec Mon Sep 17 00:00:00 2001 From: hurali97 Date: Thu, 16 Nov 2023 12:16:32 +0500 Subject: [PATCH 019/722] fix: add default value --- src/libs/OptionsListUtils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/OptionsListUtils.js b/src/libs/OptionsListUtils.js index fc306a1f31bf..37b2e0add4ab 100644 --- a/src/libs/OptionsListUtils.js +++ b/src/libs/OptionsListUtils.js @@ -514,7 +514,7 @@ function createOption(accountIDs, personalDetails, report, reportActions = {}, { (lastReportActions[report.reportID] && lastReportActions[report.reportID].originalMessage && lastReportActions[report.reportID].originalMessage.reason) || CONST.REPORT.ARCHIVE_REASON.DEFAULT; lastMessageText = Localize.translate(preferredLocale, `reportArchiveReasons.${archiveReason}`, { - displayName: archiveReason.displayName || PersonalDetailsUtils.getDisplayNameOrDefault('displayName', lastActorDetails), + displayName: archiveReason.displayName || PersonalDetailsUtils.getDisplayNameOrDefault('displayName', '', lastActorDetails), policyName: ReportUtils.getPolicyName(report), }); } From 68a40f865bb0d47e1689eb6b4c11d671fb551e4d Mon Sep 17 00:00:00 2001 From: Jakub Kosmydel <104823336+kosmydel@users.noreply.github.com> Date: Tue, 21 Nov 2023 12:34:45 +0100 Subject: [PATCH 020/722] add test navigator --- src/NAVIGATORS.ts | 1 + src/ROUTES.ts | 1 + src/SCREENS.ts | 1 + .../Navigation/AppNavigator/AuthScreens.js | 6 ++++ .../Navigators/SettingsNavigator.js | 36 +++++++++++++++++++ src/libs/Navigation/linkingConfig.js | 6 ++++ .../FloatingActionButtonAndPopover.js | 8 ++--- 7 files changed, 54 insertions(+), 5 deletions(-) create mode 100644 src/libs/Navigation/AppNavigator/Navigators/SettingsNavigator.js diff --git a/src/NAVIGATORS.ts b/src/NAVIGATORS.ts index a3a041e65684..52480d874d7b 100644 --- a/src/NAVIGATORS.ts +++ b/src/NAVIGATORS.ts @@ -5,5 +5,6 @@ export default { CENTRAL_PANE_NAVIGATOR: 'CentralPaneNavigator', RIGHT_MODAL_NAVIGATOR: 'RightModalNavigator', + SETTINGS_NAVIGATOR: 'Settings_Navigator', FULL_SCREEN_NAVIGATOR: 'FullScreenNavigator', } as const; diff --git a/src/ROUTES.ts b/src/ROUTES.ts index 57d4eb8187ec..bd5f6cc422b3 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -58,6 +58,7 @@ export default { }, SETTINGS: 'settings', + SETTINGS_NEW: 'settings_new', SETTINGS_PROFILE: 'settings/profile', SETTINGS_SHARE_CODE: 'settings/shareCode', SETTINGS_DISPLAY_NAME: 'settings/profile/display-name', diff --git a/src/SCREENS.ts b/src/SCREENS.ts index afc368858f55..f18fb49dff80 100644 --- a/src/SCREENS.ts +++ b/src/SCREENS.ts @@ -16,6 +16,7 @@ export default { NOT_FOUND: 'not-found', TRANSITION_BETWEEN_APPS: 'TransitionBetweenApps', VALIDATE_LOGIN: 'ValidateLogin', + SETTINGS_NEW: 'SettingsNew', SETTINGS: { ROOT: 'Settings_Root', PREFERENCES: 'Settings_Preferences', diff --git a/src/libs/Navigation/AppNavigator/AuthScreens.js b/src/libs/Navigation/AppNavigator/AuthScreens.js index aedb2fa8d741..52a7f0c41afe 100644 --- a/src/libs/Navigation/AppNavigator/AuthScreens.js +++ b/src/libs/Navigation/AppNavigator/AuthScreens.js @@ -35,6 +35,7 @@ import defaultScreenOptions from './defaultScreenOptions'; import getRootNavigatorScreenOptions from './getRootNavigatorScreenOptions'; import CentralPaneNavigator from './Navigators/CentralPaneNavigator'; import RightModalNavigator from './Navigators/RightModalNavigator'; +import SettingsNavigator from './Navigators/SettingsNavigator'; const loadReportAttachments = () => require('../../../pages/home/report/ReportAttachments').default; const loadSidebarScreen = () => require('../../../pages/home/sidebar/SidebarScreen').default; @@ -335,6 +336,11 @@ function AuthScreens({isUsingMemoryOnlyKeys, lastUpdateIDAppliedToClient, sessio component={RightModalNavigator} listeners={modalScreenListeners} /> + + + + + + ); +} + +SettingsNavigator.propTypes = propTypes; +SettingsNavigator.displayName = 'SettingsNavigator'; + +export default SettingsNavigator; diff --git a/src/libs/Navigation/linkingConfig.js b/src/libs/Navigation/linkingConfig.js index 44473998ac62..4137260e2390 100644 --- a/src/libs/Navigation/linkingConfig.js +++ b/src/libs/Navigation/linkingConfig.js @@ -429,6 +429,12 @@ export default { }, }, }, + + [NAVIGATORS.SETTINGS_NAVIGATOR]: { + screens: { + [SCREENS.SETTINGS_NEW]: ROUTES.SETTINGS_NEW, + } + } }, }, }; diff --git a/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.js b/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.js index 739f7e3e0295..1eebf43d8a0a 100644 --- a/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.js +++ b/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.js @@ -243,11 +243,9 @@ function FloatingActionButtonAndPopover(props) { isActive={isCreateMenuActive} ref={anchorRef} onPress={() => { - if (isCreateMenuActive) { - hideCreateMenu(); - } else { - showCreateMenu(); - } + console.log('FloatingActionButtonAndPopover.js: showCreateMenu()'); + // navigate to new screen + Navigation.navigate(ROUTES.SETTINGS_NEW); }} /> From bddaa69fad1bfc22d4cd5afe66e38c7ebba4003e Mon Sep 17 00:00:00 2001 From: Jakub Kosmydel <104823336+kosmydel@users.noreply.github.com> Date: Tue, 21 Nov 2023 13:43:00 +0100 Subject: [PATCH 021/722] draft --- src/ROUTES.ts | 1 + .../Navigators/SettingsNavigator.js | 41 +++++++++++++------ .../createCustomStackNavigator/index.js | 15 +++++-- src/libs/Navigation/linkingConfig.js | 4 +- .../FloatingActionButtonAndPopover.js | 2 +- 5 files changed, 43 insertions(+), 20 deletions(-) diff --git a/src/ROUTES.ts b/src/ROUTES.ts index bd5f6cc422b3..95d6f13a8921 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -59,6 +59,7 @@ export default { SETTINGS: 'settings', SETTINGS_NEW: 'settings_new', + SETTINGS_NEW_PROFILE: 'settings_new/profile', SETTINGS_PROFILE: 'settings/profile', SETTINGS_SHARE_CODE: 'settings/shareCode', SETTINGS_DISPLAY_NAME: 'settings/profile/display-name', diff --git a/src/libs/Navigation/AppNavigator/Navigators/SettingsNavigator.js b/src/libs/Navigation/AppNavigator/Navigators/SettingsNavigator.js index 46d80cb0fb55..ef4d0b30a05f 100644 --- a/src/libs/Navigation/AppNavigator/Navigators/SettingsNavigator.js +++ b/src/libs/Navigation/AppNavigator/Navigators/SettingsNavigator.js @@ -1,12 +1,13 @@ -import {createStackNavigator} from '@react-navigation/stack'; import PropTypes from 'prop-types'; import React from 'react'; -import {View} from 'react-native'; -import RHPScreenOptions from '@libs/Navigation/AppNavigator/RHPScreenOptions'; +import { View } from 'react-native'; import useThemeStyles from '@styles/useThemeStyles'; import NotFoundPage from '@pages/ErrorPage/NotFoundPage'; - -const Stack = createStackNavigator(); +import useWindowDimensions from '@hooks/useWindowDimensions'; +import getRootNavigatorScreenOptions from '@libs/Navigation/AppNavigator/getRootNavigatorScreenOptions'; +import createCustomStackNavigator from '@libs/Navigation/AppNavigator/createCustomStackNavigator'; +import NAVIGATORS from '@src/NAVIGATORS'; +import ROUTES from '@src/ROUTES'; const propTypes = { /* Navigation functions provided by React Navigation */ @@ -15,18 +16,32 @@ const propTypes = { }).isRequired, }; +const RootStack = createCustomStackNavigator(); + function SettingsNavigator() { const styles = useThemeStyles(); + const {isSmallScreenWidth} = useWindowDimensions(); + const screenOptions = getRootNavigatorScreenOptions(isSmallScreenWidth); return ( - - - - - + + + + + + ); } diff --git a/src/libs/Navigation/AppNavigator/createCustomStackNavigator/index.js b/src/libs/Navigation/AppNavigator/createCustomStackNavigator/index.js index 8924b01e2acb..bb2edb3aa2bb 100644 --- a/src/libs/Navigation/AppNavigator/createCustomStackNavigator/index.js +++ b/src/libs/Navigation/AppNavigator/createCustomStackNavigator/index.js @@ -19,20 +19,23 @@ const propTypes = { /* Screen options defined for this navigator */ // eslint-disable-next-line react/forbid-prop-types screenOptions: PropTypes.object, + + centralRoute: PropTypes.string, }; const defaultProps = { initialRouteName: undefined, screenOptions: undefined, + centralRoute: NAVIGATORS.CENTRAL_PANE_NAVIGATOR, }; -function reduceReportRoutes(routes) { +function reduceReportRoutes(routes, centralRoute=NAVIGATORS.CENTRAL_PANE_NAVIGATOR) { const result = []; let count = 0; const reverseRoutes = [...routes].reverse(); reverseRoutes.forEach((route) => { - if (route.name === NAVIGATORS.CENTRAL_PANE_NAVIGATOR) { + if (route.name === centralRoute) { // Remove all report routes except the last 3. This will improve performance. if (count < 3) { result.push(route); @@ -43,6 +46,8 @@ function reduceReportRoutes(routes) { } }); + console.log('reduceReportRoutes', centralRoute, routes, result); + return result.reverse(); } @@ -62,14 +67,16 @@ function ResponsiveStackNavigator(props) { }); const stateToRender = useMemo(() => { - const result = reduceReportRoutes(state.routes); + const result = reduceReportRoutes(state.routes, props.centralRoute); return { ...state, index: result.length - 1, routes: [...result], }; - }, [state]); + }, [props.centralRoute, state]); + + console.log('ResponsiveStackNavigator', props.centralRoute); return ( diff --git a/src/libs/Navigation/linkingConfig.js b/src/libs/Navigation/linkingConfig.js index 4137260e2390..05f6e3c4e344 100644 --- a/src/libs/Navigation/linkingConfig.js +++ b/src/libs/Navigation/linkingConfig.js @@ -432,8 +432,8 @@ export default { [NAVIGATORS.SETTINGS_NAVIGATOR]: { screens: { - [SCREENS.SETTINGS_NEW]: ROUTES.SETTINGS_NEW, - } + [SCREENS.SETTINGS_NEW_PROFILE]: {path: ROUTES.SETTINGS_NEW_PROFILE}, + }, } }, }, diff --git a/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.js b/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.js index 1eebf43d8a0a..c798121b1d2a 100644 --- a/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.js +++ b/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.js @@ -245,7 +245,7 @@ function FloatingActionButtonAndPopover(props) { onPress={() => { console.log('FloatingActionButtonAndPopover.js: showCreateMenu()'); // navigate to new screen - Navigation.navigate(ROUTES.SETTINGS_NEW); + Navigation.navigate(ROUTES.SETTINGS_NEW_PROFILE); }} /> From d8910f7d0d038a80b7b1e490008bf4b26a2f7527 Mon Sep 17 00:00:00 2001 From: Jakub Kosmydel <104823336+kosmydel@users.noreply.github.com> Date: Tue, 21 Nov 2023 13:53:09 +0100 Subject: [PATCH 022/722] add patch --- .../@react-navigation+stack+6.3.16+002+dontDetachScreen.patch | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/patches/@react-navigation+stack+6.3.16+002+dontDetachScreen.patch b/patches/@react-navigation+stack+6.3.16+002+dontDetachScreen.patch index d64fc4fecf74..ac4e8bafa8ab 100644 --- a/patches/@react-navigation+stack+6.3.16+002+dontDetachScreen.patch +++ b/patches/@react-navigation+stack+6.3.16+002+dontDetachScreen.patch @@ -43,7 +43,7 @@ index 7558eb3..b7bb75e 100644 }) : STATE_TRANSITIONING_OR_BELOW_TOP; } + -+ const isHomeScreenAndNotOnTop = route.name === 'Home' && isScreenActive !== STATE_ON_TOP; ++ const isHomeScreenAndNotOnTop = (route.name === 'Home' || route.name === 'SettingsHome') && isScreenActive !== STATE_ON_TOP; + const { headerShown = true, From 52388b93907b5aeef07c91e5c03244494124e1bf Mon Sep 17 00:00:00 2001 From: Jakub Kosmydel <104823336+kosmydel@users.noreply.github.com> Date: Tue, 21 Nov 2023 14:32:14 +0100 Subject: [PATCH 023/722] draft --- src/NAVIGATORS.ts | 1 - src/ROUTES.ts | 2 +- src/SCREENS.ts | 2 +- .../Navigation/AppNavigator/AuthScreens.js | 2 +- .../Navigators/SettingsNavigator.js | 27 ++++++++++++------- src/libs/Navigation/linkTo.js | 1 + src/libs/Navigation/linkingConfig.js | 15 +++++++++-- 7 files changed, 35 insertions(+), 15 deletions(-) diff --git a/src/NAVIGATORS.ts b/src/NAVIGATORS.ts index 52480d874d7b..a3a041e65684 100644 --- a/src/NAVIGATORS.ts +++ b/src/NAVIGATORS.ts @@ -5,6 +5,5 @@ export default { CENTRAL_PANE_NAVIGATOR: 'CentralPaneNavigator', RIGHT_MODAL_NAVIGATOR: 'RightModalNavigator', - SETTINGS_NAVIGATOR: 'Settings_Navigator', FULL_SCREEN_NAVIGATOR: 'FullScreenNavigator', } as const; diff --git a/src/ROUTES.ts b/src/ROUTES.ts index 95d6f13a8921..3d1a52230f3e 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -58,7 +58,7 @@ export default { }, SETTINGS: 'settings', - SETTINGS_NEW: 'settings_new', + SETTINGS_HOME: 'settings_new', SETTINGS_NEW_PROFILE: 'settings_new/profile', SETTINGS_PROFILE: 'settings/profile', SETTINGS_SHARE_CODE: 'settings/shareCode', diff --git a/src/SCREENS.ts b/src/SCREENS.ts index f18fb49dff80..b721d7f32c4b 100644 --- a/src/SCREENS.ts +++ b/src/SCREENS.ts @@ -16,7 +16,7 @@ export default { NOT_FOUND: 'not-found', TRANSITION_BETWEEN_APPS: 'TransitionBetweenApps', VALIDATE_LOGIN: 'ValidateLogin', - SETTINGS_NEW: 'SettingsNew', + SETTINGS_HOME: 'SettingsHome', SETTINGS: { ROOT: 'Settings_Root', PREFERENCES: 'Settings_Preferences', diff --git a/src/libs/Navigation/AppNavigator/AuthScreens.js b/src/libs/Navigation/AppNavigator/AuthScreens.js index 52a7f0c41afe..1d8ce5c69164 100644 --- a/src/libs/Navigation/AppNavigator/AuthScreens.js +++ b/src/libs/Navigation/AppNavigator/AuthScreens.js @@ -337,7 +337,7 @@ function AuthScreens({isUsingMemoryOnlyKeys, lastUpdateIDAppliedToClient, sessio listeners={modalScreenListeners} /> diff --git a/src/libs/Navigation/AppNavigator/Navigators/SettingsNavigator.js b/src/libs/Navigation/AppNavigator/Navigators/SettingsNavigator.js index ef4d0b30a05f..da46b8a4a761 100644 --- a/src/libs/Navigation/AppNavigator/Navigators/SettingsNavigator.js +++ b/src/libs/Navigation/AppNavigator/Navigators/SettingsNavigator.js @@ -8,38 +8,47 @@ import getRootNavigatorScreenOptions from '@libs/Navigation/AppNavigator/getRoot import createCustomStackNavigator from '@libs/Navigation/AppNavigator/createCustomStackNavigator'; import NAVIGATORS from '@src/NAVIGATORS'; import ROUTES from '@src/ROUTES'; +import SCREENS from '@src/SCREENS'; +import * as ModalStackNavigators from '@libs/Navigation/AppNavigator/ModalStackNavigators'; const propTypes = { /* Navigation functions provided by React Navigation */ navigation: PropTypes.shape({ goBack: PropTypes.func.isRequired, + getState: PropTypes.func.isRequired, }).isRequired, }; const RootStack = createCustomStackNavigator(); -function SettingsNavigator() { +function SettingsNavigator({navigation}) { const styles = useThemeStyles(); const {isSmallScreenWidth} = useWindowDimensions(); const screenOptions = getRootNavigatorScreenOptions(isSmallScreenWidth); + console.log('navigation state', navigation.getState()); + return ( - + + {/* */} ); diff --git a/src/libs/Navigation/linkTo.js b/src/libs/Navigation/linkTo.js index 286074914cf7..72ff8f795a95 100644 --- a/src/libs/Navigation/linkTo.js +++ b/src/libs/Navigation/linkTo.js @@ -58,6 +58,7 @@ export default function linkTo(navigation, path, type) { const state = getStateFromPath(path); const action = getActionFromState(state, linkingConfig.config); + console.log('linkTo', state, action); // If action type is different than NAVIGATE we can't change it to the PUSH safely if (action.type === CONST.NAVIGATION.ACTION_TYPE.NAVIGATE) { diff --git a/src/libs/Navigation/linkingConfig.js b/src/libs/Navigation/linkingConfig.js index 05f6e3c4e344..1a63a8e47569 100644 --- a/src/libs/Navigation/linkingConfig.js +++ b/src/libs/Navigation/linkingConfig.js @@ -430,9 +430,20 @@ export default { }, }, - [NAVIGATORS.SETTINGS_NAVIGATOR]: { + [NAVIGATORS.FULL_SCREEN_NAVIGATOR]: { screens: { - [SCREENS.SETTINGS_NEW_PROFILE]: {path: ROUTES.SETTINGS_NEW_PROFILE}, + Settings: { + screens: { + [SCREENS.SETTINGS_HOME]: { + path: ROUTES.SETTINGS_HOME, + exact: true, + }, + [SCREENS.SETTINGS_NEW_PROFILE]: { + path: ROUTES.SETTINGS_NEW_PROFILE, + exact: true, + }, + } + } }, } }, From 0d665ef8c9270972710606527d09671c1648de77 Mon Sep 17 00:00:00 2001 From: Jakub Kosmydel <104823336+kosmydel@users.noreply.github.com> Date: Tue, 21 Nov 2023 15:02:19 +0100 Subject: [PATCH 024/722] another step --- .../Navigators/SettingsNavigator.js | 10 +++---- src/libs/Navigation/linkingConfig.js | 27 ++++++++++--------- 2 files changed, 19 insertions(+), 18 deletions(-) diff --git a/src/libs/Navigation/AppNavigator/Navigators/SettingsNavigator.js b/src/libs/Navigation/AppNavigator/Navigators/SettingsNavigator.js index da46b8a4a761..fa0bc62cc9c0 100644 --- a/src/libs/Navigation/AppNavigator/Navigators/SettingsNavigator.js +++ b/src/libs/Navigation/AppNavigator/Navigators/SettingsNavigator.js @@ -2,15 +2,14 @@ import PropTypes from 'prop-types'; import React from 'react'; import { View } from 'react-native'; import useThemeStyles from '@styles/useThemeStyles'; -import NotFoundPage from '@pages/ErrorPage/NotFoundPage'; import useWindowDimensions from '@hooks/useWindowDimensions'; import getRootNavigatorScreenOptions from '@libs/Navigation/AppNavigator/getRootNavigatorScreenOptions'; import createCustomStackNavigator from '@libs/Navigation/AppNavigator/createCustomStackNavigator'; -import NAVIGATORS from '@src/NAVIGATORS'; -import ROUTES from '@src/ROUTES'; import SCREENS from '@src/SCREENS'; import * as ModalStackNavigators from '@libs/Navigation/AppNavigator/ModalStackNavigators'; +const loadSidebarScreen = () => require('../../../../pages/home/sidebar/SidebarScreen').default; + const propTypes = { /* Navigation functions provided by React Navigation */ navigation: PropTypes.shape({ @@ -33,15 +32,14 @@ function SettingsNavigator({navigation}) { diff --git a/src/libs/Navigation/linkingConfig.js b/src/libs/Navigation/linkingConfig.js index 1a63a8e47569..71f7f6916355 100644 --- a/src/libs/Navigation/linkingConfig.js +++ b/src/libs/Navigation/linkingConfig.js @@ -432,18 +432,21 @@ export default { [NAVIGATORS.FULL_SCREEN_NAVIGATOR]: { screens: { - Settings: { - screens: { - [SCREENS.SETTINGS_HOME]: { - path: ROUTES.SETTINGS_HOME, - exact: true, - }, - [SCREENS.SETTINGS_NEW_PROFILE]: { - path: ROUTES.SETTINGS_NEW_PROFILE, - exact: true, - }, - } - } + [SCREENS.SETTINGS_HOME]: { + path: ROUTES.SETTINGS_HOME, + }, + SettingsCentralPane: { + path: ROUTES.SETTINGS_NEW_PROFILE, + exact: true, + }, + // Settings: { + // screens: { + // [SCREENS.SETTINGS_NEW_PROFILE]: { + // path: ROUTES.SETTINGS_NEW_PROFILE, + // exact: true, + // }, + // } + // } }, } }, From dba92bfb1fe64b727baf8d56665953c36b7c1846 Mon Sep 17 00:00:00 2001 From: Jakub Kosmydel <104823336+kosmydel@users.noreply.github.com> Date: Tue, 21 Nov 2023 15:05:44 +0100 Subject: [PATCH 025/722] another step forward --- src/SCREENS.ts | 1 + .../Navigation/AppNavigator/Navigators/SettingsNavigator.js | 2 +- src/libs/Navigation/linkingConfig.js | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/SCREENS.ts b/src/SCREENS.ts index b721d7f32c4b..b7def3ce8e23 100644 --- a/src/SCREENS.ts +++ b/src/SCREENS.ts @@ -17,6 +17,7 @@ export default { TRANSITION_BETWEEN_APPS: 'TransitionBetweenApps', VALIDATE_LOGIN: 'ValidateLogin', SETTINGS_HOME: 'SettingsHome', + SETTINGS_NEW_PROFILE: 'SettingsNewProfile', SETTINGS: { ROOT: 'Settings_Root', PREFERENCES: 'Settings_Preferences', diff --git a/src/libs/Navigation/AppNavigator/Navigators/SettingsNavigator.js b/src/libs/Navigation/AppNavigator/Navigators/SettingsNavigator.js index fa0bc62cc9c0..705eaf35eb7b 100644 --- a/src/libs/Navigation/AppNavigator/Navigators/SettingsNavigator.js +++ b/src/libs/Navigation/AppNavigator/Navigators/SettingsNavigator.js @@ -39,7 +39,7 @@ function SettingsNavigator({navigation}) { getComponent={loadSidebarScreen} /> diff --git a/src/libs/Navigation/linkingConfig.js b/src/libs/Navigation/linkingConfig.js index 71f7f6916355..0d09a984ae61 100644 --- a/src/libs/Navigation/linkingConfig.js +++ b/src/libs/Navigation/linkingConfig.js @@ -435,7 +435,7 @@ export default { [SCREENS.SETTINGS_HOME]: { path: ROUTES.SETTINGS_HOME, }, - SettingsCentralPane: { + [SCREENS.SETTINGS_NEW_PROFILE]: { path: ROUTES.SETTINGS_NEW_PROFILE, exact: true, }, From 14e07418e95a4e342b33f278e8690d6525ae60a4 Mon Sep 17 00:00:00 2001 From: Jakub Kosmydel <104823336+kosmydel@users.noreply.github.com> Date: Tue, 21 Nov 2023 15:19:38 +0100 Subject: [PATCH 026/722] another step forward --- .../Navigators/SettingsNavigator.js | 7 +-- .../CustomRouter.js | 53 +++++++++++++------ .../createCustomStackNavigator/index.js | 1 + src/libs/Navigation/linkingConfig.js | 2 +- .../FloatingActionButtonAndPopover.js | 2 +- 5 files changed, 42 insertions(+), 23 deletions(-) diff --git a/src/libs/Navigation/AppNavigator/Navigators/SettingsNavigator.js b/src/libs/Navigation/AppNavigator/Navigators/SettingsNavigator.js index 705eaf35eb7b..3d82337c6ad7 100644 --- a/src/libs/Navigation/AppNavigator/Navigators/SettingsNavigator.js +++ b/src/libs/Navigation/AppNavigator/Navigators/SettingsNavigator.js @@ -32,6 +32,7 @@ function SettingsNavigator({navigation}) { - {/* */} ); diff --git a/src/libs/Navigation/AppNavigator/createCustomStackNavigator/CustomRouter.js b/src/libs/Navigation/AppNavigator/createCustomStackNavigator/CustomRouter.js index 5d3eb38d49dc..2a05a90796bb 100644 --- a/src/libs/Navigation/AppNavigator/createCustomStackNavigator/CustomRouter.js +++ b/src/libs/Navigation/AppNavigator/createCustomStackNavigator/CustomRouter.js @@ -3,12 +3,14 @@ import lodashFindLast from 'lodash/findLast'; import _ from 'underscore'; import NAVIGATORS from '@src/NAVIGATORS'; import SCREENS from '@src/SCREENS'; +import CentralPaneNavigator from '../Navigators/CentralPaneNavigator'; /** * @param {Object} state - react-navigation state + * @param {String} centralRoute - name of the central route * @returns {Boolean} */ -const isAtLeastOneCentralPaneNavigatorInState = (state) => _.find(state.routes, (r) => r.name === NAVIGATORS.CENTRAL_PANE_NAVIGATOR); +const isAtLeastOneCentralPaneNavigatorInState = (state, centralRoute) => _.find(state.routes, (r) => r.name === centralRoute); /** * @param {Object} state - react-navigation state @@ -41,22 +43,37 @@ const getTopMostReportIDFromRHP = (state) => { * The report screen will self set proper reportID param based on the helper function findLastAccessedReport (look at ReportScreenWrapper for more info) * * @param {Object} state - react-navigation state + * @param {String} centralRoute - name of the central route */ -const addCentralPaneNavigatorRoute = (state) => { +const addCentralPaneNavigatorRoute = (state, centralRoute) => { const reportID = getTopMostReportIDFromRHP(state); - const centralPaneNavigatorRoute = { - name: NAVIGATORS.CENTRAL_PANE_NAVIGATOR, - state: { - routes: [ - { - name: SCREENS.REPORT, - params: { - reportID, + let centralPaneNavigatorRoute; + if (centralRoute === NAVIGATORS.CENTRAL_PANE_NAVIGATOR) { + centralPaneNavigatorRoute = { + name: NAVIGATORS.CENTRAL_PANE_NAVIGATOR, + state: { + routes: [ + { + name: SCREENS.REPORT, + params: { + reportID, + }, }, - }, - ], - }, - }; + ], + }, + }; + } else { + centralPaneNavigatorRoute = { + name: centralRoute, + state: { + routes: [ + { + name: 'SettingsCentralPane', + }, + ], + }, + }; + } state.routes.splice(1, 0, centralPaneNavigatorRoute); // eslint-disable-next-line no-param-reassign state.index = state.routes.length - 1; @@ -64,16 +81,20 @@ const addCentralPaneNavigatorRoute = (state) => { function CustomRouter(options) { const stackRouter = StackRouter(options); + const centralRoute = options.centralRoute || NAVIGATORS.CENTRAL_PANE_NAVIGATOR; + console.log('CustomRouter', centralRoute); return { ...stackRouter, getRehydratedState(partialState, {routeNames, routeParamList}) { + console.log('getRehydratedState', centralRoute); // Make sure that there is at least one CentralPaneNavigator (ReportScreen by default) in the state if this is a wide layout - if (!isAtLeastOneCentralPaneNavigatorInState(partialState) && !options.getIsSmallScreenWidth()) { + if (!isAtLeastOneCentralPaneNavigatorInState(partialState, centralRoute) && !options.getIsSmallScreenWidth()) { + console.log('getRehydratedState', centralRoute, 'adding CentralPaneNavigator'); // If we added a route we need to make sure that the state.stale is true to generate new key for this route // eslint-disable-next-line no-param-reassign partialState.stale = true; - addCentralPaneNavigatorRoute(partialState); + addCentralPaneNavigatorRoute(partialState, centralRoute); } const state = stackRouter.getRehydratedState(partialState, {routeNames, routeParamList}); return state; diff --git a/src/libs/Navigation/AppNavigator/createCustomStackNavigator/index.js b/src/libs/Navigation/AppNavigator/createCustomStackNavigator/index.js index bb2edb3aa2bb..120e6e99dd61 100644 --- a/src/libs/Navigation/AppNavigator/createCustomStackNavigator/index.js +++ b/src/libs/Navigation/AppNavigator/createCustomStackNavigator/index.js @@ -64,6 +64,7 @@ function ResponsiveStackNavigator(props) { initialRouteName: props.initialRouteName, // Options for useNavigationBuilder won't update on prop change, so we need to pass a getter for the router to have the current state of isSmallScreenWidth. getIsSmallScreenWidth: () => isSmallScreenWidthRef.current, + centralRoute: props.centralRoute, }); const stateToRender = useMemo(() => { diff --git a/src/libs/Navigation/linkingConfig.js b/src/libs/Navigation/linkingConfig.js index 0d09a984ae61..71f7f6916355 100644 --- a/src/libs/Navigation/linkingConfig.js +++ b/src/libs/Navigation/linkingConfig.js @@ -435,7 +435,7 @@ export default { [SCREENS.SETTINGS_HOME]: { path: ROUTES.SETTINGS_HOME, }, - [SCREENS.SETTINGS_NEW_PROFILE]: { + SettingsCentralPane: { path: ROUTES.SETTINGS_NEW_PROFILE, exact: true, }, diff --git a/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.js b/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.js index c798121b1d2a..5ad3e4431b32 100644 --- a/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.js +++ b/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.js @@ -245,7 +245,7 @@ function FloatingActionButtonAndPopover(props) { onPress={() => { console.log('FloatingActionButtonAndPopover.js: showCreateMenu()'); // navigate to new screen - Navigation.navigate(ROUTES.SETTINGS_NEW_PROFILE); + Navigation.navigate(ROUTES.SETTINGS_HOME); }} /> From 18ed44a367f7cdc2e423bf3d1cdb16d2fa90a584 Mon Sep 17 00:00:00 2001 From: Jakub Kosmydel <104823336+kosmydel@users.noreply.github.com> Date: Tue, 21 Nov 2023 15:39:52 +0100 Subject: [PATCH 027/722] another step forward 123 --- .../AppNavigator/Navigators/SettingsNavigator.js | 6 +++++- .../createCustomStackNavigator/CustomRouter.js | 11 ++++++----- .../AppNavigator/createCustomStackNavigator/index.js | 6 +++++- src/libs/Navigation/NavigationRoot.js | 1 + src/libs/Navigation/linkingConfig.js | 8 ++++++-- 5 files changed, 23 insertions(+), 9 deletions(-) diff --git a/src/libs/Navigation/AppNavigator/Navigators/SettingsNavigator.js b/src/libs/Navigation/AppNavigator/Navigators/SettingsNavigator.js index 3d82337c6ad7..13cd7ebfd27c 100644 --- a/src/libs/Navigation/AppNavigator/Navigators/SettingsNavigator.js +++ b/src/libs/Navigation/AppNavigator/Navigators/SettingsNavigator.js @@ -9,6 +9,7 @@ import SCREENS from '@src/SCREENS'; import * as ModalStackNavigators from '@libs/Navigation/AppNavigator/ModalStackNavigators'; const loadSidebarScreen = () => require('../../../../pages/home/sidebar/SidebarScreen').default; +const loadPage = () => require('../../../../pages/ErrorPage/NotFoundPage').default; const propTypes = { /* Navigation functions provided by React Navigation */ @@ -27,17 +28,20 @@ function SettingsNavigator({navigation}) { console.log('navigation state', navigation.getState()); + console.log('loadSidebarScreen', loadSidebarScreen, 'not found page', loadPage) + return ( _.find(state.routes, (r) => r.name === centralRoute); +const isAtLeastOneCentralPaneNavigatorInState = (state, centralRoute) => { + console.log('isAtLeastOneCentralPaneNavigatorInState', centralRoute); + return _.find(state.routes, (r) => r.name === centralRoute) +}; /** * @param {Object} state - react-navigation state @@ -81,16 +83,15 @@ const addCentralPaneNavigatorRoute = (state, centralRoute) => { function CustomRouter(options) { const stackRouter = StackRouter(options); - const centralRoute = options.centralRoute || NAVIGATORS.CENTRAL_PANE_NAVIGATOR; - console.log('CustomRouter', centralRoute); return { ...stackRouter, getRehydratedState(partialState, {routeNames, routeParamList}) { + const centralRoute = options.centralRoute(); console.log('getRehydratedState', centralRoute); // Make sure that there is at least one CentralPaneNavigator (ReportScreen by default) in the state if this is a wide layout if (!isAtLeastOneCentralPaneNavigatorInState(partialState, centralRoute) && !options.getIsSmallScreenWidth()) { - console.log('getRehydratedState', centralRoute, 'adding CentralPaneNavigator'); + console.log('getRehydratedState', centralRoute, 'adding central pane'); // If we added a route we need to make sure that the state.stale is true to generate new key for this route // eslint-disable-next-line no-param-reassign partialState.stale = true; diff --git a/src/libs/Navigation/AppNavigator/createCustomStackNavigator/index.js b/src/libs/Navigation/AppNavigator/createCustomStackNavigator/index.js index 120e6e99dd61..25fee9a02c77 100644 --- a/src/libs/Navigation/AppNavigator/createCustomStackNavigator/index.js +++ b/src/libs/Navigation/AppNavigator/createCustomStackNavigator/index.js @@ -52,19 +52,23 @@ function reduceReportRoutes(routes, centralRoute=NAVIGATORS.CENTRAL_PANE_NAVIGAT } function ResponsiveStackNavigator(props) { + console.log('ResponsiveStackNavigator', props.centralRoute) const {isSmallScreenWidth} = useWindowDimensions(); const isSmallScreenWidthRef = useRef(isSmallScreenWidth); isSmallScreenWidthRef.current = isSmallScreenWidth; + const centralRouteRef = useRef(props.centralRoute); + centralRouteRef.current = props.centralRoute; + const {navigation, state, descriptors, NavigationContent} = useNavigationBuilder(CustomRouter, { children: props.children, screenOptions: props.screenOptions, initialRouteName: props.initialRouteName, // Options for useNavigationBuilder won't update on prop change, so we need to pass a getter for the router to have the current state of isSmallScreenWidth. getIsSmallScreenWidth: () => isSmallScreenWidthRef.current, - centralRoute: props.centralRoute, + centralRoute: () => centralRouteRef.current, }); const stateToRender = useMemo(() => { diff --git a/src/libs/Navigation/NavigationRoot.js b/src/libs/Navigation/NavigationRoot.js index 2373066cf4bd..314a324dc0fe 100644 --- a/src/libs/Navigation/NavigationRoot.js +++ b/src/libs/Navigation/NavigationRoot.js @@ -75,6 +75,7 @@ function NavigationRoot(props) { if (!navigationRef.isReady() || !props.authenticated) { return; } + // TODO: Add force rehydration! // We need to force state rehydration so the CustomRouter can add the CentralPaneNavigator route if necessary. navigationRef.resetRoot(navigationRef.getRootState()); }, [isSmallScreenWidth, props.authenticated]); diff --git a/src/libs/Navigation/linkingConfig.js b/src/libs/Navigation/linkingConfig.js index 71f7f6916355..2fd0db3cd48f 100644 --- a/src/libs/Navigation/linkingConfig.js +++ b/src/libs/Navigation/linkingConfig.js @@ -436,8 +436,12 @@ export default { path: ROUTES.SETTINGS_HOME, }, SettingsCentralPane: { - path: ROUTES.SETTINGS_NEW_PROFILE, - exact: true, + screens: { + [SCREENS.SETTINGS_NEW_PROFILE]: { + path: ROUTES.SETTINGS_NEW_PROFILE, + exact: true, + } + } }, // Settings: { // screens: { From 7fa40aedb098807d85aa709f9527e26080b58ab2 Mon Sep 17 00:00:00 2001 From: Jakub Kosmydel <104823336+kosmydel@users.noreply.github.com> Date: Tue, 21 Nov 2023 15:49:31 +0100 Subject: [PATCH 028/722] mini step forward --- .../Navigators/SettingsNavigator.js | 7 +- src/libs/Navigation/linkingConfig.js | 402 +++++++++--------- 2 files changed, 199 insertions(+), 210 deletions(-) diff --git a/src/libs/Navigation/AppNavigator/Navigators/SettingsNavigator.js b/src/libs/Navigation/AppNavigator/Navigators/SettingsNavigator.js index 13cd7ebfd27c..4cfb5a9ae82b 100644 --- a/src/libs/Navigation/AppNavigator/Navigators/SettingsNavigator.js +++ b/src/libs/Navigation/AppNavigator/Navigators/SettingsNavigator.js @@ -7,9 +7,9 @@ import getRootNavigatorScreenOptions from '@libs/Navigation/AppNavigator/getRoot import createCustomStackNavigator from '@libs/Navigation/AppNavigator/createCustomStackNavigator'; import SCREENS from '@src/SCREENS'; import * as ModalStackNavigators from '@libs/Navigation/AppNavigator/ModalStackNavigators'; +import NotFoundPage from '@pages/ErrorPage/NotFoundPage'; -const loadSidebarScreen = () => require('../../../../pages/home/sidebar/SidebarScreen').default; -const loadPage = () => require('../../../../pages/ErrorPage/NotFoundPage').default; +const loadPage = () => require('../../../../pages/settings/InitialSettingsPage').default; const propTypes = { /* Navigation functions provided by React Navigation */ @@ -28,14 +28,11 @@ function SettingsNavigator({navigation}) { console.log('navigation state', navigation.getState()); - console.log('loadSidebarScreen', loadSidebarScreen, 'not found page', loadPage) - return ( Date: Tue, 21 Nov 2023 16:14:00 +0100 Subject: [PATCH 029/722] add initial state --- .../AppNavigator/Navigators/SettingsNavigator.js | 1 - .../createCustomStackNavigator/CustomRouter.js | 11 ++++++++++- src/libs/Navigation/Navigation.js | 8 +++++++- src/pages/settings/InitialSettingsPage.js | 1 + src/pages/settings/Preferences/PreferencesPage.js | 2 +- 5 files changed, 19 insertions(+), 4 deletions(-) diff --git a/src/libs/Navigation/AppNavigator/Navigators/SettingsNavigator.js b/src/libs/Navigation/AppNavigator/Navigators/SettingsNavigator.js index 4cfb5a9ae82b..e1d68e58e973 100644 --- a/src/libs/Navigation/AppNavigator/Navigators/SettingsNavigator.js +++ b/src/libs/Navigation/AppNavigator/Navigators/SettingsNavigator.js @@ -7,7 +7,6 @@ import getRootNavigatorScreenOptions from '@libs/Navigation/AppNavigator/getRoot import createCustomStackNavigator from '@libs/Navigation/AppNavigator/createCustomStackNavigator'; import SCREENS from '@src/SCREENS'; import * as ModalStackNavigators from '@libs/Navigation/AppNavigator/ModalStackNavigators'; -import NotFoundPage from '@pages/ErrorPage/NotFoundPage'; const loadPage = () => require('../../../../pages/settings/InitialSettingsPage').default; diff --git a/src/libs/Navigation/AppNavigator/createCustomStackNavigator/CustomRouter.js b/src/libs/Navigation/AppNavigator/createCustomStackNavigator/CustomRouter.js index 31bf4a7bb1b5..3a53a54e60ad 100644 --- a/src/libs/Navigation/AppNavigator/createCustomStackNavigator/CustomRouter.js +++ b/src/libs/Navigation/AppNavigator/createCustomStackNavigator/CustomRouter.js @@ -70,7 +70,7 @@ const addCentralPaneNavigatorRoute = (state, centralRoute) => { state: { routes: [ { - name: 'SettingsCentralPane', + name: SCREENS.SETTINGS.PREFERENCES, }, ], }, @@ -86,6 +86,15 @@ function CustomRouter(options) { return { ...stackRouter, + getInitialState({routeNames, routeParamList, routeGetIdList}) { + console.log('getInitialState', routeNames, routeParamList, routeGetIdList); + const centralRoute = options.centralRoute(); + const initialState = stackRouter.getInitialState({routeNames, routeParamList, routeGetIdList}); + if (!isAtLeastOneCentralPaneNavigatorInState(initialState, centralRoute) && !options.getIsSmallScreenWidth()) { + addCentralPaneNavigatorRoute(initialState, centralRoute); + } + return initialState; + }, getRehydratedState(partialState, {routeNames, routeParamList}) { const centralRoute = options.centralRoute(); console.log('getRehydratedState', centralRoute); diff --git a/src/libs/Navigation/Navigation.js b/src/libs/Navigation/Navigation.js index 7a2c61ea7b53..bcf0effa37a4 100644 --- a/src/libs/Navigation/Navigation.js +++ b/src/libs/Navigation/Navigation.js @@ -66,7 +66,7 @@ const getActiveRouteIndex = function (route, index) { return getActiveRouteIndex(childActiveRoute, route.state.index || 0); } - if (route.name === NAVIGATORS.RIGHT_MODAL_NAVIGATOR) { + if (route.name === NAVIGATORS.RIGHT_MODAL_NAVIGATOR || route.name === NAVIGATORS.FULL_SCREEN_NAVIGATOR) { return 0; } @@ -147,6 +147,12 @@ function goBack(fallbackRoute, shouldEnforceFallback = false, shouldPopToTop = f navigationRef.current.goBack(); return; } + + if(lastRoute.name === NAVIGATORS.FULL_SCREEN_NAVIGATOR) { + console.log('lastRoute', lastRoute); + navigationRef.current.goBack(); + return; + } } if (shouldEnforceFallback || (isFirstRouteInNavigator && fallbackRoute)) { diff --git a/src/pages/settings/InitialSettingsPage.js b/src/pages/settings/InitialSettingsPage.js index d88105b31360..628ca489fc70 100755 --- a/src/pages/settings/InitialSettingsPage.js +++ b/src/pages/settings/InitialSettingsPage.js @@ -388,6 +388,7 @@ function InitialSettingsPage(props) { headerContent={headerContent} headerContainerStyles={[styles.staticHeaderImage, styles.justifyContentCenter]} backgroundColor={theme.PAGE_BACKGROUND_COLORS[SCREENS.SETTINGS.ROOT]} + onBackButtonPress={() => Navigation.goBack()} > {getMenuItems} diff --git a/src/pages/settings/Preferences/PreferencesPage.js b/src/pages/settings/Preferences/PreferencesPage.js index 4dbc5fda9198..5c056385dd2d 100755 --- a/src/pages/settings/Preferences/PreferencesPage.js +++ b/src/pages/settings/Preferences/PreferencesPage.js @@ -45,7 +45,7 @@ function PreferencesPage(props) { return ( Navigation.goBack(ROUTES.SETTINGS)} + shouldShowBackButton={false} backgroundColor={theme.PAGE_BACKGROUND_COLORS[SCREENS.SETTINGS.PREFERENCES]} illustration={LottieAnimations.PreferencesDJ} > From 6b1dee1cfb3ce68b8bb9c3a4283d3dee3f9db837 Mon Sep 17 00:00:00 2001 From: Jakub Kosmydel <104823336+kosmydel@users.noreply.github.com> Date: Tue, 21 Nov 2023 16:44:04 +0100 Subject: [PATCH 030/722] few fixes --- src/SCREENS.ts | 1 + .../AppNavigator/ModalStackNavigators.js | 6 +++--- .../CustomRouter.js | 2 +- src/libs/Navigation/Navigation.js | 21 ++++++++++++++----- src/libs/Navigation/linkingConfig.js | 5 +---- .../sidebar/PressableAvatarWithIndicator.js | 2 +- src/pages/settings/InitialSettingsPage.js | 7 ++++++- 7 files changed, 29 insertions(+), 15 deletions(-) diff --git a/src/SCREENS.ts b/src/SCREENS.ts index b7def3ce8e23..6ef776ef4507 100644 --- a/src/SCREENS.ts +++ b/src/SCREENS.ts @@ -21,6 +21,7 @@ export default { SETTINGS: { ROOT: 'Settings_Root', PREFERENCES: 'Settings_Preferences', + PROFILE: 'Settings_Profile', WORKSPACES: 'Settings_Workspaces', SECURITY: 'Settings_Security', STATUS: 'Settings_Status', diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators.js b/src/libs/Navigation/AppNavigator/ModalStackNavigators.js index a2f9bdd7a903..1368f12a0213 100644 --- a/src/libs/Navigation/AppNavigator/ModalStackNavigators.js +++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators.js @@ -1,4 +1,4 @@ -import {CardStyleInterpolators, createStackNavigator} from '@react-navigation/stack'; +import {createStackNavigator} from '@react-navigation/stack'; import React from 'react'; import _ from 'underscore'; import styles from '@styles/styles'; @@ -7,7 +7,8 @@ import SCREENS from '@src/SCREENS'; const defaultSubRouteOptions = { cardStyle: styles.navigationScreenCardStyle, headerShown: false, - cardStyleInterpolator: CardStyleInterpolators.forHorizontalIOS, + // TODO: Can remove it + // cardStyleInterpolator: CardStyleInterpolators.forHorizontalIOS, }; /** @@ -131,7 +132,6 @@ const NewTeachersUniteNavigator = createModalStackNavigator({ }); const SettingsModalStackNavigator = createModalStackNavigator({ - [SCREENS.SETTINGS.ROOT]: () => require('../../../pages/settings/InitialSettingsPage').default, Settings_Share_Code: () => require('../../../pages/ShareCodePage').default, [SCREENS.SETTINGS.WORKSPACES]: () => require('../../../pages/workspace/WorkspacesListPage').default, Settings_Profile: () => require('../../../pages/settings/Profile/ProfilePage').default, diff --git a/src/libs/Navigation/AppNavigator/createCustomStackNavigator/CustomRouter.js b/src/libs/Navigation/AppNavigator/createCustomStackNavigator/CustomRouter.js index 3a53a54e60ad..5ac04ab884a4 100644 --- a/src/libs/Navigation/AppNavigator/createCustomStackNavigator/CustomRouter.js +++ b/src/libs/Navigation/AppNavigator/createCustomStackNavigator/CustomRouter.js @@ -70,7 +70,7 @@ const addCentralPaneNavigatorRoute = (state, centralRoute) => { state: { routes: [ { - name: SCREENS.SETTINGS.PREFERENCES, + name: SCREENS.SETTINGS.PROFILE, }, ], }, diff --git a/src/libs/Navigation/Navigation.js b/src/libs/Navigation/Navigation.js index bcf0effa37a4..da5e8fbaecf0 100644 --- a/src/libs/Navigation/Navigation.js +++ b/src/libs/Navigation/Navigation.js @@ -121,6 +121,7 @@ function navigate(route = ROUTES.HOME, type) { * @param {Boolean} shouldPopToTop - Should we navigate to LHN on back press */ function goBack(fallbackRoute, shouldEnforceFallback = false, shouldPopToTop = false) { + console.log('goBack', 1, navigationRef.current.state); if (!canNavigate('goBack')) { return; } @@ -132,14 +133,17 @@ function goBack(fallbackRoute, shouldEnforceFallback = false, shouldPopToTop = f return; } } + console.log('goBack', 2); if (!navigationRef.current.canGoBack()) { Log.hmmm('[Navigation] Unable to go back'); return; } + console.log('goBack', 3); const isFirstRouteInNavigator = !getActiveRouteIndex(navigationRef.current.getState()); if (isFirstRouteInNavigator) { + console.log('goBack', 4); const rootState = navigationRef.getRootState(); const lastRoute = _.last(rootState.routes); // If the user comes from a different flow (there is more than one route in RHP) we should go back to the previous flow on UP button press instead of using the fallbackRoute. @@ -148,18 +152,21 @@ function goBack(fallbackRoute, shouldEnforceFallback = false, shouldPopToTop = f return; } - if(lastRoute.name === NAVIGATORS.FULL_SCREEN_NAVIGATOR) { - console.log('lastRoute', lastRoute); - navigationRef.current.goBack(); - return; - } + // if(lastRoute.name === NAVIGATORS.FULL_SCREEN_NAVIGATOR) { + // console.log('lastRoute', lastRoute); + // navigationRef.current.goBack(); + // return; + // } } + console.log('goBack', 5); if (shouldEnforceFallback || (isFirstRouteInNavigator && fallbackRoute)) { navigate(fallbackRoute, CONST.NAVIGATION.TYPE.UP); return; } + console.log('goBack', 6); + const isCentralPaneFocused = findFocusedRoute(navigationRef.current.getState()).name === NAVIGATORS.CENTRAL_PANE_NAVIGATOR; const distanceFromPathInRootNavigator = getDistanceFromPathInRootNavigator(fallbackRoute); @@ -169,6 +176,8 @@ function goBack(fallbackRoute, shouldEnforceFallback = false, shouldPopToTop = f return; } + console.log('goBack', 7); + // 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)); @@ -176,6 +185,8 @@ function goBack(fallbackRoute, shouldEnforceFallback = false, shouldPopToTop = f } navigationRef.current.goBack(); + + console.log('goBack', 8); } /** diff --git a/src/libs/Navigation/linkingConfig.js b/src/libs/Navigation/linkingConfig.js index 63f97f0fe6f8..8b745639147e 100644 --- a/src/libs/Navigation/linkingConfig.js +++ b/src/libs/Navigation/linkingConfig.js @@ -234,9 +234,6 @@ export default { }, SettingsCentralPane: { screens: { - [SCREENS.SETTINGS.ROOT]: { - path: ROUTES.SETTINGS, - }, [SCREENS.SETTINGS.WORKSPACES]: { path: ROUTES.SETTINGS_WORKSPACES, exact: true, @@ -309,7 +306,7 @@ export default { path: ROUTES.SETTINGS_ADD_BANK_ACCOUNT, exact: true, }, - Settings_Profile: { + [SCREENS.SETTINGS.PROFILE]: { path: ROUTES.SETTINGS_PROFILE, exact: true, }, diff --git a/src/pages/home/sidebar/PressableAvatarWithIndicator.js b/src/pages/home/sidebar/PressableAvatarWithIndicator.js index ddf89321b680..ec2f48cc6a91 100644 --- a/src/pages/home/sidebar/PressableAvatarWithIndicator.js +++ b/src/pages/home/sidebar/PressableAvatarWithIndicator.js @@ -46,7 +46,7 @@ function PressableAvatarWithIndicator({isCreateMenuOpen, currentUserPersonalDeta return; } - Navigation.navigate(ROUTES.SETTINGS); + Navigation.navigate(ROUTES.SETTINGS_HOME); }, [isCreateMenuOpen]); return ( diff --git a/src/pages/settings/InitialSettingsPage.js b/src/pages/settings/InitialSettingsPage.js index 628ca489fc70..caccb1438293 100755 --- a/src/pages/settings/InitialSettingsPage.js +++ b/src/pages/settings/InitialSettingsPage.js @@ -382,13 +382,18 @@ function InitialSettingsPage(props) { ); + const navigateBackTo = lodashGet(props.route, 'params.backTo', ROUTES.HOME); + return ( Navigation.goBack()} + onBackButtonPress={() => { + console.log('navigateBackTo', navigateBackTo); + Navigation.goBack(navigateBackTo) + }} > {getMenuItems} From 8703e12c99f6c7bb3dba18e242c65ad2bf9b49ec Mon Sep 17 00:00:00 2001 From: Jakub Kosmydel <104823336+kosmydel@users.noreply.github.com> Date: Thu, 23 Nov 2023 09:38:07 +0100 Subject: [PATCH 031/722] fix closing settings --- src/pages/settings/InitialSettingsPage.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/pages/settings/InitialSettingsPage.js b/src/pages/settings/InitialSettingsPage.js index caccb1438293..1ca111d205a0 100755 --- a/src/pages/settings/InitialSettingsPage.js +++ b/src/pages/settings/InitialSettingsPage.js @@ -390,10 +390,7 @@ function InitialSettingsPage(props) { headerContent={headerContent} headerContainerStyles={[styles.staticHeaderImage, styles.justifyContentCenter]} backgroundColor={theme.PAGE_BACKGROUND_COLORS[SCREENS.SETTINGS.ROOT]} - onBackButtonPress={() => { - console.log('navigateBackTo', navigateBackTo); - Navigation.goBack(navigateBackTo) - }} + onBackButtonPress={() => Navigation.navigate(navigateBackTo)} > {getMenuItems} From 248d664e47bd8c6234b7c63d868d2b9054903c27 Mon Sep 17 00:00:00 2001 From: Jakub Kosmydel <104823336+kosmydel@users.noreply.github.com> Date: Thu, 23 Nov 2023 09:41:10 +0100 Subject: [PATCH 032/722] revert --- src/pages/settings/Preferences/PreferencesPage.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/pages/settings/Preferences/PreferencesPage.js b/src/pages/settings/Preferences/PreferencesPage.js index 5c056385dd2d..0c02fe9772fb 100755 --- a/src/pages/settings/Preferences/PreferencesPage.js +++ b/src/pages/settings/Preferences/PreferencesPage.js @@ -45,7 +45,6 @@ function PreferencesPage(props) { return ( From a5ce5bfac7db7f8aca2c0d721f96b5cd8c13db74 Mon Sep 17 00:00:00 2001 From: Jakub Kosmydel <104823336+kosmydel@users.noreply.github.com> Date: Thu, 23 Nov 2023 09:57:55 +0100 Subject: [PATCH 033/722] fix deeplink --- .../CustomRouter.js | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/libs/Navigation/AppNavigator/createCustomStackNavigator/CustomRouter.js b/src/libs/Navigation/AppNavigator/createCustomStackNavigator/CustomRouter.js index 5ac04ab884a4..36faa6816c86 100644 --- a/src/libs/Navigation/AppNavigator/createCustomStackNavigator/CustomRouter.js +++ b/src/libs/Navigation/AppNavigator/createCustomStackNavigator/CustomRouter.js @@ -9,10 +9,7 @@ import SCREENS from '@src/SCREENS'; * @param {String} centralRoute - name of the central route * @returns {Boolean} */ -const isAtLeastOneCentralPaneNavigatorInState = (state, centralRoute) => { - console.log('isAtLeastOneCentralPaneNavigatorInState', centralRoute); - return _.find(state.routes, (r) => r.name === centralRoute) -}; +const isAtLeastOneCentralPaneNavigatorInState = (state, centralRoute) => _.find(state.routes, (r) => r.name === centralRoute); /** * @param {Object} state - react-navigation state @@ -48,9 +45,9 @@ const getTopMostReportIDFromRHP = (state) => { * @param {String} centralRoute - name of the central route */ const addCentralPaneNavigatorRoute = (state, centralRoute) => { - const reportID = getTopMostReportIDFromRHP(state); let centralPaneNavigatorRoute; if (centralRoute === NAVIGATORS.CENTRAL_PANE_NAVIGATOR) { + const reportID = getTopMostReportIDFromRHP(state); centralPaneNavigatorRoute = { name: NAVIGATORS.CENTRAL_PANE_NAVIGATOR, state: { @@ -81,6 +78,17 @@ const addCentralPaneNavigatorRoute = (state, centralRoute) => { state.index = state.routes.length - 1; }; +const addLHPRoute = (state, centralRoute) => { + const settingsHomeRoute = { + name: SCREENS.SETTINGS_HOME, + }; + if (state.routes[0].name !== SCREENS.SETTINGS_HOME && centralRoute === 'SettingsCentralPane') { + state.routes.splice(0, 0, settingsHomeRoute); + // eslint-disable-next-line no-param-reassign + state.index = state.routes.length - 1; + } +} + function CustomRouter(options) { const stackRouter = StackRouter(options); @@ -106,6 +114,7 @@ function CustomRouter(options) { partialState.stale = true; addCentralPaneNavigatorRoute(partialState, centralRoute); } + addLHPRoute(partialState, centralRoute); const state = stackRouter.getRehydratedState(partialState, {routeNames, routeParamList}); return state; }, From a30391373b3642f9316cc48124231de0952a3a5e Mon Sep 17 00:00:00 2001 From: Jakub Kosmydel <104823336+kosmydel@users.noreply.github.com> Date: Thu, 23 Nov 2023 10:11:31 +0100 Subject: [PATCH 034/722] add better linking --- src/libs/Navigation/linkingConfig.js | 364 +++++++++++++-------------- 1 file changed, 180 insertions(+), 184 deletions(-) diff --git a/src/libs/Navigation/linkingConfig.js b/src/libs/Navigation/linkingConfig.js index 8b745639147e..a3ebd12838be 100644 --- a/src/libs/Navigation/linkingConfig.js +++ b/src/libs/Navigation/linkingConfig.js @@ -36,6 +36,178 @@ export default { [NAVIGATORS.RIGHT_MODAL_NAVIGATOR]: { screens: { + Settings: { + screens: { + Settings_Preferences_PriorityMode: { + path: ROUTES.SETTINGS_PRIORITY_MODE, + exact: true, + }, + Settings_Preferences_Language: { + path: ROUTES.SETTINGS_LANGUAGE, + exact: true, + }, + Settings_Preferences_Theme: { + path: ROUTES.SETTINGS_THEME, + exact: true, + }, + Settings_Close: { + path: ROUTES.SETTINGS_CLOSE, + exact: true, + }, + Settings_Wallet_DomainCards: { + path: ROUTES.SETTINGS_WALLET_DOMAINCARD.route, + exact: true, + }, + Settings_Wallet_ReportVirtualCardFraud: { + path: ROUTES.SETTINGS_REPORT_FRAUD.route, + exact: true, + }, + Settings_Wallet_EnablePayments: { + path: ROUTES.SETTINGS_ENABLE_PAYMENTS, + exact: true, + }, + Settings_Wallet_Transfer_Balance: { + path: ROUTES.SETTINGS_WALLET_TRANSFER_BALANCE, + exact: true, + }, + Settings_Wallet_Choose_Transfer_Account: { + path: ROUTES.SETTINGS_WALLET_CHOOSE_TRANSFER_ACCOUNT, + exact: true, + }, + Settings_ReportCardLostOrDamaged: { + path: ROUTES.SETTINGS_WALLET_REPORT_CARD_LOST_OR_DAMAGED.route, + exact: true, + }, + Settings_Wallet_Card_Activate: { + path: ROUTES.SETTINGS_WALLET_CARD_ACTIVATE.route, + exact: true, + }, + Settings_Wallet_Cards_Digital_Details_Update_Address: { + path: ROUTES.SETTINGS_WALLET_CARD_DIGITAL_DETAILS_UPDATE_ADDRESS.route, + exact: true, + }, + Settings_Add_Debit_Card: { + path: ROUTES.SETTINGS_ADD_DEBIT_CARD, + exact: true, + }, + Settings_Add_Bank_Account: { + path: ROUTES.SETTINGS_ADD_BANK_ACCOUNT, + exact: true, + }, + Settings_Pronouns: { + path: ROUTES.SETTINGS_PRONOUNS, + exact: true, + }, + Settings_Display_Name: { + path: ROUTES.SETTINGS_DISPLAY_NAME, + exact: true, + }, + Settings_Timezone: { + path: ROUTES.SETTINGS_TIMEZONE, + exact: true, + }, + Settings_Timezone_Select: { + path: ROUTES.SETTINGS_TIMEZONE_SELECT, + exact: true, + }, + Settings_App_Download_Links: { + path: ROUTES.SETTINGS_APP_DOWNLOAD_LINKS, + exact: true, + }, + Settings_ContactMethods: { + path: ROUTES.SETTINGS_CONTACT_METHODS.route, + exact: true, + }, + Settings_ContactMethodDetails: { + path: ROUTES.SETTINGS_CONTACT_METHOD_DETAILS.route, + }, + Settings_Lounge_Access: { + path: ROUTES.SETTINGS_LOUNGE_ACCESS, + }, + Settings_NewContactMethod: { + path: ROUTES.SETTINGS_NEW_CONTACT_METHOD, + exact: true, + }, + Settings_PersonalDetails_Initial: { + path: ROUTES.SETTINGS_PERSONAL_DETAILS, + exact: true, + }, + Settings_PersonalDetails_LegalName: { + path: ROUTES.SETTINGS_PERSONAL_DETAILS_LEGAL_NAME, + exact: true, + }, + Settings_PersonalDetails_DateOfBirth: { + path: ROUTES.SETTINGS_PERSONAL_DETAILS_DATE_OF_BIRTH, + exact: true, + }, + Settings_PersonalDetails_Address: { + path: ROUTES.SETTINGS_PERSONAL_DETAILS_ADDRESS, + exact: true, + }, + Settings_PersonalDetails_Address_Country: { + path: ROUTES.SETTINGS_PERSONAL_DETAILS_ADDRESS_COUNTRY.route, + exact: true, + }, + Settings_TwoFactorAuth: { + path: ROUTES.SETTINGS_2FA, + exact: true, + }, + [SCREENS.SETTINGS.STATUS]: { + path: ROUTES.SETTINGS_STATUS, + exact: true, + }, + Settings_Status_Set: { + path: ROUTES.SETTINGS_STATUS_SET, + exact: true, + }, + Workspace_Initial: { + path: ROUTES.WORKSPACE_INITIAL.route, + }, + Workspace_Settings: { + path: ROUTES.WORKSPACE_SETTINGS.route, + }, + Workspace_Settings_Currency: { + path: ROUTES.WORKSPACE_SETTINGS_CURRENCY.route, + }, + Workspace_Card: { + path: ROUTES.WORKSPACE_CARD.route, + }, + Workspace_Reimburse: { + path: ROUTES.WORKSPACE_REIMBURSE.route, + }, + Workspace_RateAndUnit: { + path: ROUTES.WORKSPACE_RATE_AND_UNIT.route, + }, + Workspace_Bills: { + path: ROUTES.WORKSPACE_BILLS.route, + }, + Workspace_Invoices: { + path: ROUTES.WORKSPACE_INVOICES.route, + }, + Workspace_Travel: { + path: ROUTES.WORKSPACE_TRAVEL.route, + }, + Workspace_Members: { + path: ROUTES.WORKSPACE_MEMBERS.route, + }, + Workspace_Invite: { + path: ROUTES.WORKSPACE_INVITE.route, + }, + Workspace_Invite_Message: { + path: ROUTES.WORKSPACE_INVITE_MESSAGE.route, + }, + ReimbursementAccount: { + path: ROUTES.BANK_ACCOUNT_WITH_STEP_TO_OPEN.route, + exact: true, + }, + GetAssistance: { + path: ROUTES.GET_ASSISTANCE.route, + }, + KeyboardShortcuts: { + path: ROUTES.KEYBOARD_SHORTCUTS, + }, + } + }, Private_Notes: { screens: { PrivateNotes_View: ROUTES.PRIVATE_NOTES_VIEW.route, @@ -234,28 +406,20 @@ export default { }, SettingsCentralPane: { screens: { - [SCREENS.SETTINGS.WORKSPACES]: { - path: ROUTES.SETTINGS_WORKSPACES, - exact: true, - }, - [SCREENS.SETTINGS.PREFERENCES]: { - path: ROUTES.SETTINGS_PREFERENCES, - exact: true, - }, - Settings_Preferences_PriorityMode: { - path: ROUTES.SETTINGS_PRIORITY_MODE, + Settings_Share_Code: { + path: ROUTES.SETTINGS_SHARE_CODE, exact: true, }, - Settings_Preferences_Language: { - path: ROUTES.SETTINGS_LANGUAGE, + [SCREENS.SETTINGS.WORKSPACES]: { + path: ROUTES.SETTINGS_WORKSPACES, exact: true, }, - Settings_Preferences_Theme: { - path: ROUTES.SETTINGS_THEME, + [SCREENS.SETTINGS.PROFILE]: { + path: ROUTES.SETTINGS_PROFILE, exact: true, }, - Settings_Close: { - path: ROUTES.SETTINGS_CLOSE, + [SCREENS.SETTINGS.PREFERENCES]: { + path: ROUTES.SETTINGS_PREFERENCES, exact: true, }, [SCREENS.SETTINGS.SECURITY]: { @@ -266,180 +430,12 @@ export default { path: ROUTES.SETTINGS_WALLET, exact: true, }, - Settings_Wallet_DomainCards: { - path: ROUTES.SETTINGS_WALLET_DOMAINCARD.route, - exact: true, - }, - Settings_Wallet_ReportVirtualCardFraud: { - path: ROUTES.SETTINGS_REPORT_FRAUD.route, - exact: true, - }, - Settings_Wallet_EnablePayments: { - path: ROUTES.SETTINGS_ENABLE_PAYMENTS, - exact: true, - }, - Settings_Wallet_Transfer_Balance: { - path: ROUTES.SETTINGS_WALLET_TRANSFER_BALANCE, - exact: true, - }, - Settings_Wallet_Choose_Transfer_Account: { - path: ROUTES.SETTINGS_WALLET_CHOOSE_TRANSFER_ACCOUNT, - exact: true, - }, - Settings_ReportCardLostOrDamaged: { - path: ROUTES.SETTINGS_WALLET_REPORT_CARD_LOST_OR_DAMAGED.route, - exact: true, - }, - Settings_Wallet_Card_Activate: { - path: ROUTES.SETTINGS_WALLET_CARD_ACTIVATE.route, - exact: true, - }, - Settings_Wallet_Cards_Digital_Details_Update_Address: { - path: ROUTES.SETTINGS_WALLET_CARD_DIGITAL_DETAILS_UPDATE_ADDRESS.route, - exact: true, - }, - Settings_Add_Debit_Card: { - path: ROUTES.SETTINGS_ADD_DEBIT_CARD, - exact: true, - }, - Settings_Add_Bank_Account: { - path: ROUTES.SETTINGS_ADD_BANK_ACCOUNT, - exact: true, - }, - [SCREENS.SETTINGS.PROFILE]: { - path: ROUTES.SETTINGS_PROFILE, - exact: true, - }, - Settings_Pronouns: { - path: ROUTES.SETTINGS_PRONOUNS, - exact: true, - }, - Settings_Display_Name: { - path: ROUTES.SETTINGS_DISPLAY_NAME, - exact: true, - }, - Settings_Timezone: { - path: ROUTES.SETTINGS_TIMEZONE, - exact: true, - }, - Settings_Timezone_Select: { - path: ROUTES.SETTINGS_TIMEZONE_SELECT, - exact: true, - }, Settings_About: { path: ROUTES.SETTINGS_ABOUT, exact: true, }, - Settings_App_Download_Links: { - path: ROUTES.SETTINGS_APP_DOWNLOAD_LINKS, - exact: true, - }, - Settings_ContactMethods: { - path: ROUTES.SETTINGS_CONTACT_METHODS.route, - exact: true, - }, - Settings_ContactMethodDetails: { - path: ROUTES.SETTINGS_CONTACT_METHOD_DETAILS.route, - }, - Settings_Lounge_Access: { - path: ROUTES.SETTINGS_LOUNGE_ACCESS, - }, - Settings_NewContactMethod: { - path: ROUTES.SETTINGS_NEW_CONTACT_METHOD, - exact: true, - }, - Settings_PersonalDetails_Initial: { - path: ROUTES.SETTINGS_PERSONAL_DETAILS, - exact: true, - }, - Settings_PersonalDetails_LegalName: { - path: ROUTES.SETTINGS_PERSONAL_DETAILS_LEGAL_NAME, - exact: true, - }, - Settings_PersonalDetails_DateOfBirth: { - path: ROUTES.SETTINGS_PERSONAL_DETAILS_DATE_OF_BIRTH, - exact: true, - }, - Settings_PersonalDetails_Address: { - path: ROUTES.SETTINGS_PERSONAL_DETAILS_ADDRESS, - exact: true, - }, - Settings_PersonalDetails_Address_Country: { - path: ROUTES.SETTINGS_PERSONAL_DETAILS_ADDRESS_COUNTRY.route, - exact: true, - }, - Settings_TwoFactorAuth: { - path: ROUTES.SETTINGS_2FA, - exact: true, - }, - Settings_Share_Code: { - path: ROUTES.SETTINGS_SHARE_CODE, - exact: true, - }, - [SCREENS.SETTINGS.STATUS]: { - path: ROUTES.SETTINGS_STATUS, - exact: true, - }, - Settings_Status_Set: { - path: ROUTES.SETTINGS_STATUS_SET, - exact: true, - }, - Workspace_Initial: { - path: ROUTES.WORKSPACE_INITIAL.route, - }, - Workspace_Settings: { - path: ROUTES.WORKSPACE_SETTINGS.route, - }, - Workspace_Settings_Currency: { - path: ROUTES.WORKSPACE_SETTINGS_CURRENCY.route, - }, - Workspace_Card: { - path: ROUTES.WORKSPACE_CARD.route, - }, - Workspace_Reimburse: { - path: ROUTES.WORKSPACE_REIMBURSE.route, - }, - Workspace_RateAndUnit: { - path: ROUTES.WORKSPACE_RATE_AND_UNIT.route, - }, - Workspace_Bills: { - path: ROUTES.WORKSPACE_BILLS.route, - }, - Workspace_Invoices: { - path: ROUTES.WORKSPACE_INVOICES.route, - }, - Workspace_Travel: { - path: ROUTES.WORKSPACE_TRAVEL.route, - }, - Workspace_Members: { - path: ROUTES.WORKSPACE_MEMBERS.route, - }, - Workspace_Invite: { - path: ROUTES.WORKSPACE_INVITE.route, - }, - Workspace_Invite_Message: { - path: ROUTES.WORKSPACE_INVITE_MESSAGE.route, - }, - ReimbursementAccount: { - path: ROUTES.BANK_ACCOUNT_WITH_STEP_TO_OPEN.route, - exact: true, - }, - GetAssistance: { - path: ROUTES.GET_ASSISTANCE.route, - }, - KeyboardShortcuts: { - path: ROUTES.KEYBOARD_SHORTCUTS, - }, }, }, - // Settings: { - // screens: { - // [SCREENS.SETTINGS_NEW_PROFILE]: { - // path: ROUTES.SETTINGS_NEW_PROFILE, - // exact: true, - // }, - // } - // } }, } }, From f24f917933ccbda3a92e95bd0508932f62684f88 Mon Sep 17 00:00:00 2001 From: Jakub Kosmydel <104823336+kosmydel@users.noreply.github.com> Date: Thu, 23 Nov 2023 10:30:07 +0100 Subject: [PATCH 035/722] general refactor --- src/components/HeaderWithBackButton/index.js | 7 +++++-- src/pages/ShareCodePage.js | 1 + src/pages/settings/AboutPage/AboutPage.js | 1 + src/pages/settings/Preferences/PreferencesPage.js | 1 + src/pages/settings/Profile/LoungeAccessPage.js | 2 +- src/pages/settings/Profile/ProfilePage.js | 1 + src/pages/settings/Security/SecuritySettingsPage.js | 1 + src/pages/settings/Wallet/WalletPage/WalletPage.js | 1 + src/pages/workspace/WorkspacesListPage.js | 1 + 9 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/components/HeaderWithBackButton/index.js b/src/components/HeaderWithBackButton/index.js index edb3b8d26831..528ddb3ad310 100755 --- a/src/components/HeaderWithBackButton/index.js +++ b/src/components/HeaderWithBackButton/index.js @@ -1,5 +1,5 @@ import React from 'react'; -import {Keyboard, View} from 'react-native'; +import { Keyboard, View } from 'react-native'; import AvatarWithDisplayName from '@components/AvatarWithDisplayName'; import Header from '@components/Header'; import Icon from '@components/Icon'; @@ -18,6 +18,7 @@ import * as StyleUtils from '@styles/StyleUtils'; import useThemeStyles from '@styles/useThemeStyles'; import CONST from '@src/CONST'; import ROUTES from '@src/ROUTES'; +import useWindowDimensions from '@hooks/useWindowDimensions'; import headerWithBackButtonPropTypes from './headerWithBackButtonPropTypes'; function HeaderWithBackButton({ @@ -40,6 +41,7 @@ function HeaderWithBackButton({ shouldShowPinButton = false, shouldShowThreeDotsButton = false, shouldDisableThreeDotsButton = false, + shouldShowBackButtonOnlyOnMobile = false, stepCounter = null, subtitle = '', title = '', @@ -59,6 +61,7 @@ function HeaderWithBackButton({ const {translate} = useLocalize(); const {isKeyboardShown} = useKeyboardState(); const waitForNavigate = useWaitForNavigation(); + const {isSmallScreenWidth} = useWindowDimensions(); return ( - {shouldShowBackButton && ( + {shouldShowBackButton && (!shouldShowBackButtonOnlyOnMobile || isSmallScreenWidth) && ( { diff --git a/src/pages/ShareCodePage.js b/src/pages/ShareCodePage.js index d8322b8c58d5..05a3578557f4 100644 --- a/src/pages/ShareCodePage.js +++ b/src/pages/ShareCodePage.js @@ -82,6 +82,7 @@ class ShareCodePage extends React.Component { Navigation.goBack(isReport ? ROUTES.REPORT_WITH_ID_DETAILS.getRoute(this.props.report.reportID) : ROUTES.SETTINGS)} + shouldShowBackButtonOnlyOnMobile /> diff --git a/src/pages/settings/AboutPage/AboutPage.js b/src/pages/settings/AboutPage/AboutPage.js index a88a07117f08..59adb9a7befc 100644 --- a/src/pages/settings/AboutPage/AboutPage.js +++ b/src/pages/settings/AboutPage/AboutPage.js @@ -104,6 +104,7 @@ function AboutPage(props) { Navigation.goBack(ROUTES.SETTINGS)} + shouldShowBackButtonOnlyOnMobile /> diff --git a/src/pages/settings/Preferences/PreferencesPage.js b/src/pages/settings/Preferences/PreferencesPage.js index 0c02fe9772fb..cf2aee9d930d 100755 --- a/src/pages/settings/Preferences/PreferencesPage.js +++ b/src/pages/settings/Preferences/PreferencesPage.js @@ -47,6 +47,7 @@ function PreferencesPage(props) { title={translate('common.preferences')} backgroundColor={theme.PAGE_BACKGROUND_COLORS[SCREENS.SETTINGS.PREFERENCES]} illustration={LottieAnimations.PreferencesDJ} + shouldShowBackButtonOnlyOnMobile > Navigation.goBack(ROUTES.SETTINGS)} + onBackButtonPress={() => Navigation.goBack(ROUTES)} illustration={LottieAnimations.ExpensifyLounge} > Navigation.goBack(ROUTES.SETTINGS)} + shouldShowBackButtonOnlyOnMobile /> diff --git a/src/pages/settings/Wallet/WalletPage/WalletPage.js b/src/pages/settings/Wallet/WalletPage/WalletPage.js index 23d4112eea21..2a6ae9dc7105 100644 --- a/src/pages/settings/Wallet/WalletPage/WalletPage.js +++ b/src/pages/settings/Wallet/WalletPage/WalletPage.js @@ -326,6 +326,7 @@ function WalletPage({bankAccountList, betas, cardList, fundList, isLoadingPaymen Navigation.goBack(ROUTES.SETTINGS)} + shouldShowBackButtonOnlyOnMobile /> diff --git a/src/pages/workspace/WorkspacesListPage.js b/src/pages/workspace/WorkspacesListPage.js index dc0c6d8b3043..dbb73d9dd300 100755 --- a/src/pages/workspace/WorkspacesListPage.js +++ b/src/pages/workspace/WorkspacesListPage.js @@ -189,6 +189,7 @@ function WorkspacesListPage({policies, allPolicyMembers, reimbursementAccount, u illustration={LottieAnimations.WorkspacePlanet} onBackButtonPress={() => Navigation.goBack(ROUTES.SETTINGS)} title={translate('common.workspaces')} + shouldShowBackButtonOnlyOnMobile footer={ ); @@ -73,7 +72,6 @@ function ChronosOOOListActions(props) { ); } -ChronosOOOListActions.propTypes = propTypes; ChronosOOOListActions.displayName = 'ChronosOOOListActions'; -export default withLocalize(ChronosOOOListActions); +export default ChronosOOOListActions; diff --git a/src/libs/DateUtils.ts b/src/libs/DateUtils.ts index 80eae24d9367..e7eaca2aab6a 100644 --- a/src/libs/DateUtils.ts +++ b/src/libs/DateUtils.ts @@ -210,7 +210,7 @@ function getZoneAbbreviation(datetime: string, selectedTimezone: SelectedTimezon * * @returns Sunday, July 9, 2023 */ -function formatToLongDateWithWeekday(datetime: string): string { +function formatToLongDateWithWeekday(datetime: string | Date): string { return format(new Date(datetime), CONST.DATE.LONG_DATE_FORMAT_WITH_WEEKDAY); } @@ -228,7 +228,7 @@ function formatToDayOfWeek(datetime: string): string { * * @returns 2:30 PM */ -function formatToLocalTime(datetime: string): string { +function formatToLocalTime(datetime: string | Date): string { return format(new Date(datetime), CONST.DATE.LOCAL_TIME_FORMAT); } diff --git a/src/types/onyx/OriginalMessage.ts b/src/types/onyx/OriginalMessage.ts index fc7f8eb8ba31..1b949ac48a3f 100644 --- a/src/types/onyx/OriginalMessage.ts +++ b/src/types/onyx/OriginalMessage.ts @@ -234,4 +234,16 @@ type OriginalMessage = | OriginalMessageMoved; export default OriginalMessage; -export type {ChronosOOOEvent, Decision, Reaction, ActionName, IOUMessage, Closed, OriginalMessageActionName, ChangeLog, OriginalMessageIOU, OriginalMessageCreated}; +export type { + ChronosOOOEvent, + Decision, + Reaction, + ActionName, + IOUMessage, + Closed, + OriginalMessageActionName, + ChangeLog, + OriginalMessageIOU, + OriginalMessageCreated, + OriginalMessageChronosOOOList, +}; From 1e162ea851278c4c4df66f5ece28d44d5068b6ff Mon Sep 17 00:00:00 2001 From: Jakub Kosmydel <104823336+kosmydel@users.noreply.github.com> Date: Wed, 13 Dec 2023 12:29:00 +0100 Subject: [PATCH 090/722] move avatar picker --- src/pages/settings/InitialSettingsPage.js | 29 ++++++++++++++++++----- src/pages/settings/Profile/ProfilePage.js | 22 ----------------- src/styles/styles.ts | 6 +++++ 3 files changed, 29 insertions(+), 28 deletions(-) diff --git a/src/pages/settings/InitialSettingsPage.js b/src/pages/settings/InitialSettingsPage.js index 63718da5c75e..65c3c6bc3427 100755 --- a/src/pages/settings/InitialSettingsPage.js +++ b/src/pages/settings/InitialSettingsPage.js @@ -5,7 +5,7 @@ import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react'; import {View} from 'react-native'; import {withOnyx} from 'react-native-onyx'; import _ from 'underscore'; -import Avatar from '@components/Avatar'; +import AvatarWithImagePicker from '@components/AvatarWithImagePicker'; import bankAccountPropTypes from '@components/bankAccountPropTypes'; import cardPropTypes from '@components/cardPropTypes'; import ConfirmModal from '@components/ConfirmModal'; @@ -35,6 +35,7 @@ import useTheme from '@styles/themes/useTheme'; import useThemeStyles from '@styles/useThemeStyles'; import * as Link from '@userActions/Link'; import * as PaymentMethods from '@userActions/PaymentMethods'; +import * as PersonalDetails from '@userActions/PersonalDetails'; import * as Session from '@userActions/Session'; import * as Wallet from '@userActions/Wallet'; import CONST from '@src/CONST'; @@ -277,6 +278,10 @@ function InitialSettingsPage(props) { const accountMenuItems = useMemo(() => getMenuItemsSection(accountMenuItemsData), [accountMenuItemsData, getMenuItemsSection]); const generalMenuItems = useMemo(() => getMenuItemsSection(generaltMenuItemsData), [generaltMenuItemsData, getMenuItemsSection]); + const currentUserDetails = props.currentUserPersonalDetails || {}; + const avatarURL = lodashGet(currentUserDetails, 'avatar', ''); + const accountID = lodashGet(currentUserDetails, 'accountID', ''); + const headerContent = ( {_.isEmpty(props.currentUserPersonalDetails) || _.isUndefined(props.currentUserPersonalDetails.displayName) ? ( @@ -292,11 +297,23 @@ function InitialSettingsPage(props) { role={CONST.ACCESSIBILITY_ROLE.BUTTON} > - diff --git a/src/pages/settings/Profile/ProfilePage.js b/src/pages/settings/Profile/ProfilePage.js index efbef57dd920..b9698702503c 100755 --- a/src/pages/settings/Profile/ProfilePage.js +++ b/src/pages/settings/Profile/ProfilePage.js @@ -4,7 +4,6 @@ import React, {useEffect} from 'react'; import {ScrollView, View} from 'react-native'; import {withOnyx} from 'react-native-onyx'; import _ from 'underscore'; -import AvatarWithImagePicker from '@components/AvatarWithImagePicker'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import * as Expensicons from '@components/Icon/Expensicons'; import MenuItem from '@components/MenuItem'; @@ -19,7 +18,6 @@ import * as UserUtils from '@libs/UserUtils'; import userPropTypes from '@pages/settings/userPropTypes'; import useThemeStyles from '@styles/useThemeStyles'; import * as App from '@userActions/App'; -import * as PersonalDetails from '@userActions/PersonalDetails'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; @@ -66,8 +64,6 @@ function ProfilePage(props) { }; const currentUserDetails = props.currentUserPersonalDetails || {}; const contactMethodBrickRoadIndicator = UserUtils.getLoginListBrickRoadIndicator(props.loginList); - const avatarURL = lodashGet(currentUserDetails, 'avatar', ''); - const accountID = lodashGet(currentUserDetails, 'accountID', ''); const emojiCode = lodashGet(props, 'currentUserPersonalDetails.status.emojiCode', ''); const profileSettingsOptions = [ @@ -116,24 +112,6 @@ function ProfilePage(props) { shouldUseCentralPaneView /> - {_.map(profileSettingsOptions, (detail, index) => ( vertical: windowHeight - 75, } satisfies AnchorPosition), + createAccountMenuPositionProfile: () => + ({ + horizontal: 18, + ...getPopOverVerticalOffset(162), + } satisfies AnchorPosition), + createMenuPositionProfile: (windowWidth: number) => ({ horizontal: windowWidth - 355, From f2ddfa2858406c9defe6dc92b326c59931211666 Mon Sep 17 00:00:00 2001 From: Jakub Kosmydel <104823336+kosmydel@users.noreply.github.com> Date: Wed, 13 Dec 2023 12:34:08 +0100 Subject: [PATCH 091/722] add bottom borders --- src/pages/ShareCodePage.js | 1 + src/pages/settings/Profile/ProfilePage.js | 1 + 2 files changed, 2 insertions(+) diff --git a/src/pages/ShareCodePage.js b/src/pages/ShareCodePage.js index e734ce4ec16e..8a3ba71082a5 100644 --- a/src/pages/ShareCodePage.js +++ b/src/pages/ShareCodePage.js @@ -83,6 +83,7 @@ class ShareCodePage extends React.Component { title={this.props.translate('common.shareCode')} onBackButtonPress={() => Navigation.goBack(isReport ? ROUTES.REPORT_WITH_ID_DETAILS.getRoute(this.props.report.reportID) : ROUTES.SETTINGS_HOME)} shouldUseCentralPaneView + shouldShowBorderBottom /> diff --git a/src/pages/settings/Profile/ProfilePage.js b/src/pages/settings/Profile/ProfilePage.js index b9698702503c..197de876cbdc 100755 --- a/src/pages/settings/Profile/ProfilePage.js +++ b/src/pages/settings/Profile/ProfilePage.js @@ -110,6 +110,7 @@ function ProfilePage(props) { title={props.translate('common.profile')} onBackButtonPress={() => Navigation.goBack(ROUTES.SETTINGS_HOME)} shouldUseCentralPaneView + shouldShowBorderBottom /> From 00925563e1f756a8481b88c114efa3e94efa90dc Mon Sep 17 00:00:00 2001 From: Jakub Kosmydel <104823336+kosmydel@users.noreply.github.com> Date: Wed, 13 Dec 2023 13:06:25 +0100 Subject: [PATCH 092/722] complete merge with main --- .../AppNavigator/ModalStackNavigators.tsx | 14 +++++++------- .../CustomFullScreenRouter.tsx | 2 +- .../createCustomStackNavigator/CustomRouter.ts | 10 ++-------- src/libs/Navigation/linkingConfig.ts | 4 ++-- src/libs/Navigation/types.ts | 10 +++++----- 5 files changed, 17 insertions(+), 23 deletions(-) diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators.tsx b/src/libs/Navigation/AppNavigator/ModalStackNavigators.tsx index eda0b95b911a..622e761018a0 100644 --- a/src/libs/Navigation/AppNavigator/ModalStackNavigators.tsx +++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators.tsx @@ -28,10 +28,10 @@ import type { TeachersUniteNavigatorParamList, WalletStatementNavigatorParamList, } from '@navigation/types'; -import styles from '@styles/styles'; import useThemeStyles from '@styles/useThemeStyles'; import SCREENS from '@src/SCREENS'; import type {Screen} from '@src/SCREENS'; +import { ThemeStyles } from '@styles/styles'; type Screens = Partial React.ComponentType>>; @@ -40,7 +40,7 @@ type Screens = Partial React.ComponentType>>; * * @param screens key/value pairs where the key is the name of the screen and the value is a functon that returns the lazy-loaded component */ -function createModalStackNavigator(screens: Screens, screenOptions?: StackNavigationOptions): React.ComponentType { +function createModalStackNavigator(screens: Screens, getScreenOptions?: (styles: ThemeStyles) => StackNavigationOptions): React.ComponentType { const ModalStackNavigator = createStackNavigator(); function ModalStack() { @@ -56,7 +56,7 @@ function createModalStackNavigator(screens: ); return ( - + {Object.keys(screens as Required).map((name) => ( require('../../../pages/workspace/WorkspacesListPage').default as React.ComponentType, - [SCREENS.SETTINGS.PREFERENCES]: () => require('../../../pages/settings/Preferences/PreferencesPage').default as React.ComponentType, + [SCREENS.SETTINGS.PREFERENCES.ROOT]: () => require('../../../pages/settings/Preferences/PreferencesPage').default as React.ComponentType, [SCREENS.SETTINGS.SECURITY]: () => require('../../../pages/settings/Security/SecuritySettingsPage').default as React.ComponentType, - [SCREENS.SETTINGS.PROFILE]: () => require('../../../pages/settings/Profile/ProfilePage').default as React.ComponentType, + [SCREENS.SETTINGS.PROFILE.ROOT]: () => require('../../../pages/settings/Profile/ProfilePage').default as React.ComponentType, [SCREENS.SETTINGS.SHARE_CODE]: () => require('../../../pages/ShareCodePage').default as React.ComponentType, - [SCREENS.SETTINGS.WALLET]: () => require('../../../pages/settings/Wallet/WalletPage').default as React.ComponentType, + [SCREENS.SETTINGS.WALLET.ROOT]: () => require('../../../pages/settings/Wallet/WalletPage').default as React.ComponentType, [SCREENS.SETTINGS.ABOUT]: () => require('../../../pages/settings/AboutPage/AboutPage').default as React.ComponentType, }, - {cardStyle: styles.navigationScreenCardStyle, headerShown: false}, + (styles) => ({cardStyle: styles.navigationScreenCardStyle, headerShown: false}), ); const SettingsModalStackNavigator = createModalStackNavigator({ diff --git a/src/libs/Navigation/AppNavigator/createCustomFullScreenNavigator/CustomFullScreenRouter.tsx b/src/libs/Navigation/AppNavigator/createCustomFullScreenNavigator/CustomFullScreenRouter.tsx index 5b15e2b1f3ad..5e402162a349 100644 --- a/src/libs/Navigation/AppNavigator/createCustomFullScreenNavigator/CustomFullScreenRouter.tsx +++ b/src/libs/Navigation/AppNavigator/createCustomFullScreenNavigator/CustomFullScreenRouter.tsx @@ -20,7 +20,7 @@ const addCentralPaneNavigatorRoute = (state: State) => { state: { routes: [ { - name: SCREENS.SETTINGS.PROFILE, + name: SCREENS.SETTINGS.PROFILE.ROOT, }, ], }, diff --git a/src/libs/Navigation/AppNavigator/createCustomStackNavigator/CustomRouter.ts b/src/libs/Navigation/AppNavigator/createCustomStackNavigator/CustomRouter.ts index 797afd3337d9..738cd8ec9de3 100644 --- a/src/libs/Navigation/AppNavigator/createCustomStackNavigator/CustomRouter.ts +++ b/src/libs/Navigation/AppNavigator/createCustomStackNavigator/CustomRouter.ts @@ -59,13 +59,7 @@ const addCentralPaneNavigatorRoute = (state: State) => { }; const mapScreenNameToSettingsScreenName: Record = { - [SCREENS.SETTINGS.DISPLAY_NAME]: SCREENS.SETTINGS.PROFILE, - [SCREENS.SETTINGS.CONTACT_METHODS]: SCREENS.SETTINGS.PROFILE, - [SCREENS.SETTINGS.CONTACT_METHOD_DETAILS]: SCREENS.SETTINGS.PROFILE, - [SCREENS.SETTINGS.SECURITY]: SCREENS.SETTINGS.SECURITY, - [SCREENS.SETTINGS.PREFERENCES_LANGUAGE]: SCREENS.SETTINGS.PREFERENCES, - [SCREENS.SETTINGS.PREFERENCES_THEME]: SCREENS.SETTINGS.PREFERENCES, - [SCREENS.SETTINGS.PREFERENCES_PRIORITY_MODE]: SCREENS.SETTINGS.PREFERENCES, + // [SCREENS.SETTINGS.PROFILE.CONTACT_METHODS]: SCREENS.SETTINGS.PROFILE, }; const handleSettingsOpened = (state: State) => { @@ -89,7 +83,7 @@ const handleSettingsOpened = (state: State) => { return; } - const settingsHomeRouteName = mapScreenNameToSettingsScreenName[settingsScreenName] || SCREENS.SETTINGS.PROFILE; + const settingsHomeRouteName = mapScreenNameToSettingsScreenName[settingsScreenName] || SCREENS.SETTINGS.PROFILE.ROOT; const fullScreenRoute = { name: NAVIGATORS.FULL_SCREEN_NAVIGATOR, diff --git a/src/libs/Navigation/linkingConfig.ts b/src/libs/Navigation/linkingConfig.ts index d7a5312668b1..dd0b328a3222 100644 --- a/src/libs/Navigation/linkingConfig.ts +++ b/src/libs/Navigation/linkingConfig.ts @@ -472,7 +472,7 @@ const linkingConfig: LinkingOptions = { path: ROUTES.SETTINGS_WORKSPACES, exact: true, }, - [SCREENS.SETTINGS.PROFILE.STATUS]: { + [SCREENS.SETTINGS.PROFILE.ROOT]: { path: ROUTES.SETTINGS_PROFILE, exact: true, }, @@ -484,7 +484,7 @@ const linkingConfig: LinkingOptions = { path: ROUTES.SETTINGS_SECURITY, exact: true, }, - Settings_Wallet: { + [SCREENS.SETTINGS.WALLET.ROOT]: { path: ROUTES.SETTINGS_WALLET, exact: true, }, diff --git a/src/libs/Navigation/types.ts b/src/libs/Navigation/types.ts index 0887d22d4f1e..f6a10298530f 100644 --- a/src/libs/Navigation/types.ts +++ b/src/libs/Navigation/types.ts @@ -360,13 +360,13 @@ type RightModalNavigatorParamList = { }; type SettingsCentralPaneNavigatorParamList = { - Settings_Share_Code: undefined; + [SCREENS.SETTINGS.SHARE_CODE]: undefined; [SCREENS.SETTINGS.WORKSPACES]: undefined; - [SCREENS.SETTINGS.PROFILE]: undefined; - [SCREENS.SETTINGS.PREFERENCES]: undefined; + [SCREENS.SETTINGS.PROFILE.ROOT]: undefined; + [SCREENS.SETTINGS.PREFERENCES.ROOT]: undefined; [SCREENS.SETTINGS.SECURITY]: undefined; - Settings_Wallet: undefined; - Settings_About: undefined; + [SCREENS.SETTINGS.WALLET.ROOT]: undefined; + [SCREENS.SETTINGS.ABOUT]: undefined; }; type FullScreenNavigatorParamList = { From 307e668ad6e2c77f435b3313f3e15bb6405543d9 Mon Sep 17 00:00:00 2001 From: Jakub Kosmydel <104823336+kosmydel@users.noreply.github.com> Date: Wed, 13 Dec 2023 13:33:19 +0100 Subject: [PATCH 093/722] fix issues --- src/components/AvatarWithImagePicker.js | 10 +++++++--- src/components/IllustratedHeaderPageLayout.js | 1 - src/components/QRShare/index.js | 2 +- .../Navigation/AppNavigator/ModalStackNavigators.tsx | 2 +- .../CustomFullScreenRouter.tsx | 2 -- src/pages/settings/AboutPage/AboutPage.js | 1 + src/pages/settings/InitialSettingsPage.js | 3 ++- src/pages/workspace/WorkspaceSettingsPage.js | 1 + 8 files changed, 13 insertions(+), 9 deletions(-) diff --git a/src/components/AvatarWithImagePicker.js b/src/components/AvatarWithImagePicker.js index 9b061ba5c670..11d0e4e7b45c 100644 --- a/src/components/AvatarWithImagePicker.js +++ b/src/components/AvatarWithImagePicker.js @@ -94,6 +94,9 @@ const propTypes = { horizontal: PropTypes.oneOf(_.values(CONST.MODAL.ANCHOR_ORIGIN_HORIZONTAL)), vertical: PropTypes.oneOf(_.values(CONST.MODAL.ANCHOR_ORIGIN_VERTICAL)), }), + + /** Style applied to the avatar */ + avatarStyle: stylePropTypes.isRequired, }; const defaultProps = { @@ -141,6 +144,7 @@ function AvatarWithImagePicker({ anchorAlignment, onImageSelected, editorMaskImage, + avatarStyle, }) { const theme = useTheme(); const styles = useThemeStyles(); @@ -287,7 +291,7 @@ function AvatarWithImagePicker({ return ( - + {source ? ( React.ComponentType>>; diff --git a/src/libs/Navigation/AppNavigator/createCustomFullScreenNavigator/CustomFullScreenRouter.tsx b/src/libs/Navigation/AppNavigator/createCustomFullScreenNavigator/CustomFullScreenRouter.tsx index 5e402162a349..fbd62595f5b6 100644 --- a/src/libs/Navigation/AppNavigator/createCustomFullScreenNavigator/CustomFullScreenRouter.tsx +++ b/src/libs/Navigation/AppNavigator/createCustomFullScreenNavigator/CustomFullScreenRouter.tsx @@ -11,8 +11,6 @@ const isAtLeastOneInState = (state: State, screenName: string): boolean => !!sta /** * Adds report route without any specific reportID to the state. * The report screen will self set proper reportID param based on the helper function findLastAccessedReport (look at ReportScreenWrapper for more info) - * - * @param {Object} state - react-navigation state */ const addCentralPaneNavigatorRoute = (state: State) => { const centralPaneNavigatorRoute = { diff --git a/src/pages/settings/AboutPage/AboutPage.js b/src/pages/settings/AboutPage/AboutPage.js index ac56758080cc..ac96c802d597 100644 --- a/src/pages/settings/AboutPage/AboutPage.js +++ b/src/pages/settings/AboutPage/AboutPage.js @@ -105,6 +105,7 @@ function AboutPage(props) { title={props.translate('initialSettingsPage.about')} onBackButtonPress={() => Navigation.goBack(ROUTES.SETTINGS_HOME)} shouldUseCentralPaneView + shouldShowBorderBottom /> diff --git a/src/pages/settings/InitialSettingsPage.js b/src/pages/settings/InitialSettingsPage.js index 0c9849e71ec7..6513d2e2b05e 100755 --- a/src/pages/settings/InitialSettingsPage.js +++ b/src/pages/settings/InitialSettingsPage.js @@ -301,7 +301,8 @@ function InitialSettingsPage(props) { onImageRemoved={PersonalDetails.deleteAvatar} anchorPosition={styles.createAccountMenuPositionProfile(props.windowWidth)} anchorAlignment={{horizontal: CONST.MODAL.ANCHOR_ORIGIN_HORIZONTAL.LEFT, vertical: CONST.MODAL.ANCHOR_ORIGIN_VERTICAL.TOP}} - size={CONST.AVATAR_SIZE.LARGE} + size={CONST.AVATAR_SIZE.XLARGE} + avatarStyle={styles.avatarXLarge} pendingAction={lodashGet(props.currentUserPersonalDetails, 'pendingFields.avatar', null)} errors={lodashGet(props.currentUserPersonalDetails, 'errorFields.avatar', null)} errorRowStyles={[styles.mt6]} diff --git a/src/pages/workspace/WorkspaceSettingsPage.js b/src/pages/workspace/WorkspaceSettingsPage.js index d121134f26da..5f4e22711a5c 100644 --- a/src/pages/workspace/WorkspaceSettingsPage.js +++ b/src/pages/workspace/WorkspaceSettingsPage.js @@ -113,6 +113,7 @@ function WorkspaceSettingsPage({policy, currencyList, windowWidth, route}) { ( Date: Wed, 13 Dec 2023 17:53:25 +0300 Subject: [PATCH 094/722] minor fix --- src/pages/PrivateNotes/PrivateNotesEditPage.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/pages/PrivateNotes/PrivateNotesEditPage.js b/src/pages/PrivateNotes/PrivateNotesEditPage.js index cb8d079f29e9..966088b66ea2 100644 --- a/src/pages/PrivateNotes/PrivateNotesEditPage.js +++ b/src/pages/PrivateNotes/PrivateNotesEditPage.js @@ -54,6 +54,7 @@ const defaultProps = { function PrivateNotesEditPage({route, personalDetailsList, report}) { const styles = useThemeStyles(); const {translate} = useLocalize(); + // We need to edit the note in markdown format, but display it in HTML format const parser = new ExpensiMark(); const [privateNote, setPrivateNote] = useState( From 520186968b576a49e179e9751da6c50ab3f3c418 Mon Sep 17 00:00:00 2001 From: Adam Grzybowski Date: Tue, 12 Dec 2023 16:30:06 +0100 Subject: [PATCH 095/722] add const for bottom tab --- src/CONST.ts | 14 ++++++++++++++ src/NAVIGATORS.ts | 1 + src/ROUTES.ts | 2 ++ src/SCREENS.ts | 1 + 4 files changed, 18 insertions(+) diff --git a/src/CONST.ts b/src/CONST.ts index 072f780b54ae..fc355887d833 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -3018,6 +3018,20 @@ const CONST = { DEFAULT: 5, CAROUSEL: 3, }, + + TAB_TO_CENTRAL_PANE_MAPPING: { + [SCREENS.HOME]: [SCREENS.REPORT], + [SCREENS.ALL_SETTINGS]: [SCREENS.SETTINGS.WORKSPACES], + [SCREENS.WORKSPACE.INITIAL]: [ + SCREENS.WORKSPACE.SETTINGS, + SCREENS.WORKSPACE.CARD, + SCREENS.WORKSPACE.REIMBURSE, + SCREENS.WORKSPACE.BILLS, + SCREENS.WORKSPACE.INVOICES, + SCREENS.WORKSPACE.TRAVEL, + SCREENS.WORKSPACE.MEMBERS, + ], + }, } as const; export default CONST; diff --git a/src/NAVIGATORS.ts b/src/NAVIGATORS.ts index a3a041e65684..4bc11c5e1856 100644 --- a/src/NAVIGATORS.ts +++ b/src/NAVIGATORS.ts @@ -4,6 +4,7 @@ * */ export default { CENTRAL_PANE_NAVIGATOR: 'CentralPaneNavigator', + BOTTOM_TAB_NAVIGATOR: 'BottomTabNavigator', RIGHT_MODAL_NAVIGATOR: 'RightModalNavigator', FULL_SCREEN_NAVIGATOR: 'FullScreenNavigator', } as const; diff --git a/src/ROUTES.ts b/src/ROUTES.ts index 425ff73af56b..44563b74d48e 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -14,6 +14,8 @@ function getUrlWithBackToParam(url: TUrl, backTo?: string): const ROUTES = { HOME: '', + ALL_SETTINGS: 'all-settings', + // This is a utility route used to go to the user's concierge chat, or the sign-in page if the user's not authenticated CONCIERGE: 'concierge', FLAG_COMMENT: { diff --git a/src/SCREENS.ts b/src/SCREENS.ts index 921f57953482..44f11c059321 100644 --- a/src/SCREENS.ts +++ b/src/SCREENS.ts @@ -12,6 +12,7 @@ const PROTECTED_SCREENS = { const SCREENS = { ...PROTECTED_SCREENS, + ALL_SETTINGS: 'AllSettings', REPORT: 'Report', NOT_FOUND: 'not-found', TRANSITION_BETWEEN_APPS: 'TransitionBetweenApps', From 4f6e8691d30b844dbb94640718a076d393a6814b Mon Sep 17 00:00:00 2001 From: Adam Grzybowski Date: Tue, 12 Dec 2023 16:30:35 +0100 Subject: [PATCH 096/722] patch for react-navigation --- .../@react-navigation+stack+6.3.16+002+dontDetachScreen.patch | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/patches/@react-navigation+stack+6.3.16+002+dontDetachScreen.patch b/patches/@react-navigation+stack+6.3.16+002+dontDetachScreen.patch index d64fc4fecf74..f7e068686b36 100644 --- a/patches/@react-navigation+stack+6.3.16+002+dontDetachScreen.patch +++ b/patches/@react-navigation+stack+6.3.16+002+dontDetachScreen.patch @@ -43,7 +43,7 @@ index 7558eb3..b7bb75e 100644 }) : STATE_TRANSITIONING_OR_BELOW_TOP; } + -+ const isHomeScreenAndNotOnTop = route.name === 'Home' && isScreenActive !== STATE_ON_TOP; ++ const isHomeScreenAndNotOnTop = route.name === 'BottomTabNavigator' && isScreenActive !== STATE_ON_TOP; + const { headerShown = true, From 1592ff8bd153ded9f55a2577fdcff014c9d14895 Mon Sep 17 00:00:00 2001 From: Adam Grzybowski Date: Tue, 12 Dec 2023 16:30:56 +0100 Subject: [PATCH 097/722] styles for bottom tab navigator --- src/styles/styles.ts | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/styles/styles.ts b/src/styles/styles.ts index fb851ecfcf54..7e60c9f79629 100644 --- a/src/styles/styles.ts +++ b/src/styles/styles.ts @@ -474,6 +474,16 @@ const styles = (theme: ThemeColors) => borderRadius: variables.buttonBorderRadius, }, + bottomTabBarContainer: { + height: 80, + borderTopWidth: 1, + borderTopColor: theme.border, + backgroundColor: theme.appBG, + flexDirection: 'row', + justifyContent: 'space-around', + alignItems: 'center', + }, + button: { backgroundColor: theme.buttonDefaultBG, borderRadius: variables.buttonBorderRadius, @@ -1333,15 +1343,6 @@ const styles = (theme: ThemeColors) => zIndex: 10, } satisfies ViewStyle), - floatingActionButtonContainer: { - position: 'absolute', - right: 20, - - // The bottom of the floating action button should align with the bottom of the compose box. - // The value should be equal to the height + marginBottom + marginTop of chatItemComposeSecondaryRow - bottom: variables.fabBottom, - }, - floatingActionButton: { backgroundColor: theme.success, height: variables.componentSizeLarge, From 4696731a75342ad6d7593b97c0bd84e7b7bbd773 Mon Sep 17 00:00:00 2001 From: Adam Grzybowski Date: Wed, 13 Dec 2023 16:05:58 +0100 Subject: [PATCH 098/722] public bottom tab navigator --- .../Navigators/PublicBottomTabNavigator.tsx | 28 +++++++++++++++++++ .../Navigation/AppNavigator/PublicScreens.tsx | 4 ++- 2 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 src/libs/Navigation/AppNavigator/Navigators/PublicBottomTabNavigator.tsx diff --git a/src/libs/Navigation/AppNavigator/Navigators/PublicBottomTabNavigator.tsx b/src/libs/Navigation/AppNavigator/Navigators/PublicBottomTabNavigator.tsx new file mode 100644 index 000000000000..6ed58c178c2c --- /dev/null +++ b/src/libs/Navigation/AppNavigator/Navigators/PublicBottomTabNavigator.tsx @@ -0,0 +1,28 @@ +import {StackNavigationOptions} from '@react-navigation/stack'; +import React from 'react'; +import createCustomBottomTabNavigator from '@libs/Navigation/AppNavigator/createCustomBottomTabNavigator'; +import {BottomTabNavigatorParamList} from '@libs/Navigation/types'; +import SignInPage from '@pages/signin/SignInPage'; +import SCREENS from '@src/SCREENS'; + +const Tab = createCustomBottomTabNavigator(); + +const screenOptions: StackNavigationOptions = { + headerShown: false, +}; + +// The structure for the HOME route have to be the same in public and auth screens. That's why we need to wrap the HOME screen with "fake" bottomTabNavigator. +function PublicBottomTabNavigator() { + return ( + + + + ); +} + +PublicBottomTabNavigator.displayName = 'BottomTabNavigator'; + +export default PublicBottomTabNavigator; diff --git a/src/libs/Navigation/AppNavigator/PublicScreens.tsx b/src/libs/Navigation/AppNavigator/PublicScreens.tsx index 5c3171214bd9..0324cc85dcfa 100644 --- a/src/libs/Navigation/AppNavigator/PublicScreens.tsx +++ b/src/libs/Navigation/AppNavigator/PublicScreens.tsx @@ -8,6 +8,7 @@ import SAMLSignInPage from '@pages/signin/SAMLSignInPage'; import SignInPage from '@pages/signin/SignInPage'; import UnlinkLoginPage from '@pages/UnlinkLoginPage'; import ValidateLoginPage from '@pages/ValidateLoginPage'; +import NAVIGATORS from '@src/NAVIGATORS'; import SCREENS from '@src/SCREENS'; import defaultScreenOptions from './defaultScreenOptions'; @@ -16,8 +17,9 @@ const RootStack = createStackNavigator(); function PublicScreens() { return ( + {/* The structure for the HOME route have to be the same in public and auth screens. That's why we need to wrap the HOME screen with "fake" bottomTabNavigator. */} From 0f61ed9e9f7d2a01468ee0359883c863277648dd Mon Sep 17 00:00:00 2001 From: Adam Grzybowski Date: Wed, 13 Dec 2023 16:13:30 +0100 Subject: [PATCH 099/722] move workspace screens --- .../AppNavigator/ModalStackNavigators.tsx | 10 ----- .../BaseCentralPaneNavigator.tsx | 37 +++++++++++++++---- 2 files changed, 29 insertions(+), 18 deletions(-) diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators.tsx b/src/libs/Navigation/AppNavigator/ModalStackNavigators.tsx index 29449f52ecd6..c63dd80f7621 100644 --- a/src/libs/Navigation/AppNavigator/ModalStackNavigators.tsx +++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators.tsx @@ -180,7 +180,6 @@ const NewTeachersUniteNavigator = createModalStackNavigator({ [SCREENS.SETTINGS.ROOT]: () => require('../../../pages/settings/InitialSettingsPage').default as React.ComponentType, [SCREENS.SETTINGS.SHARE_CODE]: () => require('../../../pages/ShareCodePage').default as React.ComponentType, - [SCREENS.SETTINGS.WORKSPACES]: () => require('../../../pages/workspace/WorkspacesListPage').default as React.ComponentType, [SCREENS.SETTINGS.PROFILE.ROOT]: () => require('../../../pages/settings/Profile/ProfilePage').default as React.ComponentType, [SCREENS.SETTINGS.PROFILE.PRONOUNS]: () => require('../../../pages/settings/Profile/PronounsPage').default as React.ComponentType, [SCREENS.SETTINGS.PROFILE.DISPLAY_NAME]: () => require('../../../pages/settings/Profile/DisplayNamePage').default as React.ComponentType, @@ -220,16 +219,7 @@ const SettingsModalStackNavigator = createModalStackNavigator require('../../../pages/AddPersonalBankAccountPage').default as React.ComponentType, [SCREENS.SETTINGS.PROFILE.STATUS]: () => require('../../../pages/settings/Profile/CustomStatus/StatusPage').default as React.ComponentType, [SCREENS.SETTINGS.PROFILE.STATUS_SET]: () => require('../../../pages/settings/Profile/CustomStatus/StatusSetPage').default as React.ComponentType, - [SCREENS.WORKSPACE.INITIAL]: () => require('../../../pages/workspace/WorkspaceInitialPage').default as React.ComponentType, - [SCREENS.WORKSPACE.SETTINGS]: () => require('../../../pages/workspace/WorkspaceSettingsPage').default as React.ComponentType, - [SCREENS.WORKSPACE.CURRENCY]: () => require('../../../pages/workspace/WorkspaceSettingsCurrencyPage').default as React.ComponentType, - [SCREENS.WORKSPACE.CARD]: () => require('../../../pages/workspace/card/WorkspaceCardPage').default as React.ComponentType, - [SCREENS.WORKSPACE.REIMBURSE]: () => require('../../../pages/workspace/reimburse/WorkspaceReimbursePage').default as React.ComponentType, [SCREENS.WORKSPACE.RATE_AND_UNIT]: () => require('../../../pages/workspace/reimburse/WorkspaceRateAndUnitPage').default as React.ComponentType, - [SCREENS.WORKSPACE.BILLS]: () => require('../../../pages/workspace/bills/WorkspaceBillsPage').default as React.ComponentType, - [SCREENS.WORKSPACE.INVOICES]: () => require('../../../pages/workspace/invoices/WorkspaceInvoicesPage').default as React.ComponentType, - [SCREENS.WORKSPACE.TRAVEL]: () => require('../../../pages/workspace/travel/WorkspaceTravelPage').default as React.ComponentType, - [SCREENS.WORKSPACE.MEMBERS]: () => require('../../../pages/workspace/WorkspaceMembersPage').default as React.ComponentType, [SCREENS.WORKSPACE.INVITE]: () => require('../../../pages/workspace/WorkspaceInvitePage').default as React.ComponentType, [SCREENS.WORKSPACE.INVITE_MESSAGE]: () => require('../../../pages/workspace/WorkspaceInviteMessagePage').default as React.ComponentType, [SCREENS.REIMBURSEMENT_ACCOUNT]: () => require('../../../pages/ReimbursementAccount/ReimbursementAccountPage').default as React.ComponentType, diff --git a/src/libs/Navigation/AppNavigator/Navigators/CentralPaneNavigator/BaseCentralPaneNavigator.tsx b/src/libs/Navigation/AppNavigator/Navigators/CentralPaneNavigator/BaseCentralPaneNavigator.tsx index 228ea6bd3dce..aade06d10b16 100644 --- a/src/libs/Navigation/AppNavigator/Navigators/CentralPaneNavigator/BaseCentralPaneNavigator.tsx +++ b/src/libs/Navigation/AppNavigator/Navigators/CentralPaneNavigator/BaseCentralPaneNavigator.tsx @@ -11,23 +11,44 @@ const Stack = createStackNavigator(); const url = getCurrentUrl(); const openOnAdminRoom = url ? new URL(url).searchParams.get('openOnAdminRoom') : undefined; +type Screens = Partial React.ComponentType>>; + +const workspaceSettingsScreens = { + [SCREENS.SETTINGS.WORKSPACES]: () => require('../../../../../pages/workspace/WorkspacesListPage').default as React.ComponentType, + [SCREENS.WORKSPACE.SETTINGS]: () => require('../../../../../pages/workspace/WorkspaceSettingsPage').default as React.ComponentType, + [SCREENS.WORKSPACE.CARD]: () => require('../../../../../pages/workspace/card/WorkspaceCardPage').default as React.ComponentType, + [SCREENS.WORKSPACE.REIMBURSE]: () => require('../../../../../pages/workspace/reimburse/WorkspaceReimbursePage').default as React.ComponentType, + [SCREENS.WORKSPACE.BILLS]: () => require('../../../../../pages/workspace/bills/WorkspaceBillsPage').default as React.ComponentType, + [SCREENS.WORKSPACE.INVOICES]: () => require('../../../../../pages/workspace/invoices/WorkspaceInvoicesPage').default as React.ComponentType, + [SCREENS.WORKSPACE.TRAVEL]: () => require('../../../../../pages/workspace/travel/WorkspaceTravelPage').default as React.ComponentType, + [SCREENS.WORKSPACE.MEMBERS]: () => require('../../../../../pages/workspace/WorkspaceMembersPage').default as React.ComponentType, +} satisfies Screens; + function BaseCentralPaneNavigator() { const styles = useThemeStyles(); + const options = { + headerShown: false, + title: 'New Expensify', + + // Prevent unnecessary scrolling + cardStyle: styles.cardStyleNavigator, + }; return ( - + + + {Object.entries(workspaceSettingsScreens).map(([screenName, componentGetter]) => ( + + ))} ); } From c6f16005536cae98e9368e313dd9c238721bb0d5 Mon Sep 17 00:00:00 2001 From: Adam Grzybowski Date: Wed, 13 Dec 2023 16:14:18 +0100 Subject: [PATCH 100/722] improve types for tab to central pane mapping --- src/CONST.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/CONST.ts b/src/CONST.ts index fc355887d833..0dad726d2056 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -1,6 +1,7 @@ /* eslint-disable @typescript-eslint/naming-convention */ import Config from 'react-native-config'; import * as KeyCommand from 'react-native-key-command'; +import {BottomTabName, CentralPaneName} from '@libs/Navigation/types'; import * as Url from './libs/Url'; import SCREENS from './SCREENS'; @@ -3031,7 +3032,7 @@ const CONST = { SCREENS.WORKSPACE.TRAVEL, SCREENS.WORKSPACE.MEMBERS, ], - }, + } satisfies Record, } as const; export default CONST; From 2a22d8aa349277095cc29d7288094e9c1ca2c7c4 Mon Sep 17 00:00:00 2001 From: Adam Grzybowski Date: Wed, 13 Dec 2023 16:22:31 +0100 Subject: [PATCH 101/722] prepare BottomTabBarFloatingActionButton --- src/components/FloatingActionButton.js | 50 +++++++++---------- .../index.native.tsx | 3 ++ .../index.tsx | 42 ++++++++++++++++ .../BottomTabBarFloatingActionButton/types.ts | 5 ++ src/pages/home/sidebar/SidebarScreen/index.js | 36 +------------ 5 files changed, 76 insertions(+), 60 deletions(-) create mode 100644 src/pages/home/sidebar/BottomTabBarFloatingActionButton/index.native.tsx create mode 100644 src/pages/home/sidebar/BottomTabBarFloatingActionButton/index.tsx create mode 100644 src/pages/home/sidebar/BottomTabBarFloatingActionButton/types.ts diff --git a/src/components/FloatingActionButton.js b/src/components/FloatingActionButton.js index 791eb150f8c9..e0bbb2ddbe1c 100644 --- a/src/components/FloatingActionButton.js +++ b/src/components/FloatingActionButton.js @@ -1,6 +1,6 @@ import PropTypes from 'prop-types'; import React, {PureComponent} from 'react'; -import {Animated, Easing, View} from 'react-native'; +import {Animated, Easing} from 'react-native'; import compose from '@libs/compose'; import Icon from './Icon'; import * as Expensicons from './Icon/Expensicons'; @@ -84,31 +84,29 @@ class FloatingActionButton extends PureComponent { return ( - - { - this.fabPressable = el; - if (this.props.buttonRef) { - this.props.buttonRef.current = el; - } - }} - accessibilityLabel={this.props.accessibilityLabel} - role={this.props.role} - pressDimmingValue={1} - onPress={(e) => { - // Drop focus to avoid blue focus ring. - this.fabPressable.blur(); - this.props.onPress(e); - }} - onLongPress={() => {}} - style={[this.props.themeStyles.floatingActionButton, this.props.StyleUtils.getAnimatedFABStyle(rotate, backgroundColor)]} - > - - - + { + this.fabPressable = el; + if (this.props.buttonRef) { + this.props.buttonRef.current = el; + } + }} + accessibilityLabel={this.props.accessibilityLabel} + role={this.props.role} + pressDimmingValue={1} + onPress={(e) => { + // Drop focus to avoid blue focus ring. + this.fabPressable.blur(); + this.props.onPress(e); + }} + onLongPress={() => {}} + style={[this.props.themeStyles.floatingActionButton, this.props.StyleUtils.getAnimatedFABStyle(rotate, backgroundColor)]} + > + + ); } diff --git a/src/pages/home/sidebar/BottomTabBarFloatingActionButton/index.native.tsx b/src/pages/home/sidebar/BottomTabBarFloatingActionButton/index.native.tsx new file mode 100644 index 000000000000..74180256cc74 --- /dev/null +++ b/src/pages/home/sidebar/BottomTabBarFloatingActionButton/index.native.tsx @@ -0,0 +1,3 @@ +import FloatingActionButton from '@components/FloatingActionButton'; + +export default FloatingActionButton; diff --git a/src/pages/home/sidebar/BottomTabBarFloatingActionButton/index.tsx b/src/pages/home/sidebar/BottomTabBarFloatingActionButton/index.tsx new file mode 100644 index 000000000000..43e4c049a83e --- /dev/null +++ b/src/pages/home/sidebar/BottomTabBarFloatingActionButton/index.tsx @@ -0,0 +1,42 @@ +import React, {useCallback, useRef} from 'react'; +import FloatingActionButtonAndPopover from '@pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover'; +import FloatingActionButtonPopoverMenuRef from './types'; + +function BottomTabBarFloatingActionButton() { + const popoverModal = useRef(null); + + /** + * Method to hide popover when dragover. + */ + const hidePopoverOnDragOver = useCallback(() => { + if (!popoverModal.current) { + return; + } + popoverModal.current.hideCreateMenu(); + }, []); + + /** + * Method create event listener + */ + const createDragoverListener = () => { + document.addEventListener('dragover', hidePopoverOnDragOver); + }; + + /** + * Method remove event listener. + */ + const removeDragoverListener = () => { + document.removeEventListener('dragover', hidePopoverOnDragOver); + }; + + return ( + + ); +} + +export default BottomTabBarFloatingActionButton; diff --git a/src/pages/home/sidebar/BottomTabBarFloatingActionButton/types.ts b/src/pages/home/sidebar/BottomTabBarFloatingActionButton/types.ts new file mode 100644 index 000000000000..e8fd03ee2adc --- /dev/null +++ b/src/pages/home/sidebar/BottomTabBarFloatingActionButton/types.ts @@ -0,0 +1,5 @@ +type FloatingActionButtonPopoverMenuRef = { + hideCreateMenu: () => void; +}; + +export default FloatingActionButtonPopoverMenuRef; diff --git a/src/pages/home/sidebar/SidebarScreen/index.js b/src/pages/home/sidebar/SidebarScreen/index.js index 0b4c520c78a2..7086e8a8561a 100755 --- a/src/pages/home/sidebar/SidebarScreen/index.js +++ b/src/pages/home/sidebar/SidebarScreen/index.js @@ -1,50 +1,18 @@ -import React, {useCallback, useRef} from 'react'; +import React from 'react'; import useWindowDimensions from '@hooks/useWindowDimensions'; import FreezeWrapper from '@libs/Navigation/FreezeWrapper'; import BaseSidebarScreen from './BaseSidebarScreen'; -import FloatingActionButtonAndPopover from './FloatingActionButtonAndPopover'; import sidebarPropTypes from './sidebarPropTypes'; function SidebarScreen(props) { - const popoverModal = useRef(null); const {isSmallScreenWidth} = useWindowDimensions(); - /** - * Method to hide popover when dragover. - */ - const hidePopoverOnDragOver = useCallback(() => { - if (!popoverModal.current) { - return; - } - popoverModal.current.hideCreateMenu(); - }, []); - - /** - * Method create event listener - */ - const createDragoverListener = () => { - document.addEventListener('dragover', hidePopoverOnDragOver); - }; - - /** - * Method remove event listener. - */ - const removeDragoverListener = () => { - document.removeEventListener('dragover', hidePopoverOnDragOver); - }; - return ( - - + /> ); } From 593618f94b500c124fee9177f1e44bad99291756 Mon Sep 17 00:00:00 2001 From: Adam Grzybowski Date: Wed, 13 Dec 2023 17:32:59 +0100 Subject: [PATCH 102/722] move tab to central pane mapping --- src/CONST.ts | 14 -------------- .../Navigation/TAB_TO_CENTRAL_PANE_MAPPING.ts | 18 ++++++++++++++++++ 2 files changed, 18 insertions(+), 14 deletions(-) create mode 100755 src/libs/Navigation/TAB_TO_CENTRAL_PANE_MAPPING.ts diff --git a/src/CONST.ts b/src/CONST.ts index 0dad726d2056..dbb031b63438 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -3019,20 +3019,6 @@ const CONST = { DEFAULT: 5, CAROUSEL: 3, }, - - TAB_TO_CENTRAL_PANE_MAPPING: { - [SCREENS.HOME]: [SCREENS.REPORT], - [SCREENS.ALL_SETTINGS]: [SCREENS.SETTINGS.WORKSPACES], - [SCREENS.WORKSPACE.INITIAL]: [ - SCREENS.WORKSPACE.SETTINGS, - SCREENS.WORKSPACE.CARD, - SCREENS.WORKSPACE.REIMBURSE, - SCREENS.WORKSPACE.BILLS, - SCREENS.WORKSPACE.INVOICES, - SCREENS.WORKSPACE.TRAVEL, - SCREENS.WORKSPACE.MEMBERS, - ], - } satisfies Record, } as const; export default CONST; diff --git a/src/libs/Navigation/TAB_TO_CENTRAL_PANE_MAPPING.ts b/src/libs/Navigation/TAB_TO_CENTRAL_PANE_MAPPING.ts new file mode 100755 index 000000000000..1f728b142306 --- /dev/null +++ b/src/libs/Navigation/TAB_TO_CENTRAL_PANE_MAPPING.ts @@ -0,0 +1,18 @@ +import SCREENS from '@src/SCREENS'; +import {BottomTabName, CentralPaneName} from './types'; + +const TAB_TO_CENTRAL_PANE_MAPPING: Record = { + [SCREENS.HOME]: [SCREENS.REPORT], + [SCREENS.ALL_SETTINGS]: [SCREENS.SETTINGS.WORKSPACES], + [SCREENS.WORKSPACE.INITIAL]: [ + SCREENS.WORKSPACE.SETTINGS, + SCREENS.WORKSPACE.CARD, + SCREENS.WORKSPACE.REIMBURSE, + SCREENS.WORKSPACE.BILLS, + SCREENS.WORKSPACE.INVOICES, + SCREENS.WORKSPACE.TRAVEL, + SCREENS.WORKSPACE.MEMBERS, + ], +}; + +export default TAB_TO_CENTRAL_PANE_MAPPING; From 70b3db637abfc5c85ed33997dcb0a512a3ad36dd Mon Sep 17 00:00:00 2001 From: Adam Grzybowski Date: Wed, 13 Dec 2023 17:59:50 +0100 Subject: [PATCH 103/722] add and modify navigation types --- src/libs/Navigation/types.ts | 85 ++++++++++++++++++++++++------------ 1 file changed, 57 insertions(+), 28 deletions(-) diff --git a/src/libs/Navigation/types.ts b/src/libs/Navigation/types.ts index b69552f6fe0f..328147e6064f 100644 --- a/src/libs/Navigation/types.ts +++ b/src/libs/Navigation/types.ts @@ -1,5 +1,15 @@ /* eslint-disable @typescript-eslint/naming-convention */ -import {CommonActions, NavigationContainerRefWithCurrent, NavigationHelpers, NavigationState, NavigatorScreenParams, PartialRoute, Route} from '@react-navigation/native'; +import { + CommonActions, + NavigationContainerRefWithCurrent, + NavigationHelpers, + NavigationState, + NavigatorScreenParams, + ParamListBase, + PartialRoute, + PartialState, + Route, +} from '@react-navigation/native'; import {ValueOf} from 'type-fest'; import CONST from '@src/CONST'; import NAVIGATORS from '@src/NAVIGATORS'; @@ -30,8 +40,9 @@ type ActionNavigate = { type StackNavigationAction = GoBackAction | ResetAction | SetParamsAction | ActionNavigate | undefined; type NavigationStateRoute = NavigationState['routes'][number]; -type NavigationPartialRoute = PartialRoute>; +type NavigationPartialRoute = PartialRoute>; type StateOrRoute = NavigationState | NavigationStateRoute | NavigationPartialRoute; +type State = NavigationState | PartialState>; type CentralPaneNavigatorParamList = { [SCREENS.REPORT]: { @@ -39,6 +50,33 @@ type CentralPaneNavigatorParamList = { reportID: string; openOnAdminRoom?: boolean; }; + + [SCREENS.SETTINGS.WORKSPACES]: undefined; + [SCREENS.WORKSPACE.SETTINGS]: { + policyID: string; + }; + [SCREENS.WORKSPACE.CARD]: { + policyID: string; + }; + [SCREENS.WORKSPACE.REIMBURSE]: { + policyID: string; + }; + [SCREENS.WORKSPACE.BILLS]: { + policyID: string; + }; + [SCREENS.WORKSPACE.INVOICES]: { + policyID: string; + }; + [SCREENS.WORKSPACE.TRAVEL]: { + policyID: string; + }; + [SCREENS.WORKSPACE.MEMBERS]: { + policyID: string; + }; + [SCREENS.REIMBURSEMENT_ACCOUNT]: { + stepToOpen: string; + policyID: string; + }; }; type SettingsNavigatorParamList = { @@ -83,38 +121,14 @@ type SettingsNavigatorParamList = { [SCREENS.SETTINGS.ADD_BANK_ACCOUNT]: undefined; [SCREENS.SETTINGS.PROFILE.STATUS]: undefined; [SCREENS.SETTINGS.PROFILE.STATUS_SET]: undefined; - [SCREENS.WORKSPACE.INITIAL]: undefined; - [SCREENS.WORKSPACE.SETTINGS]: undefined; [SCREENS.WORKSPACE.CURRENCY]: undefined; - [SCREENS.WORKSPACE.CARD]: { - policyID: string; - }; - [SCREENS.WORKSPACE.REIMBURSE]: { - policyID: string; - }; [SCREENS.WORKSPACE.RATE_AND_UNIT]: undefined; - [SCREENS.WORKSPACE.BILLS]: { - policyID: string; - }; - [SCREENS.WORKSPACE.INVOICES]: { - policyID: string; - }; - [SCREENS.WORKSPACE.TRAVEL]: { - policyID: string; - }; - [SCREENS.WORKSPACE.MEMBERS]: { - policyID: string; - }; [SCREENS.WORKSPACE.INVITE]: { policyID: string; }; [SCREENS.WORKSPACE.INVITE_MESSAGE]: { policyID: string; }; - [SCREENS.REIMBURSEMENT_ACCOUNT]: { - stepToOpen: string; - policyID: string; - }; [SCREENS.GET_ASSISTANCE]: { taskID: string; }; @@ -359,8 +373,14 @@ type RightModalNavigatorParamList = { [SCREENS.RIGHT_MODAL.PRIVATE_NOTES]: NavigatorScreenParams; }; -type PublicScreensParamList = { +type BottomTabNavigatorParamList = { [SCREENS.HOME]: undefined; + [SCREENS.ALL_SETTINGS]: undefined; + [SCREENS.WORKSPACE.INITIAL]: undefined; +}; + +type PublicScreensParamList = { + [NAVIGATORS.BOTTOM_TAB_NAVIGATOR]: NavigatorScreenParams; [SCREENS.TRANSITION_BETWEEN_APPS]: { shouldForceLogin: string; email: string; @@ -381,7 +401,7 @@ type PublicScreensParamList = { }; type AuthScreensParamList = { - [SCREENS.HOME]: undefined; + [NAVIGATORS.BOTTOM_TAB_NAVIGATOR]: NavigatorScreenParams; [NAVIGATORS.CENTRAL_PANE_NAVIGATOR]: NavigatorScreenParams; [SCREENS.VALIDATE_LOGIN]: { accountID: string; @@ -412,15 +432,23 @@ type AuthScreensParamList = { type RootStackParamList = PublicScreensParamList & AuthScreensParamList; +type BottomTabName = keyof BottomTabNavigatorParamList; + +type CentralPaneName = keyof CentralPaneNavigatorParamList; + export type { NavigationRef, StackNavigationAction, CentralPaneNavigatorParamList, + BottomTabName, + CentralPaneName, RootStackParamList, StateOrRoute, NavigationStateRoute, + NavigationPartialRoute, NavigationRoot, AuthScreensParamList, + BottomTabNavigatorParamList, RightModalNavigatorParamList, PublicScreensParamList, MoneyRequestNavigatorParamList, @@ -448,4 +476,5 @@ export type { SignInNavigatorParamList, ReferralDetailsNavigatorParamList, ReimbursementAccountNavigatorParamList, + State, }; From 018c0557292e3f79784ec37773346118fb328cde Mon Sep 17 00:00:00 2001 From: Adam Grzybowski Date: Wed, 13 Dec 2023 18:00:20 +0100 Subject: [PATCH 104/722] add helpers for navigation --- .../getMatchingBottomTabRouteForState.ts | 28 ++++++++++ .../getMatchingCentralPaneRouteForState.ts | 51 +++++++++++++++++++ .../Navigation/getTopmostBottomTabRoute.ts | 19 +++++++ .../Navigation/getTopmostCentralPaneRoute.ts | 30 +++++++++++ 4 files changed, 128 insertions(+) create mode 100644 src/libs/Navigation/getMatchingBottomTabRouteForState.ts create mode 100644 src/libs/Navigation/getMatchingCentralPaneRouteForState.ts create mode 100644 src/libs/Navigation/getTopmostBottomTabRoute.ts create mode 100644 src/libs/Navigation/getTopmostCentralPaneRoute.ts diff --git a/src/libs/Navigation/getMatchingBottomTabRouteForState.ts b/src/libs/Navigation/getMatchingBottomTabRouteForState.ts new file mode 100644 index 000000000000..ac4f225fd896 --- /dev/null +++ b/src/libs/Navigation/getMatchingBottomTabRouteForState.ts @@ -0,0 +1,28 @@ +// import CONST from '@src/CONST'; +import SCREENS from '@src/SCREENS'; +import getTopmostCentralPaneRoute from './getTopmostCentralPaneRoute'; +import TAB_TO_CENTRAL_PANE_MAPPING from './TAB_TO_CENTRAL_PANE_MAPPING'; +import {BottomTabName, NavigationPartialRoute, RootStackParamList, State} from './types'; + +// Get the route that matches the topmost central pane route in the navigation stack. e.g REPORT -> HOME +function getMatchingBottomTabRouteForState(state: State): NavigationPartialRoute { + const defaultRoute = {name: SCREENS.HOME}; + const topmostCentralPaneRoute = getTopmostCentralPaneRoute(state); + + if (topmostCentralPaneRoute === undefined) { + return defaultRoute; + } + + for (const [tabName, centralPaneNames] of Object.entries(TAB_TO_CENTRAL_PANE_MAPPING)) { + if (centralPaneNames.includes(topmostCentralPaneRoute.name)) { + if (tabName === SCREENS.WORKSPACE.INITIAL) { + return {name: tabName, params: topmostCentralPaneRoute.params}; + } + return {name: tabName as BottomTabName}; + } + } + + return defaultRoute; +} + +export default getMatchingBottomTabRouteForState; diff --git a/src/libs/Navigation/getMatchingCentralPaneRouteForState.ts b/src/libs/Navigation/getMatchingCentralPaneRouteForState.ts new file mode 100644 index 000000000000..f00107308b2d --- /dev/null +++ b/src/libs/Navigation/getMatchingCentralPaneRouteForState.ts @@ -0,0 +1,51 @@ +import NAVIGATORS from '@src/NAVIGATORS'; +import SCREENS from '@src/SCREENS'; +import getTopmostBottomTabRoute from './getTopmostBottomTabRoute'; +import TAB_TO_CENTRAL_PANE_MAPPING from './TAB_TO_CENTRAL_PANE_MAPPING'; +import {CentralPaneName, NavigationPartialRoute, RootStackParamList, State} from './types'; + +/** + * @param state - react-navigation state + */ +const getTopMostReportIDFromRHP = (state: State): string => { + if (!state) { + return ''; + } + + const topmostRightPane = state.routes.filter((route) => route.name === NAVIGATORS.RIGHT_MODAL_NAVIGATOR).at(-1); + + if (topmostRightPane?.state) { + return getTopMostReportIDFromRHP(topmostRightPane.state); + } + + const topmostRoute = state.routes.at(-1); + + if (topmostRoute?.state) { + return getTopMostReportIDFromRHP(topmostRoute.state); + } + + if (topmostRoute?.params && 'reportID' in topmostRoute.params && typeof topmostRoute.params.reportID === 'string') { + return topmostRoute.params.reportID; + } + + return ''; +}; + +// Get matching central pane route for bottom tab navigator. e.g HOME -> REPORT +function getMatchingCentralPaneRouteForState(state: State): NavigationPartialRoute { + const topmostBottomTabRoute = getTopmostBottomTabRoute(state); + + const centralPaneName = TAB_TO_CENTRAL_PANE_MAPPING[topmostBottomTabRoute.name][0]; + + if (topmostBottomTabRoute.name === SCREENS.WORKSPACE.INITIAL) { + return {name: centralPaneName, params: topmostBottomTabRoute.params}; + } + + if (topmostBottomTabRoute.name === SCREENS.HOME) { + return {name: centralPaneName, params: {reportID: getTopMostReportIDFromRHP(state)}}; + } + + return {name: centralPaneName}; +} + +export default getMatchingCentralPaneRouteForState; diff --git a/src/libs/Navigation/getTopmostBottomTabRoute.ts b/src/libs/Navigation/getTopmostBottomTabRoute.ts new file mode 100644 index 000000000000..053f866bc3b5 --- /dev/null +++ b/src/libs/Navigation/getTopmostBottomTabRoute.ts @@ -0,0 +1,19 @@ +import {BottomTabName, NavigationPartialRoute, RootStackParamList, State} from './types'; + +function getTopmostBottomTabRoute(state: State): NavigationPartialRoute { + const bottomTabNavigatorRoute = state.routes[0]; + + if (!bottomTabNavigatorRoute || bottomTabNavigatorRoute.name !== 'BottomTabNavigator' || bottomTabNavigatorRoute.state === undefined) { + throw new Error('There is no bottomTabNavigator route mounted as the first route in the root state.'); + } + + const topmostBottomTabRoute = bottomTabNavigatorRoute.state.routes.at(-1); + + if (!topmostBottomTabRoute) { + throw new Error('BottomTabNavigator route have no routes.'); + } + + return {name: topmostBottomTabRoute.name as BottomTabName, params: topmostBottomTabRoute.params}; +} + +export default getTopmostBottomTabRoute; diff --git a/src/libs/Navigation/getTopmostCentralPaneRoute.ts b/src/libs/Navigation/getTopmostCentralPaneRoute.ts new file mode 100644 index 000000000000..a9935adf6fbf --- /dev/null +++ b/src/libs/Navigation/getTopmostCentralPaneRoute.ts @@ -0,0 +1,30 @@ +import NAVIGATORS from '@src/NAVIGATORS'; +import {CentralPaneName, NavigationPartialRoute, RootStackParamList, State} from './types'; + +// Get the name of topmost central pane route in the navigation stack. +function getTopmostCentralPaneRoute(state: State): NavigationPartialRoute | undefined { + if (!state) { + return; + } + + const topmostCentralPane = state.routes.filter((route) => route.name === NAVIGATORS.CENTRAL_PANE_NAVIGATOR).at(-1); + + if (!topmostCentralPane) { + return; + } + + if (!!topmostCentralPane.params && 'screen' in topmostCentralPane.params) { + return {name: topmostCentralPane.params.screen as CentralPaneName, params: topmostCentralPane.params.params}; + } + + if (!topmostCentralPane.state) { + return; + } + + // There will be at least one route in the central pane navigator. + const {name, params} = topmostCentralPane.state.routes.at(-1) as NavigationPartialRoute; + + return {name, params}; +} + +export default getTopmostCentralPaneRoute; From c1613c804f4681d3774551575fc5fddad503aa87 Mon Sep 17 00:00:00 2001 From: Adam Grzybowski Date: Wed, 13 Dec 2023 18:03:52 +0100 Subject: [PATCH 105/722] modify linking config --- src/libs/Navigation/linkingConfig.ts | 104 ++++++++++++++++++--------- 1 file changed, 71 insertions(+), 33 deletions(-) diff --git a/src/libs/Navigation/linkingConfig.ts b/src/libs/Navigation/linkingConfig.ts index e9e76f4a2e82..38117d89b611 100644 --- a/src/libs/Navigation/linkingConfig.ts +++ b/src/libs/Navigation/linkingConfig.ts @@ -1,12 +1,48 @@ /* eslint-disable @typescript-eslint/naming-convention */ -import {LinkingOptions} from '@react-navigation/native'; +import {getStateFromPath, LinkingOptions, NavigationState, PartialState} from '@react-navigation/native'; import CONST from '@src/CONST'; import NAVIGATORS from '@src/NAVIGATORS'; import ROUTES from '@src/ROUTES'; import SCREENS from '@src/SCREENS'; -import {RootStackParamList} from './types'; +import getMatchingBottomTabRouteForState from './getMatchingBottomTabRouteForState'; +import {BottomTabName, NavigationPartialRoute, RootStackParamList} from './types'; + +function getStateWithProperTab(state: PartialState>) { + // If the bottom tab navigator state is defined we don't need to do anything. + const isBottomTabNavigatorStateDefined = state.routes.at(0)?.state !== undefined; + if (isBottomTabNavigatorStateDefined) { + return state; + } + + // If not, we need to insert the tab that matches the currently generated state. + const matchingBottomTabRoute = getMatchingBottomTabRouteForState(state); + + // We need to have at least one HOME route in the state, otherwise the app won't load. + const routesForBottomTabNavigator: Array> = [{name: SCREENS.HOME}]; + + if (matchingBottomTabRoute.name !== SCREENS.HOME) { + // If the generated state requires tab other than HOME, we need to insert it. + routesForBottomTabNavigator.push(matchingBottomTabRoute); + } + + const stateWithTab = {...state}; + + // The first route in root stack is always the BOTTOM_TAB_NAVIGATOR + stateWithTab.routes[0] = {name: NAVIGATORS.BOTTOM_TAB_NAVIGATOR, state: {routes: routesForBottomTabNavigator}}; + + return stateWithTab; +} const linkingConfig: LinkingOptions = { + getStateFromPath: (path, options) => { + const state = getStateFromPath(path, options); + + if (state === undefined) { + throw new Error('Unable to parse path'); + } + const stateWithTab = getStateWithProperTab(state as PartialState>); + return stateWithTab; + }, prefixes: [ 'app://-/', 'new-expensify://', @@ -17,7 +53,7 @@ const linkingConfig: LinkingOptions = { CONST.STAGING_NEW_EXPENSIFY_URL, ], config: { - initialRouteName: SCREENS.HOME, + initialRouteName: NAVIGATORS.BOTTOM_TAB_NAVIGATOR, screens: { // Main Routes [SCREENS.VALIDATE_LOGIN]: ROUTES.VALIDATE_LOGIN, @@ -34,13 +70,43 @@ const linkingConfig: LinkingOptions = { [CONST.DEMO_PAGES.MONEY2020]: ROUTES.MONEY2020, // Sidebar - [SCREENS.HOME]: { - path: ROUTES.HOME, + [NAVIGATORS.BOTTOM_TAB_NAVIGATOR]: { + path: '', + initialRouteName: SCREENS.HOME, + screens: { + [SCREENS.HOME]: ROUTES.HOME, + [SCREENS.ALL_SETTINGS]: ROUTES.ALL_SETTINGS, + [SCREENS.WORKSPACE.INITIAL]: { + path: ROUTES.WORKSPACE_INITIAL.route, + exact: true, + }, + }, }, [NAVIGATORS.CENTRAL_PANE_NAVIGATOR]: { screens: { [SCREENS.REPORT]: ROUTES.REPORT_WITH_ID.route, + + [SCREENS.SETTINGS.WORKSPACES]: ROUTES.SETTINGS_WORKSPACES, + [SCREENS.WORKSPACE.SETTINGS]: ROUTES.WORKSPACE_SETTINGS.route, + [SCREENS.WORKSPACE.CARD]: { + path: ROUTES.WORKSPACE_CARD.route, + }, + [SCREENS.WORKSPACE.REIMBURSE]: { + path: ROUTES.WORKSPACE_REIMBURSE.route, + }, + [SCREENS.WORKSPACE.BILLS]: { + path: ROUTES.WORKSPACE_BILLS.route, + }, + [SCREENS.WORKSPACE.INVOICES]: { + path: ROUTES.WORKSPACE_INVOICES.route, + }, + [SCREENS.WORKSPACE.TRAVEL]: { + path: ROUTES.WORKSPACE_TRAVEL.route, + }, + [SCREENS.WORKSPACE.MEMBERS]: { + path: ROUTES.WORKSPACE_MEMBERS.route, + }, }, }, [SCREENS.NOT_FOUND]: '*', @@ -52,10 +118,6 @@ const linkingConfig: LinkingOptions = { [SCREENS.SETTINGS.ROOT]: { path: ROUTES.SETTINGS, }, - [SCREENS.SETTINGS.WORKSPACES]: { - path: ROUTES.SETTINGS_WORKSPACES, - exact: true, - }, [SCREENS.SETTINGS.PREFERENCES.ROOT]: { path: ROUTES.SETTINGS_PREFERENCES, exact: true, @@ -218,36 +280,12 @@ const linkingConfig: LinkingOptions = { path: ROUTES.SETTINGS_STATUS_SET, exact: true, }, - [SCREENS.WORKSPACE.INITIAL]: { - path: ROUTES.WORKSPACE_INITIAL.route, - }, - [SCREENS.WORKSPACE.SETTINGS]: { - path: ROUTES.WORKSPACE_SETTINGS.route, - }, [SCREENS.WORKSPACE.CURRENCY]: { path: ROUTES.WORKSPACE_SETTINGS_CURRENCY.route, }, - [SCREENS.WORKSPACE.CARD]: { - path: ROUTES.WORKSPACE_CARD.route, - }, - [SCREENS.WORKSPACE.REIMBURSE]: { - path: ROUTES.WORKSPACE_REIMBURSE.route, - }, [SCREENS.WORKSPACE.RATE_AND_UNIT]: { path: ROUTES.WORKSPACE_RATE_AND_UNIT.route, }, - [SCREENS.WORKSPACE.BILLS]: { - path: ROUTES.WORKSPACE_BILLS.route, - }, - [SCREENS.WORKSPACE.INVOICES]: { - path: ROUTES.WORKSPACE_INVOICES.route, - }, - [SCREENS.WORKSPACE.TRAVEL]: { - path: ROUTES.WORKSPACE_TRAVEL.route, - }, - [SCREENS.WORKSPACE.MEMBERS]: { - path: ROUTES.WORKSPACE_MEMBERS.route, - }, [SCREENS.WORKSPACE.INVITE]: { path: ROUTES.WORKSPACE_INVITE.route, }, From 2d0c560686f41bf20d9b4b2b2c733e6c88d3b981 Mon Sep 17 00:00:00 2001 From: Adam Grzybowski Date: Wed, 13 Dec 2023 18:11:10 +0100 Subject: [PATCH 106/722] add bottomTabBar --- .../BottomTabBar.tsx | 55 +++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar.tsx diff --git a/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar.tsx b/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar.tsx new file mode 100644 index 000000000000..2f1cf0309455 --- /dev/null +++ b/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar.tsx @@ -0,0 +1,55 @@ +import {useNavigationState} from '@react-navigation/native'; +import React from 'react'; +import {View} from 'react-native'; +import Icon from '@components/Icon'; +import * as Expensicons from '@components/Icon/Expensicons'; +import {PressableWithFeedback} from '@components/Pressable'; +import getTopmostBottomTabRoute from '@libs/Navigation/getTopmostBottomTabRoute'; +import Navigation from '@libs/Navigation/Navigation'; +import {RootStackParamList} from '@libs/Navigation/types'; +import BottomTabBarFloatingActionButton from '@pages/home/sidebar/BottomTabBarFloatingActionButton'; +import useThemeStyles from '@styles/useThemeStyles'; +import CONST from '@src/CONST'; +import ROUTES from '@src/ROUTES'; +import SCREENS from '@src/SCREENS'; + +function BottomTabBar() { + const styles = useThemeStyles(); + + // Parent navigator of the bottom tab bar is the root navigator. + const currentTabName = useNavigationState((state) => getTopmostBottomTabRoute(state).name); + + return ( + + { + Navigation.navigate(ROUTES.HOME); + }} + role={CONST.ACCESSIBILITY_ROLE.BUTTON} + accessibilityLabel="Chats" + > + + + + { + Navigation.navigate(ROUTES.ALL_SETTINGS); + }} + role={CONST.ACCESSIBILITY_ROLE.BUTTON} + accessibilityLabel="Settings" + > + + + + ); +} + +BottomTabBar.displayName = 'BottomTabBar'; + +export default BottomTabBar; From 62a63ecd9cf847b1226c5fc019006d76502f578c Mon Sep 17 00:00:00 2001 From: Adam Grzybowski Date: Wed, 13 Dec 2023 18:13:32 +0100 Subject: [PATCH 107/722] add comment to the PublicBottomTabNavigator --- .../AppNavigator/Navigators/PublicBottomTabNavigator.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libs/Navigation/AppNavigator/Navigators/PublicBottomTabNavigator.tsx b/src/libs/Navigation/AppNavigator/Navigators/PublicBottomTabNavigator.tsx index 6ed58c178c2c..ddf3443e9c06 100644 --- a/src/libs/Navigation/AppNavigator/Navigators/PublicBottomTabNavigator.tsx +++ b/src/libs/Navigation/AppNavigator/Navigators/PublicBottomTabNavigator.tsx @@ -5,6 +5,7 @@ import {BottomTabNavigatorParamList} from '@libs/Navigation/types'; import SignInPage from '@pages/signin/SignInPage'; import SCREENS from '@src/SCREENS'; +// This type is not exactly right because we are using the same route in public and auth screens. const Tab = createCustomBottomTabNavigator(); const screenOptions: StackNavigationOptions = { From 32ba7c6f00fc868f8db7aaa4f330a5e97ab85d83 Mon Sep 17 00:00:00 2001 From: Adam Grzybowski Date: Wed, 13 Dec 2023 18:15:01 +0100 Subject: [PATCH 108/722] update type in Navigation.js --- src/libs/Navigation/Navigation.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libs/Navigation/Navigation.ts b/src/libs/Navigation/Navigation.ts index c2dd3e76e7ad..7c1d2343159d 100644 --- a/src/libs/Navigation/Navigation.ts +++ b/src/libs/Navigation/Navigation.ts @@ -1,5 +1,5 @@ import {findFocusedRoute, getActionFromState} from '@react-navigation/core'; -import {CommonActions, EventMapCore, getPathFromState, NavigationState, PartialState, StackActions} from '@react-navigation/native'; +import {CommonActions, EventMapCore, getPathFromState, NavigationState, StackActions} from '@react-navigation/native'; import findLastIndex from 'lodash/findLastIndex'; import Log from '@libs/Log'; import CONST from '@src/CONST'; @@ -12,7 +12,7 @@ import originalGetTopmostReportId from './getTopmostReportId'; import linkingConfig from './linkingConfig'; import linkTo from './linkTo'; import navigationRef from './navigationRef'; -import {StackNavigationAction, StateOrRoute} from './types'; +import {StackNavigationAction, State, StateOrRoute} from './types'; let resolveNavigationIsReadyPromise: () => void; const navigationIsReadyPromise = new Promise((resolve) => { @@ -286,7 +286,7 @@ function setIsNavigationReady() { * * @param state - react-navigation state object */ -function navContainsProtectedRoutes(state: NavigationState | PartialState | undefined): boolean { +function navContainsProtectedRoutes(state: State | undefined): boolean { if (!state?.routeNames || !Array.isArray(state.routeNames)) { return false; } From c0f13514fb53d08b005328fb807fcd8d32ccad0c Mon Sep 17 00:00:00 2001 From: Adam Grzybowski Date: Wed, 13 Dec 2023 18:26:19 +0100 Subject: [PATCH 109/722] use proper color for BottomTabBar --- .../createCustomBottomTabNavigator/BottomTabBar.tsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar.tsx b/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar.tsx index 2f1cf0309455..3b58e110f0fd 100644 --- a/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar.tsx +++ b/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar.tsx @@ -8,12 +8,14 @@ import getTopmostBottomTabRoute from '@libs/Navigation/getTopmostBottomTabRoute' import Navigation from '@libs/Navigation/Navigation'; import {RootStackParamList} from '@libs/Navigation/types'; import BottomTabBarFloatingActionButton from '@pages/home/sidebar/BottomTabBarFloatingActionButton'; +import useTheme from '@styles/themes/useTheme'; import useThemeStyles from '@styles/useThemeStyles'; import CONST from '@src/CONST'; import ROUTES from '@src/ROUTES'; import SCREENS from '@src/SCREENS'; function BottomTabBar() { + const theme = useTheme(); const styles = useThemeStyles(); // Parent navigator of the bottom tab bar is the root navigator. @@ -30,7 +32,7 @@ function BottomTabBar() { > @@ -43,7 +45,7 @@ function BottomTabBar() { > From 7b4cef9fc413a55c194401d0397c818c349cb778 Mon Sep 17 00:00:00 2001 From: Adam Grzybowski Date: Wed, 13 Dec 2023 18:32:07 +0100 Subject: [PATCH 110/722] add bottom tab navigator --- .../Navigation/AppNavigator/AuthScreens.tsx | 6 +- .../Navigators/BottomTabNavigator.tsx | 61 +++++++++++++ .../createCustomBottomTabNavigator/index.tsx | 88 +++++++++++++++++++ 3 files changed, 152 insertions(+), 3 deletions(-) create mode 100644 src/libs/Navigation/AppNavigator/Navigators/BottomTabNavigator.tsx create mode 100644 src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/index.tsx diff --git a/src/libs/Navigation/AppNavigator/AuthScreens.tsx b/src/libs/Navigation/AppNavigator/AuthScreens.tsx index 008015db7a90..4bad503bcdd7 100644 --- a/src/libs/Navigation/AppNavigator/AuthScreens.tsx +++ b/src/libs/Navigation/AppNavigator/AuthScreens.tsx @@ -35,6 +35,7 @@ import type {SelectedTimezone, Timezone} from '@src/types/onyx/PersonalDetails'; import createCustomStackNavigator from './createCustomStackNavigator'; import defaultScreenOptions from './defaultScreenOptions'; import getRootNavigatorScreenOptions from './getRootNavigatorScreenOptions'; +import BottomTabNavigator from './Navigators/BottomTabNavigator'; import CentralPaneNavigator from './Navigators/CentralPaneNavigator'; import RightModalNavigator from './Navigators/RightModalNavigator'; @@ -56,7 +57,6 @@ type AuthScreensProps = { }; const loadReportAttachments = () => require('../../../pages/home/report/ReportAttachments').default as React.ComponentType; -const loadSidebarScreen = () => require('../../../pages/home/sidebar/SidebarScreen').default as React.ComponentType; const loadValidateLoginPage = () => require('../../../pages/ValidateLoginPage').default as React.ComponentType; const loadLogOutPreviousUserPage = () => require('../../../pages/LogOutPreviousUserPage').default as React.ComponentType; const loadConciergePage = () => require('../../../pages/ConciergePage').default as React.ComponentType; @@ -255,9 +255,9 @@ function AuthScreens({lastUpdateIDAppliedToClient, session, lastOpenedPublicRoom require('../../../../pages/workspace/WorkspaceInitialPage').default as React.ComponentType; + +const Tab = createCustomBottomTabNavigator(); + +// TODO-IDEAL replace with the actuall screen. +function SecondTab() { + return ( + + Expensify settings + + { + Navigation.navigate(ROUTES.SETTINGS_WORKSPACES); + }} + > + Workspaces + + + ); +} + +const screenOptions: StackNavigationOptions = { + headerShown: false, +}; + +function BottomTabNavigator() { + return ( + + + + + + ); +} + +BottomTabNavigator.displayName = 'BottomTabNavigator'; + +export default BottomTabNavigator; diff --git a/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/index.tsx b/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/index.tsx new file mode 100644 index 000000000000..24be4ce5a174 --- /dev/null +++ b/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/index.tsx @@ -0,0 +1,88 @@ +import { + createNavigatorFactory, + DefaultNavigatorOptions, + ParamListBase, + StackActionHelpers, + StackNavigationState, + StackRouter, + StackRouterOptions, + useNavigationBuilder, +} from '@react-navigation/native'; +import {StackNavigationEventMap, StackNavigationOptions, StackView} from '@react-navigation/stack'; +import PropTypes from 'prop-types'; +import React from 'react'; +import {View} from 'react-native'; +import {NavigationStateRoute} from '@libs/Navigation/types'; +import SCREENS from '@src/SCREENS'; +import BottomTabBar from './BottomTabBar'; + +type CustomNavigatorProps = DefaultNavigatorOptions, StackNavigationOptions, StackNavigationEventMap> & { + initialRouteName: string; +}; + +const propTypes = { + /* Children for the useNavigationBuilder hook */ + children: PropTypes.oneOfType([PropTypes.func, PropTypes.node]).isRequired, + + /* initialRouteName for this navigator */ + initialRouteName: PropTypes.oneOf([PropTypes.string, undefined]), + + /* Screen options defined for this navigator */ + // eslint-disable-next-line react/forbid-prop-types + screenOptions: PropTypes.object, +}; + +const defaultProps = { + initialRouteName: undefined, + screenOptions: undefined, +}; + +function getStateToRender(state: StackNavigationState): StackNavigationState { + const routesToRender = [state.routes.at(-1)] as NavigationStateRoute[]; + // We need to render at least one HOME screen to make sure everything load properly. + if (routesToRender[0].name !== SCREENS.HOME) { + const routeToRender = state.routes.find((route) => route.name === SCREENS.HOME); + if (routeToRender) { + routesToRender.unshift(routeToRender); + } + } + + return {...state, routes: routesToRender, index: routesToRender.length - 1}; +} + +function CustomBottomTabNavigator({initialRouteName, children, screenOptions, ...props}: CustomNavigatorProps) { + const {state, navigation, descriptors, NavigationContent} = useNavigationBuilder< + StackNavigationState, + StackRouterOptions, + StackActionHelpers, + StackNavigationOptions, + StackNavigationEventMap + >(StackRouter, { + children, + screenOptions, + initialRouteName, + }); + + const stateToRender = getStateToRender(state); + + return ( + + + + + + + ); +} + +CustomBottomTabNavigator.defaultProps = defaultProps; +CustomBottomTabNavigator.propTypes = propTypes; +CustomBottomTabNavigator.displayName = 'CustomBottomTabNavigator'; + +export default createNavigatorFactory(CustomBottomTabNavigator); From 2a23586dcd10668da78419dcc7b333ffad78adfe Mon Sep 17 00:00:00 2001 From: Adam Grzybowski Date: Wed, 13 Dec 2023 18:39:41 +0100 Subject: [PATCH 111/722] move trigger for state rehydration to createCustomStackNavigator --- .../createCustomStackNavigator/index.tsx | 14 +++++++++----- src/libs/Navigation/NavigationRoot.tsx | 8 -------- 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/src/libs/Navigation/AppNavigator/createCustomStackNavigator/index.tsx b/src/libs/Navigation/AppNavigator/createCustomStackNavigator/index.tsx index dd2e548064c4..9a882d79c6cb 100644 --- a/src/libs/Navigation/AppNavigator/createCustomStackNavigator/index.tsx +++ b/src/libs/Navigation/AppNavigator/createCustomStackNavigator/index.tsx @@ -1,7 +1,8 @@ import {createNavigatorFactory, ParamListBase, StackActionHelpers, StackNavigationState, useNavigationBuilder} from '@react-navigation/native'; import {StackNavigationEventMap, StackNavigationOptions, StackView} from '@react-navigation/stack'; -import React, {useMemo, useRef} from 'react'; +import React, {useEffect, useMemo} from 'react'; import useWindowDimensions from '@hooks/useWindowDimensions'; +import navigationRef from '@libs/Navigation/navigationRef'; import NAVIGATORS from '@src/NAVIGATORS'; import CustomRouter from './CustomRouter'; import type {ResponsiveStackNavigatorProps, ResponsiveStackNavigatorRouterOptions} from './types'; @@ -30,10 +31,6 @@ function reduceReportRoutes(routes: Routes): Routes { function ResponsiveStackNavigator(props: ResponsiveStackNavigatorProps) { const {isSmallScreenWidth} = useWindowDimensions(); - const isSmallScreenWidthRef = useRef(isSmallScreenWidth); - - isSmallScreenWidthRef.current = isSmallScreenWidth; - const {navigation, state, descriptors, NavigationContent} = useNavigationBuilder< StackNavigationState, ResponsiveStackNavigatorRouterOptions, @@ -46,6 +43,13 @@ function ResponsiveStackNavigator(props: ResponsiveStackNavigatorProps) { initialRouteName: props.initialRouteName, }); + useEffect(() => { + if (!navigationRef.isReady()) { + return; + } + navigationRef.resetRoot(navigationRef.getRootState()); + }, [isSmallScreenWidth]); + const stateToRender = useMemo(() => { const result = reduceReportRoutes(state.routes); diff --git a/src/libs/Navigation/NavigationRoot.tsx b/src/libs/Navigation/NavigationRoot.tsx index 7c0b9ef4fc8c..564daa5787ac 100644 --- a/src/libs/Navigation/NavigationRoot.tsx +++ b/src/libs/Navigation/NavigationRoot.tsx @@ -71,14 +71,6 @@ function NavigationRoot({authenticated, onReady}: NavigationRootProps) { Navigation.setShouldPopAllStateOnUP(); }, [isSmallScreenWidth]); - useEffect(() => { - if (!navigationRef.isReady() || !authenticated) { - return; - } - // We need to force state rehydration so the CustomRouter can add the CentralPaneNavigator route if necessary. - navigationRef.resetRoot(navigationRef.getRootState()); - }, [isSmallScreenWidth, authenticated]); - const handleStateChange = (state: NavigationState | undefined) => { if (!state) { return; From 644c7708e52c278640bd4a40ee38ad806e47bed7 Mon Sep 17 00:00:00 2001 From: Adam Grzybowski Date: Wed, 13 Dec 2023 18:41:46 +0100 Subject: [PATCH 112/722] modify custom router for the CustomStackNavigator --- .../CustomRouter.ts | 84 ++++++++----------- 1 file changed, 36 insertions(+), 48 deletions(-) diff --git a/src/libs/Navigation/AppNavigator/createCustomStackNavigator/CustomRouter.ts b/src/libs/Navigation/AppNavigator/createCustomStackNavigator/CustomRouter.ts index 435ebc00362b..73e26962e581 100644 --- a/src/libs/Navigation/AppNavigator/createCustomStackNavigator/CustomRouter.ts +++ b/src/libs/Navigation/AppNavigator/createCustomStackNavigator/CustomRouter.ts @@ -1,61 +1,44 @@ -import {NavigationState, PartialState, RouterConfigOptions, StackNavigationState, StackRouter} from '@react-navigation/native'; +import {RouterConfigOptions, StackNavigationState, StackRouter} from '@react-navigation/native'; import {ParamListBase} from '@react-navigation/routers'; import getIsSmallScreenWidth from '@libs/getIsSmallScreenWidth'; +import getMatchingCentralPaneRouteForState from '@libs/Navigation/getMatchingCentralPaneRouteForState'; +import getTopmostBottomTabRoute from '@libs/Navigation/getTopmostBottomTabRoute'; +import getTopmostCentralPaneRoute from '@libs/Navigation/getTopmostCentralPaneRoute'; +import TAB_TO_CENTRAL_PANE_MAPPING from '@libs/Navigation/TAB_TO_CENTRAL_PANE_MAPPING'; +import {RootStackParamList, State} from '@libs/Navigation/types'; import NAVIGATORS from '@src/NAVIGATORS'; -import SCREENS from '@src/SCREENS'; import type {ResponsiveStackNavigatorRouterOptions} from './types'; -type State = NavigationState | PartialState; - -const isAtLeastOneCentralPaneNavigatorInState = (state: State): boolean => !!state.routes.find((route) => route.name === NAVIGATORS.CENTRAL_PANE_NAVIGATOR); - -const getTopMostReportIDFromRHP = (state: State): string => { - if (!state) { - return ''; - } - - const topmostRightPane = state.routes.filter((route) => route.name === NAVIGATORS.RIGHT_MODAL_NAVIGATOR).at(-1); - - if (topmostRightPane?.state) { - return getTopMostReportIDFromRHP(topmostRightPane.state); - } - - const topmostRoute = state.routes.at(-1); - - if (topmostRoute?.state) { - return getTopMostReportIDFromRHP(topmostRoute.state); - } - - if (topmostRoute?.params && 'reportID' in topmostRoute.params && typeof topmostRoute.params.reportID === 'string' && topmostRoute.params.reportID) { - return topmostRoute.params.reportID; - } - - return ''; -}; /** * Adds report route without any specific reportID to the state. * The report screen will self set proper reportID param based on the helper function findLastAccessedReport (look at ReportScreenWrapper for more info) * * @param state - react-navigation state */ -const addCentralPaneNavigatorRoute = (state: State) => { - const reportID = getTopMostReportIDFromRHP(state); +const addCentralPaneNavigatorRoute = (state: State) => { + const matchingCentralPaneRoute = getMatchingCentralPaneRouteForState(state); + + const bottomTabRoute = state.routes.filter((route) => route.name === NAVIGATORS.BOTTOM_TAB_NAVIGATOR); + const centralPaneRoutes = state.routes.filter((route) => route.name === NAVIGATORS.CENTRAL_PANE_NAVIGATOR); + + // TODO-IDEAL Both RHP and LHP add condition for the LHP + const modalRoutes = state.routes.filter((route) => route.name === NAVIGATORS.RIGHT_MODAL_NAVIGATOR); + const centralPaneNavigatorRoute = { name: NAVIGATORS.CENTRAL_PANE_NAVIGATOR, - state: { - routes: [ - { - name: SCREENS.REPORT, - params: { - reportID, - }, - }, - ], + params: { + screen: matchingCentralPaneRoute.name, + params: matchingCentralPaneRoute.params, }, }; - state.routes.splice(1, 0, centralPaneNavigatorRoute); - // eslint-disable-next-line no-param-reassign, @typescript-eslint/non-nullable-type-assertion-style - (state.index as number) = state.routes.length - 1; + + // @ts-expect-error Updating read only property + // noinspection JSConstantReassignment + state.routes = [...bottomTabRoute, ...centralPaneRoutes, centralPaneNavigatorRoute, ...modalRoutes]; // eslint-disable-line + + // @ts-expect-error Updating read only property + // noinspection JSConstantReassignment + state.index = state.routes.length - 1; // eslint-disable-line }; function CustomRouter(options: ResponsiveStackNavigatorRouterOptions) { @@ -63,14 +46,19 @@ function CustomRouter(options: ResponsiveStackNavigatorRouterOptions) { return { ...stackRouter, - getRehydratedState(partialState: StackNavigationState, {routeNames, routeParamList, routeGetIdList}: RouterConfigOptions): StackNavigationState { + getRehydratedState(partialState: StackNavigationState, {routeNames, routeParamList, routeGetIdList}: RouterConfigOptions): StackNavigationState { const isSmallScreenWidth = getIsSmallScreenWidth(); // Make sure that there is at least one CentralPaneNavigator (ReportScreen by default) in the state if this is a wide layout - if (!isAtLeastOneCentralPaneNavigatorInState(partialState) && !isSmallScreenWidth) { - // If we added a route we need to make sure that the state.stale is true to generate new key for this route + const topmostCentralPaneRoute = getTopmostCentralPaneRoute(partialState); + const topmostBottomTabRoute = getTopmostBottomTabRoute(partialState); - // eslint-disable-next-line no-param-reassign - (partialState.stale as boolean) = true; + const isBottomTabMatchingCentralPane = topmostCentralPaneRoute && TAB_TO_CENTRAL_PANE_MAPPING[topmostBottomTabRoute.name].includes(topmostCentralPaneRoute.name); + + if (!isSmallScreenWidth && !isBottomTabMatchingCentralPane) { + // If we added a route we need to make sure that the state.stale is true to generate new key for this route + // @ts-expect-error Updating read only property + // noinspection JSConstantReassignment + partialState.stale = true; // eslint-disable-line addCentralPaneNavigatorRoute(partialState); } const state = stackRouter.getRehydratedState(partialState, {routeNames, routeParamList, routeGetIdList}); From 0c750973ae27f86c8c4d4d7ef404e75e8086e7df Mon Sep 17 00:00:00 2001 From: Adam Grzybowski Date: Wed, 13 Dec 2023 19:05:03 +0100 Subject: [PATCH 113/722] modify linkTo --- src/libs/Navigation/linkTo.ts | 84 +++++++++++++++++++++++++++++++---- 1 file changed, 75 insertions(+), 9 deletions(-) diff --git a/src/libs/Navigation/linkTo.ts b/src/libs/Navigation/linkTo.ts index 8be8dd1ecfae..265887346b8c 100644 --- a/src/libs/Navigation/linkTo.ts +++ b/src/libs/Navigation/linkTo.ts @@ -1,13 +1,19 @@ -import {getActionFromState} from '@react-navigation/core'; -import {NavigationAction, NavigationContainerRef, NavigationState, PartialState} from '@react-navigation/native'; +import {getActionFromState, PartialState} from '@react-navigation/core'; +import {NavigationAction, NavigationContainerRef, NavigationState} from '@react-navigation/native'; import {Writable} from 'type-fest'; +import getIsSmallScreenWidth from '@libs/getIsSmallScreenWidth'; import CONST from '@src/CONST'; import NAVIGATORS from '@src/NAVIGATORS'; import {Route} from '@src/ROUTES'; +import SCREENS from '@src/SCREENS'; +import getMatchingBottomTabRouteForState from './getMatchingBottomTabRouteForState'; +import getMatchingCentralPaneRouteForState from './getMatchingCentralPaneRouteForState'; import getStateFromPath from './getStateFromPath'; +import getTopmostBottomTabRoute from './getTopmostBottomTabRoute'; +import getTopmostCentralPaneRoute from './getTopmostCentralPaneRoute'; import getTopmostReportId from './getTopmostReportId'; import linkingConfig from './linkingConfig'; -import {NavigationRoot, RootStackParamList, StackNavigationAction} from './types'; +import {NavigationRoot, RootStackParamList, StackNavigationAction, State} from './types'; type ActionPayloadParams = { screen?: string; @@ -28,7 +34,7 @@ type ActionPayload = { */ function getMinimalAction(action: NavigationAction, state: NavigationState): Writable { let currentAction: NavigationAction = action; - let currentState: NavigationState | PartialState | undefined = state; + let currentState: State | undefined = state; let currentTargetKey: string | undefined; while (currentAction.payload && 'name' in currentAction.payload && currentState?.routes[currentState.index ?? -1].name === currentAction.payload.name) { @@ -55,6 +61,27 @@ function getMinimalAction(action: NavigationAction, state: NavigationState): Wri return currentAction; } +// Because we need to change the type to push, we also need to set target for this action to the bottom tab navigator. +function getActionForBottomTabNavigator(action: StackNavigationAction, state: NavigationState): Writable | undefined { + const bottomTabNavigatorRoute = state.routes.at(0); + + if (!bottomTabNavigatorRoute || bottomTabNavigatorRoute.state === undefined || !action || action.type !== CONST.NAVIGATION.ACTION_TYPE.NAVIGATE) { + return; + } + + const params = action.payload.params as ActionPayloadParams; + const screen = params.screen; + + return { + type: CONST.NAVIGATION.ACTION_TYPE.PUSH, + payload: { + name: screen, + params: params.params, + }, + target: bottomTabNavigatorRoute.state.key, + }; +} + export default function linkTo(navigation: NavigationContainerRef | null, path: Route, type?: string, isActiveRoute?: boolean) { if (!navigation) { throw new Error("Couldn't find a navigation object. Is your component inside a screen in a navigator?"); @@ -69,18 +96,33 @@ export default function linkTo(navigation: NavigationContainerRef; + const stateFromPath = getStateFromPath(path) as PartialState>; + const action: StackNavigationAction = getActionFromState(stateFromPath, linkingConfig.config); // If action type is different than NAVIGATE we can't change it to the PUSH safely if (action?.type === CONST.NAVIGATION.ACTION_TYPE.NAVIGATE) { + const topmostCentralPaneRoute = getTopmostCentralPaneRoute(rootState); // In case if type is 'FORCED_UP' we replace current screen with the provided. This means the current screen no longer exists in the stack if (type === CONST.NAVIGATION.TYPE.FORCED_UP) { action.type = CONST.NAVIGATION.ACTION_TYPE.REPLACE; // If this action is navigating to the report screen and the top most navigator is different from the one we want to navigate - PUSH the new screen to the top of the stack - } else if (action.payload.name === NAVIGATORS.CENTRAL_PANE_NAVIGATOR && getTopmostReportId(rootState) !== getTopmostReportId(state)) { + } else if ( + action.payload.name === NAVIGATORS.CENTRAL_PANE_NAVIGATOR && + topmostCentralPaneRoute && + (topmostCentralPaneRoute.name !== SCREENS.REPORT || getTopmostReportId(rootState) !== getTopmostReportId(stateFromPath)) + ) { + // We need to push a tab if the tab doesn't match the central pane route that we are going to push. + const topmostBottomTabRoute = getTopmostBottomTabRoute(rootState); + const matchingBottomTabRoute = getMatchingBottomTabRouteForState(stateFromPath); + if (topmostBottomTabRoute.name !== matchingBottomTabRoute.name) { + root.dispatch({ + type: CONST.NAVIGATION.ACTION_TYPE.PUSH, + payload: matchingBottomTabRoute, + }); + } + action.type = CONST.NAVIGATION.ACTION_TYPE.PUSH; // If the type is UP, we deeplinked into one of the RHP flows and we want to replace the current screen with the previous one in the flow @@ -91,6 +133,30 @@ export default function linkTo(navigation: NavigationContainerRef Date: Wed, 13 Dec 2023 19:22:56 +0100 Subject: [PATCH 114/722] fix linting errors --- src/CONST.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/CONST.ts b/src/CONST.ts index dbb031b63438..072f780b54ae 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -1,7 +1,6 @@ /* eslint-disable @typescript-eslint/naming-convention */ import Config from 'react-native-config'; import * as KeyCommand from 'react-native-key-command'; -import {BottomTabName, CentralPaneName} from '@libs/Navigation/types'; import * as Url from './libs/Url'; import SCREENS from './SCREENS'; From 87061091ef3938e84ed547160b7f8da0e11a8cfe Mon Sep 17 00:00:00 2001 From: Adam Grzybowski Date: Fri, 15 Dec 2023 12:45:01 +0100 Subject: [PATCH 115/722] add POP_TO_TOP when navigating to bottom tab on small screen --- src/libs/Navigation/linkTo.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/libs/Navigation/linkTo.ts b/src/libs/Navigation/linkTo.ts index 265887346b8c..550b5ddb7d62 100644 --- a/src/libs/Navigation/linkTo.ts +++ b/src/libs/Navigation/linkTo.ts @@ -155,6 +155,12 @@ export default function linkTo(navigation: NavigationContainerRef Date: Fri, 15 Dec 2023 13:37:51 +0100 Subject: [PATCH 116/722] fix padding --- src/styles/styles.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/styles/styles.ts b/src/styles/styles.ts index a87dd8d09c6f..db4ff95b1b4c 100644 --- a/src/styles/styles.ts +++ b/src/styles/styles.ts @@ -1406,7 +1406,7 @@ const styles = (theme: ThemeColors) => createAccountMenuPositionProfile: () => ({ horizontal: 18, - ...getPopOverVerticalOffset(162), + ...getPopOverVerticalOffset(202 + 40), } satisfies AnchorPosition), createMenuPositionProfile: (windowWidth: number) => From 8be9983ca0461b9a6348f3f63ef6c36b816671fd Mon Sep 17 00:00:00 2001 From: Adam Grzybowski Date: Fri, 15 Dec 2023 15:38:18 +0100 Subject: [PATCH 117/722] add removed workspace currency page --- src/libs/Navigation/AppNavigator/ModalStackNavigators.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators.tsx b/src/libs/Navigation/AppNavigator/ModalStackNavigators.tsx index c63dd80f7621..26e2e7aac0f0 100644 --- a/src/libs/Navigation/AppNavigator/ModalStackNavigators.tsx +++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators.tsx @@ -220,6 +220,7 @@ const SettingsModalStackNavigator = createModalStackNavigator require('../../../pages/settings/Profile/CustomStatus/StatusPage').default as React.ComponentType, [SCREENS.SETTINGS.PROFILE.STATUS_SET]: () => require('../../../pages/settings/Profile/CustomStatus/StatusSetPage').default as React.ComponentType, [SCREENS.WORKSPACE.RATE_AND_UNIT]: () => require('../../../pages/workspace/reimburse/WorkspaceRateAndUnitPage').default as React.ComponentType, + [SCREENS.WORKSPACE.CURRENCY]: () => require('../../../pages/workspace/WorkspaceSettingsCurrencyPage').default as React.ComponentType, [SCREENS.WORKSPACE.INVITE]: () => require('../../../pages/workspace/WorkspaceInvitePage').default as React.ComponentType, [SCREENS.WORKSPACE.INVITE_MESSAGE]: () => require('../../../pages/workspace/WorkspaceInviteMessagePage').default as React.ComponentType, [SCREENS.REIMBURSEMENT_ACCOUNT]: () => require('../../../pages/ReimbursementAccount/ReimbursementAccountPage').default as React.ComponentType, From 6eb63989f167bc46427cd66ea74014ebfc630655 Mon Sep 17 00:00:00 2001 From: Adam Grzybowski Date: Fri, 15 Dec 2023 17:00:22 +0100 Subject: [PATCH 118/722] change workspace settings to workspace overview --- src/CONST.ts | 2 +- src/ROUTES.ts | 12 ++++++------ src/SCREENS.ts | 4 ++-- src/languages/en.ts | 1 + src/languages/es.ts | 1 + .../AppNavigator/ModalStackNavigators.tsx | 2 +- .../BaseCentralPaneNavigator.tsx | 2 +- .../Navigation/TAB_TO_CENTRAL_PANE_MAPPING.ts | 2 +- src/libs/Navigation/linkingConfig.ts | 4 ++-- src/libs/Navigation/types.ts | 2 +- src/pages/workspace/WorkspaceInitialPage.js | 6 +++--- ...yPage.js => WorkspaceOverviewCurrencyPage.js} | 4 ++-- ...eSettingsPage.js => WorkspaceOverviewPage.js} | 16 ++++++++-------- 13 files changed, 30 insertions(+), 28 deletions(-) rename src/pages/workspace/{WorkspaceSettingsCurrencyPage.js => WorkspaceOverviewCurrencyPage.js} (97%) rename src/pages/workspace/{WorkspaceSettingsPage.js => WorkspaceOverviewPage.js} (95%) diff --git a/src/CONST.ts b/src/CONST.ts index 072f780b54ae..e55e3664a29b 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -1404,7 +1404,7 @@ const CONST = { GUIDES_CALL_TASK_IDS: { CONCIERGE_DM: 'NewExpensifyConciergeDM', WORKSPACE_INITIAL: 'WorkspaceHome', - WORKSPACE_SETTINGS: 'WorkspaceGeneralSettings', + WORKSPACE_OVERVIEW: 'WorkspaceGeneralSettings', WORKSPACE_CARD: 'WorkspaceCorporateCards', WORKSPACE_REIMBURSE: 'WorkspaceReimburseReceipts', WORKSPACE_BILLS: 'WorkspacePayBills', diff --git a/src/ROUTES.ts b/src/ROUTES.ts index 44563b74d48e..1ea8bca94cf6 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -422,13 +422,13 @@ const ROUTES = { route: 'workspace/:policyID/invite-message', getRoute: (policyID: string) => `workspace/${policyID}/invite-message` as const, }, - WORKSPACE_SETTINGS: { - route: 'workspace/:policyID/settings', - getRoute: (policyID: string) => `workspace/${policyID}/settings` as const, + WORKSPACE_OVERVIEW: { + route: 'workspace/:policyID/overview', + getRoute: (policyID: string) => `workspace/${policyID}/overview` as const, }, - WORKSPACE_SETTINGS_CURRENCY: { - route: 'workspace/:policyID/settings/currency', - getRoute: (policyID: string) => `workspace/${policyID}/settings/currency` as const, + WORKSPACE_OVERVIEW_CURRENCY: { + route: 'workspace/:policyID/overview/currency', + getRoute: (policyID: string) => `workspace/${policyID}/overview/currency` as const, }, WORKSPACE_CARD: { route: 'workspace/:policyID/card', diff --git a/src/SCREENS.ts b/src/SCREENS.ts index 44f11c059321..86913760e784 100644 --- a/src/SCREENS.ts +++ b/src/SCREENS.ts @@ -185,7 +185,7 @@ const SCREENS = { WORKSPACE: { INITIAL: 'Workspace_Initial', - SETTINGS: 'Workspace_Settings', + OVERVIEW: 'Workspace_Overview', CARD: 'Workspace_Card', REIMBURSE: 'Workspace_Reimburse', RATE_AND_UNIT: 'Workspace_RateAndUnit', @@ -195,7 +195,7 @@ const SCREENS = { MEMBERS: 'Workspace_Members', INVITE: 'Workspace_Invite', INVITE_MESSAGE: 'Workspace_Invite_Message', - CURRENCY: 'Workspace_Settings_Currency', + CURRENCY: 'Workspace_Overview_Currency', }, EDIT_REQUEST: { diff --git a/src/languages/en.ts b/src/languages/en.ts index c4a481cb71c0..fe7629a2a971 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -1455,6 +1455,7 @@ export default { invoices: 'Invoices', travel: 'Travel', members: 'Members', + overview: 'Overview', bankAccount: 'Bank account', connectBankAccount: 'Connect bank account', testTransactions: 'Test transactions', diff --git a/src/languages/es.ts b/src/languages/es.ts index a91a8768a3ee..ee0a38d91c61 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -1478,6 +1478,7 @@ export default { invoices: 'Enviar facturas', travel: 'Viajes', members: 'Miembros', + overview: 'Descripción', bankAccount: 'Cuenta bancaria', connectBankAccount: 'Conectar cuenta bancaria', testTransactions: 'Transacciones de prueba', diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators.tsx b/src/libs/Navigation/AppNavigator/ModalStackNavigators.tsx index 26e2e7aac0f0..ce38daa4d6cd 100644 --- a/src/libs/Navigation/AppNavigator/ModalStackNavigators.tsx +++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators.tsx @@ -220,7 +220,7 @@ const SettingsModalStackNavigator = createModalStackNavigator require('../../../pages/settings/Profile/CustomStatus/StatusPage').default as React.ComponentType, [SCREENS.SETTINGS.PROFILE.STATUS_SET]: () => require('../../../pages/settings/Profile/CustomStatus/StatusSetPage').default as React.ComponentType, [SCREENS.WORKSPACE.RATE_AND_UNIT]: () => require('../../../pages/workspace/reimburse/WorkspaceRateAndUnitPage').default as React.ComponentType, - [SCREENS.WORKSPACE.CURRENCY]: () => require('../../../pages/workspace/WorkspaceSettingsCurrencyPage').default as React.ComponentType, + [SCREENS.WORKSPACE.CURRENCY]: () => require('../../../pages/workspace/WorkspaceOverviewCurrencyPage').default as React.ComponentType, [SCREENS.WORKSPACE.INVITE]: () => require('../../../pages/workspace/WorkspaceInvitePage').default as React.ComponentType, [SCREENS.WORKSPACE.INVITE_MESSAGE]: () => require('../../../pages/workspace/WorkspaceInviteMessagePage').default as React.ComponentType, [SCREENS.REIMBURSEMENT_ACCOUNT]: () => require('../../../pages/ReimbursementAccount/ReimbursementAccountPage').default as React.ComponentType, diff --git a/src/libs/Navigation/AppNavigator/Navigators/CentralPaneNavigator/BaseCentralPaneNavigator.tsx b/src/libs/Navigation/AppNavigator/Navigators/CentralPaneNavigator/BaseCentralPaneNavigator.tsx index aade06d10b16..aa4e78137cd2 100644 --- a/src/libs/Navigation/AppNavigator/Navigators/CentralPaneNavigator/BaseCentralPaneNavigator.tsx +++ b/src/libs/Navigation/AppNavigator/Navigators/CentralPaneNavigator/BaseCentralPaneNavigator.tsx @@ -15,7 +15,7 @@ type Screens = Partial React.C const workspaceSettingsScreens = { [SCREENS.SETTINGS.WORKSPACES]: () => require('../../../../../pages/workspace/WorkspacesListPage').default as React.ComponentType, - [SCREENS.WORKSPACE.SETTINGS]: () => require('../../../../../pages/workspace/WorkspaceSettingsPage').default as React.ComponentType, + [SCREENS.WORKSPACE.OVERVIEW]: () => require('../../../../../pages/workspace/WorkspaceOverviewPage').default as React.ComponentType, [SCREENS.WORKSPACE.CARD]: () => require('../../../../../pages/workspace/card/WorkspaceCardPage').default as React.ComponentType, [SCREENS.WORKSPACE.REIMBURSE]: () => require('../../../../../pages/workspace/reimburse/WorkspaceReimbursePage').default as React.ComponentType, [SCREENS.WORKSPACE.BILLS]: () => require('../../../../../pages/workspace/bills/WorkspaceBillsPage').default as React.ComponentType, diff --git a/src/libs/Navigation/TAB_TO_CENTRAL_PANE_MAPPING.ts b/src/libs/Navigation/TAB_TO_CENTRAL_PANE_MAPPING.ts index 1f728b142306..458b592d9399 100755 --- a/src/libs/Navigation/TAB_TO_CENTRAL_PANE_MAPPING.ts +++ b/src/libs/Navigation/TAB_TO_CENTRAL_PANE_MAPPING.ts @@ -5,7 +5,7 @@ const TAB_TO_CENTRAL_PANE_MAPPING: Record = { [SCREENS.HOME]: [SCREENS.REPORT], [SCREENS.ALL_SETTINGS]: [SCREENS.SETTINGS.WORKSPACES], [SCREENS.WORKSPACE.INITIAL]: [ - SCREENS.WORKSPACE.SETTINGS, + SCREENS.WORKSPACE.OVERVIEW, SCREENS.WORKSPACE.CARD, SCREENS.WORKSPACE.REIMBURSE, SCREENS.WORKSPACE.BILLS, diff --git a/src/libs/Navigation/linkingConfig.ts b/src/libs/Navigation/linkingConfig.ts index 38117d89b611..67c71be61a86 100644 --- a/src/libs/Navigation/linkingConfig.ts +++ b/src/libs/Navigation/linkingConfig.ts @@ -88,7 +88,7 @@ const linkingConfig: LinkingOptions = { [SCREENS.REPORT]: ROUTES.REPORT_WITH_ID.route, [SCREENS.SETTINGS.WORKSPACES]: ROUTES.SETTINGS_WORKSPACES, - [SCREENS.WORKSPACE.SETTINGS]: ROUTES.WORKSPACE_SETTINGS.route, + [SCREENS.WORKSPACE.OVERVIEW]: ROUTES.WORKSPACE_OVERVIEW.route, [SCREENS.WORKSPACE.CARD]: { path: ROUTES.WORKSPACE_CARD.route, }, @@ -281,7 +281,7 @@ const linkingConfig: LinkingOptions = { exact: true, }, [SCREENS.WORKSPACE.CURRENCY]: { - path: ROUTES.WORKSPACE_SETTINGS_CURRENCY.route, + path: ROUTES.WORKSPACE_OVERVIEW_CURRENCY.route, }, [SCREENS.WORKSPACE.RATE_AND_UNIT]: { path: ROUTES.WORKSPACE_RATE_AND_UNIT.route, diff --git a/src/libs/Navigation/types.ts b/src/libs/Navigation/types.ts index 328147e6064f..f9e85317959b 100644 --- a/src/libs/Navigation/types.ts +++ b/src/libs/Navigation/types.ts @@ -52,7 +52,7 @@ type CentralPaneNavigatorParamList = { }; [SCREENS.SETTINGS.WORKSPACES]: undefined; - [SCREENS.WORKSPACE.SETTINGS]: { + [SCREENS.WORKSPACE.OVERVIEW]: { policyID: string; }; [SCREENS.WORKSPACE.CARD]: { diff --git a/src/pages/workspace/WorkspaceInitialPage.js b/src/pages/workspace/WorkspaceInitialPage.js index 3c73687ca813..6078f453b6eb 100644 --- a/src/pages/workspace/WorkspaceInitialPage.js +++ b/src/pages/workspace/WorkspaceInitialPage.js @@ -56,7 +56,7 @@ const defaultProps = { * @param {string} policyID */ function openEditor(policyID) { - Navigation.navigate(ROUTES.WORKSPACE_SETTINGS.getRoute(policyID)); + Navigation.navigate(ROUTES.WORKSPACE_OVERVIEW.getRoute(policyID)); } /** @@ -150,9 +150,9 @@ function WorkspaceInitialPage(props) { const hasCustomUnitsError = PolicyUtils.hasCustomUnitsError(policy); const menuItems = [ { - translationKey: 'workspace.common.settings', + translationKey: 'workspace.common.overview', icon: Expensicons.Gear, - action: singleExecution(waitForNavigate(() => Navigation.navigate(ROUTES.WORKSPACE_SETTINGS.getRoute(policy.id)))), + action: singleExecution(waitForNavigate(() => Navigation.navigate(ROUTES.WORKSPACE_OVERVIEW.getRoute(policy.id)))), brickRoadIndicator: hasGeneralSettingsError ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : '', }, { diff --git a/src/pages/workspace/WorkspaceSettingsCurrencyPage.js b/src/pages/workspace/WorkspaceOverviewCurrencyPage.js similarity index 97% rename from src/pages/workspace/WorkspaceSettingsCurrencyPage.js rename to src/pages/workspace/WorkspaceOverviewCurrencyPage.js index ce1e1d7b8966..e58f53e60a6e 100644 --- a/src/pages/workspace/WorkspaceSettingsCurrencyPage.js +++ b/src/pages/workspace/WorkspaceOverviewCurrencyPage.js @@ -68,11 +68,11 @@ function WorkspaceSettingsCurrencyPage({currencyList, policy, isLoadingReportDat const headerMessage = searchText.trim() && !currencyItems.length ? translate('common.noResultsFound') : ''; - const onBackButtonPress = useCallback(() => Navigation.goBack(ROUTES.WORKSPACE_SETTINGS.getRoute(policy.id)), [policy.id]); + const onBackButtonPress = useCallback(() => Navigation.goBack(ROUTES.WORKSPACE_OVERVIEW.getRoute(policy.id)), [policy.id]); const onSelectCurrency = (item) => { Policy.updateGeneralSettings(policy.id, policy.name, item.keyForList); - Navigation.goBack(ROUTES.WORKSPACE_SETTINGS.getRoute(policy.id)); + Navigation.goBack(ROUTES.WORKSPACE_OVERVIEW.getRoute(policy.id)); }; return ( diff --git a/src/pages/workspace/WorkspaceSettingsPage.js b/src/pages/workspace/WorkspaceOverviewPage.js similarity index 95% rename from src/pages/workspace/WorkspaceSettingsPage.js rename to src/pages/workspace/WorkspaceOverviewPage.js index d121134f26da..eda23089a038 100644 --- a/src/pages/workspace/WorkspaceSettingsPage.js +++ b/src/pages/workspace/WorkspaceOverviewPage.js @@ -56,7 +56,7 @@ const defaultProps = { ...policyDefaultProps, }; -function WorkspaceSettingsPage({policy, currencyList, windowWidth, route}) { +function WorkspaceOverviewPage({policy, currencyList, windowWidth, route}) { const styles = useThemeStyles(); const {translate} = useLocalize(); @@ -90,15 +90,15 @@ function WorkspaceSettingsPage({policy, currencyList, windowWidth, route}) { return errors; }, []); - const onPressCurrency = useCallback(() => Navigation.navigate(ROUTES.WORKSPACE_SETTINGS_CURRENCY.getRoute(policy.id)), [policy.id]); + const onPressCurrency = useCallback(() => Navigation.navigate(ROUTES.WORKSPACE_OVERVIEW_CURRENCY.getRoute(policy.id)), [policy.id]); const policyName = lodashGet(policy, 'name', ''); return ( {(hasVBA) => ( Date: Mon, 18 Dec 2023 13:58:54 +0100 Subject: [PATCH 119/722] cleanup: rename settings screen name --- ...react-navigation+stack+6.3.16+002+dontDetachScreen.patch | 2 +- src/ROUTES.ts | 2 -- src/SCREENS.ts | 1 - src/libs/Navigation/AppNavigator/ModalStackNavigators.tsx | 3 +-- .../AppNavigator/Navigators/FullScreenNavigator.tsx | 2 +- .../AppNavigator/createCustomStackNavigator/CustomRouter.ts | 2 +- src/libs/Navigation/linkingConfig.ts | 6 +++--- src/libs/Navigation/types.ts | 2 +- src/pages/ShareCodePage.js | 2 +- src/pages/home/sidebar/PressableAvatarWithIndicator.js | 2 +- src/pages/settings/AboutPage/AboutPage.js | 2 +- src/pages/settings/Profile/ProfilePage.js | 2 +- src/pages/settings/Security/SecuritySettingsPage.js | 2 +- src/pages/settings/Wallet/WalletEmptyState.js | 2 +- src/pages/settings/Wallet/WalletPage/WalletPage.js | 2 +- src/pages/workspace/WorkspacesListPage.js | 2 +- 16 files changed, 16 insertions(+), 20 deletions(-) diff --git a/patches/@react-navigation+stack+6.3.16+002+dontDetachScreen.patch b/patches/@react-navigation+stack+6.3.16+002+dontDetachScreen.patch index 0412f095f5ea..877521094cd4 100644 --- a/patches/@react-navigation+stack+6.3.16+002+dontDetachScreen.patch +++ b/patches/@react-navigation+stack+6.3.16+002+dontDetachScreen.patch @@ -43,7 +43,7 @@ index 7558eb3..b7bb75e 100644 }) : STATE_TRANSITIONING_OR_BELOW_TOP; } + -+ const isHomeScreenAndNotOnTop = (route.name === 'BottomTabNavigator' || route.name === 'SettingsHome') && isScreenActive !== STATE_ON_TOP; ++ const isHomeScreenAndNotOnTop = (route.name === 'BottomTabNavigator' || route.name === 'Settings_Root') && isScreenActive !== STATE_ON_TOP; + const { headerShown = true, diff --git a/src/ROUTES.ts b/src/ROUTES.ts index 103aa77b55e2..1ea8bca94cf6 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -59,8 +59,6 @@ const ROUTES = { }, SETTINGS: 'settings', - SETTINGS_HOME: 'settings_new', - SETTINGS_NEW_PROFILE: 'settings_new/profile', SETTINGS_PROFILE: 'settings/profile', SETTINGS_SHARE_CODE: 'settings/shareCode', SETTINGS_DISPLAY_NAME: 'settings/profile/display-name', diff --git a/src/SCREENS.ts b/src/SCREENS.ts index 5f87b8deef9f..81e19295d289 100644 --- a/src/SCREENS.ts +++ b/src/SCREENS.ts @@ -18,7 +18,6 @@ const SCREENS = { TRANSITION_BETWEEN_APPS: 'TransitionBetweenApps', VALIDATE_LOGIN: 'ValidateLogin', UNLINK_LOGIN: 'UnlinkLogin', - SETTINGS_HOME: 'SettingsHome', SETTINGS_CENTRAL_PANE: 'SettingsCentralPane', SETTINGS: { ROOT: 'Settings_Root', diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators.tsx b/src/libs/Navigation/AppNavigator/ModalStackNavigators.tsx index ac40d45b7a09..c64650f91133 100644 --- a/src/libs/Navigation/AppNavigator/ModalStackNavigators.tsx +++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators.tsx @@ -178,9 +178,9 @@ const NewTeachersUniteNavigator = createModalStackNavigator require('../../../pages/TeachersUnite/ImTeacherPage').default as React.ComponentType, }); -// should it be merged with SettingsModalStackNavigator? const AccountSettingsModalStackNavigator = createModalStackNavigator( { + [SCREENS.SETTINGS.ROOT]: () => require('../../../pages/settings/InitialSettingsPage').default as React.ComponentType, [SCREENS.SETTINGS.WORKSPACES]: () => require('../../../pages/workspace/WorkspacesListPage').default as React.ComponentType, [SCREENS.SETTINGS.PREFERENCES.ROOT]: () => require('../../../pages/settings/Preferences/PreferencesPage').default as React.ComponentType, [SCREENS.SETTINGS.SECURITY]: () => require('../../../pages/settings/Security/SecuritySettingsPage').default as React.ComponentType, @@ -193,7 +193,6 @@ const AccountSettingsModalStackNavigator = createModalStackNavigator( ); const SettingsModalStackNavigator = createModalStackNavigator({ - [SCREENS.SETTINGS.ROOT]: () => require('../../../pages/settings/InitialSettingsPage').default as React.ComponentType, [SCREENS.SETTINGS.SHARE_CODE]: () => require('../../../pages/ShareCodePage').default as React.ComponentType, [SCREENS.SETTINGS.PROFILE.ROOT]: () => require('../../../pages/settings/Profile/ProfilePage').default as React.ComponentType, [SCREENS.SETTINGS.PROFILE.PRONOUNS]: () => require('../../../pages/settings/Profile/PronounsPage').default as React.ComponentType, diff --git a/src/libs/Navigation/AppNavigator/Navigators/FullScreenNavigator.tsx b/src/libs/Navigation/AppNavigator/Navigators/FullScreenNavigator.tsx index 4c65bfa3ae71..cf9a0e5856f7 100644 --- a/src/libs/Navigation/AppNavigator/Navigators/FullScreenNavigator.tsx +++ b/src/libs/Navigation/AppNavigator/Navigators/FullScreenNavigator.tsx @@ -20,7 +20,7 @@ function FullScreenNavigator() { diff --git a/src/libs/Navigation/AppNavigator/createCustomStackNavigator/CustomRouter.ts b/src/libs/Navigation/AppNavigator/createCustomStackNavigator/CustomRouter.ts index 599cb4c71cc6..c79f970239a7 100644 --- a/src/libs/Navigation/AppNavigator/createCustomStackNavigator/CustomRouter.ts +++ b/src/libs/Navigation/AppNavigator/createCustomStackNavigator/CustomRouter.ts @@ -76,7 +76,7 @@ const handleSettingsOpened = (state: State) => { state: { routes: [ { - name: SCREENS.SETTINGS_HOME, + name: SCREENS.SETTINGS.ROOT, }, { name: SCREENS.SETTINGS_CENTRAL_PANE, diff --git a/src/libs/Navigation/linkingConfig.ts b/src/libs/Navigation/linkingConfig.ts index 89ded1c7edee..f3a31de7e015 100644 --- a/src/libs/Navigation/linkingConfig.ts +++ b/src/libs/Navigation/linkingConfig.ts @@ -499,10 +499,10 @@ const linkingConfig: LinkingOptions = { }, [NAVIGATORS.FULL_SCREEN_NAVIGATOR]: { - initialRouteName: SCREENS.SETTINGS_HOME, + initialRouteName: SCREENS.SETTINGS.ROOT, screens: { - [SCREENS.SETTINGS_HOME]: { - path: ROUTES.SETTINGS_HOME, + [SCREENS.SETTINGS.ROOT]: { + path: ROUTES.SETTINGS, }, [SCREENS.SETTINGS_CENTRAL_PANE]: { screens: { diff --git a/src/libs/Navigation/types.ts b/src/libs/Navigation/types.ts index 68c4bd21ec62..08a0f9727436 100644 --- a/src/libs/Navigation/types.ts +++ b/src/libs/Navigation/types.ts @@ -384,7 +384,7 @@ type SettingsCentralPaneNavigatorParamList = { }; type FullScreenNavigatorParamList = { - [SCREENS.SETTINGS_HOME]: undefined; + [SCREENS.SETTINGS.ROOT]: undefined; [SCREENS.SETTINGS_CENTRAL_PANE]: NavigatorScreenParams; }; diff --git a/src/pages/ShareCodePage.js b/src/pages/ShareCodePage.js index 8a3ba71082a5..5e8fe32b1cf5 100644 --- a/src/pages/ShareCodePage.js +++ b/src/pages/ShareCodePage.js @@ -81,7 +81,7 @@ class ShareCodePage extends React.Component { Navigation.goBack(isReport ? ROUTES.REPORT_WITH_ID_DETAILS.getRoute(this.props.report.reportID) : ROUTES.SETTINGS_HOME)} + onBackButtonPress={() => Navigation.goBack(isReport ? ROUTES.REPORT_WITH_ID_DETAILS.getRoute(this.props.report.reportID) : ROUTES.SETTINGS.ROOT)} shouldUseCentralPaneView shouldShowBorderBottom /> diff --git a/src/pages/home/sidebar/PressableAvatarWithIndicator.js b/src/pages/home/sidebar/PressableAvatarWithIndicator.js index 32dd4af8e1d7..d72aef2ef824 100644 --- a/src/pages/home/sidebar/PressableAvatarWithIndicator.js +++ b/src/pages/home/sidebar/PressableAvatarWithIndicator.js @@ -46,7 +46,7 @@ function PressableAvatarWithIndicator({isCreateMenuOpen, currentUserPersonalDeta return; } - Navigation.navigate(ROUTES.SETTINGS_HOME); + Navigation.navigate(ROUTES.SETTINGS); }, [isCreateMenuOpen]); return ( diff --git a/src/pages/settings/AboutPage/AboutPage.js b/src/pages/settings/AboutPage/AboutPage.js index ac96c802d597..819c3883fb40 100644 --- a/src/pages/settings/AboutPage/AboutPage.js +++ b/src/pages/settings/AboutPage/AboutPage.js @@ -103,7 +103,7 @@ function AboutPage(props) { <> Navigation.goBack(ROUTES.SETTINGS_HOME)} + onBackButtonPress={() => Navigation.goBack(ROUTES.SETTINGS.ROOT)} shouldUseCentralPaneView shouldShowBorderBottom /> diff --git a/src/pages/settings/Profile/ProfilePage.js b/src/pages/settings/Profile/ProfilePage.js index 197de876cbdc..036f5b5d9671 100755 --- a/src/pages/settings/Profile/ProfilePage.js +++ b/src/pages/settings/Profile/ProfilePage.js @@ -108,7 +108,7 @@ function ProfilePage(props) { > Navigation.goBack(ROUTES.SETTINGS_HOME)} + onBackButtonPress={() => Navigation.goBack(ROUTES.SETTINGS.ROOT)} shouldUseCentralPaneView shouldShowBorderBottom /> diff --git a/src/pages/settings/Security/SecuritySettingsPage.js b/src/pages/settings/Security/SecuritySettingsPage.js index 95ce2dc7eb6f..52b15c72d7a5 100644 --- a/src/pages/settings/Security/SecuritySettingsPage.js +++ b/src/pages/settings/Security/SecuritySettingsPage.js @@ -66,7 +66,7 @@ function SecuritySettingsPage(props) { return ( Navigation.goBack(ROUTES.SETTINGS_HOME)} + onBackButtonPress={() => Navigation.goBack(ROUTES.SETTINGS.ROOT)} shouldShowBackButton illustration={LottieAnimations.Safe} backgroundColor={theme.PAGE_THEMES[SCREENS.SETTINGS.SECURITY].backgroundColor} diff --git a/src/pages/settings/Wallet/WalletEmptyState.js b/src/pages/settings/Wallet/WalletEmptyState.js index c533c68c1b15..28eb3e31e9b4 100644 --- a/src/pages/settings/Wallet/WalletEmptyState.js +++ b/src/pages/settings/Wallet/WalletEmptyState.js @@ -38,7 +38,7 @@ function WalletEmptyState({onAddPaymentMethod}) { Navigation.goBack(ROUTES.SETTINGS_HOME)} + onBackButtonPress={() => Navigation.goBack(ROUTES.SETTINGS.ROOT)} title={translate('common.wallet')} footer={