Skip to content

Commit dea4217

Browse files
authored
Merge pull request Expensify#63588 from software-mansion-labs/war-in/use-listener
Reintroduce "Improve HybridApp initialProps"
2 parents 84ce63d + 5876f4e commit dea4217

6 files changed

Lines changed: 69 additions & 41 deletions

File tree

src/App.tsx

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,12 @@ import CONFIG from './CONFIG';
3939
import Expensify from './Expensify';
4040
import {CurrentReportIDContextProvider} from './hooks/useCurrentReportID';
4141
import useDefaultDragAndDrop from './hooks/useDefaultDragAndDrop';
42+
import HybridAppHandler from './HybridAppHandler';
4243
import OnyxUpdateManager from './libs/actions/OnyxUpdateManager';
4344
import {ReportAttachmentsProvider} from './pages/home/report/ReportAttachmentsContext';
4445
import type {Route} from './ROUTES';
4546
import './setup/backgroundTask';
47+
import './setup/hybridApp';
4648
import {SplashScreenStateContextProvider} from './SplashScreenStateContext';
4749

4850
/**
@@ -54,8 +56,6 @@ type AppProps = {
5456
url?: Route;
5557
/** Serialized configuration data required to initialize the React Native app (e.g. authentication details) */
5658
hybridAppSettings?: string;
57-
/** A timestamp indicating when the initial properties were last updated, used to detect changes */
58-
timestamp?: string;
5959
};
6060

