From e8f948f68656e68853e5522a8b4df732e05e6e85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanno=20J=2E=20G=C3=B6decke?= Date: Thu, 19 Oct 2023 14:24:41 +0200 Subject: [PATCH 01/56] install native-stack --- package-lock.json | 45 +++++++++++++++++++++++++++++++++++++++++++++ package.json | 1 + 2 files changed, 46 insertions(+) diff --git a/package-lock.json b/package-lock.json index 95c25f602e30..75d3e9fe0ed0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -37,6 +37,7 @@ "@react-native-picker/picker": "^2.4.3", "@react-navigation/material-top-tabs": "^6.6.3", "@react-navigation/native": "6.1.6", + "@react-navigation/native-stack": "^6.9.14", "@react-navigation/stack": "6.3.16", "@react-ng/bounds-observer": "^0.2.1", "@rnmapbox/maps": "^10.0.11", @@ -8961,6 +8962,33 @@ "react-native": "*" } }, + "node_modules/@react-navigation/native-stack": { + "version": "6.9.14", + "resolved": "https://registry.npmjs.org/@react-navigation/native-stack/-/native-stack-6.9.14.tgz", + "integrity": "sha512-7RiZkvMFN6f0kmANc63B/0m9ttQ2JpDIPWQwPU93FP698s19KTOyu7uxgl7Oi3bvsqHFO5JfiR7B+4h8lh9dxw==", + "dependencies": { + "@react-navigation/elements": "^1.3.19", + "warn-once": "^0.1.0" + }, + "peerDependencies": { + "@react-navigation/native": "^6.0.0", + "react": "*", + "react-native": "*", + "react-native-safe-area-context": ">= 3.0.0", + "react-native-screens": ">= 3.0.0" + } + }, + "node_modules/@react-navigation/native-stack/node_modules/@react-navigation/elements": { + "version": "1.3.19", + "resolved": "https://registry.npmjs.org/@react-navigation/elements/-/elements-1.3.19.tgz", + "integrity": "sha512-7hLvSYKPuDS070pza5gd43WDX7QgfuEmuTWNbCJhKdWlLudYmq3qzxGCBwCfO2dEI6+p8tla5wruaWiGKAbTYw==", + "peerDependencies": { + "@react-navigation/native": "^6.0.0", + "react": "*", + "react-native": "*", + "react-native-safe-area-context": ">= 3.0.0" + } + }, "node_modules/@react-navigation/routers": { "version": "6.1.8", "resolved": "https://registry.npmjs.org/@react-navigation/routers/-/routers-6.1.8.tgz", @@ -59320,6 +59348,23 @@ "nanoid": "^3.1.23" } }, + "@react-navigation/native-stack": { + "version": "6.9.14", + "resolved": "https://registry.npmjs.org/@react-navigation/native-stack/-/native-stack-6.9.14.tgz", + "integrity": "sha512-7RiZkvMFN6f0kmANc63B/0m9ttQ2JpDIPWQwPU93FP698s19KTOyu7uxgl7Oi3bvsqHFO5JfiR7B+4h8lh9dxw==", + "requires": { + "@react-navigation/elements": "^1.3.19", + "warn-once": "^0.1.0" + }, + "dependencies": { + "@react-navigation/elements": { + "version": "1.3.19", + "resolved": "https://registry.npmjs.org/@react-navigation/elements/-/elements-1.3.19.tgz", + "integrity": "sha512-7hLvSYKPuDS070pza5gd43WDX7QgfuEmuTWNbCJhKdWlLudYmq3qzxGCBwCfO2dEI6+p8tla5wruaWiGKAbTYw==", + "requires": {} + } + } + }, "@react-navigation/routers": { "version": "6.1.8", "resolved": "https://registry.npmjs.org/@react-navigation/routers/-/routers-6.1.8.tgz", diff --git a/package.json b/package.json index 1db859827c41..665951328bd1 100644 --- a/package.json +++ b/package.json @@ -82,6 +82,7 @@ "@react-native-picker/picker": "^2.4.3", "@react-navigation/material-top-tabs": "^6.6.3", "@react-navigation/native": "6.1.6", + "@react-navigation/native-stack": "^6.9.14", "@react-navigation/stack": "6.3.16", "@react-ng/bounds-observer": "^0.2.1", "@rnmapbox/maps": "^10.0.11", From b180872b639ceb3e4aa399645c9c85ec87b0b0eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanno=20J=2E=20G=C3=B6decke?= Date: Thu, 19 Oct 2023 15:14:37 +0200 Subject: [PATCH 02/56] create PlatformStackNavigator with different impls for web & native --- src/libs/Navigation/AppNavigator/ModalStackNavigators.js | 7 +++++-- .../AppNavigator/Navigators/CentralPaneNavigator.js | 4 ++-- src/libs/Navigation/AppNavigator/Navigators/Overlay.js | 1 + .../AppNavigator/Navigators/RightModalNavigator.js | 4 ++-- src/libs/Navigation/AppNavigator/PublicScreens.js | 4 ++-- .../AppNavigator/createCustomStackNavigator/index.js | 4 ++-- src/libs/Navigation/PlatformStackNavigator/index.native.ts | 7 +++++++ src/libs/Navigation/PlatformStackNavigator/index.ts | 7 +++++++ 8 files changed, 28 insertions(+), 10 deletions(-) create mode 100644 src/libs/Navigation/PlatformStackNavigator/index.native.ts create mode 100644 src/libs/Navigation/PlatformStackNavigator/index.ts diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators.js b/src/libs/Navigation/AppNavigator/ModalStackNavigators.js index cfc8f815e4fe..2e5950e1b094 100644 --- a/src/libs/Navigation/AppNavigator/ModalStackNavigators.js +++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators.js @@ -1,9 +1,12 @@ import _ from 'underscore'; import React from 'react'; -import {createStackNavigator, CardStyleInterpolators} from '@react-navigation/stack'; +import {CardStyleInterpolators} from '@react-navigation/stack'; +import * as PlatformStackNavigator from '../PlatformStackNavigator'; + import styles from '../../../styles/styles'; import SCREENS from '../../../SCREENS'; +// TODO: migrate options const defaultSubRouteOptions = { cardStyle: styles.navigationScreenCardStyle, headerShown: false, @@ -17,7 +20,7 @@ const defaultSubRouteOptions = { * @returns {Function} */ function createModalStackNavigator(screens) { - const ModalStackNavigator = createStackNavigator(); + const ModalStackNavigator = PlatformStackNavigator.createPlatformStackNavigator(); return () => ( {_.map(screens, (getComponent, name) => ( diff --git a/src/libs/Navigation/AppNavigator/Navigators/CentralPaneNavigator.js b/src/libs/Navigation/AppNavigator/Navigators/CentralPaneNavigator.js index 64eadcbe06c3..b5fa76a48b90 100644 --- a/src/libs/Navigation/AppNavigator/Navigators/CentralPaneNavigator.js +++ b/src/libs/Navigation/AppNavigator/Navigators/CentralPaneNavigator.js @@ -1,12 +1,12 @@ import React from 'react'; -import {createStackNavigator} from '@react-navigation/stack'; +import * as PlatformStackNavigator from '../../PlatformStackNavigator'; import SCREENS from '../../../../SCREENS'; import ReportScreenWrapper from '../ReportScreenWrapper'; import getCurrentUrl from '../../currentUrl'; import styles from '../../../../styles/styles'; import FreezeWrapper from '../../FreezeWrapper'; -const Stack = createStackNavigator(); +const Stack = PlatformStackNavigator.createPlatformStackNavigator(); const url = getCurrentUrl(); const openOnAdminRoom = url ? new URL(url).searchParams.get('openOnAdminRoom') : undefined; diff --git a/src/libs/Navigation/AppNavigator/Navigators/Overlay.js b/src/libs/Navigation/AppNavigator/Navigators/Overlay.js index 1b2faff8c5e3..ed3c27aed673 100644 --- a/src/libs/Navigation/AppNavigator/Navigators/Overlay.js +++ b/src/libs/Navigation/AppNavigator/Navigators/Overlay.js @@ -1,5 +1,6 @@ import React from 'react'; import {Animated, View} from 'react-native'; +// TODO: migrate import {useCardAnimation} from '@react-navigation/stack'; import PropTypes from 'prop-types'; diff --git a/src/libs/Navigation/AppNavigator/Navigators/RightModalNavigator.js b/src/libs/Navigation/AppNavigator/Navigators/RightModalNavigator.js index 5f24ec159828..822a1c6ead55 100644 --- a/src/libs/Navigation/AppNavigator/Navigators/RightModalNavigator.js +++ b/src/libs/Navigation/AppNavigator/Navigators/RightModalNavigator.js @@ -1,6 +1,6 @@ import React from 'react'; import {View} from 'react-native'; -import {createStackNavigator} from '@react-navigation/stack'; +import * as PlatformStackNavigator from '../../PlatformStackNavigator'; import * as ModalStackNavigators from '../ModalStackNavigators'; import RHPScreenOptions from '../RHPScreenOptions'; @@ -10,7 +10,7 @@ import styles from '../../../../styles/styles'; import Overlay from './Overlay'; import NoDropZone from '../../../../components/DragAndDrop/NoDropZone'; -const Stack = createStackNavigator(); +const Stack = PlatformStackNavigator.createPlatformStackNavigator(); const propTypes = { ...withNavigationPropTypes, diff --git a/src/libs/Navigation/AppNavigator/PublicScreens.js b/src/libs/Navigation/AppNavigator/PublicScreens.js index 7b0afb787278..6a2ad51cab6b 100644 --- a/src/libs/Navigation/AppNavigator/PublicScreens.js +++ b/src/libs/Navigation/AppNavigator/PublicScreens.js @@ -1,5 +1,5 @@ import React from 'react'; -import {createStackNavigator} from '@react-navigation/stack'; +import * as PlatformStackNavigator from '../PlatformStackNavigator'; import SignInPage from '../../../pages/signin/SignInPage'; import ValidateLoginPage from '../../../pages/ValidateLoginPage'; import LogInWithShortLivedAuthTokenPage from '../../../pages/LogInWithShortLivedAuthTokenPage'; @@ -10,7 +10,7 @@ import AppleSignInDesktopPage from '../../../pages/signin/AppleSignInDesktopPage import GoogleSignInDesktopPage from '../../../pages/signin/GoogleSignInDesktopPage'; import SAMLSignInPage from '../../../pages/signin/SAMLSignInPage'; -const RootStack = createStackNavigator(); +const RootStack = PlatformStackNavigator.createPlatformStackNavigator(); function PublicScreens() { return ( diff --git a/src/libs/Navigation/AppNavigator/createCustomStackNavigator/index.js b/src/libs/Navigation/AppNavigator/createCustomStackNavigator/index.js index 58be3d2af3da..5b9679426a4f 100644 --- a/src/libs/Navigation/AppNavigator/createCustomStackNavigator/index.js +++ b/src/libs/Navigation/AppNavigator/createCustomStackNavigator/index.js @@ -1,7 +1,7 @@ import React, {useRef} from 'react'; import PropTypes from 'prop-types'; import {useNavigationBuilder, createNavigatorFactory} from '@react-navigation/native'; -import {StackView} from '@react-navigation/stack'; +import * as PlatformStackNavigator from '../../PlatformStackNavigator'; import CustomRouter from './CustomRouter'; import useWindowDimensions from '../../../../hooks/useWindowDimensions'; @@ -42,7 +42,7 @@ function ResponsiveStackNavigator(props) { return ( - Date: Thu, 19 Oct 2023 15:22:14 +0200 Subject: [PATCH 03/56] create separate functions --- src/libs/Navigation/AppNavigator/ModalStackNavigators.js | 4 ++-- .../AppNavigator/Navigators/CentralPaneNavigator.js | 4 ++-- .../AppNavigator/Navigators/RightModalNavigator.js | 4 ++-- src/libs/Navigation/AppNavigator/PublicScreens.js | 4 ++-- .../AppNavigator/createCustomStackNavigator/index.js | 4 ++-- .../Navigation/PlatformStackNavigation/StackView.native.ts | 3 +++ src/libs/Navigation/PlatformStackNavigation/StackView.ts | 3 +++ .../createPlatformStackNavigator.native.ts | 7 +++++++ .../createPlatformStackNavigator.ts | 7 +++++++ src/libs/Navigation/PlatformStackNavigator/index.native.ts | 7 ------- src/libs/Navigation/PlatformStackNavigator/index.ts | 7 ------- 11 files changed, 30 insertions(+), 24 deletions(-) create mode 100644 src/libs/Navigation/PlatformStackNavigation/StackView.native.ts create mode 100644 src/libs/Navigation/PlatformStackNavigation/StackView.ts create mode 100644 src/libs/Navigation/PlatformStackNavigation/createPlatformStackNavigator.native.ts create mode 100644 src/libs/Navigation/PlatformStackNavigation/createPlatformStackNavigator.ts delete mode 100644 src/libs/Navigation/PlatformStackNavigator/index.native.ts delete mode 100644 src/libs/Navigation/PlatformStackNavigator/index.ts diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators.js b/src/libs/Navigation/AppNavigator/ModalStackNavigators.js index 2e5950e1b094..985aacc9da96 100644 --- a/src/libs/Navigation/AppNavigator/ModalStackNavigators.js +++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators.js @@ -1,7 +1,7 @@ import _ from 'underscore'; import React from 'react'; import {CardStyleInterpolators} from '@react-navigation/stack'; -import * as PlatformStackNavigator from '../PlatformStackNavigator'; +import createPlatformStackNavigator from '../PlatformStackNavigation/createPlatformStackNavigator'; import styles from '../../../styles/styles'; import SCREENS from '../../../SCREENS'; @@ -20,7 +20,7 @@ const defaultSubRouteOptions = { * @returns {Function} */ function createModalStackNavigator(screens) { - const ModalStackNavigator = PlatformStackNavigator.createPlatformStackNavigator(); + const ModalStackNavigator = createPlatformStackNavigator(); return () => ( {_.map(screens, (getComponent, name) => ( diff --git a/src/libs/Navigation/AppNavigator/Navigators/CentralPaneNavigator.js b/src/libs/Navigation/AppNavigator/Navigators/CentralPaneNavigator.js index b5fa76a48b90..754a25694785 100644 --- a/src/libs/Navigation/AppNavigator/Navigators/CentralPaneNavigator.js +++ b/src/libs/Navigation/AppNavigator/Navigators/CentralPaneNavigator.js @@ -1,12 +1,12 @@ import React from 'react'; -import * as PlatformStackNavigator from '../../PlatformStackNavigator'; +import createPlatformStackNavigator from '../../PlatformStackNavigation/createPlatformStackNavigator'; import SCREENS from '../../../../SCREENS'; import ReportScreenWrapper from '../ReportScreenWrapper'; import getCurrentUrl from '../../currentUrl'; import styles from '../../../../styles/styles'; import FreezeWrapper from '../../FreezeWrapper'; -const Stack = PlatformStackNavigator.createPlatformStackNavigator(); +const Stack = createPlatformStackNavigator(); const url = getCurrentUrl(); const openOnAdminRoom = url ? new URL(url).searchParams.get('openOnAdminRoom') : undefined; diff --git a/src/libs/Navigation/AppNavigator/Navigators/RightModalNavigator.js b/src/libs/Navigation/AppNavigator/Navigators/RightModalNavigator.js index 822a1c6ead55..2086490c597f 100644 --- a/src/libs/Navigation/AppNavigator/Navigators/RightModalNavigator.js +++ b/src/libs/Navigation/AppNavigator/Navigators/RightModalNavigator.js @@ -1,6 +1,6 @@ import React from 'react'; import {View} from 'react-native'; -import * as PlatformStackNavigator from '../../PlatformStackNavigator'; +import createPlatformStackNavigator from '../../PlatformStackNavigation/createPlatformStackNavigator'; import * as ModalStackNavigators from '../ModalStackNavigators'; import RHPScreenOptions from '../RHPScreenOptions'; @@ -10,7 +10,7 @@ import styles from '../../../../styles/styles'; import Overlay from './Overlay'; import NoDropZone from '../../../../components/DragAndDrop/NoDropZone'; -const Stack = PlatformStackNavigator.createPlatformStackNavigator(); +const Stack = createPlatformStackNavigator(); const propTypes = { ...withNavigationPropTypes, diff --git a/src/libs/Navigation/AppNavigator/PublicScreens.js b/src/libs/Navigation/AppNavigator/PublicScreens.js index 6a2ad51cab6b..720784f97ec1 100644 --- a/src/libs/Navigation/AppNavigator/PublicScreens.js +++ b/src/libs/Navigation/AppNavigator/PublicScreens.js @@ -1,5 +1,5 @@ import React from 'react'; -import * as PlatformStackNavigator from '../PlatformStackNavigator'; +import createPlatformStackNavigator from '../PlatformStackNavigation/createPlatformStackNavigator'; import SignInPage from '../../../pages/signin/SignInPage'; import ValidateLoginPage from '../../../pages/ValidateLoginPage'; import LogInWithShortLivedAuthTokenPage from '../../../pages/LogInWithShortLivedAuthTokenPage'; @@ -10,7 +10,7 @@ import AppleSignInDesktopPage from '../../../pages/signin/AppleSignInDesktopPage import GoogleSignInDesktopPage from '../../../pages/signin/GoogleSignInDesktopPage'; import SAMLSignInPage from '../../../pages/signin/SAMLSignInPage'; -const RootStack = PlatformStackNavigator.createPlatformStackNavigator(); +const RootStack = createPlatformStackNavigator(); function PublicScreens() { return ( diff --git a/src/libs/Navigation/AppNavigator/createCustomStackNavigator/index.js b/src/libs/Navigation/AppNavigator/createCustomStackNavigator/index.js index 5b9679426a4f..60894018ffd3 100644 --- a/src/libs/Navigation/AppNavigator/createCustomStackNavigator/index.js +++ b/src/libs/Navigation/AppNavigator/createCustomStackNavigator/index.js @@ -1,7 +1,7 @@ import React, {useRef} from 'react'; import PropTypes from 'prop-types'; import {useNavigationBuilder, createNavigatorFactory} from '@react-navigation/native'; -import * as PlatformStackNavigator from '../../PlatformStackNavigator'; +import StackView from '../../PlatformStackNavigation/StackView'; import CustomRouter from './CustomRouter'; import useWindowDimensions from '../../../../hooks/useWindowDimensions'; @@ -42,7 +42,7 @@ function ResponsiveStackNavigator(props) { return ( - Date: Thu, 19 Oct 2023 17:06:52 +0200 Subject: [PATCH 04/56] fix right modal options --- .../defaultScreenOptions/index.native.ts | 10 +++++++++ .../index.ts} | 0 .../index.native.ts | 7 +++++++ .../getRightModalNavigatorOptions/index.ts | 21 +++++++++++++++++++ .../getRootNavigatorScreenOptions.js | 15 ++----------- .../getNavigationModalCardStyles/types.ts | 4 +--- 6 files changed, 41 insertions(+), 16 deletions(-) create mode 100644 src/libs/Navigation/AppNavigator/defaultScreenOptions/index.native.ts rename src/libs/Navigation/AppNavigator/{defaultScreenOptions.js => defaultScreenOptions/index.ts} (100%) create mode 100644 src/libs/Navigation/AppNavigator/getRightModalNavigatorOptions/index.native.ts create mode 100644 src/libs/Navigation/AppNavigator/getRightModalNavigatorOptions/index.ts diff --git a/src/libs/Navigation/AppNavigator/defaultScreenOptions/index.native.ts b/src/libs/Navigation/AppNavigator/defaultScreenOptions/index.native.ts new file mode 100644 index 000000000000..12ba580c41d8 --- /dev/null +++ b/src/libs/Navigation/AppNavigator/defaultScreenOptions/index.native.ts @@ -0,0 +1,10 @@ +const defaultScreenOptions = { + contentStyle: { + overflow: 'visible', + flex: 1, + }, + headerShown: false, + animationTypeForReplace: 'push', +}; + +export default defaultScreenOptions; diff --git a/src/libs/Navigation/AppNavigator/defaultScreenOptions.js b/src/libs/Navigation/AppNavigator/defaultScreenOptions/index.ts similarity index 100% rename from src/libs/Navigation/AppNavigator/defaultScreenOptions.js rename to src/libs/Navigation/AppNavigator/defaultScreenOptions/index.ts diff --git a/src/libs/Navigation/AppNavigator/getRightModalNavigatorOptions/index.native.ts b/src/libs/Navigation/AppNavigator/getRightModalNavigatorOptions/index.native.ts new file mode 100644 index 000000000000..35d4605a2e5c --- /dev/null +++ b/src/libs/Navigation/AppNavigator/getRightModalNavigatorOptions/index.native.ts @@ -0,0 +1,7 @@ +import {NativeStackNavigationOptions} from '@react-navigation/native-stack'; + +const rightModalNavigatorOptions = (): NativeStackNavigationOptions => ({ + presentation: 'card', +}); + +export default rightModalNavigatorOptions; diff --git a/src/libs/Navigation/AppNavigator/getRightModalNavigatorOptions/index.ts b/src/libs/Navigation/AppNavigator/getRightModalNavigatorOptions/index.ts new file mode 100644 index 000000000000..ccab8ecd9fa5 --- /dev/null +++ b/src/libs/Navigation/AppNavigator/getRightModalNavigatorOptions/index.ts @@ -0,0 +1,21 @@ +import {StackNavigationOptions} from '@react-navigation/stack'; +import getNavigationModalCardStyle from '../../../../styles/getNavigationModalCardStyles'; +import modalCardStyleInterpolator from '../modalCardStyleInterpolator'; + +const rightModalNavigatorOptions = (isSmallScreenWidth: boolean): StackNavigationOptions => ({ + cardStyleInterpolator: (props) => modalCardStyleInterpolator(isSmallScreenWidth, false, props), + presentation: 'transparentModal', + + // We want pop in RHP since there are some flows that would work weird otherwise + animationTypeForReplace: 'pop', + cardStyle: { + ...getNavigationModalCardStyle(), + + // This is necessary to cover translated sidebar with overlay. + width: isSmallScreenWidth ? '100%' : '200%', + // Excess space should be on the left so we need to position from right. + right: 0, + }, +}); + +export default rightModalNavigatorOptions; diff --git a/src/libs/Navigation/AppNavigator/getRootNavigatorScreenOptions.js b/src/libs/Navigation/AppNavigator/getRootNavigatorScreenOptions.js index a7456fb071b4..ef879e269242 100644 --- a/src/libs/Navigation/AppNavigator/getRootNavigatorScreenOptions.js +++ b/src/libs/Navigation/AppNavigator/getRootNavigatorScreenOptions.js @@ -3,6 +3,7 @@ import styles from '../../../styles/styles'; import variables from '../../../styles/variables'; import getNavigationModalCardStyle from '../../../styles/getNavigationModalCardStyles'; import CONFIG from '../../../CONFIG'; +import getRightModalNavigatorOptions from './getRightModalNavigatorOptions'; const commonScreenOptions = { headerShown: false, @@ -15,19 +16,7 @@ const commonScreenOptions = { export default (isSmallScreenWidth) => ({ rightModalNavigator: { ...commonScreenOptions, - cardStyleInterpolator: (props) => modalCardStyleInterpolator(isSmallScreenWidth, false, props), - presentation: 'transparentModal', - - // We want pop in RHP since there are some flows that would work weird otherwise - animationTypeForReplace: 'pop', - cardStyle: { - ...getNavigationModalCardStyle(), - - // This is necessary to cover translated sidebar with overlay. - width: isSmallScreenWidth ? '100%' : '200%', - // Excess space should be on the left so we need to position from right. - right: 0, - }, + ...getRightModalNavigatorOptions(isSmallScreenWidth), }, homeScreen: { diff --git a/src/styles/getNavigationModalCardStyles/types.ts b/src/styles/getNavigationModalCardStyles/types.ts index 877981dd4dd2..e0dba07dc908 100644 --- a/src/styles/getNavigationModalCardStyles/types.ts +++ b/src/styles/getNavigationModalCardStyles/types.ts @@ -1,7 +1,5 @@ import {ViewStyle} from 'react-native'; -type GetNavigationModalCardStylesParams = {isSmallScreenWidth: number}; - -type GetNavigationModalCardStyles = (params: GetNavigationModalCardStylesParams) => ViewStyle; +type GetNavigationModalCardStyles = () => ViewStyle; export default GetNavigationModalCardStyles; From 27b2a131ccc8d7a9652adc127f67752f6911b447 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanno=20J=2E=20G=C3=B6decke?= Date: Thu, 19 Oct 2023 17:09:36 +0200 Subject: [PATCH 05/56] add note about card* property usage --- .../Navigation/AppNavigator/getRootNavigatorScreenOptions.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/libs/Navigation/AppNavigator/getRootNavigatorScreenOptions.js b/src/libs/Navigation/AppNavigator/getRootNavigatorScreenOptions.js index ef879e269242..578ed1881b97 100644 --- a/src/libs/Navigation/AppNavigator/getRootNavigatorScreenOptions.js +++ b/src/libs/Navigation/AppNavigator/getRootNavigatorScreenOptions.js @@ -22,8 +22,8 @@ export default (isSmallScreenWidth) => ({ homeScreen: { title: CONFIG.SITE_TITLE, ...commonScreenOptions, + // Note: The card* properties won't be applied on mobile platforms, as they use the native defaults. cardStyleInterpolator: (props) => modalCardStyleInterpolator(isSmallScreenWidth, false, props), - cardStyle: { ...getNavigationModalCardStyle(), width: isSmallScreenWidth ? '100%' : variables.sideBarWidth, @@ -36,6 +36,7 @@ export default (isSmallScreenWidth) => ({ // eslint-disable-next-line rulesdir/no-negated-variables fullScreen: { ...commonScreenOptions, + cardStyleInterpolator: (props) => modalCardStyleInterpolator(isSmallScreenWidth, true, props), cardStyle: { ...getNavigationModalCardStyle(), @@ -49,8 +50,8 @@ export default (isSmallScreenWidth) => ({ title: CONFIG.SITE_TITLE, ...commonScreenOptions, animationEnabled: isSmallScreenWidth, - cardStyleInterpolator: (props) => modalCardStyleInterpolator(isSmallScreenWidth, true, props), + cardStyleInterpolator: (props) => modalCardStyleInterpolator(isSmallScreenWidth, true, props), cardStyle: { ...getNavigationModalCardStyle(), paddingRight: isSmallScreenWidth ? 0 : variables.sideBarWidth, From 5e5deb49b113133448114eff68fb05c8547b822d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanno=20J=2E=20G=C3=B6decke?= Date: Thu, 19 Oct 2023 17:40:19 +0200 Subject: [PATCH 06/56] migrate defaultSubRouteOptions --- .../Navigation/AppNavigator/ModalStackNavigators.js | 11 +---------- .../modalStackNavigatorOptions/index.native.ts | 9 +++++++++ .../AppNavigator/modalStackNavigatorOptions/index.ts | 10 ++++++++++ 3 files changed, 20 insertions(+), 10 deletions(-) create mode 100644 src/libs/Navigation/AppNavigator/modalStackNavigatorOptions/index.native.ts create mode 100644 src/libs/Navigation/AppNavigator/modalStackNavigatorOptions/index.ts diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators.js b/src/libs/Navigation/AppNavigator/ModalStackNavigators.js index 985aacc9da96..7f5e8fbc3579 100644 --- a/src/libs/Navigation/AppNavigator/ModalStackNavigators.js +++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators.js @@ -1,17 +1,8 @@ import _ from 'underscore'; import React from 'react'; -import {CardStyleInterpolators} from '@react-navigation/stack'; import createPlatformStackNavigator from '../PlatformStackNavigation/createPlatformStackNavigator'; - -import styles from '../../../styles/styles'; import SCREENS from '../../../SCREENS'; - -// TODO: migrate options -const defaultSubRouteOptions = { - cardStyle: styles.navigationScreenCardStyle, - headerShown: false, - cardStyleInterpolator: CardStyleInterpolators.forHorizontalIOS, -}; +import defaultSubRouteOptions from './modalStackNavigatorOptions'; /** * Create a modal stack navigator with an array of sub-screens. diff --git a/src/libs/Navigation/AppNavigator/modalStackNavigatorOptions/index.native.ts b/src/libs/Navigation/AppNavigator/modalStackNavigatorOptions/index.native.ts new file mode 100644 index 000000000000..c54b1d653aca --- /dev/null +++ b/src/libs/Navigation/AppNavigator/modalStackNavigatorOptions/index.native.ts @@ -0,0 +1,9 @@ +import {NativeStackNavigationOptions} from '@react-navigation/native-stack'; +import styles from '../../../../styles/styles'; + +const defaultSubRouteOptions: NativeStackNavigationOptions = { + contentStyle: styles.navigationScreenCardStyle, + headerShown: false, +}; + +export default defaultSubRouteOptions; diff --git a/src/libs/Navigation/AppNavigator/modalStackNavigatorOptions/index.ts b/src/libs/Navigation/AppNavigator/modalStackNavigatorOptions/index.ts new file mode 100644 index 000000000000..ea241e6f441b --- /dev/null +++ b/src/libs/Navigation/AppNavigator/modalStackNavigatorOptions/index.ts @@ -0,0 +1,10 @@ +import {CardStyleInterpolators, StackNavigationOptions} from '@react-navigation/stack'; +import styles from '../../../../styles/styles'; + +const defaultSubRouteOptions: StackNavigationOptions = { + cardStyle: styles.navigationScreenCardStyle, + headerShown: false, + cardStyleInterpolator: CardStyleInterpolators.forHorizontalIOS, +}; + +export default defaultSubRouteOptions; From 6e49ccf73e6aa9907a24debc676696bdb9c83c1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanno=20J=2E=20G=C3=B6decke?= Date: Fri, 20 Oct 2023 08:08:20 +0200 Subject: [PATCH 07/56] change default animation for android --- .../Navigation/AppNavigator/defaultScreenOptions/index.native.ts | 1 + .../AppNavigator/getRightModalNavigatorOptions/index.native.ts | 1 + .../Navigation/AppNavigator/getRootNavigatorScreenOptions.js | 1 + .../AppNavigator/modalStackNavigatorOptions/index.native.ts | 1 + 4 files changed, 4 insertions(+) diff --git a/src/libs/Navigation/AppNavigator/defaultScreenOptions/index.native.ts b/src/libs/Navigation/AppNavigator/defaultScreenOptions/index.native.ts index 12ba580c41d8..17100bc71bda 100644 --- a/src/libs/Navigation/AppNavigator/defaultScreenOptions/index.native.ts +++ b/src/libs/Navigation/AppNavigator/defaultScreenOptions/index.native.ts @@ -5,6 +5,7 @@ const defaultScreenOptions = { }, headerShown: false, animationTypeForReplace: 'push', + animation: 'slide_from_right', }; export default defaultScreenOptions; diff --git a/src/libs/Navigation/AppNavigator/getRightModalNavigatorOptions/index.native.ts b/src/libs/Navigation/AppNavigator/getRightModalNavigatorOptions/index.native.ts index 35d4605a2e5c..9c0d1fe3abff 100644 --- a/src/libs/Navigation/AppNavigator/getRightModalNavigatorOptions/index.native.ts +++ b/src/libs/Navigation/AppNavigator/getRightModalNavigatorOptions/index.native.ts @@ -2,6 +2,7 @@ import {NativeStackNavigationOptions} from '@react-navigation/native-stack'; const rightModalNavigatorOptions = (): NativeStackNavigationOptions => ({ presentation: 'card', + animation: 'slide_from_right', }); export default rightModalNavigatorOptions; diff --git a/src/libs/Navigation/AppNavigator/getRootNavigatorScreenOptions.js b/src/libs/Navigation/AppNavigator/getRootNavigatorScreenOptions.js index 578ed1881b97..9d485f239fe6 100644 --- a/src/libs/Navigation/AppNavigator/getRootNavigatorScreenOptions.js +++ b/src/libs/Navigation/AppNavigator/getRootNavigatorScreenOptions.js @@ -11,6 +11,7 @@ const commonScreenOptions = { animationEnabled: true, cardOverlayEnabled: true, animationTypeForReplace: 'push', + animation: 'slide_from_right', }; export default (isSmallScreenWidth) => ({ diff --git a/src/libs/Navigation/AppNavigator/modalStackNavigatorOptions/index.native.ts b/src/libs/Navigation/AppNavigator/modalStackNavigatorOptions/index.native.ts index c54b1d653aca..96ee4c4b26d2 100644 --- a/src/libs/Navigation/AppNavigator/modalStackNavigatorOptions/index.native.ts +++ b/src/libs/Navigation/AppNavigator/modalStackNavigatorOptions/index.native.ts @@ -4,6 +4,7 @@ import styles from '../../../../styles/styles'; const defaultSubRouteOptions: NativeStackNavigationOptions = { contentStyle: styles.navigationScreenCardStyle, headerShown: false, + animation: 'slide_from_right', }; export default defaultSubRouteOptions; From 08c6181183ac2f092e739985a75fed309d8b65c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanno=20J=2E=20G=C3=B6decke?= Date: Fri, 20 Oct 2023 08:59:45 +0200 Subject: [PATCH 08/56] migrate overlay --- .../Navigators/{Overlay.js => Overlay/index.js} | 9 ++++----- .../AppNavigator/Navigators/Overlay/index.native.js | 7 +++++++ 2 files changed, 11 insertions(+), 5 deletions(-) rename src/libs/Navigation/AppNavigator/Navigators/{Overlay.js => Overlay/index.js} (86%) create mode 100644 src/libs/Navigation/AppNavigator/Navigators/Overlay/index.native.js diff --git a/src/libs/Navigation/AppNavigator/Navigators/Overlay.js b/src/libs/Navigation/AppNavigator/Navigators/Overlay/index.js similarity index 86% rename from src/libs/Navigation/AppNavigator/Navigators/Overlay.js rename to src/libs/Navigation/AppNavigator/Navigators/Overlay/index.js index ed3c27aed673..ad35484d21d8 100644 --- a/src/libs/Navigation/AppNavigator/Navigators/Overlay.js +++ b/src/libs/Navigation/AppNavigator/Navigators/Overlay/index.js @@ -1,14 +1,13 @@ import React from 'react'; import {Animated, View} from 'react-native'; -// TODO: migrate import {useCardAnimation} from '@react-navigation/stack'; import PropTypes from 'prop-types'; -import styles from '../../../../styles/styles'; +import styles from '../../../../../styles/styles'; -import PressableWithoutFeedback from '../../../../components/Pressable/PressableWithoutFeedback'; -import useLocalize from '../../../../hooks/useLocalize'; -import CONST from '../../../../CONST'; +import PressableWithoutFeedback from '../../../../../components/Pressable/PressableWithoutFeedback'; +import useLocalize from '../../../../../hooks/useLocalize'; +import CONST from '../../../../../CONST'; const propTypes = { /* Callback to close the modal */ diff --git a/src/libs/Navigation/AppNavigator/Navigators/Overlay/index.native.js b/src/libs/Navigation/AppNavigator/Navigators/Overlay/index.native.js new file mode 100644 index 000000000000..30651e32cbd6 --- /dev/null +++ b/src/libs/Navigation/AppNavigator/Navigators/Overlay/index.native.js @@ -0,0 +1,7 @@ +function Overlay() { + return null; +} + +Overlay.displayName = 'Overlay'; + +export default Overlay; From d0e147ea8351a7c351fcee1e22ee5dada4115a70 Mon Sep 17 00:00:00 2001 From: kirillzyusko Date: Fri, 26 Jan 2024 18:48:58 +0100 Subject: [PATCH 09/56] chore: bump to latest version --- package-lock.json | 73 +++++++++++++++++------------------------------ package.json | 2 +- 2 files changed, 27 insertions(+), 48 deletions(-) diff --git a/package-lock.json b/package-lock.json index 0f143bd33809..743f9b0df73c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -36,7 +36,7 @@ "@react-native-picker/picker": "2.5.1", "@react-navigation/material-top-tabs": "^6.6.3", "@react-navigation/native": "6.1.8", - "@react-navigation/native-stack": "^6.9.14", + "@react-navigation/native-stack": "^6.9.17", "@react-navigation/stack": "6.3.16", "@react-ng/bounds-observer": "^0.2.1", "@rnmapbox/maps": "^10.0.11", @@ -10045,6 +10045,17 @@ "react": "*" } }, + "node_modules/@react-navigation/elements": { + "version": "1.3.21", + "resolved": "https://registry.npmjs.org/@react-navigation/elements/-/elements-1.3.21.tgz", + "integrity": "sha512-eyS2C6McNR8ihUoYfc166O1D8VYVh9KIl0UQPI8/ZJVsStlfSTgeEEh+WXge6+7SFPnZ4ewzEJdSAHH+jzcEfg==", + "peerDependencies": { + "@react-navigation/native": "^6.0.0", + "react": "*", + "react-native": "*", + "react-native-safe-area-context": ">= 3.0.0" + } + }, "node_modules/@react-navigation/material-top-tabs": { "version": "6.6.3", "resolved": "https://registry.npmjs.org/@react-navigation/material-top-tabs/-/material-top-tabs-6.6.3.tgz", @@ -10077,11 +10088,11 @@ } }, "node_modules/@react-navigation/native-stack": { - "version": "6.9.14", - "resolved": "https://registry.npmjs.org/@react-navigation/native-stack/-/native-stack-6.9.14.tgz", - "integrity": "sha512-7RiZkvMFN6f0kmANc63B/0m9ttQ2JpDIPWQwPU93FP698s19KTOyu7uxgl7Oi3bvsqHFO5JfiR7B+4h8lh9dxw==", + "version": "6.9.17", + "resolved": "https://registry.npmjs.org/@react-navigation/native-stack/-/native-stack-6.9.17.tgz", + "integrity": "sha512-X8p8aS7JptQq7uZZNFEvfEcPf6tlK4PyVwYDdryRbG98B4bh2wFQYMThxvqa+FGEN7USEuHdv2mF0GhFKfX0ew==", "dependencies": { - "@react-navigation/elements": "^1.3.19", + "@react-navigation/elements": "^1.3.21", "warn-once": "^0.1.0" }, "peerDependencies": { @@ -10092,17 +10103,6 @@ "react-native-screens": ">= 3.0.0" } }, - "node_modules/@react-navigation/native-stack/node_modules/@react-navigation/elements": { - "version": "1.3.19", - "resolved": "https://registry.npmjs.org/@react-navigation/elements/-/elements-1.3.19.tgz", - "integrity": "sha512-7hLvSYKPuDS070pza5gd43WDX7QgfuEmuTWNbCJhKdWlLudYmq3qzxGCBwCfO2dEI6+p8tla5wruaWiGKAbTYw==", - "peerDependencies": { - "@react-navigation/native": "^6.0.0", - "react": "*", - "react-native": "*", - "react-native-safe-area-context": ">= 3.0.0" - } - }, "node_modules/@react-navigation/routers": { "version": "6.1.9", "resolved": "https://registry.npmjs.org/@react-navigation/routers/-/routers-6.1.9.tgz", @@ -10129,17 +10129,6 @@ "react-native-screens": ">= 3.0.0" } }, - "node_modules/@react-navigation/stack/node_modules/@react-navigation/elements": { - "version": "1.3.17", - "resolved": "https://registry.npmjs.org/@react-navigation/elements/-/elements-1.3.17.tgz", - "integrity": "sha512-sui8AzHm6TxeEvWT/NEXlz3egYvCUog4tlXA4Xlb2Vxvy3purVXDq/XsM56lJl344U5Aj/jDzkVanOTMWyk4UA==", - "peerDependencies": { - "@react-navigation/native": "^6.0.0", - "react": "*", - "react-native": "*", - "react-native-safe-area-context": ">= 3.0.0" - } - }, "node_modules/@react-ng/bounds-observer": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/@react-ng/bounds-observer/-/bounds-observer-0.2.1.tgz", @@ -60659,6 +60648,12 @@ "stacktrace-parser": "^0.1.10" } }, + "@react-navigation/elements": { + "version": "1.3.21", + "resolved": "https://registry.npmjs.org/@react-navigation/elements/-/elements-1.3.21.tgz", + "integrity": "sha512-eyS2C6McNR8ihUoYfc166O1D8VYVh9KIl0UQPI8/ZJVsStlfSTgeEEh+WXge6+7SFPnZ4ewzEJdSAHH+jzcEfg==", + "requires": {} + }, "@react-navigation/material-top-tabs": { "version": "6.6.3", "resolved": "https://registry.npmjs.org/@react-navigation/material-top-tabs/-/material-top-tabs-6.6.3.tgz", @@ -60680,20 +60675,12 @@ } }, "@react-navigation/native-stack": { - "version": "6.9.14", - "resolved": "https://registry.npmjs.org/@react-navigation/native-stack/-/native-stack-6.9.14.tgz", - "integrity": "sha512-7RiZkvMFN6f0kmANc63B/0m9ttQ2JpDIPWQwPU93FP698s19KTOyu7uxgl7Oi3bvsqHFO5JfiR7B+4h8lh9dxw==", + "version": "6.9.17", + "resolved": "https://registry.npmjs.org/@react-navigation/native-stack/-/native-stack-6.9.17.tgz", + "integrity": "sha512-X8p8aS7JptQq7uZZNFEvfEcPf6tlK4PyVwYDdryRbG98B4bh2wFQYMThxvqa+FGEN7USEuHdv2mF0GhFKfX0ew==", "requires": { - "@react-navigation/elements": "^1.3.19", + "@react-navigation/elements": "^1.3.21", "warn-once": "^0.1.0" - }, - "dependencies": { - "@react-navigation/elements": { - "version": "1.3.19", - "resolved": "https://registry.npmjs.org/@react-navigation/elements/-/elements-1.3.19.tgz", - "integrity": "sha512-7hLvSYKPuDS070pza5gd43WDX7QgfuEmuTWNbCJhKdWlLudYmq3qzxGCBwCfO2dEI6+p8tla5wruaWiGKAbTYw==", - "requires": {} - } } }, "@react-navigation/routers": { @@ -60712,14 +60699,6 @@ "@react-navigation/elements": "^1.3.17", "color": "^4.2.3", "warn-once": "^0.1.0" - }, - "dependencies": { - "@react-navigation/elements": { - "version": "1.3.17", - "resolved": "https://registry.npmjs.org/@react-navigation/elements/-/elements-1.3.17.tgz", - "integrity": "sha512-sui8AzHm6TxeEvWT/NEXlz3egYvCUog4tlXA4Xlb2Vxvy3purVXDq/XsM56lJl344U5Aj/jDzkVanOTMWyk4UA==", - "requires": {} - } } }, "@react-ng/bounds-observer": { diff --git a/package.json b/package.json index 13a8e64a17a5..b55f6d936b7a 100644 --- a/package.json +++ b/package.json @@ -84,7 +84,7 @@ "@react-native-picker/picker": "2.5.1", "@react-navigation/material-top-tabs": "^6.6.3", "@react-navigation/native": "6.1.8", - "@react-navigation/native-stack": "^6.9.14", + "@react-navigation/native-stack": "^6.9.17", "@react-navigation/stack": "6.3.16", "@react-ng/bounds-observer": "^0.2.1", "@rnmapbox/maps": "^10.0.11", From 21a2dc29958ce70ccfc179f34d7861fc6588d560 Mon Sep 17 00:00:00 2001 From: kirillzyusko Date: Fri, 26 Jan 2024 19:13:37 +0100 Subject: [PATCH 10/56] chore: fixes after merge --- .../AppNavigator/Navigators/RightModalNavigator.tsx | 1 - .../AppNavigator/modalStackNavigatorOptions/index.native.ts | 4 +--- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/src/libs/Navigation/AppNavigator/Navigators/RightModalNavigator.tsx b/src/libs/Navigation/AppNavigator/Navigators/RightModalNavigator.tsx index c875399c15d9..a468d5f3a114 100644 --- a/src/libs/Navigation/AppNavigator/Navigators/RightModalNavigator.tsx +++ b/src/libs/Navigation/AppNavigator/Navigators/RightModalNavigator.tsx @@ -11,7 +11,6 @@ import type {AuthScreensParamList, RightModalNavigatorParamList} from '@navigati import type NAVIGATORS from '@src/NAVIGATORS'; import SCREENS from '@src/SCREENS'; import createPlatformStackNavigator from '@libs/Navigation/PlatformStackNavigation/createPlatformStackNavigator'; -import * as ModalStackNavigators from '@libs/Navigation/AppNavigator/ModalStackNavigators'; import Overlay from './Overlay'; type RightModalNavigatorProps = StackScreenProps; diff --git a/src/libs/Navigation/AppNavigator/modalStackNavigatorOptions/index.native.ts b/src/libs/Navigation/AppNavigator/modalStackNavigatorOptions/index.native.ts index 96ee4c4b26d2..ca9769fa9972 100644 --- a/src/libs/Navigation/AppNavigator/modalStackNavigatorOptions/index.native.ts +++ b/src/libs/Navigation/AppNavigator/modalStackNavigatorOptions/index.native.ts @@ -1,8 +1,6 @@ -import {NativeStackNavigationOptions} from '@react-navigation/native-stack'; -import styles from '../../../../styles/styles'; +import type {NativeStackNavigationOptions} from '@react-navigation/native-stack'; const defaultSubRouteOptions: NativeStackNavigationOptions = { - contentStyle: styles.navigationScreenCardStyle, headerShown: false, animation: 'slide_from_right', }; From 50a5c8140b62d85933159c0bb259fbf4e69f5626 Mon Sep 17 00:00:00 2001 From: kirillzyusko Date: Mon, 29 Jan 2024 19:33:13 +0100 Subject: [PATCH 11/56] fix: issue#1 with keyboard flickering --- ...react-navigation+native-stack+6.9.17.patch | 37 +++++++++++++++++++ .../getRootNavigatorScreenOptions.ts | 4 +- 2 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 patches/@react-navigation+native-stack+6.9.17.patch diff --git a/patches/@react-navigation+native-stack+6.9.17.patch b/patches/@react-navigation+native-stack+6.9.17.patch new file mode 100644 index 000000000000..8bfd619223b4 --- /dev/null +++ b/patches/@react-navigation+native-stack+6.9.17.patch @@ -0,0 +1,37 @@ +diff --git a/node_modules/@react-navigation/native-stack/src/types.tsx b/node_modules/@react-navigation/native-stack/src/types.tsx +index 206fb0b..7104b93 100644 +--- a/node_modules/@react-navigation/native-stack/src/types.tsx ++++ b/node_modules/@react-navigation/native-stack/src/types.tsx +@@ -490,6 +490,12 @@ export type NativeStackNavigationOptions = { + * Only supported on iOS and Android. + */ + freezeOnBlur?: boolean; ++ /** ++ * Whether the keyboard should hide when swiping to the previous screen. Defaults to `false`. ++ * ++ * Only supported on iOS ++ */ ++ hideKeyboardOnSwipe?: boolean; + }; + + export type NativeStackNavigatorProps = DefaultNavigatorOptions< +diff --git a/node_modules/@react-navigation/native-stack/src/views/NativeStackView.native.tsx b/node_modules/@react-navigation/native-stack/src/views/NativeStackView.native.tsx +index a005c43..dc22c63 100644 +--- a/node_modules/@react-navigation/native-stack/src/views/NativeStackView.native.tsx ++++ b/node_modules/@react-navigation/native-stack/src/views/NativeStackView.native.tsx +@@ -161,6 +161,7 @@ const SceneView = ({ + statusBarTranslucent, + statusBarColor, + freezeOnBlur, ++ hideKeyboardOnSwipe, + } = options; + + let { +@@ -289,6 +290,7 @@ const SceneView = ({ + onNativeDismissCancelled={onNativeDismissCancelled} + // this prop is available since rn-screens 3.16 + freezeOnBlur={freezeOnBlur} ++ hideKeyboardOnSwipe={hideKeyboardOnSwipe} + > + + diff --git a/src/libs/Navigation/AppNavigator/getRootNavigatorScreenOptions.ts b/src/libs/Navigation/AppNavigator/getRootNavigatorScreenOptions.ts index 02540f83063d..9eb16e3b2658 100644 --- a/src/libs/Navigation/AppNavigator/getRootNavigatorScreenOptions.ts +++ b/src/libs/Navigation/AppNavigator/getRootNavigatorScreenOptions.ts @@ -79,7 +79,9 @@ const getRootNavigatorScreenOptions: GetRootNavigatorScreenOptions = (isSmallScr ...commonScreenOptions, animationEnabled: isSmallScreenWidth, cardStyleInterpolator: (props: StackCardInterpolationProps) => modalCardStyleInterpolator(isSmallScreenWidth, true, props), - + // temporary solution - better to hide a keyboard than see keyboard flickering + // see https://github.com/software-mansion/react-native-screens/issues/2021 for more details + hideKeyboardOnSwipe: true, cardStyle: { ...StyleUtils.getNavigationModalCardStyle(), paddingRight: isSmallScreenWidth ? 0 : variables.sideBarWidth, From e47f246fe44d188a2238dd8e295707e2404bbe78 Mon Sep 17 00:00:00 2001 From: Julian Kobrynski Date: Tue, 30 Jan 2024 15:11:59 +0100 Subject: [PATCH 12/56] migrate BaseValidateCodeForm to TypeScript --- src/components/MagicCodeInput.tsx | 1 + src/components/withToggleVisibilityView.tsx | 6 +- src/pages/signin/ChangeExpensifyLoginLink.js | 62 ----- src/pages/signin/ChangeExpensifyLoginLink.tsx | 45 ++++ ...teCodeForm.js => BaseValidateCodeForm.tsx} | 251 ++++++++---------- 5 files changed, 159 insertions(+), 206 deletions(-) delete mode 100755 src/pages/signin/ChangeExpensifyLoginLink.js create mode 100755 src/pages/signin/ChangeExpensifyLoginLink.tsx rename src/pages/signin/ValidateCodeForm/{BaseValidateCodeForm.js => BaseValidateCodeForm.tsx} (58%) diff --git a/src/components/MagicCodeInput.tsx b/src/components/MagicCodeInput.tsx index 4a6d87b48e38..67b2756b72d8 100644 --- a/src/components/MagicCodeInput.tsx +++ b/src/components/MagicCodeInput.tsx @@ -428,3 +428,4 @@ function MagicCodeInput( MagicCodeInput.displayName = 'MagicCodeInput'; export default forwardRef(MagicCodeInput); +export type {MagicCodeInputHandle}; diff --git a/src/components/withToggleVisibilityView.tsx b/src/components/withToggleVisibilityView.tsx index 86513f1bd0dc..9da862ecdebe 100644 --- a/src/components/withToggleVisibilityView.tsx +++ b/src/components/withToggleVisibilityView.tsx @@ -5,12 +5,12 @@ import type {SetOptional} from 'type-fest'; import useThemeStyles from '@hooks/useThemeStyles'; import getComponentDisplayName from '@libs/getComponentDisplayName'; -type ToggleVisibilityViewProps = { +type WithToggleVisibilityViewProps = { /** Whether the content is visible. */ isVisible: boolean; }; -export default function withToggleVisibilityView( +export default function withToggleVisibilityView( WrappedComponent: ComponentType>, ): (props: TProps & RefAttributes) => ReactElement | null { function WithToggleVisibilityView({isVisible = false, ...rest}: SetOptional, ref: ForwardedRef) { @@ -30,3 +30,5 @@ export default function withToggleVisibilityView - {!_.isEmpty(props.credentials.login) && {props.translate('loginForm.notYou', {user: props.formatPhoneNumber(props.credentials.login)})}} - - - {props.translate('common.goBack')} - {'.'} - - - - ); -} - -ChangeExpensifyLoginLink.propTypes = propTypes; -ChangeExpensifyLoginLink.defaultProps = defaultProps; -ChangeExpensifyLoginLink.displayName = 'ChangeExpensifyLoginLink'; - -export default compose( - withLocalize, - withOnyx({ - credentials: {key: ONYXKEYS.CREDENTIALS}, - }), -)(ChangeExpensifyLoginLink); diff --git a/src/pages/signin/ChangeExpensifyLoginLink.tsx b/src/pages/signin/ChangeExpensifyLoginLink.tsx new file mode 100755 index 000000000000..d5e8e21b2f4c --- /dev/null +++ b/src/pages/signin/ChangeExpensifyLoginLink.tsx @@ -0,0 +1,45 @@ +import React from 'react'; +import {View} from 'react-native'; +import type {OnyxEntry} from 'react-native-onyx'; +import {withOnyx} from 'react-native-onyx'; +import PressableWithFeedback from '@components/Pressable/PressableWithFeedback'; +import Text from '@components/Text'; +import useLocalize from '@hooks/useLocalize'; +import useThemeStyles from '@hooks/useThemeStyles'; +import CONST from '@src/CONST'; +import ONYXKEYS from '@src/ONYXKEYS'; +import type {Credentials} from '@src/types/onyx'; +import {isEmptyObject} from '@src/types/utils/EmptyObject'; + +type ChangeExpensifyLoginLinkOnyxProps = { + /** The credentials of the person logging in */ + credentials: OnyxEntry; +}; + +type ChangeExpensifyLoginLinkProps = ChangeExpensifyLoginLinkOnyxProps & { + onPress: () => void; +}; + +function ChangeExpensifyLoginLink({credentials, onPress}: ChangeExpensifyLoginLinkProps) { + const styles = useThemeStyles(); + const {translate, formatPhoneNumber} = useLocalize(); + return ( + + {!isEmptyObject(credentials?.login) && {translate('loginForm.notYou', {user: credentials?.login ? formatPhoneNumber(credentials.login) : ''})}} + + {translate('common.goBack')}. + + + ); +} + +ChangeExpensifyLoginLink.displayName = 'ChangeExpensifyLoginLink'; + +export default withOnyx({ + credentials: {key: ONYXKEYS.CREDENTIALS}, +})(ChangeExpensifyLoginLink); diff --git a/src/pages/signin/ValidateCodeForm/BaseValidateCodeForm.js b/src/pages/signin/ValidateCodeForm/BaseValidateCodeForm.tsx similarity index 58% rename from src/pages/signin/ValidateCodeForm/BaseValidateCodeForm.js rename to src/pages/signin/ValidateCodeForm/BaseValidateCodeForm.tsx index fd5e9b952612..c8331f3a3f46 100755 --- a/src/pages/signin/ValidateCodeForm/BaseValidateCodeForm.js +++ b/src/pages/signin/ValidateCodeForm/BaseValidateCodeForm.tsx @@ -1,140 +1,117 @@ import {useIsFocused} from '@react-navigation/native'; -import lodashGet from 'lodash/get'; -import PropTypes from 'prop-types'; import React, {useCallback, useEffect, useRef, useState} from 'react'; +import type {TextStyle} from 'react-native'; import {View} from 'react-native'; +import type {OnyxEntry} from 'react-native-onyx'; import {withOnyx} from 'react-native-onyx'; -import _ from 'underscore'; import Button from '@components/Button'; import FormHelpMessage from '@components/FormHelpMessage'; +import type {MagicCodeInputHandle} from '@components/MagicCodeInput'; import MagicCodeInput from '@components/MagicCodeInput'; -import networkPropTypes from '@components/networkPropTypes'; -import {withNetwork} from '@components/OnyxProvider'; import PressableWithFeedback from '@components/Pressable/PressableWithFeedback'; import Text from '@components/Text'; import TextInput from '@components/TextInput'; -import withLocalize, {withLocalizePropTypes} from '@components/withLocalize'; +import type {WithToggleVisibilityViewProps} from '@components/withToggleVisibilityView'; import withToggleVisibilityView from '@components/withToggleVisibilityView'; +import useLocalize from '@hooks/useLocalize'; +import useNetwork from '@hooks/useNetwork'; import usePrevious from '@hooks/usePrevious'; import useStyleUtils from '@hooks/useStyleUtils'; -import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; import canFocusInputOnScreenFocus from '@libs/canFocusInputOnScreenFocus'; -import compose from '@libs/compose'; import * as ErrorUtils from '@libs/ErrorUtils'; import * as ValidationUtils from '@libs/ValidationUtils'; import ChangeExpensifyLoginLink from '@pages/signin/ChangeExpensifyLoginLink'; import Terms from '@pages/signin/Terms'; -import * as Session from '@userActions/Session'; +import * as SessionActions from '@userActions/Session'; import * as User from '@userActions/User'; import CONST from '@src/CONST'; +import type {TranslationPaths} from '@src/languages/types'; import ONYXKEYS from '@src/ONYXKEYS'; +import type {Account, Credentials, Session} from '@src/types/onyx'; +import type {Errors} from '@src/types/onyx/OnyxCommon'; +import {isEmptyObject} from '@src/types/utils/EmptyObject'; -const propTypes = { - /* Onyx Props */ - +type BaseValidateCodeFormOnyxProps = { /** The details about the account that the user is signing in with */ - account: PropTypes.shape({ - /** Whether or not two-factor authentication is required */ - requiresTwoFactorAuth: PropTypes.bool, - - /** Whether or not a sign on form is loading (being submitted) */ - isLoading: PropTypes.bool, - - /** Whether or not the user has SAML enabled on their account */ - isSAMLEnabled: PropTypes.bool, - - /** Whether or not SAML is required on the account */ - isSAMLRequired: PropTypes.bool, - }), - - /** The credentials of the person signing in */ - credentials: PropTypes.shape({ - /** The login of the person signing in */ - login: PropTypes.string, - }), - - /** Session of currently logged in user */ - session: PropTypes.shape({ - /** Currently logged in user authToken */ - authToken: PropTypes.string, - }), + account: OnyxEntry; - /** Information about the network */ - network: networkPropTypes.isRequired, + /** The credentials of the person logging in */ + credentials: OnyxEntry; - /** Specifies autocomplete hints for the system, so it can provide autofill */ - autoComplete: PropTypes.oneOf(['sms-otp', 'one-time-code']).isRequired, + /** Session info for the currently logged in user. */ + session: OnyxEntry; +}; - /** Determines if user is switched to using recovery code instead of 2fa code */ - isUsingRecoveryCode: PropTypes.bool.isRequired, +type BaseValidateCodeFormProps = WithToggleVisibilityViewProps & + BaseValidateCodeFormOnyxProps & { + /** Specifies autocomplete hints for the system, so it can provide autofill */ + autoComplete: 'sms-otp' | 'one-time-code'; - /** Function to change `isUsingRecoveryCode` state when user toggles between 2fa code and recovery code */ - setIsUsingRecoveryCode: PropTypes.func.isRequired, + /** Determines if user is switched to using recovery code instead of 2fa code */ + isUsingRecoveryCode: boolean; - ...withLocalizePropTypes, -}; + /** Function to change `isUsingRecoveryCode` state when user toggles between 2fa code and recovery code */ + setIsUsingRecoveryCode: (isUsingRecoveryCode: boolean) => void; + }; -const defaultProps = { - account: {}, - credentials: {}, - session: { - authToken: null, - }, -}; +type ValidateCodeFormVariant = 'validateCode' | 'twoFactorAuthCode' | 'recoveryCode'; -function BaseValidateCodeForm(props) { - const theme = useTheme(); +function BaseValidateCodeForm({account, credentials, session, autoComplete, isUsingRecoveryCode, setIsUsingRecoveryCode, isVisible}: BaseValidateCodeFormProps) { const styles = useThemeStyles(); const StyleUtils = useStyleUtils(); + const {translate} = useLocalize(); const isFocused = useIsFocused(); - const [formError, setFormError] = useState({}); - const [validateCode, setValidateCode] = useState(props.credentials.validateCode || ''); + const {isOffline} = useNetwork(); + const [formError, setFormError] = useState>>({}); + const [validateCode, setValidateCode] = useState(credentials?.validateCode ?? ''); const [twoFactorAuthCode, setTwoFactorAuthCode] = useState(''); const [timeRemaining, setTimeRemaining] = useState(30); const [recoveryCode, setRecoveryCode] = useState(''); - const [needToClearError, setNeedToClearError] = useState(props.account.errors); + const [needToClearError, setNeedToClearError] = useState(account?.errors); - const prevRequiresTwoFactorAuth = usePrevious(props.account.requiresTwoFactorAuth); - const prevValidateCode = usePrevious(props.credentials.validateCode); + const prevRequiresTwoFactorAuth = usePrevious(account?.requiresTwoFactorAuth); + const prevValidateCode = usePrevious(credentials?.validateCode); - const inputValidateCodeRef = useRef(); - const input2FARef = useRef(); - const timerRef = useRef(); + const inputValidateCodeRef = useRef(); + const input2FARef = useRef(); + const timerRef = useRef(); - const hasError = Boolean(props.account) && !_.isEmpty(props.account.errors) && !needToClearError; - const isLoadingResendValidationForm = props.account.loadingForm === CONST.FORMS.RESEND_VALIDATE_CODE_FORM; - const shouldDisableResendValidateCode = props.network.isOffline || props.account.isLoading; + const hasError = Boolean(account) && !isEmptyObject(account?.errors) && !needToClearError; + const isLoadingResendValidationForm = account?.loadingForm === CONST.FORMS.RESEND_VALIDATE_CODE_FORM; + const shouldDisableResendValidateCode = isOffline ?? account?.isLoading; const isValidateCodeFormSubmitting = - props.account.isLoading && props.account.loadingForm === (props.account.requiresTwoFactorAuth ? CONST.FORMS.VALIDATE_TFA_CODE_FORM : CONST.FORMS.VALIDATE_CODE_FORM); + account?.isLoading && account?.loadingForm === (account?.requiresTwoFactorAuth ? CONST.FORMS.VALIDATE_TFA_CODE_FORM : CONST.FORMS.VALIDATE_CODE_FORM); useEffect(() => { - if (!(inputValidateCodeRef.current && hasError && (props.session.autoAuthState === CONST.AUTO_AUTH_STATE.FAILED || props.account.isLoading))) { + if (!(inputValidateCodeRef.current && hasError && (session?.autoAuthState === CONST.AUTO_AUTH_STATE.FAILED || account?.isLoading))) { return; } inputValidateCodeRef.current.blur(); - }, [props.account.isLoading, props.session.autoAuthState, hasError]); + }, [account?.isLoading, session?.autoAuthState, hasError]); useEffect(() => { - if (!inputValidateCodeRef.current || !canFocusInputOnScreenFocus() || !props.isVisible || !isFocused) { + if (!inputValidateCodeRef.current || !canFocusInputOnScreenFocus() || !isVisible || !isFocused) { return; } inputValidateCodeRef.current.focus(); - }, [props.isVisible, isFocused]); + }, [isVisible, isFocused]); useEffect(() => { - if (prevValidateCode || !props.credentials.validateCode) { + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing + if (prevValidateCode || !credentials?.validateCode) { return; } - setValidateCode(props.credentials.validateCode); - }, [props.credentials.validateCode, prevValidateCode]); + setValidateCode(credentials.validateCode); + }, [credentials?.validateCode, prevValidateCode]); useEffect(() => { - if (!input2FARef.current || prevRequiresTwoFactorAuth || !props.account.requiresTwoFactorAuth) { + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing + if (!input2FARef.current || prevRequiresTwoFactorAuth || !account?.requiresTwoFactorAuth) { return; } input2FARef.current.focus(); - }, [props.account.requiresTwoFactorAuth, prevRequiresTwoFactorAuth]); + }, [account?.requiresTwoFactorAuth, prevRequiresTwoFactorAuth]); useEffect(() => { if (!inputValidateCodeRef.current || validateCode.length > 0) { @@ -163,27 +140,22 @@ function BaseValidateCodeForm(props) { /** * Handle text input and clear formError upon text change - * - * @param {String} text - * @param {String} key */ - const onTextInput = (text, key) => { - let setInput; + const onTextInput = (text: string, key: ValidateCodeFormVariant) => { if (key === 'validateCode') { - setInput = setValidateCode; + setValidateCode(text); } if (key === 'twoFactorAuthCode') { - setInput = setTwoFactorAuthCode; + setTwoFactorAuthCode(text); } if (key === 'recoveryCode') { - setInput = setRecoveryCode; + setRecoveryCode(text); } - setInput(text); setFormError((prevError) => ({...prevError, [key]: ''})); - if (props.account.errors) { - Session.clearAccountMessages(); + if (account?.errors) { + SessionActions.clearAccountMessages(); } }; @@ -191,8 +163,8 @@ function BaseValidateCodeForm(props) { * Trigger the reset validate code flow and ensure the 2FA input field is reset to avoid it being permanently hidden */ const resendValidateCode = () => { - User.resendValidateCode(props.credentials.login); - inputValidateCodeRef.current.clear(); + User.resendValidateCode(credentials?.login ?? ''); + inputValidateCodeRef.current?.clear(); // Give feedback to the user to let them know the email was sent so that they don't spam the button. setTimeRemaining(30); }; @@ -204,7 +176,7 @@ function BaseValidateCodeForm(props) { setTwoFactorAuthCode(''); setFormError({}); setValidateCode(''); - props.setIsUsingRecoveryCode(false); + setIsUsingRecoveryCode(false); setRecoveryCode(''); }; @@ -213,7 +185,7 @@ function BaseValidateCodeForm(props) { */ const clearSignInData = () => { clearLocalSignInData(); - Session.clearSignInData(); + SessionActions.clearSignInData(); }; useEffect(() => { @@ -221,26 +193,26 @@ function BaseValidateCodeForm(props) { return; } - if (props.account.errors) { - Session.clearAccountMessages(); + if (account?.errors) { + SessionActions.clearAccountMessages(); return; } setNeedToClearError(false); - }, [props.account.errors, needToClearError]); + }, [account?.errors, needToClearError]); /** * Switches between 2fa and recovery code, clears inputs and errors */ const switchBetween2faAndRecoveryCode = () => { - props.setIsUsingRecoveryCode(!props.isUsingRecoveryCode); + setIsUsingRecoveryCode(!isUsingRecoveryCode); setRecoveryCode(''); setTwoFactorAuthCode(''); - setFormError((prevError) => ({...prevError, recoveryCode: '', twoFactorAuthCode: ''})); + setFormError((prevError) => ({...prevError, recoveryCode: undefined, twoFactorAuthCode: undefined})); - if (props.account.errors) { - Session.clearAccountMessages(); + if (account?.errors) { + SessionActions.clearAccountMessages(); } }; @@ -258,10 +230,10 @@ function BaseValidateCodeForm(props) { * Check that all the form fields are valid, then trigger the submit callback */ const validateAndSubmitForm = useCallback(() => { - if (props.account.isLoading) { + if (account?.isLoading) { return; } - const requiresTwoFactorAuth = props.account.requiresTwoFactorAuth; + const requiresTwoFactorAuth = account?.requiresTwoFactorAuth; if (requiresTwoFactorAuth) { if (input2FARef.current) { input2FARef.current.blur(); @@ -269,7 +241,7 @@ function BaseValidateCodeForm(props) { /** * User could be using either recovery code or 2fa code */ - if (!props.isUsingRecoveryCode) { + if (!isUsingRecoveryCode) { if (!twoFactorAuthCode.trim()) { setFormError({twoFactorAuthCode: 'validateCodeForm.error.pleaseFillTwoFactorAuth'}); return; @@ -303,30 +275,30 @@ function BaseValidateCodeForm(props) { } setFormError({}); - const recoveryCodeOr2faCode = props.isUsingRecoveryCode ? recoveryCode : twoFactorAuthCode; + const recoveryCodeOr2faCode = isUsingRecoveryCode ? recoveryCode : twoFactorAuthCode; - const accountID = lodashGet(props.credentials, 'accountID'); + const accountID = credentials?.accountID; if (accountID) { - Session.signInWithValidateCode(accountID, validateCode, recoveryCodeOr2faCode); + SessionActions.signInWithValidateCode(accountID, validateCode, recoveryCodeOr2faCode); } else { - Session.signIn(validateCode, recoveryCodeOr2faCode); + SessionActions.signIn(validateCode, recoveryCodeOr2faCode); } - }, [props.account, props.credentials, twoFactorAuthCode, validateCode, props.isUsingRecoveryCode, recoveryCode]); + }, [account, credentials, twoFactorAuthCode, validateCode, isUsingRecoveryCode, recoveryCode]); return ( <> {/* At this point, if we know the account requires 2FA we already successfully authenticated */} - {props.account.requiresTwoFactorAuth ? ( + {account?.requiresTwoFactorAuth ? ( - {props.isUsingRecoveryCode ? ( + {isUsingRecoveryCode ? ( onTextInput(text, 'recoveryCode')} maxLength={CONST.RECOVERY_CODE_LENGTH} - label={props.translate('recoveryCodeForm.recoveryCode')} - errorText={formError.recoveryCode ? props.translate(formError.recoveryCode) : ''} + label={translate('recoveryCodeForm.recoveryCode')} + errorText={formError.recoveryCode ? translate(formError.recoveryCode) : ''} hasError={hasError} onSubmitEditing={validateAndSubmitForm} autoFocus @@ -334,70 +306,70 @@ function BaseValidateCodeForm(props) { ) : ( { + input2FARef.current = magicCodeInput; + }} name="twoFactorAuthCode" value={twoFactorAuthCode} onChangeText={(text) => onTextInput(text, 'twoFactorAuthCode')} onFulfill={validateAndSubmitForm} maxLength={CONST.TFA_CODE_LENGTH} - errorText={formError.twoFactorAuthCode ? props.translate(formError.twoFactorAuthCode) : ''} + errorText={formError.twoFactorAuthCode ? translate(formError.twoFactorAuthCode) : ''} hasError={hasError} autoFocus key="twoFactorAuthCode" /> )} - {hasError && } + {hasError && } - {props.isUsingRecoveryCode ? props.translate('recoveryCodeForm.use2fa') : props.translate('recoveryCodeForm.useRecoveryCode')} + {isUsingRecoveryCode ? translate('recoveryCodeForm.use2fa') : translate('recoveryCodeForm.useRecoveryCode')} ) : ( { + inputValidateCodeRef.current = magicCodeInput; + }} name="validateCode" value={validateCode} onChangeText={(text) => onTextInput(text, 'validateCode')} onFulfill={validateAndSubmitForm} - errorText={formError.validateCode ? props.translate(formError.validateCode) : ''} + errorText={formError.validateCode ? translate(formError.validateCode) : ''} hasError={hasError} autoFocus key="validateCode" testID="validateCode" /> - {hasError && } + {hasError && !isEmptyObject(account) && } - {timeRemaining > 0 && !props.network.isOffline ? ( + {timeRemaining > 0 && !isOffline ? ( - {props.translate('validateCodeForm.requestNewCode')} + {translate('validateCodeForm.requestNewCode')} 00:{String(timeRemaining).padStart(2, '0')} ) : ( - - {hasError ? props.translate('validateCodeForm.requestNewCodeAfterErrorOccurred') : props.translate('validateCodeForm.magicCodeNotReceived')} + + {hasError ? translate('validateCodeForm.requestNewCodeAfterErrorOccurred') : translate('validateCodeForm.magicCodeNotReceived')} )} @@ -406,10 +378,10 @@ function BaseValidateCodeForm(props) { )}