From 8e93b02cb63dee1a00a368cf9effbd8dda4b82fe Mon Sep 17 00:00:00 2001 From: Rayane Djouah <77965000+rayane-djouah@users.noreply.github.com> Date: Sun, 4 Aug 2024 18:03:07 +0100 Subject: [PATCH 01/14] Replace usages of useWindowDimensions with useResponsiveLayout --- .storybook/preview.tsx | 5 +- src/App.tsx | 2 - .../PaymentCardCurrencyModal.tsx | 4 +- .../Attachments/AttachmentCarousel/index.tsx | 4 +- .../AutoCompleteSuggestions/index.tsx | 4 +- .../ConnectToNetSuiteButton/index.tsx | 4 +- .../ConnectToSageIntacctButton/index.tsx | 4 +- src/components/EmptyStateComponent/index.tsx | 6 +- src/components/ExpensifyWordmark.tsx | 17 ++-- src/components/FeatureTrainingModal.tsx | 3 +- .../FocusTrapForScreen/index.web.tsx | 4 +- src/components/Modal/BaseModal.tsx | 4 +- src/components/MoneyReportHeader.tsx | 4 +- src/components/MoneyRequestHeader.tsx | 4 +- src/components/Popover/index.native.tsx | 2 +- src/components/Popover/index.tsx | 2 +- src/components/Popover/types.ts | 5 +- src/components/PopoverWithMeasuredContent.tsx | 5 +- src/components/Search/index.tsx | 4 +- .../SelectionList/Search/ReportListItem.tsx | 4 +- .../Search/TransactionListItem.tsx | 4 +- .../Search/TransactionListItemRow.tsx | 4 +- .../SelectionList/Search/UserInfoCell.tsx | 4 +- .../SelectionList/SearchTableHeader.tsx | 4 +- src/components/Skeletons/CardRowSkeleton.tsx | 6 +- .../Skeletons/SearchRowSkeleton.tsx | 7 +- .../VideoPlayerContexts/FullScreenContext.tsx | 19 ++-- src/components/VideoPlayerContexts/types.ts | 8 +- .../withWindowDimensions/index.native.tsx | 81 ----------------- src/components/withWindowDimensions/index.tsx | 87 ------------------- src/components/withWindowDimensions/types.ts | 34 -------- src/hooks/useOnboardingLayout.ts | 19 ---- .../index.ts} | 33 ++++--- src/hooks/useResponsiveLayout/types.ts | 12 +++ src/hooks/useThumbnailDimensions.ts | 5 +- src/hooks/useWindowDimensions/index.native.ts | 28 ------ src/hooks/useWindowDimensions/index.ts | 51 ++++++----- src/hooks/useWindowDimensions/types.ts | 6 -- .../Navigation/AppNavigator/AuthScreens.tsx | 14 ++- .../useModalScreenOptions.ts | 4 +- .../Navigators/FullScreenNavigator.tsx | 4 +- .../Navigators/LeftModalNavigator.tsx | 4 +- .../Navigators/OnboardingModalNavigator.tsx | 4 +- .../Navigators/RightModalNavigator.tsx | 4 +- .../createCustomFullScreenNavigator/index.tsx | 4 +- .../createCustomStackNavigator/index.tsx | 4 +- src/libs/Navigation/NavigationRoot.tsx | 4 +- src/pages/FlagCommentPage.tsx | 2 +- .../BaseOnboardingPersonalDetails.tsx | 12 ++- .../BaseOnboardingPurpose.tsx | 3 +- .../OnboardingWork/BaseOnboardingWork.tsx | 3 +- .../withReportAndReportActionOrNotFound.tsx | 82 +++++++++-------- src/pages/iou/SplitBillDetailsPage.tsx | 3 +- .../workspace/expensifyCard/EmptyCardView.tsx | 10 ++- .../ReportActionCompose.perf-test.tsx | 3 +- .../perf-test/ReportActionsList.perf-test.tsx | 3 +- tests/perf-test/ReportScreen.perf-test.tsx | 13 +-- 57 files changed, 220 insertions(+), 463 deletions(-) delete mode 100644 src/components/withWindowDimensions/index.native.tsx delete mode 100644 src/components/withWindowDimensions/index.tsx delete mode 100644 src/components/withWindowDimensions/types.ts delete mode 100644 src/hooks/useOnboardingLayout.ts rename src/hooks/{useResponsiveLayout.ts => useResponsiveLayout/index.ts} (72%) create mode 100644 src/hooks/useResponsiveLayout/types.ts delete mode 100644 src/hooks/useWindowDimensions/index.native.ts diff --git a/.storybook/preview.tsx b/.storybook/preview.tsx index ec8e17dda4cf..d3829fe01779 100644 --- a/.storybook/preview.tsx +++ b/.storybook/preview.tsx @@ -9,7 +9,6 @@ import {LocaleContextProvider} from '@src/components/LocaleContextProvider'; import OnyxProvider from '@src/components/OnyxProvider'; import {EnvironmentProvider} from '@src/components/withEnvironment'; import {KeyboardStateProvider} from '@src/components/withKeyboardState'; -import {WindowDimensionsProvider} from '@src/components/withWindowDimensions'; import ONYXKEYS from '@src/ONYXKEYS'; import './fonts.css'; @@ -22,9 +21,7 @@ Onyx.init({ const decorators = [ (Story: React.ElementType) => ( - + ), diff --git a/src/App.tsx b/src/App.tsx index 98b5d4afeb1d..9c148555e6da 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -31,7 +31,6 @@ import {VolumeContextProvider} from './components/VideoPlayerContexts/VolumeCont import {CurrentReportIDContextProvider} from './components/withCurrentReportID'; import {EnvironmentProvider} from './components/withEnvironment'; import {KeyboardStateProvider} from './components/withKeyboardState'; -import {WindowDimensionsProvider} from './components/withWindowDimensions'; import CONFIG from './CONFIG'; import Expensify from './Expensify'; import useDefaultDragAndDrop from './hooks/useDefaultDragAndDrop'; @@ -75,7 +74,6 @@ function App({url}: AppProps) { SafeArea, LocaleContextProvider, HTMLEngineProvider, - WindowDimensionsProvider, KeyboardStateProvider, PopoverContextProvider, CurrentReportIDContextProvider, diff --git a/src/components/AddPaymentCard/PaymentCardCurrencyModal.tsx b/src/components/AddPaymentCard/PaymentCardCurrencyModal.tsx index c3c38c4aec72..ab3058ff4631 100644 --- a/src/components/AddPaymentCard/PaymentCardCurrencyModal.tsx +++ b/src/components/AddPaymentCard/PaymentCardCurrencyModal.tsx @@ -6,8 +6,8 @@ import ScreenWrapper from '@components/ScreenWrapper'; import SelectionList from '@components/SelectionList'; import RadioListItem from '@components/SelectionList/RadioListItem'; import useLocalize from '@hooks/useLocalize'; +import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useThemeStyles from '@hooks/useThemeStyles'; -import useWindowDimensions from '@hooks/useWindowDimensions'; import CONST from '@src/CONST'; type PaymentCardCurrencyModalProps = { @@ -28,7 +28,7 @@ type PaymentCardCurrencyModalProps = { }; function PaymentCardCurrencyModal({isVisible, currencies, currentCurrency = CONST.PAYMENT_CARD_CURRENCY.USD, onCurrencyChange, onClose}: PaymentCardCurrencyModalProps) { - const {isSmallScreenWidth} = useWindowDimensions(); + const {isSmallScreenWidth} = useResponsiveLayout(); const styles = useThemeStyles(); const {translate} = useLocalize(); const {sections} = useMemo( diff --git a/src/components/Attachments/AttachmentCarousel/index.tsx b/src/components/Attachments/AttachmentCarousel/index.tsx index f7ef2c6529ce..3f4f136b6efe 100644 --- a/src/components/Attachments/AttachmentCarousel/index.tsx +++ b/src/components/Attachments/AttachmentCarousel/index.tsx @@ -12,6 +12,7 @@ import BlockingView from '@components/BlockingViews/BlockingView'; import * as Illustrations from '@components/Icon/Illustrations'; import {useFullScreenContext} from '@components/VideoPlayerContexts/FullScreenContext'; import useLocalize from '@hooks/useLocalize'; +import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; import useWindowDimensions from '@hooks/useWindowDimensions'; @@ -40,7 +41,8 @@ const MIN_FLING_VELOCITY = 500; function AttachmentCarousel({report, reportActions, parentReportActions, source, onNavigate, setDownloadButtonVisibility, type, accountID, onClose}: AttachmentCarouselProps) { const theme = useTheme(); const {translate} = useLocalize(); - const {isSmallScreenWidth, windowWidth} = useWindowDimensions(); + const {windowWidth} = useWindowDimensions(); + const {isSmallScreenWidth} = useResponsiveLayout(); const styles = useThemeStyles(); const {isFullScreenRef} = useFullScreenContext(); const scrollRef = useAnimatedRef>>(); diff --git a/src/components/AutoCompleteSuggestions/index.tsx b/src/components/AutoCompleteSuggestions/index.tsx index 41a01fa27c46..f454f5e37526 100644 --- a/src/components/AutoCompleteSuggestions/index.tsx +++ b/src/components/AutoCompleteSuggestions/index.tsx @@ -1,5 +1,6 @@ import React, {useEffect} from 'react'; import useKeyboardState from '@hooks/useKeyboardState'; +import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useSafeAreaInsets from '@hooks/useSafeAreaInsets'; import useStyleUtils from '@hooks/useStyleUtils'; import useWindowDimensions from '@hooks/useWindowDimensions'; @@ -53,7 +54,8 @@ function AutoCompleteSuggestions({measureParentContainerAndReportCu const isSuggestionMenuAboveRef = React.useRef(false); const leftValue = React.useRef(0); const prevLeftValue = React.useRef(0); - const {windowHeight, windowWidth, isSmallScreenWidth} = useWindowDimensions(); + const {windowHeight, windowWidth} = useWindowDimensions(); + const {isSmallScreenWidth} = useResponsiveLayout(); const [suggestionHeight, setSuggestionHeight] = React.useState(0); const [containerState, setContainerState] = React.useState(initialContainerState); const StyleUtils = useStyleUtils(); diff --git a/src/components/ConnectToNetSuiteButton/index.tsx b/src/components/ConnectToNetSuiteButton/index.tsx index 928bc01f12c1..2758efcc81f9 100644 --- a/src/components/ConnectToNetSuiteButton/index.tsx +++ b/src/components/ConnectToNetSuiteButton/index.tsx @@ -7,8 +7,8 @@ import * as Expensicons from '@components/Icon/Expensicons'; import PopoverMenu from '@components/PopoverMenu'; import useLocalize from '@hooks/useLocalize'; import useNetwork from '@hooks/useNetwork'; +import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useThemeStyles from '@hooks/useThemeStyles'; -import useWindowDimensions from '@hooks/useWindowDimensions'; import {removePolicyConnection} from '@libs/actions/connections'; import {getAdminPoliciesConnectedToNetSuite} from '@libs/actions/Policy/Policy'; import Navigation from '@libs/Navigation/Navigation'; @@ -28,7 +28,7 @@ function ConnectToNetSuiteButton({policyID, shouldDisconnectIntegrationBeforeCon const [isDisconnectModalOpen, setIsDisconnectModalOpen] = useState(false); const hasPoliciesConnectedToNetSuite = !!getAdminPoliciesConnectedToNetSuite()?.length; - const {isSmallScreenWidth} = useWindowDimensions(); + const {isSmallScreenWidth} = useResponsiveLayout(); const [isReuseConnectionsPopoverOpen, setIsReuseConnectionsPopoverOpen] = useState(false); const [reuseConnectionPopoverPosition, setReuseConnectionPopoverPosition] = useState({horizontal: 0, vertical: 0}); const threeDotsMenuContainerRef = useRef(null); diff --git a/src/components/ConnectToSageIntacctButton/index.tsx b/src/components/ConnectToSageIntacctButton/index.tsx index 6c6523ad6e75..4cdfa3e19b6e 100644 --- a/src/components/ConnectToSageIntacctButton/index.tsx +++ b/src/components/ConnectToSageIntacctButton/index.tsx @@ -7,8 +7,8 @@ import * as Expensicons from '@components/Icon/Expensicons'; import PopoverMenu from '@components/PopoverMenu'; import useLocalize from '@hooks/useLocalize'; import useNetwork from '@hooks/useNetwork'; +import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useThemeStyles from '@hooks/useThemeStyles'; -import useWindowDimensions from '@hooks/useWindowDimensions'; import {removePolicyConnection} from '@libs/actions/connections'; import {getAdminPoliciesConnectedToSageIntacct} from '@libs/actions/Policy/Policy'; import Navigation from '@libs/Navigation/Navigation'; @@ -35,7 +35,7 @@ function ConnectToSageIntacctButton({policyID, shouldDisconnectIntegrationBefore const [isDisconnectModalOpen, setIsDisconnectModalOpen] = useState(false); const hasPoliciesConnectedToSageIntacct = !!getAdminPoliciesConnectedToSageIntacct().length; - const {isSmallScreenWidth} = useWindowDimensions(); + const {isSmallScreenWidth} = useResponsiveLayout(); const [isReuseConnectionsPopoverOpen, setIsReuseConnectionsPopoverOpen] = useState(false); const [reuseConnectionPopoverPosition, setReuseConnectionPopoverPosition] = useState({horizontal: 0, vertical: 0}); const threeDotsMenuContainerRef = useRef(null); diff --git a/src/components/EmptyStateComponent/index.tsx b/src/components/EmptyStateComponent/index.tsx index 56f8fa5e3d83..c3d8323b2cf4 100644 --- a/src/components/EmptyStateComponent/index.tsx +++ b/src/components/EmptyStateComponent/index.tsx @@ -7,8 +7,8 @@ import Lottie from '@components/Lottie'; import ScrollView from '@components/ScrollView'; import Text from '@components/Text'; import VideoPlayer from '@components/VideoPlayer'; +import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useThemeStyles from '@hooks/useThemeStyles'; -import useWindowDimensions from '@hooks/useWindowDimensions'; import CONST from '@src/CONST'; import type {EmptyStateComponentProps, VideoLoadedEventType} from './types'; @@ -27,7 +27,7 @@ function EmptyStateComponent({ emptyStateForegroundStyles, }: EmptyStateComponentProps) { const styles = useThemeStyles(); - const {isSmallScreenWidth} = useWindowDimensions(); + const {shouldUseNarrowLayout} = useResponsiveLayout(); const [videoAspectRatio, setVideoAspectRatio] = useState(VIDEO_ASPECT_RATIO); const setAspectRatio = (event: VideoReadyForDisplayEvent | VideoLoadedEventType | undefined) => { @@ -86,7 +86,7 @@ function EmptyStateComponent({ shouldAnimate={false} /> - + {HeaderComponent} diff --git a/src/components/ExpensifyWordmark.tsx b/src/components/ExpensifyWordmark.tsx index 3d340da84f8b..69b8751aa829 100644 --- a/src/components/ExpensifyWordmark.tsx +++ b/src/components/ExpensifyWordmark.tsx @@ -6,15 +6,14 @@ import DevLogo from '@assets/images/expensify-logo--dev.svg'; import StagingLogo from '@assets/images/expensify-logo--staging.svg'; import ProductionLogo from '@assets/images/expensify-wordmark.svg'; import useEnvironment from '@hooks/useEnvironment'; +import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useStyleUtils from '@hooks/useStyleUtils'; import useThemeStyles from '@hooks/useThemeStyles'; import variables from '@styles/variables'; import CONST from '@src/CONST'; import ImageSVG from './ImageSVG'; -import withWindowDimensions from './withWindowDimensions'; -import type {WindowDimensionsProps} from './withWindowDimensions/types'; -type ExpensifyWordmarkProps = WindowDimensionsProps & { +type ExpensifyWordmarkProps = { /** Additional styles to add to the component */ style?: StyleProp; }; @@ -26,19 +25,21 @@ const logoComponents = { [CONST.ENVIRONMENT.ADHOC]: AdHocLogo, }; -function ExpensifyWordmark({isSmallScreenWidth, style}: ExpensifyWordmarkProps) { +function ExpensifyWordmark({style}: ExpensifyWordmarkProps) { const styles = useThemeStyles(); const StyleUtils = useStyleUtils(); const {environment} = useEnvironment(); // PascalCase is required for React components, so capitalize the const here const LogoComponent = logoComponents[environment]; + const {shouldUseNarrowLayout} = useResponsiveLayout(); + return ( @@ -52,4 +53,4 @@ function ExpensifyWordmark({isSmallScreenWidth, style}: ExpensifyWordmarkProps) ExpensifyWordmark.displayName = 'ExpensifyWordmark'; -export default withWindowDimensions(ExpensifyWordmark); +export default ExpensifyWordmark; diff --git a/src/components/FeatureTrainingModal.tsx b/src/components/FeatureTrainingModal.tsx index d204567eee31..4ef51cff0e60 100644 --- a/src/components/FeatureTrainingModal.tsx +++ b/src/components/FeatureTrainingModal.tsx @@ -4,7 +4,6 @@ import {View} from 'react-native'; import {GestureHandlerRootView} from 'react-native-gesture-handler'; import useLocalize from '@hooks/useLocalize'; import useNetwork from '@hooks/useNetwork'; -import useOnboardingLayout from '@hooks/useOnboardingLayout'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useThemeStyles from '@hooks/useThemeStyles'; import Navigation from '@libs/Navigation/Navigation'; @@ -85,7 +84,7 @@ function FeatureTrainingModal({ }: FeatureTrainingModalProps) { const styles = useThemeStyles(); const {translate} = useLocalize(); - const {isMediumOrLargerScreenWidth} = useOnboardingLayout(); + const {isMediumOrLargerScreenWidth} = useResponsiveLayout(); const [isModalVisible, setIsModalVisible] = useState(true); const [willShowAgain, setWillShowAgain] = useState(true); const [videoStatus, setVideoStatus] = useState('video'); diff --git a/src/components/FocusTrap/FocusTrapForScreen/index.web.tsx b/src/components/FocusTrap/FocusTrapForScreen/index.web.tsx index cd8dc3ddaa0a..acbaeba5498d 100644 --- a/src/components/FocusTrap/FocusTrapForScreen/index.web.tsx +++ b/src/components/FocusTrap/FocusTrapForScreen/index.web.tsx @@ -5,7 +5,7 @@ import BOTTOM_TAB_SCREENS from '@components/FocusTrap/BOTTOM_TAB_SCREENS'; import sharedTrapStack from '@components/FocusTrap/sharedTrapStack'; import TOP_TAB_SCREENS from '@components/FocusTrap/TOP_TAB_SCREENS'; import WIDE_LAYOUT_INACTIVE_SCREENS from '@components/FocusTrap/WIDE_LAYOUT_INACTIVE_SCREENS'; -import useWindowDimensions from '@hooks/useWindowDimensions'; +import useResponsiveLayout from '@hooks/useResponsiveLayout'; import canFocusInputOnScreenFocus from '@libs/canFocusInputOnScreenFocus'; import CONST from '@src/CONST'; import type FocusTrapProps from './FocusTrapProps'; @@ -13,7 +13,7 @@ import type FocusTrapProps from './FocusTrapProps'; function FocusTrapForScreen({children}: FocusTrapProps) { const isFocused = useIsFocused(); const route = useRoute(); - const {isSmallScreenWidth} = useWindowDimensions(); + const {isSmallScreenWidth} = useResponsiveLayout(); const isActive = useMemo(() => { // Focus trap can't be active on bottom tab screens because it would block access to the tab bar. diff --git a/src/components/Modal/BaseModal.tsx b/src/components/Modal/BaseModal.tsx index 88ad2f6d5e00..f20030d7a412 100644 --- a/src/components/Modal/BaseModal.tsx +++ b/src/components/Modal/BaseModal.tsx @@ -5,6 +5,7 @@ import ColorSchemeWrapper from '@components/ColorSchemeWrapper'; import FocusTrapForModal from '@components/FocusTrap/FocusTrapForModal'; import useKeyboardState from '@hooks/useKeyboardState'; import usePrevious from '@hooks/usePrevious'; +import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useSafeAreaInsets from '@hooks/useSafeAreaInsets'; import useStyleUtils from '@hooks/useStyleUtils'; import useTheme from '@hooks/useTheme'; @@ -57,7 +58,8 @@ function BaseModal( const theme = useTheme(); const styles = useThemeStyles(); const StyleUtils = useStyleUtils(); - const {isSmallScreenWidth, windowWidth, windowHeight} = useWindowDimensions(); + const {windowWidth, windowHeight} = useWindowDimensions(); + const {isSmallScreenWidth} = useResponsiveLayout(); const keyboardStateContextValue = useKeyboardState(); const safeAreaInsets = useSafeAreaInsets(); diff --git a/src/components/MoneyReportHeader.tsx b/src/components/MoneyReportHeader.tsx index 655cdcaf2443..c427e586004c 100644 --- a/src/components/MoneyReportHeader.tsx +++ b/src/components/MoneyReportHeader.tsx @@ -4,9 +4,9 @@ import type {OnyxEntry} from 'react-native-onyx'; import {useOnyx} from 'react-native-onyx'; import useLocalize from '@hooks/useLocalize'; import useNetwork from '@hooks/useNetwork'; +import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; -import useWindowDimensions from '@hooks/useWindowDimensions'; import * as CurrencyUtils from '@libs/CurrencyUtils'; import Navigation from '@libs/Navigation/Navigation'; import * as PolicyUtils from '@libs/PolicyUtils'; @@ -86,7 +86,7 @@ function MoneyReportHeader({policy, report: moneyRequestReport, transactionThrea const [shouldShowHoldMenu, setShouldShowHoldMenu] = useState(false); const {translate} = useLocalize(); const {isOffline} = useNetwork(); - const {isSmallScreenWidth} = useWindowDimensions(); + const {isSmallScreenWidth} = useResponsiveLayout(); const {reimbursableSpend} = ReportUtils.getMoneyRequestSpendBreakdown(moneyRequestReport); const isOnHold = TransactionUtils.isOnHold(transaction); const isDeletedParentAction = !!requestParentReportAction && ReportActionsUtils.isDeletedAction(requestParentReportAction); diff --git a/src/components/MoneyRequestHeader.tsx b/src/components/MoneyRequestHeader.tsx index cd54c64a652f..802c468248f6 100644 --- a/src/components/MoneyRequestHeader.tsx +++ b/src/components/MoneyRequestHeader.tsx @@ -4,9 +4,9 @@ import {View} from 'react-native'; import {useOnyx} from 'react-native-onyx'; import type {OnyxEntry} from 'react-native-onyx'; import useLocalize from '@hooks/useLocalize'; +import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; -import useWindowDimensions from '@hooks/useWindowDimensions'; import Navigation from '@libs/Navigation/Navigation'; import * as ReportActionsUtils from '@libs/ReportActionsUtils'; import * as TransactionUtils from '@libs/TransactionUtils'; @@ -59,7 +59,7 @@ function MoneyRequestHeader({report, parentReportAction, policy, shouldUseNarrow const [shouldShowHoldMenu, setShouldShowHoldMenu] = useState(false); const isOnHold = TransactionUtils.isOnHold(transaction); const isDuplicate = TransactionUtils.isDuplicate(transaction?.transactionID ?? ''); - const {isSmallScreenWidth} = useWindowDimensions(); + const {isSmallScreenWidth} = useResponsiveLayout(); const hasAllPendingRTERViolations = TransactionUtils.allHavePendingRTERViolation([transaction?.transactionID ?? '-1']); diff --git a/src/components/Popover/index.native.tsx b/src/components/Popover/index.native.tsx index 08ed15fd0d30..694036bdfd31 100644 --- a/src/components/Popover/index.native.tsx +++ b/src/components/Popover/index.native.tsx @@ -1,7 +1,7 @@ import React from 'react'; import Modal from '@components/Modal'; import CONST from '@src/CONST'; -import type {PopoverProps} from './types'; +import type PopoverProps from './types'; /* * This is a convenience wrapper around the Modal component for a responsive Popover. diff --git a/src/components/Popover/index.tsx b/src/components/Popover/index.tsx index ebf30d773f09..d0de20611476 100644 --- a/src/components/Popover/index.tsx +++ b/src/components/Popover/index.tsx @@ -6,7 +6,7 @@ import PopoverWithoutOverlay from '@components/PopoverWithoutOverlay'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; import TooltipRefManager from '@libs/TooltipRefManager'; import CONST from '@src/CONST'; -import type {PopoverProps} from './types'; +import type PopoverProps from './types'; /* * This is a convenience wrapper around the Modal component for a responsive Popover. diff --git a/src/components/Popover/types.ts b/src/components/Popover/types.ts index 1db09d0b2f9f..aa5f0f63aad2 100644 --- a/src/components/Popover/types.ts +++ b/src/components/Popover/types.ts @@ -3,7 +3,6 @@ import type {RefObject} from 'react'; import type {Text, View} from 'react-native'; import type {PopoverAnchorPosition} from '@components/Modal/types'; import type BaseModalProps from '@components/Modal/types'; -import type {WindowDimensionsProps} from '@components/withWindowDimensions/types'; import type AnchorAlignment from '@src/types/utils/AnchorAlignment'; import type ChildrenProps from '@src/types/utils/ChildrenProps'; @@ -42,6 +41,4 @@ type PopoverProps = BaseModalProps & shouldCloseWhenBrowserNavigationChanged?: boolean; }; -type PopoverWithWindowDimensionsProps = PopoverProps & WindowDimensionsProps; - -export type {PopoverProps, PopoverWithWindowDimensionsProps}; +export default PopoverProps; diff --git a/src/components/PopoverWithMeasuredContent.tsx b/src/components/PopoverWithMeasuredContent.tsx index 32cc589bf0fb..8ad654588c5a 100644 --- a/src/components/PopoverWithMeasuredContent.tsx +++ b/src/components/PopoverWithMeasuredContent.tsx @@ -9,10 +9,9 @@ import PopoverWithMeasuredContentUtils from '@libs/PopoverWithMeasuredContentUti import CONST from '@src/CONST'; import type {AnchorDimensions, AnchorPosition} from '@src/styles'; import Popover from './Popover'; -import type {PopoverProps} from './Popover/types'; -import type {WindowDimensionsProps} from './withWindowDimensions/types'; +import type PopoverProps from './Popover/types'; -type PopoverWithMeasuredContentProps = Omit & { +type PopoverWithMeasuredContentProps = Omit & { /** The horizontal and vertical anchors points for the popover */ anchorPosition: AnchorPosition; diff --git a/src/components/Search/index.tsx b/src/components/Search/index.tsx index af952613f48f..7a6ba0596dec 100644 --- a/src/components/Search/index.tsx +++ b/src/components/Search/index.tsx @@ -11,8 +11,8 @@ import SelectionListWithModal from '@components/SelectionListWithModal'; import SearchRowSkeleton from '@components/Skeletons/SearchRowSkeleton'; import useLocalize from '@hooks/useLocalize'; import useNetwork from '@hooks/useNetwork'; +import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useThemeStyles from '@hooks/useThemeStyles'; -import useWindowDimensions from '@hooks/useWindowDimensions'; import {turnOffMobileSelectionMode, turnOnMobileSelectionMode} from '@libs/actions/MobileSelectionMode'; import * as SearchActions from '@libs/actions/Search'; import * as DeviceCapabilities from '@libs/DeviceCapabilities'; @@ -75,7 +75,7 @@ function Search({queryJSON, policyIDs, isCustomQuery}: SearchProps) { const {isOffline} = useNetwork(); const {translate} = useLocalize(); const styles = useThemeStyles(); - const {isLargeScreenWidth, isSmallScreenWidth} = useWindowDimensions(); + const {isSmallScreenWidth, isLargeScreenWidth} = useResponsiveLayout(); const navigation = useNavigation>(); const lastSearchResultsRef = useRef>(); const {setCurrentSearchHash, setSelectedTransactions, selectedTransactions, clearSelectedTransactions} = useSearchContext(); diff --git a/src/components/SelectionList/Search/ReportListItem.tsx b/src/components/SelectionList/Search/ReportListItem.tsx index 0be972b8b7ca..2795c0d71e97 100644 --- a/src/components/SelectionList/Search/ReportListItem.tsx +++ b/src/components/SelectionList/Search/ReportListItem.tsx @@ -5,9 +5,9 @@ import BaseListItem from '@components/SelectionList/BaseListItem'; import type {ListItem, ReportListItemProps, ReportListItemType, TransactionListItemType} from '@components/SelectionList/types'; import Text from '@components/Text'; import TextWithTooltip from '@components/TextWithTooltip'; +import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useStyleUtils from '@hooks/useStyleUtils'; import useThemeStyles from '@hooks/useThemeStyles'; -import useWindowDimensions from '@hooks/useWindowDimensions'; import * as CurrencyUtils from '@libs/CurrencyUtils'; import Navigation from '@libs/Navigation/Navigation'; import CONST from '@src/CONST'; @@ -63,7 +63,7 @@ function ReportListItem({ const reportItem = item as unknown as ReportListItemType; const styles = useThemeStyles(); - const {isLargeScreenWidth} = useWindowDimensions(); + const {isLargeScreenWidth} = useResponsiveLayout(); const StyleUtils = useStyleUtils(); if (reportItem.transactions.length === 0) { diff --git a/src/components/SelectionList/Search/TransactionListItem.tsx b/src/components/SelectionList/Search/TransactionListItem.tsx index a10552ca9ad8..5043d6f8f562 100644 --- a/src/components/SelectionList/Search/TransactionListItem.tsx +++ b/src/components/SelectionList/Search/TransactionListItem.tsx @@ -1,8 +1,8 @@ import React from 'react'; import BaseListItem from '@components/SelectionList/BaseListItem'; import type {ListItem, TransactionListItemProps, TransactionListItemType} from '@components/SelectionList/types'; +import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useThemeStyles from '@hooks/useThemeStyles'; -import useWindowDimensions from '@hooks/useWindowDimensions'; import TransactionListItemRow from './TransactionListItemRow'; function TransactionListItem({ @@ -21,7 +21,7 @@ function TransactionListItem({ const transactionItem = item as unknown as TransactionListItemType; const styles = useThemeStyles(); - const {isLargeScreenWidth} = useWindowDimensions(); + const {isLargeScreenWidth} = useResponsiveLayout(); const listItemPressableStyle = [styles.selectionListPressableItemWrapper, styles.pv3, styles.ph3, item.isSelected && styles.activeComponentBG, isFocused && styles.sidebarLinkActive]; diff --git a/src/components/SelectionList/Search/TransactionListItemRow.tsx b/src/components/SelectionList/Search/TransactionListItemRow.tsx index 4f83814374ba..e3eea1bab9dd 100644 --- a/src/components/SelectionList/Search/TransactionListItemRow.tsx +++ b/src/components/SelectionList/Search/TransactionListItemRow.tsx @@ -9,10 +9,10 @@ import ReceiptImage from '@components/ReceiptImage'; import type {TransactionListItemType} from '@components/SelectionList/types'; import TextWithTooltip from '@components/TextWithTooltip'; import useLocalize from '@hooks/useLocalize'; +import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useStyleUtils from '@hooks/useStyleUtils'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; -import useWindowDimensions from '@hooks/useWindowDimensions'; import * as CurrencyUtils from '@libs/CurrencyUtils'; import DateUtils from '@libs/DateUtils'; import StringUtils from '@libs/StringUtils'; @@ -247,7 +247,7 @@ function TransactionListItemRow({ shouldShowTransactionCheckbox, }: TransactionListItemRowProps) { const styles = useThemeStyles(); - const {isLargeScreenWidth} = useWindowDimensions(); + const {isLargeScreenWidth} = useResponsiveLayout(); const StyleUtils = useStyleUtils(); const theme = useTheme(); diff --git a/src/components/SelectionList/Search/UserInfoCell.tsx b/src/components/SelectionList/Search/UserInfoCell.tsx index 2a5a7da51979..2fcf8dafca0b 100644 --- a/src/components/SelectionList/Search/UserInfoCell.tsx +++ b/src/components/SelectionList/Search/UserInfoCell.tsx @@ -2,8 +2,8 @@ import React from 'react'; import {View} from 'react-native'; import Avatar from '@components/Avatar'; import Text from '@components/Text'; +import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useThemeStyles from '@hooks/useThemeStyles'; -import useWindowDimensions from '@hooks/useWindowDimensions'; import CONST from '@src/CONST'; import type {SearchAccountDetails} from '@src/types/onyx/SearchResults'; @@ -14,7 +14,7 @@ type UserInfoCellProps = { function UserInfoCell({participant, displayName}: UserInfoCellProps) { const styles = useThemeStyles(); - const {isLargeScreenWidth} = useWindowDimensions(); + const {isLargeScreenWidth} = useResponsiveLayout(); const avatarURL = participant?.avatarURL ?? participant?.avatar; const isWorkspace = participant?.avatarURL !== undefined; const iconType = isWorkspace ? CONST.ICON_TYPE_WORKSPACE : CONST.ICON_TYPE_AVATAR; diff --git a/src/components/SelectionList/SearchTableHeader.tsx b/src/components/SelectionList/SearchTableHeader.tsx index a260ee6bd0f0..a1aaad3c616c 100644 --- a/src/components/SelectionList/SearchTableHeader.tsx +++ b/src/components/SelectionList/SearchTableHeader.tsx @@ -2,9 +2,9 @@ import React from 'react'; import {View} from 'react-native'; import type {SearchColumnType, SortOrder} from '@components/Search/types'; import useLocalize from '@hooks/useLocalize'; +import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useStyleUtils from '@hooks/useStyleUtils'; import useThemeStyles from '@hooks/useThemeStyles'; -import useWindowDimensions from '@hooks/useWindowDimensions'; import * as SearchUtils from '@libs/SearchUtils'; import CONST from '@src/CONST'; import type {TranslationPaths} from '@src/languages/types'; @@ -97,7 +97,7 @@ type SearchTableHeaderProps = { function SearchTableHeader({data, metadata, sortBy, sortOrder, onSortPress, shouldShowYear}: SearchTableHeaderProps) { const styles = useThemeStyles(); const StyleUtils = useStyleUtils(); - const {isSmallScreenWidth, isMediumScreenWidth} = useWindowDimensions(); + const {isSmallScreenWidth, isMediumScreenWidth} = useResponsiveLayout(); const {translate} = useLocalize(); const displayNarrowVersion = isMediumScreenWidth || isSmallScreenWidth; diff --git a/src/components/Skeletons/CardRowSkeleton.tsx b/src/components/Skeletons/CardRowSkeleton.tsx index 82c382048415..983910e9ddb1 100644 --- a/src/components/Skeletons/CardRowSkeleton.tsx +++ b/src/components/Skeletons/CardRowSkeleton.tsx @@ -1,5 +1,6 @@ import React from 'react'; import {Circle, Rect} from 'react-native-svg'; +import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useThemeStyles from '@hooks/useThemeStyles'; import useWindowDimensions from '@hooks/useWindowDimensions'; import variables from '@styles/variables'; @@ -22,7 +23,8 @@ const rightButtonWidth = 20; function CardRowSkeleton({shouldAnimate = true, fixedNumItems, gradientOpacityEnabled = false}: CardRowSkeletonProps) { const styles = useThemeStyles(); - const {windowWidth, isSmallScreenWidth} = useWindowDimensions(); + const {windowWidth} = useWindowDimensions(); + const {shouldUseNarrowLayout} = useResponsiveLayout(); return ( - {!isSmallScreenWidth && ( + {!shouldUseNarrowLayout && ( <> (null); +type ResponsiveLayoutProperties = WindowDimensions & Partial; + function FullScreenContextProvider({children}: ChildrenProps) { const isFullScreenRef = useRef(false); - const lockedWindowDimensionsRef = useRef(null); + const lockedResponsiveLayoutResultRef = useRef(null); - const lockWindowDimensions = useCallback((newWindowDimensions: WindowDimensions) => { - lockedWindowDimensionsRef.current = newWindowDimensions; + const lockResponsiveLayoutResult = useCallback((newResponsiveLayoutResult: ResponsiveLayoutProperties) => { + lockedResponsiveLayoutResultRef.current = newResponsiveLayoutResult; }, []); - const unlockWindowDimensions = useCallback(() => { - lockedWindowDimensionsRef.current = null; + const unlockResponsiveLayoutResult = useCallback(() => { + lockedResponsiveLayoutResultRef.current = null; }, []); - const contextValue = useMemo(() => ({isFullScreenRef, lockedWindowDimensionsRef, lockWindowDimensions, unlockWindowDimensions}), [lockWindowDimensions, unlockWindowDimensions]); + const contextValue = useMemo( + () => ({isFullScreenRef, lockedResponsiveLayoutResultRef, lockResponsiveLayoutResult, unlockResponsiveLayoutResult}), + [lockResponsiveLayoutResult, unlockResponsiveLayoutResult], + ); return {children}; } @@ -32,3 +38,4 @@ function useFullScreenContext() { FullScreenContextProvider.displayName = 'FullScreenContextProvider'; export {Context as FullScreenContext, FullScreenContextProvider, useFullScreenContext}; +export type {ResponsiveLayoutProperties}; diff --git a/src/components/VideoPlayerContexts/types.ts b/src/components/VideoPlayerContexts/types.ts index 5778c321bd3b..4479aaff4a4a 100644 --- a/src/components/VideoPlayerContexts/types.ts +++ b/src/components/VideoPlayerContexts/types.ts @@ -4,8 +4,8 @@ import type {SharedValue} from 'react-native-reanimated'; import type {TupleToUnion} from 'type-fest'; import type {PopoverMenuItem} from '@components/PopoverMenu'; import type {VideoWithOnFullScreenUpdate} from '@components/VideoPlayer/types'; -import type WindowDimensions from '@hooks/useWindowDimensions/types'; import type CONST from '@src/CONST'; +import type {ResponsiveLayoutProperties} from './FullScreenContext'; type PlaybackContext = { updateCurrentlyPlayingURL: (url: string | null) => void; @@ -37,9 +37,9 @@ type VideoPopoverMenuContext = { type FullScreenContext = { isFullScreenRef: MutableRefObject; - lockedWindowDimensionsRef: MutableRefObject; - lockWindowDimensions: (newWindowDimensions: WindowDimensions) => void; - unlockWindowDimensions: () => void; + lockedResponsiveLayoutResultRef: MutableRefObject; + lockResponsiveLayoutResult: (newResponsiveLayoutResult: ResponsiveLayoutProperties) => void; + unlockResponsiveLayoutResult: () => void; }; type StatusCallback = (isPlaying: boolean) => void; diff --git a/src/components/withWindowDimensions/index.native.tsx b/src/components/withWindowDimensions/index.native.tsx deleted file mode 100644 index 1cfffeb63d43..000000000000 --- a/src/components/withWindowDimensions/index.native.tsx +++ /dev/null @@ -1,81 +0,0 @@ -import type {ComponentType, ForwardedRef, RefAttributes} from 'react'; -import React, {createContext, useEffect, useMemo, useState} from 'react'; -import {Dimensions} from 'react-native'; -import useSafeAreaInsets from '@hooks/useSafeAreaInsets'; -import getComponentDisplayName from '@libs/getComponentDisplayName'; -import getWindowHeightAdjustment from '@libs/getWindowHeightAdjustment'; -import variables from '@styles/variables'; -import type ChildrenProps from '@src/types/utils/ChildrenProps'; -import type {NewDimensions, WindowDimensionsContextData, WindowDimensionsProps} from './types'; - -const WindowDimensionsContext = createContext(null); - -function WindowDimensionsProvider(props: ChildrenProps) { - const [windowDimension, setWindowDimension] = useState(() => { - const initialDimensions = Dimensions.get('window'); - return { - windowHeight: initialDimensions.height, - windowWidth: initialDimensions.width, - }; - }); - - useEffect(() => { - const onDimensionChange = (newDimensions: NewDimensions) => { - const {window} = newDimensions; - setWindowDimension({ - windowHeight: window.height, - windowWidth: window.width, - }); - }; - - const dimensionsEventListener = Dimensions.addEventListener('change', onDimensionChange); - - return () => { - if (!dimensionsEventListener) { - return; - } - dimensionsEventListener.remove(); - }; - }, []); - const insets = useSafeAreaInsets(); - const adjustment = getWindowHeightAdjustment(insets); - const contextValue = useMemo(() => { - const isExtraSmallScreenWidth = windowDimension.windowWidth <= variables.extraSmallMobileResponsiveWidthBreakpoint; - return { - windowHeight: windowDimension.windowHeight + adjustment, - windowWidth: windowDimension.windowWidth, - isExtraSmallScreenWidth, - isSmallScreenWidth: true, - isMediumScreenWidth: false, - isLargeScreenWidth: false, - }; - }, [windowDimension.windowHeight, windowDimension.windowWidth, adjustment]); - return {props.children}; -} - -WindowDimensionsProvider.displayName = 'WindowDimensionsProvider'; - -export default function withWindowDimensions( - WrappedComponent: ComponentType>, -): (props: Omit & React.RefAttributes) => React.ReactElement | null { - function WithWindowDimensions(props: Omit, ref: ForwardedRef) { - return ( - - {(windowDimensionsProps) => ( - - )} - - ); - } - - WithWindowDimensions.displayName = `withWindowDimensions(${getComponentDisplayName(WrappedComponent)})`; - return React.forwardRef(WithWindowDimensions); -} - -export {WindowDimensionsProvider}; diff --git a/src/components/withWindowDimensions/index.tsx b/src/components/withWindowDimensions/index.tsx deleted file mode 100644 index cb175fe11e74..000000000000 --- a/src/components/withWindowDimensions/index.tsx +++ /dev/null @@ -1,87 +0,0 @@ -import lodashDebounce from 'lodash/debounce'; -import type {ComponentType, ForwardedRef, RefAttributes} from 'react'; -import React, {createContext, useEffect, useMemo, useState} from 'react'; -import {Dimensions} from 'react-native'; -import useSafeAreaInsets from '@hooks/useSafeAreaInsets'; -import getComponentDisplayName from '@libs/getComponentDisplayName'; -import getWindowHeightAdjustment from '@libs/getWindowHeightAdjustment'; -import variables from '@styles/variables'; -import type ChildrenProps from '@src/types/utils/ChildrenProps'; -import type {NewDimensions, WindowDimensionsContextData, WindowDimensionsProps} from './types'; - -const WindowDimensionsContext = createContext(null); - -function WindowDimensionsProvider(props: ChildrenProps) { - const [windowDimension, setWindowDimension] = useState(() => { - const initialDimensions = Dimensions.get('window'); - return { - windowHeight: initialDimensions.height, - windowWidth: initialDimensions.width, - }; - }); - - useEffect(() => { - const onDimensionChange = (newDimensions: NewDimensions) => { - const {window} = newDimensions; - setWindowDimension({ - windowHeight: window.height, - windowWidth: window.width, - }); - }; - - const onDimensionChangeDebounce = lodashDebounce(onDimensionChange, 300); - - const dimensionsEventListener = Dimensions.addEventListener('change', onDimensionChangeDebounce); - - return () => { - if (!dimensionsEventListener) { - return; - } - dimensionsEventListener.remove(); - }; - }, []); - const insets = useSafeAreaInsets(); - const adjustment = getWindowHeightAdjustment(insets); - const contextValue = useMemo(() => { - const isExtraSmallScreenWidth = windowDimension.windowWidth <= variables.extraSmallMobileResponsiveWidthBreakpoint; - const isSmallScreenWidth = windowDimension.windowWidth <= variables.mobileResponsiveWidthBreakpoint; - const isMediumScreenWidth = !isSmallScreenWidth && windowDimension.windowWidth <= variables.tabletResponsiveWidthBreakpoint; - const isLargeScreenWidth = !isSmallScreenWidth && !isMediumScreenWidth; - return { - windowHeight: windowDimension.windowHeight + adjustment, - windowWidth: windowDimension.windowWidth, - isExtraSmallScreenWidth, - isSmallScreenWidth, - isMediumScreenWidth, - isLargeScreenWidth, - }; - }, [windowDimension.windowHeight, windowDimension.windowWidth, adjustment]); - return {props.children}; -} - -WindowDimensionsProvider.displayName = 'WindowDimensionsProvider'; - -export default function withWindowDimensions( - WrappedComponent: ComponentType>, -): (props: Omit & React.RefAttributes) => React.ReactElement | null { - function WithWindowDimensions(props: Omit, ref: ForwardedRef) { - return ( - - {(windowDimensionsProps) => ( - - )} - - ); - } - - WithWindowDimensions.displayName = `withWindowDimensions(${getComponentDisplayName(WrappedComponent)})`; - return React.forwardRef(WithWindowDimensions); -} - -export {WindowDimensionsProvider}; diff --git a/src/components/withWindowDimensions/types.ts b/src/components/withWindowDimensions/types.ts deleted file mode 100644 index da06bb6a886e..000000000000 --- a/src/components/withWindowDimensions/types.ts +++ /dev/null @@ -1,34 +0,0 @@ -import type {ScaledSize} from 'react-native'; - -type WindowDimensionsContextData = { - windowHeight: number; - windowWidth: number; - isExtraSmallScreenWidth: boolean; - isSmallScreenWidth: boolean; - isMediumScreenWidth: boolean; - isLargeScreenWidth: boolean; -}; - -type WindowDimensionsProps = WindowDimensionsContextData & { - // Width of the window - windowWidth: number; - - // Height of the window - windowHeight: number; - - // Is the window width extra narrow, like on a Fold mobile device? - isExtraSmallScreenWidth: boolean; - - // Is the window width narrow, like on a mobile device? - isSmallScreenWidth: boolean; - - // Is the window width medium sized, like on a tablet device? - isMediumScreenWidth: boolean; - - // Is the window width wide, like on a browser or desktop? - isLargeScreenWidth: boolean; -}; - -type NewDimensions = {window: ScaledSize}; - -export type {WindowDimensionsContextData, WindowDimensionsProps, NewDimensions}; diff --git a/src/hooks/useOnboardingLayout.ts b/src/hooks/useOnboardingLayout.ts deleted file mode 100644 index 1b66c2fb2b64..000000000000 --- a/src/hooks/useOnboardingLayout.ts +++ /dev/null @@ -1,19 +0,0 @@ -// eslint-disable-next-line no-restricted-imports -import {useWindowDimensions} from 'react-native'; -import variables from '@styles/variables'; - -type OnboardingLayout = { - isMediumOrLargerScreenWidth: boolean; -}; - -/** - * The main difference between useOnboardingLayout and useWindowDimension is that - * useWindowDimension hardcodes isSmallScreenWidth, isMediumScreenWidth and - * isLargeScreenWidth on native platforms, while this hook below always takes - * screen width into consideration, no matter the platform. - */ -export default function useOnboardingLayout(): OnboardingLayout { - const {width: windowWidth} = useWindowDimensions(); - - return {isMediumOrLargerScreenWidth: windowWidth > variables.mobileResponsiveWidthBreakpoint}; -} diff --git a/src/hooks/useResponsiveLayout.ts b/src/hooks/useResponsiveLayout/index.ts similarity index 72% rename from src/hooks/useResponsiveLayout.ts rename to src/hooks/useResponsiveLayout/index.ts index a26d50bc56b9..3268ad1d7c02 100644 --- a/src/hooks/useResponsiveLayout.ts +++ b/src/hooks/useResponsiveLayout/index.ts @@ -1,20 +1,12 @@ import {NavigationContainerRefContext, NavigationContext} from '@react-navigation/native'; import {useContext, useMemo} from 'react'; +import {Dimensions} from 'react-native'; import ModalContext from '@components/Modal/ModalContext'; +import useWindowDimensions from '@hooks/useWindowDimensions'; +import variables from '@styles/variables'; import CONST from '@src/CONST'; import NAVIGATORS from '@src/NAVIGATORS'; -import useWindowDimensions from './useWindowDimensions'; - -type ResponsiveLayoutResult = { - shouldUseNarrowLayout: boolean; - isSmallScreenWidth: boolean; - isInNarrowPaneModal: boolean; - isExtraSmallScreenHeight: boolean; - isMediumScreenWidth: boolean; - isLargeScreenWidth: boolean; - isExtraSmallScreenWidth: boolean; - isSmallScreen: boolean; -}; +import type ResponsiveLayoutResult from './types'; /** * Hook to determine if we are on mobile devices or in the Modal Navigator. @@ -32,7 +24,19 @@ type ResponsiveLayoutResult = { * For more details on the various modal types we've defined for this app and implemented using react-native-modal, see `ModalType`. */ export default function useResponsiveLayout(): ResponsiveLayoutResult { - const {isSmallScreenWidth, isExtraSmallScreenHeight, isExtraSmallScreenWidth, isMediumScreenWidth, isLargeScreenWidth, isSmallScreen} = useWindowDimensions(); + const {windowWidth, windowHeight} = useWindowDimensions(); + + // When the soft keyboard opens on mWeb, the window height changes. Use static screen height instead to get real screenHeight. + const screenHeight = Dimensions.get('screen').height; + const isExtraSmallScreenHeight = screenHeight <= variables.extraSmallMobileResponsiveHeightBreakpoint; + const isSmallScreenWidth = windowWidth <= variables.mobileResponsiveWidthBreakpoint; + const isMediumScreenWidth = windowWidth > variables.mobileResponsiveWidthBreakpoint && windowWidth <= variables.tabletResponsiveWidthBreakpoint; + const isMediumOrLargerScreenWidth = windowWidth > variables.mobileResponsiveWidthBreakpoint; + const isLargeScreenWidth = windowWidth > variables.tabletResponsiveWidthBreakpoint; + const isExtraSmallScreenWidth = windowWidth <= variables.extraSmallMobileResponsiveWidthBreakpoint; + + const lowerScreenDimmension = Math.min(windowWidth, windowHeight); + const isSmallScreen = lowerScreenDimmension <= variables.mobileResponsiveWidthBreakpoint; // Note: activeModalType refers to our react-native-modal component wrapper, not react-navigation's modal stack navigators. // This means it will only be defined if the component calling this hook is a child of a modal component. See BaseModal for the provider. @@ -70,7 +74,10 @@ export default function useResponsiveLayout(): ResponsiveLayoutResult { isExtraSmallScreenHeight, isExtraSmallScreenWidth, isMediumScreenWidth, + isMediumOrLargerScreenWidth, isLargeScreenWidth, isSmallScreen, }; } + +export type {ResponsiveLayoutResult}; diff --git a/src/hooks/useResponsiveLayout/types.ts b/src/hooks/useResponsiveLayout/types.ts new file mode 100644 index 000000000000..e3507e12cdb1 --- /dev/null +++ b/src/hooks/useResponsiveLayout/types.ts @@ -0,0 +1,12 @@ +type ResponsiveLayoutResult = { + shouldUseNarrowLayout: boolean; + isSmallScreenWidth: boolean; + isInNarrowPaneModal: boolean; + isExtraSmallScreenHeight: boolean; + isMediumScreenWidth: boolean; + isLargeScreenWidth: boolean; + isExtraSmallScreenWidth: boolean; + isSmallScreen: boolean; + isMediumOrLargerScreenWidth: boolean; +}; +export default ResponsiveLayoutResult; diff --git a/src/hooks/useThumbnailDimensions.ts b/src/hooks/useThumbnailDimensions.ts index 85c5703861b4..ed23cf78df33 100644 --- a/src/hooks/useThumbnailDimensions.ts +++ b/src/hooks/useThumbnailDimensions.ts @@ -3,7 +3,6 @@ import type {StyleProp, ViewStyle} from 'react-native'; import type {DimensionValue} from 'react-native/Libraries/StyleSheet/StyleSheetTypes'; import CONST from '@src/CONST'; import useResponsiveLayout from './useResponsiveLayout'; -import useWindowDimensions from './useWindowDimensions'; type ThumbnailDimensions = { thumbnailDimensionsStyles: { @@ -14,9 +13,7 @@ type ThumbnailDimensions = { }; export default function useThumbnailDimensions(width: number, height: number): ThumbnailDimensions { - const {isInNarrowPaneModal} = useResponsiveLayout(); - const {isSmallScreenWidth} = useWindowDimensions(); - const shouldUseNarrowLayout = isSmallScreenWidth || isInNarrowPaneModal; + const {shouldUseNarrowLayout} = useResponsiveLayout(); const fixedDimension = shouldUseNarrowLayout ? CONST.THUMBNAIL_IMAGE.SMALL_SCREEN.SIZE : CONST.THUMBNAIL_IMAGE.WIDE_SCREEN.SIZE; const thumbnailDimensionsStyles = useMemo(() => { if (!width || !height) { diff --git a/src/hooks/useWindowDimensions/index.native.ts b/src/hooks/useWindowDimensions/index.native.ts deleted file mode 100644 index 8b420412cf24..000000000000 --- a/src/hooks/useWindowDimensions/index.native.ts +++ /dev/null @@ -1,28 +0,0 @@ -// eslint-disable-next-line no-restricted-imports -import {useWindowDimensions} from 'react-native'; -import variables from '@styles/variables'; -import type WindowDimensions from './types'; - -/** - * A convenience wrapper around React Native's useWindowDimensions hook that also provides booleans for our breakpoints. - */ -export default function (): WindowDimensions { - const {width: windowWidth, height: windowHeight} = useWindowDimensions(); - const isExtraSmallScreenHeight = windowHeight <= variables.extraSmallMobileResponsiveHeightBreakpoint; - const isSmallScreenWidth = true; - const isMediumScreenWidth = false; - const isLargeScreenWidth = false; - const isExtraSmallScreenWidth = windowWidth <= variables.extraSmallMobileResponsiveWidthBreakpoint; - const isSmallScreen = true; - - return { - windowWidth, - windowHeight, - isExtraSmallScreenHeight, - isSmallScreenWidth, - isMediumScreenWidth, - isLargeScreenWidth, - isExtraSmallScreenWidth, - isSmallScreen, - }; -} diff --git a/src/hooks/useWindowDimensions/index.ts b/src/hooks/useWindowDimensions/index.ts index b391e45a61aa..43ee8159d78d 100644 --- a/src/hooks/useWindowDimensions/index.ts +++ b/src/hooks/useWindowDimensions/index.ts @@ -1,6 +1,7 @@ import {useContext, useEffect, useRef} from 'react'; // eslint-disable-next-line no-restricted-imports import {Dimensions, useWindowDimensions} from 'react-native'; +import type {ResponsiveLayoutProperties} from '@components/VideoPlayerContexts/FullScreenContext'; import {FullScreenContext} from '@components/VideoPlayerContexts/FullScreenContext'; import useDebouncedState from '@hooks/useDebouncedState'; import * as Browser from '@libs/Browser'; @@ -16,17 +17,18 @@ const isMobile = Browser.isMobile(); * A convenience wrapper around React Native's useWindowDimensions hook that also provides booleans for our breakpoints. */ export default function (useCachedViewportHeight = false): WindowDimensions { - const {isFullScreenRef, lockedWindowDimensionsRef, lockWindowDimensions, unlockWindowDimensions} = useContext(FullScreenContext) ?? { + const {isFullScreenRef, lockedResponsiveLayoutResultRef, lockResponsiveLayoutResult, unlockResponsiveLayoutResult} = useContext(FullScreenContext) ?? { isFullScreenRef: useRef(false), - lockedWindowDimensionsRef: useRef(null), - lockWindowDimensions: () => {}, - unlockWindowDimensions: () => {}, + lockedResponsiveLayoutResultRef: useRef(null), + lockResponsiveLayoutResult: () => {}, + unlockResponsiveLayoutResult: () => {}, }; const isCachedViewportHeight = useCachedViewportHeight && Browser.isMobileWebKit(); const cachedViewportHeightWithKeyboardRef = useRef(initalViewportHeight); const {width: windowWidth, height: windowHeight} = useWindowDimensions(); + // These are the same as the ones in useResponsiveLayout, but we need to redefine them here toto avoid cyclic dependency. // When the soft keyboard opens on mWeb, the window height changes. Use static screen height instead to get real screenHeight. const screenHeight = Dimensions.get('screen').height; const isExtraSmallScreenHeight = screenHeight <= variables.extraSmallMobileResponsiveHeightBreakpoint; @@ -34,7 +36,6 @@ export default function (useCachedViewportHeight = false): WindowDimensions { const isMediumScreenWidth = windowWidth > variables.mobileResponsiveWidthBreakpoint && windowWidth <= variables.tabletResponsiveWidthBreakpoint; const isLargeScreenWidth = windowWidth > variables.tabletResponsiveWidthBreakpoint; const isExtraSmallScreenWidth = windowWidth <= variables.extraSmallMobileResponsiveWidthBreakpoint; - const lowerScreenDimmension = Math.min(windowWidth, windowHeight); const isSmallScreen = lowerScreenDimmension <= variables.mobileResponsiveWidthBreakpoint; @@ -94,42 +95,46 @@ export default function (useCachedViewportHeight = false): WindowDimensions { const windowDimensions = { windowWidth, windowHeight: isCachedViewportHeight ? cachedViewportHeight : windowHeight, - isExtraSmallScreenHeight, + }; + + const ResponsiveLayoutProperties = { + ...windowDimensions, isSmallScreenWidth, + isExtraSmallScreenHeight, + isExtraSmallScreenWidth, isMediumScreenWidth, isLargeScreenWidth, - isExtraSmallScreenWidth, isSmallScreen, }; - if (!lockedWindowDimensionsRef.current && !isFullScreenRef.current) { + if (!lockedResponsiveLayoutResultRef.current && !isFullScreenRef.current) { return windowDimensions; } const didScreenChangeOrientation = isMobile && - lockedWindowDimensionsRef.current && - isExtraSmallScreenWidth === lockedWindowDimensionsRef.current.isExtraSmallScreenWidth && - isSmallScreenWidth === lockedWindowDimensionsRef.current.isSmallScreen && - isMediumScreenWidth === lockedWindowDimensionsRef.current.isMediumScreenWidth && - isLargeScreenWidth === lockedWindowDimensionsRef.current.isLargeScreenWidth && - lockedWindowDimensionsRef.current.windowWidth !== windowWidth && - lockedWindowDimensionsRef.current.windowHeight !== windowHeight; + lockedResponsiveLayoutResultRef.current && + isExtraSmallScreenWidth === lockedResponsiveLayoutResultRef.current.isExtraSmallScreenWidth && + isSmallScreenWidth === lockedResponsiveLayoutResultRef.current.isSmallScreen && + isMediumScreenWidth === lockedResponsiveLayoutResultRef.current.isMediumScreenWidth && + isLargeScreenWidth === lockedResponsiveLayoutResultRef.current.isLargeScreenWidth && + lockedResponsiveLayoutResultRef.current.windowWidth !== windowWidth && + lockedResponsiveLayoutResultRef.current.windowHeight !== windowHeight; // if video is in fullscreen mode, lock the window dimensions since they can change and casue whole app to re-render - if (!lockedWindowDimensionsRef.current || didScreenChangeOrientation) { - lockWindowDimensions(windowDimensions); + if (!lockedResponsiveLayoutResultRef.current || didScreenChangeOrientation) { + lockResponsiveLayoutResult(ResponsiveLayoutProperties); return windowDimensions; } - const didScreenReturnToOriginalSize = lockedWindowDimensionsRef.current.windowWidth === windowWidth && lockedWindowDimensionsRef.current.windowHeight === windowHeight; + const didScreenReturnToOriginalSize = lockedResponsiveLayoutResultRef.current.windowWidth === windowWidth && lockedResponsiveLayoutResultRef.current.windowHeight === windowHeight; // if video exits fullscreen mode, unlock the window dimensions - if (lockedWindowDimensionsRef.current && !isFullScreenRef.current && didScreenReturnToOriginalSize) { - const lastLockedWindowDimensions = {...lockedWindowDimensionsRef.current}; - unlockWindowDimensions(); - return lastLockedWindowDimensions; + if (lockedResponsiveLayoutResultRef.current && !isFullScreenRef.current && didScreenReturnToOriginalSize) { + const lastlockedResponsiveLayoutResult = {...lockedResponsiveLayoutResultRef.current}; + unlockResponsiveLayoutResult(); + return lastlockedResponsiveLayoutResult; } - return lockedWindowDimensionsRef.current; + return lockedResponsiveLayoutResultRef.current; } diff --git a/src/hooks/useWindowDimensions/types.ts b/src/hooks/useWindowDimensions/types.ts index fa74e03f185c..4aa19a6943f9 100644 --- a/src/hooks/useWindowDimensions/types.ts +++ b/src/hooks/useWindowDimensions/types.ts @@ -1,12 +1,6 @@ type WindowDimensions = { windowWidth: number; windowHeight: number; - isExtraSmallScreenHeight: boolean; - isSmallScreenWidth: boolean; - isMediumScreenWidth: boolean; - isLargeScreenWidth: boolean; - isExtraSmallScreenWidth: boolean; - isSmallScreen: boolean; }; export default WindowDimensions; diff --git a/src/libs/Navigation/AppNavigator/AuthScreens.tsx b/src/libs/Navigation/AppNavigator/AuthScreens.tsx index e3ba198f0e30..5b546420868b 100644 --- a/src/libs/Navigation/AppNavigator/AuthScreens.tsx +++ b/src/libs/Navigation/AppNavigator/AuthScreens.tsx @@ -5,11 +5,10 @@ import Onyx, {withOnyx} from 'react-native-onyx'; import type {ValueOf} from 'type-fest'; import OptionsListContextProvider from '@components/OptionListContextProvider'; import useActiveWorkspace from '@hooks/useActiveWorkspace'; -import useOnboardingLayout from '@hooks/useOnboardingLayout'; import usePermissions from '@hooks/usePermissions'; +import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useStyleUtils from '@hooks/useStyleUtils'; import useThemeStyles from '@hooks/useThemeStyles'; -import useWindowDimensions from '@hooks/useWindowDimensions'; import {READ_COMMANDS} from '@libs/API/types'; import HttpUtils from '@libs/HttpUtils'; import KeyboardShortcut from '@libs/KeyboardShortcut'; @@ -202,15 +201,14 @@ const modalScreenListenersWithCancelSearch = { function AuthScreens({session, lastOpenedPublicRoomID, initialLastUpdateIDAppliedToClient}: AuthScreensProps) { const styles = useThemeStyles(); const StyleUtils = useStyleUtils(); - const {isSmallScreenWidth} = useWindowDimensions(); - const {isMediumOrLargerScreenWidth} = useOnboardingLayout(); - const screenOptions = getRootNavigatorScreenOptions(isSmallScreenWidth, styles, StyleUtils); + const {shouldUseNarrowLayout, isMediumOrLargerScreenWidth, isSmallScreenWidth} = useResponsiveLayout(); + const screenOptions = getRootNavigatorScreenOptions(shouldUseNarrowLayout, styles, StyleUtils); const {canUseDefaultRooms} = usePermissions(); const {activeWorkspaceID} = useActiveWorkspace(); const onboardingModalScreenOptions = useMemo(() => screenOptions.onboardingModalNavigator(isMediumOrLargerScreenWidth), [screenOptions, isMediumOrLargerScreenWidth]); const onboardingScreenOptions = useMemo( - () => getOnboardingModalScreenOptions(isSmallScreenWidth, styles, StyleUtils, isMediumOrLargerScreenWidth), - [StyleUtils, isSmallScreenWidth, isMediumOrLargerScreenWidth, styles], + () => getOnboardingModalScreenOptions(shouldUseNarrowLayout, styles, StyleUtils, isMediumOrLargerScreenWidth), + [StyleUtils, shouldUseNarrowLayout, isMediumOrLargerScreenWidth, styles], ); let initialReportID: string | undefined; @@ -350,7 +348,7 @@ function AuthScreens({session, lastOpenedPublicRoomID, initialLastUpdateIDApplie return ( - + StackNavigationOptions) { const styles = useThemeStyles(); const styleUtils = useStyleUtils(); - const {isSmallScreenWidth} = useWindowDimensions(); + const {isSmallScreenWidth} = useResponsiveLayout(); let cardStyleInterpolator = CardStyleInterpolators.forHorizontalIOS; diff --git a/src/libs/Navigation/AppNavigator/Navigators/FullScreenNavigator.tsx b/src/libs/Navigation/AppNavigator/Navigators/FullScreenNavigator.tsx index 748d92b49a1c..42587eae9bc6 100644 --- a/src/libs/Navigation/AppNavigator/Navigators/FullScreenNavigator.tsx +++ b/src/libs/Navigation/AppNavigator/Navigators/FullScreenNavigator.tsx @@ -1,9 +1,9 @@ import React from 'react'; import {View} from 'react-native'; import FocusTrapForScreens from '@components/FocusTrap/FocusTrapForScreen'; +import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useStyleUtils from '@hooks/useStyleUtils'; import useThemeStyles from '@hooks/useThemeStyles'; -import useWindowDimensions from '@hooks/useWindowDimensions'; import createCustomFullScreenNavigator from '@libs/Navigation/AppNavigator/createCustomFullScreenNavigator'; import getRootNavigatorScreenOptions from '@libs/Navigation/AppNavigator/getRootNavigatorScreenOptions'; import type {FullScreenNavigatorParamList} from '@libs/Navigation/types'; @@ -38,7 +38,7 @@ const CENTRAL_PANE_WORKSPACE_SCREENS = { function FullScreenNavigator() { const styles = useThemeStyles(); const StyleUtils = useStyleUtils(); - const {isSmallScreenWidth} = useWindowDimensions(); + const {isSmallScreenWidth} = useResponsiveLayout(); const screenOptions = getRootNavigatorScreenOptions(isSmallScreenWidth, styles, StyleUtils); return ( diff --git a/src/libs/Navigation/AppNavigator/Navigators/LeftModalNavigator.tsx b/src/libs/Navigation/AppNavigator/Navigators/LeftModalNavigator.tsx index 2aebe9f111f5..15efc28425a1 100644 --- a/src/libs/Navigation/AppNavigator/Navigators/LeftModalNavigator.tsx +++ b/src/libs/Navigation/AppNavigator/Navigators/LeftModalNavigator.tsx @@ -3,8 +3,8 @@ import {createStackNavigator} from '@react-navigation/stack'; import React, {useMemo} from 'react'; import {View} from 'react-native'; import NoDropZone from '@components/DragAndDrop/NoDropZone'; +import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useThemeStyles from '@hooks/useThemeStyles'; -import useWindowDimensions from '@hooks/useWindowDimensions'; import ModalNavigatorScreenOptions from '@libs/Navigation/AppNavigator/ModalNavigatorScreenOptions'; import type {AuthScreensParamList, LeftModalNavigatorParamList} from '@libs/Navigation/types'; import NAVIGATORS from '@src/NAVIGATORS'; @@ -21,7 +21,7 @@ const Stack = createStackNavigator(); function LeftModalNavigator({navigation}: LeftModalNavigatorProps) { const styles = useThemeStyles(); - const {isSmallScreenWidth} = useWindowDimensions(); + const {isSmallScreenWidth} = useResponsiveLayout(); const screenOptions = useMemo(() => ModalNavigatorScreenOptions(styles, 'horizontal-inverted'), [styles]); return ( diff --git a/src/libs/Navigation/AppNavigator/Navigators/OnboardingModalNavigator.tsx b/src/libs/Navigation/AppNavigator/Navigators/OnboardingModalNavigator.tsx index 64f827f3ddba..081ad02b8f43 100644 --- a/src/libs/Navigation/AppNavigator/Navigators/OnboardingModalNavigator.tsx +++ b/src/libs/Navigation/AppNavigator/Navigators/OnboardingModalNavigator.tsx @@ -6,7 +6,7 @@ import NoDropZone from '@components/DragAndDrop/NoDropZone'; import FocusTrapForScreens from '@components/FocusTrap/FocusTrapForScreen'; import useDisableModalDismissOnEscape from '@hooks/useDisableModalDismissOnEscape'; import useKeyboardShortcut from '@hooks/useKeyboardShortcut'; -import useOnboardingLayout from '@hooks/useOnboardingLayout'; +import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useThemeStyles from '@hooks/useThemeStyles'; import hasCompletedGuidedSetupFlowSelector from '@libs/hasCompletedGuidedSetupFlowSelector'; import OnboardingModalNavigatorScreenOptions from '@libs/Navigation/AppNavigator/OnboardingModalNavigatorScreenOptions'; @@ -26,7 +26,7 @@ const Stack = createStackNavigator(); function OnboardingModalNavigator() { const styles = useThemeStyles(); - const {isMediumOrLargerScreenWidth} = useOnboardingLayout(); + const {isMediumOrLargerScreenWidth} = useResponsiveLayout(); const [hasCompletedGuidedSetupFlow] = useOnyx(ONYXKEYS.NVP_ONBOARDING, { selector: hasCompletedGuidedSetupFlowSelector, }); diff --git a/src/libs/Navigation/AppNavigator/Navigators/RightModalNavigator.tsx b/src/libs/Navigation/AppNavigator/Navigators/RightModalNavigator.tsx index 44355cbbe955..0d9e66454e5c 100644 --- a/src/libs/Navigation/AppNavigator/Navigators/RightModalNavigator.tsx +++ b/src/libs/Navigation/AppNavigator/Navigators/RightModalNavigator.tsx @@ -3,9 +3,9 @@ import {createStackNavigator} from '@react-navigation/stack'; import React, {useMemo, useRef} from 'react'; import {View} from 'react-native'; import NoDropZone from '@components/DragAndDrop/NoDropZone'; +import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useStyleUtils from '@hooks/useStyleUtils'; import useThemeStyles from '@hooks/useThemeStyles'; -import useWindowDimensions from '@hooks/useWindowDimensions'; import {abandonReviewDuplicateTransactions} from '@libs/actions/Transaction'; import {isSafari} from '@libs/Browser'; import ModalNavigatorScreenOptions from '@libs/Navigation/AppNavigator/ModalNavigatorScreenOptions'; @@ -23,7 +23,7 @@ const Stack = createStackNavigator(); function RightModalNavigator({navigation, route}: RightModalNavigatorProps) { const styles = useThemeStyles(); const styleUtils = useStyleUtils(); - const {isSmallScreenWidth} = useWindowDimensions(); + const {isSmallScreenWidth} = useResponsiveLayout(); const isExecutingRef = useRef(false); const screenOptions = useMemo(() => { const options = ModalNavigatorScreenOptions(styles); diff --git a/src/libs/Navigation/AppNavigator/createCustomFullScreenNavigator/index.tsx b/src/libs/Navigation/AppNavigator/createCustomFullScreenNavigator/index.tsx index 7b928e4cf4df..33a08ba01e71 100644 --- a/src/libs/Navigation/AppNavigator/createCustomFullScreenNavigator/index.tsx +++ b/src/libs/Navigation/AppNavigator/createCustomFullScreenNavigator/index.tsx @@ -3,7 +3,7 @@ import {createNavigatorFactory, useNavigationBuilder} from '@react-navigation/na import type {StackNavigationEventMap, StackNavigationOptions} from '@react-navigation/stack'; import {StackView} from '@react-navigation/stack'; import React, {useEffect} from 'react'; -import useWindowDimensions from '@hooks/useWindowDimensions'; +import useResponsiveLayout from '@hooks/useResponsiveLayout'; import navigationRef from '@libs/Navigation/navigationRef'; import CustomFullScreenRouter from './CustomFullScreenRouter'; import type {FullScreenNavigatorProps, FullScreenNavigatorRouterOptions} from './types'; @@ -21,7 +21,7 @@ function CustomFullScreenNavigator(props: FullScreenNavigatorProps) { initialRouteName: props.initialRouteName, }); - const {isSmallScreenWidth} = useWindowDimensions(); + const {isSmallScreenWidth} = useResponsiveLayout(); useEffect(() => { if (!navigationRef.isReady()) { diff --git a/src/libs/Navigation/AppNavigator/createCustomStackNavigator/index.tsx b/src/libs/Navigation/AppNavigator/createCustomStackNavigator/index.tsx index 310766f80e9d..cf1ced179b6b 100644 --- a/src/libs/Navigation/AppNavigator/createCustomStackNavigator/index.tsx +++ b/src/libs/Navigation/AppNavigator/createCustomStackNavigator/index.tsx @@ -4,8 +4,8 @@ import type {StackNavigationEventMap, StackNavigationOptions} from '@react-navig import {StackView} from '@react-navigation/stack'; import React, {useEffect, useMemo} from 'react'; import {View} from 'react-native'; +import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useThemeStyles from '@hooks/useThemeStyles'; -import useWindowDimensions from '@hooks/useWindowDimensions'; import getTopmostCentralPaneRoute from '@libs/Navigation/getTopmostCentralPaneRoute'; import navigationRef from '@libs/Navigation/navigationRef'; import type {RootStackParamList, State} from '@libs/Navigation/types'; @@ -36,7 +36,7 @@ function reduceCentralPaneRoutes(routes: Routes): Routes { } function ResponsiveStackNavigator(props: ResponsiveStackNavigatorProps) { - const {isSmallScreenWidth} = useWindowDimensions(); + const {isSmallScreenWidth} = useResponsiveLayout(); const styles = useThemeStyles(); const {navigation, state, descriptors, NavigationContent} = useNavigationBuilder< diff --git a/src/libs/Navigation/NavigationRoot.tsx b/src/libs/Navigation/NavigationRoot.tsx index 96e3413927a5..c1f60a6000e4 100644 --- a/src/libs/Navigation/NavigationRoot.tsx +++ b/src/libs/Navigation/NavigationRoot.tsx @@ -6,8 +6,8 @@ import HybridAppMiddleware from '@components/HybridAppMiddleware'; import {ScrollOffsetContext} from '@components/ScrollOffsetContextProvider'; import useActiveWorkspace from '@hooks/useActiveWorkspace'; import useCurrentReportID from '@hooks/useCurrentReportID'; +import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useTheme from '@hooks/useTheme'; -import useWindowDimensions from '@hooks/useWindowDimensions'; import Firebase from '@libs/Firebase'; import {FSPage} from '@libs/Fullstory'; import hasCompletedGuidedSetupFlowSelector from '@libs/hasCompletedGuidedSetupFlowSelector'; @@ -79,7 +79,7 @@ function NavigationRoot({authenticated, lastVisitedPath, initialUrl, onReady}: N const {cleanStaleScrollOffsets} = useContext(ScrollOffsetContext); const currentReportIDValue = useCurrentReportID(); - const {isSmallScreenWidth} = useWindowDimensions(); + const {isSmallScreenWidth} = useResponsiveLayout(); const {setActiveWorkspaceID} = useActiveWorkspace(); const [user] = useOnyx(ONYXKEYS.USER); diff --git a/src/pages/FlagCommentPage.tsx b/src/pages/FlagCommentPage.tsx index 022d590f289a..c54edae479d1 100644 --- a/src/pages/FlagCommentPage.tsx +++ b/src/pages/FlagCommentPage.tsx @@ -31,7 +31,7 @@ type FlagCommentPageWithOnyxProps = { type FlagCommentPageNavigationProps = StackScreenProps; -type FlagCommentPageProps = FlagCommentPageNavigationProps & WithReportAndReportActionOrNotFoundProps & FlagCommentPageWithOnyxProps; +type FlagCommentPageProps = WithReportAndReportActionOrNotFoundProps & FlagCommentPageNavigationProps & FlagCommentPageWithOnyxProps; type Severity = ValueOf; diff --git a/src/pages/OnboardingPersonalDetails/BaseOnboardingPersonalDetails.tsx b/src/pages/OnboardingPersonalDetails/BaseOnboardingPersonalDetails.tsx index 4e3ebd6d0578..d136895a260c 100644 --- a/src/pages/OnboardingPersonalDetails/BaseOnboardingPersonalDetails.tsx +++ b/src/pages/OnboardingPersonalDetails/BaseOnboardingPersonalDetails.tsx @@ -13,9 +13,8 @@ import TextInput from '@components/TextInput'; import withCurrentUserPersonalDetails from '@components/withCurrentUserPersonalDetails'; import useAutoFocusInput from '@hooks/useAutoFocusInput'; import useLocalize from '@hooks/useLocalize'; -import useOnboardingLayout from '@hooks/useOnboardingLayout'; +import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useThemeStyles from '@hooks/useThemeStyles'; -import useWindowDimensions from '@hooks/useWindowDimensions'; import AccountUtils from '@libs/AccountUtils'; import * as ErrorUtils from '@libs/ErrorUtils'; import Navigation from '@libs/Navigation/Navigation'; @@ -40,8 +39,7 @@ function BaseOnboardingPersonalDetails({ }: BaseOnboardingPersonalDetailsProps) { const styles = useThemeStyles(); const {translate} = useLocalize(); - const {isSmallScreenWidth} = useWindowDimensions(); - const {isMediumOrLargerScreenWidth} = useOnboardingLayout(); + const {shouldUseNarrowLayout, isMediumOrLargerScreenWidth} = useResponsiveLayout(); const {inputCallbackRef} = useAutoFocusInput(); const [shouldValidateOnChange, setShouldValidateOnChange] = useState(false); const {accountID} = useSession(); @@ -79,7 +77,7 @@ function BaseOnboardingPersonalDetails({ // Only navigate to concierge chat when central pane is visible // Otherwise stay on the chats screen. - if (!isSmallScreenWidth && !route.params?.backTo) { + if (!shouldUseNarrowLayout && !route.params?.backTo) { if (AccountUtils.isAccountIDOddNumber(accountID ?? 0)) { Report.navigateToSystemChat(); } else { @@ -93,7 +91,7 @@ function BaseOnboardingPersonalDetails({ Navigation.navigate(ROUTES.WELCOME_VIDEO_ROOT); }, variables.welcomeVideoDelay); }, - [onboardingPurposeSelected, onboardingAdminsChatReportID, onboardingPolicyID, isSmallScreenWidth, route.params?.backTo, accountID], + [onboardingPurposeSelected, onboardingAdminsChatReportID, onboardingPolicyID, shouldUseNarrowLayout, route.params?.backTo, accountID], ); const validate = (values: FormOnyxValues<'onboardingPersonalDetailsForm'>) => { @@ -146,7 +144,7 @@ function BaseOnboardingPersonalDetails({ (undefined); const {windowHeight} = useWindowDimensions(); const {isSmallScreenWidth} = useResponsiveLayout(); diff --git a/src/pages/OnboardingWork/BaseOnboardingWork.tsx b/src/pages/OnboardingWork/BaseOnboardingWork.tsx index 5dc270cef2d9..9b331b77981d 100644 --- a/src/pages/OnboardingWork/BaseOnboardingWork.tsx +++ b/src/pages/OnboardingWork/BaseOnboardingWork.tsx @@ -10,7 +10,6 @@ import ScreenWrapper from '@components/ScreenWrapper'; import Text from '@components/Text'; import TextInput from '@components/TextInput'; import useLocalize from '@hooks/useLocalize'; -import useOnboardingLayout from '@hooks/useOnboardingLayout'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useThemeStyles from '@hooks/useThemeStyles'; import * as ErrorUtils from '@libs/ErrorUtils'; @@ -30,7 +29,7 @@ function BaseOnboardingWork({shouldUseNativeStyles, onboardingPurposeSelected, o const styles = useThemeStyles(); const {translate} = useLocalize(); const {shouldUseNarrowLayout} = useResponsiveLayout(); - const {isMediumOrLargerScreenWidth} = useOnboardingLayout(); + const {isMediumOrLargerScreenWidth} = useResponsiveLayout(); const completeEngagement = useCallback( (values: FormOnyxValues<'onboardingWorkForm'>) => { diff --git a/src/pages/home/report/withReportAndReportActionOrNotFound.tsx b/src/pages/home/report/withReportAndReportActionOrNotFound.tsx index a9ad8851dcf1..b8bb25d39c86 100644 --- a/src/pages/home/report/withReportAndReportActionOrNotFound.tsx +++ b/src/pages/home/report/withReportAndReportActionOrNotFound.tsx @@ -5,8 +5,7 @@ import React, {useCallback, useEffect} from 'react'; import type {OnyxCollection, OnyxEntry, WithOnyxState} from 'react-native-onyx'; import {withOnyx} from 'react-native-onyx'; import FullscreenLoadingIndicator from '@components/FullscreenLoadingIndicator'; -import withWindowDimensions from '@components/withWindowDimensions'; -import type {WindowDimensionsProps} from '@components/withWindowDimensions/types'; +import useResponsiveLayout from '@hooks/useResponsiveLayout'; import getComponentDisplayName from '@libs/getComponentDisplayName'; import type {FlagCommentNavigatorParamList, SplitDetailsNavigatorParamList} from '@libs/Navigation/types'; import * as ReportUtils from '@libs/ReportUtils'; @@ -44,12 +43,11 @@ type OnyxProps = { }; type WithReportAndReportActionOrNotFoundProps = OnyxProps & - WindowDimensionsProps & StackScreenProps; export default function ( WrappedComponent: ComponentType>, -): ComponentType> { +): ComponentType, keyof OnyxProps>> { function WithReportOrNotFound(props: TProps, ref: ForwardedRef) { const getReportAction = useCallback(() => { let reportAction: OnyxEntry = props.reportActions?.[`${props.route.params.reportActionID}`]; @@ -64,15 +62,17 @@ export default function { - if (!props.isSmallScreenWidth || (!isEmptyObject(props.report) && !isEmptyObject(reportAction))) { + if (!shouldUseNarrowLayout || (!isEmptyObject(props.report) && !isEmptyObject(reportAction))) { return; } Report.openReport(props.route.params.reportID); // eslint-disable-next-line react-compiler/react-compiler, react-hooks/exhaustive-deps - }, [props.isSmallScreenWidth, props.route.params.reportID]); + }, [shouldUseNarrowLayout, props.route.params.reportID]); // Perform all the loading checks const isLoadingReport = props.isLoadingReportData && !props.report?.reportID; @@ -102,43 +102,41 @@ export default function , OnyxProps>({ - report: { - key: ({route}) => `${ONYXKEYS.COLLECTION.REPORT}${route.params.reportID}`, - }, - parentReport: { - key: ({report}) => `${ONYXKEYS.COLLECTION.REPORT}${report ? report.parentReportID : '-1'}`, - }, - reportMetadata: { - key: ({route}) => `${ONYXKEYS.COLLECTION.REPORT_METADATA}${route.params.reportID}`, - }, - isLoadingReportData: { - key: ONYXKEYS.IS_LOADING_REPORT_DATA, - }, - betas: { - key: ONYXKEYS.BETAS, - }, - policies: { - key: ONYXKEYS.COLLECTION.POLICY, - }, - reportActions: { - key: ({route}) => `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${route.params.reportID}`, - canEvict: false, - }, - parentReportAction: { - key: ({report}) => `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${report ? report.parentReportID : 0}`, - selector: (parentReportActions: OnyxEntry, props?: WithOnyxState): NonNullable> | null => { - const parentReportActionID = props?.report?.parentReportActionID; - if (!parentReportActionID) { - return null; - } - return parentReportActions?.[parentReportActionID] ?? null; - }, - canEvict: false, + return withOnyx, OnyxProps>({ + report: { + key: ({route}) => `${ONYXKEYS.COLLECTION.REPORT}${route.params.reportID}`, + }, + parentReport: { + key: ({report}) => `${ONYXKEYS.COLLECTION.REPORT}${report ? report.parentReportID : '-1'}`, + }, + reportMetadata: { + key: ({route}) => `${ONYXKEYS.COLLECTION.REPORT_METADATA}${route.params.reportID}`, + }, + isLoadingReportData: { + key: ONYXKEYS.IS_LOADING_REPORT_DATA, + }, + betas: { + key: ONYXKEYS.BETAS, + }, + policies: { + key: ONYXKEYS.COLLECTION.POLICY, + }, + reportActions: { + key: ({route}) => `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${route.params.reportID}`, + canEvict: false, + }, + parentReportAction: { + key: ({report}) => `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${report ? report.parentReportID : 0}`, + selector: (parentReportActions: OnyxEntry, props?: WithOnyxState): NonNullable> | null => { + const parentReportActionID = props?.report?.parentReportActionID; + if (!parentReportActionID) { + return null; + } + return parentReportActions?.[parentReportActionID] ?? null; }, - })(React.forwardRef(WithReportOrNotFound)), - ); + canEvict: false, + }, + })(React.forwardRef(WithReportOrNotFound)); } export type {WithReportAndReportActionOrNotFoundProps}; diff --git a/src/pages/iou/SplitBillDetailsPage.tsx b/src/pages/iou/SplitBillDetailsPage.tsx index 24bac1a0dde8..e4e01ee682f4 100644 --- a/src/pages/iou/SplitBillDetailsPage.tsx +++ b/src/pages/iou/SplitBillDetailsPage.tsx @@ -1,4 +1,5 @@ import type {StackScreenProps} from '@react-navigation/stack'; +import type {ComponentType} from 'react'; import React, {useCallback, useMemo} from 'react'; import {View} from 'react-native'; import {withOnyx} from 'react-native-onyx'; @@ -176,7 +177,7 @@ const WrappedComponent = withOnyx); export default withOnyx, SplitBillDetailsPageOnyxPropsWithoutTransaction>({ report: { diff --git a/src/pages/workspace/expensifyCard/EmptyCardView.tsx b/src/pages/workspace/expensifyCard/EmptyCardView.tsx index a7d2b9949703..998d26610458 100644 --- a/src/pages/workspace/expensifyCard/EmptyCardView.tsx +++ b/src/pages/workspace/expensifyCard/EmptyCardView.tsx @@ -6,6 +6,7 @@ import ScrollView from '@components/ScrollView'; import CardRowSkeleton from '@components/Skeletons/CardRowSkeleton'; import Text from '@components/Text'; import useLocalize from '@hooks/useLocalize'; +import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useThemeStyles from '@hooks/useThemeStyles'; import useWindowDimensions from '@hooks/useWindowDimensions'; import colors from '@styles/theme/colors'; @@ -18,9 +19,10 @@ const BUTTON_MARGIN = 12; function EmptyCardView() { const {translate} = useLocalize(); const styles = useThemeStyles(); - const {windowHeight, isSmallScreenWidth} = useWindowDimensions(); + const {windowHeight} = useWindowDimensions(); + const {shouldUseNarrowLayout} = useResponsiveLayout(); - const headerHeight = isSmallScreenWidth ? HEADER_HEIGHT + BUTTON_HEIGHT + BUTTON_MARGIN : HEADER_HEIGHT; + const headerHeight = shouldUseNarrowLayout ? HEADER_HEIGHT + BUTTON_HEIGHT + BUTTON_MARGIN : HEADER_HEIGHT; return ( @@ -34,11 +36,11 @@ function EmptyCardView() { overflow: 'hidden', backgroundColor: colors.green700, }, - isSmallScreenWidth && {maxHeight: 250}, + shouldUseNarrowLayout && {maxHeight: 250}, ]} title={translate('workspace.expensifyCard.issueAndManageCards')} subtitle={translate('workspace.expensifyCard.getStartedIssuing')} - emptyStateForegroundStyles={isSmallScreenWidth && {justifyContent: 'flex-start'}} + emptyStateForegroundStyles={shouldUseNarrowLayout && {justifyContent: 'flex-start'}} /> {translate('workspace.expensifyCard.disclaimer')} diff --git a/tests/perf-test/ReportActionCompose.perf-test.tsx b/tests/perf-test/ReportActionCompose.perf-test.tsx index e3aaccd1f050..193782176b2f 100644 --- a/tests/perf-test/ReportActionCompose.perf-test.tsx +++ b/tests/perf-test/ReportActionCompose.perf-test.tsx @@ -11,7 +11,6 @@ import ComposeProviders from '@src/components/ComposeProviders'; import {LocaleContextProvider} from '@src/components/LocaleContextProvider'; import OnyxProvider from '@src/components/OnyxProvider'; import {KeyboardStateProvider} from '@src/components/withKeyboardState'; -import {WindowDimensionsProvider} from '@src/components/withWindowDimensions'; import * as Localize from '@src/libs/Localize'; import ONYXKEYS from '@src/ONYXKEYS'; import ReportActionCompose from '@src/pages/home/report/ReportActionCompose/ReportActionCompose'; @@ -84,7 +83,7 @@ beforeEach(() => { function ReportActionComposeWrapper() { return ( - + jest.fn()} reportID="1" diff --git a/tests/perf-test/ReportActionsList.perf-test.tsx b/tests/perf-test/ReportActionsList.perf-test.tsx index f0fef9a8e574..94a1050e98ce 100644 --- a/tests/perf-test/ReportActionsList.perf-test.tsx +++ b/tests/perf-test/ReportActionsList.perf-test.tsx @@ -7,7 +7,6 @@ import type Navigation from '@libs/Navigation/Navigation'; import ComposeProviders from '@src/components/ComposeProviders'; import {LocaleContextProvider} from '@src/components/LocaleContextProvider'; import OnyxProvider from '@src/components/OnyxProvider'; -import {WindowDimensionsProvider} from '@src/components/withWindowDimensions'; import * as Localize from '@src/libs/Localize'; import ONYXKEYS from '@src/ONYXKEYS'; import ReportActionsList from '@src/pages/home/report/ReportActionsList'; @@ -83,7 +82,7 @@ beforeEach(() => { function ReportActionsListWrapper() { return ( - + + Date: Sun, 4 Aug 2024 20:42:43 +0100 Subject: [PATCH 02/14] Refactor useWindowDimensions hook to return window dimensions only --- src/hooks/useWindowDimensions/index.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hooks/useWindowDimensions/index.ts b/src/hooks/useWindowDimensions/index.ts index 43ee8159d78d..1d078d5858f4 100644 --- a/src/hooks/useWindowDimensions/index.ts +++ b/src/hooks/useWindowDimensions/index.ts @@ -133,8 +133,8 @@ export default function (useCachedViewportHeight = false): WindowDimensions { if (lockedResponsiveLayoutResultRef.current && !isFullScreenRef.current && didScreenReturnToOriginalSize) { const lastlockedResponsiveLayoutResult = {...lockedResponsiveLayoutResultRef.current}; unlockResponsiveLayoutResult(); - return lastlockedResponsiveLayoutResult; + return {windowWidth: lastlockedResponsiveLayoutResult.windowWidth, windowHeight: lastlockedResponsiveLayoutResult.windowHeight}; } - return lockedResponsiveLayoutResultRef.current; + return {windowWidth: lockedResponsiveLayoutResultRef.current.windowWidth, windowHeight: lockedResponsiveLayoutResultRef.current.windowHeight}; } From 8d4c6c9da060a42f37d163e6ea6eac62b72d3e02 Mon Sep 17 00:00:00 2001 From: Rayane Djouah <77965000+rayane-djouah@users.noreply.github.com> Date: Tue, 6 Aug 2024 19:35:07 +0100 Subject: [PATCH 03/14] Remove unecessary type export --- src/hooks/useResponsiveLayout/index.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/hooks/useResponsiveLayout/index.ts b/src/hooks/useResponsiveLayout/index.ts index 3268ad1d7c02..2eb2c35d9952 100644 --- a/src/hooks/useResponsiveLayout/index.ts +++ b/src/hooks/useResponsiveLayout/index.ts @@ -79,5 +79,3 @@ export default function useResponsiveLayout(): ResponsiveLayoutResult { isSmallScreen, }; } - -export type {ResponsiveLayoutResult}; From 2c0875baa9914230bc916fa33ee487cc940041d8 Mon Sep 17 00:00:00 2001 From: Rayane Djouah <77965000+rayane-djouah@users.noreply.github.com> Date: Tue, 6 Aug 2024 19:35:20 +0100 Subject: [PATCH 04/14] Fix layout on iPad --- src/hooks/useResponsiveLayout/index.native.ts | 76 +++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 src/hooks/useResponsiveLayout/index.native.ts diff --git a/src/hooks/useResponsiveLayout/index.native.ts b/src/hooks/useResponsiveLayout/index.native.ts new file mode 100644 index 000000000000..e4f037fd9110 --- /dev/null +++ b/src/hooks/useResponsiveLayout/index.native.ts @@ -0,0 +1,76 @@ +import {NavigationContainerRefContext, NavigationContext} from '@react-navigation/native'; +import {useContext, useMemo} from 'react'; +import ModalContext from '@components/Modal/ModalContext'; +import useWindowDimensions from '@hooks/useWindowDimensions'; +import variables from '@styles/variables'; +import CONST from '@src/CONST'; +import NAVIGATORS from '@src/NAVIGATORS'; +import type ResponsiveLayoutResult from './types'; + +/** + * Hook to determine if we are on mobile devices or in the Modal Navigator. + * Use "shouldUseNarrowLayout" for "on mobile or in RHP/LHP", "isSmallScreenWidth" for "on mobile", "isInNarrowPaneModal" for "in RHP/LHP". + * + * There are two kinds of modals in this app: + * 1. Modal stack navigators from react-navigation + * 2. Modal components that use react-native-modal + * + * This hook is designed to handle both. `shouldUseNarrowLayout` will return `true` if any of the following are true: + * 1. The device screen width is narrow + * 2. The consuming component is the child of a "right docked" react-native-modal component + * 3. The consuming component is a screen in a modal stack navigator and not a child of a "non-right-docked" react-native-modal component. + * + * For more details on the various modal types we've defined for this app and implemented using react-native-modal, see `ModalType`. + */ +export default function useResponsiveLayout(): ResponsiveLayoutResult { + const {windowWidth, windowHeight} = useWindowDimensions(); + + const isExtraSmallScreenHeight = windowHeight <= variables.extraSmallMobileResponsiveHeightBreakpoint; + const isSmallScreenWidth = true; + const isMediumScreenWidth = false; + const isMediumOrLargerScreenWidth = false; + const isLargeScreenWidth = false; + const isExtraSmallScreenWidth = windowWidth <= variables.extraSmallMobileResponsiveWidthBreakpoint; + const isSmallScreen = true; + + // Note: activeModalType refers to our react-native-modal component wrapper, not react-navigation's modal stack navigators. + // This means it will only be defined if the component calling this hook is a child of a modal component. See BaseModal for the provider. + const {activeModalType} = useContext(ModalContext); + + // We are using these contexts directly instead of useNavigation/useNavigationState, because those will throw an error if used outside a navigator. + // This hook can be used within or outside a navigator, so using useNavigationState does not work. + // Furthermore, wrapping useNavigationState in a try/catch does not work either, because that breaks the rules of hooks. + // Note that these three lines are copied closely from the internal implementation of useNavigation: https://github.com/react-navigation/react-navigation/blob/52a3234b7aaf4d4fcc9c0155f44f3ea2233f0f40/packages/core/src/useNavigation.tsx#L18-L28 + const navigationContainerRef = useContext(NavigationContainerRefContext); + const navigator = useContext(NavigationContext); + const currentNavigator = navigator ?? navigationContainerRef; + + const isDisplayedInNarrowModalNavigator = useMemo( + () => + !!currentNavigator?.getParent?.(NAVIGATORS.RIGHT_MODAL_NAVIGATOR as unknown as undefined) || + !!currentNavigator?.getParent?.(NAVIGATORS.LEFT_MODAL_NAVIGATOR as unknown as undefined), + [currentNavigator], + ); + + // The component calling this hook is in a "narrow pane modal" if: + const isInNarrowPaneModal = + // it's a child of the right-docked modal + activeModalType === CONST.MODAL.MODAL_TYPE.RIGHT_DOCKED || + // or there's a "right modal navigator" or "left modal navigator" on the top of the root navigation stack + // and the component calling this hook is not the child of another modal type, such as a confirm modal + (isDisplayedInNarrowModalNavigator && !activeModalType); + + const shouldUseNarrowLayout = isSmallScreenWidth || isInNarrowPaneModal; + + return { + shouldUseNarrowLayout, + isSmallScreenWidth, + isInNarrowPaneModal, + isExtraSmallScreenHeight, + isExtraSmallScreenWidth, + isMediumScreenWidth, + isMediumOrLargerScreenWidth, + isLargeScreenWidth, + isSmallScreen, + }; +} From 8bf87ba455feb7210200001ac3c25617a5a65670 Mon Sep 17 00:00:00 2001 From: Rayane Djouah <77965000+rayane-djouah@users.noreply.github.com> Date: Tue, 6 Aug 2024 19:38:54 +0100 Subject: [PATCH 05/14] useWindowDimensions for native --- src/hooks/useWindowDimensions/index.native.ts | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 src/hooks/useWindowDimensions/index.native.ts diff --git a/src/hooks/useWindowDimensions/index.native.ts b/src/hooks/useWindowDimensions/index.native.ts new file mode 100644 index 000000000000..39ecb3902333 --- /dev/null +++ b/src/hooks/useWindowDimensions/index.native.ts @@ -0,0 +1,14 @@ +// eslint-disable-next-line no-restricted-imports +import {useWindowDimensions} from 'react-native'; +import type WindowDimensions from './types'; + +/** + * A convenience wrapper around React Native's useWindowDimensions hook that also provides booleans for our breakpoints. + */ +export default function (): WindowDimensions { + const {width: windowWidth, height: windowHeight} = useWindowDimensions(); + return { + windowWidth, + windowHeight, + }; +} From d7c75acd1d662abeffddd327290d9ba591740001 Mon Sep 17 00:00:00 2001 From: Rayane Djouah <77965000+rayane-djouah@users.noreply.github.com> Date: Tue, 6 Aug 2024 19:41:07 +0100 Subject: [PATCH 06/14] Update comments --- src/hooks/useResponsiveLayout/index.native.ts | 2 +- src/hooks/useResponsiveLayout/index.ts | 2 +- src/hooks/useWindowDimensions/index.native.ts | 2 +- src/hooks/useWindowDimensions/index.ts | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/hooks/useResponsiveLayout/index.native.ts b/src/hooks/useResponsiveLayout/index.native.ts index e4f037fd9110..4937b2cfeede 100644 --- a/src/hooks/useResponsiveLayout/index.native.ts +++ b/src/hooks/useResponsiveLayout/index.native.ts @@ -8,7 +8,7 @@ import NAVIGATORS from '@src/NAVIGATORS'; import type ResponsiveLayoutResult from './types'; /** - * Hook to determine if we are on mobile devices or in the Modal Navigator. + * Hook to determine if we are on mobile devices or in the Modal Navigator. It also provides booleans for our breakpoints * Use "shouldUseNarrowLayout" for "on mobile or in RHP/LHP", "isSmallScreenWidth" for "on mobile", "isInNarrowPaneModal" for "in RHP/LHP". * * There are two kinds of modals in this app: diff --git a/src/hooks/useResponsiveLayout/index.ts b/src/hooks/useResponsiveLayout/index.ts index 2eb2c35d9952..0ed4c894b3df 100644 --- a/src/hooks/useResponsiveLayout/index.ts +++ b/src/hooks/useResponsiveLayout/index.ts @@ -9,7 +9,7 @@ import NAVIGATORS from '@src/NAVIGATORS'; import type ResponsiveLayoutResult from './types'; /** - * Hook to determine if we are on mobile devices or in the Modal Navigator. + * Hook to determine if we are on mobile devices or in the Modal Navigator. It also provides booleans for our breakpoints * Use "shouldUseNarrowLayout" for "on mobile or in RHP/LHP", "isSmallScreenWidth" for "on mobile", "isInNarrowPaneModal" for "in RHP/LHP". * * There are two kinds of modals in this app: diff --git a/src/hooks/useWindowDimensions/index.native.ts b/src/hooks/useWindowDimensions/index.native.ts index 39ecb3902333..9adfffe5faca 100644 --- a/src/hooks/useWindowDimensions/index.native.ts +++ b/src/hooks/useWindowDimensions/index.native.ts @@ -3,7 +3,7 @@ import {useWindowDimensions} from 'react-native'; import type WindowDimensions from './types'; /** - * A convenience wrapper around React Native's useWindowDimensions hook that also provides booleans for our breakpoints. + * A wrapper around React Native's useWindowDimensions hook. */ export default function (): WindowDimensions { const {width: windowWidth, height: windowHeight} = useWindowDimensions(); diff --git a/src/hooks/useWindowDimensions/index.ts b/src/hooks/useWindowDimensions/index.ts index 1d078d5858f4..9031bb603e1a 100644 --- a/src/hooks/useWindowDimensions/index.ts +++ b/src/hooks/useWindowDimensions/index.ts @@ -14,7 +14,7 @@ const tagNamesOpenKeyboard = ['INPUT', 'TEXTAREA']; const isMobile = Browser.isMobile(); /** - * A convenience wrapper around React Native's useWindowDimensions hook that also provides booleans for our breakpoints. + * A wrapper around React Native's useWindowDimensions hook. */ export default function (useCachedViewportHeight = false): WindowDimensions { const {isFullScreenRef, lockedResponsiveLayoutResultRef, lockResponsiveLayoutResult, unlockResponsiveLayoutResult} = useContext(FullScreenContext) ?? { From 28ed41b8fd14b0700a0b9bb7b723bd44ce58ba50 Mon Sep 17 00:00:00 2001 From: Rayane Djouah <77965000+rayane-djouah@users.noreply.github.com> Date: Tue, 6 Aug 2024 20:14:58 +0100 Subject: [PATCH 07/14] Fix TS error --- src/components/ApprovalWorkflowSection.tsx | 6 +++--- src/components/VideoPlayerContexts/FullScreenContext.tsx | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/components/ApprovalWorkflowSection.tsx b/src/components/ApprovalWorkflowSection.tsx index 899e83c9440b..84bb8bfade35 100644 --- a/src/components/ApprovalWorkflowSection.tsx +++ b/src/components/ApprovalWorkflowSection.tsx @@ -1,9 +1,9 @@ import React, {useCallback} from 'react'; import {View} from 'react-native'; import useLocalize from '@hooks/useLocalize'; +import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; -import useWindowDimensions from '@hooks/useWindowDimensions'; import Navigation from '@libs/Navigation/Navigation'; import ROUTES from '@src/ROUTES'; import type ApprovalWorkflow from '@src/types/onyx/ApprovalWorkflow'; @@ -25,7 +25,7 @@ function ApprovalWorkflowSection({approvalWorkflow, policyId}: ApprovalWorkflowS const styles = useThemeStyles(); const theme = useTheme(); const {translate, toLocaleOrdinal} = useLocalize(); - const {isSmallScreenWidth} = useWindowDimensions(); + const {shouldUseNarrowLayout} = useResponsiveLayout(); const openApprovalsEdit = useCallback( () => Navigation.navigate(ROUTES.WORKSPACE_WORKFLOWS_APPROVALS_EDIT.getRoute(policyId ?? '', approvalWorkflow.approvers[0].email)), [approvalWorkflow.approvers, policyId], @@ -39,7 +39,7 @@ function ApprovalWorkflowSection({approvalWorkflow, policyId}: ApprovalWorkflowS return ( diff --git a/src/components/VideoPlayerContexts/FullScreenContext.tsx b/src/components/VideoPlayerContexts/FullScreenContext.tsx index 09e9ada481f2..31aa8cc0209c 100644 --- a/src/components/VideoPlayerContexts/FullScreenContext.tsx +++ b/src/components/VideoPlayerContexts/FullScreenContext.tsx @@ -1,5 +1,5 @@ import React, {useCallback, useContext, useMemo, useRef} from 'react'; -import type {ResponsiveLayoutResult} from '@hooks/useResponsiveLayout'; +import type ResponsiveLayoutResult from '@hooks/useResponsiveLayout/types'; import type WindowDimensions from '@hooks/useWindowDimensions/types'; import type ChildrenProps from '@src/types/utils/ChildrenProps'; import type {FullScreenContext} from './types'; From fe5ff2f5395516045431e16da66ca2d6788a18e0 Mon Sep 17 00:00:00 2001 From: Rayane Djouah <77965000+rayane-djouah@users.noreply.github.com> Date: Tue, 13 Aug 2024 02:38:06 +0100 Subject: [PATCH 08/14] Address PR review comments --- src/components/FeatureTrainingModal.tsx | 14 ++--- .../VideoPlayerContexts/FullScreenContext.tsx | 19 +++--- src/components/VideoPlayerContexts/types.ts | 6 +- src/hooks/useResponsiveLayout/index.native.ts | 6 +- src/hooks/useResponsiveLayout/index.ts | 4 +- src/hooks/useResponsiveLayout/types.ts | 2 +- src/hooks/useWindowDimensions/index.ts | 62 +++++++++---------- .../Navigation/AppNavigator/AuthScreens.tsx | 8 +-- .../Navigators/OnboardingModalNavigator.tsx | 4 +- .../BaseOnboardingPersonalDetails.tsx | 6 +- .../BaseOnboardingPurpose.tsx | 10 +-- .../OnboardingWork/BaseOnboardingWork.tsx | 6 +- 12 files changed, 74 insertions(+), 73 deletions(-) diff --git a/src/components/FeatureTrainingModal.tsx b/src/components/FeatureTrainingModal.tsx index 3cec2b6748b7..2204533f745d 100644 --- a/src/components/FeatureTrainingModal.tsx +++ b/src/components/FeatureTrainingModal.tsx @@ -88,7 +88,7 @@ function FeatureTrainingModal({ }: FeatureTrainingModalProps) { const styles = useThemeStyles(); const {translate} = useLocalize(); - const {isMediumOrLargerScreenWidth} = useResponsiveLayout(); + const {onboardingIsMediumOrLargerScreenWidth} = useResponsiveLayout(); const [isModalVisible, setIsModalVisible] = useState(true); const [willShowAgain, setWillShowAgain] = useState(true); const [videoStatus, setVideoStatus] = useState('video'); @@ -182,14 +182,14 @@ function FeatureTrainingModal({ {({safeAreaPaddingBottomStyle}) => ( - - {renderIllustration()} + + {renderIllustration()} {title && description && ( - + {title} {description} {secondaryDescription.length > 0 && {secondaryDescription}} diff --git a/src/components/VideoPlayerContexts/FullScreenContext.tsx b/src/components/VideoPlayerContexts/FullScreenContext.tsx index 31aa8cc0209c..7af71e02b955 100644 --- a/src/components/VideoPlayerContexts/FullScreenContext.tsx +++ b/src/components/VideoPlayerContexts/FullScreenContext.tsx @@ -6,24 +6,23 @@ import type {FullScreenContext} from './types'; const Context = React.createContext(null); -type ResponsiveLayoutProperties = WindowDimensions & Partial; +type ResponsiveLayoutProperties = WindowDimensions & { + responsiveLayoutResults: Partial; +}; function FullScreenContextProvider({children}: ChildrenProps) { const isFullScreenRef = useRef(false); - const lockedResponsiveLayoutResultRef = useRef(null); + const lockedWindowDimensionsRef = useRef(null); - const lockResponsiveLayoutResult = useCallback((newResponsiveLayoutResult: ResponsiveLayoutProperties) => { - lockedResponsiveLayoutResultRef.current = newResponsiveLayoutResult; + const lockWindowDimensions = useCallback((newResponsiveLayoutProperties: ResponsiveLayoutProperties) => { + lockedWindowDimensionsRef.current = newResponsiveLayoutProperties; }, []); - const unlockResponsiveLayoutResult = useCallback(() => { - lockedResponsiveLayoutResultRef.current = null; + const unlockWindowDimensions = useCallback(() => { + lockedWindowDimensionsRef.current = null; }, []); - const contextValue = useMemo( - () => ({isFullScreenRef, lockedResponsiveLayoutResultRef, lockResponsiveLayoutResult, unlockResponsiveLayoutResult}), - [lockResponsiveLayoutResult, unlockResponsiveLayoutResult], - ); + const contextValue = useMemo(() => ({isFullScreenRef, lockedWindowDimensionsRef, lockWindowDimensions, unlockWindowDimensions}), [lockWindowDimensions, unlockWindowDimensions]); return {children}; } diff --git a/src/components/VideoPlayerContexts/types.ts b/src/components/VideoPlayerContexts/types.ts index 4479aaff4a4a..bfccebb2df3f 100644 --- a/src/components/VideoPlayerContexts/types.ts +++ b/src/components/VideoPlayerContexts/types.ts @@ -37,9 +37,9 @@ type VideoPopoverMenuContext = { type FullScreenContext = { isFullScreenRef: MutableRefObject; - lockedResponsiveLayoutResultRef: MutableRefObject; - lockResponsiveLayoutResult: (newResponsiveLayoutResult: ResponsiveLayoutProperties) => void; - unlockResponsiveLayoutResult: () => void; + lockedWindowDimensionsRef: MutableRefObject; + lockWindowDimensions: (newResponsiveLayoutResult: ResponsiveLayoutProperties) => void; + unlockWindowDimensions: () => void; }; type StatusCallback = (isPlaying: boolean) => void; diff --git a/src/hooks/useResponsiveLayout/index.native.ts b/src/hooks/useResponsiveLayout/index.native.ts index 4937b2cfeede..10f8506caf4f 100644 --- a/src/hooks/useResponsiveLayout/index.native.ts +++ b/src/hooks/useResponsiveLayout/index.native.ts @@ -28,11 +28,13 @@ export default function useResponsiveLayout(): ResponsiveLayoutResult { const isExtraSmallScreenHeight = windowHeight <= variables.extraSmallMobileResponsiveHeightBreakpoint; const isSmallScreenWidth = true; const isMediumScreenWidth = false; - const isMediumOrLargerScreenWidth = false; const isLargeScreenWidth = false; const isExtraSmallScreenWidth = windowWidth <= variables.extraSmallMobileResponsiveWidthBreakpoint; const isSmallScreen = true; + // we need to always take screen width into consideration, no matter the platform. + const onboardingIsMediumOrLargerScreenWidth = windowWidth > variables.mobileResponsiveWidthBreakpoint; + // Note: activeModalType refers to our react-native-modal component wrapper, not react-navigation's modal stack navigators. // This means it will only be defined if the component calling this hook is a child of a modal component. See BaseModal for the provider. const {activeModalType} = useContext(ModalContext); @@ -69,7 +71,7 @@ export default function useResponsiveLayout(): ResponsiveLayoutResult { isExtraSmallScreenHeight, isExtraSmallScreenWidth, isMediumScreenWidth, - isMediumOrLargerScreenWidth, + onboardingIsMediumOrLargerScreenWidth, isLargeScreenWidth, isSmallScreen, }; diff --git a/src/hooks/useResponsiveLayout/index.ts b/src/hooks/useResponsiveLayout/index.ts index 0ed4c894b3df..3aa698e6d654 100644 --- a/src/hooks/useResponsiveLayout/index.ts +++ b/src/hooks/useResponsiveLayout/index.ts @@ -31,7 +31,7 @@ export default function useResponsiveLayout(): ResponsiveLayoutResult { const isExtraSmallScreenHeight = screenHeight <= variables.extraSmallMobileResponsiveHeightBreakpoint; const isSmallScreenWidth = windowWidth <= variables.mobileResponsiveWidthBreakpoint; const isMediumScreenWidth = windowWidth > variables.mobileResponsiveWidthBreakpoint && windowWidth <= variables.tabletResponsiveWidthBreakpoint; - const isMediumOrLargerScreenWidth = windowWidth > variables.mobileResponsiveWidthBreakpoint; + const onboardingIsMediumOrLargerScreenWidth = windowWidth > variables.mobileResponsiveWidthBreakpoint; const isLargeScreenWidth = windowWidth > variables.tabletResponsiveWidthBreakpoint; const isExtraSmallScreenWidth = windowWidth <= variables.extraSmallMobileResponsiveWidthBreakpoint; @@ -74,7 +74,7 @@ export default function useResponsiveLayout(): ResponsiveLayoutResult { isExtraSmallScreenHeight, isExtraSmallScreenWidth, isMediumScreenWidth, - isMediumOrLargerScreenWidth, + onboardingIsMediumOrLargerScreenWidth, isLargeScreenWidth, isSmallScreen, }; diff --git a/src/hooks/useResponsiveLayout/types.ts b/src/hooks/useResponsiveLayout/types.ts index e3507e12cdb1..c7bb021389f2 100644 --- a/src/hooks/useResponsiveLayout/types.ts +++ b/src/hooks/useResponsiveLayout/types.ts @@ -7,6 +7,6 @@ type ResponsiveLayoutResult = { isLargeScreenWidth: boolean; isExtraSmallScreenWidth: boolean; isSmallScreen: boolean; - isMediumOrLargerScreenWidth: boolean; + onboardingIsMediumOrLargerScreenWidth: boolean; }; export default ResponsiveLayoutResult; diff --git a/src/hooks/useWindowDimensions/index.ts b/src/hooks/useWindowDimensions/index.ts index 9031bb603e1a..ce487bf80e3c 100644 --- a/src/hooks/useWindowDimensions/index.ts +++ b/src/hooks/useWindowDimensions/index.ts @@ -17,18 +17,18 @@ const isMobile = Browser.isMobile(); * A wrapper around React Native's useWindowDimensions hook. */ export default function (useCachedViewportHeight = false): WindowDimensions { - const {isFullScreenRef, lockedResponsiveLayoutResultRef, lockResponsiveLayoutResult, unlockResponsiveLayoutResult} = useContext(FullScreenContext) ?? { + const {isFullScreenRef, lockedWindowDimensionsRef, lockWindowDimensions, unlockWindowDimensions} = useContext(FullScreenContext) ?? { isFullScreenRef: useRef(false), - lockedResponsiveLayoutResultRef: useRef(null), - lockResponsiveLayoutResult: () => {}, - unlockResponsiveLayoutResult: () => {}, + lockedWindowDimensionsRef: useRef(null), + lockWindowDimensions: () => {}, + unlockWindowDimensions: () => {}, }; const isCachedViewportHeight = useCachedViewportHeight && Browser.isMobileWebKit(); const cachedViewportHeightWithKeyboardRef = useRef(initalViewportHeight); const {width: windowWidth, height: windowHeight} = useWindowDimensions(); - // These are the same as the ones in useResponsiveLayout, but we need to redefine them here toto avoid cyclic dependency. + // These are the same as the ones in useResponsiveLayout, but we need to redefine them here to avoid cyclic dependency. // When the soft keyboard opens on mWeb, the window height changes. Use static screen height instead to get real screenHeight. const screenHeight = Dimensions.get('screen').height; const isExtraSmallScreenHeight = screenHeight <= variables.extraSmallMobileResponsiveHeightBreakpoint; @@ -39,6 +39,15 @@ export default function (useCachedViewportHeight = false): WindowDimensions { const lowerScreenDimmension = Math.min(windowWidth, windowHeight); const isSmallScreen = lowerScreenDimmension <= variables.mobileResponsiveWidthBreakpoint; + const responsiveLayoutResults = { + isSmallScreenWidth, + isExtraSmallScreenHeight, + isExtraSmallScreenWidth, + isMediumScreenWidth, + isLargeScreenWidth, + isSmallScreen, + }; + const [, cachedViewportHeight, setCachedViewportHeight] = useDebouncedState(windowHeight, CONST.TIMING.RESIZE_DEBOUNCE_TIME); const handleFocusIn = useRef((event: FocusEvent) => { @@ -95,46 +104,37 @@ export default function (useCachedViewportHeight = false): WindowDimensions { const windowDimensions = { windowWidth, windowHeight: isCachedViewportHeight ? cachedViewportHeight : windowHeight, + responsiveLayoutResults, }; - const ResponsiveLayoutProperties = { - ...windowDimensions, - isSmallScreenWidth, - isExtraSmallScreenHeight, - isExtraSmallScreenWidth, - isMediumScreenWidth, - isLargeScreenWidth, - isSmallScreen, - }; - - if (!lockedResponsiveLayoutResultRef.current && !isFullScreenRef.current) { + if (!lockedWindowDimensionsRef.current && !isFullScreenRef.current) { return windowDimensions; } const didScreenChangeOrientation = isMobile && - lockedResponsiveLayoutResultRef.current && - isExtraSmallScreenWidth === lockedResponsiveLayoutResultRef.current.isExtraSmallScreenWidth && - isSmallScreenWidth === lockedResponsiveLayoutResultRef.current.isSmallScreen && - isMediumScreenWidth === lockedResponsiveLayoutResultRef.current.isMediumScreenWidth && - isLargeScreenWidth === lockedResponsiveLayoutResultRef.current.isLargeScreenWidth && - lockedResponsiveLayoutResultRef.current.windowWidth !== windowWidth && - lockedResponsiveLayoutResultRef.current.windowHeight !== windowHeight; + lockedWindowDimensionsRef.current && + isExtraSmallScreenWidth === lockedWindowDimensionsRef.current.responsiveLayoutResults.isExtraSmallScreenHeight && + isSmallScreenWidth === lockedWindowDimensionsRef.current.responsiveLayoutResults.isSmallScreen && + isMediumScreenWidth === lockedWindowDimensionsRef.current.responsiveLayoutResults.isMediumScreenWidth && + isLargeScreenWidth === lockedWindowDimensionsRef.current.responsiveLayoutResults.isLargeScreenWidth && + lockedWindowDimensionsRef.current.windowWidth !== windowWidth && + lockedWindowDimensionsRef.current.windowHeight !== windowHeight; // if video is in fullscreen mode, lock the window dimensions since they can change and casue whole app to re-render - if (!lockedResponsiveLayoutResultRef.current || didScreenChangeOrientation) { - lockResponsiveLayoutResult(ResponsiveLayoutProperties); + if (!lockedWindowDimensionsRef.current || didScreenChangeOrientation) { + lockWindowDimensions(windowDimensions); return windowDimensions; } - const didScreenReturnToOriginalSize = lockedResponsiveLayoutResultRef.current.windowWidth === windowWidth && lockedResponsiveLayoutResultRef.current.windowHeight === windowHeight; + const didScreenReturnToOriginalSize = lockedWindowDimensionsRef.current.windowWidth === windowWidth && lockedWindowDimensionsRef.current.windowHeight === windowHeight; // if video exits fullscreen mode, unlock the window dimensions - if (lockedResponsiveLayoutResultRef.current && !isFullScreenRef.current && didScreenReturnToOriginalSize) { - const lastlockedResponsiveLayoutResult = {...lockedResponsiveLayoutResultRef.current}; - unlockResponsiveLayoutResult(); - return {windowWidth: lastlockedResponsiveLayoutResult.windowWidth, windowHeight: lastlockedResponsiveLayoutResult.windowHeight}; + if (lockedWindowDimensionsRef.current && !isFullScreenRef.current && didScreenReturnToOriginalSize) { + const lastlockedWindowDimensions = {...lockedWindowDimensionsRef.current}; + unlockWindowDimensions(); + return {windowWidth: lastlockedWindowDimensions.windowWidth, windowHeight: lastlockedWindowDimensions.windowHeight}; } - return {windowWidth: lockedResponsiveLayoutResultRef.current.windowWidth, windowHeight: lockedResponsiveLayoutResultRef.current.windowHeight}; + return {windowWidth: lockedWindowDimensionsRef.current.windowWidth, windowHeight: lockedWindowDimensionsRef.current.windowHeight}; } diff --git a/src/libs/Navigation/AppNavigator/AuthScreens.tsx b/src/libs/Navigation/AppNavigator/AuthScreens.tsx index 755ef2d9f497..5b01d7607827 100644 --- a/src/libs/Navigation/AppNavigator/AuthScreens.tsx +++ b/src/libs/Navigation/AppNavigator/AuthScreens.tsx @@ -201,14 +201,14 @@ const modalScreenListenersWithCancelSearch = { function AuthScreens({session, lastOpenedPublicRoomID, initialLastUpdateIDAppliedToClient}: AuthScreensProps) { const styles = useThemeStyles(); const StyleUtils = useStyleUtils(); - const {shouldUseNarrowLayout, isMediumOrLargerScreenWidth, isSmallScreenWidth} = useResponsiveLayout(); + const {shouldUseNarrowLayout, onboardingIsMediumOrLargerScreenWidth, isSmallScreenWidth} = useResponsiveLayout(); const screenOptions = getRootNavigatorScreenOptions(shouldUseNarrowLayout, styles, StyleUtils); const {canUseDefaultRooms} = usePermissions(); const {activeWorkspaceID} = useActiveWorkspace(); - const onboardingModalScreenOptions = useMemo(() => screenOptions.onboardingModalNavigator(isMediumOrLargerScreenWidth), [screenOptions, isMediumOrLargerScreenWidth]); + const onboardingModalScreenOptions = useMemo(() => screenOptions.onboardingModalNavigator(onboardingIsMediumOrLargerScreenWidth), [screenOptions, onboardingIsMediumOrLargerScreenWidth]); const onboardingScreenOptions = useMemo( - () => getOnboardingModalScreenOptions(shouldUseNarrowLayout, styles, StyleUtils, isMediumOrLargerScreenWidth), - [StyleUtils, shouldUseNarrowLayout, isMediumOrLargerScreenWidth, styles], + () => getOnboardingModalScreenOptions(shouldUseNarrowLayout, styles, StyleUtils, onboardingIsMediumOrLargerScreenWidth), + [StyleUtils, shouldUseNarrowLayout, onboardingIsMediumOrLargerScreenWidth, styles], ); let initialReportID: string | undefined; diff --git a/src/libs/Navigation/AppNavigator/Navigators/OnboardingModalNavigator.tsx b/src/libs/Navigation/AppNavigator/Navigators/OnboardingModalNavigator.tsx index 081ad02b8f43..3dcf031b85cc 100644 --- a/src/libs/Navigation/AppNavigator/Navigators/OnboardingModalNavigator.tsx +++ b/src/libs/Navigation/AppNavigator/Navigators/OnboardingModalNavigator.tsx @@ -26,7 +26,7 @@ const Stack = createStackNavigator(); function OnboardingModalNavigator() { const styles = useThemeStyles(); - const {isMediumOrLargerScreenWidth} = useResponsiveLayout(); + const {onboardingIsMediumOrLargerScreenWidth} = useResponsiveLayout(); const [hasCompletedGuidedSetupFlow] = useOnyx(ONYXKEYS.NVP_ONBOARDING, { selector: hasCompletedGuidedSetupFlowSelector, }); @@ -67,7 +67,7 @@ function OnboardingModalNavigator() { e.stopPropagation()} - style={styles.OnboardingNavigatorInnerView(isMediumOrLargerScreenWidth)} + style={styles.OnboardingNavigatorInnerView(onboardingIsMediumOrLargerScreenWidth)} > - + {translate('onboarding.whatsYourName')} diff --git a/src/pages/OnboardingPurpose/BaseOnboardingPurpose.tsx b/src/pages/OnboardingPurpose/BaseOnboardingPurpose.tsx index 2dbec3eb5827..aea005488839 100644 --- a/src/pages/OnboardingPurpose/BaseOnboardingPurpose.tsx +++ b/src/pages/OnboardingPurpose/BaseOnboardingPurpose.tsx @@ -41,7 +41,7 @@ const menuIcons = { function BaseOnboardingPurpose({shouldUseNativeStyles, shouldEnableMaxHeight, route}: BaseOnboardingPurposeProps) { const styles = useThemeStyles(); const {translate} = useLocalize(); - const {isMediumOrLargerScreenWidth} = useResponsiveLayout(); + const {onboardingIsMediumOrLargerScreenWidth} = useResponsiveLayout(); const [selectedPurpose, setSelectedPurpose] = useState(undefined); const {windowHeight} = useWindowDimensions(); const {isSmallScreenWidth} = useResponsiveLayout(); @@ -58,7 +58,7 @@ function BaseOnboardingPurpose({shouldUseNativeStyles, shouldEnableMaxHeight, ro const maxHeight = shouldEnableMaxHeight ? windowHeight : undefined; - const paddingHorizontal = isMediumOrLargerScreenWidth ? styles.ph8 : styles.ph5; + const paddingHorizontal = onboardingIsMediumOrLargerScreenWidth ? styles.ph8 : styles.ph5; const selectedCheckboxIcon = useMemo( () => ( @@ -127,16 +127,16 @@ function BaseOnboardingPurpose({shouldUseNativeStyles, shouldEnableMaxHeight, ro {({safeAreaPaddingBottomStyle}) => ( - + - + - + {translate('onboarding.purpose.title')} - + {translate('onboarding.whereYouWork')} From 6cef9bfdf53b64333db489b8cfe6cb4d02a4ab00 Mon Sep 17 00:00:00 2001 From: Rayane Djouah <77965000+rayane-djouah@users.noreply.github.com> Date: Tue, 13 Aug 2024 02:40:43 +0100 Subject: [PATCH 09/14] Fix naming --- src/hooks/useWindowDimensions/index.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hooks/useWindowDimensions/index.ts b/src/hooks/useWindowDimensions/index.ts index ce487bf80e3c..4997fc4b01a7 100644 --- a/src/hooks/useWindowDimensions/index.ts +++ b/src/hooks/useWindowDimensions/index.ts @@ -131,9 +131,9 @@ export default function (useCachedViewportHeight = false): WindowDimensions { // if video exits fullscreen mode, unlock the window dimensions if (lockedWindowDimensionsRef.current && !isFullScreenRef.current && didScreenReturnToOriginalSize) { - const lastlockedWindowDimensions = {...lockedWindowDimensionsRef.current}; + const lastLockedWindowDimensions = {...lockedWindowDimensionsRef.current}; unlockWindowDimensions(); - return {windowWidth: lastlockedWindowDimensions.windowWidth, windowHeight: lastlockedWindowDimensions.windowHeight}; + return {windowWidth: lastLockedWindowDimensions.windowWidth, windowHeight: lastLockedWindowDimensions.windowHeight}; } return {windowWidth: lockedWindowDimensionsRef.current.windowWidth, windowHeight: lockedWindowDimensionsRef.current.windowHeight}; From fe0625fdf96c69e5085971b13daa69c7afe02f46 Mon Sep 17 00:00:00 2001 From: Rayane Djouah <77965000+rayane-djouah@users.noreply.github.com> Date: Tue, 13 Aug 2024 02:55:40 +0100 Subject: [PATCH 10/14] Fix Lint and TS errors --- src/components/ConnectToNetSuiteButton/index.tsx | 2 +- src/components/ConnectToSageIntacctButton/index.tsx | 2 +- src/components/Search/index.tsx | 2 +- .../AppNavigator/Navigators/OnboardingModalNavigator.tsx | 3 +-- 4 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/components/ConnectToNetSuiteButton/index.tsx b/src/components/ConnectToNetSuiteButton/index.tsx index b70bfb609e0b..503214b141db 100644 --- a/src/components/ConnectToNetSuiteButton/index.tsx +++ b/src/components/ConnectToNetSuiteButton/index.tsx @@ -6,8 +6,8 @@ import * as Expensicons from '@components/Icon/Expensicons'; import PopoverMenu from '@components/PopoverMenu'; import useLocalize from '@hooks/useLocalize'; import useNetwork from '@hooks/useNetwork'; -import useResponsiveLayout from '@hooks/useResponsiveLayout'; import usePolicy from '@hooks/usePolicy'; +import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useThemeStyles from '@hooks/useThemeStyles'; import {removePolicyConnection} from '@libs/actions/connections'; import {getAdminPoliciesConnectedToNetSuite} from '@libs/actions/Policy/Policy'; diff --git a/src/components/ConnectToSageIntacctButton/index.tsx b/src/components/ConnectToSageIntacctButton/index.tsx index 2e819853edf7..df2c3b7fd929 100644 --- a/src/components/ConnectToSageIntacctButton/index.tsx +++ b/src/components/ConnectToSageIntacctButton/index.tsx @@ -6,8 +6,8 @@ import * as Expensicons from '@components/Icon/Expensicons'; import PopoverMenu from '@components/PopoverMenu'; import useLocalize from '@hooks/useLocalize'; import useNetwork from '@hooks/useNetwork'; -import useResponsiveLayout from '@hooks/useResponsiveLayout'; import usePolicy from '@hooks/usePolicy'; +import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useThemeStyles from '@hooks/useThemeStyles'; import {removePolicyConnection} from '@libs/actions/connections'; import {getAdminPoliciesConnectedToSageIntacct} from '@libs/actions/Policy/Policy'; diff --git a/src/components/Search/index.tsx b/src/components/Search/index.tsx index cc20a24188f5..5bffd5f4261c 100644 --- a/src/components/Search/index.tsx +++ b/src/components/Search/index.tsx @@ -11,8 +11,8 @@ import SelectionListWithModal from '@components/SelectionListWithModal'; import SearchRowSkeleton from '@components/Skeletons/SearchRowSkeleton'; import useLocalize from '@hooks/useLocalize'; import useNetwork from '@hooks/useNetwork'; -import useResponsiveLayout from '@hooks/useResponsiveLayout'; import usePrevious from '@hooks/usePrevious'; +import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useThemeStyles from '@hooks/useThemeStyles'; import {turnOffMobileSelectionMode, turnOnMobileSelectionMode} from '@libs/actions/MobileSelectionMode'; import * as SearchActions from '@libs/actions/Search'; diff --git a/src/libs/Navigation/AppNavigator/Navigators/OnboardingModalNavigator.tsx b/src/libs/Navigation/AppNavigator/Navigators/OnboardingModalNavigator.tsx index 4a7f04f72876..ecf2645642f1 100644 --- a/src/libs/Navigation/AppNavigator/Navigators/OnboardingModalNavigator.tsx +++ b/src/libs/Navigation/AppNavigator/Navigators/OnboardingModalNavigator.tsx @@ -8,7 +8,6 @@ import useDisableModalDismissOnEscape from '@hooks/useDisableModalDismissOnEscap import useKeyboardShortcut from '@hooks/useKeyboardShortcut'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useThemeStyles from '@hooks/useThemeStyles'; -import useWindowDimensions from '@hooks/useWindowDimensions'; import hasCompletedGuidedSetupFlowSelector from '@libs/hasCompletedGuidedSetupFlowSelector'; import OnboardingModalNavigatorScreenOptions from '@libs/Navigation/AppNavigator/OnboardingModalNavigatorScreenOptions'; import Navigation from '@libs/Navigation/Navigation'; @@ -32,7 +31,7 @@ function OnboardingModalNavigator() { const [hasCompletedGuidedSetupFlow] = useOnyx(ONYXKEYS.NVP_ONBOARDING, { selector: hasCompletedGuidedSetupFlowSelector, }); - const {isSmallScreenWidth} = useWindowDimensions(); + const {isSmallScreenWidth} = useResponsiveLayout(); useDisableModalDismissOnEscape(); From c2dd1f51634eb64eba3de9a60b8d1bfaa83a652e Mon Sep 17 00:00:00 2001 From: Rayane Djouah <77965000+rayane-djouah@users.noreply.github.com> Date: Wed, 21 Aug 2024 18:05:11 +0100 Subject: [PATCH 11/14] Use isSmallScreenWidth instead of shouldUseNarrowLayout for specific places only --- .../AddPaymentCard/PaymentCardCurrencyModal.tsx | 4 ++-- .../Attachments/AttachmentCarousel/index.tsx | 4 ++-- src/components/AutoCompleteSuggestions/index.tsx | 8 ++++---- src/components/ConfirmModal.tsx | 1 + src/components/ConnectToNetSuiteFlow/index.tsx | 5 +++-- .../ConnectToSageIntacctFlow/index.tsx | 6 +++--- .../FocusTrap/FocusTrapForScreen/index.web.tsx | 6 +++--- src/components/Modal/BaseModal.tsx | 6 +++--- src/components/MoneyReportHeader.tsx | 7 +++---- src/components/MoneyRequestHeader.tsx | 7 +++---- src/components/Popover/index.tsx | 13 +++++++------ src/components/PopoverMenu.tsx | 1 + src/components/ProcessMoneyReportHoldMenu.tsx | 1 + src/components/QRShare/index.tsx | 4 ++-- .../ReportActionItem/ExportWithDropdownMenu.tsx | 4 ++-- src/components/Search/SearchPageHeader.tsx | 4 ++-- src/components/SelectionListWithModal/index.tsx | 8 ++++---- .../useModalScreenOptions.ts | 4 ++-- .../Navigators/FullScreenNavigator.tsx | 6 +++--- .../Navigators/LeftModalNavigator.tsx | 6 +++--- .../Navigators/OnboardingModalNavigator.tsx | 6 +++--- .../Navigators/RightModalNavigator.tsx | 10 +++++----- .../createCustomFullScreenNavigator/index.tsx | 4 ++-- .../createCustomStackNavigator/index.tsx | 8 ++++---- src/libs/Navigation/NavigationRoot.tsx | 6 +++--- src/pages/NewChatPage.tsx | 1 + .../OnboardingPurpose/BaseOnboardingPurpose.tsx | 1 + .../report/ReportActionCompose/SendButton.tsx | 1 + .../request/step/IOURequestStepScan/index.tsx | 1 + src/pages/workspace/WorkspaceNewRoomPage.tsx | 1 + .../reportFields/ReportFieldsListValuesPage.tsx | 16 ++++++++-------- 31 files changed, 84 insertions(+), 76 deletions(-) diff --git a/src/components/AddPaymentCard/PaymentCardCurrencyModal.tsx b/src/components/AddPaymentCard/PaymentCardCurrencyModal.tsx index ab3058ff4631..5015482fc8ba 100644 --- a/src/components/AddPaymentCard/PaymentCardCurrencyModal.tsx +++ b/src/components/AddPaymentCard/PaymentCardCurrencyModal.tsx @@ -28,7 +28,7 @@ type PaymentCardCurrencyModalProps = { }; function PaymentCardCurrencyModal({isVisible, currencies, currentCurrency = CONST.PAYMENT_CARD_CURRENCY.USD, onCurrencyChange, onClose}: PaymentCardCurrencyModalProps) { - const {isSmallScreenWidth} = useResponsiveLayout(); + const {shouldUseNarrowLayout} = useResponsiveLayout(); const styles = useThemeStyles(); const {translate} = useLocalize(); const {sections} = useMemo( @@ -54,7 +54,7 @@ function PaymentCardCurrencyModal({isVisible, currencies, currentCurrency = CONS onClose={() => onClose?.()} onModalHide={onClose} hideModalContentWhileAnimating - innerContainerStyle={styles.RHPNavigatorContainer(isSmallScreenWidth)} + innerContainerStyle={styles.RHPNavigatorContainer(shouldUseNarrowLayout)} useNativeDriver > >>(); @@ -51,7 +51,7 @@ function AttachmentCarousel({report, reportActions, parentReportActions, source, const canUseTouchScreen = DeviceCapabilities.canUseTouchScreen(); - const modalStyles = styles.centeredModalStyles(isSmallScreenWidth, true); + const modalStyles = styles.centeredModalStyles(shouldUseNarrowLayout, true); const cellWidth = useMemo( () => PixelRatio.roundToNearestPixel(windowWidth - (modalStyles.marginHorizontal + modalStyles.borderWidth) * 2), [modalStyles.borderWidth, modalStyles.marginHorizontal, windowWidth], diff --git a/src/components/AutoCompleteSuggestions/index.tsx b/src/components/AutoCompleteSuggestions/index.tsx index f454f5e37526..3d1b91dce4b5 100644 --- a/src/components/AutoCompleteSuggestions/index.tsx +++ b/src/components/AutoCompleteSuggestions/index.tsx @@ -55,7 +55,7 @@ function AutoCompleteSuggestions({measureParentContainerAndReportCu const leftValue = React.useRef(0); const prevLeftValue = React.useRef(0); const {windowHeight, windowWidth} = useWindowDimensions(); - const {isSmallScreenWidth} = useResponsiveLayout(); + const {shouldUseNarrowLayout} = useResponsiveLayout(); const [suggestionHeight, setSuggestionHeight] = React.useState(0); const [containerState, setContainerState] = React.useState(initialContainerState); const StyleUtils = useStyleUtils(); @@ -98,12 +98,12 @@ function AutoCompleteSuggestions({measureParentContainerAndReportCu const contentMaxHeight = measureHeightOfSuggestionRows(suggestionsLength, true); const contentMinHeight = measureHeightOfSuggestionRows(suggestionsLength, false); let bottomValue = windowHeight - (cursorCoordinates.y - scrollValue + y) - keyboardHeight; - const widthValue = isSmallScreenWidth ? width : CONST.AUTO_COMPLETE_SUGGESTER.BIG_SCREEN_SUGGESTION_WIDTH; + const widthValue = shouldUseNarrowLayout ? width : CONST.AUTO_COMPLETE_SUGGESTER.BIG_SCREEN_SUGGESTION_WIDTH; const isEnoughSpaceToRenderMenuAboveForBig = isEnoughSpaceToRenderMenuAboveCursor({y, cursorCoordinates, scrollValue, contentHeight: contentMaxHeight, topInset}); const isEnoughSpaceToRenderMenuAboveForSmall = isEnoughSpaceToRenderMenuAboveCursor({y, cursorCoordinates, scrollValue, contentHeight: contentMinHeight, topInset}); - const newLeftOffset = isSmallScreenWidth ? x : bigScreenLeftOffset; + const newLeftOffset = shouldUseNarrowLayout ? x : bigScreenLeftOffset; // If the suggested word is longer than 150 (approximately half the width of the suggestion popup), then adjust a new position of popup const isAdjustmentNeeded = Math.abs(prevLeftValue.current - bigScreenLeftOffset) > 150; if (isInitialRender.current || isAdjustmentNeeded) { @@ -133,7 +133,7 @@ function AutoCompleteSuggestions({measureParentContainerAndReportCu cursorCoordinates, }); }); - }, [measureParentContainerAndReportCursor, windowHeight, windowWidth, keyboardHeight, isSmallScreenWidth, suggestionsLength, bottomInset, topInset]); + }, [measureParentContainerAndReportCursor, windowHeight, windowWidth, keyboardHeight, shouldUseNarrowLayout, suggestionsLength, bottomInset, topInset]); if ((containerState.width === 0 && containerState.left === 0 && containerState.bottom === 0) || (containerState.cursorCoordinates.x === 0 && containerState.cursorCoordinates.y === 0)) { return null; diff --git a/src/components/ConfirmModal.tsx b/src/components/ConfirmModal.tsx index 487d637b2ea2..e9558297e577 100755 --- a/src/components/ConfirmModal.tsx +++ b/src/components/ConfirmModal.tsx @@ -132,6 +132,7 @@ function ConfirmModal({ shouldEnableNewFocusManagement, restoreFocusType, }: ConfirmModalProps) { + // We need to use isSmallScreenWidth instead of shouldUseNarrowLayout to use the correct modal type const {isSmallScreenWidth} = useResponsiveLayout(); const styles = useThemeStyles(); diff --git a/src/components/ConnectToNetSuiteFlow/index.tsx b/src/components/ConnectToNetSuiteFlow/index.tsx index ec38da13bef0..e835a22bf53a 100644 --- a/src/components/ConnectToNetSuiteFlow/index.tsx +++ b/src/components/ConnectToNetSuiteFlow/index.tsx @@ -2,6 +2,7 @@ import React, {useEffect, useState} from 'react'; import * as Expensicons from '@components/Icon/Expensicons'; import PopoverMenu from '@components/PopoverMenu'; import useLocalize from '@hooks/useLocalize'; +import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useWindowDimensions from '@hooks/useWindowDimensions'; import {getAdminPoliciesConnectedToNetSuite} from '@libs/actions/Policy/Policy'; import Navigation from '@libs/Navigation/Navigation'; @@ -15,7 +16,7 @@ function ConnectToNetSuiteFlow({policyID}: ConnectToNetSuiteFlowProps) { const {translate} = useLocalize(); const hasPoliciesConnectedToNetSuite = !!getAdminPoliciesConnectedToNetSuite()?.length; - const {isSmallScreenWidth} = useWindowDimensions(); + const {shouldUseNarrowLayout} = useResponsiveLayout(); const [isReuseConnectionsPopoverOpen, setIsReuseConnectionsPopoverOpen] = useState(false); const [reuseConnectionPopoverPosition, setReuseConnectionPopoverPosition] = useState({horizontal: 0, vertical: 0}); const {popoverAnchorRefs} = useAccountingContext(); @@ -52,7 +53,7 @@ function ConnectToNetSuiteFlow({policyID}: ConnectToNetSuiteFlowProps) { }, []); if (threeDotsMenuContainerRef) { - if (!isSmallScreenWidth) { + if (!shouldUseNarrowLayout) { threeDotsMenuContainerRef.current?.measureInWindow((x, y, width, height) => { setReuseConnectionPopoverPosition({ horizontal: x + width, diff --git a/src/components/ConnectToSageIntacctFlow/index.tsx b/src/components/ConnectToSageIntacctFlow/index.tsx index 5d7b36eb0bbb..77a8c0280e37 100644 --- a/src/components/ConnectToSageIntacctFlow/index.tsx +++ b/src/components/ConnectToSageIntacctFlow/index.tsx @@ -2,7 +2,7 @@ import React, {useEffect, useState} from 'react'; import * as Expensicons from '@components/Icon/Expensicons'; import PopoverMenu from '@components/PopoverMenu'; import useLocalize from '@hooks/useLocalize'; -import useWindowDimensions from '@hooks/useWindowDimensions'; +import useResponsiveLayout from '@hooks/useResponsiveLayout'; import {getAdminPoliciesConnectedToSageIntacct} from '@libs/actions/Policy/Policy'; import Navigation from '@libs/Navigation/Navigation'; import {useAccountingContext} from '@pages/workspace/accounting/AccountingContext'; @@ -18,7 +18,7 @@ function ConnectToSageIntacctFlow({policyID}: ConnectToSageIntacctFlowProps) { const {translate} = useLocalize(); const hasPoliciesConnectedToSageIntacct = !!getAdminPoliciesConnectedToSageIntacct().length; - const {isSmallScreenWidth} = useWindowDimensions(); + const {shouldUseNarrowLayout} = useResponsiveLayout(); const [isReuseConnectionsPopoverOpen, setIsReuseConnectionsPopoverOpen] = useState(false); const [reuseConnectionPopoverPosition, setReuseConnectionPopoverPosition] = useState({horizontal: 0, vertical: 0}); const {popoverAnchorRefs} = useAccountingContext(); @@ -54,7 +54,7 @@ function ConnectToSageIntacctFlow({policyID}: ConnectToSageIntacctFlowProps) { }, []); if (threeDotsMenuContainerRef) { - if (!isSmallScreenWidth) { + if (!shouldUseNarrowLayout) { threeDotsMenuContainerRef.current?.measureInWindow((x, y, width, height) => { setReuseConnectionPopoverPosition({ horizontal: x + width, diff --git a/src/components/FocusTrap/FocusTrapForScreen/index.web.tsx b/src/components/FocusTrap/FocusTrapForScreen/index.web.tsx index cb56b7f3ec14..d91779540447 100644 --- a/src/components/FocusTrap/FocusTrapForScreen/index.web.tsx +++ b/src/components/FocusTrap/FocusTrapForScreen/index.web.tsx @@ -13,7 +13,7 @@ import type FocusTrapProps from './FocusTrapProps'; function FocusTrapForScreen({children, focusTrapSettings}: FocusTrapProps) { const isFocused = useIsFocused(); const route = useRoute(); - const {isSmallScreenWidth} = useResponsiveLayout(); + const {shouldUseNarrowLayout} = useResponsiveLayout(); const isActive = useMemo(() => { if (typeof focusTrapSettings?.active !== 'undefined') { @@ -30,11 +30,11 @@ function FocusTrapForScreen({children, focusTrapSettings}: FocusTrapProps) { } // Focus trap can't be active on these screens if the layout is wide because they may be displayed side by side. - if (WIDE_LAYOUT_INACTIVE_SCREENS.includes(route.name) && !isSmallScreenWidth) { + if (WIDE_LAYOUT_INACTIVE_SCREENS.includes(route.name) && !shouldUseNarrowLayout) { return false; } return true; - }, [isFocused, isSmallScreenWidth, route.name, focusTrapSettings?.active]); + }, [isFocused, shouldUseNarrowLayout, route.name, focusTrapSettings?.active]); return ( { IOU.dismissHoldUseExplanation(); @@ -410,7 +409,7 @@ function MoneyReportHeader({policy, report: moneyRequestReport, transactionThrea danger shouldEnableNewFocusManagement /> - {isSmallScreenWidth && shouldShowHoldMenu && ( + {shouldUseNarrowLayout && shouldShowHoldMenu && ( { IOU.dismissHoldUseExplanation(); @@ -191,7 +190,7 @@ function MoneyRequestHeader({report, parentReportAction, policy, shouldUseNarrow )} - {isSmallScreenWidth && shouldShowHoldMenu && ( + {shouldUseNarrowLayout && shouldShowHoldMenu && ( option.isSelected); diff --git a/src/components/ProcessMoneyReportHoldMenu.tsx b/src/components/ProcessMoneyReportHoldMenu.tsx index 4afa7aa4972c..4a63714b6157 100644 --- a/src/components/ProcessMoneyReportHoldMenu.tsx +++ b/src/components/ProcessMoneyReportHoldMenu.tsx @@ -56,6 +56,7 @@ function ProcessMoneyReportHoldMenu({ }: ProcessMoneyReportHoldMenuProps) { const {translate} = useLocalize(); const isApprove = requestType === CONST.IOU.REPORT_ACTION_TYPE.APPROVE; + // We need to use shouldUseNarrowLayout instead of shouldUseNarrowLayout to apply the correct modal type const {isSmallScreenWidth} = useResponsiveLayout(); const onSubmit = (full: boolean) => { diff --git a/src/components/QRShare/index.tsx b/src/components/QRShare/index.tsx index 9023773e8635..9e8d11ea9664 100644 --- a/src/components/QRShare/index.tsx +++ b/src/components/QRShare/index.tsx @@ -17,9 +17,9 @@ import type {QRShareHandle, QRShareProps} from './types'; function QRShare({url, title, subtitle, logo, svgLogo, svgLogoFillColor, logoBackgroundColor, logoRatio, logoMarginRatio}: QRShareProps, ref: ForwardedRef) { const styles = useThemeStyles(); const theme = useTheme(); - const {isSmallScreenWidth} = useResponsiveLayout(); + const {shouldUseNarrowLayout} = useResponsiveLayout(); const {windowWidth} = useWindowDimensions(); - const qrCodeContainerWidth = isSmallScreenWidth ? windowWidth : variables.sideBarWidth; + const qrCodeContainerWidth = shouldUseNarrowLayout ? windowWidth : variables.sideBarWidth; const [qrCodeSize, setQrCodeSize] = useState(qrCodeContainerWidth - styles.ph5.paddingHorizontal * 2 - variables.qrShareHorizontalPadding * 2); const svgRef = useRef(); diff --git a/src/components/ReportActionItem/ExportWithDropdownMenu.tsx b/src/components/ReportActionItem/ExportWithDropdownMenu.tsx index 6d73035fd8bb..aff868a74bc5 100644 --- a/src/components/ReportActionItem/ExportWithDropdownMenu.tsx +++ b/src/components/ReportActionItem/ExportWithDropdownMenu.tsx @@ -40,7 +40,7 @@ function ExportWithDropdownMenu({ const reportID = report?.reportID; const styles = useThemeStyles(); const {translate} = useLocalize(); - const {isSmallScreenWidth} = useResponsiveLayout(); + const {shouldUseNarrowLayout} = useResponsiveLayout(); const [modalStatus, setModalStatus] = useState(null); const [exportMethods] = useOnyx(ONYXKEYS.LAST_EXPORT_METHOD); const [reportActions] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`); @@ -119,7 +119,7 @@ function ExportWithDropdownMenu({ }} onOptionSelected={({value}) => savePreferredExportMethod(value)} options={dropdownOptions} - style={[isSmallScreenWidth && styles.flexGrow1]} + style={[shouldUseNarrowLayout && styles.flexGrow1]} buttonSize={CONST.DROPDOWN_BUTTON_SIZE.MEDIUM} /> ( const [isModalVisible, setIsModalVisible] = useState(false); const [longPressedItem, setLongPressedItem] = useState(null); const {translate} = useLocalize(); - const {isSmallScreenWidth} = useResponsiveLayout(); + const {shouldUseNarrowLayout} = useResponsiveLayout(); const [selectionMode] = useOnyx(ONYXKEYS.MOBILE_SELECTION_MODE); useEffect(() => { // We can access 0 index safely as we are not displaying multiple sections in table view const selectedItems = sections[0].data.filter((item) => item.isSelected); - if (!isSmallScreenWidth) { + if (!shouldUseNarrowLayout) { if (selectedItems.length === 0) { turnOffMobileSelectionMode(); } @@ -39,10 +39,10 @@ function SelectionListWithModal( if (selectedItems.length > 0 && !selectionMode?.isEnabled) { turnOnMobileSelectionMode(); } - }, [sections, selectionMode, isSmallScreenWidth]); + }, [sections, selectionMode, shouldUseNarrowLayout]); const handleLongPressRow = (item: TItem) => { - if (!turnOnSelectionModeOnLongPress || !isSmallScreenWidth) { + if (!turnOnSelectionModeOnLongPress || !shouldUseNarrowLayout) { return; } setLongPressedItem(item); diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators/useModalScreenOptions.ts b/src/libs/Navigation/AppNavigator/ModalStackNavigators/useModalScreenOptions.ts index 7277e4bee710..2193dcb2bf6b 100644 --- a/src/libs/Navigation/AppNavigator/ModalStackNavigators/useModalScreenOptions.ts +++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators/useModalScreenOptions.ts @@ -11,13 +11,13 @@ import type {ThemeStyles} from '@src/styles'; function useModalScreenOptions(getScreenOptions?: (styles: ThemeStyles) => StackNavigationOptions) { const styles = useThemeStyles(); const styleUtils = useStyleUtils(); - const {isSmallScreenWidth} = useResponsiveLayout(); + const {shouldUseNarrowLayout} = useResponsiveLayout(); let cardStyleInterpolator = CardStyleInterpolators.forHorizontalIOS; if (isSafari()) { const customInterpolator = createModalCardStyleInterpolator(styleUtils); - cardStyleInterpolator = (props: StackCardInterpolationProps) => customInterpolator(isSmallScreenWidth, false, false, props); + cardStyleInterpolator = (props: StackCardInterpolationProps) => customInterpolator(shouldUseNarrowLayout, false, false, props); } const defaultSubRouteOptions = useMemo( diff --git a/src/libs/Navigation/AppNavigator/Navigators/FullScreenNavigator.tsx b/src/libs/Navigation/AppNavigator/Navigators/FullScreenNavigator.tsx index 42587eae9bc6..1de32ed7e021 100644 --- a/src/libs/Navigation/AppNavigator/Navigators/FullScreenNavigator.tsx +++ b/src/libs/Navigation/AppNavigator/Navigators/FullScreenNavigator.tsx @@ -38,12 +38,12 @@ const CENTRAL_PANE_WORKSPACE_SCREENS = { function FullScreenNavigator() { const styles = useThemeStyles(); const StyleUtils = useStyleUtils(); - const {isSmallScreenWidth} = useResponsiveLayout(); - const screenOptions = getRootNavigatorScreenOptions(isSmallScreenWidth, styles, StyleUtils); + const {shouldUseNarrowLayout} = useResponsiveLayout(); + const screenOptions = getRootNavigatorScreenOptions(shouldUseNarrowLayout, styles, StyleUtils); return ( - + (); function LeftModalNavigator({navigation}: LeftModalNavigatorProps) { const styles = useThemeStyles(); - const {isSmallScreenWidth} = useResponsiveLayout(); + const {shouldUseNarrowLayout} = useResponsiveLayout(); const screenOptions = useMemo(() => ModalNavigatorScreenOptions(styles, 'horizontal-inverted'), [styles]); return ( - {!isSmallScreenWidth && ( + {!shouldUseNarrowLayout && ( )} - + { if (!hasCompletedGuidedSetupFlow) { @@ -40,7 +40,7 @@ function OnboardingModalNavigator() { // On small screens, pop all navigation states and go back to HOME. // On large screens, need to go back to previous route and then redirect to Concierge, // otherwise going back on Concierge will go to onboarding and then redirected to Concierge again - if (isSmallScreenWidth) { + if (shouldUseNarrowLayout) { Navigation.setShouldPopAllStateOnUP(true); Navigation.goBack(ROUTES.HOME, true, true); } else { @@ -48,7 +48,7 @@ function OnboardingModalNavigator() { Report.navigateToConciergeChat(); } }); - }, [hasCompletedGuidedSetupFlow, isSmallScreenWidth]); + }, [hasCompletedGuidedSetupFlow, shouldUseNarrowLayout]); const outerViewRef = React.useRef(null); diff --git a/src/libs/Navigation/AppNavigator/Navigators/RightModalNavigator.tsx b/src/libs/Navigation/AppNavigator/Navigators/RightModalNavigator.tsx index e5aa79867d7a..fb012139f9d8 100644 --- a/src/libs/Navigation/AppNavigator/Navigators/RightModalNavigator.tsx +++ b/src/libs/Navigation/AppNavigator/Navigators/RightModalNavigator.tsx @@ -23,22 +23,22 @@ const Stack = createStackNavigator(); function RightModalNavigator({navigation, route}: RightModalNavigatorProps) { const styles = useThemeStyles(); const styleUtils = useStyleUtils(); - const {isSmallScreenWidth} = useResponsiveLayout(); + const {shouldUseNarrowLayout} = useResponsiveLayout(); const isExecutingRef = useRef(false); const screenOptions = useMemo(() => { const options = ModalNavigatorScreenOptions(styles); // The .forHorizontalIOS interpolator from `@react-navigation` is misbehaving on Safari, so we override it with Expensify custom interpolator if (isSafari()) { const customInterpolator = createModalCardStyleInterpolator(styleUtils); - options.cardStyleInterpolator = (props: StackCardInterpolationProps) => customInterpolator(isSmallScreenWidth, false, false, props); + options.cardStyleInterpolator = (props: StackCardInterpolationProps) => customInterpolator(shouldUseNarrowLayout, false, false, props); } return options; - }, [isSmallScreenWidth, styleUtils, styles]); + }, [shouldUseNarrowLayout, styleUtils, styles]); return ( - {!isSmallScreenWidth && ( + {!shouldUseNarrowLayout && ( { if (isExecutingRef.current) { @@ -49,7 +49,7 @@ function RightModalNavigator({navigation, route}: RightModalNavigatorProps) { }} /> )} - + { if (!navigationRef.isReady()) { @@ -30,7 +30,7 @@ function CustomFullScreenNavigator(props: FullScreenNavigatorProps) { // We need to separately reset state of this navigator to trigger getRehydratedState. navigation.reset(navigation.getState()); // eslint-disable-next-line react-compiler/react-compiler, react-hooks/exhaustive-deps - }, [isSmallScreenWidth]); + }, [shouldUseNarrowLayout]); return ( diff --git a/src/libs/Navigation/AppNavigator/createCustomStackNavigator/index.tsx b/src/libs/Navigation/AppNavigator/createCustomStackNavigator/index.tsx index cf1ced179b6b..a37a102ff8a3 100644 --- a/src/libs/Navigation/AppNavigator/createCustomStackNavigator/index.tsx +++ b/src/libs/Navigation/AppNavigator/createCustomStackNavigator/index.tsx @@ -36,7 +36,7 @@ function reduceCentralPaneRoutes(routes: Routes): Routes { } function ResponsiveStackNavigator(props: ResponsiveStackNavigatorProps) { - const {isSmallScreenWidth} = useResponsiveLayout(); + const {shouldUseNarrowLayout} = useResponsiveLayout(); const styles = useThemeStyles(); const {navigation, state, descriptors, NavigationContent} = useNavigationBuilder< @@ -56,12 +56,12 @@ function ResponsiveStackNavigator(props: ResponsiveStackNavigatorProps) { return; } navigationRef.resetRoot(navigationRef.getRootState()); - }, [isSmallScreenWidth]); + }, [shouldUseNarrowLayout]); const {stateToRender, searchRoute} = useMemo(() => { const routes = reduceCentralPaneRoutes(state.routes); - if (isSmallScreenWidth) { + if (shouldUseNarrowLayout) { const isSearchCentralPane = (route: RouteProp) => getTopmostCentralPaneRoute({routes: [route]} as State)?.name === SCREENS.SEARCH.CENTRAL_PANE; const lastRoute = routes[routes.length - 1]; @@ -98,7 +98,7 @@ function ResponsiveStackNavigator(props: ResponsiveStackNavigatorProps) { }, searchRoute: undefined, }; - }, [state, isSmallScreenWidth]); + }, [state, shouldUseNarrowLayout]); return ( diff --git a/src/libs/Navigation/NavigationRoot.tsx b/src/libs/Navigation/NavigationRoot.tsx index d05b11ee3a12..4e9b775cbb8d 100644 --- a/src/libs/Navigation/NavigationRoot.tsx +++ b/src/libs/Navigation/NavigationRoot.tsx @@ -82,7 +82,7 @@ function NavigationRoot({authenticated, lastVisitedPath, initialUrl, onReady, sh const {cleanStaleScrollOffsets} = useContext(ScrollOffsetContext); const currentReportIDValue = useCurrentReportID(); - const {isSmallScreenWidth} = useResponsiveLayout(); + const {shouldUseNarrowLayout} = useResponsiveLayout(); const {setActiveWorkspaceID} = useActiveWorkspace(); const [user] = useOnyx(ONYXKEYS.USER); @@ -146,8 +146,8 @@ function NavigationRoot({authenticated, lastVisitedPath, initialUrl, onReady, sh return; } - Navigation.setShouldPopAllStateOnUP(!isSmallScreenWidth); - }, [isSmallScreenWidth]); + Navigation.setShouldPopAllStateOnUP(!shouldUseNarrowLayout); + }, [shouldUseNarrowLayout]); const handleStateChange = (state: NavigationState | undefined) => { if (!state) { diff --git a/src/pages/NewChatPage.tsx b/src/pages/NewChatPage.tsx index 4b8557dfbac3..61de2fa145be 100755 --- a/src/pages/NewChatPage.tsx +++ b/src/pages/NewChatPage.tsx @@ -144,6 +144,7 @@ function useOptions({isGroupChat}: NewChatPageProps) { function NewChatPage({isGroupChat}: NewChatPageProps) { const {translate} = useLocalize(); const {isOffline} = useNetwork(); + // We need to use isSmallScreenWidth instead of shouldUseNarrowLayout to show offline indicator on small screen only const {isSmallScreenWidth} = useResponsiveLayout(); const styles = useThemeStyles(); const personalData = useCurrentUserPersonalDetails(); diff --git a/src/pages/OnboardingPurpose/BaseOnboardingPurpose.tsx b/src/pages/OnboardingPurpose/BaseOnboardingPurpose.tsx index 6bdace2769b4..71ace34011b1 100644 --- a/src/pages/OnboardingPurpose/BaseOnboardingPurpose.tsx +++ b/src/pages/OnboardingPurpose/BaseOnboardingPurpose.tsx @@ -40,6 +40,7 @@ function BaseOnboardingPurpose({shouldUseNativeStyles, shouldEnableMaxHeight, ro const {translate} = useLocalize(); const {onboardingIsMediumOrLargerScreenWidth} = useResponsiveLayout(); const {windowHeight} = useWindowDimensions(); + // We need to use isSmallScreenWidth instead of shouldUseNarrowLayout to show offline indicator on small screen only const {isSmallScreenWidth} = useResponsiveLayout(); const theme = useTheme(); diff --git a/src/pages/home/report/ReportActionCompose/SendButton.tsx b/src/pages/home/report/ReportActionCompose/SendButton.tsx index 4b902e2c6246..6e808ae811cc 100644 --- a/src/pages/home/report/ReportActionCompose/SendButton.tsx +++ b/src/pages/home/report/ReportActionCompose/SendButton.tsx @@ -23,6 +23,7 @@ function SendButton({isDisabled: isDisabledProp, handleSendMessage}: SendButtonP const theme = useTheme(); const styles = useThemeStyles(); const {translate} = useLocalize(); + // We need to use isSmallScreenWidth instead of shouldUseNarrowLayout to manage GestureDetector correctly const {isSmallScreenWidth} = useResponsiveLayout(); const Tap = Gesture.Tap().onEnd(() => { handleSendMessage(); diff --git a/src/pages/iou/request/step/IOURequestStepScan/index.tsx b/src/pages/iou/request/step/IOURequestStepScan/index.tsx index 16e50fe5bc6c..0bc4890f348f 100644 --- a/src/pages/iou/request/step/IOURequestStepScan/index.tsx +++ b/src/pages/iou/request/step/IOURequestStepScan/index.tsx @@ -67,6 +67,7 @@ function IOURequestStepScan({ const [attachmentInvalidReason, setAttachmentValidReason] = useState(); const [pdfFile, setPdfFile] = useState(null); const [receiptImageTopPosition, setReceiptImageTopPosition] = useState(0); + // we need to use isSmallScreenWidth instead of shouldUseNarrowLayout because drag and drop is not supported on mobile const {isSmallScreenWidth} = useResponsiveLayout(); const {translate} = useLocalize(); const {isDraggingOver} = useContext(DragAndDropContext); diff --git a/src/pages/workspace/WorkspaceNewRoomPage.tsx b/src/pages/workspace/WorkspaceNewRoomPage.tsx index 7bf04bd4b449..c0e953a6a350 100644 --- a/src/pages/workspace/WorkspaceNewRoomPage.tsx +++ b/src/pages/workspace/WorkspaceNewRoomPage.tsx @@ -64,6 +64,7 @@ function WorkspaceNewRoomPage({policies, reports, formState, session, activePoli const isFocused = useIsFocused(); const {translate} = useLocalize(); const {isOffline} = useNetwork(); + // We need to use isSmallScreenWidth instead of shouldUseNarrowLayout to show offline indicator on small screen only const {isSmallScreenWidth} = useResponsiveLayout(); const [visibility, setVisibility] = useState>(CONST.REPORT.VISIBILITY.RESTRICTED); const [writeCapability, setWriteCapability] = useState>(CONST.REPORT.WRITE_CAPABILITIES.ALL); diff --git a/src/pages/workspace/reportFields/ReportFieldsListValuesPage.tsx b/src/pages/workspace/reportFields/ReportFieldsListValuesPage.tsx index 61967a729cd3..02e5d6edfcc4 100644 --- a/src/pages/workspace/reportFields/ReportFieldsListValuesPage.tsx +++ b/src/pages/workspace/reportFields/ReportFieldsListValuesPage.tsx @@ -58,7 +58,7 @@ function ReportFieldsListValuesPage({ }: ReportFieldsListValuesPageProps) { const styles = useThemeStyles(); const {translate} = useLocalize(); - const {isSmallScreenWidth} = useResponsiveLayout(); + const {shouldUseNarrowLayout} = useResponsiveLayout(); const [formDraft] = useOnyx(ONYXKEYS.FORMS.WORKSPACE_REPORT_FIELDS_FORM_DRAFT); const [selectionMode] = useOnyx(ONYXKEYS.MOBILE_SELECTION_MODE); @@ -66,7 +66,7 @@ function ReportFieldsListValuesPage({ const [deleteValuesConfirmModalVisible, setDeleteValuesConfirmModalVisible] = useState(false); const hasAccountingConnections = PolicyUtils.hasAccountingConnections(policy); - const canSelectMultiple = !hasAccountingConnections && (isSmallScreenWidth ? selectionMode?.isEnabled : true); + const canSelectMultiple = !hasAccountingConnections && (shouldUseNarrowLayout ? selectionMode?.isEnabled : true); const [listValues, disabledListValues] = useMemo(() => { let reportFieldValues: string[]; @@ -176,7 +176,7 @@ function ReportFieldsListValuesPage({ const getHeaderButtons = () => { const options: Array>> = []; - if ((isSmallScreenWidth ? selectionMode?.isEnabled : true) && selectedValuesArray.length > 0) { + if ((shouldUseNarrowLayout ? selectionMode?.isEnabled : true) && selectedValuesArray.length > 0) { if (selectedValuesArray.length > 0) { options.push({ icon: Expensicons.Trashcan, @@ -258,7 +258,7 @@ function ReportFieldsListValuesPage({ customText={translate('workspace.common.selected', {selectedNumber: selectedValuesArray.length})} options={options} isSplitButton={false} - style={[isSmallScreenWidth && styles.flexGrow1, isSmallScreenWidth && styles.mb3]} + style={[shouldUseNarrowLayout && styles.flexGrow1, shouldUseNarrowLayout && styles.mb3]} isDisabled={!selectedValuesArray.length} /> ); @@ -266,7 +266,7 @@ function ReportFieldsListValuesPage({ return (