From b9f80f501d9e1e37c133b8af13ba8a9715558906 Mon Sep 17 00:00:00 2001 From: Blazej Kustra Date: Fri, 8 Dec 2023 16:42:36 +0100 Subject: [PATCH 1/2] [TS migration] Migrate 'DeeplinkWrapper' component to TypeScript --- ...s => DeeplinkRedirectLoadingIndicator.tsx} | 49 +++++++------------ src/components/DeeplinkWrapper/index.js | 14 ------ src/components/DeeplinkWrapper/index.tsx | 9 ++++ .../{index.website.js => index.website.tsx} | 36 ++++++-------- src/components/DeeplinkWrapper/types.ts | 8 +++ src/libs/Navigation/Navigation.ts | 4 +- 6 files changed, 53 insertions(+), 67 deletions(-) rename src/components/DeeplinkWrapper/{DeeplinkRedirectLoadingIndicator.js => DeeplinkRedirectLoadingIndicator.tsx} (68%) delete mode 100644 src/components/DeeplinkWrapper/index.js create mode 100644 src/components/DeeplinkWrapper/index.tsx rename src/components/DeeplinkWrapper/{index.website.js => index.website.tsx} (79%) create mode 100644 src/components/DeeplinkWrapper/types.ts diff --git a/src/components/DeeplinkWrapper/DeeplinkRedirectLoadingIndicator.js b/src/components/DeeplinkWrapper/DeeplinkRedirectLoadingIndicator.tsx similarity index 68% rename from src/components/DeeplinkWrapper/DeeplinkRedirectLoadingIndicator.js rename to src/components/DeeplinkWrapper/DeeplinkRedirectLoadingIndicator.tsx index 3c7366949ac1..4f169ad68e52 100644 --- a/src/components/DeeplinkWrapper/DeeplinkRedirectLoadingIndicator.js +++ b/src/components/DeeplinkWrapper/DeeplinkRedirectLoadingIndicator.tsx @@ -1,40 +1,34 @@ -import PropTypes from 'prop-types'; import React from 'react'; import {View} from 'react-native'; -import {withOnyx} from 'react-native-onyx'; +import {OnyxEntry, withOnyx} from 'react-native-onyx'; import Icon from '@components/Icon'; import * as Expensicons from '@components/Icon/Expensicons'; import * as Illustrations from '@components/Icon/Illustrations'; import Text from '@components/Text'; import TextLink from '@components/TextLink'; -import withLocalize, {withLocalizePropTypes} from '@components/withLocalize'; -import compose from '@libs/compose'; +import useLocalize from '@hooks/useLocalize'; import Navigation from '@libs/Navigation/Navigation'; import useTheme from '@styles/themes/useTheme'; import useThemeStyles from '@styles/useThemeStyles'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; +import * as OnyxTypes from '@src/types/onyx'; -const propTypes = { - openLinkInBrowser: PropTypes.func.isRequired, - - session: PropTypes.shape({ - /** Currently logged-in user email */ - email: PropTypes.string, - }), - - ...withLocalizePropTypes, +type DeeplinkRedirectLoadingIndicatorOnyxProps = { + /** Current user session */ + session: OnyxEntry; }; -const defaultProps = { - session: { - email: '', - }, +type DeeplinkRedirectLoadingIndicatorProps = DeeplinkRedirectLoadingIndicatorOnyxProps & { + /** Opens the link in the browser */ + openLinkInBrowser: (value: boolean) => void; }; -function DeeplinkRedirectLoadingIndicator({translate, openLinkInBrowser, session}) { +function DeeplinkRedirectLoadingIndicator({openLinkInBrowser, session}: DeeplinkRedirectLoadingIndicatorProps) { + const {translate} = useLocalize(); const theme = useTheme(); const styles = useThemeStyles(); + return ( @@ -46,8 +40,8 @@ function DeeplinkRedirectLoadingIndicator({translate, openLinkInBrowser, session /> {translate('deeplinkWrapper.launching')} - - {translate('deeplinkWrapper.loggedInAs', {email: session.email})} + + {translate('deeplinkWrapper.loggedInAs', {email: session?.email ?? ''})} {translate('deeplinkWrapper.doNotSeePrompt')} openLinkInBrowser(true)}>{translate('deeplinkWrapper.tryAgain')} {translate('deeplinkWrapper.or')} Navigation.navigate(ROUTES.HOME)}>{translate('deeplinkWrapper.continueInWeb')}. @@ -66,15 +60,10 @@ function DeeplinkRedirectLoadingIndicator({translate, openLinkInBrowser, session ); } -DeeplinkRedirectLoadingIndicator.propTypes = propTypes; -DeeplinkRedirectLoadingIndicator.defaultProps = defaultProps; DeeplinkRedirectLoadingIndicator.displayName = 'DeeplinkRedirectLoadingIndicator'; -export default compose( - withLocalize, - withOnyx({ - session: { - key: ONYXKEYS.SESSION, - }, - }), -)(DeeplinkRedirectLoadingIndicator); +export default withOnyx({ + session: { + key: ONYXKEYS.SESSION, + }, +})(DeeplinkRedirectLoadingIndicator); diff --git a/src/components/DeeplinkWrapper/index.js b/src/components/DeeplinkWrapper/index.js deleted file mode 100644 index de50d9bdf134..000000000000 --- a/src/components/DeeplinkWrapper/index.js +++ /dev/null @@ -1,14 +0,0 @@ -import PropTypes from 'prop-types'; - -const propTypes = { - /** Children to render. */ - children: PropTypes.node.isRequired, -}; - -function DeeplinkWrapper({children}) { - return children; -} - -DeeplinkWrapper.propTypes = propTypes; - -export default DeeplinkWrapper; diff --git a/src/components/DeeplinkWrapper/index.tsx b/src/components/DeeplinkWrapper/index.tsx new file mode 100644 index 000000000000..4b0382bd6b14 --- /dev/null +++ b/src/components/DeeplinkWrapper/index.tsx @@ -0,0 +1,9 @@ +import DeeplinkWrapperProps from './types'; + +function DeeplinkWrapper({children}: DeeplinkWrapperProps) { + return children; +} + +DeeplinkWrapper.displayName = 'DeeplinkWrapper'; + +export default DeeplinkWrapper; diff --git a/src/components/DeeplinkWrapper/index.website.js b/src/components/DeeplinkWrapper/index.website.tsx similarity index 79% rename from src/components/DeeplinkWrapper/index.website.js rename to src/components/DeeplinkWrapper/index.website.tsx index 166818e4ae27..997d21c41a3f 100644 --- a/src/components/DeeplinkWrapper/index.website.js +++ b/src/components/DeeplinkWrapper/index.website.tsx @@ -1,7 +1,5 @@ import Str from 'expensify-common/lib/str'; -import PropTypes from 'prop-types'; import {useEffect, useRef, useState} from 'react'; -import _ from 'underscore'; import * as Browser from '@libs/Browser'; import Navigation from '@libs/Navigation/Navigation'; import navigationRef from '@libs/Navigation/navigationRef'; @@ -10,15 +8,9 @@ import * as App from '@userActions/App'; import CONFIG from '@src/CONFIG'; import CONST from '@src/CONST'; import ROUTES from '@src/ROUTES'; +import DeeplinkWrapperProps from './types'; -const propTypes = { - /** Children to render. */ - children: PropTypes.node.isRequired, - /** User authentication status */ - isAuthenticated: PropTypes.bool.isRequired, -}; - -function isMacOSWeb() { +function isMacOSWeb(): boolean { return !Browser.isMobile() && typeof navigator === 'object' && typeof navigator.userAgent === 'string' && /Mac/i.test(navigator.userAgent) && !/Electron/i.test(navigator.userAgent); } @@ -36,10 +28,11 @@ function promptToOpenInDesktopApp() { App.beginDeepLinkRedirect(!isMagicLink); } } -function DeeplinkWrapper({children, isAuthenticated}) { - const [currentScreen, setCurrentScreen] = useState(); + +function DeeplinkWrapper({children, isAuthenticated}: DeeplinkWrapperProps) { + const [currentScreen, setCurrentScreen] = useState(); const [hasShownPrompt, setHasShownPrompt] = useState(false); - const removeListener = useRef(); + const removeListener = useRef<() => void>(); useEffect(() => { // If we've shown the prompt and still have a listener registered, @@ -53,21 +46,21 @@ function DeeplinkWrapper({children, isAuthenticated}) { setHasShownPrompt(false); Navigation.isNavigationReady().then(() => { // Get initial route - const initialRoute = navigationRef.current.getCurrentRoute(); - setCurrentScreen(initialRoute.name); + const initialRoute = navigationRef.current?.getCurrentRoute(); + setCurrentScreen(initialRoute?.name); - removeListener.current = navigationRef.current.addListener('state', (event) => { + removeListener.current = navigationRef.current?.addListener('state', (event) => { setCurrentScreen(Navigation.getRouteNameFromStateEvent(event)); }); }); } }, [hasShownPrompt, isAuthenticated]); + useEffect(() => { // According to the design, we don't support unlink in Desktop app https://github.com/Expensify/App/issues/19681#issuecomment-1610353099 - const isUnsupportedDeeplinkRoute = _.some([CONST.REGEX.ROUTES.UNLINK_LOGIN], (unsupportRouteRegex) => { - const routeRegex = new RegExp(unsupportRouteRegex); - return routeRegex.test(window.location.pathname); - }); + const routeRegex = new RegExp(CONST.REGEX.ROUTES.UNLINK_LOGIN); + const isUnsupportedDeeplinkRoute = routeRegex.test(window.location.pathname); + // Making a few checks to exit early before checking authentication status if (!isMacOSWeb() || isUnsupportedDeeplinkRoute || CONFIG.ENVIRONMENT === CONST.ENVIRONMENT.DEV || hasShownPrompt) { return; @@ -97,5 +90,6 @@ function DeeplinkWrapper({children, isAuthenticated}) { return children; } -DeeplinkWrapper.propTypes = propTypes; +DeeplinkWrapper.displayName = 'DeeplinkWrapper'; + export default DeeplinkWrapper; diff --git a/src/components/DeeplinkWrapper/types.ts b/src/components/DeeplinkWrapper/types.ts new file mode 100644 index 000000000000..3d8cd9f407f4 --- /dev/null +++ b/src/components/DeeplinkWrapper/types.ts @@ -0,0 +1,8 @@ +import ChildrenProps from '@src/types/utils/ChildrenProps'; + +type DeeplinkWrapperProps = ChildrenProps & { + /** User authentication status */ + isAuthenticated: boolean; +}; + +export default DeeplinkWrapperProps; diff --git a/src/libs/Navigation/Navigation.ts b/src/libs/Navigation/Navigation.ts index c2dd3e76e7ad..3552ff9e7410 100644 --- a/src/libs/Navigation/Navigation.ts +++ b/src/libs/Navigation/Navigation.ts @@ -1,5 +1,5 @@ import {findFocusedRoute, getActionFromState} from '@react-navigation/core'; -import {CommonActions, EventMapCore, getPathFromState, NavigationState, PartialState, StackActions} from '@react-navigation/native'; +import {CommonActions, EventArg, getPathFromState, NavigationContainerEventMap, NavigationState, PartialState, StackActions} from '@react-navigation/native'; import findLastIndex from 'lodash/findLastIndex'; import Log from '@libs/Log'; import CONST from '@src/CONST'; @@ -247,7 +247,7 @@ function getActiveRouteWithoutParams(): string { } /** Returns the active route name from a state event from the navigationRef */ -function getRouteNameFromStateEvent(event: EventMapCore['state']): string | undefined { +function getRouteNameFromStateEvent(event: EventArg<'state', false, NavigationContainerEventMap['state']['data']>): string | undefined { if (!event.data.state) { return; } From 29553bb0adac8db48165ea66ab3b1c8c6ffbe1ef Mon Sep 17 00:00:00 2001 From: Blazej Kustra Date: Wed, 13 Dec 2023 10:45:06 +0100 Subject: [PATCH 2/2] Add new type to DeeplinkWrapperProps --- src/components/DeeplinkWrapper/types.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/components/DeeplinkWrapper/types.ts b/src/components/DeeplinkWrapper/types.ts index 3d8cd9f407f4..dfd56b62573d 100644 --- a/src/components/DeeplinkWrapper/types.ts +++ b/src/components/DeeplinkWrapper/types.ts @@ -3,6 +3,9 @@ import ChildrenProps from '@src/types/utils/ChildrenProps'; type DeeplinkWrapperProps = ChildrenProps & { /** User authentication status */ isAuthenticated: boolean; + + /** The auto authentication status */ + autoAuthState?: string; }; export default DeeplinkWrapperProps;