6161
LogBox.ignoreLogs([
@@ -71,18 +71,14 @@ const fill = {flex: 1};
7171

7272
const StrictModeWrapper = CONFIG.USE_REACT_STRICT_MODE_IN_DEV ? React.StrictMode : ({children}: {children: React.ReactElement}) => children;
7373

74-
function App({url, hybridAppSettings, timestamp}: AppProps) {
74+
function App({url, hybridAppSettings}: AppProps) {
7575
useDefaultDragAndDrop();
7676
OnyxUpdateManager();
7777

7878
return (
7979
<StrictModeWrapper>
8080
<SplashScreenStateContextProvider>
81-
<InitialURLContextProvider
82-
url={url}
83-
hybridAppSettings={hybridAppSettings}
84-
timestamp={timestamp}
85-
>
81+
<InitialURLContextProvider url={url}>
8682
<GestureHandlerRootView style={fill}>
8783
<ComposeProviders
8884
components={[
@@ -119,6 +115,7 @@ function App({url, hybridAppSettings, timestamp}: AppProps) {
119115
>
120116
<CustomStatusBarAndBackground />
121117
<ErrorBoundary errorMessage="NewExpensify crash caught by error boundary">
118+
<HybridAppHandler hybridAppSettings={hybridAppSettings} />
122119
<ColorSchemeWrapper>
123120
<Expensify />
124121
</ColorSchemeWrapper>

src/Expensify.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,10 @@ function Expensify() {
209209

210210
// Open chat report from a deep link (only mobile native)
211211
Linking.addEventListener('url', (state) => {
212+
// We use custom deeplink handler in setup/hybridApp
213+
if (CONFIG.IS_HYBRID_APP) {
214+
return;
215+
}
212216
Report.openReportFromDeepLink(state.url);
213217
});
214218

src/HybridAppHandler.tsx

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import {useContext, useState} from 'react';
2+
import type {AppProps} from './App';
3+
import CONFIG from './CONFIG';
4+
import CONST from './CONST';
5+
import {signInAfterTransitionFromOldDot} from './libs/actions/Session';
6+
import SplashScreenStateContext from './SplashScreenStateContext';
7+
8+
function HybridAppHandler({hybridAppSettings}: AppProps) {
9+
const [signInHandled, setSignInHandled] = useState(false);
10+
const {setSplashScreenState} = useContext(SplashScreenStateContext);
11+
12+
if (!CONFIG.IS_HYBRID_APP || !hybridAppSettings || signInHandled) {
13+
return null;
14+
}
15+
16+
signInAfterTransitionFromOldDot(hybridAppSettings).then(() => {
17+
setSplashScreenState(CONST.BOOT_SPLASH_STATE.READY_TO_BE_HIDDEN);
18+
setSignInHandled(true);
19+
});
20+
21+
return null;
22+
}
23+
24+
HybridAppHandler.displayName = 'HybridAppHandler';
25+
26+
export default HybridAppHandler;

src/components/InitialURLContextProvider.tsx

Lines changed: 4 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,8 @@
1-
import {findFocusedRoute} from '@react-navigation/native';
21
import React, {createContext, useEffect, useMemo, useState} from 'react';
32
import type {ReactNode} from 'react';
43
import {Linking} from 'react-native';
5-
import {signInAfterTransitionFromOldDot} from '@libs/actions/Session';
6-
import Navigation, {navigationRef} from '@navigation/Navigation';
74
import type {AppProps} from '@src/App';
8-
import CONST from '@src/CONST';
95
import type {Route} from '@src/ROUTES';
10-
import ROUTES from '@src/ROUTES';
11-
import SCREENS from '@src/SCREENS';
12-
import {useSplashScreenStateContext} from '@src/SplashScreenStateContext';
136

147
type InitialUrlContextType = {
158
initialURL: Route | undefined;
@@ -27,40 +20,18 @@ type InitialURLContextProviderProps = AppProps & {
2720
children: ReactNode;
2821
};
2922

30-
function InitialURLContextProvider({children, url, hybridAppSettings, timestamp}: InitialURLContextProviderProps) {
23+
function InitialURLContextProvider({children, url}: InitialURLContextProviderProps) {
3124
const [initialURL, setInitialURL] = useState<Route | undefined>();
32-
const {splashScreenState, setSplashScreenState} = useSplashScreenStateContext();
3325

3426
useEffect(() => {
35-
if (url && hybridAppSettings) {
36-
signInAfterTransitionFromOldDot(hybridAppSettings).then(() => {
37-
setInitialURL(url);
38-
39-
const parsedUrl = Navigation.parseHybridAppUrl(url);
40-
41-
Navigation.isNavigationReady().then(() => {
42-
if (parsedUrl.startsWith(`/${ROUTES.SHARE_ROOT}`)) {
43-
const focusRoute = findFocusedRoute(navigationRef.getRootState());
44-
if (focusRoute?.name === SCREENS.SHARE.SHARE_DETAILS || focusRoute?.name === SCREENS.SHARE.SUBMIT_DETAILS) {
45-
Navigation.goBack(ROUTES.SHARE_ROOT);
46-
return;
47-
}
48-
}
49-
Navigation.navigate(parsedUrl);
50-
});
51-
52-
if (splashScreenState === CONST.BOOT_SPLASH_STATE.HIDDEN) {
53-
return;
54-
}
55-
setSplashScreenState(CONST.BOOT_SPLASH_STATE.READY_TO_BE_HIDDEN);
56-
});
27+
if (url) {
28+
setInitialURL(url);
5729
return;
5830
}
5931
Linking.getInitialURL().then((initURL) => {
6032
setInitialURL(initURL as Route);
6133
});
62-
// eslint-disable-next-line react-compiler/react-compiler, react-hooks/exhaustive-deps
63-
}, [url, hybridAppSettings, timestamp]);
34+
}, [url]);
6435

6536
const initialUrlContext = useMemo(
6637
() => ({
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import {findFocusedRoute} from '@react-navigation/native';
2+
import {Linking} from 'react-native';
3+
import Navigation, {navigationRef} from '@navigation/Navigation';
4+
import CONFIG from '@src/CONFIG';
5+
import type {Route} from '@src/ROUTES';
6+
import ROUTES from '@src/ROUTES';
7+
import SCREENS from '@src/SCREENS';
8+
9+
if (CONFIG.IS_HYBRID_APP) {
10+
Linking.addEventListener('url', (state) => {
11+
handleHybridUrlNavigation(state.url as Route);
12+
});
13+
}
14+
15+
function handleHybridUrlNavigation(url: Route) {
16+
const parsedUrl = Navigation.parseHybridAppUrl(url);
17+
18+
Navigation.isNavigationReady().then(() => {
19+
if (parsedUrl.startsWith(`/${ROUTES.SHARE_ROOT}`)) {
20+
const focusRoute = findFocusedRoute(navigationRef.getRootState());
21+
if (focusRoute?.name === SCREENS.SHARE.SHARE_DETAILS || focusRoute?.name === SCREENS.SHARE.SUBMIT_DETAILS) {
22+
Navigation.goBack(ROUTES.SHARE_ROOT);
23+
return;
24+
}
25+
}
26+
Navigation.navigate(parsedUrl);
27+
});
28+
}

src/setup/hybridApp/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
// This file is intentionally empty as Hybrid App is a native mobile platforms feature
2+
// See `index.native.ts` for the native implementation.

0 commit comments

Comments
 (0)