Skip to content

Commit

Permalink
Merge pull request #32728 from software-mansion-labs/ts/DeeplinkWrapper
Browse files Browse the repository at this point in the history
  • Loading branch information
youssef-lr authored Dec 15, 2023
2 parents 173582f + 33e9618 commit e23eebe
Show file tree
Hide file tree
Showing 6 changed files with 56 additions and 69 deletions.
Original file line number Diff line number Diff line change
@@ -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 useLocalize from '@hooks/useLocalize';
import useTheme from '@hooks/useTheme';
import useThemeStyles from '@hooks/useThemeStyles';
import compose from '@libs/compose';
import Navigation from '@libs/Navigation/Navigation';
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<OnyxTypes.Session>;
};

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 (
<View style={styles.deeplinkWrapperContainer}>
<View style={styles.deeplinkWrapperMessage}>
Expand All @@ -46,8 +40,8 @@ function DeeplinkRedirectLoadingIndicator({translate, openLinkInBrowser, session
/>
</View>
<Text style={[styles.textHeadline, styles.textXXLarge]}>{translate('deeplinkWrapper.launching')}</Text>
<View style={[styles.mt2, styles.fontSizeNormal, styles.textAlignCenter]}>
<Text>{translate('deeplinkWrapper.loggedInAs', {email: session.email})}</Text>
<View style={[styles.mt2, styles.textAlignCenter]}>
<Text>{translate('deeplinkWrapper.loggedInAs', {email: session?.email ?? ''})}</Text>
<Text style={[styles.textAlignCenter]}>
{translate('deeplinkWrapper.doNotSeePrompt')} <TextLink onPress={() => openLinkInBrowser(true)}>{translate('deeplinkWrapper.tryAgain')}</TextLink>
{translate('deeplinkWrapper.or')} <TextLink onPress={() => Navigation.navigate(ROUTES.HOME)}>{translate('deeplinkWrapper.continueInWeb')}</TextLink>.
Expand All @@ -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<DeeplinkRedirectLoadingIndicatorProps, DeeplinkRedirectLoadingIndicatorOnyxProps>({
session: {
key: ONYXKEYS.SESSION,
},
})(DeeplinkRedirectLoadingIndicator);
14 changes: 0 additions & 14 deletions src/components/DeeplinkWrapper/index.js

This file was deleted.

9 changes: 9 additions & 0 deletions src/components/DeeplinkWrapper/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import DeeplinkWrapperProps from './types';

function DeeplinkWrapper({children}: DeeplinkWrapperProps) {
return children;
}

DeeplinkWrapper.displayName = 'DeeplinkWrapper';

export default DeeplinkWrapper;
Original file line number Diff line number Diff line change
@@ -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';
Expand All @@ -10,17 +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,
/** The auto authentication status */
autoAuthState: PropTypes.string,
};

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);
}

Expand All @@ -38,10 +28,11 @@ function promptToOpenInDesktopApp() {
App.beginDeepLinkRedirect(!isMagicLink);
}
}
function DeeplinkWrapper({children, isAuthenticated, autoAuthState}) {
const [currentScreen, setCurrentScreen] = useState();

function DeeplinkWrapper({children, isAuthenticated, autoAuthState}: DeeplinkWrapperProps) {
const [currentScreen, setCurrentScreen] = useState<string | undefined>();
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,
Expand All @@ -55,21 +46,21 @@ function DeeplinkWrapper({children, isAuthenticated, autoAuthState}) {
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 || hasShownPrompt || CONFIG.ENVIRONMENT === CONST.ENVIRONMENT.DEV || autoAuthState === CONST.AUTO_AUTH_STATE.NOT_STARTED) {
return;
Expand Down Expand Up @@ -99,5 +90,6 @@ function DeeplinkWrapper({children, isAuthenticated, autoAuthState}) {
return children;
}

DeeplinkWrapper.propTypes = propTypes;
DeeplinkWrapper.displayName = 'DeeplinkWrapper';

export default DeeplinkWrapper;
11 changes: 11 additions & 0 deletions src/components/DeeplinkWrapper/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import ChildrenProps from '@src/types/utils/ChildrenProps';

type DeeplinkWrapperProps = ChildrenProps & {
/** User authentication status */
isAuthenticated: boolean;

/** The auto authentication status */
autoAuthState?: string;
};

export default DeeplinkWrapperProps;
4 changes: 2 additions & 2 deletions src/libs/Navigation/Navigation.ts
Original file line number Diff line number Diff line change
@@ -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';
Expand Down Expand Up @@ -247,7 +247,7 @@ function getActiveRouteWithoutParams(): string {
}

/** Returns the active route name from a state event from the navigationRef */
function getRouteNameFromStateEvent(event: EventMapCore<NavigationState>['state']): string | undefined {
function getRouteNameFromStateEvent(event: EventArg<'state', false, NavigationContainerEventMap['state']['data']>): string | undefined {
if (!event.data.state) {
return;
}
Expand Down

0 comments on commit e23eebe

Please sign in to comment.