From b6e163b4bf3aae4726dae2dc944107be3fed215e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Marcin=20Warcho=C5=82?=
 <61014013+war-in@users.noreply.github.com>
Date: Fri, 30 May 2025 16:14:42 +0200
Subject: [PATCH] Revert "Improve HybridApp initialProps"

---
 src/App.tsx                                  | 17 +++---
 src/Expensify.tsx                            |  4 --
 src/HybridAppHandler.tsx                     | 57 --------------------
 src/components/InitialURLContextProvider.tsx | 37 +++++++++++--
 4 files changed, 41 insertions(+), 74 deletions(-)
 delete mode 100644 src/HybridAppHandler.tsx

diff --git a/src/App.tsx b/src/App.tsx
index 5d2450347b10..e7dd3684ef39 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -39,7 +39,6 @@ import CONFIG from './CONFIG';
 import Expensify from './Expensify';
 import {CurrentReportIDContextProvider} from './hooks/useCurrentReportID';
 import useDefaultDragAndDrop from './hooks/useDefaultDragAndDrop';
-import HybridAppHandler from './HybridAppHandler';
 import OnyxUpdateManager from './libs/actions/OnyxUpdateManager';
 import {ReportAttachmentsProvider} from './pages/home/report/ReportAttachmentsContext';
 import type {Route} from './ROUTES';
@@ -55,6 +54,8 @@ type AppProps = {
     url?: Route;
     /** Serialized configuration data required to initialize the React Native app (e.g. authentication details) */
     hybridAppSettings?: string;
+    /** A timestamp indicating when the initial properties were last updated, used to detect changes */
+    timestamp?: string;
 };
 
 LogBox.ignoreLogs([
@@ -70,14 +71,18 @@ const fill = {flex: 1};
 
 const StrictModeWrapper = CONFIG.USE_REACT_STRICT_MODE_IN_DEV ? React.StrictMode : ({children}: {children: React.ReactElement}) => children;
 
-function App({url, hybridAppSettings}: AppProps) {
+function App({url, hybridAppSettings, timestamp}: AppProps) {
     useDefaultDragAndDrop();
     OnyxUpdateManager();
 
     return (
         <StrictModeWrapper>
             <SplashScreenStateContextProvider>
-                <InitialURLContextProvider url={url}>
+                <InitialURLContextProvider
+                    url={url}
+                    hybridAppSettings={hybridAppSettings}
+                    timestamp={timestamp}
+                >
                     <GestureHandlerRootView style={fill}>
                         <ComposeProviders
                             components={[
@@ -114,12 +119,6 @@ function App({url, hybridAppSettings}: AppProps) {
                         >
                             <CustomStatusBarAndBackground />
                             <ErrorBoundary errorMessage="NewExpensify crash caught by error boundary">
-                                {CONFIG.IS_HYBRID_APP && (
-                                    <HybridAppHandler
-                                        url={url}
-                                        hybridAppSettings={hybridAppSettings}
-                                    />
-                                )}
                                 <ColorSchemeWrapper>
                                     <Expensify />
                                 </ColorSchemeWrapper>
diff --git a/src/Expensify.tsx b/src/Expensify.tsx
index ad33fca33fbe..5c60815cbedb 100644
--- a/src/Expensify.tsx
+++ b/src/Expensify.tsx
@@ -215,10 +215,6 @@ function Expensify() {
 
         // Open chat report from a deep link (only mobile native)
         Linking.addEventListener('url', (state) => {
-            // We use custom deeplink handler in HybridAppHandler
-            if (CONFIG.IS_HYBRID_APP) {
-                return;
-            }
             Report.openReportFromDeepLink(state.url);
         });
 
diff --git a/src/HybridAppHandler.tsx b/src/HybridAppHandler.tsx
deleted file mode 100644
index 61401c63e5a2..000000000000
--- a/src/HybridAppHandler.tsx
+++ /dev/null
@@ -1,57 +0,0 @@
-import {findFocusedRoute} from '@react-navigation/native';
-import {useContext, useEffect, useState} from 'react';
-import {Linking} from 'react-native';
-import type {AppProps} from './App';
-import CONST from './CONST';
-import {signInAfterTransitionFromOldDot} from './libs/actions/Session';
-import Navigation, {navigationRef} from './libs/Navigation/Navigation';
-import type {Route} from './ROUTES';
-import ROUTES from './ROUTES';
-import SCREENS from './SCREENS';
-import SplashScreenStateContext from './SplashScreenStateContext';
-
-function handleHybridUrlNavigation(url: Route) {
-    const parsedUrl = Navigation.parseHybridAppUrl(url);
-
-    Navigation.isNavigationReady().then(() => {
-        if (parsedUrl.startsWith(`/${ROUTES.SHARE_ROOT}`)) {
-            const focusRoute = findFocusedRoute(navigationRef.getRootState());
-            if (focusRoute?.name === SCREENS.SHARE.SHARE_DETAILS || focusRoute?.name === SCREENS.SHARE.SUBMIT_DETAILS) {
-                Navigation.goBack(ROUTES.SHARE_ROOT);
-                return;
-            }
-        }
-        Navigation.navigate(parsedUrl);
-    });
-}
-
-function HybridAppHandler({url, hybridAppSettings}: AppProps) {
-    const [signInHandled, setSignInHandled] = useState(false);
-    const {setSplashScreenState} = useContext(SplashScreenStateContext);
-
-    useEffect(() => {
-        const listener = Linking.addEventListener('url', (state) => {
-            handleHybridUrlNavigation(state.url as Route);
-        });
-
-        return () => {
-            listener.remove();
-        };
-    }, []);
-
-    if (!url || !hybridAppSettings || signInHandled) {
-        return null;
-    }
-
-    signInAfterTransitionFromOldDot(hybridAppSettings).then(() => {
-        handleHybridUrlNavigation(url);
-        setSplashScreenState(CONST.BOOT_SPLASH_STATE.READY_TO_BE_HIDDEN);
-        setSignInHandled(true);
-    });
-
-    return null;
-}
-
-HybridAppHandler.displayName = 'HybridAppHandler';
-
-export default HybridAppHandler;
diff --git a/src/components/InitialURLContextProvider.tsx b/src/components/InitialURLContextProvider.tsx
index 1aa40d6c1d7a..c1a0ce3cbd89 100644
--- a/src/components/InitialURLContextProvider.tsx
+++ b/src/components/InitialURLContextProvider.tsx
@@ -1,8 +1,15 @@
+import {findFocusedRoute} from '@react-navigation/native';
 import React, {createContext, useEffect, useMemo, useState} from 'react';
 import type {ReactNode} from 'react';
 import {Linking} from 'react-native';
+import {signInAfterTransitionFromOldDot} from '@libs/actions/Session';
+import Navigation, {navigationRef} from '@navigation/Navigation';
 import type {AppProps} from '@src/App';
+import CONST from '@src/CONST';
 import type {Route} from '@src/ROUTES';
+import ROUTES from '@src/ROUTES';
+import SCREENS from '@src/SCREENS';
+import {useSplashScreenStateContext} from '@src/SplashScreenStateContext';
 
 type InitialUrlContextType = {
     initialURL: Route | undefined;
@@ -20,18 +27,40 @@ type InitialURLContextProviderProps = AppProps & {
     children: ReactNode;
 };
 
-function InitialURLContextProvider({children, url}: InitialURLContextProviderProps) {
+function InitialURLContextProvider({children, url, hybridAppSettings, timestamp}: InitialURLContextProviderProps) {
     const [initialURL, setInitialURL] = useState<Route | undefined>();
+    const {splashScreenState, setSplashScreenState} = useSplashScreenStateContext();
 
     useEffect(() => {
-        if (url) {
-            setInitialURL(url);
+        if (url && hybridAppSettings) {
+            signInAfterTransitionFromOldDot(hybridAppSettings).then(() => {
+                setInitialURL(url);
+
+                const parsedUrl = Navigation.parseHybridAppUrl(url);
+
+                Navigation.isNavigationReady().then(() => {
+                    if (parsedUrl.startsWith(`/${ROUTES.SHARE_ROOT}`)) {
+                        const focusRoute = findFocusedRoute(navigationRef.getRootState());
+                        if (focusRoute?.name === SCREENS.SHARE.SHARE_DETAILS || focusRoute?.name === SCREENS.SHARE.SUBMIT_DETAILS) {
+                            Navigation.goBack(ROUTES.SHARE_ROOT);
+                            return;
+                        }
+                    }
+                    Navigation.navigate(parsedUrl);
+                });
+
+                if (splashScreenState === CONST.BOOT_SPLASH_STATE.HIDDEN) {
+                    return;
+                }
+                setSplashScreenState(CONST.BOOT_SPLASH_STATE.READY_TO_BE_HIDDEN);
+            });
             return;
         }
         Linking.getInitialURL().then((initURL) => {
             setInitialURL(initURL as Route);
         });
-    }, [url]);
+        // eslint-disable-next-line react-compiler/react-compiler, react-hooks/exhaustive-deps
+    }, [url, hybridAppSettings, timestamp]);
 
     const initialUrlContext = useMemo(
         () => ({
